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

  1. //==============================================================================
  2. // Scn35p5: AI Scenario Script for scenario 35 player 5
  3. //==============================================================================
  4. /*
  5.    AI owner:  Dave Leary
  6.    Scenario owner: Joe "the Golem" Gillum
  7.  
  8.     Handles the forward forces of Gargarensis in the finale.  Creates defend plans 
  9.     for three forward positions, and attacks the player with two different groups, 
  10.     hypaspists and catapults, and hippikons (all upgraded).  Basically a delaying 
  11.     action AI who fights until the player makes enough progress    to turn on the 
  12.     rearguard AI (scn35p2).  Includes two heroes in the mix (Theseus and Hippolyta)
  13.  
  14.    Gargarensis' scary god power actions are handled by scenario triggers.
  15.  
  16.    Some minor diff level changes for this AI - cavalry attacks do not come on Easy.
  17. */
  18. //==============================================================================
  19. // Set Town Location.
  20. //==============================================================================
  21. void setTownLocation(void)
  22. {
  23.    //Look for the "Town Location" marker.
  24.    kbSetTownLocation(kbGetBlockPosition("2447"));
  25. }
  26.  
  27. //==============================================================================
  28. // miscStartup.
  29. //==============================================================================
  30. void miscStartup(void)
  31. {
  32.     // Difficulty Level check.
  33.     int difflevel=-1;        
  34.     difflevel=aiGetWorldDifficulty();
  35.  
  36.    //Startup message(s).
  37.    aiEcho("");
  38.    aiEcho("");
  39.    aiEcho("Scn35P5 AI Start, filename='"+cFilename+"'.");
  40.     aiEcho("Difficulty Level="+difflevel+".");
  41.    //Spit out the map size.
  42.    aiEcho("  Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+").");
  43.    //Cheat like a bastard.  Once only, though.
  44.    kbLookAtAllUnitsOnMap();
  45.    //Calculate some areas.
  46.    kbAreaCalculate(1200.0);
  47.    //Set our town location.
  48.    setTownLocation();
  49.     //Reset random seed
  50.     aiRandSetSeed();
  51.    
  52.     //Allocate all resources to the root escrow by setting percentage of military/economy to 0.
  53.     kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0 );
  54.     kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0 );
  55.  
  56.     //Allocate all resources 
  57.    kbEscrowAllocateCurrentResources();
  58. }
  59.  
  60. //==============================================================================
  61. //==============================================================================
  62. // Attack stuff
  63. //==============================================================================
  64. //==============================================================================
  65. //Shared variables.
  66. int numberAttacks=0;
  67. int attackPlayerID=-1;
  68.  
  69. //TODO: Decide how to rep attack group size.
  70. int attackMinimumGroupSize=6;
  71. int attackMaximumGroupSize=12;
  72.  
  73. //Attack vars.
  74. int attackPlan1ID=-1;
  75. int attackPlan2ID=-1;
  76.  
  77. // Unit types.
  78. int attackerUnitTypeID1=cUnitTypeHoplite;
  79. int attackerUnitTypeID2=cUnitTypeHippikon;
  80. int attackerUnitTypeID3=cUnitTypeToxotes;
  81. int attackerUnitTypeID4=cUnitTypeHypaspist;
  82. int attackerUnitTypeID5=cUnitTypePeltast;
  83.  
  84. int attackerSiegeTypeID1=cUnitTypePetrobolos;
  85. int attackerSiegeTypeID2=cUnitTypeHelepolis;
  86.  
  87. int attackerMythTypeID1=cUnitTypeCyclops;
  88. int attackerMythTypeID2=cUnitTypeNemeanLion;
  89. int attackerMythTypeID3=cUnitTypeColossus;
  90.  
  91. int attackerHeroTypeID1=cUnitTypeHeroGreekTheseus;
  92. int attackerHeroTypeID2=cUnitTypeHeroGreekHippolyta;
  93.  
  94. // Maintain Plans
  95. int maintainPlan1ID=-1;
  96. int maintainPlan2ID=-1;
  97. int maintainPlan3ID=-1;
  98. int maintainPlan4ID=-1;
  99. int maintainPlan5ID=-1;
  100.  
  101. int maintainSiege1ID=-1;
  102.  
  103. int maintainMythPlan1ID=-1;
  104. int maintainMythPlan2ID=-1;
  105.  
  106. int maintainHeroPlan1ID=-1;
  107. int maintainHeroPlan2ID=-1;
  108.  
  109. // Defend Plans
  110. int defendPlan1ID=-1;
  111. int defendPlan2ID=-1;
  112. int defendPlan3ID=-1;
  113.  
  114. // Route and path vars
  115. int attackRoute1ID=-1;
  116. int attackPath1ID=-1;
  117. int attackRoute2ID=-1;
  118. int attackPath2ID=-1;
  119.  
  120. //=========================================================================================
  121. // Kidd's cool configQuery function: used to create attack routes, etc.  Oooh, lovin' that!
  122. //=========================================================================================
  123. 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 )
  124. {
  125.    if ( queryID == -1)
  126.    {
  127.       return(false);
  128.    }
  129.  
  130.    if (player != -1)
  131.       kbUnitQuerySetPlayerID(queryID, player);
  132.    
  133.    if (unitType != -1)
  134.       kbUnitQuerySetUnitType(queryID, unitType);
  135.  
  136.    if (action != -1)
  137.       kbUnitQuerySetActionType(queryID, action);
  138.  
  139.    if (state != -1)
  140.       kbUnitQuerySetState(queryID, state);
  141.  
  142.    if (center != vector(-1,-1,-1))
  143.    {
  144.       kbUnitQuerySetPosition(queryID, center);
  145.       if (sort == true)
  146.          kbUnitQuerySetAscendingSort(queryID, true);
  147.       if (radius != -1)
  148.          kbUnitQuerySetMaximumDistance(queryID, radius);
  149.    }
  150.    return(true);
  151. }
  152.  
  153. //==============================================================================
  154. // initAttack: Creates attack routes, etc.
  155. //==============================================================================
  156. void initAttack(int playerID=-1)
  157. {
  158.    //Destroy all previous attacks (if this isn't the player we're already attacking.
  159.    if (playerID != attackPlayerID)
  160.    {
  161.       //Reset the attack player ID.
  162.       attackPlayerID=-1;
  163.       //Destroy any previous attack plan.
  164.       aiPlanDestroy(attackPlan1ID);
  165.       attackPlan1ID=-1;
  166.       aiPlanDestroy(attackPlan2ID);
  167.       attackPlan2ID=-1;
  168.   
  169.       //Destroy our previous attack paths.
  170.       kbPathDestroy(attackPath1ID);
  171.       attackPath1ID=-1;
  172.       kbPathDestroy(attackPath2ID);
  173.       attackPath2ID=-1;
  174.  
  175.       //Destroy our previous attack routes.
  176.       attackRoute1ID=-1;
  177.       attackRoute2ID=-1;
  178.  
  179.       //Reset the number of attacks.
  180.       numberAttacks=0;
  181.    }
  182.  
  183.    //Save the player to attack
  184.    attackPlayerID=playerID;
  185.  
  186.    vector gatherPoint=kbGetBlockPosition("2445");
  187.     vector gatherPointWest=kbGetBlockPosition("2452");
  188.        
  189.     //Setup attack path 1 - go east
  190.    attackPath1ID=kbPathCreate("Attack Path 1");
  191.    kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("2449"));
  192.    //Create attack route 1.
  193.    attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", gatherPoint, kbGetBlockPosition("2462"));
  194.    
  195.     
  196.     if (attackRoute1ID >= 0)
  197.       kbAttackRouteAddPath(attackRoute1ID, attackPath1ID);
  198.  
  199.    //Setup attack path 2 - go west 
  200.    attackPath2ID=kbPathCreate("Attack Path 2");
  201.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("2453"));
  202.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("2454"));
  203.    //Create attack route 2.
  204.    attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", gatherPointWest, kbGetBlockPosition("2521"));
  205.    
  206.     if (attackRoute2ID >= 0)
  207.       kbAttackRouteAddPath(attackRoute2ID, attackPath2ID);
  208.  
  209. }
  210.  
  211. //==============================================================================
  212. // setupAttack
  213. //==============================================================================
  214. bool setupAttack(int playerID=-1)
  215. {
  216.     // int randomPath=aiRandInt(2);
  217.     // Difficulty Level check.
  218.     int difflevel=-1;        
  219.     difflevel=aiGetWorldDifficulty();
  220.  
  221.     //Info.
  222.     aiEcho("Attacking Player "+playerID+".");
  223.  
  224.    //If the player to attack doesn't match, init the attack.
  225.    if (attackPlayerID != playerID)
  226.    {
  227.       initAttack(playerID);
  228.       if (attackPlayerID < 0)
  229.          return(false);
  230.    }
  231.  
  232.    //Create an attack plan.
  233.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  234.    if (newAttackPlanID < 0)
  235.       return(false);
  236.  
  237.    //Target player (required).  This must work.
  238.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  239.       return(false);
  240.  
  241.    //Gather points.
  242.     vector gatherPoint=kbGetBlockPosition("2445");
  243.     
  244.  
  245.     //Set the target type.  This must work.
  246.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  247.       return(false);
  248.  
  249.    //Unit types to attack.
  250.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeBuilding);
  251.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeUnit);
  252.  
  253.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID);
  254.     aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  255.  
  256.    //Set the gather point and gather point distance.
  257.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 20.0);
  258.  
  259.    //Set up the attack route usage pattern.
  260.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  261.    
  262.     //Add the unit types to the plan.
  263.    aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID1, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize);
  264.     if ( difflevel > 0 )
  265.     {
  266.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 0, attackMaximumGroupSize, attackMaximumGroupSize);
  267.     }
  268.  
  269.     // Heroes, except on easy.
  270.     if ( difflevel > 0 )
  271.     {
  272.         aiPlanAddUnitType(newAttackPlanID, attackerHeroTypeID1, 0, 1, 1);
  273.         aiPlanAddUnitType(newAttackPlanID, attackerHeroTypeID2, 0, 1, 1);
  274.     }
  275.  
  276.     // Catapults if available; fewer on easy.
  277.     if ( difflevel > 0 )
  278.     {
  279.         aiPlanAddUnitType(newAttackPlanID, attackerSiegeTypeID1, 0, 2, 4);
  280.     }
  281.     else
  282.     {
  283.         aiPlanAddUnitType(newAttackPlanID, attackerSiegeTypeID1, 0, 1, 1);
  284.     }
  285.  
  286.     // A pair o' cyclopses if available, or one on easy.
  287.     if ( difflevel > 0 )
  288.     {
  289.         aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID1, 0, 2, 2);
  290.     }
  291.     else
  292.     {
  293.         aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID1, 0, 1, 1);
  294.     }
  295.  
  296.     // Myth units, sometimes.
  297.     // aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID2, 0, 4, 4);
  298.     // aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID3, 0, 2, 2);
  299.     
  300.    //Set the initial position.
  301.     aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  302.         
  303.    //Plan requires all need units to work (can be false).
  304.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  305.    //Activate the plan.
  306.    aiPlanSetActive(newAttackPlanID);
  307.  
  308.    //Now, save the attack plan ID appropriately.
  309.    aiPlanSetOrphan(attackPlan1ID, true);
  310.    attackPlan1ID=newAttackPlanID;
  311.  
  312.    //Increment our overall number of attacks.
  313.    numberAttacks++;
  314. }
  315.  
  316. //==============================================================================
  317. // setupCavAttack
  318. //==============================================================================
  319. bool setupCavAttack(int playerID=-1)
  320. {
  321.     //Info.
  322.     aiEcho("Attacking Player "+playerID+".");
  323.  
  324.    //If the player to attack doesn't match, init the attack.
  325.    if (attackPlayerID != playerID)
  326.    {
  327.       initAttack(playerID);
  328.       if (attackPlayerID < 0)
  329.          return(false);
  330.    }
  331.  
  332.    //Create an attack plan.
  333.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  334.    if (newAttackPlanID < 0)
  335.       return(false);
  336.  
  337.    //Target player (required).  This must work.
  338.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  339.       return(false);
  340.  
  341.    //Gather points.
  342.     vector gatherPoint=kbGetBlockPosition("2452");
  343.     
  344.  
  345.     //Set the target type.  This must work.
  346.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  347.       return(false);
  348.  
  349.     aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 3, true);
  350.  
  351.    //Unit types to attack.
  352.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeVillagerGreek);
  353.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeUnit);
  354.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 2, cUnitTypeBuilding);
  355.  
  356.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID);
  357.     aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  358.  
  359.    //Set the gather point and gather point distance.
  360.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 30.0);
  361.  
  362.     // Use the second route here.
  363.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID);
  364.  
  365.    //Set up the attack route usage pattern.
  366.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  367.    
  368.     //Add the unit types to the plan.
  369.    aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, 4, 8, 12);
  370.  
  371.     // A pair o' nemeans if available.
  372.     aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID2, 0, 2, 2);
  373.  
  374.    //Set the initial position.
  375.     aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  376.         
  377.    //Plan requires all need units to work (can be false).
  378.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  379.    //Activate the plan.
  380.    aiPlanSetActive(newAttackPlanID);
  381.  
  382.    //Now, save the attack plan ID appropriately.
  383.    aiPlanSetOrphan(attackPlan2ID, true);
  384.    attackPlan2ID=newAttackPlanID;
  385.  
  386.    //Increment our overall number of attacks.
  387.    numberAttacks++;
  388. }
  389.  
  390. //==============================================================================
  391. // Attack Generator 1 - Mixed group of human units
  392. //==============================================================================
  393. rule attackGenerator
  394.    minInterval 110
  395.    inactive
  396.    group AttackRules
  397.    runImmediately
  398. {
  399.    //See how many "idle" attack plans we have.  Don't create any more if we have
  400.    //idle plans.
  401.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  402.  
  403.    if (numberIdleAttackPlans > 0)
  404.       return;
  405.  
  406.    // If we have enough unassigned military units, create a new attack plan.
  407.     // Hoplites are the primary unit.
  408.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID1);
  409.    aiEcho("There are "+numberAvailableUnits+" hoplites available for a new attack.");
  410.    
  411.     if (numberAvailableUnits >= attackMinimumGroupSize)
  412.         setupAttack(1);
  413. }
  414.  
  415. //==============================================================================
  416. // Attack Generator 2 - Cav and Nemean raiders 
  417. //==============================================================================
  418. rule attackGeneratorCav
  419.    minInterval 160
  420.    inactive
  421.    group AttackRules
  422. {
  423.    //See how many "idle" attack plans we have.  Don't create any more if we have
  424.    //idle plans.
  425.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  426.  
  427.    if (numberIdleAttackPlans > 0)
  428.       return;
  429.  
  430.    // If we have enough unassigned military units, create a new attack plan.
  431.     // Hoplites are the primary unit.
  432.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID2);
  433.    aiEcho("There are "+numberAvailableUnits+" hoplites available for a new attack.");
  434.    
  435.     if (numberAvailableUnits >= 4)
  436.         setupCavAttack(1);
  437. }
  438.  
  439. //==============================================================================
  440. // Attack enablers - enable attacks after initial timers expire 
  441. //==============================================================================
  442. rule attack1Enabler
  443.    minInterval 150
  444.    active
  445.    group AttackRules
  446. {
  447.     // Difficulty Level check.
  448.     int difflevel=-1;        
  449.     difflevel=aiGetWorldDifficulty();
  450.  
  451.     aiEcho("*** PLAYER 5 - ATTACKS ENABLED ***");
  452.    xsEnableRule("attackGenerator");
  453.  
  454.     // Cavalry attacks on all levels other than Easy.
  455.     if ( difflevel > 0 )
  456.     {
  457.         xsEnableRule("attackGeneratorCav");
  458.     }
  459.    xsDisableSelf();
  460. }
  461.  
  462. //==============================================================================
  463. // Siege enabler - start maintaining siege weapons at ten minutes.
  464. //==============================================================================
  465. rule siegeEnabler
  466.    minInterval 600
  467.    active
  468.    group AttackRules
  469. {
  470.     aiEcho("*** PLAYER 5 - MAINTAINING SIEGE and LIONS - ATTACKING WITH CAVALRY ***");
  471.  
  472.     vector gatherPointSiege=kbGetBlockPosition("2463");
  473.     vector gatherPointLions=kbGetBlockPosition("2451");
  474.  
  475.    //Maintain Catapults (4)
  476.    maintainSiege1ID=aiPlanCreate("Maintain 4 "+kbGetProtoUnitName(attackerSiegeTypeID1), cPlanTrain);
  477.    if (maintainSiege1ID >= 0)
  478.    {
  479.         //Must set the type of unit to train. 
  480.       aiPlanSetVariableInt(maintainSiege1ID, cTrainPlanUnitType, 0, attackerSiegeTypeID1);
  481.       //You can limit the number of units that are ever trained by this plan with this call.
  482.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  483.       //Set the number of units to maintain in the world at one time.
  484.       aiPlanSetVariableInt(maintainSiege1ID, cTrainPlanNumberToMaintain, 0, 4);
  485.       //Don't train units too fast
  486.       aiPlanSetVariableInt(maintainSiege1ID, cTrainPlanFrequency, 0, 90);
  487.       //Set a gather point.
  488.       aiPlanSetVariableVector(maintainSiege1ID, cTrainPlanGatherPoint, 0, gatherPointSiege);
  489.       //Activate the plan.
  490.       aiPlanSetActive(maintainSiege1ID);
  491.    }
  492.  
  493.     // Myth Maintain Plan - two Nemeans
  494.    maintainMythPlan2ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerMythTypeID2), cPlanTrain);
  495.    if (maintainMythPlan1ID >= 0)
  496.    {
  497.         //Must set the type of unit to train.
  498.       aiPlanSetVariableInt(maintainMythPlan2ID, cTrainPlanUnitType, 0, attackerMythTypeID2);
  499.       //You can limit the number of units that are ever trained by this plan with this call.
  500.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  501.       //Set the number of units to maintain in the world at one time.
  502.       aiPlanSetVariableInt(maintainMythPlan2ID, cTrainPlanNumberToMaintain, 0, 2);
  503.       //Don't train units too fast
  504.       aiPlanSetVariableInt(maintainMythPlan2ID, cTrainPlanFrequency, 0, 90);
  505.       //Set a gather point.
  506.       aiPlanSetVariableVector(maintainMythPlan2ID, cTrainPlanGatherPoint, 0, gatherPointLions);
  507.       //Activate the plan.
  508.       aiPlanSetActive(maintainMythPlan2ID);
  509.    }
  510.    xsDisableSelf();
  511. }
  512.  
  513.  
  514. /*
  515. //==============================================================================
  516. // Tech Researching Rules - medium axemen, medium slingers, medium spearmen
  517. //==============================================================================
  518. rule researchMediumAxemen
  519.    minInterval 600
  520.    active
  521. {
  522.    int planID=aiPlanCreate("Medium Axemen research at ten minutes.", cPlanResearch);
  523.    if (planID < 0)
  524.       return;
  525.  
  526.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechMediumAxemen);
  527.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeBarracks);
  528.    aiPlanSetActive(planID);
  529.    
  530.     //Done.
  531.    xsDisableSelf();
  532. }
  533. */
  534.  
  535. //==============================================================================
  536. // Favor cheat - favor every so often.
  537. //==============================================================================
  538. rule favorCheat
  539.    minInterval 60
  540.    active
  541.    group AttackRules
  542. {
  543.     // Cheat for favor every 60 seconds.  That Gargarensis is a bastard.
  544.     aiResourceCheat( 5, cResourceFavor, 20.0 );
  545. }
  546.  
  547.  
  548. //==================================================================================================
  549. // Player has Plenties!  Or, alternatively, he's destroyed a forward fortress.  Leary sleep now.  :)
  550. //==================================================================================================
  551. void playerHasPlenties(int scriptCall = -1)
  552. {
  553.     vector defendPointWest=kbGetBlockPosition("2447");
  554.     vector defendPointEast=kbGetBlockPosition("2444");
  555.  
  556.     aiEcho("*** PLAYER 5: HP has destroyed a forward fortress ***");
  557.     
  558.     // Disable the attack generator (and the siege stuff if it hasn't fired)
  559.     xsDisableRule( "attackGenerator" );
  560.     xsDisableRule( "siegeEnabler" );
  561.  
  562.     // Disable the cavalry defend plan and stop maintaining cav, catapults, toxotes, cyclopses, and heroes.
  563.     //aiPlanDestroy( defendPlan1ID );
  564.     aiPlanDestroy( maintainPlan2ID );
  565.     aiPlanDestroy( maintainSiege1ID );
  566.     
  567.     aiPlanDestroy( maintainPlan2ID );
  568.     aiPlanDestroy( maintainPlan3ID );
  569.     aiPlanDestroy( maintainMythPlan1ID );
  570.     aiPlanDestroy( maintainHeroPlan1ID );
  571.     aiPlanDestroy( maintainHeroPlan2ID );
  572.  
  573.     // Back the other two defense plans up to the entrance to "higher ground."
  574.     aiPlanSetVariableVector(defendPlan2ID, cDefendPlanDefendPoint, 0, defendPointWest);
  575.     aiPlanSetVariableVector(defendPlan3ID, cDefendPlanDefendPoint, 0, defendPointEast);
  576. }
  577.  
  578. //==============================================================================
  579. // Maintain stuff - separated out for sanity's sake.
  580. //==============================================================================
  581. void maintainStuff(void)
  582. {
  583.    //Share a common gather point.
  584.     vector gatherPointWest=kbGetBlockPosition("2451");
  585.     vector gatherPointCenter=kbGetBlockPosition("2448");
  586.    vector gatherPointEast=kbGetBlockPosition("2445");
  587.     vector gatherPointTemple=kbGetBlockPosition("2447");
  588.     
  589.     //Share the number to maintain.
  590.    int numberToMaintain=attackMinimumGroupSize*2;
  591.  
  592.    //Maintain hoplites (16)
  593.    maintainPlan1ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain);
  594.    if (maintainPlan1ID >= 0)
  595.    {
  596.         //Must set the type of unit to train. 
  597.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1);
  598.       //You can limit the number of units that are ever trained by this plan with this call.
  599.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  600.       //Set the number of units to maintain in the world at one time.
  601.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, 12);
  602.       //Don't train units too fast
  603.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 20);
  604.       //Set a gather point.
  605.       aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointCenter);
  606.       //Activate the plan.
  607.       aiPlanSetActive(maintainPlan1ID);
  608.    }
  609.  
  610.     //Maintain hippikons (12)
  611.    maintainPlan2ID=aiPlanCreate("Maintain 12 "+kbGetProtoUnitName(attackerUnitTypeID2), cPlanTrain);
  612.    if (maintainPlan2ID >= 0)
  613.    {
  614.         //Must set the type of unit to train. 
  615.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID2);
  616.       //You can limit the number of units that are ever trained by this plan with this call.
  617.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  618.       //Set the number of units to maintain in the world at one time.
  619.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, 12);
  620.       //Don't train units too fast
  621.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 30);
  622.       //Set a gather point.
  623.       aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPointWest);
  624.       //Activate the plan.
  625.       aiPlanSetActive(maintainPlan2ID);
  626.    }
  627.  
  628.     //Maintain toxotes (8)
  629.    maintainPlan3ID=aiPlanCreate("Maintain 8 "+kbGetProtoUnitName(attackerUnitTypeID3), cPlanTrain);
  630.    if (maintainPlan3ID >= 0)
  631.    {
  632.         //Must set the type of unit to train.
  633.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeID3);
  634.       //You can limit the number of units that are ever trained by this plan with this call.
  635.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  636.       //Set the number of units to maintain in the world at one time.
  637.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  638.       //Don't train units too fast
  639.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 40);
  640.       //Set a gather point.
  641.       aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPointEast);
  642.       //Activate the plan.
  643.       aiPlanSetActive(maintainPlan3ID);
  644.    }
  645.  
  646.     //Maintain hypaspists(12)
  647.    maintainPlan4ID=aiPlanCreate("Maintain 12 "+kbGetProtoUnitName(attackerUnitTypeID4), cPlanTrain);
  648.    if (maintainPlan4ID >= 0)
  649.    {
  650.         //Must set the type of unit to train.
  651.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanUnitType, 0, attackerUnitTypeID4);
  652.       //You can limit the number of units that are ever trained by this plan with this call.
  653.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  654.       //Set the number of units to maintain in the world at one time.
  655.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, 12);
  656.       //Don't train units too fast
  657.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 45);
  658.       //Set a gather point.
  659.       aiPlanSetVariableVector(maintainPlan4ID, cTrainPlanGatherPoint, 0, gatherPointCenter);
  660.       //Activate the plan.
  661.       aiPlanSetActive(maintainPlan4ID);
  662.    }
  663.     
  664.     //Maintain peltasts(6)
  665.    maintainPlan5ID=aiPlanCreate("Maintain 4 "+kbGetProtoUnitName(attackerUnitTypeID5), cPlanTrain);
  666.    if (maintainPlan5ID >= 0)
  667.    {
  668.         //Must set the type of unit to train.
  669.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanUnitType, 0, attackerUnitTypeID5);
  670.       //You can limit the number of units that are ever trained by this plan with this call.
  671.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  672.       //Set the number of units to maintain in the world at one time.
  673.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToMaintain, 0, 6);
  674.       //Don't train units too fast
  675.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanFrequency, 0, 50);
  676.       //Set a gather point.
  677.       aiPlanSetVariableVector(maintainPlan5ID, cTrainPlanGatherPoint, 0, gatherPointEast);
  678.       //Activate the plan.
  679.       aiPlanSetActive(maintainPlan5ID);
  680.    }
  681.  
  682.     // Myth Maintain Plan - three cyclopses
  683.    maintainMythPlan1ID=aiPlanCreate("Maintain 3 "+kbGetProtoUnitName(attackerMythTypeID1), cPlanTrain);
  684.    if (maintainMythPlan1ID >= 0)
  685.    {
  686.         //Must set the type of unit to train.
  687.       aiPlanSetVariableInt(maintainMythPlan1ID, cTrainPlanUnitType, 0, attackerMythTypeID1);
  688.       //You can limit the number of units that are ever trained by this plan with this call.
  689.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  690.       //Set the number of units to maintain in the world at one time.
  691.       aiPlanSetVariableInt(maintainMythPlan1ID, cTrainPlanNumberToMaintain, 0, 3);
  692.       //Don't train units too fast
  693.       aiPlanSetVariableInt(maintainMythPlan1ID, cTrainPlanFrequency, 0, 90);
  694.       //Set a gather point.
  695.       aiPlanSetVariableVector(maintainMythPlan1ID, cTrainPlanGatherPoint, 0, gatherPointTemple);
  696.       //Activate the plan.
  697.       aiPlanSetActive(maintainMythPlan1ID);
  698.    }
  699.  
  700.     // Hero Maintain Plans
  701.    maintainHeroPlan1ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerHeroTypeID1), cPlanTrain);
  702.    if (maintainHeroPlan1ID >= 0)
  703.    {
  704.         //Must set the type of unit to train.
  705.       aiPlanSetVariableInt(maintainHeroPlan1ID, cTrainPlanUnitType, 0, attackerHeroTypeID1);
  706.       //You can limit the number of units that are ever trained by this plan with this call.
  707.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  708.       //Set the number of units to maintain in the world at one time.
  709.       aiPlanSetVariableInt(maintainHeroPlan1ID, cTrainPlanNumberToMaintain, 0, 1);
  710.       //Don't train units too fast
  711.       aiPlanSetVariableInt(maintainHeroPlan1ID, cTrainPlanFrequency, 0, 130);
  712.       //Set a gather point.
  713.       aiPlanSetVariableVector(maintainHeroPlan1ID, cTrainPlanGatherPoint, 0, gatherPointEast);
  714.       //Activate the plan.
  715.       aiPlanSetActive(maintainHeroPlan1ID);
  716.    }
  717.  
  718.    maintainHeroPlan2ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerHeroTypeID2), cPlanTrain);
  719.    if (maintainHeroPlan2ID >= 0)
  720.    {
  721.         //Must set the type of unit to train.
  722.       aiPlanSetVariableInt(maintainHeroPlan2ID, cTrainPlanUnitType, 0, attackerHeroTypeID2);
  723.       //You can limit the number of units that are ever trained by this plan with this call.
  724.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  725.       //Set the number of units to maintain in the world at one time.
  726.       aiPlanSetVariableInt(maintainHeroPlan2ID, cTrainPlanNumberToMaintain, 0, 1);
  727.       //Don't train units too fast
  728.       aiPlanSetVariableInt(maintainHeroPlan2ID, cTrainPlanFrequency, 0, 140);
  729.       //Set a gather point.
  730.       aiPlanSetVariableVector(maintainHeroPlan2ID, cTrainPlanGatherPoint, 0, gatherPointEast);
  731.       //Activate the plan.
  732.       aiPlanSetActive(maintainHeroPlan2ID);
  733.    }
  734. }
  735.  
  736. //==============================================================================
  737. // Defend plan excitement.
  738. //==============================================================================
  739. void defendPlanSetup(void)
  740. {
  741.     /*
  742.     defendPlan1ID=aiPlanCreate("West Defense", cPlanDefend);
  743.    if (defendPlan1ID >= 0)
  744.    {
  745.       //choke point
  746.       vector westChoke=kbGetBlockPosition("2452");
  747.  
  748.       //Add the unit(s).
  749.       aiPlanAddUnitType(defendPlan1ID, attackerUnitTypeID2, 0, 4, 4);
  750.                 
  751.       //Setup the vars.
  752.       aiPlanSetDesiredPriority(defendPlan1ID, 40);
  753.       aiPlanSetVariableVector(defendPlan1ID, cDefendPlanDefendPoint, 0, westChoke);
  754.       aiPlanSetVariableFloat(defendPlan1ID, cDefendPlanEngageRange, 0, 20);
  755.       aiPlanSetActive(defendPlan1ID);
  756.     }
  757.     */
  758.  
  759.    defendPlan2ID=aiPlanCreate("Center Defense", cPlanDefend);
  760.    if (defendPlan2ID >= 0)
  761.    {
  762.       //choke point
  763.       vector centerChoke=kbGetBlockPosition("2450");
  764.  
  765.       //Add the unit(s).
  766.       aiPlanAddUnitType(defendPlan2ID, attackerUnitTypeID4, 0, 6, 6);
  767.         aiPlanAddUnitType(defendPlan2ID, attackerUnitTypeID5, 0, 3, 3);
  768.         
  769.       //Setup the vars.
  770.       aiPlanSetDesiredPriority(defendPlan2ID, 40);
  771.         aiPlanSetVariableVector(defendPlan2ID, cDefendPlanDefendPoint, 0, centerChoke);
  772.       aiPlanSetVariableFloat(defendPlan2ID, cDefendPlanEngageRange, 0, 20);
  773.       aiPlanSetActive(defendPlan2ID);
  774.     }
  775.  
  776.     defendPlan3ID=aiPlanCreate("East Defense", cPlanDefend);
  777.    if (defendPlan3ID >= 0)
  778.    {
  779.       //choke point
  780.       vector eastChoke=kbGetBlockPosition("2449");
  781.  
  782.       //Add the unit(s).
  783.         aiPlanAddUnitType(defendPlan2ID, attackerUnitTypeID4, 0, 6, 6);
  784.       aiPlanAddUnitType(defendPlan3ID, attackerUnitTypeID5, 0, 3, 3);
  785.         
  786.       //Setup the vars.
  787.       aiPlanSetDesiredPriority(defendPlan3ID, 90);
  788.         aiPlanSetVariableVector(defendPlan3ID, cDefendPlanDefendPoint, 0, eastChoke);
  789.       aiPlanSetVariableFloat(defendPlan3ID, cDefendPlanEngageRange, 0, 20);
  790.       aiPlanSetActive(defendPlan3ID);
  791.     }
  792. }
  793.  
  794. //==============================================================================
  795. // MAIN
  796. //==============================================================================
  797. void main(void)
  798. {
  799.    //Startup.
  800.    miscStartup();
  801.     
  802.     //Set up maintain plans.
  803.     maintainStuff();
  804.  
  805.     // Set up a couple of defend plans.
  806.     defendPlanSetup();
  807. }