• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Trigger] trouble with a timer

Status
Not open for further replies.
Level 21
Joined
Mar 29, 2020
Messages
1,237
hey there,

this spell is supposed to display a timer (3 min) and when the timer runs out it kills all town hall type units. if the casting hero is killed first the timer is canceled.

I'm having two issues with it :

1. the timer doesn't show, just the timer window (I'm probably making a very simple mistake, I have never used timers before but I did everything this tutorial said to do )

2. for some reason however I try to remove the player group I have here as Temp_PlayerGroup (I tried with the way with bj and the way after), "jass helper" tells me there is an error.

here's the whole thing, the triggers "final loop" and "zeppelin" are prob not relevant, but I included them in case it helps get the full picture. thanks!

(using bribe's unit indexer)
  • set spell
    • Events
      • Unit - A unit Finishes casting an ability
    • Conditions
      • (Ability being cast) Equal to The Final Countdown
    • Actions
      • Unit - Create 1 dummywinventory for (Triggering player) at Hidepoint facing Default building facing degrees
      • Unit - Add a 180.00 second Generic expiration timer to (Last created unit)
      • Set CV = (Custom value of (Last created unit))
      • Set FinalDummy[(Custom value of (Triggering unit))] = (Last created unit)
      • Unit Group - Add (Last created unit) to FinalDummies
      • Set FinalCaster[CV] = (Triggering unit)
      • Game - Display to (All players) for 30.00 seconds the text: ((Name of (Triggering player)) + ('s + ((Name of (Triggering unit)) + has rigged everyone's main bases to explode. You have 3 minutes to kill him if you want to prevent this from happening. )))
      • Countdown Timer - Create a timer window for FinalTimer[CV] with title The Final Countdown
      • Set FinalTimerWindow[CV] = (Last created timer window)
      • Countdown Timer - Show (Last created timer window)
      • Countdown Timer - Start (Last started timer) as a One-shot timer that will expire in 180.00 seconds
      • Player Group - Pick every player in (All players) and do (Actions)
        • Loop - Actions
          • Unit - Grant shared vision of (Triggering unit) to (Picked player)
      • Unit Group - Add (Triggering unit) to FinalGroup
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Final Loop <gen> is on) Equal to False
        • Then - Actions
          • Trigger - Turn on Final Loop <gen>
        • Else - Actions

  • zeppelin
    • Events
      • Unit - A unit Is loaded into a transport
    • Conditions
      • ((Loading unit) is in FinalGroup) Equal to True
    • Actions
      • Set CV = (Custom value of (Triggering unit))
      • Set FinalZeppelin[CV] = (Transporting unit)
  • Final Loop
    • Events
      • Time - Every 10.00 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in FinalGroup and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is being transported) Equal to False
            • Then - Actions
              • Set TempPoint = (Position of (Picked unit))
            • Else - Actions
              • Set CV = (Custom value of (Picked unit))
              • Set TempPoint = (Position of FinalZeppelin[CV])
          • Cinematic - Ping minimap for (All players) at TempPoint for 2.00 seconds, using a Warning ping of color (100.00%, 100.00%, 100.00%)
          • Custom script: call RemoveLocation (udg_TempPoint)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (FinalGroup is empty) Equal to True
        • Then - Actions
          • Trigger - Turn off (This trigger)
        • Else - Actions

  • Stop Spell
    • Events
      • Unit - A unit Dies
    • Conditions
      • ((Triggering unit) is in FinalGroup) Equal to True
    • Actions
      • Set ID = (Custom value of (Triggering unit))
      • Set CV = (Custom value of FinalDummy[ID])
      • Set Temp_PlayerGroup = (All enemies of (Owner of (Dying unit)))
      • Player Group - Pick every player in Temp_PlayerGroup and do (Actions)
        • Loop - Actions
          • Unit - Deny shared vision of (Triggering unit) to (Picked player)
      • Custom script: Custom script: call DestroyForce(udg_Temp_PlayerGroup)
      • Unit Group - Remove (Triggering unit) from FinalGroup
      • Countdown Timer - Destroy FinalTimerWindow[CV]
      • Unit Group - Remove FinalDummy[ID] from FinalDummies
      • Unit - Remove FinalDummy[ID] from the game
      • Game - Display to (All players) for 30.00 seconds the text: ((Name of (Triggering player)) + ('s + ((Name of FinalCaster[CV]) + has been neutralized. )))
  • final finish
    • Events
      • Unit - A unit Dies
    • Conditions
      • ((Triggering unit) is in FinalDummies) Equal to True
    • Actions
      • Set CV = (Custom value of (Dying unit))
      • Set Temp_PlayerGroup = (All enemies of (Owner of (Dying unit)))
      • Player Group - Pick every player in Temp_PlayerGroup and do (Actions)
        • Loop - Actions
          • Unit - Deny shared vision of FinalCaster[CV] to (Picked player)
      • Custom script: Custom script: call DestroyForce(udg_Temp_PlayerGroup)
      • Unit Group - Remove FinalCaster[CV] from FinalGroup
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units in (Playable map area) matching (((Matching unit) is A town-hall-type unit) Equal to True)) and do (Actions)
        • Loop - Actions
          • Unit - Kill (Picked unit)
      • Countdown Timer - Destroy FinalTimerWindow[CV]
      • Unit - Remove (Triggering unit) from the game
 
Level 12
Joined
Jan 30, 2020
Messages
875
I don't have time to review your entire posted triggers here, but a quick overview made me see this :
  • Countdown Timer - Start (Last started timer) as a One-shot timer that will expire in 180.00 seconds
Why don't you use the timer you assigned the timer window to, aka FinalTimer[CV] ?

I mean the timer is obviously created and initialized at map init as you don't create it in your trigger, so nothing guarantees that it is the last created timer.

Note that it should be called Last Created Timer. The GUI action calls :
JASS:
function GetLastCreatedTimerBJ takes nothing returns timer
    return bj_lastStartedTimer
endfunction
and bj_LastStartedTimer actually is set on timer creation :
JASS:
function CreateTimerBJ takes boolean periodic, real timeout returns timer
    set bj_lastStartedTimer = CreateTimer()
    call TimerStart(bj_lastStartedTimer, timeout, periodic, null)
    return bj_lastStartedTimer
endfunction
So it indeed refers to last created timer although bj_LastCreatedTimer does not exist in Blizzard.j
I guess this might be the reason why your timer does not start, it might be in conflict with another timer with no window.

For your second issue, look closely at what you wrote :
  • Custom script: Custom script: call DestroyForce(udg_Temp_PlayerGroup)
the answer should come to you naturally ;)
 
Level 21
Joined
Mar 29, 2020
Messages
1,237
Why don't you use the timer you assigned the timer window to, aka FinalTimer[CV] ?

I mean the timer is obviously created and initialized at map init as you don't create it in your trigger, so nothing guarantees that it is the last created timer.

I didn't know that the timer was created at map init. I'll try that, thanks!

the answer should come to you naturally

oh... even now it took me a few read-overs to realize.... whoops

also, I don't understand jass, so I'm not sure what you were trying to show me with those lines, but I didn't get it...
 
Level 12
Joined
Jan 30, 2020
Messages
875
The fact is GUI is just a practical way to write scripting. But all those events / conditions and actions are actually translated into Jass or Lua when your save your map.

The actions you use in the trigger editor are usually specific functions found in the blizzard.j game file.
Most of these have the BJ suffix, to differentiate them from native functions - that can be found in the common.j game file -

This means that if you save your map (in Jass mode you can even convert a trigger to Jass directly), you can look at the code your triggers generated.
This can also help you find out what the script really does behind the trigger facade.

Thats how I found out that Starting the Last Started Timer actually means starting the last timer that was created and not the last timer that was started (something that does not make sense : when a timer is started you don't start it again. If it is paused, you can resume it though).
 
Level 21
Joined
Mar 29, 2020
Messages
1,237
Why don't you use the timer you assigned the timer window to, aka FinalTimer[CV] ?

I mean the timer is obviously created and initialized at map init as you don't create it in your trigger, so nothing guarantees that it is the last created timer.
I changed that accordingly and it still doesn't work. another fact I forgot to mention - it doesn't even show the full timer window text only part of it and "..."

any idea what I should change?

  • set spell
    • Events
      • Unit - A unit Finishes casting an ability
    • Conditions
      • (Ability being cast) Equal to The Final Countdown
    • Actions
      • Unit - Create 1 dummywinventory for (Triggering player) at Hidepoint facing Default building facing degrees
      • Unit - Add a 180.00 second Generic expiration timer to (Last created unit)
      • Set CV = (Custom value of (Last created unit))
      • Set FinalDummy[(Custom value of (Triggering unit))] = (Last created unit)
      • Unit Group - Add (Last created unit) to FinalDummies
      • Set FinalCaster[CV] = (Triggering unit)
      • Game - Display to (All players) for 30.00 seconds the text: ((Name of (Triggering player)) + ('s + ((Name of (Triggering unit)) + has rigged everyone's main bases to explode. You have 3 minutes to kill him if you want to prevent this from happening. )))
      • Countdown Timer - Create a timer window for FinalTimer[CV] with title The Final Countdown
      • Set FinalTimerWindow[CV] = (Last created timer window)
      • Countdown Timer - Show FinalTimerWindow[CV]
      • Countdown Timer - Start FinalTimer[CV] as a One-shot timer that will expire in 180.00 seconds
      • Player Group - Pick every player in (All players) and do (Actions)
        • Loop - Actions
          • Unit - Grant shared vision of (Triggering unit) to (Picked player)
      • Unit Group - Add (Triggering unit) to FinalGroup
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Final Loop <gen> is on) Equal to False
        • Then - Actions
          • Trigger - Turn on Final Loop <gen>
        • Else - Actions
 
Level 13
Joined
May 10, 2009
Messages
868
The actual timer doesn't exist yet... that's why. I am assuming you're using UnitIndexer or something similar. So, once "CV = (Custom value of (Last created unit))" is run, you'll probably be getting a different value each time it's executed (because it's different dummy unit), and the timer for that specific index doesn't exist yet.

For example, let's say that a new dummy unit is created and UnitIndexer labelled it as number 137 (custom value). Then, when the trigger execution reaches the following line
  • Countdown Timer - Create a timer window for FinalTimer[CV] with title The Final Countdown
that function won't work properly because no timer object was created for that FinalTimer index.

FinalTimer[CV] => FinalTimer[137] = null

In order to fix it, you need to create a new timer object with a custom script line and assign it to "FinalTimer[CV]" before executing this line
  • Countdown Timer - Create a timer window for FinalTimer[CV] with title The Final Countdown
It should look like this:
  • -------- --------
  • Custom script: set udg_FinalTimer[udg_CV] = CreateTimer()
  • Countdown Timer - Start FinalTimer[CV] as a One-shot timer that will expire in 180.00 seconds
  • Countdown Timer - Create a timer window for FinalTimer[CV] with title The Final Countdown
  • -------- --------
Once you're done, don't forget to destroy the timer with
  • Custom script: call DestroyTimer(udg_FinalTimer[udg_CV])
 
Level 12
Joined
Jan 30, 2020
Messages
875
The actual timer doesn't exist yet

Well as this is GUI, the Timer should be created at map init, so it should definitely not be null.

Also one must never destroy global timers, it only is necessary for local timers. Having a timer as a global variable is because it will be recycled, thus destruction would make no sense.

As for the custom value, there is indeed a problem :
The custom value of the dummy is simply not set when the trigger runs, and even if @Ender Wiggins uses a DDS that would detect unit creation, nothing guarantees that the UnitUserData would be set before he is trying to access it. Unlike Point Value, no unit has a custom value upon creation.

But maybe you wanted to use the custom value of the casting unit, @Ender Wiggins ?

These are indeed the 2 major issues with your triggers.
 
Level 21
Joined
Mar 29, 2020
Messages
1,237
The actual timer doesn't exist yet... that's why. I am assuming you're using UnitIndexer or something similar. So, once "CV = (Custom value of (Last created unit))" is run, you'll probably be getting a different value each time it's executed (because it's different dummy unit), and the timer for that specific index doesn't exist yet.

For example, let's say that a new dummy unit is created and UnitIndexer labelled it as number 137 (custom value). Then, when the trigger execution reaches the following line
  • Countdown Timer - Create a timer window for FinalTimer[CV] with title The Final Countdown
that function won't work properly because no timer object was created for that FinalTimer index.

FinalTimer[CV] => FinalTimer[137] = null

In order to fix it, you need to create a new timer object with a custom script line and assign it to "FinalTimer[CV]" before executing this line
  • Countdown Timer - Create a timer window for FinalTimer[CV] with title The Final Countdown
It should look like this:
  • -------- --------
  • Custom script: set udg_FinalTimer[udg_CV] = CreateTimer()
  • Countdown Timer - Start FinalTimer[CV] as a One-shot timer that will expire in 180.00 seconds
  • Countdown Timer - Create a timer window for FinalTimer[CV] with title The Final Countdown
  • -------- --------
Once you're done, don't forget to destroy the timer with
  • Custom script: call DestroyTimer(udg_FinalTimer[udg_CV])

this seems to have worked. thanks!!!

The custom value of the dummy is simply not set when the trigger runs

I don't get what you mean. I created the dummy at the beginning of the same trigger. I'm using bribe's unit indexer if that is the cause for the confusion... (I think I noted that in my op)

Also one must never destroy global timers, it only is necessary for local timers. Having a timer as a global variable is because it will be recycled, thus destruction would make no sense.

I'm assuming this has to do with the configuration of the custom script @BloodSoul wrote for me. in any case it seems to worked but Idk if it was actually destroyed. don't really understand what you wrote.

  • set spell
    • Events
      • Unit - A unit Finishes casting an ability
    • Conditions
      • (Ability being cast) Equal to The Final Countdown
    • Actions
      • Unit - Create 1 dummywinventory for (Triggering player) at Hidepoint facing Default building facing degrees
      • Unit - Add a 180.00 second Generic expiration timer to (Last created unit)
      • Set CV = (Custom value of (Last created unit))
      • Set FinalDummy[(Custom value of (Triggering unit))] = (Last created unit)
      • Unit Group - Add (Last created unit) to FinalDummies
      • Set FinalCaster[CV] = (Triggering unit)
      • Game - Display to (All players) for 30.00 seconds the text: ((Name of (Triggering player)) + ('s + ((Name of (Triggering unit)) + has rigged everyone's main bases to explode. You have 3 minutes to kill him if you want to prevent this from happening. )))
      • Custom script: set udg_FinalTimer[udg_CV] = CreateTimer()
      • Countdown Timer - Start FinalTimer[CV] as a One-shot timer that will expire in 180.00 seconds
      • Countdown Timer - Create a timer window for FinalTimer[CV] with title Final Countdown
      • Countdown Timer - Show FinalTimerWindow[CV]
      • Set FinalTimerWindow[CV] = (Last created timer window)
      • Player Group - Pick every player in (All players) and do (Actions)
        • Loop - Actions
          • Unit - Grant shared vision of (Triggering unit) to (Picked player)
      • Unit Group - Add (Triggering unit) to FinalGroup
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Final Loop <gen> is on) Equal to False
        • Then - Actions
          • Trigger - Turn on Final Loop <gen>
        • Else - Actions
      • Unit - For (Triggering unit), Ability (Ability being cast), Disable ability: True, Hide UI: False
 
Last edited:
Level 12
Joined
Jan 30, 2020
Messages
875
Ok sorry I confused myself between DDS and Unit indexer.

Yes using a unit indexer's event should be triggered at unit creation, and then index the unit (I have never needed a unit indexer, but I guess that one is storing the index in the unit's custom value.).

As for the timer, I haven't used GUI since 2004, but it feels strange that the map would not initialize the values of the timer array FinalTimer you are using. I will double check to make sure as soon as I'll be in front of the World Editor.

If I am right, it means that once you declare the timer array with its array size, it should initialize all timers of the array by creating a timer, so this means you would not need to re-create it to be able to start it.

EDIT :
Oh well it seems I was wrong. I created a new map, added a "FinalTimer" timer array variable of size 20, and here is the initialization script generated :
JASS:
globals
    // User-defined
timer array udg_FinalTimer

    // Generated
trigger gg_trg_Melee_Initialization= null

//JASSHelper struct globals:
endglobals

function InitGlobals takes nothing returns nothing
    local integer i= 0
    set i=0
    loop
        exitwhen ( i > 1 )
        set udg_FinalTimer[i]=CreateTimer()
        set i=i + 1
    endloop
endfunction
In other words, array initialization seems bugged in Trigger Editor because it seems to stop after the second timer because of "exitwhen ( i > 1 )".

Oh well that then explains why creating the timer made it to work.

Now for the last point, what I meant is about that :
Once you're done, don't forget to destroy the timer with
  • page.gif
    Custom script: call DestroyTimer(udg_FinalTimer[udg_CV])

NEVER EVER do that. You don't destroy global timers (a global timer is a timer variable you have created within the trigger editor).
You should only destroy local timers (variables created with custom script, only valid in the context of the trigger it is inside of).

What you should do is initialize your FinalTimer array at map initialization with a For Loop (not inside the trigger you posted). And that should be enough for the rest of your game.
Once created the global timers can be recycled at will.

Here is the initialization you should use , assuming you have 24 timers:


  • Initialize Timer
    • Events
      • Map initialization
    • Conditions
    • Actions
      • For each (Integer A) from 1 to 24, do (Actions)
        • Loop - Actions
          • Custom script: set udg_FinalTimer[bj_forLoopAIndex] = CreateTimer()
 
Last edited:
Level 21
Joined
Mar 29, 2020
Messages
1,237
NEVER EVER do that. You don't destroy global timers (a global timer is a timer variable you have created within the trigger editor).
You should only destroy local timers (variables created with custom script, only valid in the context of the trigger it is inside of).
Why?

as of now a new timer is created and destroyed for each instance of the spell. It works. I don't exactly understand what is wrong with it or how to implement what you are saying (and am a little hesitant to re-write this nicely operating spell...)
 
Level 12
Joined
Jan 30, 2020
Messages
875
Simply put, constantly re-creating and destroying a global agent simply makes no sense.

Also, why repeating this every time your trigger runs when initializing the array at map init once is enough for your entire game ?
It is bad practice, and accumulating these in the long run can indeed end up affecting your map performance.

you don't have to rewrite everything at all. Just add the initialization trigger I posted for map init, and remove the line :
  • Custom script: set udg_FinalTimer[udg_CV] = CreateTimer()
Nothing more.
 
Level 21
Joined
Mar 29, 2020
Messages
1,237
Simply put, constantly re-creating and destroying a global agent simply makes no sense.

Also, why repeating this every time your trigger runs when initializing the array at map init once is enough for your entire game ?
It is bad practice, and accumulating these in the long run can indeed end up affecting your map performance.

you don't have to rewrite everything at all. Just add the initialization trigger I posted for map init, and remove the line :
  • Custom script: set udg_FinalTimer[udg_CV] = CreateTimer()
Nothing more.
I'm assuming I should also remove the line that removes that timer, even though you said "nothing more". correct?

also, you wrote : "assuming you have 24 timers". I currently only have this timer in my map, but it's an array so there is one instance for every time the spell is cast. in essence every player can only cast 1 of these at a time. how does that figure in to the trigger you wrote?
 
Level 12
Joined
Jan 30, 2020
Messages
875
Yes you are right about the timer destruction line.

As for the array, as only instance can exist per player, simply assign 1 timer for every player.

Best way to to that is first change that 24 in my init to your number of players,
and then change the indexes of your timers and their window with Player number of (Owner of (Triggering unit)).

The issue is that your timers and their windows are currently indexed with the Unit indexer unit numbers (custom values in this case), then you are using many useless extra timers.
 
Last edited:
Level 13
Joined
May 10, 2009
Messages
868
The only reason why I told him to create and destroy a timer was because he's using a UnitIndexer as means of referencing an object which gives an arbitrary number for a unit upon their creation. Of course, using PlayerNumber is way better than using CV in this situation where you'd want to keep and recycle a small number of timers.

It is bad practice, and accumulating these in the long run can indeed end up affecting your map performance.
Anything to back up that statement?

Simply put, constantly re-creating and destroying a global agent simply makes no sense.
If that's true, then creating a new point object and destroying it after being done with them would also be a bad thing. The same would apply to special effects and units (especially dummies).

In other words, array initialization seems bugged in Trigger Editor because it seems to stop after the second timer because of "exitwhen ( i > 1 )".
It works fine for me
Capture.PNG
 
Level 12
Joined
Jan 30, 2020
Messages
875
a timer was because he's using a UnitIndexer
Yes thats what I understood after realizing he was using the custom value of units.


Anything to back up that statement?
Oh come on please this is the most basic common sense!
accumulating useless actions across a map physically cannot have a good impact on performance.
I never meant the impact was outrageous from the very beginning, but avoiding these kind of bad practices (here adding useless operations for the game engine) is a long term investment to try to keep the map seamless.
It's the same kind of debate as game wide fast repeating timers. At some points they seem to offer an easy solution, but the performance impact adds to the toll and can easily end up becoming painful.

If that's true, then creating a new point object and destroying it after being done with them would also be a bad thing. The same would apply to special effects and units (especially dummies).

Fact is GUI is not well equipped to face quite a few scripting challenges, mostly because it does not inherently support local variables.
Local variables are great in the sense that they're only accessible in the instance of their scope, preventing collisions that can happen with global variables sometimes.
The downside is of course you have to destroy their agent (and even null them for Jass) once you don't need them anymore.

But when you can use global agents, can you tell me what is the point of creating it, and then re-recreating the same agent after destroying it ?
In this case you get both drawbacks from the local and global variables with no benefit in return.

On the other hand, global variables are just as useful as local variables, because as they keep track of the agent they're referencing to across the entire map script,
it then allows you to not need to recreate the same agents across the script.

For example, I use this in my map, as it's probably the only TD on earth that has only 4 types of attackers (Balls). So all I do is make them heroes and once they are killed or reached their target, I revive them (if they are dead) and them make them invulnerable, hidden and paused. The benefit is tremendous as I only need to create my attackers at map init and store them in their respective table. Thats also the reason why I do not need to index my units at all as they already are from the very start.

It works fine for me

As I said, I haven't GUI-ed for 16 years, so whatever you did to make it work please share ! Because I created the variable, set the array size to 20 and it resulted with a (i > 1) exit condition.
If you know how to, this would greatly help @Ender Wiggins, because then he won't need to use the trigger I posted to initialize his timer array.
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,535
Thanks for all effort. The thing is, this spell is kind of a hail-mary spell that I doubt will be cast more than a handful of times per game. Is it still more efficient to wire it by player number?
If it will work using Player Number then that's most likely the better option. Custom value is fine though.

Anyway, what's the point of the Dummy in this case? It almost looks like it's completely useless but I'm not sure. Can the Dummy be attacked/killed or something?

Edit: Oh, I see now, it has an expiration timer. Couldn't you just scrap the Dummy and run the "final finish" Actions when the Timer finishes?
 
Level 21
Joined
Mar 29, 2020
Messages
1,237
Edit: Oh, I see now, it has an expiration timer. Couldn't you just scrap the Dummy and run the "final finish" Actions when the Timer finishes?

I can't figure out how to have an event "timer ends" (or whatever it's called) when the timer is an array, bc there is no way to define the cv I'm referring to in the event. having a dummy with an expiration timer is the solution I found for this on the forums.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,535
I can't figure out how to have an event "timer ends" (or whatever it's called) when the timer is an array, bc there is no way to define the cv I'm referring to in the event.
Right, so if you use the Player Number option then you know the Timers will be numbered from 1 to 24 and won't have this problem.

And if you do end up using Player Number I can show you a method of figuring out which Timer expired as it's sort of a pain in GUI. Otherwise, no worries.
 
Last edited:
Level 13
Joined
May 10, 2009
Messages
868
can you tell me what is the point of creating it, and then re-recreating the same agent after destroying it ?
Because, as you said, GUI is limited and it is a pain to be efficient and attempt to recycle every possible agent with it - heck, it's even unpractical at times. I'd rather switch to vJass where there are countless systems that take care of agents for you (group, timers, table, etc).

As I said, I haven't GUI-ed for 16 years, so whatever you did to make it work please share !
There's nothing wrong with it at all.
 
Level 12
Joined
Jan 30, 2020
Messages
875
I know what you mean.

Thats actually why i try to give extra advice that GUI users can use in the long run, especially if they switch to real scripting language one day.

We all started there after all (GUI i mean) :)
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,535
sounds like a useful thing to know anyways if you don't mind... :grin:

Iv'e had a few triggers already where I had to make a list of possible events like this and would be happy to know the efficient way to do that...
  • Example
    • Events
      • Time - Timer[1] expires
      • Time - Timer[2] expires
      • Time - Timer[3] expires
    • Conditions
    • Actions
      • For each (Integer Loop) from 1 to 3, do (Actions)
        • Loop - Actions
          • Custom script: if GetExpiredTimer() == udg_Timer[udg_Loop] then
          • Game - Display to (All players) for 2.00 seconds the text: (This timer has expired: + (String(Loop)))
          • Custom script: endif
Make sure the Array Size of your Timer variable is set to the maximum number of players (well technically just the player number of the last player). You MUST do this in the Variable editor (Control + B) or it will bug out and reset.

So you have a Timer for each Player, then whenever one of these Timers expires you run that Loop to find which of the Timers expired.

I'm looping from 1 to 3 because I'm using 3 timers (Timer[1], Timer[2] and Timer[3]). If let's say player 22 was using one of these Timers you would need to make sure your Loop goes up to 22.

And since we're dealing with Player Numbers I would save an Integer variable PN as udg_Loop when we find the correct Timer. Then you could do something like this for example:
  • Example
    • Events
      • Time - Timer[1] expires
      • Time - Timer[2] expires
      • Time - Timer[3] expires
    • Conditions
    • Actions
      • For each (Integer Loop) from 1 to 3, do (Actions)
        • Loop - Actions
          • Custom script: if GetExpiredTimer() == udg_Timer[udg_Loop] then
          • Set Variable PN = Loop
          • Custom script: endif
      • -------- PN = Player Number --------
      • Unit - Kill ExampleUnit[PN]
 
Last edited:
Something like this should work, too:

  • Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • For each (Integer A) from 1 to 24, do (Actions)
        • Loop - Actions
          • Hashtable - Save Handle OfTimers[(Integer A)] as 0 of 0 in Hashtable.
          • Hashtable - Save (Integer A) as (Key (Load 0 of 0 in Hashtable.).) of 0 in Hashtable.
          • Trigger - Add to Timer Expires <gen> the event (Time - Timers[(Integer A)] expires)
      • Hashtable - Clear all child hashtables of child 0 in Hashtable.
  • Timer Expires
    • Events
    • Conditions
    • Actions
      • Set VariableSet PlayerNumber = (Load 0 of (Key (Expiring timer).) from Hashtable.)
 
Status
Not open for further replies.
Top