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