• 🏆 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 Pickup v.4.0.1 ( vJass) // v.1.0 ( JASS )

Item Pickup

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


Available versions

Limitations

Manual


  • 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 ).
JASS:
//*                                                                                                         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.


ItemPickup vJass

ItemPickup JASS

ItemPickup GUI Demo

JASS:
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
JASS:
//===============================================================================
// 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
23:38, 26th Nov 2013 Maker: This is a cool system and it is coded well

Moderator

M

Moderator

23:38, 26th Nov 2013
Maker: This is a cool system and it is coded well
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
hey, why the autopick range is not configurable?

It is. Start the system for a unit with any radius.
JASS:
    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.)
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,182
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
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,182
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.

  • 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:
Level 19
Joined
Mar 18, 2012
Messages
1,716
First of all, nice to see this system caught your interest :thumbs_up:

please do not comment to much on those triggers
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.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,182
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
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
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.

  • 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:
JASS:
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:
JASS:
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.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Just figured that I'd point that out. Maybe you want to move that down into your actual code :p.
I agree. I'll update it later.

updated: Also changed the demo unit back to a Paladin instead of a footman. Updated documentation aswell.

udpated again: Added TimerUtils as optional requirement. (10.12.2013)

udpated again: Can now use any UnitIndexer for instance Bribes GUI version by replacing GetUnitId with GetUnitUserData. (26.12.2013)

udpated (14.03.2014)
Changelog:
  • Split the code into a light and normal version. MoveRectTo(..) seems to be ~50% faster than SetRect(..). In conclusion the light version is ~50% slower than the normal version, but uses only 1 rect.
  • Replaced static unit u with static thistype index.
  • The code looks much cleaner now.
 
Last edited:
Level 17
Joined
Nov 13, 2006
Messages
1,814
only to me have problem? when i tested in normal we and press is esc then paladin dont pick up anything, when try press esc again then say its running but acctually hero just stand, then i typed stop and pressed esc still nothing happened
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
What is new:
  • Improved the debug only code of all versions.
  • Added a Table version supporting Bribes & Vexorians Table (No UnitIndexer needed)
  • Added a version, which does not use any requirements.
  • Added a GUI version. (Easy to setup and use)
  • Mentioned GUI version is mainly written with custom script and performs only slightly worse than the vJass versions.
  • Removed the code from the description and added a manual instead.
  • Reading the manual will help you to find the perfect of all uploaded versions for your map.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
JASS:
private static method pk takes nothing returns nothing
            local item i = GetFilterItem()
            if (FilterItem(i)) and (GetWidgetLife(i) > .405) then
                call UnitAddItem(index.u, i)
            endif
            set i = null
        endmethod

Warcraft3 doesn't remove dead items from the game automatically.

Why not separate the checks and remove the item yourself?

JASS:
private static method pk takes nothing returns nothing
            local item i = GetFilterItem()
            if GetWidgetLife(i) > .405 then
                if FilterItem(i) then
                    call UnitAddItem(index.u, i)
                endif
            else
                call RemoveItem(i)
            endif
            set i = null
        endmethod
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Good question :).

First of all it should look like this:
JASS:
if FilterItem(i) and IsItemPowerup(i) then
    call SetWidgetLife(i, 1.00)
    call RemoveItem(i)
endif

I used this on previous versions of AutoPickUp.
However items objects also have death animations, by removing them you will not play
an items death animation (eventually).
That's why I removed that part from the code.

There are snippets, which remove dead items periodically after playing the death animation.
They estimate a death animation time and remove the item after it. For example after 1.5 seconds.
 
Level 6
Joined
Aug 19, 2014
Messages
72
I got a problem, when I enable the Auto Pickup No Requirements trigger, it's say "The trigger "Auto Pickup No Requirements" must have an initialization function called "InitTrig_Auto_Pickup_No_Requirements".
How can I fix that. And I don't know how to filter which item-type to be picked up. Can you give me an example how to filter more than 2 item-types. 'Cause I don't know much about Jass.

btw, this system's very useful for me. Thank you.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Update:

The previous version ( v.3.3 ) worked flawless. No need to update to v.4.0 in you map.
It's more a cosmetic update than bug fixing.


Changelog:

1. Replaced the linked list structure with a stack ( less memory allocated, more speed )
2. No longer in a struct ( there was no reason for . syntax )
3. Lookup complexity on start and stop is now O(n), before it was O(1) using a Table.

Reason: Normally start and stop are not called frequently ( stop maybe never ).
In case your map demands a better performance ( many units use this system ),
you can replace the loop with a Table to load/save the stack index per unit.


I got a problem, when I enable the Auto Pickup No Requirements trigger, it's say "The trigger "Auto Pickup No Requirements" must have an initialization function called "InitTrig_Auto_Pickup_No_Requirements".
You can ignore that message. Everything is fine :)
And I don't know how to filter which item-type to be picked up. Can you give me an example how to filter more than 2 item-types. 'Cause I don't know much about Jass.
You're still struggling with this issue? You don't need JASS knowledge for that.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I am just now seeing this resource for the first time. Here's my feedback:

Use one rect and use SetRect to the radius for each unit each loop instead of MoveRectTo. It won't slow things down enough to have 2 extra parameters and 4 arithmatic operations per unit to justify the huge difference in generated handles.

Can I make a GUI version of this? I need something to do ;)
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Use one rect and use SetRect to the radius for each unit each loop instead of MoveRectTo. It won't slow things down enough to have 2 extra parameters and 4 arithmatic operations per unit to justify the huge difference in generated handles.
The previous version ( 3.3 ) there was two types on this library in the demo map.
One with SetRect and one with 1 rect per units.

Back then I've run benchmark tests on SetRect vs MoveRect and MoveRect ( thead page 2 ) using Sharpcraft and the StopWatch native.
Turned out MoveRect is faster than SetRect. As it is a periodically running system, I've chosen the memory unfriendly but faster way.
udpated (14.03.2014)
Changelog:
Split the code into a light and normal version. MoveRectTo(..) seems to be ~50% faster than SetRect(..). In conclusion the light version is ~50% slower than the normal version, but uses only 1 rect.

I can add the 1 rect version to the demo map.

Can I make a GUI version of this? I need something to do ;)
There is also GUI version in the demo map. ( Actually it's mainly JASS / custom script )
You can see the code in tab 2 - 4 in the map description on the first page of the thread. :)
Btw, that one uses SetRect.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Oh man, those tabs can be confusing. I didn't even see that there were other triggers there.

Why in the vJass version do you filter out level 2 items? Is it just an example? I think the system should not auto-pick up tomes by default in case the wrong unit accidentally picked up the tome, though that's easy enough to set for the user on a per-map basis.

Why not use GUI Unit Indexer so that you can make removal O(1)? You can also then auto-add units to the system who have the hero inventory ability on behalf of the user.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Why in the vJass version do you filter out level 2 items? Is it just an example?
Yes it just serves as an example.

I think the system should not auto-pick up tomes by default in case the wrong unit accidentally picked up the tome, though that's easy enough to set for the user on a per-map basis
I guess the map maker can add that condition to the FilterItem function.
By default the system just filters out dead item.

Why not use GUI Unit Indexer so that you can make removal O(1)? You can also then auto-add units to the system who have the hero inventory ability on behalf of the user.
I had a UnitIndexer version uploaded before ( something v 3.1 ). I removed it in this version.
It's nearly the same like using a Table and saving the stack index on GetUnitHandlId.
Personally I'm a fan of UnitIndexers, but only for systems which significantly improve when
using such an indexer.

I agree, that if you frequently register/unregister units to ItemPickup, you'll need an indexer + array or a Table instance.

I like ItemPickup as simple as it is now. UnitIndexer or Table, both can be implemented with just a little change in the code.

So far I saw this system in pratical usage twice:
1. In the map I'm working on, which is close to the RPG genre.
2. In Glideon from Quilnez, which can be compared to Super Mario Kart.

Both examples do not need fast performing start & stop functions.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
I replaced the in custom script written GUI version with a clean JASS script.
Yet it's still very easy to use and import for GUI coders.

There are two function for user settings at the head of the ItemPick JASS library.
Don't forget to edit them to your needs.

A proper GUI demo has been added to the attached map.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Here is a Lua version of this resource:

Lua:
OnGlobalInit(function() AutoPickup = {}
--Item Pickup by BPower, converted to Lua by Bribe and renamed to AutoPickup.
--Version 1.0
 
--Requires:
--Global Initialization: https://www.hiveworkshop.com/threads/global-initialization.317099/
--Timed Call and Echo:   https://www.hiveworkshop.com/threads/timed-call-and-echo.339222/
--Linked List:           https://www.hiveworkshop.com/threads/definitive-doubly-linked-list.339392/
 
-- User settings:
-- ==============
    
    local _TIMEOUT  = 0.1   -- How frequently (in seconds) to check for nearby items.
    local _RADIUS   = 128   -- How wide a net to cast around the unit looking for items.
    local rect      = Rect(-_RADIUS,-_RADIUS,_RADIUS,_RADIUS)
    local getX      = GetUnitX
    local getY      = GetUnitY
    local alive     = UnitAlive
    local getId     = GetUnitTypeId
    local moveRect  = MoveRectTo
    local getItems  = EnumItemsInRect
    local getItem   = GetEnumItem
    local getLife   = GetWidgetLife
    local addItem   = UnitAddItem
 
    ---@param u unit
    ---@return boolean added
    function AutoPickup.start(u)
        if not AutoPickup[u] then
            AutoPickup[u] = Timed.echo(function()
                if alive(u) then
                    moveRect(rect, getX(u), getY(u))
                    getItems(rect, nil, function()
                        local i = getItem() ---@type item
                        if getLife(i) > 0.405 then
                            --one can add further comparisons above to rule out specific items.
                            addItem(u, i)
                        end
                    end)
                elseif getId(u) == 0 then
                    AutoPickup[u] = nil
                    return true
                end
            end, _TIMEOUT)
            return true
        end
    end
 
    ---@param u unit
    ---@return boolean removed
    function AutoPickup.stop(u)
        if AutoPickup[u] then
            AutoPickup[u]:remove()
            AutoPickup[u] = nil
            return true
        end
    end
end)
[/code
 
I can't get the Vjass Version to work. I think something with the increment and decrement of size and index is wrong. It seems to think that the source unit array is empty and pause the timer, even if I add multiple units to it. Size never gets bigger than 1. No matter how many units I add.

I just ran it using
JASS:
call StartItemPickup(some_unit, 64.0)

The normal jass version works for me, so will use that for now.
 
Top