• Check out the results of the Techtree Contest #19!
  • Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • Create a void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!

Loop stops running prematurely

Status
Not open for further replies.
Level 7
Joined
May 11, 2010
Messages
278
This is part of my trigger
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • ASysProjectileLifetime[ASysLoopInt] Greater than 0.00
    • Then - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in ASysKnockedTargets[ASysLoopInt]) Greater than or equal to 1
        • Then - Actions
          • Set ASysProjectileLifetime[ASysLoopInt] = (ASysProjectileLifetime[ASysLoopInt] - 0.02)
          • Game - Display to (All players) the text: (String(ASysProjectileLifetime[ASysLoopInt]))
          • Unit Group - Pick every unit in ASysKnockedTargets[ASysLoopInt] and do (Actions)
            • Loop - Actions
              • Set TempPoint = (Position of (Picked unit))
              • Set TempPoint2 = (TempPoint offset by ASysProjectileSpeed[ASysLoopInt] towards ASysKnockAngle[ASysLoopInt] degrees)
              • Unit - Move (Picked unit) instantly to TempPoint2
              • Custom script: call RemoveLocation(udg_TempPoint)
              • Custom script: call RemoveLocation(udg_TempPoint2)
        • Else - Actions
          • Game - Display to (All players) the text: test 1
          • Set ASysAttackComplete[ASysLoopInt] = True
    • Else - Actions
      • Game - Display to (All players) the text: test 2
      • Unit Group - Pick every unit in ASysKnockedTargets[ASysLoopInt] and do (Actions)
        • Loop - Actions
          • Unit - Unpause (Picked unit)
          • Unit Group - Remove (Picked unit) from ASysKnockedTargets[ASysLoopInt]
      • Set ASysAttackComplete[ASysLoopInt] = True
It runs on a time loop of 0.02 seconds. It's a knockback ability. After about 0.5 seconds, it stops running even though there's still time left on ProjectileLifetime. It doesn't show any of the "test" messages.

I've heard that too many "If/Then/Else"s in the same trigger can cause errors. Might this be because of that or is something else wrong?
 
> After about 0.5 seconds, it stops running even though there's still time left on ProjectileLifetime. It doesn't show any of the "test" messages.

That's a logic issue, not an issue with WC3. Your spell just uses some knockback library so it's hard to see the issue without all of the trigger(s).

> I've heard that too many "If/Then/Else"s in the same trigger can cause errors.

There is no specific limit on the number of conditional branches are in a trigger, but there is a very hard and very tangible limit on the number of operations that can be performed within one virtual thread. I see no indication of this happening here.

> Solved it by "outsourcing" that part to another trigger.

Specifically?
 
  • ASysKnockbackLoop
    • Events
      • Time - Every 0.02 seconds of game time
    • Conditions
    • Actions
      • For each (Integer ASysKnockLoopInt) from 1 to ASysKnockInt, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ASysKnockDuration[ASysKnockLoopInt] Greater than 0.00
            • Then - Actions
              • Set ASysKnockDuration[ASysKnockLoopInt] = (ASysKnockDuration[ASysKnockLoopInt] - 0.02)
              • Unit Group - Pick every unit in ASysKnockedTargets[ASysKnockLoopInt] and do (Actions)
                • Loop - Actions
                  • Set TempPoint = (Position of (Picked unit))
                  • Set TempPoint2 = (TempPoint offset by ASysKnockSpeed[ASysKnockLoopInt] towards ASysKnockAngle[ASysKnockLoopInt] degrees)
                  • Unit - Move (Picked unit) instantly to TempPoint2
                  • Custom script: call RemoveLocation(udg_TempPoint)
                  • Custom script: call RemoveLocation(udg_TempPoint2)
            • Else - Actions
              • Unit Group - Pick every unit in ASysKnockedTargets[ASysKnockLoopInt] and do (Actions)
                • Loop - Actions
                  • Unit - Unpause (Picked unit)
                  • Unit Group - Remove (Picked unit) from ASysKnockedTargets[ASysKnockLoopInt]
              • -------- recycle --------
              • Game - Display to (All players) the text: (ASysKnockInt = + (String(ASysKnockInt)))
              • Game - Display to (All players) the text: (ASysKnockLoopInt = + (String(ASysKnockLoopInt)))
              • Set ASysKnockAngle[ASysKnockLoopInt] = ASysKnockAngle[ASysKnockInt]
              • Set ASysKnockDuration[ASysKnockLoopInt] = ASysKnockDuration[ASysKnockInt]
              • Set ASysKnockSpeed[ASysKnockLoopInt] = ASysKnockSpeed[ASysKnockInt]
              • Set ASysKnockedTargets[ASysKnockLoopInt] = ASysKnockedTargets[ASysKnockInt]
              • -------- recycle end --------
              • Set ASysKnockInt = (ASysKnockInt - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ASysKnockInt Equal to 0
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
However, I have another, related problem. As you can see, I'm using an Unit Group array. Trying to add units to a unit group that isn't initialized causes stuff to break as I believe you're well aware. I know there's a custom script for creating unit groups, I don't know what it is though. I want something that checks if a group is created, and if it's not, it creates the group.
Essentially:
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • (UnitGroup[TempInt] exists) Equal to True
    • Then - Actions
    • Else - Actions
      • Unit Group - Create UnitGroup[TempInt]
If someone could perhaps make that for me it would be great ^^
 
I don't know what it is though.
The native is declared as...
JASS:
native CreateGroup takes nothing returns group
Here are some examples of using it.
JASS:
local group g = CreateGroup()
set udg_globalgroup = CreateGroup()
set udg_group_array[1] = CreateGroup()
set udg_garray[udg_loopint] = CreateGroup()

I want something that checks if a group is created, and if it's not, it creates the group.
Something like this would work.
JASS:
if udg_UnitGroup[udg_TempInt] == null then
    set udg_UnitGroup[udg_TempInt] = CreateGroup()
endif

// Explination of above (just another copy of it)...
// We open a conditional block testing if the group array at index TempInt is null
if udg_UnitGroup[udg_TempInt] == null then
    // If so then we set it to a new group.
    // You might want to destroy this group and null it if using an indexing/instancing system since it could be counted as a leak as the result of spike loads on the system.
    set udg_UnitGroup[udg_TempInt] = CreateGroup()
// We need to close the conditional statement. This tells the compiler to end the conditional block.
endif
Each line has to be a separate line of custom script in GUI. I added a commented version to try and explain more clearly what is going on.
 
Thanks Dr Super Good! It seems to work. My trigger, however, does not :P
It works properly as long as only one unit is being knocked. As soon as multiple units are being knocked at the same time, the trigger goes crazy.


  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • ASysIsKnockback[ASysLoopInt] Equal to True
    • Then - Actions
      • Set ASysKnockInt = (ASysKnockInt + 1)
      • Set ASysKnockAngle[ASysKnockInt] = (Facing of ASysCaster[ASysLoopInt])
      • Set ASysKnockDuration[ASysKnockInt] = ASysProjectileLifetime[ASysLoopInt]
      • Set ASysKnockSpeed[ASysKnockInt] = ASysProjectileSpeed[ASysLoopInt]
      • Custom script: if udg_ASysKnockedTargets[udg_ASysKnockInt] == null then
      • Custom script: set udg_ASysKnockedTargets[udg_ASysKnockInt] = CreateGroup()
      • Custom script: endif
      • Unit Group - Pick every unit in ASysHitTargets and do (Actions)
        • Loop - Actions
          • Unit Group - Add (Picked unit) to ASysKnockedTargets[ASysKnockInt]
          • Unit - Make (Picked unit) face ASysCaster[ASysLoopInt] over 0.00 seconds
          • Unit - Pause (Picked unit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (ASysKnockbackLoop <gen> is on) Equal to False
        • Then - Actions
          • Trigger - Turn on ASysKnockbackLoop <gen>
        • Else - Actions
    • Else - Actions
  • ASysKnockbackLoop
    • Events
      • Time - Every 0.02 seconds of game time
    • Conditions
    • Actions
      • For each (Integer ASysKnockLoopInt) from 1 to ASysKnockInt, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ASysKnockDuration[ASysKnockLoopInt] Greater than 0.00
            • Then - Actions
              • Set ASysKnockDuration[ASysKnockLoopInt] = (ASysKnockDuration[ASysKnockLoopInt] - 0.02)
              • Unit Group - Pick every unit in ASysKnockedTargets[ASysKnockLoopInt] and do (Actions)
                • Loop - Actions
                  • Set TempPoint = (Position of (Picked unit))
                  • Set TempPoint2 = (TempPoint offset by ASysKnockSpeed[ASysKnockLoopInt] towards ASysKnockAngle[ASysKnockLoopInt] degrees)
                  • Unit - Move (Picked unit) instantly to TempPoint2
                  • Custom script: call RemoveLocation(udg_TempPoint)
                  • Custom script: call RemoveLocation(udg_TempPoint2)
            • Else - Actions
              • Unit Group - Pick every unit in ASysKnockedTargets[ASysKnockLoopInt] and do (Actions)
                • Loop - Actions
                  • Unit - Unpause (Picked unit)
                  • Unit Group - Remove (Picked unit) from ASysKnockedTargets[ASysKnockLoopInt]
              • -------- recycle --------
              • Set ASysKnockAngle[ASysKnockLoopInt] = ASysKnockAngle[ASysKnockInt]
              • Set ASysKnockDuration[ASysKnockLoopInt] = ASysKnockDuration[ASysKnockInt]
              • Set ASysKnockSpeed[ASysKnockLoopInt] = ASysKnockSpeed[ASysKnockInt]
              • Set ASysKnockedTargets[ASysKnockLoopInt] = ASysKnockedTargets[ASysKnockInt]
              • -------- recycle end --------
              • Set ASysKnockInt = (ASysKnockInt - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ASysKnockInt Equal to 0
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
I have no clue as to why it doens't work. But basically, it seems as if whenever mulitple units are knocked at the same time, they move once per loop no matter what unit group they're in.
 
I didn't show the full setup trigger because it's part of another system and that trigger is looooooooong. I showed the relevant part of it.

Why should I not use the pause unit function? Never had any issues with it before.

Yeah I spent tons of time putting test messages at different places but it didn't help me figure it out.

Good news though! I realized that the way I was doing it was stupid, changed it and now it works seemingly flawlessly.

  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • ASysIsKnockback[ASysLoopInt] Equal to True
    • Then - Actions
      • Unit Group - Pick every unit in ASysHitTargets and do (Actions)
        • Loop - Actions
          • Set ASysKnockInt = (ASysKnockInt + 1)
          • Set ASysKnockAngle[ASysKnockInt] = (Facing of ASysCaster[ASysLoopInt])
          • Set ASysKnockDuration[ASysKnockInt] = ASysProjectileLifetime[ASysLoopInt]
          • Set ASysKnockSpeed[ASysKnockInt] = ASysProjectileSpeed[ASysLoopInt]
          • Set ASysKnockUnit[ASysKnockInt] = (Picked unit)
          • Unit - Make (Picked unit) face ASysCaster[ASysLoopInt] over 0.00 seconds
          • Unit - Pause (Picked unit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (ASysKnockbackLoop <gen> is on) Equal to False
        • Then - Actions
          • Trigger - Turn on ASysKnockbackLoop <gen>
        • Else - Actions
    • Else - Actions
  • ASysKnockbackLoop
    • Events
      • Time - Every 0.02 seconds of game time
    • Conditions
    • Actions
      • For each (Integer ASysKnockLoopInt) from 1 to ASysKnockInt, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ASysKnockDuration[ASysKnockLoopInt] Greater than 0.00
            • Then - Actions
              • Set ASysKnockDuration[ASysKnockLoopInt] = (ASysKnockDuration[ASysKnockLoopInt] - 0.02)
              • Set TempPoint = (Position of ASysKnockUnit[ASysKnockLoopInt])
              • Set TempPoint2 = (TempPoint offset by ASysKnockSpeed[ASysKnockLoopInt] towards ASysKnockAngle[ASysKnockLoopInt] degrees)
              • Unit - Move ASysKnockUnit[ASysKnockLoopInt] instantly to TempPoint2
              • Custom script: call RemoveLocation(udg_TempPoint)
              • Custom script: call RemoveLocation(udg_TempPoint2)
            • Else - Actions
              • Unit - Unpause ASysKnockUnit[ASysKnockLoopInt]
              • -------- recycle --------
              • Set ASysKnockAngle[ASysKnockLoopInt] = ASysKnockAngle[ASysKnockInt]
              • Set ASysKnockDuration[ASysKnockLoopInt] = ASysKnockDuration[ASysKnockInt]
              • Set ASysKnockSpeed[ASysKnockLoopInt] = ASysKnockSpeed[ASysKnockInt]
              • Set ASysKnockUnit[ASysKnockLoopInt] = ASysKnockUnit[ASysKnockInt]
              • -------- recycle end --------
              • Set ASysKnockInt = (ASysKnockInt - 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ASysKnockInt Equal to 0
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
As I was lying in my bed I was suddenly struck with the realization that there is literally no reason to use unit groups for this. So I got up at ~1 am and fixed it. Because that's how I work :P
 
wellllll that is problematic. I want to make sure the unit can't do anything while being knocked though.
I know that a common way to do this is to create a dummy unit and have them cast stormbolt on the unit. However, how do I make the duration of the spell match up to the duration of the knock? Creating one spell for every duration isn't reasonable. Can I set duration or remove the stun with triggers?

Is there another way to make sure the unit can't recieve commands during a period of time? I'd really rather not have to use a dummy unit with stormbolt.
Also, is there a way to make sure a unit can't recieve commands that doesn't disrupt its current orders? Essentially for a period of time it will not listen to any input made by the player but it will continue doing what it was doing before?
 
Status
Not open for further replies.
Back
Top