- Joined
- Sep 19, 2005
- Messages
- 169
Could someone write this script for me? Also, in my game their point value is set to their gold cost. It would be nice that even if a transport is full, that if a player clicked to load unit x and unit x was more expensive than unit y, it would take unit y's spot in the transport. You would get credit and I would implement the code and release a new version of the map on bnet right away.
StatusEvents is already used in my map, this would probably be useful.
StatusEvents is already used in my map, this would probably be useful.
JASS:
library StatusEvents requires AutoIndex
//===========================================================================
// Information:
//==============
//
// StatusEvents is an add-on library for AutoIndex. It gives you events that
// detect the following things: when units resurrect, when units are raised with
// Animate Dead, when units begin reincarnating, when units finish reincarnating,
// when transports load units, and when transports unload units. It also provides
// other useful functions: you can check if a unit is currently raised with Ani-
// mate Dead, get the transport carrying a unit, get the number of a units in a
// transport, get the passenger in a specific slot of a transport, and enumerate
// through all of the units in a transport.
//
//===========================================================================
// How to use StatusEvents:
//==========================
//
// You can use the events in this library to run specific functions when
// an event occurs. Unit-related events require a function matching the Stat-
// usEvent function interface, and transport-related events require a function
// matching the TransportEvent function interface:
//
// function interface StatusEvent takes unit u returns nothing
// function interface TransportEvent takes unit transport, unit passenger returns nothing
//
// The following examples use the StatusEvents function interface:
//
// function UnitDies takes unit u returns nothing
// call BJDebugMsg(GetUnitName(u)+" has died.")
// endfunction
//
// function UnitResurrects takes unit u returns nothing
// call BJDebugMsg(GetUnitName(u)+" has been resurrected.")
// endfunction
//
// function Init takes nothing returns nothing
// call OnUnitDeath(UnitDies)
// call OnUnitResurrect(UnitResurrects)
// endfunction
//
// And the following examples use the TransportEvents function interface:
//
// function UnitLoads takes unit transport, unit passenger returns nothing
// call BJDebugMsg(GetUnitName(transport)+" loaded +"GetUnitName(passenger))
// endfunction
//
// function UnitUnloads takes unit transport, unit passenger returns nothing
// call BJDebugMsg(GetUnitName(transport)+" unloaded +"GetUnitName(passenger))
// endfunction
//
// function Init takes nothing returns nothing
// call OnUnitLoad(UnitLoads)
// call OnUnitUnload(UnitUnloads)
// endfunction
//
// Here is an example of using ForPassengers to enumerate each unit in
// a transport and heal them for 100 life:
//
// function HealPassenger takes unit transport, unit passenger returns nothing
// call SetWidgetLife(passenger, GetWidgetLife(passenger) + 100.)
// endfunction
// function HealAllPassengers takes unit transport returns nothing
// call ForPassengers(transport, HealPassenger)
// endfunction
//
// GetPassengerBySlot provides an alternative way to enumerate the
// units within a transport. (The following example would heal a unit
// that occupies multiple slots in the transport only one time, since
// GetPassengerBySlot assumes that each unit occupies only one slot.)
//
// function HealAllPassengers takes unit transport returns nothing
// local integer slot = 1 //Start at slot 1.
// local unit passenger
// loop
// set passenger = GetPassengerBySlot(transport, slot)
// exitwhen passenger == null
// SetWidgetLife(passenger, GetWidgetLife(passenger) + 100.)
// set slot = slot + 1
// endloop
// endfunction
//
//===========================================================================
// StatusEvents API:
//===================
//
// OnUnitDeath(StatusEvent)
// This event runs when any unit dies. It fires after the unit is dead, but
// before any death triggers fire.
//
// OnUnitResurrect(StatusEvent)
// This event runs when any unit is resurrected. It also fires when units
// are raised with Animate Dead or Reincarnation, as those are forms of
// resurrection as well.
//
// OnUnitAnimateDead(StatusEvent)
// This event runs when any unit is raised with Animate Dead. It fires after
// the resurrection event.
//
// IsUnitAnimateDead(unit) -> boolean
// This function returns a boolean that indicates if the specified unit
// has been raised with Animate Dead.
//
// OnUnitReincarnateStart(StatusEvent)
// This event runs when any unit begins reincarnating. The OnUnitDeath event
// will run first.
//
// OnUnitReincarnateEnd(StatusEvent)
// This event runs when any unit finishes reincarnating. The OnUnitResurrect
// event will occur immediately after.
//
// OnUnitLoad(TransportEvent)
// This event runs when any transport loads a passenger.
//
// OnUnitUnload(TransportEvent)
// This event runs when any transport unloads a passenger.
//
// GetUnitTransport(unit)
// Returns the transport that a unit is loaded in. Returns null if the
// unit is not riding in any transport.
//
// CountPassengers(transport) -> integer
// Returns the number of passengers in the specified transport.
//
// GetPassengerBySlot(transport, slot) -> unit
// Returns the passenger in the given slot of the specified transport.
// However, if a unit takes more than one transport slot, it will only be
// treated as occupying one transport slot.
//
// ForPassengers(transport, TransportEvent)
// This function runs a TransportEvent immediately for each passenger in
// the specified transport.
//
//===========================================================================
function interface StatusEvent takes unit u returns nothing
function IsUnitAnimateDead takes unit u returns boolean
return AutoIndex.isUnitAnimateDead(u)
endfunction
//===========================================================================
//! textmacro RunStatusEvent takes EVENT
set n = 0
loop
exitwhen n > $EVENT$funcs_n
call $EVENT$funcs[n].evaluate(u)
set n = n + 1
endloop
//! endtextmacro
//Injecting this textmacro into AutoIndex will cause the events to actually run.
//===========================================================================
//! textmacro StatusEvent takes EVENT, EVENTTYPE
globals
$EVENTTYPE$ array $EVENT$funcs
integer $EVENT$funcs_n = -1
endglobals
function OnUnit$EVENT$ takes $EVENTTYPE$ func returns nothing
set $EVENT$funcs_n = $EVENT$funcs_n + 1
set $EVENT$funcs[$EVENT$funcs_n] = func
endfunction
//! endtextmacro
//Instantiate the function to register events of each type.
//! runtextmacro StatusEvent("Death", "StatusEvent")
//! runtextmacro StatusEvent("Resurrect", "StatusEvent")
//! runtextmacro StatusEvent("AnimateDead", "StatusEvent")
//===========================================================================
//The code below this point adds Reincarnation support to StatusEvents.
//Credit to ToukoAozaki for the idea behind this detection method.
//! runtextmacro StatusEvent("ReincarnationStart", "StatusEvent")
//! runtextmacro StatusEvent("ReincarnationFinish", "StatusEvent")
//Create registration functions for reincarnation start and stop events.
globals
private timer ReincarnateTimer = CreateTimer()
private boolean array Reincarnated
private unit array Reincarnating
private integer Reincarnating_N = -1
endglobals
private function OnResurrect takes unit u returns nothing
local integer index = GetUnitId(u)
local integer n
if Reincarnated[index] then
set Reincarnated[index] = false
//If a resurrecting unit is flagged as reincarnating,
//it's time to run the ReincarnationFinish event.
//! runtextmacro RunStatusEvent("ReincarnationFinish")
endif
endfunction
private function ReincarnateCheck takes nothing returns nothing
local integer n = Reincarnating_N
local unit u
loop
exitwhen n < 0
set u = Reincarnating[n]
if IsUnitIndexed(u) and Reincarnated[GetUnitId(u)] then
//If the unit is still flagged as reincarnating, it means DeathDetect didn't run.
//The unit is actually reincarnating, so run the ReincarnationStart event.
//! runtextmacro RunStatusEvent("ReincarnationStart")
endif
set Reincarnating[n] = null
set n = n - 1
endloop
set Reincarnating_N = -1
set u = null
endfunction
private function OnDeath takes unit u returns nothing
set Reincarnated[GetUnitId(u)] = true
//Assume any unit that dies is going to reincarnate, unless this
//flag is set to false later by the DeathDetect function.
set Reincarnating_N = Reincarnating_N + 1 //Add the dying unit to a stack and
set Reincarnating[Reincarnating_N] = u //check the flag 0. seconds later.
call TimerStart(ReincarnateTimer, 0., false, function ReincarnateCheck)
endfunction
private function DeathDetect takes nothing returns boolean
set Reincarnated[GetUnitId(GetTriggerUnit())] = false
return false //Set the Reincarnated flag to false if the unit will not reincarnate.
endfunction
private function OnEnter takes unit u returns nothing
set Reincarnated[GetUnitId(u)] = false
//When a unit enters the map, initialize its Reincarnated flag to false.
endfunction
private struct ReincarnationInit extends array
private static method onInit takes nothing returns nothing
local trigger deathdetect = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(deathdetect, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(deathdetect, function DeathDetect)
//This trigger runs 0. seconds after OnUnitDeath events,
//but does not fire if the unit is going to Reincarnate.
call OnUnitIndexed(OnEnter)
call OnUnitDeath(OnDeath)
call OnUnitResurrect(OnResurrect)
endmethod
endstruct
//===========================================================================
//All of the remaining code deals with transports.
function interface TransportEvent takes unit transport, unit passenger returns nothing
function GetUnitTransport takes unit u returns unit
return Transport.getUnitTransport(u)
endfunction
function CountPassengers takes unit transport returns integer
return Transport.countPassengers(transport)
endfunction
function GetPassengerBySlot takes unit transport, integer slot returns unit
return Transport.getPassengerBySlot(transport, slot)
endfunction
function ForPassengers takes unit transport, TransportEvent func returns nothing
call Transport.forPassengers(transport, func)
endfunction
//===========================================================================
//! runtextmacro StatusEvent("Load", "TransportEvent")
//! runtextmacro StatusEvent("Unload", "TransportEvent")
//Create registration functions for load and unload events.
//! textmacro TransportUnloadCheck
if GetIssuedOrderId() == 851972 and Transport.loadedin[GetUnitId(GetTriggerUnit())] != null then
call Transport.unloadUnit(GetTriggerUnit())
endif
//! endtextmacro
//If the unit recieves a stop order while loaded in a transport, it was unloaded.
//! textmacro TransportUnload
if Transport.loadedin[index] != null then
call Transport.unloadUnit(u)
endif
//! endtextmacro
//! textmacro TransportClean
if Transport.transports[index] != 0 then
call Transport.transports[index].destroy()
set Transport.transports[index] = 0
endif
//! endtextmacro
//Injecting these textmacros into AutoIndex will cause the events to actually run.
//! textmacro RunTransportEvent takes EVENT
set n = 0
loop
exitwhen n > $EVENT$funcs_n
call $EVENT$funcs[n].evaluate(transport, passenger)
set n = n + 1
endloop
//! endtextmacro
//The above textmacro is used to run the Load/Unload events in the Transport struct below.
//===========================================================================
//A transport struct is created and attached to any unit detected loading another unit.
//It keeps track of the units within a transport and updates when they load or unload.
struct Transport
static Transport array transports
static unit array loadedin
private static integer array loadedindex
private static group array groups
private static integer groups_n = -1
private unit array loaded[10] //Transports can only carry 10 units.
private integer loaded_n = -1
//===========================================================================
static method getUnitTransport takes unit u returns unit
return loadedin[GetUnitId(u)]
endmethod
static method countPassengers takes unit transport returns integer
return transports[GetUnitId(transport)].loaded_n + 1
endmethod
//===========================================================================
static method getPassengerBySlot takes unit transport, integer slot returns unit
if slot < 1 or slot > 10 then
return null
endif
return transports[GetUnitId(transport)].loaded[slot - 1]
endmethod
static method forPassengers takes unit transport, TransportEvent func returns nothing
local Transport this = transports[GetUnitId(transport)]
local integer n = 0
if loaded_n == -1 then
return //Return if transport has no units loaded inside.
endif
loop
exitwhen n > loaded_n
call func.evaluate(transport, loaded[n])
//Loop through each passenger and call the TransportEvent func on it.
set n = n + 1
endloop
endmethod
//===========================================================================
static method loadUnit takes unit transport, unit passenger returns nothing
local Transport this = transports[GetUnitId(transport)]
local integer n
if this == 0 then //If this is the first time this transport has loaded a unit...
set this = allocate() //allocate a Transport struct,
set transports[GetUnitId(transport)] = this //and attach it to the unit.
endif
set loaded_n = loaded_n + 1 //Increment the passenger counter.
set loaded[loaded_n] = passenger //Put the passenger in the unit array.
set loadedindex[GetUnitId(passenger)] = loaded_n //Attach the index to the passenger.
set loadedin[GetUnitId(passenger)] = transport //Attach the transport struct to the transport.
//! runtextmacro RunTransportEvent("Load")
endmethod //Run the OnUnitLoad events.
static method unloadUnit takes unit passenger returns nothing
local unit transport = GetUnitTransport(passenger) //Get the transport unit.
local Transport this = transports[GetUnitId(transport)] //Get the transport struct.
local integer n = loadedindex[GetUnitId(passenger)] //Get the passenger's index.
loop
exitwhen n == loaded_n
set loaded[n] = loaded[n + 1]
set loadedindex[GetUnitId(loaded[n])] = n
set n = n + 1 //Starting from the position of the removed unit,
endloop //shift everything down by one and update the index.
set loaded[n] = null
set loaded_n = loaded_n - 1 //Decrement the passenger counter.
set loadedin[GetUnitId(passenger)] = null //Null the unloaded unit's transport.
//! runtextmacro RunTransportEvent("Unload")
set transport = null //Run the OnUnitUnload events.
endmethod
//===========================================================================
private static method load takes nothing returns boolean
call loadUnit(GetTransportUnit(), GetTriggerUnit())
return false //When a unit loads another unit, run the loadUnit method.
endmethod
private static method onInit takes nothing returns nothing
local trigger load = CreateTrigger()
local integer i = 15
loop
exitwhen i < 0
call TriggerRegisterPlayerUnitEvent(load, Player(i), EVENT_PLAYER_UNIT_LOADED, function AutoIndex_UnitFilter)
set i = i - 1
endloop
call TriggerAddCondition(load, function Transport.load)
//AutoIndex will handle calling the unloadUnit method when necessary, so an unload trigger is not needed here.
set Transport(0).loaded_n = -1 //Initialize this to -1 to make the CountUnitsInTransport
endmethod //function work on null and non-transport units.
endstruct
endlibrary