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

[Solved] Trigger Loop not meeting condition goes endlessly, causing CTD

Should I dedicate to something else but triggers?

  • Yes

    Votes: 0 0.0%
  • No

    Votes: 1 100.0%
  • Get a job

    Votes: 0 0.0%

  • Total voters
    1
  • Poll closed .
Status
Not open for further replies.
Level 14
Joined
Dec 24, 2008
Messages
2,126
Hi, I needed some assitance with a code I just made up now, not only does it not do what I intended it to, but it seems that the conditions are never met and thus causing an endless loop that cause a imminent CTD.

The trigger is as follows: There are 6 regions in the map, a RNG will determine where a gold mine will spawn in any of those regions, conditioning that the maximum number of gold mines in map are equal to the amount of players playing x 1/2/3, so basically, if there's one player in-game, with a x3 multiplier, there should be only 3 Gold Mines in the whole map, distributed across various regions.

Two other conditions when checking where to spawn the Gold Mine are wheter that region already has 2 Mines in that same region, or that it spawns distanced away from any player's units.

When testing, it seems to spawn a large amount of mines across the map, about 20, when I'm only playing as singleplayer, with a x2 multiplier, however, for some reason when adding the condition that there should be less than 2 gold mines in that region in order to spawn another, it doesn't meet the requirement, thus looping forever and causing a CTD, no fatal errors, just closes the game completely.

I apologize for the tangling paragraphs ahead, but I thought a quick explanation was needed before pasting the whole thing, so here it goes:

  • Mine Nodes
    • Events
      • Time - MineNodesTimer expires
    • Conditions
    • Actions
      • Set MineNodeChance = (Random integer number between 1 and 6)
      • Set PlayerTown = (Units in (Playable map area) matching (((Matching player) controller) Equal to User))
      • Unit Group - Pick every unit in PlayerTown and do (Actions)
        • Loop - Actions
          • Set PlayerTownPoint = (Position of (Picked unit))
          • Custom script: call DestroyGroup (udg_OutsideBoundaryMines)
          • Set OutsideBoundaryMines = (Units in (Playable map area) matching (((Unit-type of (Matching unit)) Equal to Gold Mine) and (((Mine Node 1 <gen> contains (Matching unit)) Equal to False) and (((Mine Node 2 <gen> contains (Matching unit)) Equal to False) and (((Mine Node 3 <gen> contains
          • Unit Group - Pick every unit in OutsideBoundaryMines and do (Actions)
            • Loop - Actions
              • Set OutsideBoundariesMinePoint = (Position of (Picked unit))
              • Set MinesAwayFromPlayers = (Units in (Playable map area) matching ((((Matching unit) is in OutsideBoundaryMines) Equal to True) and ((Distance between OutsideBoundariesMinePoint and PlayerTownPoint) Greater than 5000.00)))
              • Unit Group - Remove all units of MinesAwayFromPlayers from OutsideBoundaryMines
              • Custom script: call DestroyGroup (udg_MinesAwayFromPlayers)
              • Custom script: call RemoveLocation (udg_OutsideBoundariesMinePoint)
          • Custom script: call RemoveLocation (udg_PlayerTownPoint)
      • Unit Group - Pick every unit in OutsideBoundaryMines and do (Unit - Remove (Picked unit) from the game)
      • Custom script: call DestroyGroup (udg_OutsideBoundaryMines)
      • Set RegionMines[1] = (Units in Mine Node 1 <gen> matching ((Unit-type of (Matching unit)) Equal to Gold Mine))
      • Set RegionMines[2] = (Units in Mine Node 2 <gen> matching ((Unit-type of (Matching unit)) Equal to Gold Mine))
      • Set RegionMines[3] = (Units in Mine Node 3 <gen> matching ((Unit-type of (Matching unit)) Equal to Gold Mine))
      • Set RegionMines[4] = (Units in Mine Node 4 <gen> matching ((Unit-type of (Matching unit)) Equal to Gold Mine))
      • Set RegionMines[5] = (Units in Mine Node 5 <gen> matching ((Unit-type of (Matching unit)) Equal to Gold Mine))
      • Set RegionMines[6] = (Units in Mine Node 6 <gen> matching ((Unit-type of (Matching unit)) Equal to Gold Mine))
      • Set TotalMines = (Units of type Gold Mine)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • MineNodeChance Equal to 1
        • Then - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Number of units in RegionMines[1]) Equal to 0
              • (Number of units in RegionMines[1]) Less than 2
            • Then - Actions
              • Custom script: call DestroyGroup (udg_RegionMines[1])
              • Set MineNodePoint = (Random point in Mine Node 1 <gen>)
              • Unit - Create 1 Gold Mine for Neutral Passive at MineNodePoint facing Default building facing degrees
              • Custom script: call DestroyGroup (udg_TotalMines)
              • Set TotalMines = (Units of type Gold Mine)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                • Then - Actions
                  • Custom script: call DestroyGroup (udg_TotalMines)
                • Else - Actions
                  • Trigger - Run (This trigger) (checking conditions)
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                • Then - Actions
                  • Custom script: call DestroyGroup (udg_TotalMines)
                • Else - Actions
                  • Trigger - Run (This trigger) (checking conditions)
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • MineNodeChance Equal to 2
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Number of units in RegionMines[2]) Equal to 0
                  • (Number of units in RegionMines[2]) Less than 2
                • Then - Actions
                  • Custom script: call DestroyGroup (udg_RegionMines[2])
                  • Set MineNodePoint = (Random point in Mine Node 2 <gen>)
                  • Unit - Create 1 Gold Mine for Neutral Passive at MineNodePoint facing Default building facing degrees
                  • Custom script: call DestroyGroup (udg_TotalMines)
                  • Set TotalMines = (Units of type Gold Mine)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                    • Then - Actions
                      • Custom script: call DestroyGroup (udg_TotalMines)
                    • Else - Actions
                      • Trigger - Run (This trigger) (checking conditions)
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                    • Then - Actions
                      • Custom script: call DestroyGroup (udg_TotalMines)
                    • Else - Actions
                      • Trigger - Run (This trigger) (checking conditions)
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MineNodeChance Equal to 3
                • Then - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Number of units in RegionMines[3]) Equal to 0
                      • (Number of units in RegionMines[3]) Less than 2
                    • Then - Actions
                      • Custom script: call DestroyGroup (udg_RegionMines[3])
                      • Set MineNodePoint = (Random point in Mine Node 3 <gen>)
                      • Unit - Create 1 Gold Mine for Neutral Passive at MineNodePoint facing Default building facing degrees
                      • Custom script: call DestroyGroup (udg_TotalMines)
                      • Set TotalMines = (Units of type Gold Mine)
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                        • Then - Actions
                          • Custom script: call DestroyGroup (udg_TotalMines)
                        • Else - Actions
                          • Trigger - Run (This trigger) (checking conditions)
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                        • Then - Actions
                          • Custom script: call DestroyGroup (udg_TotalMines)
                        • Else - Actions
                          • Trigger - Run (This trigger) (checking conditions)
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • MineNodeChance Equal to 4
                    • Then - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Number of units in RegionMines[4]) Equal to 0
                          • (Number of units in RegionMines[4]) Less than 2
                        • Then - Actions
                          • Custom script: call DestroyGroup (udg_RegionMines[4])
                          • Set MineNodePoint = (Random point in Mine Node 4 <gen>)
                          • Unit - Create 1 Gold Mine for Neutral Passive at MineNodePoint facing Default building facing degrees
                          • Custom script: call DestroyGroup (udg_TotalMines)
                          • Set TotalMines = (Units of type Gold Mine)
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                            • Then - Actions
                              • Custom script: call DestroyGroup (udg_TotalMines)
                            • Else - Actions
                              • Trigger - Run (This trigger) (checking conditions)
                        • Else - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                            • Then - Actions
                              • Custom script: call DestroyGroup (udg_TotalMines)
                            • Else - Actions
                              • Trigger - Run (This trigger) (checking conditions)
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • MineNodeChance Equal to 5
                        • Then - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (Number of units in RegionMines[5]) Equal to 0
                              • (Number of units in RegionMines[5]) Less than 2
                            • Then - Actions
                              • Custom script: call DestroyGroup (udg_RegionMines[5])
                              • Set MineNodePoint = (Random point in Mine Node 5 <gen>)
                              • Unit - Create 1 Gold Mine for Neutral Passive at MineNodePoint facing Default building facing degrees
                              • Custom script: call DestroyGroup (udg_TotalMines)
                              • Set TotalMines = (Units of type Gold Mine)
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                                • Then - Actions
                                  • Custom script: call DestroyGroup (udg_TotalMines)
                                • Else - Actions
                                  • Trigger - Run (This trigger) (checking conditions)
                            • Else - Actions
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                                • Then - Actions
                                  • Custom script: call DestroyGroup (udg_TotalMines)
                                • Else - Actions
                                  • Trigger - Run (This trigger) (checking conditions)
                        • Else - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • MineNodeChance Equal to 6
                            • Then - Actions
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • (Number of units in RegionMines[6]) Equal to 0
                                  • (Number of units in RegionMines[6]) Less than 2
                                • Then - Actions
                                  • Custom script: call DestroyGroup (udg_RegionMines[6])
                                  • Set MineNodePoint = (Random point in Mine Node 6 <gen>)
                                  • Unit - Create 1 Gold Mine for Neutral Passive at MineNodePoint facing Default building facing degrees
                                  • Custom script: call DestroyGroup (udg_TotalMines)
                                  • Set TotalMines = (Units of type Gold Mine)
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                                    • Then - Actions
                                      • Custom script: call DestroyGroup (udg_TotalMines)
                                    • Else - Actions
                                      • Trigger - Run (This trigger) (checking conditions)
                                • Else - Actions
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • (Number of units in TotalMines) Equal to ((Number of players in (All players controlled by a User player)) x MineNodesCount)
                                    • Then - Actions
                                      • Custom script: call DestroyGroup (udg_TotalMines)
                                    • Else - Actions
                                      • Trigger - Run (This trigger) (checking conditions)
                            • Else - Actions
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
Not convinced this is entirely to blame for the problem, but the way you're detecting 'mines away from players' is very flawed. First you grab all the mines that aren't in your 6 regions (maybe relevant question: how are there mines outside these regions? preplaced? spawned by another trigger? Why are they there if you're just going to remove them? in this trigger.) and then compare where they are to the townhalls of all players. Kinda. First off you can't use "matching player" in a Unit group filter like that, so PlayerTown is going to be a completely empty group. Second you're picking ALL player units, not just townhalls.

Even if it did get into the comparing of distances section, this line is going to be a problem: Set MinesAwayFromPlayers = (Units in (Playable map area) matching ((((Matching unit) is in OutsideBoundaryMines) Equal to True) and ((Distance between OutsideBoundariesMinePoint and PlayerTownPoint) Greater than 5000.00))). You're effectively only removing all of the mines that are more than 5000.00 away from the given picked unit's location, so if it's far from that particular unit but right next to another one it'll get removed anyway.

I think you would benefit from a couple organization changes. First, make a region array that contains all the 6 spawning regions; this will stop you from needing all those nested ifs since you can use an integer loop instead. Second, have a global group that contains all the spawned gold mines, that way you don't have to filter out every gold mine you don't want; when you make a new one, add it to this group.


With that in mind the trigger would probably best be written like:

  • Actions
    • Player Group - Pick every player in (All Players) and do (actions)
      • Loop - Actions
        • If (conditions) then do (actions) else (actions)
          • If - Conditions
            • (Picked Player) controller equal to User
            • -------- Might also need to check if they're actually playing, I believe there's a check for that --------
          • Then - Actions
            • Set NumTotalMines = NumTotalMines + MineNodesCount
          • Else - Actions
    • -------- Remove outside boundary mines here if necessary --------
    • -------- Set up the ALL_RELEVANT_MINES group to only contain mines in the 6 regions here if necessary --------
    • For each integer MineSpawn from 1 to NumTotalMines do (Actions)
      • Loop - Actions
        • Set MineNodeChance = Random integer from 1 to 6
        • Set MINE_COUNT = 0
        • Unit Group - Pick every unit in ALL_RELEVANT_MINES and do (Actions)
          • Loop - Actions
            • If (all conditions) then do (actions) else do (actions)
              • If - Conditions
                • (Picked unit) is in MINE_REGIONS[MineNodeChance] equal to true
              • Then - Actions
                • Set MINE_COUNT = MINE_COUNT + 1
              • Else - Actions
        • If (conditions) then (actions) else (actions)
          • If - Conditions
            • MINE_COUNT less than 2
          • Then - Actions
            • Set MineNodePoint = Random Point in MINE_REGIONS[MineNodeChance]
            • -------- Maybe check to make sure it's not too close to any other mine in this region here --------
            • Unit - Create 1 gold mine for Neutral Passive at MineNodePoint facing Default building facing degrees
            • Custom Script - call RemoveLocation(udg_MineNodePoint)
          • Else - Actions
            • -------- If the region was full then just repeat this loop as if nothing had happened and hope you get a valid random region next time; this is brute force, you could choose to exclude these regions from the search but IDK the specifics of your map --------
            • Set MineSpawn = MineSpawn - 1
 
Last edited:
Level 14
Joined
Dec 24, 2008
Messages
2,126
Not convinced this is entirely to blame for the problem, but the way you're detecting 'mines away from players' is very flawed. First you grab all the mines that aren't in your 6 regions (maybe relevant question: how are there mines outside these regions? preplaced? spawned by another trigger? Why are they there if you're just going to remove them? in this trigger.) and then compare where they are to the townhalls of all players. Kinda. First off you can't use "matching player" in a Unit group filter like that, so PlayerTown is going to be a completely empty group. Second you're picking ALL player units, not just townhalls.

Even if it did get into the comparing of distances section, this line is going to be a problem: Set MinesAwayFromPlayers = (Units in (Playable map area) matching ((((Matching unit) is in OutsideBoundaryMines) Equal to True) and ((Distance between OutsideBoundariesMinePoint and PlayerTownPoint) Greater than 5000.00))). You're effectively only removing all of the mines that are more than 5000.00 away from the given picked unit's location, so if it's far from that particular unit but right next to another one it'll get removed anyway.

I think you would benefit from a couple organization changes. First, make a region array that contains all the 6 spawning regions; this will stop you from needing all those nested ifs since you can use an integer loop instead. Second, have a global group that contains all the spawned gold mines, that way you don't have to filter out every gold mine you don't want; when you make a new one, add it to this group.


With that in mind the trigger would probably best be written like:

  • Actions
    • Player Group - Pick every player in (All Players) and do (actions)
      • Loop - Actions
        • If (conditions) then do (actions) else (actions)
          • If - Conditions
            • (Picked Player) controller equal to User
            • -------- Might also need to check if they're actually playing, I believe there's a check for that --------
          • Then - Actions
            • Set NumTotalMines = NumTotalMines + MineNodesCount
          • Else - Actions
    • -------- Remove outside boundary mines here if necessary --------
    • -------- Set up the ALL_RELEVANT_MINES group to only contain mines in the 6 regions here if necessary --------
    • For each integer MineSpawn from 1 to NumTotalMines do (Actions)
      • Loop - Actions
        • Set MineNodeChance = Random integer from 1 to 6
        • Set MINE_COUNT = 0
        • Unit Group - Pick every unit in ALL_RELEVANT_MINES and do (Actions)
          • Loop - Actions
            • If (all conditions) then do (actions) else do (actions)
              • If - Conditions
                • (Picked unit) is in MINE_REGIONS[MineNodeChance] equal to true
              • Then - Actions
                • Set MINE_COUNT = MINE_COUNT + 1
              • Else - Actions
        • If (conditions) then (actions) else (actions)
          • If - Conditions
            • MINE_COUNT less than 2
          • Then - Actions
            • Set MineNodePoint = Random Point in MINE_REGIONS[MineNodeChance]
            • -------- Maybe check to make sure it's not too close to any other mine in this region here --------
            • Unit - Create 1 gold mine for Neutral Passive at MineNodePoint facing Default building facing degrees
            • Custom Script - call RemoveLocation(udg_MineNodePoint)
          • Else - Actions
            • -------- If the region was full then just repeat this loop as if nothing had happened and hope you get a valid random region next time; this is brute force, you could choose to exclude these regions from the search but IDK the specifics of your map --------
            • Set MineSpawn = MineSpawn - 1
Thanks, this was simpler than i thought, although what would be the best way to condition that said mines always spawn distanced from each other and any other player?

And out of curiosity, what does substracting a value from MineSpawn do exactly?
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
And out of curiosity, what does substracting a value from MineSpawn do exactly?
Every time the "For each integer MineSpawn" loop completes and goes back to the top it increases MineSpawn by 1, so the purpose of that line is to counteract that automatic increment. Imagine that there should be 6 mines but MineNodeChance randomly got 3 every time: 333333. The first time it runs it'll make a mine in region 3. The second time it runs it'll make a mine in region 3, but now there are 2 there so it can't make any more. The third time it runs region 3 is full so it doesn't do anything (runs the 'else' half of the tree). The fourth time it runs region 3 is full so... eventually after all 6 runs you will only have 2 mines in region 3 and none anywhere else. I said the method was brute force because once a region is full you're not excluding it from the randomized spawn, so when it randomly picks a full spawn, you just decrease MineSpawn by 1 to run that particular iteration of the loop again until it finds a region that is not full.

what would be the best way to condition that said mines always spawn distanced from each other and any other player?
So by the time the mine spawning trigger runs players could conceivably have built in the 6 spawn regions and you don't want to spawn a gold mine in the middle of a bunch of their buildings? The easiest way would be to make a unit group of all structures and gold mines within SPAWN_RADIUS of the randomly chosen MineNodePoint and check to see that the group is empty. If not, pick a new random spawning point and check again. This is brute force again, and after enough games you will inevitably end up in a situation where no point in the entire region is far enough away from all structures and gold mines and the game is stuck in an infinite loop that crashes the trigger. To avoid that I would put the checking in its own For each Integer <variable> loop so that it eventually times out a point can't be found within X iterations.

  • If (conditions) then (actions) else (actions)
    • If - Conditions
      • MINE_COUNT less than 2
    • Then - Actions
      • For each integer MINE_RANDOMIZER from 1 to 100 do (actions)
        • Loop - Actions
          • Set MineNodePoint = Random Point in MINE_REGIONS[MineNodeChance]
          • Set TempGroup = Units within SPAWN_RADIUS of MineNodePoint matching ((Matching unit is a structure) or (Unit type of Matching unit equal to Gold Mine)
          • If (all conditions) then (actions) else (actions)
            • If - Conditions
              • TempGroup is Empty equal to true
              • -------- I don't remember if this exists in GUI, if not you may have to check that the # of units in the group is 0 --------
            • Then - Actions
              • Unit - Create 1 gold mine for Neutral Passive at MineNodePoint facing Default building facing degrees
              • Custom script: exitwhen true
              • -------- The above line exits the MINE_RANDOMIZER loop because it's successfully placed a mine --------
            • Else - Actions
          • Custom script: call RemoveLocation(udg_MineNodePoint)
          • Custom script: call DestroyGroup(udg_TempGroup)
    • Else - Actions
      • -------- If the region was full then just repeat this loop as if nothing had happened and hope you get a valid random region next time; this is brute force, you could choose to exclude these regions from the search but IDK the specifics of your map --------
      • Set MineSpawn = MineSpawn - 1
Alternatively, you could check the distance to other mines using the ALL_RELEVANT_MINES group or make your own temporary group of the mines already in the chosen region and then compare the distance from MineNodePoint to their locations. You could use the same method with a group of all player TownHall structures and compare the distance to all of them too.
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
Glad to hear! Last caveat is that with 100 loops for finding a point it is possible you could reach the OP limit and cause the trigger to crash. You could probably get away with less, but it really is dependent on how big the regions are and how likely players are to build many buildings in the regions. Probably something like 20 is sufficient and would not be at risk of a thread crash.
 
Status
Not open for further replies.
Top