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

  1. //==============================================================================
  2. // Scn09p2: AI Scenario Script for scenario 9 player 2
  3. //==============================================================================
  4.  
  5. /*
  6.    AI owner:  Dave Leary
  7.    Scenario owner: Joe "the Golem" Gillum
  8.  
  9.     The AI for the enemy (Troy) in scenario 9.  Maintains a mixture of units and
  10.     sends attack groups based on scouts returning to Troy (called from an AI Func).
  11.     The parameter sent in the AI Func determines composition and size of the
  12.     attack.
  13.  
  14.    Also does some cleanup when the Trojan horse is built, killing maintain plans
  15.     and deleting existing AI units near the gather points.  This doesn't always
  16.     catch everything (it doesn't handle units currently being trained), so it
  17.     fires another function to delete units again.  A little hack-er-ific, but it
  18.     works.
  19. */
  20.  
  21. //==============================================================================
  22. // Set Town Location
  23. //==============================================================================
  24. void setTownLocation(void)
  25. {
  26.    //Look for the "Town Location" marker.
  27.    kbSetTownLocation(kbGetBlockPosition("3031"));
  28. }
  29.  
  30. //==============================================================================
  31. // miscStartup
  32. //==============================================================================
  33. void miscStartup(void)
  34. {
  35.     // Difficulty Level check.
  36.     int difflevel=-1;        
  37.     difflevel=aiGetWorldDifficulty();
  38.     
  39.     //Startup message(s).
  40.    aiEcho("");
  41.    aiEcho("");
  42.    aiEcho("Scn09P2 AI Start, filename='"+cFilename+"'.");
  43.     aiEcho("Difficulty Level="+difflevel+".");
  44.  
  45.    //Spit out the map size.
  46.    aiEcho("  Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+").");
  47.    //Cheat like a bastard.  Once only, though.
  48.    kbLookAtAllUnitsOnMap();
  49.    //Calculate some areas.
  50.    kbAreaCalculate(1200.0);
  51.    //Set our town location.
  52.    setTownLocation();
  53.     //Reset random seed
  54.     aiRandSetSeed();
  55.     
  56.     //Allocate all resources to the root escrow by setting percentage of military/economy to 0.
  57.     kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0 );
  58.     kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0 );
  59.  
  60.    //Allocate all resources to the root escrow.
  61.    kbEscrowAllocateCurrentResources();
  62.  
  63.     // Drop the AI attack response distance for this player to 3 meters.  We'll up it later.
  64.     aiSetAttackResponseDistance(0.0);
  65. }
  66.  
  67. //==============================================================================
  68. //==============================================================================
  69. // Attack stuff.
  70. //==============================================================================
  71. //==============================================================================
  72. //Shared variables.
  73. int numberAttacks=0;
  74. int attackPlayerID=-1;
  75.  
  76. // Maintain plans
  77. int maintainPlan1ID=-1;
  78. int maintainPlan2ID=-1;
  79. int maintainPlan3ID=-1;
  80. int maintainPlan4ID=-1;
  81. int maintainPlan5ID=-1;
  82.  
  83. //Attack 1 vars.
  84. int attackPlan1ID=-1;
  85.  
  86. //Attack 2 vars.
  87. int attackPlan2ID=-1;
  88.  
  89. // Route and path vars
  90. int attackRoute1ID=-1;
  91. int attackPath1ID=-1;
  92. int attackRoute2ID=-1;
  93. int attackPath2ID=-1;
  94.  
  95. // Unit Types
  96. int attackerUnitTypeID1=cUnitTypeToxotes;
  97. int attackerUnitTypeID2=cUnitTypeHypaspist;
  98. int attackerUnitTypeID3=cUnitTypeHippikon;
  99. int attackerUnitTypeID4=cUnitTypeNemeanLion;
  100. int attackerUnitTypeID5=cUnitTypePetrobolos;
  101. int attackerUnitTypeID6=cUnitTypeShadeofHades;
  102.  
  103.  
  104. //=========================================================================================
  105. // Kidd's cool configQuery function: used to create attack routes, etc.  Oooh, lovin' that!
  106. //=========================================================================================
  107. 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 )
  108. {
  109.    if ( queryID == -1)
  110.    {
  111.       return(false);
  112.    }
  113.  
  114.    if (player != -1)
  115.       kbUnitQuerySetPlayerID(queryID, player);
  116.    
  117.    if (unitType != -1)
  118.       kbUnitQuerySetUnitType(queryID, unitType);
  119.  
  120.    if (action != -1)
  121.       kbUnitQuerySetActionType(queryID, action);
  122.  
  123.    if (state != -1)
  124.       kbUnitQuerySetState(queryID, state);
  125.  
  126.    if (center != vector(-1,-1,-1))
  127.    {
  128.       kbUnitQuerySetPosition(queryID, center);
  129.       if (sort == true)
  130.          kbUnitQuerySetAscendingSort(queryID, true);
  131.       if (radius != -1)
  132.          kbUnitQuerySetMaximumDistance(queryID, radius);
  133.    }
  134.    return(true);
  135. }
  136.  
  137. //==============================================================================
  138. // initAttack: Creates attack routes, etc.
  139. //==============================================================================
  140. void initAttack(int playerID=-1)
  141. {
  142.    //Destroy all previous attacks (if this isn't the player we're already attacking.
  143.    if (playerID != attackPlayerID)
  144.    {
  145.       //Reset the attack player ID.
  146.       attackPlayerID=-1;
  147.       //Destroy any previous attack plan.
  148.       aiPlanDestroy(attackPlan1ID);
  149.       attackPlan1ID=-1;
  150.       aiPlanDestroy(attackPlan2ID);
  151.       attackPlan2ID=-1;
  152.   
  153.       //Destroy our previous attack paths.
  154.       kbPathDestroy(attackPath1ID);
  155.       attackPath1ID=-1;
  156.       kbPathDestroy(attackPath2ID);
  157.       attackPath2ID=-1;
  158.  
  159.       //Destroy our previous attack routes.
  160.       attackRoute1ID=-1;
  161.       attackRoute2ID=-1;
  162.  
  163.       //Reset the number of attacks.
  164.       numberAttacks=0;
  165.    }
  166.  
  167.    //Save the player to attack.
  168.    attackPlayerID=playerID;
  169.  
  170.    vector gatherPoint=kbGetBlockPosition("3031");
  171.        
  172.     //Setup attack path 1 - go left
  173.    attackPath1ID=kbPathCreate("Attack Path 1");
  174.    kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3032"));
  175.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3033"));
  176.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3034"));
  177.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3035"));
  178.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3036"));
  179.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3037"));
  180.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3038"));
  181.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3039"));
  182.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3040"));
  183.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3041"));
  184.    //Create attack route 1.
  185.    attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", gatherPoint, kbGetBlockPosition("3042"));
  186.    
  187.     if (attackRoute1ID >= 0)
  188.       kbAttackRouteAddPath(attackRoute1ID, attackPath1ID);
  189.  
  190.    //Setup attack path 2 - go right
  191.    attackPath2ID=kbPathCreate("Attack Path 2");
  192.    kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3043"));
  193.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3044"));
  194.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3045"));
  195.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3046"));
  196.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3047"));
  197.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3048"));
  198.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3049"));
  199.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3050"));
  200.     
  201.    //Create attack route 2.
  202.    attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", gatherPoint, kbGetBlockPosition("3051"));
  203.    
  204.     if (attackRoute2ID >= 0)
  205.       kbAttackRouteAddPath(attackRoute2ID, attackPath2ID);
  206. }
  207.  
  208. //==============================================================================
  209. // setupAttack
  210. //==============================================================================
  211. bool setupAttack(int playerID=-1, int whichAttack=-1)
  212. {
  213.     int randomPath=aiRandInt(2);
  214.    
  215.     //Info.
  216.     aiEcho("Attacking Player "+playerID+".");
  217.  
  218.    //If the player to attack doesn't match, init the attack.
  219.    if (attackPlayerID != playerID)
  220.    {
  221.       initAttack(playerID);
  222.       if (attackPlayerID < 0)
  223.          return(false);
  224.    }
  225.  
  226.    //Create an attack plan.
  227.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  228.    if (newAttackPlanID < 0)
  229.       return(false);
  230.  
  231.    //Target player (required).  This must work.
  232.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  233.       return(false);
  234.  
  235.    //Gather point.
  236.     vector gatherPoint=kbGetBlockPosition("3031");
  237.  
  238.     //Set the target type.  This must work.
  239.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  240.       return(false);
  241.  
  242.    //Unit types to attack.
  243.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  244.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  245.  
  246.    //Attack route.
  247.    if (randomPath == 0)
  248.     {
  249.         aiEcho("Attack going left.");
  250.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID);
  251.     }
  252.    else
  253.     {
  254.         aiEcho("Attack going right.");
  255.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID);
  256.     }
  257.  
  258.    //Set the gather point and gather point distance.
  259.    aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  260.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 20.0);
  261.  
  262.    //Set up the attack route usage pattern.
  263.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  264.    
  265.     //Add the unit types to the plan.
  266.    aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID1, 6, 6, 6);
  267.     //Add some extra guys depending on which attack it is.
  268.     switch(whichAttack)
  269.    {
  270.         // Basic case, toxotes plus hypaspists
  271.        case 0:
  272.       {
  273.             aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, 2, 2, 2);
  274.             aiEcho("Attacking with toxotoes only.");
  275.             break;
  276.       }
  277.         
  278.         // Four hypaspists
  279.         case 1:
  280.       {
  281.             aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, 4, 4, 4);
  282.             break;
  283.       }
  284.         
  285.         // Four hypaspists, two hippikons.  Shades of Hades if available.
  286.         case 2:
  287.         {
  288.             aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, 4, 4, 4);
  289.             aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 2, 2, 2);
  290.             aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 2, 2);
  291.             break;
  292.         }
  293.         
  294.         // Everything from case 2, plus two Nemean Lions and a catapult.  Shades of Hades if available.
  295.         case 3:
  296.         {
  297.             aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, 4, 4, 4);
  298.             aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 2, 2, 2);
  299.             aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 2, 2);
  300.             aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID5, 0, 1, 1);
  301.             aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID6, 0, 2, 2);
  302.             break;
  303.         }
  304.     }
  305.         
  306.    //Set the initial position.
  307.    aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  308.    //Plan requires all need units to work (can be false).
  309.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  310.    //Activate the plan.
  311.    aiPlanSetActive(newAttackPlanID);
  312.  
  313.    //Now, save the attack plan ID appropriately.
  314.    aiPlanSetOrphan(attackPlan1ID, true);
  315.    attackPlan1ID=newAttackPlanID;
  316.  
  317.    //Increment our overall number of attacks.
  318.    numberAttacks++;
  319. }
  320.  
  321. //=====================================================================================
  322. // Attack Launcher.  This is called from the scenario with an AI Func effect
  323. // when the player claims his first settlement.
  324. //=====================================================================================
  325. void attackLauncher(int whichAttack = -1)
  326. {
  327.     aiEcho("*** SCOUT RETURNS - ATTACK LAUNCHER CALLED ***");
  328.     aiEcho("*** Attack Parameter: "+whichAttack+" ***");
  329.  
  330.     //See how many "idle" attack plans we have.  Don't create any more if we have
  331.    //idle plans.
  332.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  333.    if (numberIdleAttackPlans > 0)
  334.       return;
  335.  
  336.    //Create a new attack plan.
  337.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID1);
  338.    aiEcho("There are "+numberAvailableUnits+" toxotes available for a new attack.");
  339.     setupAttack(1, whichAttack);
  340. }
  341.  
  342. //*****************************************************************************
  343. // horseBuiltCleanup - used to delete the fools near the gather point and
  344. // disable a bunch of functions.  Called once the Trojan Horse is built.
  345. //*****************************************************************************
  346. void horseBuiltCleanup(int parameter = -1)
  347. {
  348.     // Destroy existing maintain plans.
  349.    aiPlanDestroy(maintainPlan1ID);
  350.     aiPlanDestroy(maintainPlan2ID);
  351.     aiPlanDestroy(maintainPlan3ID);
  352.     aiPlanDestroy(maintainPlan4ID);
  353.     aiPlanDestroy(maintainPlan5ID);
  354.    
  355.     int unassigned=0;       // Number of unassigned units found by traversing the query results
  356.    int query=-1;           // Query to find the units of unitType within radius of center.
  357.    int count=-1;           // Number of units found by the query.
  358.    int i=-1;
  359.     
  360.     vector center=kbGetBlockPosition("3031");
  361.    query = kbUnitQueryCreate("All Player 2 Units Near The Point");
  362.  
  363.     aiEcho("*** ALL UNITS AT GATHER POINT DELETED (in theory) ***");
  364.  
  365.     // Delete all existing military units near the gather point.
  366.     if (query < 0)
  367.       return();
  368.  
  369.    configQuery(query, cUnitTypeUnit, -1, cUnitStateAlive, 2, center, true, 40.0);
  370.    kbUnitQueryResetResults(query);
  371.    count = kbUnitQueryExecute(query);
  372.  
  373.     aiEcho("There are "+count+" units to delete.");
  374.  
  375.    for (i=0; <count)
  376.    {
  377.         aiTaskUnitDelete(kbUnitQueryGetResult(query, i));
  378.    }
  379.         
  380.     // Drop the AI attack response distance for this player to 10 meters.
  381.     aiSetAttackResponseDistance(5.0);
  382. }
  383.  
  384. //*****************************************************************************
  385. // horseBuiltCleanup2 - we gotta do it again to make sure we're deleting
  386. // all the units left over from extra maintain plans.
  387. //*****************************************************************************
  388. void horseBuiltCleanup2(int parameter = -1)
  389. {
  390.     int unassigned=0;       // Number of unassigned units found by traversing the query results
  391.    int query=-1;           // Query to find the units of unitType within radius of center.
  392.    int count=-1;           // Number of units found by the query.
  393.    int i=-1;
  394.     
  395.     vector center=kbGetBlockPosition("3031");
  396.    query = kbUnitQueryCreate("All Player 2 Units Near The Point");
  397.  
  398.     aiEcho("*** DOING THE CLEANUP AGAIN ***");
  399.  
  400.     // Delete all existing military units near the gather point.
  401.     if (query < 0)
  402.       return();
  403.  
  404.    configQuery(query, cUnitTypeUnit, -1, cUnitStateAlive, 2, center, true, 40.0);
  405.    kbUnitQueryResetResults(query);
  406.    count = kbUnitQueryExecute(query);
  407.  
  408.     aiEcho("There are "+count+" units to delete.");
  409.  
  410.    for (i=0; <count)
  411.    {
  412.         aiTaskUnitDelete(kbUnitQueryGetResult(query, i));
  413.    }
  414. }
  415.  
  416.  
  417. //==============================================================================
  418. // Favor Cheat so he can afford an endless stream of Nemean Lions.
  419. //==============================================================================
  420. rule favorCheat
  421.    minInterval 30
  422.    active
  423. {
  424.     aiEcho("*** Favor +50 ***");
  425.     aiResourceCheat( 2, cResourceFavor, 50.0 );
  426. }
  427.  
  428. //==============================================================================
  429. // MAIN.
  430. //==============================================================================
  431. void main(void)
  432. {
  433.    //Startup.
  434.    miscStartup();
  435.  
  436.    //Share a common gather point.
  437.    vector gatherPoint=kbGetBlockPosition("3031");
  438.     vector gatherPoint1=kbGetBlockPosition("4887");
  439.     vector gatherPoint2=kbGetBlockPosition("4888");
  440.  
  441.    //Create a simple plan to maintain 6 toxotes
  442.    maintainPlan1ID=aiPlanCreate("Maintain 12 "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain);
  443.    if (maintainPlan1ID >= 0)
  444.    {
  445.         //Must set the type of unit to train.
  446.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1);
  447.       //Set the number of units to maintain in the world at one time.
  448.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, 12);
  449.       //Don't train units faster than every 10 seconds
  450.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 2);
  451.       //Set a gather point.
  452.       aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPoint);
  453.       //Activate the plan.
  454.       aiPlanSetActive(maintainPlan1ID);
  455.    }
  456.  
  457.    //Create a simple plan to maintain 4 hypaspists
  458.    maintainPlan2ID=aiPlanCreate("Maintain 8 "+kbGetProtoUnitName(attackerUnitTypeID2), cPlanTrain);
  459.    if (maintainPlan2ID >= 0)
  460.    {
  461.         //Must set the type of unit to train.
  462.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID2);
  463.       //Set the number of units to maintain in the world at one time.
  464.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, 8);
  465.       //Don't train units faster than every 10 seconds
  466.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 2);
  467.       //Set a gather point.
  468.       aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPoint1);
  469.       //Activate the plan.
  470.       aiPlanSetActive(maintainPlan2ID);
  471.    }
  472.  
  473.    //Create a simple plan to maintain 2 hippikons
  474.    maintainPlan3ID=aiPlanCreate("Maintain 4 "+kbGetProtoUnitName(attackerUnitTypeID3), cPlanTrain);
  475.    if (maintainPlan3ID >= 0)
  476.    {
  477.         //Must set the type of unit to train.
  478.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeID3);
  479.       //Set the number of units to maintain in the world at one time.
  480.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 4);
  481.       //Don't train units faster than every 10 seconds
  482.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 2);
  483.       //Set a gather point.
  484.       aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPoint2);
  485.       //Activate the plan.
  486.       aiPlanSetActive(maintainPlan3ID);
  487.    }
  488.    //Create a simple plan to maintain 2 Nemean Lions
  489.    maintainPlan4ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerUnitTypeID4), cPlanTrain);
  490.    if (maintainPlan4ID >= 0)
  491.    {
  492.         //Must set the type of unit to train.
  493.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanUnitType, 0, attackerUnitTypeID4);
  494.       //Set the number of units to maintain in the world at one time.
  495.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, 2);
  496.       //Don't train units faster than every 10 seconds
  497.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 2);
  498.       //Set a gather point.
  499.       aiPlanSetVariableVector(maintainPlan4ID, cTrainPlanGatherPoint, 0, gatherPoint);
  500.       //Activate the plan.
  501.       aiPlanSetActive(maintainPlan4ID);
  502.    }
  503.  
  504.     //Create a simple plan to maintain 2 Petroboli
  505.    maintainPlan5ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerUnitTypeID5), cPlanTrain);
  506.    if (maintainPlan5ID >= 0)
  507.    {
  508.         //Must set the type of unit to train.
  509.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanUnitType, 0, attackerUnitTypeID5);
  510.       //Set the number of units to maintain in the world at one time.
  511.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToMaintain, 0, 2);
  512.       //Don't train units faster than every 20 seconds
  513.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanFrequency, 0, 5);
  514.       //Set a gather point.
  515.       aiPlanSetVariableVector(maintainPlan5ID, cTrainPlanGatherPoint, 0, gatherPoint1);
  516.       //Activate the plan.
  517.       aiPlanSetActive(maintainPlan5ID);
  518.    }
  519. }
  520.