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

TD respawn problem

Status
Not open for further replies.
Level 3
Joined
Feb 9, 2014
Messages
45
this is my spawning trigger:

  • Spawning Area
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set CreepsSpawnCount[1] = 20
      • Set CreepsSpawnCount[2] = 20
      • Set CreepsSpawnCount[3] = 20
      • Set CreepsSpawnCount[4] = 20
      • Set CreepsSpawnCount[5] = 2
      • Set CreepsSpawnCount[6] = 20
      • Set CreepsSpawnCount[7] = 20
      • Set CreepsSpawnCount[8] = 20
      • Set CreepsSpawnCount[9] = 20
      • Set CreepsSpawnCount[10] = 2
      • Set CreepsSpawnCount[11] = 20
      • Set CreepsSpawnCount[12] = 20
      • Set CreepsSpawnCount[13] = 20
      • Set CreepsSpawnCount[14] = 20
      • Set CreepsSpawnCount[15] = 2
      • Set CreepsSpawnCount[16] = 20
      • Set CreepsSpawnCount[17] = 20
      • Set CreepsSpawnCount[18] = 20
      • Set CreepsSpawnCount[19] = 20
      • Set CreepsSpawnCount[20] = 2
      • Set CreepsSpawnCount[21] = 20
      • Set CreepsSpawnCount[22] = 20
      • Set CreepsSpawnCount[23] = 20
      • Set CreepsSpawnCount[24] = 20
      • Set CreepsSpawnCount[25] = 2
      • Set CreepsSpawnCount[26] = 20
      • Set CreepsSpawnCount[27] = 20
      • Set CreepsSpawnCount[28] = 20
      • Set CreepsSpawnCount[29] = 20
      • Set CreepsSpawnCount[30] = 2
      • Set CreepsSpawnCount[31] = 40
      • Set CreepsSpawnCount[32] = 40
      • Set CreepsSpawnCount[33] = 40
      • Set CreepsSpawnCount[34] = 40
      • Set CreepsSpawnCount[35] = 4
      • Set CreepsSpawnCount[36] = 40
      • Set CreepsSpawnCount[37] = 40
      • Set CreepsSpawnCount[38] = 40
      • Set CreepsSpawnCount[39] = 40
      • Set CreepsSpawnCount[40] = 4
      • Set CreepsSpawnCount[41] = 40
      • Set CreepsSpawnCount[42] = 40
      • Set CreepsSpawnCount[43] = 40
      • Set CreepsSpawnCount[44] = 40
      • Set CreepsSpawnCount[45] = 4
      • Set CreepsSpawnCount[46] = 40
      • Set CreepsSpawnCount[47] = 40
      • Set CreepsSpawnCount[48] = 40
      • Set CreepsSpawnCount[49] = 40
      • Set CreepsSpawnCount[50] = 4
All Triggers works fine..
But when i add this trigger (Below): the unit spawn has change, and it only spawn 6 units.. :

  • Pool Elemental Kills
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Killing unit)) Equal to Pool Elemental
    • Actions
      • Set Int_DamageSys_ADDdamage = 2
      • Set Unit_DamageSys_Unit = (Killing unit)
      • Trigger - Run Damage System <gen> (checking conditions)
  • Damage System
    • Events
    • Conditions
    • Actions
      • -------- Required if unit does not have the dummy ability to begin with --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Level of Abi_DamageSys_Damage[1] for Unit_DamageSys_Unit) Equal to 0
        • Then - Actions
          • For each (Integer A) from 1 to Int_DamageSys_DigitCount, do (Actions)
            • Loop - Actions
              • Unit - Add Abi_DamageSys_Damage[(Integer A)] to Unit_DamageSys_Unit
        • Else - Actions
      • -------- Determine Current Damage --------
      • Set Int_DamageSys_CurrentDmg = 0
      • For each (Integer A) from 1 to Int_DamageSys_DigitCount, do (Actions)
        • Loop - Actions
          • Set Int_DamageSys_CurrentDmg = (Int_DamageSys_CurrentDmg + (((Level of Abi_DamageSys_Damage[(Integer A)] for Unit_DamageSys_Unit) - 1) x (Integer((Power(10.00, ((Real((Integer A))) - 1.00)))))))
      • -------- Add Damage --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Int_DamageSys_ADDdamage Greater than 0
        • Then - Actions
          • Set Int_DamageSys_ADDdamage = (Int_DamageSys_ADDdamage + Int_DamageSys_CurrentDmg)
          • For each (Integer A) from 1 to Int_DamageSys_DigitCount, do (Actions)
            • Loop - Actions
              • Set Int_General = ((Int_DamageSys_ADDdamage mod (Integer((Power(10.00, (Real((Integer A)))))))) / (Integer((Power(10.00, ((Real((Integer A))) - 1.00))))))
              • Unit - Set level of Abi_DamageSys_Damage[(Integer A)] for Unit_DamageSys_Unit to (Int_General + 1)
        • Else - Actions
          • For each (Integer A) from 1 to Int_DamageSys_DigitCount, do (Actions)
            • Loop - Actions
              • Unit - Set level of Abi_DamageSys_Damage[(Integer A)] for Unit_DamageSys_Unit to 1
              • Set Int_General = ((Int_DamageSys_SETdamage mod (Integer((Power(10.00, (Real((Integer A)))))))) / (Integer((Power(10.00, ((Real((Integer A))) - 1.00))))))
              • Unit - Set level of Abi_DamageSys_Damage[(Integer A)] for Unit_DamageSys_Unit to (Int_General + 1)
      • Set Int_DamageSys_ADDdamage = 0
      • Set Int_DamageSys_SETdamage = 0
  • Damage System Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set Int_DamageSys_DigitCount = 5
      • Set Abi_DamageSys_Damage[1] = (Damage System) Item Damage Bonus (+1)
      • Set Abi_DamageSys_Damage[2] = (Damage System) Item Damage Bonus (+10)
      • Set Abi_DamageSys_Damage[3] = (Damage System) Item Damage Bonus (+100)
      • Set Abi_DamageSys_Damage[4] = (Damage System) Item Damage Bonus (+1000)
      • Set Abi_DamageSys_Damage[5] = (Damage System) Item Damage Bonus (+10000)
      • Unit - Create 1 Footman for Neutral Passive at (Center of (Playable map area)) facing Default building facing degrees
      • For each (Integer A) from 1 to Int_DamageSys_DigitCount, do (Actions)
        • Loop - Actions
          • Unit - Add Abi_DamageSys_Damage[(Integer A)] to (Last created unit)
      • Unit - Remove (Last created unit) from the game
 
Last edited:
Level 3
Joined
Feb 9, 2014
Messages
45
I don't see anything in the trigger that could cause it to change it, maby it is caused from another trigger?

i have 2 integer A trigger, that one (Above) and this one (Below)

  • Spawning Region Men
    • Events
      • Time - iTsCreepTime expires
    • Conditions
    • Actions
      • Countdown Timer - Destroy TheCreepBrokenWindow
      • Trigger - Turn on Entered Name <gen>
      • For each (Integer A) from 1 to CreepsSpawnCount[LevelCount], do (Actions)
        • Loop - Actions
          • Wait 0.50 seconds
          • Player Group - Pick every player in GamePlayers and do (Actions)
            • Loop - Actions
              • Set tmPoint = ((Picked player) start location)
              • Unit - Create 1 CreepArray[LevelCount] for HostileCreeps at tmPoint facing 2.00 degrees
              • Custom script: call RemoveLocation( udg_tmPoint )
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
Although unlikely the case, do make sure that the op-limit is not being reached on the initialization thread (initialization thread crash). The limit is easily reached if using GUI arrays with large size fields. What happens in the worst case is the thread can crash after initializing only some triggers/values making hard to diagnose faults where stuff inexplicably does not work after a minor change. Usually all triggers will just stop working but that is only the case if you blow all the op-limit on GUI Arrays so no trigger initialization can occur.
 

yip

yip

Level 3
Joined
Jan 15, 2014
Messages
69
so what will i do ?

I didn't read all of it too carefully, but I'm assuming you want to spawn a creep every 0.5 seconds after the timer expires. If so...

Have another trigger be turned on when your timer expires, and have it be time based (so it'll run every 0.5 seconds). When it runs, it spawns the creep(s) you want to, and adds to an integer variable. When the integer variable reaches a certain amount (presumably the amount of creeps the wave will spawn in total), have the trigger turn off itself.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
Ok the problem is with an Integer A collision in the loop. TriggerSleepAction (Wait in GUI) suspends execution of the loop and Integer A uses a global variable to track values. Since another thread then uses Integer A while the spawn trigger is sleeping the value of Integer A is overwritten and corrupted with respects to the spawn trigger.

Although some will argue against using TriggerSleepAction, the actual solution is to not use a for loop with loop value Integer A but to instead use a for loop with loop value set to a custom global variable integer. You can then use this global variable instead of integer A in the spawn trigger for loop and since it does not overlap (coupled, shares usage with etc) with a variable used by other systems the trigger will work correctly again.

Keep in mind it will break if the trigger fires before the spawning finishes. The solution in this case would be to migrate to JASS and use a local variable integer instead. However in such a case it may be worth considering ditching TriggerSleepAction as it is inaccurate and unreliable anyway (timeout varies from session to session and exhibits Round Trip Time based latency in multiplayer games).
 
Something like:

  • Spawning Region Men
  • Events
  • Time - iTsCreepTime expires
  • Conditions
  • Actions
  • Countdown Timer - Destroy TheCreepBrokenWindow
  • Trigger - Turn on Entered Name <gen>
  • Set iCreep_Spawn = CreepsSpawnCount[LevelCount]
  • Trigger - Turn on Spawn Next <gen>
  • Spawn Next
  • Events
  • Time - Every 0.50 seconds of game time
  • Conditions
  • Actions
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • iCreep_Spawn Greater than 0
    • Then - Actions
      • Set iCreep_Spawn = (iCreep_Spawn - 1)
      • Player Group - Pick every player in GamePlayers and do (Actions)
        • Loop - Actions
          • Set tmPoint = ((Picked player) start location)
          • Unit - Create 1 CreepArray[LevelCount] for HostileCreeps at tmPoint facing 2.00 degrees
          • Custom script: call RemoveLocation( udg_tmPoint )
    • Else - Actions
      • Trigger - Turn off (This trigger)
 
Level 5
Joined
Jan 27, 2014
Messages
164
Post#8 has the easiest solution.

In case you're still confused, do this:
Code:
        Countdown Timer - Destroy TheCreepBrokenWindow
        Trigger - Turn on Entered Name <gen>
        For each [I]CUSTOM_INTEGER[/I] from 1 to CreepsSpawnCount[LevelCount], do (Actions)
            Loop - Actions
                Wait 0.50 seconds
                Player Group - Pick every player in GamePlayers and do (Actions)
                    Loop - Actions
                        Set tmPoint = ((Picked player) start location)
                        Unit - Create 1 CreepArray[LevelCount] for HostileCreeps at tmPoint facing 2.00 degrees
                        Custom script:   call RemoveLocation( udg_tmPoint )

Instead of using the default Integer A loop, use the 'For every custom integer...' loop.
Just create a custom integer variable for this matter.
And the problem is solved.
 
Level 3
Joined
Feb 9, 2014
Messages
45
hmmmm.. the problem of mine is the number of spawning ..
i make a trigger that can spawn 20 units per wave, and it works!
But when i add the damage system trigger..
the triggers went wrong, the spawn has change to 6 units per wave, why ?

Post#8 has the easiest solution.

In case you're still confused, do this:
Code:
        Countdown Timer - Destroy TheCreepBrokenWindow
        Trigger - Turn on Entered Name <gen>
        For each [I]CUSTOM_INTEGER[/I] from 1 to CreepsSpawnCount[LevelCount], do (Actions)
            Loop - Actions
                Wait 0.50 seconds
                Player Group - Pick every player in GamePlayers and do (Actions)
                    Loop - Actions
                        Set tmPoint = ((Picked player) start location)
                        Unit - Create 1 CreepArray[LevelCount] for HostileCreeps at tmPoint facing 2.00 degrees
                        Custom script:   call RemoveLocation( udg_tmPoint )

Instead of using the default Integer A loop, use the 'For every custom integer...' loop.
Just create a custom integer variable for this matter.
And the problem is solved.

hi vypur, can you help me with the trigger again ? ^_^ i'm noob for this..
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
the triggers went wrong, the spawn has change to 6 units per wave, why ?
In case you missed the reason.
Ok the problem is with an Integer A collision in the loop. TriggerSleepAction (Wait in GUI) suspends execution of the loop and Integer A uses a global variable to track values. Since another thread then uses Integer A while the spawn trigger is sleeping the value of Integer A is overwritten and corrupted with respects to the spawn trigger.
Since it is corrupted, some number of units will spawn that is possibly not the intended number.
 
Level 5
Joined
Jan 27, 2014
Messages
164
> can you help me with the trigger again
Nah. I think it's better off if you try this one.
It's pretty easy this time around.
Don't rely too much on someone else.
At least you can learn something.

Try to understand the reasons given.

To simply put this, as others have already mentioned:
Waits may break global loop.
You have more than 1 of the same type of loop.
They collide.

The remedy is just using different types of loop.
WE has different preset loops. Integer A and Integer B.
There is another type. Custom Integer loop.
Look in the GUI drop list. There is an option for you to choose for Custom Integer loop.
It's just below Integer B.
Work from there.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
JASS:
function GetForLoopIndexA takes nothing returns integer
    return bj_forLoopAIndex
endfunction
JASS:
integer bj_forLoopAIndex=0
JASS:
integer bj_forLoopAIndexEnd=0
As you can see, it shares the same global variables so can be subject to collision if a thread is suspended for some reason (wait or synchronization).
 
Only because using a global variable IntegerA may bug with waits, it's recommended to use his own custom integer? This sadly would bug the same way, as it still is global.

Also I dont see any reason discussing it here since he doesnt even use the loop_integer in any action inside the loop. :csmile:

Anyway the wait 0.5 seconds is useless inside the loop, move it before the loop or completly remove it.

Don't use Player's start location. Use your own spawn points instead, which you don't need to re-set and remove each time
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
Only because using a global variable IntegerA may bug with waits, it's recommended to use his own custom integer? This sadly would bug the same way, as it still is global.
Yes if you let it run such loops across multiple threads (which is what is happening above). No if you limit execution of the loop to 1 thread (which is possible and even safe if techniques such as locking are used). Basically you have to avoid one thread suspending inside a for loop when another thread runs a for loop using the same global variables. With JASS a local can be used to avoid this problem since it cannot possibly be used concurrently since it provides thread unique storage space.

Also I dont see any reason discussing it here since he doesnt even use the loop_integer in any action inside the loop.
The loop itself still uses the same globals to function. As the wait suspends the thread the values become corrupted by another thread which runs such a loop. This breaks the loop when the thread resumes so it spawns an incorrect number of units.

Anyway the wait 0.5 seconds is useless inside the loop, move it before the loop or completly remove it.
It suspends the thread every time the loop iterates over it, adding delay between loop iterations. He wants this to prevent all units spawning at once, an ugly and performance intensive problem. Although using wait is generally a bad practice as it is not very deterministic (varies from session to session) and is highly inaccurate it does not mean you cannot use it and create something that works.

Not all loops work like this in GUI. It only works with for loops because of how the JASS is produced (it uses a loop and endloop block). Player and Unit Group loops operate entirely differently (function calls) and will cause a thread crash if you try and wait inside them when the wait is executed. Additionally any sort of wait inside a condition function (only possible in jass) will cause a thread crash.

Don't use Player's start location. Use your own spawn points instead, which you don't need to re-set and remove each time
Probably would be more efficient if he used a point array that he filled with all spawn points at map initialization. These points will be constant and easy to navigate through fixing leaking and improving code performance (or at least maintainability).
 
It suspends the thread every time the loop iterates over it, adding delay between loop iterations. He wants this to prevent all units spawning at once, an ugly and performance intensive problem. Although using wait is generally a bad practice as it is not very deterministic (varies from session to session) and is highly inaccurate it does not mean you cannot use it and create something that works.
Yes, I see that it's supposed to work like you said. But doing so with just wait 0.5 seconds inside the loop is totaly wrong.

They will still spawn all at almost same time, because the loop doesnt wait the "wait 0.5 seconds" of first run before starting the second run.

He would want todo sth like: Wait (LoopInteger x 0.5 seconds).
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
They will still spawn all at almost same time, because the loop doesnt wait the "wait 0.5 seconds" of first run before starting the second run.
I do not understand. The thread is suspended the second it runs the wait action (calls TriggerSleepAction) so it cannot run the next iteration of the loop until it resumes (which will take >0.5 seconds normally). After it resumes it runs another iteration of the loop until it again runs the wait action and suspends (again for >0.5 seconds normally). JASS is not a HDL so does not have massive parallelism of blocks.

I do not see how it could run faster than spawning one unit every >0.5 seconds normally.
 
Status
Not open for further replies.
Top