- Joined
- Feb 27, 2019
- Messages
- 401
Hello,
You may know the following abilities:
- Orb of Slow (AIsb)
- Orb of Lightning (AIll)
- Attack black arrow bonus (AIdf)
- Melee Lightning Damage Bonus (AIlx)
They are similar, and allow you to make normal attacks have a chance of casting any ability with a target. Pretty cool no ?
However they have a known weird issue (bug from Blizzard) in which, you didn't ordered the owner of the ability to do something, and even if you have put the chance to cast the ability to 100%, it will never fire.
So I have been working on a "work-around" fix for this matter. After hours and hours of experimenting and programming, I got a detailed analysis and a custom fix that works !! It is MUI and I tested it OK with all the cases I thought of (patrol, hold position, attack, smart, move, guard-position consistence...)
What do you think of the coding ? May it be usefull for other players ? Should I provide a minimal map for players to download & install from ?
Detailed analysis:
How to use:
When you create a unit with the bugged ability, or when a unit learns the bugged ability, just call RegisterUnitForOosFix(<unit>). My code handles the rest (target aquisition, improper orders handle, unit death...).
Triggers:
OosFix RegisterUnit (JASS API function)
OosFix UnregisterUnit (JASS API function. Automatically called for non-hero dead units and removed units)
OosFix UnitIssuedOrder (GUI, disabled as default)
OosFix UnitTargetAcquisition (GUI, disabled as default)
OosFix HoldPositionResume (GUI, disabled as default)
OosFix UnitDeath (GUI, disabled as default)
OosFix UnitRemoved (GUI, disabled as default)
You may know the following abilities:
- Orb of Slow (AIsb)
- Orb of Lightning (AIll)
- Attack black arrow bonus (AIdf)
- Melee Lightning Damage Bonus (AIlx)
They are similar, and allow you to make normal attacks have a chance of casting any ability with a target. Pretty cool no ?
However they have a known weird issue (bug from Blizzard) in which, you didn't ordered the owner of the ability to do something, and even if you have put the chance to cast the ability to 100%, it will never fire.
So I have been working on a "work-around" fix for this matter. After hours and hours of experimenting and programming, I got a detailed analysis and a custom fix that works !! It is MUI and I tested it OK with all the cases I thought of (patrol, hold position, attack, smart, move, guard-position consistence...)
What do you think of the coding ? May it be usefull for other players ? Should I provide a minimal map for players to download & install from ?
Detailed analysis:
First impressions
The ability only casts when players manually gave one of the following orders:
- Order targeting an object (unit): smart (right-click), attack
- Order targeting a point (any point, but order must not be over): attack ground, attack-move, patrol
Test cases (logging last order issued & current order)
OK - Unit is on patrol, and engages a target: lastevent=patrol, currentorder=_
OK - Unit is still doing an attack position order: lastevent=attack, currentorder=attack
OK - Unit is attacking an unit because of an attack or smart order: lastevent=attack/smart, currentorder=attacks/mart (both are identical)
KO - Unit is holding position: lastevent=holdposition, currentorder=_
KO - Unit aquires a new target, and was stopped before: lastevent=stop, current=_
KO - Unit aquires a new target, and last order was irrelevant (learn skill, use skill, etc...): lastevent=****, current=_
KO - Unit finished an attack position, smart or move order; then aquires a target: lastevent=attack/smart/move, currentorder=_
KO - Unit finished an attack or smart order (the unit died or became invisible/invincible), and aquires a new one: lastevent=smart/attack, currentorder = _
The ability only casts when players manually gave one of the following orders:
- Order targeting an object (unit): smart (right-click), attack
- Order targeting a point (any point, but order must not be over): attack ground, attack-move, patrol
Test cases (logging last order issued & current order)
OK - Unit is on patrol, and engages a target: lastevent=patrol, currentorder=_
OK - Unit is still doing an attack position order: lastevent=attack, currentorder=attack
OK - Unit is attacking an unit because of an attack or smart order: lastevent=attack/smart, currentorder=attacks/mart (both are identical)
KO - Unit is holding position: lastevent=holdposition, currentorder=_
KO - Unit aquires a new target, and was stopped before: lastevent=stop, current=_
KO - Unit aquires a new target, and last order was irrelevant (learn skill, use skill, etc...): lastevent=****, current=_
KO - Unit finished an attack position, smart or move order; then aquires a target: lastevent=attack/smart/move, currentorder=_
KO - Unit finished an attack or smart order (the unit died or became invisible/invincible), and aquires a new one: lastevent=smart/attack, currentorder = _
How to use:
When you create a unit with the bugged ability, or when a unit learns the bugged ability, just call RegisterUnitForOosFix(<unit>). My code handles the rest (target aquisition, improper orders handle, unit death...).
Triggers:
OosFix RegisterUnit (JASS API function)
JASS:
function RegisterUnitForOosFix takes unit u returns nothing
// Add to registered units
call GroupAddUnitSimple( u, udg_OosFixRegisteredUnits )
// Unit is issued order events
if ( IsTriggerEnabled( gg_trg_OosFix_UnitIssuedOrder ) == false ) then
call EnableTrigger( gg_trg_OosFix_UnitIssuedOrder )
endif
call TriggerRegisterUnitEvent( gg_trg_OosFix_UnitIssuedOrder, u, EVENT_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterUnitEvent( gg_trg_OosFix_UnitIssuedOrder, u, EVENT_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterUnitEvent( gg_trg_OosFix_UnitIssuedOrder, u, EVENT_UNIT_ISSUED_ORDER )
// Unit acquires target event
if ( IsTriggerEnabled( gg_trg_OosFix_UnitTargetAcquisition ) == false ) then
call EnableTrigger( gg_trg_OosFix_UnitTargetAcquisition )
endif
call TriggerRegisterUnitEvent( gg_trg_OosFix_UnitTargetAcquisition, u, EVENT_UNIT_ACQUIRED_TARGET )
// Unit dies
if ( IsTriggerEnabled( gg_trg_OosFix_UnitDeath ) == false ) then
call EnableTrigger( gg_trg_OosFix_UnitDeath )
endif
call TriggerRegisterUnitEvent( gg_trg_OosFix_UnitDeath, u, EVENT_UNIT_DEATH )
// Unit leaves map
if ( IsTriggerEnabled( gg_trg_OosFix_UnitLeaveMap ) == false ) then
call EnableTrigger( gg_trg_OosFix_UnitLeaveMap )
endif
endfunction
OosFix UnregisterUnit (JASS API function. Automatically called for non-hero dead units and removed units)
JASS:
function UnregisterUnitForOosFix takes unit u returns nothing
// Flush datas from the hashtable
call FlushChildHashtableBJ( GetHandleIdBJ(u), udg_GameCache )
// Remove from the hold position resume group
if ( IsUnitInGroup(u, udg_OosFixHoldPositionResumeGroup) == true ) then
call GroupRemoveUnitSimple( u, udg_OosFixHoldPositionResumeGroup )
endif
// Remove from registered units
call GroupRemoveUnitSimple( u, udg_OosFixRegisteredUnits )
// If it was the last unit, pause the system
if ( IsUnitGroupEmptyBJ(udg_OosFixRegisteredUnits) == true ) then
call DisableTrigger( gg_trg_OosFix_UnitIssuedOrder )
call DisableTrigger( gg_trg_OosFix_UnitTargetAcquisition )
call DisableTrigger( gg_trg_OosFix_HoldPositionResume )
call DisableTrigger( gg_trg_OosFix_UnitDeath )
call DisableTrigger( gg_trg_OosFix_UnitLeaveMap )
endif
endfunction
OosFix UnitIssuedOrder (GUI, disabled as default)
-
OosFix UnitIssuedOrder
-
Events
-
Conditions
-
Actions
-
Set TempBoolean = True
-
-------- Patrol order is ignored if distance is too short, because no action was taken by the unit --------
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
(String((Issued order))) Equal to patrol
-
-
Then - Actions
-
Set TempPoint = (Position of (Ordered unit))
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
(Distance between TempPoint and (Target point of issued order)) Less than 100.00
-
-
Then - Actions
-
Set TempBoolean = False
-
-
Else - Actions
-
Do nothing
-
-
-
Custom script: call RemoveLocation(udg_TempPoint)
-
-
Else - Actions
-
Do nothing
-
-
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
TempBoolean Equal to True
-
-
Then - Actions
-
Hashtable - Save (String((Issued order))) as (Key UnitIssuedOrder) of (Key (Ordered unit)) in GameCache
-
-
Else - Actions
-
Do nothing
-
-
-
-
OosFix UnitTargetAcquisition (GUI, disabled as default)
-
OosFix UnitTargetAcquisition
-
Events
-
Conditions
-
Actions
-
-------- Retrieve unit issued order --------
-
Set TempString1 = <Empty String>
-
Set TempString1 = (Load (Key UnitIssuedOrder) of (Key (Triggering unit)) from GameCache)
-
-------- Case A: unit was forced back to holdposition, but re-acquires a target --------
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
TempString1 Equal to holdpositionforced
-
-
Then - Actions
-
Trigger - Turn off OosFix UnitIssuedOrder <gen>
-
-------- Attack-move in place: preserves guard position. --------
-
Set TempPoint = (Position of (Triggering unit))
-
Unit - Order (Triggering unit) to Attack-Move To TempPoint
-
Custom script: call RemoveLocation(udg_TempPoint)
-
Trigger - Turn on OosFix UnitIssuedOrder <gen>
-
Unit Group - Add (Triggering unit) to OosFixHoldPositionResumeGroup
-
Trigger - Turn on OosFix HoldPositionResume <gen>
-
Hashtable - Save holdposition as (Key UnitIssuedOrder) of (Key (Triggering unit)) in GameCache
-
-
Else - Actions
-
Do nothing
-
-
-
-------- Case B: hold position order is under execution --------
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
TempString1 Equal to holdposition
-
-
Then - Actions
-
-------- Wait for the end of this acquisition, then reload variable to ensure MUI --------
-
Wait 0.01 seconds
-
Set TempString1 = <Empty String>
-
Set TempString1 = (Load (Key UnitIssuedOrder) of (Key (Triggering unit)) from GameCache)
-
Trigger - Turn off OosFix UnitIssuedOrder <gen>
-
-------- Force back to hold position. Cancels previous acquisition. --------
-
Unit - Order (Triggering unit) to Hold Position
-
Trigger - Turn on OosFix UnitIssuedOrder <gen>
-
Hashtable - Save holdpositionforced as (Key UnitIssuedOrder) of (Key (Triggering unit)) in GameCache
-
-
Else - Actions
-
Do nothing
-
-
-
-------- Case C: no order under execution for the moment --------
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
TempString1 Not equal to patrol
-
TempString1 Not equal to holdposition
-
TempString1 Not equal to holdpositionforced
-
(String((Current order of (Triggering unit)))) Equal to <Empty String>
-
-
Then - Actions
-
Trigger - Turn off OosFix UnitIssuedOrder <gen>
-
-------- Attack-move in place: preserves guard position. Do not change acquisition. --------
-
Set TempPoint = (Position of (Triggering unit))
-
Unit - Order (Triggering unit) to Attack-Move To TempPoint
-
Custom script: call RemoveLocation(udg_TempPoint)
-
Trigger - Turn on OosFix UnitIssuedOrder <gen>
-
-
Else - Actions
-
-
-------- Case DEFAULT: no change, preserves orders under-execution. --------
-
-------- Else: string(UnitIssuedOrder) == "patrol" or (string(UnitIssuedOrder) != "holdposition" string(current order) != <string vide>) --------
-
-
OosFix HoldPositionResume (GUI, disabled as default)
-
OosFix HoldPositionResume
-
Events
-
Time - Every 0.01 seconds of game time
-
-
Conditions
-
Actions
-
Unit Group - Pick every unit in OosFixHoldPositionResumeGroup and do (Actions)
-
Loop - Actions
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
((Picked unit) is dead) Equal to True
-
-
Then - Actions
-
-------- Remove dead units from checks --------
-
Unit Group - Remove (Picked unit) from OosFixHoldPositionResumeGroup
-
-
Else - Actions
-
Set TempString1 = <Empty String>
-
Set TempString1 = (Load (Key UnitCurrentOrder) of (Key (Picked unit)) from GameCache)
-
Set TempString2 = <Empty String>
-
Set TempString2 = (Load (Key UnitIssuedOrder) of (Key (Picked unit)) from GameCache)
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
TempString1 Equal to (String((Current order of (Picked unit))))
-
-
Then - Actions
-
-------- Current order is unchanged since last check, do nothing --------
-
Do nothing
-
-
Else - Actions
-
-------- Save the new current order value --------
-
Hashtable - Save (String((Current order of (Picked unit)))) as (Key UnitCurrentOrder) of (Key (Picked unit)) in GameCache
-
-------- Case A: last issued order is hold position (normal or forced), and current order changes from something else to idle --------
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
TempString1 Not equal to holdposition
-
Or - Any (Conditions) are true
-
Conditions
-
TempString2 Equal to holdposition
-
TempString2 Equal to holdpositionforced
-
-
-
(String((Current order of (Picked unit)))) Equal to <Empty String>
-
-
Then - Actions
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
TempString2 Equal to holdpositionforced
-
-
Then - Actions
-
Hashtable - Save holdposition as (Key UnitIssuedOrder) of (Key (Picked unit)) in GameCache
-
-
Else - Actions
-
Do nothing
-
-
-
Trigger - Turn off OosFix UnitIssuedOrder <gen>
-
-------- Force back to hold position. --------
-
Unit - Order (Picked unit) to Hold Position
-
Trigger - Turn on OosFix UnitIssuedOrder <gen>
-
Unit Group - Remove (Picked unit) from OosFixHoldPositionResumeGroup
-
-
Else - Actions
-
Do nothing
-
-
-
-
-
-
-
-
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
(OosFixHoldPositionResumeGroup is empty) Equal to True
-
-
Then - Actions
-
Trigger - Turn off (This trigger)
-
-
Else - Actions
-
Do nothing
-
-
-
-
OosFix UnitDeath (GUI, disabled as default)
-
OosFix UnitDeath
-
Events
-
Conditions
-
((Triggering unit) is A Hero) Equal to False
-
-
Actions
-
-------- Non-hero units cannot be revived, clear variables --------
-
Custom script: call UnregisterUnitForOosFix( GetTriggerUnit() )
-
-
OosFix UnitRemoved (GUI, disabled as default)
-
OosFix UnitRemoved
-
Events
-
Unit - A unit leaves (Entire map)
-
-
Conditions
-
((Triggering unit) is in OosFixRegisteredUnits) Equal to True
-
-
Actions
-
Custom script: call UnregisterUnitForOosFix( GetTriggerUnit() )
-
-
Last edited: