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