Main Menu
Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - Aeg1s

#1
AI Development / Improved combat AI
March 09, 2010, 12:32:46 AM
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
#2
AI Development / AI Ability Usage xmls
March 08, 2010, 11:18:55 PM
For those of you who weren't aware TargetFindData.xml and ValidatorData.xml in the game data folder contain some of the logic for targeting and using of abilities. For example here is the stimpack section of ValidatorData:




    <!--
    StimPack
   
        if (already buffed)
            return false;
           
        if (!attacking)
            return false;
           
        if (nearby medivac can heal)
            relax next two constraints:
           
        if (recently damaged)
            return false;
           
        if (!hostile targets)
            return false;
           
        return true;
    -->
    <CValidatorCombine id="TacticalStimPack">
        <Type value="And"/>
        <CombineArray value="TacticalStimPackTestBuff"/>
        <CombineArray value="CasterIsAttacking"/>
        <CombineArray value="CasterNotInCombat"/>
        <CombineArray value="TacticalStimPackHostiles"/>
    </CValidatorCombine>
#3
AI Development / Getting the AI to wallin
March 04, 2010, 09:37:48 PM
Does anyone have any ideas on how we might go about this? I've looked at it and from what I've seen it just isn't possible :(


I can't find any function that lets us specify a point for the building (unless we could manually create the build order specifying the target point?). We'd also need the actual points which would probably need to be hard coded per map (is there even a way to get the map) or, I saw reference to being able to add regions to the map and referencing them in code?


The exposed code doesn't seem to have any concept of the maps topography either except for the function CliffLevel.
#4
AI Development / Code Snippets & Functions
March 04, 2010, 08:45:04 PM

Post any code snippets or functions you have that other people might find useful.


Pretty simple, but useful (it should probably check for the protoss string but I was lazy and didn't run my test until I figured out what PlayerRace returned for protoss.)

int GetRace(int player) {
    string oppRace = PlayerRace(player);
    if (oppRace == "Terr") {
    return c_raceTerran;
    } else if (oppRace == "Zerg") {
    return c_raceZerg;
    } else {
    return c_raceProtoss;
    }
}



A function that will produce up to ToMake # of units but will only queue at most MaxQueued at a single time; this can be used to prevent the standard AISetStock from blocking anything below it from being produced. MakeUnitsPrereq is the same but it checks if you have at least one of prereqBuilding completed first.

void MakeUnits(int player, int ToMake, int MaxQueued, string unitClass) {
    int queue = TechTreeUnitCount(player, unitClass, c_techCountQueuedOrBetter);
    int count = AIKnownUnitCount(player, player, unitClass);
    int inQueue = queue - count;
    int thisCount = ToMake - queue;
    if (queue >= ToMake || inQueue >= MaxQueued) {
        return;
    }
    if (thisCount > MaxQueued) {
        thisCount = MaxQueued;
    }
    AISetStock(player, count + thisCount, unitClass);
}


void MakeUnitsPrereq(int player, int ToMake, int MaxQueued, string unitClass, string prereqBuilding) {
    if (TechTreeUnitCount(player, prereqBuilding, c_techCountCompleteOnly) > 0) {
        MakeUnits(player, ToMake, MaxQueued, unitClass);
    }
}



Here's a sample that will fully use two barracks (1 tech lab, 1 reactor) production in a Marine/Marauder push (the script that uses this pushes before 10/30 but this is used a little longer than that; 10 & 30 were more upper limits to its expected usage. For all intents & purposes they could be 200 to constantly use the barracks until it hits max supply):


MakeUnits(player, 10, 1, c_TU_Marauder);
MakeUnitsPrereq(player, 30, 2, c_TU_Marine, c_TB_BarracksReactor);



This function will build supplyObject until you have at least 10 over your current supply. Note that this isn't useful until you've gotten out of the early game where precise supply timing is important in build orders.


void BuildSupply(int player, string supplyObject) {
    int used = PlayerGetPropertyInt(player, c_playerPropSuppliesUsed);
    //int created = PlayerGetPropertyInt(player, c_playerPropSuppliesMade); // doesn't account for queued units
       
    if (GetRace(player) == c_raceZerg) {
    created = TechTreeUnitCount(player, c_ZU_Overlord, c_techCountQueuedOrBetter) * 8 + TechTreeUnitCount(player, c_ZU_Overseer, c_techCountQueuedOrBetter) * 8;
        created += TechTreeUnitCount(player, c_ZB_Hatchery, c_techCountQueuedOrBetter) * 2 + TechTreeUnitCount(player, c_ZB_Lair, c_techCountQueuedOrBetter) * 2 + TechTreeUnitCount(player, c_ZB_Hive, c_techCountQueuedOrBetter) * 2;
    } else if (GetRace(player) == c_raceProtoss) {
    created = TechTreeUnitCount(player, c_PB_Pylon, c_techCountQueuedOrBetter) * 8 + TechTreeUnitCount(player, c_PB_Nexus, c_techCountQueuedOrBetter) * 10;
    } else if (GetRace(player) == c_raceTerran) {
    created = TechTreeUnitCount(player, c_TB_SupplyDepot, c_techCountQueuedOrBetter) * 8 + TechTreeUnitCount(player, c_TB_CommandCenter, c_techCountQueuedOrBetter) * 11;
        created += TechTreeUnitCount(player, c_TB_OrbitalCommand, c_techCountQueuedOrBetter) * 11 + TechTreeUnitCount(player, c_TB_PlanetaryFortress, c_techCountQueuedOrBetter) * 11;
        created += TechTreeUnitCount(player, "SupplyDepotLowered", c_techCountQueuedOrBetter) * 8;
        // Alias doesn't seem to work right here...
    }
       
    if (created < used + 10) {
        if (created > 60 && GetRace(player) == c_raceProtoss) {
            // Don't clutter up the map making power grids
            // Place them near factories to keep them powered
            AISetStockEx(player, c_townMain, AIKnownUnitCount(player, player, supplyObject) + 1, supplyObject, c_nearCloseFactory, 0);
        } else {
            AISetStock(player, AIKnownUnitCount(player, player, supplyObject) + 1, supplyObject);           
        }
    }
}



AddTech & AddBuilding only create a building/tech if you have a prerequisite building completed (useful for teching up).

void AddTech(int player, string tech, string prereqBuilding) {
    // Don't fill up the SetStock queue if we don't need to (Keep things simple)
    if (AITechCount(player, tech, c_techCountQueuedOrBetter) < 1 && TechTreeUnitCount(player, prereqBuilding, c_techCountCompleteOnly) > 0) {
        AISetStock(player, 1, tech);
    }   
}


void AddBuilding(int player, string building, string prereqBuilding) {
    // Don't fill up the SetStock queue if we don't need to (Keep things simple)
    if (TechTreeUnitCount(player, building, c_techCountQueuedOrBetter) < 1 && TechTreeUnitCount(player, prereqBuilding, c_techCountCompleteOnly) > 0) {
        AISetStock(player, AIKnownUnitCount(player, player, building) + 1, building);
    }   
}



BuildAt checks for a certain supply consumption before making the object


void BuildAt(int player, int count, string unitClass, int supplyCount) {
    if (PlayerGetPropertyInt(player, c_playerPropSuppliesUsed) >= supplyCount && AITechCount(player, unitClass, c_techCountQueuedOrBetter) < count) {
        AISetStock(player, count, unitClass);   
    }
}
#5
AI Development / Chrono Boost working
March 03, 2010, 01:59:11 PM
After doing some digging I've been able to get the AI using Chrono Boost; here's a simple example that will find the player's original Nexus and have it cast Chrono Boost on itself:



static void ChronoBoost(int player) {
    unit u = AIGrabUnit(player, c_PB_Nexus, c_prioScriptControlled, AIGetTownLocation(player, c_townOne));
    order o;
    if (u) {
        o = AICreateOrder(player, "TimeWarp", 0);
        OrderSetTargetUnit(o, u);
        if (UnitOrderIsValid(u, o)) {
            DebugOutput("TimeWarp", false);           
            AICast(u, o, c_noMarker, c_castHold);
        }
    }
}