• 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.
  • It's time for the first HD Modeling Contest of 2025. Join the theme discussion for Hive's HD Modeling Contest #7! Click here to post your idea!

AI Advise

Status
Not open for further replies.
Level 14
Joined
Oct 16, 2010
Messages
739
Hi,

I've gone back to an old map I made years ago and am attempting to improve the AI system

It is a game a little like castle fight where you build structures, then each round units are created based on the structures you have.

I'm not intending for the AI to absolutely incredible just smart enough to be fun to play against/with

I've generalised all the unit types into their armor types, and what their damage types are strong against. So a Rifleman counts as Medium armor but shows as strong versus Air, Light, and Unarmored (with different values for each)

It all works OK at the moment but I wanted to add another level to their decision making. At the moment the below variable AI_PriorityVS decides what the strongest armor type the enemy has, then I have a seperate buying trigger that uses this to build the relevant structure/unit.

One of the issues is that a Human AI will counter Heavy armor with a Footman, this is because I don't want them saving up gold for ages to build a flying unit or magic unit etc. However this means that they just mass Footman against eachother until they happen to have enough gold to buy something different (such as a Priest or Mortar Team)

What I want to do is have the AI also look at what the enemy DOESN'T have. So if they have lots of verus Heavy they might buy a Light armor unit instead. That's what the 2nd part of the trigger is trying to do. However I'm just getting very confused with myself and can't work out the right formulas!

So to clarify the premise I'm after - rather than the AI mass what they need to counter the enemy, also build units that the enemy can't counter very well. (For example build an Air unit if the enemy has less Air attacking units)

I'm not sure if I have the complete wrong approach for this but I'm playing around with it to see if I can make it a bit more intuative!


  • Team 1 Priority
    • Events
    • Conditions
    • Actions
      • -------- Enemy has lots of this armor type --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Team1VsAir - Team2ArmorAir) Less than or equal to (Team1VsHeavy - Team2ArmorHeavy)
          • (Team1VsAir - Team2ArmorAir) Less than or equal to (Team1VsLight - Team2ArmorLight)
          • (Team1VsAir - Team2ArmorAir) Less than or equal to (Team1VsMedium - Team2ArmorMedium)
          • (Team1VsAir - Team2ArmorAir) Less than or equal to (Team1VsUnarmored - Team2ArmorUnarmored)
        • Then - Actions
          • Set VariableSet AI_PriorityVS = Air
          • Set VariableSet AI_PriorityVS_Real = (Team1VsAir - Team2ArmorAir)
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Team1VsHeavy - Team2ArmorHeavy) Less than or equal to (Team1VsAir - Team2ArmorAir)
              • (Team1VsHeavy - Team2ArmorHeavy) Less than or equal to (Team1VsLight - Team2ArmorLight)
              • (Team1VsHeavy - Team2ArmorHeavy) Less than or equal to (Team1VsMedium - Team2ArmorMedium)
              • (Team1VsHeavy - Team2ArmorHeavy) Less than or equal to (Team1VsUnarmored - Team2ArmorUnarmored)
            • Then - Actions
              • Set VariableSet AI_PriorityVS = Heavy
              • Set VariableSet AI_PriorityVS_Real = (Team1VsHeavy - Team2ArmorHeavy)
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Team1VsLight - Team2ArmorLight) Less than or equal to (Team1VsAir - Team2ArmorAir)
                  • (Team1VsLight - Team2ArmorLight) Less than or equal to (Team1VsHeavy - Team2ArmorHeavy)
                  • (Team1VsLight - Team2ArmorLight) Less than or equal to (Team1VsMedium - Team2ArmorMedium)
                  • (Team1VsLight - Team2ArmorLight) Less than or equal to (Team1VsUnarmored - Team2ArmorUnarmored)
                • Then - Actions
                  • Set VariableSet AI_PriorityVS = Light
                  • Set VariableSet AI_PriorityVS_Real = (Team1VsLight - Team2ArmorLight)
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Team1VsMedium - Team2ArmorMedium) Less than or equal to (Team1VsAir - Team2ArmorAir)
                      • (Team1VsMedium - Team2ArmorMedium) Less than or equal to (Team1VsHeavy - Team2ArmorHeavy)
                      • (Team1VsMedium - Team2ArmorMedium) Less than or equal to (Team1VsLight - Team2ArmorLight)
                      • (Team1VsMedium - Team2ArmorMedium) Less than or equal to (Team1VsUnarmored - Team2ArmorUnarmored)
                    • Then - Actions
                      • Set VariableSet AI_PriorityVS = Medium
                      • Set VariableSet AI_PriorityVS_Real = (Team1VsMedium - Team2ArmorMedium)
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Team1VsUnarmored - Team2ArmorUnarmored) Less than or equal to (Team1VsAir - Team2ArmorAir)
                          • (Team1VsUnarmored - Team2ArmorUnarmored) Less than or equal to (Team1VsHeavy - Team2ArmorHeavy)
                          • (Team1VsUnarmored - Team2ArmorUnarmored) Less than or equal to (Team1VsLight - Team2ArmorLight)
                          • (Team1VsUnarmored - Team2ArmorUnarmored) Less than or equal to (Team1VsMedium - Team2ArmorMedium)
                        • Then - Actions
                          • Set VariableSet AI_PriorityVS = Unarmored
                          • Set VariableSet AI_PriorityVS_Real = (Team1VsUnarmored - Team2ArmorUnarmored)
                        • Else - Actions
      • -------- Enemy does not have much versus this armor type --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Team2VsAir - Team1ArmorAir) Less than or equal to (Team2VsHeavy - Team1ArmorHeavy)
          • (Team2VsAir - Team1ArmorAir) Less than or equal to (Team2VsLight - Team1ArmorLight)
          • (Team2VsAir - Team1ArmorAir) Less than or equal to (Team2VsMedium - Team1ArmorMedium)
          • (Team2VsAir - Team1ArmorAir) Less than or equal to (Team2VsUnarmored - Team1ArmorUnarmored)
        • Then - Actions
          • Set VariableSet AI_PriorityDef = Air
          • Set VariableSet AI_PriorityDef_Real = (Team2VsAir - Team1ArmorAir)
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Team2VsHeavy - Team1ArmorHeavy) Less than or equal to (Team2VsAir - Team1ArmorAir)
              • (Team2VsHeavy - Team1ArmorHeavy) Less than or equal to (Team2VsLight - Team1ArmorLight)
              • (Team2VsHeavy - Team1ArmorHeavy) Less than or equal to (Team2VsMedium - Team1ArmorMedium)
              • (Team2VsHeavy - Team1ArmorHeavy) Less than or equal to (Team2VsUnarmored - Team1ArmorUnarmored)
            • Then - Actions
              • Set VariableSet AI_PriorityDef = Heavy
              • Set VariableSet AI_PriorityDef_Real = (Team2VsHeavy - Team1ArmorHeavy)
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Team2VsLight - Team1ArmorLight) Less than or equal to (Team2VsAir - Team1ArmorAir)
                  • (Team2VsLight - Team1ArmorLight) Less than or equal to (Team2VsHeavy - Team1ArmorHeavy)
                  • (Team2VsLight - Team1ArmorLight) Less than or equal to (Team2VsMedium - Team1ArmorMedium)
                  • (Team2VsLight - Team1ArmorLight) Less than or equal to (Team2VsUnarmored - Team1ArmorUnarmored)
                • Then - Actions
                  • Set VariableSet AI_PriorityDef = Light
                  • Set VariableSet AI_PriorityDef_Real = (Team2VsLight - Team1ArmorLight)
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Team2VsMedium - Team1ArmorMedium) Less than or equal to (Team2VsAir - Team1ArmorAir)
                      • (Team2VsMedium - Team1ArmorMedium) Less than or equal to (Team2VsHeavy - Team1ArmorHeavy)
                      • (Team2VsMedium - Team1ArmorMedium) Less than or equal to (Team2VsLight - Team1ArmorLight)
                      • (Team2VsMedium - Team1ArmorMedium) Less than or equal to (Team2VsUnarmored - Team1ArmorUnarmored)
                    • Then - Actions
                      • Set VariableSet AI_PriorityDef = Medium
                      • Set VariableSet AI_PriorityDef_Real = (Team2VsMedium - Team1ArmorMedium)
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • (Team2VsUnarmored - Team1ArmorUnarmored) Less than or equal to (Team2VsAir - Team1ArmorAir)
                          • (Team2VsUnarmored - Team1ArmorUnarmored) Less than or equal to (Team2VsHeavy - Team1ArmorHeavy)
                          • (Team2VsUnarmored - Team1ArmorUnarmored) Less than or equal to (Team2VsLight - Team1ArmorLight)
                          • (Team2VsUnarmored - Team1ArmorUnarmored) Less than or equal to (Team2VsMedium - Team1ArmorMedium)
                        • Then - Actions
                          • Set VariableSet AI_PriorityDef = Unarmored
                          • Set VariableSet AI_PriorityDef_Real = (Team2VsUnarmored - Team1ArmorUnarmored)
                        • Else - Actions
      • Game - Display to (All players) the text: ((Name of (Player((Integer A)))) + ( vs priority : + AI_PriorityVS))
      • Game - Display to (All players) the text: (String(AI_PriorityVS_Real))
      • Game - Display to (All players) the text: ((Name of (Player((Integer A)))) + ( def priority : + AI_PriorityDef))
      • Game - Display to (All players) the text: (String(AI_PriorityDef_Real))
 

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,533
I think you're on the right path, however, I would suggest using Arrays/Hashtables to store your data since it'll be much more organized. This should help you think straight when working with the data and enable you to make more advanced decisions.

I also think that adding some kind of default behavior to the AI would be interesting, like each AI is randomly given a behavior at the start of the game:
"Very aggressive"
"Very defensive"
"Likes to tech"
"Random and chaotic"

It could fallback to this default behavior under certain circumstances. This way the AI isn't so reactive all of the time and feels more natural.


That aside, I attached a map with how I would go about this sort of thing - not to say that this is better or that you should use this design. Note that the map is meant to be expanded and is currently only setup to track the Power of the Attack and Defense types for the Footman, Rifleman, and Priest. Power is an Integer value that defines how strong a certain thing is. Here's a quick summary of the triggers. I've cut out a lot of the fluff in these triggers to help explain how it all works.

First I define the different Attack and Defense types using Integers. These are constant variables which should never change once set and are meant to be used in the [index] of your other variable Arrays:
  • AI Setup Constants
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • -------- Define the Attack-Type Constants: --------
      • Set VariableSet ATK_NORMAL = 1
      • Set VariableSet ATK_PIERCE = 2
      • Set VariableSet ATK_MAGIC = 3
      • -------- --------
      • -------- Define the Defense-Type Constants: --------
      • Set VariableSet DEF_MEDIUM = 1
      • Set VariableSet DEF_LARGE = 2
      • Set VariableSet DEF_UNARMORED = 3
After defining the constants, we move on to actually adding different unit-types to the system.
Here's a Priest using the system, I'm giving it a MAGIC Attack Power of 1 and UNARMORED Defense Power of 3:
  • AI Setup Unit Types
    • Events
    • Conditions
    • Actions
      • -------- ============================= --------
      • -------- Add Units To The System: --------
      • -------- ============================= --------
      • Set VariableSet AI_Setup_Unit_Type = Priest
      • Set VariableSet AI_Setup_Attack_Power[ATK_MAGIC] = 1
      • Set VariableSet AI_Setup_Defense_Power[DEF_UNARMORED] = 3
      • Trigger - Run AI Save Unit To Hashtable <gen> (ignoring conditions)
This implies that it has a very weak MAGIC attack and a very weak UNARMORED defense. These values can be used to represent anything you want though, I've chosen to represent them this way because it made sense to me. Here's where you would want to add more Setup data like "Can Attack Air = True" and stuff like that. Also, note that a unit can have multiple Attack and Defense types which could serve useful!

Now whenever you train a Unit the system will kick in and Load all of the Saved data related to said Unit:
  • AI Finish Training Unit
    • Events
      • Unit - A unit Finishes training a unit
    • Conditions
    • Actions
      • -------- Get the Integer Id of the Trained unit which we can use to load data from the Hashtable: --------
      • Set VariableSet AI_Unit = (Trained unit)
      • Custom script: set udg_AI_Unit_Type_ID = GetUnitTypeId( udg_AI_Unit )
      • -------- --------
      • -------- (Optional) By setting AI_Team_Number we tell the system to add this unit's Power Data to the Team's total power data: --------
      • Set VariableSet AI_Player = (Owner of AI_Unit)
      • Set VariableSet AI_Team_Number = (Team number of AI_Player)
      • -------- --------
      • -------- This trigger will loop through the different Attack/Defense types and set the related Variables for you to use: --------
      • Trigger - Run AI Load Unit Power Data <gen> (ignoring conditions)
      • -------- --------
      • -------- You can now use the loaded data as you please by referencing the following variables: --------
      • -------- AI_Unit_Attack_Power[ATK_TYPE] --------
      • -------- AI_Unit_Defense_Power[DEF_TYPE] --------
      • -------- AI_Team_Attack_Power[ATK_TYPE] --------
      • -------- AI_Team_Defense_Power[DEF_TYPE] --------
The listed variables in the comment at the bottom are all usable after you run the AI Load Unit Power Data trigger. The Team variables are only available if you have also provided a Team Number by setting the AI_Team_Number variable beforehand.

From that point on you have access to the Unit's power values for it's different Attack Types and Defense Types and potentially have it's Team's total power values as well if you followed the instructions. This would be a good time to tell the AI what to do based on these values.

Here's an example of loading and comparing two Team's total power data to tell your AI what to build next:
  • DEMO COMPARE TEAMS
    • Events
      • Player - Player 1 (Red) types a chat message containing -demo as An exact match
    • Conditions
    • Actions
      • -------- Let's load and store Team 1's total Pierce attack power temporarily: --------
      • Set VariableSet AI_Player = Player 1 (Red)
      • Set VariableSet AI_Team_Number = (Team number of AI_Player)
      • Trigger - Run AI Load Team Power Data <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Demo_Team_1_Attack_Power[ATK_PIERCE] = AI_Team_Attack_Power[ATK_PIERCE]
      • -------- --------
      • -------- Let's load and store Team 2's total Unarmored defense power temporarily: --------
      • Set VariableSet AI_Player = Player 2 (Blue)
      • Set VariableSet AI_Team_Number = (Team number of AI_Player)
      • Trigger - Run AI Load Team Power Data <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Demo_Team_2_Defense_Power[DEF_UNARMORED] = AI_Team_Defense_Power[DEF_UNARMORED]
      • -------- --------
      • -------- Let's compare these values to determine what to tell our AI to do: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Demo_Team_1_Attack_Power[ATK_PIERCE] Less than Demo_Team_2_Defense_Power[DEF_UNARMORED]
        • Then - Actions
          • -------- Team 1's Pierce power is < Team 2's Unarmored power -> Tell Team 1 to train more Pierce units! --------
          • -------- Build stuff --------
        • Else - Actions
          • -------- Team 1's Pierce power is >= Team 2's Unarmored power -> Tell Team 1 to stop training Pierce units! --------
          • -------- Build stuff --------
This entire system's design could use some more work but it's a good starting point. I tried to set it up in a way that it'd be dynamic and work for any number of Teams but it isn't exactly there yet. If it was tailor made for your map (it looks like you'll only ever have 2 teams) then it could be simplified some more.
 

Attachments

  • AI Example 2.w3m
    27.8 KB · Views: 3
Last edited:
Level 14
Joined
Oct 16, 2010
Messages
739
Thanks for the response! Honestly it's such an old map I already had to change up the systems and variables as I didn't know much better back then!

It's an interesting way of indexing, I've never really done that kind of thing of adding different unit types and things to an array system at the start of the map. I will look into whether I can change some bits around based on this!

As you pointed out, my system is very reactive at the moment. I haven't got a strict problem with this but wanted to try making the AI make different decisions occasionally. At the moment they will always buy units that counter the enemies highest defence type (AI_PriorityVS), this technically makes them aggressive I guess?

What I was trying to do was work out a seperate value that I guess would look for the enemies lowest attack type (or versus type as I called it). My version didn't work because it runs on an "or" condition which I think I would need to change. Below is the general layout for my AI picking system

You wouldn't know how to make them pick building spots a bit more wisely too would you? They just pick a random location in the region and will fail to build if that point is occupied. Just another thing I could do with improving

  • Team 1 AI Human
    • Events
    • Conditions
    • Actions
      • Set VariableSet TempPoint = (Random point in Team 1 Build Area <gen>)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Player((Integer A))) Current gold) Greater than or equal to 1150
          • Or - Any (Conditions) are true
            • Conditions
              • AI_PriorityDef Equal to Air
              • AI_PriorityVS Equal to Heavy
              • AI_PriorityVS Equal to Unarmored
        • Then - Actions
          • Unit - Order PlayerBuilder[(Integer A)] to build a Gryphon Aviary at TempPoint
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Player((Integer A))) Current gold) Greater than or equal to 900
              • Or - Any (Conditions) are true
                • Conditions
                  • AI_PriorityDef Equal to Air
                  • AI_PriorityVS Equal to Air
                  • AI_PriorityVS Equal to Light
                  • AI_PriorityVS Equal to Unarmored
            • Then - Actions
              • Unit - Order PlayerBuilder[(Integer A)] to build a Dragonhawk Vault at TempPoint
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Player((Integer A))) Current gold) Greater than or equal to 800
                  • Or - Any (Conditions) are true
                    • Conditions
                      • AI_PriorityDef Equal to Heavy
                      • AI_PriorityVS Equal to Heavy
                      • AI_PriorityVS Equal to Medium
                • Then - Actions
                  • Unit - Order PlayerBuilder[(Integer A)] to build a Keep at TempPoint
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • ((Player((Integer A))) Current gold) Greater than or equal to 650
                      • Or - Any (Conditions) are true
                        • Conditions
                          • AI_PriorityDef Equal to Light
                          • AI_PriorityVS Equal to Heavy
                          • AI_PriorityVS Equal to Unarmored
                    • Then - Actions
                      • Unit - Order PlayerBuilder[(Integer A)] to build a Workshop at TempPoint
                    • Else - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((Player((Integer A))) Current gold) Greater than or equal to 500
                          • Or - Any (Conditions) are true
                            • Conditions
                              • AI_PriorityDef Equal to Unarmored
                              • AI_PriorityVS Equal to Heavy
                        • Then - Actions
                          • Unit - Order PlayerBuilder[(Integer A)] to build a Arcane Sanctum at TempPoint
                        • Else - Actions
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • ((Player((Integer A))) Current gold) Greater than or equal to 350
                              • Or - Any (Conditions) are true
                                • Conditions
                                  • AI_PriorityDef Equal to Medium
                                  • AI_PriorityVS Equal to Air
                                  • AI_PriorityVS Equal to Light
                                  • AI_PriorityVS Equal to Unarmored
                            • Then - Actions
                              • Unit - Order PlayerBuilder[(Integer A)] to build a Blacksmith at TempPoint
                            • Else - Actions
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • ((Player((Integer A))) Current gold) Greater than or equal to 200
                                  • Or - Any (Conditions) are true
                                    • Conditions
                                      • AI_PriorityDef Equal to Heavy
                                      • AI_PriorityVS Equal to Heavy
                                      • AI_PriorityVS Equal to Medium
                                • Then - Actions
                                  • Unit - Order PlayerBuilder[(Integer A)] to build a Barracks at TempPoint
                                • Else - Actions
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • ((Player((Integer A))) Current gold) Greater than or equal to 100
                                      • Or - Any (Conditions) are true
                                        • Conditions
                                          • AI_PriorityDef Equal to Medium
                                          • AI_PriorityVS Equal to Medium
                                    • Then - Actions
                                      • Unit - Order PlayerBuilder[(Integer A)] to build a Farm at TempPoint
                                    • Else - Actions
      • Custom script: call RemoveLocation(udg_TempPoint)
 

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,533
You wouldn't know how to make them pick building spots a bit more wisely too would you? They just pick a random location in the region and will fail to build if that point is occupied. Just another thing I could do with improving
You could fill the Region with an Array or multiple Arrays of Points by using the Point With Polar Offset function and a For Loop. These Points would be offset from one another so there's enough room to build on each one. Then from there you could access these Points either randomly or with some kind of function (GetClosestPoint, GetFurthestPoint, GetMiddlePoint, etc). Then when a Point is chosen to be built on you can Remove it from the Array so it's no longer an available option.

Another approach would be to have two Regions, Frontline and Backline, and whenever you're going to get a Random Point in one of these Regions you instead run a function which "tests" multiple Random Points in the Region for obstacles and returns a valid one. This test can be done with an Item. The idea is simple, keep a hidden Item reserved at all times to be used with this function, then when it's time to test a Point, unhide and move the Item to said Point and proceed to check the Distance Between the Item and the Point. If the Distance is > 1 then we know that the Item was pushed away due to Warcraft 3's pathing system (an Item can't be inside of a Building and will immediately reposition to the closest pathable point). I think it'd be safe and performant to test around 5 Random Points at a time (too many Distance checks happening in the same frame can be taxing). Once you're done testing you can hide the item again. From the user's perspective they'll never even see the Item since it all happens in the same game frame.

You could also combine these methods to get pretty solid results.
 
Last edited:
Level 14
Joined
Oct 16, 2010
Messages
739
I will have to investigate both of those methods!

With the 2nd method wouldn't there be a chance that the item could be in a "valid" position but due to the size of the structure (2x2 - farm size) that clearance wouldn't be accounted for?

It's a complicated situation as the building area is actually shared across 4 players which could be a mix of players/AI. The way the AI build atm is obviously just so messy definitely need to work something out with them
 

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,533
I will have to investigate both of those methods!

With the 2nd method wouldn't there be a chance that the item could be in a "valid" position but due to the size of the structure (2x2 - farm size) that clearance wouldn't be accounted for?

It's a complicated situation as the building area is actually shared across 4 players which could be a mix of players/AI. The way the AI build atm is obviously just so messy definitely need to work something out with them
You can test multiple positions using multiple offsets if there's issues but I doubt there would be.

If the item moves even a hair away it will detect that the point is occupied by a building.
1693351064452.png


I'm not sure how your map is designed but it'd make the most sense to have the building area clear of any other obstructions besides buildings. This way the only time a random Point would fail would be because another building is in the way.
 
Last edited:

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,533
Comparing X/Y could work but remember that when working with Reals you can encounter floating point error so it's generally not a good idea to compare them. For example, a Real with a value of 10.00 could actually be equal to 9.99999, so when comparing it in a Condition you may end up with unexpected and failed results. This loss of precision often occurs after you use the Arithmetic function, so in other words when you add/subtract/multiply/divide/etc. But setting the Real to an exact value seems to always be precise.
 
Last edited:
Status
Not open for further replies.
Top