home *** CD-ROM | disk | FTP | other *** search
Wrap
//============================================================================== // Scn11p2: Initial AI Scenario Script /* AI owner: Dave Leary Scenario owner: Joe "the Golem" Gillum The AI for the main enemy in scenario 11. The HP is building up in two separated locations; the AI sends groups down each channel, one composed primarily of toxotes and the other composed primarily of hoplites. Catapults and heroes are periodically added to the groups. Some preplaced units guard the fortresses at the end of the scenario, but are not in an actual defense group. If the HP destroys the forward academies/archery ranges in each channel, the AI reacts and pulls its gather points back closer to the fortresses. Attack group sizes are grown over time. The AI does some simple researching at set times to improve its units. *** DIFFICULTY LEVEL NOTES *** Easy level - Enemy does minimal research. AI groups never increase in size. Does not maintain a hero. No myth units included in attacks. Moderate level - Enemy does less research. No myth units included in attacks. Difficult level - Default level. Nightmare - Attack groups can get much larger, and start out much larger. */ //============================================================================== // Difficulty Level int difflevel=-1; //============================================================================== // Set Town Location //============================================================================== void setTownLocation(void) { //Look for the "Town Location" marker. kbSetTownLocation(kbGetBlockPosition("554")); } //============================================================================== // miscStartup //============================================================================== void miscStartup(void) { difflevel=aiGetWorldDifficulty(); //Startup message(s). aiEcho(""); aiEcho(""); aiEcho("Scn11P2 AI Start, filename='"+cFilename+"'."); //Spit out the map size. aiEcho(" Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+")."); aiEcho("Difficulty Level="+difflevel+"."); //Cheat like a bastard. kbLookAtAllUnitsOnMap(); //Calculate some areas. kbAreaCalculate(1200.0); //Set our town location. setTownLocation(); //Reset random seed aiRandSetSeed(); //Allocate all resources to the root escrow. kbEscrowAllocateCurrentResources(); } //============================================================================== //============================================================================== // Attack stuff. //============================================================================== //============================================================================== //Shared variables. int numberAttacks=0; int attackPlayerID=-1; //TODO: Decide how to rep attack group size. int attackMinimumGroupSize=5; int attackMaximumGroupSize=9; //Attack 1 vars. int attackPlan1ID=-1; int maintainPlan1ID=-1; int attackRoute1ID=-1; int attackPath1ID=-1; int attackerUnitTypeID1=cUnitTypeToxotes; //Attack 2 vars. int attackPlan2ID=-1; int maintainPlan2ID=-1; int attackRoute2ID=-1; int attackPath2ID=-1; int attackerUnitTypeID2=cUnitTypeHoplite; //Unit type 3 vars (fewer, 'cause the petroboli get sucked into other groups) int maintainPlan3ID=-1; int attackerUnitTypeID3=cUnitTypePetrobolos; //Unit type 4 vars (hero/Atalanta) int maintainPlan4ID=-1; int attackerUnitTypeID4=cUnitTypeHeroGreekAtalanta; //Unit type 5 vars (Manticore) int maintainPlan5ID=-1; int attackerUnitTypeID5=cUnitTypeManticore; //Unit type 6 vars (Cyclops) int maintainPlan6ID=-1; int attackerUnitTypeID6=cUnitTypeCyclops; //========================================================================================= // 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; //Destroy our previous attack routes. //kbAttackRouteDestroy(attackRoute1ID); attackRoute1ID=-1; //kbAttackRouteDestroy(attackRoute2ID); attackRoute2ID=-1; //Reset the number of attacks. numberAttacks=0; } //Save the player to attack. attackPlayerID=playerID; // vector gatherPoint=kbGetBlockPosition("554"); // DAL - gather points now hardcoded // Setup attack path 1. attackPath1ID=kbPathCreate("Attack Path 1"); kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("2055")); //Create attack route 1. attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", kbGetBlockPosition("2054"), kbGetBlockPosition("2056")); if (attackRoute1ID >= 0) kbAttackRouteAddPath(attackRoute1ID, attackPath1ID); //Setup attack path 2. attackPath2ID=kbPathCreate("Attack Path 2"); kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("2058")); //Create attack route 2. attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", kbGetBlockPosition("2057"), kbGetBlockPosition("2059")); if (attackRoute2ID >= 0) kbAttackRouteAddPath(attackRoute2ID, attackPath2ID); } //============================================================================== // Query to Check if the Archery Ranges are Destroyed //============================================================================== int checkArcheryRanges(void) { static int archeryQueryID=-1; vector originalRally=kbGetBlockPosition("2054"); int archeryRangeCount=-1; if (archeryQueryID < 0) { // Doesn't exist, set it up archeryQueryID = kbUnitQueryCreate("Archery Range Query"); // Get the number if ( configQuery( archeryQueryID, cUnitTypeArcheryRange, -1, cUnitStateAlive, 2, originalRally, false, 30 ) == false ) return(-1); } kbUnitQueryResetResults(archeryQueryID); archeryRangeCount = kbUnitQueryExecute(archeryQueryID); // aiEcho("Querying - "+archeryRangeCount+" archery ranges."); return(archeryRangeCount); } //============================================================================== // Query to Check if the Academies are Destroyed //============================================================================== int checkAcademies(void) { static int academyQueryID=-1; vector originalRally=kbGetBlockPosition("2057"); int academyCount=-1; if (academyQueryID < 0) { // Doesn't exist, set it up academyQueryID = kbUnitQueryCreate("Academy Range Query"); // Get the number if ( configQuery( academyQueryID, cUnitTypeAcademy, -1, cUnitStateAlive, 2, originalRally, false, 30 ) == false ) return(-1); } kbUnitQueryResetResults(academyQueryID); academyCount = kbUnitQueryExecute(academyQueryID); // aiEcho("Querying - "+academyCount+" academies."); return(academyCount); } //============================================================================== // setupAttack //============================================================================== bool setupAttack(int playerID=-1, bool firstAttack=true) { int randomMythUnit=aiRandInt(2); difflevel=aiGetWorldDifficulty(); //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); //You must also set/add: specific target IDs or a query ID or target type IDs. //Set specific target ID. This must work. // aiPlanSetVariableInt(newAttackPlanID, cAttackPlanSpecificTargetID, 0, 1294); // aiPlanSetVariableInt(newAttackPlanID, cAttackPlanSpecificTargetID, 1, 1295); // aiPlanSetVariableInt(newAttackPlanID, cAttackPlanSpecificTargetID, 2, 9851); //Set up a query. This must work. //int attackQueryID=kbUnitQueryCreate("Attack Raid Query"); //if (attackQueryID >= 0) //{ // kbUnitQueryResetData(); // kbUnitQuerySetPlayerID(2); // kbUnitQuerySetUnitType(cUnitTypeBuilding); // kbUnitQuerySetState(cUnitStateAlive); // aiPlanSetVariableInt(newAttackPlanID, cAttackPlanQueryID, 0, attackQueryID); //} //Gather point. vector gatherPoint=kbGetBlockPosition("2054"); if ( firstAttack == true ) { gatherPoint=kbGetBlockPosition("2054"); } else gatherPoint=kbGetBlockPosition("2057"); //Set the target type. This must work. if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false) return(false); aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 3, true); //Unit types to attack. aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeTunnel); aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeUnit); aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 2, cUnitTypeBuilding); //Attack route. if (firstAttack == true) aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID); else aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID); //Set the gather point and gather point distance. aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint); aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 10.0); //Set up the attack route usage pattern. aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom); //Add the unit types to the plan. if (firstAttack == true) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID1, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize); aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 0, 1, 1); // If difflevel is hard or better... if ( difflevel > 1 ) { // Add a couple of myth units if you can. if ( randomMythUnit == 0 ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 0, 2, 2); } else aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 2, 2); } } else { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize); aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 0, 1, 1); aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 1, 1); // If difflevel is hard or better... if ( difflevel > 1 ) { // Add a couple of myth units if you can. if ( randomMythUnit == 0 ) { aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 0, 2, 2); } else aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 2, 2); } } //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. if (firstAttack == true) { //Orphan the active attack. aiPlanSetOrphan(attackPlan1ID, true); attackPlan1ID=newAttackPlanID; } else { //Orphan the active attack. aiPlanSetOrphan(attackPlan2ID, true); attackPlan2ID=newAttackPlanID; } //Increment our overall number of attacks. numberAttacks++; } //============================================================================== // Attack Generator 1 //============================================================================== rule attackGenerator1 minInterval 215 inactive group AttackRules runImmediately { //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; //If we have enough unassigned military units, create a new attack plan. int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID1); aiEcho("There are "+numberAvailableUnits+" toxotes available for a new attack."); if (numberAvailableUnits >= attackMinimumGroupSize) setupAttack(1, true); } //============================================================================== // Attack Generator 2 //============================================================================== rule attackGenerator2 minInterval 235 inactive group AttackRules runImmediately { //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; //If we have enough unassigned military units, create a new attack plan. int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID2); aiEcho("There are "+numberAvailableUnits+" hoplites available for a new attack."); if (numberAvailableUnits >= attackMinimumGroupSize) setupAttack(1, false); } //============================================================================== // Attack enabler - enable attacks once timers expire. // Some difflevel adjustments. //============================================================================== rule attack1Enabler minInterval 300 active group AttackRules { xsEnableRule("attackGenerator1"); xsDisableSelf(); } rule attack1EnablerModerate minInterval 150 active group AttackRules { difflevel=aiGetWorldDifficulty(); if ( difflevel > 0 ) { xsEnableRule("attackGenerator1"); xsDisableRule("attack1Enabler"); } xsDisableSelf(); } rule attack1EnablerNightmare minInterval 30 active group AttackRules { difflevel=aiGetWorldDifficulty(); if ( difflevel == 3 ) { xsEnableRule("attackGenerator1"); xsDisableRule("attack1EnablerModerate"); xsDisableRule("attack1Enabler"); } xsDisableSelf(); } rule attack2Enabler minInterval 220 active group AttackRules { xsEnableRule("attackGenerator2"); xsDisableSelf(); } rule attack2EnablerModerate minInterval 100 active group AttackRules { difflevel=aiGetWorldDifficulty(); if ( difflevel > 0 ) { xsEnableRule("attackGenerator2"); xsDisableRule("attack2Enabler"); } xsDisableSelf(); } rule attack2EnablerNightmare minInterval 15 active group AttackRules { difflevel=aiGetWorldDifficulty(); if ( difflevel == 3 ) { xsEnableRule("attackGenerator2"); xsDisableRule("attack2EnablerModerate"); xsDisableRule("attack2Enabler"); } xsDisableSelf(); } //============================================================================== // Rule to check if one of the archery ranges close to the point are dead. //============================================================================== rule archeryRangesDead minInterval 30 active { int numRanges=-1; vector reserveGatherPoint=kbGetBlockPosition("2109"); numRanges=checkArcheryRanges(); if (numRanges < 2) { aiEcho("One archery range destroyed; moving gather point."); aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, reserveGatherPoint); xsDisableSelf(); } } //============================================================================== // Rule to check if both academies close to the point are dead. //============================================================================== rule academiesDead minInterval 30 active { int numAcademies=-1; vector reserveGatherPoint=kbGetBlockPosition("2108"); numAcademies=checkAcademies(); if (numAcademies < 1) { aiEcho("Both academies destroyed; moving gather point."); aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, reserveGatherPoint); xsDisableSelf(); } } //============================================================================== // Simple attack size grower: Grows attack size every six minutes //============================================================================== rule attackGrower minInterval 360 inactive group AttackRules { difflevel=aiGetWorldDifficulty(); //Don't grow to more than 11 for a minimum, if it's anything other than nightmare. if ( difflevel < 3 ) { if (attackMinimumGroupSize >= 12 ) { xsDisableSelf(); return; } } // On nightmare, grow groups to 24 - ow! if (attackMinimumGroupSize >= 25 ) { 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(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); } //============================================================================== // Attack grower enabler - start upping attack group sizes at six minutes. //============================================================================== rule attackGrowerEnabler minInterval 360 active group AttackRules { xsEnableRule("attackGrower"); xsDisableSelf(); } //============================================================================== // Tech Researching Rules //============================================================================== rule researchBronzeWeapons minInterval 400 active group ModerateResearch { int planID=aiPlanCreate("Bronze Weapons Research at seven minutes.", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechBronzeWeapons); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchBronzeShields minInterval 500 active group EasyResearch { int planID=aiPlanCreate("Bronze Shields Research at nine minutes.", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechBronzeShields); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchHeavyArchers minInterval 560 active group HeavyResearch { int planID=aiPlanCreate("Heavy Archers", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechHeavyArchers); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArcheryRange); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchBronzeMail minInterval 620 active group ModerateResearch { int planID=aiPlanCreate("Bronze Mail Research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechBronzeMail); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchHeavyInfantry minInterval 750 active group ModerateResearch { int planID=aiPlanCreate("Heavy Infantry Research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechHeavyInfantry); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeAcademy); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchChampionInfantry minInterval 1200 active group TitanResearch { int planID=aiPlanCreate("Champion Infantry Research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechChampionInfantry); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeAcademy); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchIronMail minInterval 1260 active group TitanResearch { int planID=aiPlanCreate("Iron Mail Research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechIronMail); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchIronWeapons minInterval 1380 active group TitanResearch { int planID=aiPlanCreate("Iron Weapons Research", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechIronWeapons); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory); aiPlanSetActive(planID); //Done. xsDisableSelf(); } rule researchChampionArchers minInterval 1500 active group TitanResearch { int planID=aiPlanCreate("Champion Archers", cPlanResearch); if (planID < 0) return; aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechChampionArchers); aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArcheryRange); aiPlanSetActive(planID); //Done. xsDisableSelf(); } //============================================================================== // Maintain myth units, starting at seven minutes //============================================================================== rule maintainMythUnits minInterval 600 active group AttackRules { aiEcho("Rule: myth units now being maintained."); vector gatherPoint=kbGetBlockPosition("2085"); // Manticores maintainPlan5ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerUnitTypeID5), cPlanTrain); if (maintainPlan5ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanUnitType, 0, attackerUnitTypeID5); //You can limit the number of units that are ever trained by this plan with this call. aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToTrain, 0, 12); //Set the number of units to maintain in the world at one time aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToMaintain, 0, 2); //Don't train units faster than every three minutes aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanFrequency, 0, 180); //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234); //Set a gather point. aiPlanSetVariableVector(maintainPlan5ID, cTrainPlanGatherPoint, 0, gatherPoint); //Activate the plan. aiPlanSetActive(maintainPlan5ID); } // Cyclops maintainPlan6ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerUnitTypeID6), cPlanTrain); if (maintainPlan6ID >= 0) { //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan6ID, cTrainPlanUnitType, 0, attackerUnitTypeID6); //Only train 10 at most. aiPlanSetVariableInt(maintainPlan6ID, cTrainPlanNumberToTrain, 0, 10); //Set the number of units to maintain in the world at one time aiPlanSetVariableInt(maintainPlan6ID, cTrainPlanNumberToMaintain, 0, 2); //Don't train units faster than every two minutes aiPlanSetVariableInt(maintainPlan6ID, cTrainPlanFrequency, 0, 120); //Set a gather point. aiPlanSetVariableVector(maintainPlan6ID, cTrainPlanGatherPoint, 0, gatherPoint); //Activate the plan. aiPlanSetActive(maintainPlan6ID); } xsDisableSelf(); } //============================================================================== // Maintain the hero //============================================================================== rule maintainHero minInterval 510 active group AttackRules { aiEcho("Rule: hero maintain plan created."); // Create a plan to maintain 1 Atalanta hero, hanging out in front of the left fortress. // She periodically gets added to the hoplite group. maintainPlan4ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerUnitTypeID4), cPlanTrain); if (maintainPlan4ID >= 0) { vector gatherPoint4=kbGetBlockPosition("2109"); //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanUnitType, 0, attackerUnitTypeID4); //You can limit the number of units that are ever trained by this plan with this call. aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToTrain, 0, 5); //Set the number of units to maintain in the world at one time - one hero aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, 1); //Don't train units faster than every seven minutes aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 420); //Turn off training from multiple buildings. //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false); //Set a gather target ID. //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234); //Set a gather point. aiPlanSetVariableVector(maintainPlan4ID, cTrainPlanGatherPoint, 0, gatherPoint4); //Activate the plan. aiPlanSetActive(maintainPlan4ID); } xsDisableSelf(); } //===================================================================================== // fortressDestroyed. This is called from the scenario with an AI Func effect when // the central fortress is destroyed. //===================================================================================== void fortressDestroyed(int scriptCall = -1) { vector reserveGatherPoint=kbGetBlockPosition("2108"); aiEcho("*** FORTRESS DESTROYED, MODIFYING THE HOPLITE ATTACK PLAN"); aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, reserveGatherPoint); // Don't use multiple buildings any more. This should make them use one of the ones back // by the new gather point. aiPlanSetVariableBool(maintainPlan2ID, cTrainPlanUseMultipleBuildings, 0, false); } //============================================================================== // Some basic stuff based on difficulty level. //============================================================================== void difficultyLevelChanges(void) { difflevel=aiGetWorldDifficulty(); if ( difflevel == 0 ) { xsDisableRuleGroup("ModerateResearch"); xsDisableRuleGroup("TitanResearch"); xsDisableRuleGroup("HeavyResearch"); xsDisableRule("maintainHero"); xsDisableRule("attackGrowerEnabler"); } if ( difflevel == 1 ) { xsDisableRuleGroup("HeavyResearch"); xsDisableRuleGroup("TitanResearch"); } if ( difflevel == 2 ) { attackMinimumGroupSize=7; attackMaximumGroupSize=10; xsDisableRuleGroup("TitanResearch"); } if ( difflevel == 3 ) { attackMinimumGroupSize=8; attackMaximumGroupSize=12; } } //============================================================================== // MAIN. //============================================================================== void main(void) { difflevel=aiGetWorldDifficulty(); //Startup. miscStartup(); // Diff level. difficultyLevelChanges(); //Share the number to maintain. int numberToMaintain=attackMinimumGroupSize*2; //Share the common gather point. // vector gatherPoint=kbGetBlockPosition("554"); //Create a simple plan to maintain X first units. maintainPlan1ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain); if (maintainPlan1ID >= 0) { vector gatherPoint1=kbGetBlockPosition("2054"); //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1); //You can limit the number of units that are ever trained by this plan with this call. //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); //Don't train units too fast aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 20); //Turn off training from multiple buildings. //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false); //Set a gather point. aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPoint1); //Activate the plan. aiPlanSetActive(maintainPlan1ID); } //Create a simple plan to maintain X second units. maintainPlan2ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID2), cPlanTrain); if (maintainPlan2ID >= 0) { vector gatherPoint2=kbGetBlockPosition("2057"); //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID2); //You can limit the number of units that are ever trained by this plan with this call. //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25); //Set the number of units to maintain in the world at one time. aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, numberToMaintain); //Don't train units too fast. aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 25); //Turn off training from multiple buildings, 'cause hoplites don't gather very well. // DAL - taken out for now until DP bug is fixed. //aiPlanSetVariableBool(maintainPlan2ID, cTrainPlanUseMultipleBuildings, 0, false); //Set a gather point. aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPoint2); //Activate the plan. aiPlanSetActive(maintainPlan2ID); } if ( difflevel > 0 ) { //Create a simple plan to maintain 2 petroboli on all levels other than easy. maintainPlan3ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerUnitTypeID3), cPlanTrain); if (maintainPlan3ID >= 0) { vector gatherPoint3=kbGetBlockPosition("2085"); //Must set the type of unit to train. aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeID3); //You can limit the number of units that are ever trained by this plan with this call. //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25); //Set the number of units to maintain in the world at one time - two at most of the petroboli aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 2); //Don't train units faster than every 210 seconds aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 210); //Turn off training from multiple buildings. //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false); //Set a gather target ID. //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234); //Set a gather point. aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPoint3); //Activate the plan. aiPlanSetActive(maintainPlan3ID); } } }