• 🏆 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!

A method to flawlessly handle preplaced items' deindexing (for a future Item Indexer)

Status
Not open for further replies.
Level 16
Joined
Dec 15, 2011
Messages
1,423
Back then me and some other guys (Mag, Ruke, lfh, Nestharus, Purge) are quite enthusiastic about making an Item Indexer that functions essentially similiar to a Unit Indexer. I guess we didn't make it in the end because there wasn't a proper way to index items seamlessly like you can do with units. However, we are able to discover a (apparently perfect) way to handle deindexing for preplaced items. There wasn't The Lab at that time so the idea kinda got buried.

Today I somehow remembered about this and decided to bring it up again with hope that maybe we can finally have a true Item Indexer. Or at least this can prove useful in some other ways for people.

Here is a test script, attached below is a test map.

JASS:
globals
    trigger t = CreateTrigger()
endglobals

module OnInit
    static method onInit takes nothing returns nothing
        call init()
    endmethod
endmodule

struct Test extends array

    private static method onEsc takes nothing returns nothing
        call RemoveItem(gg_item_ratf_0010)
    endmethod

    private static method callBack takes nothing returns boolean
        call BJDebugMsg("Deindexed")
        return false
    endmethod
    
    private static method addItem takes nothing returns nothing
        call TriggerRegisterDeathEvent(t, GetEnumItem())
    endmethod

    static method init takes nothing returns nothing
        local trigger t1 = CreateTrigger()
        
        call TriggerRegisterPlayerEvent(t1, Player(0), EVENT_PLAYER_END_CINEMATIC)
        call TriggerAddAction(t1, function thistype.onEsc)
        
        call EnumItemsInRect(bj_mapInitialPlayableArea, null, function thistype.addItem)
        call TriggerAddCondition(t, function thistype.callBack)
        set t1 = null
    endmethod
    
    implement OnInit
endstruct

This method handles all possible situations that can cause a preplaced item to "disappear" from the map, namely:

  • Remove Item.
  • Kill Item.
  • Sell Item.
  • Tome Usage.
  • Consumable Items.
  • Charged Items.

You will be needing an Event Recycler to handle event leaks caused by this method (tested by lfh here). You can find more details and information here (read from page 1 to 3).

edit

Sorry for the long title. I am unable to come up with another that is short but informative enough.
 

Attachments

  • Item Deindexing.w3x
    25.8 KB · Views: 45
Level 26
Joined
Aug 18, 2009
Messages
4,097
And how do you access the dying item? There is no GetTriggerItem that would return it.

There is GetTriggerWidget. To convert it to item, you can use the new returnbug with SaveFogState. Or you pre-assign the item to its widget depiction via the handle id for example. A third option would be to to have a private trigger for each item and assign it to the trigger's handle id, which you can then retrieve via GetTriggeringTrigger.

And really, TriggerRegisterDeathEvent is still unknown?

For an item indexer, there are not too many ways to create a new item, hook the CreateItem native and variants, the sell item event, that's it?
 
Level 17
Joined
Jul 17, 2011
Messages
1,864
i thought the hard part about indexing items was to be able to know when do deindex them
otherwise you can just have an event when a unit aquires an item and when an item enters map bounds. the map bounds i guess is kinda tricky since there are a number of things that can happen but i think all of them can be detected through native events which can call the onindex trigger or w/e or u can just use a loop D
but there isnt much use in indexing item i mean whats next a destructable indexer?
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Hooks are done before, so i don't see how it would help there.
Unless ofc you use some silly unreliable stuff within it, like a Timer(0).

A custom CreateItem function would be the best option there but yeah then the mapmaker has to use it instead of the native one. (and ofc all GUI related stuff, included the loot thing)
But anyway as gorillabull i don't see much use in an item indexer.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
it is possible to cast integer to almost all types using
JASS:
function Cast takes integer i returns unit
    call SaveInteger(hashtable, -100, -100, ConvertFogState(i)) //[-100, -100] for no collision
    return LoadUnitHandle(hashtable, -100, -100)
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Ok for the return bug, but still i'm fairly sure you can't guess which handle id will be used, and even if you could know it, it still wouldn't work because when the hooked function will be called the item will not already be created.

So as said better hook implementation or just a custom function (but i still think an item indexer is pointless)
 
I made a couple quick examples without the onDeindex event.


JASS:
library ItemDex initializer onInit

    globals
        private integer Index = 0
        private integer Count = 0
        private integer array List
    endglobals
    
    function GetItemId takes item x returns integer
        local integer i = GetItemUserData(x)
        local integer t = Index
         
        if (i==0) then
            if (Index != 0) then
                set Index = List[t]
            else
                set Count = Count + 1
                set t = Count
            endif
                
            set List[t] = -1
                
            call SetItemUserData(x, t)
            
            debug call BJDebugMsg("ItemDex: " + GetItemName(x) + "[" + I2S(t) + "] has been indexed.")
            
            return t
        endif
        
        return i
    endfunction
    
endlibrary


JASS:
library ItemDex initializer onInit

    globals
        private trigger DeathTrigger = CreateTrigger()
        
        private integer Index = 0
        private integer Count = 0
        private integer array List
        
        private hashtable Typecast=InitHashtable()
    endglobals
    
    function GetItemId takes item x returns integer
        return GetItemUserData(x)
    endfunction
    
    function Widget2Item takes widget w returns item
        call SaveFogStateHandle(Typecast, 0, 0, ConvertFogState(GetHandleId(w)))
        return LoadItemHandle(Typecast, 0, 0)
    endfunction
    
    private function ItemDexNew takes item x returns integer
        local integer t = Index
        
        if (Index != 0) then
            set Index = List[t]
        else
            set Count = Count + 1
            set t = Count
        endif
            
        set List[t] = -1
            
        call SetItemUserData(x, t)
        
        call TriggerRegisterDeathEvent(DeathTrigger, x)
        
        return t
    endfunction
    
    private function ItemDexDel takes item x returns boolean
        local integer i = GetItemUserData(x)
        
        if (i > 0) then
            set List[i]   = Index
            set Index     = i
            debug call BJDebugMsg("ItemDex: " + GetItemName(x) + "[" + I2S(i) + "] has been removed.")
        endif
        
        set x = null
        
        return false
    endfunction
    
    private function onRemove takes nothing returns boolean
        return ItemDexDel(Widget2Item(GetTriggerWidget()))
    endfunction
    
    private function onEnter takes nothing returns nothing
        call ItemDexNew(GetEnumItem())
    endfunction
    
    private function onInit takes nothing returns nothing
        call EnumItemsInRect(bj_mapInitialPlayableArea, null, function onEnter)
        call TriggerAddCondition(DeathTrigger, Filter(function onRemove))
    endfunction
    
    // hooks
    private function CreateItemEx takes integer itemid, real x, real y returns nothing
        //call ItemDexNew(CreateItem(itemid, x, y))
    endfunction
    
    private function RemoveItemEx takes item whichItem returns nothing
        call ItemDexDel(whichItem)
    endfunction
    
    
    //hook CreateItem CreateItemEx
    hook RemoveItem RemoveItemEx
    
endlibrary
 
Last edited:

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
call TriggerRegisterDeathEvent(t, GetEnumItem()) as deindex item method as explained within "resources yet to be coded" has at least 3-4 years, and for the first time I've seen this back in 2006 or 2007. AII is perfect example of it's usage. Use google guys.

In submissions, there is ItemIndexer which I wrote basing on kingkingyyk3's script and Nes' indexer - (for api, since everyone seems to be used to his UI).
Lib's last update is within last post, still requires things to be done (making every requirement optional), yet no comments so far, thus no need to hurry with uploading new version. Vex' dex uses suggested by Purge PUI idea - for me it's the best solution, hooks alter users code, and coupling PUI + custom CreateItem function (NewItem in my version) seems to be win-win.
 
Status
Not open for further replies.
Top