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

  1. //==============================================================================
  2. // Scn11p2: Initial AI Scenario Script
  3. /*
  4.    AI owner:  Dave Leary
  5.    Scenario owner: Joe "the Golem" Gillum
  6.  
  7.     The AI for the main enemy in scenario 11.  The HP is building up in two separated
  8.     locations; the AI sends groups down each channel, one composed primarily of
  9.     toxotes and the other composed primarily of hoplites.  Catapults and heroes
  10.     are periodically added to the groups.  Some preplaced units guard the fortresses
  11.     at the end of the scenario, but are not in an actual defense group.
  12.  
  13.    If the HP destroys the forward academies/archery ranges in each channel, the
  14.     AI reacts and pulls its gather points back closer to the fortresses.
  15.  
  16.    Attack group sizes are grown over time.  The AI does some simple researching at
  17.     set times to improve its units.
  18.  
  19.                                   *** DIFFICULTY LEVEL NOTES ***
  20.  
  21.    Easy level - Enemy does minimal research.  AI groups never increase in size.
  22.     Does not maintain a hero.  No myth units included in attacks.
  23.  
  24.    Moderate level - Enemy does less research.  No myth units included in attacks.
  25.  
  26.    Difficult level - Default level.
  27.  
  28.    Nightmare - Attack groups can get much larger, and start out much larger.
  29. */
  30. //==============================================================================
  31.  
  32. // Difficulty Level
  33. int difflevel=-1;        
  34.  
  35. //==============================================================================
  36. // Set Town Location
  37. //==============================================================================
  38. void setTownLocation(void)
  39. {
  40.    //Look for the "Town Location" marker.
  41.    kbSetTownLocation(kbGetBlockPosition("554"));
  42. }
  43.  
  44. //==============================================================================
  45. // miscStartup 
  46. //==============================================================================
  47. void miscStartup(void)
  48. {
  49.     difflevel=aiGetWorldDifficulty();
  50.  
  51.    //Startup message(s).
  52.    aiEcho("");
  53.    aiEcho("");
  54.    aiEcho("Scn11P2 AI Start, filename='"+cFilename+"'.");
  55.    //Spit out the map size.
  56.    aiEcho("  Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+").");
  57.     aiEcho("Difficulty Level="+difflevel+".");
  58.    //Cheat like a bastard.
  59.    kbLookAtAllUnitsOnMap();
  60.    //Calculate some areas.
  61.    kbAreaCalculate(1200.0);
  62.    //Set our town location.
  63.    setTownLocation();
  64.     //Reset random seed
  65.     aiRandSetSeed();
  66.    //Allocate all resources to the root escrow.
  67.    kbEscrowAllocateCurrentResources();
  68. }
  69.  
  70. //==============================================================================
  71. //==============================================================================
  72. // Attack stuff.
  73. //==============================================================================
  74. //==============================================================================
  75. //Shared variables.
  76. int numberAttacks=0;
  77. int attackPlayerID=-1;
  78. //TODO: Decide how to rep attack group size.
  79. int attackMinimumGroupSize=5;
  80. int attackMaximumGroupSize=9;
  81.  
  82. //Attack 1 vars.
  83. int attackPlan1ID=-1;
  84. int maintainPlan1ID=-1;
  85. int attackRoute1ID=-1;
  86. int attackPath1ID=-1;
  87. int attackerUnitTypeID1=cUnitTypeToxotes;
  88.  
  89. //Attack 2 vars.
  90. int attackPlan2ID=-1;
  91. int maintainPlan2ID=-1;
  92. int attackRoute2ID=-1;
  93. int attackPath2ID=-1;
  94. int attackerUnitTypeID2=cUnitTypeHoplite;
  95.  
  96. //Unit type 3 vars (fewer, 'cause the petroboli get sucked into other groups)
  97. int maintainPlan3ID=-1;
  98. int attackerUnitTypeID3=cUnitTypePetrobolos;
  99.  
  100. //Unit type 4 vars (hero/Atalanta)
  101. int maintainPlan4ID=-1;
  102. int attackerUnitTypeID4=cUnitTypeHeroGreekAtalanta;
  103.  
  104. //Unit type 5 vars (Manticore)
  105. int maintainPlan5ID=-1;
  106. int attackerUnitTypeID5=cUnitTypeManticore;
  107.  
  108. //Unit type 6 vars (Cyclops)
  109. int maintainPlan6ID=-1;
  110. int attackerUnitTypeID6=cUnitTypeCyclops;
  111.  
  112. //=========================================================================================
  113. // Kidd's cool configQuery function: used to create attack routes, etc.  Oooh, lovin' that!
  114. //=========================================================================================
  115. bool configQuery( int queryID = -1, int unitType = -1, int action = -1, int state = -1, int player = -1, vector center = vector(-1,-1,-1), bool sort = false, float radius = -1 )
  116. {
  117.    if ( queryID == -1)
  118.    {
  119.       return(false);
  120.    }
  121.  
  122.    if (player != -1)
  123.       kbUnitQuerySetPlayerID(queryID, player);
  124.    
  125.    if (unitType != -1)
  126.       kbUnitQuerySetUnitType(queryID, unitType);
  127.  
  128.    if (action != -1)
  129.       kbUnitQuerySetActionType(queryID, action);
  130.  
  131.    if (state != -1)
  132.       kbUnitQuerySetState(queryID, state);
  133.  
  134.    if (center != vector(-1,-1,-1))
  135.    {
  136.       kbUnitQuerySetPosition(queryID, center);
  137.       if (sort == true)
  138.          kbUnitQuerySetAscendingSort(queryID, true);
  139.       if (radius != -1)
  140.          kbUnitQuerySetMaximumDistance(queryID, radius);
  141.    }
  142.    return(true);
  143. }
  144.  
  145. //==============================================================================
  146. // initAttack: Creates attack routes, etc.
  147. //==============================================================================
  148. void initAttack(int playerID=-1)
  149. {
  150.    //Destroy all previous attacks (if this isn't the player we're already attacking.
  151.    if (playerID != attackPlayerID)
  152.    {
  153.       //Reset the attack player ID.
  154.       attackPlayerID=-1;
  155.       //Destroy any previous attack plan.
  156.       aiPlanDestroy(attackPlan1ID);
  157.       attackPlan1ID=-1;
  158.       aiPlanDestroy(attackPlan2ID);
  159.       attackPlan2ID=-1;
  160.       //Destroy our previous attack paths.
  161.       kbPathDestroy(attackPath1ID);
  162.       attackPath1ID=-1;
  163.       kbPathDestroy(attackPath2ID);
  164.       attackPath2ID=-1;
  165.       //Destroy our previous attack routes.
  166.       //kbAttackRouteDestroy(attackRoute1ID);
  167.       attackRoute1ID=-1;
  168.       //kbAttackRouteDestroy(attackRoute2ID);
  169.       attackRoute2ID=-1;
  170.       //Reset the number of attacks.
  171.       numberAttacks=0;
  172.    }
  173.  
  174.    //Save the player to attack.
  175.    attackPlayerID=playerID;
  176.  
  177.    // vector gatherPoint=kbGetBlockPosition("554");
  178.     // DAL - gather points now hardcoded
  179.    // Setup attack path 1.
  180.    attackPath1ID=kbPathCreate("Attack Path 1");
  181.    kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("2055"));
  182.    //Create attack route 1.
  183.    attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", kbGetBlockPosition("2054"), kbGetBlockPosition("2056"));
  184.    
  185.     if (attackRoute1ID >= 0)
  186.       kbAttackRouteAddPath(attackRoute1ID, attackPath1ID);
  187.  
  188.    //Setup attack path 2.
  189.    attackPath2ID=kbPathCreate("Attack Path 2");
  190.    kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("2058"));
  191.    //Create attack route 2.
  192.    attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", kbGetBlockPosition("2057"), kbGetBlockPosition("2059"));
  193.    
  194.     if (attackRoute2ID >= 0)
  195.       kbAttackRouteAddPath(attackRoute2ID, attackPath2ID);
  196. }
  197.  
  198.  
  199. //==============================================================================
  200. // Query to Check if the Archery Ranges are Destroyed
  201. //==============================================================================
  202. int checkArcheryRanges(void)
  203. {
  204.     static int archeryQueryID=-1;
  205.     vector originalRally=kbGetBlockPosition("2054");
  206.     int archeryRangeCount=-1;
  207.  
  208.    if (archeryQueryID < 0)
  209.    {  
  210.         // Doesn't exist, set it up
  211.       archeryQueryID = kbUnitQueryCreate("Archery Range Query");
  212.  
  213.         // Get the number
  214.       if ( configQuery( archeryQueryID, cUnitTypeArcheryRange, -1, cUnitStateAlive, 2, originalRally, false, 30 ) == false )
  215.             return(-1);
  216.     }
  217.  
  218.    kbUnitQueryResetResults(archeryQueryID);
  219.    archeryRangeCount = kbUnitQueryExecute(archeryQueryID);
  220.  
  221.     // aiEcho("Querying - "+archeryRangeCount+" archery ranges.");
  222.     return(archeryRangeCount);
  223. }
  224.  
  225. //==============================================================================
  226. // Query to Check if the Academies are Destroyed
  227. //==============================================================================
  228. int checkAcademies(void)
  229. {
  230.     static int academyQueryID=-1;
  231.     vector originalRally=kbGetBlockPosition("2057");
  232.     int academyCount=-1;
  233.  
  234.    if (academyQueryID < 0)
  235.    {  
  236.         // Doesn't exist, set it up
  237.       academyQueryID = kbUnitQueryCreate("Academy Range Query");
  238.         
  239.       // Get the number
  240.       if ( configQuery( academyQueryID, cUnitTypeAcademy, -1, cUnitStateAlive, 2, originalRally, false, 30 ) == false )
  241.          return(-1);
  242.    }
  243.  
  244.    kbUnitQueryResetResults(academyQueryID);
  245.    academyCount = kbUnitQueryExecute(academyQueryID);
  246.  
  247.     // aiEcho("Querying - "+academyCount+" academies.");
  248.     return(academyCount);
  249. }
  250.  
  251. //==============================================================================
  252. // setupAttack
  253. //==============================================================================
  254. bool setupAttack(int playerID=-1, bool firstAttack=true)
  255. {
  256.     int randomMythUnit=aiRandInt(2);
  257.  
  258.     difflevel=aiGetWorldDifficulty();    
  259.  
  260.    //Info.
  261.    aiEcho("Attacking Player "+playerID+".");
  262.  
  263.    //If the player to attack doesn't match, init the attack.
  264.    if (attackPlayerID != playerID)
  265.    {
  266.       initAttack(playerID);
  267.       if (attackPlayerID < 0)
  268.          return(false);
  269.    }
  270.  
  271.    //Create an attack plan.
  272.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  273.    if (newAttackPlanID < 0)
  274.       return(false);
  275.  
  276.    //Target player (required).  This must work.
  277.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  278.       return(false);
  279.    //You must also set/add: specific target IDs or a query ID or target type IDs.
  280.    //Set specific target ID.  This must work.
  281.    //   aiPlanSetVariableInt(newAttackPlanID, cAttackPlanSpecificTargetID, 0, 1294);
  282.    //   aiPlanSetVariableInt(newAttackPlanID, cAttackPlanSpecificTargetID, 1, 1295);
  283.    //   aiPlanSetVariableInt(newAttackPlanID, cAttackPlanSpecificTargetID, 2, 9851);
  284.    //Set up a query.  This must work.
  285.    //int attackQueryID=kbUnitQueryCreate("Attack Raid Query");
  286.    //if (attackQueryID >= 0)
  287.    //{
  288.    //   kbUnitQueryResetData();
  289.    //   kbUnitQuerySetPlayerID(2);
  290.    //   kbUnitQuerySetUnitType(cUnitTypeBuilding);
  291.    //   kbUnitQuerySetState(cUnitStateAlive);
  292.    //   aiPlanSetVariableInt(newAttackPlanID, cAttackPlanQueryID, 0, attackQueryID);
  293.    //}
  294.  
  295.    //Gather point.
  296.     vector gatherPoint=kbGetBlockPosition("2054");
  297.  
  298.    if ( firstAttack == true )
  299.     {
  300.         gatherPoint=kbGetBlockPosition("2054");
  301.     }
  302.     else
  303.         gatherPoint=kbGetBlockPosition("2057");
  304.     
  305.     //Set the target type.  This must work.
  306.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  307.       return(false);
  308.  
  309.     aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 3, true);
  310.  
  311.    //Unit types to attack.
  312.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeTunnel);
  313.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeUnit);
  314.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 2, cUnitTypeBuilding);
  315.    
  316.     //Attack route.
  317.    if (firstAttack == true)
  318.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID);
  319.    else
  320.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID);
  321.  
  322.    //Set the gather point and gather point distance.
  323.    aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  324.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 10.0);
  325.  
  326.    //Set up the attack route usage pattern.
  327.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  328.  
  329.    //Add the unit types to the plan.
  330.    if (firstAttack == true)
  331.     {
  332.       aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID1, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize);
  333.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 0, 1, 1);
  334.         
  335.         // If difflevel is hard or better...
  336.         if ( difflevel > 1 )
  337.         {
  338.             // Add a couple of myth units if you can.
  339.             if ( randomMythUnit == 0 )
  340.             {
  341.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 0, 2, 2);
  342.             }
  343.             else
  344.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 2, 2);
  345.         }
  346.     }
  347.     else                                            
  348.     {
  349.       aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize);
  350.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 0, 1, 1);
  351.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 1, 1);
  352.                 
  353.         // If difflevel is hard or better...
  354.         if ( difflevel > 1 )
  355.         {
  356.             // Add a couple of myth units if you can.
  357.             if ( randomMythUnit == 0 )
  358.             {
  359.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 0, 2, 2);
  360.             }
  361.             else
  362.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 2, 2);
  363.         }
  364.     }
  365.    
  366.     //Set the initial position.
  367.    aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  368.    //Plan requires all need units to work (can be false).
  369.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  370.    //Activate the plan.
  371.    aiPlanSetActive(newAttackPlanID);
  372.  
  373.    //Now, save the attack plan ID appropriately.
  374.    if (firstAttack == true)
  375.    {
  376.       //Orphan the active attack.
  377.       aiPlanSetOrphan(attackPlan1ID, true);
  378.       attackPlan1ID=newAttackPlanID;
  379.    }
  380.    else
  381.    {
  382.       //Orphan the active attack.
  383.       aiPlanSetOrphan(attackPlan2ID, true);
  384.       attackPlan2ID=newAttackPlanID;
  385.    }
  386.  
  387.    //Increment our overall number of attacks.
  388.    numberAttacks++;
  389. }
  390.  
  391. //==============================================================================
  392. // Attack Generator 1
  393. //==============================================================================
  394. rule attackGenerator1
  395.    minInterval 215
  396.    inactive
  397.    group AttackRules
  398.    runImmediately
  399. {
  400.    //See how many "idle" attack plans we have.  Don't create any more if we have
  401.    //idle plans. 
  402.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  403.    if (numberIdleAttackPlans > 0)
  404.       return;
  405.  
  406.    //If we have enough unassigned military units, create a new attack plan.
  407.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID1);
  408.    aiEcho("There are "+numberAvailableUnits+" toxotes available for a new attack.");
  409.    if (numberAvailableUnits >= attackMinimumGroupSize)
  410.       setupAttack(1, true);
  411. }
  412.  
  413. //==============================================================================
  414. // Attack Generator 2
  415. //==============================================================================
  416. rule attackGenerator2
  417.    minInterval 235
  418.    inactive
  419.    group AttackRules
  420.    runImmediately
  421. {
  422.    //See how many "idle" attack plans we have.  Don't create any more if we have
  423.    //idle plans.
  424.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  425.    if (numberIdleAttackPlans > 0)
  426.       return;
  427.  
  428.    //If we have enough unassigned military units, create a new attack plan.
  429.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID2);
  430.    aiEcho("There are "+numberAvailableUnits+" hoplites available for a new attack.");
  431.    if (numberAvailableUnits >= attackMinimumGroupSize)
  432.       setupAttack(1, false);
  433. }
  434.  
  435. //==============================================================================
  436. // Attack enabler - enable attacks once timers expire.
  437. // Some difflevel adjustments.
  438. //==============================================================================
  439. rule attack1Enabler
  440.    minInterval 300
  441.    active
  442.    group AttackRules
  443. {
  444.    xsEnableRule("attackGenerator1");
  445.    xsDisableSelf();
  446. }
  447.  
  448. rule attack1EnablerModerate
  449.    minInterval 150
  450.    active
  451.    group AttackRules
  452. {
  453.     difflevel=aiGetWorldDifficulty();
  454.     if ( difflevel > 0 )
  455.     {
  456.         xsEnableRule("attackGenerator1");
  457.         xsDisableRule("attack1Enabler");
  458.     }
  459.    xsDisableSelf();
  460. }
  461.  
  462. rule attack1EnablerNightmare
  463.    minInterval 30
  464.    active
  465.    group AttackRules
  466. {
  467.     difflevel=aiGetWorldDifficulty();
  468.     if ( difflevel == 3 )
  469.     {
  470.         xsEnableRule("attackGenerator1");
  471.         xsDisableRule("attack1EnablerModerate");
  472.         xsDisableRule("attack1Enabler");
  473.     }
  474.    xsDisableSelf();
  475. }
  476.  
  477. rule attack2Enabler
  478.     minInterval 220
  479.     active
  480.     group AttackRules
  481. {
  482.     xsEnableRule("attackGenerator2");
  483.     xsDisableSelf();
  484. }
  485.  
  486.  
  487. rule attack2EnablerModerate
  488.    minInterval 100
  489.    active
  490.    group AttackRules
  491. {
  492.     difflevel=aiGetWorldDifficulty();
  493.     if ( difflevel > 0 )
  494.     {
  495.         xsEnableRule("attackGenerator2");
  496.         xsDisableRule("attack2Enabler");
  497.     }
  498.    xsDisableSelf();
  499. }
  500.  
  501. rule attack2EnablerNightmare
  502.    minInterval 15
  503.    active
  504.    group AttackRules
  505. {
  506.     difflevel=aiGetWorldDifficulty();
  507.     if ( difflevel == 3 )
  508.     {
  509.         xsEnableRule("attackGenerator2");
  510.         xsDisableRule("attack2EnablerModerate");
  511.         xsDisableRule("attack2Enabler");
  512.     }
  513.    xsDisableSelf();
  514. }
  515.  
  516. //==============================================================================
  517. // Rule to check if one of the archery ranges close to the point are dead.
  518. //==============================================================================
  519. rule archeryRangesDead
  520.     minInterval 30
  521.     active
  522. {
  523.     int numRanges=-1;
  524.     vector reserveGatherPoint=kbGetBlockPosition("2109");
  525.  
  526.     numRanges=checkArcheryRanges();
  527.  
  528.     if (numRanges < 2)
  529.     {
  530.         aiEcho("One archery range destroyed; moving gather point.");
  531.         aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, reserveGatherPoint);
  532.         xsDisableSelf();
  533.     }
  534. }
  535.  
  536. //==============================================================================
  537. // Rule to check if both academies close to the point are dead.
  538. //==============================================================================
  539. rule academiesDead
  540.     minInterval 30
  541.     active
  542. {
  543.     int numAcademies=-1;
  544.     vector reserveGatherPoint=kbGetBlockPosition("2108");
  545.  
  546.     numAcademies=checkAcademies();
  547.  
  548.     if (numAcademies < 1)
  549.     {
  550.         aiEcho("Both academies destroyed; moving gather point.");
  551.         aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, reserveGatherPoint);
  552.         xsDisableSelf();
  553.     }
  554. }
  555.  
  556.  
  557. //==============================================================================
  558. // Simple attack size grower:  Grows attack size every six minutes
  559. //==============================================================================
  560. rule attackGrower
  561.    minInterval 360
  562.     inactive
  563.     group AttackRules
  564. {
  565.     difflevel=aiGetWorldDifficulty();
  566.    //Don't grow to more than 11 for a minimum, if it's anything other than nightmare.
  567.     if ( difflevel < 3 )
  568.     {
  569.         if (attackMinimumGroupSize >= 12 )
  570.         {
  571.             xsDisableSelf();
  572.             return;
  573.         }
  574.     }
  575.  
  576.     // On nightmare, grow groups to 24 - ow!
  577.     if (attackMinimumGroupSize >= 25 )
  578.     {
  579.         xsDisableSelf();
  580.         return;
  581.     }
  582.  
  583.    //Increase our attack size.
  584.    attackMinimumGroupSize++;
  585.    attackMaximumGroupSize++;
  586.    aiEcho("Attack group size grown: Min="+attackMinimumGroupSize+", Max="+attackMaximumGroupSize+".");
  587.  
  588.    //Bump up our maintain size.
  589.    int numberToMaintain=attackMinimumGroupSize*2;
  590.  
  591.    aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  592.    aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  593. }
  594.  
  595. //==============================================================================
  596. // Attack grower enabler - start upping attack group sizes at six minutes.
  597. //==============================================================================
  598. rule attackGrowerEnabler
  599.    minInterval 360
  600.    active
  601.    group AttackRules
  602. {
  603.    xsEnableRule("attackGrower");
  604.    xsDisableSelf();
  605. }
  606.  
  607. //==============================================================================
  608. // Tech Researching Rules
  609. //==============================================================================
  610. rule researchBronzeWeapons
  611.    minInterval 400
  612.    active
  613.     group ModerateResearch
  614. {
  615.    int planID=aiPlanCreate("Bronze Weapons Research at seven minutes.", cPlanResearch);
  616.    if (planID < 0)
  617.       return;
  618.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechBronzeWeapons);
  619.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory);
  620.    aiPlanSetActive(planID);
  621.    //Done.
  622.    xsDisableSelf();
  623. }
  624.  
  625. rule researchBronzeShields
  626.    minInterval 500
  627.    active
  628.     group EasyResearch
  629. {
  630.    int planID=aiPlanCreate("Bronze Shields Research at nine minutes.", cPlanResearch);
  631.    if (planID < 0)
  632.       return;
  633.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechBronzeShields);
  634.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory);
  635.    aiPlanSetActive(planID);
  636.    //Done.
  637.    xsDisableSelf();
  638. }
  639.  
  640. rule researchHeavyArchers
  641.    minInterval 560
  642.    active
  643.     group HeavyResearch
  644. {
  645.    int planID=aiPlanCreate("Heavy Archers", cPlanResearch);
  646.    if (planID < 0)
  647.       return;
  648.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechHeavyArchers);
  649.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArcheryRange);
  650.    aiPlanSetActive(planID);
  651.    //Done.
  652.    xsDisableSelf();
  653. }
  654.  
  655. rule researchBronzeMail
  656.    minInterval 620
  657.    active
  658.     group ModerateResearch
  659. {
  660.    int planID=aiPlanCreate("Bronze Mail Research", cPlanResearch);
  661.    if (planID < 0)
  662.       return;
  663.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechBronzeMail);
  664.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory);
  665.    aiPlanSetActive(planID);
  666.    //Done.
  667.    xsDisableSelf();
  668. }
  669.  
  670. rule researchHeavyInfantry
  671.    minInterval 750
  672.    active
  673.     group ModerateResearch
  674. {
  675.    int planID=aiPlanCreate("Heavy Infantry Research", cPlanResearch);
  676.    if (planID < 0)
  677.       return;
  678.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechHeavyInfantry);
  679.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeAcademy);
  680.    aiPlanSetActive(planID);
  681.    //Done.
  682.    xsDisableSelf();
  683.  
  684. }
  685.  
  686. rule researchChampionInfantry
  687.    minInterval 1200
  688.    active
  689.     group TitanResearch
  690. {
  691.    int planID=aiPlanCreate("Champion Infantry Research", cPlanResearch);
  692.    if (planID < 0)
  693.       return;
  694.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechChampionInfantry);
  695.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeAcademy);
  696.    aiPlanSetActive(planID);
  697.    //Done.
  698.    xsDisableSelf();
  699.  
  700. }
  701.  
  702. rule researchIronMail
  703.    minInterval 1260
  704.    active
  705.     group TitanResearch
  706. {
  707.    int planID=aiPlanCreate("Iron Mail Research", cPlanResearch);
  708.    if (planID < 0)
  709.       return;
  710.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechIronMail);
  711.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory);
  712.    aiPlanSetActive(planID);
  713.    //Done.
  714.    xsDisableSelf();
  715.  
  716. }
  717.  
  718. rule researchIronWeapons
  719.    minInterval 1380
  720.    active
  721.     group TitanResearch
  722. {
  723.    int planID=aiPlanCreate("Iron Weapons Research", cPlanResearch);
  724.    if (planID < 0)
  725.       return;
  726.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechIronWeapons);
  727.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArmory);
  728.    aiPlanSetActive(planID);
  729.    //Done.
  730.    xsDisableSelf();
  731.  
  732. }
  733.  
  734. rule researchChampionArchers
  735.    minInterval 1500
  736.    active
  737.     group TitanResearch
  738. {
  739.    int planID=aiPlanCreate("Champion Archers", cPlanResearch);
  740.    if (planID < 0)
  741.       return;
  742.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechChampionArchers);
  743.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeArcheryRange);
  744.    aiPlanSetActive(planID);
  745.    //Done.
  746.    xsDisableSelf();
  747. }
  748.  
  749.  
  750. //==============================================================================
  751. // Maintain myth units, starting at seven minutes
  752. //==============================================================================
  753. rule maintainMythUnits
  754.     minInterval 600
  755.     active
  756.     group AttackRules
  757. {
  758.     aiEcho("Rule: myth units now being maintained.");
  759.  
  760.     vector gatherPoint=kbGetBlockPosition("2085");
  761.  
  762.     // Manticores
  763.     maintainPlan5ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerUnitTypeID5), cPlanTrain);
  764.     if (maintainPlan5ID >= 0)
  765.    {
  766.         //Must set the type of unit to train.
  767.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanUnitType, 0, attackerUnitTypeID5);
  768.       //You can limit the number of units that are ever trained by this plan with this call.
  769.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToTrain, 0, 12);
  770.         //Set the number of units to maintain in the world at one time
  771.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToMaintain, 0, 2);
  772.       //Don't train units faster than every three minutes
  773.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanFrequency, 0, 180);
  774.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234);
  775.       //Set a gather point.
  776.       aiPlanSetVariableVector(maintainPlan5ID, cTrainPlanGatherPoint, 0, gatherPoint);
  777.       //Activate the plan.
  778.       aiPlanSetActive(maintainPlan5ID);
  779.    }
  780.  
  781.     // Cyclops
  782.     maintainPlan6ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerUnitTypeID6), cPlanTrain);
  783.     if (maintainPlan6ID >= 0)
  784.    {
  785.         //Must set the type of unit to train.
  786.       aiPlanSetVariableInt(maintainPlan6ID, cTrainPlanUnitType, 0, attackerUnitTypeID6);
  787.       //Only train 10 at most.
  788.       aiPlanSetVariableInt(maintainPlan6ID, cTrainPlanNumberToTrain, 0, 10);
  789.         //Set the number of units to maintain in the world at one time
  790.       aiPlanSetVariableInt(maintainPlan6ID, cTrainPlanNumberToMaintain, 0, 2);
  791.       //Don't train units faster than every two minutes
  792.       aiPlanSetVariableInt(maintainPlan6ID, cTrainPlanFrequency, 0, 120);
  793.       //Set a gather point.
  794.       aiPlanSetVariableVector(maintainPlan6ID, cTrainPlanGatherPoint, 0, gatherPoint);
  795.       //Activate the plan.
  796.       aiPlanSetActive(maintainPlan6ID);
  797.    }
  798.     xsDisableSelf();
  799. }
  800.  
  801. //==============================================================================
  802. // Maintain the hero
  803. //==============================================================================
  804. rule maintainHero
  805.     minInterval 510
  806.     active
  807.     group AttackRules
  808. {
  809.     aiEcho("Rule: hero maintain plan created.");
  810.  
  811.     // Create a plan to maintain 1 Atalanta hero, hanging out in front of the left fortress.
  812.     // She periodically gets added to the hoplite group.
  813.     maintainPlan4ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerUnitTypeID4), cPlanTrain);
  814.    
  815.     if (maintainPlan4ID >= 0)
  816.    {
  817.         vector gatherPoint4=kbGetBlockPosition("2109");
  818.       //Must set the type of unit to train.
  819.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanUnitType, 0, attackerUnitTypeID4);
  820.       //You can limit the number of units that are ever trained by this plan with this call.
  821.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToTrain, 0, 5);
  822.       
  823.         //Set the number of units to maintain in the world at one time - one hero
  824.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, 1);
  825.       //Don't train units faster than every seven minutes
  826.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 420);
  827.       //Turn off training from multiple buildings.
  828.       //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false);
  829.       //Set a gather target ID.
  830.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234);
  831.       //Set a gather point.
  832.       aiPlanSetVariableVector(maintainPlan4ID, cTrainPlanGatherPoint, 0, gatherPoint4);
  833.       //Activate the plan.
  834.       aiPlanSetActive(maintainPlan4ID);
  835.    }
  836.     xsDisableSelf();
  837. }
  838.  
  839. //=====================================================================================
  840. // fortressDestroyed.  This is called from the scenario with an AI Func effect when
  841. // the central fortress is destroyed.
  842. //=====================================================================================
  843. void fortressDestroyed(int scriptCall = -1)
  844. {
  845.     vector reserveGatherPoint=kbGetBlockPosition("2108");
  846.  
  847.     aiEcho("*** FORTRESS DESTROYED, MODIFYING THE HOPLITE ATTACK PLAN");
  848.     aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, reserveGatherPoint);
  849.     // Don't use multiple buildings any more.  This should make them use one of the ones back
  850.     // by the new gather point.
  851.     aiPlanSetVariableBool(maintainPlan2ID, cTrainPlanUseMultipleBuildings, 0, false);
  852. }
  853.  
  854. //==============================================================================
  855. // Some basic stuff based on difficulty level.
  856. //==============================================================================
  857. void difficultyLevelChanges(void)
  858. {
  859.     difflevel=aiGetWorldDifficulty();
  860.  
  861.     if ( difflevel == 0 )
  862.     {
  863.         xsDisableRuleGroup("ModerateResearch");
  864.         xsDisableRuleGroup("TitanResearch");
  865.         xsDisableRuleGroup("HeavyResearch");
  866.         xsDisableRule("maintainHero");
  867.         xsDisableRule("attackGrowerEnabler");
  868.     }
  869.  
  870.     if ( difflevel == 1 )
  871.     {
  872.         xsDisableRuleGroup("HeavyResearch");
  873.         xsDisableRuleGroup("TitanResearch");
  874.     }
  875.  
  876.     if ( difflevel == 2 )
  877.     {
  878.         attackMinimumGroupSize=7;
  879.         attackMaximumGroupSize=10;
  880.         xsDisableRuleGroup("TitanResearch");
  881.     }
  882.  
  883.     if ( difflevel == 3 )
  884.     {
  885.         attackMinimumGroupSize=8;
  886.         attackMaximumGroupSize=12;
  887.     }
  888. }
  889.  
  890. //==============================================================================
  891. // MAIN.
  892. //==============================================================================
  893. void main(void)
  894. {
  895.     difflevel=aiGetWorldDifficulty();
  896.  
  897.    //Startup.
  898.    miscStartup();
  899.  
  900.     // Diff level.
  901.     difficultyLevelChanges();
  902.  
  903.    //Share the number to maintain.
  904.    int numberToMaintain=attackMinimumGroupSize*2;
  905.    //Share the common gather point.
  906.    // vector gatherPoint=kbGetBlockPosition("554");
  907.  
  908.    //Create a simple plan to maintain X first units.
  909.    maintainPlan1ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain);
  910.    if (maintainPlan1ID >= 0)
  911.    {
  912.         vector gatherPoint1=kbGetBlockPosition("2054");
  913.       //Must set the type of unit to train.
  914.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1);
  915.       //You can limit the number of units that are ever trained by this plan with this call.
  916.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  917.       //Set the number of units to maintain in the world at one time.
  918.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  919.       //Don't train units too fast
  920.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 20);
  921.       //Turn off training from multiple buildings.
  922.       //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false);
  923.       //Set a gather point.
  924.       aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPoint1);
  925.       //Activate the plan.
  926.       aiPlanSetActive(maintainPlan1ID);
  927.    }
  928.  
  929.    //Create a simple plan to maintain X second units.
  930.    maintainPlan2ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID2), cPlanTrain);
  931.    if (maintainPlan2ID >= 0)
  932.    {
  933.         vector gatherPoint2=kbGetBlockPosition("2057");
  934.       //Must set the type of unit to train.
  935.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID2);
  936.       //You can limit the number of units that are ever trained by this plan with this call.
  937.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  938.       //Set the number of units to maintain in the world at one time.
  939.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  940.       //Don't train units too fast.
  941.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 25);
  942.       //Turn off training from multiple buildings, 'cause hoplites don't gather very well.
  943.         // DAL - taken out for now until DP bug is fixed.
  944.       //aiPlanSetVariableBool(maintainPlan2ID, cTrainPlanUseMultipleBuildings, 0, false);
  945.       //Set a gather point.
  946.       aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPoint2);
  947.       //Activate the plan.
  948.       aiPlanSetActive(maintainPlan2ID);
  949.    }
  950.  
  951.     if ( difflevel > 0 )
  952.     {
  953.         //Create a simple plan to maintain 2 petroboli on all levels other than easy.
  954.         maintainPlan3ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerUnitTypeID3), cPlanTrain);
  955.         if (maintainPlan3ID >= 0)
  956.         {
  957.             vector gatherPoint3=kbGetBlockPosition("2085");
  958.             //Must set the type of unit to train.
  959.             aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeID3);
  960.             //You can limit the number of units that are ever trained by this plan with this call.
  961.             //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  962.       
  963.             //Set the number of units to maintain in the world at one time - two at most of the petroboli
  964.             aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 2);
  965.             //Don't train units faster than every 210 seconds
  966.             aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 210);
  967.             //Turn off training from multiple buildings.
  968.             //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false);
  969.             //Set a gather target ID.
  970.             //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234);
  971.             //Set a gather point.
  972.             aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPoint3);
  973.             //Activate the plan.
  974.             aiPlanSetActive(maintainPlan3ID);
  975.         }
  976.     }
  977. }