• 🏆 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!

Floating text countdown problem.

Status
Not open for further replies.
Level 2
Joined
Mar 28, 2021
Messages
7
A certain timer with an integer variable is set. It works fine in game - counting from fifty to around twenty. However, numbers stop appearing at approximately fifteen 'second' mark. I cannot see why.

  • Events
    • Unit - A unit enters Vicinity of Arena <gen>
  • Conditions
  • Actions
    • Set VariableSet IntegerCountdown = 49
    • Floating Text - Create floating text that reads Countdown reset; ne... at (Center of Countdown Timer1 <gen>) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
    • Wait 1.00 seconds
    • Floating Text - Destroy (Last created floating text)
    • For each (Integer A) from 1 to IntegerCountdown, do (Actions)
      • Loop - Actions
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • IntegerCountdown Greater than or equal to 0
          • Then - Actions
            • Floating Text - Create floating text that reads (String(IntegerCountdown)) at (Center of Countdown Timer1 <gen>) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
            • Wait 1.00 seconds
            • Floating Text - Destroy (Last created floating text)
            • Set VariableSet IntegerCountdown = (IntegerCountdown - 1)
          • Else - Actions
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,540
What is your goal for this trigger?

Because this current design doesn't look right. The moment a second unit enters the region it will break. The same unit could leave/enter the region and break it as well. Also, your use of Waits and Last created floating text is asking for trouble. Any newly created Floating Text will become the "Last created floating text", meaning there's a chance you'll end up destroying the wrong text. Waits inside For Loops are generally bad practice as well, you usually want to take advantage of Periodic Intervals/Timers.

Here's what I assume you want:
  • Enter
    • Events
      • Unit - A unit enters Vicinity of Arena <gen>
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Countdown Equal to 0
        • Then - Actions
          • Floating Text - Create floating text that reads Countdown Reset at (Center of Countdown Timer1 <gen>) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
          • Set VariableSet CountdownText = (Last created floating text)
        • Else - Actions
      • Set VariableSet Countdown = 50
      • Countdown Timer - Start CountdownTimer as a Repeating timer that will expire in 1.00 seconds
  • Timer
    • Events
      • Time - CountdownTimer expires
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Countdown Greater than 0
        • Then - Actions
          • Set VariableSet Countdown = (Countdown - 1)
          • Floating Text - Change text of CountdownText to (String(Countdown)) using font size 10.00
        • Else - Actions
          • Floating Text - Destroy CountdownText
          • Countdown Timer - Pause CountdownTimer

The timer/countdown reset whenever a unit enters the region. With this design only one floating text will EVER exist at a time.


Note that both your trigger and my first trigger leak Points -> Memory Leaks
It's not the end of the world but it's something to be aware of if you're interested in map performance.

Here's my first trigger but with the Point leak removed:
  • Enter
    • Events
      • Unit - A unit enters Vicinity of Arena <gen>
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Countdown Equal to 0
        • Then - Actions
          • Set VariableSet CountdownPoint = (Center of Countdown Timer1 <gen>)
          • Floating Text - Create floating text that reads Countdown Reset at CountdownPoint with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
          • Custom script: call RemoveLocation (udg_CountdownPoint)
          • Set VariableSet CountdownText = (Last created floating text)
        • Else - Actions
      • Set VariableSet Countdown = 50
      • Countdown Timer - Start CountdownTimer as a Repeating timer that will expire in 1.00 seconds
What you do is Set a Point variable at wherever you want to create the Floating Text, so in this case the Center of Countdown Timer1 <gen>. Then when you create the Floating Text you reference this Point variable instead of the Center of the Region. Finally, you run a function called RemoveLocation() which is only available through Custom script, which "deletes" the Point variable and removes it from the game's memory.

The reason for these memory leaks is due to how Blizzard designed these functions. Whenever you reference somewhere in the map like Center of Region, Position of Unit, etc... what happens is that the game creates a permanent Point at that place. A Point is simply a pair of X/Y coordinates that represents somewhere in the map. Blizzard also refers to Points as Locations hence why the function to destroy a Point is called RemoveLocation(). Annoying, I know. Anyway, long story short, when you don't manually create your Point variable, use it, and Remove it yourself, it ends up existing in the game's memory forever taking up space. It's like trash that never gets thrown away, you don't need it anymore but the game holds onto it for whatever stupid reason. That's why you need to step in and throw it away yourself.
 

Attachments

  • Countdown map.w3m
    16.6 KB · Views: 16
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,540
It puzzles me why one disregards a wait action and, instead, one is to use a countdown timer variable inside loops.
Waits are useful for triggers that only happen once or that can only have one active instance at a time. Like during your maps opening cinematic when all players have disabled control. However, beyond that you're asking for trouble unless you handle them with care. Just use them with caution is the general rule of thumb.

In your trigger's case the Event can be triggered multiple times but the trigger was designed in a way that multiple instances of it would conflict with one another. For example, it was susceptible to Destroying the wrong floating text since you're using "Last created floating text" after a Wait. What happens if another trigger creates Floating Text? That new Floating Text becomes the Last created floating text and will be destroyed instead.

So for example you were doing this:
Create countdown floating text
Wait 1.00 second
Destroy last created floating text

But what if another trigger runs before that 1.00 second Wait is up and creates it's own Floating Text:
Create countdown floating text
Wait 0.25 seconds
Create some other floating text
Wait 0.75 seconds
Destroy last created floating text (You wanted to destroy the countdown floating text but you instead destroy something else)
 
Status
Not open for further replies.
Top