Improved combat AI

Started by Aeg1s, March 09, 2010, 12:32:46 AM

Previous topic - Next topic

Aeg1s

I've been spending a lot of time lately on improving the games ridiculous combat AI and have come up with the following that I think a lot of people would be interested in so I'm posting it here. Any suggestions and feedback would be appreciated, thanks.  :)


Features:
-Several new attack states to provide a wider range of tactical options to the AI.
-Added a function to set the town gather location (for example to the Natural so the army will gather outside there instead of inside your main)
-Tweaked some values in the attack handling to hopefully provide better engagement/retreat logic
-Raised the retreat threshold so the AI will not abandon attacked towns so quickly and easily.
-The AI will now try and regroup instead of retreating all the way back to its main base.
-The AI will turn around and fire on pursuing units while its retreating if it has a distinct advantage (will revert to retreat when odds drop).




Usage:
Here's the current source for the new and changed code:
http://pastebin.com/nwgRtS1c


If you want to use this copy the constants and town gather functions to the top of MeleeAI.galaxy; and replace the AttackStateName, AIDefendTown, and AIWaveAttack functions.


Or, if you haven't changed MeleeAI or just want a .sc2data version here's the mpq with just a changed MeleeAI.galaxy:
http://dl.dropbox.com/u/5031322/CombatMod/Base.SC2Data


New States:
-Pressure: similar to attack but with a lower threshold for retreating
-Commit: commit to a fight with no chance of retreat (don't set this manually, it is used when the AI is close in strength to the enemy and retreating would most likely result in many losses).
-Defend: Stay back and defend the main base
-Regroup: Retreat for a little ways until out of combat; then regroup, wait for reinforcements and try to move in again (used instead of retreat in most instances).
-Scared_Snipe/Regroup_Snipe: if retreating and spotting a target of opportunity (like lead elements of a pursuit) stop and engage while we have a distinct advantage.


Todo:
-Fix drop attacks
-Fix retreating through the enemy
-Add multiple attack waves (harassing expos with a small force while your main army is engaged)
-Improve idle state logic to improve attack decisisons

Aeg1s


Ability Improvements:
Guardian Shield
function for the Sentry:
http://pastebin.com/dEJeJLG0
(As of right now the sentry will default to using the Guardian Shield. Also, all sentries with enough energy in a group will use it as soon as possible; I intend to fix this soon.


include and add the following to the begging of AIThinkDisruptor in TactProtAI.galaxy:


    if (GuardianShield(player, aiUnit, scanGroup)) {
        return;
    }



Todo:
-Command Centers lift off when under attack.

hd

i've almost completely finished my early game attack rush logic and afterwords am going to work on harassment logic. i think getting at least the early and mid game attack logic should be our first priority.

i also have a few ideas for build logic once i get a usable early/mid attack logic. I plan on making a few posts with code / details once its a little bit more polished. I am curious how you set the gather location and I assume it can be adjusted on the fly...

hd

Quote from: Aeg1s on March 09, 2010, 12:36:06 AM

Ability Improvements:
Guardian Shield
function for the Sentry:
http://pastebin.com/dEJeJLG0
(As of right now the sentry will default to using the Guardian Shield. Also, all sentries with enough energy in a group will use it as soon as possible; I intend to fix this soon.


include and add the following to the begging of AIThinkDisruptor in TactProtAI.galaxy:


    if (GuardianShield(player, aiUnit, scanGroup)) {
        return;
    }



Todo:
-Command Centers lift off when under attack.

As for the cc lifting, one thing you should keep in mind is to do a sweep around the command center for vikings, phoenix and whatever teh zerg one is called

you need to do a risk reward analysis for lifting the cc, in some situations it might be more beneficial to the ai to keep it on the ground rather than lift off.

Kernel64

Awesome, hd! I'll focus on my stuff, and contribute everything to you guys. This is great progress.

Aeg1s

Quote from: hd on March 09, 2010, 12:51:59 AM
I am curious how you set the gather location and I assume it can be adjusted on the fly...


I just made a function to set which town the attack waves gather at (it was using c_townMain). So once your nat goes up you can just call it and set it to the natural and they'll start gathering outside of it.

Doix

Hi Aeg1s. Nice work on changing the AI stuff. Do you have a reason to use an array instead of AISetUserInt/GetUserInt?


const int c_townGather = 109;

int GetTownGather(int player) {
    AIGetUserInt(player,c_townGather);
}

void SetTownGather(int player, int town) {
    AISetUserInt(player,c_townGather,town);
}


Don't you think that is better? This way it'd work for an unlimited number of players + you're not allocating space in an array which doesn't get used (assuming there are less than 8 players).

Sorry, if it looks like I'm trying to convince you :p, had this discussion with Sylvex and he really doesn't like AISetUserInt and AIGetUserInt for a reason which is beyond my comprehension.

hd

#7
Quote from: Aeg1s on March 09, 2010, 03:42:17 PM
Quote from: hd on March 09, 2010, 12:51:59 AM
I am curious how you set the gather location and I assume it can be adjusted on the fly...


I just made a function to set which town the attack waves gather at (it was using c_townMain). So once your nat goes up you can just call it and set it to the natural and they'll start gathering outside of it.

I wonder, can we set a location like UnitGetPosition(UnitGroupUnit(AIWaveGetUnits(c_waveAttack), RandomInt(1, AIWaveUnitCount(c_waveAttack)))) and modify it to be a little ways back towards their main base so we can set a rally location not too far from where they last fought if an attack was successful.

For example...

point hdGetOffensiveGatherLocation(int player, wave w)
{
    point pHome = AIGetTownLocation(player, c_townMain);
    point pWave = UnitGetPosition(UnitGroupUnit(AIWaveGetUnits(w), RandomInt(1, AIWaveUnitCount(w))));
    point pTest = PointAlongLine(pHome, pWave, DistanceBetweenPoints(pHome, pWave) * 0.9);
   
    // hd: return 90% of the distance between where the wave is and where the wave is from but make sure it's pathable.
    if (AIFilterPathable(AIWaveGetUnits(w), pTest))
    {
        return pTest;
    }
   
    // hd: otherwise, go recursive subtracting some distance until we find a pathable spot
    // TODO add recursive check
}

Aeg1s

Quote from: hd on March 09, 2010, 04:44:54 PM
I wonder, can we set a location like UnitGetPosition(UnitGroupUnit(AIWaveGetUnits(c_waveAttack), RandomInt(1, AIWaveUnitCount(c_waveAttack)))) and modify it to be a little ways back towards their main base so we can set a rally location not too far from where they last fought if an attack was successful.


Yeah, that should be possible; I'll look into it; access to a point's data would help a lot. I've also been messing around with getting a contain state working that'll sit outside an opponent's base.

Astazha

I'm extremely interested in this.  I just got an MPQ editor and started poking around the day before yesterday so it will take me some time to get up to speed, but I'm envisioning a modular AI with multiple states to track, and a priority based system of control.


The key part is to make it modular in such a way that multiple people can work on it.


I'd also like to deal with the unknown.  The priority of scouting changes dramatically if you haven't seen your opponent's army in the last 10 minutes, or if it's been that long since you've verified what expansions they have. 


Assumptions can also be made about what the player is building based on how far into the game we are, what the race is, and what units have been seen (particularly recently.)  There might also be some anticipatory functions.  If I just exposed my Brood Lords to my opponent for the first time then I expect an uptake in anti-air.  Doubly so if they wiped out his expansion.


Over time the behavior can be tuned by adjusting constants and multipliers.  We'll also be able to set different versions of play just by tweaking values for Aggressiveness or Defensiveness, and to change those values based on what happens in game.


Initially in creating the framework we can make dummy function that always return "yes, you should be scouting now." or return a random build order.  Once the structure is in place we can begin to refine the individual components.


I don't have anything concrete right now, but this is the direction I'm thinking in.

hd

Quote from: Astazha on March 10, 2010, 09:10:24 PM
I'm extremely interested in this.  I just got an MPQ editor and started poking around the day before yesterday so it will take me some time to get up to speed, but I'm envisioning a modular AI with multiple states to track, and a priority based system of control.


The key part is to make it modular in such a way that multiple people can work on it.


I'd also like to deal with the unknown.  The priority of scouting changes dramatically if you haven't seen your opponent's army in the last 10 minutes, or if it's been that long since you've verified what expansions they have. 


Assumptions can also be made about what the player is building based on how far into the game we are, what the race is, and what units have been seen (particularly recently.)  There might also be some anticipatory functions.  If I just exposed my Brood Lords to my opponent for the first time then I expect an uptake in anti-air.  Doubly so if they wiped out his expansion.


Over time the behavior can be tuned by adjusting constants and multipliers.  We'll also be able to set different versions of play just by tweaking values for Aggressiveness or Defensiveness, and to change those values based on what happens in game.


Initially in creating the framework we can make dummy function that always return "yes, you should be scouting now." or return a random build order.  Once the structure is in place we can begin to refine the individual components.


I don't have anything concrete right now, but this is the direction I'm thinking in.

By turning e_flagsScouting, or something along those lines, on and off, it will scout or stop scouting.

Personally, I think the top priority is attack logic, then build logic. Responding to what the opponent does should be last. I assure you, with good attack logic and build logic, the AI will be pretty tough while response logic alone won't really do much with out giving the AI extra resources to pump massive units.

Astazha

From what I've seen of the scouting AI so far, it's pretty weak.  I've been playing with that flag today, trying to get the AI to even scout all expansion locations with multiple scouts and I haven't been able to do it, even when it can operate largely unopposed.


I agree with the priorities, I just think that in the longer term the AI will need a framework to become really good.  The beauty of modularity is that it allows the contributors to focus on what interests them.


The reason I'm interested in scouting is because it relates to the attack logic.  Not just from a unit counter standpoint, which is complicated, but because the AI needs to be taking out expansions.  The current Starcrack AI often doesn't even know that I have expansions unless it stumbles into them accidentally.  Especially on maps with hidden island expansions, you can just set up camp there and be left alone more or less indefinitely, even if all of your ground accessible bases have been destroyed.  I'd like to teach the AI to exhibit better map control.

hd

Quote from: Astazha on March 10, 2010, 11:17:44 PM
From what I've seen of the scouting AI so far, it's pretty weak.  I've been playing with that flag today, trying to get the AI to even scout all expansion locations with multiple scouts and I haven't been able to do it, even when it can operate largely unopposed.


I agree with the priorities, I just think that in the longer term the AI will need a framework to become really good.  The beauty of modularity is that it allows the contributors to focus on what interests them.


The reason I'm interested in scouting is because it relates to the attack logic.  Not just from a unit counter standpoint, which is complicated, but because the AI needs to be taking out expansions.  The current Starcrack AI often doesn't even know that I have expansions unless it stumbles into them accidentally.  Especially on maps with hidden island expansions, you can just set up camp there and be left alone more or less indefinitely, even if all of your ground accessible bases have been destroyed.  I'd like to teach the AI to exhibit better map control.

I don't think that it's that the AI doesn't know about the expansion but rather it's not told to attack it.

Astazha

I'm still new at all this as I said before, but when I watch the replays in question and select the AI's point of view it has no vision of the expansion, no buildings showing on the mini-map.  Without the AI cheating I would assume that means it's unaware of the presence. 




Kernel64

Do you guys know how to make multiple waves? Like, two main attack waves, one for main attack and the other for back door drops?

Or is this even possible?

How do we control attack waves?