Hello there, just a quick code to help people trying to catch when a building with root ability is actually rooted / uprooted.
To be honest, detecting an uproot is really straightforward as the effect is immediate.
But catching when a building has finished re-rooting is more complex.
After a long chat with people on Disocrd (I added names to the first line of code), we realized that the root ability changes the unit's boolean field called "UNIT_BF_IS_A_BUILDING".
So, by starting a repeating timer, with an interval that does not need to be too small (I chose 0.3s but it could be slower), we will be checking if the unit is considered a building again.
We also need to intercept all other orders the building is given after the root order, as it cancels it.
Lua VERSION
Add this function in your map script or in a Custom Script, and add your actions where the comments say
"Do SOMETHING WITH YOUR ____ BUILDING u", your building being saved in the local variable u.
vJass VERSION, added by @SwissDerd
Same here, just add the script in your map and replace the related comments with your actions, knowing the building is saved in the local variable u
GUI VERSION, added by @crunch
- First you have to create a global unit variable in your Trigger Editor, called ROOT_UNIT.
- Then you need a slightly altered version of the script. Chose the scripting language according to your map Options. Just create a new Custom Script to put it in or add it to the main map script by clicking your map name on top of the triggers in the list.
Once done, create 2 triggers :
- one called UprootTrigger,. In there, add Conditions and Actions you want to run when the building is UPROOTED
- a second one called RootTrigger. In there ,add Conditions and Actions you want to run when the building is ROOTED
Important : remember to use ROOT_UNIT instead of Triggering Unit in your conditions and actions in these 2 triggers.
Thats all.
I have attached an example map made by @crunch to demonstrate this with the map scripting language set to Lua (but the vJass version works identically).
TypeScript VERSION, added by @Boar
- Posted by himself in the first comment.
To be honest, detecting an uproot is really straightforward as the effect is immediate.
But catching when a building has finished re-rooting is more complex.
After a long chat with people on Disocrd (I added names to the first line of code), we realized that the root ability changes the unit's boolean field called "UNIT_BF_IS_A_BUILDING".
So, by starting a repeating timer, with an interval that does not need to be too small (I chose 0.3s but it could be slower), we will be checking if the unit is considered a building again.
We also need to intercept all other orders the building is given after the root order, as it cancels it.
Lua VERSION
Add this function in your map script or in a Custom Script, and add your actions where the comments say
"Do SOMETHING WITH YOUR ____ BUILDING u", your building being saved in the local variable u.
Lua:
-- Initial idea by Macadamia
-- Credits for suggestions that made this possible (alphabetical order) : Boar, Jim-panse, spellweaver, SwissDerd, Templarfreak, Zed
function ManageRoot()
local upRoot, reRoot = CreateTrigger(), CreateTrigger()
for i = 1, GetPlayers() do
local p = Player(i-1)
if (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING) then
TriggerRegisterPlayerUnitEvent(upRoot, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, nil)
TriggerRegisterPlayerUnitEvent(reRoot, p, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, nil)
end
end
TriggerAddCondition(upRoot, Condition(function()
if (GetIssuedOrderId() == OrderId("unroot")) then
local u = GetOrderedUnit()
-- DO SOMETHING WITH YOUR UPROOTED UBUILDING u
end
return false
end))
TriggerAddCondition(reRoot, Condition(function()
if (GetIssuedOrderId() == OrderId("root")) then
local u, t, cancel = GetOrderedUnit(), CreateTimer(), CreateTrigger()
TriggerRegisterUnitEvent(cancel, u, EVENT_UNIT_ISSUED_ORDER)
TriggerRegisterUnitEvent(cancel, u, EVENT_UNIT_ISSUED_POINT_ORDER)
TriggerRegisterUnitEvent(cancel, u, EVENT_UNIT_ISSUED_TARGET_ORDER)
TriggerAddCondition(cancel, Condition(function()
-- We need to destroy the timer and cancel trigger, they will be re created on next "root" order
PauseTimer(t)
DestroyTimer(t)
DisableTrigger(cancel)
DestroyTrigger(cancel)
end))
TimerStart(t, 0.3, true, function()
if not u then
PauseTimer(t)
DestroyTimer(t)
DisableTrigger(cancel)
DestroyTrigger(cancel)
elseif BlzGetUnitBooleanField(u, UNIT_BF_IS_A_BUILDING) then
PauseTimer(t)
DestroyTimer(t)
DisableTrigger(cancel)
DestroyTrigger(cancel)
-- DO SOMETHING WITH YOUR RE-ROOTED BUILDING u
end
end)
end
return false
end))
end
OldInitBlizzard = InitBlizzard
InitBlizzard = function()
OldInitBlizzard()
ManageRoot()
end
vJass VERSION, added by @SwissDerd
Same here, just add the script in your map and replace the related comments with your actions, knowing the building is saved in the local variable u
vJASS:
// Initial idea by Macadamia
// Credits for suggestions that made this possible (alphabetical order) : Boar, Jim-panse, spellweaver, SwissDerd, Templarfreak, Zed
// Code converted to vJass by SwissDerd
library ManageRoot initializer Init
globals
private trigger UprootTrig = CreateTrigger()
private trigger RootTrig = CreateTrigger()
private hashtable Table = InitHashtable()
endglobals
private function OnUproot takes nothing returns nothing
local unit u
if (GetIssuedOrderId()== OrderId("unroot")) then
set u = GetTriggerUnit()
//
// Do whatever you want with the uprooted building u
//
endif
endfunction
private function OnCancel takes nothing returns nothing
local trigger trig = GetTriggeringTrigger()
local integer id = GetHandleId(trig)
local unit u = LoadUnitHandle(Table, id, 0)
local timer t = LoadTimerHandle(Table, id, 1)
if (t != null) then
call FlushChildHashtable(Table, id)
call FlushChildHashtable(Table, GetHandleId(u))
call FlushChildHashtable(Table, GetHandleId(t))
call PauseTimer(t)
call DestroyTimer(t)
call DisableTrigger(trig)
call DestroyTrigger(trig)
endif
set trig = null
set u = null
set t = null
endfunction
private function OnUpdate takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
local unit u = LoadUnitHandle(Table, id, 0)
local trigger cancelTrig
if (u == null) then
set cancelTrig = LoadTriggerHandle(Table, id, 1)
call FlushChildHashtable(Table, id)
call FlushChildHashtable(Table, GetHandleId(cancelTrig))
call FlushChildHashtable(Table, GetHandleId(u))
call PauseTimer(t)
call DestroyTimer(t)
call DisableTrigger(cancelTrig)
call DestroyTrigger(cancelTrig)
else if BlzGetUnitBooleanField(u, UNIT_BF_IS_A_BUILDING) then
set cancelTrig = LoadTriggerHandle(Table, id, 1)
call FlushChildHashtable(Table, id)
call FlushChildHashtable(Table, GetHandleId(cancelTrig))
call FlushChildHashtable(Table, GetHandleId(u))
call PauseTimer(t)
call DestroyTimer(t)
call DisableTrigger(cancelTrig)
call DestroyTrigger(cancelTrig)
//
// Do whatever you want with your rooted building u
//
endif
set t = null
set u = null
set cancelTrig = null
endfunction
private function OnRoot takes nothing returns nothing
local unit u
local timer t
local trigger cancelTrig
local integer id
if (GetIssuedOrderId() == OrderId("root")) then
set u = GetTriggerUnit()
set id = GetHandleId(u)
if (not LoadBoolean(Table, id, 0)) then
call SaveBoolean(Table, id, 0, true)
set cancelTrig = CreateTrigger()
set t = CreateTimer()
set id = GetHandleId(t)
call SaveUnitHandle(Table, id, 0, u)
call SaveTriggerHandle(Table, id, 1, cancelTrig)
call TimerStart(t, 0.30, true, function OnUpdate)
set id = GetHandleId(cancelTrig)
call SaveUnitHandle(Table, id, 0, u)
call SaveTimerHandle(Table, id, 1, t)
call TriggerRegisterUnitEvent(cancelTrig, u, EVENT_UNIT_ISSUED_ORDER)
call TriggerRegisterUnitEvent(cancelTrig, u, EVENT_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterUnitEvent(cancelTrig, u, EVENT_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddCondition(cancelTrig, Condition(function OnCancel))
endif
endif
set u = null
set t = null
set cancelTrig = null
endfunction
private function Init takes nothing returns nothing
local integer i = 0
loop
if (GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING) then
call TriggerRegisterPlayerUnitEvent(UprootTrig, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
call TriggerRegisterPlayerUnitEvent(RootTrig, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
endif
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(UprootTrig, Condition(function OnUproot))
call TriggerAddCondition(RootTrig, Condition(function OnRoot))
endfunction
endlibrary
GUI VERSION, added by @crunch
- First you have to create a global unit variable in your Trigger Editor, called ROOT_UNIT.
- Then you need a slightly altered version of the script. Chose the scripting language according to your map Options. Just create a new Custom Script to put it in or add it to the main map script by clicking your map name on top of the triggers in the list.
Lua:
-- Initial idea by Macadamia
-- Credits for suggestions that made this possible (alphabetical order) : Boar, Jim-panse, spellweaver, SwissDerd, Templarfreak, Zed
-- GUI adaptation by Crunch and Macadamia
function ManageRoot()
local upRoot, reRoot = CreateTrigger(), CreateTrigger()
for i = 1, GetPlayers() do
local p = Player(i-1)
if (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING) then
TriggerRegisterPlayerUnitEvent(upRoot, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, nil)
TriggerRegisterPlayerUnitEvent(reRoot, p, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, nil)
end
end
TriggerAddCondition(upRoot, Condition(function()
if (GetIssuedOrderId() == OrderId("unroot")) then
local u = GetOrderedUnit()
-- Execute GUI Uproot Trigger, checking its conditions
udg_ROOT_UNIT = u
if TriggerEvaluate(gg_trg_UprootTrigger) then
TriggerExecute(gg_trg_UprootTrigger)
end
end
return false
end))
TriggerAddCondition(reRoot, Condition(function()
if (GetIssuedOrderId() == OrderId("root")) then
local u, t, cancel = GetOrderedUnit(), CreateTimer(), CreateTrigger()
TriggerRegisterUnitEvent(cancel, u, EVENT_UNIT_ISSUED_ORDER)
TriggerRegisterUnitEvent(cancel, u, EVENT_UNIT_ISSUED_POINT_ORDER)
TriggerRegisterUnitEvent(cancel, u, EVENT_UNIT_ISSUED_TARGET_ORDER)
TriggerAddCondition(cancel, Condition(function()
-- We need to destroy the timer and cancel trigger, they will be re created on next "root" order
PauseTimer(t)
DestroyTimer(t)
DisableTrigger(cancel)
DestroyTrigger(cancel)
end))
TimerStart(t, 0.3, true, function()
if not u then
PauseTimer(t)
DestroyTimer(t)
DisableTrigger(cancel)
DestroyTrigger(cancel)
elseif BlzGetUnitBooleanField(u, UNIT_BF_IS_A_BUILDING) then
PauseTimer(t)
DestroyTimer(t)
DisableTrigger(cancel)
DestroyTrigger(cancel)
-- Execute GUI RootTrigger, checking its conditions
udg_ROOT_UNIT = u
if TriggerEvaluate(gg_trg_RootTrigger) then
TriggerExecute(gg_trg_RootTrigger)
end
end
end)
end
return false
end))
end
OldInitBlizzard = InitBlizzard
InitBlizzard = function()
OldInitBlizzard()
ManageRoot()
end
vJASS:
// Initial idea by Macadamia
// Credits for suggestions that made this possible (alphabetical order) : Boar, Jim-panse, spellweaver, SwissDerd, Templarfreak, Zed
// Code converted to vJass by SwissDerd
// GUI adaptation by Crunch and Macadamia
native UnitAlive takes unit id returns boolean
library ManageRoot initializer Init
globals
private trigger UprootTrig = CreateTrigger()
private trigger RootTrig = CreateTrigger()
private hashtable Table = InitHashtable()
endglobals
private function OnUproot takes nothing returns nothing
local unit u
if (GetIssuedOrderId()== OrderId("unroot")) then
set u = GetTriggerUnit()
// Execute GUI Uproot Trigger, checking its conditions
set udg_ROOT_UNIT = u
if TriggerEvaluate(gg_trg_UprootTrigger) then
TriggerExecute(gg_trg_UprootTrigger)
endif
endif
endfunction
private function OnCancel takes nothing returns nothing
local trigger trig = GetTriggeringTrigger()
local integer id = GetHandleId(trig)
local unit u = LoadUnitHandle(Table, id, 0)
local timer t = LoadTimerHandle(Table, id, 1)
if (t != null) then
call FlushChildHashtable(Table, id)
call FlushChildHashtable(Table, GetHandleId(u))
call FlushChildHashtable(Table, GetHandleId(t))
call PauseTimer(t)
call DestroyTimer(t)
call DisableTrigger(trig)
call DestroyTrigger(trig)
endif
set trig = null
set u = null
set t = null
endfunction
private function OnUpdate takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
local unit u = LoadUnitHandle(Table, id, 0)
local trigger cancelTrig
if (u == null) or (GetUnitTypeId(u) == 0) or not(UnitAlive(u)) then
set cancelTrig = LoadTriggerHandle(Table, id, 1)
call FlushChildHashtable(Table, id)
call FlushChildHashtable(Table, GetHandleId(cancelTrig))
call FlushChildHashtable(Table, GetHandleId(u))
call PauseTimer(t)
call DestroyTimer(t)
call DisableTrigger(cancelTrig)
call DestroyTrigger(cancelTrig)
else if BlzGetUnitBooleanField(u, UNIT_BF_IS_A_BUILDING) then
set cancelTrig = LoadTriggerHandle(Table, id, 1)
call FlushChildHashtable(Table, id)
call FlushChildHashtable(Table, GetHandleId(cancelTrig))
call FlushChildHashtable(Table, GetHandleId(u))
call PauseTimer(t)
call DestroyTimer(t)
call DisableTrigger(cancelTrig)
call DestroyTrigger(cancelTrig)
// Execute GUI RootTrigger, checking its conditions
set udg_ROOT_UNIT = u
if TriggerEvaluate(gg_trg_RootTrigger) then
TriggerExecute(gg_trg_RootTrigger)
endif
endif
set t = null
set u = null
set cancelTrig = null
endfunction
private function OnRoot takes nothing returns nothing
local unit u
local timer t
local trigger cancelTrig
local integer id
if (GetIssuedOrderId() == OrderId("root")) then
set u = GetTriggerUnit()
set id = GetHandleId(u)
if (not LoadBoolean(Table, id, 0)) then
call SaveBoolean(Table, id, 0, true)
set cancelTrig = CreateTrigger()
set t = CreateTimer()
set id = GetHandleId(t)
call SaveUnitHandle(Table, id, 0, u)
call SaveTriggerHandle(Table, id, 1, cancelTrig)
call TimerStart(t, 0.30, true, function OnUpdate)
set id = GetHandleId(cancelTrig)
call SaveUnitHandle(Table, id, 0, u)
call SaveTimerHandle(Table, id, 1, t)
call TriggerRegisterUnitEvent(cancelTrig, u, EVENT_UNIT_ISSUED_ORDER)
call TriggerRegisterUnitEvent(cancelTrig, u, EVENT_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterUnitEvent(cancelTrig, u, EVENT_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddCondition(cancelTrig, Condition(function OnCancel))
endif
endif
set u = null
set t = null
set cancelTrig = null
endfunction
private function Init takes nothing returns nothing
local integer i = 0
loop
if (GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING) then
call TriggerRegisterPlayerUnitEvent(UprootTrig, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
call TriggerRegisterPlayerUnitEvent(RootTrig, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
endif
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(UprootTrig, Condition(function OnUproot))
call TriggerAddCondition(RootTrig, Condition(function OnRoot))
endfunction
endlibrary
Once done, create 2 triggers :
- one called UprootTrigger,. In there, add Conditions and Actions you want to run when the building is UPROOTED
- a second one called RootTrigger. In there ,add Conditions and Actions you want to run when the building is ROOTED
Important : remember to use ROOT_UNIT instead of Triggering Unit in your conditions and actions in these 2 triggers.
Thats all.
I have attached an example map made by @crunch to demonstrate this with the map scripting language set to Lua (but the vJass version works identically).
TypeScript VERSION, added by @Boar
- Posted by himself in the first comment.
Attachments
Last edited: