HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

ItemHolder

04-04-2009, 03:44 AM#1
Vexorian
Err, explanation in the script's header, mostly a struct-based replacement for CS' "Safe item hiding" module. Requires xe (xebasic) xe

Collapse JASS:
library ItemHolder requires xebasic
//*************************************************************
//* ItemHolder
//* ----------
//* Requirements:* xebasic (for the dummy unit)
//*              * A inventory ability that requires
//*                no upgrades and is not able to use the items
//*
//*   Wc3 items can't get truly hidden, i.e. 
//* they will still cause side effects, for example if you
//* pick all items in a rect, hidden items will appear. AI
//* heroes pick them, when you load a game, they become visible
//* it is a little messy.
//*
//*   This library provides an abstraction
//* for safer item hiding using these ItemHolder objects
//* to store the items.
//*
//* Usage:
//*  set var = ItemHolder.holdItem( theItem) : will hide the item
//*        and keep it held inside the returned ItemHolder object 
//*
//*  call var.releaseItem( x, y )  : When called from a
//*        ItemHolder object, it will restore the item at (x,y)
//*        the item becomes 'visible' again, the object is
//*        destroyed
//*
//*   var.heldItem : a read only member variable, returns the item
//*    that is currently in custody by the object, the intention
//*    is to allow people to call things like GetItemTypeId and
//*    maybe mess with stuff attached to the item. Please do not
//*    do stuff that would modify the item's state during this
//*    stage (You can Set item data, get item id, classification
//*    mess with stuff attached to it, but you shall not
//*    change the position, give it to a unit, etc.
//*
//* Cons:
//*   - The method used is to give the items to some dummy units
//*     this makes it unable to work on runes, if an item cannot
//*     be hidden when using holdItem(), holdItem will return 0
//*     and  during debug mode, display an error message.
//*
//**************************************************************

//================================================================
// config:
//

    globals
        private integer DUMMY_INVENTORY = 'A00C'
        //a inventory ability with 6 slots that has no bonuses
    endglobals

//=================================================================
    globals
        private unit current = null
        private integer    emptyCount = 0
        private unit array empty
    endglobals


    struct ItemHolder
       
       private item  varHeldItem
       private unit  storageUnit
       
       
       method operator heldItem takes nothing returns item
           return this.varHeldItem
       endmethod
       
       static method holdItem takes item theItem returns ItemHolder
        local ItemHolder ih
           if ( current == null ) then
               if(emptyCount>0) then
                   set emptyCount = emptyCount - 1
                   set current = empty[emptyCount]
               else
                   set current = CreateUnit(Player(15), XE_DUMMY_UNITID, 0,0,0)
               endif
               call UnitAddAbility(current, DUMMY_INVENTORY)
               call ShowUnit(current,false)
           endif
           
           if not  UnitAddItem(current, theItem) then
               debug call BJDebugMsg("WARNING: ItemHolder, attempt to store item of type: ["+GetItemName(theItem)+"] has utterly failed")
               return 0
           endif
           
           set ih = ItemHolder.allocate()
           set ih.varHeldItem = theItem
           set ih.storageUnit = current
           if(UnitInventoryCount(current) == UnitInventorySize( current) ) then
               set current=null
           endif
           
           return ih
       endmethod
       
       private method onDestroy takes nothing returns nothing
           if (UnitInventoryCount( this.storageUnit ) == UnitInventorySize( this.storageUnit )) then
               set empty[emptyCount] = this.storageUnit
               set emptyCount = emptyCount+1
           endif
           call UnitRemoveItem( this.storageUnit, this.varHeldItem) 
       endmethod
       
       private static item returnItem
       method releaseItem takes real x, real y returns item
          set .returnItem = this.varHeldItem
          call this.destroy()
          call SetItemPosition(.returnItem, x,y)
          return .returnItem
       endmethod

       private static method create takes nothing returns ItemHolder
           return 0
       endmethod

    endstruct

endlibrary
04-04-2009, 04:01 AM#2
Kwah
I was un-aware of the existing bugs, but this is a quite reasonable fix.

Nice debug message.
04-04-2009, 04:39 AM#3
darkwulfv
I think ItemHider would be a better name for this, since that's techically what it's used for. Although (I think) this is done by giving the item to a dummy unit...
04-04-2009, 05:46 AM#4
fX_
What's the ItemHolder.create() for?
04-04-2009, 07:56 AM#5
akolyt0r
Quote:
Originally Posted by fX_
What's the ItemHolder.create() for?
render create useless because vex wants to have the .holdItem method for creation...
04-05-2009, 06:45 AM#6
fX_
cant he just note that ItemHolder.holdItem() is meant to be the .create method tho...
a comment or something will inform users; a 'nullified' method will just lead to errors/bugs when they are uninformed and use the .create method.
04-05-2009, 03:52 PM#7
akolyt0r
Quote:
Originally Posted by fX_
cant he just note that ItemHolder.holdItem() is meant to be the .create method tho...
a comment or something will inform users; a 'nullified' method will just lead to errors/bugs when they are uninformed and use the .create method.
totally no!
when you dont add this nullified create method vJass will allocate the instance properly, however the variables and stuff wont be initialized...which will cause random crashes...
With this nullified create-method, it will work much better, since vJass will inform you about the use of a "0"-struct... (in debug mode.) ... so you can locate your error much more easily
04-05-2009, 05:17 PM#8
fX_
ya but the comment is so that the .create method will not be used at all by users or at least they are informed.

if he added that .create method just for demonstration that .create = null and its analog is .holdItem, wouldnt a comment be more straight to the point and simpler?
04-05-2009, 10:38 PM#9
Anitarf
Quote:
Originally Posted by fX_
ya but the comment is so that the .create method will not be used at all by users or at least they are informed.
If the .create method does not appear in the documentation, then it was obviously not meant to be used.

Quote:
Originally Posted by akolyt0r
when you dont add this nullified create method vJass will allocate the instance properly, however the variables and stuff wont be initialized...which will cause random crashes...
Uninitialised arrays do not cause crashes like uninitialised variables do. Also, war3err detects, prevents and informs you of such crashes anyway.
Quote:
With this nullified create-method, it will work much better, since vJass will inform you about the use of a "0"-struct... (in debug mode.) ... so you can locate your error much more easily
Actually, the map won't even compile if you try to use it, since it's declared as a private static method.


Edit: Vex, why not put a unit on the empty list as soon as it has room for one new item instead of waiting for all the items it has to be dropped before making it available for refilling?
04-05-2009, 11:57 PM#10
Vexorian
Quote:
Edit: Vex, why not put a unit on the empty list as soon as it has room for one new item instead of waiting for all the items it has to be dropped before making it available for refilling?
I don't think it matters that much, can't think of situations in which it would help, but if I added the unit to the list I would need more code for making sure not to add twice.
04-06-2009, 01:02 AM#11
Anitarf
Quote:
Originally Posted by Vexorian
I don't think it matters that much, can't think of situations in which it would help,
Well, it could considerably cut the number of dummy units created, in theory up to 6 times (obviously not as much in practice, though the number could be approached if you were periodically hiding a lot of items for variable durations).

Quote:
but if I added the unit to the list I would need more code for making sure not to add twice.
Wouldn't only adding the unit if it has a full inventory before removing the item from it be enough? That's the same amount of code, just reordered a bit:

Expand JASS:
04-06-2009, 02:04 AM#12
Vexorian
I don't think it would decrease the count at all, but ok, done It is the right thing to do I guess.
04-06-2009, 02:48 AM#13
Anitarf
An .isItemHeld static method would be nice to have though probably too much extra code to implement...
04-06-2009, 02:52 AM#14
Vexorian
Basically, that is not the intended use, the intended use is to encapsulate the item inside an itemholder and just use the itemholder directly. Else it would be really a mess, and attachment stuff, etc...
04-06-2009, 03:46 AM#15
Anitarf
Yeah, I suppose users will just have to store the hiden-ness of an item in a separate variable if they want multiple libraries to be able to manipulate the same item.

Anyway, tested it and it works, approved.