Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
i have destructables which players can destroy but for one team it should not be possible. I want to check if a destructable is attacked... I can't find a solution for it.
Make an ability based of Channel or Eat Tree or stuff like that and you will be able to cast it on destructables.
With channel there is one problem that the destructables have to be selectable to be targeted.
In any case, that is the only way how you can use events for when a unit interacts with a destructable.
You would have to replace the attacks with customized spells to make it look the same and then destroy the destructable with triggers.
Another method would be to not use destructables and use units (probably buildings) to replace them.
Anyone know why the "harvest" order is what's used on these destructable checkers? It doesn't allow you to detect a barrel, for example. Why not simply have the harvest ability on the unit but order it to attack?
use function GetOrderTargetDestructable() in conjuntion with the event EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER.
wierd trigger sample:
JASS:
function TCondition takes nothing returns boolean
return GetDestructableTypeId(GetOrderTargetDestructable())==YOUR_DESTRUCTABLE_TYPE_ID
//Also you can check GetOrderTargetDestructable()==YOUR_DESTRUCTABLE
endfunction
function TActions takes nothing returns nothing
local unit u = GetTriggerUnit()
local destructable d = GetOrderTargetDestructable()
if (condition) then //Code to check if unit is allowed to attack the destructable if not then
call IssueInmediateOrder (u,"stop")
endif
set u = null //clean local var
set d = null
endfunction
function InitAttackedDestructableTrigger takes nothing returns nothing
local trigger DestructableTrigger = CreateTrigger( )
local integer index = 0
loop
exitwhen index> bj_MAX_PLAYER_SLOTS
call TriggerRegisterPlayerUnitEvent(DestructableTrigger, Player(index),EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null )
set index = index + 1
endloop
call TriggerAddCondition(DestructableTrigger, Condition(function TCondition))
call TriggerAddAction(DestructableTrigger, function TActions)
set DestructableTrigger = null //local var clean
endfunction
There could have better ways to attach actions to a destructable, but this one is very usefull for me. I hope It helps you.
edit: I posted another response. fixed now - Forget to add triggeractions to DestructableTrigger (fixed)
So another usefull function is GetTriggerDestructable()
There are two ways to do this... and neither are really working 100% glitchless.
One way which already has been said is to pause the unit, order it and unpause it, which basically has a weird result.
Or you add a very small delay, which is also mentioned before... however in a not really nice way.
In the second way, you would have to create a new timer, store the unit and order on the timer, start the timer and order the unit when the timer expires... this is a pain to do every single time and you will 100% forget something now and then.
However, I prefer that way and have written a nice thing that makes me be able to delay the order of the 3 most used IssueOrder functions.
It uses TimerUtils and a small library that I wrote that makes a unique index for it.
(How I make a new index in that library is discussable and I should have made that in textmacros so you can have one for each thing that you desire but who the hell cares.)
JASS:
library TimerIndex uses TimerUtils
//*********************************************************************
//* TimerIndex 1.0
//* ----------
//*
//* This library creates a unique index for the TimerData of timerUtils.
//* A timer that is created with an index must also be released as an indexed timer.
//*
globals
integer udg_NextTimerIndex = 0
boolean array udg_TimerIndex_Occupied
endglobals
function ReleaseIndexedTimer takes timer t returns nothing
set udg_TimerIndex_Occupied[GetTimerData(t)] = false
call ReleaseTimer(t)
endfunction
function NewIndexedTimer takes nothing returns timer
loop
set udg_NextTimerIndex = udg_NextTimerIndex + 1
if udg_NextTimerIndex > 8190 then
set udg_NextTimerIndex = 1
endif
exitwhen not udg_TimerIndex_Occupied[udg_NextTimerIndex]
endloop
set udg_TimerIndex_Occupied[udg_NextTimerIndex] = true
return NewTimerEx(udg_NextTimerIndex)
endfunction
endlibrary
JASS:
library DelayedOrder uses TimerIndex
globals
unit array udg_DelayedOrder_WhichUnit
integer array udg_DelayedOrder_OrderId
real array udg_DelayedOrder_TargetPoint_X
real array udg_DelayedOrder_TargetPoint_Y
widget array udg_DelayedOrder_TargetWidget
endglobals
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function IssueImmediateOrderByIdCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetTimerData(t)
call ReleaseIndexedTimer(t)
call IssueImmediateOrderById(udg_DelayedOrder_WhichUnit[id], udg_DelayedOrder_OrderId[id])
set udg_DelayedOrder_WhichUnit[id] = null
set udg_DelayedOrder_OrderId[id] = 0
endfunction
function IssueImmediateOrderByIdDelayed takes unit whichUnit, integer order, real delay returns nothing
local timer t = NewIndexedTimer()
local integer id = GetTimerData(t)
set udg_DelayedOrder_WhichUnit[id] = whichUnit
set udg_DelayedOrder_OrderId[id] = order
call TimerStart(t, delay, false, function IssueImmediateOrderByIdCallback)
set t = null
endfunction
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function IssuePointOrderByIdCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetTimerData(t)
call ReleaseIndexedTimer(t)
call IssuePointOrderById(udg_DelayedOrder_WhichUnit[id], udg_DelayedOrder_OrderId[id], udg_DelayedOrder_TargetPoint_X[id], udg_DelayedOrder_TargetPoint_Y[id])
set udg_DelayedOrder_WhichUnit[id] = null
set udg_DelayedOrder_OrderId[id] = 0
set udg_DelayedOrder_TargetPoint_X[id] = 0.
set udg_DelayedOrder_TargetPoint_Y[id] = 0.
endfunction
function IssuePointOrderByIdDelayed takes unit whichUnit, integer order, real x, real y, real delay returns nothing
local timer t = NewIndexedTimer()
local integer id = GetTimerData(t)
set udg_DelayedOrder_WhichUnit[id] = whichUnit
set udg_DelayedOrder_OrderId[id] = order
set udg_DelayedOrder_TargetPoint_X[id] = x
set udg_DelayedOrder_TargetPoint_Y[id] = y
call TimerStart(t, delay, false, function IssuePointOrderByIdCallback)
set t = null
endfunction
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function IssueTargetOrderByIdCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetTimerData(t)
call ReleaseIndexedTimer(t)
call IssueTargetOrderById(udg_DelayedOrder_WhichUnit[id], udg_DelayedOrder_OrderId[id], udg_DelayedOrder_TargetWidget[id])
set udg_DelayedOrder_WhichUnit[id] = null
set udg_DelayedOrder_OrderId[id] = 0
set udg_DelayedOrder_TargetWidget[id] = null
endfunction
function IssueTargetOrderByIdDelayed takes unit whichUnit, integer order, widget targetWidget, real delay returns nothing
local timer t = NewIndexedTimer()
local integer id = GetTimerData(t)
set udg_DelayedOrder_WhichUnit[id] = whichUnit
set udg_DelayedOrder_OrderId[id] = order
set udg_DelayedOrder_TargetWidget[id] = targetWidget
call TimerStart(t, delay, false, function IssueTargetOrderByIdCallback)
set t = null
endfunction
endlibrary
The basic difference is that you change IssueImmediateOrderById
into IssueImmediateOrderByIdDelayed
(You add "Delayed" to the function call.)
and (myUnit, myOrder)
into (myUnit, myOrder, 12.34)
(You add a real variable at the end defining the duration of the timer. This is recommended to not use a value below 0.)
Be aware that this uses the integer value of your order.
To convert the string to the integer, you use OrderId("stop") (where stop is your order string).
You can however just write another snippet that takes all order strings that you want to have as integer variables and generate their values at map initialization.
This is something that I use often.
JASS:
globals
integer ORDER_STOP
integer ORDER_ATTACK
integer ORDER_MOVE
integer ORDER_SMART
endglobals
//===========================================================================
function InitTrig_OrderIds takes nothing returns nothing
set ORDER_STOP = OrderId("stop")
set ORDER_ATTACK = OrderId("attack")
set ORDER_MOVE = OrderId("move")
set ORDER_SMART = OrderId("smart")
endfunction
Ofcourse, you can add your own stuff in here.
(Be aware that you don't break OP limit with these things so having a timer started at init and set the orders when that timer expires will help a lot... however, be sure that you initialize them before you try to use them.)
One last thing though... "Post Quick Reply"... Quick my ass.
Strange, here is works. The Hero stop attacking the gravestones and thats what i want. I'll try the pause on/off mentioned by bribe... Anyway one of them are ok for me.
DSG means that you get a slightly delay which is in some cases enough to complete the order which is kind of not what you want...
Or when you try to move the unit, he will still move for 0.15 seconds every time you right click... which means that if you spamm it, your unit will just walk "normally".
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.