HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Local triggers

06-20-2007, 08:32 PM#1
Silvenon
Hi, I'm new to using local triggers. I want the local trigger to have 2 events, one when a unit comes in range, and one timer-like. So i did like this:

Collapse JASS:
function SomeFunction_Conditions takes nothing returns boolean
    return GetUnitState(GetTriggerUnit(), UNIT_STATE_LIFE) > 0
endfunction

function SomeFunction_Actions takes nothing returns nothing
    local trigger t = GetTriggeringTrigger()
    //do stuff here
    call TriggerRemoveCondition(t, GetHandleTriggerCondition(t, "tc"))
    call TriggerRemoveAction(t, GetHandleTriggerAction(t, "ta"))
    call FlushHandleLocals(t)
    call DestroyTimer(GetExpiredTimer())
    set t = null
endfunction

function SomeFunction takes nothing returns nothing
    local trigger trig = CreateTrigger()
    local triggercondition tc
    local triggeraction ta
    local unit u = GetTriggerUnit()
    local timer t = CreateTimer()
    call TriggerRegisterUnitInRange(trig, u, 100, null)
    call TriggerRegisterTimerExpireEvent(trig, t)
    set tc = TriggerAddCondition(trig, Condition(function SomeFunction_Conditions))
    set ta = TriggerAddAction(trig, function SomeFunction_Actions)
    call TimerStart(t, 2, false, null)
    set trig = null
    set tc = null
    set ta = null
    set u = null
    set t = null
endfunction

1.) Would trigger fire when timer expires? I mean, would it ignore the conditions because in that second (timer) event there's no triggering unit
2.) Do I have any leaks here?
3.) Is there a more efficient way to do this? Did I forgot to remove stuff from gamecache?
4.) Is it ok to add a GetHandleTriggerCondition and GetHandleTriggerAction to handle vars? Would it work?
5.) Does the order in adding stuff (events, conditions, actions) matter? I mean, can I mix the order? Would it change something?

That's all for now....thanks in advance
06-20-2007, 08:41 PM#2
Captain Griffen
1) No.
2) You don't destroy the trigger.

5) Doesn't matter.
06-20-2007, 08:44 PM#3
blu_da_noob
The answer to 1 is no, but you can fix that with some EventId's.
06-20-2007, 08:52 PM#4
SFilip
From what I know you don't need to remove conditions unless you actually want to go for adding another in their place.
3. http://www.wc3campaigns.net/showthread.php?t=93797
Probably not much of a difference efficiency-vise, but better as you don't have to use the gamecache to store neither conditions nor actions. Just remember to remove the trigger itself.
Also I would recommend using not IsUnitType(GetTriggerUnit(), UNIT_TYPE_DEAD) instead of GetUnitState(GetTriggerUnit(), UNIT_STATE_LIFE) > 0. Again not more efficient, but better because GetUnitState can sometimes be tricked when it comes to dead units.
4. It's ok, but, considering the conditions deal above, not really needed.
06-20-2007, 09:00 PM#5
Captain Griffen
GetWidgetLife(u) > 0.405 is fast and safe.
06-20-2007, 10:20 PM#6
SFilip
> safe
Not really.
If you increase a dead unit's life using triggers at some point then GetWidgetLife will make it look like the unit is alive. While this is not so likely to happen, it's not impossible either. Simply a trigger that increases the life of all units in one region can cause it.
06-21-2007, 07:28 AM#7
Silvenon
Thanks guys. Whoops i forgot to put DestroyTrigger, sry i usually do that.

Quote:
The answer to 1 is no, but you can fix that with some EventId's.

EventId's? What's that? How do I do it then?

Hehe this is pretty screwed up......I'll try to understand Vex's way.....

Anyways thanks for help guys, SFilip you have been most helpful!
06-21-2007, 08:13 AM#8
blu_da_noob
'eventid' is a handle type, which all the other event types are an extension of. The native GetTriggerEventId returns an eventid type, which can be compared to any event type to allow you to determine which event fired a trigger. Now I didn't actually look at the specifics of your example before and you don't use what I would call 'normal' event registration (for lack of a better term). What you would need to do is test whether those events do give ids and what they are if they do. You could then use this information to check if the unit is alive or the trigger was fired by the timer expiration.

However, in this case it might not be necessary. GetTriggerUnit() should return null when there isn't one, so you can just check the life or GetTriggerUnit() == null.
06-21-2007, 08:22 AM#9
Silvenon
Yeeaah, that's a better solution! Thanks blu!

Uhmm if I put something like this:

return IsUnitEnemy(GetTriggerUnit(), Player(0)) and IsUnitType(GetTriggerUnit(), UNIT_TYPE_DEAD) or GetTriggerUnit() == null
What would "or" refer to? Would it be a right way to do it, or do I have to use And/Or?

Another question, if I'm not using t timer at all, just for firing trigger, is it ok if i use TriggerRegisterTimerEvent? That way I don't have to destroy anything, right?
06-21-2007, 08:31 AM#10
blu_da_noob
You know I've never bothered to find out the order of processing of logical operands. I would guess at linear (ie that would first check the and, then or the result), but it is best to add brackets to ensure the correct order of operation. So in that case I'm guessing you want return (IsUnitEnemy(GetTriggerUnit(), Player(0)) and IsUnitType(GetTriggerUnit(), UNIT_TYPE_DEAD)) or GetTriggerUnit() == null.
06-21-2007, 10:21 AM#11
Silvenon
yep, thanks :D
06-21-2007, 07:50 PM#12
Earth-Fury
Quote:
Originally Posted by blu_da_noob
You know I've never bothered to find out the order of processing of logical operands.

Left to right.
Even enclosed in brackets.

Collapse JASS:
f1() and f2 or (f3() and f4())
  • Will execute f1().
  • if f1() is false, will skip to f3(). (some optamization in JASS?! WTF?!)
  • if f1() is true, will move to f2().
  • if f2() is true, will stop executing.
  • if f2() is false, will move to f3().
  • if f3() is false, stop executing.
  • if f3() is true, go to f4().
  • ext.

as you can see, everything is done left to right. Execution stops if a conclusion can be reached without further execution. brakets also do not control order of execution, they only group things together. thus:
f1() and (f2()) is the same as f1() and f2().

To me, this is quite odd. And possibly usefull. like:
Collapse JASS:
if (IsUnitSpecial(u) or MakeUnitSpecial(u)) then
    //MakeUnitSpecial returns true on sucsess and false on failure, thus an else can be used to handle errors.
endif
mind you, such optamization tricks NEED comments.
06-21-2007, 07:56 PM#13
blu_da_noob
Ok I meant grouping not execution, but yeah processed left to right (as I assumed) groups them that way.

Quote:
Execution stops if a conclusion can be reached without further execution.

Yes. It's termed 'short circuit' boolean evaluation. It allows stuff life:
if astring != "" and GetStoredInteger(agamecache,"hi",astring) then Because the gamecache functions crash on an empty string, but short circuiting allows you to prevent that.
06-21-2007, 08:25 PM#14
Silvenon
Yeah, I learned about and or not in school, "not" has the highest priority, then comes "and" and after that "or". Those JASS optimizations are ok, because if one statement in "and" isn't true, then the result will definetly be false, so it skips an unnecessary check. Can someone answer to the question I asked?

Quote:
Another question, if I'm not using t timer at all, just for firing trigger, is it ok if i use TriggerRegisterTimerEvent? That way I don't have to destroy anything, right?
06-22-2007, 12:58 PM#15
blu_da_noob
Quote:
Another question, if I'm not using t timer at all, just for firing trigger, is it ok if i use TriggerRegisterTimerEvent? That way I don't have to destroy anything, right?

Well if you have a timer which exists solely to run a trigger then it doesn't really matter. You can register the event if you want it to be a trigger, or you can just TimerStart it and have it call a function. Neither way requires destroying anything (as long as it's intended to run all game) so I'm not sure what that part is about.