home *** CD-ROM | disk | FTP | other *** search
/ The Games Machine 8 (DVD) / XENIADVD08.iso / Fragzone / Files / AOM_MiniCampaign.exe / AI / aomMKai.xs next >
Encoding:
Text File  |  2003-01-14  |  152.1 KB  |  4,086 lines

  1. //==============================================================================
  2. // aomMKai.xs
  3. //
  4. //This is the default AOM AI script code for Computer Player AI players.
  5. //==============================================================================
  6.  
  7.  
  8. //==============================================================================
  9. //The first part of this file is just a long list of global variables.  The
  10. //'extern' keyword allows them to be used in any of the included files.  These
  11. //are here to facilitate information sharing, etc.  The global variables are
  12. //attempted to be named appropriately, but you should take a look at how they are
  13. //used before making any assumptions about their actual utility.
  14.  
  15.  
  16. //==============================================================================
  17. //Map-Related Globals.
  18. extern bool gWaterMap=false;
  19.  
  20. //==============================================================================
  21. //Escrow stuff.
  22. extern int gEconomyUnitEscrowID=-1;
  23. extern int gEconomyTechEscrowID=-1;
  24. extern int gEconomyBuildingEscrowID=-1;
  25. extern int gMilitaryUnitEscrowID=-1;
  26. extern int gMilitaryTechEscrowID=-1;
  27. extern int gMilitaryBuildingEscrowID=-1;
  28.  
  29. //==============================================================================
  30. //Housing & PopCap.
  31. extern int gHouseBuildLimit=-1;
  32. extern int gHouseAvailablePopRebuild=10;
  33. extern int gBuildersPerHouse=1;
  34. extern int gHardEconomyPopCap=-1;
  35.  
  36. //==============================================================================
  37. //Econ Globals.
  38. extern int   gGatherGoalPlanID=-1;
  39. extern int   gCivPopPlanID=-1;
  40. extern int   gNumBoatsToMaintain=6;
  41. extern int   gAgeToStartFarming=2;
  42. //AgeCapHouses.  True caps the number of houses by age (if you're using the econ's house rule).
  43. extern bool  gAgeCapHouses=true;
  44. extern float gMaxFoodImbalance=1500.0;
  45. extern float gMaxWoodImbalance=1500.0;
  46. extern float gMaxGoldImbalance=1500.0;
  47. extern float gMinWoodMarketSellCost=20.0;
  48. extern float gMinFoodMarketSellCost=20.0;
  49. extern int   gMaxTradeCarts=5;
  50.  
  51. //==============================================================================
  52. //Minor Gods.
  53. extern int gAge2MinorGod = -1;
  54. extern int gAge3MinorGod = -1;
  55. extern int gAge4MinorGod = -1;
  56.  
  57.  
  58. //==============================================================================
  59. //God Powers
  60. extern int gAge1GodPowerID = -1;
  61. extern int gAge2GodPowerID = -1;
  62. extern int gAge3GodPowerID = -1;
  63. extern int gAge4GodPowerID = -1;
  64. extern int gAge1GodPowerPlanID = -1;
  65. extern int gAge2GodPowerPlanID = -1;
  66. extern int gAge3GodPowerPlanID = -1;
  67. extern int gAge4GodPowerPlanID = -1;
  68. extern int gTownDefenseGodPowerPlanID = -1;
  69. extern int gTownDefenseEvalModel = -1;
  70. extern int gTownDefensePlayerID = -1;
  71.  
  72. //==============================================================================
  73. //Special Case Stuff
  74. extern int gDwarvenMinePlanID = -1;
  75. extern int gLandScout = -1;
  76. extern int gAirScout = -1;
  77. extern int gWaterScout = -1;
  78. extern int gMaintainNumberLandScouts = 1;
  79. extern int gMaintainNumberAirScouts = 1;
  80. extern int gMaintainNumberWaterScouts = 1;
  81. extern int gEmpowerPlanID = -1;
  82. extern int gRelicGatherPlanID = -1;
  83. extern bool gBuildWalls=false;
  84. extern bool gBuildTowers=false;
  85. extern int gTowerEscrowID=-1;
  86. extern int gLateUPID=-1;
  87. extern int gNavalUPID=-1;
  88. extern int gNavalAttackGoalID=-1;
  89. extern int gRushGoalID=-1;
  90. extern int gLandAttackGoalID=-1;
  91. //extern int gLandRushAttackGoalID=-1;
  92. extern int gMaintainWaterXPortPlanID=-1;
  93. extern int gResignType = -1;
  94. extern int gVinlandsagaTransportExplorePlanID=-1;
  95. extern int gVinlandsagaInitialBaseID=-1;
  96. extern int gNomadExplorePlanID=-1;
  97. extern int gKOTHPlentyUnitID=-1;
  98. extern int gDwarfMaintainPlanID=-1;
  99. extern int gLandExplorePlanID=-1;
  100. extern int gFarmBaseID = -1;
  101. //==============================================================================
  102. // tracking expansion
  103. extern int gTrackingPlayer = -1;
  104. extern int gNumberTrackedPlayerSettlements=-1;
  105. extern int gNumberMySettlements=-1;
  106.  
  107. //==============================================================================
  108. //Base Globals.
  109. extern int gGoldBaseID=-1;
  110. extern float gMaximumBaseResourceDistance=100.0;
  111.  
  112. //==============================================================================
  113. //Age Progression Plan IDs.
  114. extern int gAge2ProgressionPlanID = -1;
  115. extern int gAge3ProgressionPlanID = -1;
  116. extern int gAge4ProgressionPlanID = -1;
  117.  
  118. //==============================================================================
  119. //Forward declarations.
  120. //==============================================================================
  121. mutable void setOverrides(void) {}
  122. mutable void setParameters(void) {}
  123. mutable void age2Handler(int age=1) { }
  124. mutable void age3Handler(int age=2) { }
  125. mutable void age4Handler(int age=3) { }
  126. mutable void towerInBase( string planName="BUG", bool los = true, int numTowers = 6, int escrowID=-1 ) { }
  127. mutable int createSimpleMaintainPlan(int puid=-1, int number=1, bool economy=true, int baseID=-1) { }
  128. mutable bool createSimpleBuildPlan(int puid=-1, int number=1, int pri=100,
  129.    bool military=false, bool economy=true, int escrowID=-1, int baseID=-1, int numberBuilders=1) { }
  130. mutable void buildHandler(int protoID=-1) { }
  131. mutable void gpHandler(int powerID=-1)    { }
  132. mutable void wonderDeathHandler(int playerID=-1) { }
  133. mutable void retreatHandler(int planID=-1) {}
  134. mutable void relicHandler(int relicID=-1) {}
  135. mutable int createBuildSettlementGoal(string name="BUG", int minAge=-1, int maxAge=-1, int baseID=-1, int numberUnits=1, int builderUnitTypeID=-1, bool autoUpdate=true, int pri=90) { }
  136.  
  137.  
  138. //==============================================================================
  139. //Economy Include.
  140. //-- The Econ module needs to define these things:
  141. // void econAge2Handler( int age = 0 )
  142. // void econAge3Handler( int age = 0 )
  143. // void econAge4Handler( int age = 0 )
  144. // void initEcon()
  145. include "aomMKaiEconomy.xs";
  146.  
  147. //==============================================================================
  148. //Progress Include.
  149. //-- The Progress module needs to define these things:
  150. // void progressAge2Handler( int age = 0 )
  151. // void progressAge3Handler( int age = 0 )
  152. // void progressAge4Handler( int age = 0 )
  153. // void initProgress()
  154. include "aomMKaiProgress.xs";
  155.  
  156. //==============================================================================
  157. //Military Include.
  158. include "aomMKaiMilitary.xs";
  159.  
  160. //==============================================================================
  161. //God Powers Include.
  162. //-- The GP module needs to define these things:
  163. // void gpAge2Handler( int age = 0 )
  164. // void gpAge3Handler( int age = 0 )
  165. // void gpAge4Handler( int age = 0 )
  166. // void initGodPowers()
  167. include "aomMKaiGodPowers.xs";
  168.  
  169.  
  170.  
  171. //==============================================================================
  172. // RULE: updatePlayerToAttack.  Updates the player we should be attacking.
  173. //==============================================================================
  174. rule updatePlayerToAttack
  175.    minInterval 27
  176.    group AttackRules
  177.    active
  178.    runImmediately
  179. {
  180.    //Determine a random start index for our hate loop.
  181.    static int startIndex=-1;
  182.    if (startIndex < 0)
  183.       startIndex=aiRandInt(cNumberPlayers);
  184.  
  185.    //Find the "first" enemy player that's still in the game.  This will be the
  186.    //script's recommendation for who we should attack.
  187.    int comparePlayerID=-1;
  188.    for (i=0; < cNumberPlayers)
  189.    {
  190.       //If we're past the end of our players, go back to the start.
  191.       int actualIndex=i+startIndex;
  192.       if (actualIndex >= cNumberPlayers)
  193.          actualIndex=actualIndex-cNumberPlayers;
  194.       if (actualIndex <= 0)
  195.          continue;
  196.       if ((kbIsPlayerEnemy(actualIndex) == true) &&
  197.          (kbIsPlayerResigned(actualIndex) == false) &&
  198.          (kbHasPlayerLost(actualIndex) == false))
  199.       {
  200.          comparePlayerID=actualIndex;
  201.          break;
  202.       }
  203.    }
  204.  
  205.    //Pass the comparePlayerID into the AI to see what he thinks.  He'll take care
  206.    //of modifying the player in the event of wonders, etc.
  207.    int actualPlayerID=aiCalculateMostHatedPlayerID(comparePlayerID);
  208.  
  209.    //Default us off.
  210.    aiSetMostHatedPlayerID(actualPlayerID);
  211. }
  212.  
  213. //==============================================================================
  214. // setTownLocation
  215. //==============================================================================
  216. void setTownLocation(void)
  217. {
  218.    static int tcQueryID=-1;
  219.    //If we don't have a query ID, create it.
  220.    if (tcQueryID < 0)
  221.    {
  222.       tcQueryID=kbUnitQueryCreate("TownLocationQuery");
  223.       //If we still don't have one, bail.
  224.       if (tcQueryID < 0)
  225.          return;
  226.       //Else, setup the query data.
  227.       kbUnitQuerySetPlayerID(tcQueryID, cMyID);
  228.       kbUnitQuerySetUnitType(tcQueryID, cUnitTypeAbstractSettlement);
  229.       kbUnitQuerySetState(tcQueryID, cUnitStateAlive);
  230.    }
  231.  
  232.    //Reset the results.
  233.    kbUnitQueryResetResults(tcQueryID);
  234.    //Run the query.  Be dumb and just take the first TC for now.
  235.    if (kbUnitQueryExecute(tcQueryID) > 0)
  236.    {
  237.       int tcID=kbUnitQueryGetResult(tcQueryID, 0);
  238.       kbSetTownLocation(kbUnitGetPosition(tcID));
  239.    }
  240. }
  241.  
  242. //==============================================================================
  243. //createSimpleMaintainPlan
  244. //==============================================================================
  245. int createSimpleMaintainPlan(int puid=-1, int number=1, bool economy=true, int baseID=-1)
  246. {
  247.    //Create a the plan name.
  248.    string planName="Military";
  249.    if (economy == true)
  250.       planName="Economy";
  251.    planName=planName+kbGetProtoUnitName(puid)+"Maintain";
  252.    int planID=aiPlanCreate(planName, cPlanTrain);
  253.    if (planID < 0)
  254.       return(-1);
  255.  
  256.    //Economy or Military.
  257.    if (economy == true)
  258.       aiPlanSetEconomy(planID, true);
  259.    else
  260.       aiPlanSetMilitary(planID, true);
  261.    //Unit type.
  262.    aiPlanSetVariableInt(planID, cTrainPlanUnitType, 0, puid);
  263.    //Number.
  264.    aiPlanSetVariableInt(planID, cTrainPlanNumberToMaintain, 0, number);
  265.  
  266.    //If we have a base ID, use it.
  267.    if (baseID >= 0)
  268.    {
  269.       aiPlanSetBaseID(planID, baseID);
  270.       if  (economy == false)
  271.          aiPlanSetVariableVector(planID, cTrainPlanGatherPoint, 0, kbBaseGetMilitaryGatherPoint(cMyID, baseID));
  272.    }
  273.  
  274.    aiPlanSetActive(planID);
  275.  
  276.    //Done.
  277.    return(planID);
  278. }
  279.  
  280. //==============================================================================
  281. //createSimpleBuildPlan
  282. //==============================================================================
  283. bool createSimpleBuildPlan(int puid=-1, int number=1, int pri=100,
  284.    bool military=false, bool economy=true, int escrowID=-1, int baseID=-1, int numberBuilders=1)
  285. {
  286.    //Create the right number of plans.
  287.    for (i=0; < number)
  288.    {
  289.        int planID=aiPlanCreate("SimpleBuild"+kbGetUnitTypeName(puid)+" "+number, cPlanBuild);
  290.       if (planID < 0)
  291.          return(false);
  292.       //Puid.
  293.       aiPlanSetVariableInt(planID, cBuildPlanBuildingTypeID, 0, puid);
  294.       //Border layers.
  295.        aiPlanSetVariableInt(planID, cBuildPlanNumAreaBorderLayers, 2, kbAreaGetIDByPosition(kbBaseGetLocation(cMyID, baseID)) );
  296.       //Priority.
  297.       aiPlanSetDesiredPriority(planID, pri);
  298.       //Mil vs. Econ.
  299.       aiPlanSetMilitary(planID, military);
  300.       aiPlanSetEconomy(planID, economy);
  301.       //Escrow.
  302.       aiPlanSetEscrowID(planID, escrowID);
  303.       //Builders.
  304.        aiPlanAddUnitType(planID, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0),
  305.          numberBuilders, numberBuilders, numberBuilders);
  306.       //Base ID.
  307.       aiPlanSetBaseID(planID, baseID);
  308.       //Go.
  309.       aiPlanSetActive(planID);
  310.    }
  311. }
  312.  
  313. //==============================================================================
  314. // updateEM
  315. //==============================================================================
  316. void updateEM(int econPop=-1, int milPop=-1, float econPercentage=0.5,
  317.    float rootEscrow=0.2, float econFoodEscrow=0.5, float econWoodEscrow=0.5,
  318.    float econGoldEscrow=0.5, float econFavorEscrow=0.5)
  319. {
  320.    //Econ Pop (if we're allowed to change it).
  321.    if ((gHardEconomyPopCap > 0) && (econPop > gHardEconomyPopCap))
  322.       econPop=gHardEconomyPopCap;
  323.    aiSetEconomyPop(econPop);
  324.    aiSetMilitaryPop(milPop);
  325.  
  326.    //Percentages.
  327.    aiSetEconomyPercentage(econPercentage);
  328.    aiSetMilitaryPercentage(1.0-econPercentage);
  329.  
  330.    //Get the amount of the non-root pie.
  331.    float nonRootEscrow=1.0-rootEscrow;
  332.    //Track whether or not we need to redistribute the resources.
  333.    bool redistResources=false;
  334.    //Econ Food Escrow.
  335.    float v=nonRootEscrow*econFoodEscrow;
  336.    if (v != kbEscrowGetPercentage(cEconomyEscrowID, cResourceFood))
  337.       redistResources=true;
  338.    kbEscrowSetPercentage(cEconomyEscrowID, cResourceFood, v);
  339.    //Econ Wood Escrow
  340.    v=nonRootEscrow*econWoodEscrow;
  341.    if (v != kbEscrowGetPercentage(cEconomyEscrowID, cResourceWood))
  342.       redistResources=true;
  343.    kbEscrowSetPercentage(cEconomyEscrowID, cResourceWood, v);
  344.    //Econ Gold Escrow
  345.    v=nonRootEscrow*econGoldEscrow;
  346.    if (v != kbEscrowGetPercentage(cEconomyEscrowID, cResourceGold))
  347.       redistResources=true;
  348.    kbEscrowSetPercentage(cEconomyEscrowID, cResourceGold, v);
  349.    //Econ Favor Escrow
  350.    v=nonRootEscrow*econFavorEscrow;
  351.    if (v != kbEscrowGetPercentage(cEconomyEscrowID, cResourceFavor))
  352.       redistResources=true;
  353.    kbEscrowSetPercentage(cEconomyEscrowID, cResourceFavor, v);
  354.    //Military Escrow.
  355.    kbEscrowSetPercentage(cMilitaryEscrowID, cResourceFood, nonRootEscrow*(1.0-econFoodEscrow));
  356.    kbEscrowSetPercentage(cMilitaryEscrowID, cResourceWood, nonRootEscrow*(1.0-econWoodEscrow));
  357.    kbEscrowSetPercentage(cMilitaryEscrowID, cResourceGold, nonRootEscrow*(1.0-econGoldEscrow));
  358.    kbEscrowSetPercentage(cMilitaryEscrowID, cResourceFavor, nonRootEscrow*(1.0-econFavorEscrow));
  359.    //Distribute the resources we have (if we need to because we've changed
  360.    //the percentages).
  361.    if (redistResources == true)
  362.       kbEscrowAllocateCurrentResources();
  363.  
  364.    //Update the number of vils to maintain.
  365.    aiPlanSetVariableInt(gCivPopPlanID, cTrainPlanNumberToMaintain, 0, aiGetEconomyPop());
  366. }
  367.  
  368. //==============================================================================
  369. // updateEMAge1
  370. //==============================================================================
  371. rule updateEMAge1
  372.    minInterval 12
  373.    active
  374. {
  375.    static int ePopAdd=-1;
  376.    static int mPopAdd=-1;
  377.    if (ePopAdd < 0)
  378.    {
  379.       if (aiGetWorldDifficulty() == cDifficultyEasy)
  380.       {
  381.          ePopAdd=aiRandInt(2);
  382.          mPopAdd=0;
  383.       }
  384.       else if (aiGetWorldDifficulty() == cDifficultyModerate)
  385.       {
  386.          ePopAdd=aiRandInt(3);
  387.          mPopAdd=aiRandInt(2);
  388.       }
  389.       else if (aiGetWorldDifficulty() == cDifficultyHard)
  390.       {
  391.          ePopAdd=aiRandInt(4);
  392.          mPopAdd=aiRandInt(4);
  393.       }
  394.       else
  395.       {
  396.          ePopAdd=aiRandInt(5);
  397.          mPopAdd=aiRandInt(10);
  398.       }
  399.    }
  400.  
  401.    //All econ in the first age.
  402.    if (aiGetWorldDifficulty() == cDifficultyEasy)
  403.       updateEM(12+ePopAdd, 7+mPopAdd, 1.0, 0.6, 1.0, 1.0, 1.0, 1.0);
  404.    else if (aiGetWorldDifficulty() == cDifficultyModerate)
  405.       updateEM(15+ePopAdd, 19+mPopAdd, 1.0, 0.6, 1.0, 1.0, 1.0, 1.0);
  406.    else if (aiGetWorldDifficulty() == cDifficultyHard)
  407.       updateEM(19+ePopAdd, 23+mPopAdd, 1.0, 0.6, 1.0, 1.0, 1.0, 1.0);
  408.    else
  409.       updateEM(13+ePopAdd, 25+mPopAdd, 1.0, 0.6, 1.0, 1.0, 1.0, 1.0);
  410. }
  411.  
  412. //==============================================================================
  413. // updateEMAge2
  414. //==============================================================================
  415. rule updateEMAge2
  416.    minInterval 12
  417.    inactive
  418. {
  419.    static int ePopAdd=-1;
  420.    static int mPopAdd=-1;
  421.    if (ePopAdd < 0)
  422.    {
  423.       if (aiGetWorldDifficulty() == cDifficultyEasy)
  424.       {
  425.          ePopAdd=aiRandInt(2);
  426.          mPopAdd=0;
  427.       }
  428.       else if (aiGetWorldDifficulty() == cDifficultyModerate)
  429.       {
  430.          ePopAdd=aiRandInt(3);
  431.          mPopAdd=aiRandInt(2);
  432.       }
  433.       else if (aiGetWorldDifficulty() == cDifficultyHard)
  434.       {
  435.          ePopAdd=aiRandInt(4);
  436.          mPopAdd=aiRandInt(4);
  437.       }
  438.       else
  439.       {
  440.          ePopAdd=aiRandInt(5);
  441.          mPopAdd=aiRandInt(10);
  442.       }
  443.    }
  444.  
  445.    //Figure out if we have any active attacks.
  446.    int numberAttackGoals=aiGoalGetNumber(cGoalPlanGoalTypeAttack, cPlanStateWorking, true);
  447.    //Setup the econ vs. military.
  448.    if (numberAttackGoals > 0)
  449.    {
  450.       if (aiGetWorldDifficulty() == cDifficultyEasy)
  451.          updateEM(9+ePopAdd, 22+mPopAdd, 0.5, 0.6, 0.4, 0.3, 0.4, 0.15);
  452.       else if (aiGetWorldDifficulty() == cDifficultyModerate)
  453.          updateEM(14+ePopAdd, 36+mPopAdd, 0.5, 0.6, 0.4, 0.3, 0.4, 0.15);
  454.       else if (aiGetWorldDifficulty() == cDifficultyHard)
  455.          updateEM(19+ePopAdd, 49+mPopAdd, 0.5, 0.6, 0.4, 0.3, 0.4, 0.15);
  456.       else
  457.          updateEM(15+ePopAdd, 52+mPopAdd, 0.5, 0.6, 0.4, 0.3, 0.4, 0.15);
  458.    }
  459.    else
  460.    {
  461.       if (aiGetWorldDifficulty() == cDifficultyEasy)
  462.          updateEM(15+ePopAdd, 14+mPopAdd, 0.8, 0.6, 0.9, 0.5, 0.6, 0.2);
  463.       else if (aiGetWorldDifficulty() == cDifficultyModerate)
  464.          updateEM(20+ePopAdd, 28+mPopAdd, 0.8, 0.6, 0.9, 0.5, 0.6, 0.2);
  465.       else if (aiGetWorldDifficulty() == cDifficultyHard)
  466.          updateEM(32+ePopAdd, 36+mPopAdd, 0.8, 0.6, 0.9, 0.5, 0.6, 0.2);
  467.       else
  468.          updateEM(24+ePopAdd, 38+mPopAdd, 0.8, 0.6, 0.9, 0.5, 0.6, 0.2);
  469.    }
  470. }
  471.  
  472. //==============================================================================
  473. // updateEMAge3
  474. //==============================================================================
  475. rule updateEMAge3
  476.    minInterval 12
  477.    inactive
  478. {
  479.    static int ePopAdd=-1;
  480.    static int mPopAdd=-1;
  481.    if (ePopAdd < 0)
  482.    {
  483.       if (aiGetWorldDifficulty() == cDifficultyEasy)
  484.       {
  485.          ePopAdd=aiRandInt(2);
  486.          mPopAdd=0;
  487.       }
  488.       else if (aiGetWorldDifficulty() == cDifficultyModerate)
  489.       {
  490.          ePopAdd=aiRandInt(3);
  491.          mPopAdd=aiRandInt(2);
  492.       }
  493.       else if (aiGetWorldDifficulty() == cDifficultyHard)
  494.       {
  495.          ePopAdd=aiRandInt(4);
  496.          mPopAdd=aiRandInt(7);
  497.       }
  498.       else
  499.       {
  500.          ePopAdd=aiRandInt(5);
  501.          mPopAdd=aiRandInt(10);
  502.       }
  503.    }
  504.  
  505.    //Figure out if we have any active attacks.
  506.    int numberAttackGoals=aiGoalGetNumber(cGoalPlanGoalTypeAttack, cPlanStateWorking, true);
  507.    //Setup the econ vs. military.
  508.    if (numberAttackGoals > 0)
  509.    {
  510.       if (aiGetWorldDifficulty() == cDifficultyEasy)
  511.          updateEM(11+ePopAdd, 29+mPopAdd, 0.3, 0.6, 0.3, 0.2, 0.3, 0.15);
  512.       else if (aiGetWorldDifficulty() == cDifficultyModerate)
  513.          updateEM(33+ePopAdd, 56+mPopAdd, 0.3, 0.6, 0.3, 0.2, 0.3, 0.15);
  514.       else if (aiGetWorldDifficulty() == cDifficultyHard)
  515.          updateEM(47+ePopAdd, 70+mPopAdd, 0.3, 0.6, 0.3, 0.2, 0.3, 0.15);
  516.       else
  517.          updateEM(30+ePopAdd, 72+mPopAdd, 0.3, 0.6, 0.3, 0.2, 0.3, 0.15);
  518.    }
  519.    else
  520.    {
  521.       if (aiGetWorldDifficulty() == cDifficultyEasy)
  522.          updateEM(18+ePopAdd, 40+mPopAdd, 0.5, 0.6, 0.5, 0.5, 0.5, 0.2);
  523.       else if (aiGetWorldDifficulty() == cDifficultyModerate)
  524.          updateEM(38+ePopAdd, 64+mPopAdd, 0.5, 0.6, 0.5, 0.5, 0.5, 0.2);
  525.       else if (aiGetWorldDifficulty() == cDifficultyHard)
  526.          updateEM(47+ePopAdd, 85+mPopAdd, 0.5, 0.6, 0.5, 0.5, 0.5, 0.2);
  527.       else
  528.          updateEM(30+ePopAdd, 88+mPopAdd, 0.5, 0.6, 0.5, 0.5, 0.5, 0.2);
  529.    }
  530. }
  531.  
  532. //==============================================================================
  533. // updateEMAge4
  534. //==============================================================================
  535. rule updateEMAge4
  536.    minInterval 12
  537.    inactive
  538. {
  539.    static int ePopAdd=-1;
  540.    static int mPopAdd=-1;
  541.    if (ePopAdd < 0)
  542.    {
  543.       if (aiGetWorldDifficulty() == cDifficultyEasy)
  544.       {
  545.          ePopAdd=aiRandInt(2);
  546.          mPopAdd=0;
  547.       }
  548.       else if (aiGetWorldDifficulty() == cDifficultyModerate)
  549.       {
  550.          ePopAdd=aiRandInt(3);
  551.          mPopAdd=aiRandInt(2);
  552.       }
  553.       else if (aiGetWorldDifficulty() == cDifficultyHard)
  554.       {
  555.          ePopAdd=aiRandInt(4);
  556.          mPopAdd=aiRandInt(7);
  557.       }
  558.       else
  559.       {
  560.          ePopAdd=aiRandInt(5);
  561.          mPopAdd=aiRandInt(10);
  562.       }
  563.    }
  564.  
  565.    //Setup the econ vs. military.
  566.    if (aiGetWorldDifficulty() == cDifficultyEasy)
  567.       updateEM(28+ePopAdd, 30+mPopAdd, 0.3, 0.4, 0.0, 0.0, 0.0, 0.0);
  568.    else if (aiGetWorldDifficulty() == cDifficultyModerate)
  569.       updateEM(37+ePopAdd, 100+mPopAdd, 0.3, 0.4, 0.0, 0.0, 0.0, 0.0);
  570.    else if (aiGetWorldDifficulty() == cDifficultyHard)
  571.       updateEM(57+ePopAdd, -1, 0.3, 0.4, 0.0, 0.0, 0.0, 0.0);
  572.    else
  573.       updateEM(34+ePopAdd, -1, 0.3, 0.4, 0.0, 0.0, 0.0, 0.0);
  574. }
  575.  
  576. //==============================================================================
  577. //initGreek
  578. //==============================================================================
  579. void initGreek(void)
  580. {
  581.    aiEcho("GREEK Init:");
  582.  
  583.    //Modify our favor need.  A pseudo-hack.
  584.    aiSetFavorNeedModifier(10.0);
  585.  
  586.    //Greek scout types.
  587.    gLandScout=cUnitTypeScout;
  588.    gAirScout=cUnitTypePegasus;
  589.    gWaterScout=cUnitTypeFishingShipGreek;
  590.    //Create the Greek scout plan.
  591.    int exploreID=aiPlanCreate("Explore_SpecialGreek", cPlanExplore);
  592.    if (exploreID >= 0)
  593.    {
  594.       aiPlanAddUnitType(exploreID, cUnitTypeScout, 1, 1, 1);
  595.       aiPlanSetActive(exploreID);
  596.    }
  597.  
  598.    //Zeus.
  599.    if (cMyCiv == cCivZeus)
  600.    {
  601.       //Create a simple plan to maintain 1 water scout.
  602.       if (gWaterMap == true)
  603.          createSimpleMaintainPlan(gWaterScout, gMaintainNumberWaterScouts, true, -1);
  604.  
  605.       //Random Age2 God.
  606.       gAge2MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge2);
  607.       //Get Underworld Passage if we have a water map.  Else, random.
  608.       if (gWaterMap == true)
  609.          gAge3MinorGod=cTechAge3Apollo;
  610.       else
  611.          gAge3MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge3);
  612.       //Get Lightning if we're rushing.  Else, random.
  613.       if (aiGetPersonality() == "defaultRush")
  614.          gAge4MinorGod=cTechAge4Hera;
  615.       else
  616.          gAge4MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge4);
  617.    }
  618.    //Poseidon.
  619.    else if (cMyCiv == cCivPoseidon)
  620.    {
  621.       //Give him the hippocampus as his water scout.
  622.       gWaterScout=cUnitTypeHippocampus;
  623.       aiEcho("Poseidon's water scout is the "+kbGetUnitTypeName(gWaterScout)+".");
  624.  
  625.       //Random Age2 God.
  626.       gAge2MinorGod = kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge2);
  627.       //Random Age3 God.
  628.       gAge3MinorGod = kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge3);
  629.       //Get EQ if we're rushing.  Else, random.
  630.       if (aiGetPersonality() == "defaultRush")
  631.          gAge4MinorGod=cTechAge4Artemis;
  632.       else
  633.          gAge4MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge4);
  634.    }
  635.    //Hades.
  636.    else if (cMyCiv == cCivHades)
  637.    {
  638.       //Create a simple plan to maintain 1 water scout.
  639.       if (gWaterMap == true)
  640.          createSimpleMaintainPlan(gWaterScout, gMaintainNumberWaterScouts, true, -1);
  641.  
  642.       //Random Age2 God.
  643.       gAge2MinorGod = kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge2);
  644.       //Get Underworld Passage if we have a water map.  Else, random.
  645.       if (gWaterMap == true)
  646.          gAge3MinorGod=cTechAge3Apollo;
  647.       else
  648.          gAge3MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge3);
  649.       //Get EQ if we're rushing.  Else, random.
  650.       if (aiGetPersonality() == "defaultRush")
  651.          gAge4MinorGod=cTechAge4Artemis;
  652.       else
  653.          gAge4MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge4);
  654.  
  655.       //Get VOE.
  656.       int voePID=aiPlanCreate("HadesVaultsOfErebus", cPlanProgression);
  657.        if (voePID != 0)
  658.       {
  659.          aiPlanSetVariableInt(voePID, cProgressionPlanGoalTechID, 0, cTechVaultsofErebus);
  660.           aiPlanSetDesiredPriority(voePID, 25);
  661.           aiPlanSetEscrowID(voePID, cEconomyEscrowID);
  662.           aiPlanSetActive(voePID);
  663.       }
  664.    }
  665. }
  666.  
  667. //==============================================================================
  668. //initEgyptian
  669. //==============================================================================
  670. void initEgyptian(void)
  671. {
  672.    aiEcho("EGYPTIAN Init:");
  673.  
  674.    //Create a simple TC empower plan if we're not on Vinlandsaga.
  675.    if ((cRandomMapName != "vinlandsaga") && (cRandomMapName != "team migration"))
  676.    {
  677.       gEmpowerPlanID=aiPlanCreate("Pharaoh Empower", cPlanEmpower);
  678.       if (gEmpowerPlanID >= 0)
  679.       {
  680.          aiPlanSetEconomy(gEmpowerPlanID, true);
  681.          aiPlanAddUnitType(gEmpowerPlanID, cUnitTypePharaoh, 1, 1, 1);
  682.          aiPlanSetVariableInt(gEmpowerPlanID, cEmpowerPlanTargetTypeID, 0, cUnitTypeGranary);
  683.          aiPlanSetActive(gEmpowerPlanID);
  684.       }
  685.    }
  686.  
  687.    //Egyptian scout types.
  688.    gLandScout=cUnitTypePriest;
  689.    gAirScout=-1;
  690.    gWaterScout=cUnitTypeFishingShipEgyptian;
  691.    //Create a simple plan to maintain Priests for land exploration.
  692.    createSimpleMaintainPlan(cUnitTypePriest, gMaintainNumberLandScouts, true, kbBaseGetMainID(cMyID));
  693.    //Create a simple plan to maintain 1 water scout.
  694.    if (gWaterMap == true)
  695.       createSimpleMaintainPlan(gWaterScout, gMaintainNumberWaterScouts, true, -1);
  696.  
  697.    //Turn off auto favor gather.
  698.    aiSetAutoFavorGather(false);
  699.  
  700.    //Set the build limit for Outposts.
  701.    aiSetMaxLOSProtoUnitLimit(4);
  702.  
  703.    //Isis.
  704.    if (cMyCiv == cCivIsis)
  705.    {
  706.       //Random Age2 God.
  707.       gAge2MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge2);
  708.       //Get X if we're rushing, else random.
  709.       if (aiGetPersonality() == "defaultRush")
  710.          gAge3MinorGod=cTechAge3Nephthys;
  711.       else
  712.          gAge3MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge3);
  713.       //Random Age4 God.
  714.       gAge4MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge4);
  715.    }
  716.    //Ra.
  717.    else if (cMyCiv == cCivRa)
  718.    {
  719.       //Get X if we're rushing, else random.
  720.       if (aiGetPersonality() == "defaultRush")
  721.          gAge2MinorGod=cTechAge2Ptah;
  722.       else
  723.          gAge2MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge2);
  724.       //Get X if we're rushing, else random.
  725.       if (aiGetPersonality() == "defaultRush")
  726.          gAge3MinorGod=cTechAge3Hathor;
  727.       else
  728.          gAge3MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge3);
  729.       //Random Age4 God.
  730.       gAge4MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge4);
  731.    }
  732.    //Set.
  733.    else if (cMyCiv == cCivSet)
  734.    {
  735.       //Get X if we're rushing, else random.
  736.       if (aiGetPersonality() == "defaultRush")
  737.          gAge2MinorGod=cTechAge2Anubis;
  738.       else
  739.          gAge2MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge2);
  740.       //Get X if we're rushing, else random.
  741.       if (aiGetPersonality() == "defaultRush")
  742.          gAge3MinorGod=cTechAge3Nephthys;
  743.       else
  744.          gAge3MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge3);
  745.       //Random Age4 God.
  746.       gAge4MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge4);
  747.    }
  748. }
  749.  
  750. //==============================================================================
  751. //initNorse
  752. //==============================================================================
  753. void initNorse(void)
  754. {
  755.    aiEcho("NORSE Init:");
  756.  
  757.    //Set our trained dropsite PUID.
  758.    aiSetTrainedDropsiteUnitTypeID(cUnitTypeOxCart);
  759.  
  760.    //Create a reserve plan for our main base for some Ulfsarks if we're not on VS, TM, or Nomad.
  761.    if ((cRandomMapName != "nomad") && (cRandomMapName != "vinlandsaga") && (cRandomMapName != "team migration"))
  762.    {
  763.       int ulfsarkReservePlanID=aiPlanCreate("UlfsarkBuilderReserve", cPlanReserve);
  764.       if (ulfsarkReservePlanID >= 0)
  765.       {
  766.          aiPlanSetDesiredPriority(ulfsarkReservePlanID, 49);
  767.          aiPlanSetBaseID(ulfsarkReservePlanID, kbBaseGetMainID(cMyID));
  768.          aiPlanAddUnitType(ulfsarkReservePlanID, cUnitTypeUlfsark, 1, 1, 1);
  769.          aiPlanSetVariableInt(ulfsarkReservePlanID, cReservePlanPlanType, 0, cPlanBuild);
  770.          aiPlanSetActive(ulfsarkReservePlanID);
  771.       }
  772.  
  773.       //Create a simple plan to maintain X Ulfsarks.
  774.       createSimpleMaintainPlan(cUnitTypeUlfsark, gMaintainNumberLandScouts+1, true, kbBaseGetMainID(cMyID));
  775.    }
  776.  
  777.    //Turn off auto favor gather.
  778.    aiSetAutoFavorGather(false);
  779.  
  780.    //Norse scout types.
  781.    gLandScout=cUnitTypeUlfsark;
  782.    gAirScout=-1;
  783.    gWaterScout=cUnitTypeFishingShipNorse;
  784.    //Create a simple plan to maintain 1 water scout.
  785.    if (gWaterMap == true)
  786.       createSimpleMaintainPlan(gWaterScout, gMaintainNumberWaterScouts, true, -1);
  787.  
  788.    //Odin.
  789.    if (cMyCiv == cCivOdin)
  790.    {
  791.       //Create air explore plans for the ravens.
  792.       int explorePID=aiPlanCreate("Explore_SpecialOdinAir1", cPlanExplore);
  793.       if (explorePID >= 0)
  794.       {
  795.          aiPlanAddUnitType(explorePID, cUnitTypeRaven, 1, 1, 1);
  796.          aiPlanSetActive(explorePID);
  797.       }
  798.       explorePID=aiPlanCreate("Explore_SpecialOdinAir2", cPlanExplore);
  799.       if (explorePID >= 0)
  800.       {
  801.          aiPlanAddUnitType(explorePID, cUnitTypeRaven, 1, 1, 1);
  802.          aiPlanSetVariableBool(explorePID, cExplorePlanDoLoops, 0, false);
  803.          aiPlanSetActive(explorePID);
  804.       }
  805.  
  806.       //Get X if we're rushing, else random.
  807.       if (aiGetPersonality() == "defaultRush")
  808.          gAge2MinorGod=cTechAge2Heimdall;
  809.       else
  810.          gAge2MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge2);
  811.       //Random Age3 God.
  812.       gAge3MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge3);
  813.       //Random Age4 God.
  814.       gAge4MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge4);
  815.  
  816.    }
  817.    //Thor.
  818.    else if (cMyCiv == cCivThor)
  819.    {
  820.       //Random Age2 God.
  821.       gAge2MinorGod = kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge2);
  822.       //Get X if we're rushing, else random.
  823.       if (aiGetPersonality() == "defaultRush")
  824.          gAge3MinorGod=cTechAge3Bragi;
  825.       else
  826.          gAge3MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge3);
  827.       //Random Age4 God.
  828.       gAge4MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge4);
  829.  
  830.       //Thor likes dwarves.
  831.       if (aiGetGameMode() != cGameModeLightning)
  832.          gDwarfMaintainPlanID=createSimpleMaintainPlan(cUnitTypeDwarf, 2, true, -1);
  833.    }
  834.    //Loki.
  835.    else if (cMyCiv == cCivLoki)
  836.    {
  837.       //Get X if we're rushing, else random.
  838.       if (aiGetPersonality() == "defaultRush")
  839.          gAge2MinorGod=cTechAge2Heimdall;
  840.       else
  841.          gAge2MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge2);
  842.       //Get X if we're rushing, else random.
  843.       if (aiGetPersonality() == "defaultRush")
  844.          gAge3MinorGod=cTechAge3Bragi;
  845.       else
  846.          gAge3MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge3);
  847.       //Random Age4 God.
  848.       gAge4MinorGod=kbTechTreeGetMinorGodChoices(aiRandInt(2), cAge4);
  849.    }
  850.  
  851.    //Enable our no-infantry check.
  852.    xsEnableRule("norseInfantryCheck");
  853. }
  854.  
  855. //==============================================================================
  856. // norseInfantryCheck
  857. //==============================================================================
  858. rule norseInfantryCheck
  859.    minInterval 10
  860.    inactive
  861.    group Norse
  862. {
  863.    //Get a count of our infantry.
  864.    int infantryCount=kbUnitCount(cMyID, cUnitTypeAbstractInfantry, cUnitStateAlive);
  865.    if (infantryCount > 0)
  866.       return;
  867.  
  868.    //If we're out of infantry, make sure we have at least X pop slots free.
  869.    int availablePopSlots=kbGetPopCap()-kbGetPop();
  870.    if (availablePopSlots >= 2)
  871.       return;
  872.  
  873.    //Else, find a villager to delete.
  874.    //Create/get our query.
  875.    static int vQID=-1;
  876.    if (vQID < 0)
  877.    {
  878.       vQID=kbUnitQueryCreate("NorseInfantryCheckVillagers");
  879.       if (vQID < 0)
  880.       {
  881.          xsDisableSelf();
  882.          return;
  883.       }
  884.    }
  885.     kbUnitQuerySetPlayerID(vQID, cMyID);
  886.    kbUnitQuerySetUnitType(vQID, cUnitTypeAbstractVillager);
  887.    kbUnitQuerySetState(vQID, cUnitStateAlive);
  888.    kbUnitQueryResetResults(vQID);
  889.     int numberVillagers=kbUnitQueryExecute(vQID);
  890.    for (i=0; < numberVillagers)
  891.    {
  892.       int villagerID=kbUnitQueryGetResult(vQID, i);
  893.       if (aiTaskUnitDelete(villagerID) == true)
  894.          return;
  895.    }
  896. }
  897.  
  898. //==============================================================================
  899. // initUnitPicker
  900. //==============================================================================
  901. int initUnitPicker(string name="BUG", int numberTypes=1, int minUnits=10,
  902.    int maxUnits=20, int minPop=-1, int maxPop=-1, int numberBuildings=1,
  903.    bool guessEnemyUnitType=false)
  904. {
  905.    //Create it.
  906.    int upID=kbUnitPickCreate(name);
  907.    if (upID < 0)
  908.       return(-1);
  909.  
  910.    //Default init.
  911.    kbUnitPickResetAll(upID);
  912.    //1 Part Preference, 2 Parts CE, 2 Parts Cost.
  913.    kbUnitPickSetPreferenceWeight(upID, 1.0);
  914.    kbUnitPickSetCombatEfficiencyWeight(upID, 2.0);
  915.    kbUnitPickSetCostWeight(upID, 2.0);
  916.    //Desired number units types, buildings.
  917.    kbUnitPickSetDesiredNumberUnitTypes(upID, numberTypes, numberBuildings, true);
  918.    //Min/Max units and Min/Max pop.
  919.    kbUnitPickSetMinimumNumberUnits(upID, minUnits);
  920.    kbUnitPickSetMaximumNumberUnits(upID, maxUnits);
  921.    kbUnitPickSetMinimumPop(upID, minPop);
  922.    kbUnitPickSetMaximumPop(upID, maxPop);
  923.    //Default to land units.
  924.    kbUnitPickSetAttackUnitType(upID, cUnitTypeLogicalTypeLandMilitary);
  925.    kbUnitPickSetGoalCombatEfficiencyType(upID, cUnitTypeLogicalTypeMilitaryUnitsAndBuildings);
  926.  
  927.    //Setup the military unit preferences.  These are just various strategies of unit
  928.    //combos and what-not that are more or less setup to coincide with the bonuses
  929.    //and mainline units of each civ.  We start with a random choice.  If we have
  930.    //an enemy unit type to preference against, we override that random choice.
  931.    //0:  Counter infantry (i.e. enemyUnitTypeID == cUnitTypeAbstractInfantry).
  932.    //1:  Counter archer (i.e. enemyUnitTypeID == cUnitTypeAbstractArcher).
  933.    //2:  Counter cavalry (i.e. enemyUnitTypeID == cUnitTypeAbstractCavalry).
  934.    int upRand=aiRandInt(3);
  935.  
  936.    //Figure out what we're going to assume our opponent is building.
  937.    int enemyUnitTypeID=-1;
  938.    int mostHatedPlayerID=aiGetMostHatedPlayerID();
  939.    if ((guessEnemyUnitType == true) && (mostHatedPlayerID > 0))
  940.    {
  941.       //If the enemy is Norse, assume infantry.
  942.       //Zeus is infantry.
  943.       if ((kbGetCultureForPlayer(mostHatedPlayerID) == cCultureNorse) ||
  944.          (kbGetCivForPlayer(mostHatedPlayerID) == cCivZeus))
  945.       {
  946.          enemyUnitTypeID=cUnitTypeAbstractInfantry;
  947.          upRand=0;
  948.       }
  949.       //Hades is archers.
  950.       else if (kbGetCivForPlayer(mostHatedPlayerID) == cCivHades)
  951.       {
  952.          enemyUnitTypeID=cUnitTypeAbstractArcher;
  953.          upRand=1;
  954.       }
  955.       //Poseidon is cavalry.
  956.       else if (kbGetCivForPlayer(mostHatedPlayerID) == cCivPoseidon)
  957.       {
  958.          enemyUnitTypeID=cUnitTypeAbstractCavalry;
  959.          upRand=2;
  960.       }
  961.    }
  962.  
  963.    //Do the preference actual work now.
  964.    switch (cMyCiv)
  965.    {
  966.       //Zeus.
  967.       case cCivZeus:
  968.       {
  969.          if (upRand == 0)
  970.          {
  971.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.5);
  972.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.5);
  973.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.3);
  974.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.4);
  975.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  976.          }
  977.          else if (upRand == 1)
  978.          {
  979.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.8);
  980.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.2);
  981.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.5);
  982.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.4);
  983.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  984.          }
  985.          else
  986.          {
  987.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.9);
  988.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.3);
  989.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.1);
  990.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.4);
  991.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMedusa, 0.8);
  992.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  993.          }
  994.          break;
  995.       }
  996.       //Poseidon.
  997.       case cCivPoseidon:
  998.       {
  999.          if (upRand == 0)
  1000.          {
  1001.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.4);
  1002.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.6);
  1003.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.9);
  1004.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.1);
  1005.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1006.          }
  1007.          else if (upRand == 1)
  1008.          {
  1009.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.2);
  1010.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.6);
  1011.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.9);
  1012.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.5);
  1013.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1014.          }
  1015.          else
  1016.          {
  1017.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.7);
  1018.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.2);
  1019.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.5);
  1020.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.7);
  1021.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1022.          }
  1023.          break;
  1024.       }
  1025.       //Hades.
  1026.       case cCivHades:
  1027.       {
  1028.          if (upRand == 0)
  1029.          {
  1030.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.2);
  1031.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.9);
  1032.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.2);
  1033.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.5);
  1034.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1035.          }
  1036.          else if (upRand == 1)
  1037.          {
  1038.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.4);
  1039.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.9);
  1040.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.4);
  1041.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.1);
  1042.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1043.          }
  1044.          else
  1045.          {
  1046.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.6);
  1047.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.6);
  1048.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.2);
  1049.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.7);
  1050.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1051.          }
  1052.          break;
  1053.       }
  1054.       //Isis.
  1055.       case cCivIsis:
  1056.       {
  1057.          if (upRand == 0)
  1058.          {
  1059.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.6);
  1060.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.6);
  1061.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.4);
  1062.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.5);
  1063.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1064.          }
  1065.          else if (upRand == 1)
  1066.          {
  1067.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.4);
  1068.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.4);
  1069.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.4);
  1070.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.8);
  1071.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1072.          }
  1073.          else
  1074.          {
  1075.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.9);
  1076.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.2);
  1077.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.2);
  1078.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.7);
  1079.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1080.          }
  1081.          break;
  1082.       }
  1083.       //Ra.
  1084.       case cCivRa:
  1085.       {
  1086.          if (upRand == 0)
  1087.          {
  1088.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.2);
  1089.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.8);
  1090.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.9);
  1091.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.8);
  1092.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1093.          }
  1094.          else if (upRand == 1)
  1095.          {
  1096.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.4);
  1097.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.5);
  1098.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.9);
  1099.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.2);
  1100.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1101.          }
  1102.          else
  1103.          {
  1104.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.5);
  1105.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.9);
  1106.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.6);
  1107.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.5);
  1108.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1109.          }
  1110.          break;
  1111.       }
  1112.       //Set.
  1113.       case cCivSet:
  1114.       {
  1115.          if (upRand == 0)
  1116.          {
  1117.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.2);
  1118.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.9);
  1119.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.2);
  1120.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.6);
  1121.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1122.          }
  1123.          else if (upRand == 1)
  1124.          {
  1125.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.5);
  1126.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.9);
  1127.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.8);
  1128.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.1);
  1129.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1130.          }
  1131.          else
  1132.          {
  1133.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.7);
  1134.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractArcher, 0.6);
  1135.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.3);
  1136.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeMythUnit, 0.3);
  1137.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1138.          }
  1139.          break;
  1140.       }
  1141.       //Loki.
  1142.       case cCivLoki:
  1143.       {
  1144.          if (upRand == 0)
  1145.          {
  1146.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.75);
  1147.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeHeroNorse, 0.9);
  1148.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.5);
  1149.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1150.          }
  1151.          else if (upRand == 1)
  1152.          {
  1153.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.5);
  1154.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeHeroNorse, 0.9);
  1155.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.5);
  1156.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.5);
  1157.          }
  1158.          else
  1159.          {
  1160.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.9);
  1161.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeHeroNorse, 0.5);
  1162.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.1);
  1163.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.3);
  1164.          }
  1165.          break;
  1166.       }
  1167.       //Odin.
  1168.       case cCivOdin:
  1169.       {
  1170.          if (upRand == 0)
  1171.          {
  1172.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.5);
  1173.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeHuskarl, 0.9);
  1174.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.1);
  1175.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeJarl, 0.9);
  1176.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1177.          }
  1178.          else if (upRand == 1)
  1179.          {
  1180.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.5);
  1181.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeHuskarl, 0.9);
  1182.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.8);
  1183.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.8);
  1184.          }
  1185.          else
  1186.          {
  1187.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.5);
  1188.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.7);
  1189.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.2);
  1190.          }
  1191.          break;
  1192.       }
  1193.       //Thor.
  1194.       case cCivThor:
  1195.       {
  1196.          if (upRand == 0)
  1197.          {
  1198.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.5);
  1199.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeUlfsark, 0.6);
  1200.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeThrowingAxeman, 0.9);
  1201.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.5);
  1202.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.7);
  1203.          }
  1204.          else if (upRand == 1)
  1205.          {
  1206.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.7);
  1207.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.9);
  1208.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.1);
  1209.          }
  1210.          else
  1211.          {
  1212.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractInfantry, 0.6);
  1213.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeUlfsark, 0.9);
  1214.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeThrowingAxeman, 0.9);
  1215.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractCavalry, 0.1);
  1216.             kbUnitPickSetPreferenceFactor(upID, cUnitTypeAbstractSiegeWeapon, 0.3);
  1217.          }
  1218.          break;
  1219.       }
  1220.    }
  1221.  
  1222.    //Done.
  1223.    return(upID);
  1224. }
  1225.  
  1226. //==============================================================================
  1227. // init( void )
  1228. //==============================================================================
  1229. void init(void)
  1230. {
  1231.    //We're in a random map.
  1232.    aiSetRandomMap(true);
  1233.  
  1234.    //Startup messages.
  1235.    aiEcho("Init(): AI Player Name is "+cMyName+".");
  1236.    aiEcho("AI Filename='"+cFilename+"'.");
  1237.    aiEcho("Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+").");
  1238.    aiEcho("MapName="+cRandomMapName+".");
  1239.    aiEcho("FirstRand="+aiRandInt(10000000)+".");
  1240.    aiEcho("Civ="+kbGetCivName(cMyCiv)+".");
  1241.    aiEcho("Culture="+kbGetCultureName(cMyCulture)+".");
  1242.    aiEcho("DifficultyLevel="+aiGetWorldDifficultyName(aiGetWorldDifficulty())+".");
  1243.    aiEcho("Personality="+aiGetPersonality()+".");
  1244.  
  1245.    //Decide if we have a water map.
  1246.    if ((cRandomMapName == "mediterranean") ||
  1247.       (cRandomMapName == "midgard") ||
  1248.       (cRandomMapName == "archipelago") ||
  1249.       (cRandomMapName == "river nile") ||
  1250.       (cRandomMapName == "vinlandsaga") ||
  1251.       (cRandomMapName == "anatolia") ||
  1252.       (cRandomMapName == "team migration") ||
  1253.       (cRandomMapName == "black sea") ||
  1254.       (cRandomMapName == "river styx") ||
  1255.       (cRandomMapName == "sea of worms") ||
  1256.       (cRandomMapName == "sudden death"))
  1257.    {
  1258.       gWaterMap=true;
  1259.       aiEcho("This is a water map.");
  1260.    }
  1261.  
  1262.    //Tell the AI what kind of map we are on.
  1263.    aiSetWaterMap(gWaterMap);
  1264.  
  1265.    //Find someone to hate.
  1266.    updatePlayerToAttack();
  1267.    aiEcho("MostHatedPlayer is Player #"+aiGetMostHatedPlayerID()+".");
  1268.  
  1269.    //Bind our age handlers.
  1270.    aiSetAgeEventHandler(cAge2, "age2Handler");
  1271.    aiSetAgeEventHandler(cAge3, "age3Handler");
  1272.    aiSetAgeEventHandler(cAge4, "age4Handler");
  1273.  
  1274.    if (cvMaxAge == cAge1)
  1275.    {
  1276.       aiEcho("Suspending age upgrades.");
  1277.       aiSetPauseAllAgeUpgrades(true);
  1278.    }
  1279.  
  1280.    //Setup god power handler
  1281.    aiSetGodPowerEventHandler("gpHandler");
  1282.    //Setup build handler
  1283.    aiSetBuildEventHandler("buildHandler");
  1284.    //Setup the wonder handler
  1285.    aiSetWonderDeathEventHandler("wonderDeathHandler");
  1286.    //Setup the retreat handler
  1287.    aiSetRetreatEventHandler("retreatHandler");
  1288.    //Setup the relic handler
  1289.    aiSetRelicEventHandler("relicHandler");
  1290.     //Setup the resign handler
  1291.    aiSetResignEventHandler("resignHandler");
  1292.  
  1293.    //Calculate some areas.
  1294.    kbAreaCalculate();
  1295.    //Set our town location.
  1296.    setTownLocation();
  1297.  
  1298.    //Economy.
  1299.    initEcon();
  1300.    //Progress.
  1301.    initProgress();
  1302.    //God Powers
  1303.    initGodPowers();
  1304.  
  1305.  
  1306.    //Various map overrides.
  1307.    //Erebus and River Styx.
  1308.    if ((cRandomMapName == "erebus") || (cRandomMapName == "river styx"))
  1309.    {
  1310.       aiSetMinNumberNeedForGatheringAggressvies(2);
  1311.       kbBaseSetMaximumResourceDistance(cMyID, kbBaseGetMainID(cMyID), 200.0);
  1312.    }
  1313.    //Vinlandsaga.
  1314.    if ((cRandomMapName == "vinlandsaga") || (cRandomMapName == "team migration"))
  1315.    {
  1316.       //Enable the rule that looks for the mainland.
  1317.       xsEnableRule("findVinlandsagaBase");
  1318.       //Turn off auto dropsite building.
  1319.       aiSetAllowAutoDropsites(false);
  1320.       aiSetAllowBuildings(false);
  1321.       //Make a plan to explore with the initial transport.
  1322.        gVinlandsagaTransportExplorePlanID=aiPlanCreate("Vinlandsaga Transport Explore", cPlanExplore);
  1323.        if (gVinlandsagaTransportExplorePlanID >= 0)
  1324.        {
  1325.          aiPlanAddUnitType(gVinlandsagaTransportExplorePlanID, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionWaterTransport, 0), 1, 1, 1);
  1326.            aiPlanSetDesiredPriority(gVinlandsagaTransportExplorePlanID, 1);
  1327.          aiPlanSetVariableBool(gVinlandsagaTransportExplorePlanID, cExplorePlanDoLoops, 0, false);
  1328.          aiPlanSetActive(gVinlandsagaTransportExplorePlanID);
  1329.          aiPlanSetEscrowID(gVinlandsagaTransportExplorePlanID);
  1330.        }
  1331.       //Turn off fishing.
  1332.       xsDisableRule("fishing");
  1333.       //Pause the age upgrades.
  1334.       aiSetPauseAllAgeUpgrades(true);
  1335.    }
  1336.    //Nomad.
  1337.    else if (cRandomMapName == "nomad")
  1338.    {
  1339.       //Enable the rule that looks for a settlement.
  1340.       int nomadSettlementGoalID=createBuildSettlementGoal("BuildNomadSettlement", 0, -1, -1, 1,
  1341.          kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder,0), true, 100);
  1342.       if (nomadSettlementGoalID != -1)
  1343.       {
  1344.          //Create the callback goal.
  1345.          int nomadCallbackGID=createCallbackGoal("Nomad BuildSettlement Callback", "nomadBuildSettlementCallBack", 1, 0, -1, false);
  1346.          if (nomadCallbackGID >= 0)
  1347.             aiPlanSetVariableInt(nomadSettlementGoalID, cGoalPlanDoneGoal, 0, nomadCallbackGID);
  1348.       }
  1349.  
  1350.       //Make a plan to explore with the initial villager.
  1351.        gNomadExplorePlanID=aiPlanCreate("Nomad Explore", cPlanExplore);
  1352.        if (gNomadExplorePlanID >= 0)
  1353.        {
  1354.          aiPlanAddUnitType(gNomadExplorePlanID, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 1, 1, 1);
  1355.            aiPlanSetDesiredPriority(gNomadExplorePlanID, 1);
  1356.          aiPlanSetVariableBool(gNomadExplorePlanID, cExplorePlanDoLoops, 0, false);
  1357.          aiPlanSetActive(gNomadExplorePlanID);
  1358.          aiPlanSetEscrowID(gNomadExplorePlanID);
  1359.        }
  1360.       //Turn off fishing.
  1361.       xsDisableRule("fishing");
  1362.       //Turn off buildhouse.
  1363.       xsDisableRule("buildHouse");
  1364.       //Pause the age upgrades.
  1365.       aiSetPauseAllAgeUpgrades(true);
  1366.    }
  1367.    //Unknown.
  1368.    else if (cRandomMapName == "the unknown")
  1369.    {
  1370.       xsEnableRule("findFish");
  1371.    }
  1372.    //Make a scout plan to find the plenty vault/
  1373.    else if (cRandomMapName == "king of the hill")
  1374.    {
  1375.       aiEcho("looking for KOTH plenty Vault");
  1376.       int KOTHunitQueryID = kbUnitQueryCreate("findPlentyVault");
  1377.       kbUnitQuerySetPlayerRelation(KOTHunitQueryID, cPlayerRelationAny);
  1378.       kbUnitQuerySetUnitType(KOTHunitQueryID, cUnitTypePlentyVaultKOTH);
  1379.       kbUnitQuerySetState(KOTHunitQueryID, cUnitStateAny);
  1380.        kbUnitQueryResetResults(KOTHunitQueryID);
  1381.        int numberFound = kbUnitQueryExecute(KOTHunitQueryID);
  1382.       gKOTHPlentyUnitID = kbUnitQueryGetResult(KOTHunitQueryID, 0);
  1383.       kbSetForwardBasePosition(kbUnitGetPosition(gKOTHPlentyUnitID));
  1384.  
  1385.       xsEnableRule("findFish");
  1386.    }
  1387.  
  1388.  
  1389.    //Create bases for all of our settlements.  Ignore any that already have
  1390.    //bases set.  If we have an invalid main base, the first base we create
  1391.    //will be our main base.
  1392.    int settlementQueryID=kbUnitQueryCreate("MySettlements");
  1393.    if (settlementQueryID > -1)
  1394.    {
  1395.         kbUnitQuerySetPlayerID(settlementQueryID, cMyID);
  1396.       kbUnitQuerySetUnitType(settlementQueryID, cUnitTypeAbstractSettlement);
  1397.       kbUnitQuerySetState(settlementQueryID, cUnitStateAlive);
  1398.       kbUnitQueryResetResults(settlementQueryID);
  1399.        int numberSettlements=kbUnitQueryExecute(settlementQueryID);
  1400.       for(i=0; < numberSettlements)
  1401.       {
  1402.          int settlementID=kbUnitQueryGetResult(settlementQueryID, i);
  1403.          //Skip this settlement if it already has a base.
  1404.          if (kbUnitGetBaseID(settlementID) >= 0)
  1405.             continue;
  1406.  
  1407.          vector settlementPosition=kbUnitGetPosition(settlementID);
  1408.          //Create a new base.
  1409.          int newBaseID=kbBaseCreate(cMyID, "Base"+kbBaseGetNextID(), settlementPosition, 75.0);
  1410.          if (newBaseID > -1)
  1411.          {
  1412.             //Figure out the front vector.
  1413.             vector baseFront=xsVectorNormalize(kbGetMapCenter()-settlementPosition);
  1414.             kbBaseSetFrontVector(cMyID, newBaseID, baseFront);
  1415.             //Military gather point.
  1416.             vector militaryGatherPoint=settlementPosition+baseFront*40.0;
  1417.             kbBaseSetMilitaryGatherPoint(cMyID, newBaseID, militaryGatherPoint);
  1418.             //Set the other flags.
  1419.             kbBaseSetMilitary(cMyID, newBaseID, true);
  1420.             kbBaseSetEconomy(cMyID, newBaseID, true);
  1421.             //Set the resource distance limit.
  1422.             kbBaseSetMaximumResourceDistance(cMyID, newBaseID, gMaximumBaseResourceDistance);
  1423.             //Add the settlement to the base.
  1424.             kbBaseAddUnit(cMyID, newBaseID, settlementID);
  1425.             kbBaseSetSettlement(cMyID, newBaseID, true);
  1426.             //Set the main-ness of the base.
  1427.             kbBaseSetMain(cMyID, newBaseID, true);
  1428.          }
  1429.       }
  1430.    }
  1431.  
  1432.  
  1433.    //Culture setup.
  1434.    switch (cMyCulture)
  1435.    {
  1436.       case cCultureGreek:
  1437.       {
  1438.          initGreek();
  1439.          break;
  1440.       }
  1441.       case cCultureEgyptian:
  1442.       {
  1443.          initEgyptian();
  1444.          break;
  1445.       }
  1446.       case cCultureNorse:
  1447.       {
  1448.          initNorse();
  1449.          break;
  1450.       }
  1451.    }
  1452.    //Setup the progression to follow these minor gods.
  1453.    kbTechTreeAddMinorGodPref(gAge2MinorGod);
  1454.    kbTechTreeAddMinorGodPref(gAge3MinorGod);
  1455.    kbTechTreeAddMinorGodPref(gAge4MinorGod);
  1456.  
  1457.  
  1458.    //Set the Explore Danger Threshold.
  1459.    aiSetExploreDangerThreshold(300.0);
  1460.    //Auto gather our military units.
  1461.    aiSetAutoGatherMilitaryUnits(true);
  1462.  
  1463.    //Get our house build limit.
  1464.    gHouseBuildLimit=kbGetBuildLimit(cMyID, cUnitTypeHouse);
  1465.    //Set the housing rebuild bound to 4 for the first age.
  1466.    gHouseAvailablePopRebuild=4;
  1467.  
  1468.    //Set the hard pop caps.
  1469.    if (aiGetGameMode() == cGameModeLightning)
  1470.    {
  1471.       gHardEconomyPopCap=25;
  1472.       //If we're Norse, get our 5 dwarfs.
  1473.       if (cMyCulture == cCultureNorse)
  1474.          createSimpleMaintainPlan(cUnitTypeDwarf, 5, true, -1);
  1475.    }
  1476.    else if (aiGetGameMode() == cGameModeDeathmatch)
  1477.       gHardEconomyPopCap=12;
  1478.    else
  1479.    {
  1480.       if (aiGetWorldDifficulty() == cDifficultyEasy)
  1481.          gHardEconomyPopCap=20;
  1482.       else if (aiGetWorldDifficulty() == cDifficultyModerate)
  1483.          gHardEconomyPopCap=40;
  1484.       else
  1485.          gHardEconomyPopCap=-1;
  1486.    }
  1487.  
  1488.    //Set the default attack response distance.
  1489.    if (aiGetWorldDifficulty() == cDifficultyEasy)
  1490.       aiSetAttackResponseDistance(1.0);
  1491.    else if (aiGetWorldDifficulty() == cDifficultyModerate)
  1492.       aiSetAttackResponseDistance(30.0);
  1493.    else
  1494.       aiSetAttackResponseDistance(65.0);
  1495.  
  1496.    //Walls and towers.
  1497.    if ( ((aiGetWorldDifficulty() == cDifficultyEasy) || (aiGetPersonality() == "defaultboom")) &&
  1498.       (cRandomMapName != "acropolis"))
  1499.    {
  1500.       int doWalls=aiRandInt(4);
  1501.       if (doWalls == 1)
  1502.       {
  1503.          gBuildWalls=true;
  1504.          gBuildTowers=true;
  1505.       }
  1506.       else
  1507.       {
  1508.          gBuildWalls=false;
  1509.          gBuildTowers=true;
  1510.       }
  1511.    }
  1512.  
  1513.    //If we're on easy, set our default stance to defensive.
  1514.    if (aiGetWorldDifficulty() == cDifficultyEasy)
  1515.       aiSetDefaultStance(cUnitStanceDefensive);
  1516.  
  1517.    
  1518.    //Decide whether or not we're doing a rush/raid.
  1519.    int rushCount=0;
  1520.    int forwardBaseGoalID=-1;
  1521.    if ( ((aiGetWorldDifficulty() != cDifficultyEasy) && (aiGetGameMode() != cGameModeDeathmatch)) ||
  1522.       (cRandomMapName == "king of the hill"))
  1523.    {
  1524.       if (aiGetWorldDifficulty() == cDifficultyModerate)
  1525.          rushCount=aiRandInt(1);
  1526.       else
  1527.          rushCount=aiRandInt(2);
  1528.       //If we're booming, no early raiding.
  1529.       if (aiGetPersonality() == "defaultboom")
  1530.          rushCount=0;
  1531.       else if (aiGetPersonality() == "defaultrush")
  1532.          rushCount=rushCount+1;
  1533.       //Specific maps prevent rushing.
  1534.       if ((cRandomMapName == "vinlandsaga") ||
  1535.          (cRandomMapName == "river nile") ||
  1536.          (cRandomMapName == "team migration") ||
  1537.          (cRandomMapName == "archipelago") ||
  1538.          (cRandomMapName == "black sea"))
  1539.          rushCount=0;
  1540.       //If we have no teammates, we shant be rushing.
  1541.       if (kbGetNumberMutualAllies() <= 0)
  1542.          rushCount=0;
  1543.       //Specific maps to make rushing happen.
  1544.       if (cRandomMapName == "king of the hill")
  1545.          rushCount=rushCount+1;
  1546.       
  1547.       //If we're rushing, decide if we want to build a forward base.
  1548.       if (rushCount > 0)
  1549.       {
  1550.          if ((aiGetPersonality() == "defaultrush") || ((aiGetPersonality() == "default") && (aiRandInt(5) == 0)) )
  1551.             forwardBaseGoalID=createBaseGoal("Forward Base", cGoalPlanGoalTypeForwardBase, -1, 1, 1, -1, kbBaseGetMainID(cMyID));
  1552.       }
  1553.  
  1554.       //Create our UP.
  1555.       int rushUPID=initUnitPicker("Rush", 2, 4, 8, -1, -1, 1, true);
  1556.       if (rushUPID >= 0)
  1557.       {
  1558.          //If we're on hard or titan, up the units.
  1559.          if (aiGetWorldDifficulty() != cDifficultyModerate)
  1560.          {
  1561.             kbUnitPickSetMinimumNumberUnits(rushUPID, 7);
  1562.             kbUnitPickSetMaximumNumberUnits(rushUPID, 20);
  1563.          }
  1564.          //No myth units in the second age.
  1565.          kbUnitPickSetPreferenceFactor(rushUPID, cUnitTypeMythUnit, 0.0);
  1566.          //Reset a few of the UP parms.
  1567.          kbUnitPickSetPreferenceWeight(rushUPID, 1.0);
  1568.          kbUnitPickSetCombatEfficiencyWeight(rushUPID, 0.0);
  1569.          kbUnitPickSetCostWeight(rushUPID, 1.0);
  1570.          //Setup the retreat to only be allowed on non-water maps.
  1571.          bool allowRetreat=true;
  1572.          if ((gWaterMap == true) || (cRandomMapName == "king of the hill"))
  1573.             allowRetreat=false;
  1574.          //Create the rush goal if we're rushing.
  1575.          if ((rushCount > 0) && (gBuildWalls == false) && (gBuildTowers == false))
  1576.          {
  1577.             //Create the attack.
  1578. //            gRushGoalID = -1;
  1579.             if (forwardBaseGoalID < 0)
  1580.                gRushGoalID=createSimpleAttackGoal("Rush Land Attack", -1, rushUPID, rushCount, 1, 1, kbBaseGetMainID(cMyID), allowRetreat);
  1581.             else
  1582.                gRushGoalID=createSimpleAttackGoal("Rush Land Attack", -1, rushUPID, rushCount, 1, 1, -1, allowRetreat);
  1583.             //-- attach a callbackgoal to this rush goal
  1584.             if (gRushGoalID > 0)
  1585.             {
  1586.                //Go for hitpoint upgrade first.
  1587.                aiPlanSetVariableInt(gRushGoalID, cGoalPlanUpgradeFilterType, 0, cUpgradeTypeHitpoints);
  1588.                //Set the callback.
  1589.                int callbackGID=createCallbackGoal("Attack Callback", "attackChatCallback",1, 0, 2, false);
  1590.                if (callbackGID >= 0)
  1591.                   aiPlanSetVariableInt(gRushGoalID, cGoalPlanExecuteGoal, 0, callbackGID);
  1592.                //Create an idle attack goal that will maintain our military until the next age after
  1593.                //we're done rushing.
  1594.                int idleAttackGID=createSimpleAttackGoal("Rush Idle", -1, rushUPID, -1, 1, 1, -1, allowRetreat);
  1595.                if (idleAttackGID >= 0)
  1596.                {
  1597.                   aiPlanSetVariableBool(idleAttackGID, cGoalPlanIdleAttack, 0, true);
  1598.                   aiPlanSetVariableBool(idleAttackGID, cGoalPlanAutoUpdateState, 0, false);
  1599.                   aiPlanSetVariableInt(gRushGoalID, cGoalPlanDoneGoal, 0, idleAttackGID);
  1600.                   aiPlanSetVariableInt(idleAttackGID, cGoalPlanUpgradeFilterType, 0, cUpgradeTypeHitpoints);
  1601.                }
  1602.             }
  1603.          }
  1604.          //Else, if we're not on Moderate and we're not attacking, create some military anyway.
  1605.          else if (aiGetWorldDifficulty() != cDifficultyModerate)
  1606.          {
  1607.             //Create an idle attack goal that will maintain our military until the next age.
  1608.             int idleForceGID=createSimpleAttackGoal("Idle Force", -1, rushUPID, -1, 1, 1, -1, allowRetreat);
  1609.             if (idleForceGID >= 0)
  1610.             {
  1611.                aiPlanSetVariableBool(idleForceGID, cGoalPlanIdleAttack, 0, true);
  1612.                //Go for hitpoint upgrades.
  1613.                aiPlanSetVariableInt(idleForceGID, cGoalPlanUpgradeFilterType, 0, cUpgradeTypeHitpoints);
  1614.                //Reset the rushUPID down to 1 unit type and 1 building.
  1615.                kbUnitPickSetDesiredNumberUnitTypes(rushUPID, 1, 1, true);
  1616.             }
  1617.          }
  1618.       }
  1619.  
  1620.       //If our rush count is 0, enable the rule that monitors our main base
  1621.       //for being under attack before we're ready.
  1622.       if (rushCount <= 0)
  1623.          xsEnableRule("townDefense");
  1624.    }
  1625.  
  1626.    //Create our late age attack goal.
  1627.    int numberBuildings=3;
  1628.    if (cRandomMapName == "king of the hill")
  1629.       numberBuildings=1;
  1630.    if (aiGetWorldDifficulty() == cDifficultyEasy)
  1631.       gLateUPID=initUnitPicker("Late", 1, -1, -1, 8, 16, numberBuildings, false);
  1632.    else if (aiGetWorldDifficulty() == cDifficultyModerate)
  1633.    {
  1634.       int minPop=20+aiRandInt(14);
  1635.       int maxPop=minPop+16;
  1636.       //If we're on KOTH, make the attack groups smaller.
  1637.       if (cRandomMapName == "king of the hill")
  1638.       {
  1639.          minPop=minPop-10;
  1640.          maxPop=maxPop-10;
  1641.       }
  1642.       gLateUPID=initUnitPicker("Late", 2, -1, -1, minPop, maxPop, numberBuildings, false);
  1643.    }
  1644.    else
  1645.    {
  1646.       minPop=40+aiRandInt(20);
  1647.       maxPop=minPop+30+aiRandInt(10);
  1648.       //If we're on KOTH, make the attack groups smaller.
  1649.       if (cRandomMapName == "king of the hill")
  1650.       {
  1651.          minPop=minPop-16;
  1652.          maxPop=maxPop-16;
  1653.       }
  1654.       gLateUPID=initUnitPicker("Late", 3, -1, -1, minPop, maxPop, numberBuildings, true);
  1655.    }
  1656.    int lateAttackAge=2;
  1657.    if (gLateUPID >= 0)
  1658.    {
  1659.       if (aiGetGameMode() == cGameModeDeathmatch)
  1660.          lateAttackAge=3;
  1661.  
  1662. //      gLandAttackGoalID=-1;
  1663.       if (forwardBaseGoalID < 0)
  1664.          gLandAttackGoalID=createSimpleAttackGoal("Main Land Attack", -1, gLateUPID, -1, lateAttackAge, -1, kbBaseGetMainID(cMyID), false);
  1665.       else
  1666.          gLandAttackGoalID=createSimpleAttackGoal("Main Land Attack", -1, gLateUPID, -1, lateAttackAge, -1, -1, false);
  1667.  
  1668.       //-- attach a callbackgoal to this attack goal
  1669.       if (gLandAttackGoalID >= 0)
  1670.       {
  1671.          //If this is easy, this is an idle attack.
  1672.          if (aiGetWorldDifficulty() == cDifficultyEasy)
  1673.             aiPlanSetVariableBool(gLandAttackGoalID, cGoalPlanIdleAttack, 0, true);
  1674.          else
  1675.          {
  1676.             callbackGID=createCallbackGoal("Attack Callback", "attackChatCallback", 1, 0, lateAttackAge, false);
  1677.             if (callbackGID >= 0)
  1678.                aiPlanSetVariableInt(gLandAttackGoalID, cGoalPlanExecuteGoal, 0, callbackGID);
  1679.          }
  1680.  
  1681.          aiPlanSetVariableInt(gLandAttackGoalID, cGoalPlanUpgradeFilterType, 0, cUpgradeTypeHitpoints);
  1682.       }
  1683.    }
  1684.  
  1685.    //Create our naval attack starter if we're on a water map.
  1686.    if (gWaterMap == true)
  1687.       xsEnableRule("NavalGoalMonitor");
  1688.  
  1689.    //If we're going to build walls and we're not rushing, we have a 50% chance to build a wonder.
  1690.    if ((aiGetGameMode() == cGameModeSupremacy) && (gBuildWalls == true) &&
  1691.       (rushCount == 0) && (aiRandInt(2) == 0))
  1692.    {
  1693.       //-- reserve some building space in the base for the wonder.
  1694.       int wonderBPID = kbBuildingPlacementCreate( "WonderBP" );
  1695.       if(wonderBPID != -1)
  1696.       {
  1697.          kbBuildingPlacementSetBuildingType( cUnitTypeWonder );
  1698.          kbBuildingPlacementSetBaseID( kbBaseGetMainID(cMyID), cBuildingPlacementPreferenceBack );
  1699.          kbBuildingPlacementStart();
  1700.       }
  1701.       
  1702.       createBuildBuildingGoal("Wonder Goal", cUnitTypeWonder, 1, 3, 4, kbBaseGetMainID(cMyID),
  1703.          50, cUnitTypeAbstractVillager, true, 100, wonderBPID);
  1704.    }
  1705.  
  1706.  
  1707.    //Create our econ goal (which is really just to store stuff together).
  1708.    gGatherGoalPlanID=aiPlanCreate("GatherGoals", cPlanGatherGoal);
  1709.    if (gGatherGoalPlanID >= 0)
  1710.    {
  1711.       //Overall percentages.
  1712.       aiPlanSetDesiredPriority(gGatherGoalPlanID, 90);
  1713.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanScriptRPGPct, 0, 0.5);
  1714.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanCostRPGPct, 0, 0.5);
  1715.       aiPlanSetNumberVariableValues(gGatherGoalPlanID, cGatherGoalPlanGathererPct, 4, true);
  1716.       //Egyptians like gold.
  1717.       if (cMyCulture == cCultureEgyptian)
  1718.       {
  1719.          aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceGold, 0.15);
  1720.          aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceWood, 0.0);
  1721.          aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceFood, 0.85);
  1722.          aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceFavor, 0.0);
  1723.          if ((cRandomMapName == "vinlandsaga") || (cRandomMapName == "team migration"))
  1724.          {
  1725.             aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceWood, 0.05);
  1726.             aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceGold, 0.1);
  1727.          }
  1728.       }
  1729.       else
  1730.       {
  1731.          aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceGold, 0.0);
  1732.          aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceWood, 0.2);
  1733.          aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceFood, 0.8);
  1734.          aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceFavor, 0.0);
  1735.       }
  1736.  
  1737.       //Standard RB setup.
  1738.       aiPlanSetNumberVariableValues(gGatherGoalPlanID, cGatherGoalPlanNumFoodPlans, 5, true);
  1739.       aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumFoodPlans, cAIResourceSubTypeEasy, 1);
  1740.       aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumFoodPlans, cAIResourceSubTypeHunt, 0);
  1741.       aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumFoodPlans, cAIResourceSubTypeHuntAggressive, 0);
  1742.       aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumFoodPlans, cAIResourceSubTypeFarm, 0);
  1743.       aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumFoodPlans, cAIResourceSubTypeFish, 0);
  1744.       aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumWoodPlans, 0, 1);
  1745.       aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumGoldPlans, 0, 1);
  1746.       aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumFavorPlans, 0, 0);
  1747.       //Hunt on Erebus and River Styx.
  1748.       if ((cRandomMapName == "erebus") || (cRandomMapName == "river styx"))
  1749.       {
  1750.          aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumFoodPlans, cAIResourceSubTypeEasy, 0);
  1751.          aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumFoodPlans, cAIResourceSubTypeHuntAggressive, 2);
  1752.       }
  1753.  
  1754.       //Min resource amounts.
  1755.       aiPlanSetNumberVariableValues(gGatherGoalPlanID, cGatherGoalPlanMinResourceAmt, 4, true);
  1756.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanMinResourceAmt, cResourceGold, 500.0);
  1757.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanMinResourceAmt, cResourceWood, 500.0);
  1758.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanMinResourceAmt, cResourceFood, 500.0);
  1759.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanMinResourceAmt, cResourceFavor, 50.0);
  1760.       //Resource skew.
  1761.       aiPlanSetNumberVariableValues(gGatherGoalPlanID, cGatherGoalPlanResourceSkew, 4, true);
  1762.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanResourceSkew, cResourceGold, 1000.0);
  1763.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanResourceSkew, cResourceWood, 1000.0);
  1764.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanResourceSkew, cResourceFood, 1000.0);
  1765.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanResourceSkew, cResourceFavor, 100.0);
  1766.       //Cost weights.
  1767.       aiPlanSetNumberVariableValues(gGatherGoalPlanID, cGatherGoalPlanResourceCostWeight, 4, true);
  1768.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanResourceCostWeight, cResourceGold, 1.5);
  1769.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanResourceCostWeight, cResourceWood, 1.0);
  1770.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanResourceCostWeight, cResourceFood, 1.5);
  1771.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanResourceCostWeight, cResourceFavor, 10.0);
  1772.  
  1773.       //Set our farm limits.
  1774.       aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanFarmLimitPerPlan, 0, 4);
  1775.       aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanMaxFarmLimit, 0, 24);
  1776.       aiSetFarmLimit(aiPlanGetVariableInt(gGatherGoalPlanID, cGatherGoalPlanFarmLimitPerPlan, 0));
  1777.       //Do our late econ init.
  1778.       postInitEcon();
  1779.       //Lastly, update our EM.
  1780.       updateEM(25, 0, 0.8, 0.6, 1.0, 1.0, 1.0, 1.0);
  1781.    }
  1782.  
  1783.    //If we're in deathmatch, immediately build a temple.
  1784.    if (aiGetGameMode() == cGameModeDeathmatch)
  1785.    {
  1786.       createSimpleBuildPlan(cUnitTypeTemple, 1, 100, false, false, cEconomyEscrowID, kbBaseGetMainID(cMyID), 5);
  1787.       createSimpleBuildPlan(cUnitTypeHouse, 3, 99, false, false, cEconomyEscrowID, kbBaseGetMainID(cMyID), 2);
  1788.    }
  1789. }
  1790.  
  1791. //==============================================================================
  1792. // Age 2 Handler
  1793. //==============================================================================
  1794. void age2Handler(int age=1)
  1795. {
  1796.    aiEcho("I'm now in Age "+age+".");
  1797.    if (cvMaxAge == age)
  1798.    {
  1799.       aiEcho("Suspending age upgrades.");
  1800.       aiSetPauseAllAgeUpgrades(true);
  1801.    }
  1802.    //Econ.
  1803.    econAge2Handler(age);
  1804.    //Progress.
  1805.    progressAge2Handler(age);
  1806.    //GP.
  1807.    gpAge2Handler(age);
  1808.    aiEcho("  Done with misc handlers.");
  1809.  
  1810.    //Set the housing rebuild bound.
  1811.    gHouseAvailablePopRebuild=10;
  1812.  
  1813.    //Switch the EM rule.
  1814.    xsDisableRule("updateEMAge1");
  1815.    xsEnableRule("updateEMAge2");
  1816.  
  1817.    //Enable building repair.
  1818.    if (aiGetWorldDifficulty() != cDifficultyEasy)
  1819.       xsEnableRule("repairBuildings");
  1820.  
  1821.    //Misc Econ.
  1822.    if (gGatherGoalPlanID >= 0)
  1823.    {
  1824.       //Greeks need favor.
  1825.       if (cMyCulture == cCultureGreek)
  1826.       {
  1827.          aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumFavorPlans, 0, 1);
  1828.          aiSetResourceBreakdown(cResourceFavor, cAIResourceSubTypeEasy, 1, 40, 1.0, kbBaseGetMainID(cMyID));
  1829.       }
  1830.  
  1831.       //Resource percentages.
  1832.       int woodPriority=55;
  1833.       int goldPriority=50;
  1834.       float goldPct=0.3;
  1835.       float foodPct=0.5;      
  1836.       float woodPct=0.2;
  1837.       float favorPct=0.0;
  1838.       if (cMyCulture == cCultureEgyptian)
  1839.       {
  1840.          woodPct=0.1;
  1841.          goldPct=0.4;
  1842.          goldPriority=55;
  1843.          woodPriority=50;
  1844.       }
  1845.       else if (cMyCulture == cCultureGreek)
  1846.       {
  1847.          favorPct=0.1;
  1848.          foodPct=0.4;
  1849.       }
  1850.       //Breakdowns.
  1851.       int numWoodPlans=aiPlanGetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumWoodPlans, 0);
  1852.       int numGoldPlans=aiPlanGetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumGoldPlans, 0);
  1853.       aiSetResourceBreakdown(cResourceWood, cAIResourceSubTypeEasy, numWoodPlans, woodPriority, 1.0, kbBaseGetMainID(cMyID));
  1854.        aiSetResourceBreakdown(cResourceGold, cAIResourceSubTypeEasy, numGoldPlans, goldPriority, 1.0, kbBaseGetMainID(cMyID));
  1855.       //Pct.
  1856.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceWood, woodPct);
  1857.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceFavor, favorPct);
  1858.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceFood, foodPct);
  1859.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceGold, goldPct);
  1860.       //Set the RGP weights.
  1861.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanScriptRPGPct, 0, 0.4);
  1862.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanCostRPGPct, 0, 0.6);
  1863.       aiSetResourceGathererPercentageWeight(cRGPScript, 0.4);
  1864.       aiSetResourceGathererPercentageWeight(cRGPCost, 0.6);
  1865.    }
  1866.  
  1867.    //Maintain a water transport, if this is a water map.
  1868.    if ((gWaterMap == true) && (gMaintainWaterXPortPlanID < 0))
  1869.       gMaintainWaterXPortPlanID=createSimpleMaintainPlan(kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionWaterTransport, 0), 1, false, -1);
  1870.  
  1871.    //If we're building walls and/or towers, start those up.
  1872.    if (gBuildWalls == true)
  1873.       xsEnableRule("wallUpgrade");
  1874.    if (gBuildTowers == true)
  1875.       xsEnableRule("towerUpgrade");
  1876.  
  1877.    //Store our relic gatherer type.
  1878.    int gatherRelicType=-1;
  1879.    //Greek.
  1880.    if (cMyCulture == cCultureGreek)
  1881.    {
  1882.       //Greeks gather with heros.
  1883.       gatherRelicType=cUnitTypeHero;
  1884.  
  1885.       //Always want 4 hoplites.
  1886.       createSimpleMaintainPlan(cUnitTypeHoplite, 4, false, kbBaseGetMainID(cMyID));
  1887.  
  1888.       //Create our hero maintain plans.  These do first and second age heroes.
  1889.       if (cMyCiv == cCivZeus)
  1890.       {
  1891.          createSimpleMaintainPlan(cUnitTypeHeroGreekJason, 1, false, kbBaseGetMainID(cMyID));
  1892.          createSimpleMaintainPlan(cUnitTypeHeroGreekOdysseus, 1, false, kbBaseGetMainID(cMyID));
  1893.       }
  1894.       else if (cMyCiv == cCivPoseidon)
  1895.       {
  1896.          createSimpleMaintainPlan(cUnitTypeHeroGreekTheseus, 1, false, kbBaseGetMainID(cMyID));
  1897.          createSimpleMaintainPlan(cUnitTypeHeroGreekHippolyta, 1, false, kbBaseGetMainID(cMyID));
  1898.       }
  1899.       else if (cMyCiv == cCivHades)
  1900.       {
  1901.          createSimpleMaintainPlan(cUnitTypeHeroGreekAjax, 1, false, kbBaseGetMainID(cMyID));
  1902.          createSimpleMaintainPlan(cUnitTypeHeroGreekChiron, 1, false, kbBaseGetMainID(cMyID));
  1903.       }
  1904.    }
  1905.    //Egyptian.
  1906.    else if (cMyCulture == cCultureEgyptian)
  1907.    {
  1908.       //Egyptians gather relics with their Pharaoh.
  1909.       gatherRelicType=cUnitTypePharaoh;
  1910.  
  1911.       //Move our pharaoh empower to a generic "dropsite"
  1912.       if (gEmpowerPlanID > -1)
  1913.          aiPlanSetVariableInt(gEmpowerPlanID, cEmpowerPlanTargetTypeID, 0, cUnitTypeDropsite);
  1914.  
  1915.       //Always want 4 axeman.
  1916.       createSimpleMaintainPlan(cUnitTypeAxeman, 4, false, kbBaseGetMainID(cMyID));
  1917.  
  1918.       //If we're Ra, create some more priests and empower with them.
  1919.       if (cMyCiv == cCivRa)
  1920.       {
  1921.          createSimpleMaintainPlan(cUnitTypePriest, 4, true, -1);
  1922.          int ePlanID=aiPlanCreate("Mining Camp Empower", cPlanEmpower);
  1923.          if (ePlanID >= 0)
  1924.          {
  1925.             aiPlanSetEconomy(ePlanID, true);
  1926.             aiPlanAddUnitType(ePlanID, cUnitTypePriest, 1, 1, 1);
  1927.             aiPlanSetVariableInt(ePlanID, cEmpowerPlanTargetTypeID, 0, cUnitTypeMiningCamp);
  1928.             aiPlanSetActive(ePlanID);
  1929.          }
  1930.          ePlanID=aiPlanCreate("Lumber Camp Empower", cPlanEmpower);
  1931.          if (ePlanID >= 0)
  1932.          {
  1933.             aiPlanSetEconomy(ePlanID, true);
  1934.             aiPlanAddUnitType(ePlanID, cUnitTypePriest, 1, 1, 1);
  1935.             aiPlanSetVariableInt(ePlanID, cEmpowerPlanTargetTypeID, 0, cUnitTypeLumberCamp);
  1936.             aiPlanSetActive(ePlanID);
  1937.          }
  1938.          ePlanID=aiPlanCreate("Monument Empower", cPlanEmpower);
  1939.          if (ePlanID >= 0)
  1940.          {
  1941.             aiPlanSetEconomy(ePlanID, true);
  1942.             aiPlanAddUnitType(ePlanID, cUnitTypePriest, 1, 1, 1);
  1943.             aiPlanSetVariableInt(ePlanID, cEmpowerPlanTargetTypeID, 0, cUnitTypeAbstractMonument);
  1944.             aiPlanSetActive(ePlanID);
  1945.          }
  1946.       }
  1947.  
  1948.       //Up the build limit for Outposts.
  1949.       aiSetMaxLOSProtoUnitLimit(6);
  1950.    }
  1951.    //Norse.
  1952.    else if (cMyCulture == cCultureNorse)
  1953.    {
  1954.       //Norse gather with their heros.
  1955.       gatherRelicType=cUnitTypeHeroNorse;
  1956.  
  1957.       //We always want 4 Norse heroes.
  1958.       createSimpleMaintainPlan(cUnitTypeHeroNorse, 4, false, kbBaseGetMainID(cMyID));
  1959.  
  1960.       //Force a long house to go down.
  1961.        int longhousePlanID=aiPlanCreate("NorseBuildLonghouse", cPlanBuild);
  1962.       if (longhousePlanID >= 0)
  1963.       {
  1964.          aiPlanSetVariableInt(longhousePlanID, cBuildPlanBuildingTypeID, 0, cUnitTypeLonghouse);
  1965.            aiPlanSetVariableInt(longhousePlanID, cBuildPlanNumAreaBorderLayers, 2, kbGetTownAreaID());      
  1966.          aiPlanSetDesiredPriority(longhousePlanID, 100);
  1967.            aiPlanAddUnitType(longhousePlanID, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0),
  1968.             gBuildersPerHouse, gBuildersPerHouse, gBuildersPerHouse);
  1969.          aiPlanSetEscrowID(longhousePlanID, cMilitaryEscrowID);
  1970.          aiPlanSetBaseID(longhousePlanID, kbBaseGetMainID(cMyID));
  1971.          aiPlanSetActive(longhousePlanID);
  1972.       }
  1973.  
  1974.       //Up our Thor dwarf count.
  1975.       if (gDwarfMaintainPlanID > -1)
  1976.          aiPlanSetVariableInt(gDwarfMaintainPlanID, cTrainPlanNumberToMaintain, 0, 4);
  1977.  
  1978.       //Init our myth unit rule.
  1979.       xsEnableRule("trainNorseMythUnit");
  1980.    }
  1981.  
  1982.    //Relics:  Always on Hard or Nightmare, 50% of the time on Moderate, Never on Easy.
  1983.    bool gatherRelics=true;
  1984.    if ((aiGetWorldDifficulty() == cDifficultyEasy) ||
  1985.       ((aiGetWorldDifficulty() == cDifficultyModerate) && (aiRandInt(2) == 0)) )
  1986.       gatherRelics=false;
  1987.    //If we're going to gather relics, do it.
  1988.    if (gatherRelics == true)
  1989.    {
  1990.       gRelicGatherPlanID=aiPlanCreate("Relic Gather", cPlanGatherRelic);
  1991.       if (gRelicGatherPlanID >= 0)
  1992.       {
  1993.          aiPlanAddUnitType(gRelicGatherPlanID, gatherRelicType, 1, 1, 1);
  1994.          aiPlanSetVariableInt(gRelicGatherPlanID, cGatherRelicPlanTargetTypeID, 0, cUnitTypeRelic);
  1995.            aiPlanSetVariableInt(gRelicGatherPlanID, cGatherRelicPlanDropsiteTypeID, 0, cUnitTypeTemple);
  1996.          aiPlanSetBaseID(gRelicGatherPlanID, kbBaseGetMainID(cMyID));
  1997.          aiPlanSetDesiredPriority(gRelicGatherPlanID, 100);
  1998.            aiPlanSetActive(gRelicGatherPlanID);
  1999.       }
  2000.    }
  2001.  
  2002.    //Build walls if we should.
  2003.    if (gBuildWalls==true)
  2004.    {
  2005.       int wallPlanID=aiPlanCreate("WallInBase", cPlanBuildWall);
  2006.       if (wallPlanID != -1)
  2007.       {
  2008.          aiPlanSetVariableInt(wallPlanID, cBuildWallPlanWallType, 0, cBuildWallPlanWallTypeRing);
  2009.          aiPlanAddUnitType(wallPlanID, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 1, 3, 3);
  2010.          aiPlanSetVariableVector(wallPlanID, cBuildWallPlanWallRingCenterPoint, 0, kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID)));
  2011.          aiPlanSetVariableFloat(wallPlanID, cBuildWallPlanWallRingRadius, 0, 50.0);
  2012.          aiPlanSetVariableInt(wallPlanID, cBuildWallPlanNumberOfGates, 0, 5);
  2013.          aiPlanSetBaseID(wallPlanID, kbBaseGetMainID(cMyID));
  2014.          aiPlanSetEscrowID(wallPlanID, cEconomyEscrowID);
  2015.          aiPlanSetDesiredPriority(wallPlanID, 100);
  2016.          aiPlanSetActive(wallPlanID, true);
  2017.          //Enable our wall gap rule, too.
  2018.          xsEnableRule("fillInWallGaps");
  2019.       }
  2020.    }
  2021.  
  2022.    //If we're in deathmatch, immediately build our armory.
  2023.    if (aiGetGameMode() == cGameModeDeathmatch)
  2024.    {
  2025.       gHardEconomyPopCap=15;
  2026.       if (cMyCiv == cCivThor)
  2027.          createSimpleBuildPlan(cUnitTypeDwarfFoundry, 1, 100, false, false, cEconomyEscrowID, kbBaseGetMainID(cMyID), 5);
  2028.       else
  2029.          createSimpleBuildPlan(cUnitTypeArmory, 1, 100, false, false, cEconomyEscrowID, kbBaseGetMainID(cMyID), 5);
  2030.       createSimpleBuildPlan(cUnitTypeHouse, 3, 99, false, false, cEconomyEscrowID, kbBaseGetMainID(cMyID), 2);
  2031.    }
  2032. }
  2033.  
  2034. //==============================================================================
  2035. // RULE tradeWithCaravans
  2036. //==============================================================================
  2037. rule tradeWithCaravans
  2038.    minInterval 11
  2039.    inactive
  2040. {
  2041.    //Force build a market.
  2042.    static bool builtMarket=false;
  2043.    if (builtMarket == false)
  2044.    {
  2045.       string buildPlanName="BuildMarket";
  2046.       int buildPlanID=aiPlanCreate(buildPlanName, cPlanBuild);
  2047.       if (buildPlanID < 0)
  2048.          return;
  2049.  
  2050.       //Put it way in the back.
  2051.       vector backVector=kbBaseGetBackVector(cMyID, kbBaseGetMainID(cMyID));
  2052.       float x = xsVectorGetX(backVector);
  2053.       float z = xsVectorGetZ(backVector);
  2054.       x = x * 60.0;
  2055.       z = z * 60.0;
  2056.       backVector = xsVectorSetX(backVector, x);
  2057.       backVector = xsVectorSetZ(backVector, z);
  2058.       backVector = xsVectorSetY(backVector, 0.0);
  2059.       vector location = kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID));
  2060.       location = location + backVector;
  2061.       //Setup the build plan.
  2062.       aiPlanSetVariableInt(buildPlanID, cBuildPlanBuildingTypeID, 0, cUnitTypeMarket);
  2063.       aiPlanSetVariableVector(buildPlanID, cBuildPlanInfluencePosition, 0, location);
  2064.       aiPlanSetVariableFloat(buildPlanID, cBuildPlanInfluencePositionDistance, 0, 30.0);
  2065.       aiPlanSetVariableFloat(buildPlanID, cBuildPlanInfluencePositionValue, 0, 100.0);
  2066.       aiPlanSetDesiredPriority(buildPlanID, 100);
  2067.       aiPlanAddUnitType(buildPlanID, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 1, 1, 1);
  2068.       aiPlanSetEscrowID(buildPlanID, cEconomyEscrowID);
  2069.       aiPlanSetBaseID(buildPlanID, kbBaseGetMainID(cMyID));
  2070.       aiPlanSetActive(buildPlanID);
  2071.       //Don't build another one.
  2072.       builtMarket = true;
  2073.    }
  2074.    
  2075.    //If we don't have a query ID, create it.
  2076.    static int marketQueryID=-1;
  2077.    if (marketQueryID < 0)
  2078.    {
  2079.       marketQueryID=kbUnitQueryCreate("MarketQuery");
  2080.       //If we still don't have one, bail.
  2081.       if (marketQueryID < 0)
  2082.          return;
  2083.       //Else, setup the query data.
  2084.       kbUnitQuerySetPlayerID(marketQueryID, cMyID);
  2085.       kbUnitQuerySetUnitType(marketQueryID, cUnitTypeMarket);
  2086.       kbUnitQuerySetState(marketQueryID, cUnitStateAlive);
  2087.    }
  2088.  
  2089.    //Reset the results.
  2090.    kbUnitQueryResetResults(marketQueryID);
  2091.    //Run the query.  Be dumb and just take the first one for now.
  2092.    if (kbUnitQueryExecute(marketQueryID) <= 0)
  2093.       return;
  2094.    int marketUnitID=kbUnitQueryGetResult(marketQueryID, 0);
  2095.    if (marketUnitID == -1)
  2096.       return;
  2097.  
  2098.    //Create the market trade plan.
  2099.    string planName="MarketTrade";
  2100.    int planID=aiPlanCreate(planName, cPlanTrade);
  2101.    if (planID < 0)
  2102.       return;
  2103.  
  2104.    //Get our cart PUID.
  2105.    int tradeCartPUID=kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionTrade, 0);
  2106.    aiPlanSetVariableInt(planID, cTradePlanTargetUnitTypeID, 0, cUnitTypeAbstractSettlement);
  2107.    aiPlanSetDesiredPriority(planID, 100);
  2108.    aiPlanSetInitialPosition(planID, kbUnitGetPosition(marketUnitID));
  2109.    aiPlanSetVariableVector(planID, cTradePlanStartPosition, 0, kbUnitGetPosition(marketUnitID));
  2110.    aiPlanSetVariableInt(planID, cTradePlanTradeUnitType, 0, tradeCartPUID);
  2111.    aiPlanSetVariableInt(planID, cTradePlanTradeUnitTypeMax, 0, gMaxTradeCarts);
  2112.    aiPlanSetVariableInt(planID, cTradePlanMarketID, 0, marketUnitID);
  2113.    aiPlanAddUnitType(planID, tradeCartPUID, gMaxTradeCarts, gMaxTradeCarts, gMaxTradeCarts);
  2114.    aiPlanSetEconomy(planID, true);
  2115.    aiPlanSetActive(planID);
  2116.  
  2117.    //Go away.
  2118.    xsDisableSelf();
  2119. }
  2120.  
  2121. //==============================================================================
  2122. // Age 3 Handler
  2123. //==============================================================================
  2124. void age3Handler(int age=2)
  2125. {
  2126.    aiEcho("I'm now in Age "+age+".");
  2127.    if (cvMaxAge == age)
  2128.    {
  2129.       aiEcho("Suspending age upgrades.");
  2130.       aiSetPauseAllAgeUpgrades(true);
  2131.    }
  2132.    //Econ.
  2133.    econAge3Handler(age);
  2134.    //Progress.
  2135.    progressAge3Handler(age);
  2136.    //GP.
  2137.    gpAge3Handler(age);
  2138.    aiEcho("  Done with misc handlers.");
  2139.  
  2140.    //Disable town defense (in case it's active).
  2141.    xsDisableRule("townDefense");
  2142.  
  2143.    //Switch the EM rule.
  2144.    xsDisableRule("updateEMAge2");
  2145.    xsEnableRule("updateEMAge3");
  2146.    //We can trade now.
  2147.    xsEnableRule("tradeWithCaravans");
  2148.  
  2149.    //Up the number of water transports to maintain.
  2150.    if (gMaintainWaterXPortPlanID >= 0)
  2151.       aiPlanSetVariableInt(gMaintainWaterXPortPlanID, cTrainPlanNumberToMaintain, 0, 2);
  2152.  
  2153.    //Econ.
  2154.    if (gGatherGoalPlanID >= 0)
  2155.    {
  2156.       //UP the number of gold gather plans (if we have more than one gold site in our main base).
  2157.       int numberGoldSites=kbGetNumberValidResources(kbBaseGetMainID(cMyID), cResourceGold, cAIResourceSubTypeEasy);
  2158.       if (numberGoldSites > 1)
  2159.       {
  2160.          int numGoldPlans = aiPlanGetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumGoldPlans, 0);
  2161.           aiSetResourceBreakdown(cResourceGold, cAIResourceSubTypeEasy, numGoldPlans+1, 50, 1.0, kbBaseGetMainID(cMyID));
  2162.          aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumGoldPlans, 0, numGoldPlans+1);
  2163.       }
  2164.  
  2165.       //UP the number of wood gather plans.
  2166.       int numWoodPlans = aiPlanGetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumWoodPlans, 0);
  2167.        aiSetResourceBreakdown(cResourceWood, cAIResourceSubTypeEasy, numWoodPlans+1, 55, 1.0, kbBaseGetMainID(cMyID));
  2168.       aiPlanSetVariableInt(gGatherGoalPlanID, cGatherGoalPlanNumWoodPlans, 0, numWoodPlans+1);
  2169.       //Egyptians like gold.  Greeks like favor.
  2170.       float goldPct=0.4;
  2171.       float foodPct=0.45;      
  2172.       float woodPct = 0.15;
  2173.       float favorPct=0.0;
  2174.       if(cMyCulture == cCultureEgyptian)
  2175.       {
  2176.          woodPct=0.1;
  2177.          goldPct=0.45;
  2178.       }
  2179.       else if (cMyCulture == cCultureGreek)
  2180.       {
  2181.          favorPct=0.1;
  2182.          goldPct=0.35;
  2183.          woodPct=0.10;
  2184.       }
  2185.       //Modify percentages if we're building towers.
  2186.       if (gBuildTowers == true)
  2187.       {
  2188.          goldPct=goldPct-woodPct/2.0;
  2189.          foodPct=foodPct-woodPct/2.0;
  2190.          woodPct = woodPct * 2.0;
  2191.       }
  2192.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceWood, woodPct);
  2193.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceFavor, favorPct);
  2194.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceFood, foodPct);
  2195.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceGold, goldPct);
  2196.  
  2197.       //Set the RGP weights.
  2198.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanScriptRPGPct, 0, 0.3);
  2199.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanCostRPGPct, 0, 0.7);
  2200.       aiSetResourceGathererPercentageWeight(cRGPScript, 0.3);
  2201.       aiSetResourceGathererPercentageWeight(cRGPCost, 0.7);
  2202.    }
  2203.    
  2204.    //Create new greek hero maintain plans.
  2205.    if (cMyCulture == cCultureGreek)
  2206.    {
  2207.       if (cMyCiv == cCivZeus)
  2208.          createSimpleMaintainPlan(cUnitTypeHeroGreekHeracles, 1, false, kbBaseGetMainID(cMyID));
  2209.       else if (cMyCiv == cCivPoseidon)
  2210.          createSimpleMaintainPlan(cUnitTypeHeroGreekAtalanta, 1, false, kbBaseGetMainID(cMyID));
  2211.       else if (cMyCiv == cCivHades)
  2212.          createSimpleMaintainPlan(cUnitTypeHeroGreekAchilles, 1, false, kbBaseGetMainID(cMyID));
  2213.  
  2214.       //Build a fortress and train some catapults.
  2215.       if (aiGetWorldDifficulty() != cDifficultyEasy)
  2216.       {
  2217.           int fortressPlanID=aiPlanCreate("BuildFortress", cPlanBuild);
  2218.          if (fortressPlanID >= 0)
  2219.          {
  2220.             aiPlanSetVariableInt(fortressPlanID, cBuildPlanBuildingTypeID, 0, cUnitTypeFortress);
  2221.               aiPlanSetVariableInt(fortressPlanID, cBuildPlanNumAreaBorderLayers, 2, kbGetTownAreaID());      
  2222.             aiPlanSetDesiredPriority(fortressPlanID, 100);
  2223.               aiPlanAddUnitType(fortressPlanID, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 1, 1, 1);
  2224.             aiPlanSetEscrowID(fortressPlanID, cMilitaryEscrowID);
  2225.             aiPlanSetBaseID(fortressPlanID, kbBaseGetMainID(cMyID));
  2226.             aiPlanSetActive(fortressPlanID);
  2227.          }
  2228.          createSimpleMaintainPlan(cUnitTypePetrobolos, 2, false, kbBaseGetMainID(cMyID));
  2229.       }
  2230.    }
  2231.    else if (cMyCulture == cCultureEgyptian)
  2232.    {
  2233.       //Build a siege workshop.
  2234.       if (aiGetWorldDifficulty() != cDifficultyEasy)
  2235.       {
  2236.           int siegeCampPlanID=aiPlanCreate("BuildSiegeCamp", cPlanBuild);
  2237.          if (siegeCampPlanID >= 0)
  2238.          {
  2239.             aiPlanSetVariableInt(siegeCampPlanID, cBuildPlanBuildingTypeID, 0, cUnitTypeSiegeCamp);
  2240.               aiPlanSetVariableInt(siegeCampPlanID, cBuildPlanNumAreaBorderLayers, 2, kbGetTownAreaID());      
  2241.             aiPlanSetDesiredPriority(siegeCampPlanID, 100);
  2242.               aiPlanAddUnitType(siegeCampPlanID, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 1, 1, 1);
  2243.             aiPlanSetEscrowID(siegeCampPlanID, cMilitaryEscrowID);
  2244.             aiPlanSetBaseID(siegeCampPlanID, kbBaseGetMainID(cMyID));
  2245.             aiPlanSetActive(siegeCampPlanID);
  2246.          }
  2247.          //Maintain a couple of siege towers.
  2248.          createSimpleMaintainPlan(cUnitTypeSiegeTower, 2, false, kbBaseGetMainID(cMyID));
  2249.       }
  2250.  
  2251.       //Set the build limit for Outposts.
  2252.       aiSetMaxLOSProtoUnitLimit(9);
  2253.    }
  2254.  
  2255.    //Up our Thor dwarf count.
  2256.    if (gDwarfMaintainPlanID > -1)
  2257.       aiPlanSetVariableInt(gDwarfMaintainPlanID, cTrainPlanNumberToMaintain, 0, 6);
  2258.  
  2259.    //If we're building towers, do that.
  2260.    if (gBuildTowers == true)
  2261.       towerInBase("Age3TowerBuild", false, 6, cEconomyEscrowID);
  2262.  
  2263.    //If we're in deathmatch, immediately build some more houses.  Also, call tradeWithCaravans to 
  2264.    //get our market put down ASAP.
  2265.    if (aiGetGameMode() == cGameModeDeathmatch)
  2266.    {
  2267.       gHardEconomyPopCap=20;
  2268.       createSimpleBuildPlan(cUnitTypeHouse, 2, 99, false, false, cEconomyEscrowID, kbBaseGetMainID(cMyID), 2);
  2269.       tradeWithCaravans();
  2270.    }
  2271. }
  2272.  
  2273. //==============================================================================
  2274. // Age 4 Handler
  2275. //==============================================================================
  2276. void age4Handler(int age=3)
  2277. {
  2278.    aiEcho("I'm now in Age "+age+".");
  2279.    //Econ.
  2280.    econAge4Handler(age);
  2281.    //Progress.
  2282.    progressAge4Handler(age);
  2283.    //GP.
  2284.    gpAge4Handler(age);
  2285.    aiEcho("  Done with misc handlers.");
  2286.  
  2287.    //Switch the EM rule.
  2288.    xsDisableRule("updateEMAge3");
  2289.    xsEnableRule("updateEMAge4");
  2290.  
  2291.    //Enable our siege rule.
  2292.    xsEnableRule("increaseSiegeWeaponUP");
  2293.    //Enable our degrade unit preference rule.
  2294.    xsEnableRule("degradeUnitPreference");
  2295.    //Enable our omniscience rule.
  2296.    xsEnableRule("getOmniscience");
  2297.  
  2298.    //Econ.
  2299.    if(gGatherGoalPlanID >= 0)
  2300.    {
  2301.       //Set the RGP weights.  Cost in charge now.
  2302.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanScriptRPGPct, 0, 0.15);
  2303.       aiPlanSetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanCostRPGPct, 0, 0.85);
  2304.       aiSetResourceGathererPercentageWeight(cRGPScript, 0.15);
  2305.       aiSetResourceGathererPercentageWeight(cRGPCost, 0.85);
  2306.    }
  2307.       
  2308.    //Create new greek hero maintain plans.
  2309.    if (cMyCulture == cCultureGreek)
  2310.    {
  2311.       if (cMyCiv == cCivZeus)
  2312.       {
  2313.          createSimpleMaintainPlan(cUnitTypeHeroGreekBellerophon, 1, false, kbBaseGetMainID(cMyID));
  2314.       }
  2315.       else if (cMyCiv == cCivPoseidon)
  2316.          createSimpleMaintainPlan(cUnitTypeHeroGreekPolyphemus, 1, false, kbBaseGetMainID(cMyID));
  2317.       else if (cMyCiv == cCivHades)
  2318.          createSimpleMaintainPlan(cUnitTypeHeroGreekPerseus, 1, false, kbBaseGetMainID(cMyID));
  2319.       if (aiGetWorldDifficulty() != cDifficultyEasy)
  2320.          createSimpleMaintainPlan(cUnitTypeHelepolis, 1, false, kbBaseGetMainID(cMyID));
  2321.  
  2322.       
  2323.    }
  2324.    else if (cMyCulture == cCultureEgyptian)
  2325.    {
  2326.       //Catapults.
  2327.       if (aiGetWorldDifficulty() != cDifficultyEasy)
  2328.          createSimpleMaintainPlan(cUnitTypeCatapult, 2, false, kbBaseGetMainID(cMyID));
  2329.       //Set the build limit for Outposts.
  2330.       aiSetMaxLOSProtoUnitLimit(11);
  2331.       
  2332.       if(gAge4MinorGod == cTechAge4Thoth)
  2333.       {
  2334.          int botPID=aiPlanCreate("GetBookOfThoth", cPlanProgression);
  2335.           if (botPID != 0)
  2336.          {
  2337.             aiPlanSetVariableInt(botPID, cProgressionPlanGoalTechID, 0, cTechBookofThoth);
  2338.              aiPlanSetDesiredPriority(botPID, 25);
  2339.              aiPlanSetEscrowID(botPID, cMilitaryEscrowID);
  2340.              aiPlanSetActive(botPID);
  2341.          }
  2342.       }
  2343.       else if(gAge4MinorGod == cTechAge4Osiris)
  2344.       {
  2345.          int nkPID=aiPlanCreate("GetnewKingdom", cPlanProgression);
  2346.           if (nkPID != 0)
  2347.          {
  2348.             aiPlanSetVariableInt(nkPID, cProgressionPlanGoalTechID, 0, cTechNewKingdom);
  2349.              aiPlanSetDesiredPriority(nkPID, 25);
  2350.              aiPlanSetEscrowID(nkPID, cMilitaryEscrowID);
  2351.              aiPlanSetActive(nkPID);
  2352.          }
  2353.       }
  2354.    }
  2355.  
  2356.    //If we're in deathmatch, no more hard pop cap.
  2357.    if (aiGetGameMode() == cGameModeDeathmatch)
  2358.    {
  2359.       gHardEconomyPopCap=-1;
  2360.       createSimpleBuildPlan(cUnitTypeHouse, 2, 99, false, false, cEconomyEscrowID, kbBaseGetMainID(cMyID), 2);
  2361.    }
  2362. }
  2363.  
  2364. //==============================================================================
  2365. // degradeUnitPreference
  2366. //==============================================================================
  2367. rule degradeUnitPreference
  2368.    minInterval 119
  2369.    inactive
  2370. {
  2371.    //If we're not 4th age, skip.
  2372.    if (kbGetAge() < 3)
  2373.       return;
  2374.    float newPreferenceWeight=kbUnitPickGetPreferenceWeight(gLateUPID);
  2375.    if (newPreferenceWeight <= 0.0)
  2376.       return;
  2377.    newPreferenceWeight=newPreferenceWeight*0.9;
  2378.    kbUnitPickSetPreferenceWeight(gLateUPID, newPreferenceWeight);
  2379. }
  2380.  
  2381. //==============================================================================
  2382. // towerUpgrade
  2383. //==============================================================================
  2384. rule towerUpgrade
  2385.    minInterval 31
  2386.    inactive
  2387.    runImmediately
  2388. {
  2389.    //Must be setup for wood before we do any of this.
  2390.    if (kbSetupForResource(kbBaseGetMainID(cMyID), cResourceWood, 25.0, 400) == false)
  2391.       return;
  2392.       
  2393.    //Start upgrading my defenses.
  2394.    int pid=aiPlanCreate("towerUpgrade", cPlanProgression);
  2395.    if (pid >= 0)
  2396.    { 
  2397.       aiPlanSetVariableBool(pid, cProgressionPlanRunInParallel, 0, true);
  2398.       aiPlanSetDesiredPriority(pid, 30);
  2399.         aiPlanSetEscrowID(pid, gTowerEscrowID);
  2400.       aiPlanSetBaseID(pid, kbBaseGetMainID(cMyID));
  2401.       
  2402.       if(cMyCulture == cCultureGreek)
  2403.       {
  2404.          aiPlanSetNumberVariableValues(pid, cProgressionPlanGoalTechID, 5, true);
  2405.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 0, cTechSignalFires);
  2406.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 1, cTechCarrierPigeons);
  2407.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 2, cTechBoilingOil);
  2408.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 3, cTechWatchTower);
  2409.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 4, cTechGuardTower);
  2410.          aiPlanSetActive(pid);
  2411.       }
  2412.       else if(cMyCulture == cCultureEgyptian)
  2413.       {
  2414.          aiPlanSetNumberVariableValues(pid, cProgressionPlanGoalTechID, 5, true);
  2415.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 0, cTechSignalFires);
  2416.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 1, cTechCarrierPigeons);
  2417.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 2, cTechBoilingOil);
  2418.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 3, cTechGuardTower);
  2419.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 4, cTechBallistaTower);
  2420.          aiPlanSetActive(pid);
  2421.       }
  2422.       else if(cMyCulture == cCultureNorse)
  2423.       {
  2424.          aiPlanSetNumberVariableValues(pid, cProgressionPlanGoalTechID, 4, true);
  2425.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 0, cTechSignalFires);
  2426.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 1, cTechCarrierPigeons);
  2427.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 2, cTechBoilingOil);
  2428.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 3, cTechWatchTower);
  2429.          aiPlanSetActive(pid);
  2430.       }
  2431.       else
  2432.          aiPlanDestroy(pid);
  2433.  
  2434.       xsDisableSelf();
  2435.    }
  2436. }
  2437.  
  2438. //==============================================================================
  2439. // wallUpgrade
  2440. //==============================================================================
  2441. rule wallUpgrade
  2442.    minInterval 30
  2443.    inactive
  2444.    runImmediately
  2445. {
  2446.    //Must be setup for wood first.
  2447.    if (kbSetupForResource(kbBaseGetMainID(cMyID), cResourceWood, 25.0, 600) == false)
  2448.       return;
  2449.       
  2450.    //Start upgrading my defenses.
  2451.    int pid=aiPlanCreate("wallUpgrade", cPlanProgression);
  2452.    if (pid >= 0)
  2453.    { 
  2454.       aiPlanSetVariableBool(pid, cProgressionPlanRunInParallel, 0, true);
  2455.       aiPlanSetDesiredPriority(pid, 30);
  2456.         aiPlanSetEscrowID(pid, cMilitaryEscrowID);
  2457.       aiPlanSetBaseID(pid, kbBaseGetMainID(cMyID));
  2458.       if( cMyCulture == cCultureNorse )
  2459.       {
  2460.          aiPlanSetNumberVariableValues(pid, cProgressionPlanGoalTechID, 1, true);
  2461.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 0, cTechStoneWall);
  2462.       }
  2463.       else
  2464.       {
  2465.          aiPlanSetNumberVariableValues(pid, cProgressionPlanGoalTechID, 2, true);
  2466.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 0, cTechStoneWall);
  2467.          aiPlanSetVariableInt(pid, cProgressionPlanGoalTechID, 1, cTechFortifiedWall);
  2468.       }
  2469.       aiPlanSetActive(pid);
  2470.       xsDisableSelf();
  2471.    }
  2472.    xsDisableSelf();
  2473. }
  2474.  
  2475. //==============================================================================
  2476. // periodicSaveGames
  2477. //==============================================================================
  2478. rule periodicSaveGames
  2479.    minInterval 5
  2480.    active
  2481. {
  2482.    //Dont save if we are told not to.
  2483.    if (aiGetAutosaveOn() == false)
  2484.    {
  2485.       xsDisableSelf();
  2486.       return;
  2487.    }
  2488.  
  2489.    int firstCPPlayerID = -1;
  2490.    for(i=0; < cNumberPlayers)
  2491.    {
  2492.       if(kbIsPlayerHuman(i) == true)
  2493.          continue;
  2494.  
  2495.       firstCPPlayerID = i;
  2496.    }
  2497.    if (cMyID != firstCPPlayerID)
  2498.       return;
  2499.  
  2500.    //Create the savegame name.
  2501.    static int psCount=0;
  2502.    //Save it.
  2503.    if (cvDoAutoSaves == true)
  2504.    {
  2505.       aiQueueAutoSavegame(psCount);
  2506.       //Inc our count.
  2507.       psCount=psCount+1;
  2508.    }
  2509.  
  2510.    //After the first time, set it to every five minutes.
  2511.    xsSetRuleMinIntervalSelf(180);
  2512. }
  2513.  
  2514.  
  2515. //==============================================================================
  2516. // towerInBase
  2517. //==============================================================================
  2518. void towerInBase(string planName="BUG", bool los = true, int numTowers = 6, int escrowID=-1)
  2519. {
  2520.    int planID=aiPlanCreate(planName, cPlanTower);
  2521.    if (planID >= 0)
  2522.    {
  2523.       //Save the escrow ID.
  2524.       gTowerEscrowID=escrowID;
  2525.  
  2526.       aiPlanSetVariableFloat(planID, cTowerPlanDistanceFromCenter, 0, 75.0);
  2527.       aiPlanSetVariableBool(planID, cTowerPlanMaximizeLOS, 0, los);
  2528.       if(los)
  2529.          aiPlanSetVariableFloat(planID, cTowerPlanLOSModifier, 0, 1.0);
  2530.       else
  2531.          aiPlanSetVariableFloat(planID, cTowerPlanAttackLOSModifier, 0, 0.75);
  2532.       
  2533.       aiPlanSetVariableInt(planID, cTowerPlanNumberToBuild, 0, numTowers);
  2534.       aiPlanSetVariableInt(planID, cTowerPlanProtoIDToBuild, 0, cUnitTypeTower);
  2535.       
  2536.       aiPlanSetDesiredPriority(planID, 100);
  2537.       aiPlanSetEscrowID(planID, gTowerEscrowID);
  2538.       aiPlanSetBaseID(planID, kbBaseGetMainID(cMyID));
  2539.       aiPlanSetActive(planID);
  2540.    }
  2541. }
  2542.  
  2543. //==============================================================================
  2544. // RULE: updateEconGathererPercentCaps
  2545. //
  2546. // updates the GathererPerecnt if they are completely out of whack(tm).
  2547. //==============================================================================
  2548. rule updateEconGathererPercentCaps
  2549.    minInterval 7
  2550.    active
  2551. {
  2552.    if(gGatherGoalPlanID < 0)
  2553.       return;
  2554.  
  2555.    float foodGPct = aiPlanGetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceFood);
  2556.    float woodGPct = aiPlanGetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceWood);
  2557.    float goldGPct = aiPlanGetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceGold);
  2558.    float favorGPct = aiPlanGetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanGathererPct, cResourceFavor);
  2559.  
  2560.    //-- get current resource amounts
  2561.    float currentFood  = kbResourceGet(cResourceFood);
  2562.    float currentWood  = kbResourceGet(cResourceWood);
  2563.    float currentGold  = kbResourceGet(cResourceGold);
  2564.    float currentFavor = kbResourceGet(cResourceFavor);
  2565.  
  2566.    //-- get current resource needs.
  2567.    float currentFoodNeed = aiGetCurrentResourceNeed(cResourceFood);
  2568.    float currentWoodNeed = aiGetCurrentResourceNeed(cResourceWood);
  2569.    float currentGoldNeed = aiGetCurrentResourceNeed(cResourceGold);
  2570.    float currentFavorNeed = aiGetCurrentResourceNeed(cResourceFavor);
  2571.    
  2572.    //-- get the script specified need minimums.
  2573.    float minFood = aiPlanGetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanMinResourceAmt, cResourceFood);
  2574.    float minWood = aiPlanGetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanMinResourceAmt, cResourceWood);
  2575.    float minGold = aiPlanGetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanMinResourceAmt, cResourceGold);
  2576.    
  2577.    //-- make sure our need is at least the specified minimum.
  2578.    if(currentFoodNeed < minFood)
  2579.       currentFoodNeed = minFood;
  2580.    if(currentWoodNeed < minWood)
  2581.       currentWoodNeed = minWood;
  2582.    if(currentGoldNeed < minGold)
  2583.       currentGoldNeed = minGold;
  2584.   
  2585.    //-- get our gold to ratios.
  2586.    float goldToFood = currentGold-currentFood;
  2587.    float goldToWood = currentGold-currentWood;
  2588.  
  2589.    //-- calc the resource to need ratios.  anything greater than 1, means that we have more of that resource than we need.
  2590.    float foodToNeedRatio = 100000.0;
  2591.    if(currentFoodNeed > 0.0)
  2592.       foodToNeedRatio = currentFood / currentFoodNeed;
  2593.    float woodToNeedRatio = 100000.0;
  2594.    if(currentWoodNeed > 0.0)
  2595.       woodToNeedRatio = currentWood / currentWoodNeed;
  2596.    float goldToNeedRatio = 100000.0;
  2597.    if(currentGoldNeed > 0.0)
  2598.       goldToNeedRatio = currentGold / currentGoldNeed;
  2599.  
  2600.    //-- get the script specified buffer amounts per resource.
  2601.    float foodBuffer = aiPlanGetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanResourceSkew, cResourceFood);
  2602.    float woodBuffer = aiPlanGetVariableFloat(gGatherGoalPlanID, cGatherGoalPlanResourceSkew, cResourceWood);
  2603.  
  2604.    int numMarkets = kbUnitCount(cMyID, cUnitTypeMarket, cUnitStateAlive);
  2605.    int resource = -1;
  2606.  
  2607.    if(goldToNeedRatio > 1.0)
  2608.    {
  2609.       //-- sell gold if
  2610.       // 0. we have a market.
  2611.       // 1. we have more gold than we need
  2612.       // 2. we have more food than the min we want to keep.
  2613.       // 3. we have more food or wood than gold.
  2614.  
  2615.       //-- we will buy food if 
  2616.       // 1, we have more gold than food.
  2617.       // 2. we need more food than wood.
  2618.  
  2619.       //-- otherwise, we will buy wood.
  2620.       
  2621.       //-- if we have we have the min amount of gold AND we have more gold than we need,
  2622.       //-- buy which ever resource we have the most, as long as one of them is larger than gold.
  2623.       if(numMarkets > 0)
  2624.       {
  2625.          if((foodToNeedRatio<woodToNeedRatio) && (foodToNeedRatio<1.0))
  2626.          {
  2627.             aiBuyResourceOnMarket(cResourceFood);
  2628.             return;
  2629.          }
  2630.          else if(woodToNeedRatio<1.0)
  2631.          {
  2632.             aiBuyResourceOnMarket(cResourceWood);
  2633.             return;
  2634.          }
  2635.       }
  2636.       else
  2637.       {
  2638.          //-- Turn down gold
  2639.          //goldGPct = 0.1;
  2640.       }
  2641.    }
  2642.    
  2643.    if(foodToNeedRatio > woodToNeedRatio)
  2644.    {
  2645.       //-- sell food if
  2646.       // 0. we have a market.
  2647.       // 1. we have more food than we need
  2648.       // 2. we have more food than the min we want to keep.
  2649.       // 3. we have more fo0d than gold by the skew amount.
  2650.       if((currentFood > minFood) && (numMarkets > 0) && ((currentFood-currentGold) > foodBuffer))
  2651.       {
  2652.          aiSellResourceOnMarket(cResourceFood);
  2653.          return;
  2654.       }
  2655.       else
  2656.       {
  2657.          //-- Turn down food
  2658.          //foodGPct = 0.1;
  2659.       }
  2660.  
  2661.    }
  2662.    
  2663.    //-- sell wood if
  2664.    // 0. we have a market.
  2665.    // 1. we have more wood than we need
  2666.    // 2. we have more wood than the min we want to keep.
  2667.    // 3. we have more wood than gold by the skew amount.
  2668.    if((currentWood > minWood) && (numMarkets > 0) && ((currentWood-currentGold) > woodBuffer))
  2669.    {
  2670.       aiSellResourceOnMarket(cResourceWood);
  2671.       return;
  2672.    }
  2673.    else
  2674.    {
  2675.       //-- Turn down food
  2676.       //woodGPct = 0.1;
  2677.    }
  2678.    
  2679.    aiSetResourceGathererPercentage(cResourceFood, foodGPct, false, cRGPScript);
  2680.    aiSetResourceGathererPercentage(cResourceWood, woodGPct, false, cRGPScript);
  2681.    aiSetResourceGathererPercentage(cResourceGold, goldGPct, false, cRGPScript);
  2682.    aiSetResourceGathererPercentage(cResourceFavor, favorGPct, false, cRGPScript);
  2683.    aiNormalizeResourceGathererPercentages(cRGPScript);
  2684. }
  2685.  
  2686. //==============================================================================
  2687. // ShouldIResign
  2688. //==============================================================================
  2689. rule ShouldIResign
  2690.    minInterval 7
  2691.    active
  2692. {
  2693.    //Don't resign in MP games.
  2694.    if(aiIsMultiplayer() == true)
  2695.    {
  2696.       xsDisableSelf();
  2697.       return;
  2698.    }
  2699.  
  2700.    if(cvOkToResign == false)
  2701.    {
  2702.       xsDisableSelf();     // Must be re-enabled if cvOkToResign is set true.
  2703.       return;     
  2704.    }
  2705.  
  2706.    //Don't resign if you're teamed with a human.
  2707.    static bool checkTeamedWithHuman=true;
  2708.    if (checkTeamedWithHuman == true)
  2709.    {
  2710.       for (i=1; < cNumberPlayers)
  2711.       {
  2712.          if (i == cMyID)
  2713.             continue;
  2714.          //Skip if not human.
  2715.          if (kbIsPlayerHuman(i) == false)
  2716.             continue;
  2717.          //If this is a mutually allied human, go away.
  2718.          if (kbIsPlayerMutualAlly(i) == true)
  2719.          {
  2720.             xsDisableSelf();
  2721.             return;
  2722.          }
  2723.       }
  2724.       //Don't check again.
  2725.       checkTeamedWithHuman=false;
  2726.    }
  2727.  
  2728.    //Don't resign too soon.
  2729.    if (xsGetTime() < 1200000)
  2730.      return;
  2731.  
  2732.    int numSettlements=kbUnitCount(cMyID, cUnitTypeAbstractSettlement, cUnitStateAliveOrBuilding);
  2733.    //If on easy, don't only resign if you have no settlements.
  2734.    if (aiGetWorldDifficulty() == cDifficultyEasy)
  2735.    {
  2736.       if (numSettlements <= 0)
  2737.       {
  2738.          aiEcho("Resign: Easy numSettlements("+numSettlements+")");
  2739.          gResignType = cResignSettlements;
  2740.          aiAttemptResign(cAICommPromptResignQuestion);
  2741.          xsDisableSelf();
  2742.          return;
  2743.       }
  2744.       return;
  2745.    }
  2746.  
  2747.    //Don't resign if we have over 30 active pop slots.
  2748.    if (kbGetPop() >= 30)
  2749.       return;
  2750.    
  2751.    //If we don't have any builders, we're not Norse, and we cannot afford anymore, try to resign.
  2752.    int builderUnitID=kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0);
  2753.    int numBuilders=kbUnitCount(cMyID, builderUnitID, cUnitStateAliveOrBuilding);   
  2754.    if ((numBuilders <= 0) && (cMyCulture != cCultureNorse))
  2755.    {
  2756.       if (kbCanAffordUnit(builderUnitID, cEconomyEscrowID) == false)
  2757.       {
  2758.         aiEcho("Resign: numBuilders("+numBuilders+")");
  2759.         gResignType=cResignGatherers;
  2760.         //aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptAIResignGatherers, -1);
  2761.         aiAttemptResign(cAICommPromptResignQuestion);
  2762.         xsDisableSelf();
  2763.         return;
  2764.       }
  2765.    }
  2766.  
  2767.    if ((numSettlements <= 0) && (numBuilders <= 10))
  2768.    {
  2769.       if ((kbCanAffordUnit(cUnitTypeSettlementLevel1, cEconomyEscrowID) == false) || (numBuilders <= 0))
  2770.       {
  2771.          aiEcho("Resign: numSettlements("+numSettlements+"): numBuilders("+numBuilders+")");
  2772.          gResignType = cResignSettlements;
  2773.          //aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptAIResignSettlements, -1);
  2774.          aiAttemptResign(cAICommPromptResignQuestion);
  2775.          xsDisableSelf();
  2776.          return;
  2777.       }
  2778.    }
  2779.    //Don't quit if we have more than one settlement.
  2780.    if (numSettlements > 1)
  2781.       return;
  2782.  
  2783.    //3. if all of my teammates have left the game.
  2784.    int activeEnemies=0;
  2785.    int activeTeammates=0;
  2786.    int deadTeammates=0;
  2787.    float currentEnemyMilPop=0.0;
  2788.    float currentMilPop=0.0;
  2789.    for (i=1; < cNumberPlayers)
  2790.    {
  2791.       if (i == cMyID)
  2792.       {
  2793.          currentMilPop=currentMilPop+kbUnitCount(i, cUnitTypeMilitary, cUnitStateAlive);
  2794.          continue;
  2795.       }
  2796.  
  2797.       if (kbIsPlayerAlly(i) == false)
  2798.       {
  2799.          //Increment the active number of enemies there currently are.
  2800.          if (kbIsPlayerResigned(i) == false)
  2801.          {
  2802.             activeEnemies=activeEnemies+1;
  2803.             currentEnemyMilPop=currentEnemyMilPop+kbUnitCount(i, cUnitTypeMilitary, cUnitStateAlive);
  2804.          }
  2805.          continue;
  2806.       }
  2807.      
  2808.       //If I still have an active teammate, don't resign.
  2809.       if (kbIsPlayerResigned(i) == true)
  2810.          deadTeammates=deadTeammates+1;
  2811.       else
  2812.          activeTeammates=activeTeammates+1;
  2813.    }
  2814.  
  2815.    //3a. if at least one player from my team has left the game and I am the only player left on my team, 
  2816.    //    and the other team(s) have 2 or more players in the game.
  2817.    if ((activeEnemies >= 2) && (activeTeammates <= 0) && (deadTeammates>0))
  2818.    {
  2819.       aiEcho("Resign: activeEnemies ("+activeEnemies +"): activeTeammates ("+activeTeammates +"), deadTeammates ("+deadTeammates +")");
  2820.       gResignType=cResignTeammates;
  2821.       //aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptAIResignActiveEnemies, -1);
  2822.       aiAttemptResign(cAICommPromptResignQuestion);
  2823.       xsDisableSelf();
  2824.       return;
  2825.    }
  2826.    
  2827.    //4. my mil pop is low and the enemy's mil pop is high,
  2828.    //Don't do this eval until 4th age and at least 30 min. into the game.
  2829.    if ((xsGetTime() < 1800000) || (kbGetAge() < 3))
  2830.      return;
  2831.    
  2832.    static float enemyMilPopTotal=0.0;
  2833.    static float myMilPopTotal=0.0;
  2834.    static float count=0.0;
  2835.    count=count+1.0;
  2836.    enemyMilPopTotal=enemyMilPopTotal+currentEnemyMilPop;
  2837.    myMilPopTotal=myMilPopTotal+currentMilPop;
  2838.    if (count >= 10.0)
  2839.    {
  2840.       if ((enemyMilPopTotal > (7.0*myMilPopTotal)) || (myMilPopTotal <= count))
  2841.       {
  2842.          aiEcho("Resign: Count("+count+"): EMP Total("+enemyMilPopTotal+"), MMP Total("+myMilPopTotal+")");
  2843.          aiEcho("Resign: EMP Current("+currentEnemyMilPop+"), MMP Current("+currentMilPop+")");
  2844.         
  2845.          gResignType=cResignMilitaryPop;
  2846.          //aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptAIResignActiveEnemies, -1);
  2847.          aiAttemptResign(cAICommPromptResignQuestion);
  2848.          xsDisableSelf();
  2849.          return;
  2850.       }
  2851.  
  2852.       count=0.0;
  2853.       enemyMilPopTotal=0.0;
  2854.       myMilPopTotal=0.0;
  2855.    }
  2856. }
  2857.  
  2858.  
  2859. //==============================================================================
  2860. // resignTimer
  2861. //==============================================================================
  2862. rule resignTimer
  2863.    minInterval 60
  2864.    inactive
  2865. {
  2866.    //This rule turns the resign rule back on after a bit of time.
  2867.    //Used when the human player refuses to allow quarter
  2868.  
  2869.    static bool bFirstUpdate=false;
  2870.    if (bFirstUpdate == false)
  2871.    {
  2872.       bFirstUpdate=true;
  2873.       return;
  2874.    }
  2875.    xsEnableRule("ShouldIResign");
  2876. }
  2877.  
  2878.  
  2879. //==============================================================================
  2880. // findVinlandsagaBase
  2881. //==============================================================================
  2882. rule findVinlandsagaBase
  2883.    minInterval 10
  2884.    inactive
  2885. {
  2886.    //Save our initial base ID.
  2887.    gVinlandsagaInitialBaseID=kbBaseGetMainID(cMyID);
  2888.  
  2889.    //Get our initial location.
  2890.    vector location=kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID));
  2891.    //Find the mainland area group.
  2892.    int mainlandGroupID=-1;
  2893.    if (cRandomMapName == "vinlandsaga")
  2894.       mainlandGroupID=kbFindAreaGroup(cAreaGroupTypeLand, 3.0, kbAreaGetIDByPosition(location));
  2895.    else
  2896.       mainlandGroupID=kbFindAreaGroupByLocation(cAreaGroupTypeLand, 0.5, 0.5);
  2897.    if (mainlandGroupID < 0)
  2898.       return;
  2899.    aiEcho("findVinlandsagaBase: Found the mainland, AGID="+mainlandGroupID+".");
  2900.  
  2901.    //Create the mainland base.
  2902.    int mainlandBaseGID=createBaseGoal("Mainland Base", cGoalPlanGoalTypeMainBase,
  2903.       -1, 1, 0, -1, kbBaseGetMainID(cMyID));
  2904.    if (mainlandBaseGID >= 0)
  2905.    {
  2906.       //Set the area ID.
  2907.       aiPlanSetVariableInt(mainlandBaseGID, cGoalPlanAreaGroupID, 0, mainlandGroupID);
  2908.       //Create the callback goal.
  2909.       int callbackGID=createCallbackGoal("Vinlandsaga Base Callback", "vinlandsagaBaseCallback",
  2910.          1, 0, -1, false);
  2911.       if (callbackGID >= 0)
  2912.          aiPlanSetVariableInt(mainlandBaseGID, cGoalPlanDoneGoal, 0, callbackGID);
  2913.    }
  2914.  
  2915.    //Done.
  2916.    xsDisableSelf();
  2917. }  
  2918.  
  2919. //==============================================================================
  2920. // vindlandsagaEnableFishing
  2921. //==============================================================================
  2922. rule vindlandsagaEnableFishing
  2923.    minInterval 10
  2924.    inactive
  2925. {
  2926.    //See how many wood dropsites we have.
  2927.    static int wdQueryID=-1;
  2928.    //If we don't have a query ID, create it.
  2929.    if (wdQueryID < 0)
  2930.    {
  2931.       wdQueryID=kbUnitQueryCreate("Wood Dropsite Query");
  2932.       //If we still don't have one, bail.
  2933.       if (wdQueryID < 0)
  2934.          return;
  2935.       //Else, setup the query data.
  2936.       kbUnitQuerySetPlayerID(wdQueryID, cMyID);
  2937.       if (cMyCulture == cCultureGreek)
  2938.          kbUnitQuerySetUnitType(wdQueryID, cUnitTypeStorehouse);
  2939.       else if (cMyCulture == cCultureEgyptian)
  2940.          kbUnitQuerySetUnitType(wdQueryID, cUnitTypeLumberCamp);
  2941.       else if (cMyCulture == cCultureNorse)
  2942.          kbUnitQuerySetUnitType(wdQueryID, cUnitTypeLogicalTypeLandMilitary);
  2943.       kbUnitQuerySetAreaGroupID(wdQueryID, kbAreaGroupGetIDByPosition(kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID))) );
  2944.       kbUnitQuerySetState(wdQueryID, cUnitStateAlive);
  2945.    }
  2946.    //Reset the results.
  2947.    kbUnitQueryResetResults(wdQueryID);
  2948.    //Run the query.  If we don't have anything, skip.
  2949.    if (kbUnitQueryExecute(wdQueryID) <= 0)
  2950.       return;
  2951.  
  2952.    //Enable the rule.
  2953.    xsEnableRule("fishing");
  2954.    //Unpause the age upgrades.
  2955.    aiSetPauseAllAgeUpgrades(false);
  2956.    //Unpause the pause kicker.
  2957.    xsEnableRule("unPauseAge2");
  2958.    xsSetRuleMinInterval("unPauseAge2", 15);
  2959.  
  2960.    //Create a simple plan to maintain X Ulfsarks (since we didn't do this as part of initNorse).
  2961.    createSimpleMaintainPlan(cUnitTypeUlfsark, gMaintainNumberLandScouts+1, true, kbBaseGetMainID(cMyID));
  2962.  
  2963.    //Disable us.
  2964.    xsDisableSelf();
  2965. }  
  2966.  
  2967. //==============================================================================
  2968. // vinlandsagaBaseCallback
  2969. //==============================================================================
  2970. void vinlandsagaBaseCallback(int parm1=-1)
  2971. {
  2972.    aiEcho("VinlandsagaBaseCallback:");
  2973.  
  2974.    //Get our water transport type.
  2975.    int transportPUID=kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionWaterTransport, 0);
  2976.    if (transportPUID < 0)
  2977.       return;
  2978.    //Get our main base.  This needs to be different than our initial base.
  2979.    if (kbBaseGetMainID(cMyID) == gVinlandsagaInitialBaseID)
  2980.       return;
  2981.  
  2982.    //Kill the transport explore plan.
  2983.    aiPlanDestroy(gVinlandsagaTransportExplorePlanID);
  2984.    //Kill the land scout explore.
  2985.    aiPlanDestroy(gLandExplorePlanID);
  2986.    //Create a new land based explore plan for the mainland.
  2987.     gLandExplorePlanID=aiPlanCreate("Explore_Land_VS", cPlanExplore);
  2988.    if (gLandExplorePlanID >= 0)
  2989.    {
  2990.       aiPlanAddUnitType(gLandExplorePlanID, gLandScout, 1, 1, 1);
  2991.       aiPlanSetActive(gLandExplorePlanID);
  2992.       aiPlanSetEscrowID(gLandExplorePlanID, cEconomyEscrowID);
  2993.       aiPlanSetBaseID(gLandExplorePlanID, kbBaseGetMainID(cMyID));
  2994.       //Don't loop as egyptian.
  2995.       if (cMyCulture == cCultureEgyptian)
  2996.          aiPlanSetVariableBool(gLandExplorePlanID, cExplorePlanDoLoops, 0, false);
  2997.    }
  2998.  
  2999.    //Get our start area ID.
  3000.    int startAreaID=kbAreaGetIDByPosition(kbBaseGetLocation(cMyID, gVinlandsagaInitialBaseID));
  3001.    //Get our goal area ID.
  3002.    int goalAreaID=kbAreaGetIDByPosition(kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID)));
  3003.  
  3004.    //Create the scout xport plan.  If it works, add the unit type(s).
  3005.    int planID=createTransportPlan("Scout Transport", startAreaID, goalAreaID,
  3006.       false, transportPUID, 100, gVinlandsagaInitialBaseID);
  3007.    if (planID >= 0)
  3008.    {
  3009.       aiPlanAddUnitType(planID, gLandScout, 1, 1, 1);
  3010.       if (cMyCulture == cCultureNorse)
  3011.          aiPlanAddUnitType(planID, cUnitTypeOxCart, 1, 1, 1);
  3012.       //We require all need units on this one.
  3013.       aiPlanSetRequiresAllNeedUnits(planID, true);
  3014.    }
  3015.  
  3016.    //Create the villager xport plan.  If it works, add the unit type(s).
  3017.    planID=createTransportPlan("Villager Transport", startAreaID, goalAreaID,
  3018.       true, transportPUID, 75, gVinlandsagaInitialBaseID);
  3019.    if (planID >= 0)
  3020.    {
  3021.       aiPlanAddUnitType(planID, cUnitTypeAbstractVillager, 1, 5, 5);
  3022.       aiPlanAddUnitType(planID, cUnitTypeLogicalTypeLandMilitary, 0, 1, 1);
  3023.       if (cMyCulture == cCultureNorse)
  3024.          aiPlanAddUnitType(planID, cUnitTypeOxCart, 0, 1, 4);
  3025.    }
  3026.  
  3027.    //change the farming baseID
  3028.    gFarmBaseID=kbBaseGetMainID(cMyID);
  3029.  
  3030.    //Allow auto dropsites again.
  3031.    aiSetAllowAutoDropsites(true);
  3032.    aiSetAllowBuildings(true);
  3033.  
  3034.    //Enable the rule that will eventually enable fishing and other stuff.
  3035.    xsEnableRule("vindlandsagaEnableFishing");
  3036. }
  3037.  
  3038. //==============================================================================
  3039. // nomadBuildSettlementCallBack
  3040. //==============================================================================
  3041. void nomadBuildSettlementCallBack(int parm1=-1)
  3042. {
  3043.    aiEcho("nomadBuildSettlementCallBack:");
  3044.  
  3045.    //Find our one settlement.and make it the main base.
  3046.    int settlementID=findUnit(cMyID, cUnitStateAliveOrBuilding, cUnitTypeAbstractSettlement);
  3047.    if (settlementID < 0)
  3048.    {
  3049.       //Enable the rule that looks for a settlement.
  3050.       int nomadSettlementGoalID=createBuildSettlementGoal("BuildNomadSettlement", 0, -1, -1, 1, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder,0), true, 100);
  3051.       if (nomadSettlementGoalID != -1)
  3052.       {
  3053.          //Create the callback goal.
  3054.          int nomadCallbackGID=createCallbackGoal("Nomad BuildSettlement Callback", "nomadBuildSettlementCallBack", 1, 0, -1, false);
  3055.          if (nomadCallbackGID >= 0)
  3056.             aiPlanSetVariableInt(nomadSettlementGoalID, cGoalPlanDoneGoal, 0, nomadCallbackGID);
  3057.       }
  3058.       return;
  3059.    }
  3060.  
  3061.    //Kill the villie explore plan.
  3062.    aiPlanDestroy(gNomadExplorePlanID);
  3063.  
  3064.    //Find our one settlement and make it the main base.
  3065.    int newBaseID=kbUnitGetBaseID(findUnit(cMyID, cUnitStateAliveOrBuilding, cUnitTypeAbstractSettlement));
  3066.    aiSwitchMainBase(newBaseID, true);
  3067.    kbBaseSetMain(cMyID, newBaseID, true);
  3068.  
  3069.    //Unpause the age upgrades.
  3070.    aiSetPauseAllAgeUpgrades(false);
  3071.    //Unpause the pause kicker.
  3072.    xsEnableRule("unPauseAge2");
  3073.    xsSetRuleMinInterval("unPauseAge2", 15);
  3074.  
  3075.    //Turn on buildhouse.
  3076.    xsEnableRule("buildHouse");
  3077. }
  3078.  
  3079. //==============================================================================
  3080. // build handler
  3081. //==============================================================================
  3082. void buildHandler(int protoID=-1) 
  3083. {
  3084.    if (protoID == cUnitTypeSettlement)
  3085.    {
  3086.       for (i=1; < cNumberPlayers)
  3087.       {
  3088.          if (i == cMyID)
  3089.             continue;
  3090.          if (kbIsPlayerAlly(i) == true)
  3091.             continue;
  3092.          if( cvOkToChat == true ) aiCommsSendStatement(i, cAICommPromptAIBuildSettlement, -1);
  3093.       }
  3094.    }
  3095. }
  3096.  
  3097. //==============================================================================
  3098. // god power handler
  3099. //==============================================================================
  3100. void gpHandler(int powerProtoID=-1)
  3101.    if (powerProtoID == -1)
  3102.       return;
  3103.    if (powerProtoID == cPowerSpy)
  3104.       return;
  3105.  
  3106.    //Most hated player chats.
  3107.    if ((powerProtoID == cPowerPlagueofSerpents) ||
  3108.       (powerProtoID == cPowerEarthquake)        ||
  3109.       (powerProtoID == cPowerCurse)             ||
  3110.       (powerProtoID == cPowerFlamingWeapons)    || 
  3111.       (powerProtoID == cPowerForestFire)        ||
  3112.       (powerProtoID == cPowerFrost)             ||
  3113.       (powerProtoID == cPowerLightningStorm)    ||
  3114.       (powerProtoID == cPowerLocustSwarm)       ||
  3115.       (powerProtoID == cPowerMeteor)            ||
  3116.       (powerProtoID == cPowerAncestors)         ||
  3117.       (powerProtoID == cPowerFimbulwinter)      ||
  3118.       (powerProtoID == cPowerTornado)           ||
  3119.       (powerProtoID == cPowerBolt))
  3120.    {
  3121.       if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptOffensiveGodPower, -1);
  3122.       return;
  3123.    }
  3124.    
  3125.    //Any player chats.
  3126.    int type=cAICommPromptGenericGodPower;
  3127.    if ((powerProtoID == cPowerProsperity) || 
  3128.       (powerProtoID == cPowerPlenty)      ||
  3129.       (powerProtoID == cPowerLure)        ||
  3130.       (powerProtoID == cPowerDwarvenMine) ||
  3131.       (powerProtoID == cPowerGreatHunt)   ||
  3132.       (powerProtoID == cPowerRain))
  3133.    {
  3134.       type=cAICommPromptEconomicGodPower;
  3135.    }
  3136.  
  3137.    //Tell all the enemy players
  3138.    for (i=1; < cNumberPlayers)
  3139.    {
  3140.       if (i == cMyID)
  3141.          continue;
  3142.       if (kbIsPlayerAlly(i) == true)
  3143.          continue;
  3144.       if( cvOkToChat == true ) aiCommsSendStatement(i, type, -1);
  3145.    }
  3146. }
  3147.  
  3148. //==============================================================================
  3149. // wonder death handler
  3150. //==============================================================================
  3151. void wonderDeathHandler(int playerID = -1)
  3152. {
  3153.    if (playerID == cMyID)
  3154.    {
  3155.       if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptAIWonderDestroyed, -1);
  3156.       return;
  3157.    }
  3158.    if (playerID == aiGetMostHatedPlayerID())
  3159.       if( cvOkToChat == true ) aiCommsSendStatement(playerID, cAICommPromptPlayerWonderDestroyed, -1);
  3160. }
  3161.  
  3162.  
  3163. //==============================================================================
  3164. // retreat handler
  3165. //==============================================================================
  3166. void retreatHandler(int planID = -1)
  3167. {
  3168.    if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptAIRetreat, -1);
  3169. }
  3170.  
  3171. //==============================================================================
  3172. // relic handler
  3173. //==============================================================================
  3174. void relicHandler(int relicID = -1)
  3175. {
  3176.    if (aiRandInt(3) != 0)
  3177.       return;
  3178.  
  3179.    for (i=1; < cNumberPlayers)
  3180.    {
  3181.       if (i == cMyID)
  3182.          continue;
  3183.  
  3184.       //Only a 33% chance for either of these chats
  3185.       if (kbIsPlayerAlly(i) == true)
  3186.       {
  3187.          if (relicID != -1)
  3188.          {
  3189.             vector position = kbUnitGetPosition(relicID);
  3190.             if( cvOkToChat == true ) aiCommsSendStatementWithVector(i, cAICommPromptTakingAllyRelic, -1, position);
  3191.          }
  3192.          else 
  3193.             if( cvOkToChat == true ) aiCommsSendStatement(i, cAICommPromptTakingAllyRelic, -1);
  3194.       }
  3195.       else 
  3196.          if( cvOkToChat == true ) aiCommsSendStatement(i, cAICommPromptTakingEnemyRelic, -1);
  3197.    }
  3198. }
  3199.  
  3200. //==============================================================================
  3201. // relic handler
  3202. //==============================================================================
  3203. void resignHandler(int result =-1)
  3204. {
  3205.    if (result == 0)
  3206.    {
  3207.       //xsEnableRule("resignTimer");
  3208.       return;
  3209.    }
  3210.  
  3211.    if (gResignType == cResignGatherers)
  3212.    {
  3213.       aiResign();
  3214.       return;
  3215.    }
  3216.    if (gResignType == cResignSettlements)
  3217.    {
  3218.       aiResign();
  3219.       return;
  3220.    }
  3221.    if (gResignType == cResignTeammates)
  3222.    {
  3223.       aiResign();
  3224.       return;
  3225.    }
  3226.    if (gResignType == cResignMilitaryPop)
  3227.    {
  3228.      aiResign();
  3229.      return;
  3230.    }
  3231. }
  3232.  
  3233. //==============================================================================
  3234. // attackChatCallback
  3235. //==============================================================================
  3236. void attackChatCallback(int parm1=-1)
  3237. {
  3238.     if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptAIAttack, -1); 
  3239. }
  3240.  
  3241. //==============================================================================
  3242. // findTownDefenseGP
  3243. //==============================================================================
  3244. void findTownDefenseGP(int baseID=-1)
  3245. {
  3246.  
  3247.    if (gTownDefenseGodPowerPlanID != -1)
  3248.       return;
  3249.    gTownDefenseGodPowerPlanID=aiFindBestTownDefenseGodPowerPlan();
  3250.    if (gTownDefenseGodPowerPlanID == -1)
  3251.       return;
  3252.  
  3253.    //Change the evaluation model (and remember it).
  3254.    gTownDefenseEvalModel=aiPlanGetVariableInt(gTownDefenseGodPowerPlanID, cGodPowerPlanEvaluationModel, 0);
  3255.    aiPlanSetVariableInt(gTownDefenseGodPowerPlanID, cGodPowerPlanEvaluationModel, 0, cGodPowerEvaluationModelCombatDistancePosition);
  3256.    //Change the player (and remember it).
  3257.    gTownDefensePlayerID=aiPlanGetVariableInt(gTownDefenseGodPowerPlanID, cGodPowerPlanQueryPlayerID, 0);
  3258.    //Set the location.
  3259.    aiPlanSetVariableVector(gTownDefenseGodPowerPlanID, cGodPowerPlanQueryLocation, 0, kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID)) );
  3260. }
  3261.  
  3262. //==============================================================================
  3263. // releaseTownDefenseGP
  3264. //==============================================================================
  3265. void releaseTownDefenseGP()
  3266. {
  3267.    if (gTownDefenseGodPowerPlanID == -1)
  3268.       return;
  3269.    //Change the evaluation model back.
  3270.    aiPlanSetVariableInt(gTownDefenseGodPowerPlanID, cGodPowerPlanEvaluationModel, 0, gTownDefenseEvalModel);
  3271.    //Reset the player.
  3272.    aiPlanSetVariableInt(gTownDefenseGodPowerPlanID, cGodPowerPlanQueryPlayerID, 0, gTownDefensePlayerID);
  3273.    //Release the plan.
  3274.    gTownDefenseGodPowerPlanID=-1;
  3275.    gTownDefenseEvalModel=-1; 
  3276.    gTownDefensePlayerID=-1;
  3277. }
  3278.  
  3279. //==============================================================================
  3280. // RULE introChat
  3281. //==============================================================================
  3282. rule introChat
  3283.    minInterval 15
  3284.    active
  3285. {
  3286.    if (aiGetWorldDifficulty() != cDifficultyEasy)
  3287.    {
  3288.       for (i=1; < cNumberPlayers)
  3289.       {
  3290.          if (i == cMyID)
  3291.             continue;
  3292.          if (kbIsPlayerAlly(i) == true)
  3293.             continue;
  3294.          if (kbIsPlayerHuman(i) == true)
  3295.             if( cvOkToChat == true ) aiCommsSendStatement(i, cAICommPromptIntro, -1); 
  3296.       }
  3297.    }
  3298.  
  3299.    xsDisableSelf();
  3300. }
  3301.  
  3302. //==============================================================================
  3303. // RULE myAgeTracker
  3304. //==============================================================================
  3305. rule myAgeTracker
  3306.    minInterval 60
  3307.    active
  3308. {
  3309.    static bool bMessage=false;
  3310.    static int messageAge=-1;
  3311.  
  3312.    //Disable this in deathmatch.
  3313.    if (aiGetGameMode() == cGameModeDeathmatch)
  3314.    {
  3315.       xsDisableSelf();
  3316.       return;
  3317.    }
  3318.  
  3319.    //Only the captain does this.
  3320.    if (aiGetCaptainPlayerID(cMyID) != cMyID)
  3321.       return;
  3322.  
  3323.    //Are we greater age than our most hated enemy?
  3324.    int myAge=kbGetAge();
  3325.    int hatedPlayerAge=kbGetAgeForPlayer(aiGetMostHatedPlayerID());
  3326.  
  3327.    //Reset the message counter if we have changed ages.
  3328.    if (bMessage == true)
  3329.    {
  3330.       if (messageAge == myAge)
  3331.          return;
  3332.       bMessage=false;
  3333.    }
  3334.  
  3335.    //Make a message??
  3336.    if ((myAge > hatedPlayerAge) && (bMessage == false))
  3337.    {
  3338.       bMessage=true;
  3339.       messageAge=myAge;
  3340.       if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptAIWinningAgeRace, -1);
  3341.    }
  3342.    if ((hatedPlayerAge > myAge) && (bMessage == false))
  3343.    {
  3344.       bMessage=true;
  3345.       messageAge=myAge;
  3346.       if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptAILosingAgeRace, -1);
  3347.    }
  3348.  
  3349.    //Stop when we reach the finish line.
  3350.    if (myAge == cAge4)
  3351.       xsDisableSelf();
  3352. }
  3353.  
  3354. //==============================================================================
  3355. // RULE mySettlementTracker
  3356. //==============================================================================
  3357. rule mySettlementTracker
  3358.    minInterval 11
  3359.    active
  3360. {
  3361.    static int tcCountQueryID=-1;
  3362.    //Only the captain does this
  3363.    if (aiGetCaptainPlayerID(cMyID) != cMyID)
  3364.       return;
  3365.  
  3366.    //If we don't have a query ID, create it.
  3367.    if (tcCountQueryID < 0)
  3368.    {
  3369.       tcCountQueryID=kbUnitQueryCreate("SettlementCount");
  3370.       //If we still don't have one, bail.
  3371.       if (tcCountQueryID < 0)
  3372.          return;
  3373.    }
  3374.  
  3375.    //Else, setup the query data.
  3376.    kbUnitQuerySetPlayerID(tcCountQueryID, cMyID);
  3377.    kbUnitQuerySetUnitType(tcCountQueryID, cUnitTypeAbstractSettlement);
  3378.    kbUnitQuerySetState(tcCountQueryID, cUnitStateAlive);
  3379.  
  3380.    //Reset the results.
  3381.    kbUnitQueryResetResults(tcCountQueryID);
  3382.    //Run the query.  Be dumb and just take the first TC for now.
  3383.    int count=kbUnitQueryExecute(tcCountQueryID);
  3384.  
  3385.    if ((count < gNumberMySettlements) && (gNumberMySettlements != -1))
  3386.    {
  3387.       if (count == 0)
  3388.          if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptAILostLastSettlement, -1);
  3389.       else
  3390.          if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptAILostSettlement, -1);
  3391.    }
  3392.  
  3393.    //Set the number.
  3394.    gNumberMySettlements=count;
  3395. }
  3396.  
  3397. //==============================================================================
  3398. // RULE earlySettlementTracker
  3399. //==============================================================================
  3400. rule earlySettlementTracker
  3401.    minInterval 7
  3402.    active
  3403. {
  3404.    //If this is 3rd age, go away.
  3405.    if (kbGetAge() >= 2)
  3406.    {
  3407.       xsDisableSelf();
  3408.       return;
  3409.    }
  3410.  
  3411.    //If we have no alive or building settlements, return.
  3412.    if (kbUnitCount(cMyID, cUnitTypeAbstractSettlement, cUnitStateAliveOrBuilding) > 0)
  3413.       return;
  3414.    //If we have a plan to build a settlement, return.
  3415.    if (aiPlanGetIDByTypeAndVariableType(cPlanBuild, cBuildPlanBuildingTypeID, cUnitTypeSettlementLevel1) > -1)
  3416.       return;
  3417.  
  3418.    xsEnableRule("buildSettlements");
  3419. }
  3420.  
  3421. //==============================================================================
  3422. // RULE enemySettlementTracker
  3423. //==============================================================================
  3424. rule enemySettlementTracker
  3425.    minInterval 9
  3426.    active
  3427. {
  3428.   //Only the captain does this.
  3429.    if (aiGetCaptainPlayerID(cMyID) != cMyID)
  3430.       return;
  3431.  
  3432.    if (gTrackingPlayer == -1)
  3433.       gTrackingPlayer = aiGetMostHatedPlayerID(); 
  3434.  
  3435.    bool reset=false;
  3436.    if (aiGetMostHatedPlayerID() != gTrackingPlayer)
  3437.    {
  3438.       gTrackingPlayer = aiGetMostHatedPlayerID();
  3439.       gNumberTrackedPlayerSettlements = -1;
  3440.       reset = true;
  3441.    }
  3442.  
  3443.    if (gTrackingPlayer == -1)
  3444.       return;
  3445.  
  3446.    static int tcCountQueryID=-1;
  3447.    //If we don't have a query ID, create it.
  3448.    if (tcCountQueryID < 0)
  3449.    {
  3450.       tcCountQueryID=kbUnitQueryCreate("SettlementCount");
  3451.       //If we still don't have one, bail.
  3452.       if (tcCountQueryID < 0)
  3453.          return;
  3454.    }
  3455.  
  3456.    //Else, setup the query data.
  3457.    kbUnitQuerySetPlayerID(tcCountQueryID, gTrackingPlayer);
  3458.    kbUnitQuerySetUnitType(tcCountQueryID, cUnitTypeAbstractSettlement);
  3459.    kbUnitQuerySetState(tcCountQueryID, cUnitStateAlive);
  3460.  
  3461.    //Reset the results.
  3462.    kbUnitQueryResetResults(tcCountQueryID);
  3463.    //Run the query.  Be dumb and just take the first TC for now.
  3464.    int count=kbUnitQueryExecute(tcCountQueryID);
  3465.  
  3466.    //If we are doing a reset, then just get out after storing the count.
  3467.    if (reset == true)
  3468.    {
  3469.       gNumberTrackedPlayerSettlements=count;
  3470.       return;
  3471.    }
  3472.  
  3473.    //If the number of settlements is greater than 1, and we have not sent a message.
  3474.    if ((count > 1) && (gNumberTrackedPlayerSettlements == -1))
  3475.    {
  3476.       if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptEnemyBuildSettlement, -1);
  3477.       gNumberTrackedPlayerSettlements=count;
  3478.    }
  3479.  
  3480.    //If the number of settlements is equal to one and we have sent a message
  3481.    //about them growing, then send one about the loss of territory
  3482.    if ((count == 1) && (gNumberTrackedPlayerSettlements > 1))
  3483.    {
  3484.       if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptEnemyLostSettlement, -1);
  3485.       gNumberTrackedPlayerSettlements=1;
  3486.    }
  3487.  
  3488.    //The count is = 0, and we think they have nothing left, and we have already sent a message
  3489.    if ((count == 0) && (gNumberTrackedPlayerSettlements != -1))
  3490.    { 
  3491.       if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptEnemyLostSettlement, -1);
  3492.       gNumberTrackedPlayerSettlements=-1;
  3493.    }
  3494. }
  3495.  
  3496. //==============================================================================
  3497. // RULE enemyWallTracker
  3498. //==============================================================================
  3499. rule enemyWallTracker
  3500.    minInterval 61
  3501.    active
  3502. {
  3503.    static int wallCountQueryID=-1;
  3504.    //Only the captain does this.
  3505.    if (aiGetCaptainPlayerID(cMyID) != cMyID)
  3506.       return;
  3507.  
  3508.    //If we don't have a query ID, create it.
  3509.    if (wallCountQueryID < 0)
  3510.    {
  3511.       wallCountQueryID=kbUnitQueryCreate("WallCount");
  3512.       //If we still don't have one, bail.
  3513.       if (wallCountQueryID < 0)
  3514.          return;
  3515.    }
  3516.  
  3517.    //Else, setup the query data.
  3518.    kbUnitQuerySetPlayerID(wallCountQueryID, aiGetMostHatedPlayerID());
  3519.    kbUnitQuerySetUnitType(wallCountQueryID, cUnitTypeAbstractWall);
  3520.    kbUnitQuerySetState(wallCountQueryID, cUnitStateAlive);
  3521.  
  3522.    //Reset the results.
  3523.    kbUnitQueryResetResults(wallCountQueryID);
  3524.    //Run the query. 
  3525.    int count=kbUnitQueryExecute(wallCountQueryID);
  3526.  
  3527.    //Do we have enough knowledge of walls to send a message?
  3528.    if (count > 10)
  3529.    {
  3530.       if( cvOkToChat == true ) aiCommsSendStatement(aiGetMostHatedPlayerID(), cAICommPromptPlayerBuildingWalls, -1); 
  3531.       //Kill this rule.
  3532.       xsDisableSelf();  
  3533.    }
  3534. }
  3535.  
  3536. //==============================================================================
  3537. // RULE baseAttackTracker
  3538. //==============================================================================
  3539. rule baseAttackTracker
  3540.    minInterval 23
  3541.    active
  3542. {
  3543.    static bool messageSent=false;
  3544.    //Set our min interval back to 23 if it has been changed.
  3545.    if (messageSent == true)
  3546.    {
  3547.       xsSetRuleMinIntervalSelf(23);
  3548.       messageSent=false;
  3549.    }
  3550.  
  3551.    //Get our main base.
  3552.    int mainBaseID=kbBaseGetMainID(cMyID);
  3553.    if (mainBaseID < 0)
  3554.       return;
  3555.  
  3556.    //Get the time under attack.
  3557.    int secondsUnderAttack=kbBaseGetTimeUnderAttack(cMyID, mainBaseID);
  3558.    if (secondsUnderAttack < 30)
  3559.          return;
  3560.  
  3561.    vector location=kbBaseGetLastKnownDamageLocation(cMyID, kbBaseGetMainID(cMyID));
  3562.    for (i=1; < cNumberPlayers)
  3563.    {
  3564.       if (i == cMyID)
  3565.          continue;
  3566.       if(kbIsPlayerAlly(i) == true)
  3567.          if( cvOkToChat == true ) aiCommsSendStatementWithVector(i, cAICommPromptHelpHere, -1, location);
  3568.    } 
  3569.    
  3570.    //Try to use a god power to help us.
  3571.    findTownDefenseGP(kbBaseGetMainID(cMyID));  
  3572.  
  3573.    //Keep the books
  3574.    messageSent=true;
  3575.    xsSetRuleMinIntervalSelf(600);  
  3576. }
  3577.  
  3578. //==============================================================================
  3579. // RULE repairBuildings
  3580. //==============================================================================
  3581. rule repairBuildings
  3582.    minInterval 12
  3583.    inactive
  3584. {
  3585.    int buildingID=kbFindBestBuildingToRepair(kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID)), 50.0, 1.0, cUnitTypeBuildingsThatShoot);
  3586.    if (buildingID >= 0)
  3587.    {
  3588.       //Don't create another plan for the same building.
  3589.       if (aiPlanGetIDByTypeAndVariableType(cPlanRepair, cRepairPlanTargetID, buildingID, true) >= 0)
  3590.          return;
  3591.       
  3592.       //Create the plan.
  3593.       static int num=0;
  3594.       num=num+1;
  3595.       string planName="Repair_"+num;
  3596.       int planID=aiPlanCreate(planName, cPlanRepair);
  3597.       if (planID < 0)
  3598.          return;
  3599.  
  3600.       aiPlanSetDesiredPriority(planID, 100);
  3601.       aiPlanSetBaseID(planID, kbBaseGetMainID(cMyID));
  3602.       aiPlanSetVariableInt(planID, cRepairPlanTargetID, 0, buildingID);
  3603.       aiPlanSetInitialPosition(planID, kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID)));
  3604.       aiPlanAddUnitType(planID, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 1, 1, 5);
  3605.       aiPlanSetActive(planID);
  3606.    }
  3607. }
  3608.  
  3609. //==============================================================================
  3610. // RULE townDefense
  3611. //==============================================================================
  3612. rule townDefense
  3613.    minInterval 11
  3614.    inactive
  3615. {
  3616.    //Get our main base ID.
  3617.    int mainBaseID=kbBaseGetMainID(cMyID);
  3618.    if (mainBaseID < 0)
  3619.       return;
  3620.    //Get the time under attack.
  3621.    int secondsUnderAttack=kbBaseGetTimeUnderAttack(cMyID, mainBaseID);
  3622.  
  3623.    //Factor in a dulled Moderate response for the rest of this.
  3624.    if (aiGetWorldDifficulty() == cDifficultyModerate)
  3625.    {
  3626.       if (secondsUnderAttack < 30)
  3627.          return;
  3628.    }
  3629.    else
  3630.    {
  3631.       if (secondsUnderAttack < 10)
  3632.          return;
  3633.    }
  3634.  
  3635.    //If the enemy has > 4 military units that we've seen and we've been attacked in our town,
  3636.    //tower up.
  3637.    if (gBuildTowers == false)
  3638.    {
  3639.       int numHatedUnits=kbUnitCount(aiGetMostHatedPlayerID(), cUnitTypeMilitary, cUnitStateAlive);
  3640.       if (numHatedUnits > 4)
  3641.       {
  3642.          aiEcho("townDefense:  Player "+aiGetMostHatedPlayerID()+" has "+numHatedUnits+" units, building towers.");
  3643.          gBuildTowers=true;
  3644.          towerInBase("Defensive Towers", false, 2, cMilitaryEscrowID);
  3645.          xsEnableRule("towerUpgrade");
  3646.       }
  3647.    }
  3648.  
  3649.    //If we've been under siege for long enough, see if we have enough stuff to
  3650.    //be worried.
  3651.    int numberEnemyUnits=kbBaseGetNumberUnits(cMyID, mainBaseID, cPlayerRelationEnemy, cUnitTypeUnit);
  3652.    int numberEnemyMilitaryBuildings=kbBaseGetNumberUnits(cMyID, mainBaseID, cPlayerRelationEnemy, cUnitTypeMilitaryBuilding);
  3653.    if ((numberEnemyUnits < 2) && (numberEnemyMilitaryBuildings <= 0))
  3654.       return;
  3655.  
  3656.    //We're worried.  If we're in the first age, ensure that we go up fast.  If 
  3657.    //we're not in the first age, ensure that we have an attack goal setup for
  3658.    //the current age. If not, create one.
  3659.    switch (kbGetAge())
  3660.    {
  3661.       //First age.
  3662.       case 0:
  3663.       {
  3664.          //Go attack econ with minimal villagers.
  3665.          updateEM(50, 12, 0.5, 0.75, 0.5, 0.5, 0.5, 0.0);
  3666.          //Turn off the standard rule.
  3667.          xsDisableRule("updateEMAge1");
  3668.          break;
  3669.       }
  3670.  
  3671.       //Second age.
  3672.       case 1:
  3673.       {
  3674.          //Go attack econ with minimal villagers.
  3675.          updateEM(75, 22, 0.5, 0.75, 0.0, 0.0, 0.0, 0.0);
  3676.          //Turn off the standard rule.
  3677.          xsDisableRule("updateEMAge2");
  3678.          break;
  3679.       }
  3680.  
  3681.       //Don't do anything else in 3rd or 4th.
  3682.    }
  3683. }
  3684.  
  3685. //==============================================================================
  3686. // RULE fillInWallGaps
  3687. //==============================================================================
  3688. rule fillInWallGaps
  3689.    minInterval 31
  3690.    inactive
  3691. {
  3692.    //If we're not building walls, go away.
  3693.    if (gBuildWalls == false)
  3694.    {
  3695.       xsDisableSelf();
  3696.       return;
  3697.    }
  3698.  
  3699.    //If we already have a build wall plan, don't make another one.
  3700.    if(aiPlanGetIDByTypeAndVariableType(cPlanBuildWall, cBuildWallPlanWallType, cBuildWallPlanWallTypeRing, true) >= 0)
  3701.       return;
  3702.  
  3703.    int wallPlanID=aiPlanCreate("FillInWallGaps", cPlanBuildWall);
  3704.    if (wallPlanID != -1)
  3705.    {
  3706.       aiPlanSetVariableInt(wallPlanID, cBuildWallPlanWallType, 0, cBuildWallPlanWallTypeRing);
  3707.       aiPlanAddUnitType(wallPlanID, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 1, 3, 3);
  3708.       aiPlanSetVariableVector(wallPlanID, cBuildWallPlanWallRingCenterPoint, 0, kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID)));
  3709.       aiPlanSetVariableFloat(wallPlanID, cBuildWallPlanWallRingRadius, 0, 50.0);
  3710.       aiPlanSetVariableInt(wallPlanID, cBuildWallPlanNumberOfGates, 0, 5);
  3711.       aiPlanSetBaseID(wallPlanID, kbBaseGetMainID(cMyID));
  3712.       aiPlanSetEscrowID(wallPlanID, cEconomyEscrowID);
  3713.       aiPlanSetDesiredPriority(wallPlanID, 100);
  3714.       aiPlanSetActive(wallPlanID, true);
  3715.    }
  3716. }
  3717.  
  3718. //==============================================================================
  3719. // RULE findFish
  3720. //==============================================================================
  3721. rule findFish
  3722.    minInterval 11
  3723.    inactive
  3724. {
  3725.    //Create the fish query.
  3726.    static int unitQueryID=-1;
  3727.    if(unitQueryID < 0)
  3728.       unitQueryID = kbUnitQueryCreate("findFish");
  3729.     //Define a query to get all matching units
  3730.     if (unitQueryID == -1)
  3731.       return;
  3732.  
  3733.    //Run it.
  3734.     kbUnitQuerySetPlayerID(unitQueryID, 0);
  3735.    kbUnitQuerySetUnitType(unitQueryID, cUnitTypeFish);
  3736.    kbUnitQuerySetState(unitQueryID, cUnitStateAny);
  3737.     kbUnitQueryResetResults(unitQueryID);
  3738.     int numberFound=kbUnitQueryExecute(unitQueryID);
  3739.    if (numberFound > 0)
  3740.    {
  3741.       gWaterMap=true;
  3742.       
  3743.       //Tell the AI what kind of map we are on.
  3744.       aiSetWaterMap(gWaterMap);
  3745.  
  3746.       xsEnableRule("fishing");
  3747.  
  3748.       if (cMyCiv != cCivPoseidon)
  3749.          createSimpleMaintainPlan(gWaterScout, gMaintainNumberWaterScouts, true, -1);
  3750.  
  3751.       //Enable our naval attack goal starter.
  3752.       if (aiGetWorldDifficulty() != cDifficultyEasy)
  3753.          xsEnableRule("NavalGoalMonitor");
  3754.  
  3755.       //Fire up.
  3756.       if (gMaintainWaterXPortPlanID < 0)
  3757.          gMaintainWaterXPortPlanID=createSimpleMaintainPlan(kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionWaterTransport, 0), 1, false, -1);
  3758.  
  3759.       xsDisableSelf();
  3760.    }
  3761. }
  3762.  
  3763. //==============================================================================
  3764. // RULE getKingOfTheHillVault
  3765. //==============================================================================
  3766. rule getKingOfTheHillVault
  3767.    minInterval 17
  3768.    runImmediately
  3769.    active
  3770. {
  3771.    //If we're not on KOTH, go away.
  3772.    if ((cRandomMapName != "king of the hill") || (gKOTHPlentyUnitID == -1))
  3773.    {
  3774.       xsDisableSelf();
  3775.       return;
  3776.    }
  3777.  
  3778.    //If we already have a attack goals, then quit.
  3779.    if (aiPlanGetIDByTypeAndVariableType(cPlanGoal, cGoalPlanGoalType, cGoalPlanGoalTypeAttack, true) >= 0)
  3780.       return;
  3781.    //If we already have a scout plan for this, bail.
  3782.    if (aiPlanGetIDByTypeAndVariableType(cPlanExplore, cExplorePlanNumberOfLoops, -1, true) >= 0)
  3783.       return;
  3784.    
  3785.    //Create an explore plan to go there.
  3786.    vector unitLocation=kbUnitGetPosition(gKOTHPlentyUnitID);
  3787.    int exploreID=aiPlanCreate("getPlenty", cPlanExplore);
  3788.     if (exploreID >= 0)
  3789.     {
  3790.       aiPlanAddUnitType(exploreID, cUnitTypeLogicalTypeLandMilitary, 5, 5, 5);
  3791.       aiPlanAddWaypoint(exploreID, unitLocation);
  3792.       aiPlanSetVariableBool(exploreID, cExplorePlanDoLoops, 0, false);
  3793.       aiPlanSetVariableBool(exploreID, cExplorePlanQuitWhenPointIsVisible, 0, true);
  3794.       aiPlanSetVariableBool(exploreID, cExplorePlanAvoidingAttackedAreas, 0, false);
  3795.       aiPlanSetVariableInt(exploreID, cExplorePlanNumberOfLoops, 0, -1);
  3796.       aiPlanSetRequiresAllNeedUnits(exploreID, true);
  3797.       aiPlanSetVariableVector(exploreID, cExplorePlanQuitWhenPointIsVisiblePt, 0, unitLocation);
  3798.         aiPlanSetDesiredPriority(exploreID, 100);
  3799.       aiPlanSetActive(exploreID);
  3800.     }
  3801. }
  3802.  
  3803. //==============================================================================
  3804. // RULE trainNorseMythUnit
  3805. //==============================================================================
  3806. rule trainNorseMythUnit
  3807.    minInterval 18
  3808.    inactive
  3809. {
  3810.    //Get the PUID of a myth unit that we can train right now.
  3811.    int puid=kbGetRandomEnabledPUID(cUnitTypeMythUnit, cMilitaryEscrowID);
  3812.    if (puid < 0)
  3813.       return;
  3814.  
  3815.    //Create the plan.
  3816.    string planName="Norse Train "+kbGetProtoUnitName(puid);
  3817.    int planID=aiPlanCreate(planName, cPlanTrain);
  3818.    if (planID < 0)
  3819.       return;
  3820.    //Military.
  3821.    aiPlanSetMilitary(planID, true);
  3822.    //Unit type.
  3823.    aiPlanSetVariableInt(planID, cTrainPlanUnitType, 0, puid);
  3824.    //Number.
  3825.    aiPlanSetVariableInt(planID, cTrainPlanNumberToTrain, 0, 1);
  3826.    //Train at main base.
  3827.    int mainBaseID=kbBaseGetMainID(cMyID);
  3828.    if (mainBaseID >= 0)
  3829.    {
  3830.       aiPlanSetBaseID(planID, mainBaseID);
  3831.       aiPlanSetVariableVector(planID, cTrainPlanGatherPoint, 0, kbBaseGetMilitaryGatherPoint(cMyID, mainBaseID));
  3832.    }
  3833.  
  3834.    aiPlanSetActive(planID);
  3835. }
  3836.  
  3837. //==============================================================================
  3838. // RULE increaseSiegeWeaponUP
  3839. //==============================================================================
  3840. rule increaseSiegeWeaponUP
  3841.    minInterval 21
  3842.    inactive
  3843. {
  3844.    //See how many walls our enemies have built.  Create our query if
  3845.    //we don't already have one.
  3846.    static int wallQID=-1;
  3847.    if (wallQID < 0)
  3848.    {
  3849.       wallQID=kbUnitQueryCreate("wallQuery");
  3850.       kbUnitQuerySetPlayerRelation(wallQID, cPlayerRelationEnemy);
  3851.       kbUnitQuerySetUnitType(wallQID, cUnitTypeAbstractWall);
  3852.       kbUnitQuerySetState(wallQID, cUnitStateAlive);
  3853.    }
  3854.    //Reset the results.
  3855.     kbUnitQueryResetResults(wallQID);
  3856.  
  3857.    //If we find a "lot" of walls, bump our siege weapon percentage and go away.
  3858.     int numberWalls=kbUnitQueryExecute(wallQID);
  3859.    if (numberWalls > 20)
  3860.    {
  3861.       kbUnitPickSetPreferenceFactor(gLateUPID, cUnitTypeAbstractSiegeWeapon, 1.0);
  3862.       kbUnitPickSetCostWeight(gLateUPID, 0.25);
  3863.       xsDisableSelf();
  3864.    }
  3865. }
  3866.  
  3867. //==============================================================================
  3868. // RULE NavalGoalMonitor
  3869. //==============================================================================
  3870. rule NavalGoalMonitor
  3871.    minInterval 13
  3872.    inactive
  3873. {
  3874.    //Don't do anything in the first age.
  3875.    if ((kbGetAge() < 1) || (aiGetMostHatedPlayerID() < 0))
  3876.       return;
  3877.  
  3878.    //See if we have any enemy warships running around.
  3879.    int numberEnemyWarships=0;
  3880.    //Find the largest warship count for any of our enemies.
  3881.    for (i=0; < cNumberPlayers)
  3882.    {
  3883.       if ((kbIsPlayerEnemy(i) == true) &&
  3884.          (kbIsPlayerResigned(i) == false) &&
  3885.          (kbHasPlayerLost(i) == false))
  3886.       {
  3887.          int tempNumberEnemyWarships=kbUnitCount(i, cUnitTypeLogicalTypeNavalMilitary, cUnitStateAlive);
  3888.          //int tempNumberEnemyDocks=kbUnitCount(i, cUnitTypeDock, cUnitStateAlive);
  3889.          if (tempNumberEnemyWarships > numberEnemyWarships)
  3890.             numberEnemyWarships=tempNumberEnemyWarships;
  3891.       }
  3892.    }
  3893.    //Figure out the min/max number of warships we want.
  3894.    int minShips=0;
  3895.    int maxShips=0;
  3896.    if (numberEnemyWarships > 0)
  3897.    {
  3898.       //Build at most 2 ships on easy.
  3899.       if (aiGetWorldDifficulty() == cDifficultyEasy)
  3900.       {
  3901.          minShips=1;
  3902.          maxShips=2;
  3903.       }
  3904.       //Build at most "6" ships on moderate.
  3905.       else if (aiGetWorldDifficulty() == cDifficultyModerate)
  3906.       {
  3907.          minShips=numberEnemyWarships/2;
  3908.          maxShips=numberEnemyWarships*3/4;
  3909.          if (minShips < 1)
  3910.             minShips=1;
  3911.          if (maxShips < 1)
  3912.             maxShips=1;
  3913.          if (minShips > 3)
  3914.             minShips=3;
  3915.          if (maxShips > 6)
  3916.             maxShips=6;
  3917.       }
  3918.       //Build the "same" number (within reason) on Hard/Titan.
  3919.       else
  3920.       {
  3921.          minShips=numberEnemyWarships*3/4;
  3922.          maxShips=numberEnemyWarships;
  3923.          if (minShips < 1)
  3924.             minShips=1;
  3925.          if (maxShips < 1)
  3926.             maxShips=1;
  3927.          if (minShips > 5)
  3928.             minShips=5;
  3929.          if (maxShips > 8)
  3930.             maxShips=8;
  3931.       }
  3932.    }
  3933.  
  3934.    //If this is enabled on KOTH, that means we have the water version.  Pretend the enemy
  3935.    //has lots of boats so that we will have lots, too.
  3936.    if (cRandomMapName == "king of the hill")
  3937.    {
  3938.       minShips=6;
  3939.       maxShips=12;
  3940.    }
  3941.  
  3942.    //If we already have a Naval UP, just set the numbers and be done.  If we don't
  3943.    //want anything, just set 1 since we've already done it before.
  3944.    if (gNavalUPID >= 0)
  3945.    {
  3946.       if (maxShips <= 0)
  3947.       {
  3948.          kbUnitPickSetMinimumNumberUnits(gNavalUPID, 1);
  3949.          kbUnitPickSetMaximumNumberUnits(gNavalUPID, 1);
  3950.       }
  3951.       else
  3952.       {
  3953.          kbUnitPickSetMinimumNumberUnits(gNavalUPID, minShips);
  3954.          kbUnitPickSetMaximumNumberUnits(gNavalUPID, maxShips);
  3955.       }
  3956.       return;
  3957.    }
  3958.  
  3959.    //Else, we don't have a Naval attack goal yet.  If we don't want any ships,
  3960.    //just return.
  3961.    if (maxShips <= 0)
  3962.       return;
  3963.     
  3964.    //Else, create the Naval attack goal.
  3965.    aiEcho("Creating NavalAttackGoal for "+maxShips+" ships since I've seen "+numberEnemyWarships+" for Player "+aiGetMostHatedPlayerID()+".");
  3966.    gNavalUPID=kbUnitPickCreate("Naval");
  3967.    if (gNavalUPID < 0)
  3968.    {
  3969.       xsDisableSelf();
  3970.       return;
  3971.    }
  3972.    //Fill in the UP.
  3973.    kbUnitPickResetAll(gNavalUPID);
  3974.    kbUnitPickSetPreferenceWeight(gNavalUPID, 1.0);
  3975.    kbUnitPickSetCombatEfficiencyWeight(gNavalUPID, 2.0);
  3976.    kbUnitPickSetCostWeight(gNavalUPID, 2.0);
  3977.    kbUnitPickSetDesiredNumberUnitTypes(gNavalUPID, 3, 2, true);
  3978.    kbUnitPickSetMinimumNumberUnits(gNavalUPID, minShips);
  3979.    kbUnitPickSetMaximumNumberUnits(gNavalUPID, maxShips);
  3980.    kbUnitPickSetAttackUnitType(gNavalUPID, cUnitTypeLogicalTypeNavalMilitary);
  3981.    kbUnitPickSetGoalCombatEfficiencyType(gNavalUPID, cUnitTypeLogicalTypeNavalMilitary);
  3982.    kbUnitPickSetPreferenceFactor(gNavalUPID, cUnitTypeLogicalTypeNavalMilitary, 1.0);
  3983.    kbUnitPickSetMovementType(gNavalUPID, cMovementTypeWater);
  3984.    //Create the attack goal.
  3985.    gNavalAttackGoalID=createSimpleAttackGoal("Naval Attack", -1, gNavalUPID, -1, kbGetAge(), -1, -1, false);
  3986.    if (gNavalAttackGoalID < 0)
  3987.    {
  3988.       xsDisableSelf();
  3989.       return;
  3990.    }
  3991.    aiPlanSetVariableBool(gNavalAttackGoalID, cGoalPlanAutoUpdateBase, 0, false);
  3992.    aiPlanSetVariableBool(gNavalAttackGoalID, cGoalPlanSetAreaGroups, 0, false);
  3993. }
  3994.  
  3995. //==============================================================================
  3996. // RULE getOmniscience
  3997. //==============================================================================
  3998. rule getOmniscience
  3999.    minInterval 24
  4000.    inactive
  4001. {
  4002.    //If we can afford it twice over, then get it.
  4003.    float goldCost=kbTechCostPerResource(cTechOmniscience, cResourceGold) * 2.0;
  4004.    float currentGold=kbResourceGet(cResourceGold);
  4005.    if(goldCost>currentGold)
  4006.       return;
  4007.  
  4008.    //Get Omniscience
  4009.    int voePID=aiPlanCreate("GetOmniscience", cPlanProgression);
  4010.     if (voePID != 0)
  4011.    {
  4012.       aiPlanSetVariableInt(voePID, cProgressionPlanGoalTechID, 0, cTechOmniscience);
  4013.        aiPlanSetDesiredPriority(voePID, 25);
  4014.        aiPlanSetEscrowID(voePID, cMilitaryEscrowID);
  4015.        aiPlanSetActive(voePID);
  4016.    }
  4017.    xsDisableSelf();
  4018. }
  4019.  
  4020. //==============================================================================
  4021. // RULE getOlympicParentage
  4022. //==============================================================================
  4023. rule getOlympicParentage
  4024.    minInterval 16
  4025.    active
  4026. {
  4027.    //If we're not Zeus, go away.
  4028.    if (cMyCiv != cCivZeus)
  4029.    {
  4030.       xsDisableSelf();
  4031.       return;
  4032.    }
  4033.    //Skip if in 1st or 2nd age.
  4034.    if (kbGetAge() < 2)
  4035.       return;
  4036.    //If in 3rd, make sure we have enough food.
  4037.    if (kbGetAge() == 2)
  4038.    {
  4039.       if(kbResourceGet(cResourceFood) < 600)
  4040.          return;
  4041.    }
  4042.  
  4043.    //Get Olympic Parentage.
  4044.    int opPID=aiPlanCreate("GetOlympicParentage", cPlanProgression);
  4045.    if (opPID != 0)
  4046.    {
  4047.       aiPlanSetVariableInt(opPID, cProgressionPlanGoalTechID, 0, cTechOlympicParentage);
  4048.        aiPlanSetDesiredPriority(opPID, 25);
  4049.        aiPlanSetEscrowID(opPID, cMilitaryEscrowID);
  4050.        aiPlanSetActive(opPID);
  4051.    }
  4052.  
  4053.    xsDisableSelf();
  4054. }
  4055.  
  4056. //==============================================================================
  4057. // MAIN.
  4058. //==============================================================================
  4059. void main(void)
  4060. {
  4061.    //Set our random seed.  "-1" is a random init.
  4062.    aiRandSetSeed(-1);
  4063.  
  4064.    //If we have the "defaultrandom" personality, pick one of the others and
  4065.    //stuff it.  We handle all of this here so that none of the rest of the script
  4066.    //is polluted by this stuff.
  4067.    if (aiGetPersonality() == "defaultrandom")
  4068.    {
  4069.       int personalityRand=aiRandInt(2);
  4070.       if (personalityRand == 0)
  4071.          aiSetPersonality("default");
  4072.       else
  4073.          aiSetPersonality("defaultrush");
  4074.    }
  4075.  
  4076.    //We always rush on KOTH.
  4077.    if ((cRandomMapName == "king of the hill") && (aiGetWorldDifficulty() != cDifficultyEasy))
  4078.       aiSetPersonality("defaultrush");
  4079.    
  4080.    //Go.
  4081.    setParameters();     // Set the control variables before anything else
  4082.    init();
  4083.    setOverrides();      // Allow the loader to override anything it needs to.
  4084. }
  4085.