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

Messages - MisterTea

#1
they simply modified files already presents : http://darkblizz.org/Forum2/index.php?topic=577.0
#2
Not enough Pylons / Re: m3 and m3h files?
February 28, 2010, 02:33:15 PM
Ok found out, its a bit different of m2 files of wow.
There is a php file converter available...
I will try to open the converted files with 3ds max later ...
#3
AI Development / Re: Starcraft 2 functions/libraries here
February 28, 2010, 02:23:58 PM
Quote from: 2g4u on February 28, 2010, 09:02:14 AM
What about the protoss one ?
> page 1 :)
#4
Not enough Pylons / m3 and m3h files?
February 27, 2010, 03:52:12 PM
Hi guys, I would like to open some models/animations but I just can't find any m3 file opener.
Any 3d app can run it ?
#5
AI Development / Re: Starcraft 2 functions/libraries here
February 27, 2010, 03:37:09 PM
Ok I am done, you can discuss ^^ . Hope it will come to help for someone
#6
AI Development / Re: Starcraft 2 functions/libraries here
February 27, 2010, 03:36:28 PM


Zerg.galaxy
//==================================================================================================
//  Zerg Melee AI
//==================================================================================================

include "TriggerLibs/Zerg0"

//--------------------------------------------------------------------------------------------------
//  Counter-Attack Units
//--------------------------------------------------------------------------------------------------
static void InitCounters (int player) {
//xxx lots of old data -- needs to be totally redone
    // versus Protoss
    AICounterUnit(player, c_PU_Zealot,              1.00, c_ZU_Baneling);
    AICounterUnit(player, c_PU_Stalker,             1.00, c_ZU_Roach);
    AICounterUnit(player, c_PU_Immortal,            8.00, c_ZU_Zergling);
    AICounterUnit(player, c_PU_HighTemplar,         2.00, c_ZU_Roach);
    AICounterUnit(player, c_PU_Disruptor,           4.00, c_ZU_Zergling);
    AICounterUnit(player, c_PU_Archon,              4.00, c_ZU_Zergling);
    AICounterUnit(player, c_PU_Archon,              2.00, c_ZU_Hydralisk);
    AICounterUnit(player, c_PU_Archon,              2.00, c_ZU_Roach);
    AICounterUnit(player, c_PU_Colossus,            1.00, c_ZU_Mutalisk);
    AICounterUnit(player, c_PU_VoidRay,             2.00, c_ZU_Corruptor);
    AICounterUnit(player, c_PU_VoidRay,             1.00, c_ZU_Mutalisk);
    AICounterUnit(player, c_PU_Phoenix,             2.00, c_ZU_Hydralisk);
    AICounterUnit(player, c_PU_Carrier,             2.00, c_ZU_Hydralisk);
    AICounterUnit(player, c_PU_Carrier,             2.00, c_ZU_Corruptor);

    // versus Terran
    AICounterUnit(player, c_TU_Marine,              0.60, c_ZU_Baneling);
    AICounterUnit(player, c_TU_Marauder,            3.00, c_ZU_Zergling);
    AICounterUnit(player, c_TU_Hellion,             0.60, c_ZU_Roach);
    AICounterUnit(player, c_TU_Ghost,               6.00, c_ZU_Zergling);
    AICounterUnit(player, c_TU_SiegeTank_Alias,     6.00, c_ZU_Zergling);
    AICounterUnit(player, c_TU_Reaper,              0.30, c_ZU_Mutalisk);
    AICounterUnit(player, c_TU_Thor,               12.00, c_ZU_Zergling);
    AICounterUnit(player, c_TU_Banshee,             0.50, c_ZU_Mutalisk);
    AICounterUnit(player, c_TU_BattlecruiserClass,  2.00, c_ZU_Corruptor);
    AICounterUnit(player, c_TU_BattlecruiserClass,  2.00, c_ZU_Hydralisk);

    // versus Zerg
    AICounterUnit(player, c_ZU_Zergling,            0.25, c_ZU_Baneling);
    AICounterUnit(player, c_ZU_Baneling,            0.25, c_ZU_Lurker);
    AICounterUnit(player, c_ZU_Roach,               3.00, c_ZU_Zergling);
    AICounterUnit(player, c_ZU_Hydralisk,           1.00, c_ZU_Hydralisk);
    AICounterUnit(player, c_ZU_Lurker,              1.50, c_ZU_Hydralisk);
    AICounterUnit(player, c_ZU_Mutalisk,            0.50, c_ZU_Mutalisk);
    AICounterUnit(player, c_ZU_Mutalisk,            0.50, c_ZU_Corruptor);
    AICounterUnit(player, c_ZU_Corruptor,           1.00, c_ZU_Corruptor);
    AICounterUnit(player, c_ZU_BroodLord,       0.50, c_ZU_Corruptor);
}

//--------------------------------------------------------------------------------------------------
//  ZergSubStateName
//--------------------------------------------------------------------------------------------------
string ZergSubStateName (int state) {
    // TODO Call the individual difficulties to return a real substate name
    return "-" + IntToString(state) + "-";
}

//--------------------------------------------------------------------------------------------------
//  DebugCallbackZerg
//--------------------------------------------------------------------------------------------------
void DebugCallbackZerg (int player) {
    DebugAI("=====ZERG=====\n");
    DebugMelee(player);
    DebugAI("e_mainState = "        + MainStateName(AIState(player, e_mainState))           +
            ", e_mainSubState = "   + ZergSubStateName(AIState(player, e_mainSubState))     +
            ", e_attackState = "    + AttackStateName(AIState(player, e_attackState))
    );
}

//--------------------------------------------------------------------------------------------------
//  AINewUnitZerg
//--------------------------------------------------------------------------------------------------
void AINewUnitZerg (int player, unit u) {
    wave w;
    string type = UnitGetType(u);

    // ignored units
    //
    if (type == c_ZU_Larva ||
        type == c_ZU_Broodling ||
        type == c_ZU_Mantaling) {
        return;
    }
    if (UnitTypeTestAttribute(type, c_unitAttributeStructure)) {
        return;
    }
    if (UnitTypeTestFlag(type, c_unitFlagWorker)) {
        return;
    }

    // units that stay near home
    //
    if (type == c_ZB_SpineCrawler || type == c_ZB_SporeCrawler) {
        AIWaveAddUnitPriority(AIWaveGet(player, c_waveHome), u, c_prioWavePeon);
        return;
    }
    if (type == c_ZU_Queen) {
        AIWaveAddUnitPriority(AIWaveGet(player, c_waveHome), u, c_prioWavePeon);
        return;
    }
   
    // detector
    //
    if (type == c_ZU_Overseer) {
        AINewDetector(player, u, true);
        return;
    }

    // extra scout units
    //
    if (type == c_ZU_Overlord || type == c_ZU_OverlordCocoon ) {
        AIAddToExtraScoutGroup(player, u);
        return;
    }

    // clear obstacle units
    //
    if (AIWaveNeedClearObsUnits(player)) {
        if (type == c_ZU_Zergling || type == c_ZU_Roach || type == c_ZU_Hydralisk) {
            AIMergeUnit(player, u, AIWaveGet(player, c_waveClearObs));
            return;
        }
    }

    // main wave units
    //
    AINewUnitDefault(player, u);
}

//--------------------------------------------------------------------------------------------------
//  AIGetScoutZerg
//--------------------------------------------------------------------------------------------------
unit AIGetScoutZerg (int player, int index, unit prev) {   
    unit seer;

    if (!AIGetFlag(player, e_flagsScouting)) {
        return c_nullUnit;
    }
    if (UnitGetType(prev) == c_ZU_Overseer) {
        return prev;
    } 
    seer = AIGrabUnit(player, c_ZU_Overseer, c_prioScout, null);
    if (seer) {
        return seer;
    }
    if (prev) {
        return prev;
    }
    if (AIGetFlag(player, e_flagsLateScout)) {
        return c_nullUnit;
    }
    return AIGrabUnit(player, c_ZU_Overlord, c_prioScout, null);
}

//--------------------------------------------------------------------------------------------------
//  AIEarlyDefScoutZerg
//--------------------------------------------------------------------------------------------------
unit AIEarlyDefScoutZerg (int player, unit prev) {
    unit obs;
   
    if (!AIGetFlag(player, e_flagsEarlyDefScout)) {
        return c_nullUnit;
    }
    if (UnitGetType(prev) == c_ZU_Overseer) {
        return prev;
    }
    obs = AIGrabUnit(player, c_ZU_Overseer, c_prioScout, null);
    if (obs) {
        return obs;
    }
    if (UnitGetType(prev) == c_ZU_Zergling) {
        return prev;
    }
    obs = AIGrabUnit(player, c_ZU_Zergling, c_prioScout, null);
    if (obs) {
        return obs;
    }
    if (prev) {
        return prev;
    }
    return AIGrabUnit(player, c_ZU_Drone, c_prioScout, null);
}


//--------------------------------------------------------------------------------------------------
//  AIWaveThinkZerg
//--------------------------------------------------------------------------------------------------
void AIWaveThinkZerg (int player, wave w, int type) {
    AIWaveThinkDefault(player, w, type);
}

//--------------------------------------------------------------------------------------------------
//  Zerg Init
//--------------------------------------------------------------------------------------------------
static void ZergInit (int player) {
    int state;

    InitCounters(player);
    AISetNumScouts(player, 1);
    AISetFlag(player, e_flagsScouting, true);
    AISetFlag(player, e_flagsEarlyDefScout, false);
    AIReqCountAsBuiltObject(player, c_ZU_Larva);
    AITechCountFixupSingle(player, c_ZB_HydraliskDen, c_ZB_LurkerDen);
    AITechCountFixupSingle(player, c_ZB_Spire, c_ZB_GreaterSpire);
    AITechCountFixupInOrder(player, c_ZB_Hatchery, c_ZB_Lair, c_ZB_Hive);
    AISetCreepBuilding(player, c_ZB_CreepTumor, "ZergBuildingNotOnCreep");

    if (AIGetGroundStartLocs(PlayerStartLocation(player)) > 0) {
        state = AIDiffEnum(player, e_mainState_OpenGnd0);
    }
    else {
        state = AIDiffEnum(player, e_mainState_OpenAir0);
    }
    AISetMainState(player, state, e_mainSubState_Unset);
}

//--------------------------------------------------------------------------------------------------
//  AIMeleeZerg
//--------------------------------------------------------------------------------------------------
void AIMeleeZerg (int player) {
    int mainState = AIState(player, e_mainState);

    if (mainState == e_mainState_Init)              { ZergInit(player);       }

    else if (mainState == e_mainState_OpenGnd0)     { ZergOpenGnd0(player);   }
    //else if (mainState == e_mainState_OpenGnd1)     { ZergOpenGnd1(player);   }
    //else if (mainState == e_mainState_OpenGnd2)     { ZergOpenGnd2(player);   }
    //else if (mainState == e_mainState_OpenGnd3)     { ZergOpenGnd3(player);   }
    //else if (mainState == e_mainState_OpenGnd4)     { ZergOpenGnd4(player);   }
    //else if (mainState == e_mainState_OpenGnd5)     { ZergOpenGnd5(player);   }

    else if (mainState == e_mainState_OpenAir0)     { ZergOpenAir0(player);   }
    //else if (mainState == e_mainState_OpenAir1)     { ZergOpenAir1(player);   }
    //else if (mainState == e_mainState_OpenAir2)     { ZergOpenAir2(player);   }
    //else if (mainState == e_mainState_OpenAir3)     { ZergOpenAir3(player);   }
    //else if (mainState == e_mainState_OpenAir4)     { ZergOpenAir4(player);   }
    //else if (mainState == e_mainState_OpenAir5)     { ZergOpenAir5(player);   }

    else if (mainState == e_mainState_Mid0)         { ZergMid0(player);       }
    //else if (mainState == e_mainState_Mid1)         { ZergMid1(player);       }
    //else if (mainState == e_mainState_Mid2)         { ZergMid2(player);       }
    //else if (mainState == e_mainState_Mid3)         { ZergMid3(player);       }
    //else if (mainState == e_mainState_Mid4)         { ZergMid4(player);       }
    //else if (mainState == e_mainState_Mid5)         { ZergMid5(player);       }

    else if (mainState == e_mainState_Late0)        { ZergLate0(player);      }
    //else if (mainState == e_mainState_Late1)        { ZergLate1(player);      }
    //else if (mainState == e_mainState_Late2)        { ZergLate2(player);      }
    //else if (mainState == e_mainState_Late3)        { ZergLate3(player);      }
    //else if (mainState == e_mainState_Late4)        { ZergLate4(player);      }
    //else if (mainState == e_mainState_Late5)        { ZergLate5(player);      }

    else if (mainState == e_mainState_Off)          { EndMeleeScript(player); }
    else if (mainState == e_mainState_Disabled)     {                         }
   
    else { ErrorMeleeScript(player, "Invalid mainState"); }
}

#7
AI Development / Re: Starcraft 2 functions/libraries here
February 27, 2010, 03:36:04 PM
Terran.galaxy < suite

//--------------------------------------------------------------------------------------------------
//  AIWaveThinkTerr
//--------------------------------------------------------------------------------------------------
void AIWaveThinkTerr (int player, wave w, int type) {
    AIWaveThinkDefault(player, w, type);
}

//--------------------------------------------------------------------------------------------------
//  Terran Init
//--------------------------------------------------------------------------------------------------
static void TerranInit (int player) {
    int state;

    InitCounters(player);
    AISetNumScouts(player, 1);
    AISetFlag(player, e_flagsScouting, false);
    AISetFlag(player, e_flagsEarlyDefScout, false);
    AITechCountFixupEither(player, c_TB_CommandCenter, c_TB_OrbitalCommand, c_TB_PlanetaryFortress);

    if (AIGetGroundStartLocs(PlayerStartLocation(player)) > 0) {
        state = AIDiffEnum(player, e_mainState_OpenGnd0);
    }
    else {
        state = AIDiffEnum(player, e_mainState_OpenAir0);
    }
    AISetMainState(player, state, e_mainSubState_Unset);
}

//--------------------------------------------------------------------------------------------------
//  AIMeleeTerr
//--------------------------------------------------------------------------------------------------
void AIMeleeTerr (int player) {
    int mainState = AIState(player, e_mainState);

    if (mainState == e_mainState_Init)              { TerranInit(player);     }

    else if (mainState == e_mainState_OpenGnd0)     { TerranOpenGnd0(player); }
    //else if (mainState == e_mainState_OpenGnd1)     { TerranOpenGnd1(player); }
    //else if (mainState == e_mainState_OpenGnd2)     { TerranOpenGnd2(player); }
    //else if (mainState == e_mainState_OpenGnd3)     { TerranOpenGnd3(player); }
    //else if (mainState == e_mainState_OpenGnd4)     { TerranOpenGnd4(player); }
    //else if (mainState == e_mainState_OpenGnd5)     { TerranOpenGnd5(player); }

    else if (mainState == e_mainState_OpenAir0)     { TerranOpenAir0(player); }
    //else if (mainState == e_mainState_OpenAir1)     { TerranOpenAir1(player); }
    //else if (mainState == e_mainState_OpenAir2)     { TerranOpenAir2(player); }
    //else if (mainState == e_mainState_OpenAir3)     { TerranOpenAir3(player); }
    //else if (mainState == e_mainState_OpenAir4)     { TerranOpenAir4(player); }
    //else if (mainState == e_mainState_OpenAir5)     { TerranOpenAir5(player); }

    else if (mainState == e_mainState_Mid0)         { TerranMid0(player);     }
    //else if (mainState == e_mainState_Mid1)         { TerranMid1(player);     }
    //else if (mainState == e_mainState_Mid2)         { TerranMid2(player);     }
    //else if (mainState == e_mainState_Mid3)         { TerranMid3(player);     }
    //else if (mainState == e_mainState_Mid4)         { TerranMid4(player);     }
    //else if (mainState == e_mainState_Mid5)         { TerranMid5(player);     }

    else if (mainState == e_mainState_Late0)        { TerranLate0(player);    }
    //else if (mainState == e_mainState_Late1)        { TerranLate1(player);    }
    //else if (mainState == e_mainState_Late2)        { TerranLate2(player);    }
    //else if (mainState == e_mainState_Late3)        { TerranLate3(player);    }
    //else if (mainState == e_mainState_Late4)        { TerranLate4(player);    }
    //else if (mainState == e_mainState_Late5)        { TerranLate5(player);    }

    else if (mainState == e_mainState_Off)          { EndMeleeScript(player); }
    else if (mainState == e_mainState_Disabled)     {                         }
   
    else { ErrorMeleeScript(player, "Invalid mainState"); }
}


Zerg0.galaxy
//==================================================================================================
//  Zerg Melee Very Easy
//==================================================================================================

static void RandomInfantry (int player);
static void LateGround (int player);

//--------------------------------------------------------------------------------------------------
//  ZergOpenGnd0
//--------------------------------------------------------------------------------------------------
void ZergOpenGnd0 (int player) {
    AIClearStock(player);

    AISetStock( player, 1, c_ZB_Hatchery_Alias );
    AISetStock( player, 2, c_ZU_Drone );
    AISetStock( player, 1, c_ZU_Overlord );
    AISetStock( player, 8, c_ZU_Drone );
    AISetStock( player, 1, c_ZB_Extractor );

    AISetStock( player, 1, c_ZU_Queen );
    AISetStock( player, 2, c_ZU_Overlord_Alias );   

    // around 100 resources in about 2 units
    AISetStock( player, 1, c_ZU_Hydralisk );
    ZergTechUp(player, 1);

    if (AIEnableVeryEasyStockOpen(player, c_ZU_Drone)) {
        return;
    }

    // around 300 resources in about 3 unit
    RandomInfantry(player);
}

//--------------------------------------------------------------------------------------------------
//  ZergMidGndA
//--------------------------------------------------------------------------------------------------
static void ZergMidGndA (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_ZB_Hatchery_Alias, c_ZB_Extractor, c_ZU_Overlord_Alias, c_ZU_Drone, 8, c_stockIdle);

    if (AISawCloakedUnit(player)) {
        AISetStock( player, 1, c_ZU_Overseer );
    }

    AISetStockUserData(player);
    AISetStock( player, 1, c_ZU_Queen );
    ZergTechUp(player, 2);

    if (AIEnableVeryEasyStockMidA(player, c_ZU_Drone, 3)) {
        return;
    }

    // around 600 resources in about 4 unit
    RandomInfantry(player);
    AIAddStringInt(player, c_ZU_Infestor, 1);
}

//--------------------------------------------------------------------------------------------------
//  ZergMidGndB
//--------------------------------------------------------------------------------------------------
static void ZergMidGndB (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_ZB_Hatchery_Alias, c_ZB_Extractor, c_ZU_Overlord_Alias, c_ZU_Drone, 8, c_stockIdle);

    if (AISawCloakedUnit(player)) {
        AISetStock( player, 1, c_ZU_Overseer );
        AISetStock( player, 2, c_ZB_SporeCrawler );
    }

    AISetStockUserData(player);
    AISetStock( player, 1, c_ZU_Queen );
    ZergTechUp(player, 3);

    if (AIEnableVeryEasyStockMidB(player, c_ZU_Drone, 4)) {
        return;
    }

    // around 900 resources in about 5 unit
    LateGround(player);
}

//--------------------------------------------------------------------------------------------------
//  LateGround
//--------------------------------------------------------------------------------------------------
static void LateGround (int player) {
    int roll = RandomInt(0,2); // infestors
    if (roll == 0) {
        AIAddStringInt(player, c_ZU_Zergling, 1);
        roll = RandomInt(2,6);
        AIAddStringInt(player, c_ZU_Hydralisk, roll);
        AIAddStringInt(player, c_ZU_Roach, 8 - roll);
    }
    else if (roll == 1) {
        AIAddStringInt(player, c_ZU_Zergling, 1);
        roll = RandomInt(2,3);
        AIAddStringInt(player, c_ZU_Hydralisk, roll);
        AIAddStringInt(player, c_ZU_Roach, 5 - roll);
        AIAddStringInt(player, c_ZU_Infestor, 1);
    }
    else { // infestors == 2
        AIAddStringInt(player, AIPickFrom2(c_ZU_Zergling, c_ZU_Roach), 1);
        AIAddStringInt(player, c_ZU_Hydralisk, 2);
        AIAddStringInt(player, c_ZU_Infestor, 2);
    }
}

//--------------------------------------------------------------------------------------------------
//  LateGnd
//--------------------------------------------------------------------------------------------------
static void LateGnd (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_ZB_Hatchery_Alias, c_ZB_Extractor, c_ZU_Overlord, c_ZU_Drone, 8, c_stockIdle);
    AIDefaultExpansion(player, c_ZB_Hatchery_Alias, 6000, 0, c_expandDefault);

    AISetStockUserData(player);
    AISetStock( player, 1, c_ZR_OverlordTransport );
    AISetStock( player, 3, c_ZU_Overseer );
    ZergTechUp(player, 4);

    if (AIEnableVeryEasyStockLate(player, c_TU_SCV, 4)) {
        return;
    }
    LateGround(player);
}

//--------------------------------------------------------------------------------------------------
//  ZergOpenAir0
//--------------------------------------------------------------------------------------------------
void ZergOpenAir0 (int player) {
    fixed time = AIGetTime();

    AIClearStock(player);
    AISetGasPeons(player, 3, c_ZU_Drone, c_ZB_Extractor );

    AISetStock( player, 1, c_ZB_Hatchery_Alias );
    AISetStock( player, 1, c_ZU_Overlord );
    AISetStock( player, 10, c_ZU_Drone );
    AISetStock( player, 1, c_ZB_Extractor );
    AISetStock( player, 1, c_ZB_SpawningPool );

    if (time >= 150) {
        AISetStock( player, 2, c_ZB_Extractor );
        AISetStock( player, 1, c_ZB_Lair );

        if (time >= 200) {
            AISetStock( player, 2, c_ZU_Overlord );
            AISetStock( player, 1, c_ZB_Spire );
            AISetStock( player, 1, c_ZU_Queen );
            AISetStock( player, 1, c_ZB_HydraliskDen );
            AISetStock( player, 1, c_ZU_Mutalisk );
            AISetStock( player, 2, c_ZU_Hydralisk );

            AISetGasPeons(player, 4, c_ZU_Drone, c_ZB_Extractor );
        }
    }
    AIEnableStock(player);

    //---------------------------------------------------------

    if (AITechCount(player, c_ZU_Mutalisk, c_techCountCompleteOnly) < 1) {
        return;
    }
    AIWaveMerge(player, c_waveMain, c_waveAttack);
    AISetAttackState(player, e_attackState_Attack);
    AISetMainState(player, e_mainState_Mid1, e_mainSubState_AirA);
}

//--------------------------------------------------------------------------------------------------
//  ZergMidAirA
//--------------------------------------------------------------------------------------------------
static void ZergMidAirA (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_ZB_Hatchery_Alias, c_ZB_Extractor, c_ZU_Overlord, c_ZU_Drone, 8, c_stockIdle);

    AISetStock( player, 1, c_ZU_Queen );
    AISetStock( player, 1, c_ZB_Lair );
    AISetStock( player, 1, c_ZU_Mutalisk );
    AISetStock( player, 2, c_ZU_Hydralisk );

    AISetStock( player, 1, c_ZR_OverlordTransport );
    AISetStock( player, 1, c_ZU_Overseer );

    AISetStock( player, 1, c_ZB_EvolutionChamber );
    AISetStock( player, 2, c_ZU_Mutalisk );
    AISetStock( player, 3, c_ZB_SporeCrawler );
    AISetStock( player, 1, c_ZU_Corruptor );

    AIEnableStock(player);

    AISetGasPeons(player, 4, c_ZU_Drone, c_ZB_Extractor );

    //---------------------------------------------------------

    if (AITechCount(player, c_ZU_Corruptor, c_techCountCompleteOnly) < 1) {
        return;
    }
    AIWaveMerge(player, c_waveMain, c_waveAttack);
    AISetAttackState(player, e_attackState_Attack);
    AISetMainState(player, e_mainState_Mid1, e_mainSubState_AirB);
}

//--------------------------------------------------------------------------------------------------
//  ZergMidAirB
//--------------------------------------------------------------------------------------------------
static void ZergMidAirB (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_ZB_Hatchery_Alias, c_ZB_Extractor, c_ZU_Overlord, c_ZU_Drone, 8, c_stockIdle);
    AIDefaultExpansion(player, c_ZB_Hatchery_Alias, 6000, 1000, c_expandDefault);

    AISetStock( player, 1, c_ZU_Queen );
    AISetStock( player, 2, c_ZU_Mutalisk );
    AISetStock( player, 2, c_ZU_Hydralisk );

    AISetStock( player, 1, c_ZR_OverlordTransport );
    AISetStock( player, 1, c_ZR_OverseerSpeed );
    AISetStock( player, 1, c_ZU_Overseer );

    AISetStock( player, 3, c_ZB_SporeCrawler );
    AISetStock( player, 1, c_ZU_Corruptor );

    AISetStock( player, 3, c_ZU_Mutalisk );
    AISetStock( player, 2, c_ZU_Corruptor );

    AIEnableStock(player);

    AISetGasPeons(player, 4, c_ZU_Drone, c_ZB_Extractor );

    //---------------------------------------------------------

    if (AIGetTime() < 1200) {
        return;
    }
    AIWaveMerge(player, c_waveMain, c_waveAttack);
    AISetAttackState(player, e_attackState_Attack);
    AISetMainState(player, e_mainState_Late1, e_mainSubState_AirA);

    AISetFlag(player, e_flagsScouting, true);
    AISetFlag(player, e_flagsClearObs, true);
}

//--------------------------------------------------------------------------------------------------
//  LateAir
//--------------------------------------------------------------------------------------------------
static void LateAir (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_ZB_Hatchery_Alias, c_ZB_Extractor, c_ZU_Overlord, c_ZU_Drone, 8, c_stockIdle);
    AIDefaultExpansion(player, c_ZB_Hatchery_Alias, 6000, 1000, c_expandDefault);

    AISetStock( player, 1, c_ZU_Queen );
    AISetStock( player, 2, c_ZU_Mutalisk );
    AISetStock( player, 2, c_ZU_Hydralisk );

    AISetStock( player, 1, c_ZR_OverlordTransport );
    AISetStock( player, 1, c_ZR_OverseerSpeed );
    AISetStock( player, 2, c_ZU_Overseer );

    AISetStock( player, 3, c_ZB_SporeCrawler );
    AISetStock( player, 1, c_ZU_Corruptor );

    AISetStock( player, 4, c_ZU_Mutalisk );
    AISetStock( player, 3, c_ZU_Corruptor );
    AISetStock( player, 1, c_ZU_BroodLord );
    AISetStock( player, 4, c_ZU_Overseer );

    AISetStock( player, 1, c_ZR_CorruptorAttack );

    AIEnableStock(player);

    AISetGasPeons(player, 4, c_ZU_Drone, c_ZB_Extractor );

    //---------------------------------------------------------

    if (AIGetTime() % 300 > 5) {
        return;
    }
    AIWaveMerge(player, c_waveMain, c_waveAttack);
    AISetAttackState(player, e_attackState_Attack);

    AISetFlag(player, e_flagsScouting, true);
    AISetFlag(player, e_flagsClearObs, true);
}

//--------------------------------------------------------------------------------------------------
//    RandomInfantry
//--------------------------------------------------------------------------------------------------
static void RandomInfantry (int player) {
    AIAddStringInt(player, c_ZU_Hydralisk, 1);
    AIAddStringInt(player, AIPickFrom2(c_ZU_Hydralisk, c_ZU_Roach), 1);
    AIAddStringInt(player, AIPickFrom2(c_ZU_Zergling, c_ZU_Roach), 1);
}

//--------------------------------------------------------------------------------------------------
//  ZergMid0
//--------------------------------------------------------------------------------------------------
void ZergMid0 (int player) {
    int mainSubState = AIState(player, e_mainSubState);
    if (mainSubState == e_mainSubState_GndA)          { ZergMidGndA(player);  }
    else if (mainSubState == e_mainSubState_GndB)     { ZergMidGndB(player);  }
    else if (mainSubState == e_mainSubState_AirA)     { ZergMidAirA(player);  }
    else if (mainSubState == e_mainSubState_AirB)     { ZergMidAirB(player);  }
    else { ErrorMeleeScript(player, "Invalid Mid mainSubState"); }
}

//--------------------------------------------------------------------------------------------------
//  ZergLate0
//--------------------------------------------------------------------------------------------------
void ZergLate0 (int player) {
    int mainSubState = AIState(player, e_mainSubState);
    if (mainSubState == e_mainSubState_GndA)          { LateGnd(player);  }
    else if (mainSubState == e_mainSubState_AirA)     { LateAir(player);  }
    else { ErrorMeleeScript(player, "Invalid Late mainSubState"); }
}
#8
AI Development / Re: Starcraft 2 functions/libraries here
February 27, 2010, 03:35:09 PM


Terran0.galaxy
//==================================================================================================
//  Terran Melee Very Easy
//==================================================================================================

static void RandomInfantry (int player);
static void LateGround (int player);

//--------------------------------------------------------------------------------------------------
//  TerranOpenGnd0
//--------------------------------------------------------------------------------------------------
void TerranOpenGnd0 (int player) {
    AIClearStock(player);

    AISetStock( player, 1, c_TB_CommandCenter_Alias );
    AISetStock( player, 8, c_TU_SCV );
   
    // around 100 resources in about 2 units
    AISetStock( player, 2, c_TU_Marine );
    TerranTechUp(player, 1);
   
    if (AIEnableVeryEasyStockOpen(player, c_TU_SCV)) {
        return;
    }

    // around 300 resources in about 3 unit
    RandomInfantry(player);
}

//--------------------------------------------------------------------------------------------------
//  TerranMidGndA
//--------------------------------------------------------------------------------------------------
static void TerranMidGndA (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_TB_CommandCenter_Alias, c_TB_Refinery, c_TB_SupplyDepot, c_TU_SCV, 8, c_stockAlways);

    if (AISawCloakedUnit(player)) {
        AISetStock( player, 2, c_TB_MissileTurret );
        AISetStock( player, 1, c_TB_OrbitalCommand );
    }

    AISetStockUserData(player);
    TerranTechUp(player, 2);

    if (AIEnableVeryEasyStockMidA(player, c_TU_SCV, 4)) {
        return;
    }
   
    // around 600 resources in about 4 unit
    AIAddStringInt(player, AIPickFrom2(c_TU_Ghost, c_TU_SiegeTank), 1);
    RandomInfantry(player);
}

//--------------------------------------------------------------------------------------------------
//  TerranMidGndB
//--------------------------------------------------------------------------------------------------
static void TerranMidGndB (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_TB_CommandCenter_Alias, c_TB_Refinery, c_TB_SupplyDepot, c_TU_SCV, 8, c_stockAlways);

    if (AISawCloakedUnit(player)) {
        AISetStock( player, 2, c_TB_MissileTurret );
        AISetStock( player, 1, c_TB_OrbitalCommand );
    }

    AISetStockUserData(player);
    TerranTechUp(player, 3);

    if (AIEnableVeryEasyStockMidB(player, c_TU_SCV, 4)) {
        return;
    }

    // around 900 resources in about 5 unit
    LateGround(player);
}

//--------------------------------------------------------------------------------------------------
//  LateGround
//--------------------------------------------------------------------------------------------------
static void LateGround (int player) {
    AIAddStringInt(player, c_TU_Marine, 1);
    AIAddStringInt(player, AIPickFrom2(c_TU_Hellion, c_TU_Marauder), 1);
    AIAddStringInt(player, AIPickFrom2(c_TU_Hellion, c_TU_Marine), 1);
    AIAddStringInt(player, AIPickFrom2(c_TU_Marauder, c_TU_Marine), 1);
    AIAddStringInt(player, AIPickFrom2(c_TU_SiegeTank, c_TU_Ghost), 1);
    AIAddStringInt(player, AIPickFrom2(c_TU_SiegeTank, c_TU_Ghost), 1);
}

//--------------------------------------------------------------------------------------------------
//  LateGnd
//--------------------------------------------------------------------------------------------------
static void LateGnd (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_TB_CommandCenter_Alias, c_TB_Refinery, c_TB_SupplyDepot, c_TU_SCV, 8, c_stockAlways);
    AIDefaultExpansion(player, c_TB_CommandCenter_Alias, 6000, 0, c_expandDefault);

    AISetStockUserData(player);
    AISetStock( player, 1, c_TB_OrbitalCommand );
    AISetStock( player, 3, c_TU_Medivac );
    AISetStock( player, 1, c_TU_Raven );
    TerranTechUp(player, 4);

    if (AIEnableVeryEasyStockLate(player, c_TU_SCV, 4)) {
        return;
    }
    LateGround(player);
}

//--------------------------------------------------------------------------------------------------
//  TerranOpenAir0
//--------------------------------------------------------------------------------------------------
void TerranOpenAir0 (int player) {
    AIClearStock(player);

    AISetStock( player, 1, c_TB_CommandCenter_Alias );
    AISetStock( player, 8, c_TU_SCV );
    AISetStock( player, 1, c_TB_Refinery );
    AISetStock( player, 1, c_TB_Barracks );
    AISetStock( player, 1, c_TB_Factory );
    AISetStock( player, 1, c_TB_Starport );
    AISetStock( player, 1, c_TU_Viking );
    AISetStock( player, 1, c_TB_BarracksReactor );
    AISetStock( player, 1, c_TB_SupplyDepot );
    AISetStock( player, 1, c_TU_Marine );

    AIEnableStock(player);

//    SetGasPeons(player, 3);

    //---------------------------------------------------------

    if (AITechCount(player, c_TU_Viking, c_techCountCompleteOnly) < 1) {
        return;
    }
    AIWaveMerge(player, c_waveMain, c_waveAttack);
    AISetAttackState(player, e_attackState_Attack);
    AISetMainState(player, e_mainState_Mid1, e_mainSubState_AirA);
}

//--------------------------------------------------------------------------------------------------
//  TerranMidAirA
//--------------------------------------------------------------------------------------------------
static void TerranMidAirA (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_TB_CommandCenter_Alias, c_TB_Refinery, c_TB_SupplyDepot, c_TU_SCV, 8, c_stockAlways);

    AISetStockUnitNext( player, 4, c_TU_Marine, c_stockAlways );

    AISetStock( player, 1, c_TU_Viking );
    AISetStock( player, 1, c_TB_StarportTechLab );

    AISetStock( player, 2, c_TU_Viking );
    AISetStock( player, 1, c_TU_Raven );
    AISetStock( player, 1, c_TU_Banshee );
    AISetStock( player, 1, c_TU_Medivac );

    AISetStock( player, 1, c_TB_OrbitalCommand );

    AIEnableStock(player);

//    SetGasPeons(player, 3);

    //---------------------------------------------------------

    if (AIGetTime() < 700) {
        return;
    }
    AIWaveMerge(player, c_waveMain, c_waveAttack);
    AISetAttackState(player, e_attackState_Attack);
    AISetMainState(player, e_mainState_Mid1, e_mainSubState_AirB);
}

//--------------------------------------------------------------------------------------------------
//  TerranMidAirB
//--------------------------------------------------------------------------------------------------
static void TerranMidAirB (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_TB_CommandCenter_Alias, c_TB_Refinery, c_TB_SupplyDepot, c_TU_SCV, 8, c_stockAlways);
    AIDefaultExpansion(player, c_TB_CommandCenter_Alias, 6000, 1000, c_expandDefault);

    AISetStockUnitNext( player, 4, c_TU_Marine, c_stockAlways );
    AISetStockUnitNext( player, 3, c_TU_Viking, c_stockAlways );
    AISetStockUnitNext( player, 1, c_TU_Raven, c_stockAlways );
    AISetStockUnitNext( player, 1, c_TU_Medivac, c_stockAlways );
    AISetStock( player, 1, c_TB_OrbitalCommand );
    AISetStockUnitNext( player, 3, c_TB_MissileTurret, c_stockIdle );
    AISetStockUnitNext( player, 2, c_TU_Banshee, c_stockAlways );
    AISetStockUnitNext( player, 1, c_TU_Battlecruiser, c_stockAlways );

    AIEnableStock(player);

//    SetGasPeons(player, 4);

    //---------------------------------------------------------

    if (AIGetTime() < 1200) {
        return;
    }
    AIWaveMerge(player, c_waveMain, c_waveAttack);
    AISetAttackState(player, e_attackState_Attack);
    AISetMainState(player, e_mainState_Late1, e_mainSubState_AirA);

    AISetFlag(player, e_flagsScouting, true);
    AISetFlag(player, e_flagsClearObs, true);
}

//--------------------------------------------------------------------------------------------------
//  LateAir
//--------------------------------------------------------------------------------------------------
static void LateAir (int player) {
    AIClearStock(player);

    AIDefaultEconomy(player, c_TB_CommandCenter_Alias, c_TB_Refinery, c_TB_SupplyDepot, c_TU_SCV, 8, c_stockAlways);
    AIDefaultExpansion(player, c_TB_CommandCenter_Alias, 6000, 1000, c_expandDefault);

    AISetStockUnitNext( player, 4, c_TU_Marine, c_stockAlways );
    AISetStockUnitNext( player, 5, c_TU_Viking, c_stockAlways );
    AISetStockUnitNext( player, 1, c_TU_Raven, c_stockAlways );
    AISetStockUnitNext( player, 1, c_TU_Medivac, c_stockAlways );
    AISetStock( player, 1, c_TB_OrbitalCommand );
    AISetStockUnitNext( player, 3, c_TB_MissileTurret, c_stockIdle );
    AISetStockUnitNext( player, 4, c_TU_Banshee, c_stockAlways );
    AISetStockUnitNext( player, 1, c_TU_Battlecruiser, c_stockAlways );

    AIEnableStock(player);

//    SetGasPeons(player, 4);

    //---------------------------------------------------------

    if (AIGetTime() % 300 > 5) {
        return;
    }
    AIWaveMerge(player, c_waveMain, c_waveAttack);
    AISetAttackState(player, e_attackState_Attack);

    AISetFlag(player, e_flagsScouting, true);
    AISetFlag(player, e_flagsClearObs, true);
}

//--------------------------------------------------------------------------------------------------
//    RandomInfantry
//--------------------------------------------------------------------------------------------------
static void RandomInfantry (int player) {
    AIAddStringInt(player, c_TU_Marine, 1);
    AIAddStringInt(player, AIPickFrom2(c_TU_Hellion, c_TU_Marauder), 1);
    AIAddStringInt(player, AIPickFrom2(c_TU_Hellion, c_TU_Marauder), 1);
}

//--------------------------------------------------------------------------------------------------
//  TerranMid0
//--------------------------------------------------------------------------------------------------
void TerranMid0 (int player) {
    int mainSubState = AIState(player, e_mainSubState);
    if (mainSubState == e_mainSubState_GndA)          { TerranMidGndA(player);  }
    else if (mainSubState == e_mainSubState_GndB)     { TerranMidGndB(player);  }
    else if (mainSubState == e_mainSubState_AirA)     { TerranMidAirA(player);  }
    else if (mainSubState == e_mainSubState_AirB)     { TerranMidAirB(player);  }
    else { ErrorMeleeScript(player, "Invalid Mid mainSubState"); }
}

//--------------------------------------------------------------------------------------------------
//  TerranLate0
//--------------------------------------------------------------------------------------------------
void TerranLate0 (int player) {
    int mainSubState = AIState(player, e_mainSubState);
    if (mainSubState == e_mainSubState_GndA)          { LateGnd(player);  }
    else if (mainSubState == e_mainSubState_AirA)     { LateAir(player);  }
    else { ErrorMeleeScript(player, "Invalid Late mainSubState"); }
}


Terran.galaxy
//==================================================================================================
//  Terran Melee AI
//==================================================================================================

include "TriggerLibs/Terran0"

//--------------------------------------------------------------------------------------------------
//  Counter-Attack Units
//--------------------------------------------------------------------------------------------------
static void InitCounters (int player) {
//xxx lots of old data -- needs to be totally redone
    // versus Protoss
    AICounterUnit(player, c_PB_PhotonCannon,         0.50, c_TU_SiegeTank);
    AICounterUnit(player, c_PU_Zealot,              1.00, c_TU_Hellion);
    AICounterUnit(player, c_PU_Stalker,             1.00, c_TU_Marauder);
    AICounterUnit(player, c_PU_Immortal,            2.00, c_TU_Marauder);
    AICounterUnit(player, c_PU_Disruptor,           1.00, c_TU_Ghost);
    AICounterUnit(player, c_PU_HighTemplar,         1.00, c_TU_Ghost);
    AICounterUnit(player, c_PU_DarkTemplar,         1.00, c_TU_Hellion);
    AICounterUnit(player, c_PU_Archon,              0.33, c_TU_Hellion);
    AICounterUnit(player, c_PU_Colossus,            1.00, c_TU_Thor);
    AICounterUnit(player, c_PU_VoidRay,             0.50, c_TU_Battlecruiser);
    AICounterUnit(player, c_PU_Phoenix,             0.50, c_TU_BattlecruiserMissile);
    AICounterUnit(player, c_PU_Carrier,             0.75, c_TU_BattlecruiserYamato);

    // versus Terran
    AICounterUnit(player, c_TB_Bunker,              0.33, c_TU_SiegeTank);
    AICounterUnit(player, c_TU_Marine,              0.50, c_TU_Hellion);
    AICounterUnit(player, c_TU_Reaper,              0.70, c_TU_Hellion);
    AICounterUnit(player, c_TU_Marauder,            0.50, c_TU_SiegeTank);
    AICounterUnit(player, c_TU_Ghost,               2.00, c_TU_Hellion);
    AICounterUnit(player, c_TU_Hellion,             0.25, c_TU_Thor);
    AICounterUnit(player, c_TU_SiegeTank_Alias,     0.50, c_TU_Thor);
    AICounterUnit(player, c_TU_Thor,                3.00, c_TU_Marauder);
    AICounterUnit(player, c_TU_Viking_Alias,        1.00, c_TU_Viking);
    AICounterUnit(player, c_TU_Banshee,             1.00, c_TU_Viking);
    AICounterUnit(player, c_TU_BattlecruiserClass,  1.00, c_TU_BattlecruiserYamato);

    // versus Zerg
    AICounterUnit(player, c_ZB_SpineCrawler,        0.33, c_TU_SiegeTank);
    AICounterUnit(player, c_ZU_Zergling,            0.25, c_TU_Hellion);
    AICounterUnit(player, c_ZU_Roach,               0.80, c_TU_Marauder);
    AICounterUnit(player, c_ZU_Hydralisk,           0.50, c_TU_Ghost);
    AICounterUnit(player, c_ZU_Lurker,              1.00, c_TU_Marauder);
    AICounterUnit(player, c_ZU_Infestor,            0.50, c_TU_Ghost);
    AICounterUnit(player, c_ZU_Ultralisk,           1.00, c_TU_Thor);
    AICounterUnit(player, c_ZU_Mutalisk,            0.80, c_TU_Viking);
    AICounterUnit(player, c_ZU_Corruptor,           0.50, c_TU_Battlecruiser);
    AICounterUnit(player, c_ZU_BroodLord,           0.50, c_TU_Viking);
}

//--------------------------------------------------------------------------------------------------
//  TerranSubStateName
//--------------------------------------------------------------------------------------------------
string TerranSubStateName (int state) {
    // TODO Call the individual difficulties to return a real substate name
    return "-" + IntToString(state) + "-";
}

//--------------------------------------------------------------------------------------------------
//  DebugCallbackTerr
//--------------------------------------------------------------------------------------------------
void DebugCallbackTerr (int player) {
    DebugAI("=====TERRAN=====\n");
    DebugMelee(player);
    DebugAI("e_mainState = "        + MainStateName(AIState(player, e_mainState))           +
            ", e_mainSubState = "   + TerranSubStateName(AIState(player, e_mainSubState))   +
            ", e_attackState = "    + AttackStateName(AIState(player, e_attackState))
    );
}

//--------------------------------------------------------------------------------------------------
//  AINewUnitTerr
//--------------------------------------------------------------------------------------------------
void AINewUnitTerr (int player, unit u) {
    wave w;
    string type = UnitGetType(u);

    // ignored units
    //
    if (UnitTypeTestAttribute(type, c_unitAttributeStructure)) {
        return;
    }
    if (UnitTypeTestFlag(type, c_unitFlagWorker)) {
        return;
    }
   
    if (type == c_TU_Medivac) {
        // TODO after normal scouting claims the ones it wants give the rest to the
        //      attack wave instead of the extra scout group
        AIAddToExtraScoutGroup(player, u);
        return;
    }

    // detector
    //
    if (type == c_TU_Raven) {
        AINewDetector(player, u, false);
        return;
    }

    // clear obstacle units
    //
    if (AIWaveNeedClearObsUnits(player)) {
        if (type == c_TU_Marine || type == c_TU_Reaper || type == c_TU_Marauder) {
            AIMergeUnit(player, u, AIWaveGet(player, c_waveClearObs));
            return;
        }
    }

    // diversion units
    if (AIGetFlag(player, e_flagsDiversion)) {
        if (type == c_TU_Reaper) {
            AIMergeUnit(player, u, AIWaveGet(player, c_waveDivert1));
            return;
        }
        if (type == c_TU_Banshee) {
            AIMergeUnit(player, u, AIWaveGet(player, c_waveDivert2));
            return;
        }
    }

    // main wave units
    //
    AINewUnitDefault(player, u);
}

//--------------------------------------------------------------------------------------------------
//  AIGetScoutTerr
//--------------------------------------------------------------------------------------------------
unit AIGetScoutTerr (int player, int index, unit prev) {
    unit medivac;
   
    if (!AIGetFlag(player, e_flagsScouting)) {
        return c_nullUnit;
    }
    if (UnitGetType(prev) == c_TU_Medivac) {
        return prev;
    }
    medivac = AIGrabUnit(player, c_TU_Medivac, c_prioScout, null);
    if (medivac) {
        return medivac;
    }
    if (prev) {
        return prev;
    }
    if (AIGetFlag(player, e_flagsLateScout)) {
        return c_nullUnit;
    }
    return AIGrabUnit(player, c_TU_SCV, c_prioScout, null);
}

//--------------------------------------------------------------------------------------------------
//  AIEarlyDefScoutTerr
//--------------------------------------------------------------------------------------------------
unit AIEarlyDefScoutTerr (int player, unit prev) {
    unit obs;
   
    if (!AIGetFlag(player, e_flagsEarlyDefScout)) {
        return c_nullUnit;
    }
    if (UnitGetType(prev) == c_TU_Medivac) {
        return prev;
    }
    obs = AIGrabUnit(player, c_TU_Medivac, c_prioScout, null);
    if (obs) {
        return obs;
    }
    if (UnitGetType(prev) == c_TU_Marine) {
        return prev;
    }
    obs = AIGrabUnit(player, c_TU_Marine, c_prioScout, null);
    if (obs) {
        return obs;
    }
    if (prev) {
        return prev;
    }
    return AIGrabUnit(player, c_TU_SCV, c_prioScout, null);
}
#9
AI Development / Re: Starcraft 2 functions/libraries here
February 27, 2010, 03:34:04 PM
TactZergAI.galaxy < suite

//--------------------------------------------------------------------------------------------------
//  Limit the number of enemies we check since AIPathCost could be expensive over
//  too many units.
const int c_maxEnemyCount = 5;

order Changeling (int player, unit aiUnit, unitgroup scanGroup, fixed range) {
    int enemyPlayer = -1;
    point here;
    order ord;
    point camPoint;
    fixed camDistance;

    ord = AICreateOrder(player, c_AB_Changeling, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    enemyPlayer = AIGetPlayerGroup(scanGroup);
    if (enemyPlayer == -1) {
        return null;
    }

    //  A good player should be able to tell when the enemy isn't paying attention
    //  and then cast changeling.  To simulate this, the computer looks for an enemy
    //  player's camera on hard and insanse.
    //
    if (AICampSkirDiffTest(player, c_campExpert, c_skirVeryHard)) {
        camPoint = CameraGetTarget(enemyPlayer);
        here = UnitGetPosition(aiUnit);
        camDistance = DistanceBetweenPoints(camPoint, here);
       
        if (camDistance < 20) {
            return null;
        }
    }

    //  Check to see if we already have a changeling.
    if (AINearbyUnits(player, c_ZU_Changeling, here, range, 1) ||
        AINearbyUnits(player, c_ZU_ChangelingZealot, here, range, 1) ||
        AINearbyUnits(player, c_ZU_ChangelingZergling, here, range, 1) ||
        AINearbyUnits(player, c_ZU_ChangelingMarine, here, range, 1) ||
        AINearbyUnits(player, c_ZU_ChangelingZerglingWings, here, range, 1)) {
        return null;
    }

    //  Check to see if there are enough basic units around to follow.
    if ((UnitGroupCount(AIFilterPathable(AIFindUnits(enemyPlayer, c_PU_Zealot, here, range, c_maxEnemyCount), here), c_unitCountAlive) >= 2) ||
        (UnitGroupCount(AIFilterPathable(AIFindUnits(enemyPlayer, c_ZU_Zergling, here, range, c_maxEnemyCount), here), c_unitCountAlive) >= 2) ||
        (UnitGroupCount(AIFilterPathable(AIFindUnits(enemyPlayer, c_TU_Marine, here, range, c_maxEnemyCount), here), c_unitCountAlive) >= 2)) {
        return ord;
    }

    return null;
}

bool MakeChangeling (int player, unit aiUnit, unitgroup scanGroup) {
    order ord;
    unitgroup allyGroup;
    region r;
    aifilter filter;
    point position;
    bool groundEnemies;
    bool airEnemies;
    fixed range;

    if (AIIsCampaign(player)) {
        // don't auto make changlings on campaign
        return false;
    }

    //  If we already have a changeling order, ignore new orders so that
    //  we don't cast again
    if (UnitOrderHasAbil(aiUnit, c_AB_Changeling)) {
        return false;
    }

    //  Test to see whether the overseer is scouting or fighting.
    //  For now, just test to see if there are nearby allied units that can fight the enemy.
    r = RegionCircle(UnitGetPosition(aiUnit), AIRangeOverseer(player, aiUnit));
    allyGroup = UnitGroupAlliance(player, c_unitAllianceAlly, r, null, c_noMaxCount);
   
    position = UnitGetPosition(aiUnit);
    range = AIRangeOverseer(player, aiUnit);
    groundEnemies = AINearbyPlaneTest(position, player, range, c_planeGround, c_unitAllianceEnemy);
    airEnemies = AINearbyPlaneTest(position, player, range, c_planeAir, c_unitAllianceEnemy);

    filter = AIFilter(player);
    AISetFilterCanAttackAlly(filter, groundEnemies, airEnemies);
    allyGroup = AIGetFilterGroup(filter, allyGroup);

    if (UnitGroupCount(allyGroup, c_unitCountAll) == 0) {
        ord = Changeling(player, aiUnit, scanGroup, range);
        if (ord != null) {
            AICast(aiUnit, ord, c_noMarker, c_castRetreat);
            return true;
        }
    }

    return false;
}

//--------------------------------------------------------------------------------------------------
void AIThinkOverseer (int player, unit aiUnit, unitgroup scanGroup) {
    order ord;
    marker mark;
    marker gameMark;

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

    //gameMark = AIMarker(aiUnit, c_MK_GameFungalGrowth);
    //mark = AIMarker(aiUnit, c_MK_FungalGrowth);
    //ord = FungalGrowth(player, aiUnit, mark, gameMark, scanGroup);
    //if (ord != null) {
    //    AICast(aiUnit, ord, mark, c_castHold);
    //    return;
    //}

    //ord = AcidSpores(player, aiUnit, scanGroup);
    //if (ord != null) {
    //    AICast(aiUnit, ord, c_noMarker, c_castHold);
    //    return;
    //}

}

//--------------------------------------------------------------------------------------------------
//  *** CHANGELING ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeChangeling (int player, unit aiUnit) {
    return AIUnitFixed(player, c_ZU_Overlord, c_fieldSightDawn);
}

void AIThinkChangelingUnit (int player, unit aiUnit, unitgroup scanGroup, string followUnit) {
    unitgroup followGroup;
    order ord;
    int enemyPlayer;
    region r;
    unitgroup allyGroup;
    unitgroup enemyGroup;

    if (AIIsFollowingUnit(aiUnit, followUnit)) {
        return;
    }

    //  Create a move order, and check validity
    ord = AICreateOrder(player, c_AB_Follow, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return;
    }

    r = RegionCircle(UnitGetPosition(aiUnit), AIRangeOverseer(player, aiUnit));
    enemyGroup = UnitGroupAlliance(player, c_unitAllianceEnemy, r, null, c_noMaxCount);

    enemyPlayer = AIGetPlayerGroup(enemyGroup);
    if (enemyPlayer == -1) {
        return;
    }

    //  By default, follow the provided unit type.
    followGroup = AIFindUnits(enemyPlayer, followUnit, UnitGetPosition(aiUnit), AIRangeChangeling(player, aiUnit), c_noMaxCount);
    ord = AIUnitGroupGetValidOrder(followGroup, ord, aiUnit, c_forwards);

    if (ord != null) {
        AICast(aiUnit, ord, c_noMarker, c_castHold);
        return;
    }

    //  Otherwise, find any enemy to follow.
    ord = AICreateOrder(player, c_AB_Follow, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return;
    }
   
    ord = AIUnitGroupGetValidOrder(scanGroup, ord, aiUnit, c_forwards);
    if (ord != null) {
        AICast(aiUnit, ord, c_noMarker, c_castHold);
        return;
    }

    return;
}

//--------------------------------------------------------------------------------------------------
void AIThinkChangelingZergling (int player, unit aiUnit, unitgroup scanGroup) {
    AIThinkChangelingUnit(player, aiUnit, scanGroup, c_ZU_Zergling);
}

void AIThinkChangelingMarine (int player, unit aiUnit, unitgroup scanGroup) {
    AIThinkChangelingUnit(player, aiUnit, scanGroup, c_TU_Marine);
}

void AIThinkChangelingZealot (int player, unit aiUnit, unitgroup scanGroup) {
    AIThinkChangelingUnit(player, aiUnit, scanGroup, c_PU_Zealot);
}
#10
AI Development / Re: Starcraft 2 functions/libraries here
February 27, 2010, 03:32:20 PM


TactZergAI.galaxy
//--------------------------------------------------------------------------------------------------
//  *** QUEEN ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeQueen (int player, unit aiUnit) {
    return MaxF(AIAbilityFixed(player, c_AB_Transfusion, c_fieldRange0),
                AIAbilityFixed(player, c_AB_SpawnMutantLarva, c_fieldRange0)) + 1;
}

//--------------------------------------------------------------------------------------------------
order Transfusion (int player, unit aiUnit) {
    order ord;
    unitgroup group;
    aifilter filter;

    ord = AICreateOrder(player, c_AB_Transfusion, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    group = AIFindUnits(player, null, UnitGetPosition(aiUnit),
                        AIAbilityFixed(player, c_AB_Transfusion, c_fieldRange0) + 1,
                        c_noMaxCount)
    ;

    filter = AIFilter(player);
    AISetFilterAlliance(filter, c_playerGroupAlly);
    AISetFilterLifeLost(filter, AIEffectFixed(player, c_EF_Transfusion, c_fieldEffectChange0), c_noMax);
    group = AIGetFilterGroup(filter, group);

    return AIUnitGroupGetValidOrder(group, ord, aiUnit, c_forwards);
}

//--------------------------------------------------------------------------------------------------
order SpawnLarva (int player, unit aiUnit) {
    order ord;
    unitgroup hatcheries;
    int larvaCount;

    //  Only cast if idle.
    //
    if (UnitOrder(aiUnit, 0) != null) {
        return null;
    }

    ord = AICreateOrder(player, c_AB_SpawnMutantLarva, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    //  Don't cast if we already own at least 10 larva
    //
    larvaCount =
        TechTreeBehaviorCount(player, c_BF_MutantLarvaTimer, c_techCountQueuedOrBetter) * 4
      + TechTreeUnitCount(player, c_ZU_Larva, c_techCountQueuedOrBetter)
    ;
    if (larvaCount >= 10) {
        return null;
    }

    hatcheries = AIFindUnits(player,
                             c_ZB_Hatchery_Alias,
                             UnitGetPosition(aiUnit),
                             15,
                             c_noMaxCount)
                             ;
    return AIUnitGroupGetValidOrder(hatcheries, ord, aiUnit, c_backwards);
}

//--------------------------------------------------------------------------------------------------
order CreepTumor (int player, unit aiUnit) {

    order ord;
    point p;

    //  Only cast if idle.
    //
    if (UnitOrder(aiUnit, 0) != null) {
        return null;
    }

    ord = AICreateOrder(player, c_AB_QueenBuild, 1);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    //  Don't cast if there is no creep point set for this player.
    p = AIGetBestCreepSpot(player, aiUnit, 8);
    if (p == null) {
        return null;
    }

    OrderSetTargetPlacement(ord, p, aiUnit, c_ZU_CreepTumor);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    return ord;
}

//--------------------------------------------------------------------------------------------------
void AIThinkQueen (int player, unit aiUnit, unitgroup scanGroup) {
    order ord;
    unit heal;

    if (AIEvalTacticalData(aiUnit, null)) {
        return;
    }
    ord = Transfusion(player, aiUnit);
    if (ord != null) {
        AICast(aiUnit, ord, c_noMarker, c_castHold);
        return;
    }
    ord = SpawnLarva(player, aiUnit);
    if (ord != null) {
        AICast(aiUnit, ord, c_noMarker, c_castHold);
        return;
    }
    ord = CreepTumor(player, aiUnit);
    if (ord != null) {
        AICast(aiUnit, ord, c_noMarker, c_castRetreat);
        return;
    }
}

//--------------------------------------------------------------------------------------------------
//  *** INFESTOR ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeInfestor (int player, unit aiUnit) {
    return MaxF(AIAbilityFixed(player, c_AB_InfestedTerrans, c_fieldRange0),
                AIAbilityFixed(player, c_AB_NeuralParasite, c_fieldRange0)) + 1;

    // AIAbilityFixed(player, c_AB_UnstableMutation, c_fieldRange0)
}

//  Minimum vitality of a unit in order to mind control it,
//  infestors will mind control units > carrier.
const fixed c_neuralParasiteMinVitality = 425;

//---------------------------------------------------------------------------------------------
order NeuralParasite (int player, unit aiUnit, unitgroup scanGroup, marker mark, marker gameMark, bool lowVitality) {
    order ord;
    aifilter filter;
    unit target;

    //  vars related to nearby enemies.
    //
    aifilter groundAirFilter;
    unitgroup threatGroup;
    int enemyGroundCount;
    int enemyAirCount;
   
    //  Create order and check validity
    //
    ord = AICreateOrder(player, c_AB_NeuralParasite, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    //  Scan for enemy air and ground units
    //
    enemyGroundCount = 0;
    enemyAirCount = 0;

    groundAirFilter = AIFilter(player);
    AISetFilterAlliance(groundAirFilter, c_playerGroupEnemy);
    AISetFilterPlane(groundAirFilter, c_planeGround);
    enemyGroundCount = UnitGroupCount(AIGetFilterGroup(groundAirFilter, scanGroup), c_unitCountAlive);

    AISetFilterPlane(groundAirFilter, c_planeAir);
    enemyAirCount = UnitGroupCount(AIGetFilterGroup(groundAirFilter, scanGroup), c_unitCountAlive);

    //  Apply filters to enemies
    //
    filter = AIFilter(player);
    AISetFilterAlliance(filter, c_playerGroupEnemy);
    AISetFilterBits(filter, UnitFilterStr(AIAbilityStr(player, c_AB_NeuralParasite, c_fieldTargetFiltersAB)));
    AISetFilterRange(filter, aiUnit, AIAbilityFixed(player, c_AB_NeuralParasite, c_fieldRange0) + 1);
    AISetFilterLife(filter, c_neuralParasiteMinVitality, c_noMax);
    AISetFilterMarker(filter, c_noMarkersMin, c_noMarkersMax, mark);
    AISetFilterCanAttackEnemy(filter, enemyGroundCount, enemyAirCount);
    scanGroup = AIGetFilterGroup(filter, scanGroup);

    //  Since it's a missile, we also have to check the game-side marker
    //
    filter = AIFilter(player);
    AISetFilterMarker(filter, c_noMarkersMin, c_noMarkersMax, gameMark);
    scanGroup = AIGetFilterGroup(filter, scanGroup);

    //  Return valid target
    //
    return AIUnitGroupGetValidOrder(scanGroup, ord, aiUnit, c_forwards);
}

//--------------------------------------------------------------------------------------------------
//fixed MinToCastUnstableMutation (int player) {
//    return AIAbilityFixed(player, c_AB_NeuralParasite, c_fieldEnergyCost) +
//           AIAbilityFixed(player, c_AB_UnstableMutation, c_fieldEnergyCost);
//}
//
//order UnstableMutation (int player, unit aiUnit, unitgroup scanGroup, marker mark, bool lowVitality) {
//    order ord;
//    int energy;
//    aifilter filter;
//    unitgroup enemyCasters;
//   
//    ord = AICreateOrder(player, c_AB_UnstableMutation, 0);
//    if (!UnitOrderIsValid(aiUnit, ord)) {
//        return null;
//    }
//
//    //  Save energy for neural parasite
//    energy = UnitGetPropertyInt(aiUnit, c_unitPropEnergy, c_unitPropCurrent);
//    if (energy < MinToCastUnstableMutation(player)) {
//        return null;
//    }
//
//    //  For now, only use on enemy casters, since we want them dead and they can't attack our units.
//    filter = AIFilter(player);
//    AISetFilterBits(filter, UnitFilterStr(AIAbilityStr(player, c_AB_UnstableMutation, c_fieldTargetFiltersAB)));
//    AISetFilterAlliance(filter, c_playerGroupEnemy);
//    AISetFilterLife(filter, c_noMin, c_noMax);
//    AISetFilterMarker(filter, c_noMarkersMin, c_noMarkersMax, mark);
//    AISetFilterBehaviorCount(filter, c_noBehaviorMin, c_noBehaviorMax, c_BF_UnstableMutation);
//    enemyCasters = AIGetFilterGroup(filter, scanGroup);
//
//    enemyCasters = AIFilterCasters(enemyCasters);
//
//    return AIUnitGroupGetValidOrder(enemyCasters, ord, aiUnit, c_forwards);
//}

//---------------------------------------------------------------------------------------------
fixed MinToCastInfestedTerrans (int player) {
    return AIAbilityFixed(player, c_AB_NeuralParasite, c_fieldEnergyCost) +
           AIAbilityFixed(player, c_AB_InfestedTerrans, c_fieldEnergyCost);
}

order InfestedTerrans (int player, unit aiUnit, unitgroup scanGroup, bool lowVitality) {
    order ord;
    int energy;
    aifilter filter;
    point castPoint;
    unit target;
    unitgroup targetGroup;  //  Don't want to modify the scanGroup... still need it for neural parasite.
   
    ord = AICreateOrder(player, c_AB_InfestedTerrans, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    //  Reserve 125 mana for neural parasite
    energy = UnitGetPropertyInt(aiUnit, c_unitPropEnergy, c_unitPropCurrent);
    if (energy < MinToCastInfestedTerrans(player) && !lowVitality) {
        return null;
    }

    //  Cast on top of the weakest unit.
    //
    filter = AIFilter(player);
    AISetFilterAlliance(filter, c_playerGroupEnemy);
    AISetFilterBits(filter, UnitFilterStr(AIWeaponStr(player, c_WE_InfestedTerran, c_fieldTargetFilters)));
    AISetFilterRange(filter, aiUnit, AIAbilityFixed(player, c_AB_InfestedTerrans, c_fieldRange0) + 1);
    AISetFilterLifePercent(filter, c_noMin, c_noMax);
    targetGroup = AIGetFilterGroup(filter, scanGroup);

    //  Check for valid target
    //
    target = UnitGroupUnit(targetGroup, UnitGroupCount(targetGroup, c_unitCountAll));
    if (target == null) {
        return null;
    }
   
    castPoint = AIPlacementNearbyFindTest(player, UnitGetPosition(target), 5.0, c_ZU_InfestedTerranEgg);
    if (castPoint == c_nullPoint) {
        return null;
    }

    OrderSetTargetPoint(ord, castPoint);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    return ord;
}

//---------------------------------------------------------------------------------------------
const fixed enemyMultiplierInfestor = 1.25;
const fixed minThreshold = 100.0;
const int lowVitalityPercent = 75;

void AIThinkInfestor (int player, unit aiUnit, unitgroup scanGroup) {
    //  **Infestor disease in TargetFindData.xml** Currently not in the game.
    marker mark;
    marker gameMark;
    order ord;
    unitfilter f;
    bool lowVitality;

    if (AIEvalTacticalData(aiUnit, null)) {
        return;
    }

    //  Low Vitality = less than 75%, since it takes a WHILE for the infested marines to hatch
    lowVitality = (UnitGetPropertyInt(aiUnit, c_unitPropVitalityPercent, c_unitPropCurrent) < lowVitalityPercent);
   
    //  If we outnumber the enemy, don't even bother casting any spell, unless we are less than 75%
    if (!lowVitality) {
        //  If we have greater than 1.25 * the enemies forces, we outnumber, so don't cast.
        f = UnitFilterStr("-;Missile,Dead,Stasis,Worker");
        if (AIAllyEnemyRatio(player, UnitGetPosition(aiUnit), f, AIRangeInfestor(player, aiUnit), minThreshold) > enemyMultiplierInfestor) {
            return;
        }
    }

    //  This must preserve scanGroup for Neural Parasite check.
    ord = InfestedTerrans(player, aiUnit, scanGroup, lowVitality);
    if (ord != null) {
        AICast(aiUnit, ord, c_noMarker, c_castRetreat);
    }

    //mark = AIMarker(aiUnit, c_MK_UnstableMutation);
    //ord = UnstableMutation(player, aiUnit, scanGroup, mark, lowVitality);
    //if (ord != null) {
    //    AICast(aiUnit, ord, mark, c_castRetreat);
    //    return;
    //}
   
    mark = AIMarker(aiUnit, c_MK_NeuralParasite);
    gameMark = AIMarker(aiUnit, c_MK_GameNeuralParasite);
    ord = NeuralParasite(player, aiUnit, scanGroup, mark, gameMark, lowVitality);
    if (ord != null) {
        AICast(aiUnit, ord, mark, c_castRetreat);
        return;
    }
}

//--------------------------------------------------------------------------------------------------
//  *** BANELING ***
//--------------------------------------------------------------------------------------------------
const fixed c_banelingRange = 8;
fixed AIRangeBaneling (int player, unit aiUnit) {
    return c_banelingRange;
}

//---------------------------------------------------------------------------------------------
order SapStructure (int player, unit aiUnit, unitgroup scanGroup, marker mark) {
    order ord;
    unitgroup enemyBuildingGroup;
    unitgroup enemyUnitGroup;
    unit closestEnemy;
    point banelingPosition;
    fixed distanceToEnemy;
    unit closestEnemyBuilding;
   
    bool airAllies = false;
    int damage;

    aifilter buildingFilter;
    aifilter unitFilter;

    //  Create and check the validity of order.
    //
    ord = AICreateOrder(player, c_AB_SapStructure, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    //  Create non-building filter to find the closest enemy.
    //
    unitFilter = AIFilter(player);
    AISetFilterAlliance(unitFilter, c_playerGroupEnemy);
    AISetFilterBits(unitFilter, UnitFilterStr(AIEffectStr(player, c_EF_BaneUnit, c_fieldFilters)));
    AISetFilterRange(unitFilter, aiUnit, AIRangeBaneling(player, aiUnit));
    enemyUnitGroup = AIGetFilterGroup(unitFilter, scanGroup);
   
    banelingPosition = UnitGetPosition(aiUnit);
    closestEnemy = UnitGroupNearestUnit(enemyUnitGroup, banelingPosition);
    if (closestEnemy != null) {
        distanceToEnemy = DistanceBetweenPoints(banelingPosition, UnitGetPosition(closestEnemy));
    }
    else {
        distanceToEnemy = AIRangeBaneling(player, aiUnit);  //  Default distance.
    }

    //  Create building filter.
    //
    buildingFilter = AIFilter(player);
    AISetFilterAlliance(buildingFilter, c_playerGroupEnemy);
    AISetFilterBits(buildingFilter, UnitFilterStr(AIAbilityStr(player, c_AB_SapStructure, c_fieldTargetFiltersAB)));
    AISetFilterRange(buildingFilter, aiUnit, distanceToEnemy);
    damage = AIEffectInt(player, c_EF_BaneBuilding, c_fieldAmount);
    AISetFilterLifePerMarker(buildingFilter, damage, mark);
    airAllies = AINearbyPlaneTest(UnitGetPosition(aiUnit), player, AIRangeBaneling(player, aiUnit), c_planeAir, c_unitAllianceAlly);
    AISetFilterCanAttackAlly(buildingFilter, c_groundAlliesNearby, airAllies); //  Ground allies always true, since banelings are ground units.
    enemyBuildingGroup = AIGetFilterGroup(buildingFilter, scanGroup);

    closestEnemyBuilding = UnitGroupNearestUnit(enemyBuildingGroup, banelingPosition);
    if (closestEnemyBuilding == null) {
        return null;
    }

    OrderSetTargetUnit(ord, closestEnemyBuilding);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    return ord;
}

//---------------------------------------------------------------------------------------------
void AIThinkBaneling (int player, unit aiUnit, unitgroup scanGroup) {
    marker mark;
    order ord;
   
    if (AIEvalTacticalData(aiUnit, null)) {
        return;
    }

    mark = AIMarker(aiUnit, c_MK_SapStructure);
    ord = SapStructure(player, aiUnit, scanGroup, mark);
    if (ord != null) {
        AICast(aiUnit, ord, mark, c_castHold);
    }
}

//--------------------------------------------------------------------------------------------------
//  *** OVERSEER ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeOverseer (int player, unit aiUnit) { 
    return AIUnitFixed(player, c_ZU_Overseer, c_fieldSightDawn) + 1;

    //return MaxF(MaxF(AIAbilityFixed(player, c_AB_FungalGrowth, c_fieldRange0),
    //    AIAbilityFixed(player, c_AB_AcidSpores, c_fieldRange0)),
    //    AIAbilityFixed(player, c_AB_Changeling, c_fieldRange0)) + 1;
}

//fixed MinToCastFungalGrowth (int player) {
//    return AIAbilityFixed(player, c_AB_FungalGrowth, c_fieldEnergyCost) +
//           AIAbilityFixed(player, c_AB_AcidSpores, c_fieldEnergyCost);
//}

//order FungalGrowth (int player, unit aiUnit, marker mark, marker gameMark, unitgroup scanGroup) {
//    order ord;
//    fixed energy;
//    aifilter filter;
//    bool groundAllies;
//    unitgroup enemyGroup;
   
//    ord = AICreateOrder(player, c_AB_FungalGrowth, 0);
//    if (!UnitOrderIsValid(aiUnit, ord)) {
//        return null;
//    }

//    //  Save energy for acid spores
//    energy = UnitGetPropertyFixed(aiUnit, c_unitPropEnergy, c_unitPropCurrent);
//    if (energy < MinToCastFungalGrowth(player)) {
//        return null;
//    }

//   
//    groundAllies = AINearbyPlaneTest(UnitGetPosition(aiUnit), player, AIRangeOverseer(player, aiUnit), c_planeGround, c_unitAllianceAlly);

//    //  Cast on strongest enemy that can attack our allies
//    filter = AIFilter(player);
//    AISetFilterBits(filter, UnitFilterStr(AIAbilityStr(player, c_AB_FungalGrowth, c_fieldTargetFiltersAB)));
//    AISetFilterCanAttackAlly(filter, groundAllies, c_airAlliesNearby);
//    AISetFilterLife(filter, c_noMin, c_noMax);
//    AISetFilterMarker(filter, c_noMarkersMin, c_noMarkersMax, mark);
//    AISetFilterBehaviorCount(filter, c_noBehaviorMin, c_noBehaviorMax, c_BF_FungalGrowth);
//    enemyGroup = AIGetFilterGroup(filter, scanGroup);
//
//    AISetFilterMarker(filter, c_noMarkersMin, c_noMarkersMax, gameMark);
//    enemyGroup = AIGetFilterGroup(filter, scanGroup);
//
//    return AIUnitGroupGetValidOrder(enemyGroup, ord, aiUnit, c_forwards);
//}

//--------------------------------------------------------------------------------------------------
//const int c_minAlliesCanAttack = 3;

//order AcidSpores (int player, unit aiUnit, unitgroup scanGroup) {
//    order ord;
//    aifilter filter;
//    bool groundEnemies;
//    bool airEnemies;
//    region r;
//    unitgroup allyGroup;
//    int allyCount;
//    point position;
//
//    ord = AICreateOrder(player, c_AB_AcidSpores, 0);
//    if (!UnitOrderIsValid(aiUnit, ord)) {
//        return null;
//    }
//
//    DebugVarInt("const", c_planeAir);
//
//    position = UnitGetPosition(aiUnit);
//    //  Only use it if we have some units that will be able to attack the enemy.
//    groundEnemies = AINearbyPlaneTest(position, player, AIRangeOverseer(player, aiUnit), c_planeGround, c_unitAllianceEnemy);
//    airEnemies = AINearbyPlaneTest(position, player, AIRangeOverseer(player, aiUnit), c_planeAir, c_unitAllianceEnemy);
//
//    //AIEffectFixed(player, c_EF_AcidSporesArea, c_fieldAreaRadius0)
//    //UnitFilterStr(AIAbilityStr(player, c_AB_AcidSpores, c_fieldTargetFiltersAB)
//    DebugVarBool("grnd", groundEnemies);
//    DebugVarBool("air", airEnemies);
//
//    r = RegionCircle(UnitGetPosition(aiUnit), AIRangeOverseer(player, aiUnit));
//    allyGroup = UnitGroupAlliance(player,
//                                  c_unitAllianceAlly,
//                                  r,
//                                  null,
//                                  c_noMaxCount)
//                                  ;
//
//    AISetFilterCanAttackAlly(filter, groundEnemies, airEnemies);
//    allyGroup = AIGetFilterGroup(filter, allyGroup);
//    allyCount = UnitGroupCount(allyGroup, c_unitCountAll);
//
//    DebugVarInt("allyCount:", allyCount);
//
//    if (allyCount < c_minAlliesCanAttack) {
//        return null;
//    }
//
//    return null;
//}
#11
AI Development / Re: Starcraft 2 functions/libraries here
February 27, 2010, 03:28:52 PM
TactTerrAI.galaxy < suite


//--------------------------------------------------------------------------------------------------
//  CargoDefend
//--------------------------------------------------------------------------------------------------
const fixed c_campaignBunkerLoadRange = 4.0;
const bool c_bunkerUnload = true;
const bool c_bunkerLoad = false;

//---------------------------------------------------------------------------------------------
unit CampaignWantsToBeInBunker (int player, unit aiUnit, unitgroup bunkerGroup, bool unload) {
    int bunkerCount;
    unit unitToCheck;
    bool wantsToBeInBunker;

    //  When loading, check to see if there is space in the bunker at all.
    //
    if (!unload) {
        if (UnitCargoValue(aiUnit, c_unitCargoSpaceFree) == 0) {
            return null;
        }
    }

    bunkerCount = UnitGroupCount(bunkerGroup, c_unitCountAll);
    while (bunkerCount > 0) {
        unitToCheck = UnitGroupUnit(bunkerGroup, bunkerCount);
        bunkerCount = bunkerCount - 1;

        //  Make sure the unit is alive.
        //
        if (!UnitIsAlive(unitToCheck)) {
            continue;
        }
        //  When loading, make sure the unit is not allready in a transport.
        //
        if (!unload) {
            if (UnitTestState(unitToCheck, c_unitStateInsideTransport)) {
                continue;
            }
        }

        //  The unit wants to be somewhere far away, do not load it.
        //
        wantsToBeInBunker = true;

        //  The unit is forced to move, do not load.
        if (AIControlForceToMove(unitToCheck)) {
            wantsToBeInBunker = false;
        }
        //  The unit wants to execute order, do not load.
        else if (UnitOrderCount(unitToCheck) > 0) {
            wantsToBeInBunker = false;
        }
        //  The unit wants to move, do not load if safe.
        else if (AIControlWantsToMove(unitToCheck)) {
            if (!AIUnitIsInCombat(unitToCheck) && !AIUnitIsInCombat(aiUnit)) {
                wantsToBeInBunker = false;
            }
        }
        else {
            // Need to check the home point
            if (AIGetHomePosition(unitToCheck) == c_nullPoint) {
                wantsToBeInBunker = false;
            }
            else if (!PointsInRange(UnitGetPosition(aiUnit), AIGetHomePosition(unitToCheck), c_campaignBunkerLoadRange)) {
                wantsToBeInBunker = false;
            }
        }

        //  Do not care about units that want to be in bunker when we want to unload.
        //  Similarly, do not care about units that do not want to be in bunker when we want to load.
        //
        if (wantsToBeInBunker == unload) {
            continue;
        }

        return unitToCheck;
    }
    return null;
}

//---------------------------------------------------------------------------------------------
bool CargoDefend (int player, unit aiUnit, unitgroup scanGroup, int searchRange, int loadRange, string wanted, string command) {
    unitgroup nearBunkerGroup;
    int bunkerCount;
    unit unitToCheck;   
    order ord = null;
    bool autoLoad = false;
    bool wantsToBeInBunker;

    scanGroup = UnitGroupFilterThreat(scanGroup, aiUnit, null, 0);
    scanGroup = UnitGroupFilterRegion(scanGroup, RegionCircle(UnitGetPosition(aiUnit), searchRange), 0);
   
    if (UnitGroupCount(scanGroup, c_unitCountAlive) == 0) { // no nearby enemies.

        //  Both checks are needed because auto loading bunkers is needed on campaign before the
        //  AI is active.....
        if (AIIsCampaign(player)) {
            autoLoad = true;
        }
        else if (AIGetDifficulty(player, c_diffAutoLoadBunkers)) {
            autoLoad = true;
        }

        if (autoLoad && (command == c_AB_BunkerChange)) {
            // handle bunkers on campaign differently.
            unitToCheck = CampaignWantsToBeInBunker(player, aiUnit, UnitCargoGroup(aiUnit), c_bunkerUnload);
            if (unitToCheck != null) {
                ord = AICreateOrder(player, command, e_AB_TransportUnloadUnit); // unload the bunker.
                OrderSetTargetPassenger(ord, unitToCheck);
            }

            if (ord == null) {

                unitToCheck = CampaignWantsToBeInBunker(player,
                                                        aiUnit,
                                                        AIFindUnits(player, wanted, UnitGetPosition(aiUnit), c_campaignBunkerLoadRange, c_noMaxCount),
                                                        c_bunkerLoad);
                if (unitToCheck != null) {
                    ord = AICreateOrder(player, command, e_AB_TransportLoadUnit); // load the bunker.
                    OrderSetTargetUnit(ord, unitToCheck);
                }
            }
        }
        else { // not a campaign bunker
            if (UnitCargoValue(aiUnit, c_unitCargoSpaceUsed) == 0) { // nothing to unload
                return false;
            }
            ord = AICreateOrder(player, command, e_AB_TransportUnloadAll); // unload bunker
        }
    }
    else { // nearby enemies found.
        if (UnitCargoValue(aiUnit, c_unitCargoSpaceFree) == 0) { // check for space
            return false;
        }

        if (command == c_AB_CommandCenterChange) {
            if (!AIAnyWorkersFleeingNearby(player,UnitGetPosition(aiUnit),8.0)) {
                return false;
            }
        }

        nearBunkerGroup = AIFindUnits(player, wanted, UnitGetPosition(aiUnit), loadRange, c_noMaxCount);
        bunkerCount = UnitGroupCount(nearBunkerGroup, c_unitCountAll);
        while (bunkerCount > 0) {
            unitToCheck = UnitGroupUnit(nearBunkerGroup, bunkerCount);
            bunkerCount = bunkerCount - 1;

            if (!UnitIsAlive(unitToCheck)) {
                continue;
            }
            if (UnitTestState(unitToCheck, c_unitStateInsideTransport)) {
                continue;
            }
           
            if (command == c_AB_CommandCenterChange) {
                ord = AICreateOrder(player, command, e_AB_TransportLoadAll);
            }
            else {
                ord = AICreateOrder(player, command, e_AB_TransportLoadUnit);
                OrderSetTargetUnit(ord, unitToCheck);
            }
            break;
        }
    }
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return false;
    }
    AICast(aiUnit, ord, c_noMarker, c_castHold);
    return true;
}

//--------------------------------------------------------------------------------------------------
//  *** COMMAND CENTER ***
//--------------------------------------------------------------------------------------------------
static order CallDownSupply (int player, unit aiUnit) {
    unitgroup scanGroup;
    int scanCount;
    unit depot;
    order ord;
    aifilter filter;
   
    ord = AICreateOrder(player, c_AB_SupplyDrop, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    scanGroup = AIFindUnits(player, "SupplyDepotUnderground", UnitGetPosition(aiUnit),
                            AIUnitFixed(player, c_TB_CommandCenter, c_fieldRadius)
                            + AIAbilityFixed(player, c_AB_SupplyDrop, c_fieldRange0),
                            c_noMaxCount
    );

    //  Filter out supply depots that are already buffed.
    //
    filter = AIFilter(player);
    AISetFilterBits(filter, UnitFilterStr(AIAbilityStr(player, c_AB_SupplyDrop, c_fieldTargetFiltersAB)));
    AISetFilterBehaviorCount(filter, c_noBehaviorMin, c_noBehaviorMax, c_BF_SupplyDrop);
   
    scanGroup = AIGetFilterGroup (filter, scanGroup);
    return AIUnitGroupGetValidOrder(scanGroup, ord, aiUnit, c_backwards);
}

static bool CallDownMule (int player, unit aiUnit) {
    unitgroup scanGroup;
    int scanCount;
    unit peon;
    order ord;

    ord = AICreateOrder(player, c_AB_CalldownMULE, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return false;
    }

    scanGroup = AIFindUnits(player, c_TU_SCV, UnitGetPosition(aiUnit),
                            AIAbilityFixed(player, c_AB_CalldownMULE, c_fieldRange0),
                            c_noMaxCount
    );

    //  Find only scv's that are gathering minerals and are close to their mineral target.
    scanGroup = AIFilterGathering(scanGroup, c_resourceTypeMinerals, c_maxDistanceToMinerals);
    scanCount = UnitGroupCount(scanGroup, c_unitCountAll);
    while (scanCount > 0) {
        //  Pick one to cast on / next to.
        peon = UnitGroupUnit(scanGroup, scanCount);
        scanCount = scanCount - 1;

        ord = AICreateOrder(player, c_AB_CalldownMULE, 0);
        OrderSetTargetPoint(ord, UnitGetPosition(peon));
        if (!UnitOrderIsValid(aiUnit, ord)) {
            continue;
        }
        AICast(aiUnit, ord, c_noMarker, c_castHold);
        return true;
    }
    return false;
}

void AIThinkCommandCenter(int player, unit aiUnit, unitgroup scanGroup) {
    order ord;

    if (CargoDefend(player, aiUnit, scanGroup, 10, 10, c_TU_SCV, c_AB_CommandCenterChange))
    {
        return;
    }

    if (AIEvalTacticalData(aiUnit, null)) {
        return;
    }

    if (AIIsCampaign(player)) {
        return;
    }

    if (AISuspectDetectionDanger(player)) {
        if (UnitGetPropertyInt(aiUnit, c_unitPropEnergy, c_unitPropCurrent) < 150) {
            return; // save for two comsats
        }
    }
    if (CallDownMule(player, aiUnit)) {
        return;
    }

    //  For now do supply only if we can't do mule,
    //  tempted to comment this out entirely
    ord = CallDownSupply(player, aiUnit);
    if (ord != null) {
        AICast(aiUnit, ord, c_noMarker, c_castHold);
        return;
    }
}

//--------------------------------------------------------------------------------------------------
//  *** BUNKER ***
//--------------------------------------------------------------------------------------------------
void AIThinkBunker(int player, unit aiUnit, unitgroup scanGroup) {
    CargoDefend(player, aiUnit, scanGroup, 8, 10, c_TU_Marine, c_AB_BunkerChange);
}

//--------------------------------------------------------------------------------------------------
//  ScannerSweep
//--------------------------------------------------------------------------------------------------
bool ScannerSweep (int player, unit aiUnit) {
    order ord;
    point loc;

    ord = AICreateOrder(player, c_AB_ScannerSweep, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return false;
    }

    //  If something is attacking while cloaked and we can defend if we reveal it, cast sweep.
    //
    loc = AIGetCloakedAttacker(player);

    //  Else if we have high energy then use sweep to scout something.
    //
    if (loc == null) {
        // TODO fix AIGetNextScoutLoc to return only important locations
        //if (UnitGetPropertyFixed(aiUnit, c_unitPropEnergyPercent, true) >= 200) {
        //    loc = AIGetNextScoutLoc(player);
        //}
    }
    if (loc == null) {
        return false;
    }
    OrderSetTargetPoint(ord, loc);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return false;
    }
    AICast(aiUnit, ord, c_noMarker, c_castHold);
    AIClearCloakedAttacker(player, loc);
    return true;
}

//--------------------------------------------------------------------------------------------------
//  *** SURVEILLANCE STATION ***
//--------------------------------------------------------------------------------------------------
void AIThinkOrbitalCommand (int player, unit aiUnit, unitgroup scanGroup) {
    if (AIEvalTacticalData(aiUnit, null)) {
        return;
    }

    if (!ScannerSweep(player, aiUnit)) {
        AIThinkCommandCenter(player, aiUnit, scanGroup);
    }
}

//--------------------------------------------------------------------------------------------------
//  *** MagneticMine ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeD8Charge (int player, unit aiUnit) {
    return AIEffectFixed(player, c_EF_D8ChargeDmg, c_fieldAreaRadius2) + 1.0;
}

void AIThinkD8Charge (int player, unit aiUnit, unitgroup scanGroup) {
    int scanCount;
    marker mark = AIMarker(aiUnit, c_MK_D8ChargeFlee);
    aifilter filter = AIFilter(player);

    scanGroup = AIFindUnits(player, null, UnitGetPosition(aiUnit), AIRangeD8Charge(player, aiUnit), c_noMaxCount);

    AISetFilterAlliance(filter, c_playerGroupAlly);
    AISetFilterMarker(filter, c_noMarkersMin, c_noMarkersMax, mark);
    AISetFilterSelf(filter, aiUnit);
    scanGroup = AIGetFilterGroup(filter, scanGroup);

    scanCount = UnitGroupCount(scanGroup, c_unitCountAll);
    while (scanCount > 0) {
        AICastFlee(UnitGroupUnit(scanGroup, scanCount), aiUnit, 6, mark);
        scanCount = scanCount - 1;
    }
}

//--------------------------------------------------------------------------------------------------
//  *** Raven ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeRaven (int player, unit aiUnit) {
    return 10;
}

const int c_seekerMissileMinMarker = 0;
const int c_seekerMissileMaxMarker = 0;

order HunterSeekerMissile (int player, unit aiUnit, unitgroup scanGroup, marker mark) {
    fixed damage;
    unitgroup targetGroup;
    aifilter filter;

    order ord = AITacticalOrder(player, aiUnit, c_AB_SeekerMissile);
    if (!ord) {
        return null;
    }

    //  Create the filters
    //
    filter = AIFilter(player);
    AISetFilterBits(filter, UnitFilterStr(AIAbilityStr(player, c_AB_SeekerMissile, c_fieldTargetFiltersAB)));
    AISetFilterAlliance(filter, c_playerGroupEnemy);
    damage = AIEffectFixed(player, c_EF_SeekerDamage, c_fieldAmount);
    AISetFilterLife(filter, damage*c_minDamageFraction, c_noMax);
    AISetFilterMarker(filter, c_noMarkersMin, c_noMarkersMax, mark);
    AISetFilterLifeSortReference(filter, damage, damage*c_distanceFromDamage);
   
    //  Select starting from the end, which is the target who's health is closest to the missile's
    //  damage.
    //
    targetGroup = AIGetFilterGroup(filter, scanGroup);
    return AIUnitGroupGetValidOrder(targetGroup, ord, aiUnit, c_backwards);
}

//---------------------------------------------------------------------------------------------
static bool CastAutoTurret (int player, unit aiUnit, unitgroup scanGroup, bool lowVitality) {   
    // must not modify scanGroup in this function
    point loc;
    order ord = AITacticalOrder(player, aiUnit, c_AB_AutoTurret);
    fixed minScore;

    if (!ord) {
        return false;
    }

    //  Relax the constraints a little if the raven is low on health.
    //
    if (lowVitality) {
        minScore = 1.0;
    }
    else {
        minScore = 2.0;
    }

    //  Finds the best point for the ai to cast an area of effect spell.  The point must put the
    //  turret in range of min hits targets, with an accumulative score GE 2.  Each target is assigned
    //  a score of 0.0 to 1.0 points, depending on whether the target's vitality is from 0.0 to 40.0.
    //  Up to an additional 1.0 point can be rewarded if the target has the optional bonus attribute.
    //
    loc = AIBestTargetPoint(
        AIWeaponGroup(player, c_WE_AutoTurret, scanGroup),
        2, // min hits
        40, // damage base
        minScore, // min score
        AIWeaponFixed(player, c_WE_AutoTurret, c_fieldRange),
        UnitGetPosition(aiUnit),
        AIRangeRaven(player, aiUnit),
        c_unitAttributeNone
    );
    if (!loc) {
        return false;
    }
    OrderSetTargetPoint(ord, loc);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return false;
    }
    AICast(aiUnit, ord, c_noMarker, c_castRetreat);
    return true;
}

fixed minToCastAutoTurret(int player) {
    return AIAbilityFixed(player, c_AB_AutoTurret, c_fieldEnergyCost) +
           AIAbilityFixed(player, c_AB_SeekerMissile, c_fieldEnergyCost);
}

const int c_RavenLowVitalityPercent = 65;

//---------------------------------------------------------------------------------------------
void AIThinkRaven (int player, unit aiUnit, unitgroup scanGroup) {
    order ord;
    marker mark;
    bool lowVitality;

    //  Must not modify scanGroup because it will be used for CastAutoTurret.
    mark = AIMarker(aiUnit, c_MK_SeekerMissile);
    ord = HunterSeekerMissile(player, aiUnit, scanGroup, mark);
    if (ord != null) {
        AICast(aiUnit, ord, mark, c_castRetreat);
        return;
    }
   
    //  If Raven not in danger, save enough energy for seeker missile.
    lowVitality = UnitGetPropertyInt(aiUnit, c_unitPropVitalityPercent, c_unitPropCurrent) < c_RavenLowVitalityPercent;
    if (!lowVitality && UnitGetPropertyInt(aiUnit, c_unitPropEnergy, c_unitPropCurrent) < minToCastAutoTurret(player)) {
        return;
    }

    if (CastAutoTurret(player, aiUnit, scanGroup, lowVitality)) {
        return;
    }
}
#12
AI Development / Re: Starcraft 2 functions/libraries here
February 27, 2010, 03:28:01 PM

TactTerrAI.galaxy
//--------------------------------------------------------------------------------------------------
//  *** THOR ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeThor (int player, unit aiUnit) {
    return AIAbilityFixed(player, c_AB_250mmStrikeCannons, c_fieldRange0) + 1;
}

order AIOrder250mmStrikeCannons(int player, unit aiUnit, unitgroup scanGroup, marker mark) {
    order ord;
    fixed damage;
    aifilter filter;
    bool airAllies;

    ord = AICreateOrder(player, c_AB_250mmStrikeCannons, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    damage = AIEffectFixed(player, c_EF_250mmStrikeCannonsPersistent, c_fieldPeriodCount) *
             AIEffectFixed(player, c_EF_250mmStrikeCannonsDamage, c_fieldAmount)
             ;

    filter = AIFilter(player);
    AISetFilterAlliance(filter, c_playerGroupEnemy);
    AISetFilterBits(filter, UnitFilterStr(AIAbilityStr(player, c_AB_250mmStrikeCannons, c_fieldTargetFiltersAB)));
    AISetFilterRange(filter, aiUnit, AIRangeThor(player, aiUnit));
    AISetFilterMarker(filter, c_noMarkersMin, c_noMarkersMax, mark);
    AISetFilterLife(filter, damage*c_minDamageFraction, c_noMax);
    AISetFilterLifeSortReference(filter, damage, damage*c_distanceFromDamage);
    //  Filter out units that can't attack allies since this ability is a disable.
    //
    airAllies = AINearbyPlaneTest(UnitGetPosition(aiUnit),
                                  player,
                                  AIRangeThor(player, aiUnit),
                                  c_planeAir,
                                  c_unitAllianceAlly)
                                  ;
    AISetFilterCanAttackAlly(filter, c_groundAlliesNearby, airAllies);

    //  Select starting from the end, which is the target that has health closest to the cannon's damage
    //
    scanGroup = AIGetFilterGroup(filter, scanGroup);
    return AIUnitGroupGetValidOrder(scanGroup, ord, aiUnit, c_backwards);
}

void AIThinkThor (int player, unit aiUnit, unitgroup scanGroup) {
    order ord;
    marker mark;
   
    //  If we already have a cannon order, ignore new orders so that we do not count
    //  our own marker again, when validating.
    //
    if (UnitOrderHasAbil(aiUnit, c_AB_250mmStrikeCannons)) {
        return;
    }

    mark = AIMarker(aiUnit, c_MK_250mmStrikeCannons);
    ord = AIOrder250mmStrikeCannons(player, aiUnit, scanGroup, mark);
    if (ord != null) {
        AICast(aiUnit, ord, c_noMarker, c_castHold);
    }
}

//--------------------------------------------------------------------------------------------------
//  *** GHOST ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeGhost (int player, unit aiUnit) {
    return MaxF(AIAbilityFixed(player, c_AB_EMP, c_fieldRange0) + 1,
                AIAbilityFixed(player, c_AB_Snipe, c_fieldRange0) + 1);
}

//---------------------------------------------------------------------------------------------
order AIOrderSnipe (int player, unit aiUnit, unitgroup scanGroup, marker mark) {
    order ord;
    fixed damage;
    aifilter filter;

    ord = AICreateOrder(player, c_AB_Snipe, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    damage = AIEffectInt(player, c_EF_SnipeDamage, c_fieldAmount);

    filter = AIFilter(player);
    AISetFilterAlliance(filter, c_playerGroupEnemy);
    AISetFilterBits(filter, UnitFilterStr(AIAbilityStr(player, c_AB_Snipe, c_fieldTargetFiltersAB)));
    AISetFilterRange(filter, aiUnit, AIAbilityFixed(player, c_AB_Snipe, c_fieldRange0) + 1);
    AISetFilterLifePerMarker(filter, damage, mark);
    AISetFilterLifeSortReference(filter, damage, damage*c_distanceFromDamage);

    //  Select starting from the end, to obtain the target that has health closest to snipe
    //  damage.
    //
    scanGroup = AIGetFilterGroup(filter, scanGroup);
    return AIUnitGroupGetValidOrder(scanGroup, ord, aiUnit, c_backwards);
}

//
const int c_gameLoopsPerSecond = 16;
const int c_framesPerThink = 12;
const int c_secondsPerSnipe = 4;
const int c_ghostMaxRandom = c_gameLoopsPerSecond * c_secondsPerSnipe / c_framesPerThink;

//---------------------------------------------------------------------------------------------
void AIThinkGhost (int player, unit aiUnit, unitgroup scanGroup) {
    // **Cloaking / EMP relocated to XML**
    marker mark;
    order ord;
    int randomVal;

    //  Add a delay on campaign.
    //
    if (AIIsCampaign(player)) {
        if (RandomInt(0, c_ghostMaxRandom) != 1) {
            return;
        }
    }

    if (AIEvalTacticalData(aiUnit, null)) {
        return;
    }

    mark = AIMarker(aiUnit, c_MK_Snipe);
    ord = AIOrderSnipe(player, aiUnit, scanGroup, mark); // this modifies scanGroup.
    if (ord != null) {
        AICast(aiUnit, ord, mark, c_castHold);
        return;
    }
}

//--------------------------------------------------------------------------------------------------
//  *** REAPER ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeReaper (int player, unit aiUnit) {
    return AIWeaponFixed(player, c_WE_Reaper, c_fieldRange);
}

const int c_BldgOnlyPercent = 60;

order AIOrderReapMine (int player, unit aiUnit, unitgroup scanGroup, marker mark) {
    order ord;
    int scanCount;
    unit target;
    bool bldgOnly;
    unitgroup friends;
    aifilter filter;
    unitfilter f;
    int bonus;

    //  See if this spell can be cast at all.
    //
    ord = AICreateOrder(player, c_AB_D8Charge, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    bonus = AIEffectInt(player, c_EF_D8ChargeDmg, c_fieldAttrArmored) * 2;
    bldgOnly = (UnitGetPropertyInt(aiUnit, c_unitPropVitalityPercent, c_unitPropCurrent) > c_BldgOnlyPercent);

    if (AICampSkirDiffTest(player, c_campAdvanced, c_skirVeryHard)) {
        bldgOnly = false;
    }

    //  Get enemies with enough life to be around when the spell goes off.
    //
    filter = AIFilter(player);
    AISetFilterAlliance(filter, c_playerGroupEnemy);
    AISetFilterLife(filter, AIEffectInt(player, c_EF_D8ChargeDmg, c_fieldAmount) * 2, c_noMax - bonus);
    AISetFilterLifeMod(filter, c_unitAttributeArmored, bonus);
    AISetFilterMarker(filter, c_noMarkersMin, c_noMarkersMax, mark);
    if (bldgOnly) {
        f = UnitFilterStr("Structure;Missile,Dead,Stasis,Worker"); // require buildings.
    }
    else {
        f = UnitFilterStr("-;Missile,Dead,Stasis,Worker"); // default filter.
    }
   
    //  Pick a building/unit with no allies nearby, starting with lowest health buildings that passed above tests.
    //
    scanGroup = AIGetFilterGroup(filter, scanGroup);
    scanCount = UnitGroupCount(scanGroup, c_unitCountAll);

    while (scanCount > 0) {
        target = UnitGroupUnit(scanGroup, scanCount);
        scanCount = scanCount - 1;
   
        //  For now, Reapers are only used as a diversion wave, so we can't target photon cannons.
        //  Photon cannons are very dangerous to reapers
        //
        if (UnitGetType(target) == c_PB_PhotonCannon) {
            continue;
        }

        //  Check for friendly fire.
        //
        friends = UnitGroupFilterAlliance(
            AIFindUnits(player, null, UnitGetPosition(target), AIEffectFixed(player, c_EF_D8ChargeDmg, c_fieldAreaRadius2), c_noMaxCount),
            player,
            c_allianceIdPassive,
            0
        );
        if (UnitGroupCount(friends, c_unitCountAlive) > 0) {
            continue;
        }

        //  Check target validity.
        //
        OrderSetTargetUnit(ord, target);
        if (UnitOrderIsValid(aiUnit, ord)) {
            return ord;
        }
    }
    return null;
}

void AIThinkReaper (int player, unit aiUnit, unitgroup scanGroup) {
    // **Reaper AI reproduced in XML**
    //  Melee AI does not call this AIThink routine.

    //  Reaper AI is left in TactTerrAI to serve as an example of two different ways to write the same
    //  AI.  To see the xml equivalent of the Reaper AI, look in TacticalData.xml and TargetFindData.xml.
    //  In general, AI implemented in galaxy scripts will be slower than AI implemented in data.
    //  If it is convenient to express AI in data, one should do so.  In this case, converting reaper AI
    //  to xml resulted in a 2x performance gain.
    //
    marker mark = AIMarker(aiUnit, c_MK_D8Charge);
    order ord;

    scanGroup = UnitGroupFilterPlane(scanGroup, c_planeGround, 0);
    ord = AIOrderReapMine(player, aiUnit, scanGroup, mark); //  Modifies scanGroup.
    if (ord == null) {
        return;
    }
    AICast(aiUnit, ord, mark, c_castRetreat);
}

//--------------------------------------------------------------------------------------------------
//  *** BATTLE CRUISER ***
//--------------------------------------------------------------------------------------------------
order AIOrderYamato (int player, unit aiUnit, unitgroup scanGroup, marker mark) {
    order ord;
    aifilter filter;
    fixed damage;

    //  Only cast as part of an existing offensive.
    //
    if (!AIIsAttackOrder(UnitOrder(aiUnit, 0))) {
        return null;
    }
   
    //  See if this spell can be cast at all.
    //
    ord = AICreateOrder(player, c_AB_Yamato, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }

    damage = AIEffectFixed(player, c_EF_YamatoDamage, c_fieldAmount);

    //  Search enemies for those with hit points closest to the damage yamato gun inflicts.
    //
    filter = AIFilter(player);
    AISetFilterAlliance(filter, c_playerGroupEnemy);
    AISetFilterLifePerMarker(filter, damage, mark);
    AISetFilterLifeSortReference(filter, damage, damage*c_distanceFromDamage);
    scanGroup = AIGetFilterGroup(filter, scanGroup);
   
    return AIUnitGroupGetValidOrder(scanGroup, ord, aiUnit, c_backwards);
}

//---------------------------------------------------------------------------------------------
void AIThinkBattleCruiser (int player, unit aiUnit, unitgroup scanGroup) {
    // **Defensive Matrix located in TacticalData.xml / ValidatorData.xml**
    // **Missile Pods located in TacticalData.xml / TargetFindData.xml**
   
    marker mark;
    order ord;

    //  If we already have a yamato order, ignore new orders so that we do not count
    //  our own markers again.
    if (UnitOrderHasAbil(aiUnit, c_AB_Yamato)) {
        return;
    }
   
    //  This modifies scanGroup, which is Ok.. so long as it is not used elsewhere.
    mark = AIMarker(aiUnit, c_MK_Yamato);
    ord = AIOrderYamato(player, aiUnit, scanGroup, mark);
    if (ord != null) {
        AICast(aiUnit, ord, mark, c_castHold);
        return;
    }
}

//--------------------------------------------------------------------------------------------------
//  *** VIKING (ground mode) ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeViking (int player, unit aiUnit) {
    return AIWeaponFixed(player, c_WE_VikingFighter, c_fieldRange) + 2;
}

point VikingModeChange (int player, unit aiUnit, unitgroup scanGroup, bool inAssault) {
    int scanCount;
    int inAir;
    int onGround;
    int cliffLevel;
    int testCliffLevel;
    string type = AIGetBullyType(aiUnit);
    point here = UnitGetPosition(aiUnit);
    point there;
    unitgroup scanGroupThreat;
    int onGroundThreatCount;

    //  First, find all units within viking range.
    //
    scanGroup = UnitGroupFilterRegion(scanGroup, RegionCircle(here, AIRangeViking(player, null)), 0);
    inAir = UnitGroupCount(scanGroup, c_unitCountAlive);

    //  Next, find the number of ground and air units within viking range.
    //
    scanGroup = UnitGroupFilterPlane(scanGroup, c_planeGround, 0);
    onGround = UnitGroupCount(scanGroup, c_unitCountAlive);
    inAir = inAir - onGround; // air = all - ground

    //  If a bully type is set, check to see if we're in the right mode if idle.
    if (type != null && onGround == 0 && inAir == 0 && UnitOrderCount(aiUnit) == 0) {
        if (type == UnitGetType(aiUnit)) {
            return null;
        }
        else {
            return UnitGetPosition(aiUnit);
        }
    }

    //  Only pay attention to threats on the ground.
    //
    scanGroupThreat = UnitGroupFilterThreat(scanGroup, aiUnit, null, 0);
    onGroundThreatCount = UnitGroupCount(scanGroupThreat, c_unitCountAlive);

    if (inAssault) { // viking is on ground.
        //  Go to air mode when there's nothing on the ground anymore.
        //
        if (onGround == 0) {
            return UnitGetPosition(aiUnit);
        }
        //  Also, go to air mode when a pack of new air units shows up and we have killed most of the
        //  ground units.
        if (inAir >= onGroundThreatCount + 3 || (inAir > 0 && onGroundThreatCount == 0)) {
            return UnitGetPosition(aiUnit);
        }
    }
    else { // viking is in air.
        //  If air targets remain, finish them off before switching.
        //
        if (inAir != 0) {
            return null;
        }

        if (onGround > 0) {
            cliffLevel = CliffLevel(here);
           
            //  Only switch if there is a ground target on the same or lower cliff level so that
            //  we are guaranteed to be able to navigate to it.
            //
            while (onGround > 0) {
                there = UnitGetPosition(UnitGroupUnit(scanGroup, onGround));
                testCliffLevel = CliffLevel(there);
                if (cliffLevel >= testCliffLevel) {
                    return there;
                }
                onGround = onGround - 1;
            }
        }
    }
    return null;
}

//---------------------------------------------------------------------------------------------
void AIThinkVikingAssault (int player, unit aiUnit, unitgroup scanGroup) {
    order ord = AICreateOrder(player, c_AB_FighterMode, 0);
    unitgroup airGroup;
    int inAir;
   
    //  Check to see if this is a valid order at all.
    //
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return;
    }

    //  Check the number of air units to decide whether to ignore based on order count.
    //
    airGroup = UnitGroupFilterRegion(scanGroup,
                                     RegionCircle(UnitGetPosition(aiUnit), AIRangeViking(player, null)),
                                     0)
                                     ;
    airGroup = UnitGroupFilterPlane(airGroup, c_planeAir, 0);
    inAir = UnitGroupCount(airGroup, c_unitCountAlive);

    //  Do not switch to an air unit while processing an order on the ground. That way we won't
    //  interrupt the queued attack move order we get when we were told to land.
    //
    if (inAir == 0 && UnitOrderCount(aiUnit) > 0) {
        return;
    }

    if (VikingModeChange(player, aiUnit, scanGroup, true) == null) {
        return;
    }

    AICast(aiUnit, ord, c_noMarker, c_castHold);
}

//--------------------------------------------------------------------------------------------------
//  *** VIKING (air mode) ***
//--------------------------------------------------------------------------------------------------
void AIThinkVikingFighter (int player, unit aiUnit, unitgroup scanGroup) {
    point there;
    order ord = AICreateOrder(player, c_AB_AssaultMode, 0);

    if (!UnitOrderIsValid(aiUnit, ord)) {
        return;
    }

    there = VikingModeChange(player, aiUnit, scanGroup, false);
    if (there == null) {
        return;
    }

    AICast(aiUnit, ord, c_noMarker, c_castHold);

    //  Queue an attack move towards the threat to make sure we path past a LOS blocker.
    //
    AISetTacticalAttackTargetPoint(aiUnit, there);
}
#13
AI Development / Re: Starcraft 2 functions/libraries here
February 27, 2010, 03:26:41 PM
TactProtAI.galaxy < suite

//--------------------------------------------------------------------------------------------------
void AIThinkObelisk (int player, unit aiUnit, unitgroup scanGroup) {
    ////  1. Buff harvesting probes
    ////  2. If unit shields low & enemies nearby, heal it.
    ////  3. If high templar nearby, charge mana.
    //order ord;

    ////ord = ProtonCharge(player, aiUnit, scanGroup);
    ////if (ord != null) {
    ////    AICast(aiUnit, ord, c_noMarker, c_castHold);
    ////    return;
    ////}

    ////ord = ArgusLink(player, aiUnit, scanGroup);
    ////if (ord != null) {
    ////    AICast(aiUnit, ord, c_noMarker, c_castHold);
    ////}

    ////ord = ShieldBattery(player, aiUnit, scanGroup);
    ////if (ord != null) {
    ////    AICast(aiUnit, ord, c_noMarker, c_castHold);
    ////}
}

//--------------------------------------------------------------------------------------------------
//  *** MOTHERSHIP ***
//--------------------------------------------------------------------------------------------------

fixed AIRangeMothership (int player, unit aiUnit) {
    return MaxF(AIAbilityFixed(player, c_AB_Vortex, c_fieldRange0) + 1,
                AIAbilityFixed(player, c_AB_TemporalRift, c_fieldRange0) + 1);
}

fixed MinToCastMotherShip (int player) {
    //return AIAbilityFixed(player, c_AB_Vortex, c_fieldEnergyCost) + //  To Save enough mana for wormhole transit, swap out the commented lines.
    //       AIAbilityFixed(player, c_AB_WormholeTransit, c_fieldEnergyCost);
    return AIAbilityFixed(player, c_AB_Vortex, c_fieldEnergyCost);
}

const fixed c_enemyMultiplierVortex = 1.25;

//--------------------------------------------------------------------------------------------------
order Vortex (int player, unit aiUnit, unitgroup scanGroup) {
    point loc;
    unitgroup vortexGroup;

    order ord = AITacticalOrder(player, aiUnit, c_AB_Vortex);
    if (ord == null) {
        return null;
    }

    vortexGroup = AIEffectGroup(player, c_EF_VortexArea, scanGroup);

    loc = AIBestTargetPoint(
        vortexGroup,
        5, // min hits
        40, // damage base
        4.0, // score
        AIEffectFixed(player, c_EF_VortexArea, c_fieldAreaRadius0),
        UnitGetPosition(aiUnit),
        AIRangeMothership(player, aiUnit),
        c_unitAttributeNone
    );

    if (loc == null) {
        return null;
    }
   
    OrderSetTargetPoint(ord, loc);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }
    return ord;
}

//--------------------------------------------------------------------------------------------------
order TemporalRift (int player, unit aiUnit, unitgroup scanGroup) {
    point loc;
   
    order ord = AITacticalOrder(player, aiUnit, c_AB_TemporalRift);
    if (ord == null) {
        return null;
    }

    loc = AIBestTargetPoint(
        AIEffectGroup(player, c_EF_TemporalRiftSearchArea, scanGroup),
        5, // min hits
        40, // damage base
        3.85, // min score
        AIEffectFixed(player, c_EF_TemporalRiftSearchArea, c_fieldAreaRadius0),
        UnitGetPosition(aiUnit),
        AIRangeMothership(player, aiUnit),
        c_unitAttributeNone
    );

    if (loc == null) {
        return null;
    }
   
    OrderSetTargetPoint(ord, loc);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return null;
    }
    return ord;
}

//--------------------------------------------------------------------------------------------------
void AIThinkMothership (int player, unit aiUnit, unitgroup scanGroup) {
    order ord;
    unitfilter f;
    fixed allyEnemyRatio;
    aifilter filter;
   
    //  Make sure to save mana so we use both abilities.
    //
    if (UnitGetPropertyInt(aiUnit, c_unitPropEnergy, c_unitPropCurrent) < MinToCastMotherShip(player)) {
        return;
    }
   
    //  If a unit already has temporal rift, filter it.
    //
    filter = AIFilter(player);
    AISetFilterBehaviorCount(filter, c_noBehaviorMin, c_noBehaviorMax, c_BF_TemporalBuff);
    scanGroup = AIGetFilterGroup(filter, scanGroup);

    //  Get the ratio of allies to enemies to see if we should cast vortex or temporal rift
    //
    f = UnitFilterStr("-;Missile,Dead,Stasis,Worker");
    allyEnemyRatio = AIAllyEnemyRatio(player, UnitGetPosition(aiUnit), f, AIRangeMothership(player, aiUnit), c_noThreshold);

    if (allyEnemyRatio < c_enemyMultiplierVortex) {
        ord = Vortex(player, aiUnit, scanGroup);
        if (ord != null) {
            AICast(aiUnit, ord, c_noMarker, c_castRetreat);
            return;
        }
    }

    ord = TemporalRift(player, aiUnit, scanGroup);
    if (ord != null) {
        AICast(aiUnit, ord, c_noMarker, c_castRetreat);
        return;
    }
}

//--------------------------------------------------------------------------------------------------
//  *** HIGH TEMPLAR ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeHighTemplar (int player, unit aiUnit) {
    return AIAbilityFixed(player, c_AB_PhaseShift, c_fieldRange0) + 1;
}

const int c_phaseShiftMinHealth = 425; //  carriers and above.
const int c_phaseShiftLowVitMinHealth = 300;

order PhaseShift (int player, unit aiUnit, unitgroup scanGroup, marker mark, bool lowVitality) {
    order ord;
    aifilter filter;
    bool airAllies;
    int minVitality;

    ord = AITacticalOrder(player, aiUnit, c_AB_PhaseShift);
    if (ord == null) {
        return null;
    }

    if (lowVitality) {
        minVitality = c_phaseShiftLowVitMinHealth;
    }
    else {
        minVitality = c_phaseShiftMinHealth;
    }

    //  Test to see if we have airborne allies, to determine whether to PhaseShift
    //  an enemy that only attacks air.
    airAllies = AINearbyPlaneTest(UnitGetPosition(aiUnit), player, AIRangeHighTemplar(player, aiUnit), c_planeAir, c_unitAllianceAlly);
   
    filter = AIFilter(player);
    AISetFilterBits(filter, UnitFilterStr(AIAbilityStr(player, c_AB_PhaseShift, c_fieldTargetFiltersAB)));
    AISetFilterLife(filter, minVitality, c_noMax);
    AISetFilterMarker(filter, c_noMarkersMin, c_noMarkersMax, mark);
    AISetFilterCanAttackAlly(filter, c_groundAlliesNearby, airAllies);
   
    scanGroup = AIGetFilterGroup(filter, scanGroup);
    return AIUnitGroupGetValidOrder(scanGroup, ord, aiUnit, c_forwards);
}

//--------------------------------------------------------------------------------------------------
const fixed c_EnemyMultiplierHighTemplar = 1.25;
const fixed c_MinThreshold = 100.0;
const int c_HighTemplarLowVitPerc = 50;

void UnitGroupTest (unitgroup scanGroup) {
    DebugVarInt("group strength", FixedToInt(AIUnitGroupStrength(scanGroup)));
}

void AIThinkHighTemplar (int player, unit aiUnit, unitgroup scanGroup) {
    marker mark;
    order ord;
    bool lowVitality;
    unitfilter f;
    region r;
    unitgroup enemyGroup;

    if (AIEvalTacticalData(aiUnit, null)) {
        return;
    }

    //  If we already have a psi storm order, ignore any new orders since psi storm is more important.
    //  If we already have an PhaseShift order, ignore any new PhaseShift orders.
    if (UnitOrderHasAbil(aiUnit, c_AB_PhaseShift) || UnitOrderHasAbil(aiUnit, c_AB_PsiStorm)) {
        return;
    }

    //  Low Vitality = less than 50%, then use this to escape.
    lowVitality = (UnitGetPropertyInt(aiUnit, c_unitPropVitalityPercent, c_unitPropCurrent) < c_HighTemplarLowVitPerc);

    if (!lowVitality) {
        //  Don't cast if the enemy only has 1 unit when we are at full health.
        //  If we have less than 1.25 * the enemies forces.
        f = UnitFilterStr("-;Missile,Dead,Stasis,Worker");
        r = RegionCircle(UnitGetPosition(aiUnit), AIRangeHighTemplar(player, aiUnit));
        if ((UnitGroupCount(UnitGroupAlliance(player, c_unitAllianceEnemy, r, null, c_noMaxCount), c_unitCountAll) < 2) ||
            AIAllyEnemyRatio(player, UnitGetPosition(aiUnit), f, AIRangeHighTemplar(player, aiUnit), c_MinThreshold) > c_EnemyMultiplierHighTemplar) {
            return;
        }
    }

    mark = AIMarker(aiUnit, c_MK_PhaseShift);
    ord = PhaseShift(player, aiUnit, scanGroup, mark, lowVitality);
    if (ord != null) {
        AICast(aiUnit, ord, mark, c_castRetreat);
        return;
    }
}


//--------------------------------------------------------------------------------------------------
void AIThinkGateway (int player, unit aiUnit, unitgroup scanGroup) {
    order ord;
   
    if (AIEvalTacticalData(aiUnit, null)) {
        return;
    }

    if (AITechCount(player, c_PR_WarpGateResearch, c_techCountCompleteOnly) == 0) {
        return;
    }

    AISetWantsToUpgrade(aiUnit);

    ord = AICreateOrder(player, c_AB_UpgradeToWarpGate, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return;
    }
 
    AICast(aiUnit, ord, c_noMarker, c_castHold);
}


//--------------------------------------------------------------------------------------------------
//  *** WarpPrism ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeWarpPrism (int player, unit aiUnit) {
    return 1;
}

//--------------------------------------------------------------------------------------------------
//  *** WarpPrism (transport mode) ***
//--------------------------------------------------------------------------------------------------
const fixed c_warpPrismPhaseRange = 1.0;

void AIThinkWarpPrism (int player, unit aiUnit, unitgroup scanGroup) {
    order ord = AICreateOrder(player, c_AB_WPPhasingMode, 0);
    string type = AIGetBullyType(aiUnit);
   
    if (UnitOrderCount(aiUnit) > 0) {
        return;
    }

    if (!UnitOrderIsValid(aiUnit, ord)) {
        return;
    }

    if (type != c_PU_WarpPrismPhasing) {
        return;
    }

    if (AIGetHomePosition(aiUnit) == c_nullPoint) {
        return;
    }

    if (!PointsInRange(UnitGetPosition(aiUnit), AIGetHomePosition(aiUnit), c_warpPrismPhaseRange)) {
        return;
    }

    AICast(aiUnit, ord, c_noMarker, c_castHold);
}

//--------------------------------------------------------------------------------------------------
//  *** WarpPrism (power mode) ***
//--------------------------------------------------------------------------------------------------
void AIThinkWarpPrismPhasing (int player, unit aiUnit, unitgroup scanGroup) {
    order ord = AICreateOrder(player, c_AB_WPTransportMode, 0);
    string type = AIGetBullyType(aiUnit);
   
    if (UnitOrderCount(aiUnit) > 0) {
        return;
    }

    if (!UnitOrderIsValid(aiUnit, ord)) {
        return;
    }

    if (type == c_PU_WarpPrismPhasing) {
        if (AIGetHomePosition(aiUnit) != c_nullPoint) {
            if (PointsInRange(UnitGetPosition(aiUnit), AIGetHomePosition(aiUnit), c_warpPrismPhaseRange)) {
                // we're supposed to provide power at this point
                return;
            }
        }
    }

    AICast(aiUnit, ord, c_noMarker, c_castHold);
}
#14
AI Development / Re: Starcraft 2 functions/libraries here
February 27, 2010, 03:24:57 PM


TactProtAI.galaxy
//--------------------------------------------------------------------------------------------------
//  *** Disruptor ***
//--------------------------------------------------------------------------------------------------
const fixed c_forceFieldRadius = 3;
const fixed c_disruptorRange = 11;

fixed AIRangeDisruptor (int player, unit aiUnit) {
    return c_disruptorRange;
}

order AIForceField (int player, unit aiUnit, unitgroup scanGroup, fixed scanRange, marker m) {
    order ord;
    order enemyOrd;
    unitgroup enemyGroup;
    unitgroup friendlyGroup;
    unitfilter filter;
    unit enemyUnit;
    unit friendlyUnit;
    unit possibleTargetUnit;
    unit bestTargetUnit = null;
    point myPos = UnitGetPosition(aiUnit);
    fixed myFacing = UnitGetFacing(aiUnit);
    point forceFieldTarget;
    int forceFieldMaxRadius = 5;
    int priorityFound = 10;
    bool emergencyCast = false;

    // Loop control
    int enemyCount = 0;
    int friendlyCount = 0;

    // Enemy test values
    int enemyVit = 0;
    point enemyPos;
    fixed enemyFacing = 0;

    // Friendly test values
    int friendlyVit = 0;
    fixed friendlyFacing = 0;

    // Do not proceed if the order is invalid for some reason
    ord = AICreateOrder(player, c_AB_ForceField, 0);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return ord;
    }

    // Is there a threat in the area
    enemyGroup = UnitGroupFilterThreat(scanGroup, aiUnit, null, 0);
    enemyCount = UnitGroupCount(enemyGroup, c_unitCountAlive);
    if (enemyCount <= 0) {
        return ord;
    }

    // Assess life and energy
    // A good energy buffer is 50 energy left over.  100 energy is needed to cast in any battle
    // If our life is less than 50%, use the energy buffer.
    if (UnitGetPropertyInt(aiUnit, c_unitPropEnergy, c_unitPropCurrent) <= 100) {
        if (UnitGetPropertyInt(aiUnit, c_unitPropLifePercent, c_unitPropCurrent) <= 50) {
            emergencyCast = true;
        }
    }

    // Setup a friendly filter
    filter = UnitFilter(0,0,0,0);
    UnitFilterSetState(filter, c_targetFilterSelf,                      c_unitFilterRequired);
    UnitFilterSetState(filter, c_targetFilterAlly,                      c_unitFilterRequired);

    UnitFilterSetState(filter, c_targetFilterUncommandable,             c_unitFilterExcluded);
    UnitFilterSetState(filter, c_targetFilterWorker,                    c_unitFilterExcluded);
    UnitFilterSetState(filter, c_targetFilterUnderConstruction,         c_unitFilterExcluded);
    UnitFilterSetState(filter, c_targetFilterStructure,                 c_unitFilterExcluded);

    // *** Scan the area for the following, set priority unit when found ***
    // Priority 1: A friendly unit close to death, who has a melee enemy close by
    // Priority 2: An enemy unit close to death, who has a friendly unit close by
    // Priority 3: A friendly ranged unit who has a melee enemy close by
    // Priority 4: Enemy near me
    // Priority 5: Any Enemy close to death, facing away from me
    //
    // Scan enemies
    while (enemyCount > 0) {
        enemyUnit = UnitGroupUnit(enemyGroup, enemyCount);
        enemyCount = enemyCount - 1;

        // Get enemy data
        enemyVit = UnitGetPropertyInt(enemyUnit, c_unitPropLifePercent, c_unitPropCurrent);
        enemyFacing = UnitGetFacing(enemyUnit);
        enemyPos = UnitGetPosition(enemyUnit);
        enemyOrd = UnitOrder(enemyUnit, 0);
   
        friendlyGroup = UnitGroup(null, c_playerAny, RegionCircle(enemyPos, forceFieldMaxRadius), filter, 0);
        friendlyCount = UnitGroupCount(friendlyGroup, c_unitCountAll);

        // Scan friends near enemyUnit
        while (friendlyCount > 0) {
            friendlyUnit = UnitGroupUnit(friendlyGroup, friendlyCount);
            friendlyCount = friendlyCount - 1;
            // Get friendly data
            friendlyVit = UnitGetPropertyInt(friendlyUnit, c_unitPropLifePercent, c_unitPropCurrent);

            if (UnitMarkerCount(friendlyUnit, m) > 0) {
                continue;
            }
            // Test Priority Target 4 first, if we are in a state of saving ourself
            if (emergencyCast) {
                if (PointsInRange(myPos, enemyPos, forceFieldMaxRadius)) {
                    priorityFound = 1;
                    bestTargetUnit = friendlyUnit;
                    break;
                }
            }
            // Test Priority Target 1
            else if (friendlyVit < 25) {
                priorityFound = 1;
                bestTargetUnit = friendlyUnit;
                break;
            }
            // Test Priority Target 2
            else if (priorityFound > 2 && enemyVit < 25) { // && Test for non-ranged only
                priorityFound = 2;
                possibleTargetUnit = enemyUnit;
            }
            // Test Priority Target 3
            else if (false) { //priorityFound > 3
                // Not really able to test for this yet
                // Need to determine if the unit in question has a ranged weapon
            }
            // Test Priority Target 4
            else if (priorityFound > 4 && PointsInRange(myPos, enemyPos, forceFieldMaxRadius)) {
                priorityFound = 4;
                possibleTargetUnit = enemyUnit;
            }
            // Test Priority Target 5
            else if (priorityFound > 5 && enemyVit < 25 && enemyFacing - myFacing < 90) {
                priorityFound = 5;
                possibleTargetUnit = enemyUnit;
            }
            // More tests here
        }

        if (bestTargetUnit) {
            break;
        }
    }

    if (bestTargetUnit != null) {
        if (possibleTargetUnit) {
            bestTargetUnit = possibleTargetUnit;
        }
    }

    // Do some other things here, like if we are targetting a retreating enemy (priority 5)
    // adjust the target offset a bit ahead of the unit based on facing.
    // We would want this for priority 3 as well when that is valid.

    forceFieldTarget = UnitGetPosition(bestTargetUnit);

    if (!forceFieldTarget) {
        return null;
    }
    OrderSetTargetPoint(ord, forceFieldTarget);

    return ord;
}

//--------------------------------------------------------------------------------------------------
static bool Hallucinate (int player, unit aiUnit, unitgroup scanGroup) {
    point here;
    order ord;

    // wait until fighting 5+ enemy units
    //
    if (!AIIsAttackOrder(UnitOrder(aiUnit, 0))) {
        return false;
    }
    if (UnitGroupCount(scanGroup, c_unitCountAlive) < 5) {
        return false;
    }

    ord = AICreateOrder(player, c_AB_Hallucinate, e_AB_Hallucinate_Zealot);
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return false;
    }

    here = UnitGetPosition(aiUnit);
    if (AINearbyUnits(player, c_PU_Zealot, here, 5, 2)) {
        AICast(aiUnit, ord, c_noMarker, c_castHold);
        return true;
    }
    if (AINearbyUnits(player, c_PU_Stalker, here, 5, 2)) {
        ord = AICreateOrder(player, c_AB_Hallucinate, e_AB_Hallucinate_Stalker);
        AICast(aiUnit, ord, c_noMarker, c_castHold);
        return true;
    }
    if (AINearbyUnits(player, c_PU_Immortal, here, 5, 2)) {
        ord = AICreateOrder(player, c_AB_Hallucinate, e_AB_Hallucinate_Immortal);
        AICast(aiUnit, ord, c_noMarker, c_castHold);
        return true;
    }
    return false;
}

//--------------------------------------------------------------------------------------------------
static bool ForceField (int player, unit aiUnit, unitgroup scanGroup) {

    return false;

//    forceFieldMarker = MarkerCastingUnit(c_MK_Snipe, aiUnit);
//    MarkerSetMatchFlag(forceFieldMarker, c_markerMatchLink, true);
//    MarkerSetMismatchFlag(forceFieldMarker, c_markerMatchId, true);
//
//    ord = AIForceField(player, aiUnit, scanGroup, c_disruptorRange, forceFieldMarker);
//
//    if (ord) {
//        AICast(aiUnit, ord, forceFieldMarker, c_castHold);
//        return;
//    }
}

//--------------------------------------------------------------------------------------------------
static bool MolDisplacer (int player, unit aiUnit, unitgroup scanGroup) {
    return false;
}

//--------------------------------------------------------------------------------------------------
void AIThinkDisruptor (int player, unit aiUnit, unitgroup scanGroup) {
    if (Hallucinate(player, aiUnit, scanGroup)) {
        return;
    }
    if (ForceField(player, aiUnit, scanGroup)) {
        return;
    }
    MolDisplacer(player, aiUnit, scanGroup);
}

//--------------------------------------------------------------------------------------------------
//  *** DARK PYLON ***
//--------------------------------------------------------------------------------------------------
fixed AIRangeObelisk (int player, unit aiUnit) {
    return AIAbilityFixed(player, c_AB_ShieldBattery, c_fieldRange0) + 1;

    //return MaxF(AIAbilityFixed(player, c_AB_ArgusLink, c_fieldRange0),
    //            AIAbilityFixed(player, c_AB_ShieldBattery, c_fieldRange0)) + 1
    //            ;
}

////--------------------------------------------------------------------------------------------------
//order ProtonCharge (int player, unit aiUnit, unitgroup scanGroup) {
//    order ord;
//    point loc;
//    unitgroup probeGroup;
//    aifilter filter;
//
//    ord = AITacticalOrder(player, aiUnit, c_AB_ProbeBuff);
//    if (!UnitOrderIsValid(aiUnit, ord)) {
//        return null;
//    }
//
//    probeGroup = AIFindUnits(
//        player,
//        c_PU_Probe,
//        UnitGetPosition(aiUnit),
//        AIAbilityFixed(player, c_AB_ProbeBuff, c_fieldRange0) + AIEffectFixed(player, c_EF_ProtonChargeSearchArea, c_fieldAreaRadius0),
//        c_noMaxCount
//    );
//
//    //  Filter for probes that are gathering, but not buffed.
//    //
//    filter = AIFilter(player);
//    AISetFilterBits(filter, UnitFilterStr(AIAbilityStr(player, c_AB_ProbeBuff, c_fieldTargetFiltersAB)));
//    AISetFilterBehaviorCount(filter, c_noBehaviorMin, c_noBehaviorMax, c_BF_ProbeBuff);
//    probeGroup = AIGetFilterGroup(filter, probeGroup);
//    probeGroup = AIFilterGathering(probeGroup, c_resourceTypeMinerals, c_maxDistanceToMinerals);
//
//    loc = AIBestTargetPoint(
//        probeGroup,
//        5, // min hits
//        50, // damage base. set to whatever since don't care about score.
//        0, // score. set to zero since only care about hits.
//        AIEffectFixed(player, c_EF_ProtonChargeSearchArea, c_fieldAreaRadius0),
//        UnitGetPosition(aiUnit),
//        AIAbilityFixed(player, c_AB_ProbeBuff, c_fieldRange0),
//        c_unitAttributeNone
//    );
//
//    if (loc == null) {
//        return null;
//    }
//   
//    OrderSetTargetPoint(ord, loc);
//    if (!UnitOrderIsValid(aiUnit, ord)) {
//        return null;
//    }
//    return ord;
//}

////--------------------------------------------------------------------------------------------------
//const fixed c_argusLinkMax = 150;
//
//order ArgusLink (int player, unit aiUnit, unitgroup scanGroup) {
//    order ord;
//    unitgroup group;
//    aifilter filter;
//   
//    fixed reserve;
//    fixed highTemplarMaxEnergy;
//    fixed energy;
//    fixed argusLinkMin;
//   
//    ord = AITacticalOrder(player, aiUnit, c_AB_ArgusLink);
//    if (!UnitOrderIsValid(aiUnit, ord)) {
//        return null;
//    }
//
//    //  Find the minimum amount of mana the high templar must have in order to
//    //  save 25 mana for buffing probes.
//    //
//    reserve = AIAbilityFixed(player, c_AB_ProbeBuff, c_fieldEnergyCost);
//    highTemplarMaxEnergy = AIUnitFixed(player, c_PU_HighTemplar, c_fieldEnergyMax);
//    energy = UnitGetPropertyFixed(aiUnit, c_unitPropEnergy, c_unitPropCurrent);
//    argusLinkMin = highTemplarMaxEnergy + (reserve - energy) / AIAbilityFixed(player, c_AB_ArgusLink, c_fieldDrainFactor);
//
//    if (argusLinkMin > c_argusLinkMax) {
//        return null;
//    }
//
//    //  For now, just recharge high templars.
//    //
//    group = AIFindUnits(player, c_PU_HighTemplar, UnitGetPosition(aiUnit), AIRangeObelisk(player, aiUnit), c_noMaxCount);
//    filter = AIFilter(player);
//    AISetFilterBits(filter, UnitFilterStr(AIAbilityStr(player, c_AB_ArgusLink, c_fieldTargetFiltersAB)));
//    AISetFilterAlliance(filter, c_playerGroupAlly);
//    AISetFilterEnergy(filter, argusLinkMin, c_argusLinkMax);   
//    AISetFilterLife(filter, c_noMin, c_noMax);  //  Give the energy to the highest life high templar first.
//   
//    group = AIGetFilterGroup(filter, group);
//    return AIUnitGroupGetValidOrder(group, ord, aiUnit, c_forwards);
//}

////--------------------------------------------------------------------------------------------------
//const fixed c_shieldBatteryMaxShields = 15;
//const int c_batteryMinEnergyNoHostiles = 100;
//const int c_batteryMinEnergyHostiles = 6;
//
//order ShieldBattery (int player, unit aiUnit, unitgroup scanGroup) {
//    order ord;
//    aifilter allyFilter;
//    unitgroup group;
//    region r;
//    int energy = UnitGetPropertyInt(aiUnit, c_unitPropEnergy, c_unitPropCurrent);
//
//    //  It looks silly to cast every time the shield battery gains one energy, so require some low minimum threshold.
//    //
//    if (energy < c_batteryMinEnergyHostiles) {
//        return null;
//    }
//
//    ord = AITacticalOrder(player, aiUnit, c_AB_ShieldBattery);
//    if (!UnitOrderIsValid(aiUnit, ord)) {
//        return null;
//    }
// 
//    //  If there are no enemy units, and energy is too low, don't heal.
//    //
//    r = RegionCircle(UnitGetPosition(aiUnit), AIRangeObelisk(player, aiUnit));
//    if (UnitGroupCount(UnitGroupAlliance(player, c_unitAllianceEnemy, r, null, c_noMaxCount), c_unitCountAll) == 0 && energy > c_batteryMinEnergyNoHostiles) {
//        return null;
//    }
//
//    //  Otherwise, look for allies with low shields to heal.
//    //
//    group = AIFindUnits(player, null, UnitGetPosition(aiUnit), AIRangeObelisk(player, aiUnit), c_noMaxCount);
//    allyFilter = AIFilter(player);
//    AISetFilterBits(allyFilter, UnitFilterStr(AIAbilityStr(player, c_AB_ShieldBattery, c_fieldTargetFiltersAB)));
//    AISetFilterAlliance(allyFilter, c_playerGroupAlly);
//    AISetFilterShields(allyFilter, c_noMin, c_shieldBatteryMaxShields);
//   
//    group = AIGetFilterGroup(allyFilter, group);
//    return AIUnitGroupGetValidOrder(group, ord, aiUnit, c_forwards);
//}
#15
AI Development / Re: Starcraft 2 functions/libraries here
February 27, 2010, 03:23:54 PM


TacticalAI.galaxy
//==================================================================================================
//  Tactical AI Functions
//==================================================================================================

//==================================================================================================
//
//  Tactical AI System Known Issues:
//  * Marker Bug With Abilities that are missiles (Assigned to Andy / Dave)
//      - i.e. infestor, hunter seeker missile
//      - marker dissapears after cast, but before effect, so multiple casters may cast on the same unit
//  * Some Infestor / Overseer spells need AI (Assigned to Dave, Bob, or Andy & David Kim)
//      - An untested version of the old fungal growth and acid spores were started and then abandoned
//        when abilities changed fundamentally (see TactZergAI)
//      - An untested version of the old unstable mutation was started and then abandoned when the ability
//        changed fundamentally (see TactZergAI)
//      - Check with David Kim, who said that these are 90% sure going to change again.
//  * Infested Marine / Civilian Burrow (Task assigned to Andy Bond)
//      - AI Commented out for Burrow
//      - Needs to be placed back in after Andy fixes support to turn off abilities on Campaign
//      - Maps with infested units need to be tested
//
//  Wish List
//  * Need equivalent of AITime from synapses for tactical ai thinks
//      - scale it back when too much thinking, scale it up when too little
//
//==================================================================================================

//--------------------------------------------------------------------------------------------------
//  CATALOG ACCESSOR CONSTANTS
//--------------------------------------------------------------------------------------------------

const string c_fieldAmount          = "Amount";
const string c_fieldAreaRadius0     = "AreaArray[0].Radius";
const string c_fieldAreaRadius1     = "AreaArray[1].Radius";
const string c_fieldAreaRadius2     = "AreaArray[2].Radius";
const string c_fieldAreaFraction0   = "AreaArray[0].Fraction";
const string c_fieldAreaFraction1   = "AreaArray[1].Fraction";
const string c_fieldAreaFraction2   = "AreaArray[2].Fraction";
const string c_fieldAttrStructure   = "AttributeBonus[Structure]";
const string c_fieldAttrArmored     = "AttributeBonus[Armored]";
const string c_fieldAttrPsionic     = "AttributeBonus[Psionic]";
const string c_fieldAttrLight       = "AttributeBonus[Light]";
const string c_fieldDrainFactor     = "DrainVitalCostFactor";
const string c_fieldEffectChange0   = "VitalArray[0].Change";
const string c_fieldEffectChange1   = "VitalArray[1].Change";
const string c_fieldEffectChange2   = "VitalArray[2].Change";
const string c_fieldEnergyCost      = "Cost[0].Vital[Energy]";
const string c_fieldEnergyMax       = "EnergyMax";
const string c_fieldFilters         = "SearchFilters";
const string c_fieldMinRange        = "MinimumRange";
const string c_fieldModification0   = "Modification.VitalRegenArray[Energy]";
const string c_fieldPeriodCount     = "PeriodCount";
const string c_fieldRadius          = "Radius";
const string c_fieldRadiusBonus0    = "AreaArray[0].RadiusBonus";
const string c_fieldRange0          = "Range[0]";
const string c_fieldRange           = "Range";
const string c_fieldSightDawn       = "Sight";
const string c_fieldTargetFilters   = "TargetFilters";
const string c_fieldTargetFiltersAB = "TargetFilters[0]";
const string c_fieldTargetFilters0  = "ValidatorArray[0].value.value";

//--------------------------------------------------------------------------------------------------
//  TACTICAL API
//
//  Usage:
//      filter = AIFilter(owner);
//      ...set various filter information...
//      newGroup = AIGetFilterGroup(filter, oldGroup);
//--------------------------------------------------------------------------------------------------
native aifilter AIFilter (int player);

native void AISetFilterAlliance (aifilter filter, int want);
native void AISetFilterMarker (aifilter filter, int min, int max, marker m);
native void AISetFilterSelf (aifilter filter, unit exclude);
native void AISetFilterBits (aifilter filter, unitfilter uf);
native void AISetFilterRange (aifilter filter, unit center, fixed radius);
native void AISetFilterLife (aifilter filter, fixed min, fixed max);
native void AISetFilterLifeLost (aifilter filter, fixed min, fixed max);
native void AISetFilterLifePercent (aifilter filter, fixed min, fixed max);
native void AISetFilterLifeSortReference (aifilter filter, fixed value, fixed distance);
native void AISetFilterLifeMod (aifilter filter, int type, fixed mod);
native void AISetFilterLifePerMarker (aifilter filter, fixed each, marker m);
native void AISetFilterShields (aifilter filter, fixed min, fixed max);
native void AISetFilterPlane (aifilter filter, int plane);
native void AISetFilterCanAttackEnemy (aifilter filter, int enemyGroundCount, int enemyAirCount);
native void AISetFilterCanAttackAlly (aifilter filter, bool groundAllies, bool airAllies);
native void AISetFilterBehaviorCount (aifilter filter, int minBehavior, int maxBehavior, string behaviorType);

const fixed c_minDamageFraction = .5;
const fixed c_distanceFromDamage = .2;

const int c_noMarkersMin = 0;
const int c_noMarkersMax = 0;

const int c_noBehaviorMin = 0;
const int c_noBehaviorMax = 0;

const int c_noMax = -1;
const int c_noMin = -1;

const bool c_groundAlliesNearby = true;
const bool c_airAlliesNearby = true;

const fixed c_noThreshold = 0;

native unitgroup AIGetFilterGroup (aifilter filter, unitgroup group);

const fixed c_maxDistanceToMinerals = 10;

native unitgroup AIFilterCasters (unitgroup group);
native unitgroup AIFilterPathable (unitgroup group, point inStart);
native unitgroup AIFilterGathering (unitgroup group, int inResource, fixed distance);

native fixed AIUnitGroupStrength (unitgroup inGroup);
native fixed AIAllyEnemyRatio (int player, point p, unitfilter filter, fixed range, fixed minThreshold);

native bool AIIsFollowingUnit (unit aiUnit, string unitType);
native int AIGetPlayerGroup (unitgroup inGroup);
native bool AINearbyPlaneTest (point p, int player, fixed range, int inPlane, int inAlliance);

//--------------------------------------------------------------------------------------------------
//  *** CATALOG INFO ***
//--------------------------------------------------------------------------------------------------
string AIAbilityStr (int player, string entry, string field) {
    return CatalogFieldValueGet(c_gameCatalogAbil, entry, field, player);
}
string AIEffectStr (int player, string entry, string field) {
    return CatalogFieldValueGet(c_gameCatalogEffect, entry, field, player);
}
string AIWeaponStr (int player, string entry, string field) {
    return CatalogFieldValueGet(c_gameCatalogWeapon, entry, field, player);
}
string AIUnitStr (int player, string entry, string field) {
    return CatalogFieldValueGet(c_gameCatalogUnit, entry, field, player);
}
string AIBehaviorStr (int player, string entry, string field) {
    return CatalogFieldValueGet(c_gameCatalogBehavior, entry, field, player);
}

fixed AIAbilityFixed (int player, string entry, string field) {
    return StringToFixed(AIAbilityStr(player, entry, field));
}
fixed AIEffectFixed (int player, string entry, string field) {
    return StringToFixed(AIEffectStr(player, entry, field));
}
fixed AIWeaponFixed (int player, string entry, string field) {
    return StringToFixed(AIWeaponStr(player, entry, field));
}
fixed AIUnitFixed (int player, string entry, string field) {
    return StringToFixed(AIUnitStr(player, entry, field));
}
fixed AIBehaviorFixed (int player, string entry, string field) {
    return StringToFixed(AIBehaviorStr(player, entry, field));
}

int AIAbilityInt (int player, string entry, string field) {
    return StringToInt(AIAbilityStr(player, entry, field));
}
int AIEffectInt (int player, string entry, string field) {
    return StringToInt(AIEffectStr(player, entry, field));
}
int AIWeaponInt (int player, string entry, string field) {
    return StringToInt(AIWeaponStr(player, entry, field));
}
int AIUnitInt (int player, string entry, string field) {
    return StringToInt(AIUnitStr(player, entry, field));
}
int AIBehaviorInt (int player, string entry, string field) {
    return StringToInt(AIBehaviorStr(player, entry, field));
}

unitgroup AIAbilityGroup (int player, string entry, unitgroup base) {
    return UnitGroupFilter(null, c_playerAny, base,
        UnitFilterStr(AIAbilityStr(player, entry, c_fieldTargetFiltersAB)), 0);
}
unitgroup AIEffectGroup (int player, string entry, unitgroup base) {
    return UnitGroupFilter(null, c_playerAny, base,
        UnitFilterStr(AIEffectStr(player, entry, c_fieldFilters)), 0);
}
unitgroup AIWeaponGroup (int player, string entry, unitgroup base) {
    return UnitGroupFilter(null, c_playerAny, base,
        UnitFilterStr(AIWeaponStr(player, entry, c_fieldTargetFilters)), 0);
}

//--------------------------------------------------------------------------------------------------
native void AISetTacticalAttackTargetPoint (unit u, point t);
native void AISetTacticalAttackTargetUnit (unit u, unit t);

//--------------------------------------------------------------------------------------------------
//  AIUnitGroupGetValidOrder
//--------------------------------------------------------------------------------------------------
const bool c_forwards = true;
const bool c_backwards = false;

//  Loops over a unitgroup forwards or backwards until finding a unit that makes a valid order.
//
native order AIUnitGroupGetValidOrder(unitgroup inGroup, order inOrder, unit caster, bool forwards);

//--------------------------------------------------------------------------------------------------
//  AICampSkirDiffTest
//--------------------------------------------------------------------------------------------------
bool AICampSkirDiffTest (int player, int campMinDiff, int skirMinDiff) {

    if (AIIsCampaign(player)) {
        return PlayerDifficulty(player) >= campMinDiff;
    }
    return PlayerDifficulty(player) >= skirMinDiff;
}

//--------------------------------------------------------------------------------------------------
//  AICastStandard
//--------------------------------------------------------------------------------------------------
bool AICastStandard (unit aiUnit, order ord, marker mark, bool retreat) {
    if (!UnitOrderIsValid(aiUnit, ord)) {
        return false;
    }
    AICast(aiUnit, ord, mark, retreat);
    return true;
}

//--------------------------------------------------------------------------------------------------
//  AIMarker
//--------------------------------------------------------------------------------------------------
marker AIMarker (unit aiUnit, string name) {
    marker mark = MarkerCastingUnit(name, aiUnit);
    MarkerSetMatchFlag(mark, c_markerMatchLink, true);
    MarkerSetMatchFlag(mark, c_markerMatchCasterPlayer, true);
    return mark;
}

//--------------------------------------------------------------------------------------------------
//  AISpellPriority
//--------------------------------------------------------------------------------------------------
void AISpellPriority (unitgroup src, unitgroup dst) {

    // TODO: units that currently have an order should be prioritized lower than idle units since
    //  they're already doing something.


    // this simple AI just takes the first unit plus all following that share the same command
    //
    int count = UnitGroupCount(src, c_unitCountAll);
    unit first = UnitGroupUnit(src, 1);
    unit test;

    UnitGroupAdd(dst, first);
   
    while (count > 1) {
        test = UnitGroupUnit(src, count);
        count = count - 1;

        if (AISameCommand(first, test)) {
            UnitGroupAdd(dst, test);
        }
    }
}

//--------------------------------------------------------------------------------------------------
//  AIIsAttackOrder
//--------------------------------------------------------------------------------------------------
bool AIIsAttackOrder (order o) {
    return StringEqual(AbilityCommandGetAbility(OrderGetAbilityCommand(o)), c_AB_Attack, true);
}

// These should both be replaced by the xml/code versions CTargetFindRallyPoint
////--------------------------------------------------------------------------------------------------
////  AIThinkSetRallyDefault
////--------------------------------------------------------------------------------------------------
//void AIThinkSetRallyDefault (int player, unit aiUnit, int commandIndex) {
//    point rally;
//    order ord;
//
//    // Don't set rally points on campaign
//    if (AIIsCampaign(player)) {
//        return;
//    }
//
//    if (UnitRallyPointTargetCount(aiUnit, commandIndex + 1) != 0) {
//        return;
//    }
//
//    ord = AICreateOrder(player, c_AB_Rally, commandIndex);
//    if (!UnitOrderIsValid(aiUnit, ord)) {
//        return;
//    }
//
//    rally = AIWaveTargetGatherOPoint(player, c_townMax);
//    if (UnitRallyPointTargetPoint(aiUnit, 1, 1) == rally) {
//        return;
//    }
//
//    OrderSetTargetPoint(ord, rally);
//    AICast(aiUnit, ord, c_noMarker, c_castHold);
//}
//
////--------------------------------------------------------------------------------------------------
////  AIThinkSetRallyWorker
////--------------------------------------------------------------------------------------------------
//void AIThinkSetRallyWorker (int player, unit aiUnit, int commandIndex) {
//    order ord;
//    unitgroup findResults;
//
//    if (UnitRallyPointTargetCount(aiUnit, commandIndex + 1) != 0) {
//        return;
//    }
//
//    ord = AICreateOrder(player, c_AB_Rally, commandIndex);
//    if (!UnitOrderIsValid(aiUnit, ord)) {
//        return;
//    }
//
//    findResults = AIFindUnits(0, c_NU_Minerals, UnitGetPosition(aiUnit), 8, c_noMaxCount);
//    if (UnitGroupCount(findResults, c_unitCountAll) == 0) {
//        findResults = AIFindUnits(0, c_NU_HighYieldMinerals, UnitGetPosition(aiUnit), 8, c_noMaxCount);
//        if (UnitGroupCount(findResults, c_unitCountAll) == 0) {
//            OrderSetTargetPoint(ord, UnitGetPosition(aiUnit));
//            AICast(aiUnit, ord, c_noMarker, c_castHold);
//            return;
//        }
//    }
//
//    OrderSetTargetUnit(ord, UnitGroupUnit(findResults, 1));
//    AICast(aiUnit, ord, c_noMarker, c_castHold);
//}

//--------------------------------------------------------------------------------------------------
//  PointAlongLine
//--------------------------------------------------------------------------------------------------
point PointAlongLine (point from, point toward, fixed distance) {
    return PointWithOffsetPolar(from, distance, AngleBetweenPoints(toward, from));
}

//--------------------------------------------------------------------------------------------------
//  Set Nuke Constants
//--------------------------------------------------------------------------------------------------
void AISetNukeConstants (int player) {
    AISetNukeGhost(player, c_TU_Ghost);
    AISetNukeNukeEffect(player, c_EF_Nuke);
    AISetNukeCloak(player, c_TR_GhostCloak);
    AISetNukeNukeAbilLink(player, c_AB_Nuke);
    AISetNukeCloakAbilLink(player, c_AB_GhostCloak);
   
    AISetNukeCloakRegenRate(player, AIBehaviorFixed(player, c_BF_PersonalCloaking, c_fieldModification0));
    AISetNukeCloakCost(player, AIAbilityFixed(player, c_AB_GhostCloak, c_fieldEnergyCost));
    AISetNukeNukeCastTime(player, 20);

    AISetNukeDamage(player, AIEffectFixed(player, c_EF_NukeDamage, c_fieldAmount), AIEffectFixed(player, c_EF_NukeDamage, c_fieldAttrStructure));
    AISetNukeRadiusClose(player, AIEffectFixed(player, c_EF_NukeDamage, c_fieldAreaRadius0), AIEffectFixed(player, c_EF_NukeDamage, c_fieldAreaFraction0));
    AISetNukeRadiusMedium(player, AIEffectFixed(player, c_EF_NukeDamage, c_fieldAreaRadius1), AIEffectFixed(player, c_EF_NukeDamage, c_fieldAreaFraction1));
    AISetNukeRadiusFar(player, AIEffectFixed(player, c_EF_NukeDamage, c_fieldAreaRadius2), AIEffectFixed(player, c_EF_NukeDamage, c_fieldAreaFraction2));
}

//--------------------------------------------------------------------------------------------------
//  AISetDefaultCombatFlags
//--------------------------------------------------------------------------------------------------
void AISetDefaultCombatFlags (int player, bool isMelee) {
    int group1;
    int group2;

    if (isMelee) {
        group1 = c_skirVeryEasy;
        group2 = c_skirHard;
    }
    else {
        group1 = c_campBeginner;
        group2 = c_campExpert;
    }

    AICombatTargetProduction       (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatTargetDropOffs         (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatTargetFood             (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatTargetActiveProduction (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatTargetSelfThreats      (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatTargetCurrent          (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatTargetAir              (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatTargetMovers           (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatTargetInAttackRange    (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatTargetThreats          (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatTargetAttackers        (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatTargetSpecial          (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatAvoidNonThreats        (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatAvoidTimedUnits        (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatAvoidWeakUnits         (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));
    AICombatAvoidDisabledUnits     (player, AIDiffThreshold(player, c_combatDisable, group1, c_combatEnable));

    AICombatTargetWorkers          (player, AIDiffThreshold(player, c_combatDisable, group2, c_combatEnable));
    AICombatTargetAllyThreats      (player, AIDiffThreshold(player, c_combatDisable, group2, c_combatEnable));
    AICombatTargetInjuries         (player, AIDiffThreshold(player, c_combatDisable, group2, c_combatEnable));
    AICombatTargetHealers          (player, AIDiffThreshold(player, c_combatDisable, group2, c_combatEnable));
    AICombatTargetSiege            (player, AIDiffThreshold(player, c_combatDisable, group2, c_combatEnable));
}

//--------------------------------------------------------------------------------------------------
include "TriggerLibs/TactProtAI"
include "TriggerLibs/TactTerrAI"
include "TriggerLibs/TactZergAI"