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

  1. //==============================================================================
  2. // Scn35p2: AI Scenario Script for scenario 35 player 2
  3. //==============================================================================
  4. /*
  5.    AI owner:  Dave Leary
  6.    Scenario owner: Joe "the Golem" Gillum
  7.  
  8.     Handles the rearguard forces of Gargarensis in the finale.  Creates defend plans 
  9.     of    hypaspists and peltasts for the choke points leading to the enemy base.
  10.     
  11.     Periodically generates heroes (Atalanta and Polyphemus) and includes them in
  12.     attack groups.  Also sets up a defend plan that includes "one bad titan" so 
  13.     the titan sticks around the "endgame" area.
  14.     
  15.     After the HP owns two plenty vaults, an AI Func starts the AI attacking.  Attacks 
  16.     are composed of strong myth-centric armies, and choose an attack route based on 
  17.     which fortress was destroyed first.
  18.  
  19.    Gargarensis' scary god power actions are handled by scenario triggers.
  20. */
  21. //==============================================================================
  22. // Set Town Location.
  23. //==============================================================================
  24. void setTownLocation(void)
  25. {
  26.    //Look for the "Town Location" marker.
  27.    kbSetTownLocation(kbGetBlockPosition("3989"));
  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("Scn35P2 AI Start, filename='"+cFilename+"'.");
  43.     aiEcho("Difficulty Level="+difflevel+".");
  44.    //Spit out the map size.
  45.    aiEcho("  Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+").");
  46.    //Cheat like a bastard.  Once only, though.
  47.    kbLookAtAllUnitsOnMap();
  48.    //Calculate some areas.
  49.    kbAreaCalculate(1200.0);
  50.    //Set our town location.
  51.    setTownLocation();
  52.     //Reset random seed
  53.     aiRandSetSeed();
  54.    
  55.     //Allocate all resources to the root escrow by setting percentage of military/economy to 0.
  56.     kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0 );
  57.     kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0 );
  58.  
  59.     //Allocate all resources 
  60.    kbEscrowAllocateCurrentResources();
  61. }
  62.  
  63. //==============================================================================
  64. //==============================================================================
  65. // Attack stuff
  66. //==============================================================================
  67. //==============================================================================
  68. //Shared variables.
  69. int numberAttacks=0;
  70. int attackPlayerID=-1;
  71.  
  72. //TODO: Decide how to rep attack group size.
  73. int attackMinimumGroupSize=8;
  74. int attackMaximumGroupSize=12;
  75.  
  76. //Attack vars.
  77. int attackPlan1ID=-1;
  78. int attackPlan2ID=-1;
  79.  
  80. // Unit types.
  81. int attackerUnitTypeID1=cUnitTypeHoplite;
  82. int attackerUnitTypeID2=cUnitTypeHippikon;
  83. int attackerUnitTypeID3=cUnitTypeToxotes;
  84. int attackerUnitTypeID4=cUnitTypeHypaspist;
  85. int attackerUnitTypeID5=cUnitTypePeltast;
  86.  
  87. int attackerSiegeTypeID1=cUnitTypePetrobolos;
  88. int attackerSiegeTypeID2=cUnitTypeHelepolis;
  89.  
  90. int attackerMythTypeID1=cUnitTypeCyclops;
  91. int attackerMythTypeID2=cUnitTypeNemeanLion;
  92. int attackerMythTypeID3=cUnitTypeColossus;
  93.  
  94. int attackerHeroTypeID1=cUnitTypeHeroGreekAtalanta;
  95. int attackerHeroTypeID2=cUnitTypeHeroGreekPolyphemus;
  96.  
  97. // Maintain Plans
  98. int maintainPlan1ID=-1;
  99. int maintainPlan2ID=-1;
  100. int maintainPlan3ID=-1;
  101. int maintainPlan4ID=-1;
  102. int maintainPlan5ID=-1;
  103.  
  104. int maintainVillagerID=-1;
  105.  
  106. int maintainMythPlan1ID=-1;
  107. int maintainMythPlan2ID=-1;
  108.  
  109. int maintainHeroPlan1ID=-1;
  110. int maintainHeroPlan2ID=-1;
  111.  
  112. int maintainSiegePlanID=-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 gatherPointEast=kbGetBlockPosition("2442");
  187.     vector gatherPointWest=kbGetBlockPosition("2455");
  188.        
  189.     //Setup attack path 1 - go east
  190.    attackPath1ID=kbPathCreate("Attack Path 1");
  191.    kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("2443"));
  192.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("2444"));
  193.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("2445"));
  194.    //Create attack route 1.
  195.    attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", gatherPointEast, kbGetBlockPosition("2449"));
  196.    
  197.     if (attackRoute1ID >= 0)
  198.       kbAttackRouteAddPath(attackRoute1ID, attackPath1ID);
  199.  
  200.    //Setup attack path 2 - go west
  201.    attackPath2ID=kbPathCreate("Attack Path 2");
  202.    kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("2446"));
  203.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("2447"));
  204.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("2450"));
  205.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("2453"));
  206.    //Create attack route 2.
  207.    attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", gatherPointWest, kbGetBlockPosition("2454"));
  208.    
  209.     if (attackRoute2ID >= 0)
  210.       kbAttackRouteAddPath(attackRoute2ID, attackPath2ID);
  211. }
  212.  
  213. //==============================================================================
  214. // setupHumanAttack (human fun)
  215. //==============================================================================
  216. bool setupHumanAttack(int playerID=-1)
  217. {
  218.     // Difficulty Level check.
  219.     int difflevel=-1;        
  220.     difflevel=aiGetWorldDifficulty();
  221.  
  222.     int randomPath=aiRandInt(2);
  223.    
  224.     //Info.
  225.     aiEcho("Attacking Player "+playerID+".");
  226.  
  227.    //If the player to attack doesn't match, init the attack.
  228.    if (attackPlayerID != playerID)
  229.    {
  230.       initAttack(playerID);
  231.       if (attackPlayerID < 0)
  232.          return(false);
  233.    }
  234.  
  235.    //Create an attack plan.
  236.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  237.    if (newAttackPlanID < 0)
  238.       return(false);
  239.  
  240.    //Target player (required).  This must work.
  241.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  242.       return(false);
  243.  
  244.    //Gather points.
  245.     vector gatherPointEast=kbGetBlockPosition("2442");
  246.     vector gatherPointWest=kbGetBlockPosition("2455");
  247.  
  248.     //Set the target type.  This must work.
  249.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  250.       return(false);
  251.  
  252.    //Unit types to attack.
  253.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  254.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  255.  
  256.    //Attack route.
  257.    if (randomPath == 0)
  258.     {
  259.         aiEcho("Attack Going East.");
  260.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID);
  261.         aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPointEast);
  262.     }
  263.    else
  264.     {
  265.         aiEcho("Attack Going West.");
  266.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID);
  267.         aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPointWest);
  268.     }
  269.  
  270.    //Set the gather point and gather point distance.
  271.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 50.0);
  272.  
  273.    //Set up the attack route usage pattern.
  274.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  275.    
  276.     //Add the unit types to the plan.
  277.    aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID1, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize);
  278.     if ( difflevel > 0 )
  279.     {
  280.         aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, attackMinimumGroupSize, attackMaximumGroupSize, attackMaximumGroupSize);
  281.     }
  282.  
  283.     // Myth units if available...fewer on easy.
  284.     if ( difflevel > 0 )
  285.     {
  286.         aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID2, 0, 4, 4);
  287.         aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID3, 0, 2, 2);
  288.     }
  289.     else
  290.     {
  291.         aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID2, 0, 1, 1);
  292.         aiPlanAddUnitType(newAttackPlanID, attackerMythTypeID3, 0, 1, 1);
  293.     }
  294.  
  295.     // Both heroes if available, except on easy.
  296.     if ( difflevel > 0 )
  297.     {
  298.         aiPlanAddUnitType(newAttackPlanID, attackerHeroTypeID1, 0, 1, 1);
  299.         aiPlanAddUnitType(newAttackPlanID, attackerHeroTypeID2, 0, 1, 1);
  300.     }
  301.  
  302.     // Siege towers if available
  303.     if ( difflevel > 0 )
  304.     {
  305.         aiPlanAddUnitType(newAttackPlanID, attackerSiegeTypeID2, 0, 2, 2);
  306.     }
  307.     else
  308.     {
  309.         aiPlanAddUnitType(newAttackPlanID, attackerSiegeTypeID2, 0, 1, 1);
  310.     }
  311.     
  312.    //Set the initial position.
  313.    if (randomPath == 0)
  314.     {
  315.        aiPlanSetInitialPosition(newAttackPlanID, gatherPointEast);
  316.     }
  317.     else
  318.     {
  319.         aiPlanSetInitialPosition(newAttackPlanID, gatherPointWest);
  320.     }
  321.  
  322.    //Plan requires all need units to work (can be false).
  323.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  324.    //Activate the plan.
  325.    aiPlanSetActive(newAttackPlanID);
  326.  
  327.    //Now, save the attack plan ID appropriately.
  328.    aiPlanSetOrphan(attackPlan1ID, true);
  329.    attackPlan1ID=newAttackPlanID;
  330.  
  331.    //Increment our overall number of attacks.
  332.    numberAttacks++;
  333. }
  334.  
  335. //==============================================================================
  336. // Attack Generator 1 - Mixed group of human units
  337. //==============================================================================
  338. rule attackGeneratorHuman
  339.    minInterval 115
  340.    inactive
  341.    group AttackRules
  342.    runImmediately
  343. {
  344.    //See how many "idle" attack plans we have.  Don't create any more if we have
  345.    //idle plans.
  346.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  347.  
  348.    if (numberIdleAttackPlans > 0)
  349.       return;
  350.  
  351.    // If we have enough unassigned military units, create a new attack plan.
  352.     // Hoplites are the primary unit.
  353.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID1);
  354.    aiEcho("There are "+numberAvailableUnits+" hoplites available for a new attack.");
  355.    
  356.     if (numberAvailableUnits >= attackMinimumGroupSize)
  357.         setupHumanAttack(1);
  358. }
  359.  
  360. //==============================================================================
  361. // Attack enablers - enable attacks after initial timers expire
  362. //==============================================================================
  363. /*
  364. // Axemen
  365. rule attack1Enabler
  366.    minInterval 240
  367.    active
  368.    group AttackRules
  369. {
  370.    xsEnableRule("attackGenerator1");
  371.    xsDisableSelf();
  372. }
  373. */
  374.  
  375. //==============================================================================
  376. // Tech Researching Rules - medium axemen, medium slingers, medium spearmen
  377. //==============================================================================
  378. /*
  379. rule researchMediumAxemen
  380.    minInterval 600
  381.    active
  382. {
  383.    int planID=aiPlanCreate("Medium Axemen research at ten minutes.", cPlanResearch);
  384.    if (planID < 0)
  385.       return;
  386.  
  387.    aiPlanSetVariableInt(planID, cResearchPlanTechID, 0, cTechMediumAxemen);
  388.    aiPlanSetVariableInt(planID, cResearchPlanBuildingTypeID, 0, cUnitTypeBarracks);
  389.    aiPlanSetActive(planID);
  390.    
  391.     //Done.
  392.    xsDisableSelf();
  393. }
  394. */
  395.  
  396. //==============================================================================
  397. // Favor cheat - favor every so often.
  398. //==============================================================================
  399. rule favorCheat
  400.    minInterval 40
  401.    active
  402.    group AttackRules
  403. {
  404.     // Cheat for favor.  That Gargarensis is a bastard.
  405.     aiResourceCheat( 2, cResourceFavor, 20.0 );
  406. }
  407.  
  408.  
  409. //==============================================================================
  410. // RULE repairBuildings
  411. //==============================================================================
  412. rule repairBuildings
  413.    minInterval 10
  414.    inactive
  415. {
  416.    int buildingID = kbFindBestBuildingToRepair(kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID)), 100.0, 1.0, cUnitTypeBuilding);
  417.    if(buildingID >= 0)
  418.    {
  419.       //-- Don't create another plan for the same building.
  420.       if(aiPlanGetIDByTypeAndVariableType(cPlanRepair, cRepairPlanTargetID, buildingID, true) >= 0)
  421.          return;
  422.       
  423.       //Create the plan.
  424.       static int num=0;
  425.       num = num + 1;
  426.       string planName="Repair_"+num;
  427.       int planID=aiPlanCreate(planName, cPlanRepair);
  428.       if (planID < 0)
  429.          return;
  430.  
  431.       aiPlanSetDesiredPriority(planID, 30);
  432.       aiPlanSetVariableInt(planID, cRepairPlanTargetID, 0, buildingID);
  433.       aiPlanAddUnitType(planID, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 0, 3, 3);
  434.       aiPlanSetActive(planID);
  435.    }
  436. }
  437.  
  438. //=====================================================================================
  439. // Player has Plenties!  Once the player has destroyed a fortress, this AI FUNC
  440. // fires and the Temple Mount AI kicks into high gear and starts attacking.
  441. //
  442. // Don't ask why this is called what it is.  It's a long story.   :)
  443. //
  444. // Also forward-builds walls and adds a couple of towers to the rear.  
  445. // DAL: This may end up being a difficulty-dependent thing.
  446. //=====================================================================================
  447. void playerHasPlenties(int scriptCall = -1)
  448. {
  449.     aiEcho("*** PLAYER 2: HP has destroyed a forward fortress ***");
  450.  
  451.     // Start launching attacks.
  452.     xsEnableRule("attackGeneratorHuman");
  453.  
  454.     // Start maintaining myth units.
  455.     vector gatherPointTemple=kbGetBlockPosition("2458");
  456.     vector gatherPointSiege=kbGetBlockPosition("2512");
  457.  
  458.     vector Wall1Point1=kbGetBlockPosition("2916");
  459.     vector Wall1Point2=kbGetBlockPosition("2917");
  460.  
  461.     vector Wall2Point1=kbGetBlockPosition("2918");
  462.     vector Wall2Point2=kbGetBlockPosition("2919");
  463.  
  464.     vector TowerPoint1=kbGetBlockPosition("2918");
  465.     vector TowerPoint2=kbGetBlockPosition("2919");
  466.     
  467.    //Maintain Nemean Lions (4)
  468.    maintainMythPlan1ID=aiPlanCreate("Maintain 4 "+kbGetProtoUnitName(attackerMythTypeID2), cPlanTrain);
  469.    if (maintainMythPlan1ID >= 0)
  470.    {
  471.         //Must set the type of unit to train. 
  472.       aiPlanSetVariableInt(maintainMythPlan1ID, cTrainPlanUnitType, 0, attackerMythTypeID2);
  473.       //You can limit the number of units that are ever trained by this plan with this call.
  474.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  475.       //Set the number of units to maintain in the world at one time.
  476.       aiPlanSetVariableInt(maintainMythPlan1ID, cTrainPlanNumberToMaintain, 0, 4);
  477.       //Don't train units too fast
  478.       aiPlanSetVariableInt(maintainMythPlan1ID, cTrainPlanFrequency, 0, 90);
  479.       //Set a gather point.
  480.       aiPlanSetVariableVector(maintainMythPlan1ID, cTrainPlanGatherPoint, 0, gatherPointTemple);
  481.       //Activate the plan.
  482.       aiPlanSetActive(maintainMythPlan1ID);
  483.    }
  484.  
  485.     //Maintain Colossi (2)
  486.    maintainMythPlan2ID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerMythTypeID3), cPlanTrain);
  487.    if (maintainMythPlan2ID >= 0)
  488.    {
  489.         //Must set the type of unit to train.
  490.       aiPlanSetVariableInt(maintainMythPlan2ID, cTrainPlanUnitType, 0, attackerMythTypeID3);
  491.       //You can limit the number of units that are ever trained by this plan with this call.
  492.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  493.       //Set the number of units to maintain in the world at one time.
  494.       aiPlanSetVariableInt(maintainMythPlan2ID, cTrainPlanNumberToMaintain, 0, 2);
  495.       //Don't train units too fast
  496.       aiPlanSetVariableInt(maintainMythPlan2ID, cTrainPlanFrequency, 0, 70);
  497.       //Set a gather point.
  498.       aiPlanSetVariableVector(maintainMythPlan2ID, cTrainPlanGatherPoint, 0, gatherPointTemple);
  499.       //Activate the plan.
  500.       aiPlanSetActive(maintainMythPlan2ID);
  501.    }
  502.  
  503.     //Maintain Siege Things (2)
  504.    maintainSiegePlanID=aiPlanCreate("Maintain 2 "+kbGetProtoUnitName(attackerSiegeTypeID2), cPlanTrain);
  505.    if (maintainMythPlan2ID >= 0)
  506.    {
  507.         //Must set the type of unit to train.
  508.       aiPlanSetVariableInt(maintainSiegePlanID, cTrainPlanUnitType, 0, attackerSiegeTypeID2);
  509.       //You can limit the number of units that are ever trained by this plan with this call.
  510.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  511.       //Set the number of units to maintain in the world at one time.
  512.       aiPlanSetVariableInt(maintainSiegePlanID, cTrainPlanNumberToMaintain, 0, 2);
  513.       //Don't train units too fast
  514.       aiPlanSetVariableInt(maintainSiegePlanID, cTrainPlanFrequency, 0, 120);
  515.       //Set a gather point.
  516.       aiPlanSetVariableVector(maintainSiegePlanID, cTrainPlanGatherPoint, 0, gatherPointSiege);
  517.       //Activate the plan.
  518.       aiPlanSetActive(maintainSiegePlanID);
  519.    }
  520.  
  521.     // Tasty Villager-on-Villager action.  Mmm, lovin' that.
  522.     // Build a wall.  Or two.
  523.     // DAL - removed for now.
  524.     /*
  525.     aiWallFromAToB("Build Wall 1", Wall1Point1, Wall1Point2, 1, 1, 1, cRootEscrowID, 1 );
  526.     aiWallFromAToB("Build Wall 2", Wall2Point1, Wall2Point2, 1, 1, 1, cRootEscrowID, 1 );
  527.     */
  528.     
  529.    //-- Build a tower
  530.     /*
  531.    int buildTower1 = aiPlanCreate("Build Tower 1", cPlanBuild);
  532.    if(buildTower1 >= 0)
  533.    {
  534.       //BP Type and Priority.
  535.       aiPlanSetVariableInt(buildTower1, cBuildPlanBuildingTypeID, 0, cUnitTypeTower);
  536.       aiPlanSetDesiredPriority(buildTower1, 40);
  537.       aiPlanSetVariableVector(buildTower1, cBuildPlanCenterPosition, 0, TowerPoint1);
  538.         aiPlanSetVariableFloat(buildTower1, cBuildPlanCenterPositionDistance, 0, 10);
  539.       aiPlanAddUnitType(buildTower1, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 1, 1, 1);
  540.       aiPlanSetEscrowID(buildTower1, cRootEscrowID);
  541.       aiPlanSetActive(buildTower1);
  542.    }
  543.  
  544.    //-- Build another tower
  545.    int buildTower2 = aiPlanCreate("Build Tower 2", cPlanBuild);
  546.    if(buildTower2 >= 0)
  547.    {
  548.       //BP Type and Priority.
  549.       aiPlanSetVariableInt(buildTower2, cBuildPlanBuildingTypeID, 0, cUnitTypeTower);
  550.       aiPlanSetDesiredPriority(buildTower2, 40);
  551.       aiPlanSetVariableVector(buildTower2, cBuildPlanCenterPosition, 0, TowerPoint2);
  552.         aiPlanSetVariableFloat(buildTower2, cBuildPlanCenterPositionDistance, 0, 10);
  553.       aiPlanAddUnitType(buildTower2, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 1, 1, 1);
  554.       aiPlanSetEscrowID(buildTower2, cRootEscrowID);
  555.       aiPlanSetActive(buildTower2);
  556.    }
  557.     */
  558.  
  559.     // Repair stuff with all the villagers once you're done building stuff (in theory).
  560.     xsEnableRule("repairBuildings");
  561. }
  562.  
  563. //==============================================================================
  564. // Maintain stuff - separated out for sanity's sake.
  565. //==============================================================================
  566. void maintainStuff(void)
  567. {
  568.    //Share a common gather point.
  569.     vector gatherPointAcademy=kbGetBlockPosition("2456");
  570.     vector gatherPointArcheryRange=kbGetBlockPosition("2457");
  571.    vector gatherPointTemple=kbGetBlockPosition("2458");
  572.     vector gatherPointHero=kbGetBlockPosition("2512");
  573.  
  574.     vector gatherPointVillager=kbGetBlockPosition("2922");
  575.  
  576.     //Share the number to maintain.
  577.    int numberToMaintain=attackMinimumGroupSize*2;
  578.  
  579.    //Maintain hoplites (base #)
  580.    maintainPlan1ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain);
  581.    if (maintainPlan1ID >= 0)
  582.    {
  583.         //Must set the type of unit to train. 
  584.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1);
  585.       //You can limit the number of units that are ever trained by this plan with this call.
  586.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  587.       //Set the number of units to maintain in the world at one time.
  588.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  589.       //Don't train units too fast
  590.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 30);
  591.       //Set a gather point.
  592.       aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointAcademy);
  593.       //Activate the plan.
  594.       aiPlanSetActive(maintainPlan1ID);
  595.    }
  596.  
  597.     //Maintain toxotes (base #)
  598.    maintainPlan3ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID3), cPlanTrain);
  599.    if (maintainPlan3ID >= 0)
  600.    {
  601.         //Must set the type of unit to train. 
  602.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeID3);
  603.       //You can limit the number of units that are ever trained by this plan with this call.
  604.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  605.       //Set the number of units to maintain in the world at one time.
  606.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
  607.       //Don't train units too fast
  608.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 35);
  609.       //Set a gather point.
  610.       aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPointArcheryRange);
  611.       //Activate the plan.
  612.       aiPlanSetActive(maintainPlan3ID);
  613.    }
  614.  
  615.     //Maintain hypaspists(12)
  616.    maintainPlan4ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID4), cPlanTrain);
  617.    if (maintainPlan4ID >= 0)
  618.    {
  619.         //Must set the type of unit to train.
  620.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanUnitType, 0, attackerUnitTypeID4);
  621.       //You can limit the number of units that are ever trained by this plan with this call.
  622.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  623.       //Set the number of units to maintain in the world at one time.
  624.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, 12);
  625.       //Don't train units too fast
  626.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 45);
  627.       //Set a gather point.
  628.       aiPlanSetVariableVector(maintainPlan4ID, cTrainPlanGatherPoint, 0, gatherPointAcademy);
  629.       //Activate the plan.
  630.       aiPlanSetActive(maintainPlan4ID);
  631.    }
  632.     
  633.     //Maintain peltasts(8)
  634.    maintainPlan5ID=aiPlanCreate("Maintain "+numberToMaintain+" "+kbGetProtoUnitName(attackerUnitTypeID4), cPlanTrain);
  635.    if (maintainPlan5ID >= 0)
  636.    {
  637.         //Must set the type of unit to train.
  638.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanUnitType, 0, attackerUnitTypeID5);
  639.       //You can limit the number of units that are ever trained by this plan with this call.
  640.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  641.       //Set the number of units to maintain in the world at one time.
  642.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanNumberToMaintain, 0, 8);
  643.       //Don't train units too fast
  644.       aiPlanSetVariableInt(maintainPlan5ID, cTrainPlanFrequency, 0, 55);
  645.       //Set a gather point.
  646.       aiPlanSetVariableVector(maintainPlan5ID, cTrainPlanGatherPoint, 0, gatherPointArcheryRange);
  647.       //Activate the plan.
  648.       aiPlanSetActive(maintainPlan5ID);
  649.    }
  650.  
  651.     // Hero Maintain Plans
  652.    maintainHeroPlan1ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerHeroTypeID1), cPlanTrain);
  653.    if (maintainHeroPlan1ID >= 0)
  654.    {
  655.         //Must set the type of unit to train.
  656.       aiPlanSetVariableInt(maintainHeroPlan1ID, cTrainPlanUnitType, 0, attackerHeroTypeID1);
  657.       //You can limit the number of units that are ever trained by this plan with this call.
  658.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  659.       //Set the number of units to maintain in the world at one time.
  660.       aiPlanSetVariableInt(maintainHeroPlan1ID, cTrainPlanNumberToMaintain, 0, 1);
  661.       //Don't train units too fast
  662.       aiPlanSetVariableInt(maintainHeroPlan1ID, cTrainPlanFrequency, 0, 105);
  663.       //Set a gather point.
  664.       aiPlanSetVariableVector(maintainHeroPlan1ID, cTrainPlanGatherPoint, 0, gatherPointHero);
  665.       //Activate the plan.
  666.       aiPlanSetActive(maintainHeroPlan1ID);
  667.    }
  668.  
  669.    maintainHeroPlan2ID=aiPlanCreate("Maintain "+kbGetProtoUnitName(attackerHeroTypeID2), cPlanTrain);
  670.    if (maintainHeroPlan2ID >= 0)
  671.    {
  672.         //Must set the type of unit to train.
  673.       aiPlanSetVariableInt(maintainHeroPlan2ID, cTrainPlanUnitType, 0, attackerHeroTypeID2);
  674.       //You can limit the number of units that are ever trained by this plan with this call.
  675.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  676.       //Set the number of units to maintain in the world at one time.
  677.       aiPlanSetVariableInt(maintainHeroPlan2ID, cTrainPlanNumberToMaintain, 0, 1);
  678.       //Don't train units too fast
  679.       aiPlanSetVariableInt(maintainHeroPlan2ID, cTrainPlanFrequency, 0, 140);
  680.       //Set a gather point.
  681.       aiPlanSetVariableVector(maintainHeroPlan2ID, cTrainPlanGatherPoint, 0, gatherPointHero);
  682.       //Activate the plan.
  683.       aiPlanSetActive(maintainHeroPlan2ID);
  684.    }
  685.  
  686.    maintainVillagerID=aiPlanCreate("Maintain "+kbGetProtoUnitName(cUnitTypeVillagerGreek), cPlanTrain);
  687.    if (maintainHeroPlan2ID >= 0)
  688.    {
  689.         //Must set the type of unit to train.
  690.       aiPlanSetVariableInt(maintainVillagerID, cTrainPlanUnitType, 0, cUnitTypeVillagerGreek);
  691.       //You can limit the number of units that are ever trained by this plan with this call.
  692.         // After nine total villagers, don't build any more ever.
  693.       aiPlanSetVariableInt(maintainVillagerID, cTrainPlanNumberToTrain, 0, 3);
  694.       //Set the number of units to maintain in the world at one time - three should do it.
  695.       aiPlanSetVariableInt(maintainVillagerID, cTrainPlanNumberToMaintain, 0, 3);
  696.       //Don't train units too fast
  697.       aiPlanSetVariableInt(maintainVillagerID, cTrainPlanFrequency, 0, 10);
  698.       //Set a gather point.
  699.       aiPlanSetVariableVector(maintainVillagerID, cTrainPlanGatherPoint, 0, gatherPointVillager);
  700.       //Activate the plan.
  701.       aiPlanSetActive(maintainVillagerID);
  702.    }
  703.  
  704. }
  705.  
  706. //==============================================================================
  707. // Defend plan excitement.
  708. //==============================================================================
  709. void defendPlanSetup(void)
  710. {
  711.     // Six hypaspists at each of the defend locations.
  712.    int defendPlan1ID=aiPlanCreate("East Defense", cPlanDefend);
  713.    if (defendPlan1ID >= 0)
  714.    {
  715.       //Main gate location
  716.       vector eastChoke=kbGetBlockPosition("2443");
  717.  
  718.       //Add the unit(s).
  719.       aiPlanAddUnitType(defendPlan1ID, attackerUnitTypeID4, 0, 6, 6);
  720.         aiPlanAddUnitType(defendPlan1ID, attackerUnitTypeID5, 0, 4, 4);
  721.         
  722.       //Setup the vars.
  723.       aiPlanSetDesiredPriority(defendPlan1ID, 40);
  724.       aiPlanSetVariableVector(defendPlan1ID, cDefendPlanDefendPoint, 0, eastChoke);
  725.       aiPlanSetVariableFloat(defendPlan1ID, cDefendPlanEngageRange, 0, 20);
  726.       aiPlanSetActive(defendPlan1ID);
  727.     }
  728.  
  729.    int defendPlan2ID=aiPlanCreate("West Defense", cPlanDefend);
  730.    if (defendPlan2ID >= 0)
  731.    {
  732.       //Main gate location
  733.       vector westChoke=kbGetBlockPosition("2446");
  734.  
  735.       //Add the unit(s).
  736.       aiPlanAddUnitType(defendPlan2ID, attackerUnitTypeID4, 0, 6, 6);
  737.         aiPlanAddUnitType(defendPlan2ID, attackerUnitTypeID5, 0, 4, 4);
  738.         
  739.       //Setup the vars.
  740.       aiPlanSetDesiredPriority(defendPlan2ID, 40);
  741.         aiPlanSetVariableVector(defendPlan2ID, cDefendPlanDefendPoint, 0, westChoke);
  742.       aiPlanSetVariableFloat(defendPlan2ID, cDefendPlanEngageRange, 0, 20);
  743.       aiPlanSetActive(defendPlan2ID);
  744.     }
  745.  
  746.     // A single evil Titan defending at the gate
  747.    int defendPlan3ID=aiPlanCreate("Titan Defense", cPlanDefend);
  748.    if (defendPlan3ID >= 0)
  749.    {
  750.       //Main gate location
  751.       vector theGate=kbGetBlockPosition("2511");
  752.  
  753.       //Add the unit(s).
  754.       aiPlanAddUnitType(defendPlan3ID, cUnitTypeTitanBad, 1, 1, 1);
  755.         
  756.       //Setup the vars.
  757.       aiPlanSetDesiredPriority(defendPlan3ID, 90);
  758.         aiPlanSetVariableVector(defendPlan3ID, cDefendPlanDefendPoint, 0, theGate);
  759.       aiPlanSetVariableFloat(defendPlan3ID, cDefendPlanEngageRange, 0, 25);
  760.         aiPlanSetUnitStance(defendPlan3ID, cUnitStanceDefensive);
  761.         aiPlanSetAllowUnderAttackResponse(defendPlan3ID, false);
  762.       aiPlanSetActive(defendPlan3ID);
  763.     }
  764. }
  765.  
  766. //==============================================================================
  767. // MAIN
  768. //==============================================================================
  769. void main(void)
  770. {
  771.     // Difficulty Level check.
  772.     int difflevel=-1;        
  773.     difflevel=aiGetWorldDifficulty();
  774.  
  775.    //Startup.
  776.    miscStartup();
  777.     
  778.     //Set up maintain plans.
  779.     maintainStuff();
  780.  
  781.     // Set up a couple of defend plans.
  782.     defendPlanSetup();
  783.  
  784.     // Difflevel adjustments.
  785.     if ( difflevel < 1 )
  786.     {
  787.         xsSetRuleMinInterval( "favorCheat", 90 );
  788.     }
  789.  
  790.     if ( difflevel == 3 )
  791.     {
  792.         xsSetRuleMinInterval( "favorCheat", 20 );
  793.         xsSetRuleMinInterval("attackGeneratorHuman", 75);
  794.         aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 20);
  795.         aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 20);
  796.         aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 15);
  797.         aiPlanSetVariableInt(maintainHeroPlan2ID, cTrainPlanFrequency, 0, 40);
  798.         aiPlanSetVariableInt(maintainMythPlan1ID, cTrainPlanFrequency, 0, 45);
  799.     }
  800. }