PurgeandFire
zxcvmkgdfg
- Reaction score
- 509
Combat State
It is a quick, awesome library that allows units to enter and leave combat, and allows you to register it.
It is based off of Darthfett's library, which is sadly outdated:
http://www.thehelper.net/forums/showthread.php/91529-In-Combat-Status
So I decided to make one, and I added a few features.
Basically, if you attack something with your unit or get attacked by an opposing player, you enter combat. To leave combat, your unit must not be attacked and must not attack anyone for COMBAT_DURATION, which is default 5 seconds.
Requirements:
- Event - Jesus4Lyf
- AIDS - Jesus4Lyf
- OPTIONAL: TimerUtils
If you have TimerUtils, it will recycle timers. If you don't have TimerUtils, then it will use hashtable attachment and destroy/create timers each time a unit enters combat.
Code:
JASS:
library CombatState requires AIDS, Event, optional TimerUtils
//******** COMBAT STATE ******************************************//
// - This library registers whether or not some unit is in combat.
// - To be registered as in combat, the unit must attack or have been attacked by an enemy unit.
// - Any spell that is cast by an opposing player onto the unit will flag them as in combat.
// - Being in combat only lasts a specific duration, in this case 5 seconds, before the unit leaves combat.
// Requirements:
// -- AIDS by Jesus4Lyf
// -- Event by Jesus4Lyf
// - This will allow you to register when a unit enters or leaves combat.
// -- *OPTIONAL* TimerUtils by Vexorian
// - This will recycle timers instead of creating/destroying them, so it is a bit more optimal. As far as speed goes,
// it is pretty negligible. Without TimerUtils, it will use a hashtable.
// API:
// Configurables:
// - COMBAT_DURATION: This determines the time before a unit is considered to be out of combat, default 5 seconds.
// The unit must remain unattacked and attack no one for COMBAT_DURATION to leave combat.
// Data Modify/Retrieve:
// CombatState[whichUnit].inCombat -> returns boolean
// set CombatState[whichUnit].inCombat = flag
// Function Wrappers:
// function GetUnitCombatState takes unit whichUnit returns boolean
// - This returns the combat state of a unit. If it returns true, the unit is in combat. If it returns false, then the unit
// is not in combat.
// function SetUnitCombatState takes unit whichUnit, boolean flag returns nothing
// - This allows you to force a unit in or out of combat, and it will register the corresponding events.
// If you are using Event:
// call CombatState.ENTER.register(trigger)
// - Registers when some unit enters combat after being out of combat.
// call CombatState.LEAVE.register(trigger)
// - Registers when some unit leaves combat after having been just in combat.
// function GetTriggerCombatUnit takes nothing returns unit
// - When using registering an event, this will basically return the unit who entered or left combat. GetTriggerCombatUnit()
// Credits:
// - Jesus4Lyf for Event and AIDS
// - Darthfett for the original combat library
// - Vexorian for TimerUtils
// - Nestharus for optimizations
//****************************************************************//
globals
private constant real COMBAT_DURATION = 5
//**************DO NOT EDIT PAST THIS POINT***********************//
private unit combatUnit = null
private hashtable Hash
endglobals
function GetTriggerCombatUnit takes nothing returns unit
return combatUnit
endfunction
struct CombatState extends array
private timer combatTimer
private boolean inCombatV
readonly static Event LEAVE = 0
readonly static Event ENTER = 0
static method operator [] takes unit u returns thistype
return GetUnitUserData(u)
endmethod
private static method CombatLeave takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit prev = combatUnit
static if LIBRARY_TimerUtils then
local integer id = GetTimerData(t)
call ReleaseTimer(t)
else
local integer id = LoadInteger(Hash,GetHandleId(t),0)
call PauseTimer(t)
call DestroyTimer(t)
set t = null
endif
set combatUnit = GetIndexUnit(id)
set thistype(id).inCombatV = false
set thistype(id).combatTimer = null
call thistype.LEAVE.fire()
set combatUnit = prev
set prev = null
endmethod
method operator inCombat takes nothing returns boolean
return this.inCombatV
endmethod
method operator inCombat= takes boolean flag returns nothing
local unit prev = combatUnit
set this.inCombatV = flag
set combatUnit = GetIndexUnit(this)
if flag then
if this.combatTimer == null then
call thistype.ENTER.fire()
static if LIBRARY_TimerUtils then
set this.combatTimer = NewTimer()
call SetTimerData(this.combatTimer,this)
else
set this.combatTimer = CreateTimer()
call SaveInteger(Hash,GetHandleId(this.combatTimer),0,this)
endif
endif
call TimerStart(this.combatTimer,COMBAT_DURATION,false,function thistype.CombatLeave)
else
if this.combatTimer != null then
static if LIBRARY_TimerUtils then
call ReleaseTimer(this.combatTimer)
else
call PauseTimer(this.combatTimer)
call DestroyTimer(this.combatTimer)
endif
endif
set this.combatTimer = null
call thistype.LEAVE.fire()
endif
set combatUnit = prev
set prev = null
endmethod
private static method CombatEnter takes nothing returns boolean
local unit u = GetAttacker()
if GetTriggerEventId()==EVENT_PLAYER_UNIT_DEATH then
set thistype[GetTriggerUnit()].inCombat=false
return false
elseif u == null then
set u = GetSpellTargetUnit()
endif
if u != null and IsUnitEnemy(u,GetTriggerPlayer()) then
set thistype[GetTriggerUnit()].inCombat=true
set thistype<u>.inCombat=true
endif
set u = null
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
static if not LIBRARY_TimerUtils then
set Hash = InitHashtable()
endif
set thistype.ENTER = Event.create()
set thistype.LEAVE = Event.create()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_ATTACKED)
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t,Condition(function thistype.CombatEnter))
endmethod
endstruct
function GetUnitCombatState takes unit whichUnit returns boolean
return CombatState[whichUnit].inCombat
endfunction
function SetUnitCombatState takes unit whichUnit, boolean flag returns nothing
set CombatState[whichUnit].inCombat = flag
endfunction
function TriggerRegisterEnterCombat takes trigger t returns nothing
call CombatState.ENTER.register(t)
endfunction
function TriggerRegisterLeaveCombat takes trigger t returns nothing
call CombatState.LEAVE.register(t)
endfunction
endlibrary</u>
Usage:
The documentation should explain most of it, but here is the main API:
JASS:
set CombatState[whichUnit].inCombat = flag //force unit in/out of combat
call CombatState.ENTER.register(whichTrigger) //register enter combat
call CombatState.LEAVE.register(whichTrigger) //register leave combat
call TriggerRegisterEnterCombat(whichTrigger) //wrapper for above
call TriggerRegisterLeaveCombat(whichTrigger) //wrapper for above
call SetUnitCombatState(whichUnit,flag) //force unit in/out of combat, wrapper
call GetUnitCombatState(whichUnit) //retrieves whether or not a unit is in combat
call GetTriggerCombatUnit() //triggering unit corresponding to the combat events
When creating a trigger and registering an enter or leave event, the unit corresponding to the event can be found by using GetTriggerCombatUnit().
Example of Usage:
JASS:
function Example takes nothing returns boolean
if GetUnitTypeId(GetTriggerCombatUnit())==039;hfoo039; then //if the combat unit is a footman
call SetUnitExploded(GetTriggerCombatUnit(),true) //explode him
call KillUnit(GetTriggerCombatUnit())
endif
return false
endfunction
function InitTrig_TestEnterCombat takes nothing returns nothing
local trigger t = CreateTrigger()
call CombatState.ENTER.register(t) //register a unit entering combat
call TriggerAddCondition(t,Condition(function Example))
endfunction
You don't have to give credits if you use this in your map, but you can if you want.
Attached below is a demo map that features some spells that change based on whether or not you are in combat. You can press ESCAPE to force-swap whether you are in or out of combat. You automatically leave combat after 5 seconds.
Enjoy.