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

Fuck you Warcraft 3, do my waits for me.

Status
Not open for further replies.
Level 23
Joined
Oct 18, 2008
Messages
938
Disclaimer: I mostly come here for specific purposes and am quite unaware of happenings, codecraft and the state of science. Everything following may be horribly wrong or invalidated by something simple I haven't heard of.

The problem:
Warcraft 3 really doesn't like waits. GUI "wait" is a cruel joke/eldritch monstrosity and triggers can't create timer variables, only refer to the pre-created ones. I said "give me a spell that does a thing 10 seconds after it is used", the world editor made inappropriate remarks about my mother.

Warcraft 3 is constantly running itself, because duh. But it can't run a wait without you first filling out fifty forms in chinese and sacrificing a goat. You're tempted to create a useless dummy unit that will notify the game for your effects at the end of its timed life, but a couple hundred instances of that will just kill the game.

So, really just go ahead and make some code to tell blizzard's code to do things exactly like what it's already figuring out for approximately all the hardcoded behavior?

Alternatively, find a function of the game that's effectively a timer, but hardcoded and replicable to your desire. I've made an extremely durable footman, and spawn a hero unit which gains a point of its main attribute and therefore damage with each iteration. the projectile is extremely slow and by changing the distance I'd create a timer. Though the attacker is removed shortly after sending it, the damage value of the projectile will remain and upon impact, remind the target what the array number of further instructions is. These units could be hidden away outside of camera bounds, or whatever.

Issues:
- Other than the Reaction Delay gameplay constant there are minimal inaccuracies in timing.
- Projectiles can live up to 60 seconds.

Questions:
- Efficient? Who knows.
- Reliable? ...Probably?
- Is there a better function to use for this?

Uses:
- ???
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Warcraft 3 really doesn't like waits. GUI "wait" is a cruel joke/eldritch monstrosity and triggers can't create timer variables, only refer to the pre-created ones. I said "give me a spell that does a thing 10 seconds after it is used", the world editor made inappropriate remarks about my mother.

Warcraft 3 is constantly running itself, because duh. But it can't run a wait without you first filling out fifty forms in chinese and sacrificing a goat. You're tempted to create a useless dummy unit that will notify the game for your effects at the end of its timed life, but a couple hundred instances of that will just kill the game.
WolrdEdit GUI is quite literally a "PoS". Even JASS does not give you easy delays for writing sequential code, forcing one to break code into separate sub-functions for scheduling later with timers or events.

Luckily Blizzard fixed this in StarCraft II. There the wait works perfectly, giving you precision to the nearest game frame (smallest unit of time that matters) and able to choose between real time (for UIs) and game time (for game mechanics).
 
Level 19
Joined
Jul 2, 2011
Messages
2,162
you could change your attack to a parasitic spell ability

they damage one every few seconds, this timer which is set by you can be any length of time

how to do this

change your spell to the parasitic spell. then set the attack points and seconds timer. then create a trig that removes that buff from your target after the damage is taken

if it's set like this
parasitic spell damages unit every 9 seconds
trig disables buff after 14seconds

Then there is hardly ever a chance your attack will damage twice and you have a nice easy timer

=) Hope this helps
 
Last edited by a moderator:

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183

Can not be compared to the usefulness of a proper thread.sleep (wait).
Coding spells would be sooooooooo much easier with waits, timerutils does not really make it easier. Just more efficient. Mainly speaking from a GUI perspective.

edit: If this was somewhat viable I would find coding spells funny.
  • Untitled Trigger 001
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
    • Actions
      • -------- do spell init stuff --------
      • For each (Integer A) from 1 to 3, do (Actions)
        • Loop - Actions
          • Wait 0.03 seconds
          • -------- do spell loop stuff --------
 
Level 23
Joined
Oct 18, 2008
Messages
938
From initial testing, variation seems to stay within the second decimal of a second.

This might just be usable.

--

hory shet

5LKcf2I.png


I thought this would be unusable for short waits but it may just be the opposite
 
Level 23
Joined
Oct 18, 2008
Messages
938
Custom script: call UnitRemoveAbility(udg_TempUnit, 'Amov')
there was an initial random delay, but this appears to address it perfectly.

qFVjt3V.png


projectiles in flight for a long time seem to pick up random delays, though these are quite small. at 30 seconds it stayed under 0.010

there are a lot of factors in the projectile type that may be able to affect it somehow.
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,183
Timers sucks.
JASS:
function x takes nothing returns nothing
    //do something
    call TriggerSleepAction(...)
    //do something else
endfunction

// vs

function y takes nothing returns nothing
     //do something else
endfunction

function x takes nothing returns nothing
    //do something
    call TimerStart(... function y)
endfunction
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Just move to StarCraft II already. The below is possible there and it is accurate.
  • Untitled Trigger 001
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
    • Actions
      • -------- do spell init stuff --------
      • For each (Integer A) from 1 to 3, do (Actions)
        • Loop - Actions
          • Wait 0.0625 seconds
          • -------- do spell loop stuff --------
Combined with how GUI has local variables and there are no leaks I wonder why so many people stay with WC3.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Promises are basically waits for async code:
Code:
    doSomething().then((data) => {
        return doSomethingElse(data);
    }).then((data) => {
        return doSomethingMore(data);
    }).then((data) => {
        resolve(data);
    }).catch((err) => {
        reject(err);
    });

You will use it a lot when dealing with online programming... ussually API code.
Timers dont really differ that much if you know how to use them properly.
 
Level 19
Joined
Dec 12, 2010
Messages
2,069
Just move to StarCraft II already. The below is possible there and it is accurate.
  • Untitled Trigger 001
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
    • Actions
      • -------- do spell init stuff --------
      • For each (Integer A) from 1 to 3, do (Actions)
        • Loop - Actions
          • Wait 0.0625 seconds
          • -------- do spell loop stuff --------
Combined with how GUI has local variables and there are no leaks I wonder why so many people stay with WC3.
cause nobody plays SC2 comparing to wc3/dota2 audience
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
Great, the data editor is better for coding things than the trigger editor.
For art/animation related tasks it is because it feeds straight into the graphics system allowing you much more precise control over art.

Anything that alters gameplay has to be done with triggers and is limited to 1/16 of a game second (usually 1/20 or less of a real second). This limitation is a non-issue as that is the minimum unit of deterministic time in StarCraft II anyway, so stuff that alters gameplay cannot happen with a shorter period.
 
Level 7
Joined
Oct 19, 2015
Messages
286
For art/animation related tasks it is because it feeds straight into the graphics system allowing you much more precise control over art.
That's the problem. It's a graphical user interface that feeds straight into the graphics system instead of there being an intermediate level where I could write code, which would be inherently more powerful and productive than any kind of GUI (doesn't matter if it's the data or the trigger editor).
 
Level 13
Joined
Nov 7, 2014
Messages
571
Well, if one had a decent compiler it could possible translate code like:

JASS:
function accurate_wait takes nothing returns nothing
    local integer i

    call BJDebugMsg("foo")
    wait 0.5
    call BJDebugMsg("bar")
    wait 1.0
    call BJDebugMsg("baz")
    wait 1.5

    set i = 1
    loop
        exitwhen i > 9

        call BJDebugMsg(I2S(i))

        set i = i + 1
        wait 0.1
    endloop

    call BJDebugMsg("done")
endfunction

to something like this:

JASS:
globals
    timer w_timer = CreateTimer()
    integer w_state
    integer w_i
endglobals

function accurate_wait_loop takes nothing returns nothing
    // local integer i

if w_state == 1 then

    call BJDebugMsg("foo")

    set w_state = 2
    call TimerStart(w_timer, 0.5, false, function accurate_wait_loop)

elseif w_state == 2 then

    call BJDebugMsg("bar")

    set w_state = 3
    call TimerStart(w_timer, 1.0, false, function accurate_wait_loop)

elseif w_state == 3 then

    call BJDebugMsg("baz")

    set w_state = 4
    call TimerStart(w_timer, 1.5, false, function accurate_wait_loop)

elseif w_state == 4 then

    set w_i = 1

    set w_state = 5
    call TimerStart(w_timer, 0, false, function accurate_wait_loop)

elseif w_state == 5 then

    if not ( w_i > 9 ) then
        call BJDebugMsg(I2S(w_i))

        set w_i = w_i + 1
        call TimerStart(w_timer, 0.1, false, function accurate_wait_loop)

    else
        set w_state = 6
        call TimerStart(w_timer, 0, false, function accurate_wait_loop)
    endif

elseif w_state == 6 then

    call BJDebugMsg("done")

endif
endfunction

function accurate_wait takes nothing returns nothing
    set w_state = 1
    call accurate_wait_loop()
endfunction

which is hardly something anyone would want to write by hand for more than 5-10 states (compilers++).

Of course it would only work for functions that return nothing but it's still something =).
 
Level 6
Joined
Jul 30, 2013
Messages
282
you could always write another precompiler that searches for TriggerSleepAction and translates that to something that actually works...

good luck with that tho. getting all those corner cases right.. :p
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
If you would only increase the counter of an int, you would use exactly 0 seconds to do that.
If you do that a billion times, it still takes 0 in-game seconds to do so, because the game doesnt go to the next frame until all actions are done.

On the other hand, it is not only increasing an int, it also starts a new timer.
 
Status
Not open for further replies.
Top