Item Stacking

Tyrulan

Ultra Cool Member
Reaction score
37
I read a few of the resources and tutorials and eventually came up with this:

JASS:

method CollectResource takes integer itemId returns item        
            local item    anItem = CreateItem(itemId, 0, 0)
            local integer index            
            local item    indexItem
            local boolean hasItem = false

            set index = 0
            loop
                set indexItem = UnitItemInSlot(.Caster, index)
                if (indexItem != null) and (GetItemTypeId(indexItem) == itemId) then
                    set hasItem = true
                endif
                set index = index + 1
                exitwhen index >= bj_MAX_INVENTORY or hasItem
            endloop                  
                        
            if (hasItem) then
                call SetItemCharges(indexItem, GetItemCharges(indexItem) + 1)
            else                     
                call UnitAddItem(.Caster, anItem)                        
            endif
            return anItem
        endmethod


The problem with this is that it only merges items as they are created via gathering abilities. In order to merge a manipulated item being picked up do I need to create an array of items that are mergeable? And if so, how would I set the maximum number of stacks?

I've hummed and hawwed about this and have a few ideas but I'd like to see what is out there first.
 

Tyrulan

Ultra Cool Member
Reaction score
37
Bump:

This is my progress thus far.

JASS:

library MergeItems initializer onInit

    function MergeItem takes nothing returns nothing
        local item    anItem           = GetManipulatedItem()
        local item    indexItem        = null
        local unit    aUnit            = GetTriggerUnit()
        local integer itemId           = GetItemTypeId(anItem)
        local integer index            = 0        
        local integer isMergeableIndex = 0
        local boolean itemIsMergeable  = false        
        local boolean hasItem          = false
        
        call BJDebugMsg("Merging...")
        
        loop
            if (MergeableItems[isMergeableIndex] == itemId) then
                set itemIsMergeable = true
            endif
            exitwhen itemIsMergeable or index >= NUMBER_OF_MERGEABLE_ITEMS
            set isMergeableIndex = isMergeableIndex + 1
        endloop
        
        if (itemIsMergeable) then    
            call BJDebugMsg("Item is Mergeable...")
            loop
                set indexItem = UnitItemInSlot(aUnit, index)
                if (indexItem != null) and (GetItemTypeId(indexItem) == itemId) then
                    set hasItem = true
                endif
                set index = index + 1
                exitwhen index >= bj_MAX_INVENTORY or hasItem
            endloop                  
                            
            //If the unit does not have the item already, allow them to receive it normally.            
            if (hasItem) then
                call BJDebugMsg("Unit has Item...")
                if (GetItemCharges(indexItem) == MaximumStacks[isMergeableIndex]) then
                    //Do Nothing
                else
                    call SetItemCharges(indexItem, GetItemCharges(indexItem) + GetItemCharges(anItem))
                endif
            else
                //Do Nothing
            endif
        endif
    endfunction

    //===========================================================================
    function onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_PICKUP_ITEM)
        call TriggerAddAction(t, function MergeItem )
    endfunction
endlibrary



As it is, I'm having problems with this because the item is already added to a units' inventory as well as adding a charge to a previously held item. Can anyone suggest a solution to this?
 

SanKakU

Member
Reaction score
21
wow, i have no idea what you were trying to do.
what's the difference between what you're trying to do and what i did?
this is the thread i made about stacking items, which also links to another thread about stacking items, haha.
fun stuff.
http://www.thehelper.net/forums/showthread.php?t=148590

"The problem with this is that it only merges items as they are
created via gathering abilities. " hmm...you mean like acolyte gold mine and peon harvest and goblin shredder and ghoul lumber and wisp lumbr and gold abilities and all that? i don't understand at all...

"how would I set the maximum number of stacks?"
is that all you're up to? why don't you mention it sooner?

ok, i updated my snippet with some textmacros that should properly limit the charges. i got one for the regular charges, and one for the ammo charges. i guess i'll test it tonight. i'd feel silly if my snippet had something that didn't function properly in it.
 

Tyrulan

Ultra Cool Member
Reaction score
37
Hmmm.. I think I figured out what my problem was. I wanted an am going to avoid using many, many methods to do this.

EDIT: Nevermind still stuck. I'm going to need to think about this. At this point I've got some circular referencing and dependency issues.

EDIT2: I looked at your system a while back but it didn't help me much. I'll take another look when I get some time now that I understand the concepts behind item stacking a little better. Kingking's system seems to be very complete, and I'd like to look into that as well.
 

SanKakU

Member
Reaction score
21
actually, you know what? on second thought, that won't do the trick i think...because what i implemented doesn't account for refunding items when you try to go over the limit...i'll have to think about what to do about that...

as far as i know kinking's system only accomplishes stacking charged items manually. it's a simple matter to automatically stack those charged items which his system enhanced which you can manually stack, which is what i did. the thing that impressed me about his system is that you can't for example without it stack any charged item above count 1. it's just impossible. using my textmacro you need to still create lots of objects, but you get automatic stacking, which is good for the player.

you can check out his test map as it does use some crazy weird system that might be useful for you...i'd look at that except i don't understand it one bit. heh.
 

Tyrulan

Ultra Cool Member
Reaction score
37
JASS:


    function MergeItem takes nothing returns nothing
        local item    anItem           = GetManipulatedItem()
        local item    indexItem        = null
        local unit    aUnit            = GetTriggerUnit()
        local integer itemId           = GetItemTypeId(anItem)
        local integer index            = 0        
        local integer isMergeableIndex = 0
        local boolean itemIsMergeable  = false        
        local boolean hasItem          = false
                                
        loop
            if (MergeableItems[isMergeableIndex] == itemId) then
                set itemIsMergeable = true
            endif
            exitwhen itemIsMergeable or index >= NUMBER_OF_MERGEABLE_ITEMS
            set isMergeableIndex = isMergeableIndex + 1
        endloop
        
        if (itemIsMergeable) then                
            loop
                set indexItem = UnitItemInSlot(aUnit, index)
                if (GetItemTypeId(indexItem) == itemId and UnitItemInSlot(aUnit, index) != anItem) then
                    if (GetItemCharges(indexItem) == MaximumStacks[isMergeableIndex]) then 
                        //Pretend the unit does not have to the item, and move on to                         
                        //finding a stack with room.
                    else
                        set hasItem = true
                    endif
                    
                endif
                set index = index + 1
                exitwhen index >= bj_MAX_INVENTORY or hasItem
            endloop                  
                            
            //If the unit does not have the item already, allow them to receive it normally.            
            if (hasItem) then                
                if (GetItemCharges(indexItem) == MaximumStacks[isMergeableIndex]) then
                    //Do Nothing
                else 
                    //If the unit is picking up a stack which is exceeds the capacity of stacks,
                    //merge them and create and full stack + a smaller one.
                    if (GetItemCharges(indexItem) + GetItemCharges(anItem) > MaximumStacks[isMergeableIndex]) then
                        call SetItemCharges(anItem, GetItemCharges(indexItem) + GetItemCharges(anItem) - MaximumStacks[isMergeableIndex])
                        call SetItemCharges(indexItem, MaximumStacks[isMergeableIndex])
                    else
                        call SetItemCharges(indexItem, GetItemCharges(indexItem) + GetItemCharges(anItem))
                        call RemoveItem(anItem)
                    endif
                endif
                                
            else
                //Do Nothing
            endif
        endif
    endfunction




Hurrah! Solved! :) Suggestions, comments anyone?
 

retupmoc258

New Member
Reaction score
1
It looks pretty good. I am not a JASS expert, but I can't see any flaws. The only thing I'm curious about is your variable "MergeableItems" I am guessing that is a global declared and set elsewhere?
 

SanKakU

Member
Reaction score
21
why don't you post a demo map? you can use perhaps kingkingyyk3's demo map or mine for a base.

your code is sortof confusing...first you had a method...now you have a function...

i guess you only posted part of your code so that's why i don't get it. well, anyway...i plan to try adding limits to charges in my next version of my demo map. i just released it today, so you should check it out.

and btw...your indents are ENOURMOUS.

edit: ok, so i decided to put your code in my editor and take away the indents...whoa!

JASS:
local itemanItem   = GetManipulatedItem()
local itemindexItem= null
local unitaUnit= GetTriggerUnit()

what's all that from? how're we supposed to know without references?
edit: lol...nevermind...you indented to line up variable names, that's dirty code.
wow...it's been a while since i've seen a function this big...why aren't you posting the whole scope or library that it's in, anyway?
 

Tyrulan

Ultra Cool Member
Reaction score
37
JASS:

library MergeableItems initializer onInit

    globals

        integer array MergeableItems
        integer array MaximumStacks
        constant integer NUMBER_OF_MERGEABLE_ITEMS = 2
    
    endglobals    
    

    
    private function onInit takes nothing returns nothing
        set MergeableItems[0] = 'I000' //Burrow Fish
        set MaximumStacks [0] = 5
        set MergeableItems[1] = 'I001' //Cat Fish
        set MaximumStacks [1] = 5
    endfunction 

endlibrary


This trigger contains all items that are meant to be mergeable.

JASS:

library MergeItems initializer onInit

    function MergeItem takes nothing returns nothing
        local item    anItem           = GetManipulatedItem()
        local item    indexItem        = null
        local unit    aUnit            = GetTriggerUnit()
        local integer itemId           = GetItemTypeId(anItem)
        local integer index            = 0        
        local integer isMergeableIndex = 0
        local boolean itemIsMergeable  = false        
        local boolean hasItem          = false
                                
        loop
            if (MergeableItems[isMergeableIndex] == itemId) then
                set itemIsMergeable = true
            endif
            exitwhen itemIsMergeable or index >= NUMBER_OF_MERGEABLE_ITEMS
            set isMergeableIndex = isMergeableIndex + 1
        endloop
        
        if (itemIsMergeable) then                
            loop
                set indexItem = UnitItemInSlot(aUnit, index)
                if (GetItemTypeId(indexItem) == itemId and UnitItemInSlot(aUnit, index) != anItem) then
                    if (GetItemCharges(indexItem) == MaximumStacks[isMergeableIndex]) then 
                        //Pretend the unit does not have the item, and move on to                         
                        //finding a stack with room.
                    else
                        set hasItem = true
                    endif                
                endif
                set index = index + 1
                exitwhen index >= bj_MAX_INVENTORY or hasItem
            endloop                  
                            
            //If the unit does not have the item already, allow them to receive it normally.            
            //Otherwise, merge them accordingly.
            if (hasItem) then                
                if (GetItemCharges(indexItem) == MaximumStacks[isMergeableIndex]) then
                    //Do Nothing
                else 
                    //If the unit is picking up a stack which is exceeds the capacity of stacks,
                    //merge them and create and full stack + a smaller one.
                    if (GetItemCharges(indexItem) + GetItemCharges(anItem) > MaximumStacks[isMergeableIndex]) then
                        call SetItemCharges(anItem, GetItemCharges(indexItem) + GetItemCharges(anItem) - MaximumStacks[isMergeableIndex])
                        call SetItemCharges(indexItem, MaximumStacks[isMergeableIndex])
                    else
                        call SetItemCharges(indexItem, GetItemCharges(indexItem) + GetItemCharges(anItem))
                        call RemoveItem(anItem)
                    endif
                endif                            
            endif
        endif
    endfunction

    //===========================================================================
    function onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_PICKUP_ITEM)
        call TriggerAddAction(t, function MergeItem )
    endfunction

endlibrary


This function contains the logic to stack items as they are picked up. Has logic for a maximum number of stacks as well. However does not contain logic to stack items when they are moved within the inventory (working on this). Aside from dirty details, the code is self explanatory.

Demo Map maybe coming in the future. Need to add more features first and work out some bugs.
 

SanKakU

Member
Reaction score
21
thanks for posting the library. those variables were quite the mystery.

it seems like your system could have a very big loop.
i'm not familiar with loops so idk if that would be a problem or not.

maybe ask J4L how this would compare with using his GT event system. (which is what my stacking system does)
 

Tyrulan

Ultra Cool Member
Reaction score
37
Most definitely cleaning up which needs to be done here. (Nullifying variables etc.) I'm working on several things at once here. Just getting the logic part done first.
 

retupmoc258

New Member
Reaction score
1
One thing I've thought would be more efficient than using loops is using a hashtable. Basically having each item by name or integer ID be a look-up value inside of a hashtable. Since the hashtable is 2 dimensional (needs two input), you might just have 0 or some default thing be the second input variable, so all you need is the integer ID and it will look up an integer that corresponds to its value in the list of MergeableItems. With that, then the computer only has to do one look-up (which is more efficient than say 20 loops), and then you have the value you need. Just a suggestion: I've started using that with my map, which involves 20 variables for every weapon. So I have just tried to put everything into a hashtable. So far it seems to work, but I haven't tried it extensively--I need to make the items still.
 

Tyrulan

Ultra Cool Member
Reaction score
37
I'll give it a shot. I'd have to work with it to make it "skip" items which are holding their maximum capacity of items.
 

retupmoc258

New Member
Reaction score
1
I'll give it a shot. I'd have to work with it to make it "skip" items which are holding their maximum capacity of items.

What do you mean by that? Basically this triggers when you pick up an item, right? So once you pick it up, you identify the unit ID integer, look up the integer value assigned it in the MergeableItems, then find the max there, then check the inventory to see if they are at maximum capacity . . . you'd have to do that without the hashtable, right? Just this way you identify the integer you use for it quickly.
 

Tyrulan

Ultra Cool Member
Reaction score
37
Haven't used a hashtable before, it's not my forte. So it'll take some learning.
 

retupmoc258

New Member
Reaction score
1
Basically it looks more complicated than it really is. All you have to do is do something like this:

JASS:
globals
   hashtable MergeableLookup = InitHashtable()
   local integer A = 0
   local integer B = MaxMergeItems //replace this with a number or something else that you would use
   loop
      call SaveInteger( MergeableLookup, StringHash(MergeableItems[A]), 0, A ) //This uses the Mergeable Items ID lookup, so all you have to do is find the Integer ID of the item, then look it up in this fashion.
      //So to clarify, this so far uses your MergeableItems list and goes through all of them and enters all the Object Integer ID's into the hashtable under the ID and 0 (as an empty integer value that you can change to anything--but be consistent otherwise you have to keep track of a lot of variables)
      //Then the last part is the integer A, which obviously corresponds to which entry in the MergeableItems the item IS.  So when you tell the computer to load the hashtable value, it uses the Object Integer ID and 0 and finds A.
      Set A = A + 1
      exitwhen A >= B
   endloop
endglobals

//Now when you want to use it, use this:
set Variable = LoadInteger( MergeableLookup, GetItemTypeId(GetManipulatedItem()), 0 ) //Note: If you have already done something such as "set MergeItem = GetItemTypeId(GetManipulatedItem())" then use that, otherwise you can use this as is, from the look of your code.
//So this piece looks up the integer you saved earlier and returns you the integer assocated with it in your MergeableItems[] array.  Once you have that integer, you can use it for all of your other arrays.  Simple as that, really.


That should do it, I think.
 

Tyrulan

Ultra Cool Member
Reaction score
37
Your system is confusing to me, so this is more about the learning process. Does it have support for a maximum number of stacks?
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top