- Joined
- Nov 11, 2006
- Messages
- 7,647
Combat State
A quick, awesome library I made to register when a unit "enters combat" or "leaves combat". The idea has been around for a while, but I haven't seen any libraries/systems for it except for this one:
http://www.thehelper.net/forums/showthread.php/91529-In-Combat-Status
Which uses CSData and PUI. So I decided to make my own, and modeled it after that library a bit, and added some other things I thought would be good.
Requirements:
Here is the code:
JASS:
library CombatState requires UnitIndexer, 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.
// - Once a unit dies, the dying unit will be taken out of combat.
// Requirements:
// -- UnitIndexer by Nestharus
// -- Event by Nestharus
// - 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.EnterCombat.register(trigger)
// - Registers when some unit enters combat after being out of combat.
// call CombatState.LeaveCombat.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:
// - Nestharus for UnitIndexer, Event, and optimizations
// - Darthfett for the original combat library
// - Vexorian for TimerUtils
//****************************************************************//
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
private module Init
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 UnitIndexer.DEINDEX.register(Condition(function thistype.deindex))
call TriggerAddCondition(t,Condition(function thistype.CombatEnter))
endmethod
endmodule
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 = GetUnitById(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 combatUnit = GetUnitById(this)
if flag then
if this.combatTimer == null then
set this.inCombatV = true
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)
elseif (this.inCombatV) then
set this.inCombatV = false
static if LIBRARY_TimerUtils then
call ReleaseTimer(this.combatTimer)
else
call PauseTimer(this.combatTimer)
call DestroyTimer(this.combatTimer)
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 then
if IsUnitEnemy(u,GetTriggerPlayer()) then
set thistype[GetTriggerUnit()].inCombat=true
set thistype[u].inCombat=true
elseif CombatState[u].inCombat then
set thistype[GetTriggerUnit()].inCombat=true
endif
endif
set u = null
return false
endmethod
private static method deindex takes nothing returns boolean
set thistype(GetIndexedUnitId()).inCombat=false
return false
endmethod
implement Init
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
endlibrary
You don't have to give credits if you use it, but credits would be nice.
JASS Usage:
The library is nice in that it works for all units, so you don't have to manually add which units you want to track combat status of.
The key function is this:
JASS:
function GetUnitCombatState takes unit whichUnit returns boolean
return CombatState[whichUnit].inCombat
endfunction
CombatState[whichUnit].inCombat
If it returns true, then the unit is in combat. If it returns false, then the unit is out of combat.
Here is an example of the usage:
JASS:
function Example takes nothing returns boolean
local unit u = GetTriggerUnit()
if GetUnitCombatState(u) then
call DisplayTextToPlayer(Player(0),0,0,"Unit is in combat!")
call SetUnitExploded(u,true)
call KillUnit(u)
else
call DisplayTextToPlayer(Player(0),0,0,"Unit is out of combat!")
call SetUnitState(u,UNIT_STATE_LIFE,GetWidgetLife(u)+500)
endif
set u = null
return false
endfunction
function InitTrig_TestSpell takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Example))
endfunction
In that example, the function registers whenever a spell is cast. If the caster is in combat, he'll be exploded and it will say "Unit is in combat!", but if he is out of combat, it will heal him for 500 hit points and say "Unit is out of combat!".
The only configurable is this:
JASS:
private constant real COMBAT_DURATION = 5
Modifying this will control how long it takes to leave combat after being in combat. However, if you enter combat it doesn't necessarily mean that you will leave combat in 5 seconds. Each time you attack or get attacked, the timer will be refreshed to 5 seconds, so you must not attack or be attacked to successfully leave combat.
You can also force a unit into or out of combat by doing this:
JASS:
set CombatState[whichUnit].inCombat = true //enter combat
set CombatState[whichUnit].inCombat = false //leave combat
JASS:
call SetUnitCombatState(whichUnit,flag)
If you use the Event Library:
If you use the Event library, then you can register when a unit enters or leaves combat. It is pretty neat. Example:
JASS:
function Example takes nothing returns boolean
if GetUnitTypeId(GetTriggerCombatUnit())=='hfoo' then
call SetUnitExploded(GetTriggerCombatUnit(),true)
call KillUnit(GetTriggerCombatUnit())
endif
return false
endfunction
function InitTrig_TestEnterCombat takes nothing returns nothing
local trigger t = CreateTrigger()
call CombatState.ENTER.registerTrigger(t)
call TriggerAddCondition(t,Condition(function Example))
endfunction
If you enter combat as a footman, it will explode you. Simple as that.
To register entering and leaving, you simply use this:
JASS:
call CombatState.ENTER.registerTrigger(t)
call CombatState.LEAVE.registerTrigger(t)
GUI Usage:
Yep, this is pretty easy to use in GUI as well.
-
Explode
-
Events
-
Unit - A unit Starts the effect of an ability
-
-
Conditions
-
(Ability being cast) Equal to Acid Bomb
-
-
Actions
-
Custom script: set udg_InCombat = GetUnitCombatState(GetTriggerUnit())
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
InCombat Equal to True
-
-
Then - Actions
-
Set TempPoint = (Position of (Triggering unit))
-
Special Effect - Create a special effect at TempPoint using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
-
Special Effect - Destroy (Last created special effect)
-
Custom script: call RemoveLocation(udg_TempPoint)
-
-
Else - Actions
-
Unit - Explode (Triggering unit)
-
-
-
-
-
Custom script: set udg_InCombat = GetUnitCombatState(GetTriggerUnit())
If you want to register when a unit enters combat, you'll have to do something along these lines.
-
AddCombatEvent
-
Events
-
Map initialization
-
-
Conditions
-
Actions
-
Set CombatTrigger = RegisterEnterCombat <gen>
-
Custom script: call CombatState.ENTER.register(udg_CombatTrigger)
-
Set CombatTrigger = RegisterLeaveCombat <gen>
-
Custom script: call CombatState.LEAVE.register(udg_CombatTrigger)
-
-
-
RegisterEnterCombat
-
Events
-
Conditions
-
Actions
-
Custom script: set udg_CombatUnit = GetTriggerCombatUnit()
-
Unit - Set life of CombatUnit to 100.00%
-
-
-
RegisterLeaveCombat
-
Events
-
Conditions
-
Actions
-
Custom script: set udg_CombatUnit = GetTriggerCombatUnit()
-
Unit - Explode CombatUnit
-
-
Demo Map:
Attached below is a demo map of the combat system. Basically, it has some nifty spells that only work if you are in combat, out of combat, or change based on whether or not you are in combat. Press ESCAPE to swap between being in combat or out of combat.
Attachments
Last edited: