home *** CD-ROM | disk | FTP | other *** search
/ CD-ROM Today (BR) Volume 4 #16 / Cdrtv4n16.iso / Jogos / ALEXANDE / DEMO / _SETUP.1 / BASICMAN.AI < prev    next >
Text File  |  1996-12-18  |  27KB  |  992 lines

  1. import "constant.ai";
  2.  
  3. ' Forward declarations
  4. procedure AttackInZOC(movingUnit);
  5. procedure ShootMissiles(shootingUnit);
  6. procedure Defend(hexToDefend);
  7. procedure RecoverUnits();
  8. procedure Rally();
  9. procedure PartialRecover();
  10. procedure GetUnitsInRange();
  11. procedure GetUnitsOutOfRange();
  12.  
  13. ' GetFrontalFacings takes a list id and a facing (direction).  It fills the
  14. ' list with the (2) directions of that a unit can go.  It returns 1 if the
  15. ' original facing is correct, otherwise it returns 0.  (NORTH and SOUTH are
  16. ' NOT valid facings).
  17. procedure GetFrontalFacings(listID, facing)
  18. {
  19.     var retVal;
  20.  
  21.     retVal = 0;
  22.     if (facing == NORTHEAST)
  23.     {
  24.         AddToList(listID, NORTH);
  25.         AddToList(listID, NORTHEAST);
  26.         retVal = 1;
  27.     };
  28.     if (facing == EAST)
  29.     {
  30.         AddToList(listID, NORTHEAST);
  31.         AddToList(listID, SOUTHEAST);
  32.         retVal = 1;
  33.     };
  34.     if (facing == SOUTHEAST)
  35.     {
  36.         AddToList(listID, SOUTHEAST);
  37.         AddToList(listID, SOUTH);
  38.         retVal = 1;
  39.     };
  40.     if (facing == SOUTHWEST)
  41.     {
  42.         AddToList(listID, SOUTH);
  43.         AddToList(listID, SOUTHWEST);
  44.         retVal = 1;
  45.     };
  46.     if (facing == WEST)
  47.     {
  48.         AddToList(listID, SOUTHWEST);
  49.         AddToList(listID, NORTHWEST);
  50.         retVal = 1;
  51.     };
  52.     if (facing == NORTHWEST)
  53.     {
  54.         AddToList(listID, NORTHWEST);
  55.         AddToList(listID, NORTH);
  56.         retVal = 1;
  57.     };
  58.     return retVal;
  59. };
  60.  
  61. ' inProximity looks at the identifying hex lists (flank, rear, or frontal)
  62. ' to see if the hex in question is in that list.  It returns TRUE if it is,
  63. ' otherwise it returns FALSE.  For the identifying list types it is:
  64. ' 0 = ZOC
  65. ' 1 = flank
  66. ' 2 = rear
  67. procedure inProximity(hexInQuestion, nation, hexType)
  68. {
  69.     var dir, hex, hexList, retVal, unit, n, isLeader;
  70.  
  71.     retVal = FALSE;
  72.  
  73.     for dir = NORTH to NORTHWEST
  74.     {
  75.         hex = AdjacentHex(hexInQuestion, dir);
  76.         if (hex != -1)
  77.         {
  78.             unit = HexOccupancy(hex);
  79.             if (unit!=-1)
  80.             {
  81.                 isLeader = IsLeader(unit);
  82.                 if (NOT isLeader)
  83.                 {
  84.                     n = Query(NATION, unit);
  85.                     if (n != nation)
  86.                     {
  87.                         hexList = GetList();
  88.                         AssignList(hexList, hexType, unit);    ' Assign flank hexes
  89.                         if (IsMemberOf(hexList, hexInQuestion))
  90.                             retVal = TRUE;
  91.                     };
  92.                     ' ReleaseList(hexList);
  93.                 };
  94.             };
  95.         };
  96.     };
  97.     return retVal;
  98. };
  99.  
  100. '**************************************************************************
  101. ' InFlank checks to see if the hex in question is in the flank of an enemy
  102. ' unit.
  103. procedure InFlank(hexInQuestion, nation)
  104. {
  105.     return inProximity(hexInQuestion, nation, 1);    ' 1 identifies flank hexes
  106. };
  107.  
  108. '**************************************************************************
  109. ' InRear checks to see if the hex in question is in the rear of an enemy
  110. ' unit.
  111. procedure InRear(hexInQuestion, nation)
  112. {
  113.     return inProximity(hexInQuestion, nation, 2);    ' 2 identifies rear hexes
  114. };
  115.  
  116. '**************************************************************************
  117. ' InFrontal checks to see if the hex in question is in the frontal of an
  118. ' enemy unit.
  119. procedure InFrontal(hexInQuestion, nation)
  120. {
  121.     return inProximity(hexInQuestion, nation, 0);    ' 0 identifies frontal hexes
  122. };
  123.  
  124. '**************************************************************************
  125. ' WeightCombatPath looks at the path of a combat unit and weights it
  126. ' according to the following:
  127. ' Clear = 9
  128. ' Rear = 7
  129. ' Flank = 5
  130. ' Frontal = 2
  131. ' DS = 0
  132. ' These values may be modified in the CONSTANT.AI file.
  133. ' Currently (7/31/96), only the final hex in the path is looked at.  That
  134. ' may change to be every hex is looked at.
  135. procedure WeightCombatPath(pathID, nation)
  136. {
  137.     var hexInQuestion, weight, w;
  138.  
  139.     ' Assume the path is going to be clear.
  140.     weight = CLEAR;
  141.  
  142.     hexInQuestion = GetLast(pathID);
  143.     w = InFlank(hexInQuestion, nation);
  144.     if (w == TRUE)
  145.     {
  146.         weight = FLANK;
  147.     };
  148.     ' A rear attack would be much more desirable than a flank attack so that
  149.     ' why it is checked for after the flank
  150.     if (InRear(hexInQuestion, nation) == TRUE)
  151.     {
  152.         weight = REAR;
  153.     };
  154.     ' A frontal attack is the least desirable but it needs to be checked for
  155.     ' last since it is something that the unit would not want to move into
  156.     if (InFrontal(hexInQuestion, nation) == TRUE)
  157.     {
  158.         weight = FRONTAL;
  159.     };
  160.  
  161.     return weight;
  162. };
  163.  
  164. procedure GenericMove(hex);
  165.  
  166. procedure FlankingPosAcheived(hex)
  167. {
  168.     var unit, retVal, n;
  169.  
  170.     unit = HexOccupancy(hex);
  171.     retVal = False;
  172.     if (unit != -1)
  173.     {
  174.         n = Query(NATION, unit);
  175.         if (n == INDIAN)
  176.             retVal = True;
  177.     };
  178.     return retVal;
  179. };
  180.  
  181. procedure DoNothing()
  182. {
  183. };
  184.  
  185. procedure GetUnitsOutOfRange(list)
  186. {
  187.     var unit, numOutOfRange;
  188.  
  189.     GroupListReset();
  190.     numOutOfRange = 0;
  191.     unit = GroupListGetNext();
  192.     while (unit != -1)
  193.     {
  194.         if (NOT InCommandRange(unit))
  195.         {
  196.             AddToList(list, unit);
  197.             numOutOfRange = numOutOfRange+1;
  198.         };
  199.         unit = GroupListGetNext();
  200.     };
  201.     return numOutOfRange;
  202. };
  203.  
  204. procedure GetUnitsInRange(list)
  205. {
  206.     var unit, numInRange;
  207.  
  208.     GroupListReset();
  209.     numInRange = 0;
  210.     unit = GroupListGetNext();
  211.     while (unit != -1)
  212.     {
  213.         if (InCommandRange(unit))
  214.         {
  215.             AddToList(list, unit);
  216.             numInRange = numInRange+1;
  217.         };
  218.         unit = GroupListGetNext();
  219.     };
  220.     return numInRange;
  221. };
  222.  
  223. ' This procedure will tell how many of the units are engaged in battle.
  224. ' The definition of "engaged in battle" means if someone is in his ZOC OR
  225. ' he is in someone else's ZOC.
  226. procedure GetUnitsEngagedInBattle(list)
  227. {
  228.     var unit, nation, numEngagedInBattle, surroundingHexes, zocHexes, hex,
  229.          enemy, enemyNation, added, unitHex, leader, isLeader;
  230.  
  231.     GroupListReset();
  232.     numEngagedInBattle = 0;
  233.     leader = GetLeader();
  234.     watch "Leader = " leader;
  235.     unit = GroupListGetNext();
  236.     if (unit == leader)
  237.         unit = GroupListGetNext();
  238.     while (unit != -1)
  239.     {
  240.         nation = Query(NATION, unit);
  241.         added = False;
  242.         unitHex = Query(REGION_NUM, unit);
  243.         ' First, check to see if he has someone in his ZOC.
  244.         zocHexes = GetList();
  245.         AssignList(zocHexes, 0, unit);    ' The 0 stands for ZOC hexes.
  246.         ResetList(zocHexes);
  247.         hex = GetNextInList(zocHexes);
  248.         while ((hex!=-1) AND (NOT added))
  249.         {
  250.             enemy = HexOccupancy(hex);
  251.             if (enemy != -1)
  252.             {
  253.                 enemyNation = Query(NATION, enemy);
  254.                 if (enemyNation != nation)
  255.                 {
  256.                     ' Found an enemy in his ZOC... add him to the list.
  257.                     AddToList(list, unit);
  258.                     added = True;
  259.                     numEngagedInBattle = numEngagedInBattle + 1;
  260.                 };
  261.             };
  262.             hex = GetNextInList(zocHexes);
  263.         };
  264.         ' ReleaseList(zocHexes);
  265.         ' Now check to see if anyone has him in his ZOC.
  266.         surroundingHexes = GetList();
  267.         AssignList(surroundingHexes, 5, unit);    ' The 5 stands for surrounding hexes.
  268.         ResetList(surroundingHexes);
  269.         hex = GetNextInList(surroundingHexes);
  270.         while ((hex != -1) AND (NOT added))
  271.         {
  272.             enemy = HexOccupancy(hex);
  273.             if (enemy != -1)
  274.             {
  275.                 enemyNation = Query(NATION, enemy);
  276.                 if (enemyNation != nation)
  277.                 {
  278.                     isLeader = IsLeader(enemy);
  279.                     if (NOT isLeader)
  280.                     {
  281.                         ClearList(zocHexes);
  282.                         AssignList(zocHexes, 0, enemy);    ' The 0 stands for ZOC hexes
  283.                         ResetList(zocHexes);
  284.                         if (IsMemberOf(zocHexes, unitHex))
  285.                         {
  286.                             AddToList(list, unit);
  287.                             added = True;
  288.                             numEngagedInBattle = numEngagedInBattle + 1;
  289.                         };
  290.                     };
  291.                 };
  292.             };
  293.             hex = GetNextInList(surroundingHexes);
  294.         };
  295.         ' ReleaseList(surroundingHexes);
  296.         unit = GroupListGetNext();
  297.         if (unit == leader)
  298.             unit = GroupListGetNext();
  299.     };
  300.     return numEngagedInBattle;
  301. };
  302.  
  303. procedure ParePathListDown(pathList, destHex)
  304. {
  305.     var path, hex, shortestDist, d, tempPath, tPath;
  306.  
  307.     d = SizeOfList(pathList);
  308.     ResetList(pathList);
  309.     shortestDist = 100;
  310.     path = GetNextInList(pathList);
  311.     while (path!=-1)
  312.     {
  313.         hex = GetLast(path);
  314.         d = Distance(hex, destHex);
  315.         if (d<shortestDist)
  316.         {
  317.             shortestDist = d;
  318.             ' Remove all lists up to this point.
  319.             ResetList(pathList);
  320.             tempPath = GetNextInList(pathList);
  321.             while (tempPath != path)
  322.             {
  323.                 tPath = tempPath;
  324.                 tempPath = GetNextInList(pathList);
  325.                 RemoveFromList(pathList, tPath);
  326.                 ' ReleaseList(tPath);
  327.             };
  328.             ResetList(pathList);
  329.             tPath = -1;
  330.         }
  331.         else
  332.         {
  333.             if (d<shortestDist)
  334.                 tPath = path;
  335.         };
  336.         path = GetNextInList(pathList);
  337.         if (tPath != -1)
  338.         {
  339. '                RemoveFromList(pathList, tPath);
  340. '                ReleaseList(tPath);
  341.         };
  342.     };
  343.     d = SizeOfList(pathList);
  344.     watch "Size of pathList: " d;
  345. };
  346.  
  347. ' This procedure causes the unit to pick a hex in its ZOC and attack it.
  348. procedure AttackFrom(unit, hex, facing)
  349. {
  350.     var direction, zoc, d, nation, enemyNation, attacked, enemyUnit;
  351.  
  352.     ' Get the "pretend" ZOC of the unit.
  353.     direction = GetList();
  354.     GetFrontalFacings(direction, facing);
  355.     write "**** Here in AttackFrom ****";
  356.     watch "unit = " unit;
  357.     watch "hex = " hex;
  358.     watch "facing = " facing;
  359.  
  360.     ' Look at one hex and then the other one.  Choose the left then the right.
  361.     ResetList(direction);
  362.     BreakPoint();
  363.     d = GetNextInList(direction);
  364.     watch "First direction = " d;
  365.     zoc = AdjacentHex(hex, d);
  366.     watch "First zoc = " zoc;
  367.     enemyUnit = HexOccupancy(zoc);
  368.     attacked = False;
  369.     nation = Query(NATION, unit);
  370.     if (enemyUnit!=-1)
  371.     {
  372.         enemyNation = Query(NATION, enemyUnit);
  373.         if (enemyNation != nation)
  374.         {
  375.             ' ATTACK!
  376.             Attack(unit, zoc);
  377.             ShootMissiles(unit);
  378.             attacked = True;
  379.         };
  380.     };
  381.     d = GetNextInList(direction);
  382.     watch "Second direction = " d;
  383.     zoc = AdjacentHex(hex, d);
  384.     watch "Second zoc = " zoc;
  385.     enemyUnit = HexOccupancy(zoc);
  386.     if ( (enemyUnit != -1) AND (NOT attacked) )
  387.     {
  388.         enemyNation = Query(NATION, enemyUnit);
  389.         if (enemyNation != nation)
  390.         {
  391.             ' ATTACK!
  392.             Attack(unit, zoc);
  393.             ShootMissiles(unit);
  394.             attacked = True;
  395.         };
  396.     };
  397.     return attacked;
  398. };
  399.  
  400. ' This procedure looks at the current units that can move, weights their
  401. ' paths and choose which unit to move.  The units that are unable to move
  402. ' need to be passed into the unitsUnableToMove.  This functions should only
  403. ' be called when the conditions are clear (no unit in the group is in
  404. ' battle).  If a unit cannot move because his frontal hexes are covered (by
  405. ' friendlies), he is also not considered.
  406. ' If a unit is forced into a non-clear path, the most advantageous unit is
  407. ' moved to the most advantageous hex and assigned to combat.  After that,
  408. ' this routine should NOT be called again!
  409. procedure weightAndMove(unitsUnableToMove, destHex)
  410. {
  411.     var whichUnitToMove, unitLookingAt, d, tempUnit, tempHex, tempDistance,
  412.          pathList, nation, shortestDist, tempPath, tPath, highPath,
  413.          highPathWeight, hex, unitHex, path, weight, unitList,
  414.          movementRemaining, movementAllowance, potentialUnitsToMove,
  415.          numUnitsToLookAt, leader, highDistance, highUnit,
  416.          unitHighPath, unitHighPathWeight, facing, retVal;
  417.  
  418.     ' First, create a list of units that can move.  This involves checking
  419.     ' the group list and NOT adding units in the "unitsUnableToMove" list
  420.     ' and also excluding units that have already moved by this leader.  This
  421.     ' little routine also includes units that have friendlies in their
  422.     ' frontal hexes
  423.     GroupListReset();
  424.     unitList = GetList();
  425.     unitLookingAt = GroupListGetNext();
  426.     while (unitLookingAt != -1)
  427.     {
  428.         if (IsMemberOf(unitsUnableToMove, unitLookingAt) == FALSE)
  429.         {
  430.             movementRemaining = Query(5, unitLookingAt);
  431.             movementAllowance = Query(4, unitLookingAt);
  432.             if (movementRemaining == movementAllowance)
  433.             {
  434.                 if (CanMove(unitLookingAt))
  435.                     AddToList(unitList, unitLookingAt);
  436.             };
  437.         };
  438.         unitLookingAt = GroupListGetNext();
  439.     };
  440.  
  441.     whichUnitToMove = -1;
  442.     ' All the units that can move are put into the 'potentialUnitsToMove'
  443.     ' list.  There are numUnitsToLookAt to look at.  numUnitsToLookAt is
  444.     ' simply the number of commands remaining for the leader.
  445.     potentialUnitsToMove = GetList();
  446.     leader = GetLeader();
  447.     numUnitsToLookAt = Query(COMMANDS_REMAINING, leader);
  448.     ResetList(unitList);
  449.     unitLookingAt = GetNextInList(unitList);
  450.     while (unitLookingAt != -1)
  451.     {
  452.         unitHex = Query(REGION_NUM, unitLookingAt);
  453.         d = Distance(unitHex, destHex);
  454.         if (SizeOfList(potentialUnitsToMove) < numUnitsToLookAt)
  455.             AddToList(potentialUnitsToMove, unitLookingAt)
  456.         else
  457.         {
  458.             ' The list of potential units is full; see if the current unit will
  459.             ' displace one in the list.
  460.             ResetList(potentialUnitsToMove);
  461.             tempUnit = GetNextInList(potentialUnitsToMove);
  462.             highDistance = 0;
  463.             ' First, get the unit that is farthest away that already exists in
  464.             ' the list of selected units.
  465.             while (tempUnit != -1)
  466.             {
  467.                 tempHex = Query(REGION_NUM, tempUnit);
  468.                 tempDistance = Distance(tempHex, destHex);
  469.                 if (tempDistance > highDistance)
  470.                 {
  471.                     highDistance = tempDistance;
  472.                     highUnit = tempUnit;
  473.                 };
  474.                 tempUnit = GetNextInList(potentialUnitsToMove);
  475.             };
  476.             ' Check to see if the unit that is being looked at will replace one
  477.             ' in the list.
  478.             if (d < highDistance)
  479.             {
  480.                 RemoveFromList(potentialUnitsToMove, highUnit);
  481.                 AddToList(potentialUnitsToMove, unitLookingAt);
  482.             };
  483.         };
  484.         unitLookingAt = GetNextInList(unitList);
  485.     };
  486.     DumpList(potentialUnitsToMove);
  487.  
  488.     highPathWeight = 0;
  489.     highPath = -1;
  490.     highUnit = -1;
  491.     if (SizeOfList(potentialUnitsToMove) == 0)
  492.     {
  493.         write "No more units to move... moving the leader.";
  494.         whichUnitToMove = GetLeader();
  495.         pathList = GetList();
  496.         GetUnitPaths(whichUnitToMove, pathList);
  497.         ResetList(pathList);
  498.         highPath = GetNextInList(pathList);
  499.         watch "Leader high path = " highPath;
  500.         highPathWeight = 9;    ' Force it to be 9 for now.
  501.     }
  502.     else
  503.     {
  504.         ' Weight the different paths of the selected units and then move
  505.         ' the one with the highest weight < 7.  If all of them have 9, any one
  506.         ' of them can be moved.
  507.         ResetList(potentialUnitsToMove);
  508.         unitLookingAt = GetNextInList(potentialUnitsToMove);
  509.         while (unitLookingAt != -1)
  510.         {
  511.             ' Keep only the shortest paths to the dest hex.  Those are most
  512.             ' likely to have to keep the units from changing facing next time
  513.             ' he has to move.  In other words, we want him to get as close to
  514.             ' the hex as possible.
  515.             nation = Query(NATION, unitLookingAt);
  516.             ' Get all the potential paths that he may follow.
  517.             pathList = GetList();
  518.             GetUnitPaths(unitLookingAt, pathList);
  519.             ParePathListDown(pathList, destHex);
  520.             write "Removed some of the paths...";
  521.             ' Now, weight the remaining paths and take the path of least resistance.
  522.             ResetList(pathList);
  523.             path = GetNextInList(pathList);
  524.             unitHighPath = -1;
  525.             unitHighPathWeight = -1;
  526.             while (path != -1)
  527.             {
  528.                 weight = WeightCombatPath(path, nation);
  529.                 if (weight > unitHighPathWeight)
  530.                 {
  531.                     if (unitHighPath != -1)
  532.                         tPath = unitHighPath;
  533.                     unitHighPath = path;
  534.                     unitHighPathWeight = weight;
  535.                 }
  536.                 else
  537.                 {
  538.                     tPath = path;
  539.                 };
  540.                 path = GetNextInList(pathList);
  541.                 if (tPath != -1)
  542.                 {
  543.     '                RemoveFromList(pathList, tPath);
  544.     '                ReleaseList(tPath);
  545.                 };
  546.             };
  547.             ' I've got the unit's highest weighted path.  Compare it to the
  548.             ' current high path weight and replace if necessary.
  549.             if ((unitHighPathWeight > highPathWeight) AND (unitHighPathWeight != 9))
  550.             {
  551.                 highPath = unitHighPath;
  552.                 highPathWeight = unitHighPathWeight;
  553.                 highUnit = unitLookingAt;
  554.             };
  555.             if ( (unitHighPathWeight == 9) AND (highUnit == -1) )
  556.             {
  557.                 highPath = unitHighPath;
  558.                 highPathWeight = unitHighPathWeight;
  559.                 highUnit = unitLookingAt;
  560.             };
  561.             unitLookingAt = GetNextInList(potentialUnitsToMove);
  562.         };
  563.         ' The highUnit contains the unit to move.
  564.         whichUnitToMove = highUnit;
  565.     };
  566.  
  567.     write "Got the path... now moving him...";
  568.     ' I have the unit, I have the path - let's move him!
  569.     hex = GetLast(highPath);
  570.     watch "The unit is moving to hex #" hex;
  571.     retVal = MoveToward(hex, whichUnitToMove);
  572.     if (retVal == 0)
  573.     {
  574.         FinishLeader();
  575.       return retVal;
  576.    };
  577.     if (highPathWeight < 9)
  578.     {
  579.         ' If I get here, I need to attack somebody.  There will probably be
  580.         ' some logic put in here eventually to check to see if the unit
  581.         ' is superior or not.  If it isn't, then the attack probably won't
  582.         ' happen.  But, for now (8/26/96), the unit blindly attacks.
  583.         write "About to call AttackFrom...";
  584.         facing = Query(FACING, whichUnitToMove);
  585.         AttackFrom(whichUnitToMove, hex, facing);
  586.     };
  587. '        RemoveFromList(pathList, highPath);
  588. '        ReleaseList(highPath);
  589. '        ReleaseList(pathList);
  590.     ' ReleaseList(potentialUnitsToMove);
  591. };
  592.  
  593. procedure SupportMoves(battlingList, unitsOutOfRange);
  594. procedure SupportUnit(movingUnit, unitToSupport);
  595. procedure AttackWithSkirmishers();
  596.  
  597. procedure GenericMove(hex)
  598. {
  599.     var outOfRangeList, battlingList, unitRallied, unitRecovered;
  600.  
  601.     unitRallied = Rally();
  602.     if (unitRallied)
  603.     {
  604.         write "A unit was rallied from GenericMove";
  605.       return 1;
  606.     };
  607.     unitRecovered = PartialRecover();
  608.     if (unitRecovered)
  609.     {
  610.         write "A unit was recovered";
  611.         return 1;
  612.     };
  613.     outOfRangeList = GetList();
  614.     battlingList = GetList();
  615.     GetUnitsOutOfRange(outOfRangeList);
  616.     GetUnitsEngagedInBattle(battlingList);
  617.  
  618.     ' Check to see if there are no units in battle.  If there aren't, weight
  619.     ' units and paths and move the appropriate unit.
  620.     if (SizeOfList(battlingList) == 0)
  621.     {
  622.         ' ReleaseList(battlingList);
  623.         weightAndMove(outOfRangeList, hex);
  624.         ' ReleaseList(outOfRangeList);
  625.     }
  626.     else
  627.         SupportMoves(battlingList, outOfRangeList);
  628. };
  629.  
  630. ' This procedure is used for moving units to support other units already
  631. ' in combat.  It should be covering a unit's flanks and his 6.
  632. procedure SupportMoves(battlingList, unitsOutOfRange)
  633. {
  634.     var unitList, unitLookingAt, movementRemaining, movementAllowance,
  635.          whichUnitToMove, shortestDist, unitInNeed, hex1, hex2, distance,
  636.          unitToSupport, unitType, retVal;
  637.  
  638.     ' Compile a list of units that can absolutely move.  Units that are in
  639.     ' battle are left in battle.  No regard for how close a unit is to routing
  640.     ' is given here.
  641.  
  642.     write "Now in SupportMoves";
  643.  
  644.     GroupListReset();
  645.     unitList = GetList();
  646.     unitLookingAt = GroupListGetNext();
  647.     while (unitLookingAt != -1)
  648.     {
  649.         if (IsMemberOf(battlingList, unitLookingAt) == FALSE)
  650.         {
  651.             if (IsMemberOf(unitsOutOfRange, unitLookingAt) == FALSE)
  652.             {
  653.                 movementRemaining = Query(5, unitLookingAt);
  654.                 movementAllowance = Query(4, unitLookingAt);
  655.                 if (movementRemaining == movementAllowance)
  656.                 {
  657.                     if (CanMove(unitLookingAt))
  658.                     {
  659.                         AddToList(unitList, unitLookingAt);
  660.                     };
  661.                 };
  662.             };
  663.         };
  664.         unitLookingAt = GroupListGetNext();
  665.     };
  666.  
  667.     ' Choose which unit to move into support position.  The only criteria for
  668.     ' that is the two units that are closest: one is currently in battle; the
  669.     ' other is capable of being moved.  A more probable criteria should be
  670.     ' used.  This is just being used because it is simple to implement.
  671.     whichUnitToMove = -1;
  672.     unitToSupport = -1;
  673.     shortestDist = 100;
  674.     ResetList(unitList);
  675.     write "Now looking for the shortest distance between unit in need and support unit";
  676.     unitLookingAt = GetNextInList(unitList);
  677.     while (unitLookingAt != -1)
  678.     {
  679.         unitType = Query(UNIT_TYPE, unitLookingAt);
  680.         ' Skirmishers can't shock so don't even consider them.  If they are
  681.         ' the only units left, then they will be treated extra-special later.
  682.         if (unitType != SK)
  683.         {
  684.             hex1 = Query(REGION_NUM, unitLookingAt);
  685.             ResetList(battlingList);
  686.             unitInNeed = GetNextInList(battlingList);
  687.             while (unitInNeed != -1)
  688.             {
  689.                 hex2 = Query(REGION_NUM, unitInNeed);
  690.                 distance = Distance(hex1,hex2);
  691.                 if (distance < shortestDist)
  692.                 {
  693.                     shortestDist = distance;
  694.                     whichUnitToMove = unitLookingAt;
  695.                     unitToSupport = unitInNeed;
  696.                 };
  697.                 unitInNeed = GetNextInList(battlingList);
  698.             };
  699.         };
  700.         unitLookingAt = GetNextInList(unitList);
  701.     };
  702.  
  703.     watch "The unit to move for support = " whichUnitToMove;
  704.     watch "Unit to be supported = " unitToSupport;
  705.     ' Check to see if the unit was gotten.  If not, then that means that only
  706.     ' skirmishers are left and they need to be treated differently.
  707.     if (whichUnitToMove == -1)
  708.         AttackWithSkirmishers()
  709.     else
  710.     {
  711.         ' Got a "real" unit.  Move him appropriately...
  712.         retVal = SupportUnit(whichUnitToMove, unitToSupport);
  713.         if (retVal == 0)
  714.             FinishLeader();
  715.     };
  716.     return 1;    ' What else to return?
  717. };
  718.  
  719. procedure AttackWithSkirmishers()
  720. {
  721.     ' Just end the leader for right now.
  722.     FinishLeader();
  723.     return 1;
  724. };
  725.  
  726. procedure SupportUnit(movingUnit, unitToSupport)
  727. {
  728.     var flankHexes, hex1, hex2, hex1Unit, hex2Unit, occupiedHex, canAttack,
  729.          nation, unitNation, unit, zocHexes, hex, enemy, emptyHex, retVal;
  730.  
  731.     write "Here in SupportUnit";
  732.     nation = Query(NATION, movingUnit);
  733.     ' First, look at the flank hexes.  To do that, I need to get the flank
  734.     ' hexes.
  735.     write "Checking the flank hexes first.";
  736.     flankHexes = GetList();
  737.     AssignList(flankHexes, FLANK_HEXES, unitToSupport);
  738.     ResetList(flankHexes);
  739.     hex1 = GetNextInList(flankHexes);
  740.     hex2 = GetNextInList(flankHexes);
  741.     BreakPoint();
  742.     hex1Unit = HexOccupancy(hex1);
  743.     hex2Unit = HexOccupancy(hex2);
  744.     if ((hex1Unit == -1) AND (hex2Unit == -1))
  745.     {
  746.         ' Both hexes are clear!  Move to one of them.
  747.         write "Both flank hexes are clear, moving to one of them now...";
  748.         retVal = MoveToward(hex1, movingUnit);
  749.         if (retVal == 0)
  750.         {
  751.             FinishLeader();
  752.             return retVal;
  753.         };
  754.  
  755.         ' If there is someone in his ZOC, attack him...
  756.         AttackInZOC(movingUnit);
  757.         return 1;
  758.     };
  759.  
  760.     ' Both flank hexes are NOT clear.  The priority is the second flank for
  761.     ' no special reason other than it exists.  But first, check to see the
  762.     ' unit to see if it is an enemy or not.
  763.     occupiedHex = -1;
  764.     write "Now checking to see if they (the flanks) are occupied by enemy units";
  765.     if (hex1Unit!=-1)
  766.     {
  767.         unitNation = Query(NATION, hex1Unit);
  768.         if (unitNation != nation)
  769.             occupiedHex = hex1;
  770.     };
  771.     if (hex2Unit!=-1)
  772.     {
  773.         unitNation = Query(NATION , hex2Unit);
  774.         if (unitNation != nation)
  775.             occupiedHex = hex2;
  776.     };
  777.     if (occupiedHex != -1)
  778.     {
  779.         watch "Attacking flank hex #" occupiedHex;
  780.         ' See if the hex is in his movement range, and if it is, bang it.
  781.         canAttack = CanAttack(movingUnit, occupiedHex);
  782.         if (canAttack)
  783.         {
  784.             Attack(movingUnit, occupiedHex);
  785.             ShootMissiles(movingUnit);
  786.         };
  787.     };
  788.  
  789.     ' There is not an enemy unit in either of the flank hexes.  So, if only
  790.     ' one of them is empty, move into that one.
  791.     emptyHex = -1;
  792.     if (hex1Unit == -1)
  793.         emptyHex = hex1;
  794.     if (hex2Unit == -1)
  795.         emptyHex = hex2;
  796.     if (emptyHex != -1)
  797.     {
  798.         retVal = MoveToward(emptyHex, movingUnit);
  799.         if (retVal == 0)
  800.         {
  801.             FinishLeader();
  802.             return retVal;
  803.         };
  804.         AttackInZOC(movingUnit);
  805.         return 1;
  806.     };
  807.  
  808.     ' If the thread of execution gets to here, its because there are two
  809.     ' units flanking the target unit.  Check the target's rear...
  810.     write "Now checking the rear of the unit.";
  811.     return 0;
  812. };
  813.  
  814. procedure AttackInZOC(movingUnit)
  815. {
  816.     var zocHexes, unit, hex, enemy;
  817.  
  818.     zocHexes = GetList();
  819.     AssignList(zocHexes, ZOC_HEXES, movingUnit);
  820.     ResetList(zocHexes);
  821.     hex = GetNextInList(zocHexes);
  822.     while (hex!=-1)
  823.     {
  824.         unit = HexOccupancy(hex);
  825.         if (unit != -1)
  826.         {
  827.             enemy = IsEnemy(movingUnit, unit);
  828.             Attack(movingUnit, hex);
  829.             ShootMissiles(movingUnit);
  830.             return 1;
  831.         };
  832.         hex = GetNextInList(zocHexes);
  833.     };
  834. };
  835.  
  836. procedure ShootMissiles(shootingUnit)
  837. {
  838.     var zocHexes, unit, hex, enemy;
  839.     if (Query(MISSILE_CAPABLE, shootingUnit) == 0)
  840.     {
  841.         write "This unit CANNOT fire any missiles";
  842.         return 0;
  843.     };
  844.     write "This unit CAN shoot missiles";
  845.     ' Look in his ZOC and just see if he can shoot somebody...
  846.     zocHexes = GetList();
  847.     AssignList(zocHexes, ZOC_HEXES, shootingUnit);
  848.     ResetList(zocHexes);
  849.     hex = GetNextInList(zocHexes);
  850.     while (hex!=-1)
  851.     {
  852.         unit = HexOccupancy(hex);
  853.         if (unit != -1)
  854.         {
  855.             enemy = IsEnemy(shootingUnit, unit);
  856.             if (enemy)
  857.             {
  858.                 Fire(shootingUnit, hex);
  859.                 return 1;
  860.             };
  861.         };
  862.         hex = GetNextInList(zocHexes);
  863.     };
  864.     return 0;
  865. };
  866.  
  867. procedure Defend(hexToDefend)
  868. {
  869.     ' First, get a list of units in range and a list of units out of range.
  870.     var retVal;
  871.  
  872.     write "Here in Defend";
  873.     retVal = Rally();
  874.     if (retVal)
  875.        return 1;
  876.     write "Couldn't find any units to rally!";
  877.     retVal = RecoverUnits();
  878.     if (retVal == -1)
  879.         FinishLeader();
  880. };
  881.  
  882. procedure Rally()
  883. {
  884.     ' This function attempts to rally anyone in the leader's range.
  885.     ' The return value is 1 if someone was rallied and 0 if not.
  886.  
  887.     var outOfRangeUnits, numUnitsOutOfRange, routingUnitsInRange, unit, notInRange,
  888.          routing, retVal;
  889.  
  890.     outOfRangeUnits = GetList();
  891.     numUnitsOutOfRange = GetUnitsOutOfRange(outOfRangeUnits);
  892.  
  893.     ' Get a list of units that are in range and routing...
  894.     routingUnitsInRange = GetList();
  895.     GroupListReset();
  896.     unit = GroupListGetNext();
  897.     while (unit != -1)
  898.     {
  899.         notInRange = IsMemberOf(outOfRangeUnits, unit);
  900.         routing = False;
  901.         if (NOT notInRange)
  902.         {
  903.             watch "Looking at unit " unit;
  904.             routing = Query(ROUTING, unit);
  905.             if (routing)
  906.                 write "He IS routing"
  907.             else
  908.                 write "He is NOT routing";
  909.         };
  910.         if (routing)
  911.         {
  912.             watch "Found a routing unit: " unit;
  913.             retVal = AttemptToRally(unit);
  914.             return retVal;
  915.         };
  916.         unit = GroupListGetNext();
  917.     };
  918.     write "Couldn't find any units to rally!";
  919. };
  920.  
  921. procedure PartialRecover()
  922. {
  923.     ' Find any unit that is within 3 cohesion hits or routing and recover him
  924.  
  925.     var unitsOutOfRange, numUnitsOutOfRange, notInRange, unit, tq, cohesionHit,
  926.          difference;
  927.  
  928.     write "Here in PartialRecover";
  929.     unitsOutOfRange = GetList();
  930.     numUnitsOutOfRange = GetUnitsOutOfRange(unitsOutOfRange);
  931.     GroupListReset();
  932.     unit = GroupListGetNext();
  933.     while (unit!=-1)
  934.     {
  935.         notInRange = IsMemberOf(unitsOutOfRange, unit);
  936.         if (NOT notInRange)
  937.         {
  938.             cohesionHit = Query(COHESION_HIT, unit);
  939.             tq = Query(TROOP_Q, unit);
  940.             difference = tq-cohesionHit;
  941.             if (difference <= 3)
  942.             {
  943.                 Recover(unit);
  944.             watch "Recovered unit: " unit;
  945.                 return 1;
  946.             };
  947.         };
  948.       unit = GroupListGetNext();
  949.     };
  950.    return 0;
  951. };
  952.  
  953. procedure RecoverUnits()
  954. {
  955.     ' Find all the units within range and recover he who has the most cohesion
  956.     ' hits.
  957.  
  958.     var unitsOutOfRange, numUnitsOutOfRange, notInRange, unit, highUnit,
  959.          highCH, cohesionHit;
  960.  
  961.     write "Here in RecoverUnits";
  962.     unitsOutOfRange = GetList();
  963.     numUnitsOutOfRange = GetUnitsOutOfRange(unitsOutOfRange);
  964.     highCH = 0;
  965.     highUnit = -1;
  966.     GroupListReset();
  967.     unit = GroupListGetNext();
  968.     while (unit != -1)
  969.     {
  970.         notInRange = IsMemberOf(unitsOutOfRange, unit);
  971.         if (NOT notInRange)
  972.         {
  973.             watch "Looking at unit " unit;
  974.             cohesionHit = Query(COHESION_HIT, unit);
  975.             if (cohesionHit > highCH)
  976.             {
  977.                 highCH = cohesionHit;
  978.                 highUnit = unit;
  979.                 watch "New high cohesion hit: " highCH;
  980.             };
  981.         };
  982.       unit = GroupListGetNext();
  983.     };
  984.     if (highUnit == -1)
  985.     {
  986.         write "There weren't any units that needed recovering...";
  987.         return -1;
  988.     };
  989.     Recover(highUnit);
  990.     return highUnit;
  991. };
  992.