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

  1. //==============================================================================
  2. // Scn07p2: AI Scenario Script for scenario 7 player 2
  3. //==============================================================================
  4. /*
  5.    AI owner:  Mike Kidd
  6.    Scenario owner: Jeff Brown
  7.  
  8.    Overview:
  9.       The player's challenge is to take down the main gate at Troy, starting 
  10.       from the south end of the map.  The main gate is behind several layers of
  11.       walls.  Near the map center, just inside the outer walls, is a Trojan
  12.       market.  Trade units travel from this market to town centers at the east
  13.       and west map ends, and these trade units generate "income" for Troy.  
  14.  
  15.       Every time a trade unit completes a trip, Troy gets "income"...a counter
  16.       is incremented.  As this counter advances, Troy is allowed to research 
  17.       unit line upgrades, attack and armor upgrades, and age advances.  If the
  18.       player is effective at suppressing or eliminating this trade, he will 
  19.       face a rather weak army when assaulting Troy.  Killed trade units will 
  20.       gradually be replaced, but replacement is slow enough to make killing 
  21.       worthwhile.  If the market is destroyed, trade unit activity and replacement
  22.       is suspended.  A trickle of "income" is provided to Troy so that even with
  23.       all trade suspended, it will eventually age up.
  24.  
  25.       Attacking the trade is also good because Troy will devote its armies to 
  26.       defense, rather than raiding the player's town.  Troy's priorities are:
  27.          1)  Guard the market
  28.          2)  Guard and replace the trade units
  29.          3)  Raid the player's town
  30.  
  31.       When the player reaches the inner walls, other reserve units will appear 
  32.       to help defend the walls, including cyclopses, catapults, etc.  These units 
  33.       will not be used offensively.  The reserve units are kept in two defense plans,
  34.       one for hoplites near the gate, and one for cavalry further back.  The 
  35.       defense plan radii should be such that the units respond appropriately.
  36.  
  37.       In addition to the entity-AI-only units scattered around the map, the 
  38.       CP trains hoplites and hippikons behind the innermost wall, attempting to 
  39.       maintain a target population.  At attackInterval times, the CP drafts an army
  40.       of attackSize units, and sends them at the target indicated by attackMode.
  41.  
  42.       AttackMode is set to the market if an army is within the outer walls.  If an 
  43.       enemy army has been detected near either trade route in the last few minutes, 
  44.       the armies select targets based on a query centered on that area and restricted 
  45.       in radius to avoid the CP town.  If the center is clear, and no enemy unit
  46.       groups have been seen on the trade routes recently, then Troy goes offensive 
  47.       and attacks the HP's town.
  48.      
  49.       CP starts as Zeus in age 2, with Bolt and Cease Fire available.  
  50.       Age3: Dionysos (Bronze).
  51.       Age 4: Hera (lightning storm).
  52.  
  53.       Difficulty:  Implemented 7/17/2002
  54.  
  55.       7/18/2002:  Changed effect of killing donkeys.  In addition to delaying upgrades,
  56.       the attack group size is modified downward if the number of donkeys remaining isn't
  57.       at the desired level.  That is, by killing donkeys, the player reduces the size
  58.       of attack groups.
  59.  
  60.       7/24/2002:  Totally removing the effects of trade on age upgrade times.  Will 
  61.       make the trickle trade the only thing that counts, it will come in at a higher rate.
  62.       Fixing a bug where the target unit type for the attack plans is set to -1.  (Only matters when
  63.       the query is empty.)  Totally removing the queries for attack groups, we're not
  64.       limiting the attack range any more based on trade damage.
  65.  
  66.       7/31/2002:  Tweaked the difficulty down a bit, to compensate for the added threat on the water.
  67.       Decreased trade point accumulation (slower age upgrades) and reduced frequency of attacks.
  68.  
  69.       8/20/2002:  Fixed the side effects of age2EventHandler no longer firing on startup.
  70.  
  71.       8/20/2002:  Difficulty feedback.  Made the following changes:
  72.  
  73.             Killing trade carts affects number of hoplite in attack group.  Normally half the cav number,
  74.             the number will be 1/2 cav times % trade carts remaining.
  75.  
  76.             Trade carts will not be replaced.
  77.  
  78.             Starting attack group size, and max size are reduced for hard and nightmare.
  79.  
  80.       9/03/2002:  Reduced attack size, maxAttackSize and defend qty's for easy and moderate.
  81.             Slowed attack frequency on easy.
  82.  
  83.       9/06/2002:  Added check for the existance of the market.  If it doesn't exist, leave donkeys at corner TCs.
  84.       Also reduced attack group size by 15% on easy.  Added seige to attack groups on hard/titan.
  85.  
  86.       9/07/2002:  Changed "need" from 0 to 1 for hoplites and hippikons in attack plan, to avoid weirdness in the unit selection.
  87. */
  88. //==============================================================================
  89.  
  90.  
  91. include "scn lib.xs";
  92.  
  93. float tradePoints = 0.0;       // Variable used to track how much trade Troy has been able to keep going.
  94.                            // Used to activate upgrades for this CP.
  95. float tradePointIncrement = 1.0; // Used to adjust difficulty level
  96.  
  97. int      routeWest=-1;     // Attack route for west side
  98. int      routeEast=-1;     // Attack route for east side
  99. int      routeCenter=-1;   // Attack route to market area
  100.  
  101. int      lastAttackPlan=-1;   // ID of the most recent attack plan, for god power monitoring
  102. int      attackQuery=-1;      // Query used for target selection in all attack plans
  103. int      defendPlan = -1;
  104. int      defendPlan2 = -1;    // Extra for hippikons
  105.  
  106. vector   attackVector = vector(-1,-1,-1);    // Defines the center of the area in which attack plans look for targets.
  107. float    attackRadius = 75.0; // How far away from the vector can it select targets?
  108.  
  109.  
  110. int      attackInterval=360000;        // Seconds between attacks
  111. int      nextAttackTime=360000;        // Time for next attack
  112. float     attackSize=2.55;             // Number of units
  113. float    attackMultiplier = 1.2;
  114. int      maxAttackSize=6;
  115. int      hopliteQty = 7;
  116. int      hippikonQty = 9;
  117. int      trainInterval = 20;        // Seconds between training hoplites, hippikons
  118.  
  119. int      lastWestAttack=-600000;    // Last time west trade route was attacked.
  120. int      lastEastAttack=-600000;
  121.  
  122. bool     okToUseLightning = false;     // Set to true in the lightning() aiFunc.
  123.  
  124. /* This functionality suppressed 7/24/2002
  125.  int      attackMode=0;             // Attack mode.  Determines CP AI priorities.  Values:
  126. const int cAttackModeHPTown = 0;    //    0:  Hasn't been attacked, primary focus is HP city.
  127. const int cAttackModeDefense = 1;   //    1:  Deep attack, enemy units inside fortification...all-out defense
  128. const int cAttackModeWest = 2;      //    2:  Defending west side trade route
  129. const int cAttackModeEast = 3;      //    3:  Defending east side trade route
  130. */
  131.  
  132. const string cWestSide="3470";    // Cinematic block markers
  133. const string cCenter="3469";
  134. const string cEastSide="3471";
  135. const string cWestGate="3514";
  136. const string cEastGate="3515";
  137. const string cHPTown="3516";
  138. const string cInfGather="3472";
  139. const string cCavGather="3473";
  140. const string cMarket="3660";
  141. const string cWestTown="3661";
  142. const string cEastTown="3662";
  143. const string cAttackGather="7673";
  144.  
  145. int   donkeyQueryMiddle=-1;      // Checks for idle donkeys at market
  146. int   donkeyQueryWest=-1;        // Checks for idle donkeys at west town
  147. int   donkeyQueryEast=-1;        // Checks for idle donkeys at east town
  148. int   donkeyQueryIdleOther=-1;
  149. bool  donkeyGoEast=false;        // Flip-flop controller for donkey direction from center market
  150. int   TCQueryWest=-1;            // Query to find out if west TC is still CP-owned
  151. int   TCQueryEast=-1;            // Ditto east
  152. int   marketQuery=-1;            // Ditto market
  153.  
  154. int   donkeyQty = 8;
  155.  
  156. // *****************************************************************************
  157. //
  158. //                                FUNCTIONS
  159. //
  160. // *****************************************************************************
  161.  
  162.  
  163.  
  164. void age2EventHandler(int bogus=-1)
  165. {
  166.  
  167. }
  168.  
  169. void age3EventHandler(int bogus=-1)
  170. {
  171.    xsEnableRule("useBronze");
  172. }
  173.  
  174. void age4EventHandler(int bogus=-1)
  175. {
  176.    xsEnableRule("useLightningStorm");
  177. }
  178.  
  179.  
  180. void lightning(int ignore = 0)
  181. {
  182.    aiEcho("Lightning func called, it is now OK to use lightning when available.");
  183.    okToUseLightning = true;
  184. }
  185.  
  186.  
  187. void tradePoint(int parm=1)     // Called via a trigger each time a caravan finishes a trade route.
  188. // On 7/24, changed it so that trickleTrade is the only thing that calls this.
  189. {
  190.    tradePoints = tradePoints+tradePointIncrement;
  191.    //aiEcho("TradePoint firing, total is "+tradePoints);
  192. }
  193.  
  194.  
  195. /* Disabled 7/24/2002
  196. void attack(int side=-1)         // Called via a trigger (actually, now a rule) when a caravan is attacked, 0 for west, 1 for east
  197. {
  198.    if (xsGetTime() < 10000)
  199.       return;  // avoid initial false alarms
  200.    //aiEcho("I'm being attacked! ("+side+")");
  201.  
  202.    if (side == 0)
  203.       lastWestAttack = xsGetTime();
  204.  
  205.    if (side == 1)
  206.       lastEastAttack = xsGetTime();
  207. }
  208. */
  209.  
  210.  
  211.  
  212.  
  213. void testAttack()
  214. {
  215.    int   attackID=aiPlanCreate("Test Attack "+timeString()+"  ", cPlanAttack);
  216.    if (attackID < 0)
  217.    {
  218.       return;
  219.    }
  220.  
  221.    if (aiPlanSetVariableInt(attackID, cAttackPlanPlayerID, 0, 1) == false)
  222.    {
  223.       return;
  224.    }
  225.  
  226.    if (aiPlanSetNumberVariableValues(attackID, cAttackPlanTargetTypeID, 2, true) == false)
  227.    {
  228.       return;
  229.    }
  230.  
  231.    float adjustedAttackSize = -1;   // Adjusts attack size to account for number of donkeys MIA
  232.    float donkeyActual = 0.0;
  233.    float donkeyRatio = 0.0;
  234.    donkeyActual = kbUnitCount(2, cUnitTypeCaravanGreek, cUnitStateAlive);
  235.    donkeyRatio = donkeyActual/donkeyQty;   
  236.    adjustedAttackSize = donkeyRatio*attackSize;     // Used to modify number of hoplites.
  237.  
  238.    if ( donkeyRatio < .75)
  239.    {
  240.       aiEcho("Donkey ratio "+donkeyRatio);
  241.       aiEcho("Attack group reduced from "+attackSize+" to "+adjustedAttackSize+".");
  242.    }
  243.  
  244. // Query disabled 7/24/2002   aiPlanSetVariableInt(attackID, cAttackPlanQueryID, 0, attackQuery);
  245.  
  246.    // add "unit" and "building" to attack list
  247.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  248.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  249.  
  250. /*  Attack modes disabled 7/24/2002
  251.    if (attackMode == cAttackModeWest)
  252.       aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeWest);
  253.    else if (attackMode == cAttackModeEast)
  254.       aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeEast);
  255.    else */if (aiRandInt(2) > 0)
  256.       aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeEast);
  257.    else
  258.       aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeWest);
  259.  
  260.    aiPlanSetVariableInt(attackID, cAttackPlanLastRefreshTime, 0, 30);
  261.  
  262.    aiPlanSetVariableVector(attackID, cAttackPlanGatherPoint, 0, kbGetBlockPosition(cAttackGather));
  263.    aiPlanSetVariableFloat(attackID, cAttackPlanGatherDistance, 0, 15.0);
  264.  
  265.    aiPlanAddUnitType(attackID, cUnitTypeHippikon, 1, (2*attackSize+1)/3, (2*attackSize+1)/3);
  266.    aiPlanAddUnitType(attackID, cUnitTypeHoplite, 1, (adjustedAttackSize+2)/3, (adjustedAttackSize+2)/3);
  267.    if (aiGetWorldDifficulty() > 1)  // We're on hard or nightmare
  268.       aiPlanAddUnitType(attackID, cUnitTypePetrobolos, 0, aiGetWorldDifficulty()-1, aiGetWorldDifficulty()-1);
  269.  
  270.    aiPlanSetInitialPosition(attackID, kbGetBlockPosition(cAttackGather));
  271.    aiPlanSetRequiresAllNeedUnits(attackID, true);
  272.    aiPlanSetActive(attackID);
  273.    aiEcho("Activating attack plan "+attackID);
  274. //   if (lastAttackPlan >= 0)
  275. //      aiPlanDestroy(lastAttackPlan);   // free up last set of units?
  276.    lastAttackPlan = attackID; // update the global var
  277. }
  278.  
  279.  
  280.  
  281.  
  282.  
  283. void main()
  284. {
  285.  
  286.    aiEcho("Starting Scn07p2.xs");
  287.    aiRandSetSeed();
  288.    kbSetTownLocation(kbGetBlockPosition(cCenter));
  289.    //Calculate some areas.
  290.    kbAreaCalculate(1200.0);
  291.  
  292.    aiSetAttackResponseDistance(20.0);
  293.  
  294.    // Kill escrows
  295.    kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0);
  296.    kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0);
  297.    kbEscrowAllocateCurrentResources();
  298.  
  299.    aiSetAgeEventHandler(cAge2, "age2EventHandler");
  300.    aiSetAgeEventHandler(cAge3, "age3EventHandler");
  301.    aiSetAgeEventHandler(cAge4, "age4EventHandler");
  302.  
  303.  
  304.    routeWest = attackRoute("West Attack Route",cInfGather,cCenter,cWestGate);
  305.    routeEast = attackRoute("East Attack Route",cInfGather,cCenter,cEastGate);
  306.    routeCenter = attackRoute("Center Attack Route",cInfGather,cCenter);
  307.    
  308.    attackVector = kbGetBlockPosition(cHPTown);   // in HP's town
  309.    attackRadius = 75.0;
  310.  
  311.    // Set up the attack query with the appropriate vector
  312.    /* Query disabled 7/24/2002
  313.    if (attackQuery < 0)
  314.    {
  315.       attackQuery = kbUnitQueryCreate("Attack Query");
  316.       configQuery(attackQuery, cUnitTypeUnit, -1, cUnitStateAlive, 1, kbGetBlockPosition(cHPTown), false, 200.0); // really anywhere
  317.    }
  318.    */
  319.  
  320.    aiEcho("Difficulty = "+aiGetWorldDifficulty());
  321.    switch(aiGetWorldDifficulty())
  322.    {
  323.    case 1:
  324.       {
  325.          attackInterval = 300000;
  326.          nextAttackTime = 240000;
  327.          attackSize = 4;
  328.          attackMultiplier = 1.2;
  329.          maxAttackSize = 10;
  330.          hopliteQty = 8;
  331.          hippikonQty = 12;
  332.          trainInterval = 20;
  333.          tradePointIncrement = 1.8;
  334.          break;
  335.       }
  336.    case 2:
  337.       {
  338.          attackInterval = 230000;
  339.          nextAttackTime = 120000;
  340.          attackSize = 6;
  341.          attackMultiplier = 1.2;
  342.          maxAttackSize = 20;
  343.          hopliteQty = 15;
  344.          hippikonQty = 20;
  345.          trainInterval = 15;
  346.          tradePointIncrement = 2.5;
  347.          break;
  348.       }
  349.    case 3:
  350.       {
  351.          attackInterval = 180000;
  352.          nextAttackTime = 30000;
  353.          attackSize = 6;
  354.          attackMultiplier = 1.2;
  355.          maxAttackSize = 30;
  356.          hopliteQty = 20;
  357.          hippikonQty = 30;
  358.          trainInterval = 8;
  359.          tradePointIncrement = 4.0;
  360.          break;
  361.       }
  362.    }
  363.  
  364.    // Init low-priority defend plan to manage hoplites
  365.    defendPlan =aiPlanCreate("Defend Plan", cPlanDefend);
  366.    if (defendPlan >= 0)
  367.    {
  368.       aiPlanAddUnitType(defendPlan, cUnitTypeHoplite, 0, 200, 200);    // All unassigned mil units
  369.       aiPlanSetDesiredPriority(defendPlan, 10);                       // Way low, below scouting and attack
  370.       aiPlanSetVariableVector(defendPlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cInfGather));
  371.       aiPlanSetVariableFloat(defendPlan, cDefendPlanEngageRange, 0, 40);
  372.       aiPlanSetVariableBool(defendPlan, cDefendPlanPatrol, 0, false);
  373.       aiPlanSetVariableFloat(defendPlan, cDefendPlanGatherDistance, 0, 10.0);
  374.       aiPlanSetInitialPosition(defendPlan, kbGetBlockPosition(cInfGather));
  375.       aiPlanSetUnitStance(defendPlan, cUnitStanceDefensive);
  376.  
  377.       aiPlanSetVariableInt(defendPlan, cDefendPlanRefreshFrequency, 0, 5);
  378.       aiPlanSetNumberVariableValues(defendPlan, cDefendPlanAttackTypeID, 2, true);
  379.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit);
  380.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 1, cUnitTypeBuilding);
  381.  
  382.       aiPlanSetActive(defendPlan); 
  383.       aiEcho("Creating defend plan");
  384.    }
  385.  
  386.    // Extra one for cav
  387.    defendPlan2 =aiPlanCreate("Hippikon Defend Plan", cPlanDefend);
  388.    if (defendPlan2 >= 0)
  389.    {
  390.       aiPlanAddUnitType(defendPlan2, cUnitTypeHippikon, 0, 200, 200);    // All unassigned mil units
  391.       aiPlanSetDesiredPriority(defendPlan2, 10);                       // Way low, below scouting and attack
  392.       aiPlanSetVariableVector(defendPlan2, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cCavGather));
  393.       aiPlanSetVariableFloat(defendPlan2, cDefendPlanEngageRange, 0, 50);
  394.       aiPlanSetVariableBool(defendPlan2, cDefendPlanPatrol, 0, false);
  395.       aiPlanSetVariableFloat(defendPlan2, cDefendPlanGatherDistance, 0, 10.0);
  396.       aiPlanSetInitialPosition(defendPlan2, kbGetBlockPosition(cCavGather));
  397.       aiPlanSetUnitStance(defendPlan2, cUnitStanceDefensive);
  398.  
  399.       aiPlanSetVariableFloat(defendPlan2, cDefendPlanRefreshFrequency, 0, 5);
  400.       aiPlanSetNumberVariableValues(defendPlan2, cDefendPlanAttackTypeID, 2, true);
  401.       aiPlanSetVariableInt(defendPlan2, cDefendPlanAttackTypeID, 0, cUnitTypeUnit);
  402.       aiPlanSetVariableInt(defendPlan2, cDefendPlanAttackTypeID, 1, cUnitTypeBuilding);
  403.  
  404.       aiPlanSetActive(defendPlan2); 
  405.       aiEcho("Creating defend plan");
  406.    }
  407.  
  408.  
  409.    // Set up the queries for idle donkeys
  410.    donkeyQueryWest = kbUnitQueryCreate("Idle Donkey West");
  411.    donkeyQueryMiddle = kbUnitQueryCreate("Idle Donkey Middle");
  412.    donkeyQueryEast = kbUnitQueryCreate("Idle Donkey East");
  413.    donkeyQueryIdleOther = kbUnitQueryCreate("Idle Donkeys Elsewhere");
  414.    
  415.    configQuery(donkeyQueryWest, cUnitTypeCaravanGreek, cActionIdle, cUnitStateAlive, 2, kbGetBlockPosition(cWestTown), false, 20.0);
  416.    configQuery(donkeyQueryEast, cUnitTypeCaravanGreek, cActionIdle, cUnitStateAlive, 2, kbGetBlockPosition(cEastTown), false, 20.0);
  417.    configQuery(donkeyQueryMiddle, cUnitTypeCaravanGreek, cActionIdle, cUnitStateAlive, 2, kbGetBlockPosition(cMarket), false, 20.0);
  418.    configQuery(donkeyQueryIdleOther, cUnitTypeCaravanGreek, cActionIdle, cUnitStateAlive, 2);
  419.  
  420.    // See if the CP still owns outlying settlements
  421.    TCQueryWest = kbUnitQueryCreate("West Town");
  422.    TCQueryEast = kbUnitQueryCreate("East Town");
  423.    marketQuery = kbUnitQueryCreate("Market query");
  424.    configQuery(TCQueryWest, cUnitTypeSettlementLevel1, -1, cUnitStateAlive, 2, kbGetBlockPosition(cWestTown), false, 10.0);   
  425.    configQuery(TCQueryEast, cUnitTypeSettlementLevel1, -1, cUnitStateAlive, 7, kbGetBlockPosition(cEastTown), false, 10.0);   // Player 7 owns it
  426.    configQuery(marketQuery, cUnitTypeMarket, -1, cUnitStateAlive, 2, kbGetBlockPosition(cMarket), false, 10.0);   
  427.  
  428.    xsEnableRule("useCeaseFire");
  429. }
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437. // *****************************************************************************
  438. //
  439. // RULES
  440. //
  441. // *****************************************************************************
  442.  
  443.  
  444. // See what the attack query says
  445. rule dumpAttack
  446.    inactive
  447.    minInterval 30
  448. {
  449.    int query=-1;
  450.    int count = -1;
  451.    int i=-1;
  452.  
  453.    if (lastAttackPlan < 0)
  454.       return;
  455.  
  456.    query = aiPlanGetVariableInt(lastAttackPlan, cAttackPlanQueryID, 0);
  457.  
  458.    if (query < 0)
  459.    {
  460.       aiEcho("Last attack plan has bad query ID");
  461.       return;
  462.    }
  463.  
  464.    kbUnitQueryResetResults(query);
  465.    count = kbUnitQueryExecute(query);
  466.    aiEcho("Attack Query found "+count+" results:");
  467.    for (i=0; < count)
  468.       aiEcho("    "+kbUnitQueryGetResult(query, i));
  469.  
  470.  
  471. }
  472.  
  473.  
  474.  
  475. rule seeDonkeyRun
  476.    active
  477.    minInterval 10
  478. {     // Look for idle donkeys at the market or side towns, and get them moving.
  479.    int count = -1;
  480.    int donkey = -1;
  481.  
  482.    bool westTC = false;
  483.    bool eastTC = false;
  484.    bool market = false;
  485.  
  486.    kbUnitQueryResetResults(TCQueryWest);
  487.    if (kbUnitQueryExecute(TCQueryWest) > 0)
  488.       westTC = true;
  489.    kbUnitQueryResetResults(TCQueryEast);
  490.    if (kbUnitQueryExecute(TCQueryEast) > 0)
  491.       eastTC = true;
  492.    kbUnitQueryResetResults(marketQuery);
  493.    if (kbUnitQueryExecute(marketQuery) > 0)
  494.       market = true;
  495.  
  496.   
  497.    // Check middle
  498.    kbUnitQueryResetResults(donkeyQueryMiddle);
  499.    count = kbUnitQueryExecute(donkeyQueryMiddle);
  500.    if (count > 0)
  501.    {
  502.       for (i=0; <count)    // Find each donkey, scoot them alternately east or west, subject to TC availability
  503.       {
  504.          donkey = kbUnitQueryGetResult(donkeyQueryMiddle, i);
  505.          if (donkeyGoEast == true)
  506.          {
  507.             if (eastTC == true)
  508.             {
  509.                aiTaskUnitMove(donkey,kbGetBlockPosition(cEastTown));
  510.             }
  511.             donkeyGoEast = false;
  512.          }
  513.          else
  514.          {
  515.             if (westTC == true)
  516.             {
  517.                aiTaskUnitMove(donkey,kbGetBlockPosition(cWestTown));
  518.             }
  519.             donkeyGoEast = true;
  520.          }
  521.       }
  522.    }
  523.  
  524.    // Check west
  525.    kbUnitQueryResetResults(donkeyQueryWest);
  526.    count = kbUnitQueryExecute(donkeyQueryWest);
  527.    if (count > 0)
  528.    {
  529.       if (market == true)
  530.       {
  531.          for (i=0; <count)    // Find each donkey, scoot them to the market
  532.          {
  533.             donkey = kbUnitQueryGetResult(donkeyQueryWest, i);
  534.             aiTaskUnitMove(donkey,kbGetBlockPosition(cMarket));
  535.             //tradePoint(1);  // Count it as a complete run...counting this end to avoid credit for newly trained donkeys at market
  536.          }
  537.       }
  538.    }
  539.  
  540.  
  541.    // Check east
  542.    kbUnitQueryResetResults(donkeyQueryEast);
  543.    count = kbUnitQueryExecute(donkeyQueryEast);
  544.    if (count > 0)
  545.    {
  546.       if (market == true)
  547.       {
  548.          for (i=0; <count)    // Find each donkey, scoot them to the market
  549.          {
  550.             donkey = kbUnitQueryGetResult(donkeyQueryEast, i);
  551.             aiTaskUnitMove(donkey,kbGetBlockPosition(cMarket));
  552.             //tradePoint(1);  // Count it as a complete run
  553.          }
  554.       }
  555.    }
  556. /*
  557.    // Check other
  558.    kbUnitQueryResetResults(donkeyQueryIdleOther);
  559.    count = kbUnitQueryExecute(donkeyQueryIdleOther);
  560.    if (count > 0)
  561.    {
  562.       for (i=0; <count)    // Find each donkey, scoot them to the market
  563.       {
  564.          donkey = kbUnitQueryGetResult(donkeyQueryIdleOther, i);
  565.          aiTaskUnitMove(donkey,kbGetBlockPosition(cMarket));
  566.          //tradePoint(1);  // Count it as a complete run
  567.       }
  568.    }
  569. */
  570.  
  571. }
  572.  
  573.  
  574. /* Disabled 7/24/2002
  575.  
  576. rule setAttackMode      // Evaluates CP's top-level attack military priorities
  577.    active
  578.    minInterval 5
  579. {
  580.    int currentTime = 0;
  581.  
  582.    currentTime = xsGetTime();
  583.  
  584.    static int  invaderQuery = -1;
  585.    static int  westArmyQuery = -1;
  586.    static int  eastArmyQuery = -1;
  587.  
  588.    if ( invaderQuery < 0 ) // Set up query if it doesn't exist
  589.    {
  590.       invaderQuery = kbUnitQueryCreate("Invader Query");
  591.       // Enemy units within 30 meters of center mark
  592.       configQuery(invaderQuery, cUnitTypeMilitary, -1, cUnitStateAlive, 1, kbGetBlockPosition(cCenter), false, 30.0);  
  593.    }
  594.  
  595.    if ( westArmyQuery < 0 ) // Set up query if it doesn't exist
  596.    {
  597.       westArmyQuery = kbUnitQueryCreate("West Enemy Army Query");
  598.       // Enemy units within 50 meters of west mark
  599.       configQuery(westArmyQuery, cUnitTypeMilitary, -1, cUnitStateAlive, 1, kbGetBlockPosition(cWestSide), false, 50.0);  
  600.    }
  601.  
  602.    if ( eastArmyQuery < 0 ) // Set up query if it doesn't exist
  603.    {
  604.       eastArmyQuery = kbUnitQueryCreate("East Enemy Army Query");
  605.       // Enemy units within 50 meters of west mark
  606.       configQuery(eastArmyQuery, cUnitTypeMilitary, -1, cUnitStateAlive, 1, kbGetBlockPosition(cEastSide), false, 50.0);  
  607.    }
  608.  
  609.  
  610.    // Check to see if either side is invaded
  611.    kbUnitQueryResetResults(westArmyQuery);
  612.    if (kbUnitQueryExecute(westArmyQuery) > 3)
  613.       attack(0);     // Register a west side attack
  614.    kbUnitQueryResetResults(eastArmyQuery);
  615.    if (kbUnitQueryExecute(eastArmyQuery) > 3)
  616.       attack(1);     // Register an east side attack
  617.  
  618.    // Check for center invaders
  619.    kbUnitQueryResetResults(invaderQuery);
  620.    if ( kbUnitQueryExecute(invaderQuery) > 2 )  // More than two units?
  621.    {
  622.       if (attackMode != cAttackModeDefense)
  623.          aiEcho("Attack mode: Defense");
  624.       attackMode = cAttackModeDefense;
  625.       kbUnitQuerySetPosition(attackQuery, kbGetBlockPosition(cCenter));
  626.       kbUnitQuerySetMaximumDistance(attackQuery, 50.0);
  627.  
  628.       return;     // Defense mode overrides others
  629.    }
  630.  
  631.    // If no center attack, see if we've been attacked on the east or west side recently.
  632.    if (lastWestAttack < lastEastAttack)   // East attacked most recently
  633.    {
  634.       if ( lastEastAttack > (currentTime-360000) ) // East attacked within last six minutes
  635.       {
  636.          if (attackMode != cAttackModeEast)
  637.             aiEcho("Attack mode: East");
  638.          attackMode = cAttackModeEast;
  639.          kbUnitQuerySetPosition(attackQuery, kbGetBlockPosition(cEastSide));      // East block
  640.          kbUnitQuerySetMaximumDistance(attackQuery, 50.0);
  641.          return;
  642.       }
  643.    }
  644.    else  // West attacked most recently
  645.    {
  646.       if ( lastWestAttack > (currentTime-360000)) // West attacked within last six minutes
  647.       {
  648.          if (attackMode != cAttackModeWest)
  649.             aiEcho("Attack mode: West");
  650.          attackMode = cAttackModeWest;
  651.          kbUnitQuerySetPosition(attackQuery, kbGetBlockPosition(cWestSide));      // East block
  652.          kbUnitQuerySetMaximumDistance(attackQuery, 50.0);
  653.          return;
  654.       }
  655.    }
  656.  
  657.  
  658.    // If we get here, attack the player.
  659.    if (attackMode != cAttackModeHPTown)
  660.       aiEcho("Attack mode: HP Town");
  661.    attackMode = cAttackModeHPTown;
  662.    kbUnitQuerySetPosition(attackQuery, kbGetBlockPosition(cHPTown));      // HP town
  663.    kbUnitQuerySetMaximumDistance(attackQuery, 200.0);   
  664.  
  665. }
  666. */
  667.  
  668.  
  669.  
  670. rule testArmy
  671.    active
  672.    minInterval 20
  673. {
  674.    maintainUnit(cUnitTypeHoplite, hopliteQty, kbGetBlockPosition(cInfGather), trainInterval);
  675.    maintainUnit(cUnitTypeHippikon, hippikonQty, kbGetBlockPosition(cCavGather), trainInterval);
  676.    maintainUnit(cUnitTypePegasus, 1, kbGetBlockPosition(cAttackGather), 20);
  677.    if (aiGetWorldDifficulty() > 1) // We're hard or titan
  678.       maintainUnit(cUnitTypePetrobolos, aiGetWorldDifficulty(), kbGetBlockPosition(cAttackGather), 30);
  679.    xsDisableSelf();
  680. }
  681.  
  682.  
  683. rule maintainDonkeys
  684.    active
  685.    minInterval 30
  686. {
  687.    //maintainUnit(cUnitTypeCaravanGreek, donkeyQty, kbGetBlockPosition(cMarket), 60);   // Keep 8 donkeys, 1 minute between respawns, rebuild at market
  688.    xsDisableSelf();
  689. }
  690.  
  691.  
  692. rule trickleTrade
  693.    active
  694.    minInterval 30
  695. {
  696.    tradePoint();     // Give a minimal trickle of trade points even if the CP loses all donkeys.
  697.    // 7/24/2000:  This is the only source of trade points
  698. }
  699.  
  700.  
  701. // Research chain...get progressively more upgrades as the trade points pile up
  702.  
  703. rule firstUnitUpgrades
  704.    active
  705.    minInterval 5
  706. {
  707.    if (tradePoints < 15)
  708.       return;
  709.    researchTech(cTechMediumCavalry);
  710.    researchTech(cTechMediumInfantry);
  711.    tradePoints = 0;
  712.    xsDisableSelf();
  713.    xsEnableRule("firstAttackUpgrade");
  714. }
  715.  
  716. rule firstAttackUpgrade
  717.    inactive
  718.    minInterval 5
  719. {
  720.    if (tradePoints < 15)
  721.       return;
  722.    researchTech(cTechCopperWeapons);
  723.    researchTech(cTechCopperMail);
  724.    researchTech(cTechCopperShields);
  725.    tradePoints = 0;
  726.    xsDisableSelf();
  727.    xsEnableRule("age3Upgrade");
  728. }
  729.  
  730. rule age3Upgrade
  731.    inactive
  732.    minInterval 5
  733. {
  734.    if (tradePoints < 30)
  735.       return;
  736.    researchTech(cTechAge3Dionysos);
  737.    tradePoints = 0;
  738.    xsDisableSelf();
  739.    xsEnableRule("secondUnitUpgrades");
  740. }
  741.  
  742. rule secondUnitUpgrades
  743.    inactive
  744.    minInterval 5
  745. {
  746.    if (tradePoints < 15)
  747.       return;
  748.    researchTech(cTechHeavyInfantry);
  749.    researchTech(cTechHeavyCavalry);
  750.    tradePoints = 0;
  751.    xsDisableSelf();
  752.    xsEnableRule("secondAttackUpgrade");
  753. }
  754.  
  755. rule secondAttackUpgrade
  756.    inactive
  757.    minInterval 5
  758. {
  759.    if (tradePoints < 15)
  760.       return;
  761.    researchTech(cTechBronzeWeapons);
  762.    researchTech(cTechBronzeMail);
  763.    researchTech(cTechBronzeShields);
  764.    tradePoints = 0;
  765.    xsDisableSelf();
  766.    xsEnableRule("age4Upgrade");
  767. }
  768.  
  769. rule age4Upgrade
  770.    inactive
  771.    minInterval 5
  772. {
  773.    if (tradePoints < 30)
  774.       return;
  775.    researchTech(cTechAge4Hera);
  776.    tradePoints = 0;
  777.    xsDisableSelf();
  778.    xsEnableRule("thirdUnitUpgrades");
  779. }
  780.  
  781. rule thirdUnitUpgrades
  782.    inactive
  783.    minInterval 5
  784. {
  785.    if (tradePoints < 15)
  786.       return;
  787.    researchTech(cTechChampionCavalry);
  788.    researchTech(cTechChampionInfantry);
  789.    tradePoints = 0;
  790.    xsDisableSelf();
  791.    xsEnableRule("thirdAttackUpgrade");
  792. }
  793.  
  794. rule thirdAttackUpgrade
  795.    inactive
  796.    minInterval 5
  797. {
  798.    if (tradePoints < 15)
  799.       return;
  800.    researchTech(cTechIronWeapons);
  801.    researchTech(cTechIronMail);
  802.    researchTech(cTechIronShields);
  803.    tradePoints = 0;
  804.    xsDisableSelf();
  805. //  xsEnableRule("next");
  806. }
  807.  
  808.  
  809.  
  810. rule scout
  811.    active
  812. {
  813.    // just set up an explore plan
  814.    int exploreID = aiPlanCreate("Explore", cPlanExplore);
  815.    if(exploreID >= 0)
  816.    {
  817.       //aiPlanAddVariableFloat( exploreID, cExplorePlanLOSMultiplier, "LOS Multiplier", 1);
  818.       aiPlanSetVariableFloat( exploreID, cExplorePlanLOSMultiplier,  0, 4.0 );
  819.       aiPlanAddUnitType(exploreID, cUnitTypeScout, 1, 1, 1);
  820.       aiPlanSetActive(exploreID);
  821.    }
  822.    // Add a pegasus plan
  823.    int exploreAirID = aiPlanCreate("Air Explore", cPlanExplore);
  824.    if(exploreAirID >= 0)
  825.    {
  826.       //aiPlanAddVariableFloat( exploreID, cExplorePlanLOSMultiplier, "LOS Multiplier", 1);
  827.       aiPlanSetVariableFloat( exploreAirID, cExplorePlanLOSMultiplier,  0, 4.0 );
  828.       aiPlanAddUnitType(exploreAirID, cUnitTypePegasus, 1, 1, 1);
  829.       aiPlanSetActive(exploreAirID);
  830.    }
  831.    xsDisableSelf();
  832. }
  833.  
  834.  
  835.  
  836.  
  837. rule useBolt
  838.    minInterval 5
  839.    active
  840. {
  841.    if (xsGetTime() < (13*60*1000) )
  842.       return;     // Don't bolt until 13:00
  843.  
  844.    static int tempQuery = -1;
  845.    if (tempQuery < 0)
  846.    {  // Doesn't exist, set it up
  847.       tempQuery = kbUnitQueryCreate("useBolt");
  848.       if ( configQuery(tempQuery, cUnitTypeHippikon, -1, cUnitStateAlive, 1) == false)
  849.          return;
  850.    }
  851.    kbUnitQueryResetResults(tempQuery);
  852.    int targetCount = kbUnitQueryExecute(tempQuery); 
  853.  
  854.    if (targetCount < 1)
  855.       return;
  856.  
  857.    int targetUnit = kbUnitQueryGetResult(tempQuery, 0);  // grab first unit
  858.  
  859.    // confirm LOS
  860.    if ( kbUnitVisible(targetUnit) != true )
  861.       return;
  862.  
  863.    // whoop 'em
  864.    if (aiCastGodPowerAtUnit(cTechBolt, targetUnit)  == true)
  865.       xsDisableSelf();
  866. }
  867.  
  868.  
  869.  
  870.  
  871. rule useLightningStorm 
  872.    minInterval 5
  873.    inactive
  874. {
  875.    if (okToUseLightning == false)
  876.       return;
  877.  
  878.    // look for a group of 8 enemy units, at my main army's location
  879.    int targetUnit = -1;
  880.    int attackArmyID = -1;
  881.  
  882.    vector pVec = aiPlanGetLocation(lastAttackPlan);
  883.    if (xsVectorGetX(pVec)<0)
  884.       return;
  885.  
  886.    static int tempQuery = -1;
  887.    if (tempQuery < 0)
  888.    {  // Doesn't exist, set it up
  889.       tempQuery = kbUnitQueryCreate("useLightningStorm");
  890.  
  891.       if ( configQuery(tempQuery, cUnitTypeMilitary, -1, cUnitStateAlive, 1, pVec, true, 50) == false)
  892.          return;
  893.    }
  894.    else
  895.       kbUnitQuerySetPosition(tempQuery, pVec); // Because pVec changes as army moves
  896.    kbUnitQueryResetResults(tempQuery);
  897.    int targetCount = kbUnitQueryExecute(tempQuery);  
  898.    if (targetCount < 8)
  899.       return;
  900.  
  901.    targetUnit = kbUnitQueryGetResult(tempQuery, 0);  // grab first unit
  902.  
  903.    // confirm LOS
  904.    if ( kbUnitVisible(targetUnit) != true )
  905.    {
  906.       aiEcho("Don't have LOS to unit "+targetUnit);
  907.    //   return;
  908.    }
  909.  
  910.    aiEcho("Using Lightning Storm");
  911.    if ( aiCastGodPowerAtPosition(cTechLightningStorm, kbUnitGetPosition(targetUnit)) == true)
  912.       xsDisableSelf();
  913.  
  914. }
  915.  
  916.  
  917. rule useBronze 
  918.    minInterval 5
  919.    inactive
  920. {
  921.    // look for a group of 6 enemy units, at my main army's location
  922.    int   attackArmyID = -1;
  923.  
  924.    vector pVec = aiPlanGetLocation(lastAttackPlan);
  925.    if (xsVectorGetX(pVec)<0)
  926.       return;
  927.  
  928.    static int tempQuery = -1;
  929.    if (tempQuery < 0)
  930.    {  // Doesn't exist, set it up
  931.       tempQuery = kbUnitQueryCreate("useBronze");
  932.  
  933.       if ( configQuery(tempQuery, cUnitTypeMilitary, -1, cUnitStateAlive, 1, pVec, true, 50) == false)
  934.          return;
  935.    }
  936.    else
  937.       kbUnitQuerySetPosition(tempQuery, pVec); // Because pVec changes as army moves
  938.    kbUnitQueryResetResults(tempQuery);
  939.    int targetCount = kbUnitQueryExecute(tempQuery);  
  940.  
  941.    if (targetCount < 6)
  942.       return;
  943.  
  944.    aiEcho("Using Bronze");
  945.    if ( aiCastGodPowerAtPosition(cTechBronze, pVec) == true)
  946.    {
  947.       aiEcho("Deactivating UseBronze");
  948.       xsDisableSelf();
  949.    }
  950. }
  951.  
  952.  
  953.  
  954. rule useCeaseFire 
  955.    minInterval 5
  956.    inactive
  957. {
  958.    // look for a group of 6 enemy units at my town
  959.    int targetUnit = -1;
  960.    int   attackArmyID = -1;
  961.  
  962.    
  963.    static int tempQuery = -1;
  964.    if (tempQuery < 0)
  965.    {  // Doesn't exist, set it up
  966.       tempQuery = kbUnitQueryCreate("useCeaseFire");
  967.       if ( configQuery(tempQuery, cUnitTypeMilitary, -1, cUnitStateAlive, 1, kbGetTownLocation(), true, 30) == false)
  968.          return;
  969.    }
  970.    kbUnitQueryResetResults(tempQuery);
  971.    int targetCount = kbUnitQueryExecute(tempQuery);  
  972.  
  973.    if (targetCount < 6)
  974.       return;
  975.    targetUnit = kbUnitQueryGetResult(tempQuery, 0);  // grab first unit
  976.  
  977.    // confirm LOS
  978.    if ( kbUnitVisible(targetUnit) != true )
  979.    {
  980.       aiEcho("Don't have LOS to unit "+targetUnit);
  981.    //   return;
  982.    }
  983.  
  984.    aiEcho("Using Cease Fire");
  985.    if ( aiCastGodPowerAtPosition(cTechCeaseFire, kbUnitGetPosition(targetUnit)) == true)
  986.       xsDisableSelf();
  987.  
  988.  
  989.  
  990.  
  991.  
  992. rule attackGenerator
  993.    minInterval 10
  994.    active
  995. {
  996.    //aiEcho("attack check running, next time is "+nextAttackTime);
  997.    if ( xsGetTime() < nextAttackTime )
  998.       return;
  999.  
  1000.    testAttack();
  1001.    nextAttackTime = xsGetTime() + attackInterval;
  1002.    attackSize = attackSize * attackMultiplier;
  1003.    if (attackSize > maxAttackSize)
  1004.       attackSize = maxAttackSize;
  1005.    aiEcho("Next attack size will be "+attackSize+".");
  1006. }
  1007.  
  1008.  
  1009.  
  1010.  
  1011.  
  1012.