home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 2002-09-24 | 38.5 KB | 1,132 lines
//============================================================================== // Scn34p2: AI Scenario Script for scenario 34 player 2 //============================================================================== /* AI owner: Dave Leary Scenario owner: Joe "the Golem" Gillum AI for the main enemy in 34. This AI assembles large groups of units and sends them to attack the player's settlement (after the player claims one). *** DIFFICULTY LEVEL NOTES *** Easy level - Fewer units in attack groups. Myth attacks are limited to a couple of cyclopses. No Polyphemus. One less Colossi guarding the temples. Moderate level - Base level. Difficult level - Attacks can grow more over time. Myth attacks potentially stronger. More base units at start. Nightmare - Attacks can grow more over time. Myth attacks potentially stronger. Even more base units at start. */ //============================================================================== // Set Town Location //============================================================================== void setTownLocation(void) { //Look for the "Town Location" marker. kbSetTownLocation(kbGetBlockPosition("3218")); } //============================================================================== // miscStartup //============================================================================== void miscStartup(void) { // Difficulty Level check. int difflevel=-1; difflevel=aiGetWorldDifficulty(); //Startup message(s). aiEcho(""); aiEcho(""); aiEcho("Scn34P2 AI Start, filename='"+cFilename+"'."); aiEcho("Difficulty Level="+difflevel+"."); //Spit out the map size. aiEcho(" Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+")."); //Cheat like a bastard. Once only, though. kbLookAtAllUnitsOnMap(); //Calculate some areas. kbAreaCalculate(1200.0); //Set our town location. setTownLocation(); //Reset random seed aiRandSetSeed(); //Allocate all resources to the root escrow by setting percentage of military/economy to 0. kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0 ); kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0 ); //Allocate all resources. kbEscrowAllocateCurrentResources(); } //============================================================================== //============================================================================== // Attack stuff //============================================================================== //============================================================================== //Shared variables. int numberAttacks=0; int attackPlayerID=-1; //TODO: Decide how to rep attack group size. int attackMinimumGroupSize=4; int attackMaximumGroupSize=7; //Attack 1 vars. int attackPlan1ID=-1; //Attack 2 vars. int attackPlan2ID=-1; // Route and path vars int attackRoute1ID=-1; int attackRoute2ID=-1; int attackRoute3ID=-1; int attackRoute4ID=-1; int attackPath1ID=-1; int attackPath2ID=-1; int attackPath3ID=-1; // Predefined plans (that get modified/defined later) int maintainPlan1ID=-1; int maintainPlan2ID=-1; int maintainPlan3ID=-1; int maintainPlan4ID=-1; int maintainPlan5ID=-1; int maintainPlan6ID=-1; int heroMaintainPlan1ID=-1; int heroMaintainPlan2ID=-1; int heroMaintainPlan3ID=-1; int heroMaintainPlan4ID=-1; int mythMaintainPlan1ID=-1; int mythMaintainPlan2ID=-1; int mythMaintainPlan3ID=-1; int siegeMaintainPlan1ID=-1; int exploreID=-1; // Unit types. int attackerUnitTypeID1=cUnitTypeHoplite; int attackerUnitTypeID2=cUnitTypeHippikon; int attackerUnitTypeID3=cUnitTypeToxotes; int attackerUnitTypeID4=cUnitTypeHypaspist; int attackerUnitTypeID5=cUnitTypePeltast; int attackerUnitTypeID6=cUnitTypeProdromos; int attackerSiegeTypeID1=cUnitTypePetrobolos; int attackerSiegeTypeID2=cUnitTypeHelepolis; int attackerMythTypeID1=cUnitTypeCyclops; int attackerMythTypeID2=cUnitTypeHydra; int attackerMythTypeID3=cUnitTypeChimera; int attackerHeroTypeID1=cUnitTypeHeroGreekTheseus; int attackerHeroTypeID2=cUnitTypeHeroGreekHippolyta; int attackerHeroTypeID3=cUnitTypeHeroGreekAtalanta; int attackerHeroTypeID4=cUnitTypeHeroGreekPolyphemus; // Shared variables to handle the various settlements being claimed. bool settlement1Claimed=false; bool settlement2Claimed=false; bool settlement3Claimed=false; bool settlement4Claimed=false; //========================================================================================= // Kidd's cool configQuery function: used to create attack routes, etc. Oooh, lovin' that! //========================================================================================= bool configQuery( int queryID = -1, int unitType = -1, int action = -1, int state = -1, int player = -1, vector center = vector(-1,-1,-1), bool sort = false, float radius = -1 ) { if ( queryID == -1) { return(false); } if (player != -1) kbUnitQuerySetPlayerID(queryID, player); if (unitType != -1) kbUnitQuerySetUnitType(queryID, unitType); if (action != -1) kbUnitQuerySetActionType(queryID, action); if (state != -1) kbUnitQuerySetState(queryID, state); if (center != vector(-1,-1,-1)) { kbUnitQuerySetPosition(queryID, center); if (sort == true) kbUnitQuerySetAscendingSort(queryID, true); if (radius != -1) kbUnitQuerySetMaximumDistance(queryID, radius); } return(true); } //============================================================================== // initAttack: Creates attack routes, etc. //============================================================================== void initAttack(int playerID=-1) { //Destroy all previous attacks (if this isn't the player we're already attacking. if (playerID != attackPlayerID) { //Reset the attack player ID. attackPlayerID=-1; //Destroy any previous attack plan. aiPlanDestroy(attackPlan1ID); attackPlan1ID=-1; aiPlanDestroy(attackPlan2ID); attackPlan2ID=-1; //Destroy our previous attack paths. kbPathDestroy(attackPath1ID); attackPath1ID=-1; kbPathDestroy(attackPath2ID); attackPath2ID=-1; kbPathDestroy(attackPath3ID); attackPath3ID=-1; //Destroy our previous attack routes. attackRoute1ID=-1; attackRoute2ID=-1; attackRoute3ID=-1; attackRoute4ID=-1; //Reset the number of attacks. numberAttacks=0; } //Save the player to attack. attackPlayerID=playerID; vector gatherPoint=kbGetBlockPosition("3219"); //Setup attack path 1 - top route attackPath1ID=kbPathCreate("Attack Path 1"); kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3255")); kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3256")); kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3215")); kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3257")); //Create attack route 1. attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", gatherPoint, kbGetBlockPosition("3258")); if (attackRoute1ID >= 0) kbAttackRouteAddPath(attackRoute1ID, attackPath1ID); //Setup attack path 2 - down the middle attackPath2ID=kbPathCreate("Attack Path 2"); kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3251")); kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3220")); kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3252")); //Create attack route 2. attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", gatherPoint, kbGetBlockPosition("3253")); if (attackRoute2ID >= 0) kbAttackRouteAddPath(attackRoute2ID, attackPath2ID); //Create attack route 3 (uses same path as 2) attackRoute3ID=kbCreateAttackRouteWithPath("Attack Route 3", gatherPoint, kbGetBlockPosition("3254")); if (attackRoute3ID >= 0) kbAttackRouteAddPath(attackRoute3ID, attackPath2ID); //Setup attack path 3 - to the bottom attackPath3ID=kbPathCreate("Attack Path 3"); kbPathAddWaypoint(attackPath3ID, kbGetBlockPosition("3259")); kbPathAddWaypoint(attackPath3ID, kbGetBlockPosition("3260")); //Create attack route 4. attackRoute4ID=kbCreateAttackRouteWithPath("Attack Route 4", gatherPoint, kbGetBlockPosition("3261")); if (attackRoute4ID >= 0) kbAttackRouteAddPath(attackRoute4ID, attackPath3ID); } //============================================================================== // setupMainAttack - uses primarily human units. //============================================================================== bool setupMainAttack(int playerID=-1, int primaryUnit=-1) { // Difficulty Level check. int difflevel=-1; difflevel=aiGetWorldDifficulty(); // Random number to define which heroes the main group tries to grab. int whichHeroes=aiRandInt(4); vector gatherPoint=kbGetBlockPosition("3219"); //Info. aiEcho("Attacking Player "+playerID+"."); //If the player to attack doesn't match, init the attack. if (attackPlayerID != playerID) { initAttack(playerID); if (attackPlayerID < 0) return(false); } //Create an attack plan. int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack); if (newAttackPlanID < 0) return(false); //Target player (required). This must work. if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false) return(false); //Gather point. if ( primaryUnit == attackerUnitTypeID2 ) { gatherPoint=kbGetBlockPosition("3213"); } else { gatherPoint=kbGetBlockPosition("3219"); } //Set the target type. This must work. if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false) return(false); //Attack route selection. if (settlement1Claimed == true) { aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID); aiEcho("AI Attack Path: chose north settlement to attack."); } else if (settlement4Claimed == true) { aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute4ID); aiEcho("AI Attack Path: chose southern settlement to attack."); } else // go down the middle if neither north nor south claimed. { aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute3ID); aiEcho("AI Attack Path: chose center settlement to attack."); } // Unit types to attack // If Hippikons...villagers first if ( primaryUnit == attackerUnitTypeID2 ) { aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 3, true); aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeVillagerGreek); aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeUnit); aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 2, cUnitTypeBuilding); } // else if Hypaspists... else { aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit); aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding); } //Set the gather point and gather point distance. aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint); aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 20.0); //Set up the attack route usage pattern. aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom); //Add the primary unit type to the plan. aiPlanAddUnitType(newAttackPlanID, primaryUnit, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize); // Additional units - depends on the primary unit. // If Hippikons...none, if ( primaryUnit == attackerUnitTypeID2 ) { //Prodromosi if available. This is the fast-attack raiding bunch. if ( difflevel > 0 ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 4, 6); } else { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 2, 4); } } // else if Hypaspists...add Peltasts and Toxotes, and possibly Petroboli. Bring the pain! else { if ( difflevel > 0 ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 0, 2, 6); aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 0, 4, 8); aiPlanAddUnitType(newAttackPlanID, attackerSiegeTypeID1, 0, 2, 3); } else { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 0, 2, 4); aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 0, 2, 4); } } // Heroes - sometimes two, sometimes four, sometimes none. None on Easy. if ( difflevel > 0 ) { if (whichHeroes == 0) { aiPlanAddUnitType(newAttackPlanID, attackerHeroTypeID1, 0, 1, 1); aiPlanAddUnitType(newAttackPlanID, attackerHeroTypeID4, 0, 1, 1); } if (whichHeroes <= 2) { aiPlanAddUnitType(newAttackPlanID, attackerHeroTypeID2, 0, 1, 1); aiPlanAddUnitType(newAttackPlanID, attackerHeroTypeID3, 0, 1, 1); } } //Set the initial position. aiPlanSetInitialPosition(newAttackPlanID, gatherPoint); //Plan requires all need units to work (can be false). aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true); //Activate the plan. aiPlanSetActive(newAttackPlanID); //Now, save the attack plan ID appropriately. aiPlanSetOrphan(attackPlan1ID, true); attackPlan1ID=newAttackPlanID; //Increment our overall number of attacks. numberAttacks++; } //============================================================================== // setupMythAttack - uses primarily human units. //============================================================================== bool setupMythAttack(int playerID=-1) { // Difficulty Level check. int difflevel=-1; difflevel=aiGetWorldDifficulty(); // Random number to define which heroes the main group tries to grab. int whichHeroes=aiRandInt(4); //Gather point. vector gatherPoint=kbGetBlockPosition("3218"); //Info. aiEcho("Attacking Player "+playerID+"."); //If the player to attack doesn't match, init the attack. if (attackPlayerID != playerID) { initAttack(playerID); if (attackPlayerID < 0) return(false); } //Info. aiEcho("Attacking Player "+playerID+"."); //Create an attack plan. int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack); if (newAttackPlanID < 0) return(false); //Target player (required). This must work. if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false) return(false); //Set the target type. This must work. if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false) return(false); //Attack route selection. if (settlement1Claimed == true) { aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID); aiEcho("AI Attack Path: chose north settlement to attack."); } else if (settlement4Claimed == true) { aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute4ID); aiEcho("AI Attack Path: chose southern settlement to attack."); } else // go down the middle if neither north nor south claimed. { aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute3ID); aiEcho("AI Attack Path: chose center settlement to attack."); } // Unit types to attack aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit); aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding); //Set the gather point and gather point distance. aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint); aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 20.0); //Set up the attack route usage pattern. aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom); //Cyclopses are the base myth unit - take up to 6, plus chimeras, if available. Make sure you got two. :) if ( difflevel > 0 ) { aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID1, 2, 2, 6); aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID3, 0, 2, 3); } else { aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID1, 1, 1, 1); } // Heroes - half the time, the first two heros if available. Mixed myth/heroes = pain! if (whichHeroes <= 1) { aiPlanAddUnitType(newAttackPlanID, attackerHeroTypeID1, 0, 1, 1); if ( difflevel > 0 ) { aiPlanAddUnitType(newAttackPlanID, attackerHeroTypeID2, 0, 1, 1); } } // Once in a while, Polyphemus instead. :) if (whichHeroes == 4) { if ( difflevel > 0 ) { aiPlanAddUnitType(newAttackPlanID, attackerHeroTypeID4, 0, 1, 1); } } //Set the initial position. aiPlanSetInitialPosition(newAttackPlanID, gatherPoint); //Plan requires all need units to work (can be false). aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true); //Activate the plan. aiPlanSetActive(newAttackPlanID); //Now, save the attack plan ID appropriately. aiPlanSetOrphan(attackPlan2ID, true); attackPlan2ID=newAttackPlanID; //Increment our overall number of attacks. numberAttacks++; } //============================================================================== // Attack Generator 1 - Primary = hippikons or hypaspists, randomly. //============================================================================== rule attackGenerator1 minInterval 235 inactive group AttackRules { //See how many "idle" attack plans we have. Don't create any more if we have //idle plans. int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack); if (numberIdleAttackPlans > 0) return; // Random primary unit for the attack, either hippikons or hypaspists. int attackerType=-1; int whichAttacker=aiRandInt(2); if ( whichAttacker == 0 ) { attackerType=attackerUnitTypeID2; aiEcho("Primary Unit = Hippikons"); } else { attackerType=attackerUnitTypeID4; aiEcho("Primary Unit = Hypaspists"); } //If we have enough unassigned military units, create a new attack plan. int numberAvailableUnits=aiNumberUnassignedUnits(attackerType); aiEcho("There are "+numberAvailableUnits+" of the primary unit available for a new attack."); if (numberAvailableUnits >= attackMinimumGroupSize) setupMainAttack(1, attackerType); } //============================================================================== // Attack Generator 2 - Myth unit fun, with cyclopses and friends. //============================================================================== rule attackGenerator2 minInterval 320 inactive group AttackRules { //See how many "idle" attack plans we have. Don't create any more if we have //idle plans. // // DAL - screw this, we're sending them. :) /* int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack); if (numberIdleAttackPlans > 0) return; */ //If we have enough unassigned military units, create a new attack plan. int numberAvailableUnits=aiNumberUnassignedUnits(cUnitTypeCyclops); aiEcho("There are "+numberAvailableUnits+" of the primary unit available for a new attack."); if (numberAvailableUnits >= 2) setupMythAttack(1); } // Start adding chimeras to the mix. rule chimeraEnabler minInterval 1000 inactive group AttackRules { aiEcho("*** CHIMERA ENABLER FIRING ***"); vector gatherPointTemple2=kbGetBlockPosition("3217"); //Create a simple plan to maintain cyclopses (6 of 'em). Chimeras forthcoming. mythMaintainPlan3ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerMythTypeID3), cPlanTrain); if (mythMaintainPlan3ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(mythMaintainPlan3ID, cTrainPlanUnitType, 0, attackerMythTypeID3); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(mythMaintainPlan3ID, cTrainPlanNumberToMaintain, 0, 10); //Don't train units too fast. aiPlanSetVariableInt(mythMaintainPlan3ID, cTrainPlanFrequency, 0, 120); //Set a gather point. aiPlanSetVariableVector(mythMaintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPointTemple2); //Activate the plan. aiPlanSetActive(mythMaintainPlan3ID); } xsDisableSelf(); } //============================================================================== // Favor cheat //============================================================================== rule favorCheat minInterval 60 inactive group AttackRules { // Cheat for favor. That Gargarensis is a bastard. aiResourceCheat( 2, cResourceFavor, 80.0 ); } // Four minutes after a settlement is claimed, start maintaining myth units and // get ready to send attacks. rule mythAttackEnabler minInterval 360 inactive group AttackRules { aiEcho("*** MYTH ATTACK ENABLER FIRING ***"); vector gatherPointTemple1=kbGetBlockPosition("3216"); //Create a simple plan to maintain cyclopses (6 of 'em). Chimeras forthcoming. mythMaintainPlan1ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerMythTypeID1), cPlanTrain); if (mythMaintainPlan1ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(mythMaintainPlan1ID, cTrainPlanUnitType, 0, attackerMythTypeID1); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(mythMaintainPlan1ID, cTrainPlanNumberToMaintain, 0, 10); //Don't train units too fast. aiPlanSetVariableInt(mythMaintainPlan1ID, cTrainPlanFrequency, 0, 75); //Set a gather point. aiPlanSetVariableVector(mythMaintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointTemple1); //Activate the plan. aiPlanSetActive(mythMaintainPlan1ID); } xsEnableRule("attackGenerator2"); xsEnableRule("chimeraEnabler"); xsEnableRule("favorCheat"); xsDisableSelf(); } rule defendPlan1 minInterval 60 inactive group DefendRules { int defendPlan1ID=aiPlanCreate("Main Gate Defense", cPlanDefend); if (defendPlan1ID >= 0) { //Main gate location vector frontGate=kbGetBlockPosition("3220"); //Add the unit(s). aiPlanAddUnitType(defendPlan1ID, attackerUnitTypeID1, 0, 4, 8); aiPlanAddUnitType(defendPlan1ID, attackerUnitTypeID3, 0, 2, 4); //Setup the vars. aiPlanSetDesiredPriority(defendPlan1ID, 40); aiPlanSetVariableVector(defendPlan1ID, cDefendPlanDefendPoint, 0, frontGate); aiPlanSetVariableFloat(defendPlan1ID, cDefendPlanEngageRange, 0, 20); aiPlanSetActive(defendPlan1ID); } xsDisableSelf(); } rule defendPlan2 minInterval 60 inactive group DefendRules { int defendPlan2ID=aiPlanCreate("North Side Defense", cPlanDefend); if (defendPlan2ID >= 0) { //North side defense plan vector northSide=kbGetBlockPosition("3257"); //Add the unit(s). aiPlanAddUnitType(defendPlan2ID, attackerUnitTypeID1, 0, 4, 8); aiPlanAddUnitType(defendPlan2ID, attackerUnitTypeID3, 0, 2, 4); //Setup the vars. aiPlanSetDesiredPriority(defendPlan2ID, 40); aiPlanSetVariableVector(defendPlan2ID, cDefendPlanDefendPoint, 0, northSide); aiPlanSetVariableFloat(defendPlan2ID, cDefendPlanEngageRange, 0, 20); aiPlanSetActive(defendPlan2ID); } xsDisableSelf(); } //============================================================================== // Siege Units Fun - start addin' in Petroboli at the ten-minute mark, even // if the player hasn't landed. //============================================================================== rule maintainSiege minInterval 600 active group AttackRules { // Difficulty Level check. int difflevel=-1; difflevel=aiGetWorldDifficulty(); vector gatherPointSiege=kbGetBlockPosition("3260"); vector gatherPointStables=kbGetBlockPosition("3213"); vector gatherPointStables2=kbGetBlockPosition("4105"); //Create a simple plan to maintain petroboli. siegeMaintainPlan1ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain); if (siegeMaintainPlan1ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(siegeMaintainPlan1ID, cTrainPlanUnitType, 0, attackerSiegeTypeID1); //Set the number of units to maintain in the world at one time. if ( difflevel < 2 ) { aiPlanSetVariableInt(siegeMaintainPlan1ID, cTrainPlanNumberToMaintain, 0, 2); aiPlanSetVariableInt(siegeMaintainPlan1ID, cTrainPlanFrequency, 0, 75); } else { aiPlanSetVariableInt(siegeMaintainPlan1ID, cTrainPlanNumberToMaintain, 0, 3); aiPlanSetVariableInt(siegeMaintainPlan1ID, cTrainPlanFrequency, 0, 50); } //Set a gather point. aiPlanSetVariableVector(siegeMaintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointSiege); //Activate the plan. aiPlanSetActive(siegeMaintainPlan1ID); } //Time for Prodromosi things. Train 'em slowly. maintainPlan6ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID6), cPlanTrain); if (maintainPlan6ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan6ID, cTrainPlanUnitType, 0, attackerUnitTypeID6); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan6ID, cTrainPlanNumberToMaintain, 0, 6); //Don't train units too fast aiPlanSetVariableInt(maintainPlan6ID, cTrainPlanFrequency, 0, 75); //Set a gather point. aiPlanSetVariableVector(maintainPlan6ID, cTrainPlanGatherPoint, 0, gatherPointStables2); //Activate the plan. aiPlanSetActive(maintainPlan6ID); } xsDisableSelf(); } //============================================================================== // Attack size grower. //============================================================================== rule attackGrower minInterval 420 inactive group AttackRules { // Difficulty Level check. int difflevel=-1; difflevel=aiGetWorldDifficulty(); // On lower difficulties, minimum group limited to 10. if ( difflevel < 2 ) { //Don't grow to more than 10 for a minimum. if (attackMinimumGroupSize >= 10) { xsDisableSelf(); return; } } else { //Don't grow to more than 15 for a minimum. if (attackMinimumGroupSize >= 15) { xsDisableSelf(); return; } } //Increase our attack size. attackMinimumGroupSize++; attackMaximumGroupSize++; aiEcho("Attack group size grown: Min="+attackMinimumGroupSize+", Max="+attackMaximumGroupSize+"."); //Bump up our maintain size. int numberToMaintain=attackMinimumGroupSize*2; aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); } //===================================================================================== // Settlement Selector. This is called from the scenario with an AI Func effect // when the player claims his first settlement, which will serve as the focus of the // AI's attack routes. //===================================================================================== void settlementSelector(int whichone = -1) { aiEcho("*** Settlement claimed, enemy attacks and other fun enabled..***"); xsEnableRule("attackGenerator1"); switch(whichone) { case 0: { settlement1Claimed=true; xsEnableRule("defendPlan2"); break; } case 1: { settlement2Claimed=true; xsEnableRule("defendPlan1"); break; } case 2: { settlement3Claimed=true; xsEnableRule("defendPlan1"); break; } case 3: { settlement4Claimed=true; xsEnableRule("defendPlan1"); break; } } // Once a settlement is claimed, myth unit attacks are prepped. xsEnableRule("mythAttackEnabler"); // Prepare to grow attacks. xsEnableRule("attackGrower"); } //============================================================================== // Difficulty Level Adjustments //============================================================================== void difficultyLevelAdjustments(void) { // Difficulty Level check. int difflevel=-1; difflevel=aiGetWorldDifficulty(); switch(difflevel) { case 0: { attackMinimumGroupSize=3; attackMaximumGroupSize=5; break; } case 1: { break; } case 2: { attackMinimumGroupSize=8; attackMaximumGroupSize=10; break; } case 3: { attackMinimumGroupSize=9; attackMaximumGroupSize=13; break; } } } //============================================================================== // Maintain stuff - separated out for sanity's sake //============================================================================== void maintainStuff(void) { // Difficulty Level check. int difflevel=-1; difflevel=aiGetWorldDifficulty(); //Various gather points, whee! vector gatherPointAcademy=kbGetBlockPosition("3212"); vector gatherPointStables=kbGetBlockPosition("3213"); vector gatherPointArcheryRange=kbGetBlockPosition("3214"); vector gatherPointTemple1=kbGetBlockPosition("3216"); vector gatherPointTemple2=kbGetBlockPosition("3217"); //Bump up our maintain size. int numberToMaintain=attackMinimumGroupSize*2; //Create a simple plan to maintain hoplites. maintainPlan1ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain); if (maintainPlan1ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); //Don't train units too fast if ( difflevel > 1 ) { aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 25); } else if ( difflevel == 0 ) { aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 70); } else { aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 45); } //Set a gather point. aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointAcademy); //Activate the plan. aiPlanSetActive(maintainPlan1ID); } //Create a plan to maintain hippikons. maintainPlan2ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID2), cPlanTrain); if (maintainPlan2ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID2); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); //Don't train units too fast if ( difflevel > 1 ) { aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 30); } else { aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 55); } //Set a gather point. aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPointStables); //Activate the plan. aiPlanSetActive(maintainPlan2ID); } //Create a plan to maintain toxotes. maintainPlan3ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID3), cPlanTrain); if (maintainPlan3ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeID3); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 8); if ( difflevel == 0 ) { aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 70); } else { aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 40); } //Set a gather point. aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPointArcheryRange); //Activate the plan. aiPlanSetActive(maintainPlan3ID); } //Create a plan to maintain hypaspists maintainPlan4ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID4), cPlanTrain); if (maintainPlan4ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanUnitType, 0, attackerUnitTypeID4); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); //Don't train units too fast if ( difflevel == 0 ) { aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 60); } else { aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 40); } //Set a gather point. aiPlanSetVariableVector(maintainPlan4ID, cTrainPlanGatherPoint, 0, gatherPointAcademy); //Activate the plan. aiPlanSetActive(maintainPlan4ID); } //Create a plan to maintain peltasts maintainPlan5ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID5), cPlanTrain); if (maintainPlan5ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanUnitType, 0, attackerUnitTypeID5); //Set the number of units to maintain in the world at one time. if ( difflevel == 0 ) { aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToMaintain, 0, 6); } else { aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToMaintain, 0, 8); } //Don't train units too fast if ( difflevel == 0 ) { aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanFrequency, 0, 70); } else { aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanFrequency, 0, 45); } //Set a gather point. aiPlanSetVariableVector(maintainPlan5ID, cTrainPlanGatherPoint, 0, gatherPointArcheryRange); //Activate the plan. aiPlanSetActive(maintainPlan5ID); } // Maintain all four heroes at all times, but on long timers (180 for first three, 240 for Polyphemus) heroMaintainPlan1ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerHeroTypeID1), cPlanTrain); if (heroMaintainPlan1ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(heroMaintainPlan1ID, cTrainPlanUnitType, 0, attackerHeroTypeID1); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(heroMaintainPlan1ID, cTrainPlanNumberToMaintain, 0, 1); //Don't train units too fast aiPlanSetVariableInt(heroMaintainPlan1ID, cTrainPlanFrequency, 0, 195); // Stop using stupid fortresses and use settlements instead. aiPlanSetVariableInt(heroMaintainPlan1ID, cTrainPlanBuildFromType, 0, cUnitTypeSettlementLevel1); //Set a gather point. aiPlanSetVariableVector(heroMaintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointTemple1); //Activate the plan. aiPlanSetActive(heroMaintainPlan1ID); } heroMaintainPlan2ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerHeroTypeID2), cPlanTrain); if (heroMaintainPlan2ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(heroMaintainPlan2ID, cTrainPlanUnitType, 0, attackerHeroTypeID2); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(heroMaintainPlan2ID, cTrainPlanNumberToMaintain, 0, 1); //Don't train units too fast aiPlanSetVariableInt(heroMaintainPlan2ID, cTrainPlanFrequency, 0, 205); // Stop using stupid fortresses and use settlements instead. aiPlanSetVariableInt(heroMaintainPlan2ID, cTrainPlanBuildFromType, 0, cUnitTypeSettlementLevel1); //Set a gather point. aiPlanSetVariableVector(heroMaintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPointTemple2); //Activate the plan. aiPlanSetActive(heroMaintainPlan2ID); } heroMaintainPlan3ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerHeroTypeID3), cPlanTrain); if (heroMaintainPlan3ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(heroMaintainPlan3ID, cTrainPlanUnitType, 0, attackerHeroTypeID3); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(heroMaintainPlan3ID, cTrainPlanNumberToMaintain, 0, 1); //Don't train units too fast aiPlanSetVariableInt(heroMaintainPlan3ID, cTrainPlanFrequency, 0, 210); // Stop using stupid fortresses and use settlements instead. aiPlanSetVariableInt(heroMaintainPlan3ID, cTrainPlanBuildFromType, 0, cUnitTypeSettlementLevel1); //Set a gather point. aiPlanSetVariableVector(heroMaintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPointTemple1); //Activate the plan. aiPlanSetActive(heroMaintainPlan3ID); } if ( difflevel > 0 ) { heroMaintainPlan4ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerHeroTypeID4), cPlanTrain); if (heroMaintainPlan4ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(heroMaintainPlan4ID, cTrainPlanUnitType, 0, attackerHeroTypeID4); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(heroMaintainPlan4ID, cTrainPlanNumberToMaintain, 0, 1); //Don't train units too fast if ( difflevel > 1 ) { aiPlanSetVariableInt(heroMaintainPlan4ID, cTrainPlanFrequency, 0, 420); } else { aiPlanSetVariableInt(heroMaintainPlan4ID, cTrainPlanFrequency, 0, 520); } // Stop using stupid fortresses and use settlements instead. aiPlanSetVariableInt(heroMaintainPlan4ID, cTrainPlanBuildFromType, 0, cUnitTypeSettlementLevel1); //Set a gather point. aiPlanSetVariableVector(heroMaintainPlan4ID, cTrainPlanGatherPoint, 0, gatherPointTemple2); //Activate the plan. aiPlanSetActive(heroMaintainPlan4ID); } } } //============================================================================== // MAIN. //============================================================================== void main(void) { //Startup. miscStartup(); // Maintain a ton o' units. maintainStuff(); difficultyLevelAdjustments(); // Explore plan. He has some extra scouts around in case the first one dies. exploreID = aiPlanCreate("Explore", cPlanExplore); if(exploreID >= 0) { aiPlanAddUnitType(exploreID, cUnitTypeScout, 1, 1); aiPlanSetActive(exploreID); } }