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

Move Units from Region A to B each round

Status
Not open for further replies.
Level 4
Joined
May 12, 2022
Messages
22
I have multiple small regions in which i'm supposed to build units into. I need to trigger this so that whenever someone builds a unit into any of these regions ex:region A; a copy of said unit will be created on ex:region B. So far i can manage this much as well as add orders to created unit of region B. The problem i'm having is after the next round when it's supposed to recreate the unit again and for each round after that.

So far I have something similar to this:

Event:
Unit - A unit owned by Player 1 (Red) Finishes construction

Condition:
(Region-A <gen> contains (Position of (Triggering unit))) Equal to True
((Triggering unit) is A Hero) Equal to False


Action:
Unit - Create 1 (Unit-type of (Triggering unit)) for (Owner of (Triggering unit)) at (Center of (Region-B <gen> offset by (0.00, 0.00).)) facing Default building facing degrees
Unit - Move (Triggering unit) instantly to (Center of Region-B <gen>)


As the unit is already built in region A repreating the trigger won't do anything.

I thought I needed to change either the event or make a trigger for Set variable = Triggering unit but it doesn't seem to work either. the trigger seems to be dependable on:
Unit - A unit owned by Player 1 (Red) Finishes construction

This is much like Hellhalt TD's battle after level 10 20 30 .. except i need the first built units to stay there and only make copies of themselves each round.
(I have the triggers ready for the rounds but I can't use them if the units can't be recreated)

Sorry if I made a poor job at explaining this. It's the first map I ever make and i'm new to triggers and such.
 
Level 4
Joined
May 12, 2022
Messages
22
I would do it something like this -

have a periodic trigger that checks what units are in region a, and creates doubles in region b.

After I went through every condition that I thought had a chance of working this is what I managed so far with a periodic event.

Events
Time - Every 60.00 seconds of game time

Conditions
((Triggering unit) is A Hero) Equal to False

Actions
Unit Group - Pick every unit in (Units in Region A <gen>) and do (Actions)
Loop - Actions
Unit - Create 1 (Unit-type of (Picked unit)) for (Owner of (Picked unit)) at (Center of Region B <gen>) facing (Center of Region D <gen>)


It seems to do the trick but it might not be very practical as I have 144 regions that need this trigger. This could have been avoided if I had an option to copy/create units from ex:Region A to ex:Region B but to retain the same position they had in region A. The only reason I made this many regions in the first place is because I couldn't find an option of units retaining position like that.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,579
I'm not really following. Can you maybe post some pictures and elaborate some more? It sounds like you want to use Unit Groups but it also sounds like you'll want to use Hashtables/Unit Indexing to manage original positions.

Do the units in Region A get teleported to Region B? I'm not too sure what you mean about retaining position, by your description the units in Region A never move once built, so their position should never be lost.

[Edit]
Correct me if I'm wrong but is this what you want?

Each player has their own "build area" and "battle area". Any units constructed in a player's build area will have a copy created in their battle area at a position relative to their build position.

If this is the case then you should only need 1 Region per build area and battle area. You can store these Regions in a Region array variable and use the Player Number as the [Index]:
  • Events
  • Map initialization
  • Actions
  • -- setup player 1
  • Set Variable BuildArea[1] = Player1BuildArea <gen>
  • Set Variable BattleArea[1] = Player1BattleArea <gen>
  • Set Variable BattleAngle[1] = 270.00
  • --- setup player 2
  • Set Variable BuildArea[2] = Player2BuildArea <gen>
  • Set Variable BattleArea[2] = Player2BattleArea <gen>
  • Set Variable BattleAngle[2] = 270.00
  • --- continue for each player
(I'm writing triggers from memory so they'll look a little weird)

Now whenever a unit is constructed you need to get the Player Number of their owning player:
  • Events
  • Unit - A unit Finishes construction
  • Actions
  • Set Variable BuildPN = Player number of (Owner of (Constructed unit))
BuildPN is an Integer variable. We can plug this Integer into our Array variables to reference that player's specific Region(s) and any other data we've stored for them.

Here's the system in action:
  • Events
  • Unit - A unit Finishes construction
  • Actions
  • Set Variable BuildUnit = Constructed unit
  • Set Variable BuildPlayer = (Owner of BuildUnit)
  • Set Variable BuildPN = Player number of BuildPlayer
  • Set Variable CenterPoint = Center of BuildArea[BuildPN]
  • Set Variable BuildPoint = Position of BuildUnit
  • Set Variable BuildAngle = Angle between CenterPoint and BuildPoint
  • Set Variable BuildOffset = Distance between CenterPoint and BuildPoint
  • Custom script: call RemoveLocation(udg_CenterPoint)
  • Custom script: call RemoveLocation(udg_BuildPoint)
  • Set Variable CenterPoint = Center of BattleArea[BuildPN]
  • Set Variable BuildPoint = CenterPoint offset by BuildOffset towards BuildAngle
  • Unit - Create 1 (Unit-type of BuildUnit) at BuildPoint for BuildPlayer facing BattleAngle[BuildPN]
  • Custom script: call RemoveLocation(udg_CenterPoint)
  • Custom script: call RemoveLocation(udg_BuildPoint)
Variable Types:
BuildUnit = Unit
BuildPlayer = Player
BuildPN = Integer
CenterPoint = Point
BuildPoint = Point
BuildAngle = Real
BuildOffset = Real

Some functions I take advantage of to get the angle, distance, and position of the battle point:
Angle between points
Distance between points
Point with polar offset


If you wanted to create units periodically you would want to store your built units into a Unit Group:
  • Unit - Add BuildUnit to BuildGroup[BuildPN]
You could add this action to the previous trigger. BuildGroup[] is a Unit Group array variable. You NEED to define it's Size in the Variable Editor, unlike most other Array variables where you can leave the Size at the default value of 1. Set it's Size to the highest Player Number in your game, for example 24 if your game has 24 players.

Now you can periodically pick through each unit in BuildGroup[BuildPN] and use the above methods to create their duplicates at the correct positions:
  • Events
  • Time - Every 60.00 seconds of game time
  • Actions
  • Set Variable BuildPlayer = Player 1 (red)
  • Set Variable BuildPN = 1
  • Unit Group - Pick every unit in BuildGroup[BuildPN] and do Actions:
    • Set Variable BuildUnit = (Picked unit)
    • Set Variable CenterPoint = Center of BuildArea[BuildPN]
    • Set Variable BuildPoint = Position of BuildUnit
    • Set Variable BuildAngle = Angle between CenterPoint and BuildPoint
    • Set Variable BuildOffset = Distance between CenterPoint and BuildPoint
    • Custom script: call RemoveLocation(udg_CenterPoint)
    • Custom script: call RemoveLocation(udg_BuildPoint)
    • Set Variable CenterPoint = Center of BattleArea[BuildPN]
    • Set Variable BuildPoint = CenterPoint offset by BuildOffset towards BuildAngle
    • Unit - Create 1 (Unit-type of BuildUnit) at BuildPoint for BuildPlayer facing BattleAngle[BuildPN]
    • Custom script: call RemoveLocation(udg_CenterPoint)
    • Custom script: call RemoveLocation(udg_BuildPoint)
This could be optimized by having the Center of BuildArea/BattleArea permanently stored in a Point array variable for easy access. This would remove the need for the CenterPoint variable to be set/removed constantly.

It could be optimized even further by storing this data directly to the units. It's taxing to run all of these Actions for so many units all at once, but by having this information stored beforehand you avoid needing to do so many calculations. And in this case a lot of the data stays the same so constantly recalculating it is just inefficient. Game spikes or game freezes often occur when A LOT of stuff happens all at once.
 
Last edited:
Level 4
Joined
May 12, 2022
Messages
22
I'm not really following. Can you maybe post some pictures and elaborate some more? It sounds like you want to use Unit Groups but it also sounds like you'll want to use Hashtables/Unit Indexing to manage original positions.

Do the units in Region A get teleported to Region B? I'm not too sure what you mean about retaining position, by your description the units in Region A never move once built, so their position should never be lost.

[Edit]
Correct me if I'm wrong but is this what you want?

Each player has their own "build area" and "battle area". Any units constructed in a player's build area will have a copy created in their battle area at a position relative to their build position.

That's almost correct. There are supposed to be 2 teams, so only 1 build area per team(5 players). That's 2 build areas in total and 1 battlefield with 2 regions in the battlefield(where each team's units are supposed to be created at).
1652528489712.png

The map is a sort of an auto chess/ teamfight tactics or Hellhalt battle style but with a common build area for better fights.(hopefully)
After the units are created they are supposed to attack the enemy team's units and after either team's unit count reaches 0 the round is supposed to be over.

I had a look at the triggers you suggested and even though I'm not yet very familiar with using variables, it looks fairly simple and promising. I hope it will work.
There is 1 variable which I couldn't find on my editor:
  • set.gif
    Set Variable BuildUnit = Constructed unit
The closest one to "Constructed unit" that I can see is:
  • set.gif
    Set Variable BuildUnit = Constructed Structure
Perhaps it works with "Picked unit" as this seems to relate it:
  • unitgroup.gif
    Unit Group - Pick every unit in BuildGroup[BuildPN] and do Actions:

Other than that, I will make some tests soon and reply here. But right now I have some IRL stuff going on.

Anyway, thank you very much for your help. It's much appreciated!
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,579
No problem, and I meant Constructed structure, like I said I was writing all of these triggers from memory so some things wouldn't be perfect.

From the looks of your picture it sounds like a good design would be this:
Fill in the regions inside of the build area with buildable terrain.
Fill in the rest of the build area with unbuildable terrain.
Now you can delete the grid of regions. Do this for both teams.
Use an Integer array variable to track the number of units in the battlefield for both teams.
You'll want to increase this variable by 1 whenever a unit is created and decrease it by 1 whenever a unit dies. It's up to you as to whether summoned units should increase/decrease this variable.
When decreasing this Integer in response to a unit dying, also check to see if it's Equal to 0 using an If Then Else statement. If the Integer is equal to 0 then we know that the team's battlefield is completely empty and can end the round.
Divide all of your players into a Player Group array, one [index] representing North team and the other [index] representing South team. This allows you to use the Pick Every Player action which is very handy when you want to do something for all of the player's on a specific team. For example, rewarding the North team players with 100 gold for winning a round.
How you handle leaving players is up to you but it's something keep in mind. For example, you might want to remove a player from their Team Player Group when they leave the game so that they're excluded from future triggers that would interact with the team.

Here's a triggered example:
  • Events
  • Unit - A unit dies
  • Conditions
  • (Triggering unit) is Summoned Equal to False
  • (Triggering unit) is an Illusion Equal to False
  • Actions
  • Set Variable DeathPN = Player number of (Owner of (Triggering unit))
  • Set Variable DeathTN = TeamNumber[DeathPN]
  • Set Variable BattlefieldCount[DeathTN] = BattlefieldCount[DeathTN] - 1
  • If BattlefieldCount[DeathTN] Equal to 0 then do Actions:
  • Player Group - Pick every player in AlliedTeam[DeathTN] and do (Actions)
    • Loop - Actions
      • Player - Add -100 to (Picked player).Current gold
  • Player Group - Pick every player in EnemyTeam[DeathTN] and do (Actions)
    • Loop - Actions
      • Player - Add 100 to (Picked player).Current gold
Also, here's some explanations that might help you out:

Event Responses are exactly as they sound, a response to an Event. This means that each Event Response is tied to a specific Event. The Event "A unit dies" and the Event Response (Dying unit) or "A unit enters a region" and (Entering unit) are examples of this. You also have access to the (Triggering unit) and (Triggering player) Event Responses which are generic and can be used in any Event that involves a unit or player. For example, when a unit dies, you can get access to that unit using either (Dying unit) or (Triggering unit). It's often recommended to use (Triggering unit) when possible but we won't worry about that just yet.

Variables are a way to preserve data so that you can reference it at any given moment of time from any trigger. They help you send information between different triggers and can also help optimize your triggers to be more efficient. In this case I'm using Variables as a way to keep the triggers efficient and memory leak free.

Memory leaks are basically data that is no longer needed but is still being stored in the game's memory. This stored data isn't going to prevent your map from functioning properly but it will slow it down as the leaks build up over time. We're only really concerned about certain types of memory leaks which come from these main culprits: Points, Unit Groups, Player Groups, and Special Effects. If this concept overwhelms you, don't worry, it's not a do or die situation and is totally optional (but recommended).

The Custom Script action is used to deal with most memory leaks when working in the standard Trigger Editor (GUI). Unfortunately, there's no action like "Remove memory leak" so we have to use Custom Script to manually destroy the leaks ourselves. Custom Script gives your triggers access to code, and when you code your map you have access to more Events/Conditions/Actions. It's basically advanced mode for the Trigger Editor.
 
Last edited:
Status
Not open for further replies.
Top