| 04-26-2009, 11:59 AM | #1 |
My goal is to create a function that prevents aggro from 0 damage events. The problem with it is, that units can attack nearby enemies without having the "attack", "smart" or "patrol" order. The following code is what I got so far. JASS:// Max Creep Camp Range is set to 1 to avoid other creeps coming to help globals private constant integer DisableId = 'Abun' private unit tempU endglobals private function Callback takes unit u returns nothing call UnitRemoveAbility(u,DisableId) endfunction private function IsUnitSelectedFilter takes nothing returns boolean return IsUnitSelected(tempU,GetFilterPlayer())==true endfunction private function StopAggression takes unit u returns nothing local player p = GetOwningPlayer(u) local force f = CreateForce() local integer i = GetUnitCurrentOrder(u) if (i==851974 or i==851971 or i==851972 or i==851990 or i==851993 or i==0) then if (GetPlayerId(p)>12) then call UnitAddAbility(u,DisableId) call Callback.execute(u) else call SyncSelections() set tempU = u call ForceEnumAllies(f,p,Filter(function IsUnitSelectedFilter)) if (CountPlayersInForceBJ(f)<1) then call UnitAddAbility(u,DisableId) call Callback.execute(u) endif endif endif call DestroyForce(f) set f = null endfunction Therefore my question: Is there anyway to check what a unit is currently doing, especially if it is attacking anything? If you have any other suggestions to improve my code please post them aswell. |
| 04-26-2009, 12:38 PM | #2 |
When units start to attack nearby enemies by themselves they trigger the EVENT_UNIT_ACQUIRED_TARGET event. When they disengage because they're lured too far away from their idle spot then they get a move order. You can use these two events to determine if a unit is in combat. Sometimes a unit also disengages without using the move order... then you'd have to check periodically if its current order is "idle". I wrote a little script that stores information like this and also adds interface functions for several important events that have to do with combat behavior but I haven't really tested it enough to recommend it yet. If you're interested I can pm you my current results though. |
| 04-26-2009, 02:37 PM | #3 |
Sounds definitely interesting, I'd love to get that PM. Already tried to use the approach you suggested. JASS:library UnitInCombat initializer Init uses AutoIndex globals private boolean array IsUnitInCombat private unit array UnitTarget private constant integer DisableId = 'Abun' endglobals function GetUnitCombatState takes unit u returns boolean return GetUnitId(u):IsUnitInCombat endfunction private function Callback takes unit u returns nothing call UnitRemoveAbility(u,DisableId) endfunction function MakeUnitDisengage takes unit u returns nothing local integer i = GetUnitId(u) call UnitAddAbility(u,DisableId) call Callback.execute(u) set i:IsUnitInCombat = false set i:UnitTarget = null debug call MsgFadingText(u, 255, 255, 255, GetUnitName(u)+" was forced to disengage") endfunction private struct instance private static trigger T1 private static trigger T2 private static method isMoveOrder takes nothing returns boolean return GetIssuedOrderId()==851986 endmethod private static method onDisengage takes nothing returns nothing local unit u = GetTriggerUnit() local integer i = GetUnitId(u) if (i:IsUnitInCombat==true) then set i:IsUnitInCombat = false debug call MsgFadingText(u, 255, 255, 255, GetUnitName(u)+" disengaged battle") endif endmethod private static method onAcquire takes nothing returns nothing local unit u = GetTriggerUnit() local integer i = GetUnitId(u) local unit target = GetEventTargetUnit() set i:UnitTarget = target //************************************** // Here's the culprit // call TriggerSleepAction(0.) //************************************** if (target==i:UnitTarget) then set i:IsUnitInCombat = true debug call MsgFadingText(u, 255, 255, 255, GetUnitName(u)+" engaged battle") endif endmethod private static method unitEntersMap takes unit u returns nothing debug call BJDebugMsg("a unit was registered") set GetUnitId(u):IsUnitInCombat = false call TriggerRegisterUnitEvent(thistype.T1,u,EVENT_UNIT_ACQUIRED_TARGET) // this should be okay, since I'm going to use a UnitRecycler call TriggerRegisterUnitEvent(thistype.T2,u,EVENT_UNIT_ISSUED_POINT_ORDER) // " endmethod implement UnitEntersMap private static method onInit takes nothing returns nothing set thistype.T1 = CreateTrigger() set thistype.T2 = CreateTrigger() call TriggerAddAction(thistype.T1,function thistype.onAcquire) call TriggerAddAction(thistype.T2,function thistype.onDisengage) call TriggerAddCondition(thistype.T2,Condition(function thistype.isMoveOrder)) call .initUnitEntersMap() endmethod endstruct endlibrary Works, looks nice, but has a flaw I'd like to get rid off. I currently use a TriggerSleepAction within the onAcquire method to allow the user to force disengage the unit before the unit is detected as engaging. So I'm still hoping for suggestions on code improvement. |
