home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2003 January / maximum-cd-2003-01.iso / Software / Games / AoM / mtrial.exe / AOM / AI / SCN18P2.XS < prev    next >
Encoding:
Text File  |  2002-09-17  |  37.9 KB  |  1,060 lines

  1. //==============================================================================
  2. // Scn18p2: AI Scenario Script for scenario 18 player 2.
  3. //==============================================================================
  4. /*
  5.    AI owner:  Dave Leary
  6.    Scenario owner: Joe "The Golem" Gillum
  7.  
  8.    Overview: 
  9.  
  10.                             *** DIFFICULTY LEVEL NOTES ***
  11.  
  12.    Easy level - Red player has fewer defenses.  Additional resources granted to
  13.     the player.
  14.  
  15.    Moderate level - Smallest of starting three gold mines goes away.
  16.  
  17.    Difficult - Only one gold mine near player's starting base.  Increased frequency
  18.     and severity of naval attacks.
  19.  
  20.    Nightmare - Only one gold mine near player's starting base, and it changes to
  21.     a tiny one. Very few trees.around player's base. Purple (allied) town has only 
  22.     a town center.  Large and painful naval attacks, including Leviathans.
  23. */
  24. //==============================================================================
  25. // Need scn lib for some stuff here.
  26. include "scn lib.xs";
  27.  
  28. // Variable for main base.
  29. int gMainBaseID=-1;
  30.  
  31. //==============================================================================
  32. // Set Town Location
  33. //==============================================================================
  34. void setTownLocation(void)
  35. {
  36.    //Look for the "Town Location" marker.
  37.    kbSetTownLocation(kbGetBlockPosition("9976"));
  38. }
  39.  
  40. //==============================================================================
  41. // miscStartup
  42. //==============================================================================
  43. void miscStartup(void)
  44. {
  45.     // Difficulty Level check.
  46.     int difflevel=-1;        
  47.     difflevel=aiGetWorldDifficulty();
  48.  
  49.    //Startup message(s).
  50.    aiEcho("");
  51.    aiEcho("");
  52.    aiEcho("Scn18P2 AI Start, filename='"+cFilename+"'.");
  53.     aiEcho("Difficulty Level="+difflevel+".");
  54.    //Spit out the map size.
  55.    aiEcho("  Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+").");
  56.    //Cheat like a bastard.  Once only, though.
  57.    kbLookAtAllUnitsOnMap();
  58.    //Calculate some areas.
  59.    kbAreaCalculate(1200.0);
  60.    //Set our town location.
  61.    setTownLocation();
  62.     //Reset random seed
  63.     aiRandSetSeed();
  64.  
  65.     //Set the base location.
  66.     gMainBaseID=kbBaseGetMainID(cMyID);
  67.  
  68.     // Drop the AI attack response distance for this player to 5 meters, to simulate the surprise thing
  69.     aiSetAttackResponseDistance(10.0);
  70. }
  71.  
  72. //==============================================================================
  73. //==============================================================================
  74. // Attack stuff.
  75. //==============================================================================
  76. //==============================================================================
  77. //Shared variables.
  78. int numberAttacks=0;
  79. int attackPlayerID=-1;
  80.  
  81. //TODO: Decide how to rep attack group size.
  82. int attackMinimumGroupSize=3;
  83. int attackMaximumGroupSize=5;
  84.  
  85. //Attack 1 vars.
  86. int attackPlan1ID=-1;
  87.  
  88. //Attack 2 vars.
  89. int attackPlan2ID=-1;
  90.  
  91. // Defend plans.
  92. int defendPlan1ID=-1;
  93. int defendPlan2ID=-1;
  94.  
  95. int shipDefendPlanID=-1;
  96.  
  97. // Route and path vars
  98. int attackRoute1ID=-1;
  99. int attackPath1ID=-1;
  100. int attackRoute2ID=-1;
  101. int attackPath2ID=-1;
  102.  
  103. // Saved plan IDs
  104. int maintainPlan1ID=-1;
  105. int maintainPlan2ID=-1;
  106.  
  107. int maintainMyth1ID=-1;
  108. int maintainMyth2ID=-1;
  109.  
  110. int maintainShip1ID=-1;
  111. int maintainShip2ID=-1;
  112.  
  113. int maintainMythSeaID=-1;
  114.  
  115. int maintainPlanVillagerID=-1;
  116.  
  117. int exploreID=-1;
  118.  
  119. int attackerUnitTypeID1=cUnitTypeSpearman;
  120. int attackerUnitTypeID2=cUnitTypeChariotArcher;
  121.  
  122. int attackerShipTypeID1=cUnitTypeSiegeShipEgyptian;
  123. int attackerShipTypeID2=cUnitTypeRammingShipEgyptian;
  124.  
  125. int attackerMythSeaTypeID=cUnitTypeLeviathan;
  126.  
  127. int mythUnitTypeID1=cUnitTypeWadjet;
  128. int mythUnitTypeID2=cUnitTypeScorpionMan;
  129.  
  130. // Initial gather percentages
  131. float totalFoodGathererPercentage  = 0.3;
  132. float totalWoodGathererPercentage  = 0.3;
  133. float totalGoldGathererPercentage  = 0.4;
  134. float totalFavorGathererPercentage = 0.0;
  135.  
  136. //==============================================================================
  137. // initMainBase - Mike's spiffy function to relocate the main base.
  138. //==============================================================================
  139. void initMainBase()
  140. {
  141.     vector basePosition=kbGetBlockPosition("9976");
  142.  
  143.    // Nuke bases, add one base to rule them all
  144.    kbBaseDestroyAll(cMyID);
  145.  
  146.    gMainBaseID = kbBaseCreate(cMyID, "Base "+kbBaseGetNextID(), basePosition, 50.0);
  147.    
  148.     if (gMainBaseID < 0)
  149.       aiEcho("***** Main base creation failed. *****");
  150.  
  151.    vector baseFront=xsVectorNormalize(kbGetMapCenter()-basePosition);     // Set front
  152.    kbBaseSetFrontVector(cMyID, gMainBaseID, baseFront);                 
  153.    kbBaseSetMaximumResourceDistance(cMyID, gMainBaseID, 50.0);
  154.    kbBaseSetMain(cMyID, gMainBaseID, true);     // Make this the main base
  155.  
  156.    // Add the buildings
  157.    int buildingQuery = -1;
  158.    int count = 0;
  159.    buildingQuery = kbUnitQueryCreate("Building Query");     // All buildings in the base
  160.    configQuery(buildingQuery, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, cMyID, basePosition, false, 50.0);
  161.    kbUnitQueryResetResults(buildingQuery);
  162.    count = kbUnitQueryExecute(buildingQuery);
  163.  
  164.    int i = 0;
  165.    int buildingID = -1;
  166.     echoQuery(buildingID);
  167.    for (i=0; < count)
  168.    {
  169.       buildingID = kbUnitQueryGetResult(buildingQuery, i);
  170.       // Add it to the base
  171.       kbBaseAddUnit( cMyID, gMainBaseID, buildingID );
  172.    }
  173. }
  174.  
  175. //==============================================================================
  176. // initEcon
  177. //
  178. // Set Up the initial Economy.
  179. //==============================================================================
  180. void initEcon()
  181. {
  182.    aiEcho("Economy Init.");
  183.  
  184.     /* Don't need this for what we're doing here.
  185.    // Set our update resource handler.
  186.    aiSetUpdateResourceEventHandler("updateResourceHandler");
  187.     */
  188.  
  189.    //-- Setup AI Cost weights.
  190.    kbSetAICostWeight(cResourceFood, 1.5);
  191.    kbSetAICostWeight(cResourceWood, 1.0);
  192.    kbSetAICostWeight(cResourceGold, 1.5);
  193.    kbSetAICostWeight(cResourceFavor, 10.0);
  194.  
  195.    //-- Dont auto gather favor
  196.    //totalFavorGathererPercentage = 0;
  197.  
  198.    //-- Set initial gatherer percentages.
  199.    aiSetResourceGathererPercentage(cResourceFood, totalFoodGathererPercentage, false, cRGPScript);
  200.    aiSetResourceGathererPercentage(cResourceWood, totalWoodGathererPercentage, false, cRGPScript);
  201.    aiSetResourceGathererPercentage(cResourceGold, totalGoldGathererPercentage, false, cRGPScript);
  202.    aiSetResourceGathererPercentage(cResourceFavor, totalFavorGathererPercentage, false, cRGPScript);
  203.    aiNormalizeResourceGathererPercentages(cRGPScript);
  204.  
  205.    aiSetResourceGathererPercentageWeight(cRGPScript, 1);
  206.    aiSetResourceGathererPercentageWeight(cRGPCost, 0);
  207.  
  208.    //-- Set up the initial resource subtype breakdowns - all farming, all the time.
  209.     // aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeEasy, 1, 50, 0.0, gMainBaseID);
  210.     // aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeHunt, 1, 50, 0.1, gMainBaseID);
  211.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFarm, 1, 50, 1.0, gMainBaseID);
  212.     // aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFish, 1, 50, 1.0, gMainBaseID);
  213.     aiSetResourceBreakdown(cResourceWood, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  214.     aiSetResourceBreakdown(cResourceGold, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  215.    aiSetResourceBreakdown(cResourceFavor, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  216.     
  217.    //-- Set up auto-gather escrows
  218.    aiSetAutoGatherEscrowID(cRootEscrowID);
  219.    aiSetAutoFarmEscrowID(cRootEscrowID);
  220.  
  221.     //Allocate all resources to the root escrow by setting percentage of military/economy to 0.
  222.     kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0 );
  223.     kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0 );
  224.  
  225.     //-- create a herd plan to gather any herdables that we encounter.
  226.    int herdPlanID=aiPlanCreate("HerdThings", cPlanHerd);
  227.    if (herdPlanID >= 0)
  228.    {
  229.       aiPlanAddUnitType(herdPlanID, cUnitTypeHerdable, 0, 100, 100);
  230.       aiPlanSetVariableInt(herdPlanID, cHerdPlanBuildingTypeID, 0, cUnitTypeSettlementLevel1);
  231.       aiPlanSetActive(herdPlanID);
  232.    }
  233.  
  234.     //Allocate all resources
  235.    kbEscrowAllocateCurrentResources();
  236.  
  237.     // Don't gather too far away from the main base.
  238.     // kbBaseSetMaximumResourceDistance( 2, gMainBaseID, 50.0 );
  239. }
  240.  
  241. //==============================================================================
  242. // initAttack: Creates attack routes, etc.
  243. //==============================================================================
  244. void initAttack(int playerID=-1)
  245. {
  246.    //Destroy all previous attacks (if this isn't the player we're already attacking.
  247.    if (playerID != attackPlayerID)
  248.    {
  249.       //Reset the attack player ID.
  250.       attackPlayerID=-1;
  251.       //Destroy any previous attack plan.
  252.       aiPlanDestroy(attackPlan1ID);
  253.       attackPlan1ID=-1;
  254.       aiPlanDestroy(attackPlan2ID);
  255.       attackPlan2ID=-1;
  256.   
  257.       //Destroy our previous attack paths.
  258.       kbPathDestroy(attackPath1ID);
  259.       attackPath1ID=-1;
  260.       kbPathDestroy(attackPath2ID);
  261.       attackPath2ID=-1;
  262.  
  263.       //Destroy our previous attack routes.
  264.       attackRoute1ID=-1;
  265.       attackRoute2ID=-1;
  266.  
  267.       //Reset the number of attacks.
  268.       numberAttacks=0;
  269.    }
  270.  
  271.    //Save the player to attack.
  272.    attackPlayerID=playerID;
  273.  
  274.    vector gatherPoint=kbGetBlockPosition("6451");
  275.     vector waterGatherPoint=kbGetBlockPosition("9971");
  276.        
  277.     /*
  278.     //Setup attack path 1
  279.    attackPath1ID=kbPathCreate("Attack Path Land");
  280.    // kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("6456"));
  281.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("6457"));
  282.    
  283.     //Create attack route 1.
  284.    attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", gatherPoint, kbGetBlockPosition("6458"));
  285.    
  286.     if (attackRoute1ID >= 0)
  287.       kbAttackRouteAddPath(attackRoute1ID, attackPath1ID);
  288.     */
  289.  
  290.    //Setup attack path 2 - water attack
  291.    attackPath2ID=kbPathCreate("Attack Path Water");
  292.  
  293.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("9972"));
  294.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("9973"));
  295.  
  296.    //Create attack route 2.
  297.    attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", waterGatherPoint, kbGetBlockPosition("9974"));
  298.        
  299.     if (attackRoute2ID >= 0)
  300.       kbAttackRouteAddPath(attackRoute2ID, attackPath2ID);
  301. }
  302.  
  303. //==============================================================================
  304. // setupAttack
  305. //==============================================================================
  306. bool setupLandAttack(int playerID=-1)
  307. {
  308.     // int randomPath=aiRandInt(2);
  309.  
  310.    //Info.
  311.     aiEcho("Attacking Player "+playerID+".");
  312.  
  313.    //If the player to attack doesn't match, init the attack.
  314.    if (attackPlayerID != playerID)
  315.    {
  316.       initAttack(playerID);
  317.       if (attackPlayerID < 0)
  318.          return(false);
  319.    }
  320.  
  321.    //Create an attack plan.
  322.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  323.    if (newAttackPlanID < 0)
  324.       return(false);
  325.  
  326.    //Target player (required).  This must work.
  327.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  328.       return(false);
  329.  
  330.    //Gather point.
  331.     vector gatherPoint=kbGetBlockPosition("6451");
  332.  
  333.     //Set the target type.  This must work.
  334.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  335.       return(false);
  336.  
  337.     aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true);
  338.  
  339.    //Unit types to attack.
  340.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  341.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  342.  
  343.     // aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID);
  344.  
  345.    //Set the gather point and gather point distance.
  346.    aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  347.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 30.0);
  348.  
  349.    //Set up the attack route usage pattern.
  350.    // aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  351.    
  352.     //Add the unit types to the plan, as long as there's enough axemen.
  353.    aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID1, 6, 12, 12);
  354.     aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, 0, 6, 6);
  355.     aiPlanAddUnitType(newAttackPlanID, mythUnitTypeID1, 0, 4, 4);
  356.     aiPlanAddUnitType(newAttackPlanID, mythUnitTypeID2, 0, 3, 3);
  357.  
  358.    //Set the initial position.
  359.    aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  360.    
  361.     //Plan requires all need units to work (can be false).
  362.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  363.    //Activate the plan.
  364.    aiPlanSetActive(newAttackPlanID);
  365.  
  366.    //Now, save the attack plan ID appropriately.
  367.    aiPlanSetOrphan(attackPlan1ID, true);
  368.    attackPlan1ID=newAttackPlanID;
  369.  
  370.    //Increment our overall number of attacks.
  371.    numberAttacks++;
  372. }
  373.  
  374. //==============================================================================
  375. // setupWaterAttack
  376. //==============================================================================
  377. bool setupWaterAttack(int playerID=-1)
  378. {
  379.     // int randomPath=aiRandInt(2);
  380.     int difflevel=-1;        
  381.     difflevel=aiGetWorldDifficulty();
  382.  
  383.    //Info.
  384.     aiEcho("Attacking Player "+playerID+".");
  385.  
  386.    //If the player to attack doesn't match, init the attack.
  387.    if (attackPlayerID != playerID)
  388.    {
  389.       initAttack(playerID);
  390.       if (attackPlayerID < 0)
  391.          return(false);
  392.    }
  393.  
  394.    //Create an attack plan.
  395.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  396.    if (newAttackPlanID < 0)
  397.       return(false);
  398.  
  399.    //Target player (required).  This must work.
  400.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  401.       return(false);
  402.  
  403.    //Gather point.
  404.     vector gatherPoint=kbGetBlockPosition("3081");
  405.  
  406.     //Set the target type.  This must work.
  407.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  408.       return(false);
  409.  
  410.     aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true);
  411.  
  412.    //Unit types to attack.
  413.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeBuilding);
  414.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeUnit);
  415.     
  416.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID);
  417.  
  418.    //Set the gather point and gather point distance.
  419.    aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  420.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 30.0);
  421.  
  422.    //Set up the attack route usage pattern.
  423.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  424.    
  425.     //Add the unit types to the plan
  426.    aiPlanAddUnitType(newAttackPlanID, attackerShipTypeID1, 2, 2, 6);
  427.  
  428.     // On Titan, add Leviathans to the attack.
  429.     if ( difflevel == 3 )
  430.     {
  431.         aiPlanAddUnitType(newAttackPlanID, attackerMythSeaTypeID, 1, 2, 2);
  432.     }
  433.  
  434.    //Set the initial position.
  435.    aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  436.    //Plan requires all need units to work (can be false).
  437.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  438.    //Activate the plan.
  439.    aiPlanSetActive(newAttackPlanID);
  440.  
  441.    //Now, save the attack plan ID appropriately.
  442.    aiPlanSetOrphan(attackPlan1ID, true);
  443.    attackPlan2ID=newAttackPlanID;
  444.  
  445.    //Increment our overall number of attacks.
  446.    numberAttacks++;
  447. }
  448.  
  449. //==============================================================================
  450. // createUnitProgression
  451. //==============================================================================
  452. int createUnitProgression(int unitTypeID=-1, string name="BUG")
  453. {
  454.    int pID=aiPlanCreate(name, cPlanProgression);
  455.    
  456.     if (pID < 0)
  457.       return(-1);
  458.  
  459.    //This is a military plan.
  460.    //aiPlanSetMilitary(pID, true);
  461.    //Set it for the building that we get our unit from.
  462.    aiPlanSetVariableInt(pID, cProgressionPlanGoalUnitID, 0, kbTechTreeGetUnitIDByTrain(unitTypeID));
  463.    
  464.     //Build it in our main base using the root escrow.
  465.     aiPlanSetBaseID(pID, gMainBaseID);
  466.     aiPlanSetEscrowID(pID, cRootEscrowID);
  467.    
  468.     //Go.
  469.    aiPlanSetActive(pID);
  470.    return(pID);
  471. }
  472.  
  473. //==============================================================================
  474. // createTechProgression
  475. //==============================================================================
  476. int createTechProgression(int techID=-1, string name="BUG", int researchFromProto=-1)
  477. {
  478.    //Check for old plan.
  479.     int oldPlanID=aiPlanGetIDByTypeAndVariableType(cPlanProgression, cProgressionPlanGoalTechID, techID);
  480.    if(oldPlanID != -1)
  481.    {
  482.       aiEcho("createTechProgression: already have a plan("+oldPlanID+") for this Tech("+techID+").");
  483.       return(oldPlanID);
  484.    }
  485.    
  486.     //Create a new one.
  487.    int pID=aiPlanCreate(name, cPlanProgression);
  488.    if (pID < 0)
  489.    {
  490.       aiEcho("createTechProgression: couldn't create Progression.");
  491.       return(-1);
  492.    }
  493.    //This is a military plan.
  494.    //aiPlanSetMilitary(pID, true);
  495.    aiPlanSetVariableInt(pID, cProgressionPlanGoalTechID, 0, techID);
  496.    aiPlanSetVariableInt(pID, cProgressionPlanBuildingPref, 0, researchFromProto);
  497.    
  498.     //Build it in our main base using the root escrow.
  499.    aiPlanSetBaseID(pID, gMainBaseID);
  500.     aiPlanSetEscrowID(pID, cRootEscrowID);
  501.  
  502.    //Go.
  503.    aiPlanSetActive(pID);
  504.    aiEcho("createTechProgression: creating Tech Progression("+name+") to TechID("+techID+").");
  505.    return(pID);
  506. }
  507.  
  508. //==============================================================================
  509. // Queryin' for enemies landing in the logical spots
  510. //==============================================================================
  511. int checkForEnemiesLeft(void)
  512. {
  513.     static int enemyQueryID=-1;
  514.     vector leftSide=kbGetBlockPosition("9967");
  515.     int enemyCount=-1;
  516.  
  517.    if (enemyQueryID < 0)
  518.    {  
  519.         // Doesn't exist, set it up
  520.       enemyQueryID = kbUnitQueryCreate("Enemy Query 1");
  521.         
  522.       // Get the number
  523.       if ( configQuery( enemyQueryID, cUnitTypeMilitary, -1, cUnitStateAlive, 1, leftSide, false, 20 ) == false )
  524.          return(-1);
  525.    }
  526.  
  527.    kbUnitQueryResetResults(enemyQueryID);
  528.    enemyCount = kbUnitQueryExecute(enemyQueryID);
  529.     return(enemyCount);
  530. }
  531.  
  532. int checkForEnemiesRight(void)
  533. {
  534.     static int enemyQueryID=-1;
  535.     vector rightSide=kbGetBlockPosition("9969");
  536.     int enemyCount=-1;
  537.  
  538.    if (enemyQueryID < 0)
  539.    {  
  540.         // Doesn't exist, set it up
  541.       enemyQueryID = kbUnitQueryCreate("Enemy Query 2");
  542.         
  543.       // Get the number
  544.       if ( configQuery( enemyQueryID, cUnitTypeMilitary, -1, cUnitStateAlive, 1, rightSide, false, 20 ) == false )
  545.          return(-1);
  546.    }
  547.  
  548.    kbUnitQueryResetResults(enemyQueryID);
  549.    enemyCount = kbUnitQueryExecute(enemyQueryID);
  550.     return(enemyCount);
  551. }
  552.  
  553. //==============================================================================
  554. // Attack Generator Land - Send dudes now!  Or, well, soon,
  555. //==============================================================================
  556. rule attackGeneratorLand
  557.    minInterval 90
  558.    inactive
  559.    group AttackRules
  560. {
  561.    //See how many "idle" attack plans we have.  Don't create any more if we have
  562.    //idle plans.
  563.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  564.  
  565.    if (numberIdleAttackPlans > 0)
  566.       return;
  567.  
  568.    //If we have enough unassigned military units, create a new attack plan.
  569.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID1);
  570.    aiEcho("There are "+numberAvailableUnits+" spearmen available for a new attack.");
  571.    
  572.     if (numberAvailableUnits >= 6)
  573.         setupLandAttack(1);
  574. }
  575.  
  576. //==============================================================================
  577. // Attack Generator Boat - Send siege ships when you have them.
  578. //==============================================================================
  579. rule attackGeneratorBoat
  580.    minInterval 90
  581.    inactive
  582.    group AttackRules
  583. {
  584.     int difflevel=-1;        
  585.     difflevel=aiGetWorldDifficulty();
  586.  
  587.    //See how many "idle" attack plans we have.  Don't create any more if we have
  588.    //idle plans.
  589.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  590.  
  591.    if (numberIdleAttackPlans > 0)
  592.       return;
  593.  
  594.    //If we have enough unassigned military units, create a new attack plan.
  595.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerShipTypeID1);
  596.    aiEcho("There are "+numberAvailableUnits+" siege ships available for a new attack.");
  597.  
  598.  
  599.     if ( difflevel < 2 )
  600.     {
  601.         if (numberAvailableUnits >= 2)
  602.             setupWaterAttack(1);
  603.     }
  604.     else
  605.     {
  606.         if (numberAvailableUnits >= 4)
  607.             setupWaterAttack(1);
  608.     }
  609. }
  610.  
  611. //==============================================================================
  612. // Maintain Myth Units, starting four minutes after being alerted.
  613. //==============================================================================
  614. rule maintainMythUnits
  615.    minInterval 240
  616.    inactive
  617. {
  618.     vector gatherPointWadjet=kbGetBlockPosition("6649");
  619.     vector gatherPointScorpionMan=kbGetBlockPosition("10038");
  620.  
  621.     // Lots more villagers maintained now.
  622.     aiPlanSetVariableInt(maintainPlanVillagerID, cTrainPlanNumberToMaintain, 0, 20);
  623.  
  624.     // Maintain the two myth units.  These will be added to attacks.
  625.    maintainMyth1ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(mythUnitTypeID1), cPlanTrain);
  626.    if (maintainMyth1ID >= 0)
  627.    {
  628.         //Must set the type of unit to train.
  629.       aiPlanSetVariableInt(maintainMyth1ID, cTrainPlanUnitType, 0, mythUnitTypeID1);
  630.       //You can limit the number of units that are ever trained by this plan with this call.
  631.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  632.       //Set the number of units to maintain in the world at one time.
  633.       aiPlanSetVariableInt(maintainMyth1ID, cTrainPlanNumberToMaintain, 0, 4);
  634.       //Don't train units too fast
  635.       aiPlanSetVariableInt(maintainMyth1ID, cTrainPlanFrequency, 0, 90);
  636.       //Set a gather point.
  637.       aiPlanSetVariableVector(maintainMyth1ID, cTrainPlanGatherPoint, 0, gatherPointWadjet);
  638.       //Activate the plan.
  639.       aiPlanSetActive(maintainMyth1ID);
  640.    }
  641.  
  642.    maintainMyth2ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(mythUnitTypeID2), cPlanTrain);
  643.    if (maintainMyth2ID >= 0)
  644.    {
  645.         //Must set the type of unit to train.
  646.       aiPlanSetVariableInt(maintainMyth2ID, cTrainPlanUnitType, 0, mythUnitTypeID2);
  647.       //You can limit the number of units that are ever trained by this plan with this call.
  648.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  649.       //Set the number of units to maintain in the world at one time.
  650.       aiPlanSetVariableInt(maintainMyth2ID, cTrainPlanNumberToMaintain, 0, 3);
  651.       //Don't train units too fast
  652.       aiPlanSetVariableInt(maintainMyth2ID, cTrainPlanFrequency, 0, 120);
  653.       //Set a gather point.
  654.       aiPlanSetVariableVector(maintainMyth2ID, cTrainPlanGatherPoint, 0, gatherPointScorpionMan);
  655.       //Activate the plan.
  656.       aiPlanSetActive(maintainMyth2ID);
  657.    }
  658.     xsDisableSelf();
  659. }
  660.  
  661. //==================================================================================
  662. // More ramming boats, fifteen minutes after being alerted (except on Easy/Moderate)
  663. //==================================================================================
  664. rule moreBoats
  665.    minInterval 900
  666.    inactive
  667. {
  668.     int difflevel=-1;
  669.     difflevel=aiGetWorldDifficulty();
  670.  
  671.     if ( difflevel > 1 )
  672.     {
  673.         aiPlanSetVariableInt(maintainShip2ID, cTrainPlanNumberToMaintain, 0, 4);
  674.     }
  675.     xsDisableSelf();
  676. }
  677.  
  678. //==============================================================================
  679. // Rules to check for enemies landing on the peninsulae left and right
  680. //==============================================================================
  681. rule enemiesLandLeft
  682.     minInterval 10
  683.     active
  684. {
  685.     int difflevel=-1;
  686.     difflevel=aiGetWorldDifficulty();
  687.  
  688.     int numEnemies=-1;
  689.     numEnemies=checkForEnemiesLeft();
  690.  
  691.     if (numEnemies > 2)
  692.     {
  693.         aiEcho("*** P2: ENEMY HAS LANDED ON THE LEFT ***");
  694.         xsEnableRule("attackGeneratorLand");
  695.         xsDisableRule("enemiesLandRight");
  696.  
  697.         // Destroy the defend plans
  698.         aiPlanDestroy( defendPlan1ID );
  699.         aiPlanDestroy( defendPlan2ID );
  700.  
  701.         // Cheat a little.  Okay, a lot.  Different on lower levels.
  702.         if ( difflevel < 2 )
  703.         {
  704.             aiResourceCheat( 2, cResourceFood, 100.0 );
  705.             aiResourceCheat( 2, cResourceWood, 400.0 );
  706.             aiResourceCheat( 2, cResourceGold, 250.0 );
  707.             aiResourceCheat( 2, cResourceFavor, 10.0 );
  708.         }
  709.         else
  710.         {
  711.             aiResourceCheat( 2, cResourceFood, 200.0 );
  712.             aiResourceCheat( 2, cResourceWood, 600.0 );
  713.             aiResourceCheat( 2, cResourceGold, 500.0 );
  714.             aiResourceCheat( 2, cResourceFavor, 20.0 );
  715.         }
  716.         xsDisableSelf();
  717.     }
  718. }
  719.  
  720. rule enemiesLandRight
  721.     minInterval 10
  722.     active
  723. {
  724.     int difflevel=-1;
  725.     difflevel=aiGetWorldDifficulty();
  726.  
  727.     int numEnemies=-1;
  728.     numEnemies=checkForEnemiesRight();
  729.  
  730.     if (numEnemies > 2)
  731.     {
  732.         aiEcho("*** P2: ENEMY HAS LANDED ON THE RIGHT ***");
  733.         xsEnableRule("attackGeneratorLand");
  734.         xsDisableRule("enemiesLandLeft");
  735.  
  736.         // Destroy the defend plans.
  737.         aiPlanDestroy( defendPlan1ID );
  738.         aiPlanDestroy( defendPlan2ID );
  739.  
  740.         // Cheat a little.  Okay, a lot.  Different on lower levels.
  741.         if ( difflevel < 2 )
  742.         {
  743.             aiResourceCheat( 2, cResourceFood, 100.0 );
  744.             aiResourceCheat( 2, cResourceWood, 400.0 );
  745.             aiResourceCheat( 2, cResourceGold, 250.0 );
  746.             aiResourceCheat( 2, cResourceFavor, 10.0 );
  747.         }
  748.         else
  749.         {
  750.             aiResourceCheat( 2, cResourceFood, 200.0 );
  751.             aiResourceCheat( 2, cResourceWood, 600.0 );
  752.             aiResourceCheat( 2, cResourceGold, 500.0 );
  753.             aiResourceCheat( 2, cResourceFavor, 20.0 );
  754.         }
  755.         xsDisableSelf();
  756.     }
  757. }
  758.  
  759. //==============================================================================
  760. // armoryUpgrades, oh yeah!  Six minutes after AI is alerted, if it's still got
  761. // an armory.  And if it doesn't, it should rebuild one, even!
  762. //==============================================================================
  763. /*
  764. rule armoryUpgrades
  765.    minInterval 360
  766.    inactive
  767. {
  768.     aiEcho("*** GETTING ARMORY UPGRADES ***");
  769.     createTechProgression(cTechBronzeWeapons, "Research Bronze Weapons", cUnitTypeArmory);
  770.     createTechProgression(cTechBronzeMail, "Research Bronze Mail", cUnitTypeArmory);
  771.     createTechProgression(cTechCopperShields, "Research Copper Shields", cUnitTypeArmory);
  772.  
  773.     xsDisableSelf();
  774. }
  775. */
  776.  
  777. //==============================================================================
  778. // cheatResources - for Titan level only.
  779. //==============================================================================
  780. rule cheatResources
  781.    minInterval 60
  782.    inactive
  783.    group TitanRules
  784. {
  785.     // Cheat for favor and gold, to keep the Leviathans rolling.
  786.     aiResourceCheat( 2, cResourceFavor, 25.0 );
  787.     aiResourceCheat( 2, cResourceGold, 250.0 );
  788. }
  789.  
  790. //==============================================================================
  791. // playerLands - fires when the player initially lands.
  792. //==============================================================================
  793. void playerLands( int parameter=-1 )
  794. {
  795.     int difflevel=-1;        
  796.     difflevel=aiGetWorldDifficulty();
  797.  
  798.     aiEcho("*** P2 Attacks now Possible ***");
  799.  
  800.     // Maintain ships.
  801.     vector gatherPointShip1=kbGetBlockPosition("9971");
  802.     vector gatherPointShip2=kbGetBlockPosition("9975");
  803.     vector defendPlanSpot=kbGetBlockPosition("9968");
  804.  
  805.     // Cheat and have some wood
  806.     aiResourceCheat( 2, cResourceWood, 750.0 );
  807.  
  808.     // Defend plan on each peninsula.
  809.    defendPlan1ID=aiPlanCreate("West Defense", cPlanDefend);
  810.    if (defendPlan1ID >= 0)
  811.    {
  812.       //Main gate location
  813.       defendPlanSpot=kbGetBlockPosition("9968");
  814.  
  815.       //Add the unit(s).
  816.       aiPlanAddUnitType(defendPlan1ID, attackerUnitTypeID1, 0, 4, 4);
  817.         aiPlanAddUnitType(defendPlan1ID, attackerUnitTypeID2, 0, 3, 3);
  818.         
  819.       //Setup the vars - priority is slightly higher than the attack plans.
  820.       aiPlanSetDesiredPriority(defendPlan1ID, 60);
  821.       aiPlanSetVariableVector(defendPlan1ID, cDefendPlanDefendPoint, 0, defendPlanSpot);
  822.       aiPlanSetVariableFloat(defendPlan1ID, cDefendPlanEngageRange, 0, 25);
  823.       aiPlanSetActive(defendPlan1ID);
  824.     }
  825.  
  826.     // Defend plan on each peninsula.
  827.    defendPlan2ID=aiPlanCreate("West Defense", cPlanDefend);
  828.    if (defendPlan2ID >= 0)
  829.    {
  830.       //Main gate location
  831.       defendPlanSpot=kbGetBlockPosition("9969");
  832.  
  833.       //Add the unit(s).
  834.       aiPlanAddUnitType(defendPlan2ID, attackerUnitTypeID1, 0, 4, 4);
  835.         aiPlanAddUnitType(defendPlan2ID, attackerUnitTypeID2, 0, 3, 3);
  836.         
  837.       //Setup the vars - priority is slightly higher than the attack plans.
  838.       aiPlanSetDesiredPriority(defendPlan2ID, 60);
  839.       aiPlanSetVariableVector(defendPlan2ID, cDefendPlanDefendPoint, 0, defendPlanSpot);
  840.       aiPlanSetVariableFloat(defendPlan2ID, cDefendPlanEngageRange, 0, 15);
  841.       aiPlanSetActive(defendPlan2ID);
  842.     }
  843.  
  844.     // Defend plan on each peninsula.
  845.    shipDefendPlanID=aiPlanCreate("Ship Defense", cPlanDefend);
  846.    if (shipDefendPlanID >= 0)
  847.    {
  848.       //Main gate location
  849.       defendPlanSpot=kbGetBlockPosition("9972");
  850.  
  851.       //Add the unit(s).
  852.       aiPlanAddUnitType(shipDefendPlanID, attackerShipTypeID2, 0, 4, 4);
  853.         
  854.       //Setup the vars - priority is slightly higher than the attack plans.
  855.       aiPlanSetDesiredPriority(shipDefendPlanID, 60);
  856.       aiPlanSetVariableVector(shipDefendPlanID, cDefendPlanDefendPoint, 0, defendPlanSpot);
  857.       aiPlanSetVariableFloat(shipDefendPlanID, cDefendPlanEngageRange, 0, 20);
  858.       aiPlanSetActive(shipDefendPlanID);
  859.     }
  860.  
  861.    maintainShip1ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerShipTypeID1), cPlanTrain);
  862.    if (maintainShip1ID >= 0)
  863.    {
  864.         //Must set the type of unit to train.
  865.       aiPlanSetVariableInt(maintainShip1ID, cTrainPlanUnitType, 0, attackerShipTypeID1);
  866.       //You can limit the number of units that are ever trained by this plan with this call.
  867.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  868.  
  869.         //Set the number of units to maintain in the world at one time (based on difficulty)
  870.         if ( difflevel < 2 )
  871.         {
  872.             aiPlanSetVariableInt(maintainShip1ID, cTrainPlanNumberToMaintain, 0, 2);
  873.         }
  874.         else if ( difflevel == 2 )
  875.         {
  876.             aiPlanSetVariableInt(maintainShip1ID, cTrainPlanNumberToMaintain, 0, 5);
  877.             aiResourceCheat( 2, cResourceWood, 400.0 );
  878.             aiResourceCheat( 2, cResourceGold, 400.0 );
  879.         }
  880.         else
  881.         {
  882.             aiPlanSetVariableInt(maintainShip1ID, cTrainPlanNumberToMaintain, 0, 6);
  883.             aiResourceCheat( 2, cResourceWood, 600.0 );
  884.             aiResourceCheat( 2, cResourceGold, 600.0 );
  885.         }
  886.  
  887.       //Don't train units too fast
  888.         if ( difflevel < 2 )
  889.         {
  890.             aiPlanSetVariableInt(maintainShip1ID, cTrainPlanFrequency, 0, 120);
  891.         }
  892.         else
  893.         {
  894.             aiPlanSetVariableInt(maintainShip1ID, cTrainPlanFrequency, 0, 50);
  895.         }
  896.  
  897.       //Set a gather point.
  898.       aiPlanSetVariableVector(maintainShip1ID, cTrainPlanGatherPoint, 0, gatherPointShip1);
  899.       //Activate the plan.
  900.       aiPlanSetActive(maintainShip1ID);
  901.    }
  902.  
  903.    maintainShip2ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerShipTypeID2), cPlanTrain);
  904.    if (maintainShip2ID >= 0)
  905.    {
  906.         //Must set the type of unit to train.
  907.       aiPlanSetVariableInt(maintainShip2ID, cTrainPlanUnitType, 0, attackerShipTypeID2);
  908.       //You can limit the number of units that are ever trained by this plan with this call.
  909.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  910.       //Set the number of units to maintain in the world at one time.
  911.       aiPlanSetVariableInt(maintainShip2ID, cTrainPlanNumberToMaintain, 0, 2);
  912.       //Don't train units too fast
  913.       aiPlanSetVariableInt(maintainShip2ID, cTrainPlanFrequency, 0, 105);
  914.       //Set a gather point.
  915.       aiPlanSetVariableVector(maintainShip2ID, cTrainPlanGatherPoint, 0, gatherPointShip2);
  916.       //Activate the plan.
  917.       aiPlanSetActive(maintainShip2ID);
  918.    }
  919.  
  920.     // Enable attacks and activate some other long-term rules
  921.     xsEnableRule("attackGeneratorBoat");
  922.     xsEnableRule("maintainMythUnits");
  923.     xsEnableRule("moreBoats");
  924.  
  925.     // xsEnableRule("armoryUpgrades");
  926.  
  927.     // Mmm, unit upgrades.  Let's go!
  928.     // createTechProgression(cTechHeavySpearmen, "Research up to Heavy Spearmen", cUnitTypeBarracks);
  929.     // createTechProgression(cTechHeavySlingers, "Research up to Medium Slingers", cUnitTypeBarracks);
  930.  
  931.     // Attack response range increases to 40.
  932.     aiSetAttackResponseDistance(40.0);
  933. }
  934.  
  935. //==============================================================================
  936. // MAIN.
  937. //==============================================================================
  938. void main(void)
  939. {
  940.     int difflevel=-1;        
  941.     difflevel=aiGetWorldDifficulty();
  942.  
  943.    //Startup.
  944.    miscStartup();
  945.     initMainBase();
  946.     initEcon();
  947.  
  948.    //Gather Points
  949.    vector gatherPointVillager=kbGetBlockPosition("9976");
  950.     vector gatherPointMilitary1=kbGetBlockPosition("9966");
  951.     vector gatherPointMilitary2=kbGetBlockPosition("10033");
  952.  
  953.     vector gatherPointLeviathan=kbGetBlockPosition("9975");
  954.  
  955.    maintainPlanVillagerID=aiPlanCreate("Maintain Villagers", cPlanTrain);
  956.    if (maintainPlanVillagerID >= 0)
  957.    {
  958.         //Must set the type of unit to train.
  959.       aiPlanSetVariableInt(maintainPlanVillagerID, cTrainPlanUnitType, 0, cUnitTypeVillagerEgyptian);
  960.       //You can limit the number of units that are ever trained by this plan with this call.
  961.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  962.       //Set the number of units to maintain in the world at one time.
  963.       aiPlanSetVariableInt(maintainPlanVillagerID, cTrainPlanNumberToMaintain, 0, 10);
  964.       //Don't train units faster than every 20 seconds
  965.       aiPlanSetVariableInt(maintainPlanVillagerID, cTrainPlanFrequency, 0, 15);
  966.       //Set a gather point.
  967.       aiPlanSetVariableVector(maintainPlanVillagerID, cTrainPlanGatherPoint, 0, gatherPointVillager);
  968.       //Activate the plan.
  969.       aiPlanSetActive(maintainPlanVillagerID);
  970.    }
  971.  
  972.    maintainPlan1ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain);
  973.    if (maintainPlan1ID >= 0)
  974.    {
  975.         //Must set the type of unit to train.
  976.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1);
  977.       //You can limit the number of units that are ever trained by this plan with this call.
  978.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  979.       //Set the number of units to maintain in the world at one time.
  980.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, 6);
  981.       //Don't train units too fast
  982.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 30);
  983.       //Set a gather point.
  984.       aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointMilitary1);
  985.       //Activate the plan.
  986.       aiPlanSetActive(maintainPlan1ID);
  987.    }
  988.  
  989.     maintainPlan2ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID2), cPlanTrain);
  990.    if (maintainPlan2ID >= 0)
  991.    {
  992.         //Must set the type of unit to train.
  993.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID2);
  994.       //You can limit the number of units that are ever trained by this plan with this call.
  995.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  996.       //Set the number of units to maintain in the world at one time.
  997.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, 6);
  998.  
  999.       //Don't train units too fast
  1000.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 45);
  1001.       //Set a gather point.
  1002.       aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPointMilitary2);
  1003.       //Activate the plan.
  1004.       aiPlanSetActive(maintainPlan2ID);
  1005.    }
  1006.  
  1007.     if ( difflevel == 3 )
  1008.     {
  1009.         maintainMythSeaID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerMythSeaTypeID), cPlanTrain);
  1010.         if (maintainMythSeaID >= 0)
  1011.         {
  1012.             //Must set the type of unit to train.
  1013.             aiPlanSetVariableInt(maintainMythSeaID, cTrainPlanUnitType, 0, attackerMythSeaTypeID);
  1014.             //You can limit the number of units that are ever trained by this plan with this call.
  1015.             //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  1016.             //Set the number of units to maintain in the world at one time.
  1017.             aiPlanSetVariableInt(maintainMythSeaID, cTrainPlanNumberToMaintain, 0, 2);
  1018.             //Don't train units too fast
  1019.             aiPlanSetVariableInt(maintainMythSeaID, cTrainPlanFrequency, 0, 55);
  1020.             //Set a gather point.
  1021.             aiPlanSetVariableVector(maintainMythSeaID, cTrainPlanGatherPoint, 0, gatherPointLeviathan);
  1022.             //Activate the plan.
  1023.             aiPlanSetActive(maintainMythSeaID);
  1024.         }
  1025.         xsEnableRule("cheatResources");
  1026.     }
  1027.     
  1028.     // Create a fishing plan.
  1029.     int fishGatherer = kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionFish, 0);
  1030.     int fishPlanID=aiPlanCreate("FishPlan", cPlanFish);
  1031.  
  1032.     if (fishPlanID >= 0)
  1033.     {
  1034.         aiEcho("Setting up the Fishing Plan.");
  1035.       aiPlanSetDesiredPriority(fishPlanID, 70);
  1036.         aiPlanSetVariableVector(fishPlanID, cFishPlanLandPoint, 0, kbBaseGetLocation(cMyID, gMainBaseID));
  1037.         
  1038.         //-- If you don't explicitly set the water point, the plan will find one for you.
  1039.         aiPlanSetVariableBool(fishPlanID, cFishPlanAutoTrainBoats, 0, false);   // I'm going to have a  maintain plan for fishing + scouting combined
  1040.         aiPlanSetEscrowID(fishPlanID, cRootEscrowID);
  1041.  
  1042.         aiPlanAddUnitType(fishPlanID, fishGatherer, 3, 3, 3);
  1043.         aiPlanSetActive(fishPlanID);
  1044.     }
  1045.  
  1046.     // Empower a Wood Choppery with Mr. Pharoah
  1047.     int empowerPlan1ID=aiPlanCreate("EmpowerPlan", cPlanEmpower);
  1048.     if (empowerPlan1ID >= 0)
  1049.     {
  1050.         aiPlanSetDesiredPriority(empowerPlan1ID, 50);
  1051.         aiPlanAddUnitType(empowerPlan1ID, cUnitTypePharaoh, 1, 1, 1);
  1052.         aiPlanSetVariableInt(empowerPlan1ID, cEmpowerPlanTargetTypeID, 0, cUnitTypeLumberCamp);
  1053.         aiPlanSetActive(empowerPlan1ID);
  1054.     }
  1055.  
  1056.     // Basic tech progressions to upgrade our operations (better gold mining, wood chopping, and farms)
  1057.     createTechProgression(cTechShaftMine, "Research up to Shaft Mine", cUnitTypeMiningCamp);
  1058.     createTechProgression(cTechIrrigation, "Research up to Irrigation", cUnitTypeGranary);
  1059.     createTechProgression(cTechBowSaw, "Research up to Bow Saw", cUnitTypeLumberCamp);
  1060. }