• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Item Stacking and Splitting - Submission

Status
Not open for further replies.
Mission Type: Item
Missions Performed: Item Stacking, Item Splitting

Reason for Merging of Missions: These two felt like they are mutually inclusive of each other, which led me to submit both of these snippets.

Code

Description

API

Approach



(User-defined) Globals used:

JASS:
globals
    integer array udg_ItemType_ChargeItem
    integer array udg_ItemType_ChargeLimit
    integer udg_ItemType_getInstance                     = 0
    integer udg_ItemType_maxIndex                        = 0
    integer array udg_ItemType_recycler
endglobals

Mandatory:
JASS:
    ...
    function PrintTo takes player p, string s, real dur returns nothing
        call DisplayTimedTextToPlayer(p, 0, 0, dur, s)
    endfunction
 
    function Print takes string s returns nothing
        call PrintTo(GetLocalPlayer(), s, (StringLength(s) * 0.3 + 1.5))
    endfunction
    ...

    // This frees up an instance in the recycler stack...
    function ItemType_deallocate takes integer this returns nothing
        set udg_ItemType_recycler[this] = udg_ItemType_recycler[0]
        set udg_ItemType_recycler[0] = this
        if this == udg_ItemType_maxIndex then
            set udg_ItemType_maxIndex = udg_ItemType_maxIndex - 1
        endif
    endfunction

    // This gives us an instance to work with...
    function ItemType_allocate takes nothing returns integer
        local integer this = udg_ItemType_recycler[0]
        if udg_ItemType_recycler[this] == 0 then
            set this = this + 1
            set udg_ItemType_recycler[0] = this
            set udg_ItemType_maxIndex = this
            return this
        endif
        set udg_ItemType_recycler[0] = udg_ItemType_recycler[this]
        set udg_ItemType_recycler[this] = 0
        return this
    endfunction

    // Now, we search for a certain item-type and see if a match comes up..
    // If it does, then we can stack items of that item-type
    function ItemType_search takes integer itemType returns integer
        local integer this = 1
        loop
            exitwhen this > udg_ItemType_maxIndex or udg_ItemType_ChargeItem[this] == itemType
            set this = this + 1
        endloop
        if this > udg_ItemType_maxIndex then
            set this = 0
        endif
        return this
    endfunction

    // Searches for an instance, then checks if it is not zero.
    // If it is not zero, then we have a stackable item.
    function IsItemCharged takes item whichItem returns boolean
        set udg_ItemType_getInstance = ItemType_search(GetItemTypeId(whichItem))
        return udg_ItemType_getInstance != 0
    endfunction
  
    // This removes a certain item-type from the stack.
    // What this truly does is to no longer allow items with the item-type to stack.
    function ItemType_destroy takes integer itemType returns nothing
        local integer this = ItemType_search(itemType)
        if this == 0 then
            return
        endif
        set udg_ItemType_ChargeItem[this] = 0
        set udg_ItemType_ChargeLimit[this] = 0
        call ItemType_deallocate(this)
    endfunction

    // This checks if the item type is not yet in the stack, and allocates a new instance if it is so.
    // After checking, it would just set the limit of charges to its' maximum
    function ItemType_create takes integer itemType, integer numCharges returns integer
        local integer this = ItemType_search(itemType)
        if this == 0 then
            set this = ItemType_allocate()
            set udg_ItemType_ChargeItem[this] = itemType
        endif
        set udg_ItemType_ChargeLimit[this] = numCharges
        return this
    endfunction

    // Had to create this function so that JassHelper will not yell at me for referencing functions below a requesting function..
    function InitTrig_Item_Charge_Handler takes nothing returns nothing
    endfunction

Item Stacking

Item Splitting


JASS:
    // Due to pJASS, this compiles just fine, even if you're supposed to return a boolean.
    // This is a filterfunc...
    function Item_Charger_Actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local item i_targ = GetManipulatedItem()
        local item item_iterator = null
        local integer item_items = 0
        local integer i_targ_type = GetItemTypeId(i_targ)
        local integer i = 0
  
        // We check if the item is stackable as defined by the stack..
        if IsItemCharged(i_targ) then
      
            loop
                // item_iterator acts as the comparator...
                set item_iterator = UnitItemInSlot(u, i)
                set item_items = GetItemCharges(item_iterator)
                
                // We terminate the search should we end in either the last element or the current item eing manipulated.
                exitwhen i > 5 or item_iterator == i_targ

                // We compare the comparator and the manipulated item to see if they are of the same item-type
                if GetItemTypeId(item_iterator) == i_targ_type then
                    // If the number of charges is less than the item-type's limit, then we stack the item.
                    if item_items < udg_ItemType_ChargeLimit[udg_ItemType_getInstance] then
                        call SetItemCharges(item_iterator, GetItemCharges(i_targ) + item_items)
                        call Print(GetItemName(item_iterator) + "[" + I2S(GetItemCharges(item_iterator)) + "]" + " [+ " + I2S(GetItemCharges(item_iterator) - item_items) + "]")

                        // Should the number of charges exceed that of the limit, the number of charges in the comparator would be reset to the limit, and the number of charges of the manipulated item would be updated.
                        // Otherwise, the comparator has technically absorbed the item.
                        if GetItemCharges(item_iterator) > udg_ItemType_ChargeLimit[udg_ItemType_getInstance] then
                            call SetItemCharges(i_targ, GetItemCharges(item_iterator) - udg_ItemType_ChargeLimit[udg_ItemType_getInstance])
                            call SetItemCharges(item_iterator, udg_ItemType_ChargeLimit[udg_ItemType_getInstance])
                        else
                            call RemoveItem(i_targ)
                            exitwhen true
                        endif
                    endif
                endif
                set i = i + 1
            endloop
            // Unlikely case, but if the number of charges exceed that of the limit as assigned in the stack of item types, then we split the item and try again.
            if item_iterator == i_targ then
                if GetItemCharges(i_targ) > udg_ItemType_ChargeLimit[udg_ItemType_getInstance] then
                    set bj_lastCreatedItem = CreateItem(i_targ_type, GetUnitX(u), GetUnitY(u))
                    call SetItemCharges(bj_lastCreatedItem, GetItemCharges(i_targ) - udg_ItemType_ChargeLimit[udg_ItemType_getInstance])
                    call SetItemCharges(i_targ, udg_ItemType_ChargeLimit[udg_ItemType_getInstance])
                    call UnitAddItem(u, bj_lastCreatedItem)
                    return
                endif
            endif
        endif
  
        set i_targ = null
        set u = null
    endfunction

    // this function is just a wrapper function, which makes the code a bit more readable.
    function ItemCharger__RegisterItems takes nothing returns nothing
        call ItemType_create('stwp', 3)
    endfunction
//===========================================================================
    function InitTrig_Item_Charger takes nothing returns nothing
        set gg_trg_Item_Charger = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(gg_trg_Item_Charger, EVENT_PLAYER_UNIT_PICKUP_ITEM)
        call TriggerAddCondition(gg_trg_Item_Charger, Filter(function Item_Charger_Actions))
        call ItemCharger__RegisterItems()
    endfunction

JASS:
    // This function attempts to find the item in a unit, returning -1 if the item is not found.
    function GetItemSlotInUnit takes item whichItem, unit whichUnit returns integer
        local integer i = 0
        loop
            exitwhen i > 5 or UnitItemInSlot(whichUnit, i) == whichItem
            set i = i + 1
        endloop
        if i > 5 then
            return -1
        endif
        return i
    endfunction
 
    // To do the split, one must take note that the order fires triggers registered to the issuance of an order targeting a certain target.
    // using Order tracking, the bounds of the orders issued are 852002 (slot 1) to 852007 (slot 6)
    function Item_Disassembler_Actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local integer order = GetIssuedOrderId()
        local integer itemSlotOrigin = 0
        local integer itemSlotTarget = 0
        local item i_targ
        local item i_new
  
        // this tells us if the order is that of relocating a certain item to another slot.
        if 852002 <= order and order <= 852007 then
            set i_targ = GetOrderTargetItem()
            if IsItemCharged(i_targ) then
                set itemSlotOrigin = GetItemSlotInUnit(i_targ, u)
                set itemSlotTarget = order - 852002
                if itemSlotOrigin != itemSlotTarget then
                    set i_new = UnitItemInSlot(u, itemSlotTarget)
                    if i_new != null then
                        call Print("An item was found!")
                        if GetItemTypeId(i_new) == GetItemTypeId(i_targ) then
                            if GetItemCharges(i_new) < udg_ItemType_ChargeLimit[udg_ItemType_getInstance] and GetItemCharges(i_targ) < udg_ItemType_ChargeLimit[udg_ItemType_getInstance] then
                                call Print("Item charges in target slot less than 3! Attempting merge!")
                                call SetItemCharges(i_new, GetItemCharges(i_new) + GetItemCharges(i_targ))
                                if GetItemCharges(i_new) > udg_ItemType_ChargeLimit[udg_ItemType_getInstance] then
                                    call SetItemCharges(i_new, GetItemCharges(i_new) - udg_ItemType_ChargeLimit[udg_ItemType_getInstance])
                                    call SetItemCharges(i_targ, udg_ItemType_ChargeLimit[udg_ItemType_getInstance])
                                else
                                    call RemoveItem(i_targ)
                                endif
                            else
                                call Print("Item charges in target slot greater than or equal to 3. Ignoring merge!")
                            endif
                        else
                            call Print("Comparison between two different types are not allowed!")
                        endif
                    else
                        call Print("No item in item slot found")
                        if GetItemCharges(i_targ) != 1 then
                            call Print("Item charges are in excess, splitting!")
                            set i_new = CreateItem(GetItemTypeId(i_targ), GetUnitX(u), GetUnitY(u))
                            call SetItemCharges(i_targ, GetItemCharges(i_targ) - GetItemCharges(i_new))
                      
                            call DisableTrigger(gg_trg_Item_Charger)
                            call UnitAddItem(u, i_new)
                            call EnableTrigger(gg_trg_Item_Charger)
                      
                            call SetItemCharges(i_targ, GetItemCharges(i_targ) + GetItemCharges(i_new))
                            call SetItemCharges(i_new, GetItemCharges(i_targ) - GetItemCharges(i_new))
                            call SetItemCharges(i_targ, GetItemCharges(i_targ) - GetItemCharges(i_new))
                        else
                            call Print("Item charges are atomic, ignoring!")
                        endif
                    endif
                    set i_new = null
                endif
            endif
            set i_targ = null
        endif
        set u = null
    endfunction

    //===========================================================================
    function InitTrig_Item_Disassembler takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
        call TriggerAddCondition(t, Filter(function Item_Disassembler_Actions))
        set t = null
    endfunction



The missions performed in this submission are: Item Stacking and Item Splitting.

Item Stacking refers to the process of incrementing the number of charges for a particular item. What the Item Stacking mission mandates is to allow charged items to stack with each other.

Item Splitting refers to the process of division of a particular item into two sub-items.


Globals:
integer array udg_ItemType_ChargeItem
- This array is a parallel array that stores the item-types that will be stacked.

integer array udg_ItemType_ChargeLimit
- This array is also a parallel array. It acts as the upper bound of the amount of charges for a certain item-type.

integer udg_ItemType_getInstance
- Is worth something after you call the function IsItemCharged

integer udg_ItemType_maxIndex
- Acts as the maximum index of the item-type stack.

integer array udg_ItemType_recycler
- Allows allocation and deallocation of ItemType instances (implicitly)

Functions:
function ItemType_create takes integer itemType, integer numCharges returns integer
- This allows the triggers above to detect when a certain item of the requested item-type is acquired, and allows the stacking of said item...

function IsItemCharged takes item whichItem returns boolean
- The function automatically converts the item into an item-type and searches for it in the item-type stack, returning true if it is in the stack, or false otherwise.

I decided to approach this mission with a sense of modularity, because I thought of a case-scenario wherein you do not want a certain item-type (which you know to be charged) to stack with itself. The allocation scheme is purely for including item-types in the stack, so that when the acquirement of a stackable item occurs, the system checks for it and its' internal limit.
 

Attachments

  • Item Charges.w3x
    19.5 KB · Views: 58
Last edited:
@IcemanBo

Just in case some of those who'll read this do not understand, the API is there for clarification of how the system works.
As for the allocation, I thought it would be more fun to include it, though this can be made without it.
(Mostly because I thought an item-type stack would be sensible, and flexible as well)

I challenged myself to make it in vanilla JASS, which explains the udg_s...
 
Last edited:
If there is used code, make docu, docu and docu. If you already don't wanna waste time for explaining, why should someone waste time for interpretation. Especially here in JASS Class, which is meant to be beginner friendly. I just don't understand why the goal is to write extra fun things that makes things more complex, but ok, that's your personal fun part, but heck then please explain what and why exactly you do at code places.

custom globals block require jasshelper to be moved automaticaly in the globals block, so not sure udg_ makes sense in combination.
 
Okay, gonna update the code with comments.

About the globals part, I added that to tell those who would read the code that the variable names that come up are global variables, and that they have udg_ prefixes because they were generated using the variable editor.

My approach on documentation is object first, description later.
 
Last edited:
Status
Not open for further replies.
Top