(Discovery?) Cripple causes Nested Function.

Status
Not open for further replies.
Level 15
Joined
Aug 31, 2009
Messages
776
Hello all.

I previously made a topic in this forum about one of my spells, and through tedious testing I found the cause of the issue - but it's something I've never experience before in the Warcraft III editor.

The way to demonstrate this bug is simple:

First, have yourself a dummy unit with cast point 0 and all the subsequent usual conditions to cast a spell immediately. Make 3 dummy spells based on Firebolt, Frost Nova, and Cripple.

In a trigger, write the following, and of course adjust points and locations etc to fill your need.
Put a Footman in the middle of the map somewhere.

  • For each Integer (MyInt) from 1 to 100 do (Multiple Actions)
    • Loop (Actions)
      • Unit - Create 1 (Dummy Unit) at [some point near the footman] facing default building degrees.
      • Unit - Add (Dummy Fire Bolt) to last created unit.
      • Unit - Order (last created unit) to Orc Warlock - Firebolt [Footman]
      • Unit - Add a 2 second generic expiration timer to (Last created unit)
      • Game - Display to (all players) the text: String(MyInt)
Okay, nothing strange so far. The trigger loops 100 times through a variable. It creates 100 dummies, and orders them to Firebolt the footman. It then prints out the current value of MyInt

The result is as you'd expect - the Footman gets Fire Bolted 100 times, and all the numbers from 1 to 100 are printed.

Now make another trigger:
  • Events
    • A unit starts the effect of an ability
  • Conditions
    • Ability being cast equal to (Dummy Fire Bolt)
  • Actions
    • Set MyInt = 100
So what does this do? Basically, when the dummy spell from above is cast, this trigger causes MyInt to get set to 100.

As there's a small delay between the time the spell is cast to the time that the spell hits the target (even if projectile speed is set to 9999999), then the value of myInt doesn't get changed until all 100 loops have run.

Okay, nothing too strange so far, right?

Where it gets really weird, is if you use a spell like Cripple.

If you use Cripple, it casts SO FAST that the second trigger gets NESTED INSIDE THE FIRST TRIGGER. The result is that the spell cripple is only cast once. You can demonstrate this clearly by making the actions of the second trigger deal damage to target - it only deal the damage once.

This means that the loop creates a dummy, casts a single cripple, goes into the nested trigger, sets the value of MyInt to 100, and therefore instantly breaks the loop of the first trigger.

What's even more weird, is that if you use Frost Nova for this, it doesn't cause this behavior, despite the fact that Frost Nova is also instant and has no projectile speed associated with it.

I haven't yet tested with other spells, but this is absolutely true for cripple.

So why am I posting this? I dunno, thought it might be nice to let people know in case they run into a similar bug to mine!

tl;dr version:
Cripple casts so fast that if a trigger is to be run from the effect of the cripple spell, it will cause that trigger to be nested inside the first trigger that issued the order to cast. This can break your spells, so watch out.
 
Level 16
Joined
Mar 25, 2016
Messages
1,327
It also depends on the facing of the dummy caster. If facing, position, cast animation time is set correctly, it will take 0 seconds between order and spell cast. 0 seconds does not necessarily mean, that it is instantly, because the first trigger could still finish running, before the second trigger starts and no time would pass.
I tested it on my own and also tested it for different facing angles. I found no differences between cripple and hurl boulder. If the caster faces towards the target, the spell is cast instantly and the second trigger runs after the first, so the spell only cast once. If the caster does not face the target, the spell takes some time to cast, because the caster has to turn around first, so the spell is cast 100 times.

There is a tutorial about using only one dummy to cast several single target spells at the same time. This only works, because the cast is instant and the moment you order the unit to cast it, it actually casts the spell, so ordering it to cast it multiple times without a delay will also cast the spell multiple times: Single Target Spell for Multiple Units
https://www.hiveworkshop.com/threads/single-target-spell-for-multiple-units.242153/
This trigger for example would cripple two archers, if you meet all the requirements for instant casting spells as described in the tutorial.
  • Unit - Order (Last created unit) to Undead Necromancer - Cripple Archer 0017 <gen>
  • Unit - Order (Last created unit) to Undead Necromancer - Cripple Archer 0016 <gen>
 
There is also the wand of illusion spell. Base order id: 852274;

It exhibits a similar behavior, in that when casting that ability, you can instantly reach 100 in your example. Some systems take advantage of that 0-frame delay, like Flux's Illusion where in those lines of code, youu will only take note of the casting of the wand of illusion and the retrieval of the summoned unit as an illusion to that system.

How about Carrion Swarm?
 
Level 26
Joined
Aug 18, 2009
Messages
4,099
Not really strange and with Firebolt/missile spells it does not depend on the missile speed (you can pick 0 btw) since the event is about the casting, not the arrival of the missile. I think the "begins casting" event might even fire earlier but the bug you encountered was more due to the risk of using global variables (GUI).
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,285
As there's a small delay between the time the spell is cast to the time that the spell hits the target (even if projectile speed is set to 9999999), then the value of myInt doesn't get changed until all 100 loops have run.
This is making so many false assumptions. First the event fires then the effect fires, not when the bolt impacts. Secondly if the ability instantly triggers an effect event it could potentially interrupt the currently executing trigger.
If you use Cripple, it casts SO FAST that the second trigger gets NESTED INSIDE THE FIRST TRIGGER. The result is that the spell cripple is only cast once. You can demonstrate this clearly by making the actions of the second trigger deal damage to target - it only deal the damage once.
Which is exactly what I said above. The effect is started as part of the cast procedure which results in the game engine having to interrupt the current thread to execute an event response.

As far as Warcraft III is concerned there is no delay unless explicitly generated. If an action causes an event to fire it will interrupt the current thread to run any event handler triggers.
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,285
Except Dr Super good that this never happens when using Firebolt - ever.
So? What does Firebolt have to do with Cripple? They are two completely different abilities backed by almost completely different code in the game engine that do completely different things. Just because something happens for one abilities does not mean it has to happen for another.

One might find that Firebolt was developed mechanically different from other skills. It might have had a different purpose originally during development, or was created before other comparable skills early on in development before mechanics were finalized.
 
Level 15
Joined
Aug 31, 2009
Messages
776
You don't think it's pretty significant that this ability acts totally differently to others? Especially as Firebolt is the go-to spell for dummy-spells to cause a stun effect.

I discovered this in the reverse order (I assumed all spells acted like Firebolt), sure, but you're being a bit defensive about this whole thing aren't you?
 
Last edited:
Level 26
Joined
Aug 18, 2009
Messages
4,099
Semantically it can be surmised that the interrupt happens. The wc3 abilities are all very different in their behavior as they have custom source code backing them up. Some of the default abilities you see in the object editor base on the same code, they usually possess the same order strings and you can see this when looking up the SLKs. Cripple and firebolt are obviously not the same, also as indicated above there are more factors between applying an order and the spell starting its effect. Anyway, minimizing assumptions about how the game works and coding more securely and semantically correctly helps avoiding such dependencies. The example used global variables when clearly it should not have.

edit: This is also a reason why "the way to go" is normally to build yourself functions whose properties are known to you in their entirety, like write a function that stuns a unit. This encapsulates the quirks of wc3 and allows you to mount an own system rather than relying on vague wc3 mechanics everywhere.
 
Last edited:
Level 15
Joined
Aug 31, 2009
Messages
776
The map I'm building has well over 200 custom spells all using the same global variables for temporary groups, temporary integers, indexers etc. and NONE of them interfere with each other at all as it has been carefully orchestrated as such. The above example breaks because I wrote it on purpose to do that. That's the entire point of this thread.

Writing functions can't be done if you're only using the GUI editor. That is also my point. I can't write in JASS, and I'm sure many newer map creators also can't, and as such use the inbuilt GUI editor. While it has its limitations, this is one such error that isn't obvious - or at least certainly wasn't obvious to me. That's the point I'm trying to make.
 
Level 26
Joined
Aug 18, 2009
Messages
4,099
I can kinda understand it. A fixed workflow allows you much more throughput. jass/vJass/... users tend to have less features in their map because they left the secure sandbox of GUI and are more do-it-yourself style, which bestows greater control but is also less obvious and independent. Plus the ingame mechanics have optimized performance, recreating them often yields worse results performance-wise.
 
Status
Not open for further replies.
Top