• 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.

AI prioritize points with more units

Status
Not open for further replies.
Level 12
Joined
May 20, 2009
Messages
822
Okay, so basically I'm trying to make a proof of concept that an AI can make effective use of point-target spells. So, I made a simple version of StarCraft's Psionic Storm, and now I'm building an AI to effectively use it. I have the concept, but it's becoming difficult to script. But basically, the idea is:

A unit comes in range of the caster at any time.
The system will find all units nearby the unit coming in range, within the caster's own sight range. (Important, otherwise it could potentially stream down the whole map because it found a group of units bigger than the group that initially approached the caster)
The system will then bubble sort all the values, to get the top 3 units with the highest number of other nearby units.
Finally, it will cast my Psionic Storm.
Really finally, it will see if any other Psionic Storms are in effect within it's range, and space it out accordingly. (This part hasn't been done yet, but I got ideas)

So, my issue right now is there's an error somewhere I can't quite point out. This is VERY unfinished, so there's a lot of point leaks and other misc leaks that I haven't gotten to yet and I don't think it's MUI yet either, but that doesn't really matter it just needs to function.

Here are the triggers:

  • Add to AI Group
    • Events
      • Map initialization
      • Unit - A unit enters (Playable map area)
      • Unit - A unit leaves (Playable map area)
    • Conditions
    • Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units in (Playable map area) matching ((Unit-type of (Matching unit)) Equal to High Templar)) and do (Actions)
        • Loop - Actions
          • Unit Group - Add (Picked unit) to AI_Group
          • Set AI_MaxIndex = (AI_MaxIndex + 1)
          • Set HT_Unit[AI_MaxIndex] = (Picked unit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Unit-type of (Triggering unit)) Equal to High Templar
        • Then - Actions
          • Unit Group - Add (Triggering unit) to AI_Group
          • Set AI_MaxIndex = (AI_MaxIndex + 1)
          • Set HT_Unit[AI_MaxIndex] = (Triggering unit)
          • For each (Integer AI_Index[2]) from 1 to AI_MaxIndex, do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Leaving unit) Equal to AI_TargetingGroup[AI_Index[2]]
                • Then - Actions
                  • Set AI_TargetingGroup[AI_Index[2]] = AI_TargetingGroup[AI_MaxIndex]
                  • Set AI_TargetingGroup[AI_MaxIndex] = No unit
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Leaving unit) Equal to HT_Unit[AI_Index[2]]
                    • Then - Actions
                      • Unit Group - Add HT_Unit[AI_Index[2]] to AI_Group
                      • Set HT_Unit[AI_Index[2]] = HT_Unit[AI_MaxIndex]
                      • Set HT_Unit[AI_MaxIndex] = No unit
                    • Else - Actions
        • Else - Actions
  • AI
    • Events
      • Time - Every 0.33 seconds of game time
    • Conditions
    • Actions
      • For each (Integer AI_Index[1]) from 1 to AI_MaxIndex, do (Actions)
        • Loop - Actions
          • Set IndexSave[AI_Index[1]] = AI_Index[1]
          • Set AI_Index[1] = 1
          • Custom script: set bj_wantDestroyGroup = true
          • Unit Group - Pick every unit in (Units within 900.00 of (Position of HT_Unit[AI_Index[1]])) and do (Actions)
            • Loop - Actions
              • Set AI_TargetingGroup[AI_Index[1]] = (Picked unit)
              • Set AI_Index[1] = (AI_Index[1] + 1)
              • Set TargetingCount[AI_Index[1]] = (TargetingCount[AI_Index[1]] + 1)
          • Set AI_Index[1] = IndexSave[1]
          • Unit Group - Pick every unit in (Units within 300.00 of (Position of AI_TargetingGroup[AI_Index[1]])) and do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Distance between (Position of HT_Unit[AI_Index[1]]) and (Position of (Picked unit))) Less than or equal to 1400.00
                • Then - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • AI_TargetingGroup[AI_Index[1]] Not equal to No unit
                    • Then - Actions
                      • Set AI_Index[1] = (AI_Index[1] + 1)
                    • Else - Actions
                      • Set AI_TargetingGroup[AI_Index[1]] = (Picked unit)
                      • Set TargetingCount[AI_Index[1]] = (TargetingCount[AI_Index[1]] + 1)
                • Else - Actions
          • For each (Integer AI_Index[3]) from 1 to TargetingCount[AI_Index[1]], do (Actions)
            • Loop - Actions
              • Set bubblesort[AI_Index[3]] = (Number of units in (Units within 300.00 of (Position of AI_TargetingGroup[AI_Index[3]])))
              • Set bubblepoint[AI_Index[3]] = (Position of AI_TargetingGroup[AI_Index[3]])
              • Set bubblecount[AI_Index[1]] = (bubblecount[AI_Index[1]] + 1)
          • For each (Integer AI_Index[4]) from 1 to bubblecount[AI_Index[1]], do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • bubblesort[(AI_Index[4] + tempvar[1])] Greater than bubblesort[(AI_Index[4] + tempvar[2])]
                • Then - Actions
                  • Set tempvar[10] = bubblesort[(AI_Index[4] + tempvar[2])]
                  • Set bubblesort[(AI_Index[4] + tempvar[2])] = bubblesort[(AI_Index[4] + tempvar[1])]
                  • Set bubblesort[(AI_Index[4] + tempvar[1])] = tempvar[10]
                  • Set tempoint[10] = bubblepoint[(AI_Index[4] + tempvar[2])]
                  • Set bubblepoint[(AI_Index[4] + tempvar[2])] = bubblepoint[(AI_Index[4] + tempvar[1])]
                  • Set bubblepoint[(AI_Index[4] + tempvar[1])] = tempoint[10]
                  • Set tempvar[1] = (tempvar[1] + 1)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • tempvar[1] Equal to bubblecount[AI_Index[1]]
                    • Then - Actions
                      • Set tempvar[2] = (tempvar[2] + 1)
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • tempvar[2] Equal to 3
                        • Then - Actions
                          • Set AI_Index[4] = tempvar[1]
                          • Set tempvar[1] = 0
                          • Set tempvar[2] = 0
                        • Else - Actions
                          • Set AI_Index[4] = tempvar[2]
                          • Set tempvar[1] = 0
                    • Else - Actions
                      • Set tempvar[1] = 0
                      • Set AI_Index[4] = tempvar[2]
                • Else - Actions
                  • Set AI_Index[4] = 1
                  • Set tempvar[2] = (tempvar[2] + 1)
          • Unit - Order HT_Unit[AI_Index[1]] to Neutral Dark Ranger - Silence tempoint[10]
 
Level 11
Joined
Dec 19, 2012
Messages
411
Your triggers are quite messy, still I will try to point out the problems inside your triggers.



1.
  • Events
    • Map initialization
    • Unit - A unit enters (Playable map area)
    • Unit - A unit leaves (Playable map area)
I suggest you to separate these events independently, events (especially for Map initialization) are too different to be merged together.


2.
  • Add to AI Group
    • Events
      • Map initialization
      • Unit - A unit enters (Playable map area)
      • Unit - A unit leaves (Playable map area)
    • Conditions
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units in (Playable map area) matching ((Unit-type of (Matching unit)) Equal to High Templar)) and do (Actions)
        • Loop - Actions
          • Unit Group - Add (Picked unit) to AI_Group
          • Set AI_MaxIndex = (AI_MaxIndex + 1)
          • Set HT_Unit[AI_MaxIndex] = (Picked unit)
In first sight, this is a VERY wrong action. Assuming that you have 2 "High Templar" in your map, when map initialization, AI_MaxIndex increased by 2, in game another 1 unit (not "High Templar") added, your AI_MaxIndex would be 4, 2 indexes are again assigned to the same units again. For a unit leaving, you again increase it by 2, and again repeating the same thing.


3.
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • (Unit-type of (Triggering unit)) Equal to High Templar
    • Then - Actions
      • Unit Group - Add (Triggering unit) to AI_Group
      • Set AI_MaxIndex = (AI_MaxIndex + 1)
      • Set HT_Unit[AI_MaxIndex] = (Triggering unit)
Similar problem as 2.


4.
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • (Leaving unit) Equal to HT_Unit[AI_Index[2]]
    • Then - Actions
      • Unit Group - Add HT_Unit[AI_Index[2]] to AI_Group
      • Set HT_Unit[AI_Index[2]] = HT_Unit[AI_MaxIndex]
      • Set HT_Unit[AI_MaxIndex] = No unit
    • Else - Actions
Add a leaving unit to group?


5
  • If - Conditions
    • (Leaving unit) Equal to AI_TargetingGroup[AI_Index[2]]
  • Then - Actions
    • Set AI_TargetingGroup[AI_Index[2]] = AI_TargetingGroup[AI_MaxIndex]
    • Set AI_TargetingGroup[AI_MaxIndex] = No unit
  • Else - Actions
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Leaving unit) Equal to HT_Unit[AI_Index[2]]
      • Then - Actions
        • Unit Group - Add HT_Unit[AI_Index[2]] to AI_Group
        • Set HT_Unit[AI_Index[2]] = HT_Unit[AI_MaxIndex]
        • Set HT_Unit[AI_MaxIndex] = No unit
      • Else - Actions
  • Else - Actions
You forgot to deindex AI_MaxIndex after "High Templar" unit leaves playable map area.




1. Another VERY wrong action, AI_Index[1] shouldn't be used once you're using it in loop. All of the actions are messing due to modification of value of AI_Index[1]


2.
  • AI
    • Events
      • Time - Every 0.33 seconds of game time
    • Conditions
    • Actions
      • For each (Integer AI_Index[1]) from 1 to AI_MaxIndex, do (Actions)
        • Loop - Actions
          • Set IndexSave[AI_Index[1]] = AI_Index[1]
          • Set AI_Index[1] = 1
          • Custom script: set bj_wantDestroyGroup = true
          • Unit Group - Pick every unit in (Units within 900.00 of (Position of HT_Unit[AI_Index[1]])) and do (Actions)
            • Loop - Actions
              • Set AI_TargetingGroup[AI_Index[1]] = (Picked unit)
              • Set AI_Index[1] = (AI_Index[1] + 1)
              • Set TargetingCount[AI_Index[1]] = (TargetingCount[AI_Index[1]] + 1)
          • Set AI_Index[1] = IndexSave[1]
Your HT_Unit[AI_Index[1]] would always returns to same unit due to your
  • Set AI_Index[1] = 1
There still 1 problem present in this unit group looping, but I'll skip it first.

3. I'm unable to find where you define "tempvar" values.


For the rest I'm unable to continue, hopefully you can understand what your triggers doing. Since you mentioned it is a VERY unfinished trigger, i suggest you to recode them, currently it too messy and full of flaws.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,287
Using periodical every 0.33sec is not a good idea in my opinion.
But this is how StarCraft II does it for abilities like feedback and Archon Merge. They run a periodic "Tactical AI" function for the unit which decides that sort of thing.

Psionic Storm is different. Although the Tactical AI function does manage its cooldown and cast ability (for low difficulties), the actual casting of Psionic Storm is done using Tactical AI data. This is all handled internally with various kinds of "Target Search" data. They probably do this for speed, because the sort of searches may be slower in triggers.

StarCraft II has a very useful native function for effective AoE casts. You give it a group, a radius, and a minimum number of units and it returns an optimized point. If one could make such a function efficiently for WC3 your AI will probably be easier to make.
 
Level 12
Joined
May 20, 2009
Messages
822
But this is how StarCraft II does it for abilities like feedback and Archon Merge. They run a periodic "Tactical AI" function for the unit which decides that sort of thing.

Really? Neato. I don't suppose I'd be able to look into how SC2 does this, though, would I? It'd be great if I could see the exact methods they use.

Anyway, this is just another thing to add onto my list of WC3 to-do's. Can't really do it right now due to lack of interest, however.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,287
I don't suppose I'd be able to look into how SC2 does this, though, would I?
You can. You just need to extract the tactical AI galaxy file for the Protoss tactical AI. The function is bound to the High Templar as his tactical AI function.

If you have an AI player controlling the High Templar while running the trigger debugger you can see it making calls to that tactical AI function periodically. I think it is usually every second or so though, so not really "0.33sec".

As I mentioned, Psionic Storm appears to be cast differently. It uses a purely data solution either for convenience of efficiency.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,287
Any idea of the exact filename I should be looking for?
In the "TriggerLibs\Tactical" folder...
Code:
TacticalAI.galaxy
TactProtAI.galaxy
TactTerrAI.galaxy
TactZergAI.galaxy
Should I be looking for an XML file, or a Galaxy file, or an SC2Lib, or what?
Galaxy since they are galaxy functions.

Btw, why even code this when there is a natural implementation already existing in the WC3 AI? Just base your spell of blizzard or fire strike and the AI will use it intelligently on clusters.
It will use it vaguely intelligently. If the ability does something more than simple damage in something more than a simple radius then it will not use it intelligently at all.

For example an ability that damages units in an area but deals more to units above 50% health. The default WC3 cast behaviour cannot use it correctly. In StarCraft II you could create an AI which does.
 
Status
Not open for further replies.
Top