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

  1. //==============================================================================
  2. // Scn08p2: AI Scenario Script for scenario 8 player 2
  3. //==============================================================================
  4. /*
  5.    AI owner:  Mike Kidd
  6.    Scenario owner: Jeff Brown
  7.  
  8.    Overview:
  9.    The human player rescues Ajax from the Trojan army, then joins forces at the 
  10.    allied TC.  His goal is to build up and take out the red town to the north, without
  11.    the availability of siege units.
  12.  
  13.    The CP sends one trivial attack early, which dies hopelessly to the HP's huge 
  14.    army left over from the start.  Several of the following attack rules are currently 
  15.    implementedby triggers which attempt to build military buildings near
  16.    the HP's town.
  17.    
  18.    The CP attacks down any one of three channels, with the west channel reserved for 
  19.    higher difficulty levels.
  20.  
  21.    No attempt is made to train units out of the forward buildings, even if the 
  22.    feeble attempt to build succeeds.  If the forward building concept stays in, we should
  23.    add rules to make a local army out of each building and use them for extra attacks.   
  24.  
  25.    CP starts as age 2 with Animal Magnet (not used) and Pestilence.
  26.    Age 3: Aphrodite: Curse
  27.    Age 4: Hephaestus: Plenty
  28.      
  29.    Difficulty:  First try on 7/9/2002.  Deactivated the entire attack rule chain,
  30.    jumped straight to attack generator.
  31.  
  32.    Defend plan added 7/19/2002.
  33.  
  34.    Increased Titan difficulty on 9/10/2002.
  35.  
  36.    9/17/2002:  Tweaked titan back down a touch.
  37. */
  38. //==============================================================================
  39.  
  40.  
  41. include "scn lib.xs";
  42.  
  43. // Globals
  44. int         lastAttackPlanID = -1;        // Updated with plan ID as each attack is launched
  45. int         defendPlan = -1;
  46. int         reservePlan = -1;             // Extra defend plan, higher priority, for final resistance
  47.  
  48. int         startTime = -1;               // Updated with start time when cinematic is done.  In seconds.
  49. int         age3Time = 1500;               // Time (in seconds) to go to age 3
  50. int         age4Time = 10000;              
  51.  
  52. int         siegeMaintainPlan = -1;
  53. int         mythMaintainPlan = -1;
  54. int         hopliteMaintainPlan = -1;
  55. int         toxotesMaintainPlan = -1;
  56. int         hippikonMaintainPlan = -1;
  57. int         villagerMaintainPlan = -1;
  58.  
  59. int         routeWestPass = -1;
  60. int         routeNorthPass = -1;
  61. int         routeEastPass = -1;
  62.  
  63. // Initial settings are for the easiest difficulty level, others are set in main().
  64. int         nextAttackTime = 480000;     // 8 minutes
  65. float       attackSize = 4.0; 
  66. float       maxAttackSize = 9.0;
  67. float       attackSizeMultiplier = 1.2; 
  68. int         attackInterval = 300000;      // 5 minutes
  69. float       reserveSize = 15.0;           // Army to keep in reserve
  70. int         attackCount = 0;
  71. int         trainDelay = 30;
  72. int         cavTrainDelay = 30;
  73. int         archerTrainDelay = 15;
  74. int         infantryTrainDelay = 20;
  75.  
  76. int builderQty = 1;     // For forward building
  77. int defendQty = 0;      // For escort group
  78.  
  79. // Cinematic block markers
  80. const string cbVillagerGather = "1872";
  81. const string cbSiegeGather = "1873";
  82. const string cbArcherGather = "1878";
  83. const string cbCavalryGather = "1874";
  84. const string cbInfantryGather = "1875";
  85. const string cbP2TC = "1876";
  86. const string cbGateEast = "1826";
  87. const string cbGateWest = "1827";
  88. const string cbWestPass1 = "1833";
  89. const string cbWestPass2 = "1832";
  90. const string cbNorthWestPlateau = "1834";
  91. const string cbNorthEastPlateau = "1835";
  92. const string cbP1Gold = "1831";
  93. const string cbP1Granary = "1830";
  94. const string cbSouthField = "1877";
  95. const string cbEastPass1 = "1828";
  96. const string cbEastPass2 = "1829";
  97. const string cbP1TC = "1836";
  98. const string cbNorthPass = "2272";
  99. const string cbAttack2Stable = "1882";
  100. const string cbAttack2Army = "1883";
  101. const string cbAttack5Tower = "1880";
  102. const string cbAttack3Army = "1881";
  103.  
  104. // Econ 
  105. int   maxVills = 20;        // Will scale with difficulty
  106. int   maxFishBoats = 0;    // Including one to scout
  107. float goldPercent = 0.25;
  108. float woodPercent = 0.15;
  109. float foodPercent = 0.60;
  110. int   gathererTypeID = -1;
  111. int   fishGatherer = -1;
  112. int   mainBase = -1;
  113. float mainRadius = 100.0;
  114.  
  115.  
  116. // *****************************************************************************
  117. //
  118. // Building plan support for forward building
  119. //
  120. // *****************************************************************************
  121. int buildPlan = -1;
  122. int buildDefend = -1;
  123. // Set the following four vars, then just enable testBuildPlan.
  124. int buildUnit = cUnitTypeTower;
  125. vector buildVec = cInvalidVector;
  126. vector startPoint = cInvalidVector;
  127.  
  128. rule buildPlanRule
  129.    inactive
  130. {
  131.  
  132.    buildPlan = aiPlanCreate("Build Plan", cPlanBuild);
  133.    if(buildPlan >= 0)
  134.    {
  135.       aiPlanSetVariableInt(buildPlan, cBuildPlanBuildingTypeID, 0, buildUnit);
  136.       aiPlanSetDesiredPriority(buildPlan, 40);
  137.       aiPlanSetVariableVector(buildPlan, cBuildPlanCenterPosition, 0, buildVec);
  138.       aiPlanSetInitialPosition(buildPlan, startPoint);
  139.         aiPlanSetVariableFloat(buildPlan, cBuildPlanCenterPositionDistance, 0, 12);
  140.       aiPlanAddUnitType(buildPlan, kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionBuilder, 0), 1, builderQty, builderQty);
  141.       aiPlanSetEscrowID(buildPlan, cRootEscrowID);
  142.       aiPlanSetInitialPosition(buildPlan, buildVec);
  143.       aiPlanSetActive(buildPlan);
  144.    }
  145.  
  146.    buildDefend =aiPlanCreate("Build Defend Plan", cPlanDefend);
  147.    if (buildDefend >= 0)
  148.    {
  149.       aiPlanAddUnitType(buildDefend, cUnitTypeMilitary, 0, defendQty, defendQty);    
  150.       aiPlanSetDesiredPriority(buildDefend, 60);                       // Above other defend plans
  151.       aiPlanSetVariableVector(buildDefend, cDefendPlanDefendPoint, 0, buildVec);
  152.       aiPlanSetVariableFloat(buildDefend, cDefendPlanEngageRange, 0, 15);
  153.       aiPlanSetVariableBool(buildDefend, cDefendPlanPatrol, 0, false);
  154.       aiPlanSetVariableFloat(buildDefend, cDefendPlanGatherDistance, 0, 8.0);
  155.       aiPlanSetInitialPosition(buildDefend, kbGetBlockPosition(cbInfantryGather));
  156.       aiPlanSetUnitStance(buildDefend, cUnitStanceDefensive);
  157.  
  158.       aiPlanSetVariableInt(buildDefend, cDefendPlanRefreshFrequency, 0, 5);
  159.       aiPlanSetNumberVariableValues(buildDefend, cDefendPlanAttackTypeID, 2, true);
  160.       aiPlanSetVariableInt(buildDefend, cDefendPlanAttackTypeID, 0, cUnitTypeUnit);
  161.       aiPlanSetVariableInt(buildDefend, cDefendPlanAttackTypeID, 1, cUnitTypeBuilding);
  162.       
  163.       aiPlanSetActive(buildDefend); 
  164.       aiEcho("Creating defend plan");
  165.    }
  166.    xsEnableRule("endBuildDefend");
  167.    xsDisableSelf();
  168. }
  169.  
  170. rule endBuildDefend
  171.    inactive
  172.    minInterval 7
  173. {
  174.    aiEcho("Build Plan state is "+aiPlanGetState(buildPlan));
  175.    if (aiPlanGetState(buildPlan) == -1)
  176.    {
  177.       aiPlanDestroy(buildDefend);
  178.       aiEcho("Destroying build defend plan");
  179.       xsDisableSelf();
  180.    }
  181. }
  182.  
  183.  
  184.  
  185.  
  186.  
  187. // *****************************************************************************
  188. //
  189. //                                FUNCTIONS
  190. //
  191. // *****************************************************************************
  192.  
  193.  
  194. void age2EventHandler(int bogus=-1)
  195. {
  196.    xsEnableRule("usePestilence");
  197.    xsEnableRule("goToAge3");
  198.    xsEnableRule("getAge2UnitUpgrades");
  199.    xsEnableRule("getAge2ArmoryUpgrades");
  200. }
  201.  
  202.  
  203.  
  204. void age3EventHandler(int bogus=-1)
  205. {
  206.    xsEnableRule("useCurse");
  207.    siegeMaintainPlan = maintainUnit(cUnitTypePetrobolos, reserveSize/8, kbGetBlockPosition(cbSiegeGather), 60);
  208.    xsEnableRule("getAge3UnitUpgrades");
  209.    xsEnableRule("getAge3ArmoryUpgrades");
  210. }
  211.  
  212.  
  213. void age4EventHandler(int bogus=-1)
  214. {
  215.    xsEnableRule("usePlenty");
  216.    xsEnableRule("getAge4UnitUpgrades");
  217.    xsEnableRule("getAge4ArmoryUpgrades");
  218.    xsEnableRule("usePlenty");
  219. }
  220.  
  221.  
  222. // Called by a trigger, to let AI know that the game has started
  223. void wakeup(int parm=-1)
  224. {
  225.    startTime = xsGetTime()/1000;
  226.    aiEcho("Wakeup running at "+startTime);
  227.  
  228.    if (kbGetAge() >= cAge2)
  229.       age2EventHandler(0);
  230.    if (kbGetAge() >= cAge3)
  231.       age3EventHandler(0);
  232.    if (kbGetAge() >= cAge4)
  233.       age4EventHandler(0);
  234.  
  235.  
  236. //   xsEnableRule("attack1");
  237.    xsEnableRule("attackGenerator");
  238.    xsEnableRule("scout");
  239. //   villagerMaintainPlan = maintainUnit(cUnitTypeVillagerGreek, 25, kbGetBlockPosition(cbVillagerGather), 20);
  240.    hippikonMaintainPlan = maintainUnit(cUnitTypeHippikon, reserveSize/3, kbGetBlockPosition(cbCavalryGather), cavTrainDelay);
  241.    toxotesMaintainPlan = maintainUnit(cUnitTypeToxotes, reserveSize/3, kbGetBlockPosition(cbArcherGather), archerTrainDelay);
  242.    hopliteMaintainPlan = maintainUnit(cUnitTypeHoplite, reserveSize/3, kbGetBlockPosition(cbInfantryGather), infantryTrainDelay);
  243.  
  244.    // Init low-priority defend plan to manage spare units
  245.    defendPlan =aiPlanCreate("Defend Plan", cPlanDefend);
  246.    if (defendPlan >= 0)
  247.    {
  248.       aiPlanAddUnitType(defendPlan, cUnitTypeMilitary, 0, 200, 200);    // All unassigned mil units
  249.       aiPlanSetDesiredPriority(defendPlan, 10);                       // Way low, below scouting and attack
  250.       aiPlanSetVariableVector(defendPlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbInfantryGather));
  251.       aiPlanSetVariableFloat(defendPlan, cDefendPlanEngageRange, 0, 30);
  252.  
  253.       aiPlanSetVariableFloat(defendPlan, cDefendPlanGatherDistance, 0, 15.0);
  254.       aiPlanSetInitialPosition(defendPlan, kbGetBlockPosition(cbInfantryGather));
  255.       aiPlanSetUnitStance(defendPlan, cUnitStanceDefensive);
  256.  
  257.       aiPlanSetNumberVariableValues(defendPlan, cDefendPlanPatrolWaypoint, 3, true);
  258.       aiPlanSetVariableVector(defendPlan, cDefendPlanPatrolWaypoint, 0, kbGetBlockPosition(cbGateEast));
  259.       aiPlanSetVariableVector(defendPlan, cDefendPlanPatrolWaypoint, 1, kbGetBlockPosition(cbEastPass1));
  260.       aiPlanSetVariableVector(defendPlan, cDefendPlanPatrolWaypoint, 2, kbGetBlockPosition(cbGateWest));
  261.       aiPlanSetVariableBool(defendPlan, cDefendPlanPatrol, 0, true);
  262.  
  263.       aiPlanSetVariableInt(defendPlan, cDefendPlanRefreshFrequency, 0, 5);
  264.       aiPlanSetNumberVariableValues(defendPlan, cDefendPlanAttackTypeID, 2, true);
  265.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit);
  266.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 1, cUnitTypeBuilding);
  267.       
  268.       aiPlanSetActive(defendPlan); 
  269.       aiEcho("Creating defend plan");
  270.    }
  271.  
  272.    // Higher-priority defend plan to reserve units for final push
  273.    reservePlan =aiPlanCreate("Reserve Plan", cPlanDefend);
  274.    if (reservePlan >= 0)
  275.    {
  276.       aiPlanAddUnitType(reservePlan, cUnitTypeMilitary, 0, reserveSize/2, reserveSize/2);    // All unassigned mil units
  277.       aiPlanSetDesiredPriority(reservePlan, 30);                       // Higher than other defend plans
  278.       aiPlanSetVariableVector(reservePlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbP2TC));
  279.       aiPlanSetVariableFloat(reservePlan, cDefendPlanEngageRange, 0, 15);
  280.  
  281.       aiPlanSetVariableFloat(reservePlan, cDefendPlanGatherDistance, 0, 15.0);
  282.       aiPlanSetInitialPosition(reservePlan, kbGetBlockPosition(cbInfantryGather));
  283.       aiPlanSetUnitStance(reservePlan, cUnitStanceDefensive);
  284.  
  285.       aiPlanSetVariableBool(reservePlan, cDefendPlanPatrol, 0, false);
  286.  
  287.       aiPlanSetVariableInt(reservePlan, cDefendPlanRefreshFrequency, 0, 5);
  288.       aiPlanSetNumberVariableValues(reservePlan, cDefendPlanAttackTypeID, 2, true);
  289.       aiPlanSetVariableInt(reservePlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit);
  290.       aiPlanSetVariableInt(reservePlan, cDefendPlanAttackTypeID, 1, cUnitTypeBuilding);
  291.       
  292.       aiPlanSetActive(reservePlan); 
  293.       aiEcho("Creating defend plan");
  294.    }
  295.  
  296.       // Create villager maintain plan
  297.    createSimpleMaintainPlan(gathererTypeID, maxVills, true, mainBase);
  298. }
  299.  
  300.  
  301.  
  302. void initMainBase()
  303. {
  304.    // Nuke bases, add one base to rule them all
  305.    kbBaseDestroyAll(cMyID);
  306.  
  307.    mainBase = kbBaseCreate(cMyID, "Base "+kbBaseGetNextID(), kbGetBlockPosition(cbP2TC), mainRadius);
  308.    if (mainBase < 0)
  309.       aiEcho("***** Main base creation failed. *****");
  310.  
  311.    vector baseFront=xsVectorNormalize(kbGetMapCenter()-kbGetBlockPosition(cbP2TC));     // Set front
  312.    kbBaseSetFrontVector(cMyID, mainBase, baseFront);                 
  313.    kbBaseSetMaximumResourceDistance(cMyID, mainBase, mainRadius+20.0);                    // Gather up to 20m beyond base perimeter
  314.    kbBaseSetMain(cMyID, mainBase, true);     // Make this the main base
  315.  
  316.    // Add the buildings
  317.    int buildingQuery = -1;
  318.    int count = 0;
  319.    buildingQuery = kbUnitQueryCreate("Building Query");     // All buildings in the base
  320.    configQuery(buildingQuery, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, cMyID, kbGetBlockPosition(cbP2TC), false, mainRadius);
  321.    kbUnitQueryResetResults(buildingQuery);
  322.    count = kbUnitQueryExecute(buildingQuery);
  323.  
  324.    int i = 0;
  325.    int buildingID = -1;
  326.    for (i=0; < count)
  327.    {
  328.       buildingID = kbUnitQueryGetResult(buildingQuery, i);
  329.       // Add it to the base
  330.       kbBaseAddUnit( cMyID, mainBase, buildingID );
  331.    }
  332. }
  333.  
  334.  
  335. void initEcon()
  336. {
  337.  
  338.  
  339.  
  340.    aiSetAutoGatherEscrowID(cRootEscrowID);
  341.    aiSetAutoFarmEscrowID(cRootEscrowID);
  342.    gathererTypeID = kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionGatherer,0);
  343.  
  344.    
  345.    int herdPlanID=aiPlanCreate("GatherHerdable Plan", cPlanHerd);
  346.    if (herdPlanID >= 0)
  347.    {
  348.       aiPlanAddUnitType(herdPlanID, cUnitTypeHerdable, 0, 100, 100);
  349.       aiPlanSetVariableInt(herdPlanID, cHerdPlanBuildingTypeID, 0, cUnitTypeSettlementLevel1);
  350.       aiPlanSetActive(herdPlanID);
  351.    }
  352.  
  353.    aiSetResourceGathererPercentageWeight(cRGPScript, 1);
  354.    aiSetResourceGathererPercentageWeight(cRGPCost, 0);
  355.  
  356.    kbSetAICostWeight(cResourceFood, 1.0);
  357.    kbSetAICostWeight(cResourceWood, 0.7);
  358.    kbSetAICostWeight(cResourceGold, 0.8);
  359.    kbSetAICostWeight(cResourceFavor, 7.0);
  360.  
  361.    aiSetResourceGathererPercentage(cResourceFood, foodPercent, false, cRGPScript);
  362.    aiSetResourceGathererPercentage(cResourceWood, woodPercent, false, cRGPScript);
  363.    aiSetResourceGathererPercentage(cResourceGold, goldPercent, false, cRGPScript);
  364.    aiSetResourceGathererPercentage(cResourceFavor, 0.0, false, cRGPScript);
  365.    aiNormalizeResourceGathererPercentages(cRGPScript);
  366.  
  367.    //bool aiSetResourceBreakdown( int resourceTypeID, int resourceSubTypeID, int numberPlans, int planPriority, float percentage, int baseID )
  368. //    aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeEasy, numFoodEasyPlans, 50, 1.0, gMainBaseID);
  369. //   aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeHuntAggressive, numFoodHuntAggressivePlans, 100, 1.0, gMainBaseID);
  370.    aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFish, 1, 50, 1.0, mainBase);
  371.    aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFarm, 1, 50, 1.0, mainBase);
  372.    aiSetResourceBreakdown(cResourceWood, cAIResourceSubTypeEasy, 1, 50, 1.0, mainBase);
  373.     aiSetResourceBreakdown(cResourceGold, cAIResourceSubTypeEasy, 1, 50, 1.0, mainBase);
  374. //   aiSetResourceBreakdown(cResourceFavor, cAIResourceSubTypeEasy, numFavorPlans, 50, 1.0, gMainBaseID);
  375. }
  376.  
  377.  
  378.  
  379.  
  380.  
  381. void main()
  382. {
  383.    aiEcho("Starting Scn08p2.xs");
  384.    kbSetTownLocation(kbGetBlockPosition(cbP2TC));
  385.    aiRandSetSeed();
  386.  
  387.    //Calculate some areas.
  388.    kbAreaCalculate(1200.0);
  389.    aiSetAttackResponseDistance(10.0);
  390.  
  391.    kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0);
  392.    kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0);
  393.    kbEscrowAllocateCurrentResources();
  394.  
  395.  
  396.    initMainBase();    // Destroy all auto-bases, make one manual base for everything
  397.    initEcon();
  398.  
  399.    aiSetAgeEventHandler(cAge2, "age2EventHandler");
  400.    aiSetAgeEventHandler(cAge3, "age3EventHandler");
  401.    aiSetAgeEventHandler(cAge4, "age4EventHandler");
  402.  
  403.    // Create attack routes
  404.    routeWestPass = attackRoute("West Pass",cbGateWest, cbWestPass1, cbWestPass2);
  405.    routeEastPass = attackRoute("East Pass",cbGateEast, cbEastPass1, cbEastPass2);
  406.    routeNorthPass = attackRoute("North Pass", cbGateWest, cbNorthPass, cbP1TC);
  407.  
  408.    switch(aiGetWorldDifficulty())
  409.    {     // ignores 0 (easiest), uses initial values in that case.
  410.    case 1:     // medium
  411.       {
  412.          nextAttackTime = 300000;      // 5 minutes
  413.          attackSize = 6.0; 
  414.          maxAttackSize = 12.0;
  415.          attackSizeMultiplier = 1.2; 
  416.          attackInterval = 240000;      // 4 minutes   
  417.          reserveSize = 20;
  418.          age3Time = 1200;               // Time (in seconds) to go to age 3
  419.          age4Time = 1800; 
  420.          defendQty = 2;
  421.          builderQty = 2;
  422.          trainDelay = 25;
  423.          break;
  424.       }
  425.    case 2:     // difficult/hard
  426.       {
  427.          nextAttackTime = 180000;      // 3 minutes
  428.          attackSize = 8.0; 
  429.          maxAttackSize = 30.0;
  430.          attackSizeMultiplier = 1.2; 
  431.          attackInterval = 180000;      // 3 minutes    
  432.          reserveSize = 35;
  433.          age3Time = 900;               // Time (in seconds) to go to age 3
  434.          age4Time = 1500;                   
  435.          defendQty = 3;
  436.          builderQty = 5;
  437.          trainDelay = 15;
  438.          break;
  439.       }
  440.    case 3:     // hardest/nightmare
  441.       {
  442.          nextAttackTime = 60000;      // 60 sec
  443.          attackSize = 10.0; 
  444.          maxAttackSize = 40.0;
  445.          attackSizeMultiplier = 1.2; 
  446.          attackInterval = 150000;      // 2.5 minutes     
  447.          reserveSize = 45;
  448.          age3Time = 500;               // Time (in seconds) to go to age 3
  449.          age4Time = 900;                   
  450.          defendQty = 6;
  451.          builderQty = 10;
  452.          trainDelay = 10;
  453.          break;
  454.       }
  455.    }
  456.  
  457.    cavTrainDelay = trainDelay;
  458.    archerTrainDelay = trainDelay/2;
  459.    infantryTrainDelay = (2*trainDelay)/3;
  460.  
  461.  
  462. }
  463.  
  464.  
  465. void siegeUnitAttack(vector location=vector(-1,-1,-1), int qty=1)
  466. {
  467.  
  468.    static int attackQuery = -1;
  469.    static int attackQuery2 = -1;
  470.    int   attackID=aiPlanCreate("Mixed Unit Attack at "+timeString(),cPlanAttack);
  471.    if (attackID < 0)
  472.    {
  473.       return;
  474.    }
  475.  
  476.    if (aiPlanSetVariableInt(attackID, cAttackPlanPlayerID, 0, 1) == false)
  477.    {
  478.       return;
  479.    }
  480.  
  481.    if (aiPlanSetNumberVariableValues(attackID, cAttackPlanTargetTypeID, 3, true) == false)
  482.       return;
  483.  
  484.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  485.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  486.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 2, cUnitTypeAbstractWall);
  487.  
  488.    // Set up the attack queries with the appropriate vectors
  489.    if (aiPlanSetNumberVariableValues(attackID, cAttackPlanQueryID, 2, true) == false)
  490.    {
  491.       return;
  492.    }
  493.    if (attackQuery < 0)
  494.    {
  495.       attackQuery = kbUnitQueryCreate("Attack Query");
  496.       configQueryRelation(attackQuery, cUnitTypeUnit, -1, cUnitStateAlive, cPlayerRelationEnemy, location, false, 50);
  497.    }
  498.    else
  499.    {
  500.       kbUnitQuerySetPosition(attackQuery, location);
  501.    }
  502.  
  503.    if (attackQuery2 < 0)
  504.    {
  505.       attackQuery2 = kbUnitQueryCreate("Attack Query #2");
  506.       configQuery(attackQuery2, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, cPlayerRelationEnemy, location, false, 50);
  507.    }
  508.    else
  509.    {
  510.       kbUnitQuerySetPosition(attackQuery2, location);
  511.    }
  512.    aiPlanSetVariableInt(attackID, cAttackPlanQueryID, 0, attackQuery);
  513.    aiPlanSetVariableInt(attackID, cAttackPlanQueryID, 1, attackQuery2);
  514.  
  515.  
  516.    if (aiRandInt(2) == 0)
  517.       aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeNorthPass);
  518.    else
  519.       aiPlanSetVariableInt(attackID, cAttackPlanAttackRouteID, 0, routeEastPass);
  520.  
  521.  
  522.    aiPlanSetVariableVector(attackID, cAttackPlanGatherPoint, 0, kbGetBlockPosition(cbInfantryGather));
  523.    aiPlanSetVariableFloat(attackID, cAttackPlanGatherDistance, 0, 25.0);
  524.  
  525.    aiPlanAddUnitType(attackID, cUnitTypeHoplite, 1, 3*qty/10, 3*qty/10);
  526.    aiPlanAddUnitType(attackID, cUnitTypeToxotes, 1, 4*qty/10, 4*qty/10);
  527.    aiPlanAddUnitType(attackID, cUnitTypeHippikon, 1, 3*qty/10, 3*qty/10);
  528.    // Add siege if this is attack 4 or higher.
  529.    if (attackCount > 4)
  530.       aiPlanAddUnitType(attackID, cUnitTypePetrobolos, 1, (qty+5)/10, (qty+5)/10);
  531.  
  532.    aiPlanSetInitialPosition(attackID, kbGetBlockPosition(cbInfantryGather));
  533.    aiPlanSetRequiresAllNeedUnits(attackID, false);
  534.    aiPlanSetActive(attackID);
  535.    aiEcho("Activating attack plan "+attackID);
  536. //   if (lastAttackPlanID >= 0)
  537. //      aiPlanDestroy(lastAttackPlanID);   // free up last set of units?
  538.    lastAttackPlanID = attackID; // update the global var
  539. }
  540.  
  541.  
  542.  
  543.  
  544.  
  545. // *****************************************************************************
  546. //
  547. // RULES
  548. //
  549. // *****************************************************************************
  550.  
  551.  
  552. rule goToAge3
  553.    inactive
  554.    mininterval 20
  555. {
  556.    if ( (xsGetTime()/1000) < age3Time )
  557.       return;
  558.    researchTech(cTechAge3Aphrodite);
  559.    xsEnableRule("goToAge4");
  560.    xsEnableRule("getAge3UnitUpgrades");
  561.    xsEnableRule("getAge3ArmoryUpgrades");
  562.    xsDisableSelf();
  563. }
  564.  
  565. rule goToAge4
  566.    inactive
  567.    mininterval 20
  568. {
  569.    return;  // disabled for now.
  570.  
  571.    if ( (xsGetTime()/1000) < age4Time )
  572.       return;
  573.    researchTech(cTechAge4Hephaestus);
  574.    xsEnableRule("getAge4UnitUpgrades");
  575.    xsEnableRule("getAge4ArmoryUpgrades");
  576.    xsDisableSelf();
  577. }
  578.  
  579.  
  580.  
  581. rule getAge2UnitUpgrades
  582.    inactive
  583.    minInterval 20
  584. {
  585.    if ( (xsGetTime()/1000) < (age3Time/3) )
  586.       return;     
  587.    researchTech(cTechMediumInfantry);
  588.    researchTech(cTechMediumArchers);
  589. //   researchTech(cTechMediumCavalry);
  590.    xsDisableSelf();
  591. }
  592.  
  593. rule getAge2ArmoryUpgrades
  594.    inactive
  595.    minInterval 20
  596. {
  597.    if ( (xsGetTime()/1000) < (2*age3Time)/3 )
  598.       return;     
  599.    aiEcho("Getting age 2 armory upgrades");
  600.    researchTech(cTechCopperWeapons);
  601.    researchTech(cTechCopperMail);
  602.    researchTech(cTechCopperShields);
  603.    xsDisableSelf();
  604. }
  605.  
  606. rule getAge3UnitUpgrades
  607.    inactive
  608.    minInterval 20
  609. {
  610.    researchTech(cTechHeavyInfantry);
  611.    researchTech(cTechHeavyArchers);
  612.    researchTech(cTechHeavyCavalry);
  613.    xsDisableSelf();
  614. }
  615.  
  616. rule getAge3ArmoryUpgrades
  617.    inactive
  618.    minInterval 20
  619. {
  620.    researchTech(cTechBronzeWeapons);
  621.    researchTech(cTechBronzeMail);
  622.    researchTech(cTechBronzeShields);
  623.    xsDisableSelf();
  624. }
  625.  
  626. rule getAge4UnitUpgrades
  627.    inactive
  628.    minInterval 20
  629. {
  630.    researchTech(cTechChampionInfantry);
  631.    researchTech(cTechChampionArchers);
  632.    researchTech(cTechChampionCavalry);
  633.    xsDisableSelf();
  634. }
  635.  
  636. rule getAge4ArmoryUpgrades
  637.    inactive
  638.    minInterval 20
  639. {
  640.    researchTech(cTechIronWeapons);
  641.    researchTech(cTechIronMail);
  642.    researchTech(cTechIronShields);
  643.    xsDisableSelf();
  644. }
  645.  
  646.  
  647.  
  648. rule scout
  649.    inactive
  650. {
  651.    // just set up an explore plan
  652.    int exploreID = aiPlanCreate("Explore", cPlanExplore);
  653.    if(exploreID >= 0)
  654.    {
  655.       //aiPlanAddVariableFloat( exploreID, cExplorePlanLOSMultiplier, "LOS Multiplier", 1);
  656.       aiPlanSetVariableFloat( exploreID, cExplorePlanLOSMultiplier,  0, 4.0 );
  657.       aiPlanAddUnitType(exploreID, cUnitTypeHippikon, 1, 1, 1);
  658.       aiPlanSetInitialPosition( exploreID, kbGetBlockPosition(cbNorthWestPlateau));
  659.       aiPlanSetActive(exploreID);
  660.    }
  661.    xsDisableSelf();
  662. }
  663.  
  664.  
  665.  
  666.  
  667.  
  668. rule attackGenerator
  669.    minInterval 10
  670.    inactive
  671. {
  672.    static int buildingQuery = -1;
  673.  
  674.     //aiEcho("attack check running, next time is "+nextAttackTime);
  675.    if ( xsGetTime() < nextAttackTime )
  676.       return;
  677.  
  678.    if (buildingQuery < 0)
  679.    {
  680.       buildingQuery = kbUnitQueryCreate("Building Query");
  681.       configQuery(buildingQuery, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, 1, kbGetBlockPosition(cbAttack5Tower), false, 20);
  682.    }
  683.  
  684.  
  685.    attackCount = attackCount + 1;
  686.  
  687.    // Add forward building coincident with some attacks
  688.    if (attackCount == 3)   // Make tower
  689.    {
  690.       buildUnit = cUnitTypeTower;
  691.       buildVec = kbGetBlockPosition(cbAttack5Tower);    // Gold mine
  692.       startPoint = kbGetBlockPosition(cbWestPass1);
  693.       kbUnitQueryResetResults(buildingQuery);
  694.       if (kbUnitQueryExecute(buildingQuery) == 0)
  695.          xsEnableRule("buildPlanRule");
  696.       else
  697.          aiEcho("Skipping tower build because of enemy buildings.");
  698.    }
  699.    if (attackCount == 5)   // Make stable
  700.    {
  701.       buildUnit = cUnitTypeStable;
  702.       buildVec = kbGetBlockPosition(cbEastPass2);
  703.       startPoint = kbGetBlockPosition(cbEastPass1);
  704.       kbUnitQuerySetPosition(buildingQuery, startPoint);
  705.       kbUnitQueryResetResults(buildingQuery);
  706.       if (kbUnitQueryExecute(buildingQuery) == 0)
  707.          xsEnableRule("buildPlanRule");
  708.       else
  709.          aiEcho("Skipping stable build because of enemy buildings.");   }
  710.    if (attackCount == 7)   // Make fortress
  711.    {
  712.       buildUnit = cUnitTypeFortress;
  713.       buildVec = kbGetBlockPosition(cbNorthEastPlateau);   // Elevated area north of town
  714.       startPoint = kbGetBlockPosition(cbWestPass1);
  715.       kbUnitQuerySetPosition(buildingQuery, startPoint);
  716.       kbUnitQueryResetResults(buildingQuery);
  717.       if (kbUnitQueryExecute(buildingQuery) == 0)
  718.          xsEnableRule("buildPlanRule");
  719.       else
  720.          aiEcho("Skipping fortress build because of enemy buildings.");   }
  721.    if (aiRandInt(3) > 0)
  722.    {
  723.       aiEcho("Normal attack");
  724.       siegeUnitAttack(kbGetBlockPosition(cbP1TC), attackSize);
  725.    }
  726.    else
  727.    {
  728.       siegeUnitAttack(kbGetBlockPosition("2259"), attackSize); // 1 in 3 chance of aiming for green TC
  729.       aiEcho("Deep attack");
  730.    }
  731.    nextAttackTime = xsGetTime() + attackInterval;
  732.    attackSize = attackSize * attackSizeMultiplier;
  733.    if (attackSize > maxAttackSize)
  734.       attackSize = maxAttackSize;
  735.    aiEcho("Next attack size will be "+attackSize+".");
  736. }
  737.  
  738.  
  739.  
  740. rule useCurse 
  741.    minInterval 5
  742.    inactive
  743. {
  744.  
  745.    // look for a group of 6 enemy military units, at my TC location or at my main army's location
  746.    int targetUnit = -1;
  747.  
  748.    
  749.    static int tempQuery = -1;
  750.    if (tempQuery < 0)
  751.    {  // Doesn't exist, set it up
  752.       tempQuery = kbUnitQueryCreate("useCurseHome");
  753.       if ( configQuery(tempQuery, cUnitTypeUnit, -1, cUnitStateAlive, 1, kbGetBlockPosition(cbP2TC), true, 50) == false)
  754.          return;
  755.    }
  756.    kbUnitQueryResetResults(tempQuery);
  757.    int targetCount = kbUnitQueryExecute(tempQuery);  
  758.  
  759.    if ( targetCount < 6 )
  760.    {
  761.       vector pVec = aiPlanGetLocation(lastAttackPlanID);
  762.       if (xsVectorGetX(pVec)>=0)
  763.       {
  764.          static int tempQuery2 = -1;
  765.          if (tempQuery2 < 0)
  766.          {  // Doesn't exist, set it up
  767.             tempQuery2 = kbUnitQueryCreate("useCurseArmy");
  768.             if ( configQuery(tempQuery2, cUnitTypeUnit, -1, cUnitStateAlive, 1, pVec, true, 50) == false)
  769.                return;
  770.          }
  771.          else
  772.             kbUnitQuerySetPosition(tempQuery2, pVec); // Because pVec changes as army moves
  773.          kbUnitQueryResetResults(tempQuery2);
  774.          targetCount = kbUnitQueryExecute(tempQuery2);  
  775.          if (targetCount < 6)
  776.             return;
  777.          else
  778.             targetUnit = kbUnitQueryGetResult(tempQuery2, targetCount/2);  // grab middle unit
  779.       }
  780.       else
  781.          return;
  782.    } 
  783.    else
  784.       targetUnit = kbUnitQueryGetResult(tempQuery, targetCount/2);  // grab middle unit
  785.  
  786.  
  787.    aiEcho("Using Curse on unit "+targetUnit+" at "+kbUnitGetPosition(targetUnit));
  788.    if ( aiCastGodPowerAtUnit(cTechCurse, targetUnit) == true)
  789.       xsDisableSelf();
  790. }
  791.  
  792.  
  793.  
  794. rule usePestilence
  795.    minInterval 5
  796.    inactive
  797. {
  798.    // look for a group of 2 enemy buildings near my army.
  799.  
  800.    if (lastAttackPlanID < 0)
  801.       return;
  802.    
  803.  
  804.    vector pVec = aiPlanGetLocation(lastAttackPlanID);
  805.    if (xsVectorGetX(pVec)<0)
  806.       return;
  807.  
  808.    static int tempQuery = -1;
  809.    if (tempQuery < 0)
  810.    {  // Doesn't exist, set it up
  811.       tempQuery = kbUnitQueryCreate("useBronze");
  812.  
  813.       if ( configQuery(tempQuery, cUnitTypeLogicalTypeBuildingsThatTrainMilitary, -1, cUnitStateAlive, 1, pVec, true, 50) == false)
  814.          return;
  815.    }
  816.    else
  817.       kbUnitQuerySetPosition(tempQuery, pVec); // Because pVec changes as army moves
  818.    kbUnitQueryResetResults(tempQuery);
  819.    int targetCount = kbUnitQueryExecute(tempQuery);  
  820.  
  821.    if (targetCount < 2)
  822.       return;
  823.  
  824.    aiEcho("Using Pestilence at "+kbUnitGetPosition(kbUnitQueryGetResult(tempQuery, 0)));
  825.    if ( aiCastGodPowerAtPosition(cTechPestilence, kbUnitGetPosition(kbUnitQueryGetResult(tempQuery, 0))) == true)
  826.    {
  827.       aiEcho("Deactivating UsePestilence");
  828.       xsDisableSelf();
  829.    }
  830. }
  831.  
  832.  
  833. rule usePlenty
  834.    minInterval 5
  835.    inactive
  836. {
  837.    vector aimHere = kbGetBlockPosition(cbP2TC);
  838.    float dx = aiRandInt(40)-20.0;
  839.    float dz = aiRandInt(40)-20.0;
  840.    float newX = xsVectorGetX(kbGetBlockPosition(cbP2TC));
  841.    float newZ = xsVectorGetZ(kbGetBlockPosition(cbP2TC));
  842.    newX = newX + dx;
  843.    newZ = newZ + dz;
  844.  
  845.    aimHere = xsVectorSetX(aimHere, newX);    // TC vector +/-20 in x and z
  846.    aimHere = xsVectorSetZ(aimHere, newZ);
  847.  
  848.    if ( aiCastGodPowerAtPosition(cTechPlenty, aimHere) == true)
  849.    {
  850.       aiEcho("Plenty worked at "+aimHere);
  851.       xsDisableSelf();
  852.    }
  853.    else
  854.       aiEcho("Plenty failed at "+aimHere);
  855. }
  856.  
  857.  
  858.  
  859.