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

  1. //==============================================================================
  2. // Scn22p2: AI Scenario Script for scenario 22 player 2 (revised)
  3. //==============================================================================
  4. /*
  5.    AI owner:  Dave Leary
  6.    Scenario owner: Joe "The Golem" Gillum
  7.  
  8.    Overview: Basic AI script for the enemy main town in 22.
  9.  
  10.                                   *** DIFFICULTY LEVEL NOTES ***
  11.  
  12.     Note that most of the difficulty here is handled via trigger - the timing of
  13.     the AI's initial attacks after the player lands is the primary difficulty
  14.     level adjustment for this scenario.
  15.  
  16.    Easy level - Smaller groups in general.
  17.  
  18.    Moderate level - Base level.
  19.  
  20.    Difficult - Larger groups.  More towers.
  21.  
  22.    Nightmare - Lots more elephants and scarabs.  More towers.  Faster upgrades.
  23.     Will go for heavy elephants (ow).
  24. */
  25. //==============================================================================
  26. // Need scn lib for some stuff here.
  27. include "scn lib.xs";
  28.  
  29. // Variable for main base.
  30. int gMainBaseID=-1;
  31.  
  32. //==============================================================================
  33. // Set Town Location
  34. //==============================================================================
  35. void setTownLocation(void)
  36. {
  37.    //Look for the "Town Location" marker.
  38.    kbSetTownLocation(kbGetBlockPosition("1851"));
  39. }
  40.  
  41. //==============================================================================
  42. // miscStartup
  43. //==============================================================================
  44. void miscStartup(void)
  45. {
  46.     // Difficulty Level check.
  47.     int difflevel=-1;        
  48.     difflevel=aiGetWorldDifficulty();
  49.  
  50.    //Startup message(s).
  51.    aiEcho("");
  52.    aiEcho("");
  53.    aiEcho("Scn22P2 AI Start, filename='"+cFilename+"'.");
  54.     aiEcho("Difficulty Level="+difflevel+".");
  55.    //Spit out the map size.
  56.    aiEcho("  Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+").");
  57.    //Cheat like a bastard.  Once only, though.
  58.    kbLookAtAllUnitsOnMap();
  59.    //Calculate some areas.
  60.    kbAreaCalculate(1200.0);
  61.    //Set our town location.
  62.    setTownLocation();
  63.     //Reset random seed
  64.     aiRandSetSeed();
  65.  
  66.     //Set the base location.
  67.     gMainBaseID=kbBaseGetMainID(cMyID);
  68.  
  69.     // Drop the AI attack response distance for this player to 5 meters, to simulate the surprise thing
  70.     aiSetAttackResponseDistance(5.0);
  71. }
  72.  
  73. //==============================================================================
  74. //==============================================================================
  75. // Attack stuff.
  76. //==============================================================================
  77. //==============================================================================
  78. //Shared variables.
  79. int numberAttacks=0;
  80. int attackPlayerID=-1;
  81.  
  82. //TODO: Decide how to rep attack group size.
  83. int attackMinimumGroupSize=3;
  84. int attackMaximumGroupSize=5;
  85.  
  86. //Attack 1 vars.
  87. int attackPlan1ID=-1;
  88.  
  89. //Attack 2 vars.
  90. int attackPlan2ID=-1;
  91.  
  92. // Defend plans.
  93. int defendPlan1ID=-1;
  94.  
  95. // Route and path vars
  96. int attackRoute1ID=-1;
  97. int attackPath1ID=-1;
  98. int attackRoute2ID=-1;
  99. int attackPath2ID=-1;
  100.  
  101. // Saved plan IDs
  102. int maintainPlan1ID=-1;
  103. int maintainPlan2ID=-1;
  104. int maintainPlan3ID=-1;
  105. int maintainPlan4ID=-1;
  106. int maintainPlanVillagerID=-1;
  107. int exploreID=-1;
  108.  
  109. int attackerUnitTypeID1=cUnitTypeSpearman;
  110. int attackerUnitTypeID2=cUnitTypeSlinger;
  111. int attackerUnitTypeID3=cUnitTypeWarElephant;
  112. int attackerUnitTypeID4=cUnitTypeScarab;
  113.  
  114. // Initial gather percentages
  115. float totalFoodGathererPercentage  = 0.35;
  116. float totalWoodGathererPercentage  = 0.25;
  117. float totalGoldGathererPercentage  = 0.4;
  118. float totalFavorGathererPercentage = 0.0;
  119.  
  120. //==============================================================================
  121. // initMainBase - Mike's spiffy function to relocate the main base.
  122. //==============================================================================
  123. void initMainBase()
  124. {
  125.     vector basePosition=kbGetBlockPosition("3090");
  126.  
  127.    // Nuke bases, add one base to rule them all
  128.    kbBaseDestroyAll(cMyID);
  129.  
  130.    gMainBaseID = kbBaseCreate(cMyID, "Base "+kbBaseGetNextID(), basePosition, 50.0);
  131.    
  132.     if (gMainBaseID < 0)
  133.       aiEcho("***** Main base creation failed. *****");
  134.  
  135.    vector baseFront=xsVectorNormalize(kbGetMapCenter()-basePosition);     // Set front
  136.    kbBaseSetFrontVector(cMyID, gMainBaseID, baseFront);                 
  137.    kbBaseSetMaximumResourceDistance(cMyID, gMainBaseID, 50.0);
  138.    kbBaseSetMain(cMyID, gMainBaseID, true);     // Make this the main base
  139.  
  140.    // Add the buildings
  141.    int buildingQuery = -1;
  142.    int count = 0;
  143.    buildingQuery = kbUnitQueryCreate("Building Query");     // All buildings in the base
  144.    configQuery(buildingQuery, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, cMyID, basePosition, false, 50.0);
  145.    kbUnitQueryResetResults(buildingQuery);
  146.    count = kbUnitQueryExecute(buildingQuery);
  147.  
  148.    int i = 0;
  149.    int buildingID = -1;
  150.     echoQuery(buildingID);
  151.    for (i=0; < count)
  152.    {
  153.       buildingID = kbUnitQueryGetResult(buildingQuery, i);
  154.       // Add it to the base
  155.       kbBaseAddUnit( cMyID, gMainBaseID, buildingID );
  156.    }
  157. }
  158.  
  159. //==============================================================================
  160. // initEcon
  161. //
  162. // Set Up the initial Economy.
  163. //==============================================================================
  164. void initEcon()
  165. {
  166.    aiEcho("Economy Init.");
  167.  
  168.     /* Don't need this for what we're doing here.
  169.    // Set our update resource handler.
  170.    aiSetUpdateResourceEventHandler("updateResourceHandler");
  171.     */
  172.  
  173.    //-- Setup AI Cost weights.
  174.    kbSetAICostWeight(cResourceFood, 1.5);
  175.    kbSetAICostWeight(cResourceWood, 1.0);
  176.    kbSetAICostWeight(cResourceGold, 1.5);
  177.    kbSetAICostWeight(cResourceFavor, 10.0);
  178.  
  179.    //-- Dont auto gather favor
  180.    //totalFavorGathererPercentage = 0;
  181.  
  182.    //-- Set initial gatherer percentages.
  183.    aiSetResourceGathererPercentage(cResourceFood, totalFoodGathererPercentage, false, cRGPScript);
  184.    aiSetResourceGathererPercentage(cResourceWood, totalWoodGathererPercentage, false, cRGPScript);
  185.    aiSetResourceGathererPercentage(cResourceGold, totalGoldGathererPercentage, false, cRGPScript);
  186.    aiSetResourceGathererPercentage(cResourceFavor, totalFavorGathererPercentage, false, cRGPScript);
  187.    aiNormalizeResourceGathererPercentages(cRGPScript);
  188.  
  189.    aiSetResourceGathererPercentageWeight(cRGPScript, 1);
  190.    aiSetResourceGathererPercentageWeight(cRGPCost, 0);
  191.  
  192.    //-- Set up the initial resource subtype breakdowns - all farming, all the time.
  193.     // aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeEasy, 1, 50, 0.0, gMainBaseID);
  194.     // aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeHunt, 1, 50, 0.1, gMainBaseID);
  195.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFarm, 1, 55, 1.0, gMainBaseID);
  196.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFish, 1, 50, 1.0, gMainBaseID);
  197.     aiSetResourceBreakdown(cResourceWood, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  198.     aiSetResourceBreakdown(cResourceGold, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  199.    aiSetResourceBreakdown(cResourceFavor, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  200.     
  201.    //-- Set up auto-gather escrows
  202.    aiSetAutoGatherEscrowID(cRootEscrowID);
  203.    aiSetAutoFarmEscrowID(cRootEscrowID);
  204.  
  205.     //Allocate all resources to the root escrow by setting percentage of military/economy to 0.
  206.     kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0 );
  207.     kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0 );
  208.  
  209.     //-- create a herd plan to gather all herdables that we encounter.
  210.    int herdPlanID=aiPlanCreate("HerdTest", cPlanHerd);
  211.    if (herdPlanID >= 0)
  212.    {
  213.       aiPlanAddUnitType(herdPlanID, cUnitTypeHerdable, 0, 100, 100);
  214.       aiPlanSetVariableInt(herdPlanID, cHerdPlanBuildingTypeID, 0, cUnitTypeSettlementLevel1);
  215.       aiPlanSetActive(herdPlanID);
  216.    }
  217.  
  218.     //Allocate all resources
  219.    kbEscrowAllocateCurrentResources();
  220. }
  221.  
  222. //==============================================================================
  223. // initAttack: Creates attack routes, etc.
  224. //==============================================================================
  225. void initAttack(int playerID=-1)
  226. {
  227.    //Destroy all previous attacks (if this isn't the player we're already attacking.
  228.    if (playerID != attackPlayerID)
  229.    {
  230.       //Reset the attack player ID.
  231.       attackPlayerID=-1;
  232.       //Destroy any previous attack plan.
  233.       aiPlanDestroy(attackPlan1ID);
  234.       attackPlan1ID=-1;
  235.       aiPlanDestroy(attackPlan2ID);
  236.       attackPlan2ID=-1;
  237.   
  238.       //Destroy our previous attack paths.
  239.       kbPathDestroy(attackPath1ID);
  240.       attackPath1ID=-1;
  241.       kbPathDestroy(attackPath2ID);
  242.       attackPath2ID=-1;
  243.  
  244.       //Destroy our previous attack routes.
  245.       attackRoute1ID=-1;
  246.       attackRoute2ID=-1;
  247.  
  248.       //Reset the number of attacks.
  249.       numberAttacks=0;
  250.    }
  251.  
  252.    //Save the player to attack.
  253.    attackPlayerID=playerID;
  254.  
  255.    vector gatherPoint=kbGetBlockPosition("3081");
  256.        
  257.     //Setup attack path 1 - go north
  258.    attackPath1ID=kbPathCreate("Attack Path North");
  259.    kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3078"));
  260.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3079"));
  261.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3080"));
  262.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3073"));
  263.    
  264.     //Create attack route 1.
  265.    attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", gatherPoint, kbGetBlockPosition("3075"));
  266.    
  267.     if (attackRoute1ID >= 0)
  268.       kbAttackRouteAddPath(attackRoute1ID, attackPath1ID);
  269.  
  270.    //Setup attack path 2 - go south
  271.    attackPath2ID=kbPathCreate("Attack Path South");
  272.  
  273.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("1851"));
  274.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("1853"));
  275.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("1849"));
  276.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3080"));
  277.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3073"));
  278.  
  279.    //Create attack route 2.
  280.    attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", gatherPoint, kbGetBlockPosition("3075"));
  281.    
  282.     if (attackRoute2ID >= 0)
  283.       kbAttackRouteAddPath(attackRoute2ID, attackPath2ID);
  284. }
  285.  
  286. //==============================================================================
  287. // setupAttack
  288. //==============================================================================
  289. bool setupAttack(int playerID=-1)
  290. {
  291.     // Difficulty Level check.
  292.     int difflevel=-1;        
  293.     difflevel=aiGetWorldDifficulty();
  294.  
  295.     int randomPath=aiRandInt(2);
  296.  
  297.    //Info.
  298.     aiEcho("Attacking Player "+playerID+".");
  299.  
  300.    //If the player to attack doesn't match, init the attack.
  301.    if (attackPlayerID != playerID)
  302.    {
  303.       initAttack(playerID);
  304.       if (attackPlayerID < 0)
  305.          return(false);
  306.    }
  307.  
  308.    //Create an attack plan. 
  309.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  310.    if (newAttackPlanID < 0)
  311.       return(false);
  312.  
  313.    //Target player (required).  This must work.
  314.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  315.       return(false);
  316.  
  317.    //Gather point.
  318.     vector gatherPoint=kbGetBlockPosition("3081");
  319.  
  320.     //Set the target type.  This must work.
  321.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  322.       return(false);
  323.  
  324.    //Unit types to attack.
  325.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  326.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  327.  
  328.    //Attack route.
  329.    if (randomPath == 0)
  330.     {
  331.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID);
  332.     }
  333.    else
  334.     {
  335.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID);
  336.     }
  337.  
  338.    //Set the gather point and gather point distance.
  339.    aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  340.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 20.0);
  341.  
  342.    //Set up the attack route usage pattern.
  343.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  344.    
  345.     //Add the unit types to the plan
  346.    aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID1, 4, 4, 12);
  347.     aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, 0, 4, 6);
  348.  
  349.     // Elephants if you got 'em
  350.     aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 0, 4, 8);
  351.  
  352.     // Scarabs!  More on higher levels.
  353.     if ( difflevel < 3 )
  354.     {
  355.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 2, 2);
  356.     }
  357.     else
  358.     {
  359.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 2, 4);
  360.     }
  361.     
  362.    //Set the initial position.
  363.    aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  364.    //Plan requires all need units to work (can be false).
  365.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  366.    //Activate the plan.
  367.    aiPlanSetActive(newAttackPlanID);
  368.  
  369.    //Now, save the attack plan ID appropriately.
  370.    aiPlanSetOrphan(attackPlan1ID, true);
  371.    attackPlan1ID=newAttackPlanID;
  372.  
  373.    //Increment our overall number of attacks.
  374.    numberAttacks++;
  375. }
  376.  
  377. //==============================================================================
  378. // createUnitProgression
  379. //==============================================================================
  380. int createUnitProgression(int unitTypeID=-1, string name="BUG")
  381. {
  382.    int pID=aiPlanCreate(name, cPlanProgression);
  383.    
  384.     if (pID < 0)
  385.       return(-1);
  386.  
  387.    //This is a military plan.
  388.    //aiPlanSetMilitary(pID, true);
  389.    //Set it for the building that we get our unit from.
  390.    aiPlanSetVariableInt(pID, cProgressionPlanGoalUnitID, 0, kbTechTreeGetUnitIDByTrain(unitTypeID));
  391.    
  392.     //Build it in our main base using the root escrow.
  393.     aiPlanSetBaseID(pID, gMainBaseID);
  394.     aiPlanSetEscrowID(pID, cRootEscrowID);
  395.    
  396.     //Go.
  397.    aiPlanSetActive(pID);
  398.    return(pID);
  399. }
  400.  
  401. //==============================================================================
  402. // createTechProgression
  403. //==============================================================================
  404. int createTechProgression(int techID=-1, string name="BUG", int researchFromProto=-1)
  405. {
  406.    //Check for old plan.
  407.     int oldPlanID=aiPlanGetIDByTypeAndVariableType(cPlanProgression, cProgressionPlanGoalTechID, techID);
  408.    if(oldPlanID != -1)
  409.    {
  410.       aiEcho("createTechProgression: already have a plan("+oldPlanID+") for this Tech("+techID+").");
  411.       return(oldPlanID);
  412.    }
  413.    
  414.     //Create a new one.
  415.    int pID=aiPlanCreate(name, cPlanProgression);
  416.    if (pID < 0)
  417.    {
  418.       aiEcho("createTechProgression: couldn't create Progression.");
  419.       return(-1);
  420.    }
  421.    //This is a military plan.
  422.    //aiPlanSetMilitary(pID, true);
  423.    aiPlanSetVariableInt(pID, cProgressionPlanGoalTechID, 0, techID);
  424.    aiPlanSetVariableInt(pID, cProgressionPlanBuildingPref, 0, researchFromProto);
  425.    
  426.     //Build it in our main base using the root escrow.
  427.    aiPlanSetBaseID(pID, gMainBaseID);
  428.     aiPlanSetEscrowID(pID, cRootEscrowID);
  429.  
  430.    //Go.
  431.    aiPlanSetActive(pID);
  432.    aiEcho("createTechProgression: creating Tech Progression("+name+") to TechID("+techID+").");
  433.    return(pID);
  434. }
  435.  
  436. //==============================================================================
  437. // Attack Generator 1 - Send dudes now!  Or, well, soon,
  438. //==============================================================================
  439. rule attackGenerator1
  440.    minInterval 90
  441.    inactive
  442.    group AttackRules
  443. {
  444.     // Difficulty Level check.
  445.     int difflevel=-1;        
  446.     difflevel=aiGetWorldDifficulty();
  447.  
  448.    //See how many "idle" attack plans we have.  Don't create any more if we have
  449.    //idle plans.
  450.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  451.  
  452.    if (numberIdleAttackPlans > 0)
  453.       return;
  454.  
  455.    //If we have enough unassigned military units, create a new attack plan.
  456.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID1);
  457.    aiEcho("There are "+numberAvailableUnits+" spearmen available for a new attack.");
  458.  
  459.     if ( difflevel < 2 )
  460.     {
  461.         if (numberAvailableUnits >= 4)
  462.             setupAttack(1);
  463.     }
  464.     else
  465.     {
  466.         if (numberAvailableUnits >= 6)
  467.             setupAttack(1);
  468.     }
  469. }
  470.  
  471.  
  472. //==============================================================================
  473. // Maintain Scarabs, starting four minutes after being alerted.
  474. //==============================================================================
  475. rule maintainScarabs
  476.    minInterval 240
  477.    inactive
  478. {
  479.     // Difficulty Level check.
  480.     int difflevel=-1;        
  481.     difflevel=aiGetWorldDifficulty();
  482.  
  483.     vector gatherPointMyth=kbGetBlockPosition("1853");
  484.  
  485.     // Two should be plenty.
  486.    maintainPlan4ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID4), cPlanTrain);
  487.    if (maintainPlan4ID >= 0)
  488.    {
  489.         //Must set the type of unit to train.
  490.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanUnitType, 0, attackerUnitTypeID4);
  491.       //You can limit the number of units that are ever trained by this plan with this call.
  492.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  493.  
  494.       //Set the number of units to maintain in the world at one time.
  495.         if ( difflevel < 3 )
  496.         {
  497.           aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, 2);
  498.            aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 90);
  499.         }
  500.         else
  501.         {
  502.           aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, 4);
  503.            aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 45);
  504.         }
  505.  
  506.       //Set a gather point.
  507.       aiPlanSetVariableVector(maintainPlan4ID, cTrainPlanGatherPoint, 0, gatherPointMyth);
  508.       //Activate the plan.
  509.       aiPlanSetActive(maintainPlan4ID);
  510.    }
  511.  
  512.     // While we're here, destroy the defend plan at the gate.  It should have been
  513.     // there long enough to cover the builders.
  514.     aiPlanDestroy(defendPlan1ID);
  515.     xsDisableSelf();
  516. }
  517.  
  518.  
  519. //==============================================================================
  520. // armoryUpgrades, oh yeah!  Six minutes after AI is alerted, if it's still got
  521. // an armory.  And if it doesn't, it should rebuild one, even!
  522. //==============================================================================
  523. rule armoryUpgrades
  524.    minInterval 360
  525.    inactive
  526. {
  527.     // Difficulty Level check.
  528.     int difflevel=-1;        
  529.     difflevel=aiGetWorldDifficulty();
  530.  
  531.     aiEcho("*** GETTING ARMORY UPGRADES ***");
  532.     createTechProgression(cTechBronzeWeapons, "Research Bronze Weapons", cUnitTypeArmory);
  533.     createTechProgression(cTechBronzeMail, "Research Bronze Mail", cUnitTypeArmory);
  534.  
  535.     if ( difflevel == 3 )
  536.     {
  537.         createTechProgression(cTechBronzeShields, "Research Bronze Shields", cUnitTypeArmory);
  538.         createTechProgression(cTechHeavyElephants, "Research Heavy Elephants", cUnitTypeMigdolStronghold);
  539.     }
  540.     else
  541.     {
  542.         createTechProgression(cTechCopperShields, "Research Copper Shields", cUnitTypeArmory);
  543.     }
  544.  
  545.     xsDisableSelf();
  546. }
  547.  
  548.  
  549. //==============================================================================
  550. // Resource cheat for Titan.
  551. //==============================================================================
  552. rule cheatResources
  553.    minInterval 120
  554.    inactive
  555.    group TitanRules
  556. {
  557.     // Cheat, cheat, cheat...
  558.     aiResourceCheat( 2, cResourceFood, 300.0 );
  559.     aiResourceCheat( 2, cResourceFavor, 30.0 );
  560. }
  561.  
  562.  
  563. //==============================================================================
  564. // alertEnemy - fired with an AI FUNC when the player kills an anubite, or
  565. // builds a dock of his own.
  566. //
  567. // This causes the AI to wall up and then to start attacking.
  568. //==============================================================================
  569. void alertEnemy( int parameter=-1 )
  570. {
  571.     // Difficulty Level check.
  572.     int difflevel=-1;        
  573.     difflevel=aiGetWorldDifficulty();
  574.  
  575.     aiEcho("*** ENEMY ALERTED ***");
  576.     vector WallPointA=kbGetBlockPosition("3086");
  577.     vector WallPointB=kbGetBlockPosition("3087");
  578.     
  579.     vector WallPointC=kbGetBlockPosition("3088");
  580.     vector WallPointD=kbGetBlockPosition("3089");
  581.  
  582.     aiWallFromAToB("Build Wall", WallPointA, WallPointB, 1, 1, 1, cRootEscrowID, 1 );
  583.     aiWallFromAToB("Build Wall", WallPointC, WallPointD, 1, 1, 1, cRootEscrowID, 1 );
  584.  
  585.     vector TowerPoint=kbGetBlockPosition("1853");
  586.  
  587.     vector gatherPointElephants=kbGetBlockPosition("3101");
  588.  
  589.     // Difficulty level resource cheats.
  590.     if ( difflevel > 1 )
  591.     {
  592.         aiResourceCheat( 2, cResourceFood, 500.0 );
  593.         aiResourceCheat( 2, cResourceWood, 300.0 );
  594.         aiResourceCheat( 2, cResourceGold, 500.0 );
  595.     }
  596.  
  597.     // Even more on Titan, plus enable a semiconstant stream of stuff.
  598.     if ( difflevel > 2 )
  599.     {
  600.         aiResourceCheat( 2, cResourceFood, 300.0 );
  601.         aiResourceCheat( 2, cResourceWood, 200.0 );
  602.         aiResourceCheat( 2, cResourceGold, 300.0 );
  603.         xsEnableRule("cheatResources");
  604.     }
  605.  
  606.     // Maintain four elephants (eight on higher levels)
  607.    maintainPlan3ID=aiPlanCreate("Maintain 4 "+kbGetProtoUnitName(attackerUnitTypeID3), cPlanTrain);
  608.    if (maintainPlan3ID >= 0)
  609.    {
  610.         //Must set the type of unit to train.
  611.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeID3);
  612.       //You can limit the number of units that are ever trained by this plan with this call.
  613.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  614.       //Set the number of units to maintain in the world at one time.
  615.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 4);
  616.       //Don't train units too fast
  617.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 90);
  618.  
  619.         // Modifiers based on difficulty level.
  620.         if ( difflevel > 1 )
  621.         {
  622.             aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 50);
  623.         }
  624.  
  625.         if ( difflevel == 3) 
  626.         {
  627.             aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 8);
  628.         }
  629.  
  630.       //Set a gather point.
  631.       aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPointElephants);
  632.       //Activate the plan.
  633.       aiPlanSetActive(maintainPlan3ID);
  634.    }
  635.  
  636.     // Lots more villagers maintained.
  637.     if ( difflevel < 2 )
  638.     {
  639.         aiPlanSetVariableInt(maintainPlanVillagerID, cTrainPlanNumberToMaintain, 0, 16);
  640.     }
  641.     else
  642.     {
  643.         aiPlanSetVariableInt(maintainPlanVillagerID, cTrainPlanNumberToMaintain, 0, 20);
  644.     }
  645.  
  646.     // Defend plan at the main gate 
  647.    defendPlan1ID=aiPlanCreate("Gate Defense", cPlanDefend);
  648.    if (defendPlan1ID >= 0)
  649.    {
  650.       //Main gate location
  651.       vector defendPlanSpot=kbGetBlockPosition("3080");
  652.  
  653.         // On higher difficulty levels, more.
  654.         if ( difflevel > 1 )
  655.         {
  656.             //Add the unit(s).
  657.            aiPlanAddUnitType(defendPlan1ID, attackerUnitTypeID1, 0, 7, 7);
  658.             aiPlanAddUnitType(defendPlan1ID, attackerUnitTypeID2, 0, 6, 6);
  659.         }
  660.         else
  661.         {
  662.             //Add the unit(s).
  663.            aiPlanAddUnitType(defendPlan1ID, attackerUnitTypeID1, 0, 3, 3);
  664.             aiPlanAddUnitType(defendPlan1ID, attackerUnitTypeID2, 0, 2, 2);
  665.         }
  666.  
  667.       //Setup the vars - priority is slightly higher than the attack plans.
  668.       aiPlanSetDesiredPriority(defendPlan1ID, 60);
  669.       aiPlanSetVariableVector(defendPlan1ID, cDefendPlanDefendPoint, 0, defendPlanSpot);
  670.       aiPlanSetVariableFloat(defendPlan1ID, cDefendPlanEngageRange, 0, 15);
  671.       aiPlanSetActive(defendPlan1ID);
  672.     }
  673.  
  674.     // Create an explore plan with a single spearman.
  675.     /*
  676.    exploreID = aiPlanCreate("Explore", cPlanExplore);
  677.    if(exploreID >= 0)
  678.    {
  679.       aiPlanAddUnitType(exploreID, attackerUnitTypeID1, 1, 1);
  680.       aiPlanSetActive(exploreID);
  681.    }
  682.     */
  683.  
  684.    //-- Build a tower near the center of the lower route.
  685.    int buildTower = aiPlanCreate("Build Tower", cPlanBuild);
  686.    if(buildTower >= 0)
  687.    {
  688.       //BP Type and Priority.
  689.       aiPlanSetVariableInt(buildTower, cBuildPlanBuildingTypeID, 0, cUnitTypeTower);
  690.       aiPlanSetDesiredPriority(buildTower, 75);
  691.       aiPlanSetVariableVector(buildTower, cBuildPlanCenterPosition, 0, TowerPoint);
  692.         aiPlanSetVariableFloat(buildTower, cBuildPlanCenterPositionDistance, 0, 5);
  693.       aiPlanAddUnitType(buildTower, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 2, 2, 2);
  694.       aiPlanSetEscrowID(buildTower, cRootEscrowID);
  695.       aiPlanSetActive(buildTower);
  696.    }
  697.  
  698.     // Enable attacks, and set up for maintaining Scarabs in a few minutes.
  699.     xsEnableRule("attackGenerator1");
  700.     xsEnableRule("maintainScarabs");
  701.     
  702.     if ( difflevel > 0 )
  703.     {
  704.         xsEnableRule("armoryUpgrades");
  705.     }
  706.  
  707.     // Mmm, unit upgrades.  Let's go!
  708.     createTechProgression(cTechHeavySpearmen, "Research up to Heavy Spearmen", cUnitTypeBarracks);
  709.     createTechProgression(cTechHeavySlingers, "Research up to Heavy Slingers", cUnitTypeBarracks);
  710.  
  711.     // Attack response range increases to 20.
  712.     aiSetAttackResponseDistance(20.0);
  713. }
  714.  
  715. //==============================================================================
  716. // MAIN.
  717. //==============================================================================
  718. void main(void)
  719. {
  720.     // Difficulty Level check.
  721.     int difflevel=-1;        
  722.     difflevel=aiGetWorldDifficulty();
  723.  
  724.    //Startup.
  725.    miscStartup();
  726.     initMainBase();
  727.     initEcon();
  728.  
  729.    //Gather Points
  730.    vector gatherPointVillager=kbGetBlockPosition("1851");
  731.     vector gatherPointMilitary1=kbGetBlockPosition("3076");
  732.     vector gatherPointMilitary2=kbGetBlockPosition("3077");
  733.  
  734.     // On Titan difficulty level, Scarabs start getting cranked out right away, and he gets
  735.     // armory upgrades faster.
  736.     if ( difflevel == 3 )
  737.     {
  738.         xsSetRuleMinInterval("maintainScarabs", 30 );
  739.         xsSetRuleMinInterval("armoryUpgrades", 60 );
  740.     }
  741.  
  742.    maintainPlanVillagerID=aiPlanCreate("Maintain Villagers", cPlanTrain);
  743.    if (maintainPlanVillagerID >= 0)
  744.    {
  745.         //Must set the type of unit to train.
  746.       aiPlanSetVariableInt(maintainPlanVillagerID, cTrainPlanUnitType, 0, cUnitTypeVillagerEgyptian);
  747.       //You can limit the number of units that are ever trained by this plan with this call.
  748.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  749.       //Set the number of units to maintain in the world at one time.
  750.       aiPlanSetVariableInt(maintainPlanVillagerID, cTrainPlanNumberToMaintain, 0, 8);
  751.       //Don't train units faster than every 20 seconds
  752.       aiPlanSetVariableInt(maintainPlanVillagerID, cTrainPlanFrequency, 0, 20);
  753.       //Set a gather point.
  754.       aiPlanSetVariableVector(maintainPlanVillagerID, cTrainPlanGatherPoint, 0, gatherPointVillager);
  755.       //Activate the plan.
  756.       aiPlanSetActive(maintainPlanVillagerID);
  757.    }
  758.  
  759.    maintainPlan1ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain);
  760.    if (maintainPlan1ID >= 0)
  761.    {
  762.         //Must set the type of unit to train.
  763.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1);
  764.       //You can limit the number of units that are ever trained by this plan with this call.
  765.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  766.       // On higher difficulty levels, more.
  767.         if ( difflevel > 1 )
  768.         {
  769.             aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, 20);
  770.             aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 25);
  771.         }
  772.         else 
  773.         {
  774.             aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, 12);
  775.             aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 40);
  776.         }
  777.       //Set a gather point.
  778.       aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointMilitary1);
  779.       //Activate the plan.
  780.       aiPlanSetActive(maintainPlan1ID);
  781.    }
  782.  
  783.    maintainPlan2ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerUnitTypeID2), cPlanTrain);
  784.    if (maintainPlan2ID >= 0)
  785.    {
  786.         //Must set the type of unit to train.
  787.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID2);
  788.       //You can limit the number of units that are ever trained by this plan with this call.
  789.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  790.       //Set the number of units to maintain in the world at one time.
  791.       // On higher difficulty levels, more.
  792.         if ( difflevel > 1 )
  793.         {
  794.             aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, 12);
  795.             aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 40);
  796.         }
  797.         else
  798.         {
  799.             aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, 8);
  800.             aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 60);
  801.         }
  802.       
  803.       //Set a gather point.
  804.       aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPointMilitary2);
  805.       //Activate the plan.
  806.       aiPlanSetActive(maintainPlan2ID);
  807.    }
  808.  
  809.     // Create a fishing plan.
  810.     int fishGatherer = kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionFish, 0);
  811.     int fishPlanID=aiPlanCreate("FishPlan", cPlanFish);
  812.  
  813.     if (fishPlanID >= 0)
  814.     {
  815.         aiEcho("Setting up the Fishing Plan.");
  816.       aiPlanSetDesiredPriority(fishPlanID, 70);
  817.         aiPlanSetVariableVector(fishPlanID, cFishPlanLandPoint, 0, kbBaseGetLocation(cMyID, gMainBaseID));
  818.         
  819.         //-- If you don't explicitly set the water point, the plan will find one for you.
  820.         aiPlanSetVariableBool(fishPlanID, cFishPlanAutoTrainBoats, 0, false);   // I'm going to have a  maintain plan for fishing + scouting combined
  821.         aiPlanSetEscrowID(fishPlanID, cRootEscrowID);
  822.  
  823.         aiPlanAddUnitType(fishPlanID, fishGatherer, 3, 3, 3);
  824.         aiPlanSetActive(fishPlanID);
  825.     }
  826.  
  827.     // Empower the mining camp.
  828.     int empowerPlan1ID=aiPlanCreate("EmpowerPlan", cPlanEmpower);
  829.     if (empowerPlan1ID >= 0)
  830.     {
  831.         aiPlanSetDesiredPriority(empowerPlan1ID, 50);
  832.         aiPlanAddUnitType(empowerPlan1ID, cUnitTypePharaoh, 1, 1, 1);
  833.         aiPlanSetVariableInt(empowerPlan1ID, cEmpowerPlanTargetTypeID, 0, cUnitTypeMiningCamp);
  834.         aiPlanSetActive(empowerPlan1ID);
  835.     }
  836.  
  837.     // Empower a Migdol.
  838.     int empowerPlan2ID=aiPlanCreate("EmpowerPlan", cPlanEmpower);
  839.     if (empowerPlan2ID >= 0)
  840.     {
  841.         aiPlanSetDesiredPriority(empowerPlan2ID, 50);
  842.         aiPlanAddUnitType(empowerPlan2ID, cUnitTypePriest, 1, 1, 1);
  843.         aiPlanSetVariableInt(empowerPlan2ID, cEmpowerPlanTargetTypeID, 0, cUnitTypeMigdolStronghold);
  844.         aiPlanSetActive(empowerPlan2ID);
  845.     }
  846.  
  847.  
  848.     // Basic tech progressions to upgrade our operations.
  849.     createTechProgression(cTechShaftMine, "Research up to Shaft Mine", cUnitTypeMiningCamp);
  850.     createTechProgression(cTechIrrigation, "Research up to Irrigation", cUnitTypeGranary);
  851. }
  852.