Inventory System - JASS Interface

Jesus4Lyf

Good Idea™
Reaction score
397
Got tired of changing the thread topic for the other one, and it's was originally about LUA, and the practicalities of it.

I'm wondering now, what sort of JASS features need to be available to an inventory system? The structure is this:

Every unit with an inventory has pockets in the normal items area. There can be any number of pockets, which are declared in the script. In each pocket, a unit may hold up to 10 different itemtypes, and any number of each item type. So they can hold 10 items unless they stack. Demo. And to clarify, each ItemType has a fixed pocket it goes to.

So then. What JASS functions are required? Inevitably, the user will want to know if the unit has an item of a certain type. Since this system allows attaching to individual items and stacking of items, there is a slight issue - if one item is "enchanted" or has certain stats, and the user then picks up one which is not, the order of the items becomes important. Dropping an item will always drop the latest one picked up. The real issue is, the user will wish to retrieve all items of type x from a unit. So to get an actual item, syntax is something like:
JASS:
Inventory[unit].getItemList(MyItemType)[1] // the last is the item number, in order of pick up.

Seems to make sense to me. Anyone have other ideas?

What about getting all items for a pocket? Will people need that? Or the number of items in a pocket?
JASS:
Inventory[unit].getPocket(MyPocket) // returns a list of ItemTypes that the unit has.

Hm. It kind of makes sense to me. What will the list object be like? Will it be an iterator? Does it need to destroy itself automatically? Should I just add a .forAllItemsInList(some method) kinda thing? Hm!

Need interface ideas...
 

Narks

Vastly intelligent whale-like being from the stars
Reaction score
90
make a struct called ItemGroup or something, that simulates a unit group except with items?
 

Jesus4Lyf

Good Idea™
Reaction score
397
And that will either have O(n) complexity retrieval for myGroup[x], or O(n) complexity removal for dropping items...

Alternatively, perhaps this is a job for BTrees. Makes lots of sense because it removes hashtable use from the process, makes searching O(log(n)) and removing O(1).

Edit: Alternatively, maybe myGroup[x] is not necessary, and I say you can get myGroup.first, myGroup.last, or call myGroup.forEach(method). That makes lots of sense...
 

weaaddar

New Member
Reaction score
6
this almost looks like a case to use a dictionary... :p (I've added a forEach I just haven't updated the resource yet). Constant time for all the ops that matter, retrieval, removal, addition.

As I was a big writer of systems like this back in the day.

As for things that really need to be done on the item side is scripting events and giving good hooks back to the user. There should be events on ItemUse, ,Drop, Equip etc.

If you can bother digging it up my DT4a I think was pretty extensive from a scriptability stand point for its time.

I would think its better to think of items to have classifications rather then pocket forcing of types, that way I can say this pocket right hand can use items with class [Heavy weapons], and class [light weapons], and make pocket left hand use items with class [light weapons] and class [shields] or something.
 

Narks

Vastly intelligent whale-like being from the stars
Reaction score
90
ooh, something that would be cool, would be that you can specify an item's weight, so that way people could make a system that the more items you carry the slower you get (no more packrats!)
 

Jesus4Lyf

Good Idea™
Reaction score
397
That will all be easy to accomplish with this system, not within this system. :thup:

ItemTypes are declared in a structy thing, as per here. It will be like:
JASS:
//! runtextmacro ItemType("Sword")
    //! runtextmacro SetItemName("Really Big Sword")
    //! runtextmacro SetItemDescription("No really, this sword is huge.")
    //! runtextmacro SetItemHotkey("X")
    //! runtextmacro SetItemIcon("ReplaceableTextures\\\\CommandButtons\\\\BTNDaggerOfEscape.blp")
//! runtextmacro ItemStruct()
    method onCreate takes nothing returns nothing
    endmethod
    method onUse takes nothing returns nothing
    endmethod
    method onAcquire takes nothing returns nothing
    endmethod
    method onDrop takes nothing returns nothing
    endmethod
//! runtextmacro EndItem()

I was going to add equipping items, but actually that can all be triggered through onUse, and makes more sense to have a system build it on top. Think: [LJASS]implement Weapon[/LJASS].

As for the dictionary suggestion, it is not O(1) for maintaining an infinitely sized array which shifts itself when removing an item from the middle to leave no gaps - nothing is. That's why I think maybe using .last, .first and .forEach(...) makes more sense (the index isn't meaningful). :thup:

Edit: Once again, dictionaries aren't useful here because you can't get all dictionaries an item is a value in, to remove it. :p
 

weaaddar

New Member
Reaction score
6
Well then a Hashset, so that atleast you can ask fast contains (do I have sword of awesome+=3?), and getFirstEntry, (I don't see a need to expose both first and last entry). And you can certainly attach back pointers for the node you are storing, but thats super duper annoying.

And Jesus4lyf making the equipping all handles in onItemUse can be quiet daunting.
 

Jesus4Lyf

Good Idea™
Reaction score
397
And Jesus4lyf making the equipping all handles in onItemUse can be quiet daunting.
That's why I'll release an "equipment types" library shortly after, which will extend that [LJASS]implement Weapon[/LJASS] syntax afterwards (or something like that). The point is it is neither core to this system nor necessary to integrate directly.

Edit: Alright, so far:
JASS:
library MYSYS requires AIDS
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! runtextmacro MYSYS__StartConfig()

//===========================================================================
// CONFIG AREA
//
    
    //===========================================================================
    // System Object Editor IDs.
    //
    
    //! runtextmacro MYSYS__BeginSysIds()
        // Uses:
        //  - 'Ixx&' for item type.
        //  - 'Axx&' for use ability.
        //  - 'Sxx&' for hider spellbook.
        
        //! runtextmacro MYSYS__AllowSysId("0a")
        //! runtextmacro MYSYS__AllowSysId("0b")
        //! runtextmacro MYSYS__AllowSysId("0c")
        //! runtextmacro MYSYS__AllowSysId("0d")
        //! runtextmacro MYSYS__AllowSysId("0e")
        //! runtextmacro MYSYS__AllowSysId("0f")
        //! runtextmacro MYSYS__AllowSysId("0g")
        //! runtextmacro MYSYS__AllowSysId("0h")
        //! runtextmacro MYSYS__AllowSysId("0i")
        //! runtextmacro MYSYS__AllowSysId("0j")
        //! runtextmacro MYSYS__AllowSysId("0k")
        //! runtextmacro MYSYS__AllowSysId("0l")
        //! runtextmacro MYSYS__AllowSysId("0m")
        //! runtextmacro MYSYS__AllowSysId("0n")
        //! runtextmacro MYSYS__AllowSysId("0o")
        //! runtextmacro MYSYS__AllowSysId("0p")
        //! runtextmacro MYSYS__AllowSysId("0q")
        //! runtextmacro MYSYS__AllowSysId("0r")
        //! runtextmacro MYSYS__AllowSysId("0s")
        //! runtextmacro MYSYS__AllowSysId("0t")
        //! runtextmacro MYSYS__AllowSysId("0u")
        //! runtextmacro MYSYS__AllowSysId("0v")
        //! runtextmacro MYSYS__AllowSysId("0w")
        //! runtextmacro MYSYS__AllowSysId("0x")
        //! runtextmacro MYSYS__AllowSysId("0y")
        //! runtextmacro MYSYS__AllowSysId("0z")
        //! runtextmacro MYSYS__AllowSysId("0A")
        //! runtextmacro MYSYS__AllowSysId("0B")
        //! runtextmacro MYSYS__AllowSysId("0C")
        //! runtextmacro MYSYS__AllowSysId("0D")
        //! runtextmacro MYSYS__AllowSysId("0E")
        //! runtextmacro MYSYS__AllowSysId("0F")
        //! runtextmacro MYSYS__AllowSysId("0G")
        //! runtextmacro MYSYS__AllowSysId("0H")
        //! runtextmacro MYSYS__AllowSysId("0I")
        //! runtextmacro MYSYS__AllowSysId("0J")
        //! runtextmacro MYSYS__AllowSysId("0K")
        //! runtextmacro MYSYS__AllowSysId("0L")
        //! runtextmacro MYSYS__AllowSysId("0M")
        //! runtextmacro MYSYS__AllowSysId("0N")
        //! runtextmacro MYSYS__AllowSysId("0O")
        //! runtextmacro MYSYS__AllowSysId("0P")
        //! runtextmacro MYSYS__AllowSysId("0Q")
        //! runtextmacro MYSYS__AllowSysId("0R")
        //! runtextmacro MYSYS__AllowSysId("0S")
        //! runtextmacro MYSYS__AllowSysId("0T")
        //! runtextmacro MYSYS__AllowSysId("0U")
        //! runtextmacro MYSYS__AllowSysId("0V")
        //! runtextmacro MYSYS__AllowSysId("0W")
        //! runtextmacro MYSYS__AllowSysId("0X")
        //! runtextmacro MYSYS__AllowSysId("0Y")
        //! runtextmacro MYSYS__AllowSysId("0Z")
        
    //! runtextmacro MYSYS__EndSysIds()
    
    //===========================================================================
    // System Object Editor Orders.
    //
    
    //! runtextmacro MYSYS__BeginSysOrders()
        
        //! runtextmacro MYSYS__AllowSysOrder("earthquake")
        //! runtextmacro MYSYS__AllowSysOrder("chainlightning")
        //! runtextmacro MYSYS__AllowSysOrder("thunderclap")
        //! runtextmacro MYSYS__AllowSysOrder("stormbolt")
        //! runtextmacro MYSYS__AllowSysOrder("mirrorimage")
        
    //! runtextmacro MYSYS__EndSysOrders()
    
    //===========================================================================
    // Pockets
    //
    
    //! runtextmacro MYSYS__BeginPockets()
        
        // Something special that relates to pockets.
        //! runtextmacro MYSYS__BeginLastOpenedIcon()
            //! runtextmacro MYSYS__SetLastOpenedIconHotkey("Y")
            //! runtextmacro MYSYS__SetLastOpenedIconX("2")
            //! runtextmacro MYSYS__SetLastOpenedIconY("1")
            //! runtextmacro MYSYS__SetLastOpenedIconIcon("ReplaceableTextures\\CommandButtons\\BTNChestOfGold.blp")
            //! runtextmacro MYSYS__SetLastOpenedIconTooltip("Open Inventor|cffffcc00y|r Pocket")
            //! runtextmacro MYSYS__SetLastOpenedIconUbertip("Opens up the last pocket you accessed in your inventory.")
        //! runtextmacro MYSYS__EndLastOpenedIcon()
        
        // Pockets.
        //! runtextmacro MYSYS__Pocket("Pocket1")
            
        //! runtextmacro MYSYS__EndPocket()
        
    //! runtextmacro MYSYS__EndPockets()
    
//===========================================================================
// END CONFIG AREA
//
    //! runtextmacro MYSYS__EndConfig()
    
    
    //===========================================================================
    // SYSTEM AREA (don't touch)
    //
    
    //! textmacro MYSYS__StartConfig
        // For IdBase struct members.
        //private keyword ...
    //! endtextmacro
    //! textmacro MYSYS__EndConfig
    //! endtextmacro
    
    
    //===========================================================================
    // Id Declaration
    //
    
    //! textmacro MYSYS__BeginSysIds
        private module IdBaseInitModule
            private static method onInit takes nothing returns nothing
                //! i sysIds={}
                //! i maxSysIds=0
    //! endtextmacro
    //! textmacro MYSYS__EndSysIds
            endmethod
        endmodule
        //! i sysIdsUsed=0
    //! endtextmacro
    
    //! textmacro MYSYS__AllowSysId takes SYSID
        set thistype.idMax=thistype.idMax+1
        //! i maxSysIds=maxSysIds+1
        
        set thistype(thistype.idMax).ItemStruct__itemType='I$SYSID$&'
        set thistype(thistype.idMax).ItemStruct__spellbookType='S$SYSID$&'
        set thistype(thistype.idMax).ItemStruct__abilityType='A$SYSID$&'
        //! i sysIds[maxSysIds]={itemType="I$SYSID$&", spellbookType="S$SYSID$&", abilityType="A$SYSID$&"}
    //! endtextmacro
    
    
    //===========================================================================
    // Order Declaration
    //
    
    //! textmacro MYSYS__BeginSysOrders
        globals
            private integer array SysOrders
            private integer MaxSysOrders=0
        endglobals
        private module OrdersInitModule
            private static method onInit takes nothing returns nothing
                //! i sysOrders={}
                //! i maxSysOrders=0
    //! endtextmacro
    //! textmacro MYSYS__EndSysOrders
            endmethod
        endmodule
        globals
            private integer SysOrdersUsed=0
        endglobals
        //! i sysOrdersUsed=0
    //! endtextmacro
    
    //! textmacro MYSYS__AllowSysOrder takes SYSORDER
        set MaxSysOrders=MaxSysOrders+1
        set SysOrders[MaxSysOrders]=OrderId("$SYSORDER$")
        //! i maxSysOrders=maxSysOrders+1
        //! i sysOrders[maxSysOrders]="$SYSORDER$"
    //! endtextmacro
    
    
    //===========================================================================
    // Pocket Declaration
    //
    
    //! textmacro MYSYS__BeginPockets
        private function PocketInit takes nothing returns nothing
            local Pocket this
            //! i setobjecttype("abilities")
            // Dummy ability for pockets.
            // Get id from first pocket's ability id (unused).
            //! i dummyItemAbility=sysIds[sysIdsUsed+1].abilityType
            //! i createobject("AItb",dummyItemAbility)
            //! i makechange(current,"acat","")
            //! i makechange(current,"anam","Dummy Item Ability")
            //! i makechange(current,"ansf","(ItemStruct)")
            //! i makechange(current,"Det1",1,0)
            //! i makechange(current,"aare",1,0)
            //! i makechange(current,"abuf",1,"")
            //! i makechange(current,"acdn",1,0)
            //! i makechange(current,"ahdu",1,0)
            //! i makechange(current,"adur",1,0)
            //! i makechange(current,"atar",1,"")
            // Init
            //! i maxPockets=0
    //! endtextmacro
    //! textmacro MYSYS__EndPockets
        endfunction
        //! i setobjecttype("abilities")
        //! i createobject("AInv","AInv")
        //! i if maxPockets>=6 then
            //! i makechange(current,"inv1",1,6)
        //! else
            //! i makechange(current,"inv1",1,maxPockets)
        //! i end
        // Pocket-orders duplication
        //! i pocketOrders={}
        //! i for tempPocketNum=0,maxPockets do
            //! i pocketOrders[tempPocketNum]=sysOrdersUsed
        //! i end
        private module PocketInitModule
            private static method onInit takes nothing returns nothing
                call PocketInit()
            endmethod
        endmodule
    //! endtextmacro
    
    //! textmacro MYSYS__BeginLastOpenedIcon
        //! i setobjecttype("abilities")
        //! i lastOpenedPocketAbility=sysIds[sysIdsUsed+1].spellbookType
        //! i createobject("Aspb",dummyItemAbility)
        //! i makechange(current,"aite",0)
        //! i makechange(current,"anam","Open Inventory Pocket")
        //! i makechange(current,"ansf","(ItemStruct)")
        //! i makechange(current,"spb4",1,11)
        //! i makechange(current,"spb3",1,0)
        //! i makechange(current,"spb2",1,0)
        // Default spell list.
        //! i makechange(current,"spb1",1,"")
        // Order Issues.
        globals
            private integer LAST_OPENED_OID
        endglobals
        set SysOrdersUsed=SysOrdersUsed+1
        set LAST_OPENED_OID=SysOrders[SysOrdersUsed]
        //! i sysOrdersUsed=sysOrdersUsed+1
        //! i LAST_OPENED_ORDER=sysOrders[sysOrdersUsed]
        //! i makechange(current,"aord",LAST_OPENED_ORDER)
        //! i makechange(current,"spb5",1,LAST_OPENED_ORDER)
        // Defaults.
        globals
            private string LAST_OPENED_HOTKEY="Y"
        endglobals
        //! i makechange(current,"ahky","Y")
        //! i makechange(current,"abpx",2)
        //! i makechange(current,"abpy",1)
        //! i makechange(current,"aart","ReplaceableTextures\\CommandButtons\\BTNChestOfGold.blp")
        //! i makechange(current,"atp1",1,"Open Inventor|cffffcc00y|r Pocket")
        //! i makechange(current,"aub1",1,"Opens up the last pocket you accessed in your inventory.")
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconHotkey takes VAL
        set LAST_OPENED_HOTKEY="$VAL$"
        //! i makechange(current,"ahky","$VAL$")
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconX takes VAL
        //! i makechange(current,"abpx",$VAL$)
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconY takes VAL
        //! i makechange(current,"abpy",$VAL$)
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconIcon takes VAL
        //! i makechange(current,"aart","$VAL$")
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconTooltip takes VAL
        //! i makechange(current,"atp1",1,"$VAL$")
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconUbertip takes VAL
        //! i makechange(current,"aub1",1,"$VAL$")
    //! endtextmacro
    //! textmacro MYSYS__EndLastOpenedIcon
    //! endtextmacro
    
    //! textmacro MYSYS__Pocket takes IDENTIFIER
        globals
            Pocket $IDENTIFIER$
        endglobals
        set $IDENTIFIER$=Pocket.create()
        set this=$IDENTIFIER$
        //! i sysIdsUsed=sysIdsUsed+1
        //! i maxPockets=maxPockets+1
        //! i $IDENTIFIER$=maxPockets
        //! i pocketIdentifier="$IDENTIFIER$"
        
        // Defaults.
        //! i pocketName=""
        //! i pocketDescription=""
        //! i pocketIcon=""
    //! endtextmacro
    
    //! textmacro MYSYS__SetPocketName takes NAME
        set this.ItemStruct__name="$NAME$"
        //! i pocketName="$NAME$"
    //! endtextmacro
    //! textmacro MYSYS__SetPocketDescription takes DESCRIPTION
        set this.ItemStruct__description="$DESCRIPTION$"
        //! i pocketDescription="$DESCRIPTION$"
    //! endtextmacro
    //! textmacro MYSYS__SetPocketIcon takes ICON
        //! i pocketIcon="$ICON$"
    //! endtextmacro
    
    //! textmacro MYSYS__EndPocket
        // Make object data.
        //! i setobjecttype("items")
        //! i createobject("ssil",sysIds[sysIdsUsed].itemType)
        //! i makechange(current,"iabi",dummyItemAbility)
        //! i makechange(current,"idro",0)
        //! i makechange(current,"isel",0)
        //! i makechange(current,"icla","Miscellaneous")
        //! i makechange(current,"igol",0)
        //! i makechange(current,"iicd",1)
        //! i makechange(current,"iprn",0)
        //! i makechange(current,"ilev",0)
        //! i makechange(current,"ipri",0)
        //! i makechange(current,"isto",0)
        //! i makechange(current,"istr",0)
        //! i makechange(current,"ides","")
        //! i makechange(current,"uhot","")
        //! i makechange(current,"utip","")
        //! i makechange(current,"iabi",pocketIcon)
        //! i makechange(current,"unam",pocketName)
        //! i makechange(current,"utub",pocketDescription)
    //! endtextmacro
    
    
    //===========================================================================
    // Item Declaration
    //
    
    //! textmacro ItemType takes IDENTIFIER
        globals
            ItemType $IDENTIFIER$=0
        endglobals
        struct ItemStruct__$IDENTIFIER$ extends Item
            private static ItemType itemType=0
            //! i itemIdentifier="$IDENTIFIER$"
            private static method ItemStruct__init takes nothing returns nothing
                local integer i=bj_MAX_PLAYERS
                set thistype.itemType=ItemType.create(thistype.ItemStruct__create)
                //! i sysIdsUsed=sysIdsUsed+1
                set $IDENTIFIER$=thistype.itemType
                // Hide spellbook
                loop
                    set i=i-1
                    call SetPlayerAbilityAvailable(Player(i),thistype.itemType.ItemStruct__spellbookType,false)
                    exitwhen i==0
                endloop
                // Attach ItemType to item rawcode.
                call ItemStruct__RegisterItemType(thistype.itemType.ItemStruct__itemType,thistype.itemType)
                // Defaults.
                set thistype.itemType.ItemStruct__name="$IDENTIFIER$"
                //! i itemName="$IDENTIFIER$"
                set thistype.itemType.ItemStruct__model="Objects\\InventoryItems\\TreasureChest\\treasurechest.mdl"
                //! i itemModel="Objects\\InventoryItems\\TreasureChest\\treasurechest.mdl"
                set thistype.itemType.ItemStruct__redTint=255
                set thistype.itemType.ItemStruct__greenTint=255
                set thistype.itemType.ItemStruct__blueTint=255
                //! i itemTint={red=255,green=255,blue=255}
                set thistype.itemType.ItemStruct__scale=1.0
                //! i itemScale=1.0
                set thistype.itemType.ItemStruct__goldCost=0
                set thistype.itemType.ItemStruct__lumberCost=0
                //! i itemCost={gold=0,lumber=0}
                set thistype.itemType.ItemStruct__stockMax=0
                //! i itemStockMax=0
                set thistype.itemType.ItemStruct__stockReplenishInterval=0
                //! i itemStockReplenishInterval=0
                set thistype.itemType.ItemStruct__stockStartDelay=0
                //! i itemStockStartDelay=0
                //! i itemPocket=0
                //! i itemIcon=""
                //! i itemHotkey=""
                //! i itemDescription=""
                
                //! i itemBaseAbility="ANcl"
                //! i itemAbilityData={}
                //! i itemAbilityLevelData={}
    //! endtextmacro
    //! textmacro ItemStruct
            endmethod
            implement ItemStruct
    //! endtextmacro
    //! textmacro EndItem
            private static method ItemStruct__create takes nothing returns thistype
                local thistype this=thistype.create()
                // means the ItemType, not item rawcode, in this case.
                set this.ItemStruct__itemType=thistype.itemType
                call this.onCreate()
                return this
            endmethod
        endstruct
        // Make object data.
        // Dummy item.
        //! i setobjecttype("items")
        //! i createobject("rspd",sysIds[sysIdsUsed].itemType)
        //! i makechange(current,"iabi",dummyItemAbility)
        //! i makechange(current,"iico",itemIcon)
        //! i makechange(current,"ifil",itemModel)
        //! i makechange(current,"iclr",itemTint.red)
        //! i makechange(current,"iclg",itemTint.green)
        //! i makechange(current,"iclb",itemTint.blue)
        //! i makechange(current,"isel",1)
        //! i makechange(current,"igol",itemCost.gold)
        //! i makechange(current,"ilum",itemCost.lumber)
        //! i makechange(current,"iicd",1)
        //! i makechange(current,"isto",itemStockMax)
        //! i makechange(current,"istr",itemStockReplenishInterval)
        //! i makechange(current,"isst",itemStockStartDelay)
        //! i makechange(current,"ides",itemDescription)
        //! i makechange(current,"uhot",itemHotkey)
        //! i makechange(current,"utip","[|cffffcc00"..itemHotkey.."|r] Purchase "..itemName)
        //! i makechange(current,"utub",itemDescription)
        // Use ability.
        //! i setobjecttype("abilities")
        //! i createobject(itemBaseAbility,sysIds[sysIdsUsed].abilityType)
        //! i makechange(current,"aart",itemIcon)
        //! i makechange(current,"aher",0)
        //! i makechange(current,"aite",0)
        //! i makechange(current,"alev",1)
        //! i makechange(current,"ahky",itemHotkey)
        //! i makechange(current,"anam",itemName)
        //! i if itemBaseAbility=="ANcl" then
            //! i pocketOrders[itemPocket]=pocketOrders[itemPocket]+1
            //! i makechange(current,"aord",sysOrders[pocketOrders[itemPocket]])
            //! i makechange(current,"Ncl6",1,sysOrders[pocketOrders[itemPocket]])
            //! i makechange(current,"Ncl5",1,0)
            //! i makechange(current,"Ncl1",1,0)
            //! i makechange(current,"Ncl3",1,1)
        //! i end
        //! i makechange(current,"atp1",1,"[|cffffcc00"..itemHotkey.."|r] "..itemName)
        //! i makechange(current,"aub1",1,itemDescription)
        /*
        // TODO: Broken.
        //! for key,value in pairs(itemAbilityData) do
            //! i makechange(current,key,value)
        //! end
        //! for key,value in pairs(itemAbilityLevelData) do
            //! i makechange(current,key,1,value)
        //! end
        */
        // Spellbook
        //! i setobjecttype("abilities")
        //! i createobject("Aspb",sysIds[sysIdsUsed].spellbookType)
        //! i makechange(current,"aart","")
        //! i makechange(current,"aite",0)
        //! i makechange(current,"anam",itemName)
        //! i makechange(current,"ansf","(ItemStruct Spellbook)")
        //! i makechange(current,"aord",LAST_OPENED_ORDER)
        //! i makechange(current,"spb5",1,LAST_OPENED_ORDER)
        //! i makechange(current,"spb4",1,11)
        //! i makechange(current,"spb3",1,0)
        //! i makechange(current,"spb2",1,0)
        //! i makechange(current,"spb1",1,sysIds[sysIdsUsed].abilityType)
    //! endtextmacro
    
    //! textmacro SetItemName takes VAL
        set thistype.itemType.ItemStruct__name="$VAL$"
        //! i itemName="$VAL$"
    //! endtextmacro
    //! textmacro SetItemPocket takes POCKET
        set thistype.itemType.ItemStruct__pocket=$POCKET$
        //! i itemPocket=$POCKET$
    //! endtextmacro
    //! textmacro SetItemIcon takes VAL
        set thistype.itemType.ItemStruct__icon="$VAL$"
        //! i itemIcon="$VAL$"
    //! endtextmacro
    //! textmacro SetItemHotkey takes VAL
        set thistype.itemType.ItemStruct__hotkey="$VAL$"
        //! i itemHotkey="$VAL$"
    //! endtextmacro
    //! textmacro SetItemDescription takes VAL
        set thistype.itemType.ItemStruct__description="$VAL$"
        //! i itemDescription="$VAL$"
    //! endtextmacro
    //! textmacro SetItemModel takes VAL
        set thistype.itemType.ItemStruct__model="$VAL$"
        //! i itemModel="$VAL$"
    //! endtextmacro
    //! textmacro SetItemTint takes RED, GREEN, BLUE
        set thistype.itemType.ItemStruct__redTint=$RED$
        set thistype.itemType.ItemStruct__greenTint=$GREEN$
        set thistype.itemType.ItemStruct__blueTint=$BLUE$
        //! i itemTint={red=$RED$,green=$GREEN$,blue=$BLUE$}
    //! endtextmacro
    //! textmacro SetItemScale takes VAL
        set thistype.itemType.ItemStruct__scale=$VAL$
        //! i itemScale="$VAL$"
    //! endtextmacro
    //! textmacro SetItemCost takes GOLD, LUMBER
        set thistype.itemType.ItemStruct__goldCost=$GOLD$
        set thistype.itemType.ItemStruct__lumberCost=$LUMBER$
        //! i itemCost={gold=$GOLD$,lumber=$LUMBER$}
    //! endtextmacro
    //! textmacro SetItemStockMax takes VAL
        set thistype.itemType.ItemStruct__stockMax=$VAL$
        //! i itemStockMax=$VAL$
    //! endtextmacro
    //! textmacro SetItemStockReplenishInterval takes VAL
        set thistype.itemType.ItemStruct__stockReplenishInterval=$VAL$
        //! i itemStockReplenishInterval=$VAL$
    //! endtextmacro
    //! textmacro SetItemStockStartDelay takes VAL
        set thistype.itemType.ItemStruct__stockStartDelay=$VAL$
        //! i itemStockStartDelay=$VAL$
    //! endtextmacro
    //! textmacro SetItemBaseAbility takes VAL
        //! i itemBaseAbility="$VAL$"
    //! endtextmacro
    //! textmacro SetItemAbilityData takes ATTRIBUTE, VALUE
        //! i itemAbilityData["$ATTRIBUTE$"]="$VALUE$"
    //! endtextmacro
    //! textmacro SetItemAbilityLevelData takes ATTRIBUTE, VALUE
        //! i itemAbilityData["$ATTRIBUTE$"]="$VALUE$"
    //! endtextmacro
    
    //===========================================================================
    // JASS System
    //
    
    globals
        private hashtable Store=InitHashtable() // stores:
        // item rawcode, 0 --> ItemType
    endglobals
    function ItemStruct__RegisterItemType takes integer rawCode, ItemType itemType returns nothing
        call SaveInteger(Store,rawCode,0,itemType)
    endfunction
    //Exposed:
    function GetItemItemType takes item i returns ItemType
        return ItemType(GetItemUserData(i))
    endfunction
    
    //===========================================================================
    // Pockets and ItemTypes
    //
    
    //private function interface CreateItemTypeXY takes real x, real y returns integer
    //private function interface CreateItemUnit takes unit u
    
    private struct IdBase
        static integer idMax=0
        implement IdBaseInitModule
        implement OrdersInitModule
        
        // Autofilled.
        integer ItemStruct__itemType
        integer ItemStruct__spellbookType
        integer ItemStruct__abilityType
        
        // Filled on init.
        string ItemStruct__name
        string ItemStruct__description
        string ItemStruct__icon
        string ItemStruct__model
    endstruct
    
    //! textmacro MYSYS__Expose takes TYPE, MEMBER
        method operator $MEMBER$ takes nothing returns $TYPE$
            return this.ItemStruct__$MEMBER$
        endmethod
    //! endtextmacro
    
    struct Pocket extends IdBase
        //! runtextmacro MYSYS__Expose("string","name")
        //! runtextmacro MYSYS__Expose("string","description")
        
        readonly thistype nextPocket=0
        readonly static integer maxPockets=0
        private static thistype lastPocket=0
        static method create takes nothing returns thistype
            set thistype.maxPockets=thistype.maxPockets+1
            set thistype.lastPocket.nextPocket=thistype.allocate()
            set thistype.lastPocket=thistype.lastPocket.nextPocket
            return thistype.lastPocket
        endmethod
        implement PocketInitModule
    endstruct
    
    
    private function interface Method takes integer this returns nothing
    private function interface ItemAllocator takes nothing returns Item
    private keyword allocator
    private keyword generateInstance
    
    struct ItemType extends IdBase
        /*libprivate*/ ItemAllocator allocator
        
        /*libprivate*/ static method create takes ItemAllocator allocator returns thistype
            local thistype this=thistype.allocate()
            set this.allocator=allocator
            return this
        endmethod
        
        /*libprivate*/ method generateInstance takes nothing returns Item
            return this.allocator.evaluate()
        endmethod
        
        //! runtextmacro MYSYS__Expose("string","name")
        //! runtextmacro MYSYS__Expose("string","description")
        //! runtextmacro MYSYS__Expose("integer","itemType")
        //! runtextmacro MYSYS__Expose("integer","abilityType")
        
        string ItemStruct__hotkey
        //! runtextmacro MYSYS__Expose("string","hotkey")
        Pocket ItemStruct__pocket
        //! runtextmacro MYSYS__Expose("Pocket","pocket")
        integer ItemStruct__redTint=255
        //! runtextmacro MYSYS__Expose("integer","redTint")
        integer ItemStruct__greenTint=255
        //! runtextmacro MYSYS__Expose("integer","greenTint")
        integer ItemStruct__blueTint=255
        //! runtextmacro MYSYS__Expose("integer","blueTint")
        real ItemStruct__scale=1.0
        //! runtextmacro MYSYS__Expose("real","scale")
        integer ItemStruct__goldCost=0
        //! runtextmacro MYSYS__Expose("integer","goldCost")
        integer ItemStruct__lumberCost=0
        //! runtextmacro MYSYS__Expose("integer","lumberCost")
        integer ItemStruct__stockMax=0
        //! runtextmacro MYSYS__Expose("integer","stockMax")
        integer ItemStruct__stockReplenishInterval=0
        //! runtextmacro MYSYS__Expose("integer","stockReplenishInterval")
        integer ItemStruct__stockStartDelay=0
        //! runtextmacro MYSYS__Expose("integer","stockStartDelay")
    endstruct
    
    /*libprivate*/ module ItemStruct // implemented in all items.
        private static method onInit takes nothing returns nothing
            call thistype.ItemStruct__init() // default values and stuff
        endmethod
    endmodule
    
    //===========================================================================
    // ItemStruct
    //
    
    private keyword itemListNext
    private keyword itemListPrev
    
    private interface DEFAULTS
        method onCreate takes nothing returns nothing defaults nothing // always on x/y.
        method onAcquire takes nothing returns nothing defaults nothing
        method onUse takes nothing returns nothing defaults nothing
        method onDrop takes nothing returns nothing defaults nothing
        
        /*libprivate*/ DEFAULTS itemListNext // thistype does not compile.
        /*libprivate*/ DEFAULTS itemListPrev // thistype does not compile.
    endinterface
    
    struct Item extends DEFAULTS
        static method operator [] takes item i returns thistype
            return thistype(GetItemUserData(i))
        endmethod
        
        Inventory holder=Inventory(0)
        delegate ItemType ItemStruct__itemType
        //! runtextmacro MYSYS__Expose("ItemType","itemType")
    endstruct
    
    
    private function interface ItemFunction takes Item i returns nothing
    
    struct ItemList extends DEFAULTS // will always exist for each pocket for each unit.
        /*libprivate*/ readonly ItemType itemType
        readonly integer count
        //DEFAULTS itemListNext // thistype does not compile.
        //DEFAULTS itemListPrev // thistype does not compile.
        
        // links together ItemInstanceLists, items bunched by ItemTypes,
        // forming a PocketList, the ItemTypes that are in a Pocket for a unit.
        /*libprivate*/ readonly thistype next
        /*libprivate*/ readonly thistype prev
        /*libprivate*/ static method createPocketList takes nothing returns thistype
            local thistype this=thistype.allocate()
            set this.next=this
            set this.prev=this
            return this
        endmethod
        /*libprivate*/ method createItemInstanceList takes Item firstNode returns thistype
            local thistype new=thistype.allocate()
            set new.itemType=firstNode.itemType
            set new.count=1
            
            // attach to PocketList this.
            set this.prev.next=new
            set new.prev=this.prev
            set this.prev=new
            set new.next=this
            
            // circularly link with item.
            set new.itemListNext=firstNode
            set new.itemListPrev=firstNode
            set firstNode.itemListNext=new
            set firstNode.itemListPrev=new
            
            return new
        endmethod
        
        method forEach takes ItemFunction func returns nothing
            local Item curr=Item(this.itemListNext)
            loop
                exitwhen curr==this
                call func.evaluate(curr)
                set curr=Item(curr.itemListNext)
            endloop
        endmethod
        method operator first takes nothing returns Item
            // empty should never exist
            return Item(this.itemListNext)
        endmethod
        method operator last takes nothing returns Item
            // empty should never exist
            return Item(this.itemListPrev)
        endmethod
        /*libprivate*/ method operator append= takes Item whichItem returns nothing
            set this.itemListPrev.itemListNext=whichItem
            set whichItem.itemListPrev=this.itemListPrev
            set this.itemListPrev=whichItem
            set whichItem.itemListNext=this
            set this.count=this.count+1
        endmethod
        /*libprivate*/ method operator remove= takes Item whichItem returns nothing
            set whichItem.itemListPrev.itemListNext=whichItem.itemListNext
            set whichItem.itemListNext.itemListPrev=whichItem.itemListPrev
            set this.count=this.count-1
        endmethod
        /*libprivate*/ method destroyItemInstanceList takes nothing returns nothing
            // assumes the list is empty.
            set this.next.prev=this.prev
            set this.prev.next=this.next
            call this.deallocate()
        endmethod
    endstruct
    
    struct Inventory extends array
        private static hashtable itemListHash=InitHashtable()
        //Exposed:
        method getItemList takes ItemType itemType returns ItemList
            return ItemList(LoadInteger(thistype.itemListHash,this,itemType))
        endmethod
        private method setItemList takes ItemType itemType, ItemList itemInstanceList returns nothing
            call SaveInteger(thistype.itemListHash,this,itemType,itemInstanceList)
        endmethod
        private method removeItemList takes ItemType itemType returns nothing
            call RemoveSavedInteger(thistype.itemListHash,this,itemType)
        endmethod
        
        private static ItemList array pocketListArray // look at my leet hashtable.
        private method getPocketList takes Pocket pocket returns ItemList
            return pocketListArray[this*Pocket.maxPockets+pocket]
        endmethod
        private method setPocketList takes Pocket pocket, ItemList pocketList returns nothing
            set pocketListArray[this*Pocket.maxPockets+pocket]=pocketList
        endmethod
        
        private static method AIDS_filter takes unit u returns boolean
            return GetUnitAbilityLevel(u,'inv1')>0
        endmethod
        private method AIDS_onCreate takes nothing returns nothing
            local Pocket pocket=Pocket(0)
            loop
                set pocket=pocket.nextPocket
                exitwhen pocket==0
                call this.setPocketList(pocket,ItemList.createPocketList())
                call UnitAddItemById(this.unit,pocket.ItemStruct__itemType)
            endloop
        endmethod
        private method AIDS_onDestroy takes nothing returns nothing
            
        endmethod
        //! runtextmacro AIDS()
        
        /*libprivate*/ method addItem takes Item whichItem returns nothing
            // does not affect the Item's existance, just attaches.
            // assumes the item is in no inventory.
            local ItemList itemInstanceList=this.getItemList(whichItem.itemType)
            
            if itemInstanceList==0 then
                set itemInstanceList=this.getPocketList(whichItem.itemType.pocket).createItemInstanceList(whichItem)
                call this.setItemList(whichItem.itemType,itemInstanceList)
            else
                set itemInstanceList.append=whichItem
            endif
            
            //other:
            set whichItem.holder=this
        endmethod
        
        /*libprivate*/ method removeItem takes Item whichItem returns nothing
            // does not affect the Item's existance, just detaches.
            // assumes the item is in this inventory.
            local ItemList itemInstanceList=this.getItemList(whichItem.itemType)
            set itemInstanceList.remove=whichItem
            if itemInstanceList.count==0 then
                call this.removeItemList(whichItem.itemType)
                call itemInstanceList.destroyItemInstanceList()
            endif
            
            //other:
            set whichItem.holder=Inventory(0)
        endmethod
    endstruct
    
    //===========================================================================
    // Event Responses
    //
    
    globals//locals
        private item TriggeringItem
    endglobals
    private function OnAcquire takes nothing returns boolean
        set TriggeringItem=GetManipulatedItem()
        call Inventory[GetManipulatingUnit()].addItem(Item[TriggeringItem])
        call SetWidgetLife(TriggeringItem,0) // safety
        call RemoveItem(TriggeringItem)
        return false
    endfunction
    private function OnSell takes nothing returns boolean
        set TriggeringItem=GetManipulatedItem()
        call SetItemUserData(TriggeringItem,GetItemItemType(TriggeringItem).generateInstance())
        return false
    endfunction
    
    //===========================================================================
    // Init
    //
    
    private module InitModule
        private static method onInit takes nothing returns nothing
            local trigger t
            //! textmacro MYSYS__InitTrigger takes EVENT, FUNCTION
                set t=CreateTrigger()
                call TriggerAddCondition(t,Filter(function $FUNCTION$))
                call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_$EVENT$)
            //! endtextmacro
            //! runtextmacro MYSYS__InitTrigger("PICKUP_ITEM","OnAcquire")
            //! runtextmacro MYSYS__InitTrigger("SELL_ITEM","OnSell")
        endmethod
    endmodule
    struct InitModuleStruct extends array
        implement InitModule
    endstruct
endlibrary

I've used dynamically sized array of circularly linked lists of circularly linked lists of Items. The circularly linked lists of Items are hash-attached to (Inventory, ItemType) as well. The lists of them are to display what's in a pocket. Looks like I'm over the hill. :thup:
 

Jesus4Lyf

Good Idea™
Reaction score
397
Ok. New issue. People are obviously going to want to write item systems, things like weapons and armor and stuff like that. That means using the onUse, onCreate, onAcquire and onDrop methods. Which means you could only implement one such system... :nuts:

So I came up with this idea:
JASS:
struct MyItemData extends array
    implement ItemData
    private method onUse takes nothing returns boolean
        call this.item.destroy()
        return false // unusable item, will disappear instead of running the item's onUse method.
    endmethod
    private method onCreate takes nothing returns nothing // should this run before or after the item's onCreate? Theoretically, before, I think.
    endmethod // maybe have preCreate postCreate instead?
    //etc..
endstruct

The only thing is making items extend an interface. As in, calling a method which is different for each item - can't be done easily. But that should be solvable with a module that stores the method in the struct implementing ItemData. I'll think about it. :thup:

Edit: This whole thing's starting to work: (mostly here for safekeeping, backing it up :p)
JASS:
library MYSYS requires AIDS
//! externalblock extension=lua ObjectMerger $FILENAME$
    //! runtextmacro MYSYS__StartConfig()

//===========================================================================
// CONFIG AREA
//
    
    //===========================================================================
    // System Object Editor IDs.
    //
    
    //! runtextmacro MYSYS__BeginSysIds()
        // Uses:
        //  - 'Ixx&' for item type.
        //  - 'Axx&' for use ability.
        //  - 'Sxx&' for hider spellbook.
        
        //! runtextmacro MYSYS__AllowSysId("0a")
        //! runtextmacro MYSYS__AllowSysId("0b")
        //! runtextmacro MYSYS__AllowSysId("0c")
        //! runtextmacro MYSYS__AllowSysId("0d")
        //! runtextmacro MYSYS__AllowSysId("0e")
        //! runtextmacro MYSYS__AllowSysId("0f")
        //! runtextmacro MYSYS__AllowSysId("0g")
        //! runtextmacro MYSYS__AllowSysId("0h")
        //! runtextmacro MYSYS__AllowSysId("0i")
        //! runtextmacro MYSYS__AllowSysId("0j")
        //! runtextmacro MYSYS__AllowSysId("0k")
        //! runtextmacro MYSYS__AllowSysId("0l")
        //! runtextmacro MYSYS__AllowSysId("0m")
        //! runtextmacro MYSYS__AllowSysId("0n")
        //! runtextmacro MYSYS__AllowSysId("0o")
        //! runtextmacro MYSYS__AllowSysId("0p")
        //! runtextmacro MYSYS__AllowSysId("0q")
        //! runtextmacro MYSYS__AllowSysId("0r")
        //! runtextmacro MYSYS__AllowSysId("0s")
        //! runtextmacro MYSYS__AllowSysId("0t")
        //! runtextmacro MYSYS__AllowSysId("0u")
        //! runtextmacro MYSYS__AllowSysId("0v")
        //! runtextmacro MYSYS__AllowSysId("0w")
        //! runtextmacro MYSYS__AllowSysId("0x")
        //! runtextmacro MYSYS__AllowSysId("0y")
        //! runtextmacro MYSYS__AllowSysId("0z")
        //! runtextmacro MYSYS__AllowSysId("0A")
        //! runtextmacro MYSYS__AllowSysId("0B")
        //! runtextmacro MYSYS__AllowSysId("0C")
        //! runtextmacro MYSYS__AllowSysId("0D")
        //! runtextmacro MYSYS__AllowSysId("0E")
        //! runtextmacro MYSYS__AllowSysId("0F")
        //! runtextmacro MYSYS__AllowSysId("0G")
        //! runtextmacro MYSYS__AllowSysId("0H")
        //! runtextmacro MYSYS__AllowSysId("0I")
        //! runtextmacro MYSYS__AllowSysId("0J")
        //! runtextmacro MYSYS__AllowSysId("0K")
        //! runtextmacro MYSYS__AllowSysId("0L")
        //! runtextmacro MYSYS__AllowSysId("0M")
        //! runtextmacro MYSYS__AllowSysId("0N")
        //! runtextmacro MYSYS__AllowSysId("0O")
        //! runtextmacro MYSYS__AllowSysId("0P")
        //! runtextmacro MYSYS__AllowSysId("0Q")
        //! runtextmacro MYSYS__AllowSysId("0R")
        //! runtextmacro MYSYS__AllowSysId("0S")
        //! runtextmacro MYSYS__AllowSysId("0T")
        //! runtextmacro MYSYS__AllowSysId("0U")
        //! runtextmacro MYSYS__AllowSysId("0V")
        //! runtextmacro MYSYS__AllowSysId("0W")
        //! runtextmacro MYSYS__AllowSysId("0X")
        //! runtextmacro MYSYS__AllowSysId("0Y")
        //! runtextmacro MYSYS__AllowSysId("0Z")
        
    //! runtextmacro MYSYS__EndSysIds()
    
    //===========================================================================
    // System Object Editor Orders.
    //
    
    //! runtextmacro MYSYS__BeginSysOrders()
        
        //! runtextmacro MYSYS__AllowSysOrder("earthquake")
        //! runtextmacro MYSYS__AllowSysOrder("chainlightning")
        //! runtextmacro MYSYS__AllowSysOrder("thunderclap")
        //! runtextmacro MYSYS__AllowSysOrder("stormbolt")
        //! runtextmacro MYSYS__AllowSysOrder("mirrorimage")
        
    //! runtextmacro MYSYS__EndSysOrders()
    
    //===========================================================================
    // Pockets
    //
    
    //! runtextmacro MYSYS__BeginPockets()
        
        // Something special that relates to pockets.
        //! runtextmacro MYSYS__BeginLastOpenedIcon()
            //! runtextmacro MYSYS__SetLastOpenedIconHotkey("Y")
            //! runtextmacro MYSYS__SetLastOpenedIconX("2")
            //! runtextmacro MYSYS__SetLastOpenedIconY("1")
            //! runtextmacro MYSYS__SetLastOpenedIconIcon("ReplaceableTextures\\CommandButtons\\BTNChestOfGold.blp")
            //! runtextmacro MYSYS__SetLastOpenedIconTooltip("Open Inventor|cffffcc00y|r Pocket")
            //! runtextmacro MYSYS__SetLastOpenedIconUbertip("Opens up the last pocket you accessed in your inventory.")
        //! runtextmacro MYSYS__EndLastOpenedIcon()
        
        // Pockets.
        //! runtextmacro MYSYS__Pocket("Pocket1")
            //! runtextmacro MYSYS__SetPocketName("MyFirstPocket")
            //! runtextmacro MYSYS__SetPocketDescription("It's a REAL pocket.")
            //! runtextmacro MYSYS__SetPocketIcon("ReplaceableTextures\\CommandButtons\\BTNControlMagic.blp")
        //! runtextmacro MYSYS__EndPocket()
        
    //! runtextmacro MYSYS__EndPockets()
    
//===========================================================================
// END CONFIG AREA
//
    //! runtextmacro MYSYS__EndConfig()
    
    
    //===========================================================================
    // SYSTEM AREA (don't touch)
    //
    
    //! textmacro MYSYS__StartConfig
        // For IdBase struct members.
        //private keyword ...
    //! endtextmacro
    //! textmacro MYSYS__EndConfig
    //! endtextmacro
    
    
    //===========================================================================
    // Id Declaration
    //
    
    //! textmacro MYSYS__BeginSysIds
        private module IdBaseInitModule
            private static method onInit takes nothing returns nothing
                //! i sysIds={}
                //! i maxSysIds=0
    //! endtextmacro
    //! textmacro MYSYS__EndSysIds
            endmethod
        endmodule
        //! i sysIdsUsed=0
    //! endtextmacro
    
    //! textmacro MYSYS__AllowSysId takes SYSID
        set thistype.idMax=thistype.idMax+1
        //! i maxSysIds=maxSysIds+1
        
        set thistype(thistype.idMax).ItemStruct__itemType='I$SYSID$&'
        set thistype(thistype.idMax).ItemStruct__spellbookType='S$SYSID$&'
        set thistype(thistype.idMax).ItemStruct__abilityType='A$SYSID$&'
        //! i sysIds[maxSysIds]={itemType="I$SYSID$&", spellbookType="S$SYSID$&", abilityType="A$SYSID$&"}
    //! endtextmacro
    
    
    //===========================================================================
    // Order Declaration
    //
    
    //! textmacro MYSYS__BeginSysOrders
        globals
            private integer array SysOrders
            private integer MaxSysOrders=0
        endglobals
        private module OrdersInitModule
            private static method onInit takes nothing returns nothing
                //! i sysOrders={}
                //! i maxSysOrders=0
    //! endtextmacro
    //! textmacro MYSYS__EndSysOrders
            endmethod
        endmodule
        globals
            private integer SysOrdersUsed=0
        endglobals
        //! i sysOrdersUsed=0
    //! endtextmacro
    
    //! textmacro MYSYS__AllowSysOrder takes SYSORDER
        set MaxSysOrders=MaxSysOrders+1
        set SysOrders[MaxSysOrders]=OrderId("$SYSORDER$")
        //! i maxSysOrders=maxSysOrders+1
        //! i sysOrders[maxSysOrders]="$SYSORDER$"
    //! endtextmacro
    
    
    //===========================================================================
    // Pocket Declaration
    //
    
    //! textmacro MYSYS__BeginPockets
        // Moved here for accessibility.
        private keyword Store
        private function RegisterPocketType takes integer rawCode, Pocket pocket returns nothing
            call SaveInteger(Store,rawCode,0,pocket)
        endfunction
        private function GetItemPocketType takes integer rawCode returns Pocket
            return Pocket(LoadInteger(Store,rawCode,0))
        endfunction
        
        private function PocketInit takes nothing returns nothing
            local Pocket this
            //! i setobjecttype("abilities")
            // Dummy ability for pockets.
            // Get id from first pocket's ability id (unused).
            //! i dummyItemAbility=sysIds[sysIdsUsed+1].abilityType
            //! i createobject("AItb",dummyItemAbility)
            //! i makechange(current,"acat","")
            //! i makechange(current,"anam","Dummy Item Ability")
            //! i makechange(current,"ansf","(ItemStruct)")
            //! i makechange(current,"Det1",1,0)
            //! i makechange(current,"aare",1,0)
            //! i makechange(current,"abuf",1,"")
            //! i makechange(current,"acdn",1,0)
            //! i makechange(current,"ahdu",1,0)
            //! i makechange(current,"adur",1,0)
            //! i makechange(current,"atar",1,"")
            // Init
            //! i maxPockets=0
    //! endtextmacro
    //! textmacro MYSYS__EndPockets
        endfunction
        //! i setobjecttype("abilities")
        ////! i createobject("AInv","AInv")
        //! i if maxPockets>=6 then
            //! i makechange("AInv","inv1",1,6)
        //! else
            //TODO: Make this actually work. maxPockets
            //! i makechange("AInv","inv1",1,2)
        //! i end
        // Pocket-orders duplication
        //! i pocketOrders={}
        //! i for tempPocketNum=0,maxPockets do
            //! i pocketOrders[tempPocketNum]=sysOrdersUsed
        //! i end
        private module PocketInitModule
            private static method onInit takes nothing returns nothing
                call PocketInit()
            endmethod
        endmodule
    //! endtextmacro
    
    //! textmacro MYSYS__BeginLastOpenedIcon
        globals
            private integer LAST_OPENED_ABIL=0
        endglobals
        set LAST_OPENED_ABIL=Pocket(1).ItemStruct__spellbookType
        //! i setobjecttype("abilities")
        //! i lastOpenedPocketAbility=sysIds[sysIdsUsed+1].spellbookType
        //! i createobject("Aspb",lastOpenedPocketAbility)
        //! i makechange(current,"aite",0)
        //! i makechange(current,"anam","Open Inventory Pocket")
        //! i makechange(current,"ansf","(ItemStruct)")
        //! i makechange(current,"spb4",1,11)
        //! i makechange(current,"spb3",1,0)
        //! i makechange(current,"spb2",1,0)
        // Default spell list.
        //! i makechange(current,"spb1",1,"")
        // Order Issues.
        globals
            private integer LAST_OPENED_OID
        endglobals
        set SysOrdersUsed=SysOrdersUsed+1
        set LAST_OPENED_OID=SysOrders[SysOrdersUsed]
        //! i sysOrdersUsed=sysOrdersUsed+1
        //! i LAST_OPENED_ORDER=sysOrders[sysOrdersUsed]
        //! i makechange(current,"aord",LAST_OPENED_ORDER)
        //! i makechange(current,"spb5",1,LAST_OPENED_ORDER)
        // Defaults.
        globals
            private string LAST_OPENED_HOTKEY="Y"
        endglobals
        //! i makechange(current,"ahky","Y")
        //! i makechange(current,"abpx",2)
        //! i makechange(current,"abpy",1)
        //! i makechange(current,"aart","ReplaceableTextures\\CommandButtons\\BTNChestOfGold.blp")
        //! i makechange(current,"atp1",1,"Open Inventor|cffffcc00y|r Pocket")
        //! i makechange(current,"aub1",1,"Opens up the last pocket you accessed in your inventory.")
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconHotkey takes VAL
        set LAST_OPENED_HOTKEY="$VAL$"
        //! i makechange(current,"ahky","$VAL$")
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconX takes VAL
        //! i makechange(current,"abpx",$VAL$)
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconY takes VAL
        //! i makechange(current,"abpy",$VAL$)
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconIcon takes VAL
        //! i makechange(current,"aart","$VAL$")
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconTooltip takes VAL
        //! i makechange(current,"atp1",1,"$VAL$")
    //! endtextmacro
    //! textmacro MYSYS__SetLastOpenedIconUbertip takes VAL
        //! i makechange(current,"aub1",1,"$VAL$")
    //! endtextmacro
    //! textmacro MYSYS__EndLastOpenedIcon
    //! endtextmacro
    
    //! textmacro MYSYS__Pocket takes IDENTIFIER
        globals
            Pocket $IDENTIFIER$
        endglobals
        set $IDENTIFIER$=Pocket.create()
        set this=$IDENTIFIER$
        call RegisterPocketType(this.ItemStruct__itemType,this)
        //! i sysIdsUsed=sysIdsUsed+1
        //! i maxPockets=maxPockets+1
        //! i $IDENTIFIER$=maxPockets
        //! i pocketIdentifier="$IDENTIFIER$"
        
        // Defaults.
        //! i pocketName=""
        //! i pocketDescription=""
        //! i pocketIcon=""
    //! endtextmacro
    
    //! textmacro MYSYS__SetPocketName takes NAME
        set this.ItemStruct__name="$NAME$"
        //! i pocketName="$NAME$"
    //! endtextmacro
    //! textmacro MYSYS__SetPocketDescription takes DESCRIPTION
        set this.ItemStruct__description="$DESCRIPTION$"
        //! i pocketDescription="$DESCRIPTION$"
    //! endtextmacro
    //! textmacro MYSYS__SetPocketIcon takes ICON
        //! i pocketIcon="$ICON$"
    //! endtextmacro
    
    //! textmacro MYSYS__EndPocket
        // Make object data.
        //! i setobjecttype("items")
        //! i createobject("ssil",sysIds[sysIdsUsed].itemType)
        //! i makechange(current,"iabi",dummyItemAbility)
        //! i makechange(current,"idro",0)
        //! i makechange(current,"isel",0)
        //! i makechange(current,"icla","Miscellaneous")
        //! i makechange(current,"igol",0)
        //! i makechange(current,"iicd",1)
        //! i makechange(current,"iprn",0)
        //! i makechange(current,"ilev",0)
        //! i makechange(current,"ipri",0)
        //! i makechange(current,"isto",0)
        //! i makechange(current,"istr",0)
        //! i makechange(current,"ides","")
        //! i makechange(current,"uhot","")
        //! i makechange(current,"utip","")
        //! i makechange(current,"iico",pocketIcon)
        //! i makechange(current,"unam",pocketName)
        //! i makechange(current,"utub",pocketDescription)
    //! endtextmacro
    
    
    //===========================================================================
    // Item Declaration
    //
    
    //! textmacro ItemType takes IDENTIFIER
        globals
            ItemType $IDENTIFIER$=0
        endglobals
        struct ItemStruct__$IDENTIFIER$ extends Item
            private static ItemType itemType=0
            //! i itemIdentifier="$IDENTIFIER$"
            private static method ItemStruct__init takes nothing returns nothing
                local integer i=bj_MAX_PLAYERS
                set thistype.itemType=ItemType.create(thistype.ItemStruct__create)
                //! i sysIdsUsed=sysIdsUsed+1
                set $IDENTIFIER$=thistype.itemType
                // Hide spellbook
                loop
                    set i=i-1
                    call SetPlayerAbilityAvailable(Player(i),thistype.itemType.ItemStruct__spellbookType,false)
                    exitwhen i==0
                endloop
                // Attach ItemType to item rawcode.
                call ItemStruct__RegisterItemType(thistype.itemType.ItemStruct__itemType,thistype.itemType)
                // Attach ItemType to item ability.
                call ItemStruct__RegisterItemType(thistype.itemType.ItemStruct__abilityType,thistype.itemType)
                // Defaults.
                set thistype.itemType.ItemStruct__name="$IDENTIFIER$"
                //! i itemName="$IDENTIFIER$"
                set thistype.itemType.ItemStruct__model="Objects\\InventoryItems\\TreasureChest\\treasurechest.mdl"
                //! i itemModel="Objects\\InventoryItems\\TreasureChest\\treasurechest.mdl"
                set thistype.itemType.ItemStruct__redTint=255
                set thistype.itemType.ItemStruct__greenTint=255
                set thistype.itemType.ItemStruct__blueTint=255
                //! i itemTint={red=255,green=255,blue=255}
                set thistype.itemType.ItemStruct__scale=1.0
                //! i itemScale=1.0
                set thistype.itemType.ItemStruct__goldCost=0
                set thistype.itemType.ItemStruct__lumberCost=0
                //! i itemCost={gold=0,lumber=0}
                set thistype.itemType.ItemStruct__stockMax=0
                //! i itemStockMax=0
                set thistype.itemType.ItemStruct__stockReplenishInterval=0
                //! i itemStockReplenishInterval=0
                set thistype.itemType.ItemStruct__stockStartDelay=0
                //! i itemStockStartDelay=0
                //! i itemPocket=0
                //! i itemIcon=""
                //! i itemHotkey=""
                //! i itemDescription=""
                
                //! i itemBaseAbility="ANcl"
                //! i itemAbilityData={}
                //! i itemAbilityLevelData={}
    //! endtextmacro
    //! textmacro ItemStruct
            endmethod
            implement ItemStruct
    //! endtextmacro
    //! textmacro EndItem
            private static method ItemStruct__create takes item i returns thistype
                local thistype this=thistype.create()
                set this.item=i
                call SetItemUserData(i,this)
                // means the ItemType, not item rawcode, in this case.
                set this.ItemStruct__itemType=thistype.itemType
                call this.onCreate()
                return this
            endmethod
        endstruct
        // Make object data.
        // Dummy item.
        /*
        //! i setobjecttype("items")
        //! i createobject("rspd",sysIds[sysIdsUsed].itemType)
        //! i makechange(current,"iabi",dummyItemAbility)
        //! i makechange(current,"iico",itemIcon)
        //! i makechange(current,"ifil",itemModel)
        //! i makechange(current,"isca",itemScale)
        //! i makechange(current,"iclr",itemTint.red)
        //! i makechange(current,"iclg",itemTint.green)
        //! i makechange(current,"iclb",itemTint.blue)
        //! i makechange(current,"icid","AIav")
        //! i makechange(current,"igol",itemCost.gold)
        //! i makechange(current,"ilum",itemCost.lumber)
        //! i makechange(current,"iicd",1)
        //! i makechange(current,"iuse",1)
        //! i makechange(current,"isto",itemStockMax)
        //! i makechange(current,"istr",itemStockReplenishInterval)
        //! i makechange(current,"isst",itemStockStartDelay)
        //! i makechange(current,"ipow",1)
        //! i makechange(current,"ides",itemDescription)
        //! i makechange(current,"uhot",itemHotkey)
        //! i makechange(current,"inam",itemName)
        //! i makechange(current,"utip","[|cffffcc00"..itemHotkey.."|r] Purchase "..itemName)
        //! i makechange(current,"utub",itemDescription)
        */
        //! i setobjecttype("items")
        //! i createobject("dust",sysIds[sysIdsUsed].itemType)
        //! i makechange(current,"iabi",dummyItemAbility)
        //! i makechange(current,"ubpx",0)
        //! i makechange(current,"iico",itemIcon)
        //! i makechange(current,"ifil",itemModel)
        //! i makechange(current,"iclr",itemTint.red)
        //! i makechange(current,"iclg",itemTint.green)
        //! i makechange(current,"iclb",itemTint.blue)
        //! i makechange(current,"isel",1)
        //! i makechange(current,"igol",itemCost.gold)
        //! i makechange(current,"ilum",itemCost.lumber)
        //! i makechange(current,"iicd",1)
        //! i makechange(current,"isto",itemStockMax)
        //! i makechange(current,"istr",itemStockReplenishInterval)
        //! i makechange(current,"isst",itemStockStartDelay)
        //! i makechange(current,"ides",itemDescription)
        //! i makechange(current,"uhot",itemHotkey)
        //! i makechange(current,"utip","[|cffffcc00"..itemHotkey.."|r] Purchase "..itemName)
        //! i makechange(current,"utub",itemDescription)
        // Use ability.
        //! i setobjecttype("abilities")
        //! i createobject(itemBaseAbility,sysIds[sysIdsUsed].abilityType)
        //! i makechange(current,"aart",itemIcon)
        //! i makechange(current,"aher",0)
        //! i makechange(current,"aite",0)
        //! i makechange(current,"alev",1)
        //! i makechange(current,"ahky",itemHotkey)
        //! i makechange(current,"anam",itemName)
        //! i if itemBaseAbility=="ANcl" then
            //! i pocketOrders[itemPocket]=pocketOrders[itemPocket]+1
            //! i makechange(current,"aord",sysOrders[pocketOrders[itemPocket]])
            //! i makechange(current,"Ncl6",1,sysOrders[pocketOrders[itemPocket]])
            //! i makechange(current,"Ncl5",1,0)
            //! i makechange(current,"Ncl1",1,0)
            //! i makechange(current,"Ncl3",1,1)
        //! i end
        //! i makechange(current,"atp1",1,"[|cffffcc00"..itemHotkey.."|r] "..itemName)
        //! i makechange(current,"aub1",1,itemDescription)
        /*
        // TODO: Broken.
        //! for key,value in pairs(itemAbilityData) do
            //! i makechange(current,key,value)
        //! end
        //! for key,value in pairs(itemAbilityLevelData) do
            //! i makechange(current,key,1,value)
        //! end
        */
        // Spellbook
        //! i setobjecttype("abilities")
        //! i createobject("Aspb",sysIds[sysIdsUsed].spellbookType)
        //! i makechange(current,"aart","")
        //! i makechange(current,"aite",0)
        //! i makechange(current,"anam",itemName)
        //! i makechange(current,"ansf","(ItemStruct Spellbook)")
        //! i makechange(current,"aord",LAST_OPENED_ORDER)
        //! i makechange(current,"spb5",1,LAST_OPENED_ORDER)
        //! i makechange(current,"spb4",1,11)
        //! i makechange(current,"spb3",1,0)
        //! i makechange(current,"spb2",1,0)
        //! i makechange(current,"spb1",1,sysIds[sysIdsUsed].abilityType)
    //! endtextmacro
    
    //! textmacro SetItemName takes VAL
        set thistype.itemType.ItemStruct__name="$VAL$"
        //! i itemName="$VAL$"
    //! endtextmacro
    //! textmacro SetItemPocket takes POCKET
        set thistype.itemType.ItemStruct__pocket=$POCKET$
        //! i itemPocket=$POCKET$
    //! endtextmacro
    //! textmacro SetItemIcon takes VAL
        set thistype.itemType.ItemStruct__icon="$VAL$"
        //! i itemIcon="$VAL$"
    //! endtextmacro
    //! textmacro SetItemHotkey takes VAL
        set thistype.itemType.ItemStruct__hotkey="$VAL$"
        //! i itemHotkey="$VAL$"
    //! endtextmacro
    //! textmacro SetItemDescription takes VAL
        set thistype.itemType.ItemStruct__description="$VAL$"
        //! i itemDescription="$VAL$"
    //! endtextmacro
    //! textmacro SetItemModel takes VAL
        set thistype.itemType.ItemStruct__model="$VAL$"
        //! i itemModel="$VAL$"
    //! endtextmacro
    //! textmacro SetItemTint takes RED, GREEN, BLUE
        set thistype.itemType.ItemStruct__redTint=$RED$
        set thistype.itemType.ItemStruct__greenTint=$GREEN$
        set thistype.itemType.ItemStruct__blueTint=$BLUE$
        //! i itemTint={red=$RED$,green=$GREEN$,blue=$BLUE$}
    //! endtextmacro
    //! textmacro SetItemScale takes VAL
        set thistype.itemType.ItemStruct__scale=$VAL$
        //! i itemScale="$VAL$"
    //! endtextmacro
    //! textmacro SetItemCost takes GOLD, LUMBER
        set thistype.itemType.ItemStruct__goldCost=$GOLD$
        set thistype.itemType.ItemStruct__lumberCost=$LUMBER$
        //! i itemCost={gold=$GOLD$,lumber=$LUMBER$}
    //! endtextmacro
    //! textmacro SetItemStockMax takes VAL
        set thistype.itemType.ItemStruct__stockMax=$VAL$
        //! i itemStockMax=$VAL$
    //! endtextmacro
    //! textmacro SetItemStockReplenishInterval takes VAL
        set thistype.itemType.ItemStruct__stockReplenishInterval=$VAL$
        //! i itemStockReplenishInterval=$VAL$
    //! endtextmacro
    //! textmacro SetItemStockStartDelay takes VAL
        set thistype.itemType.ItemStruct__stockStartDelay=$VAL$
        //! i itemStockStartDelay=$VAL$
    //! endtextmacro
    //! textmacro SetItemBaseAbility takes VAL
        //! i itemBaseAbility="$VAL$"
    //! endtextmacro
    //! textmacro SetItemAbilityData takes ATTRIBUTE, VALUE
        //! i itemAbilityData["$ATTRIBUTE$"]="$VALUE$"
    //! endtextmacro
    //! textmacro SetItemAbilityLevelData takes ATTRIBUTE, VALUE
        //! i itemAbilityData["$ATTRIBUTE$"]="$VALUE$"
    //! endtextmacro
    
    //===========================================================================
    // JASS System
    //
    
    globals
        private hashtable Store=InitHashtable() // stores:
        // item rawcode, 0 --> ItemType
        // item rawcode, 0 --> Pocket
    endglobals
    function ItemStruct__RegisterItemType takes integer rawCode, ItemType itemType returns nothing
        call SaveInteger(Store,rawCode,0,itemType)
    endfunction
    private function GetItemItemType takes integer rawCode returns ItemType
        return ItemType(LoadInteger(Store,rawCode,0))
    endfunction
    // pocket funcs declared above.
    
    //===========================================================================
    // Pockets and ItemTypes
    //
    
    //private function interface CreateItemTypeXY takes real x, real y returns integer
    //private function interface CreateItemUnit takes unit u
    
    private struct IdBase
        static integer idMax=0
        implement IdBaseInitModule
        implement OrdersInitModule
        
        // Autofilled.
        integer ItemStruct__itemType
        integer ItemStruct__spellbookType
        integer ItemStruct__abilityType
        
        // Filled on init.
        string ItemStruct__name
        string ItemStruct__description
        string ItemStruct__icon
        string ItemStruct__model
    endstruct
    
    //! textmacro MYSYS__Expose takes TYPE, MEMBER
        method operator $MEMBER$ takes nothing returns $TYPE$
            return this.ItemStruct__$MEMBER$
        endmethod
    //! endtextmacro
    
    struct Pocket extends IdBase
        //! runtextmacro MYSYS__Expose("string","name")
        //! runtextmacro MYSYS__Expose("string","description")
        
        private static hashtable hash
        
        readonly thistype nextPocket=0
        readonly static integer maxPockets=0
        private static thistype lastPocket=0
        static method create takes nothing returns thistype
            // increment maxPockets.
            set thistype.maxPockets=thistype.maxPockets+1
            // maintain pocket linked list.
            set thistype.lastPocket.nextPocket=thistype.allocate()
            set thistype.lastPocket=thistype.lastPocket.nextPocket
            // hash attach pocket to itemtype.
            return thistype.lastPocket
        endmethod
        implement PocketInitModule
    endstruct
    
    
    private function interface Method takes integer this returns nothing
    private function interface ItemAllocator takes item i returns Item
    private keyword allocator
    private keyword generateInstance
    
    struct ItemType extends IdBase
        /*libprivate*/ ItemAllocator allocator
        
        /*libprivate*/ static method create takes ItemAllocator allocator returns thistype
            local thistype this=thistype.allocate()
            set this.allocator=allocator
            return this
        endmethod
        
        /*libprivate*/ method generateInstance takes item i returns Item
            return this.allocator.evaluate(i)
        endmethod
        
        //! runtextmacro MYSYS__Expose("string","name")
        //! runtextmacro MYSYS__Expose("string","description")
        //! runtextmacro MYSYS__Expose("integer","itemType")
        //! runtextmacro MYSYS__Expose("integer","abilityType")
        
        string ItemStruct__hotkey
        //! runtextmacro MYSYS__Expose("string","hotkey")
        Pocket ItemStruct__pocket
        //! runtextmacro MYSYS__Expose("Pocket","pocket")
        integer ItemStruct__redTint=255
        //! runtextmacro MYSYS__Expose("integer","redTint")
        integer ItemStruct__greenTint=255
        //! runtextmacro MYSYS__Expose("integer","greenTint")
        integer ItemStruct__blueTint=255
        //! runtextmacro MYSYS__Expose("integer","blueTint")
        real ItemStruct__scale=1.0
        //! runtextmacro MYSYS__Expose("real","scale")
        integer ItemStruct__goldCost=0
        //! runtextmacro MYSYS__Expose("integer","goldCost")
        integer ItemStruct__lumberCost=0
        //! runtextmacro MYSYS__Expose("integer","lumberCost")
        integer ItemStruct__stockMax=0
        //! runtextmacro MYSYS__Expose("integer","stockMax")
        integer ItemStruct__stockReplenishInterval=0
        //! runtextmacro MYSYS__Expose("integer","stockReplenishInterval")
        integer ItemStruct__stockStartDelay=0
        //! runtextmacro MYSYS__Expose("integer","stockStartDelay")
    endstruct
    
    /*libprivate*/ module ItemStruct // implemented in all items.
        private static method onInit takes nothing returns nothing
            call thistype.ItemStruct__init() // default values and stuff
        endmethod
    endmodule
    
    //===========================================================================
    // ItemStruct
    //
    
    private keyword itemListNext
    private keyword itemListPrev
    
    private interface DEFAULTS
        method onCreate takes nothing returns nothing defaults nothing // always on x/y.
        method onAcquire takes nothing returns nothing defaults nothing
        method onUse takes nothing returns nothing defaults nothing
        method onDrop takes nothing returns nothing defaults nothing
        
        /*libprivate*/ DEFAULTS itemListNext // thistype does not compile.
        /*libprivate*/ DEFAULTS itemListPrev // thistype does not compile.
    endinterface
    
    struct Item extends DEFAULTS
        static method operator [] takes item i returns thistype
            return thistype(GetItemUserData(i))
        endmethod
        
        Inventory holder=Inventory(0) // updated by Inventory only.
        delegate ItemType ItemStruct__itemType
        //! runtextmacro MYSYS__Expose("ItemType","itemType")
        
        /*libprivate*/ item item
        
        method setPosition takes real x, real y returns nothing
            if this.holder==0 then
                call SetItemPosition(this.item,x,y)
            else
                call holder.removeItem(this)
                set this.item=CreateItem(this.itemType.ItemStruct__itemType,x,y)
                call SetItemUserData(this.item,this)
            endif
        endmethod
        method giveToUnit takes unit whichUnit returns nothing
            if this.holder==0 then
                call RemoveItem(this.item)
                set this.item=null
            else
                call holder.removeItem(this)
            endif
            call Inventory[whichUnit].addItem(this)
        endmethod
    endstruct
    function CreateItemXY takes ItemType itemType, real x, real y returns Item
        return itemType.generateInstance(CreateItem(itemType.ItemStruct__itemType,x,y))
    endfunction
    function CreateItemUnit takes ItemType itemType, unit whichUnit returns Item
        local Item i=itemType.generateInstance(CreateItem(itemType.ItemStruct__itemType,GetUnitX(whichUnit),GetUnitY(whichUnit)))
        call UnitAddItem(whichUnit,i.item)
        return i
    endfunction
    
    
    private function interface ItemFunction takes Item i returns nothing
    
    struct ItemList extends DEFAULTS // will always exist for each pocket for each unit.
        /*libprivate*/ readonly ItemType itemType
        readonly integer count
        //DEFAULTS itemListNext // thistype does not compile.
        //DEFAULTS itemListPrev // thistype does not compile.
        
        // links together ItemInstanceLists, items bunched by ItemTypes,
        // forming a PocketList, the ItemTypes that are in a Pocket for a unit.
        private thistype next
        private thistype prev
        /*libprivate*/ method loadPocketList takes unit u returns nothing
            local thistype curr=this.next
            loop
                exitwhen curr==this
                call UnitAddAbility(u,curr.itemType.ItemStruct__spellbookType)
                call UnitMakeAbilityPermanent(u,true,curr.itemType.ItemStruct__spellbookType)
                set curr=curr.next
            endloop
        endmethod
        /*libprivate*/ method unloadPocketList takes unit u returns nothing
            local thistype curr=this.next
            loop
                exitwhen curr==this
                call UnitMakeAbilityPermanent(u,false,curr.itemType.ItemStruct__spellbookType)
                call UnitRemoveAbility(u,curr.itemType.ItemStruct__spellbookType)
                set curr=curr.next
            endloop
        endmethod
        /*libprivate*/ static method createPocketList takes nothing returns thistype
            local thistype this=thistype.allocate()
            set this.next=this
            set this.prev=this
            return this
        endmethod
        /*libprivate*/ method createItemInstanceList takes Item firstNode returns thistype
            local thistype new=thistype.allocate()
            set new.itemType=firstNode.itemType
            set new.count=1
            
            // attach to PocketList this.
            set this.prev.next=new
            set new.prev=this.prev
            set this.prev=new
            set new.next=this
            
            // circularly link with item.
            set new.itemListNext=firstNode
            set new.itemListPrev=firstNode
            set firstNode.itemListNext=new
            set firstNode.itemListPrev=new
            
            return new
        endmethod
        
        method forEach takes ItemFunction func returns nothing
            local Item curr=Item(this.itemListNext)
            loop
                exitwhen curr==this
                call func.evaluate(curr)
                set curr=Item(curr.itemListNext)
            endloop
        endmethod
        method operator first takes nothing returns Item
            // empty should never exist
            return Item(this.itemListNext)
        endmethod
        method operator last takes nothing returns Item
            // empty should never exist
            return Item(this.itemListPrev)
        endmethod
        /*libprivate*/ method operator append= takes Item whichItem returns nothing
            set this.itemListPrev.itemListNext=whichItem
            set whichItem.itemListPrev=this.itemListPrev
            set this.itemListPrev=whichItem
            set whichItem.itemListNext=this
            set this.count=this.count+1
        endmethod
        /*libprivate*/ method operator remove= takes Item whichItem returns nothing
            set whichItem.itemListPrev.itemListNext=whichItem.itemListNext
            set whichItem.itemListNext.itemListPrev=whichItem.itemListPrev
            set this.count=this.count-1
        endmethod
        /*libprivate*/ method destroyItemInstanceList takes nothing returns nothing
            // assumes the list is empty.
            set this.next.prev=this.prev
            set this.prev.next=this.next
            call this.deallocate()
        endmethod
    endstruct
    
    struct Inventory extends array
        private static hashtable itemListHash=InitHashtable()
        //Exposed:
        method getItemList takes ItemType itemType returns ItemList
            return ItemList(LoadInteger(thistype.itemListHash,this,itemType))
        endmethod
        private method setItemList takes ItemType itemType, ItemList itemInstanceList returns nothing
            call SaveInteger(thistype.itemListHash,this,itemType,itemInstanceList)
        endmethod
        private method removeItemList takes ItemType itemType returns nothing
            call RemoveSavedInteger(thistype.itemListHash,this,itemType)
        endmethod
        
        private static ItemList array pocketListArray // look at my leet hashtable.
        private method getPocketList takes Pocket pocket returns ItemList
            return pocketListArray[this*Pocket.maxPockets+pocket]
        endmethod
        private method setPocketList takes Pocket pocket, ItemList pocketList returns nothing
            set pocketListArray[this*Pocket.maxPockets+pocket]=pocketList
        endmethod
        
        private static method AIDS_filter takes unit u returns boolean
            return GetUnitAbilityLevel(u,'AInv')>0
        endmethod
        private method AIDS_onCreate takes nothing returns nothing
            local Pocket pocket=Pocket(0).nextPocket
            // load first pocket as default.
            set this.currentPocket=pocket // assumes unit has no items, does not update list.
            // add dummy items and create PocketLists.
            loop
                exitwhen pocket==0
                call UnitAddItemById(this.unit,pocket.ItemStruct__itemType)
                call this.setPocketList(pocket,ItemList.createPocketList())
                set pocket=pocket.nextPocket
            endloop
            // add last opened pocket ability.
            call UnitAddAbility(this.unit,LAST_OPENED_ABIL)
            call UnitMakeAbilityPermanent(this.unit,true,LAST_OPENED_ABIL)
        endmethod
        private method AIDS_onDestroy takes nothing returns nothing
            //TODO
        endmethod
        //! runtextmacro AIDS()
        
        private Pocket currentPocket
        /*libprivate*/ method setCurrentPocket takes Pocket pocket returns nothing
            call this.getPocketList(this.currentPocket).unloadPocketList(this.unit)
            set this.currentPocket=pocket
            call this.getPocketList(pocket).loadPocketList(this.unit)
        endmethod
        
        /*libprivate*/ method addItem takes Item whichItem returns nothing
            // does not affect the Item's existance, just attaches.
            // assumes the item is in no inventory.
            local ItemType itemType=whichItem.itemType
            local ItemList itemInstanceList=this.getItemList(itemType)
            
            if itemInstanceList==0 then
                set itemInstanceList=this.getPocketList(itemType.pocket).createItemInstanceList(whichItem)
                call this.setItemList(itemType,itemInstanceList)
                // If the instance list is created for the current pocket, update display list...
                if itemType.pocket==this.currentPocket then
                    call UnitAddAbility(this.unit,itemType.ItemStruct__spellbookType)
                    call UnitMakeAbilityPermanent(this.unit,true,itemType.ItemStruct__spellbookType)
                endif
            else
                set itemInstanceList.append=whichItem
            endif
            
            //other:
            set whichItem.holder=this
        endmethod
        
        /*libprivate*/ method removeItem takes Item whichItem returns nothing
            // does not affect the Item's existance, just detaches.
            // assumes the item is in this inventory.
            local ItemType itemType=whichItem.itemType
            local ItemList itemInstanceList=this.getItemList(whichItem.itemType)
            set itemInstanceList.remove=whichItem
            if itemInstanceList.count==0 then
                // If the instance list is destroyed for the current pocket, update display list...
                if itemType.pocket==this.currentPocket then
                    call UnitMakeAbilityPermanent(this.unit,false,itemType.ItemStruct__spellbookType)
                    call UnitRemoveAbility(this.unit,itemType.ItemStruct__spellbookType)
                endif
                call this.removeItemList(whichItem.itemType)
                call itemInstanceList.destroyItemInstanceList()
            endif
            
            //other:
            set whichItem.holder=Inventory(0)
        endmethod
    endstruct
    
    //===========================================================================
    // Event Responses
    //
    
    globals//locals
        private item TriggeringItem
        private Item TriggeringItemItem
        private Pocket TriggeringPocket
        private ItemType TriggeringItemType
    endglobals
    private function OnAcquire takes nothing returns boolean
        set TriggeringItem=GetManipulatedItem()
        set TriggeringItemItem=Item[TriggeringItem]
        if TriggeringItemItem!=0 then
            call Inventory[GetManipulatingUnit()].addItem(TriggeringItemItem)
            set TriggeringItemItem.item=null
            call TriggeringItemItem.onAcquire()
            call SetWidgetLife(TriggeringItem,0) // safety
            call RemoveItem(TriggeringItem)
        endif
        return false
    endfunction
    private function OnSell takes nothing returns boolean
        set TriggeringItem=GetSoldItem()
        // will set to 0 for invalid items.
        call GetItemItemType(GetItemTypeId(TriggeringItem)).generateInstance(TriggeringItem)
        return false
    endfunction
    private function OnUseItem takes nothing returns boolean
        set TriggeringPocket=GetItemPocketType(GetItemTypeId(GetManipulatedItem()))
        if TriggeringPocket!=0 then
            call Inventory[GetManipulatingUnit()].setCurrentPocket(TriggeringPocket)
        endif
        return false
    endfunction
    private function OnSpellEffect takes nothing returns boolean
        set TriggeringItemType=GetItemItemType(GetSpellAbilityId())
        if TriggeringItemType!=0 then
            call Inventory[GetTriggerUnit()].getItemList(TriggeringItemType).first.onUse()
        endif
        return false
    endfunction
    
    //===========================================================================
    // Init
    //
    
    private module InitModule
        private static method onInit takes nothing returns nothing
            local trigger t
            //! textmacro MYSYS__InitTrigger takes EVENT, FUNCTION
                set t=CreateTrigger()
                call TriggerAddCondition(t,Filter(function $FUNCTION$))
                call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_$EVENT$)
            //! endtextmacro
            //! runtextmacro MYSYS__InitTrigger("PICKUP_ITEM","OnAcquire")
            //! runtextmacro MYSYS__InitTrigger("SELL_ITEM","OnSell")
            //! runtextmacro MYSYS__InitTrigger("SPELL_EFFECT","OnSpellEffect")
            //! runtextmacro MYSYS__InitTrigger("USE_ITEM","OnUseItem")
        endmethod
    endmodule
    struct InitModuleStruct extends array
        implement InitModule
    endstruct
endlibrary
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +1
  • The Helper The Helper:
    The recipe today is Sloppy Joe Casserole - one of my faves LOL https://www.thehelper.net/threads/sloppy-joe-casserole-with-manwich.193585/
  • The Helper The Helper:
    Decided to put up a healthier type recipe to mix it up - Honey Garlic Shrimp Stir-Fry https://www.thehelper.net/threads/recipe-honey-garlic-shrimp-stir-fry.193595/
  • The Helper The Helper:
    Here is another comfort food favorite - Million Dollar Casserole - https://www.thehelper.net/threads/recipe-million-dollar-casserole.193614/

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top