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

  1. //==============================================================================
  2. // Scn26p2: AI Scenario Script for scenario 26 player 2
  3. //==============================================================================
  4. /*
  5.    AI owner:  Mike Kidd
  6.    Scenario owner: Greg Street
  7.  
  8.    Overview:
  9.    
  10.    Has no economy. Just sends in waves of units for a "weather the storm".
  11.  
  12.    Starts fully upgraded in Age4. Does not need any techs.
  13.  
  14.    Player 2 should periodically attack with mostly giants while HP is building up. 
  15.    Once HP has reached the Dwarven Forge, Player 2 changes attacks to focus on that
  16.    area and sends in large waves of giants, Trolls and Ballistae.
  17.  
  18.    Note to MK: Many of the "route" CBs have changed numbers below const area, and may be incorrect.
  19.    Note to GTS:  Many of these routes have been fixed, and should all be correct.  ;-)
  20.  
  21.    9/19/2002:  Removed wakeup() call from main() as a wakeup trigger does exist.
  22.    Reduced difficulty on Titan from this:
  23.          nextAttackTime = 60000;
  24.          attackInterval = 120000;
  25.          attackSize = 8.0;
  26.          attackMultiplier = 1.4;    // 40% per period
  27.          maxAttackSize = 25;
  28.          age2Time = -1;       // N/A
  29.          age3Time = 1*60*1000;   // 1 min
  30.          age4Time = 5*60*1000;       
  31.          armyReserveSize = 35;
  32.    to this:
  33.          nextAttackTime = 120000;
  34.          attackInterval = 132000;
  35.          attackSize = 5.0;
  36.          attackMultiplier = 1.2;    // 20% per period
  37.          maxAttackSize = 18;
  38.          age2Time = -1;       // N/A
  39.          age3Time = 1*60*1000;   // 1 min
  40.          age4Time = 5*60*1000;       
  41.          armyReserveSize = 30;
  42.          standardDelay = 1;  // seconds     
  43.     also increased the hard attack interval by 20%.
  44.  
  45. */
  46. //==============================================================================
  47.  
  48.  
  49. include "scn lib.xs";
  50.  
  51.  
  52. // *****************************************************************************
  53. //
  54. // Globals
  55. //
  56. // *****************************************************************************
  57.  
  58.  
  59. // Cinematic blocks
  60.  
  61. const string cbMountainGiantGather = "2534";
  62. const string cbTrollGather = "2535";
  63. const string cbDefendPoint = "2535";
  64.  
  65. const string cbAttackGather = "2558";
  66. const string cbP1TCNorth = "2537";
  67. const string cbP1TCSouth = "2538"; 
  68. const string cbP2TC = "3690";
  69. const string cbWalkingWoods = "2540";
  70.  
  71. const string cbRouteA1 = "2546";    // Route A:  West channel
  72. const string cbRouteA2 = "2557";
  73. const string cbRouteA3 = "2544";
  74.  
  75. const string cbRouteB1 = "2546";    // Route B:  Center channel
  76. const string cbRouteB2 = "2547";
  77. const string cbRouteB3 = "2551";
  78.  
  79. const string cbRouteC1 = "2549";    // Route C:  East channel (initially closed)
  80. const string cbRouteC2 = "2550";
  81. const string cbRouteC3 = "2538";
  82.  
  83. const string cbRouteD1 = "2541";    // Route D:  SW entrance to forge
  84. const string cbRouteD2 = "2539";
  85. const string cbRouteD3 = "1886";
  86.  
  87. const string cbRouteE1 = "2536";    // Route E:  NW entrance to forge 
  88. const string cbRouteE2 = "2553";
  89. const string cbRouteE3 = "1886";
  90.  
  91. const string cbRouteF1 = "2536";    // Route F:  NE entrance to forge 
  92. const string cbRouteF2 = "2534";
  93. const string cbRouteF3 = "1886";
  94.  
  95. const string cbForge ="1886";          // Center of forge area
  96.  
  97.  
  98. // Attack routes and queries
  99. int   routeA = -1;
  100. int   routeB = -1;
  101. int   routeC = -1;
  102. int   routeD = -1;
  103. int   routeE = -1;
  104. int   routeF = -1;
  105.  
  106.  
  107. // Army control
  108. int   lastAttackPlan = -1;       // Used to find "my army" for god power position info
  109. int   defendPlan = -1;
  110. int   navalDefendPlan = -1;
  111. bool  defendOnly = false;        // When true, cancels last attack plan, all military go to defense
  112.  
  113.  
  114. // The following are set in main() based on difficulty level.
  115. int      nextAttackTime = 240000;   // Will be adjusted for the wakeup time
  116. int      attackInterval = 240000;   // Attack every 4:00 
  117. float    attackSize = 6.0;
  118. float    attackMultiplier = 1.2;
  119. int      maxAttackSize = 25;
  120. int   armyReserveSize = -1;   // Target size for total reserve army, to be adjusted for difficulty
  121. int   standardDelay = -1;     // Used to set unit-training delay times, adjusted for difficulty
  122.  
  123.  
  124. int   maintainQty1 = -1;         // Quantity to maintain
  125. int   maintainUnit1 = -1;        // Unit type
  126. int   maintainDelay1 = -1;       // Interval between training units
  127. vector   maintainGather1 = cInvalidVector;
  128. int   maintainID1 = -1;          // Maintain plan for primary military unit
  129.  
  130. int   maintainQty2 = -1;         // Quantity to maintain
  131. int   maintainUnit2 = -1;        // Unit type
  132. int   maintainDelay2 = -1;       // Interval between training units
  133. vector   maintainGather2 = cInvalidVector;
  134. int   maintainID2 = -1;          // Maintain plan for secondary military unit
  135.  
  136. int   maintainQty3 = -1;         // Quantity to maintain
  137. int   maintainUnit3 = -1;        // Unit type
  138. int   maintainDelay3 = -1;       // Interval between training units
  139. vector   maintainGather3 = cInvalidVector;
  140. int   maintainID3 = -1;          // Maintain plan for tertiary military unit
  141.  
  142. int   maintainQty4 = -1;         // Quantity to maintain
  143. int   maintainUnit4 = -1;        // Unit type
  144. int   maintainDelay4 = -1;       // Interval between training units
  145. vector   maintainGather4 = cInvalidVector;
  146. int   maintainID4 = -1;          // Maintain plan for quatenary military unit
  147.  
  148. int   maintainQtyScout = 1;
  149. int   maintainUnitScout = cUnitTypeFenrisWolf;
  150. int   maintainDelayScout = 1;
  151. vector   maintainGatherScout = cInvalidVector;
  152. int   maintainIDScout = -1;      // Scout unit
  153.  
  154.  
  155.  
  156.  
  157.  
  158. // Misc.
  159. int   age2Time = -1;       // Will be adjusted in main() for difficulty
  160. int   age3Time = -1;        
  161. int   age4Time = -1;       
  162. int   startTime = -1;      // Time of the wakeup() function...will be added to the age times.
  163.  
  164. int   difficulty = -1;     // Global to store difficulty, set early in main.
  165.  
  166. bool  forge = false;       // Set to true when the AI should be attacking the forge area
  167. bool  route3Open = false;  // Set to true when the trigger tells us that the third route is open.
  168.  
  169. // *****************************************************************************
  170. //
  171. //                                FUNCTIONS
  172. //
  173. // *****************************************************************************
  174.  
  175.  
  176. // Called by trigger when the cinematics are done
  177.  
  178. void wakeup(int parm=-1)
  179. {
  180.    static bool alreadyRun = false;
  181.    aiEcho("Wakeup running at "+timeString()+".");
  182.    if (alreadyRun == true)
  183.       return;
  184.    alreadyRun = true;
  185.  
  186.    startTime = xsGetTime();
  187.    if (age2Time > 0)
  188.       age2Time = age2Time + startTime; // Adjust for delay in wakeup.
  189.    xsEnableRule("goToAge3");
  190.    if (age3Time > 0)
  191.       age3Time = age3Time + startTime;     
  192.    if (age4Time > 0)
  193.       age4Time = age4Time + startTime;
  194.    if (nextAttackTime  > 0)
  195.       nextAttackTime = nextAttackTime + startTime;
  196.  
  197.    // Init maintain plans
  198.    if (maintainUnit1 > 0)
  199.       maintainID1 = maintainUnit(maintainUnit1, maintainQty1, maintainGather1, maintainDelay1);
  200.    if (maintainUnit2 > 0)
  201.       maintainID2 = maintainUnit(maintainUnit2, maintainQty2, maintainGather2, maintainDelay2); 
  202.    if (maintainUnit3 > 0)
  203.       maintainID3 = maintainUnit(maintainUnit3, maintainQty3, maintainGather3, maintainDelay3);  
  204.    if (maintainUnit4 > 0)
  205.       maintainID4 = maintainUnit(maintainUnit4, maintainQty4, maintainGather4, maintainDelay4);  
  206.    if (maintainUnitScout > 0)
  207.       maintainIDScout = maintainUnit(maintainUnitScout, maintainQtyScout, maintainGatherScout, maintainDelayScout);
  208.  
  209.  
  210.    // Init low-priority defend plan to manage all extra mil units
  211.    defendPlan =aiPlanCreate("Defend Plan", cPlanDefend);
  212.    if (defendPlan >= 0)
  213.    {
  214.       aiPlanAddUnitType(defendPlan, cUnitTypeMilitary, 0, 200, 200);    // All unassigned mil units
  215.       aiPlanSetDesiredPriority(defendPlan, 10);                       // Way low, below scouting and attack
  216.       aiPlanSetVariableVector(defendPlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbDefendPoint));
  217.       aiPlanSetVariableFloat(defendPlan, cDefendPlanEngageRange, 0, 20);
  218.       aiPlanSetVariableBool(defendPlan, cDefendPlanPatrol, 0, false);
  219.       aiPlanSetVariableFloat(defendPlan, cDefendPlanGatherDistance, 0, 20.0);
  220.       aiPlanSetVariableInt(defendPlan, cDefendPlanRefreshFrequency, 0, 5);
  221.       aiPlanSetNumberVariableValues(defendPlan, cDefendPlanAttackTypeID, 2, true);
  222.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit);
  223.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 1, cUnitTypeBuilding);
  224.  
  225.       aiPlanSetInitialPosition(defendPlan, kbGetBlockPosition(cbAttackGather));
  226.       aiPlanSetActive(defendPlan); 
  227.       aiEcho("Creating defend plan");
  228.    }
  229.  
  230.    xsEnableRule("scout");
  231.    xsEnableRule("attackGenerator");
  232. }
  233.  
  234.  
  235. // Called by a trigger to let the AI know that the third route is open (the boulder is gone). 
  236. void route3IsOpen(int ignore=0)
  237. {
  238.    route3Open = true;
  239.    aiEcho("Route C is open.");
  240. }
  241.  
  242.  
  243. // AIFunc
  244. void runAway(int ignore=0)
  245. {     // All units should run away from the forge
  246.    aiEcho("RunAway function called at "+timeString());
  247.    aiPlanSetVariableVector(defendPlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbDefendPoint));
  248.    aiPlanSetVariableFloat(defendPlan, cDefendPlanEngageRange, 0, 5);
  249.    aiSetAttackResponseDistance(5.0);
  250.  
  251.    aiPlanDestroy(lastAttackPlan);
  252.    aiPlanDestroy(defendPlan);
  253.    xsDisableRule("attackGenerator");
  254.       
  255.    // Force every unit to move NOW
  256.    int query=-1;
  257.    query = kbUnitQueryCreate("Unit list");
  258.    configQuery(query, cUnitTypeUnit, -1, cUnitStateAlive, cMyID);
  259.    int count = -1;
  260.    int i = -1;
  261.    int unit = -1;
  262.    kbUnitQueryResetResults(query);
  263.    count = kbUnitQueryExecute(query);
  264.    aiEcho("Moving "+count+" units.");
  265.    for (i=0; < count)
  266.    {
  267.       unit = kbUnitQueryGetResult(query, i);
  268.       aiTaskUnitMove(unit, kbGetBlockPosition(cbDefendPoint));
  269.       aiEcho("    "+unit);
  270.    }
  271. }
  272.  
  273.  
  274. // AIFunc
  275. void charge(int ignore=0)     // Time to have everybody attack
  276. {
  277.    aiEcho("Charge function called at "+timeString());
  278.    aiPlanSetVariableVector(defendPlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbForge));
  279.    aiPlanSetVariableFloat(defendPlan, cDefendPlanEngageRange, 0, 5);
  280.    aiSetAttackResponseDistance(20.0);
  281. }
  282.  
  283.  
  284. // Called by a trigger when the player has successfully captured the forge.  The bulk of offensive attacks will be on 
  285. // forge from this point forward,with occasional attacks on the HP's economy.
  286. void attackForge(int ignore=0)
  287. {
  288.    forge = true;     // Sets the global variable, monitored by attack function for choosing routes.
  289. //   aiPlanSetVariableVector(defendPlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbForge));
  290. //   xsEnableRule("restoreNormalDefense");     // When this rule fires, reset the defense to its normal position
  291. //   if ( (nextAttackTime + 90000) > xsGetTime() )      // Make sure we don't attack until the defense goes normal
  292. //      nextAttackTime = xsGetTime() + 90000;
  293.    aiEcho("Starting forge attacks");
  294.  
  295.    switch(difficulty)      // Attack more often now
  296.    {
  297.       case 0:     // Easy
  298.       {
  299.          attackInterval = 120000;
  300.          attackSize = 5;
  301.          armyReserveSize = 12;
  302.       }
  303.       case 1:     // Moderate
  304.       {
  305.          attackInterval = 90000;
  306.          attackSize = 9;
  307.          armyReserveSize = 18;
  308.       }
  309.       case 2:     // Hard
  310.       {
  311.          attackInterval = 75000;
  312.          attackSize = 12;
  313.          armyReserveSize = 25;
  314.       }
  315.       case 3:     // Titan
  316.       {
  317.          attackInterval = 60000;
  318.          attackSize = 12;
  319.          armyReserveSize = 35;
  320.       }
  321.    }
  322.    if (nextAttackTime > (xsGetTime() + attackInterval))
  323.       nextAttackTime = xsGetTime()+attackInterval;
  324.  
  325.    aiPlanDestroy(lastAttackPlan);
  326. }
  327.  
  328.  
  329.  
  330.  
  331. // Cancel last offensive plan and put all units on defense.
  332. void defend(int parm=-1)
  333. {
  334.    aiEcho("Defend function called.");
  335.    defendOnly = true;
  336.    aiPlanDestroy(lastAttackPlan);
  337. }
  338.  
  339.  
  340.  
  341.  
  342. // Used to delete units that are being replaced by a new type.
  343. void deleteObsoleteUnits(int unitType=cUnitTypeUnit, int player=2, vector center=vector(-1,-1,-1), float radius = 20.0, float percent=1.00)
  344. {
  345.    // Make query
  346.    int query = -1;
  347.    int count = -1;
  348.  
  349.    query = kbUnitQueryCreate("Unit deletion query");
  350.    if ( configQuery(query, unitType, -1, cUnitStateAlive, player, center, false, radius) == false)
  351.       return;
  352.    kbUnitQueryResetResults(query);
  353.    count = kbUnitQueryExecute(query);
  354.    
  355.    // Iterate list, deleting percentage indicated
  356.    float remainder=0.0; // Used to handle percentages, when this gets >= 1, it's time to delete a unit.
  357.    
  358.    for (i=0; <count)
  359.    {
  360.       remainder = remainder + percent;
  361.       if (remainder >= 1.0)   // time to delete one
  362.       {
  363.          aiTaskUnitDelete(kbUnitQueryGetResult(query,i));
  364.          remainder = remainder - 1.0;
  365.       }
  366.    }
  367. }
  368.  
  369.  
  370. void age2EventHandler(int bogus=-1)
  371. {
  372.    xsEnableRule("goToAge3");
  373.    xsEnableRule("getAge2UnitUpgrades");
  374.    xsEnableRule("getAge2ArmoryUpgrades");
  375.  
  376. /*   xsEnableRule("useHealingSpring"); */
  377. }
  378.  
  379.  
  380.  
  381. void age3EventHandler(int bogus=-1)
  382. {
  383.  
  384.    if (age4Time > 0) // May be suppressed for difficulty
  385.       xsEnableRule("goToAge4");
  386.    xsEnableRule("getAge3UnitUpgrades");
  387.    xsEnableRule("getAge3ArmoryUpgrades");
  388.  
  389.  
  390. // aiPlanSetVariableInt(navyMaintainID, cTrainPlanUnitType, 0, navyUnit);
  391. //   if (navyUnit != oldUnit)
  392. //   {
  393. //      deleteObsoleteUnits(oldUnit, 2, kbGetBlockPosition(cbFinalGate), 50, .5);   // Delete half of the old units
  394. //      aiEcho("Deleting units: "+kbGetProtoUnitName(oldUnit));
  395. //   }
  396.  
  397.    xsEnableRule("useWalkingWoods");
  398. }
  399.  
  400.  
  401.  
  402. void age4EventHandler(int bogus=-1)
  403. {
  404.    xsEnableRule("getAge4UnitUpgrades");
  405.    xsEnableRule("getAge4ArmoryUpgrades");
  406.  
  407.   //xsEnableRule("useNidhogg");
  408. }
  409.  
  410.  
  411.  
  412.  
  413. void attack(int size=0)
  414. {
  415.    if (defendOnly == true)
  416.       return;
  417.  
  418.    int   attackID=aiPlanCreate("Attack at "+timeString(true)+" ", cPlanAttack);
  419.    if (attackID < 0) 
  420.       return;
  421.  
  422.    if (aiPlanSetVariableInt(attackID, cAttackPlanPlayerID, 0, 1) == false)
  423.       return;
  424.  
  425.    if (aiPlanSetNumberVariableValues(attackID, cAttackPlanTargetTypeID, 3, true) == false)
  426.       return;
  427.  
  428.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  429.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  430.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 2, cUnitTypeAbstractWall);
  431.  
  432.    int rand = -1;
  433.    
  434.    if (forge == true)
  435.       rand = 3 + aiRandInt(3);   // 3, 4, 5, meaning routes D-F to attack forge
  436.    else
  437.    {
  438.       if (route3Open == true)
  439.          rand = aiRandInt(3);    // 0, 1, 2, routes A-C
  440.       else
  441.          rand = aiRandInt(2);    // 0, 1, just routes A or B, C is not yet open.
  442.    }
  443.    switch(rand)    // Pick a random path
  444.    {
  445.    case 0:
  446.       {
  447.          aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeA);
  448.          break;
  449.       }
  450.    case 1:
  451.       {
  452.          aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeB);
  453.          break;
  454.       }
  455.    case 2:
  456.       {
  457.          aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeC);
  458.          break;
  459.       }
  460.    case 3:
  461.       {
  462.          aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeD);
  463.          break;
  464.       }
  465.    case 4:
  466.       {
  467.          aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeE);
  468.          break;
  469.       }
  470.    case 5:
  471.       {
  472.          aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeF);
  473.          break;
  474.       }
  475.    }
  476.  
  477.    aiPlanSetVariableVector(attackID, cAttackPlanGatherPoint, 0, kbGetBlockPosition(cbAttackGather));
  478.    aiPlanSetVariableFloat(attackID, cAttackPlanGatherDistance, 0, 20.0);
  479.  
  480. /*   switch(kbGetAge())      // Set the targets and unit composition
  481.    {
  482.    case cAge1:
  483.       {  
  484.          aiPlanAddUnitType(attackID, cUnitTypeMilitary, 1, size, size);
  485.          break;
  486.       }
  487.    case cAge2:
  488.       {  
  489.          aiPlanAddUnitType(attackID, cUnitTypeMilitary, 1, size, size);
  490.          break;
  491.       }
  492.    case cAge3:
  493.       {  // 
  494.           aiPlanAddUnitType(attackID, cUnitTypeMilitary, 1, size, size);
  495.         //aiPlanAddUnitType(attackID, navyUnit, 1, (size+1)/2, (size+1)/2);
  496.          //aiPlanAddUnitType(attackID, barracksUnit, 1, (size+2)/4, (size+2)/4);
  497.          //aiPlanAddUnitType(attackID, cUnitTypeMythUnit, 0, (size+2)/4, (size+2)/4);
  498.          break;
  499.       }
  500.    case cAge4:
  501.       {  
  502.          aiPlanAddUnitType(attackID, cUnitTypeMilitary, 1, size, size);
  503. //         aiPlanAddUnitType(attackID, navyUnit, 1, (size+1)/2, (size+1)/2);
  504. //         aiPlanAddUnitType(attackID, barracksUnit, 1, (size+2)/4, (size+2)/4);
  505. //         aiPlanAddUnitType(attackID, cUnitTypeMythUnit, 0, (size+2)/4, (size+2)/4);
  506. //         aiPlanSetNumberVariableValues(attackID, cAttackPlanQueryID, 3);
  507. //         aiPlanSetVariableInt(attackID, cAttackPlanQueryID, 0, queryP1Monuments);
  508. //         aiPlanSetVariableInt(attackID, cAttackPlanQueryID, 1, queryP1Units);        
  509. //         aiPlanSetVariableInt(attackID, cAttackPlanQueryID, 2, queryP1Buildings); 
  510.  
  511.          break;
  512.       }
  513.    }*/
  514.  
  515.    if(kbGetAge() < cAge4)
  516.    {
  517.    aiPlanAddUnitType(attackID, maintainUnit1, 0, (size+1)/2, (size+1)/2);  // Just trolls and mountain giants
  518.    aiPlanAddUnitType(attackID, maintainUnit2, 0, (size)/2, (size)/2);
  519.    }
  520.    else
  521.    {
  522.    aiPlanAddUnitType(attackID, maintainUnit1, 0, (size+3)/4, (size+3)/4);
  523.    aiPlanAddUnitType(attackID, maintainUnit2, 0, (size+2)/4, (size+2)/4);
  524.    aiPlanAddUnitType(attackID, maintainUnit3, 0, (size+1)/4, (size+1)/4);
  525.    aiPlanAddUnitType(attackID, maintainUnit4, 0, (size)/4, (size)/4);
  526.  
  527.    }
  528.  
  529.    aiPlanSetInitialPosition(attackID, kbGetBlockPosition(cbAttackGather));
  530.    aiPlanSetRequiresAllNeedUnits(attackID, false);
  531.    aiPlanSetDesiredPriority(attackID, 50);   // Less than scouting, more than defense
  532.    aiPlanSetActive(attackID);
  533.    aiEcho("Activating attack plan "+attackID+" with appx "+size+" units.");
  534.    lastAttackPlan = attackID; // update the global var
  535. }
  536.  
  537.  
  538.  
  539.  
  540. void main()
  541. {
  542.    aiEcho("Starting Scn26p2.xs");
  543.  
  544.    //Calculate some areas.
  545.    kbAreaCalculate(1200.0);
  546.    aiRandSetSeed();
  547.    kbSetTownLocation(kbGetBlockPosition(cbP2TC));
  548.  
  549.    aiSetAgeEventHandler(cAge2, "age2EventHandler");
  550.    aiSetAgeEventHandler(cAge3, "age3EventHandler");
  551.    aiSetAgeEventHandler(cAge4, "age4EventHandler");
  552.  
  553.    aiSetAttackResponseDistance(10.0);
  554.  
  555.    kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0);
  556.    kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0);
  557.    kbEscrowAllocateCurrentResources();
  558.  
  559.  
  560.    // Set difficulty vars
  561.    difficulty = aiGetWorldDifficulty();
  562.    aiEcho("Difficulty = "+difficulty);   
  563.  
  564.    switch(difficulty)      // Set up the attack control and age-up parameters
  565.    {
  566.    case 0:     // Easy
  567.       {
  568.          nextAttackTime = 300000;   // 5 min
  569.          attackInterval = 390000;   //  6.5 min
  570.          attackSize = 1.3;          
  571.          attackMultiplier = 1.2;    // 20% per interval
  572.          maxAttackSize = 3;
  573.          age2Time = -1;       // N/A
  574.          age3Time = 1200000;  // 20 min
  575.          age4Time = 40*60*1000;       
  576.          armyReserveSize = 6;
  577.          standardDelay = 1;  // seconds
  578.          break;
  579.       }
  580.    case 1:     // Moderate
  581.       {
  582.          nextAttackTime = 180000;   // 3 min 
  583.          attackInterval = 300000;   // 5 min
  584.          attackSize = 3.0;          
  585.          attackMultiplier = 1.2;    // 20% per period
  586.          maxAttackSize = 6;
  587.          age2Time = -1;       // N/A
  588.          age3Time = 720000;   // 12 min
  589.          age4Time = 20*60*1000;      
  590.          armyReserveSize = 9;
  591.          standardDelay = 1;  // seconds
  592.          break;
  593.       }
  594.    case 2:     // Difficult
  595.       {
  596.          nextAttackTime = 120000;
  597.          attackInterval = 180000;
  598.          attackSize = 6.0;
  599.          attackMultiplier = 1.3;    // 30% per period
  600.          maxAttackSize = 12;
  601.          age2Time = -1;       // N/A
  602.          age3Time = 4*60*1000;   // 4 min
  603.          age4Time = 8*60*1000;       
  604.          armyReserveSize = 20;
  605.          standardDelay = 1;  // seconds
  606.          break;
  607.       }
  608.    case 3:     // Nightmare
  609.       {
  610.          nextAttackTime = 120000;
  611.          attackInterval = 132000;
  612.          attackSize = 5.0;
  613.          attackMultiplier = 1.2;    // 20% per period
  614.          maxAttackSize = 18;
  615.          age2Time = -1;       // N/A
  616.          age3Time = 1*60*1000;   // 1 min
  617.          age4Time = 5*60*1000;       
  618.          armyReserveSize = 30;
  619.          standardDelay = 1;  // seconds
  620.          break;
  621.       }
  622.    }
  623.  
  624.  
  625.    // Set global unit control vars
  626.    maintainQty1 = (armyReserveSize+2)/4;         // Quantity to maintain
  627.    maintainUnit1 = cUnitTypeTroll;        // Unit type
  628.    maintainDelay1 = standardDelay;       // Interval between training units
  629.    maintainGather1 = kbGetBlockPosition(cbTrollGather);
  630.  
  631.    maintainQty2 = (armyReserveSize+2)/4;         // Quantity to maintain
  632.    maintainUnit2 = cUnitTypeMountainGiant;        // Unit type
  633.    maintainDelay2 = standardDelay;       // Interval between training units
  634.    maintainGather2 = kbGetBlockPosition(cbMountainGiantGather);
  635.  
  636.    maintainQty3 = (armyReserveSize+2)/4;         // Quantity to maintain
  637.    maintainUnit3 = cUnitTypeFireGiant;        // Unit type
  638.    maintainDelay3 = standardDelay;       // Interval between training units
  639.    maintainGather3 = cInvalidVector;
  640.  
  641.    maintainQty4 = (armyReserveSize+2)/4;         // Quantity to maintain
  642.    maintainUnit4 = cUnitTypeBallista;        // Unit type
  643.    maintainDelay4 = standardDelay;       // Interval between training units
  644.    maintainGather4 = cInvalidVector;
  645.  
  646.    maintainQtyScout = 1;
  647.    maintainUnitScout = cUnitTypeFenrisWolf;
  648.    maintainDelayScout = 1;
  649.    maintainGatherScout = cInvalidVector;
  650.  
  651.  
  652.    // Init attack routes
  653.    routeA = attackRoute("Attack Route A", cbRouteA1, cbRouteA2, cbRouteA3);
  654.    routeB = attackRoute("Attack Route B", cbRouteB1, cbRouteB2, cbRouteB3);
  655.    routeC = attackRoute("Attack Route C", cbRouteC1, cbRouteC2, cbRouteC3);
  656.    routeD = attackRoute("Attack Route D", cbRouteD1, cbRouteD2, cbRouteD3);
  657.    routeE = attackRoute("Attack Route E", cbRouteE1, cbRouteE2, cbRouteE3);
  658.    routeF = attackRoute("Attack Route F", cbRouteF1, cbRouteF2, cbRouteF3);
  659.  
  660.  
  661.  
  662.  
  663. /*
  664.    // Initialize the target queries
  665.    queryP1Units = kbUnitQueryCreate("Player 1 Units");
  666.    configQuery(queryP1Units, cUnitTypeUnit, -1, cUnitStateAlive, 1);
  667.  
  668.    queryP1Buildings = kbUnitQueryCreate("Player 1 Buildings");
  669.    configQuery(queryP1Buildings, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, 1);
  670.  
  671.    queryP1Farms = kbUnitQueryCreate("Player 1 Farms");
  672.    configQuery(queryP1Farms, cUnitTypeFarm, -1, cUnitStateAliveOrBuilding, 1);
  673.  
  674.    queryP1Monuments = kbUnitQueryCreate("Player 1 Monuments");
  675.    configQuery(queryP1Monuments, cUnitTypeAbstractMonument, -1, cUnitStateAliveOrBuilding, 1);
  676.  
  677.    queryP1Citadels = kbUnitQueryCreate("Player 1 Citadels");
  678.    configQuery(queryP1Citadels, cUnitTypeCitadelCenter, -1, cUnitStateAliveOrBuilding, 1);
  679. */
  680.  
  681.    // wakeup(0);     // No wakeup trigger...call it immediately
  682.  
  683. }
  684.  
  685.  
  686.  
  687.  
  688.  
  689.  
  690.  
  691. // *****************************************************************************
  692. //
  693. // RULES
  694. //
  695. // *****************************************************************************
  696. rule cheatScout   // Spawn a fenris wolf if none exist
  697.    active
  698.    minInterval 15
  699. {
  700.    int count = -1;
  701.    count = kbUnitCount(2, maintainUnitScout, cUnitStateAlive);
  702.    if (count < maintainQtyScout)
  703.       aiUnitCreateCheat( 2, maintainUnitScout, kbGetBlockPosition(cbAttackGather), "Scout group", maintainQtyScout - count); 
  704.  
  705. }
  706.  
  707.  
  708. rule restoreNormalDefense  // Reset defense to normal after storming the forge
  709.    inactive
  710.    minInterval 45
  711. {
  712.    aiPlanSetVariableVector(defendPlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbDefendPoint));
  713.    aiEcho("Defend plan reset to normal location.");
  714.    xsDisableSelf();
  715.  
  716. }
  717.  
  718.  
  719. rule favorGenerator
  720.    active
  721.    minInterval 15
  722. {
  723.    aiResourceCheat( 2, cResourceFavor, 100.0 );    // Max out the favor every 15 seconds
  724.    kbEscrowAllocateCurrentResources();             // Make sure the escrow knows about it.
  725. }
  726.  
  727.  
  728. rule scout
  729.    inactive
  730.    minInterval 5
  731. {
  732.    // just set up an explore plan
  733.    int exploreID = aiPlanCreate("Explore", cPlanExplore);
  734.    if(exploreID >= 0)
  735.    {
  736.       aiPlanSetVariableFloat( exploreID, cExplorePlanLOSMultiplier,  0, 4.0 );
  737.       aiPlanAddUnitType(exploreID, maintainUnitScout, 1, 1, 1);
  738.       aiPlanSetDesiredPriority(exploreID, 90);
  739.       aiPlanSetInitialPosition(exploreID, kbGetBlockPosition(cbAttackGather));
  740.       aiPlanSetActive(exploreID);
  741.    }
  742.    xsDisableSelf();
  743. }
  744.  
  745.  
  746.  
  747.  
  748. /*
  749. rule getWatchTower
  750.    inactive
  751.    minInterval 10
  752.    group upgradeGroup
  753. {
  754.    if (kbGetTechStatus(cTechWatchTower) == cTechStatusAvailable)
  755.    {
  756.       int x=-1;
  757.       x = aiPlanCreate("WatchTower", cPlanResearch);
  758.       aiPlanSetVariableInt(x, cResearchPlanTechID, 0, cTechWatchTower);
  759.       aiPlanSetActive(x);
  760.       xsDisableSelf();
  761.       aiEcho("Getting Watch Tower");
  762.    }
  763. }
  764. */
  765.  
  766.  
  767.  
  768.  
  769. rule goToAge2
  770.    inactive
  771.    minInterval 10
  772. {
  773.    if ( xsGetTime() < age2Time)
  774.       return;
  775.    researchTech(cTechAge2Heimdall);
  776.    xsDisableSelf();
  777. }
  778.  
  779.  
  780.  
  781. rule goToAge3
  782.    inactive
  783.    mininterval 20
  784. {
  785.    if ( xsGetTime() < age3Time )
  786.       return;
  787.    researchTech(cTechAge3Njord);
  788.    xsDisableSelf();
  789. }
  790.  
  791.  
  792. rule goToAge4
  793.    inactive
  794.    mininterval 20
  795. {
  796.    if ( xsGetTime() < age4Time )
  797.       return;
  798.    researchTech(cTechAge4Hel);
  799.    xsDisableSelf();
  800. }
  801.  
  802.  
  803.  
  804. rule getAge2UnitUpgrades
  805.    inactive
  806.    minInterval 20
  807. {
  808.    if ( xsGetTime() < (age2Time + age2Time + age3Time)/3 )
  809.       return;     // Wait till 1/3 to age3
  810. //   researchTech(cTechMediumInfantry);
  811. //   researchTech(cTechMediumCavalry);
  812.    xsDisableSelf();
  813. }
  814.  
  815. rule getAge2ArmoryUpgrades
  816.    inactive
  817.    minInterval 20
  818. {
  819.    if ( xsGetTime() < (age2Time + age3Time + age3Time)/3 )
  820.       return;     // Wait till 2/3 to age3
  821. //   aiEcho("Getting age 2 armory upgrades");
  822. //   researchTech(cTechCopperWeapons);
  823. //   researchTech(cTechCopperMail);
  824. //   researchTech(cTechCopperShields);
  825.    xsDisableSelf();
  826. }
  827.  
  828. rule getAge3UnitUpgrades
  829.    inactive
  830.    minInterval 20
  831. {
  832.    if ( xsGetTime() < (age3Time+180000) )
  833.       return;
  834. //   researchTech(cTechHeavyInfantry);
  835.  //  researchTech(cTechHeavyCavalry);
  836.    xsDisableSelf();
  837. }
  838.  
  839. rule getAge3ArmoryUpgrades
  840.    inactive
  841.    minInterval 20
  842. {
  843.    if ( xsGetTime() < (age3Time+300000) )
  844.       return;
  845. //   researchTech(cTechBronzeWeapons);
  846. //   researchTech(cTechBronzeMail);
  847. //   researchTech(cTechBronzeShields);
  848.    xsDisableSelf();
  849. }
  850.  
  851. rule getAge4UnitUpgrades
  852.    inactive
  853.    minInterval 20
  854. {
  855.    if ( xsGetTime() < (age4Time+300000) )
  856.       return;
  857.    researchTech(cTechChampionInfantry);
  858.    researchTech(cTechChampionCavalry);
  859.    xsDisableSelf();
  860. }
  861.  
  862. rule getAge4ArmoryUpgrades
  863.    inactive
  864.    minInterval 20
  865. {
  866.    if ( xsGetTime() < (age4Time+600000) )
  867.       return;
  868.    researchTech(cTechIronWeapons);
  869.    researchTech(cTechIronMail);
  870.    researchTech(cTechIronShields);
  871.    xsDisableSelf();
  872. }
  873.  
  874.  
  875.  
  876. rule attackGenerator
  877.    minInterval 10
  878.    inactive
  879. {
  880.    //aiEcho("attack check running, next time is "+nextAttackTime);
  881.    if ( xsGetTime() < nextAttackTime )
  882.       return;
  883.  
  884.    attack(attackSize);
  885.    nextAttackTime = xsGetTime() + attackInterval;
  886.    attackSize = attackSize * attackMultiplier;
  887.    if (attackSize > maxAttackSize)
  888.       attackSize = maxAttackSize;
  889.    aiEcho("Next attack size will be "+attackSize+".");
  890. }
  891.  
  892.  
  893. /*
  894. // Checks to see if a large P1 army is near the prison, if so, set off a swarm attack.
  895. rule armyNearPrison
  896.    inactive
  897.    minInterval 15
  898. {
  899.    static int queryPrison=-1; // Used for unit count and targeting.
  900.    int   count=0;
  901.    int   attackID=-1;
  902.    
  903.    if (queryPrison < 0)
  904.    {
  905.       // Create query
  906.       queryPrison = kbUnitQueryCreate("Prison query");
  907.       if ( configQuery(queryPrison, cUnitTypeUnit, -1, cUnitStateAlive, 1, kbGetBlockPosition(cbNearPrison), false, 50) == false)
  908.          return;
  909.    }
  910.  
  911.    // Check for enemies
  912.    kbUnitQueryResetResults(queryPrison);
  913.    count = kbUnitQueryExecute(queryPrison);
  914.  
  915.    if (count < 6)
  916.       return;
  917.  
  918.  
  919.  
  920.    // Rally units to defend...all units within 100 meters, to a maximum of 30 units
  921.    aiEcho("Outer wall emergency.");
  922.    attackID = aiPlanCreate("Prison Attack", cPlanAttack);
  923.    count = getUnassignedUnitCount(kbGetBlockPosition(cbAttackGather), 100.0, 2, cUnitTypeMilitary);
  924.    if (count > 30)
  925.       count = 30;
  926.    
  927.    if (attackID < 0)
  928.       return;
  929.  
  930.    if (aiPlanSetVariableInt(attackID, cAttackPlanPlayerID, 0, 1) == false)
  931.       return;
  932.  
  933.    aiPlanSetNumberVariableValues(attackID, cAttackPlanQueryID, 2);
  934.    aiPlanSetVariableInt(attackID, cAttackPlanQueryID, 0, queryPrison);     // Attack units near prison, then
  935.    aiPlanSetVariableInt(attackID, cAttackPlanQueryID, 1, queryP1Units);    // Attack any units
  936.  
  937.    aiPlanSetVariableVector(attackID, cAttackPlanGatherPoint, 0, kbGetBlockPosition(cbAttackGather));
  938.    aiPlanSetVariableFloat(attackID, cAttackPlanGatherDistance, 0, 10.0);
  939.  
  940.    aiPlanAddUnitType(attackID, cUnitTypeMilitary, 1, count, count );
  941.  
  942.    aiEcho("Responding with "+count+" units.");
  943.    aiPlanSetInitialPosition(attackID, kbGetBlockPosition(cbAttackGather));
  944.    aiPlanSetRequiresAllNeedUnits(attackID, true);
  945.    aiPlanSetActive(attackID);
  946.    xsDisableSelf();
  947. }
  948. */
  949.  
  950.  
  951. // Use walking woods as soon as we have LOS
  952. rule useWalkingWoods
  953.    minInterval 5
  954.    inactive
  955. {
  956.    if (kbLocationVisible(kbGetBlockPosition(cbWalkingWoods)) == false)
  957.       return;
  958.  
  959.    aiCastGodPowerAtPosition(cTechWalkingWoods, kbGetBlockPosition(cbWalkingWoods));
  960.    aiEcho("Using walking woods at "+kbGetBlockPosition(cbWalkingWoods));
  961.    xsDisableSelf();
  962. }
  963.  
  964. /*
  965.  
  966. // Use healing spring only after "forge" is true
  967. rule useHealingSpring
  968.    minInterval 5
  969.    inactive
  970. {
  971.    if (forge == false)
  972.       return;
  973.  
  974.    aiCastGodPowerAtPosition(cTechHealingSpring, kbGetBlockPosition(cbMountainGiantGather));
  975.    aiEcho("Using Healing Spring at "+kbGetBlockPosition(cbMountainGiantGather));
  976.    xsDisableSelf();
  977. } */
  978.  
  979.  
  980.  
  981.  
  982.  
  983. /*
  984. rule useUndermine // Look for 2 walls near my army
  985.    minInterval 5
  986.    inactive
  987. {
  988.    int targetUnit = -1;
  989.    int attackArmyID = -1;
  990.  
  991.    if (lastAttackPlan < 0)
  992.       return;
  993.    vector pVec = aiPlanGetLocation(lastAttackPlan);
  994.    if (xsVectorGetX(pVec)<0)
  995.       return;
  996.  
  997.    static int tempQuery = -1;
  998.    if (tempQuery < 0)
  999.    {  // Doesn't exist, set it up
  1000.       tempQuery = kbUnitQueryCreate("useUndermine");
  1001.  
  1002.       if ( configQuery(tempQuery, cUnitTypeAbstractWall, -1, cUnitStateAliveOrBuilding, 1, pVec, true, 25) == false)
  1003.          return;
  1004.    }
  1005.    else
  1006.       kbUnitQuerySetPosition(tempQuery, pVec); // Because pVec changes as army moves
  1007.  
  1008.    kbUnitQueryResetResults(tempQuery);
  1009.    int targetCount = kbUnitQueryExecute(tempQuery);  
  1010.  
  1011.    if (targetCount < 2)
  1012.       return;
  1013.    targetUnit = kbUnitQueryGetResult(tempQuery, 0);  // grab first wall
  1014.  
  1015.    // confirm LOS
  1016.    if ( kbUnitVisible(targetUnit) != true )
  1017.    {
  1018.       aiEcho("Undermine: Don't have LOS for unit "+targetUnit+" "+kbGetProtoUnitName(targetUnit));
  1019.       return;
  1020.    }
  1021.  
  1022.    aiEcho("Using Undermine at "+kbUnitGetPosition(targetUnit));
  1023.    if ( aiCastGodPowerAtPosition(cTechUndermine, kbUnitGetPosition(targetUnit)) == true)
  1024.       xsDisableSelf();
  1025.    else 
  1026.       aiEcho("Undermine failed at "+kbUnitGetPosition(targetUnit));
  1027. }
  1028. */
  1029.  
  1030.