1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. The Aftermath has been revealed for the 19th Terraining Contest! Be sure to check out the Results and see what came out of it.
    Dismiss Notice
  3. Melee Mapping Contest #3 - Results are out! Congratulate the winners and check plenty of new 4v4 melee maps designed for this competition!
    Dismiss Notice
  4. The winners of our cinematic soundtrack competition have been decided! Step by the Music Contest #11 - Results to check the entries and congratulate the winners!
    Dismiss Notice

Item Pickup v.4.0.1 ( vJass) // v.1.0 ( JASS )

Submitted by BPower
This bundle is marked as approved. It works and satisfies the submission rules.
Item Pickup

Automatically picks up items for an unit in a configurable radius.



    • ItemPickup vJass
    • ItemPickup JASS

    • None hero units can't pick up items of type power up.
    • If the pickup range is too large, items can't be dropped ( game constants ).
  • Code (vJASS):

    //*                                                                                                         19.06.2016
    //*                                              READ ME
    //*
    //*  ItemPickup allows units with inventory to pick up items automatically in a variable radius around its position.
    //* Of course ItemPickup is MUI, leakless and runs very smooth.
    //*
    //*  What is the optimal timer timeout for the periodic pickup loop?
    //*    o Mainly depends on your type of map. I would recommend something between 0.1 and 0.2. Requires in-game feedback.
    //*      Note: Permanent active timers over a game season, with small timeouts are perfomance killers for weaker enignes.
    //*
    //*  Important information, when dealing with items in Warcraft III:
    //*
    //*      Warcraft III doesn't remove dead items from the game automatically. It's recommended to
    //*      use a snippet to remove those items for memory management and ingame performance (rendered objects).
    //*      You can find such a snippet on TheHiveWorkshop.com in the JASS section.
    //*
    //*
    //*  ItemPickup written by BPower.
     



  • Code (vJASS):
    library ItemPickup /* Version 4.0.1
    *************************************************************************************
    *
    *   Automatically pickup items for a unit in a configurable radius.
    *
    *   The system automatically clean invalid units ( removed )
    *   from the stack. Ergo no unit cleanup from your side is required.
    *
    *   Note: The system doesn't clean powerup items and dead items!
    *         Hence you should consider to import the following snippet aswell:
    *             - ItemCleanup: hiveworkshop.com/forums/jass-resources-412/system-item-cleanup-175663/
    *
    *   If you wish to use ItemPickup on more than ~40 units during the same time,
    *   you should consider adding a Table to lower the lookup complexity
    *   on start & stop from O(n) to O(1).
    *
    *************************************************************************************
    *
    *   */
    uses /*
    *
    *       */
    optional ErrorMessage /* github.com/nestharus/JASS/tree/master/jass/Systems/ErrorMessage
    *
    **************************************************************************************
    *
    *   Import instructions:
    *   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    *       • Copy library ItemPickup into your map.
    *
    *   API:
    *   ¯¯¯¯
    *      function StartItemPickup takes unit whichUnit, real radius returns nothing
    *          • Note: The system always checks if "whichUnit" is already in the stack.
    *                  This makes the function 100% fail-safe against a double allocation.
    *
    *      function StopItemPickup takes unit whichUnit returns nothing
    *          • Does nothing on an invalid "whichUnit" argument.
    *
    **************************************************************************************/


    // User settings:
    // ==============

        globals

            // Set the timer interval in which nearby items are enumerated.
            //
            private constant real TIMER_TIMEOUT = 0.1
        endglobals
     
        // Define the item filter for picked up items
        //     • A is widget alive check is done internally.
        //
        private function FilterItem takes unit picker, item whichItem returns boolean
            return true
        endfunction
     
    //===============================================================================
    // Functions, constants and variables used by ItemPickup. Make changes carefully.
    //===============================================================================

        native UnitAlive takes unit id returns boolean

        globals
            //======================================================
            // Constants
            //

            private constant timer TIMER = CreateTimer()
     
            //======================================================
            // Variables
            //
     
            // Max index and item enum helper variable
            private integer size  = 0
            private integer temp  = -1
     
            // Array variables
            private unit array source
            private rect array square
        endglobals
     
        private function EnumItems takes nothing returns nothing
            local item i = GetFilterItem()
     
            if GetWidgetLife(i) > 0.405 and FilterItem(source[temp], i) and UnitAddItem(source[temp], i) then
            endif
     
            set i = null
        endfunction
     
        // The stack has a lookup speed of O(n).
        // This is utterly acceptable as this function is only
        // called on start and stop. If you think different, then implement a Table.
        private function Get takes unit whichUnit returns integer
            local integer index = 0
     
            loop
                exitwhen index == size
                if source[index] == whichUnit then
                    return index
                endif
                set index = index + 1
            endloop
            return -1
        endfunction

        private function Clear takes unit whichUnit returns nothing
            local integer index = Get(whichUnit)
     
            if index != -1 then
                set size = size - 1
                set source[index] = source[size]
                set square[index] = square[size]
                call RemoveRect(square[size])
                set square[size] = null
                set source[size] = null
                if size == 0 then
                    call PauseTimer(TIMER)
                endif
            endif
        endfunction

        private function OnPeriodic takes nothing returns nothing
            local integer index = 0
     
            loop
                exitwhen index == size
                if UnitAlive(source[index]) then
                    call MoveRectTo(square[index], GetUnitX(source[index]), GetUnitY(source[index]))
                    set temp = index
                    call EnumItemsInRect(square[index], null, function EnumItems)
           
                // Automatically pops invalid indexes.
                elseif GetUnitTypeId(source[index]) == 0 then
                    call Clear(source[index])
                endif
                set index = index + 1
            endloop
        endfunction

        function StartItemPickup takes unit whichUnit, real radius returns nothing

            static if LIBRARY_ErrorMessage then
                debug call ThrowWarning(GetUnitTypeId(whichUnit) == 0, "ItemPickup", "StartItemPickup", "whichUnit", 0, "Invalid unit argument ( null )!")
            endif

            call Clear(whichUnit)
            if size == 0 then
                call TimerStart(TIMER, TIMER_TIMEOUT, true, function OnPeriodic)
            endif
            set source[size] = whichUnit
            set square[size] = Rect(-radius, -radius, radius, radius)
            set size = size + 1
        endfunction

        function StopItemPickup takes unit whichUnit returns nothing
            call Clear(whichUnit)
        endfunction

    endlibrary

     
  • Code (vJASS):
    //===============================================================================
    // ItemPickup. Version 1.0
    //===============================================================================
    //
    // Automatically pickup items for a unit in a configurable radius.
    //
    // Furthermore the system automatically clean invalid units ( removed )
    // from the stack. Ergo no extra cleanup from your side is required.
    //
    // Note: ItemPickup doesn't clean powerup- and dead items!
    //       Therefore you should consider importing the following system aswell:
    //           - ItemCleanup: hiveworkshop.com/threads/item-cleanup-1-2.201057/
    //
    //   Import instructions:
    //   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    //       • Copy this trigger into your map.
    //
    //   API:
    //   ¯¯¯¯
    //       unit    udg_ItemPickup_Unit
    //                   • The unit you wish to add / remove.
    //
    //       real    udg_ItemPickup_Radius
    //                   • The desired pickup radius.
    //
    //       boolean udg_ItemPickup_AddUnit
    //                    • Determines whether the unit should be added or removed.
    //
    //       Trigger - Run ItemPickup JASS <gen> ( Ignoring/Checking conditions )
    //           • Executes your settings.
    //
    // User settings:
    // ==============

    // Set the timer interval in which nearby items are enumerated.
    //
    constant function ItemPickup_GetTimerTimeout takes nothing returns real
        return 0.1
    endfunction

    // Define the item filter for picked up items
    //     • A is widget alive check is done internally.
    //
    function ItemPickup_FilterItem takes unit picker, item whichItem returns boolean
        return true
    endfunction

    //===============================================================================
    // ItemPickup source code. Make changes carefully.
    //===============================================================================

    function ItemPickup_EnumItems takes nothing returns nothing
        local item i = GetFilterItem()
     
        if GetWidgetLife(i) > 0.405 and ItemPickup_FilterItem(udg_ItemPickup_Unit[udg_ItemPickup_Index], i) then
            call UnitAddItem(udg_ItemPickup_Unit[udg_ItemPickup_Index], i)
        endif
     
        set i = null
    endfunction

    function ItemPickup_GetIndexByUnit takes unit whichUnit returns integer
        local integer index = 0
     
        loop
            exitwhen index == udg_ItemPickup_Max
            if udg_ItemPickup_Unit[index] == whichUnit then
                return index
            endif
            set index = index + 1
        endloop
        return -1
    endfunction

    function ItemPickup_Clear takes unit whichUnit returns nothing
        local integer index = ItemPickup_GetIndexByUnit(whichUnit)
     
        if index != -1 then
            set udg_ItemPickup_Max = udg_ItemPickup_Max - 1
            set udg_ItemPickup_Unit[index] = udg_ItemPickup_Unit[udg_ItemPickup_Max]
            set udg_ItemPickup_Rect[index] = udg_ItemPickup_Rect[udg_ItemPickup_Max]
            call RemoveRect(udg_ItemPickup_Rect[udg_ItemPickup_Max])
            set udg_ItemPickup_Rect[udg_ItemPickup_Max] = null
            set udg_ItemPickup_Unit[udg_ItemPickup_Max] = null
            if udg_ItemPickup_Max == 0 then
                call PauseTimer(udg_ItemPickup_Timer)
            endif
        endif
    endfunction

    function ItemPickup_OnPeriodic takes nothing returns nothing
        local integer index = 0
     
        loop
            exitwhen index == udg_ItemPickup_Max

           // Automatically pops invalid indexes.
            if GetUnitTypeId(udg_ItemPickup_Unit[index]) == 0 then
                call ItemPickup_Clear(udg_ItemPickup_Unit[index])
     
            elseif not IsUnitType(udg_ItemPickup_Unit[index], UNIT_TYPE_DEAD) then
                call MoveRectTo(udg_ItemPickup_Rect[index], GetUnitX(udg_ItemPickup_Unit[index]), GetUnitY(udg_ItemPickup_Unit[index]))
                set udg_ItemPickup_Index = index
                call EnumItemsInRect(udg_ItemPickup_Rect[index], null, function ItemPickup_EnumItems)
            endif
            set index = index + 1
        endloop
    endfunction

    function ItemPickup_TriggerResponse takes nothing returns nothing
        call ItemPickup_Clear(udg_ItemPickup__Unit)

        if not udg_ItemPickup__AddUnit or GetUnitTypeId(udg_ItemPickup__Unit) == 0 or udg_ItemPickup__Radius < 0.00 then
            return
        endif

        if udg_ItemPickup_Max == 0 then
            call TimerStart(udg_ItemPickup_Timer, ItemPickup_GetTimerTimeout(), true, function ItemPickup_OnPeriodic)
        endif
        set udg_ItemPickup_Unit[udg_ItemPickup_Max] = udg_ItemPickup__Unit
        set udg_ItemPickup_Rect[udg_ItemPickup_Max] = Rect(-udg_ItemPickup__Radius, -udg_ItemPickup__Radius, udg_ItemPickup__Radius, udg_ItemPickup__Radius)
        set udg_ItemPickup_Max = udg_ItemPickup_Max + 1
    endfunction

    //===========================================================================
    function InitTrig_Item_Pickup_JASS takes nothing returns nothing
        set gg_trg_Item_Pickup_JASS = CreateTrigger()
        call TriggerAddAction(gg_trg_Item_Pickup_JASS, function ItemPickup_TriggerResponse)
    endfunction
     
    • Demo Map
      • Events
        • Map initialization
      • Conditions
      • Actions
        • Custom script: set bj_wantDestroyGroup = true
        • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
          • Loop - Actions
            • Set ItemPickup__Unit = (Picked unit)
            • Set ItemPickup__Radius = 50.00
            • Set ItemPickup__AddUnit = True
            • Trigger - Run Item Pickup JASS <gen> (checking conditions)



Final note:
Warcraft III doesn't remove dead items from the game automatically. It's recommended to
use a snippet to remove those items for memory management and ingame performance ( rendered objects ).
You can find such a snippet on TheHiveWorkshop.com in the JASS section ( link ) or for GUI'ers here in the spell section. ( link )

Keywords:
GUI, vJass, Item, pickup, pick , up, system, auto, atuomatic, autoitem, itemsystem, itempickup,
autopickup
Contents

ItemPickup (Map)

Reviews
Moderator
23:38, 26th Nov 2013 Maker: This is a cool system and it is coded well
  1. 23:38, 26th Nov 2013
    Maker: This is a cool system and it is coded well
     
  2. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    why JASS? :(

    well, this could be useful for anyone who is too lazy just to do right clicks.. :p
     
  3. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    The API is designed very easy even for GUI only users, it just requires JNPG. Everything is explained inside the demo map. No need to cry :)

    Because it is much faster, even if one is capable of doing miracles in GUI .
     
    Last edited: Apr 20, 2015
  4. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    no cry, just sad :(

    hey, why the autopick range is not configurable?
     
  5. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    It is. Start the system for a unit with any radius.
    Code (vJASS):
        function StartAutoPickUp takes unit u, real radius returns nothing
            call AutoPickUp.start(u, radius)
        endfunction

    or in GUI. Note 50 is the radius, therefore the pickup range will be 100.
    • Custom script: call StartAutoPickUp(udg_TESTER, 50.)
     
  6. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    so, you can set a different radius for each unit?
     
  7. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Exactly.
     
  8. Quilnez

    Quilnez

    Joined:
    Oct 12, 2011
    Messages:
    3,169
    Resources:
    37
    Icons:
    2
    Tools:
    1
    Maps:
    7
    Spells:
    21
    Tutorials:
    2
    JASS:
    4
    Resources:
    37
    convert it to GUI and I will approve this..
    <<MODERATOR
     
  9. Zeatherann

    Zeatherann

    Joined:
    Nov 25, 2008
    Messages:
    1,303
    Resources:
    6
    Skins:
    1
    Tools:
    1
    Maps:
    4
    Resources:
    6
    Interesting that is written in vJASS and not JASS. I might create my own JASS version then.
     
  10. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,500
    Resources:
    17
    Maps:
    1
    Spells:
    10
    Tutorials:
    6
    Resources:
    17
    hm, either it just seems like a long code or you got more features than I can see.

    basicly I would loop and then detect items within X range. The range would be stored in a real array variable. Use with with an indexer and its really simple.

    3/5

    I think this could be done very easy in vjass aswell.
    this.radius = argument. done
     
  11. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    If you can make it shorter and provide the same speed, then I bow to you.
    But you won't :grin:
     
  12. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,193
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    Chaosy, to me the code looks quite short. A lot of it is the indexing/linked list.

    He is looping through a list of units, and picking units within a square. Each unit has it's own search distance.
     
  13. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,500
    Resources:
    17
    Maps:
    1
    Spells:
    10
    Tutorials:
    6
    Resources:
    17
    I dont know vjass very well. So I dont really read the code. I just imagined it to be shorter considering how I would have done it in GUI.

    but recycle index is quite complex (atleast to me xD) so I guess the code isnt very long then.
     
  14. Zeatherann

    Zeatherann

    Joined:
    Nov 25, 2008
    Messages:
    1,303
    Resources:
    6
    Skins:
    1
    Tools:
    1
    Maps:
    4
    Resources:
    6
    Hmm... I'm tempted to try to write a shorter same speed/or faster version in pain ol'e JASS.
     
  15. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,500
    Resources:
    17
    Maps:
    1
    Spells:
    10
    Tutorials:
    6
    Resources:
    17
    I made a GUI version out of boredom.

    It currently work ok but I know it have some flaws. Like if unit dies the hashtable still contains data which I could potentionaly reset but I am too lazy :p
    here it is anyway.
    triggers

    • init
      • Events
        • Map initialization
      • Conditions
      • Actions
        • Hashtable - Create a hashtable
        • Set hash = (Last created hashtable)
        • Set u = Paladin 0001 <gen>
        • Set range = 100.00
        • Trigger - Run Set Range <gen> (ignoring conditions)

    • Set Range
      • Events
      • Conditions
      • Actions
        • Unit Group - Add u to group
        • Custom script: call SaveReal( udg_hash, GetHandleId(udg_u), 1, udg_range )

    • loop
      • Events
        • Time - Every 0.20 seconds of game time
      • Conditions
        • (Number of units in group) Greater than 0
      • Actions
        • Unit Group - Pick every unit in group and do (Actions)
          • Loop - Actions
            • Set u = (Picked unit)
            • Set u_loc = (Position of u)
            • Custom script: set udg_range = LoadReal( udg_hash, GetHandleId(udg_u), 1 )
            • Item - Pick every item in (Playable map area) and do (Actions)
              • Loop - Actions
                • Set item_loc = (Position of (Picked item))
                • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • (Distance between item_loc and u_loc) Less than or equal to range
                    • Or - Any (Conditions) are true
                      • Conditions
                        • (Item-class of (Picked item)) Equal to Powerup
                        • (Item carried by u in slot 1) Equal to No item
                        • (Item carried by u in slot 2) Equal to No item
                        • (Item carried by u in slot 3) Equal to No item
                        • (Item carried by u in slot 4) Equal to No item
                        • (Item carried by u in slot 5) Equal to No item
                        • (Item carried by u in slot 6) Equal to No item
                  • Then - Actions
                    • Hero - Give (Picked item) to u
                  • Else - Actions
                • Custom script: call RemoveLocation(udg_item_loc)
            • Custom script: call RemoveLocation(udg_u_loc)


    please do not comment to much on those triggers it is not meant to be a perfect final released prodct. Then I would have submited it as a resource.
    http://www.hiveworkshop.com/forums/pastebin.php?id=rrsam1

    NOTE: that this is only for GUIers who want to learn how it works or needs to modify the system but doesnt know vJASS. Else I strongly suggest you use the original system.
     
    Last edited: Dec 2, 2013
  16. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    First of all, nice to see this system caught your interest :thumbs_up:

    The code has some serious issues, but I'll respect your please.

    What can't stay uncommented are two things:
    1. If the group is empty the timer isn't stopped.
    2. Power Up items can be picked up with full inventory.

    Just for the GUI community I didn't use List or SharedList or Alloc as requirement. And UnitIndexer is a must have in my eyes.
    Also the API is easy to understand.

    The reason such resources should be vJass and use a linked list is, because they are "passive" resources. They don't add any eyecandy to the game.
    Therefore they must run as silent and undetectable as possible.
    GUI just cannot provide the speed that vJass or JASS have, not only because it generates redundant lines of code.
     
  17. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,500
    Resources:
    17
    Maps:
    1
    Spells:
    10
    Tutorials:
    6
    Resources:
    17
    1. oh yeah, I can fix that.
    2. not a big deal will fix that too.

    I highly dislike arrays since they make code fugly. Else I would have gone with an unit indexer instead of an hashtable.

    And I don't question the functions and advantages of vjass. If I made it in C# I would have used an list but GUI doesnt have it so yeah.

    edit: done
     
  18. BPower

    BPower

    Joined:
    Mar 18, 2012
    Messages:
    1,745
    Resources:
    21
    Spells:
    15
    Tutorials:
    1
    JASS:
    5
    Resources:
    21
    Better but the trigger has to be turned off when the group is empty and turned on when the first unit is added to the group.
    Also you picked every item in playable map area every 0.2 seconds for each unit in the group. That's not effective, especially in really big maps.

    Your skript won't work the way it is, because items are not removed on death.
    Example: You kill a claw of attack +15 item. Then you walk over it with your skript on. You will find that item in your inventory. If you use a tome of strength + 2. It will die, but not beeing removed. Aslong as you stay on that position every 0.2 seconds a tome of strenght +2 will be added to your hero.

    Another thing
    • Item - Pick every item in (Playable map area) and do (Actions)
      • Loop - Actions
    Mistakenly you think this is a short and clean piece of code. Actually it is:
    Code (vJASS):
    function PickItemInPlayable takes nothing returns nothing
        call EnumItemsInRectBJ( GetPlayableMapRect(), function action)
    endfunction
    function EnumItemsInRectBJ takes rect r, code actionFunc returns nothing
        call EnumItemsInRect(r, null, actionFunc)
    endfunction
    function GetPlayableMapRect takes nothing returns rect
        return bj_mapInitialPlayableArea
    endfunction


    In my code it is only:
    Code (vJASS):
    call SetRect(TEMP, x - .rad, y - .rad, x + .rad, y + .rad)
    call EnumItemsInRect(TEMP, null, function thistype.pick)//thistype. is used when dealing with methods instead of functions

    And I use a very small rect --> the actually pickup rect.
     
  19. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,149
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Why are these in your settings area if you don't want users to touch them? lol..

    Code (vJASS):

            private rect TEMP               = Rect(0,0,0,0)//Don't touch this
            private timer TMR               = CreateTimer()//Don't touch this. Used timer.
     


    Just figured that I'd point that out. Maybe you want to move that down into your actual code :p.