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

  1. //==============================================================================
  2. // Scn05p2: AI Scenario Script for p2
  3. //==============================================================================
  4. /*
  5.    AI owner:  Dave Leary
  6.    Scenario owner: Dave Leary
  7.  
  8.     The AI for the enemy (pirate camp) in scenario 5.  Fairly simple.
  9.     Maintains axemen and slingers.  Periodically sends out small groups to
  10.     attack the player, choosing one of two directions (north or south) for
  11.     axemen groups.  Sends slingers to the cliff above the player's first gold
  12.     mining area (but don't be surprised if they retarget and move once they
  13.     get there).
  14.     
  15.     Standard attack grower code is in place to increase the size of the groups over
  16.     time.  One large attack is launched with the "doBigAttack" rule late in the
  17.     game (currently 1320 seconds in); this grabs up a random selection of
  18.     other units preplaced on the map (typically catapults and minotaurs).
  19.     
  20.     Naval stuff has currently been taken out of the scenario, but may be added
  21.     back in as time allows.
  22.  
  23.    The AI is cheating like mad.  Don't look for it to gather resources; it has
  24.     plenty of everything it might need.
  25.  
  26.                                 *** DIFFICULTY LEVEL NOTES ***
  27.  
  28.    Easy level - no towers at all.  Slingers do not attack.  Large attack never
  29.     comes.  Enemy does not research.
  30.  
  31.    Moderate level - a couple of towers; no towers at the back entrance.
  32.  
  33.    Difficult level - additional towers.  Attack group sizes grow over time.  Fewer
  34.     resources from shipwreck event.  Kebenits attack player's ships and buildings.
  35.  
  36.    Nightmare - additional towers, including a forward-built tower.  Reduced
  37.     starting food sources and gold.  Attack group sizes grow over time.  Larger
  38.     starting attack groups.  Attack groups continue to grow every fifteen
  39.     minutes until player is overwhelmed. Kebenits attack player's ships and
  40.     buildings; more kebenits than on difficult.  Fewer resources from shipwreck 
  41.     event.
  42. */
  43.  
  44. //==============================================================================
  45. // Set Town Location
  46. //==============================================================================
  47. void setTownLocation(void)
  48. {
  49.    //Look for the "Town Location" marker.
  50.    kbSetTownLocation(kbGetBlockPosition("569"));
  51. }
  52.  
  53. //==============================================================================
  54. // miscStartup
  55. //==============================================================================
  56. void miscStartup(void)
  57. {
  58.     // Difficulty Level check.
  59.     int difflevel=-1;        
  60.     difflevel=aiGetWorldDifficulty();
  61.  
  62.     //Startup message(s).
  63.    aiEcho("");
  64.    aiEcho("");
  65.    aiEcho("Scn05P2 AI Start, filename='"+cFilename+"'.");
  66.    //Spit out the map size.
  67.    aiEcho("  Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+").");
  68.    //Cheat like a bastard.  Once only, though.
  69.    kbLookAtAllUnitsOnMap();
  70.    //Calculate some areas.
  71.    kbAreaCalculate(1200.0);
  72.    //Set our town location.
  73.    setTownLocation();
  74.     //Reset random seed
  75.     aiRandSetSeed();
  76.    //Allocate all resources to the root escrow.
  77.    kbEscrowAllocateCurrentResources();
  78.     // Drop the AI attack response distance for this player to 20 meters.
  79.     aiSetAttackResponseDistance(20.0);
  80. }
  81.  
  82. //==============================================================================
  83. //==============================================================================
  84. // Attack stuff.
  85. //==============================================================================
  86. //==============================================================================
  87. //Shared variables.
  88. int numberAttacks=0;
  89. int attackPlayerID=-1;
  90.  
  91. //TODO: Decide how to rep attack group size.
  92. int attackMinimumGroupSize=3;
  93. int attackMaximumGroupSize=4;
  94.  
  95. //Attack 1 vars.
  96. int attackPlan1ID=-1;
  97. int maintainPlan1ID=-1;
  98. int attackerUnitTypeID1=cUnitTypeAxeman;
  99.  
  100. //Attack 2 vars.
  101. int attackPlan2ID=-1;
  102. int maintainPlan2ID=-1;
  103. int attackerUnitTypeID2=cUnitTypeSlinger;
  104.  
  105. // Boat attack vars
  106. int attackPlan3ID=-1;
  107. int maintainPlan3ID=-1;
  108. int attackerUnitTypeID3=cUnitTypeKebenit;
  109.  
  110. // Other unit types
  111. int attackerUnitTypeID4=cUnitTypeSpearman;
  112. int attackerUnitTypeID5=cUnitTypeCatapult;
  113. int attackerUnitTypeID6=cUnitTypeAnubite;
  114.  
  115. // Route and path vars
  116. int attackRoute1ID=-1;
  117. int attackPath1ID=-1;
  118. int attackRoute2ID=-1;
  119. int attackPath2ID=-1;
  120. int attackRoute3ID=-1;
  121. int attackPath3ID=-1;
  122. int attackRoute4ID=-1;
  123. int attackPath4ID=-1;
  124.  
  125. // A check for launching a single big attack (several minutes in).
  126. bool launchBigAttack=false;
  127.  
  128. //=========================================================================================
  129. // Kidd's cool configQuery function: used to create attack routes, etc.  Oooh, lovin' that!
  130. //=========================================================================================
  131. 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 )
  132. {
  133.    if ( queryID == -1)
  134.    {
  135.       return(false);
  136.    }
  137.  
  138.    if (player != -1)
  139.       kbUnitQuerySetPlayerID(queryID, player);
  140.    
  141.    if (unitType != -1)
  142.       kbUnitQuerySetUnitType(queryID, unitType);
  143.  
  144.    if (action != -1)
  145.       kbUnitQuerySetActionType(queryID, action);
  146.  
  147.    if (state != -1)
  148.       kbUnitQuerySetState(queryID, state);
  149.  
  150.    if (center != vector(-1,-1,-1))
  151.    {
  152.       kbUnitQuerySetPosition(queryID, center);
  153.       if (sort == true)
  154.          kbUnitQuerySetAscendingSort(queryID, true);
  155.       if (radius != -1)
  156.          kbUnitQuerySetMaximumDistance(queryID, radius);
  157.    }
  158.    return(true);
  159. }
  160.  
  161. //==============================================================================
  162. // initAttack: Creates attack routes, etc.
  163. //==============================================================================
  164. void initAttack(int playerID=-1)
  165. {
  166.    //Destroy all previous attacks (if this isn't the player we're already attacking.
  167.    if (playerID != attackPlayerID)
  168.    {
  169.       //Reset the attack player ID.
  170.       attackPlayerID=-1;
  171.       //Destroy any previous attack plan.
  172.       aiPlanDestroy(attackPlan1ID);
  173.       attackPlan1ID=-1;
  174.       aiPlanDestroy(attackPlan2ID);
  175.       attackPlan2ID=-1;
  176.       aiPlanDestroy(attackPlan3ID);
  177.       attackPlan3ID=-1;
  178.  
  179.       //Destroy our previous attack paths.
  180.       kbPathDestroy(attackPath1ID);
  181.       attackPath1ID=-1;
  182.       kbPathDestroy(attackPath2ID);
  183.       attackPath2ID=-1;
  184.        kbPathDestroy(attackPath3ID);
  185.       attackPath3ID=-1;
  186.       kbPathDestroy(attackPath4ID);
  187.       attackPath4ID=-1;
  188.  
  189.       //Destroy our previous attack routes.
  190.       attackRoute1ID=-1;
  191.       attackRoute2ID=-1;
  192.         attackRoute3ID=-1;
  193.         attackRoute4ID=-1;
  194.       //Reset the number of attacks.
  195.       numberAttacks=0;
  196.    }
  197.  
  198.    //Save the player to attack.
  199.    attackPlayerID=playerID;
  200.  
  201.    vector gatherPoint=kbGetBlockPosition("1954");
  202.        
  203.     //Setup attack path 1 - the northern route
  204.    attackPath1ID=kbPathCreate("Attack Path 1");
  205.    kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("1955"));
  206.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("1956"));
  207.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("1957"));
  208.    //Create attack route 1.
  209.    attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", kbGetBlockPosition("1954"), kbGetBlockPosition("1958"));
  210.    
  211.     if (attackRoute1ID >= 0)
  212.       kbAttackRouteAddPath(attackRoute1ID, attackPath1ID);
  213.  
  214.    //Setup attack path 2 - the southern route
  215.    attackPath2ID=kbPathCreate("Attack Path 2");
  216.    kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("1961"));
  217.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("1962"));
  218.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("1963"));
  219.    //Create attack route 2.
  220.    attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", kbGetBlockPosition("1954"), kbGetBlockPosition("1964"));
  221.    
  222.     if (attackRoute2ID >= 0)
  223.       kbAttackRouteAddPath(attackRoute2ID, attackPath2ID);
  224.  
  225.     // Create attack route 3 (ship route)
  226.    attackPath3ID=kbPathCreate("Attack Path 3");
  227.    kbPathAddWaypoint(attackPath3ID, kbGetBlockPosition("1967"));
  228.     kbPathAddWaypoint(attackPath3ID, kbGetBlockPosition("1968"));
  229.     
  230.     //Create attack route 3.
  231.    attackRoute3ID=kbCreateAttackRouteWithPath("Attack Route 3", kbGetBlockPosition("1966"), kbGetBlockPosition("1969"));
  232.  
  233.     if (attackRoute3ID >= 0)
  234.       kbAttackRouteAddPath(attackRoute3ID, attackPath3ID);
  235.  
  236.     // Create attack route 4 (slinger route)
  237.    attackPath4ID=kbPathCreate("Attack Path 4");
  238.    kbPathAddWaypoint(attackPath4ID, kbGetBlockPosition("1959"));
  239.         
  240.     //Create attack route 4
  241.    attackRoute4ID=kbCreateAttackRouteWithPath("Attack Route 4", kbGetBlockPosition("1954"), kbGetBlockPosition("1960"));
  242.  
  243.     if (attackRoute4ID >= 0)
  244.       kbAttackRouteAddPath(attackRoute4ID, attackPath4ID);
  245.  
  246. }
  247.  
  248. //==============================================================================
  249. // setupAxemenAttack
  250. //==============================================================================
  251. bool setupAxemenAttack(int playerID=-1)
  252. {
  253.     int randomPath=aiRandInt(2);
  254.    //Info.
  255.     aiEcho("Attacking Player "+playerID+".");
  256.  
  257.    //If the player to attack doesn't match, init the attack.
  258.    if (attackPlayerID != playerID)
  259.    {
  260.       initAttack(playerID);
  261.       if (attackPlayerID < 0)
  262.          return(false);
  263.    }
  264.  
  265.    //Create an attack plan.
  266.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  267.    if (newAttackPlanID < 0)
  268.       return(false);
  269.  
  270.    //Target player (required).  This must work.
  271.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  272.       return(false);
  273.  
  274.    //Gather point.
  275.     vector gatherPoint=kbGetBlockPosition("1954");
  276.  
  277.     //Set the target type.  This must work.
  278.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  279.       return(false);
  280.  
  281.    //Unit types to attack.
  282.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  283.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  284.  
  285.    //Attack route.
  286.    if (randomPath == 0)
  287.     {
  288.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID);
  289.         aiEcho("AI Attack Path: chose northern route.");
  290.     }
  291.    else
  292.     {
  293.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID);
  294.         aiEcho("AI Attack Path: chose southern route.");
  295.     }
  296.  
  297.    //Set the gather point and gather point distance.
  298.    aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  299.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 30.0);
  300.  
  301.    //Set up the attack route usage pattern.
  302.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  303.    
  304.     //Add the unit types to the plan.
  305.    aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID1, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize);
  306.     
  307.     // Is this the big attack?  If so, throw in a random mix of "extra" units.
  308.     if ( launchBigAttack == true )
  309.     {
  310.         int randomGroup=aiRandInt(5);
  311.         aiEcho("AI Attack: Big attack heading in!");
  312.       switch(randomGroup)
  313.       {
  314.            case 0:
  315.          {
  316.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 3, 3);
  317.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 2, 2);
  318.             break;
  319.          }
  320.            case 1:
  321.          {
  322.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 4, 4);
  323.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 0, 1, 1);
  324.             break;
  325.          }
  326.             case 2:
  327.          {
  328.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 2, 2);
  329.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 0, 1, 1);
  330.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 4, 4);
  331.             break;
  332.          }
  333.             case 3:
  334.          {
  335.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 4, 4);
  336.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 0, 1, 1);
  337.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 2, 2);
  338.             break;
  339.          }
  340.             case 4:
  341.          {
  342.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 5, 5);
  343.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 0, 1, 1);
  344.                 aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 1, 1);
  345.             break;
  346.          }
  347.       }
  348.         launchBigAttack=false;
  349.     }
  350.         
  351.    //Set the initial position.
  352.    aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  353.    //Plan requires all need units to work (can be false).
  354.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  355.    //Activate the plan.
  356.    aiPlanSetActive(newAttackPlanID);
  357.  
  358.    //Now, save the attack plan ID appropriately.
  359.    aiPlanSetOrphan(attackPlan1ID, true);
  360.    attackPlan1ID=newAttackPlanID;
  361.  
  362.    //Increment our overall number of attacks.
  363.    numberAttacks++;
  364. }
  365.  
  366.  
  367. //==============================================================================
  368. // setupSlinger
  369. //==============================================================================
  370. bool setupSlingerAttack(int playerID=-1)
  371. {
  372.     //Info.
  373.     aiEcho("Attacking Player "+playerID+".");
  374.  
  375.    //If the player to attack doesn't match, init the attack.
  376.    if (attackPlayerID != playerID)
  377.    {
  378.       initAttack(playerID);
  379.       if (attackPlayerID < 0)
  380.          return(false);
  381.    }
  382.  
  383.    //Create an attack plan.
  384.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  385.    if (newAttackPlanID < 0)
  386.       return(false);
  387.  
  388.    //Target player (required).  This must work.
  389.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  390.       return(false);
  391.  
  392.    //Gather point.
  393.     vector gatherPoint=kbGetBlockPosition("1954");
  394.  
  395.     //Set the target type.  This must work.
  396.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 3, true) == false)
  397.       return(false);
  398.  
  399.    //Unit types to attack - slingers go for your villagers, to piss you off.
  400.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeVillagerGreek);
  401.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeUnit);
  402.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 2, cUnitTypeBuilding);
  403.    
  404.     // Route to take
  405.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute4ID);
  406.  
  407.    //Set the gather point and gather point distance.
  408.    aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  409.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 30.0);
  410.  
  411.    //Set up the attack route usage pattern.
  412.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  413.    
  414.     //Add the unit types to the plan.
  415.    aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize);
  416.         
  417.    //Set the initial position.
  418.    aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  419.    //Plan requires all need units to work (can be false).
  420.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  421.    //Activate the plan.
  422.    aiPlanSetActive(newAttackPlanID);
  423.  
  424.    //Now, save the attack plan ID appropriately.
  425.    aiPlanSetOrphan(attackPlan2ID, true);
  426.    attackPlan2ID=newAttackPlanID;
  427.  
  428.    //Increment our overall number of attacks.
  429.    numberAttacks++;
  430. }
  431.  
  432.  
  433. //==============================================================================
  434. // setupBoatAttack (on Hard or better only)
  435. //==============================================================================
  436. bool setupBoatAttack(int playerID=-1)
  437. {
  438.     // Difficulty Level check
  439.     int difflevel=-1;        
  440.     difflevel=aiGetWorldDifficulty();
  441.  
  442.     //Info.
  443.     aiEcho("SHIPS Attacking Player "+playerID+".");
  444.  
  445.    //If the player to attack doesn't match, init the attack.
  446.    if (attackPlayerID != playerID)
  447.    {
  448.       initAttack(playerID);
  449.       if (attackPlayerID < 0)
  450.          return(false);
  451.    }
  452.  
  453.    //Create an attack plan.
  454.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  455.    if (newAttackPlanID < 0)
  456.       return(false);
  457.  
  458.    //Target player (required).  This must work.
  459.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  460.       return(false);
  461.  
  462.    //Gather point.
  463.     vector gatherPoint=kbGetBlockPosition("1966");
  464.  
  465.     //Set the target type.  This must work.
  466.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  467.       return(false);
  468.  
  469.    //Unit types to attack - slingers go for your villagers, to piss you off.
  470.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeShip);
  471.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  472.    
  473.     // Route to take
  474.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute3ID);
  475.  
  476.    //Set the gather point and gather point distance.
  477.    aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  478.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 30.0);
  479.  
  480.    //Set up the attack route usage pattern.
  481.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  482.    
  483.     //Add the unit types to the plan.
  484.     if ( difflevel < 3 )
  485.     {
  486.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 1, 2, 2);
  487.     }
  488.     else
  489.     {
  490.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 1, 4, 4);
  491.     }
  492.         
  493.    //Set the initial position.
  494.    aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  495.    //Plan requires all need units to work (can be false).
  496.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  497.    //Activate the plan.
  498.    aiPlanSetActive(newAttackPlanID);
  499.  
  500.    //Now, save the attack plan ID appropriately.
  501.    aiPlanSetOrphan(attackPlan3ID, true);
  502.    attackPlan3ID=newAttackPlanID;
  503.  
  504.    //Increment our overall number of attacks.
  505.    numberAttacks++;
  506. }
  507.  
  508.  
  509. //==============================================================================
  510. // Queryin' for enemies, for casting Serpents (cool!)
  511. //==============================================================================
  512. int checkForEnemies(void)
  513. {
  514.     static int enemyQueryID=-1;
  515.     vector homeBase=kbGetBlockPosition("569");
  516.     int enemyCount=-1;
  517.  
  518.    if (enemyQueryID < 0)
  519.    {  
  520.         // Doesn't exist, set it up
  521.       enemyQueryID = kbUnitQueryCreate("Enemy Query");
  522.         
  523.       // Get the number
  524.       if ( configQuery( enemyQueryID, cUnitTypeUnit, -1, cUnitStateAlive, 1, homeBase, false, 15 ) == false )
  525.          return(-1);
  526.    }
  527.  
  528.    kbUnitQueryResetResults(enemyQueryID);
  529.    enemyCount = kbUnitQueryExecute(enemyQueryID);
  530.     return(enemyCount);
  531. }
  532.  
  533. //==============================================================================
  534. // Attack Generator 1 - Axemen and friends
  535. //==============================================================================
  536. rule attackGenerator1
  537.    minInterval 90
  538.    inactive
  539.    group AttackRules
  540.    runImmediately
  541. {
  542.    //See how many "idle" attack plans we have.  Don't create any more if we have
  543.    //idle plans.
  544.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  545.  
  546.    if (numberIdleAttackPlans > 0)
  547.       return;
  548.  
  549.    //If we have enough unassigned military units, create a new attack plan.
  550.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID1);
  551.    aiEcho("There are "+numberAvailableUnits+" axemen available for a new attack.");
  552.    
  553.     if (numberAvailableUnits >= attackMinimumGroupSize)
  554.         setupAxemenAttack(1);
  555. }
  556.  
  557. //==============================================================================
  558. // Attack Generator 2 - Slingers
  559. //==============================================================================
  560. rule attackGenerator2
  561.    minInterval 120
  562.    inactive
  563.    group AttackRules
  564.    runImmediately
  565. {
  566.    //See how many "idle" attack plans we have.  Don't create any more if we have
  567.    //idle plans.
  568.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  569.  
  570.    if (numberIdleAttackPlans > 0)
  571.       return;
  572.  
  573.    //If we have enough unassigned military units, create a new attack plan.
  574.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID2);
  575.    aiEcho("There are "+numberAvailableUnits+" slingers available for a new attack.");
  576.    
  577.     if (numberAvailableUnits >= attackMinimumGroupSize)
  578.         setupSlingerAttack(1);
  579. }
  580.  
  581.  
  582. //==============================================================================
  583. // Attack Generator 3 - Boats, every seven minutes.
  584. //==============================================================================
  585. rule attackGenerator3
  586.    minInterval 420
  587.    inactive
  588.    group AttackRules
  589. {
  590.    //See how many "idle" attack plans we have.  Don't create any more if we have
  591.    //idle plans.
  592.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  593.  
  594.    if (numberIdleAttackPlans > 0)
  595.       return;
  596.  
  597.    //If we have enough unassigned military units, create a new attack plan.
  598.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID3);
  599.    aiEcho("There are "+numberAvailableUnits+" kebenits available for a boat attack.");
  600.    
  601.     if (numberAvailableUnits >= 1)
  602.         setupBoatAttack(1);
  603. }
  604.  
  605.  
  606. //==============================================================================
  607. // Attack enablers - enable attacks after initial timers expire
  608. // Lots of delay, giving time for newbies to screw around 
  609. //==============================================================================
  610. // Axemen
  611. rule attack1Enabler
  612.    minInterval 420
  613.    active
  614.    group AttackRules
  615. {
  616.    xsEnableRule("attackGenerator1");
  617.    xsDisableSelf();
  618. }
  619.  
  620. // Hard or higher attack enabler - three minutes in
  621. rule attack1EnablerHard
  622.    minInterval 180
  623.    active
  624.    group AttackRules
  625. {
  626.     int difflevel=-1;        
  627.     difflevel=aiGetWorldDifficulty();
  628.  
  629.     if ( difflevel > 1 )
  630.     {
  631.         xsEnableRule("attackGenerator1");
  632.         xsDisableRule("attack1Enabler");
  633.     }
  634.     xsDisableSelf();
  635. }
  636.  
  637. // Slingers
  638. rule attack2Enabler
  639.     minInterval 420
  640.     active
  641.     group ModerateAttackRules
  642. {
  643.     xsEnableRule("attackGenerator2");
  644.     xsDisableSelf();
  645. }
  646.  
  647. // Titan or higher attack enabler 2 - slinger pain
  648. rule attack2EnablerNightmare
  649.    minInterval 200
  650.    active
  651.    group AttackRules
  652. {
  653.     int difflevel=-1;        
  654.     difflevel=aiGetWorldDifficulty();
  655.  
  656.     if ( difflevel > 2 )
  657.     {
  658.         xsEnableRule("attackGenerator2");
  659.         xsDisableRule("attack2Enabler");
  660.     }
  661.     xsDisableSelf();
  662. }
  663.  
  664.  
  665. //==============================================================================
  666. // Attack size grower:  Slightly grows attack sizes of slinger and axemen groups
  667. // at the 15-minute mark.
  668. //==============================================================================
  669.  
  670. rule attackGrower1
  671.    minInterval 900
  672.     active
  673.     group DifficultAttackRules
  674. {
  675.     // Difficulty Level check
  676.     int difflevel=-1;        
  677.     difflevel=aiGetWorldDifficulty();
  678.    
  679.     //Increase our attack group sizes by one.
  680.    attackMinimumGroupSize++;
  681.    attackMaximumGroupSize++;
  682.    aiEcho("Attack group size grown: Min="+attackMinimumGroupSize+", Max="+attackMaximumGroupSize+".");
  683.  
  684.    //Bump up our maintain size.
  685.    int numberToMaintain=attackMinimumGroupSize*2;
  686.    aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  687.    aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  688.  
  689.     // Scary - we don't disable this on nightmare until attack groups are really big.  :).
  690.     if ( difflevel <= 2 || attackMinimumGroupSize > 15 )
  691.     {
  692.         xsDisableSelf();
  693.     }
  694. }
  695.  
  696. //==============================================================================
  697. // Attack size grower 2:  Slightly grows attack sizes of slinger and axemen groups
  698. // a second time at the 20-minute mark.
  699. //
  700. // This rule is disabled on normal and easy levels.
  701. //==============================================================================
  702.  
  703. rule attackGrower2
  704.    minInterval 1200
  705.     active
  706.     group DifficultAttackRules
  707. {
  708.    //Increase our attack group sizes by one.
  709.    attackMinimumGroupSize++;
  710.    attackMaximumGroupSize++;
  711.    aiEcho("Attack group size grown: Min="+attackMinimumGroupSize+", Max="+attackMaximumGroupSize+".");
  712.  
  713.    //Bump up our maintain size.
  714.    int numberToMaintain=attackMinimumGroupSize*2;
  715.    aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  716.    aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  717.     xsDisableSelf();
  718. }
  719.  
  720. //==============================================================================
  721. // Tech Researching Rules - medium axemen, medium slingers, medium spearmen
  722. //==============================================================================
  723. rule researchMediumAxemen
  724.    minInterval 1000
  725.    active
  726.     group ModerateResearchRules
  727. {
  728.    int planID=aiPlanCreate("Medium Axemen research at ten minutes.", cPlanResearch);
  729.    if (planID < 0)
  730.       return;
  731.  
  732.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechMediumAxemen);
  733.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeBarracks);
  734.    aiPlanSetActive(planID);
  735.    
  736.     //Done.
  737.    xsDisableSelf();
  738. }
  739.  
  740. rule researchMediumSpearman
  741.    minInterval 1300
  742.    active
  743.     group ModerateResearchRules
  744. {
  745.    int planID=aiPlanCreate("Medium Spearmen research at twelve minutes.", cPlanResearch);
  746.    if (planID < 0)
  747.       return;
  748.  
  749.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechMediumSpearmen);
  750.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeBarracks);
  751.    aiPlanSetActive(planID);
  752.    
  753.     //Done.
  754.    xsDisableSelf();
  755. }
  756.  
  757. rule researchMediumSlinger
  758.    minInterval 1600
  759.    active
  760.     group ModerateResearchRules
  761. {
  762.    int planID=aiPlanCreate("Medium Slinger research at fourteen minutes.", cPlanResearch);
  763.    if (planID < 0)
  764.       return;
  765.  
  766.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechMediumSlingers);
  767.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeBarracks);
  768.    aiPlanSetActive(planID);
  769.    
  770.     //Done.
  771.    xsDisableSelf();
  772. }
  773.  
  774. //==============================================================================
  775. // At twenty minutes, crank out axemen every five seconds
  776. //==============================================================================
  777. rule increaseAxemanTrainFrequency
  778.     minInterval 1200
  779.     active
  780.     group ModerateAttackRules
  781. {
  782.     aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 5);
  783.     aiEcho("Rule: Axemen Training Frequency Increased.");
  784.     xsDisableSelf();
  785. }
  786.  
  787. //==============================================================================
  788. // Set the "launchBigAttack" flag - 22 minutes in
  789. // This makes the AI send a big mixed group next time the axemen attack
  790. //==============================================================================
  791. rule doBigAttack
  792.     minInterval 1320
  793.     active
  794.     group ModerateAttackRules
  795. {
  796.     launchBigAttack=true;
  797.     xsDisableSelf();
  798. }
  799.  
  800. //==============================================================================
  801. // Rule to check for enemies close to the TC - if so, use Serpents.
  802. //==============================================================================
  803. rule enemiesCloseToTC
  804.     minInterval 15
  805.     active
  806.     group ModerateAttackRules
  807. {
  808.     int numEnemies=-1;
  809.     vector serpentPoint=kbGetBlockPosition("569");
  810.     numEnemies=checkForEnemies();
  811.  
  812.     if (numEnemies > 5)
  813.     {
  814.         aiEcho("Enemies close to TC, serpentize 'em.");
  815.         if ( aiCastGodPowerAtPosition(cTechSerpents, serpentPoint) == true )
  816.             xsDisableSelf();
  817.         else
  818.             aiEcho("Serpents failed - try again later.");
  819.     }
  820. }
  821.  
  822. //==============================================================================
  823. // Difficulty level adjustments.
  824. //==============================================================================
  825. void difficultyLevelAdjustments(void)
  826. {
  827.     // Difficulty Level check
  828.     int difflevel=-1;        
  829.     difflevel=aiGetWorldDifficulty();
  830.  
  831.    switch(difflevel)
  832.    {
  833.         case 0:        // Easy
  834.       {
  835.             xsDisableRuleGroup("ModerateAttackRules");
  836.             xsDisableRuleGroup("DifficultAttackRules");
  837.             xsDisableRuleGroup("ModerateResearchRules");
  838.          break;
  839.       }
  840.         case 1:        // Moderate
  841.       {
  842.             xsDisableRuleGroup("DifficultAttackRules");
  843.          break;
  844.       }
  845.         case 2:        // Difficult
  846.       {
  847.             attackMinimumGroupSize=6;
  848.             attackMaximumGroupSize=8;
  849.             xsEnableRule("attackGenerator3");
  850.  
  851.          break;
  852.       }
  853.         case 3:        // Nightmare
  854.         {
  855.             attackMinimumGroupSize=9;
  856.             attackMaximumGroupSize=11;
  857.             xsEnableRule("attackGenerator3");
  858.             break;
  859.         }
  860.         default:
  861.         {
  862.             break;
  863.         }
  864.     }
  865.  
  866.     // On hard/titan difficulty levels, explore plan with the Hyena o' Set.
  867.     // This should bug the player a little.
  868.     if ( difflevel > 1 )
  869.     {
  870.         int exploreID = aiPlanCreate("Explore", cPlanExplore);
  871.         if(exploreID >= 0)
  872.         {
  873.             aiPlanAddUnitType(exploreID, cUnitTypeHyenaofSet, 1, 1);
  874.             aiPlanSetActive(exploreID);
  875.         }
  876.     }
  877. }
  878.  
  879. //==============================================================================
  880. // MAIN.
  881. //==============================================================================
  882. void main(void)
  883. {
  884.     // Difficulty Level check
  885.     int difflevel=-1;        
  886.     difflevel=aiGetWorldDifficulty();
  887.  
  888.    //Startup.
  889.    miscStartup();
  890.     difficultyLevelAdjustments();
  891.     
  892.    //Share the number to maintain.
  893.    int numberToMaintain=attackMinimumGroupSize*2;
  894.  
  895.    //Share a common gather point.
  896.    vector gatherPoint=kbGetBlockPosition("569");
  897.     vector gatherPoint2=kbGetBlockPosition("2487");
  898.  
  899.     //Except for the ships.
  900.     vector shipGatherPoint=kbGetBlockPosition("1966");
  901.  
  902.    //Create a simple plan to maintain X axemen.
  903.    int maintainPlan1ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain);
  904.    if (maintainPlan1ID >= 0)
  905.    {
  906.         //Must set the type of unit to train.
  907.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1);
  908.       //You can limit the number of units that are ever trained by this plan with this call.
  909.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  910.       //Set the number of units to maintain in the world at one time.
  911.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  912.       //Don't train units too fast
  913.         if ( difflevel < 2 )
  914.         {
  915.             aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 25);
  916.         }
  917.         else if ( difflevel == 2 )
  918.         {
  919.             aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 15);
  920.         }
  921.         else
  922.         {
  923.             aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 10);
  924.         }
  925.       //Turn off training from multiple buildings.
  926.       //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false);
  927.       //Set a gather target ID.
  928.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234);
  929.       //Set a gather point.
  930.       aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPoint);
  931.       //Activate the plan.
  932.       aiPlanSetActive(maintainPlan1ID);
  933.    }
  934.  
  935.    int maintainPlan2ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID2), cPlanTrain);
  936.    if (maintainPlan2ID >= 0)
  937.    {
  938.         //Must set the type of unit to train.
  939.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID2);
  940.       //You can limit the number of units that are ever trained by this plan with this call.
  941.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  942.       //Set the number of units to maintain in the world at one time.
  943.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  944.       //Don't train units too fast
  945.         if ( difflevel < 3 )
  946.         {
  947.             aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 60);
  948.         }
  949.         else
  950.         {
  951.             aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 30);
  952.         }
  953.       //Turn off training from multiple buildings.
  954.       //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false);
  955.       //Set a gather target ID.
  956.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234);
  957.       //Set a gather point.
  958.       aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPoint2);
  959.       //Activate the plan.
  960.       aiPlanSetActive(maintainPlan2ID);
  961.    }
  962.  
  963.     // Maintain up to 2 Kebenits,
  964.    int maintainPlan3ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerUnitTypeID3), cPlanTrain);
  965.    if (maintainPlan3ID >= 0)
  966.    {
  967.         //Must set the type of unit to train.
  968.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeID3);
  969.       //You can limit the number of units that are ever trained by this plan with this call.
  970.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  971.       //Set the number of units to maintain in the world at one time - more if nightmare...
  972.         if ( difflevel < 3 )
  973.         {
  974.             aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 2);
  975.         }
  976.         else
  977.         {
  978.             aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 4);
  979.         }
  980.  
  981.       //Don't train units faster than every 90 seconds
  982.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 90);
  983.       //Turn off training from multiple buildings.
  984.       //aiPlanSetVariableBool(maintainPlanID, cTrainPlanUseMultipleBuildings, 0, false);
  985.       //Set a gather target ID.
  986.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanGatherTargetID, 0, 1234);
  987.       //Set a gather point.
  988.       aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, shipGatherPoint);
  989.       //Activate the plan.
  990.       aiPlanSetActive(maintainPlan3ID);
  991.    }
  992. }
  993.