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

[Trigger] A (Simple?) Problem of "For each Integer A" Loop

Status
Not open for further replies.
Level 2
Joined
Jan 12, 2010
Messages
13
Hello forum fellows.

I'm getting stuck in my Map with a simple problem of Loop. The loop doesn't acts as I expected, and I have no idea why... Here's the trigger:

EDIT: To make your understanding easier, my goal with this trigger is
First> To detect which units have both "Poison Wave" and "Disease Plague"
Second> To make these units get a new Poison that lasts for 8 seconds, dealing (2% MAX Caster HP + Caster Level) damage per second.
The problem> The "For Each Integer A" Loop only occurs once, and even if I apply the damage, it will only proc one time.
The question> Why is the Loop ending sooner than expected? It was intended to range from 1 to 8, increasing by 1 for each second.

-> In my opinion, the Trigger should Display the A integer variable number in each second for all players. ie:

1... (1 second later)
2... (1 second later)
3... (1 second later)
4... (1 second later)

But it Only displays "1 1 1" (it was the number of targets wich had both Poison wave and Disease buffs, as the "Matching condition" dictates) and then the Loop simply ends, as if it had already hit its maximum value (8). Wtf is going on? any ideas?

  • Poison Wave
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
      • (Ability being cast) Equal to Poison Wave (Reworked)
    • Actions
      • Set PWave_Caster = (Casting unit)
      • Set PWave_Damage = ((0.02 x (Max life of PWave_Caster)) + (Real((Level of PWave_Caster))))
      • Wait 2.00 seconds
      • Set PWave_Pickgroup = (Units in (Playable map area) matching ((((Matching unit) has buff Poison Wave ) Equal to True) and (((Matching unit) has buff Disease) Equal to True)))
      • Unit Group - Pick every unit in PWave_Pickgroup and do (Actions)
        • Loop - Actions
          • For each (Integer A) from 1 to 8, do (Actions)
            • Loop - Actions
              • Game - Display to (All players) for 4.00 seconds the text: (String((Integer A)))
              • Wait 1.00 seconds
 
Level 21
Joined
Nov 4, 2013
Messages
2,017
The function you are using is intended to run multiple times according to the second number you set (in your case the 8) so the functions in the "For each integer A loop" will run 8 times instantly.
By the way, replace Begins casting an ability with Starts the effect of an ability so that the damage happens immediately when the ability is casted, not while the hero is still casting it. This also prevents multiple errors like casting the spell when the caster is stunned.
All right, this is a bit complicated but I think it can be solved. You should use a wait of 1 second (no harassing about wait commands being imprecise, thank you xD) as the first function then put the damage. However, this will not allow multiple casters to trigger the damage, just one caster only otherwise overlapping will occur. To be clearer, a unit uses Poison Wave so he becomes the PWave_Caster. 4 seconds of the 8 pass and then another unit casts Poison Wave, causing this unit to be the new PWave_Caster therefore modifying the PWave_Damage. So my question is: Will this skill be applied to one hero of every team, just one specific hero or to multiple heroes of multiple teams?

Waits are not permitted inside Foreach object loops.

They are. I just tested that myself by creating a footman with For each Integer A from 1 to 10 by waiting one second then spawning a footman. Result? 10 footmen spawned in 10 seconds.
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
I wrote foreach object, namely ForGroup, ForForce, EnumItemsInRect, EnumDestructablesInRect, EnumUnits...

That is because they invoke a function pointer and therefore create a new thread that is no longer part of a trigger thread. Even if they were permitted, it would probably not be in succession. It's just more difficult to handle when the LIFO principle is not given and you need to queue things up, hold the iteration in memory etc.

Also it's not good to have Waits in For Each Integer A/B loops either because those are globals, you cannot sensefully have another trigger use Integer A/B meanwhile if one is occupying it over time.
 
Level 2
Joined
Jan 12, 2010
Messages
13
The function you are using is intended to run multiple times according to the second number you set (in your case the 8) so the functions in the "For each integer A loop" will run 8 times instantly.
By the way, replace Begins casting an ability with Starts the effect of an ability so that the damage happens immediately when the ability is casted, not while the hero is still casting it. This also prevents multiple errors like casting the spell when the caster is stunned.
All right, this is a bit complicated but I think it can be solved. You should use a wait of 1 second (no harassing about wait commands being imprecise, thank you xD) as the first function then put the damage. However, this will not allow multiple casters to trigger the damage, just one caster only otherwise overlapping will occur. To be clearer, a unit uses Poison Wave so he becomes the PWave_Caster. 4 seconds of the 8 pass and then another unit casts Poison Wave, causing this unit to be the new PWave_Caster therefore modifying the PWave_Damage. So my question is: Will this skill be applied to one hero of every team, just one specific hero or to multiple heroes of multiple teams?



They are. I just tested that myself by creating a footman with For each Integer A from 1 to 10 by waiting one second then spawning a footman. Result? 10 footmen spawned in 10 seconds.
I just need it For One Hero, this skill gona be unique. And for the "Waits are not permitted inside Foreach object loops.", They are, I tested it by displaying the Integer Number to All players Each second. The problem Here, I THINK, is the Unit Group. For some reason, when actions are determined to occur within an Unit group, somehow it goes bugged.
 
Level 21
Joined
Nov 4, 2013
Messages
2,017
I just need it For One Hero, this skill gona be unique. And for the "Waits are not permitted inside Foreach object loops.", They are, I tested it by displaying the Integer Number to All players Each second. The problem Here, I THINK, is the Unit Group. For some reason, when actions are determined to occur within an Unit group, somehow it goes bugged.

Fantastic! This is easy as pie then. Do what I said and it will work perfectly.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Lets just do this, kay?

  • Apply Poison Damage
    • Events
    • Conditions
    • Actions
      • Custom script: local integer udg_INTEGER
      • Custom script: local unit udg_PoisonDmg_Source
      • Custom script: local unit udg_PoisonDmg_Target
      • Custom script: local integer udg_PoisonDmg_Duration
      • Custom script: local real udg_PoisonDmg_Damage
      • Set PoisonDmg_Source = TempUnit[0]
      • Set PoisonDmg_Target = TempUnit[1]
      • Set PoisonDmg_Duration = TempInteger[0]
      • Set PoisonDmg_Damage = TempReal[0]
      • -------- - --------
      • -------- - --------
      • -------- - --------
      • For each (Integer INTEGER) from 1 to PoisonDmg_Duration, do (Actions)
        • Loop - Actions
          • Wait 1.00 game-time seconds
          • Unit - Cause PoisonDmg_Source to damage PoisonDmg_Target, dealing PoisonDmg_Damage damage of attack type Spells and damage type Poison
      • -------- - --------
      • -------- - --------
      • -------- - --------
      • Set PoisonDmg_Source = No unit
      • Set PoisonDmg_Target = No unit
That trigger will deal MUI damage for Duration seconds. (inaccurate)

To run that trigger, you do:
  • Unit Group - Pick every unit in PWave_Pickgroup and do (Actions)
    • Loop - Actions
      • Set TempUnit[0] = (Triggering unit)
      • Set TempUnit[1] = (Picked unit)
      • Set TempReal[0] = 100.00
      • Set TempInteger[0] = 8
      • Trigger - Run Apply Poison Damage <gen> (ignoring conditions)
However, I assume that this ability is based of Carrison Swarm or Breath of Frost or someting like that.
In that case, you should be using a DDS and preferably a unit indexer to make sure that you apply the poison debuff on the right moment and without having to loop through all units on the map.

One other thing that you should do.
Copy this script below and paste it in the header of your map:
JASS:
    function WaitGameTime takes real duration returns nothing
        local timer t
        local real  timeRemaining
        
        if duration > 0 then
            set t = CreateTimer()
            call TimerStart(t, duration, false, null)
            loop
                set timeRemaining = TimerGetRemaining(t)
                exitwhen timeRemaining <= 0
                
                if timeRemaining > bj_POLLED_WAIT_SKIP_THRESHOLD then
                    call TriggerSleepAction(0.1 * timeRemaining)
                else
                    call TriggerSleepAction(bj_POLLED_WAIT_INTERVAL)
                endif
            endloop
            call DestroyTimer(t)
            set t = null
        endif
    endfunction

then replace the wait action with this:
  • Custom script: call WaitGameTime(1)
@Shadow Fury
Sorry but your solution wouldnt work.
You still need or a new trigger or use timers instead of waits.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
it is not necessarily more effective but this one doesnt leak.

The "Wait <real> seconds" uses real life time and therefor is not paused when the game is paused or cares for game speed. (and is inaccurate)

The "Wait <real> seconds of game-time" uses in game time and therefor does calculate game speed and pauses. (is also inaccurate)
But this one leaks a timer handle.

The custom script is an exact copy of that second wait where I placed that timer handle leak fix in.
So it is not more effective or efficient but it just doesnt leak.
 
Level 2
Joined
Jan 12, 2010
Messages
13
Copy this script below and paste it in the header of your map:
JASS:
    function WaitGameTime takes real duration returns nothing
        local timer t
        local real  timeRemaining
        
        if duration > 0 then
            set t = CreateTimer()
            call TimerStart(t, duration, false, null)
            loop
                set timeRemaining = TimerGetRemaining(t)
                exitwhen timeRemaining <= 0
                
                if timeRemaining > bj_POLLED_WAIT_SKIP_THRESHOLD then
                    call TriggerSleepAction(0.1 * timeRemaining)
                else
                    call TriggerSleepAction(bj_POLLED_WAIT_INTERVAL)
                endif
            endloop
            call DestroyTimer(t)
            set t = null
        endif
    endfunction

then replace the wait action with this:
  • Custom script: call WaitGameTime(1)
@Shadow Fury
Sorry but your solution wouldnt work.
You still need or a new trigger or use timers instead of waits.

I copied this script, but the Editor says it contains an error: call InitTrig_WaitGameTime( ) - Expected a function name
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Ow, you misunderstood the part of the "header file".

Click on that blue WE icon at the top of your triggers with the text "Advanced Cruzer Hill 1.5d.w3x"
That file is called the header file.
Place the script in that place instead of in a new trigger.

@Shadow Fury
If you intended to have a wait action inside the for group, then your solution wouldnt work.
It just breaks execution.
 
Level 2
Joined
Jan 12, 2010
Messages
13
ow, you misunderstood the part of the "header file".

Click on that blue we icon at the top of your triggers with the text "advanced cruzer hill 1.5d.w3x"
that file is called the header file.
Place the script in that place instead of in a new trigger.

@shadow fury
if you intended to have a wait action inside the for group, then your solution wouldnt work.
It just breaks execution.

THANKS A LOT. I would Rep+ you If hadn't already in another post :p
 
Status
Not open for further replies.
Top