//------------------------------------------------------------------- // RM USED PARAMS: These are the parameters typically updated via RM extern float btAttackDelayMod = 0.0; extern float btTrainBonusMod = 0.0; extern int RMSeed01 = 0; extern int RMSeed02 = 0; extern int RMSeed03 = 0; extern int RMSeed04 = 0; extern int RMSeed05 = 0; extern int PlayerLevel = 0; extern bool bAllowFRT = false; extern bool bAllowTCAge1 = false; extern bool bAllowTCBuild = true; extern bool bAllowAge4Siege = true; extern bool bAllowAutoResign = false; extern bool bAllowResourcePatrol = true; extern bool bPreventLevelUpTCChanges = false; extern bool bPreventLevelUpFortChanges = false; extern bool bPreventLevelUpMaxAgeChanges = false; //------------------------------------------------------------------- // CORE PARAMS: These are the parameters typically updated based on data from // a given AI parent script along with Mission Tool bias // sliders and Mission Tool flags, these parameters determine // virtually all aspects of the AI extern float btBiasINF = 0.0; extern float btBiasARC = 0.0; extern float btBiasCAV = 0.0; extern float btBiasNAV = 0.0; extern float btBiasSIE = 0.0; extern float btBiasSPC = 0.0; extern float btStrengthATK = 0.0; extern float btStrengthDEF = 0.0; extern float btStrengthECO = 0.0; extern bool bAllowBAM = true; extern bool bAllowScaling = true; extern bool bAllowMarketDefense = true; //------------------------------------------------------------------- // DERRIVED PARAMS: These are the parameters typically only set in this file // These are based on the core parameters, Mission Tool // bias sliders, and Mission Tool flags extern float btRevealDelay = 0.0; extern float btAttackDelay = 0.0; extern float btDefendDelay = 0.0; extern float btGuardADelay = 0.0; extern bool bAllowFactory_INF01 = false; extern bool bAllowFactory_INF02 = false; extern bool bAllowFactory_ARC01 = false; extern bool bAllowFactory_CAV01 = false; extern bool bAllowFactory_SIE01 = false; extern bool bAllowFactory_SPC01 = false; extern bool bAllowTOW = true; extern bool bAllowMKT = true; extern bool bAllowARM = true; extern bool bAllowGRV = true; extern bool bAllowHAL = true; extern bool bAllowTCAge2 = false; extern bool bAllowTCAge3 = false; extern bool bAllowAttack = true; extern bool bAllowDefend = true; extern bool bAllowGuardA = true; extern bool bAllowReveal = true; extern int MaxFortCount = 0; extern int MaxTCCount = 0; extern int FactoryType_INF01 = cUnitTypeUnitTypeBldgBarracks; extern int FactoryType_INF02 = -1; extern int FactoryType_ARC01 = cUnitTypeUnitTypeBldgArcheryRange; extern int FactoryType_CAV01 = cUnitTypeUnitTypeBldgStables; extern int FactoryType_SIE01 = cUnitTypeUnitTypeBldgSiegeWorkshop; extern int FactoryType_SPC01 = cUnitTypeUnitTypeBldgTemple; extern int BuildStage_INF01 = cAgeStateEarly; extern int BuildStage_INF02 = cAgeStateEarly; extern int BuildStage_ARC01 = cAgeStateEarly; extern int BuildStage_CAV01 = cAgeStateEarly; extern int BuildStage_SIE01 = cAgeStateMid; extern int BuildStage_SPC01 = cAgeStateMid; extern int BuildStage_MKT = cAgeStateMid; extern int BuildStage_ARM = cAgeStateMid; extern int BuildStage_GRV = cAgeStateMid; extern int BuildStage_HAL = cAgeStateMid; extern int BuildStage_FRT = cAgeStateLate; extern int BuildStage_TC1 = cAgeStateEarly; extern int BuildStage_TC2 = cAgeStateLate; extern int BuildStage_TC3 = cAgeStateLate; //------------------------------------------------------------------- // INTERNAL PARAMS: These are really only intended for the mechanics // of this AI content, and not meant to be tuned extern int BuildUpdateCount = 0; extern int BuildUpdateCountMax = 4; extern int BuildUpdateLastAge = -1; extern int BuildUpdateMaxAge = -1; extern vector gCustomRallyLOC = cInvalidVector; extern int gResourceQuery = -1; extern int gLandPatrolPlan = -1; extern int gNavalPatrolPlan = -1; extern int gResourcePatrolPlan = -1; extern int btMilitaryCapExtraCount = 0; extern int btDefenseTowerCount = 0; extern int btResignCheckCount = 0; extern float btLandPatrolRadius = 30.0; extern float btNavalPatrolRadius = 150.0; extern bool bEnablePatrolEcho = false; extern bool bEnableEconEcho = false; extern int ResignCheckCount = 10; extern float gBAMAttackPeriodPercent = 0.5; extern int ForcedResignMinCount = 0; //------------------------------------------------------------------- // SCORE PARAMS: extern float HumanScore = -1; extern float LastHumanScore = -1; extern float StartingHumanScore = -1; extern float HighestHumanScore = -1; extern int HumanWeakMinuteCount = 0; extern int HumanDeclineMinuteCount = 0; extern int HumanLowScoreMinuteCount = 0; extern float AIScore = -1; extern float LastAIScore = -1; extern float StartingAIScore = -1; extern float HighestAIScore = -1; extern int AIWeakMinuteCount = 0; extern int AIDeclineMinuteCount = 0; extern int AIAdjustedMinuteCount = 0; extern bool bScalingInEffect = false; //------------------------------------------------------------------- void SetCampaignDefaults() { //-------------------------------- // MISSION TOOL SETTINGS: btBiasInf = aiGetInfantryBias(); btBiasArcher = aiGetArcherBias(); btBiasCav = aiGetCavalryBias(); btBiasNavy = aiGetNavyBias(); btBiasArt = aiGetSiegeBias(); cvOkToFish = aiGetOKToFish(); cvOkToResign = aiGetOKToResign(); cvOkToExplore = aiGetOKToScout(); cvOKToResearchEcon = aiGetOKToResearchEcon(); cvOKToResearchMilitary = aiGetOKToResearchMilitary(); cvOkToTrainArmy = aiGetOKToTrainArmy(); cvOkToTrainNavy = aiGetOKToTrainNavy(); bAllowAttack = aiGetOKToAttack(); bAllowReveal = aiGetOKToAutoReveal(); //NOTE: incorporating a default econ nerf into all CampaignCore AI btBaselineHandicap = (aiGetEconHandicap() + 1) * 0.9; //-------------------------------- // CORE SETTINGS: btBiasINF = 0.5 + (btBiasInf / 2.0); btBiasARC = 0.5 + (btBiasArcher / 2.0); btBiasCAV = 0.5 + (btBiasCav / 2.0); btBiasNAV = 0.5 + (btBiasNavy / 2.0); btBiasSIE = 0.5 + (btBiasArt / 2.0); btBiasSPC = 0.0; // 0.0 - 1.0, no priests to lots of priests btStrengthATK = 0.0; // 0.0 - 4.0, weak attack strength to hardcore attack strength btStrengthDEF = 0.0; // 0.0 - 4.0, weak defense strength to hardcore defense strength btStrengthECO = 0.0; // 0.0 - 4.0, weak economy strength to economy attack strength btRushBoom = 0.0; // -1.0 = max rush, 1.0 = max boom cvMaxAge = cAge4; // can be used to force a character to stop aging at a point lower than would be normal cvOkToBuild = true; cvOkToGatherFood = true; cvOkToGatherGold = true; cvOkToGatherWood = true; cvOkToGatherStone = true; cvOkToRepair = false; cvOkToHerd = false; cvOkToCaravan = true; cvPlayerToAttack = -1; // -1 = select based on AI code, otherwise, attack the specified PlayerID if there is intel on their units gBAMMaxNumRams = 4; gBAMMaxNumCatapults = 2; gBAMMaxNumTrebuchets = 1; //-------------------------------- // DYNAMIC BEHAVIOR FLAGS: (Not Able to be Forced) cvOkToAttack = false;// initially off, enabled later cvOKToDefend = false;// initially off, enabled later cvGuardAlliedBases = false;// initially off, enabled later } //------------------------------------------------------------------- void CalculateMilitaryCap(int Extras = 0) { //start by calculating what we need at the basic level if (bAllowBAM) { // when using BAM, use the bam values, which are allowed to adapt to player skill levels btMilitaryCap = gBAMAttackGroups * gBAMTargetAge4GroupSize * 1.6; } else { btMilitaryCap = btAttackGroups * btTargetAge4ArmyCount * 1.6; } // now update the amount of extras we have accumulated btMilitaryCapExtraCount = btMilitaryCapExtraCount + Extras; // add in the extras btMilitaryCap = btMilitaryCap + btMilitaryCapExtraCount; } //------------------------------------------------------------------- float calculateTrainPercentBonus() { float ret = 0.0; if (bAllowBAM && (gBAMAttackGroups > 1)) { float BaseTrainingBonus = 0.0; float AgeUpTrainingBonus = 0.0; if (PlayerLevel < 20) { // Before level 20, for all attacks we train 10% extra for each group above 1 BaseTrainingBonus = 0.10 * (gBAMAttackGroups-1); // Before level 20, for each age after Age1, we train additional units based on attack strength and rush-boom AgeUpTrainingBonus = (0.1 + (0.05 * btStrengthATK)) * (1.0 + btRushBoom) * kbGetAge(); } else if (PlayerLevel < 30) { // Before level 30, for all attacks we train 25% extra for each group above 1 BaseTrainingBonus = 0.25 * (gBAMAttackGroups-1); // Before level 30, for each age after Age1, we train additional units based on attack strength only AgeUpTrainingBonus = (0.1 + (0.05 * btStrengthATK)) * kbGetAge(); } else { // After level 30, for all attacks we train 40% extra for each group above 1 BaseTrainingBonus = 0.40 * (gBAMAttackGroups-1); // After level 30, for each age after Age1, we train additional units based on attack strength only AgeUpTrainingBonus = (0.1 + (0.05 * btStrengthATK)) * kbGetAge(); } // skip any sort of dynamic training bonus until at least 5 minutes have passed if (xsGetTime() < 300000) { ret = btTrainBonusMod; } else { ret = btTrainBonusMod + BaseTrainingBonus + AgeUpTrainingBonus; } aiEcho("CampaignCore: --- calculateTrainPercentBonus: Full[" + ret + "] Mod[" + btTrainBonusMod + "] Base[" + BaseTrainingBonus + "] AgeUp[" + AgeUpTrainingBonus + "]"); } return (ret); } //------------------------------------------------------------------- float CalculatePlayerScore(int PlayerID = 0) { float ret = 0; if (PlayerID > 0) { float countSIE = kbUnitCount(PlayerID, cUnitTypeAbstractArtillery, cUnitStateAlive); float countMIL = kbUnitCount(PlayerID, cUnitTypeLogicalTypeLandMilitary, cUnitStateAlive) - countSIE; float countNAV = kbUnitCount(PlayerID, cUnitTypeAbstractWarShip, cUnitStateAlive); float CountVIL = kbUnitCount(PlayerID, cUnitTypeUnitTypeVillager1, cUnitStateAlive); float countTOW = kbUnitCount(PlayerID, cUnitTypeUnitTypeBldgTower, cUnitStateAlive); float countFRT = kbUnitCount(PlayerID, cUnitTypeUnitTypeBldgFortress, cUnitStateAlive); float countINF_FACTORY = kbUnitCount(PlayerID, cUnitTypeUnitTypeBldgBarracks, cUnitStateAlive); float countARC_FACTORY = kbUnitCount(PlayerID, cUnitTypeUnitTypeBldgArcheryRange, cUnitStateAlive); float countCAV_FACTORY = kbUnitCount(PlayerID, cUnitTypeUnitTypeBldgStables, cUnitStateAlive); float countSIE_FACTORY = kbUnitCount(PlayerID, cUnitTypeUnitTypeBldgSiegeWorkshop, cUnitStateAlive); float countFAC = countINF_FACTORY + countARC_FACTORY + countCAV_FACTORY + countSIE_FACTORY; // only include the factory count if the player has a large number of factories if (countFAC > 6) { countFAC = countFAC - 6; } ret = (countSIE *6) + (countMIL*2) + (countNAV*4) + (CountVIL*1.5) + (countTOW*5) + (countFRT*10) + (countFAC*5); //aiEcho("CampaignCore: --- CalculatePlayerScore: [Player" + PlayerID + "] SCORE[" + ret + "]"); } return (ret); } //------------------------------------------------------------------- // GetAttackMissionInterval // This function calculates the attack mission interval, which is necessary so we scale it adaptively. float GetAttackMissionInterval(bool isBAMEnabled = true) { float baseInterval = 250; float attackScale = 15; float rushBoomScale = 120; float milliScale = 1000; if(isBAMEnabled) { rushBoomScale = 60; milliScale = 1; } return(milliScale * (baseInterval - (btStrengthATK * attackScale) + (btRushBoom * rushBoomScale))); } //------------------------------------------------------------------- void HandleAttackSettings() { //-------------------------------- // set all of the core attack params based off ATK, DEF and RushBoom btAttackRampUp = 10; gAttackMissionInterval = GetAttackMissionInterval(false); gDefendMissionInterval = 1000 * ( 390 - (btStrengthDEF * 80) ); // in case we use BAM, define a percent of each attack interval during which attacks can take place // set this different for each archytype float attackPeriodPercent = 0.5; // account for rush vs boom strategic differences if (btRushBoom < -0.5) { // when we rush, we need to attack early if allowed btMilitaryInAge1 = bAllowAttack; btRevealDelay = 1000 * ( 150 - (btStrengthATK * 30) + (btRushBoom * 120) ); btAttackDelay = 1000 * ( 270 - (btStrengthATK * 60) + (btRushBoom * 120) ); // rush means smaller groups, more of them, more often btAttackGroups = 3; btTargetAge1ArmyCount = 2 + (0.7 * btStrengthATK); // 3 @ 2-5 btTargetAge2ArmyCount = 3 + (1.5 * btStrengthATK); // 3 @ 3-7 btTargetAge3ArmyCount = 4 + (2.0 * btStrengthATK); // 3 @ 4-12 btTargetAge4ArmyCount = 6 + (3.0 * btStrengthATK); // 3 @ 6-18 // for naval maps, force even rush to use less groups if(isCurrentMapNaval() == true) { btAttackGroups = 2; btTargetAge1ArmyCount = 3 + (0.5 * btStrengthATK); // 2 @ 3-5 btTargetAge2ArmyCount = 5 + (1.5 * btStrengthATK); // 2 @ 5-11 btTargetAge3ArmyCount = 7 + (2.5 * btStrengthATK); // 2 @ 7-17 btTargetAge4ArmyCount = 11 + (4.0 * btStrengthATK); // 2 @ 11-27 } // when rushing, attack for a greater percentage of the total attack period attackPeriodPercent = 0.6; } else if (btRushBoom > 0.5) { btMilitaryInAge1 = false; btRevealDelay = 1000 * ( 150 - (btStrengthATK * 30) ); btAttackDelay = 1000 * ( 270 - (btStrengthATK * 60) ); // boom means average group count, more units per group, less often attacks btAttackGroups = 1; btTargetAge1ArmyCount = 4 + (1.0 * btStrengthATK); // 1 @ 4-8 btTargetAge2ArmyCount = 8 + (2.0 * btStrengthATK); // 1 @ 8-16 btTargetAge3ArmyCount = 12 + (4.0 * btStrengthATK); // 1 @ 12-28 btTargetAge4ArmyCount = 20 + (6.0 * btStrengthATK); // 1 @ 20-44 } else { btMilitaryInAge1 = false; btRevealDelay = 1000 * ( 150 - (btStrengthATK * 30) ); btAttackDelay = 1000 * ( 270 - (btStrengthATK * 60) ); // balanced means average group count, more units per group, less often attacks btAttackGroups = 2; btTargetAge1ArmyCount = 4 + (1.0 * btStrengthATK); // 2 @ 4-8 btTargetAge2ArmyCount = 6 + (2.0 * btStrengthATK); // 2 @ 6-14 btTargetAge3ArmyCount = 8 + (3.0 * btStrengthATK); // 2 @ 8-20 btTargetAge4ArmyCount = 10 + (4.0 * btStrengthATK); // 2 @ 10-26 // when balanced, build up for a greater percentage of the total attack period attackPeriodPercent = 0.4; } // when allowed, use BAM instrad of the standard attack system if (bAllowBAM) { // let aimilitary know we are using BAM gUseBetterAttackManager = true; // set this to zero, as we want to not have any attack delay other than what is managed from aiCampaignCore.xs gBAMInitialAttackDelay = 0; // the attack interval is different when using BAM, because BAM actually works gBAMAttackInterval = GetAttackMissionInterval(true); gBAMAttackPeriodPercent = attackPeriodPercent; // set additional BAM params gBAMGroupInterval = (gBAMAttackInterval * gBAMAttackPeriodPercent) / btAttackGroups; gBAMAttackGroups = btAttackGroups; gBAMAttackRoutePattern = cAttackPlanAttackRoutePatternBest; gBAMTargetAge1GroupSize = btTargetAge1ArmyCount; gBAMTargetAge2GroupSize = btTargetAge2ArmyCount; gBAMTargetAge3GroupSize = btTargetAge3ArmyCount; gBAMTargetAge4GroupSize = btTargetAge4ArmyCount; gBAMGroupSizeRampUp = gBAMAttackGroups * 3; gBAMEngageRadius = 30; } // finally, update the number of extra transports that will be built based on the group sizes gExtraTransportCount = (btAttackGroups * btTargetAge4ArmyCount) / 16; if (gExtraTransportCount > 3) { // force this to be 3, the AI is not very good at optimizing, and there gets to be too many boats otherwise gExtraTransportCount = 3; } } //------------------------------------------------------------------- void HandleDefenseSettings() { //-------------------------------- // defense settings bAllowDefend = (btStrengthDEF >= 0); bAllowGuardA = (btStrengthDEF >= 1); btDefendDelay = 1000 * (270 - (btStrengthDEF * 60)); btGuardADelay = 1000 * (270 - (btStrengthDEF * 60)); cvNumTowers = 2 * (btStrengthDEF + 0.5);//1/3/5/7/9 cvMinTowerAge = cAge3; if (btStrengthDEF > 0) { cvMinTowerAge = cAge2; if (btStrengthDEF >= 3) { BuildStage_FRT = cAgeStateEarly; } else if (btStrengthDEF >= 2) { BuildStage_FRT = cAgeStateMid; } } if (bAllowTOW == false) { cvNumTowers = 0; } } //------------------------------------------------------------------- void HandleEconomySettings() { //-------------------------------- // economy settings btTargetAge1VilCount = 12 + btStrengthECO; btTargetAge4VilCount = 43 + (8 * btStrengthECO); gMaxFarms = 9 + (3 * btStrengthECO); gCaravanCountNorm = 1 + (2 * btStrengthECO); gCaravanCountNoGold = 5 + (2 * btStrengthECO); gNumFishBoats = 2 + (3 * btStrengthECO); // having a strong economy will force the market to be prioritized if (btStrengthECO > 2) { BuildStage_MKT = cAgeStateEarly; } } //------------------------------------------------------------------- void HandleNavalSettings() { //-------------------------------- // naval settings btBuild2ndDockAge2 = (btBiasNAV >= 0.5); gTriremeCount = (4.0 * btBiasNAV) + (2.0 * btBiasNAV * btStrengthATK); //(0-12) gFireshipCount = (1.6 * btBiasNAV) + (1.1 * btBiasNAV * btStrengthATK); //(0-6) gSiegeshipCount = (1.2 * btBiasNAV) + (0.7 * btBiasSIE * btStrengthATK); //(0-4) // if this is a naval map, go ahead and boost the military cap if(isCurrentMapNaval() == true) { // assume these units have had their pop cap impact reduced from the RM side of things int potentialPopNeed = gTriremeCount + gFireshipCount + gSiegeshipCount; CalculateMilitaryCap(potentialPopNeed); } } //------------------------------------------------------------------- void HandleFactorySettings() { //-------------------------------- // factory needs if (btBiasINF > 0.0) {bAllowFactory_INF01 = cvOkToTrainArmy;} if (btBiasARC > 0.0) {bAllowFactory_ARC01 = cvOkToTrainArmy;} if (btBiasCAV > 0.0) {bAllowFactory_CAV01 = cvOkToTrainArmy;} if (btBiasSIE > 0.0) {bAllowFactory_SIE01 = cvOkToTrainArmy;} if (btBiasSPC > 0.0) {bAllowFactory_SPC01 = cvOkToTrainArmy;} //-------------------------------- // set unit line counts // base this off the number of core factories we intend on building gAge1UnitLineCap = 1; gAge2UnitLineCap = 1; gAge3UnitLineCap = 1; gAge4UnitLineCap = 1; if (bAllowFactory_ARC01) { gAge2UnitLineCap = gAge2UnitLineCap + 1; gAge3UnitLineCap = gAge3UnitLineCap + 1; gAge4UnitLineCap = gAge4UnitLineCap + 1; } if (bAllowFactory_CAV01) { gAge2UnitLineCap = gAge2UnitLineCap + 1; gAge3UnitLineCap = gAge3UnitLineCap + 1; gAge4UnitLineCap = gAge4UnitLineCap + 1; } if (bAllowFactory_SIE01) { gAge3UnitLineCap = gAge3UnitLineCap + 1; gAge4UnitLineCap = gAge4UnitLineCap + 1; } if (bAllowFactory_SPC01) { gAge3UnitLineCap = gAge3UnitLineCap + 1; gAge4UnitLineCap = gAge4UnitLineCap + 1; } } //------------------------------------------------------------------- void HandleBaseBuildingSettings() { gTCNearTCMin = 50.0;//orginal - 40.0 gHouseNearTCMin = 15.0;//orginal - 12.0 gHouseNearTCMax = 30.0;//orginal - 25.0 gBuildingNearTCMin = 40.0;//orginal - 25.0 gMarketNearMainBaseMin = 90.0;//orginal - 80.0 gMarketNearTowerMax = 15.0;//orginal - 0.0 } //------------------------------------------------------------------- void HandleCivSpecificSettings() { int curCiv = kbGetCiv(); //-------------------------------- // special cases for C02 if(curCiv == gEgyptianCivID) { FactoryType_ARC01 = cUnitTypeUnitTypeBldgBarracks; } //-------------------------------- // special cases for C03 if(curCiv == gCelticCivID) { bAllowGRV = true; FactoryType_SIE01 = cUnitTypeUnitTypeBldgFortress; } //-------------------------------- // special cases for C04 if(curCiv == gPersianCivID) { if (btBiasINF > 0.0) { bAllowFactory_INF02 = cvOkToTrainArmy; FactoryType_INF02 = cUnitTypeUnitTypeBldgTemple; } FactoryType_SPC01 = cUnitTypeUnitTypeBldgAcademy; } } //------------------------------------------------------------------- void HandlePrimaryFocusSettings() { //-------------------------------- // special cases for dominant strategies other than INF int fINF = 0; int fARC = 0; int fCAV = 0; int fNAV = 0; int fSIE = 0; int fSPC = 0; if (btBiasINF > 0.8) {fINF = 1;} if (btBiasARC > 0.8) {fARC = 1;} if (btBiasCAV > 0.8) {fCAV = 1;} if (btBiasNAV > 0.8) {fNAV = 1;} if (btBiasSIE > 0.8) {fSIE = 1;} if (btBiasSPC > 0.8) {fSPC = 1;} //-------------------------------- // special cases for INF focus if ( bAllowFactory_INF01 && (fINF == 1) && ((fARC + fCAV + fNAV) == 0) ) { gMilitaryBuildingForInitialize = kbFindBuilding(FactoryType_INF01); // delay building ARC01 if it has a low bias if (bAllowFactory_ARC01 && (btBiasARC < 0.4)) { BuildStage_ARC01 = cAgeStateMid; } // delay building CAV01 if it has a low bias if (bAllowFactory_CAV01 && (btBiasCAV < 0.4)) { BuildStage_CAV01 = cAgeStateMid; } } //-------------------------------- // special cases for ARC focus if ( bAllowFactory_ARC01 && (fARC == 1) && ((fINF + fCAV + fNAV) == 0) ) { gMilitaryBuildingForInitialize = kbFindBuilding(FactoryType_ARC01); // delay building INF01 if it has a low bias if (bAllowFactory_INF01 && (btBiasINF < 0.4)) { BuildStage_INF01 = cAgeStateMid; } // delay building CAV01 if it has a low bias if (bAllowFactory_CAV01 && (btBiasCAV < 0.4)) { BuildStage_CAV01 = cAgeStateMid; } } //-------------------------------- // special cases for CAV focus if ( bAllowFactory_CAV01 && (fCAV == 1) && ((fINF + fARC + fNAV) == 0) ) { gMilitaryBuildingForInitialize = kbFindBuilding(FactoryType_CAV01); // delay building INF01 if it has a low bias if (bAllowFactory_INF01 && (btBiasINF < 0.4)) { BuildStage_INF01 = cAgeStateMid; } // delay building ARC01 if it has a low bias if (bAllowFactory_ARC01 && (btBiasARC < 0.4)) { BuildStage_ARC01 = cAgeStateMid; } } //-------------------------------- // special cases for SIE focus if ( bAllowFactory_SIE01 && (fSIE == 1) && ((fINF + fARC + fCAV + fNAV + fSPC) == 0) ) { gMilitaryBuildingForInitialize = kbFindBuilding(FactoryType_SIE01); BuildStage_SIE01 = cAgeStateEarly; // delay building INF01 if it has a low bias if (bAllowFactory_INF01 && (btBiasINF < 0.4)) { BuildStage_INF01 = cAgeStateMid; } // delay building ARC01 if it has a low bias if (bAllowFactory_ARC01 && (btBiasARC < 0.4)) { BuildStage_ARC01 = cAgeStateMid; } // delay building CAV01 if it has a low bias if (bAllowFactory_CAV01 && (btBiasCAV < 0.4)) { BuildStage_CAV01 = cAgeStateMid; } } else if (bAllowFactory_SIE01 && (btBiasSIE > 0.6)) { // even having a significant focus on siege should prioritize the siege workshop BuildStage_SIE01 = cAgeStateEarly; } //-------------------------------- // special cases for SPC focus // when we want these units, the other biases must be shifted so that this is considered by the picker if (fSPC == 1) { if (btBiasINF > 0.0) {btBiasINF = btBiasINF * 0.3;} if (btBiasARC > 0.0) {btBiasARC = btBiasARC * 0.3;} if (btBiasCAV > 0.0) {btBiasCAV = btBiasCAV * 0.3;} if (btBiasSIE > 0.0) {btBiasSIE = btBiasSIE * 0.3;} if ( bAllowFactory_SPC01 && ((fINF + fARC + fCAV + fNAV + fSIE) == 0) ) { gMilitaryBuildingForInitialize = kbFindBuilding(FactoryType_SPC01); BuildStage_SPC01 = cAgeStateEarly; // delay building INF01 if it has a low bias if (bAllowFactory_INF01 && (btBiasINF < 0.4)) { BuildStage_INF01 = cAgeStateMid; } // delay building ARC01 if it has a low bias if (bAllowFactory_ARC01 && (btBiasARC < 0.4)) { BuildStage_ARC01 = cAgeStateMid; } // delay building CAV01 if it has a low bias if (bAllowFactory_CAV01 && (btBiasCAV < 0.4)) { BuildStage_CAV01 = cAgeStateMid; } } } else if (bAllowFactory_SPC01 && (btBiasSPC > 0.6)) { // even having a significant focus on priests should prioritize the siege workshop BuildStage_SPC01 = cAgeStateEarly; } } //------------------------------------------------------------------- void ObjectiveHandler(int objID=-1) { if (objID == -1) { return; } int objType = kbGetObjectiveType(objID); if (objType == cKill) { bool caseHandled = false; bool isMobile = false; int unitType = kbFindBuilding( kbGetObjectiveUnitType(objID) ); if (unitType < 0) { unitType = kbFindUnit( kbGetObjectiveUnitType(objID) ); if (unitType < 0) { unitType = kbGetObjectiveUnitType(objID); } else { isMobile = true; } } if (kbIsPlayerAlly(1) == true) { aiEcho("CampaignCore: --- ObjectiveHandler: Kill objective detected, but AI is an Ally of player 1 - taking no action"); caseHandled = true; } else if (isMobile) { aiEcho("CampaignCore: --- ObjectiveHandler: Kill objective detected for mobile unit type[" + unitType + "] - taking no action"); } else if (unitType > 0) { if (kbProtoUnitIsType(cMyID, unitType, cUnitTypeUnitTypeBldgTownCenter) || (unitType == cUnitTypeUnitTypeBldgTownCenter)) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[cUnitTypeUnitTypeBldgTownCenter]"); bAllowTCBuild = false; bAllowTCAge1 = false; bAllowTCAge2 = false; bAllowTCAge3 = false; bPreventLevelUpTCChanges = true; caseHandled = true; } if (kbProtoUnitIsType(cMyID, unitType, cUnitTypeUnitTypeBldgFortress) || (unitType == cUnitTypeUnitTypeBldgFortress)) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[cUnitTypeUnitTypeBldgFortress]"); bAllowFRT = false; bPreventLevelUpFortChanges = true; MaxFortCount = 0; MaxTCCount = 0; caseHandled = true; } if (kbProtoUnitIsType(cMyID, unitType, cUnitTypeUnitTypeBldgTower) || (unitType == cUnitTypeUnitTypeBldgTower)) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[cUnitTypeUnitTypeBldgTower]"); bAllowTOW = false; cvNumTowers = 0; caseHandled = true; } if (kbProtoUnitIsType(cMyID, unitType, cUnitTypeUnitTypeBldgMarket) || (unitType == cUnitTypeUnitTypeBldgMarket)) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[cUnitTypeUnitTypeBldgMarket]"); bAllowMKT = false; caseHandled = true; } if (kbProtoUnitIsType(cMyID, unitType, cUnitTypeUnitTypeBldgArmory) || (unitType == cUnitTypeUnitTypeBldgArmory)) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[cUnitTypeUnitTypeBldgArmory]"); bAllowARM = false; caseHandled = true; } if (kbProtoUnitIsType(cMyID, unitType, cUnitTypeUnitTypeBldgAcademy) || (unitType == cUnitTypeUnitTypeBldgAcademy)) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[cUnitTypeUnitTypeBldgAcademy]"); bAllowHAL = false; caseHandled = true; } if ((kbGetCiv() == gCelticCivID) && ( kbProtoUnitIsType(cMyID, unitType, cUnitTypeUnitTypeBldgTemple) || (unitType == cUnitTypeUnitTypeBldgTemple) )) { aiEcho("CampaignCore: --- ObjectiveHandler: gCelticCivID: no rebuild of[cUnitTypeUnitTypeBldgTemple]"); bAllowGRV = false; caseHandled = true; } if ( (kbGetCiv() == gEgyptianCivID) && (unitType == gAge2Building) ) { aiEcho("CampaignCore: --- ObjectiveHandler: gEgyptianCivID: no rebuild of[gAge2Building]"); gAge2Building = -1;//Temple level 1 caseHandled = true; } else if ( (kbGetCiv() == gEgyptianCivID) && (unitType == gAge3Building) ) { aiEcho("CampaignCore: --- ObjectiveHandler: gEgyptianCivID: no rebuild of[gAge3Building]"); gAge3Building = -1;//Temple level 2 caseHandled = true; } else if ( (kbGetCiv() == gEgyptianCivID) && (unitType == gAge4Building) ) { aiEcho("CampaignCore: --- ObjectiveHandler: gEgyptianCivID: no rebuild of[gAge4Building]"); gAge4Building = -1;//Temple level 3 caseHandled = true; } if (kbProtoUnitIsType(cMyID, unitType, cUnitTypeUnitTypeBldgDock) || (unitType == cUnitTypeUnitTypeBldgDock)) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[cUnitTypeUnitTypeBldgDock]"); cvOkToBuildDocks = false; caseHandled = true; } if (kbProtoUnitIsType(cMyID, unitType, cUnitTypeUnitTypeBldgHouse) || (unitType == cUnitTypeUnitTypeBldgHouse)) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[cUnitTypeUnitTypeBldgHouse]"); cvOkToBuildHouses = false; caseHandled = true; } if (kbProtoUnitIsType(cMyID, unitType, cUnitTypeUnitTypeBldgFarm) || (unitType == cUnitTypeUnitTypeBldgFarm)) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[cUnitTypeUnitTypeBldgFarm]"); cvOkToBuildFarms = false; caseHandled = true; } if ((FactoryType_INF01 > -1) && ( kbProtoUnitIsType(cMyID, unitType, FactoryType_INF01) || (unitType == FactoryType_INF01) )) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[FactoryType_INF01]"); bAllowFactory_INF01 = false; caseHandled = true; } if ((FactoryType_INF02 > -1) && ( kbProtoUnitIsType(cMyID, unitType, FactoryType_INF02) || (unitType == FactoryType_INF02) )) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[FactoryType_INF02]"); bAllowFactory_INF02 = false; caseHandled = true; } if ((FactoryType_ARC01 > -1) && ( kbProtoUnitIsType(cMyID, unitType, FactoryType_ARC01) || (unitType == FactoryType_ARC01) )) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[FactoryType_ARC01]"); bAllowFactory_ARC01 = false; caseHandled = true; } if ((FactoryType_CAV01 > -1) && ( kbProtoUnitIsType(cMyID, unitType, FactoryType_CAV01) || (unitType == FactoryType_CAV01) )) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[FactoryType_CAV01]"); bAllowFactory_CAV01 = false; caseHandled = true; } if ((FactoryType_SIE01 > -1) && ( kbProtoUnitIsType(cMyID, unitType, FactoryType_SIE01) || (unitType == FactoryType_SIE01) )) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[FactoryType_SIE01]"); bAllowFactory_SIE01 = false; caseHandled = true; } if ((FactoryType_SPC01 > -1) && ( kbProtoUnitIsType(cMyID, unitType, FactoryType_SPC01) || (unitType == FactoryType_SPC01) )) { aiEcho("CampaignCore: --- ObjectiveHandler: prevent rebuilding of[FactoryType_SPC01]"); bAllowFactory_SPC01 = false; caseHandled = true; } } else { aiEcho("CampaignCore: --- ObjectiveHandler: ------ Kill objective detected for an unhandled INVALID case ------"); caseHandled = true; } if (caseHandled == false) { aiEcho("CampaignCore: --- ObjectiveHandler: ------ Kill objective detected for an unhandled building case ------"); } } } //------------------------------------------------------------------- void ObjectiveEnumerationComplete(int param=-1) { // TODO: anything we want here? } //------------------------------------------------------------------- void CalculateCampaignSettings() { HandleAttackSettings(); HandleDefenseSettings(); HandleEconomySettings(); HandleNavalSettings(); HandleFactorySettings(); HandleBaseBuildingSettings(); HandleCivSpecificSettings(); HandlePrimaryFocusSettings(); CalculateMilitaryCap(); kbEnumerateQuestObjectives("ObjectiveHandler", "ObjectiveEnumerationComplete"); } //------------------------------------------------------------------- void EchoCampaignSettings() { int TotalAnticipatedPop = (btMilitaryCap + btTargetAge4VilCount + gNumFishBoats + gCaravanCountNorm + gExtraTransportCount); //-------------------------------- // Echo Data aiEcho("---------------------------------------------------------------"); aiEcho("----------- BEGIN CAMPAIGN SETTINGS ----------------"); aiEcho("---------------------------------------------------------------"); aiEcho("--------- BAM BAM BAM: Enabled[" + gUseBetterAttackManager + "]"); aiEcho("--------- BAM BAM BAM: ATDelay[" + gBAMInitialAttackDelay + "]"); aiEcho("--------- BAM BAM BAM: ATInter[" + gBAMAttackInterval + "]"); aiEcho("--------- BAM BAM BAM: GRInter[" + gBAMGroupInterval + "]"); aiEcho("--------- BAM BAM BAM: RampUp [" + gBAMGroupSizeRampUp + "]"); aiEcho("--------- BAM BAM BAM: MaxRams[" + gBAMMaxNumRams + "]"); aiEcho("--------- BAM BAM BAM: MaxCats[" + gBAMMaxNumCatapults + "]"); aiEcho("--------- BAM BAM BAM: MaxPals[" + gBAMMaxNumTrebuchets + "]"); aiEcho("--------- CORE AI Data: INF [" + btBiasINF + "]"); aiEcho("--------- CORE AI Data: ARC [" + btBiasARC + "]"); aiEcho("--------- CORE AI Data: CAV [" + btBiasCAV + "]"); aiEcho("--------- CORE AI Data: NAV [" + btBiasNAV + "]"); aiEcho("--------- CORE AI Data: SIE [" + btBiasSIE + "]"); aiEcho("--------- CORE AI Data: SPC [" + btBiasSPC + "]"); aiEcho("--------- CORE AI Data: ATK [" + btStrengthATK + "]"); aiEcho("--------- CORE AI Data: DEF [" + btStrengthDEF + "]"); aiEcho("--------- CORE AI Data: ECO [" + btStrengthECO + "]"); aiEcho("--------- CORE AI Data: HCP [" + btBaselineHandicap + "]"); aiEcho("--------- CORE AI Data: R - B [" + btRushBoom + "]"); aiEcho("--------- CORE AI Data: MaxAge[" + (cvMaxAge+1) + "]"); aiEcho("--------- Derived Data: Lines [" + gAge1UnitLineCap + "][" + gAge2UnitLineCap + "][" + gAge3UnitLineCap + "][" + gAge4UnitLineCap + "]"); aiEcho("--------- Derived Data: Counts[" + btTargetAge1ArmyCount + "][" + btTargetAge2ArmyCount + "][" + btTargetAge3ArmyCount + "][" + btTargetAge4ArmyCount + "]"); aiEcho("--------- Derived Data: RampUp[" + btAttackRampUp + "]"); aiEcho("--------- Derived Data: Groups[" + btAttackGroups + "]"); aiEcho("--------- Derived Data: MilCap[" + btMilitaryCap + "]"); aiEcho("--------- Derived Data: Age1AT[" + btMilitaryInAge1 + "]"); aiEcho("--------- Derived Data: Age2DK[" + btBuild2ndDockAge2 + "]"); aiEcho("--------- Derived Data: Vils [" + btTargetAge1VilCount + "][" + btTargetAge4VilCount + "]"); aiEcho("--------- Derived Data: Farms [" + gMaxFarms + "]"); aiEcho("--------- Derived Data: Caravs[" + gCaravanCountNorm + "][" + gCaravanCountNoGold + "]"); aiEcho("--------- Derived Data: FishSH[" + gNumFishBoats + "]"); aiEcho("--------- Derived Data: TimeAT[" + gAttackMissionInterval/1000 + "]"); aiEcho("--------- Derived Data: TimeDE[" + gDefendMissionInterval/1000 + "]"); aiEcho("--------- Derived Data: Towers[" + cvNumTowers + "]"); aiEcho("--------- Derived Data: TowAGE[" + cvMinTowerAge + "]"); aiEcho("--------- Derived Data: Defend[" + bAllowDefend + "]"); aiEcho("--------- Derived Data: GuardA[" + bAllowGuardA + "]"); aiEcho("--------- Derived Data: DelayR[" + btRevealDelay/1000 + "]"); aiEcho("--------- Derived Data: DelayA[" + btAttackDelay/1000 + "]"); aiEcho("--------- Derived Data: DelayD[" + btDefendDelay/1000 + "]"); aiEcho("--------- Derived Data: DelayG[" + btGuardADelay/1000 + "]"); aiEcho("--------- Derived Data: FocusB[" + gMilitaryBuildingForInitialize + "]"); aiEcho("--------- Derived Data: TrirSH[" + gTriremeCount + "]"); aiEcho("--------- Derived Data: FireSH[" + gFireshipCount + "]"); aiEcho("--------- Derived Data: SiegSH[" + gSiegeshipCount + "]"); aiEcho("--------- Derived Data: TranSH[" + gExtraTransportCount + "]"); aiEcho("--------- Derived Data: POPTOT[" + TotalAnticipatedPop + "]"); aiEcho("---------------------------------------------------------------"); aiEcho("----------- END CAMPAIGN SETTINGS -------------------"); aiEcho("---------------------------------------------------------------"); } //------------------------------------------------------------------- rule CampaignScalingManager active minInterval 60 { //-------------------------------- if (bAllowScaling == false) { // shut down if we are restricted from doing this behavior xsDisableSelf(); return; } //-------------------------------- // evaluate if we need to shut down base building float CurrentTime = xsGetTime(); int TCCount = kbUnitCount(cMyID, cUnitTypeUnitTypeBldgTownCenter, cUnitStateAlive); if ( (PlayerLevel < 20) && (CurrentTime > 1200000) ) { // after 20 minutes, for lower level players, if the AI base is basically destroyed // shut down and let the player finish us off if (TCCount < 1) { aiEcho("CampaignCore: --- CSM: TCCount[" + TCCount + "] shutting down base building"); cvOkToBuild = false; xsDisableSelf(); return; } } else if (CurrentTime > 1800000) { // after 30 minutes, for all level players, if the AI base is basically destroyed // shut down and let the player finish us off if (TCCount < 1) { aiEcho("CampaignCore: --- CSM: TCCount[" + TCCount + "] shutting down base building"); cvOkToBuild = false; xsDisableSelf(); return; } } //-------------------------------- // calculate our scores AIScore = CalculatePlayerScore(cMyID); HumanScore = CalculatePlayerScore(1); if (aiIsMultiplayer()) { // increase each value by the counts of any human team members int HumanTeam = kbGetPlayerTeam(1); for (i=1; <=cNumberPlayers) { if ( (kbGetPlayerTeam(i) == HumanTeam) && (kbIsPlayerHuman(i) == true) ) { HumanScore = HumanScore + CalculatePlayerScore(i); } } } //-------------------------------- // define several tracking values to use if we need to make adjustments bool bLowScore = false; bool bAdjustNeeded = false; bool bAIDecline = (LastAIScore > AIScore); bool bAIWeak = (HumanScore > AIScore); float AdjustedAIScore = AIScore - StartingAIScore; float AdjustedHumanScore = HumanScore - StartingHumanScore; float GroupAdjust = 1.0; float AttackAdjust = 1.0; float EconAdjust = 1.0; float PercentAdjust = 1.0; float AttackIntervalAdjust = 1.0; //-------------------------------- // determine HighScore thresholds float ScorePerMinute = 10.0; float BonusScorePerMinute = 0.0; // scale HighScore for multiplayer and high starting scores if (aiIsMultiplayer()) { BonusScorePerMinute = ScorePerMinute * 0.5; } // scale HighScore for high starting unit counts if (StartingHumanScore > 20) { BonusScorePerMinute = BonusScorePerMinute + ((StartingHumanScore/20) * 0.1); } float HighScoreCheck = ((ScorePerMinute + BonusScorePerMinute) * (CurrentTime/60000)); float EarlyGameScoreCheck = ((ScorePerMinute + BonusScorePerMinute) * 5); //aiEcho("CampaignCore: --- CSM: HighScoreCheck[" + HighScoreCheck + "] ScorePerMinute[" + ScorePerMinute + "] BonusScorePerMinute[" + BonusScorePerMinute + "]"); //-------------------------------- // CASE 1: Low Human Score if ( (HumanScore < 20) && (AIScore > 50) ) { // pull attack punches if the AI is dominant aiEcho("CampaignCore: --- CSM: CASE 1: RAW AIScore[" + AIScore + "] RAW HumanScore[" + HumanScore + "]"); bLowScore = true; bAdjustNeeded = true; bScalingInEffect = true; GroupAdjust = 0.5; AttackAdjust = 0.5; } //-------------------------------- // CASE 2: Weaker or Declining AI Score, Early Player Aggression else if ( (CurrentTime < 300000) && (AdjustedHumanScore > EarlyGameScoreCheck) && (bAIDecline || bAIWeak) ) { // aggressively try and recover aiEcho("CampaignCore: --- CSM: CASE 2: AI[" + AdjustedAIScore + "] H[" + AdjustedHumanScore + "] bAIDecline[" + bAIDecline + "] bAIWeak[" + bAIWeak + "]"); bAdjustNeeded = true; bScalingInEffect = true; GroupAdjust = 1.5; AttackAdjust = 1.5; EconAdjust = 2.0; } //-------------------------------- // CASE 3: Weaker or Declining AI Score, Late Player Aggression else if ( (AdjustedHumanScore > HighScoreCheck) && (bAIDecline || bAIWeak) ) { // derive a value for our adjustments that scales by the amount we are over the HighScgoreCheck PercentAdjust = AdjustedHumanScore/HighScoreCheck; // clamp our percent adjust based on a semi-arbitrary value that can be adjusted a bit by player level float maxPercentAdjust = 2.0; if (PlayerLevel < 20) { maxPercentAdjust = 1.5; } else if (PlayerLevel < 30) { maxPercentAdjust = 1.8; } if (PercentAdjust > maxPercentAdjust) { PercentAdjust = maxPercentAdjust; } // try and recover aiEcho("CampaignCore: --- CSM: CASE 3: AI[" + AdjustedAIScore + "] H[" + AdjustedHumanScore + "] bAIDecline[" + bAIDecline + "] bAIWeak[" + bAIWeak + "] HighScoreCheck[" + HighScoreCheck + "] PercentAdjust[" + PercentAdjust + "]"); bAdjustNeeded = true; bScalingInEffect = true; GroupAdjust = PercentAdjust; AttackAdjust = PercentAdjust; EconAdjust = PercentAdjust; // since attack interval is a bit more complex than a simple percentage, calculate it using the following equation // this equation is designed to only reduce the attack intervale by at most 30% AttackIntervalAdjust = 1.0 - (PercentAdjust/maxPercentAdjust * 0.3); } //-------------------------------- // CASE 4: Restoring to original settings else if (bScalingInEffect) { // reset the dirty flag, and update back to the defaults aiEcho("CampaignCore: --- CSM: CASE 4: AI[" + AdjustedAIScore + "] H[" + AdjustedHumanScore + "] bAIDecline[" + bAIDecline + "] bAIWeak[" + bAIWeak + "]"); bAdjustNeeded = true; bScalingInEffect = false; } //-------------------------------- // Make Adjustments if (bAdjustNeeded) { aiEcho("CampaignCore: --- CSM: OLD: Handicap[" + kbGetPlayerHandicap(cMyID) + "] Groups[" + gBAMAttackGroups + "] Counts[" + gBAMTargetAge1GroupSize + "][" + gBAMTargetAge2GroupSize + "][" + gBAMTargetAge3GroupSize + "][" + gBAMTargetAge4GroupSize + "] ATInterval[" + gBAMAttackInterval + "]"); gBAMAttackGroups = btAttackGroups * GroupAdjust; gBAMTargetAge1GroupSize = btTargetAge1ArmyCount * AttackAdjust; gBAMTargetAge2GroupSize = btTargetAge2ArmyCount * AttackAdjust; gBAMTargetAge3GroupSize = btTargetAge3ArmyCount * AttackAdjust; gBAMTargetAge4GroupSize = btTargetAge4ArmyCount * AttackAdjust; kbSetPlayerHandicap( cMyID, (btBaselineHandicap * EconAdjust) ); gBAMAttackInterval = GetAttackMissionInterval(bAllowBAM) * AttackIntervalAdjust; gBAMGroupInterval = (gBAMAttackInterval * gBAMAttackPeriodPercent) / btAttackGroups; CalculateMilitaryCap(); aiEcho("CampaignCore: --- CSM: NEW: Handicap[" + kbGetPlayerHandicap(cMyID) + "] Groups[" + gBAMAttackGroups + "] Counts[" + gBAMTargetAge1GroupSize + "][" + gBAMTargetAge2GroupSize + "][" + gBAMTargetAge3GroupSize + "][" + gBAMTargetAge4GroupSize + "] ATInterval[" + gBAMAttackInterval + "]"); } else { aiEcho("CampaignCore: --- CSM: NO CHANGE: AI[" + AdjustedAIScore + "] H[" + AdjustedHumanScore + "] bAIDecline[" + bAIDecline + "] bAIWeak[" + bAIWeak + "] HighScoreCheck[" + HighScoreCheck + "] PercentAdjust[" + PercentAdjust + "]"); } //-------------------------------- // LONG REPORT: if (LastHumanScore > HumanScore) { HumanDeclineMinuteCount = HumanDeclineMinuteCount + 1; } if (LastAIScore > AIScore) { AIDeclineMinuteCount = AIDeclineMinuteCount + 1; } if (AIScore > HumanScore) { HumanWeakMinuteCount = HumanWeakMinuteCount + 1; } if (HumanScore > AIScore) { AIWeakMinuteCount = AIWeakMinuteCount + 1; } if (bAdjustNeeded) { AIAdjustedMinuteCount = AIAdjustedMinuteCount + 1; } if (bLowScore) { HumanLowScoreMinuteCount = HumanLowScoreMinuteCount + 1; } if (HumanScore > HighestHumanScore) { HighestHumanScore = HumanScore; } if (AIScore > HighestAIScore) { HighestAIScore = AIScore; } aiEcho("---------------------------------------------"); aiEcho("--------------- BEGIN CSM REPORT"); aiEcho("--- [" + HumanDeclineMinuteCount + "] --- HumanDeclineMinuteCount"); aiEcho("--- [" + AIDeclineMinuteCount + "] --- AIDeclineMinuteCount"); aiEcho("--- [" + HumanWeakMinuteCount + "] --- HumanWeakMinuteCount"); aiEcho("--- [" + AIWeakMinuteCount + "] --- AIWeakMinuteCount"); aiEcho("--- [" + AIAdjustedMinuteCount + "] --- AIAdjustedMinuteCount"); aiEcho("--- [" + HumanLowScoreMinuteCount + "] --- HumanLowScoreMinuteCount"); aiEcho("--- [" + StartingHumanScore + "] --- StartingHumanScore"); aiEcho("--- [" + HighestHumanScore + "] --- HighestHumanScore"); aiEcho("--- [" + StartingAIScore + "] --- StartingAIScore"); aiEcho("--- [" + HighestAIScore + "] --- HighestAIScore"); aiEcho("--------------- END CSM REPORT"); aiEcho("---------------------------------------------"); //-------------------------------- // update values for the next round if (HumanScore > -1) { // if needed, set starting score if (LastHumanScore == -1) { StartingHumanScore = HumanScore; } // give three minutes to let the score assessment settle down else if (CurrentTime < 180000) { StartingHumanScore = HumanScore; } LastHumanScore = HumanScore; } if (AIScore > -1) { // if needed, set starting score if (LastAIScore == -1) { StartingAIScore = AIScore; } LastAIScore = AIScore; } } //------------------------------------------------------------------- rule CampaignResignManager inactive minInterval 6 { if (bAllowAutoResign == false) { // shut down if we are restricted from doing this behavior xsDisableSelf(); return; } // setup some counting variables int countTC = 0; int countVC = 0; // determine counts for the entire AI team int myTeam = kbGetPlayerTeam(cMyID); for (i=1; <=cNumberPlayers) { if (kbGetPlayerTeam(i) == myTeam) { countTC = countTC + kbUnitCount(i, cUnitTypeUnitTypeBldgTownCenter, cUnitStateAlive); countVC = countVC + kbUnitCount(i, cUnitTypeLogicalTypeNeededForVictory, cUnitStateAlive); } } // if all the TCs are dead or gone, and we have less than a nominal amount of VC units // start checking for the main base areas to be clear of VC units if (countTC < 1) { // looks like we are done already if (countVC < 8) { aiEcho("CampaignCore: --- CampaignCoreResignManager: Resign Case 1"); aiResign(); xsDisableSelf(); return; } else if (countVC < 20) { // give the AI a few tries to recover - after which call it done if (btResignCheckCount >= ResignCheckCount) { aiEcho("CampaignCore: --- CampaignCoreResignManager: Resign Case 2"); aiResign(); xsDisableSelf(); return; } else { btResignCheckCount = btResignCheckCount + 1; } aiEcho("CampaignCore: --- CampaignCoreResignManager: No TC and Low VC[" + countVC + "] check[" + btResignCheckCount + "]"); } else { aiEcho("CampaignCore: --- CampaignCoreResignManager: No TC but still a large enough VC[" + countVC + "]"); btResignCheckCount = 0; } } } //------------------------------------------------------------------- rule ForcedResignManager inactive minInterval 60 { if (ForcedResignMinCount > 1) { xsSetRuleMinIntervalSelf( (ForcedResignMinCount-1) * 60 ); ForcedResignMinCount = 0; } else { aiEcho("---------------------------------------------------"); aiEcho("---------------------------------------------------"); aiEcho("---------------------------------------------------"); aiEcho("ForcedResignManager: SUCCESS COUNT[" + gBAMCount_AttackFormed + "]FAILURE COUNT[" + gBAMCount_NotEnoughUnits + "]"); aiEcho("---------------------------------------------------"); aiEcho("---------------------------------------------------"); aiEcho("---------------------------------------------------"); aiResign(); xsDisableSelf(); return; } } //------------------------------------------------------------------- rule CamapaignPatrolResources active minInterval 29 { if ( bAllowResourcePatrol && (btStrengthDEF > 0) ) { static int waypointResource = 1; static int LastUnitCount = 0; int units = btStrengthDEF * (kbGetAge()+ 3);//btStrengthDEF * 3/4/5/6 float MaxPatrolDistance = (kbGetMapXSize() + kbGetMapZSize()) * 0.25; vector MainBaseLoc = kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID)); if (gResourcePatrolPlan < 0) { gResourcePatrolPlan = aiPlanCreate("Resource Patrol", cPlanDefend); aiPlanAddUnitType(gResourcePatrolPlan, cUnitTypeLogicalTypeLandMilitary, units, units, units); aiPlanSetVariableVector(gResourcePatrolPlan, cDefendPlanDefendPoint, 0, kbBaseGetMilitaryGatherPoint(cMyID, kbBaseGetMainID(cMyID))); if (kbBaseGetMilitaryGatherPoint(cMyID, kbBaseGetMainID(cMyID)) == cInvalidVector) { aiPlanSetVariableVector(gResourcePatrolPlan, cDefendPlanDefendPoint, 0, kbUnitGetCentroid(cUnitTypeLogicalTypeLandMilitary)); } aiPlanSetVariableFloat(gResourcePatrolPlan, cDefendPlanEngageRange, 0, cvDefenseReflexRadiusPassive); aiPlanSetRequiresAllNeedUnits(gResourcePatrolPlan, true); aiPlanSetVariableFloat(gResourcePatrolPlan, cDefendPlanGatherDistance, 0, cvDefenseReflexRadiusPassive - 10.0); aiPlanSetInitialPosition(gResourcePatrolPlan, MainBaseLoc); aiPlanSetUnitStance(gResourcePatrolPlan, cUnitStanceAggressive); aiPlanSetVariableInt(gResourcePatrolPlan, cDefendPlanRefreshFrequency, 0, 5); aiPlanSetVariableInt(gResourcePatrolPlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit); // be sure this is considered fairly low priority aiPlanSetDesiredPriority(gResourcePatrolPlan, 20); aiPlanSetActive(gResourcePatrolPlan); // update our unit count tracking value LastUnitCount = units; // update the military cap CalculateMilitaryCap(LastUnitCount); } else if (LastUnitCount < units) { // determine the difference between the two values int delta = units - LastUnitCount; // update the number of defender units aiPlanAddUnitType(gResourcePatrolPlan, cUnitTypeLogicalTypeLandMilitary, units, units, units); // update our unit count tracking value LastUnitCount = units; // update the military cap CalculateMilitaryCap(delta); } if (gResourceQuery < 0) { gResourceQuery = kbUnitQueryCreate("CampaignResourceQuery"); kbUnitQuerySetPlayerRelation(gResourceQuery, cPlayerRelationAny); kbUnitQuerySetUnitType(gResourceQuery, cUnitTypeAbstractMine); kbUnitQuerySetState(gResourceQuery, cUnitStateAny); } kbUnitQuerySetPosition(gResourceQuery, MainBaseLoc); kbUnitQuerySetMaximumDistance(gResourceQuery, MaxPatrolDistance); kbUnitQueryResetResults(gResourceQuery); if (kbUnitQueryExecute(gResourceQuery) > 0) { int ResourceID = 0; if (waypointResource == 1) { ResourceID = getUnit(cUnitTypeUnitTypeBldgMarket, cMyID, cUnitStateAny, RMSeed05); } else { ResourceID = kbUnitQueryGetResult(gResourceQuery, waypointResource); } if (ResourceID > 0) { vector testVec = kbUnitGetPosition(ResourceID); aiPlanSetVariableVector(gResourcePatrolPlan, cDefendPlanDefendPoint, 0, testVec); if (bEnablePatrolEcho) { aiEcho("CampaignCore: --- CamapaignPatrolResources: plan[" + gResourcePatrolPlan + "]: loc[" + testVec + "] Range[" + MaxPatrolDistance + "]"); aiEcho("CampaignCore: --- CamapaignPatrolResources: units[" + LastUnitCount + "] btMilitaryCap[" + btMilitaryCap + "]"); } } waypointResource = waypointResource + 1; // since we are only allowed 4 points, stop trying to cycle if we are at the 4 points or if there are no more resources if( (waypointResource > kbUnitQueryNumberResults(gResourceQuery)) || (waypointResource > 4) ) { waypointResource = 1; } } } else { // shut down if we are restricted from doing this behavior xsDisableSelf(); return; } } //------------------------------------------------------------------- rule CamapaignDefendMarket active minInterval 37 { if (bAllowMarketDefense && bAllowTOW && bAllowMKT) { if (kbGetAge() < cvMinTowerAge) { // early out if there is no way to build towers yet return; } if (aiPlanGetIDByTypeAndVariableType(cPlanBuild, cBuildPlanBuildingTypeID, gTower) >= 0) { // early out if there is tower in the middle of being built return; } // determine how many towers will be built around the market btDefenseTowerCount = (btStrengthDEF * 0.8) + 1; if ( (btRushBoom < 0) && (btStrengthDEF < 2) ) { btDefenseTowerCount = btDefenseTowerCount - btRushBoom; } int currentTowerCount = kbUnitCount(cMyID, gTower, cUnitStateABQ); if ( currentTowerCount >= (btDefenseTowerCount + cvNumTowers) ) { //early out if we are already at the max tower vap if (bEnablePatrolEcho) { aiEcho("CampaignCore: --- CamapaignDefendMarket: early out: total towers[" + currentTowerCount + "] >= [" + btDefenseTowerCount + "] + [" + cvNumTowers + "]"); } return; } // find our market first int MarketID = getUnit(cUnitTypeUnitTypeBldgMarket, cMyID, cUnitStateAny, RMSeed05); if (MarketID > 0) { // get the position of our market vector marketLoc = kbUnitGetPosition(MarketID); if (gTowerSearch < 0) { gTowerSearch = kbUnitQueryCreate("Tower placement search"); kbUnitQuerySetPlayerRelation(gTowerSearch, cPlayerRelationAny); kbUnitQuerySetUnitType(gTowerSearch, gTower); kbUnitQuerySetState(gTowerSearch, cUnitStateABQ); } kbUnitQuerySetPosition(gTowerSearch, marketLoc); kbUnitQuerySetMaximumDistance(gTowerSearch, 40); kbUnitQueryResetResults(gTowerSearch); int queryResults = kbUnitQueryExecute(gTowerSearch); if (queryResults < btDefenseTowerCount) { int buildPlan = aiPlanCreate("CamapaignDefendMarket", cPlanBuild); if (bEnablePatrolEcho) { aiEcho("CampaignCore: --- CamapaignDefendMarket: plan[" + buildPlan + "]: now building tower[" + (queryResults+1) + "] of[" + btDefenseTowerCount + "]"); } aiPlanSetVariableInt(buildPlan, cBuildPlanBuildingTypeID, 0, gTower); aiPlanSetDesiredPriority(buildPlan, 95); aiPlanSetMilitary(buildPlan, false); aiPlanSetEconomy(buildPlan, true); aiPlanSetEscrowID(buildPlan, cEconomyEscrowID); aiPlanAddUnitType(buildPlan, gEconUnit, 1, 1, 1); //build the towers pretty close to the market aiPlanSetVariableVector(buildPlan, cBuildPlanCenterPosition, 0, marketLoc); aiPlanSetVariableFloat(buildPlan, cBuildPlanCenterPositionDistance, 0, gMarketNearTowerMax); // stay away from other towers aiPlanSetVariableInt(buildPlan, cBuildPlanInfluenceUnitTypeID, 0, gTower); aiPlanSetVariableFloat(buildPlan, cBuildPlanInfluenceUnitDistance, 0, 20.0); aiPlanSetVariableFloat(buildPlan, cBuildPlanInfluenceUnitValue, 0, 100.0); aiPlanSetVariableInt(buildPlan, cBuildPlanInfluenceUnitFalloff, 0, cBPIFalloffLinearInverse); aiPlanSetVariableInt(buildPlan, cBuildPlanInfluenceUnitCap, 0, -1); aiPlanSetVariableBool(buildPlan, cBuildPlanNoFailOutOfUnits, 0, true); aiPlanSetAllowHandleDamage(buildPlan, false); aiPlanSetActive(buildPlan); } else if (bEnablePatrolEcho) { aiEcho("CampaignCore: --- CamapaignDefendMarket: early out: found nearby tower count[" + queryResults + "] and only need[" + btDefenseTowerCount + "]"); } } } else { // shut down if we are restricted from doing this behavior xsDisableSelf(); return; } } //------------------------------------------------------------------- rule CamapaignRevealDelay active minInterval 5 { if (bAllowReveal == false) { xsDisableSelf(); return; } float totalTime = xsGetTime(); if ( cvOkToAttack || (totalTime >= btRevealDelay) ) { kbLookAtAllUnitsOnMap(); aiCheatReveal(); aiEcho("CampaignCore: --- CamapaignRevealDelay[" + btRevealDelay + "]: now revealing enemy"); xsSetRuleMinIntervalSelf(123); } } //------------------------------------------------------------------- rule CampaignAttackDelay active minInterval 7 { if (bAllowAttack == false) { xsDisableSelf(); return; } static bool ready = false; float totalTime = xsGetTime(); if ( cvOkToAttack || (totalTime >= (btAttackDelay + btAttackDelayMod)) ) { aiEcho("CampaignCore: --- CampaignAttackDelay[" + btAttackDelay + "][" + btAttackDelayMod + "]: now allowing attacks"); ready = true; cvOkToAttack = true; xsDisableSelf(); } } //------------------------------------------------------------------- rule CampaignDefendDelay active minInterval 9 { if (bAllowDefend == false) { xsDisableSelf(); return; } static bool ready = false; float totalTime = xsGetTime(); if (totalTime >= btDefendDelay) { aiEcho("CampaignCore: --- CampaignDefendDelay[" + btDefendDelay + "]: now allowing defense"); ready = true; cvOKToDefend = true; xsDisableSelf(); } } //------------------------------------------------------------------- rule CampaignGuardADelay active minInterval 11 { if (bAllowGuardA == false) { xsDisableSelf(); return; } static bool ready = false; float totalTime = xsGetTime(); if (totalTime >= btGuardADelay) { aiEcho("CampaignCore: --- CampaignGuardADelay[" + btGuardADelay + "]: now allowing ally guarding"); ready = true; cvGuardAlliedBases = true; xsDisableSelf(); } } //------------------------------------------------------------------- rule BeginLandPatrol inactive minInterval 12 { static int waypointLand = 0; int enemyArmySize = numEnemiesInBase(cMyID, kbBaseGetMainID(cMyID)); if(enemyArmySize > 0) { aiPlanSetVariableVector(gLandPatrolPlan, cDefendPlanDefendPoint, 0, kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID))); return; } vector center = kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID)); vector testVec = center; float DirX = 0; float DirZ = 0; float Radius = btLandPatrolRadius; float Mult = Radius/15; // allow this system to use a way point object if there is one placed on the map int WaypointPUID = -1; switch(waypointLand) { case 0: { WaypointPUID = cUnitTypeAILandPoint1; Radius = Radius + (Mult * RMSeed01) - (Mult * RMSeed04); DirX = Radius; DirZ = -1.0 * Radius; break; } case 1: { WaypointPUID = cUnitTypeAILandPoint2; Radius = Radius + (Mult * RMSeed02) - (Mult * RMSeed03); DirX = Radius; DirZ = Radius; break; } case 2: { WaypointPUID = cUnitTypeAILandPoint3; Radius = Radius + (Mult * RMSeed03) - (Mult * RMSeed02); DirX = -1.0 * Radius; DirZ = Radius; break; } case 3: { WaypointPUID = cUnitTypeAILandPoint4; Radius = Radius + (Mult * RMSeed04) - (Mult * RMSeed01); DirX = -1.0 * Radius; DirZ = -1.0 * Radius; break; } } int WaypointUnitID = getUnit(WaypointPUID, cMyID, cUnitStateAny, RMSeed05); if (WaypointUnitID > 0) { testVec = kbUnitGetPosition(WaypointUnitID); } else { testVec = xsVectorSetX(testVec, xsVectorGetX(center) + DirX); testVec = xsVectorSetZ(testVec, xsVectorGetZ(center) + DirZ); } aiPlanSetVariableVector(gLandPatrolPlan, cDefendPlanDefendPoint, 0, testVec); waypointLand = waypointLand + 1; if(waypointLand > 3) { waypointLand = 0; } } //------------------------------------------------------------------- rule BeginNavalPatrol inactive minInterval 23 { static int waypointNaval = 0; vector center = gNavyVec; vector testVec = center; float DirX = 0; float DirZ = 0; float Radius = btNavalPatrolRadius; // allow this system to use a way point object if there is one placed on the map int WaypointPUID = -1; switch(waypointNaval) { case 0: { WaypointPUID = cUnitTypeAINavalPoint1; DirX = 1.0 * Radius; DirZ = 0; break; } case 1: { WaypointPUID = cUnitTypeAINavalPoint2; DirX = 0.5 * Radius; DirZ = 0.1 * Radius; break; } case 2: { WaypointPUID = cUnitTypeAINavalPoint3; DirX = -0.5 * Radius; DirZ = 0.1 * Radius; break; } case 3: { WaypointPUID = cUnitTypeAINavalPoint4; DirX = -1.0 * Radius; DirZ = 0; break; } } int WaypointUnitID = getUnit(WaypointPUID, cMyID, cUnitStateAny, RMSeed05); if (WaypointUnitID > 0) { aiPlanSetVariableVector(gNavalPatrolPlan, cDefendPlanDefendPoint, 0, kbUnitGetPosition(WaypointUnitID)); } else { testVec = xsVectorSetX(testVec, xsVectorGetX(center) + DirX); testVec = xsVectorSetZ(testVec, xsVectorGetZ(center) + DirZ); int tempAreaID = -1; tempAreaID = kbAreaGetClosestArea(testVec, cAreaTypeWater, -1, 50.0); aiPlanSetVariableVector(gNavalPatrolPlan, cDefendPlanDefendPoint, 0, kbAreaGetCenter(tempAreaID)); } waypointNaval = waypointNaval + 1; if(waypointNaval > 3) { waypointNaval = 0; } } //------------------------------------------------------------------- rule SetCustomRallyPoints active minInterval 9 { int RallyPUID = cUnitTypeAILandRally; int rallyUnitID = getUnit(RallyPUID, cMyID, cUnitStateAny, RMSeed05); if ( rallyUnitID > 0 ) { gCustomRallyLOC = kbUnitGetPosition(rallyUnitID); if(gCustomRallyLOC != cInvalidVector) { kbBaseSetMilitaryGatherPoint(cMyID, kbBaseGetMainID(cMyID), gCustomRallyLOC); aiEcho("CampaignCore: --- SetCustomRallyPoints: [" + rallyUnitID + "] gCustomRallyLOC[" + gCustomRallyLOC + "]"); } } int NavalRallyPUID = cUnitTypeAINavalRally; int NavalRallyUnitID = getUnit(NavalRallyPUID, cMyID, cUnitStateAny, RMSeed05); if ( NavalRallyUnitID > 0 ) { gUseCustomNavyVec = true; gNavyDefendGatherDist = 15.0; gNavyVec = kbUnitGetPosition(NavalRallyUnitID); aiEcho("CampaignCore: --- SetCustomRallyPoints: [" + NavalRallyUnitID + "] gNavyVec[" + gNavyVec + "]"); } xsDisableSelf(); } //------------------------------------------------------------------- void RMUpdate_AttackDelayMod(int val = -99) { if ( val > -99 ) { // NOTE: this value was converted to ms with a random variance before being sent from the RM btAttackDelayMod = val; aiEcho("CampaignCore: --- RMUpdate_AttackDelayMod: [" + btAttackDelayMod + "]"); } } //------------------------------------------------------------------- void RMUpdate_TrainBonusMod(int val = -99) { if ( val > -99 ) { // convert to a percentage btTrainBonusMod = 0.01 * val; aiEcho("CampaignCore: --- RMUpdate_TrainBonusMod: [" + btTrainBonusMod + "]"); } } //------------------------------------------------------------------- void RMUpdate_AllowTCAge1(int val = 0) { if ( val == 1 ) { if (bAllowTCBuild == false) { aiEcho("CampaignCore: --- RMUpdate_AllowTCAge1: Trying to allow age 1 TCS when TC building is already restricted - this will not work."); } bAllowTCAge1 = true; aiEcho("CampaignCore: --- RMUpdate_AllowTCAge1: [" + bAllowTCAge1 + "]"); // force the AI to redo the build order right now setupBuildingInfo(); } } //------------------------------------------------------------------- void RMUpdate_AllowTCBuilding(int val = 1) { if ( val == 0 ) { bAllowTCBuild = false; bPreventLevelUpTCChanges = true; aiEcho("CampaignCore: --- RMUpdate_AllowTCBuilding: [" + bAllowTCBuild + "]"); } } //------------------------------------------------------------------- void RMUpdate_AllowFortBuilding(int val = 1) { if ( val == 0 ) { bAllowFRT = false; bPreventLevelUpFortChanges = true; aiEcho("CampaignCore: --- RMUpdate_AllowFortBuilding: [" + bAllowFRT + "]"); } } //------------------------------------------------------------------- void RMUpdate_AllowAge4Siege(int val = 1) { if ( val == 0 ) { bAllowAge4Siege = false; aiEcho("CampaignCore: --- RMUpdate_AllowAge4Siege: [" + bAllowAge4Siege + "]"); } } //------------------------------------------------------------------- void RMUpdate_AllowResourcePatrol(int val = 1) { if ( val == 0 ) { bAllowResourcePatrol = false; aiEcho("CampaignCore: --- RMUpdate_AllowResourcePatrol: [" + bAllowResourcePatrol + "]"); } } //------------------------------------------------------------------- void RMUpdate_HatedEnemyOverride(int val = 0) { if ( val > 0 ) { cvPlayerToAttack = val; aiEcho("CampaignCore: --- RMUpdate_HatedEnemyOverride: [" + cvPlayerToAttack + "]"); // go ahead and execute the mostHatedEnemy calculation right now mostHatedEnemy(); } } //------------------------------------------------------------------- void RMUpdate_HateThreshold(int val = 0) { if ( val > 0 ) { gPlayerHateThreshold = 1.0 + (0.01 * val); aiEcho("CampaignCore: --- RMUpdate_HateThreshold: [" + gPlayerHateThreshold + "] passed in val[" + val + "]"); // go ahead and execute the mostHatedEnemy calculation right now mostHatedEnemy(); } } //------------------------------------------------------------------- void RMUpdate_SetPlayerLevel(int val = 0) { if ( val > 0 ) { // because this gets called more than once by the RM side, we need to only retain the highest value if (val > PlayerLevel ) { PlayerLevel = val; if (PlayerLevel > 8) { if (bPreventLevelUpTCChanges == false) { // allow a second TC, but only in Age 3 bAllowTCAge3 = true; MaxTCCount = 2; } if ( (bPreventLevelUpFortChanges == false) && (btStrengthDEF > 0) ) { // allow fort building bAllowFRT = true; MaxFortCount = 1; } } else if (PlayerLevel < 8) { // unless already constrained, constrain aging up if the player is not at least 1 level into the new age if (bPreventLevelUpMaxAgeChanges == false) { cvMaxAge = cAge2; } } if (PlayerLevel > 16) { if (bPreventLevelUpTCChanges == false) { // allow a second TC in Age 2, and a third TC in Age 3 bAllowTCAge2 = true; MaxTCCount = 3; } if ( (bPreventLevelUpFortChanges == false) && (btStrengthDEF > 3) ) { // allow for as much as two forts MaxFortCount = 2; } } else if ( (PlayerLevel >= 8) && (PlayerLevel < 16) ) { // unless already constrained, constrain aging up if the player is not at least 1 level into the new age if (bPreventLevelUpMaxAgeChanges == false) { cvMaxAge = cAge3; } } if (PlayerLevel >= 20) { if (bPreventLevelUpTCChanges == false) { // allow the fourth TC MaxTCCount = 4; } if (bPreventLevelUpFortChanges == false) { // increase the chances of two forts if (btStrengthDEF > 2) { MaxFortCount = btStrengthDEF; } else { // go ahead and allow fort building, even for AIs that have no defense needs bAllowFRT = true; MaxFortCount = 1; } } } else if ( (PlayerLevel >= 16) && (PlayerLevel < 16) ) { // unless already constrained, constrain aging up if the player is not at least 1 level into the new age if (bPreventLevelUpMaxAgeChanges == false) { cvMaxAge = cAge4; } } aiEcho("CampaignCore: --- RMUpdate_SetPlayerLevel: [" + PlayerLevel + "+] cvMaxAge[Age" + (cvMaxAge+1) + "] MaxFortCount[" + MaxFortCount + "] MaxTCCount[" + MaxTCCount + "]"); } } } //------------------------------------------------------------------- void RMUpdate_ForceTransports(int val = 0) { if ( val > 0 ) { gBAMForceTransportUsage = true; aiEcho("CampaignCore: --- RMUpdate_ForceTransports: AI will now always use transports for attacks"); } else { gBAMForceTransportUsage = false; aiEcho("CampaignCore: --- RMUpdate_ForceTransports: AI will now always use transports for attacks"); } } //------------------------------------------------------------------- void RMUpdate_AllowAutoResign(int val = 0) { if ( val > 0 ) { float MapSize = (kbGetMapXSize() + kbGetMapZSize())/2; if (MapSize <= 200) { ResignCheckCount = 5; } else if (MapSize <= 300) { ResignCheckCount = 7; } bAllowAutoResign = true; xsEnableRule("CampaignResignManager"); aiEcho("CampaignCore: --- RMUpdate_AllowAutoResign: AI will now resign when team meets criteria"); } } //------------------------------------------------------------------- void RMUpdate_ForcedResign(int val = 0) { if ( val > 0 ) { aiResign(); aiEcho("CampaignCore: --- RMUpdate_ForcedResign: forcing AI to resign..."); } } //------------------------------------------------------------------- void RMUpdate_ForcedResignMinCount(int val = 0) { if ( val > 0 ) { ForcedResignMinCount = val; xsEnableRule("ForcedResignManager"); aiEcho("CampaignCore: --- RMUpdate_ForcedResignMinCount: forcing AI to resign after Min[" + ForcedResignMinCount + "]"); } } //------------------------------------------------------------------- void RMUpdate_RandomSeed(int val = -99) { if ( val > -99 ) { // NOTE: ((val/10000) * 10) is not the same thing as (val/1000) // using this method reduces the number of significant digits, treating each digit of the original number as a unique random int from 0-9 int temp = val + 100000; RMSeed01 = temp/10000 - 10; RMSeed02 = (temp/1000) - ((temp/10000) * 10); RMSeed03 = (temp/100) - ((temp/1000) * 10); RMSeed04 = (temp/10) - ((temp/100) * 10); RMSeed05 = temp - ((temp/10) * 10); aiEcho("CampaignCore: --- RMUpdate_RandomSeed: setting seeds with[" + val + "]:[" + RMSeed01 + "][" + RMSeed02 + "][" + RMSeed03 + "][" + RMSeed04 + "][" + RMSeed05 + "]"); } } //------------------------------------------------------------------- void RMUpdate_CreateLandPatrol(int val = 0) { if ( val > 0 ) { gLandPatrolPlan = aiPlanCreate("Land Patrol", cPlanDefend); int units = val; aiPlanAddUnitType(gLandPatrolPlan, cUnitTypeLogicalTypeLandMilitary, units, units, units); aiPlanSetVariableVector(gLandPatrolPlan, cDefendPlanDefendPoint, 0, kbBaseGetMilitaryGatherPoint(cMyID, kbBaseGetMainID(cMyID))); if (kbBaseGetMilitaryGatherPoint(cMyID, kbBaseGetMainID(cMyID)) == cInvalidVector) { aiPlanSetVariableVector(gLandPatrolPlan, cDefendPlanDefendPoint, 0, kbUnitGetCentroid(cUnitTypeLogicalTypeLandMilitary)); } aiPlanSetVariableFloat(gLandPatrolPlan, cDefendPlanEngageRange, 0, cvDefenseReflexRadiusPassive); aiPlanSetRequiresAllNeedUnits(gLandPatrolPlan, true); aiPlanSetVariableFloat(gLandPatrolPlan, cDefendPlanGatherDistance, 0, cvDefenseReflexRadiusPassive - 10.0); aiPlanSetInitialPosition(gLandPatrolPlan, kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID))); aiPlanSetUnitStance(gLandPatrolPlan, cUnitStanceAggressive); aiPlanSetVariableInt(gLandPatrolPlan, cDefendPlanRefreshFrequency, 0, 5); aiPlanSetVariableInt(gLandPatrolPlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit); aiPlanSetDesiredPriority(gLandPatrolPlan, 100); aiPlanSetActive(gLandPatrolPlan); aiEcho("CampaignCore: --- RMUpdate_CreatelandPatrol: count[" + val + "]"); xsEnableRule("BeginLandPatrol"); } } //------------------------------------------------------------------- void RMUpdate_CreateNavalPatrol(int val = 0) { if ( val > 0 ) { gNavalPatrolPlan = aiPlanCreate("Naval Patrol", cPlanDefend); int units = val; int curNaval = kbUnitCount(cMyID, gNavalMilitaryUnitType, cUnitStateAlive); int maxNaval = gTriremeCount + curNaval; if (units > maxNaval) { // if we are asking for a higher count than we intended to support, reduce units units = maxNaval; } aiPlanAddUnitType(gNavalPatrolPlan, cUnitTypeAbstractWarShip, units, units, gTriremeCount); aiPlanAddUnitType(gNavalPatrolPlan, cUnitTypeUnitTypeShipSiege1, units, units, gFireshipCount); aiPlanAddUnitType(gNavalPatrolPlan, cUnitTypeUnitTypeShipAntiShip1, units, units, gSiegeshipCount); aiPlanSetVariableVector(gNavalPatrolPlan, cDefendPlanDefendPoint, 0, gNavyVec); aiPlanSetVariableFloat(gNavalPatrolPlan, cDefendPlanEngageRange, 0, cvDefenseReflexRadiusPassive); aiPlanSetRequiresAllNeedUnits(gNavalPatrolPlan, true); aiPlanSetVariableFloat(gNavalPatrolPlan, cDefendPlanGatherDistance, 0, cvDefenseReflexRadiusPassive - 10.0); aiPlanSetInitialPosition(gNavalPatrolPlan, gNavyVec); aiPlanSetUnitStance(gNavalPatrolPlan, cUnitStanceAggressive); aiPlanSetVariableInt(gNavalPatrolPlan, cDefendPlanRefreshFrequency, 0, 5); aiPlanSetVariableInt(gNavalPatrolPlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit); aiPlanSetDesiredPriority(gNavalPatrolPlan, 100); aiPlanSetActive(gNavalPatrolPlan); aiEcho("CampaignCore: --- RMUpdate_CreateNavalPatrol: max[" + maxNaval + "] desired[" + val + "] adjusted[" + units + "]"); xsEnableRule("BeginNavalPatrol"); } } //------------------------------------------------------------------- void RMUpdate_IncreaseBaseScale(int val = 0) { if ( val > 0 ) { // support up to three tiers of base scale, no more if ( val > 3 ) { val = 3; } gTCNearTCMin = 40.0 + (30.0 * val);//60/90/120 (campaign orginal - 50.0) gHouseNearTCMin = 10.0 + (10.0 * val);//20/30/40 (campaign orginal - 15.0) gHouseNearTCMax = 20.0 + (20.0 * val);//40/60/80 (campaign orginal - 30.0) gBuildingNearTCMin = 20.0 + (30.0 * val);//50/80/110 (campaign orginal - 40.0) gMarketNearMainBaseMin = 80.0 + (20.0 * val);//100/120/140 (campaign orginal - 90.0) aiEcho("CampaignCore: --- RMUpdate_IncreaseBaseScale: gTCNearTCMin[" + gTCNearTCMin + "]"); aiEcho("CampaignCore: --- RMUpdate_IncreaseBaseScale: gHouseNearTCMin[" + gHouseNearTCMin + "]"); aiEcho("CampaignCore: --- RMUpdate_IncreaseBaseScale: gHouseNearTCMax[" + gHouseNearTCMax + "]"); aiEcho("CampaignCore: --- RMUpdate_IncreaseBaseScale: gBuildingNearTCMin[" + gBuildingNearTCMin + "]"); aiEcho("CampaignCore: --- RMUpdate_IncreaseBaseScale: gMarketNearMainBaseMin[" + gMarketNearMainBaseMin + "]"); } } //------------------------------------------------------------------- rule SetBuildUpdateMaxAge active minInterval 3 { int curCiv = kbGetCiv(); //-------------------------------- if (cvMaxAge == cAge4) { // if the max age is Age 4, assume that this is a default // and determine the max age possible for the current character if (gAge4Building > -1 || kbTechGetStatus(gAge4Tech) == cTechStatusObtainable) {BuildUpdateMaxAge = cAge4;} else if (gAge3Building > -1 || kbTechGetStatus(gAge3Tech) == cTechStatusObtainable) {BuildUpdateMaxAge = cAge3;} else if (gAge2Building > -1 || kbTechGetStatus(gAge2Tech) == cTechStatusObtainable) {BuildUpdateMaxAge = cAge2;} } else { // if the max age is not Age 4, assume that this was an intentional setting // and force the value of BuildUpdateMaxAge to correspond BuildUpdateMaxAge = cvMaxAge; } aiEcho("CampaignCore: --- SetBuildUpdateMaxAge[Age" + (BuildUpdateMaxAge+1) + "]"); xsDisableSelf(); } //------------------------------------------------------------------- void setupBuildingInfo() { int currentAge = kbGetAge(); // run this function if we are not at max age OR if we are at max age allow it to run several times before calling it done if (currentAge > BuildUpdateLastAge) { BuildUpdateLastAge = currentAge; BuildUpdateCount = 1; } else if ( (currentAge >= BuildUpdateMaxAge) && (BuildUpdateCount >= BuildUpdateCountMax) ) { aiEcho("CampaignCore: --- setupBuildingInfo: MAX REACHED: [Age" + (currentAge+1) + "] count[" + BuildUpdateCount + "]"); xsDisableRule("updateBuildingInfo"); return; } else { BuildUpdateCount = BuildUpdateCount + 1; } // Create arrays if needed initializeAndClearBuildingArrays(); int bt = 0; int count = 0; int offset = 0; int currentVillCount = kbUnitCount(cMyID, gEconUnit, cUnitStateAlive); aiEcho("CampaignCore: --- setupBuildingInfo CONTINUE: CurAge[Age" + (currentAge+1) + "] MaxAge[Age" + (BuildUpdateMaxAge+1) + "] count[" + BuildUpdateCount + "] vil[" + currentVillCount + "]"); switch (currentAge) { case cAge1: { if (bAllowFactory_INF01) { bt = kbFindBuilding(FactoryType_INF01); count = 1; offset = addBuildingToList(bt, count, cEconomyEscrowID, BuildStage_INF01, true, offset); } if (bAllowTCBuild && bAllowTCAge1) { bt = kbFindBuilding(cUnitTypeUnitTypeBldgTownCenter); count = 1; offset = addBuildingToList(bt, count, cEconomyEscrowID, BuildStage_TC1, true, offset); } break; } case cAge2: { if(bAllowFactory_INF01) { bt = kbFindBuilding(FactoryType_INF01); count = currentVillCount / (20 - (btBiasINF * 5) - btStrengthATK); if (count < 1) { count = 1; } offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_INF01, true, offset); } if(bAllowFactory_ARC01) { bt = kbFindBuilding(FactoryType_ARC01); count = currentVillCount / (21 - (btBiasARC * 5) - btStrengthATK); if (count < 1) { count = 1; } offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_ARC01, true, offset); } if(bAllowFactory_CAV01) { bt = kbFindBuilding(FactoryType_CAV01); count = currentVillCount / (22 - (btBiasCAV * 5) - btStrengthATK); if (count < 1) { count = 1; } offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_CAV01, true, offset); } if (bAllowMKT) { bt = kbFindBuilding(cUnitTypeUnitTypeBldgMarket); count = 1; offset = addBuildingToList(bt, count, cEconomyEscrowID, BuildStage_MKT, true, offset); } if (bAllowARM) { bt = kbFindBuilding(cUnitTypeUnitTypeBldgArmory); count = 1; offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_ARM, true, offset); } if (bAllowGRV) { bt = kbFindBuilding(cUnitTypeUnitTypeBldgTemple); count = 1; offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_GRV, true, offset); } if (bAllowTCBuild && bAllowTCAge2) { bt = kbFindBuilding(cUnitTypeUnitTypeBldgTownCenter); count = 2; offset = addBuildingToList(bt, count, cEconomyEscrowID, BuildStage_TC2, true, offset); } break; } default: { if(bAllowFactory_INF01) { bt = kbFindBuilding(FactoryType_INF01); count = currentVillCount / (20 - (btBiasINF * 5) - btStrengthATK); if (count < 1) { count = 1; } offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_INF01, true, offset); } if(bAllowFactory_INF02) { bt = kbFindBuilding(FactoryType_INF02); count = currentVillCount / (20 - (btBiasINF * 5) - btStrengthATK); if (count < 1) { count = 1; } offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_INF02, true, offset); } if(bAllowFactory_ARC01) { bt = kbFindBuilding(FactoryType_ARC01); count = currentVillCount / (21 - (btBiasARC * 5) - btStrengthATK); if (count < 1) { count = 1; } offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_ARC01, true, offset); } if(bAllowFactory_CAV01) { bt = kbFindBuilding(FactoryType_CAV01); count = currentVillCount / (22 - (btBiasCAV * 5) - btStrengthATK); if (count < 1) { count = 1; } offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_CAV01, true, offset); } if(bAllowFactory_SIE01) { bt = kbFindBuilding(FactoryType_SIE01); count = currentVillCount / (25 - (btBiasSIE * 5) - btStrengthATK); offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_SIE01, true, offset); } if(bAllowFactory_SPC01) { bt = kbFindBuilding(FactoryType_SPC01); count = currentVillCount / (25 - (btBiasSPC * 5) - btStrengthATK); offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_SPC01, true, offset); } if (bAllowMKT) { bt = kbFindBuilding(cUnitTypeUnitTypeBldgMarket); count = 1; offset = addBuildingToList(bt, count, cEconomyEscrowID, BuildStage_MKT, true, offset); } if (bAllowARM) { bt = kbFindBuilding(cUnitTypeUnitTypeBldgArmory); count = 1; offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_ARM, true, offset); } if (bAllowGRV) { bt = kbFindBuilding(cUnitTypeUnitTypeBldgTemple); count = 1; offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_GRV, true, offset); } if (bAllowHAL) { bt = kbFindBuilding(cUnitTypeUnitTypeBldgAcademy); count = 1; offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_HAL, true, offset); } if (bAllowFRT) { bt = kbFindBuilding(cUnitTypeUnitTypeBldgFortress); count = MaxFortCount; offset = addBuildingToList(bt, count, cMilitaryEscrowID, BuildStage_FRT, true, offset); } if (bAllowTCBuild && bAllowTCAge3) { bt = kbFindBuilding(cUnitTypeUnitTypeBldgTownCenter); count = MaxTCCount; offset = addBuildingToList(bt, count, cEconomyEscrowID, BuildStage_TC3, true, offset); } break; } } } //------------------------------------------------------------------- // Updates the unit picker biases void setUnitPickerPreference(int upID = -1) { if (upID < 0) return; kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, btBiasINF); kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, btBiasARC); kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, btBiasCAV); kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArtillery, btBiasSIE); kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractPriest, btBiasSPC); // ensure that priests are considered for attack planning kbUnitPickSetDefaultCombatEfficiency(upID, cUnitTypeAbstractPriest, btBiasSPC); // if required, restrict Age4 Siege from ever being considered if (bAllowAge4Siege == false) { kbUnitPickSetPreferenceFactor(upID, cUnitTypeUnitTypeSiegeTrebuchet1, 0); kbUnitPickSetPreferenceFactor(upID, cUnitTypeUnitTypeSiegeBallista1, 0); kbUnitPickSetPreferenceFactor(upID, cUnitTypeUnitTypeShipSiege1, 0); // unless we are greek, restrict catapults as well if(kbGetCiv() != gGreekCivID) { kbUnitPickSetPreferenceFactor(upID, cUnitTypeUnitTypeSiegeCatapult1, 0); } } else if ( (btBiasSIE > 0.6) && (PlayerLevel >= 20) && (kbGetAge() == cAge4) ) { // go ahead and give some extra value to age 4 land siege kbUnitPickSetDefaultCombatEfficiency(upID, cUnitTypeUnitTypeSiegeTrebuchet1, 2.1*btBiasSIE); kbUnitPickSetDefaultCombatEfficiency(upID, cUnitTypeUnitTypeSiegeBallista1, 2.1*btBiasSIE); // unless we are greek, boost catapults as well if(kbGetCiv() != gGreekCivID) { kbUnitPickSetDefaultCombatEfficiency(upID, cUnitTypeUnitTypeSiegeCatapult1, 2.1*btBiasSIE); } } } //------------------------------------------------------------------- // override the default food plan management void updateFoodPlans() { if (bEnableEconEcho) { aiEcho("CampaignCore: --- updateFoodPlans..."); } //-------------------------------- // setup several key tracking values const int cMaxSettlersPerPlan = 8; // max villagers that will be used per plan const int cMinSettlersPerPlan = 2; // Must be much less than Max/2 to avoid thrashing static int totalFoodPlans = 0; // How many are currently requested? Try to avoid thrashing this number // Final plan numbers int easyFoodPlans = 0; int herdFoodPlans = 0; int huntFoodPlans = 0; int farmFoodPlans = 0; // basic count of villagers and farms int numVills = kbUnitCount(cMyID, gEconUnit, cUnitStateAlive); int numFarms = kbUnitCount(cMyID, gFarmUnit, cUnitStateABQ); // set the gatherer count // Round to the closest villager instead of truncating float floatVills = numVills; int numGatherers = (floatVills * aiGetResourceGathererPercentage(cResourceFood)) + 0.5; int MainBaseID = kbBaseGetMainID(cMyID); //-------------------------------- // first allocate villagers to any farms, fill all farms if possible farmFoodPlans = numFarms; if (numFarms > numGatherers) { farmFoodPlans = numGatherers; } if (bEnableEconEcho) { aiEcho("---------- VILS: Total[" + numVills + "] Gathering[" + numGatherers + "]"); aiEcho("---------- FARMS: Total[" + numFarms + "] Used[" + farmFoodPlans + "] Max[" + gMaxFarms + "]"); aiEcho("---------- MAIN BASE: ID[" + MainBaseID + "] LOC[" + kbBaseGetLocation(cMyID, MainBaseID) + "]"); } // update the gatherer count numGatherers = numGatherers - farmFoodPlans; //-------------------------------- // now allocate the remaining villagers to other tasks, as needed if (numGatherers > 0) { int HerdFoodNear = kbGetAmountValidResources(MainBaseID, cResourceFood, cAIResourceSubTypeHerdable, 20.0); int EasyFoodNear = kbGetAmountValidResources(MainBaseID, cResourceFood, cAIResourceSubTypeEasy, 30.0); int EasyFoodFar = kbGetAmountValidResources(MainBaseID, cResourceFood, cAIResourceSubTypeEasy, 60.0); int HuntFoodFar = kbGetAmountValidResources(MainBaseID, cResourceFood, cAIResourceSubTypeHunt, 60.0); if (bEnableEconEcho) { aiEcho("---------- RESOURCES: HerdN[" + HerdFoodNear + "] EasyN[" + EasyFoodNear + "] EasyF[" + EasyFoodFar + "] HuntF[" + HuntFoodFar + "]"); } // Figure out how many plans we should have int otherPlans = totalFoodPlans - farmFoodPlans; if (otherPlans < 1) { otherPlans = 1; } // Too many plans, not enough gatherers while ( (numGatherers / otherPlans) < cMinSettlersPerPlan ) { otherPlans = otherPlans - 1; } // Too many gatherers, not enough plans while ( (numGatherers / otherPlans) > cMaxSettlersPerPlan ) { otherPlans = otherPlans + 1; } totalFoodPlans = otherPlans + farmFoodPlans; //-------------------------------- // check if we have herdables to gather from if (otherPlans > 0 && HerdFoodNear > 0) { // set all gatherers to herding herdFoodPlans = otherPlans; // update available plan count otherPlans = 0; } //-------------------------------- // See if we have any "easy" food nearby if (otherPlans > 0 && EasyFoodNear > 0) { if(otherPlans > 1) { easyFoodPlans = otherPlans / 2; } else { easyFoodPlans = otherPlans; } // update available plan count otherPlans = otherPlans - easyFoodPlans; } //-------------------------------- // Nope, see if we have any huntable food nearby if (otherPlans > 0 && HuntFoodFar > 0) { if (kbGetAge() > cAge2 && otherPlans > 1) { //Age 3 and 4 we cap at 1 hunting group huntFoodPlans = 1; } else if (kbGetAge() == cAge2 && otherPlans > 2) { //Age 2 we cap at 2 hunting groups huntFoodPlans = 2; } else { huntFoodPlans = otherPlans; } // update available plan count otherPlans = otherPlans - huntFoodPlans; } //-------------------------------- // if no plans were made yet, go ahead and use the farther away easy food if (otherPlans > 0 && EasyFoodFar > 0) { // if we are still Age1, set all remaining gatherers to easy food // otherwise just leave one plan for the father away food if (kbGetAge() == cAge1) { easyFoodPlans = otherPlans; } else { easyFoodPlans = easyFoodPlans + 1; } // update available plan count otherPlans = otherPlans - easyFoodPlans; } //-------------------------------- // if there are still available plans, and we are past Age1, build farms if more are needed if ( cvOkToBuildFarms && (otherPlans > 0) && (kbGetAge() > cAge1) && (numFarms < gMaxFarms) ) { // Make sure we don't already have a farm queued int planID = aiPlanGetIDByTypeAndVariableType(cPlanBuild, cBuildPlanBuildingTypeID, gFarmUnit); //We only want to build farms for villagers we are not hunting with. int calcFarms = numGatherers - numFarms - ( (huntFoodPlans + easyFoodPlans + herdFoodPlans) * cMaxSettlersPerPlan ); if ( (planID == -1) && (calcFarms > 0) ) { // SEM: Borrow from the emergency escrow if we're under 5 farms // This stops greedy military escrow from hogging all the wood while simultaneously starving if (numFarms < 5) createSimpleBuildPlan(gFarmUnit, calcFarms, 90, true, cEmergencyEscrowID, MainBaseID, 1); else createSimpleBuildPlan(gFarmUnit, calcFarms, 90, true, cEconomyEscrowID, MainBaseID, 1); } } } if (bEnableEconEcho) { aiEcho("---------- PLANS: Easy[" + easyFoodPlans + "] Herd[" + herdFoodPlans + "] Hunt[" + huntFoodPlans + "] Farm[" + farmFoodPlans + "]"); } aiSetResourceBreakdown( cResourceFood, cAIResourceSubTypeEasy, easyFoodPlans, 79, 1.0, MainBaseID ); aiSetResourceBreakdown( cResourceFood, cAIResourceSubTypeHerdable, herdFoodPlans, 82, 1.0, MainBaseID ); aiSetResourceBreakdown( cResourceFood, cAIResourceSubTypeHunt, huntFoodPlans, 51, 1.0, MainBaseID ); aiSetResourceBreakdown( cResourceFood, cAIResourceSubTypeFarm, farmFoodPlans, 81, 1.0, MainBaseID ); aiSetResourceBreakdown( cResourceFood, cAIResourceSubTypeHuntAggressive, 0, 79, 0.0, MainBaseID ); aiSetResourceBreakdown( cResourceFood, cAIResourceSubTypeFish, 0, 79, 0.0, MainBaseID ); }