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

  1. //==============================================================================
  2. // Scn19ap2: AI Scenario Script for scenario 19a player 2
  3. //==============================================================================
  4. /*
  5.    AI owner:  Mike Kidd
  6.    Scenario owner: Jeff Brown
  7.    Handed off to: Greg Street
  8.  
  9.    Overview:
  10.    The player lands on an open plain, with the goal of destroying the CP-owned 
  11.    wonder.  He starts with a sizeable myth army, and must build up sufficient
  12.    forces to break into the well-defended city.  
  13.  
  14.    The CP will build up and maintain land armies and a navy.  The land army will
  15.    be predominately Cav with some infantry.  At the time of launching each attack,
  16.    the CP will randomly choose land or water (2/3 land) and send in an appropriate
  17.    attack wave.
  18.  
  19.    There will be a special invocation of Earthquake if the CP survives to reach
  20.    age 4.   A pegasus will do a fly-over of the HP's town, and the CP will 
  21.    invoke Earthquake on the TC at that time.  The pegasus will then fly off, and
  22.    the CP will refrain from sending any attacks for the next 4 minutes.
  23.  
  24.    Difficulty:  7/17/2002
  25.  
  26.      
  27. */
  28. //==============================================================================
  29.  
  30.  
  31. include "scn lib.xs";
  32.  
  33.  
  34. // *****************************************************************************
  35. //
  36. // Globals
  37. //
  38. // *****************************************************************************
  39.  
  40. // Attack routes and queries
  41. // TODO
  42.  
  43. int   queryP1Units = -1;
  44. int   queryP1Buildings = -1;
  45.  
  46.  
  47. // Army control
  48. int   lastAttackPlan = -1;       // Used to find "my army" for god power position info
  49. int   lastNavyPlan = -1;
  50. int   nextAttackTime = 300000;   // Will be adjusted for the wakeup time
  51. int   attackInterval = 240000;   // Attack every 4:00
  52. float attackSize = 8;
  53. float attackSizeMultiplier = 1.2;    
  54. int   maxAttackSize = 12;
  55. int   reserveSize = 12;
  56.  
  57. // TODO:ships
  58. int   hippikonMaintainID = -1;      // Plan for maintaining population of hippikon units
  59. int   hippikonMaintainQty = 4;      // How many to maintain
  60. int   hippikonMaintainDelay = 60;   // How many seconds between training units
  61.  
  62. int   prodromosMaintainID = -1;
  63. int   prodromosMaintainQty = 4;
  64. int   prodromosMaintainDelay = 60;
  65.  
  66. int   hypaspistMaintainID = -1;
  67. int   hypaspistMaintainQty = 2;
  68. int   hypaspistMaintainDelay = 40;
  69.  
  70. int   hopliteMaintainID = -1;
  71. int   hopliteMaintainQty = 2;
  72. int   hopliteMaintainDelay = 40;
  73.  
  74. int   petrobolosMaintainID = -1;
  75. int   petrobolosMaintainQty = 2;
  76. int   petrobolosMaintainDelay = 90;
  77.  
  78.  
  79. // Cinematic blocks
  80. const string cbAttackGather = "1491";
  81. const string cbNavyGather = "1492";
  82. const string cbHypaspistGather = "1493";
  83. const string cbHippikonGather = "1494";
  84. const string cbHopliteGather = "1495";
  85. const string cbProdromosGather = "1496";
  86. const string cbSiegeGather  = "1497";
  87. const string cbTownLocation = "1498";
  88. const string cbAnimalMagnet = "1499";
  89. const string cbEarthquake = "1500";
  90.  
  91.  
  92. // Misc.
  93. int   age2Time = 0;    // 
  94. int   age3Time = 0;  // We start in 3rd age
  95. int   age4Time = 720000;  // Go to 4th age in 12 min
  96. int   startTime = -1;      // Time of the wakeup() function...will be added to the age times.
  97.  
  98.  
  99.  
  100. // *****************************************************************************
  101. //
  102. //                                FUNCTIONS
  103. //
  104. // *****************************************************************************
  105.  
  106.  
  107. // Called by trigger when the cinematics are done
  108. void wakeup(int parm=-1)
  109. {
  110.    static bool alreadyRun = false;
  111.    aiEcho("Wakeup running at "+timeString()+".");
  112.    if (alreadyRun == true)
  113.       return;
  114.    alreadyRun = true;
  115.  
  116.    startTime = xsGetTime();
  117.    age2Time = age2Time + startTime;
  118.    xsEnableRule("goToAge3");
  119.    age3Time = age3Time + startTime;    // Adjust for delay in wakeup. 
  120.    age4Time = age4Time + startTime;
  121.    nextAttackTime = nextAttackTime + startTime;
  122.  
  123.    // Init  maintain plans
  124.    maintainUnit(cUnitTypePegasus, 1, kbGetBlockPosition(cbTownLocation), 10);
  125.    // TODO: add ships
  126.    hippikonMaintainID = maintainUnit(cUnitTypeHippikon, hippikonMaintainQty, kbGetBlockPosition(cbHippikonGather), hippikonMaintainDelay);
  127.    hopliteMaintainID = maintainUnit(cUnitTypeHoplite, hopliteMaintainQty, kbGetBlockPosition(cbHopliteGather), hopliteMaintainDelay);
  128.  
  129.  
  130.  
  131.    xsEnableRule("useAnimalMagnet");
  132.    xsEnableRule("usePestilence");
  133.    xsEnableRule("scout");
  134.    xsEnableRule("attackGenerator");
  135. }
  136.  
  137.  
  138. // Used to delete units that are being replaced by a new type.
  139. void deleteObsoleteUnits(int unitType=cUnitTypeUnit, int player=2, vector center=vector(-1,-1,-1), float radius = 20.0, float percent=1.00)
  140. {
  141.    // Make query
  142.    int query = -1;
  143.    int count = -1;
  144.  
  145.    query = kbUnitQueryCreate("Unit deletion query");
  146.    if ( configQuery(query, unitType, -1, cUnitStateAlive, player, center, false, radius) == false)
  147.       return;
  148.    kbUnitQueryResetResults(query);
  149.    count = kbUnitQueryExecute(query);
  150.    
  151.    // Iterate list, deleting percentage indicated
  152.    float remainder=0.0; // Used to handle percentages, when this gets >= 1, it's time to delete a unit.
  153.    
  154.    for (i=0; <count)
  155.    {
  156.       remainder = remainder + percent;
  157.       if (remainder >= 1.0)   // time to delete one
  158.       {
  159.          aiTaskUnitDelete(kbUnitQueryGetResult(query,i));
  160.          remainder = remainder - 1.0;
  161.       }
  162.    }
  163. }
  164.  
  165.  
  166. void age2EventHandler(int bogus=-1)
  167. {
  168.    xsEnableRule("goToAge3");
  169.    xsEnableRule("getAge2UnitUpgrades");
  170.    xsEnableRule("getAge2ArmoryUpgrades");
  171.  
  172.  
  173. }
  174.  
  175.  
  176.  
  177. void age3EventHandler(int bogus=-1)
  178. {
  179.    xsEnableRule("useBronze");
  180.    xsEnableRule("goToAge4");
  181.    xsEnableRule("getAge3UnitUpgrades");
  182.    xsEnableRule("getAge3ArmoryUpgrades");
  183.  
  184. // TODO:  Add hero defense...
  185. //   mythMaintainID = maintainUnit(mythUnit, mythMaintainQty, kbGetBlockPosition(cbMythGather), mythMaintainDelay);
  186.    hypaspistMaintainID = maintainUnit(cUnitTypeHypaspist, hypaspistMaintainQty, kbGetBlockPosition(cbHypaspistGather), hypaspistMaintainDelay);
  187.    prodromosMaintainID = maintainUnit(cUnitTypeProdromos, prodromosMaintainQty, kbGetBlockPosition(cbProdromosGather), prodromosMaintainDelay);
  188.    petrobolosMaintainID = maintainUnit(cUnitTypePetrobolos, petrobolosMaintainQty, kbGetBlockPosition(cbSiegeGather), petrobolosMaintainDelay);
  189. }
  190.  
  191.  
  192.  
  193. void age4EventHandler(int bogus=-1)
  194. {
  195.    xsEnableRule("getAge4UnitUpgrades");
  196.    xsEnableRule("getAge4ArmoryUpgrades");
  197.    xsEnableRule("useEarthquake");
  198.  
  199. }
  200.  
  201.  
  202.  
  203.  
  204. void attack(int size=0)
  205. {
  206.    int   attackID=aiPlanCreate("Attack at "+timeString(true)+" ", cPlanAttack);
  207.    if (attackID < 0)
  208.       return;
  209.  
  210.    if (aiPlanSetVariableInt(attackID, cAttackPlanPlayerID, 0, 1) == false)
  211.       return;
  212.  
  213.    if (aiPlanSetNumberVariableValues(attackID, cAttackPlanTargetTypeID, 2, true) == false)
  214.       return;
  215.  
  216.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  217.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  218.  
  219. //         aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeLeft);
  220.   
  221.    aiPlanSetVariableVector(attackID, cAttackPlanGatherPoint, 0, kbGetBlockPosition(cbAttackGather));
  222.    aiPlanSetVariableFloat(attackID, cAttackPlanGatherDistance, 0, 10.0);
  223.    aiPlanSetInitialPosition(attackID, kbGetBlockPosition(cbAttackGather));
  224.    aiPlanAddUnitType(attackID, cUnitTypeMilitary, 1, size-1, size-1);
  225.  
  226. //         aiPlanSetNumberVariableValues(attackID, cAttackPlanQueryID, 2);
  227. //         aiPlanSetVariableInt(attackID, cAttackPlanQueryID, 0, queryP1Farms);
  228. //         aiPlanSetVariableInt(attackID, cAttackPlanQueryID, 1, queryP1Units);
  229.  
  230. //   aiPlanSetInitialPosition(attackID, kbGetBlockPosition(cbAttackGather));
  231.    aiPlanSetRequiresAllNeedUnits(attackID, true);
  232.    aiPlanSetActive(attackID);
  233.    aiEcho("Activating attack plan "+attackID+" with appx "+size+" units.");
  234.    lastAttackPlan = attackID; // update the global vars
  235.  
  236. }
  237.  
  238.  
  239.  
  240.  
  241. void main()
  242. {
  243.    aiEcho("Starting Scn19ap2.xs");
  244.  
  245.    kbAreaCalculate(1200.0);
  246.    aiRandSetSeed();
  247.    kbSetTownLocation(kbGetBlockPosition(cbTownLocation));
  248.  
  249.    aiSetAgeEventHandler(cAge2, "age2EventHandler");
  250.    aiSetAgeEventHandler(cAge3, "age3EventHandler");
  251.    aiSetAgeEventHandler(cAge4, "age4EventHandler");
  252.  
  253.    // Init attack routes
  254. //   routeLeft = attackRoute("Left Attack Route",cbAttackGather, cbRouteLeft1, cbRouteLeft2);
  255.  
  256.    // Initialize the target queries
  257.    queryP1Units = kbUnitQueryCreate("Player 1 Units");
  258.    configQuery(queryP1Units, cUnitTypeUnit, -1, cUnitStateAlive, 1);
  259.  
  260.    queryP1Buildings = kbUnitQueryCreate("Player 1 Buildings");
  261.    configQuery(queryP1Buildings, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, 1);
  262.  
  263.  
  264.    switch(aiGetWorldDifficulty())
  265.    {     // ignores 0 (easiest), uses initial values in that case.
  266.    case 1:     // medium
  267.       {
  268.          nextAttackTime = 300000;      // 5 minutes
  269.          attackSize = 6.0; 
  270.          maxAttackSize = 12.0;
  271.          attackSizeMultiplier = 1.2; 
  272.          attackInterval = 240000;      // 4 minutes   
  273.          reserveSize = 20;
  274.          age4Time = 8*60*1000;
  275.          break;
  276.       }
  277.    case 2:     // difficult/hard
  278.       {
  279.          nextAttackTime = 240000;      // 3 minutes
  280.          attackSize = 8.0; 
  281.          maxAttackSize = 30.0;
  282.          attackSizeMultiplier = 1.2; 
  283.          attackInterval = 180000;      // 3 minutes    
  284.          reserveSize = 35;
  285.          age4Time = 6*60*1000;
  286.          break;
  287.       }
  288.    case 3:     // hardest/nightmare
  289.       {
  290.          nextAttackTime = 30000;      // 30 sec
  291.          attackSize = 10.0; 
  292.          maxAttackSize = 50.0;
  293.          attackSizeMultiplier = 1.3; 
  294.          attackInterval = 120000;      // 2 minutes     
  295.          reserveSize = 60;
  296.          age4Time = 6*60*1000;
  297.          break;
  298.       }
  299.    }
  300.    hippikonMaintainQty = (reserveSize+1) / 3;
  301.    prodromosMaintainQty = (reserveSize+1) / 3;
  302.    hypaspistMaintainQty = (reserveSize+3) / 6;
  303.    hopliteMaintainQty = (reserveSize+3) / 6;
  304.  
  305.    aiEcho("Difficulty = "+aiGetWorldDifficulty());
  306. }
  307.  
  308.  
  309.  
  310.  
  311.  
  312. // *****************************************************************************
  313. //
  314. // RULES
  315. //
  316. // *****************************************************************************
  317.  
  318. rule scout
  319.    inactive
  320.    minInterval 5
  321. {
  322.    // just set up an explore plan
  323.    int exploreID = aiPlanCreate("Explore", cPlanExplore);
  324.    if(exploreID >= 0)
  325.    {
  326.       aiPlanSetVariableFloat( exploreID, cExplorePlanLOSMultiplier,  0, 4.0 );
  327.       aiPlanAddUnitType(exploreID, cUnitTypePegasus, 1, 1, 1);
  328.       aiPlanSetDesiredPriority(exploreID, 90);
  329.       aiPlanSetInitialPosition(exploreID, kbGetBlockPosition(cbAttackGather));
  330.       aiPlanSetActive(exploreID);
  331.    }
  332.  
  333.    int explore2ID = aiPlanCreate("Water explore", cPlanExplore);
  334.    if(explore2ID >= 0)
  335.    {
  336.       aiPlanSetVariableFloat( explore2ID, cExplorePlanLOSMultiplier,  0, 4.0 );
  337.       aiPlanAddUnitType(explore2ID, cUnitTypeHippocampus, 1, 1, 1);
  338.       aiPlanSetDesiredPriority(explore2ID, 90);
  339.       aiPlanSetInitialPosition(explore2ID, kbGetBlockPosition(cbNavyGather));
  340.       aiPlanSetActive(explore2ID);
  341.    }
  342.  
  343.    xsDisableSelf();
  344. }
  345.  
  346. rule goToAge2
  347.    inactive
  348.    minInterval 10
  349. {
  350.    if ( xsGetTime() < age2Time)
  351.       return;
  352. //   researchTech(cTechAge2Ptah);
  353.    xsDisableSelf();
  354. }
  355.  
  356.  
  357.  
  358. rule goToAge3
  359.    inactive
  360.    mininterval 20
  361. {
  362.    if ( xsGetTime() < age3Time )
  363.       return;
  364.    researchTech(cTechAge3Dionysos);
  365.    xsDisableSelf();
  366. }
  367.  
  368.  
  369. rule goToAge4
  370.    inactive
  371.    mininterval 20
  372. {
  373.    if ( xsGetTime() < age4Time )
  374.       return;
  375.    if (aiGetWorldDifficulty() != 0)
  376.       researchTech(cTechAge4Artemis);
  377.    xsDisableSelf();
  378. }
  379.  
  380.  
  381.  
  382. rule getAge2UnitUpgrades
  383.    inactive
  384.    minInterval 20
  385. {
  386.    if ( xsGetTime() < (age2Time + age2Time + age3Time)/3 )
  387.       return;     // Wait till 1/3 to age3
  388.    researchTech(cTechMediumCavalry);
  389.    researchTech(cTechMediumInfantry);
  390.    xsDisableSelf();
  391. }
  392.  
  393. rule getAge2ArmoryUpgrades
  394.    inactive
  395.    minInterval 20
  396. {
  397.    if ( xsGetTime() < (age2Time + age3Time + age3Time)/3 )
  398.       return;     // Wait till 2/3 to age3
  399.    aiEcho("Getting age 2 armory upgrades");
  400.    researchTech(cTechCopperWeapons);
  401.    researchTech(cTechCopperMail);
  402.    researchTech(cTechCopperShields);
  403.    xsDisableSelf();
  404. }
  405.  
  406. rule getAge3UnitUpgrades
  407.    inactive
  408.    minInterval 20
  409. {
  410.    if ( xsGetTime() < (age3Time+180000) )
  411.       return;
  412.    researchTech(cTechHeavyCavalry);
  413.    researchTech(cTechHeavyInfantry);
  414.    xsDisableSelf();
  415. }
  416.  
  417. rule getAge3ArmoryUpgrades
  418.    inactive
  419.    minInterval 20
  420. {
  421.    if ( xsGetTime() < (age3Time+300000) )
  422.       return;
  423.    researchTech(cTechBronzeWeapons);
  424.    researchTech(cTechBronzeMail);
  425.    researchTech(cTechBronzeShields);
  426.    xsDisableSelf();
  427. }
  428.  
  429. rule getAge4UnitUpgrades
  430.    inactive
  431.    minInterval 20
  432. {
  433.    if ( xsGetTime() < (age4Time+300000) )
  434.       return;
  435.    researchTech(cTechChampionCavalry);
  436.    researchTech(cTechChampionInfantry);
  437.    xsDisableSelf();
  438. }
  439.  
  440. rule getAge4ArmoryUpgrades
  441.    inactive
  442.    minInterval 20
  443. {
  444.    if ( xsGetTime() < (age4Time+600000) )
  445.       return;
  446.    researchTech(cTechIronWeapons);
  447.    researchTech(cTechIronMail);
  448.    researchTech(cTechIronShields);
  449.    xsDisableSelf();
  450. }
  451.  
  452.  
  453.  
  454. rule attackGenerator
  455.    minInterval 10
  456.    inactive
  457. {
  458.    // aiEcho("attack check running, next time is "+nextAttackTime);
  459.    if ( xsGetTime() < nextAttackTime )
  460.       return;
  461.  
  462.    attack(attackSize);
  463.    nextAttackTime = xsGetTime() + attackInterval;
  464.    attackSize = attackSize * attackSizeMultiplier;
  465.    if (attackSize > maxAttackSize)
  466.       attackSize = maxAttackSize;
  467.    aiEcho("Next attack size will be "+attackSize+".");
  468. }
  469.  
  470.  
  471.  
  472. rule useAnimalMagnetism
  473.    minInterval 5
  474.    inactive
  475. {
  476.    vector aimHere = kbGetBlockPosition(cbAnimalMagnet);
  477.  
  478.  
  479.    if (aiCastGodPowerAtPosition(cTechAnimalMagnetism, aimHere) == true)
  480.    {
  481.       xsDisableSelf();
  482.       aiEcho("Invoking animal magnetism at "+aimHere);
  483.    }
  484.    else
  485.       aiEcho("Couldn't do animal magnetism at "+aimHere);
  486. }
  487.  
  488.  
  489.  
  490.  
  491. rule usePestilence // Look for 2 military buildings near my army
  492.    minInterval 5
  493.    inactive
  494. {
  495.    int targetUnit = -1;
  496.    int attackArmyID = -1;
  497.  
  498.    if (lastAttackPlan < 0)
  499.       return;
  500.    vector pVec = aiPlanGetLocation(lastAttackPlan);
  501.    if (xsVectorGetX(pVec)<0)
  502.       return;
  503.  
  504.    static int tempQuery = -1;
  505.    if (tempQuery < 0)
  506.    {  // Doesn't exist, set it up
  507.       tempQuery = kbUnitQueryCreate("usePestilence");
  508.  
  509.       if ( configQuery(tempQuery, cUnitTypeMilitaryBuilding, -1, cUnitStateAliveOrBuilding, 1, pVec, true, 50) == false)
  510.          return;
  511.    }
  512.    else
  513.       kbUnitQuerySetPosition(tempQuery, pVec); // Because pVec changes as army moves
  514.  
  515.    kbUnitQueryResetResults(tempQuery);
  516.    int targetCount = kbUnitQueryExecute(tempQuery);  
  517.  
  518.    if (targetCount < 2)
  519.       return;
  520. //   targetUnit = kbUnitQueryGetResult(tempQuery, targetCount/2);  // grab middle farm
  521.  
  522.  
  523.    aiEcho("Using Pestilence");
  524.    if ( aiCastGodPowerAtPosition(cTechPestilence, pVec) == true)
  525.       xsDisableSelf();
  526.    else 
  527.       aiEcho("Pestilence failed at "+pVec);
  528. }
  529.  
  530.  
  531. rule useBronze // Look for 8 military units near my army
  532.    minInterval 5
  533.    inactive
  534. {
  535.    int targetUnit = -1;
  536.    int attackArmyID = -1;
  537.  
  538.    if (lastAttackPlan < 0)
  539.       return;
  540.    vector pVec = aiPlanGetLocation(lastAttackPlan);
  541.    if (xsVectorGetX(pVec)<0)
  542.       return;
  543.  
  544.    static int tempQuery = -1;
  545.    if (tempQuery < 0)
  546.    {  // Doesn't exist, set it up
  547.       tempQuery = kbUnitQueryCreate("useBronze");
  548.  
  549.       if ( configQuery(tempQuery, cUnitTypeMilitary, -1, cUnitStateAlive, 1, pVec, true, 50) == false)
  550.          return;
  551.    }
  552.    else
  553.       kbUnitQuerySetPosition(tempQuery, pVec); // Because pVec changes as army moves
  554.  
  555.    kbUnitQueryResetResults(tempQuery);
  556.    int targetCount = kbUnitQueryExecute(tempQuery);  
  557.  
  558.    if (targetCount < 8)
  559.       return;
  560. //   targetUnit = kbUnitQueryGetResult(tempQuery, targetCount/2);  // grab middle farm
  561.  
  562. // confirm that we have at least 10 miltary units there
  563.    static int query2 = -1;
  564.    if (query2 < 0)
  565.    {
  566.       query2 = kbUnitQueryCreate("useBronze2");
  567.       configQuery(query2, cUnitTypeMilitary, -1, cUnitStateAlive, 2, pVec, true, 25);
  568.    }
  569.       else
  570.          kbUnitQuerySetPosition(query2, pVec); // Because pVec changes as army moves
  571.    kbUnitQuerySetPosition(query2, pVec);
  572.    kbUnitQueryResetResults(query2);
  573.    targetCount = kbUnitQueryExecute(query2);
  574.    if (targetCount < 10)
  575.       return;
  576.  
  577.  
  578.    aiEcho("Using Bronze");
  579.    if ( aiCastGodPowerAtPosition(cTechBronze, kbUnitGetPosition(kbUnitQueryGetResult(query2, targetCount/2))) == true)
  580.       xsDisableSelf();
  581.    else 
  582.       aiEcho("Bronze failed on "+kbUnitQueryGetResult(query2, targetCount/2));
  583. }
  584.  
  585. /*
  586. rule useEarthquake // Look for 12 buildings near my army
  587.    minInterval 5
  588.    inactive
  589. {
  590.    int targetUnit = -1;
  591.    int attackArmyID = -1;
  592.  
  593.    if (lastAttackPlan < 0)
  594.       return;
  595.    vector pVec = aiPlanGetLocation(lastAttackPlan);
  596.    if (xsVectorGetX(pVec)<0)
  597.       return;
  598.  
  599.    static int tempQuery = -1;
  600.    if (tempQuery < 0)
  601.    {  // Doesn't exist, set it up
  602.       tempQuery = kbUnitQueryCreate("useEarthQuake");
  603.  
  604.       if ( configQuery(tempQuery, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, 1, pVec, true, 50) == false)
  605.          return;
  606.    }
  607.    else
  608.       kbUnitQuerySetPosition(tempQuery, pVec); // Because pVec changes as army moves
  609.  
  610.    kbUnitQueryResetResults(tempQuery);
  611.    int targetCount = kbUnitQueryExecute(tempQuery);  
  612.  
  613.    if (targetCount < 12)
  614.       return;
  615.    targetUnit = kbUnitQueryGetResult(tempQuery, targetCount/2);  // grab middle building
  616.  
  617.  
  618.    aiEcho("Using Earthquake");
  619.    if ( aiCastGodPowerAtPosition(cTechEarthquake, pVec) == true)
  620.       xsDisableSelf();
  621.    else 
  622.       aiEcho("Earthquake failed at "+pVec);
  623. }
  624. */
  625.  
  626. rule useEarthquake      // Ultra-hacked variant...grab pegasus, send to HP TC, do quake there.
  627.    minInterval 5
  628.    inactive
  629. {
  630.    static int lastPegasusMove = -20000;
  631.    static int pegQuery = -1;
  632.    static int pegUnit = -1;
  633.  
  634.    // Make sure pegasus is en route
  635.    if ( (xsGetTime()-20000) > lastPegasusMove ) // Move it again if last move was > 20 sec ago
  636.    {
  637.       if (pegQuery < 0)
  638.       {
  639.          pegQuery = kbUnitQueryCreate("Pegasus");
  640.          configQuery(pegQuery, cUnitTypePegasus, -1, cUnitStateAlive, 2);
  641.       }
  642.       kbUnitQueryResetResults(pegQuery);
  643.       if ( kbUnitQueryExecute(pegQuery) > 0 )
  644.          pegUnit = kbUnitQueryGetResult(pegQuery, 0);
  645.       else
  646.          return;
  647.       aiTaskUnitMove(pegUnit, kbGetBlockPosition(cbEarthquake));
  648.       lastPegasusMove = xsGetTime();
  649.    }
  650.  
  651.    // See if it's there
  652.    vector pegVec = kbUnitGetPosition(pegUnit);
  653.    if ( xsVectorGetX(pegVec) < 0)
  654.       return;
  655.    float dx = xsVectorGetX(pegVec) - xsVectorGetX(kbGetBlockPosition(cbEarthquake));
  656.    float dz = xsVectorGetZ(pegVec) - xsVectorGetZ(kbGetBlockPosition(cbEarthquake));
  657.    if (dx > 10.0)
  658.       return;
  659.    if (dx < -10.0)
  660.       return;
  661.    if (dz > 10.0)
  662.       return;
  663.    if (dz < -10.0)
  664.       return;
  665.  
  666.    // Pegasus is close enough for LOS
  667.    aiCastGodPowerAtPosition(cTechEarthquake, kbGetBlockPosition(cbEarthquake));
  668.    xsDisableSelf();
  669.    aiTaskUnitMove(pegUnit, kbGetBlockPosition(cbTownLocation));      // Bug out!
  670.  
  671.    // Prevent attacks for 4 minutes
  672.    nextAttackTime = xsGetTime() + 4*60*1000;    
  673. }
  674.  
  675.  
  676.  
  677.  
  678.