home *** CD-ROM | disk | FTP | other *** search
/ The Games Machine 8 (DVD) / XENIADVD08.iso / Fragzone / Files / AOM_MiniCampaign.exe / AI / mc04p2.xs < prev    next >
Encoding:
Text File  |  2002-12-09  |  150.9 KB  |  4,077 lines

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