1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. The 15th Mini-Mapping Contest came to an end. The Secrets of Warcraft 3 are soon to be revealed! Come and vote in the public poll for your favorite maps.
    Dismiss Notice
  4. The 12th incarnation of the Music Contest is LIVE! The theme is Synthwave. Knight Rider needs a song to listen to on his journey. You should definitely have some fun with this theme!
    Dismiss Notice
  5. Join other hivers in a friendly concept-art contest. The contestants have to create a genie coming out of its container. We wish you the best of luck!
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Item Indexer v1.4.0 [GUI friendly]

Submitted by NightSkyAurora
This bundle is marked as approved. It works and satisfies the submission rules.
Item Indexer
Code (vJASS):

/********************************Item Indexer v1.4.0 by NightSkyAurora********************************
    WHAT IT DOES:
        - Assigns a unique custom value (ItemUserData in JASS) to all the items in the game
        - Creates an event that fires when an item is created/sold/destroyed/removed from the game
        - Instantly removes items that are not removed properly when used such as Tome of Experience

    IMPORTING THE SYSTEM:
        1. file -> preferences -> general -> check outomaticly create unknown varibles when pasting trigger data.
        2. Copy the 'Item Indexer' trigger folder and paste it in your map
        3. Delete the 'variable creator' trigger

    USING THE SYSTEM
        If you have the item but wants to get its id, get the custom value of that item
        If you have the id but wants to get the item it referes to, use IDexItems[id] to get the item

    CONS:
        - The item's custom value becomes unusible for other purposes
        - Item Id cannot always be accessed immediately without calling IndexItem() manually

    ////////////////////////////   API   /////////////////////////////
    //////////////////////////////////////////////////////////////////
   
    function IndexItem takes item itm returns integer
        Indexes a selected item and returns it's new id
   
    function IndexEnumItem takes nothing returns nothing
        Indexes a group of items such as items in playable map area
   
    function IndexItemOnTheGround takes real x, real y returns integer
        Finds items at a nearby point and index them
        returns id of last indexed item
       
    //////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////
   
    IMPORTANT!!
    The following functions doesn't guarentee imidiate access to an item's id
    If the id is needed immediately, please use the functions as explained in the api
   
        CreateItem
        CreateItemLoc | GUI Item - Create
        UnitAddItemByIdSwapped | GUI Hero - Create Item For Hero
        UnitAddItemById
        UnitAddItemToSlotById
        UnitDropItem | Items dropped by dying units
        WidgetDropItem | Items dropped by dying destructables
   
******************************************************************************************************/


library ItemIndexer initializer Init
    globals
        private integer InstCount = 0
        private hashtable hash = InitHashtable()
        private trigger array TrigDeindexer
        private integer array recycle
    endglobals
   
    //De-index items that are destroyed
    private function DeindexDestroyed takes nothing returns nothing
        local trigger t = GetTriggeringTrigger()
        local integer i = LoadInteger(hash, GetHandleId(t), 0)
        call FlushChildHashtable(hash, GetHandleId(t))
        call DisableTrigger(t)
        set udg_IDex = i
        set udg_ItemEvent = 2.00
        set udg_ItemEvent = 0.00
        call TriggerSleepAction(1)
        set udg_IDex = i
        set udg_ItemEvent = 4.00
        set udg_ItemEvent = 0.00
        call SetWidgetLife(udg_IDexItems[i], 1)
        call RemoveItem( udg_IDexItems[i] )
        set udg_IDexItems[i] = null
        set TrigDeindexer[i] = null
        set recycle[i] = recycle[0]
        set recycle[0] = i
        call DestroyTrigger(t)
    endfunction
   
    //De-index items that are sold
    private function DeindexSold takes nothing returns nothing
        local integer i = GetItemUserData(GetSoldItem())
        set udg_IDex = i
        set udg_ItemEvent = 3.00
        set udg_ItemEvent = 0.00
        set udg_IDexItems[i] = null
        set recycle[i] = recycle[0]
        set recycle[0] = i
        //clean and destroy the item's destruction trigger
        call FlushChildHashtable(hash, GetHandleId(TrigDeindexer[i]))
        call DestroyTrigger(TrigDeindexer[i])
        set TrigDeindexer[i] = null
    endfunction
   
    //This function ultimately assigns a unique custom value to each item and returns its id
    function IndexItem takes item itm returns integer
        local integer i = GetItemUserData(itm)
        if not udg_IDexIsIndexed[i] and itm != null then
            if recycle[0] == 0 then
                set InstCount = InstCount + 1
                set i = InstCount
            else
                set i = recycle[0]
                set recycle[0] = recycle[i]
            endif
            set udg_IDexItems[i] = itm
            call SetItemUserData(itm, i)
            set udg_IDexIsIndexed[i] = true
            //create a trigger that detects when the item is destroyed
            set TrigDeindexer[i] = CreateTrigger()
            call TriggerRegisterDeathEvent(TrigDeindexer[i], itm)
            call TriggerAddAction(TrigDeindexer[i], function DeindexDestroyed)
            call SaveInteger(hash, GetHandleId(TrigDeindexer[i]), 0, i)
            set udg_IDex = i
            set udg_ItemEvent = 1.00
            set udg_ItemEvent = 0.00
        endif
        return i
    endfunction

    //Index each enum item
    function IndexEnumItem takes nothing returns nothing
        call IndexItem(GetEnumItem())
    endfunction
   
    //Index items near a target point
    function IndexItemOnTheGround takes real x, real y returns integer
        local rect r = Rect(x-256.00, y-256.00, x+256.00, y+256.00)
        call EnumItemsInRect(r, null, function IndexEnumItem)
        set r=null
        return udg_IDex // returns last indexed item's id
    endfunction

    //Searches the saved locations for any items and request enum items to be indexed
    private function LoadItemLoc takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer h_id = GetHandleId(t)
        local real x = LoadReal(hash, h_id, 0)
        local real y = LoadReal(hash, h_id, 1)
        local rect r = Rect(x-256.00, y-256.00, x+256.00, y+256.00)
        call EnumItemsInRect(r, null, function IndexEnumItem)
        call FlushChildHashtable(hash, h_id)
        call DestroyTimer(t)
        set t=null
        set r=null
    endfunction

    //Saves the location of an item and wait 0.00 seconds for the item to be created
    private function SaveItemLoc takes real x, real y returns nothing
        local timer t = CreateTimer()
        local integer h_id = GetHandleId(t)
        call SaveReal(hash, h_id, 0, x)
        call SaveReal(hash, h_id, 1, y)
        call TimerStart(t, 0.00, false, function LoadItemLoc)
        set t=null
    endfunction
   
    //The following functions hooks all functions that can create an item to index it
    private function CreateItemHook takes integer itemId, real x, real y returns nothing
        call SaveItemLoc(x, y)
    endfunction

    private function CreateItemLocHook takes integer itemId, location loc returns nothing
        call SaveItemLoc(GetLocationX(loc), GetLocationY(loc))
    endfunction

    private function UnitAddItemByIdSwappedHook takes integer itemId, unit u returns nothing
        if UnitInventoryCount(u) == UnitInventorySize(u) then
            call SaveItemLoc(GetUnitX(u), GetUnitY(u))
        endif
    endfunction

    private function UnitAddItemByIdHook takes unit u, integer itemId returns nothing
        if UnitInventoryCount(u) == UnitInventorySize(u) then
            call SaveItemLoc(GetUnitX(u), GetUnitY(u))
        endif
    endfunction

    private function UnitAddItemToSlotByIdHook takes unit u, integer i, integer slot returns nothing
        call SaveItemLoc(GetUnitX(u), GetUnitY(u))
    endfunction

    //Index items that is dropped when a unit dies
    private function UnitDropItemHook takes unit inUnit, integer inItemID returns nothing
        call SaveItemLoc(GetUnitX(inUnit), GetUnitY(inUnit))
    endfunction

    //Index items that is dropped when a widget dies
    private function WidgetDropItemHook takes widget inWidget, integer inItemID returns nothing
        call SaveItemLoc(GetWidgetX(inWidget), GetWidgetY(inWidget))
    endfunction

    //Index items in inventories that were given to units via the map editor
    private function IndexInventories takes nothing returns nothing
        local integer i = 0
        local unit u = GetEnumUnit()
        if UnitInventorySize(u) > 0 then
            loop
                call IndexItem(UnitItemInSlot(u, i))
                set i = i + 1
                exitwhen i >= bj_MAX_INVENTORY
            endloop
        endif
        set u=null
    endfunction

    //Index items that are sold to a unit
    private function IndexOnCreate takes nothing returns nothing
        call IndexItem(GetManipulatedItem())
    endfunction
   
    //Index items that are sold to the ground
    private function IndexOnBuy takes nothing returns boolean
        local real x = GetUnitX(GetOrderedUnit())
        local real y = GetUnitY(GetOrderedUnit())
        local item i = CreateItem(GetIssuedOrderId(), x, y)
        if i != null then
            call RemoveItem(i)
            call SaveItemLoc(x, y)
        endif
        set i = null
        return false
    endfunction

    private function Init takes nothing returns nothing
        local trigger TrigIndexOnCreate = CreateTrigger()
        local trigger TrigIndexOnBuy = CreateTrigger()
        local trigger TrigItemDeindexer = CreateTrigger()
        local rect rt = GetPlayableMapRect()
        local group g = GetUnitsInRectAll(rt)
       
        hook CreateItem CreateItemHook
        hook CreateItemLoc CreateItemLocHook
        hook UnitAddItemByIdSwapped UnitAddItemByIdSwappedHook
        hook UnitAddItemById UnitAddItemByIdHook
        hook UnitAddItemToSlotById UnitAddItemToSlotByIdHook
        hook UnitDropItem UnitDropItemHook
        hook WidgetDropItem WidgetDropItemHook
       
        call TriggerRegisterAnyUnitEventBJ(TrigIndexOnCreate, EVENT_PLAYER_UNIT_PICKUP_ITEM )
        call TriggerAddAction(TrigIndexOnCreate, function IndexOnCreate)
        call TriggerRegisterAnyUnitEventBJ(TrigIndexOnBuy, EVENT_PLAYER_UNIT_ISSUED_ORDER )
        call TriggerAddAction(TrigIndexOnBuy, function IndexOnBuy)
        call TriggerRegisterAnyUnitEventBJ( TrigItemDeindexer, EVENT_PLAYER_UNIT_PAWN_ITEM )
        call TriggerAddAction(TrigItemDeindexer, function DeindexSold)  
        call EnumItemsInRect(rt, null, function IndexEnumItem )
        call ForGroup(g, function IndexInventories)
        set rt = null
        call DestroyGroup(g)
    endfunction
endlibrary
 


changelog

v1.4.0

-Give one second change before removing items to display death animation
-Added an event to differentiate between destroyed and removed item

v1.3f

-Removed a leak

v1.3e

-Some small code improvements

v1.3d

-Removed some leaks
-Optimized some code to improve performance
-Improved documentation

v1.3c

-Each item now has its own trigger
-The system can distinguish between sold and destroyed items more clearly
-Some minor performance improvements

v1.3b

-Huge code optimizations. Credits to ZiBitheWand3r3r once again...
-The whole system is now in one trigger. No more header code
-Fixed on-index event not working

v1.3

-Got hooked functions working (thanks ZiBitheWand3r3r)
-Organized code to improve performance

v1.2

-Uses a different index approach as requested by Reventhous
-Converted the main trigger to custom text

v1.1

-Index items that are created for hero
-Index items that are dropped by natural creeps
-Index items that are given to units via the map editor
-Merged all the triggers into one trigger
-Uses hash table to find the destroyed item quicker
-Added an "on index" event
-int IDex can be used to get the id of the last created item

v1.0b

-Fixed a bug where the event is fired twice when items are sold

v1.0

uploaded



Huge credits to ZiBitheWand3r3r for all your support!
Contents

Item Indexer v1.4.0 (Map)

Reviews
ZiBitheWand3r3r
This System deprecates [System] Item Cleanup in my opinion. Also this thread can be updated Resources That Have Yet To Be Coded All possible ways to create items in game are supported by this library. Including GUI actions: Hero - Create...
  1. Reventhous

    Reventhous

    Joined:
    May 2, 2015
    Messages:
    104
    Resources:
    1
    Spells:
    1
    Resources:
    1
    Nice work!

    -use ["jass"]["/jass"] without " " for the trigger code. :)
    -why "Game - Display to (All players) the text: abc" and "Game - Display to (All players) the text: def" are in your code?
    -in this line,
        if GetItemUserData(itm) == 0 then
    .
    I think you should replace it with this
    if not udg_IDexIsIndexed[udg_IDexNext] then
    line.
    udg_IDexIsIndexed[udg_IDexNext] = true
    after the item gets its index.

    EDIT:
    In my opinion, this
    Code (vJASS):
    function IndexItem takes item itm returns nothing
        if GetItemUserData(itm) == 0 then
            set udg_IDexItems[udg_IDexNext] = itm
            call SetItemUserData(itm, udg_IDexNext)
            call TriggerRegisterDeathEvent(gg_trg_Item_DeIndexer, itm)
            loop
                exitwhen udg_IDexItems[udg_IDexNext] == null
                set udg_IDexNext = udg_IDexNext + 1
            endloop
        endif
    endfunction


    should be like this

    Code (vJASS):
    function IndexItem takes item itm returns nothing
        local integer i = GetItemUserData(itm)

        if not udg_IDexIsIndexed[udg_IDexNext] then

            if udg_IDexRecycle[0] == 0 then
                set udg_IDexInstanceCount = udg_IDexInstanceCount + 1
                set i = udg_IDexInstanceCount
            else
                set i = udg_IDexRecycle[0]
                set udg_IDexRecycle[0] = udg_IDexRecycle[i]
            endif

            set udg_IDexItems[i] = itm
            call SetItemUserData(itm, i)
            set udg_IDexIsIndexed[i] = true

            call TriggerRegisterDeathEvent(gg_trg_Item_DeIndexer, itm)
        endif
    endfunction


    then add this code in Deindexer
    Code (vJASS):
        set udg_IDexRecycle[itemIndex] = udg_IDexRecycle[0]
        set udg_IDexRecycle[0] = itemIndex


    It just my opinion :)
     
    Last edited: Apr 10, 2017
  2. NightSkyAurora

    NightSkyAurora

    Joined:
    Mar 1, 2013
    Messages:
    528
    Resources:
    8
    Models:
    4
    Spells:
    4
    Resources:
    8
    Thanks, I will in next update
    It is some testing code I forgot to remove, obvously :ao:

    I tried the code that you provided but it didn't work properly. To be honest, by reading your code, I don't fully understand how that algorithm works.
    I've also noticed this:
    Code (vJASS):
    if not udg_IDexIsIndexed[udg_IDexNext] then[\jass]
    In my system, udg_IDexNext will ALWAYS point to an open index (which is the next id that will be given when an item is indexed) Won't this always return true?
     
  3. Reventhous

    Reventhous

    Joined:
    May 2, 2015
    Messages:
    104
    Resources:
    1
    Spells:
    1
    Resources:
    1
    My mistake, It suppose to be like this :)
    Code (vJASS):
    function IndexItem takes item itm returns nothing
        local integer i = GetItemUserData(itm)

        if not udg_IDexIsIndexed[i] then

            if udg_IDexRecycle[0] == 0 then
                set udg_IDexInstanceCount = udg_IDexInstanceCount + 1
                set i = udg_IDexInstanceCount
            else
                set i = udg_IDexRecycle[0]
                set udg_IDexRecycle[0] = udg_IDexRecycle[i]
            endif

            set udg_IDexItems[i] = itm
            call SetItemUserData(itm, i)
            set udg_IDexIsIndexed[i] = true

            call TriggerRegisterDeathEvent(gg_trg_Item_DeIndexer, itm)
        endif
    endfunction


    Ofcourse it will return true, but after this
    set udg_IDexIsIndexed[i] = true
    line do its work, it will return false and that will avoid multiple index for one item.

    Well, I think it will take hours for me to explain this. I'll try make it short.

    About
    udg_IDexIsIndexed

    using
    if GetItemUserData(itm) == 0 then
    might cause conflict, because user has the independence to use
    call SetItemUserData(itm, i)

    So, boolean will avoid that problem.

    I'll explain the "recycle" things later, when I have the time.

    EDIT: Here, read this
    Introduction to Collections: Index Array, Linked List, Stack, Queue, Dequeue
     
    Last edited: Apr 10, 2017
  4. Reventhous

    Reventhous

    Joined:
    May 2, 2015
    Messages:
    104
    Resources:
    1
    Spells:
    1
    Resources:
    1
    -from GUI/JASS, now this system is vJass (the
    globals
    is vJass). Intentional?
    -the Init trigger, why GUI form while JASS form is better
    -indent your code
    -can you post your update summary in the reply.

    I've downloaded your map and what I get is v1.0b, not the latest. And, I tried to replace your code with my code that I mentioned and it works fine.
     
  5. NightSkyAurora

    NightSkyAurora

    Joined:
    Mar 1, 2013
    Messages:
    528
    Resources:
    8
    Models:
    4
    Spells:
    4
    Resources:
    8
    I apologize I uploaded the wrong map. You can see the triggers and changes of the new map in the description.

    I also tried your code and it worked :) It is just that I prefer to understand what I submit
     
  6. NightSkyAurora

    NightSkyAurora

    Joined:
    Mar 1, 2013
    Messages:
    528
    Resources:
    8
    Models:
    4
    Spells:
    4
    Resources:
    8
    Oh my goodness I can't believe I just created a vJass system o_O Thanks for your help Reventhous, I believe I uploaded the correct map this time! ;)
     
  7. Reventhous

    Reventhous

    Joined:
    May 2, 2015
    Messages:
    104
    Resources:
    1
    Spells:
    1
    Resources:
    1
    Not entirely. I recommend you to go back to easy GUI/JASS. (just remove the
    globals
    )

    But, if you really want your code to be in vJass, you will need to learn more about it. You can do the learning by reading the jasshelpermanual.html in jasshelper directory or just find vJass tutorials in HIVE or wc3c.

    Anyway,

    -when it come to JASS, this
    Code (vJASS):
    function Trig_Item_Indexer_Actions takes nothing returns nothing
        call ExecuteFunc("InitializeItemIndexer")
    endfunction

    code shouldn't. Just directly use
    InitializeItemIndexer
    as action function.

    -your code looks empty and dead, some
    //documentation
    will fix that

    -
    set TrigItemDeindexer = CreateTrigger()

    why TrigItemDeindexer is global, not local.

    -I forgot to mention this, put
    set udg_IDexIsIndexed[i] = false
    before
    Code (vJASS):
        set udg_IDexRecycle[i] = udg_IDexRecycle[0]
        set udg_IDexRecycle[0] = i


    -in
    function IndexOnDeath takes nothing returns nothing
    , add
    set u = null

    How this function works? Is it will index when item drops?

    -is this
    Code (vJASS):
            call SaveWidgetHandle(udg_IDexHash, 0, 0, GetTriggerWidget())
            set i = GetItemUserData(LoadItemHandleBJ(0, 0, udg_IDexHash))

    really work? I haven't test it yet and haven't done it before.

    Actually, there's lot more to say but, thats it for now :)
     
  8. KILLCIDE

    KILLCIDE

    Administrator

    Joined:
    Jul 22, 2015
    Messages:
    3,491
    Resources:
    20
    Models:
    2
    Icons:
    10
    Spells:
    7
    Tutorials:
    1
    Resources:
    20
    Errm I wouldn't really call this vJASS. Your code is basically in JASS given all your variables are still user defined, and you don't use scope or library. You just threw on JNGP as a requirement for your system with the single global inside the globals block.
     
  9. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,334
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    So this index items upon pickup not upon creation? People normally use an Indexer for the "Create/Remove Events" but this does not index them upon creation instead it index them when that item is acquired or bought which is already possible to do using native events. Also, it only deindex when the item is sold not when it is generically removed e.g. using RemoveItem(). Item Indexer has a small discussion here.
     
  10. ZiBitheWand3r3r

    ZiBitheWand3r3r

    Joined:
    Nov 21, 2012
    Messages:
    896
    Resources:
    15
    Maps:
    7
    Spells:
    8
    Resources:
    15
    Is hashtable the only way to convert widget to item? I'm just currious..

    By the way quite smart approach
    Code (vJASS):
    call TriggerRegisterDeathEvent(TrigItemDeindexer, itm)
    good job :)

    But as Flux said: you have to index items upon creation. It's not Item Indexer w/o this ability.
    Im not sure but maybe hook ?
    Code (vJASS):
    hook CreateItem CreateItem_Ex
     
  11. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,334
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    hooks will not work on unit item drops though.
     
  12. NightSkyAurora

    NightSkyAurora

    Joined:
    Mar 1, 2013
    Messages:
    528
    Resources:
    8
    Models:
    4
    Spells:
    4
    Resources:
    8
    I've tested this system when I created it and made sure that you can't create an item without causing it to be indexed. When you use "create item for hero", the "hero aquires item" even will fire. If the hero simply picks up an item that is already indexed, the system won't index it again. There is no way (that I know of) to detect when an item is created at a location, unless you loop through all the items in playable map area that will greatly affect performance. This is why I created those custom functions that DOES index the item when created at a location. It is also de-indexed when you remove it. Just enter the id of the item you wan't removed. It will be removed by a GUI function and will be de-indexed successfully.

    Its the only conversion process I can think of...
    I don't know how to detect items when created at a location. As explained above, a looping trigger can do the job but there might be a 0.03125 second delay and it will reduce game performance. An alternative function is the only solution I can think off :/

    btw... what does "hook" do??????
     
  13. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,334
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    Sorry I missed the header file, so it seems you typecast (using hashtable) the item to a widget and it runs the unit death event to detect item death? That's a cool and hacky approach. I guess using hooks and forcing the map maker to not use unit item drops will suffice.

    JassHelper 0.A.0.0
     
  14. Aniki

    Aniki

    Joined:
    Nov 7, 2014
    Messages:
    517
    Resources:
    4
    Spells:
    1
    JASS:
    3
    Resources:
    4
    Code (vJASS):

    // from common.j
    type widget extends agent // an interactive game object with life
    type item extends widget
     


    item
    extends
    widget
    , i.e it can be passed to functions that take a widget (think of the
    GetHandleId
    function, it can take any handle type (units, items, widgets, etc.) because all handle types extend handle)
    native TriggerRegisterDeathEvent takes trigger whichTrigger, widget whichWidget returns event


    The
    TriggerRegisterDeathEvent
    function takes a widget, i.e it can be passed a widget or any type that extends widget (unit, item, destructable).

    The typecast in the function
    ItemDeindexer
    is actually a downcast, from widget to item, and its needed because there is no
    GetTrigger|DyingItem
    , but there are
    GetTriggerUnit()
    ,
    GetTriggerDestructable
    and
    GetTriggerWidget
    .
    Code (vJASS):

    call SaveWidgetHandle(udg_IDexHash, 0, 0, GetTriggerWidget())
    ... LoadItemHandleBJ(0, 0, udg_IDexHash)) // could use LoadItemHandle?
     


    So nothing really "hacky" in my opinion.
    The funny/strange thing is that TriggerRegisterDeathEvent's action function gets called by RemoveItem =)

    leandrotp's Typecast library would probably work (it doesn't come with a widget to item typecasting function but it should be easy to write one).
     
  15. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,334
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    I got confused and thought TriggerRegisterDeathEvent takes unit argument. Everything makes sense now.
     
  16. NightSkyAurora

    NightSkyAurora

    Joined:
    Mar 1, 2013
    Messages:
    528
    Resources:
    8
    Models:
    4
    Spells:
    4
    Resources:
    8
    Hooks looks pretty awesome :D thanks!

    Ok so I guess the idea is to "detect" when the CreateItemLoc() is called and then just indexed the item that is returned by that function? Ok so I added this:
    Code (vJASS):
    hook CreateItemLoc CreateItemLocEx

    and altered my function to look like this:
    Code (vJASS):

    function CreateItemLocEx takes integer itemid, location loc returns item
        call IndexItem(bj_lastCreatedItem)
        call BJDebugMsg("function was hooked!")
        call BJDebugMsg(I2S(GetItemUserData(bj_lastCreatedItem)))
        return bj_lastCreatedItem
    endfunction


    But bj_lastCreatedItem didn't return the item that was created by the hooked function. Sooo.. how do I access it?
     
  17. ZiBitheWand3r3r

    ZiBitheWand3r3r

    Joined:
    Nov 21, 2012
    Messages:
    896
    Resources:
    15
    Maps:
    7
    Spells:
    8
    Resources:
    15
    hook allows you to catch when original function is called as well as parameters passed to that function,
    Code (vJASS):

    function CreateItemLoc takes integer itemId, location loc returns item
        set bj_lastCreatedItem = CreateItem(itemId, GetLocationX(loc), GetLocationY(loc))
        return bj_lastCreatedItem
    endfunction
     
    so you have access to integer itemid and location loc only, but with 0sec timer you can get
    bj_lastCreatedItem
    :
    Code (vJASS):

    function TimerOnExp takes nothing returns nothing
        call IndexItem(bj_lastCreatedItem)
    endfunction
    function CreateItemLoc_Ex takes integer itemId, location loc returns nothing
        call TimerStart(g_timerItems, 0.00, false, function TimerOnExp)
    endfunction

    I guess you have to hook all possible BJ and natives like
    UnitAddItemByIdSwapped CreateItem UnitAddItemById UnitAddItemToSlotById
    something like move rect to x, y and enum items searching for non-indexed one. Also loop thru target unit's inventory to find new item.
     
  18. Tank-Commander

    Tank-Commander

    Spell Reviewer

    Joined:
    May 26, 2009
    Messages:
    1,543
    Resources:
    44
    Packs:
    1
    Spells:
    41
    Tutorials:
    2
    Resources:
    44
    Thanks for the submission, a quick few notes on what I noticed with the system
    V1.2:
    - InitTrig_Item_Indexer, Trig_Item_Indexer_Actions and InitializeItemIndexer could all be combined
    - you use "local rect rt = GetPlayableMapRect()" and then later "set rt = GetPlayableMapRect()" in your init trigger, don't need this second one, also this could be replaced with "bj_mapInitialPlayableArea"
    - you forgot to actually use group g in your init trigger and instead use GetUnitsInRectAll(rt), speaking of you should use "call GroupEnumUnitsInRect(g, r, filter)" instead
    - LoadItemHandle() instead of LoadItemHandleBJ()
    - You should implement hooks for the item creation functions to make this a true Item Indexer as others have mentioned
     
  19. NightSkyAurora

    NightSkyAurora

    Joined:
    Mar 1, 2013
    Messages:
    528
    Resources:
    8
    Models:
    4
    Spells:
    4
    Resources:
    8
    ZiBitheWand3r3r
    The TimerStart() function causes hooked functions to not work properly.

    Tank-Commander
    Thanks for all the suggestions. Now that you pointed it out, it looks rather obvious :csup:
    I'm just having trouble to get access to the last created item in the hooked function