- Joined
- Sep 26, 2009
- Messages
- 9,521
CargoEvent was inspired by the methods in Jesus4Lyf's Transport and grim001's AutoEvents. Originally, this was just meant to be an efficient, UnitIndexer-compatible build, but during testing I found everything having to do with the unload-detection had to be redone to compensate for some crazy errors that abound in the other two transport libraries.
JASS:
library CargoEvent requires UnitIndexer
/*
CargoEvent by Bribe, v1.1.0.0
Working on this library has been quite educational. During the process,
I found the existing detection in Jesus4Lyf's "Transport" and grim001's
"AutoEvents" needed to be remade.
Those libraries move the unit to the edge of the map. What about Bound-
Sentinel, which knocks them back into bounds? This fires the unload event
prematurely. Don't use BoundSentinel? What about a unit that is loaded
while in the process of being knocked-back? That screws it up as well.
I've tried debugging this by setting the unit's position out of bounds a
second time, but it strangely won't re-fire the event. And BoundSentinel
would cause an infinite loop even if it worked. Time for a new method.
On top of that, A recursion bug in the other systems that can cause big
problems - a load order at the same time a unit is unloaded.
This library fixes those bugs but factors in other considerations:
1. Units must be indexed by UnitIndexer (have a unique ID)
2. Units paused while loaded on a transport will not be issued a stop
order when they are unloaded, so I have implemented a safety catch
that unpauses units when they are paused in-transit. If you do not
want this check (or don't have any risk of this happening in your
map), set PAUSE_SAFETY to false.
API
struct CargoEvent extends array
Event LOAD
> Fires when a passenger is loaded into a transport.
Event UNLOAD
> Fires when a passenger is unloaded from a transport.
readonly integer transport
> The unit-id of this unit's transport.
function GetUnitTransport takes unit passenger returns unit
> returns the unit carrying the passenger.
function GetEventLoadedUnit
> returns the passenger that was loaded/unloaded.
function GetEventTransportUnit takes nothing returns unit
> returns the transport loading/unloading the passenger.
*/
native UnitAlive takes unit id returns boolean
globals
private boolean array block
private constant boolean PAUSE_SAFETY = true
endglobals
private module Init
private static method onInit takes nothing returns nothing
local boolexpr l = Filter(function thistype.unload)
static if PAUSE_SAFETY then
local boolexpr p = Filter(function thistype.unpause)
endif
local integer i = 15
local trigger t = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_LOADED, null)
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, l)
static if PAUSE_SAFETY then
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, p)
endif
exitwhen i == 0
set i = i - 1
endloop
call TriggerAddCondition(t, Filter(function thistype.load))
set LOAD = Event.create()
set UNLOAD = Event.create()
set t = null
set l = null
static if PAUSE_SAFETY then
set p = null
endif
endmethod
endmodule
struct CargoEvent extends array
readonly static Event LOAD = 0
readonly static Event UNLOAD = 0
readonly integer transport
private static method unload takes nothing returns boolean
local thistype this = GetUnitId(GetFilterUnit())
if this.transport != 0 and not block[this] and not (IsUnitLoaded(GetUnitById(this)) and UnitAlive(GetUnitById(this))) then
/*
How this works:
1. Ignore units that aren't currently loaded.
2. Check for recursion so as to not double-fire the event (if
a unit is loaded at the same time it was unloaded)
3. A stop order is issued by a unit when it's unloaded.
4. Ensure the unit was not ordered to stop while loaded.
5. A unit fires the unload event when it dies in-transit.
*/
set block[this] = true
call UNLOAD.fireData(this)
set block[this] = false
if not (IsUnitLoaded(GetUnitById(this)) and UnitAlive(GetUnitById(this.transport))) then
// Also recursion-safe
set this.transport = 0
endif
endif
return false
endmethod
private static method load takes nothing returns boolean
local thistype this = GetUnitId(GetTriggerUnit())
set this.transport = GetUnitId(GetTransportUnit())
call LOAD.fireData(this)
return false
endmethod
static if PAUSE_SAFETY then
private static method unpause takes nothing returns boolean
if IsUnitLoaded(GetFilterUnit()) and IsUnitPaused(GetFilterUnit()) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 99, "CargoEvent Safety: A passenger was paused in-transit and is now being un-paused to ensure proper unload-detection.")
call PauseUnit(GetFilterUnit(), false)
endif
return false
endmethod
endif
implement Init
endstruct
function GetUnitTransport takes unit passenger returns unit
return GetUnitById(CargoEvent(GetUnitId(passenger)).transport)
endfunction
function GetEventLoadedUnit takes nothing returns unit
return GetUnitById(GetEventData())
endfunction
function GetEventTransportUnit takes nothing returns unit
return GetUnitById(CargoEvent(GetEventData()).transport)
endfunction
endlibrary
- 1.1.0.0 - Added optional PAUSE_SAFETY to protect against bugs.
- 1.0.1.0 - Optimized the boolean checks, merged the "order" and "load" triggers into one.
- 1.0.0.0 - Public release
Last edited: