Advertisement
Guest User

CivDOS - AI "unit's orders" routine (complete/unreviewed)

a guest
Jun 16th, 2014
1,050
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 48.36 KB | None | 0 0
  1. //This post aims to describe, in pseudo-code, the AI logic for moving units around (excluding Barbarians which have their own logic).
  2.  
  3. //All address references are assuming CIV.EXE version 474.01, unless specified otherwise.
  4.  
  5. //Note that, as this is pseudo-code, it may inevitably contain typos and inconsistencies, as well as some undocumented global variables.
  6.  
  7. //Manually reversed by darkpanda (darkpandaman @ gee mail.com) - 2014/06/16
  8.  
  9. /*
  10.  * This routine takes a unit (and its owner Civ) as an input, and
  11.  * returns a "command code", which can be a direction (next square
  12.  * to move to) or an order (skip turn, build city, etc.).
  13.  *   Function signature:
  14.  */
  15.  
  16. //seg010:0C76
  17. int AIprocessUnit(int civID, int unitID) {
  18.  
  19.     //seg010_C9A: to seg010_CA3:
  20.     if(civ == Barbarians)  return AImoveBarbarianUnit(civID, unitID); // specific logic for Barbarian units
  21.    
  22.     Unit unit = Units[civID][unitID];
  23.    
  24.     //seg010_CB4:
  25.     if(unit.typeID == 0xF) { // is it a Bomber ?
  26.         //seg010_CCE:
  27.         if(unit.specialMoves <= 0) {
  28.             //seg010_CD8:
  29.             return 0x68; // 'h' -> presumably, go Home or stay put
  30.         }
  31.     }
  32.    
  33.     //seg010_CDE:
  34.     if(unit.typeID == 0xE) { // is it a Fighter jet?
  35.         //seg010_CF8:
  36.         if(unit.gotoX == -1) { // if it is not already on the move (GoTo)
  37.             //seg010_D02:
  38.             if(unit.remainingMoves < 3*(FIGHTER.totalMoves/2) ) {
  39.                 //seg010_D26:
  40.                 return 0x68; // 'h' -> presumably, go Home or stay put
  41.             }
  42.             //seg010_D2C:
  43.             int shortestDist = 999;
  44.             int closestUnitID = -1;
  45.             int dist = 999;
  46.             for(int unitLoop = 0; unitLoop<128; unitLoop++) {
  47.                 //seg010_D4B:
  48.                 if(Units[playerCivID][unitLoop].typeID == 0xF) { // look for human player's Bombers
  49.                     //seg010_D66:
  50.                     if((Units[playerCivID][unitLoop].visibleFlag & (1<<civID)) !=0) { // if AI can see player's Bomber
  51.                         Unit bomber = Units[playerCivID][unitLoop];
  52.                         dist = distance(unit.x, bomber.x, unit.y, bomber.y);
  53.                         if(dist<shortestDist) {
  54.                             //seg010_DBC:
  55.                             shortestDist = dist;
  56.                             closestUnitID = unitLoop;
  57.                         }
  58.                     }
  59.                 }
  60.             }
  61.             //seg010_DCB:
  62.             if(closestUnitID != -1) {
  63.                 Unit closestBomber = Units[playerCivID][closestUnitID];
  64.                 //seg010_DD4:
  65.                 if(dist>1) { // potential bug here: shouldn't we rather look at shortestDist?
  66.                     //seg010_DDD:
  67.                     if(FIGHTER.totalMoves > dist) {
  68.                         //seg010_E01:
  69.                         unit.GoToX = bomber.x;
  70.                         unit.GoToY = bomber.y;
  71.                     } else {
  72.                         //seg010_E25:
  73.                         shortestDistance = 999;
  74.                         int closestCityID = -1;
  75.                         //seg010_E3A:
  76.                         for(int cityLoop=0; cityLoop<128; cityLoop++) {
  77.                             City city = Cities[cityLoop];
  78.                             //seg010_E44:
  79.                             if(city.status != -1) { // if city exists
  80.                                 //seg010_E56:
  81.                                 if(city.ownerID == civID) { // city belongs to AI civ
  82.                                     //seg010_E66:
  83.                                     dist = distance(city.x, unit.x, city.y, unit.y);
  84.                                     if(FIGHTER.totalMoves >= dist) {
  85.                                         //seg010_EB8:
  86.                                         dist = distance(city.x, closestBomber.x, city.y, closestBomber.y);
  87.                                         if(dist<shortestDist) {
  88.                                             //seg010_F03:
  89.                                             shortestDist = dist;
  90.                                             closestCityID = cityLoop;
  91.                                         }
  92.                                     }
  93.                                 }
  94.                             }
  95.                         }
  96.                         if(closestCityID==-1) {
  97.                             return 0x20; // ' ' blank space... presumably, skip turn?
  98.                         }
  99.                         unit.GoToX = city.x;
  100.                         unit.GoToY = city.y;
  101.                     }
  102.                 }
  103.             }
  104.         }
  105.     } // end of seg010_CDE:
  106.    
  107.     //seg010_F4C:
  108.     // init a bunch of variables
  109.     boolean enemyUnitNearby = isEnemyUnitNearby(civID, unit.x, unit.y); // check if an enemy unit is nearby
  110.     int bestNeighbourID = 0;
  111.     int unitX = unit.x;
  112.     int unitY = unit.y;
  113.     int unitType = unit.typeID;
  114.     int closestCity = findNearestCity(unitX, unitY);
  115.     unit.typeID = -1; // quick hack to bluff the next function call, which would otherwise return the unit itself
  116.     int closestUnitID = findNearestFriendlyUnit(civID, unitID, unitX, unitY); // this call also sets a global variable "glob_distanceToNearestCityOrUnit"
  117.     int distToClosestCity = glob_distanceToNearestCityOrUnit;
  118.     unit.typeID = unitType; // rollback unit type
  119.     int terrainType = getTerrainType(unitX, unitY);
  120.     int unitRole = unit.role; // 0 - settler, 1 - land attack, 2 - defense, 3 - sea attack, 4 - air attack, 5 - transport, 6 - civilian
  121.     int continentID = getContinentOrOceanID(unitX, unitY);
  122.     int AIcontinentPolicy = PerContinentCivAIpolicy[civID][continentID];
  123.     int civFlag = (1 << civID);
  124.    
  125.     if(unitType == 0x19) { // if unit is Nuclear
  126.         //seg010_102F:
  127.         int bestNukeAppeal = -1;
  128.         //seg010_103F:
  129.         int cityLoop;
  130.         for(cityLoop=0; cityLoop<128; cityLoop++) {
  131.             City city = Cities[cityLoop];
  132.             //seg010_1049:
  133.             int cityOwner_nukeAppeal_landValue = city.ownerID;
  134.             if(city.status != -1) {
  135.                 //seg010_1063:
  136.                 if(!city.has(SDI_DEFENSE)) {
  137.                     //seg010_106E:
  138.                     int AImilitaryPower = PerCivTotalMilitaryPower[civID];
  139.                     if( (3*AImilitaryPower <= 2*PerCivTotalMilitaryPower[cityOwner]) // if 2*AI power is less than 2*city owner power ...
  140.                             //seg010_1092:
  141.                             || (CivDiplomaticStatus[civID][cityOwner] & 0x8) != 0 // ... or AI is in vendetta with city owner
  142.                             ||
  143.                                 //seg010_10A3:
  144.                                 (PerCivActiveUnits[cityOwner][0x19] == 0 // ... or ( city owner has no nukes ...
  145.                                     &&
  146.                                 //seg010_10B5:
  147.                                 AImilitaryPower < 2*PerCivTotalMilitaryPower[cityOwner]) // ... and AI power is less than twice city owner power )
  148.                             ) {
  149.                         //seg010_10BD:
  150.                         if((CivDiplomaticStatus[civID][cityOwner] & 0x82) == 0x80) { // if AI and city owner are in nuke stance (0x80) and NOT at peace (0x2)
  151.                             //seg010_10D6:
  152.                             if(city.size > 4) {
  153.                                 //seg010:10E8:
  154.                                 cityOwner_nukeAppeal_landValue = 0;
  155.                                 //seg010_10F8:
  156.                                 for(int neighbourLoop=0; neighbourLoop<8; neighbourLoop++) {
  157.                                     //seg001_1101:
  158.                                     int nx = city.x + RelativeCitSqaureX_3[neighbourLoop];
  159.                                     int ny = city.y + RelativeCitSqaureY_3[neighbourLoop];
  160.                                     int nID = whatCivOccupies(nx, ny);
  161.                                     if(nID != -1) {
  162.                                         //seg010_1142:
  163.                                         if((CivDiplomaticStatus[civID][nID] & 0x82) == 0x80) {
  164.                                             //seg010_115D:
  165.                                             cityOwner_nukeAppeal_landValue++;
  166.                                         }
  167.                                         //seg010_1163:
  168.                                         else if (civID!= nID) {
  169.                                             //seg010_116E:
  170.                                             cityOwner_nukeAppeal_landValue -= 2;
  171.                                         } else { // civID == nID
  172.                                             //seg010_1175:
  173.                                             cityOwner_nukeAppeal_landValue -= 99;
  174.                                         }
  175.                                     }
  176.                                 }
  177.                                 //seg010_117C:
  178.                                 cityOwner_nukeAppeal_landValue += (city.size/2);
  179.                             }
  180.                         }
  181.                     }
  182.                 }
  183.             }
  184.             //seg010_1191:
  185.             if(cityOwner_nukeAppeal_landValue > bestNukeAppeal) {
  186.                 //seg010_119C:
  187.                 boolean nukeLaunchSiteAvailable = false;
  188.                 //seg010_11AC:
  189.                 for(int launchSiteLoop=0; launchSiteLoop<128; launchSiteLoop++) {
  190.                     City launchSite = Cities[launchSiteLoop];
  191.                     //seg010_11B6:
  192.                     if(launchSite.status != -1) {
  193.                         //seg010_11C8:
  194.                         if(launchSite.ownerID == civID) {
  195.                             //seg010_11D5:
  196.                             if(distance(launchSite.x, city.x, launchsite.y, city.y) <= NUCLEAR.totalMoves) { // in CIV.EXE, hardcoded as '0x10'
  197.                                 //seg010_1209:
  198.                                 launchSiteAvailable = true;
  199.                                 break;
  200.                             }
  201.                         }
  202.                     }
  203.                 }
  204.                 //seg010_1214:
  205.                 if(launchSiteAvailable) {
  206.                     //seg010_121D:
  207.                     bestNukeAppeal = cityOwner_nukeAppeal_landValue;
  208.                     closestCityID = cityLoop;
  209.                 }
  210.             }
  211.         }// end for cityLoop
  212.         //seg010_122C:
  213.         if(bestNukeAppeal >= 0xA) {
  214.             //seg010_1235:
  215.             if(PerCivActiveUnits[civID][0x10]>1) { // if AI has more than 1 active nukes
  216.                 //seg010_1247:
  217.                 cityLoop = closestCityID;
  218.                 unit.GoToX = Cities[cityLoop].x;
  219.                 unit.GoToY = Cities[cityLoop].y;
  220.                 //seg010_1280:
  221.                 for(int neighbourLoop=1; neighbourLoop<8; neighbourLoop++) {
  222.                     //seg010_1289:
  223.                     int nx = unit.GoToX + RelativeCitySquareX_3[neighbourLoop];
  224.                     int ny = unit.GoToY + RelativeCitySquareY_3[neighbourLoop];
  225.                     if(whatCivOccupies(nx, ny) == -1) {
  226.                         //seg010_12CC:
  227.                         refreshMapSquareUnitStatus(civID, unitID, unitX, unitY);
  228.                         unit.x = nx;
  229.                         unit.y = ny;
  230.                         putUnitAtXY(civID, unitID, nx, ny);
  231.                         if(Cities[closestCityID].ownerID = playerCivID) {
  232.                             //seg010_1318:
  233.                             NextContactWithPlayer[civID] = -2; // Let's hold NUCLEAR talks...
  234.                         }
  235.                         //seg010_1323:
  236.                         return ( (neighbourLoop+4)%8 ); // a handy formula to select the "opposite" direction from a neighbour... this is to say "next square is the city to nuke" ...
  237.                     }
  238.                 }
  239.             }
  240.         }
  241.         return 0x20; // ' ' blanks space character, to skip turn?
  242.     }
  243.    
  244.     //seg010_1337:
  245.     if(unitType == 0x1A) { // if unit is Diplomat
  246.         //seg010_1340:
  247.         if(unit.GoToX != -1) {
  248.             //seg010_135A:
  249.             return 0; // what does this mean? nothing to do?
  250.         }
  251.         //seg010_1360:
  252.         if(Cities[closestCityID].ownerID != civID) {
  253.             //seg010_1375:
  254.             unit.GoToX = Cities[closestCityID].x;
  255.             unit.GoToY = Cities[closestCityID].y;
  256.             return 0; // what does this mean? nothing to do?
  257.         }
  258.         //seg010_139B:
  259.         deleteUnit(civID, unitID); // Diplomat is useless, just get rid of him already...
  260.     }
  261.    
  262.     //seg010_13A9:
  263.     if(unitRole == 0) { // settler role
  264.         //seg010_13B2:
  265.         resetStrategicLocationsWithinRadius(civID, 0, unitX, unitY, 0); // civ, status, x, y, radius: locations in status 'status' within 'radius' of x,y are reset to '-1'
  266.     }
  267.     //seg010_13CB:
  268.     int bestLandValue = getRelativeLandValue(unitX, unitY);
  269.     if(bestLandValue!=0) {
  270.         //seg010_13ED:
  271.         if(unitRole<3) { // settler, or land attack/defense
  272.             //seg010_13F6:
  273.             int bestNeighbour = 0;
  274.             int neighbourLoop = 1;
  275.             //seg010_1406:
  276.             for( ; neighbourLoop<=8; neighbourLoop++) {
  277.                 //seg010_140F:
  278.                 int nx = unitX + AlignXinMapRange(RelativeCitySquareX_3[neighbourLoop]);
  279.                 int ny = unitY + RelativeCitySquareY_3[neighbourLoop];
  280.                 int nval = getRelativeLandValue(nx, ny);
  281.                 if(bestLandValue<nval) {
  282.                     //seg010_1455:
  283.                     bestLandValue = nval;
  284.                     bestNeighbour = neighbourLoop;
  285.                 }
  286.                 //seg010_1461:
  287.                 if(CheckTribalHut(getTerrainType(nx, ny), nx, ny)) {
  288.                     //seg010_1486:
  289.                     if(unitRole != 0) {
  290.                         //seg010_148F:
  291.                         return neighbourLoop; // go lookup the tribal hut (if you're not a settler)
  292.                     }
  293.                 }
  294.             }
  295.             //seg010_1498:
  296.             if(currentGameTurn == 0) {
  297.                 //seg010_14A2:
  298.                 if(!UseEARTHmapFlag) { // if not playing on EARTH, and turn is 0, AI settler is compelled to build a city right away
  299.                     //seg010_14AC:
  300.                     bestLandValue = 0xF;
  301.                     bestNeighbour = 0;
  302.                 }
  303.             }
  304.             //seg010_14B6:
  305.             if(bestLandValue>=8) {
  306.                 //seg010_14BF:
  307.                 if(0xF-distToClosestCity <= bestLandValue) {
  308.                     //seg010_14CD:
  309.                     if(!enemyUnitNearby) {
  310.                         //seg010_14D6:
  311.                         if(unitRole == 0) {
  312.                             //seg010_14DF:
  313.                             if(bestNeighour == 0) {
  314.                                 //seg010_148E:
  315.                                 return 0x62; // 'b' char -> build a city right here!
  316.                             }
  317.                             //seg010_14F1:
  318.                             return bestNeighbour;
  319.                         }
  320.                         //seg010_14FA:
  321.                         setStrategicLocation(civID, unitX, unitY, 0, 2);
  322.                     }
  323.                 }
  324.             }
  325.         }
  326.     }
  327.     //seg010_1513:
  328.     if(unitRole == 0) {
  329.         //seg010_151C:
  330.         if(difficultyLevel != 0) {
  331.             //seg010_1526:
  332.             if(Cities[closestCityID].ownerID == playerCivID) {
  333.                 //seg010_153E:
  334.                 if(!enemyUnitNearby) {
  335.                     //seg010_1547:
  336.                     if(distToClosestCity > 1) {
  337.                         //seg010_1550:
  338.                         if(Cities[closestCityID].ownerID != civID) {
  339.                             //seg010_1558:
  340.                             if(PerCivTechCount[civID] < PerCivTechCount[playerCivID]) {
  341.                                 //seg010_1570:
  342.                                 cityOwner_nukeAppeal_landValue = getLandValue(unitX, unitY);
  343.                                 if(cityOwner_nukeAppeal_landValue >= 9) {
  344.                                     //seg010_1596:
  345.                                     if(14-distToClosestCity <= cityOwner_nukeAppeal_landValue) {
  346.                                         //seg010_15A4:
  347.                                         return 0x62; // 'b' char -> build a city right here!
  348.                                     }
  349.                                 }
  350.                             }
  351.                         }
  352.                     }
  353.                 }
  354.             }
  355.         }
  356.     }
  357.     //seg010_15AA:
  358.     if(hasCity(unitX, unitY)) { // unit is in a city...
  359.         //seg010_15BF:
  360.         if(unitRole == 2) { // ... and it is a defensive unit
  361.             //seg010_15C8:
  362.             if(unit.nextUnitInStack == -1) { // ... and it is alone in the city ...
  363.                 //seg010_15E2:
  364.                 return 0x66; // 'f' char -> fortify the unit
  365.             }
  366.             //seg010_15EB:
  367.             int typeBAK = unit.typeID;
  368.             unit.typeID = 0x1A; // hack: set unit type to diplomat...
  369.             int bestDefender = findBestDefensiveUnitInStack(civID, unitID); // ... so unit is excluded from the search
  370.             unit.typeID = tpyeBAK; // unit type reset to original type after search
  371.             if(bestDefender != -1) {
  372.                 //seg010_1629:
  373.                 if(UnitTypes[Units[civID][bestDefender].typeID].defense < UnitTypes[unit.typeID].defense) { // current unit has the strongest defense in the stack
  374.                     //seg010_164F:
  375.                     return 0x66; // 'f' char -> fortify the unit
  376.                 }
  377.             }
  378.             //seg010_1655:
  379.             int threatLevel; // the lower the level, the higher the threat
  380.             if(isEnemyUnitOrCityNearby(civID, unitX, unitY)) { // check if an enemy unit or city is nearby
  381.                 //seg010_166E:
  382.                 threatLevel = 3;
  383.             } else {
  384.                 //seg010_1674:
  385.                 threatLevel = 4;
  386.             }
  387.             //seg010_1677:
  388.             if(Cities[closestCityID].has(PALACE)) { // closest city is a capital
  389.                 //seg010_168C:
  390.                 threatLevel --;
  391.             } //seg010_1692:
  392.                 else if(AIcontinentPolicy == 0) {
  393.                 //seg010_169B:
  394.                 threatLevel ++;
  395.             }
  396.             //seg010_169E:
  397.             int defenderCount = unitStackRoleCount(civID, unitID, 2); // count defensive units in stack
  398.             if(defenderCount < (Cities[closestCityID]/threatLevel)+1) {
  399.                 //seg010_16CF:
  400.                 assignNewTacticalLocation(civID, unitX, unitY, 2, 2); // civ, x, y, role, priority
  401.             }
  402.             //seg010_16E8:
  403.             if(defenderCount<=(Cities[closestCityID].size/threatLevel)+1) {
  404.                 //seg010_1704:
  405.                 return 0x66; // 'f' char -> fortify the unit
  406.             }
  407.             //seg010_170A:
  408.             int tmpStatus = unit.status;
  409.             unit.status |= 0x8; // artificially fortify the unit...
  410.             if(unitID == findBestDefensiveUnitInStack(civID, unitID)) {
  411.                 //seg010_173D:
  412.                 if(aggregateUnitStackAttribute(civID, unitID, 4)<=(Cities[closestCityID].size/threatLevel)+1) { // another way to count defensive units...
  413.                     //seg010_176C:
  414.                     unit.status = tmpStatus;
  415.                     return 0x66; // 'f' char -> fortify the unit
  416.                 }
  417.                 //seg010_177A:
  418.                 unit.status = tmpStatus;
  419.                 if( ((unitID+currentGameTurn)&0x7) == 0 ) {
  420.                     //seg010_17A1:
  421.                     unit.status &= 0xF2; // rolling wake up of AI units, every 4 turns...
  422.                 }
  423.             }
  424.             //seg010_17A4:
  425.         } else { // .. and it is *not* a defensive unit
  426.             //seg010_17A7:
  427.             if(distToClosestUnit > 0) {
  428.                 //seg010_17B0:
  429.                 if(unitRole != 0) {
  430.                     //seg010_17B9:
  431.                     assignNewTacticalLocation(civID, unitX, unitY, 2, 4); // civ, x, y, role, priority
  432.                     return 0x20; // ' ' blank char, skip turn?
  433.                 }
  434.             }
  435.         }
  436.     }
  437.  
  438.     //seg010_17D8:
  439.     if(unitRole == 5 || unitRole == 3) { // maritime unit, for sea attack or transport
  440.         //seg010_17EA:
  441.         bestNeighbourID = 0;
  442.         unitRoleFlag = 0;
  443.         var_54 = 0;
  444.         int nextUnitID = unit.nextUnitInStack;
  445.         //seg010_180E:
  446.         while(nextUnitID != -1 && nextUnitID != unitID) {
  447.             //seg010_1822:
  448.             if( (Units[civID][nextUnitID].status & 0x8) == 0) { // next unit is not fortified
  449.                 //seg010_183C:
  450.                 if(UnitTypes[Units[civID][nextUnitID].typeID].terrainCategory == 0) { // land unit
  451.                     //seg010_185A:
  452.                     var_54 ++;
  453.                 }
  454.             } else {
  455.                 //seg010_1860:
  456.                 if(AIcontinentPolicy == 5) {
  457.                     //seg010_1869:
  458.                     if( (Cities[closestCityID].size/5) < (bestNeighbourID++) ) {
  459.                         //seg010_1888:
  460.                         Units[civID][nextUnitID].status &= ~0x8; // unfortify next unit
  461.                         var_54 ++;
  462.                     }
  463.                 }
  464.             }
  465.             //seg010_18A0:
  466.             nextUnitID = Units[civID][nextUnitID].nextUnitInStack;
  467.         }
  468.         //seg010_18BB:
  469.         if( ((distToClosestCity==0?3:1)<=var_54
  470.                     ||
  471.                     //seg010_18D5:
  472.                     unitRoleFlag == 1)
  473.                     &&
  474.                     //seg010_18DE:
  475.                     unitRole == 5 ) {
  476.             //seg010_18E7:
  477.             shortestDistance = 999;
  478.             int policy = -1; // ??
  479.             //seg010_18F7:
  480.             for(cityLoop=0; cityLoop<128; cityLoop++) {
  481.                 //seg010_1901:
  482.                 if(Cities[cityLoop].status != -1) { // does the city exist ?
  483.                     //seg010_1913:
  484.                     if(Cities[cityLoop].ownerID == civID) { // does the city belong to AI ?
  485.                         //seg010_1920:
  486.                         if( (Cities[cityLoop].status & 0x2) != 0) { // is it a coastal city ?
  487.                             //seg010_192D:
  488.                             distanceToUnitOrCity = distance(Cities[cityLoop].x, unitX, Cities[cityLoop].y, unitY);
  489.                             int coastalCityContinentID = getContinent(Cities[cityLoop].x, Cities[cityLoop].y);
  490.                             if(PerContinentCivDefense[civID][coastalCityContinentID] >= 0x10) {
  491.                                 //seg010_1986:
  492.                                 int unitInCoastalCity = getUnitAt(Cities[cityLoop].x, Cities[cityLoop].y);
  493.                                 if(unitInCoastalCity != -1) {
  494.                                     //seg010_19B0:
  495.                                     int transportCount = unitStackRoleCount(civID, unitInCoastalCity, 5); // count transports in stack
  496.                                     if(transportCount>(distanceToUnitOrCity<1?1:0)) {
  497.                                         //seg010_19D1:
  498.                                         distanceToUnitOrCity += 0x10;
  499.                                     }
  500.                                 }
  501.                                 //seg010_19D5:
  502.                                 if(PerContinentCivAIpolicy[civID][costalCityContinentID] == 5) {
  503.                                     //seg010_19F2:
  504.                                     distanceToUnitOrCity -= PerContinentCivAttack[civID][costalCityContinentID] / 4;
  505.                                 } else {
  506.                                     //seg010_19EB:
  507.                                     distanceToUnitOrCity += 0x10;
  508.                                 }
  509.                                 //seg010_1A13:
  510.                                 if(distanceToUnitOrCity < shortestDistance) {
  511.                                     //seg010_1A1E:
  512.                                     shortestDistance = distanceToUnitOrCity;
  513.                                     unit.GoToX = Cities[cityLoop].x;
  514.                                     unit.GoToY = Cities[cityLoop].y;
  515.                                     policy = PerContinentCivAIpolicy[civID][costalCityContinentID];
  516.                                 }
  517.                             }
  518.                         }
  519.                     }
  520.                 }
  521.                 //seg010_192A:
  522.                 //seg010_18F4:
  523.             }
  524.             //seg010_1A64:
  525.             if(policy == 5) {
  526.                 //seg010_1A6D:
  527.                 distanceToUnitOrCity = 4;
  528.             } else {
  529.                 //seg010_1A73:
  530.                 distanceToUnitOrCity = 2;
  531.             }
  532.             //seg010_1A76:
  533.             if(distanceToUnitOrCity*3 >= shortestDistance) {
  534.                 //seg010_1A87:
  535.                 if(policy != 0) {
  536.                     //seg010_1A90:
  537.                     assignNewTacticalLocation(civID, unit.GoToX, unit.GoToY, 0, distanceToUnitOrCity);
  538.                 }
  539.                 //seg010_1AC0:
  540.                 if(policy != 2) {
  541.                     //seg010_1AC9:
  542.                     assignNewTacticalLocation(civID, unit.GoToX, unit.GoToY, 2, distanceToUnitOrCity);
  543.                 }
  544.                 //seg010_1AF9:
  545.                 if(policy != 1) {
  546.                     //seg010_1B02:
  547.                     assignNewTacticalLocation(civID, unit.GoToX, unit.GoToY, 1, distanceToUnitOrCity);
  548.                 }
  549.             }
  550.             //seg010_1B32: goto seg010_2192, after the 'else'
  551.         } else {
  552.             //seg010_1B35:
  553.             if(unitRole == 5) {
  554.                 //seg010_1B3E:
  555.                 int neighbourLoop=1
  556.                 //seg010_1B49:
  557.                 for(; neighbourLoop<=8; neighbourLoop++) {
  558.                     //seg010_1B52:
  559.                     int nx = AlignXinMapRange(unitX + RelativeCitSqaureX_3[neighbourLoop]);
  560.                     int ny = unitY + RelativeCitSqaureY_3[neighbourLoop];
  561.                     int nID = whatCivOccupies(nx, ny);
  562.                     if(getTerrainType(nx, ny) != 0xA) { // if neighbour square is not ocean...
  563.                         //seg010_1B9B:
  564.                         if(inMapRange(nx, ny)) {
  565.                             //seg010_1BB1:
  566.                             if(nID == -1
  567.                                     ||
  568.                                 //seg010_1BBA:
  569.                                 nID == civID) {
  570.                                 //seg010_1BC5:
  571.                                 if(nID != civID
  572.                                         ||
  573.                                     //seg010_1BD0:
  574.                                     aggregateUnitStackAttribute(civID, getUnitAt(nx, ny), 2) < 2) { // total unit count less than 2
  575.                                         //seg010_1BF9:
  576.                                         if( (CivDiplomaticStatus[civID][playerCivID] & 0x2) == 0 // not at peace with player...
  577.                                                     ||
  578.                                                 //seg010_1C10:
  579.                                                 getLandOwner(nx, ny) != playerCivID // ... or player not owner of neighbour ...
  580.                                                     ||
  581.                                                 //seg010_1C27:
  582.                                                 (getImprovements(nx, ny) & 0xF) == 0) { // ... or no improvements at all on neighbour
  583.                                             //seg010_1C3F:
  584.                                             coastalCityContinentID = getContinentOrOceanID(nx, ny);
  585.                                             int var_3C = 0;
  586.                                             if( (PerContinentCivDefence[civID][coastalCityContinentID] < 0x10
  587.                                                         &&
  588.                                                     //seg010_1C6D:
  589.                                                     PerContinentCivAIpolicy[civID][coastalCityContinentID] != 5)
  590.                                                     ||
  591.                                                     //seg010_1C77:
  592.                                                 (((1<<PerContinentCivAIpolicy[civID][coastalCityContinentID]) & unitRoleFlag) & 0x6) != 0) {
  593.                                                 //seg010_1C95:
  594.                                                 var_3C = 1;
  595.                                             }
  596.                                             //seg010_1C9A:
  597.                                             if(unit.GoToX != -1) {
  598.                                                 //seg010_1CB4:
  599.                                                 if(getContinentOrOceanID(unit.GoToX, unit.GoToY) == coastalCityContinentID) {
  600.                                                     //seg010_1CD2:
  601.                                                     var_3C = 1;
  602.                                                 }
  603.                                             }
  604.                                             //seg010_1CD7:
  605.                                             if(var_3C != 0) {
  606.                                                 //seg010_1CE0:
  607.                                                 if(PerContinentBuildableSquareCount[coastalCityContinentID] >= 5) {
  608.                                                     //seg010_1CEF:
  609.                                                     if(ny>1) {
  610.                                                         //seg010_1CF8:
  611.                                                         if(ny<0x30) {
  612.                                                             //seg010_1D01:
  613.                                                             if(unit.remainingMoves>3) {
  614.                                                                 //seg010_1D1B:
  615.                                                                 int bestNeighbourForLandingSites = findNeighbourWithMaximumLandingSites(civID, unitX, unitY);
  616.                                                                 if(bestNeighbourForLandingSites > 0) {
  617.                                                                     //seg010:1D38     seg010_1D38:                            ; CODE XREF: AIprocessUnit_civID_unitID+10BDj
  618.                                                                     //seg010:1D38 064                 mov     ax, [bp+var_cityOwner_or_nukeAppeal_or_landValue_or_defenderCount_or_policy]
  619.                                                                     //seg010:1D3B 064                 jmp     seg010_344B     ; Jump
  620.                                                                     return bestNeighbourForLandingSites;
  621.                                                                 }
  622.                                                             }
  623.                                                             //seg010_1D3E:
  624.                                                             if(PerContinentCivAIpolicy[civID][coastalCityContinentID] == 1) {
  625.                                                                 //seg010:1D54
  626.                                                                 assignNewTacticalLocation(civID, unitX, unitY, 3, 5);
  627.                                                             }
  628.                                                             //seg010:1D6D
  629.                                                             unit.remainingMoves = 0;
  630.                                                             unit.GoToX = -1;
  631.                                                             return 0x75; // 'u' char -> no idea what this means...
  632.                                                         }
  633.                                                     }
  634.                                                 }
  635.                                             }
  636.                                             //seg010_1D90:
  637.                                             if( (currentGameTurn & 0x3) == 0) { // every 4 turns, remove GoTo from units
  638.                                                 //seg010_1D9A:
  639.                                                 unit.GoToX = -1;
  640.                                             }
  641.                                             break; // if starting at seg010_1BF9, jumping to seg010_1DB5:
  642.                                         }
  643.                                 }
  644.                             }
  645.                         }
  646.                     }
  647.                     //seg010_1B46:  loop increment
  648.                 }
  649.                 //seg010_1DB5:
  650.                 if(unit.remainingMoves <= 3) {
  651.                     //seg010_1DCF:
  652.                     int nx = (unit.x + unit.GoToX)/2;
  653.                     int ny = (unit.y + unit.GoToY)/2;
  654.                     if(unit.GoToX != -1) {
  655.                         //seg01_1DFF:
  656.                         if(getTerrainType(nx, ny) == 0xA) { // middle square is ocean ?
  657.                             //seg010_1E18:
  658.                             assignNewTacticalLocation(civID, nx, ny, 3, 3);
  659.                         }
  660.                     }
  661.                 }
  662.             }
  663.             //seg010_1E31:
  664.             if(!enemyUnitNearby
  665.                 //seg010_1E3A:
  666.              || unitRole == 5) {
  667.                 //seg010_1E43:
  668.                 if(unit.GoToX == -1) {
  669.                     //seg010_1E5D:
  670.                     if( (unitRoleFlag & 0x2) != 0
  671.                         //seg010_1E66:
  672.                         || (unitRoleFlag & 0x1) == 0) {
  673.                         //seg310_1E6F:
  674.                         if(unit.typeID != 0x10) { // if unit is not Trireme
  675.                             //seg010_1E89:
  676.                             shortestDistance = 999;
  677.                             int loop = currentGameTurn & 0x7;
  678.                             //seg010_1E9E:
  679.                             for(; loop<128; loop+=8) {
  680.                                 //seg010_1EA8:
  681.                                 cityOwner = Cities[loop].ownerID;
  682.                                 if(Cities[loop].status != -1) {
  683.                                     //seg010_1EC2:
  684.                                     if(civID != cityOwner) {
  685.                                         //seg010_1ECD:
  686.                                         if( (CivDiplomaticStatus[civID][cityOwner] & 0x102) != 0x2 ) { // don't know what 0x100 stands for (0x2 is PEACE)
  687.                                             //seg010_1EE8:
  688.                                             if(CivRankings[playerCivID]<7
  689.                                                     //seg010_1EF8:
  690.                                                     || cityOwner == playerCivID) {
  691.                                                 //seg010_1F03:
  692.                                                 distanceToUnitOrCity = distance(unitX, Cities[loop].x, unitY, Cities[loop].y);
  693.                                                 if(distanceToUnitOrCity < shortestDistance) {
  694.                                                     //seg010_1F35:
  695.                                                     shortestDistance = distanceToUnitOrCity;
  696.                                                     unit.GoToX = Cities[loop].x;
  697.                                                     unit.GoToY = Cities[loop].y;
  698.                                                 }
  699.                                             }
  700.                                         }
  701.                                     }
  702.                                 }
  703.                             }// end for loop at seg010_1E9E
  704.                         }
  705.                     }
  706.                 }
  707.                 //seg010_1F5E:
  708.                 if(unit.GoToX == -1) { // no destination yet
  709.                     //seg010_1F78:
  710.                     if(unit.typeID != 0x10) { // not a Trireme
  711.                         //seg010_1F82:
  712.                         shortestDistance = 999;
  713.                         neighbourLandValue = -1;
  714.                         if(getTerrainType(unitX, unitY) != 0xA) { // unit is not at sea
  715.                             //seg010_1FA2:
  716.                             neighbourLandValue = continentOrOceanID;
  717.                         }
  718.                         //seg010_1FA8:
  719.                         int loop = 0;
  720.                         //seg010_1FB3:
  721.                         for(; loop<128; loop++) {
  722.                             //seg010_1FBD:
  723.                             cityOwner = Cities[loop].ownerID;
  724.                             if(Cities[loop].status != -1) {
  725.                                 //seg010_1FD7:
  726.                                 if(cityOwner == civID) {
  727.                                     //seg010_1FE2:
  728.                                     distanceToUnitOrCity = distance(unitX, Cities[loop].x, unitY, Cities[loop].y);
  729.                                     if(distanceToUnitOrCity >= 8) {
  730.                                         //seg010_200D:
  731.                                         coastalCityContinentID = getContinentOrOceanID(Cities[loop].x, Cities[loop].y);
  732.                                         if(coastalCityContinentID != neighbourLandValue) {
  733.                                             //seg010_203C:
  734.                                             if(PerContinentCivAIpolicy[civID][coastalCityContinentID] != 5) {
  735.                                                 //seg010_2055:
  736.                                                 if( (((1<<PerContinentCivAIpolicy[civID][coastalCityContinentID]) & unitRoleFlag) & 0x7) == 0) {
  737.                                                     //seg010_2073:
  738.                                                     distanceToUnitOrCity <<= 1; // multiply by 2
  739.                                                 }
  740.                                                 //seg010_2076:
  741.                                                 if(shortestDistance>distanceToUnitOrCity) {
  742.                                                     //seg010_2081:
  743.                                                     shortestDistance = distanceToUnitOrCity;
  744.                                                     unit.GoToX = Cities[loop].x;
  745.                                                     unit.GoToY = Cities[loop].y;
  746.                                                 }
  747.                                             }
  748.                                         }
  749.                                     }
  750.                                 }
  751.                             }
  752.                         }
  753.                     }
  754.                 }
  755.                 //seg010_20B2:
  756.                 if(unit.GoToX == -1) { // still no destination... so we will do some random exploration
  757.                     //seg010_20CC:
  758.                     int loop = 2;
  759.                     //seg010_20D7:
  760.                     for(; loop<24; loop++) {
  761.                         //seg010_20E0:
  762.                         int randomNeighbour = random(9);
  763.                         int nx = AlignXinMapRange(loop * RelativeCitySquareX_3[randomNeighbour] + unitX);
  764.                         int ny = loop * RelativeCitySquareX_3[randomNeighbour] + unitY;
  765.                         if(ny>2) {
  766.                             //seg010_213A:
  767.                             if(ny<47) {
  768.                                 //seg010_2143:
  769.                                 if(getTerrainType(nx, ny) != 0xA){
  770.                                     //seg010_2159:
  771.                                     if(PerContinentCivCityCount[civID][getContinentOrOceanID(nx, ny)] == 0) {
  772.                                         //seg010_217E:
  773.                                         unit.GoToX = nx;
  774.                                         unit.GoToY = ny;
  775.                                         break; // goto seg010_2192:
  776.                                     }
  777.                                 }
  778.                             }
  779.                         }
  780.                     }// end for loop at seg010_20D7
  781.                 }
  782.             }
  783.         }
  784.     }
  785.  
  786.     //seg010_2192:
  787.     if(UnitTypes[unit.typeID].totalMoves < 2) { // unit type has less than 2 total moves
  788.         //seg010_21B4:
  789.         if(distToClosestCity<4) { // closest city is less than 4 moves away
  790.             //seg010_21BD:
  791.             if(Cities[closestCity].ownerID == playerCivID) { // closest city belongs to player
  792.                 //seg010_21D5:
  793.                 if( (CivDiplomaticStatus[civID][playerCivID]&2) == 0 ) { // not at Peace with player
  794.                     //seg010_21EC:
  795.                     if( (getImprovements(unitX, unitY) & 0x6) != 0) { // there is Mine or Irrigation on unit square (do you see it coming?)
  796.                         //seg010_2201:
  797.                         if(Cities[closestCity].ownerID != civID) { // closest city does not belong to AI civ itself (useless because of player check above...)
  798.                             //seg010_220C:
  799.                             return 0x50; // 'P' char -> pillage the square
  800.                         }
  801.                     }
  802.                 }
  803.             }
  804.         }
  805.     }
  806.    
  807.     //seg010_2212
  808.     if(unitRole == 0) { // Settlers
  809.         //seg010_221B:
  810.         if(terrainType != 0xA) { // terrain is not Ocean
  811.             //seg010_2224:
  812.             if(distToClosestUnit >= 2) { // closest unit is 2 or more moves away
  813.                 //seg010_222D:
  814.                 assignNewTacticalLocation(civID, unitX, unitY, 2, 2); // civ, x, y, role, priority
  815.             }
  816.             //seg010_2246:
  817.             if(
  818.                 //seg010_2263:
  819.                 (!Civ[civID].knows(MONARCHY) && TerrainImprovementRules[terrainType].canAIimproveBeforeMonarchy)
  820.                   ||
  821.                 //seg010_225D:  
  822.                 (Civ[civID].knows(MONARCHY) && TerrainImprovementRules[terrainType].canAIimproveAfterMonarchy)
  823.                   ||
  824.                 //seg010_227A:
  825.                 (AIcontinentPolicy == 5)) {
  826.                     //seg010_2283:
  827.                     if(distToClosestCity > 0) {
  828.                         //seg010_228C:
  829.                         if(distToClosestCity <= 2) {
  830.                             //seg010_2295:
  831.                             if(Cities[closestCity].ownerID == civID) { // city belongs to AI civ
  832.                                 //seg010_22AA:
  833.                                 if(
  834.                                     (Cities[closestCity].actualSize >= 3) // city size larger or equal to 3
  835.                                       ||
  836.                                     //seg010_22B4:
  837.                                     (terrainType != 0x4) // terrain is not Hills
  838.                                       ||
  839.                                     //seg010_22BD:
  840.                                     (hasSpecialRsource(unitX, unitY, terrainType)) // unit square has special resource
  841.                                     ) {
  842.                                     //seg010_22D6:
  843.                                     if( (debugSwitches & 0x2) != 0 ) { // debug switches...
  844.                                         //seg010_22E0:
  845.                                         switch( CheckPossibleTerrainImprovementBonus(unitX, unitY) ) { /* This sub-routine checks a square for potential improvements and returns:
  846.                                                                                                                                                                              - 0 if the square is already improved or has a city
  847.                                                                                                                                                                              - 2 if mining the square can provide at least 2 shields
  848.                                                                                                                                                                              - 1 if irrigating the sqaure can provide at 1 food and the sqaure is next to an ocean or river square
  849.                                                                                                                                                                              - 0 otherwise
  850.                                                                                                                                                                         */
  851.                                             //seg010_232A:
  852.                                             case 1: // irrigation is the best
  853.                                                 //seg010_22F1:
  854.                                                 unit.GoToX = -1;
  855.                                                 return 0x69; // 'i' char -> irrigate
  856.                                             //seg010_2332:
  857.                                             case 2: // mining is the best
  858.                                                 //seg010_230C:
  859.                                                 unit.GoToX = -1;
  860.                                                 return 0x6D; // 'm' char -> mine
  861.                                             default:
  862.                                         }
  863.                                         //seg010_233D:
  864.                                         int var_impr = getAbsoluteTerrainImprovements(unitX, unitY);
  865.                                         if((var_impr&0x6)!= 0 // square has mine or irrigation
  866.                                             &&
  867.                                            //seg010_2357:
  868.                                            (var_impr&0x8)== 0 // square does not have road
  869.                                             &&
  870.                                            //seg010_2360:
  871.                                            (terrainType <= 2) // square is DESERT, PLAINS or GRASSLAND
  872.                                            ) {
  873.                                             //seg010_2369:
  874.                                             unit.GoToX = -1;
  875.                                             return 0x72; // 'r' char -> build road
  876.                                         }
  877.                                         //seg010_2384:
  878.                                         if( (var_impr&0x18) != 0x18 ) { // square not railroaded yet: 0x10 = railroad flag, 0x8 = road flag
  879.                                             //seg010_2390:
  880.                                             if(Civ[civID].knows(RAILROAD)) {
  881.                                                 //seg010_23A7:
  882.                                                 if(getSquareProduction(unitX, unitY, SHIELDS) >= ((var_impr&0x8)!=0?1:2) {
  883.                                                     //seg010_23D4:
  884.                                                     unit.GoToX = -1;
  885.                                                     return 0x72; // 'r' char -> build road or railroad
  886.                                                 }
  887.                                             }
  888.                                         }
  889.                                     }
  890.                                 }
  891.                             }
  892.                         }
  893.                     }
  894.             }
  895.             //seg010_23EF:
  896.             if( (getAbsoluteTerrainImprovements(unitX, unitY) & 0x40) != 0 ) { // square is polluted
  897.                 //seg010_2404:
  898.                 return 0x70; // 'p' char -> depollute
  899.             }
  900.             //seg010_240A:
  901.             if(unit.GoToX != -1) {
  902.                 //seg010_2424:
  903.                 if((Civs[civID].leaderExpansionAttitude+1)*PerContinentBuildableSquareCount[continentOrOceanID] > (PerContinentCivCityCount[civID][continentOrOceanID]*32) ) {
  904.                     //seg010_2456:
  905.                     return 0; //?
  906.                 }
  907.             }
  908.             //seg010_245C:
  909.             if(distToClosestCity <= 1) {
  910.                 //seg010_2465:
  911.                 if(civID == Cities[closestCity].ownerID) {
  912.                     //seg010_247A:
  913.                     if(debugSwitches&0x2!=0) {
  914.                         //seg010_2484:
  915.                         int neighbourLoop = 1;
  916.                         //seg010_248F:
  917.                         while(neighbourLoop<=8) {
  918.                             //seg010_2498:
  919.                             int neighbour2 = ((neighbourLoop+currentGameTurn)&0x7)+1;
  920.                             int nx = unitX + RelativeCitySquareX_3[neighbour2];
  921.                             int ny = unitY + RelativeCitySquareY_3[neighbour2];
  922.                             Unit nunit = getUnitAt(nx, ny);
  923.                             if( (nunit==null) // no unit on neighbour square
  924.                                  ||
  925.                                     //seg010_2D49:
  926.                                     ((civID == nunit.ownerID) // neighbour square belongs to AI civ...
  927.                                       &&
  928.                                     //seg010_24E4:
  929.                                       countUnitsInStackWithRole(civID, nunit.ID, 0) == 0) // ... and no Settler on neighbour square
  930.                                       ) {
  931.                                 //seg010_2501:
  932.                                 if(
  933.                                     (!Civ[civID].knows(MONARCHY) && TerrainImprovementRules[terrainType].canAIimproveBeforeMonarchy)
  934.                                     ||
  935.                                         //seg010_2538:  
  936.                                     (Civ[civID].knows(MONARCHY) && TerrainImprovementRules[terrainType].canAIimproveAfterMonarchy)) {
  937.                                     //seg010_2544:
  938.                                     if(CheckPossibleTerrainImprovementBonus(unitX, unitY) != 0) {
  939.                                         //seg010_255A:
  940.                                         if( (Cities[closestCity].actualSize >= 3)
  941.                                                 ||
  942.                                                 //seg010_256C:
  943.                                                 getTerrain(nx, ny) != 4
  944.                                                 ||
  945.                                                 //seg010_2582:
  946.                                                 hasSpecialResource(nx, ny, 4)) {
  947.                                             //seg010_259C:
  948.                                             if(distance2(nx - Cities[closestCity].x, ny - Cities[closestCity].y) <= 2) {
  949.                                                 unit.GoToX = nx;
  950.                                                 unit.GoToY = ny;
  951.                                                 return 0; // no special order, check GoTo
  952.                                             }
  953.                                         }
  954.                                     }
  955.                                 }
  956.                             }
  957.                             neighbourLoop++;
  958.                         }
  959.                     }
  960.                 }
  961.             }
  962.             //seg010_25F3:
  963.             if( (getAbsoluteTerrainImprovements(unitX, unitY)&0x8) == 0
  964.                     &&
  965.                     //seg010_2608:
  966.                     ( (terrainType != 11) // not RIVER
  967.                         ||
  968.                         //seg010_2611:
  969.                         Civs[civID].knows(BRIDGE_BUILDING) )
  970.                 ) {
  971.                 //seg010_2628:
  972.                 if(Cities[closestCity].ownerID == civID) {
  973.                     //seg010_263D:
  974.                     if(distToClosestCity <= 2) {
  975.                         //seg010_2646:
  976.                         if(terrainType == 1 // PLAINS
  977.                                 ||
  978.                             //seg010_264F:
  979.                             terrainType == 2) { // GRASSLAND
  980.                                 //seg010_2658:
  981.                                 return 0x72; // 'r' char -> build road
  982.                         }
  983.                     }
  984.                     //seg010_265E:
  985.                     int policy = 0;
  986.                     int neighbourRoadsCount = 0;
  987.                     int neighbourRoadsFlag = 0;
  988.                     int neighbourLoop = 0;
  989.                     //seg010_2675:
  990.                     while(neighbourLoop <= 8) {
  991.                         //seg010_267E:
  992.                         if((getAbsoluteTerrainImprovements(unitX + RelativeCitySquareX_3[neighbourLoop], unitY + RelativeCitySquareY_3[neighbourLoop])&0x8)!=0) {
  993.                             //seg010_26A2:
  994.                             neighbourRoadsFlag |= (1<<(neighbourLoop-1));
  995.                             neighbourRoadsCount++;
  996.                             if((getAbsoluteTerrainImprovements(unitX + 2*RelativeCitySquareX_3[neighbourLoop], unitY + 2*RelativeCitySquareY_3[neighbourLoop])&0x8)!=0) {
  997.                                 //seg010_26D5:
  998.                                 policy = 1; // no idea what this is supposed to do...
  999.                             }
  1000.                         }
  1001.                         neighbourLoop++;
  1002.                     }
  1003.                     //seg010_26DD:
  1004.                     neighbourRoadsFlag = neighbourRoadsFlag & (neighbourRoadsFlag>>4); // high nibble AND low nibble...
  1005.                     if(neighbourRoadsFlag < 4) { // "below 4" means bits 3 and 2 are 0... hard to interpret
  1006.                         //seg010_26F0:
  1007.                         if(neighbourRoadsFlag != 0
  1008.                                 ||
  1009.                                 //seg010_26F9:
  1010.                                 (distToClosestCity==1 && terrainType <=2)) {
  1011.                             //seg010_272F:
  1012.                             return 0x72; // 'r' char -> build road
  1013.                         }
  1014.                     }
  1015.                     //seg010_270B:
  1016.                     if(neighbourRoadsCount == 1
  1017.                             &&
  1018.                             //seg010_2714:
  1019.                             policy != 0
  1020.                             &&
  1021.                             //seg010_271D:
  1022.                             TerrainType[terrainType].movementCost == 1) {
  1023.                             //seg010_272F:
  1024.                             return 0x72; // 'r' char -> build road
  1025.                     }
  1026.                 }
  1027.             }
  1028.         }
  1029.         //seg010_2735:
  1030.         if(unit.GoToX != -1) {
  1031.             //seg010_274F:
  1032.             return 0;
  1033.         }
  1034.         //seg010_2755:
  1035.         int randomNeighbour = random(20) + 1;
  1036.         int nx = unit.x/4 + RelativeCitySquareX_3[randomNeighbour];
  1037.         int ny = unit.y/4 + RelativeCitySquareY_3[randomNeighbour];
  1038.         if( seg029_1498[nx*13+ny] & 0x3 == 0 ) {
  1039.             //seg010_27B6:
  1040.             unit.GoToX = unit.x + RelativeCitySquareX_3[randomNeighbour]*4;
  1041.             unit.GoToY = unit.y + RelativeCitySquareY_3[randomNeighbour]*4;
  1042.             if( inMapRange(unit.GoToX, unit.GoToY) ) {
  1043.                 //seg010_27F4:
  1044.                 if(TerrainType[getTerrainType(unit.GoToX, unit.GoToY)].shieldProduction != 0) {
  1045.                     //seg010_281B:
  1046.                     if(getContinentOrOceanID(unit.GoToX, unit.GoToY) == continentOrOceanID) {
  1047.                         //seg010_2839:
  1048.                         return 0;
  1049.                     }
  1050.                 }
  1051.             }
  1052.             //seg010_2842:
  1053.             unit.GoToX = -1;
  1054.         }
  1055.     }
  1056.  
  1057.     //seg010_2857:
  1058.     if(unit.GoToX != -1
  1059.             &&
  1060.             //seg010_2871:
  1061.             ((unitRole != 3)
  1062.                 ||
  1063.             !isEnemyUnitNearby(civID, unit.x, unit.y)) {
  1064.         //seg010_2893:
  1065.         return 0;
  1066.     }
  1067.     //seg010_2899:
  1068.     if(unitRole == 2) { // defensive unit
  1069.         //seg010_28A2:
  1070.         if(terrainType != 10) {
  1071.             //seg010_28AB:
  1072.             if((distToClosestUnit > 1
  1073.                         //seg010_28B4:
  1074.                         && distToClosestCity <= 3
  1075.                         //seg010_:
  1076.                         && Cities[closestCity].ownerID == civID
  1077.                     ) || (
  1078.                         //seg010_28D2:
  1079.                         enemyNearby
  1080.                         &&
  1081.                         //seg010_:
  1082.                         distToClosestUnit!=0
  1083.                     ) {
  1084.                 //seg010_:
  1085.                 return 0x66; // 'f' char -> fortify
  1086.             }
  1087.         }
  1088.     }
  1089.    
  1090.     //seg010_28EA:
  1091.     if(unitRole == 0) {
  1092.         //seg010_28F3:
  1093.         if( (PerContinentBuildableSquareCount[continentOrOceanID]>>3) < PerContinentCivCityCount[civID][continentID]( {
  1094.             //seg010_291A:
  1095.             if(distToClosestCity == 0
  1096.                     &&
  1097.                     //seg010_2923:
  1098.                     Cities[closestCity].actualSize < 10) {
  1099.                 //seg010_2935:
  1100.                 return 0x62; // 'b' char -> 'build' in city, i.e. add 1 pop
  1101.             }
  1102.             //seg010_293B:
  1103.             if(Cities[closestCity].ownerID == civID) {
  1104.                 //seg010_2950:
  1105.                 if(Cities[closestCity].actualSize < 10) {
  1106.                     //seg010_295A:
  1107.                     unit.GoToX = Cities[closestCity].x;
  1108.                     unit.GoToY = Cities[closestCity].y;
  1109.                     return 0; //
  1110.                 }
  1111.             }
  1112.         }
  1113.     }
  1114.    
  1115.     //seg010_2980:
  1116.     int bestValue = -999;
  1117.     int bestNeighbour = 0;
  1118.     int var_5C = 0;
  1119.     if(isEnemyUnitOrCityNearby(civID, unitX, unitY)) {
  1120.         //seg010_29A8:
  1121.         unit.unknown9 = -1; // unknown9, here you are...
  1122.     } else {
  1123.         //seg010_29C0:
  1124.         var_5C = 1;
  1125.     }
  1126.     //seg010_29C5:
  1127.     if(unitType == 1) {
  1128.         //seg010_29CE:
  1129.         if(AIcontinentPolicy == 1) {
  1130.             //seg010_29D7:
  1131.             unitRole = 1; // Militia becomes an attack unit...
  1132.         }
  1133.     }
  1134.     //seg010_29DC:
  1135.     int neighbourLoop = 1;
  1136.     //seg010_29E7:
  1137.     while(neighbourLoop <= 8) {
  1138.         //seg010_29F0:
  1139.         int nx = alignXinMapRange(unitX + RelativeCitySquareX_3[neighbourLoop]);
  1140.         int ny = unitY + RelativeCitySquareY_3[neighbourLoop];
  1141.         if(isInMapRange(nx, ny) {
  1142.             //seg010_2A2B:
  1143.             int nOwner = getOwner(nx, ny);
  1144.             int nTerrainType = getTerrainType(nx, ny);
  1145.             if(nTerrainType != 10 // OCEAN
  1146.                     ||
  1147.                     //seg010_2A56:
  1148.                     UnitType[unit.typeID].terrainCategory != 0) {
  1149.                 //seg010_2A7B:
  1150.                 int nUnit = getUnitAt(nx, ny);
  1151.                 if(nUnit != null) {
  1152.                     if(nUnit.typeID == 26) { // Diplomat?
  1153.                         Unit nOccupant = nUnit;
  1154.                         while( (nOccupant = nOccupant.next) != null
  1155.                                 &&
  1156.                                 //seg010_2AD8;
  1157.                                 nOccupant != nUnit
  1158.                                 &&
  1159.                                 //seg010_2AE3;
  1160.                                 nOccupant.typeID == 26); //
  1161.                         //seg010_2AFE:
  1162.                         if(nOccupant =! -1) {
  1163.                             nUnit = nOccupant;
  1164.                         }
  1165.                     }
  1166.                 }
  1167.                 //seg010_2B0D:
  1168.                 if(enemyNearby &&
  1169.                         //seg010_2B16:
  1170.                         UnitTypes[unit.typeID].terrainCategory == 0 &&
  1171.                         //seg010_2B3A:
  1172.                         isEnemyUnitNearby(civID, nx, ny) &&
  1173.                         //seg010_2B5C:
  1174.                         unit.typeID < 26 &&
  1175.                         //seg010_2B64:
  1176.                         terrainType != 10) {
  1177.                     //seg010_2B6D:
  1178.                     continue;
  1179.                 }
  1180.                 //seg010_2B70:
  1181.                 if(terrainType == 10 &&
  1182.                         //seg010_2B79:
  1183.                         UnitTypes[unit.typeID].terrainCategory == 0 &&
  1184.                         //seg010_2B9B:
  1185.                         nUnit != null &&
  1186.                         //seg010_2BA4:
  1187.                         civID != nOwner) {
  1188.                     //seg010_2BAF:
  1189.                     continue;
  1190.                 }
  1191.                 //seg010_2BB2:
  1192.                 if(UnitTypes[unit.typeID].terrainCategory == 2) {
  1193.                     //seg010_2BD4:
  1194.                     if(nTerrainType != 10) {
  1195.                         //seg010_2BBD:
  1196.                         if(nUnit == null) continue;
  1197.                         //seg010_2BE6:
  1198.                         if(civID == nOwner) continue;
  1199.                         //seg010_2BF1:
  1200.                         if(unit.typeID == 0x16) continue; // submarine
  1201.                         //seg010_2BFA:
  1202.                         if(terrainType != 10) continue;
  1203.                     }
  1204.                 }
  1205.                 //seg010_2C06:
  1206.                 if(nUnit != null &&
  1207.                         //seg010_2C0F:
  1208.                         civID == nOwner &&
  1209.                         //seg010_2C1A:
  1210.                         aggregateUnitStackAttribute(civID, nUnit.ID, 2) {
  1211.                     //seg010_2C37:
  1212.                     continue;
  1213.                 }
  1214.                 //seg010_2C37:
  1215.                 if(unitRole != 0) {
  1216.                     //seg010_2C6D:
  1217.                     if(unit.visibilityFlag == 0 &&
  1218.                             //seg010_2C87:
  1219.                             terrainType != 10) {
  1220.                         //seg010_2C90:
  1221.                         if(unitRole == 1) {
  1222.                             //seg010_2C99:
  1223.                             neighbourValue = random(3) - 2*TerrainTypes[nTerrainType].movementCost;
  1224.                         } else {
  1225.                             //seg010_2CBE:
  1226.                             neighbourValue = random(3) - TerrainTypes[nTerrainType].defenseRatio;
  1227.                         }
  1228.                     } else {
  1229.                         //seg010_2CE1:
  1230.                         neighbourValue = random(5);
  1231.                         if(nUnit != null &&
  1232.                                 //seg010_2CF9:
  1233.                                 nOwner == civID) {
  1234.                             //seg010_2D04:
  1235.                             if(unitRole == 1) {
  1236.                                 //seg010_2D0D:
  1237.                                 neighbourValue += (aggregateUnitStackAttribute(civID, nUnit.ID, 1)*4) / (aggregateUnitStackAttribute(civID, nUnit.ID, 2)+1);
  1238.                             }
  1239.                             //seg010_2D40:
  1240.                             if(unitRole == 0) {
  1241.                                 //seg010_2D49:
  1242.                                 neighbourValue += 2*(TerrainTypes[nTerrainType].defenseRatio + aggregateUnitStackAttribute(civID, nUnit.ID, 1));
  1243.                             }
  1244.                             //seg010_2D71:
  1245.                             if(unitRole == 2) {
  1246.                                 //seg010_2D7A:
  1247.                                 neighbourValue += (aggregateUnitStackAttribute(civID, nUnit.ID, 3)*2)/(aggregateUnitStackAttribute(civID, nUnit.ID, 1)+1);
  1248.                             }
  1249.                         } else {
  1250.                             //seg010_2DAE:
  1251.                             neighbourValue += TerrainTypes[nTerrainType].defenseRatio*4;
  1252.                         }
  1253.                     }
  1254.                     //seg010_2DC2:
  1255.                     if( UnitTypes[unit.typeID].terrainCategroy == 1 ) {
  1256.                         //seg010_2DE4:
  1257.                         neighbourValue = random(3);
  1258.                     }
  1259.                 } else {
  1260.                     //seg010_2C40:
  1261.                     neighbourValue = 0;
  1262.                     if(terrainType == 10) {
  1263.                         //seg010_2C4E:
  1264.                         if(isNearbyEnemyUnitOrCity(civID, nx, ny)) continue;
  1265.                     }
  1266.                 }
  1267.                 //seg010_2DF3:
  1268.                 AImilitaryPower = unit.unknown9;
  1269.                 if(AImilitaryPower != -1) {
  1270.                     //seg010_2E13:
  1271.                     int var_A = abs(AImilitaryPower - neighbourLoop);
  1272.                     if(var_A > 4) {
  1273.                         //seg010_2Ee2F:
  1274.                         var_A = 8 - var_A;
  1275.                     }
  1276.                     //seg010_2E38:
  1277.                     neighbourValue -= 2*(var_A*var_A);
  1278.                 }
  1279.                 //seg010_2E43:
  1280.                 int var_1C = 0;
  1281.                 if(nUnit != null) {
  1282.                     //seg010_2E51:
  1283.                     if(civID != nOwner) {
  1284.                         //seg010_2E5C:
  1285.                         var_1C == 1;
  1286.                         if(unitRole == 0) {
  1287.                             //seg010_2E6A:
  1288.                             continue;
  1289.                         }
  1290.                         //seg010_2E6D:
  1291.                         if( (CivDiplomaticStatus[civID][nOwner] & 0x2) != 0) { // if at peace with neighbour
  1292.                             //seg010_30A2:
  1293.                             if(unitRole == 1) { // attack unit
  1294.                                 //seg010_30AB:
  1295.                                 if(AIcontinentPolicy == 1) { // attack policy on continent
  1296.                                     //seg010_30B4:
  1297.                                     if(UnitTypes[unit.typeID].terrainCategory == 0) { // current unit is land uit
  1298.                                         //seg010_30D6:
  1299.                                         if((nUnit.status & 0x8) != 0) { // if neighbour unit is fortified
  1300.                                             //seg010_30F0:
  1301.                                             if( (CivDiplomaticStatus[civID][playerCivID] & 0x3) == 1 ) { // at War with player
  1302.                                                 //seg010_310A:
  1303.                                                 if( (CivDiplomaticStatus[civID][nOwner] & 0x3) != 1 ) { // not at war with neighbour
  1304.                                                     //seg010_311E:
  1305.                                                     if( PerContinentCivCityCount[playerCivID][continentOrOceanID] != 0 ) {
  1306.                                                         //seg010_3135:
  1307.                                                         if(aggregateUnitStackAttribute(nOwner, nUnit, 2) < 2) {
  1308.                                                             //seg010_314F:
  1309.                                                             if(random(8) == 0
  1310.                                                                     ||
  1311.                                                                     //seg010_3163:
  1312.                                                                     Cities[closestCity].ownerID == playerCivID) {
  1313.                                                                 //seg010_3179:
  1314.                                                                 if((getAbosluteTerrainImprovements(nx, ny)) & 0x1 == 0) { // no city on neighbour square
  1315.                                                                     //seg010_318E:
  1316.                                                                     bribeUnit(nOwner, nUnit, civID); // attempt to bribe the neighbour unit! even if you're not a diplomat!!!
  1317.                                                                 }
  1318.                                                             }
  1319.                                                         }
  1320.                                                     }
  1321.                                                 }
  1322.                                             }
  1323.                                         }
  1324.                                     }
  1325.                                 }
  1326.                             }
  1327.                             //seg010_319F:
  1328.                             //seg010_29E4:
  1329.                             continue;
  1330.                         }
  1331.                         //seg010_2E83:
  1332.                         nUnit = getFrontLineDefensiveUnit(civID, unitID);
  1333.                         if(UnitTypes[nUnit.typeID].terrainCategory == 1) { // unit is a flyer
  1334.                             //seg010_2EB6:
  1335.                             if(unit.typeID != 0xE) { // if unit is not Fighter
  1336.                                 //seg010_2ED0:
  1337.                                 if( (getAbsoluteTerrainImprovements(nx, ny) & 0x1) == 0 ) { // no city in neighbour square
  1338.                                     //seg010_2EE5:
  1339.                                     continue;
  1340.                                 }
  1341.                             }
  1342.                         }
  1343.                         //seg010_2EE8:
  1344.                         int battleAppeal = battleRoutine(civID, unitID, nOwner, nUnit, false); // 'false' means simulation only, not real battle
  1345.                         battleAppeal = battleAppeal * (1 + aggregateUnitStackAttribute(mOwner, nUnit, 0) );
  1346.                         battleAppeal = battleAppeal / UnitTypes[unit.typeID].cost;
  1347.                         if( (getAbsoluteTerrainImprovements(nx, ny) & 0x1) != 0 ) {
  1348.                             //seg010_2F56:
  1349.                             battleAppeal = battleAppeal * 3;
  1350.                         }
  1351.                        
  1352.                         //seg010_2F5F:
  1353.                         if(unitRole == 1) {
  1354.                             //seg010_2F68:
  1355.                             if(AIcontinentPolicy == 1) {
  1356.                                 battleAppeal = battleAppeal * 3;
  1357.                             }
  1358.                         }
  1359.                         //seg010_2F7A:
  1360.                         if(unitRole == 1) {
  1361.                             //seg010_2F83:
  1362.                             if( (UnitTypes[unit.typeID].attack << 1) < aggregateUnitStackAttribute(civID, unitID, 3) ) {
  1363.                                 //seg010_2FBC:
  1364.                                 battleAppeal = battleAppeal << 1;
  1365.                             }
  1366.                         }
  1367.                        
  1368.                         //seg010_2FBF:
  1369.                         if( (civID!=0?6:12) <= battleAppeal ) {
  1370.                             //seg010_2FD9:
  1371.                             neighbourValue += battleAppeal << 2;
  1372.                         } else {
  1373.                             //seg010_2FE6:
  1374.                             neighbourValue -= 999;
  1375.                             if(unitRole == 1) { // land attack unit
  1376.                                 //seg010_2FF4:
  1377.                                 if(AIcontinentPolicy == 1) { // policy for continent is to attack
  1378.                                     //seg010_2FFD:
  1379.                                     if(UnitTypes[unit.typeID].terrainCategory == 0) { // unit terrain cat is LAND
  1380.                                         //seg010_301F:
  1381.                                         if( (nUnit.status & 0x28) != 0 ) { // neighbour Unit is Veteran (0x20) or Fortified (0x8)
  1382.                                             //seg010_3039:
  1383.                                             if(TerrainTypes[nTerrainType].defesneRatio >= 4) {
  1384.                                                 //seg010_304B:
  1385.                                                 if(aggregateUnitStackAttribute(nOwner, nUnit, 2) < 2) {
  1386.                                                     //seg010_3065:
  1387.                                                     if(random(4) == 0) {
  1388.                                                         //seg010_3079:
  1389.                                                         if( (getAbsoluteTerrainImprovements(nx, ny) & 0x1) == 0) { // no city on neighbour square
  1390.                                                             //seg010_308E:
  1391.                                                             bribeUnit(nOwner, nUnit, civID); // attempt to bribe the neighbour unit
  1392.                                                         }
  1393.                                                     }
  1394.                                                 }
  1395.                                             }
  1396.                                         }
  1397.                                     }
  1398.                                 }
  1399.                             }
  1400.                         }
  1401.                         //seg010_309F:
  1402.                     } else {
  1403.                         //seg010_31A5:
  1404.                         neighbourValue -= UnitTypes[unit.typeID].defense;
  1405.                     }
  1406.                     //seg010_31C4:
  1407.                 } else {
  1408.                     //seg010_31C7:
  1409.                     if( (getAbosluteTerrainImprovements(nx, ny) & 0x1) != 0) { // neighbour square has a city...
  1410.                         //seg010_31DC:
  1411.                         if(civID != nOwner) { // from another civ
  1412.                             //seg010_31E7:
  1413.                             neighbourValue = 999; // Yahoo! An undefended enemy city, let's take it!
  1414.                         }
  1415.                     }
  1416.                     //seg010_31EC:
  1417.                     if(hasTribalHut(mTerrainType, nx, ny) {
  1418.                         //seg010_3205:
  1419.                         neighbourValue += 20;
  1420.                     }
  1421.                 }
  1422.                 //seg010_3209:
  1423.                 if(var_5C != 0) {
  1424.                     //seg010_3212:
  1425.                     nx = unitX + 4*RelativeCitySquareX_3[neighbourLoop];
  1426.                     ny = unitY + 4*RelativeCitySquareY_3[neighbourLoop];
  1427.                     if( seg029_1498[(nx/4)*13+(ny/4)] == 0) {
  1428.                         //seg010_326D:
  1429.                         if(getTerrainType(nx, ny) != 0xA) { // neighbour TILE's square is not ocean
  1430.                             //seg010_3283:
  1431.                             if(withinMapRange(nx, ny) {
  1432.                                 //seg010_3299:
  1433.                                 neighbourValue += 8;
  1434.                             }
  1435.                         }
  1436.                     }
  1437.                     //seg010_329D:
  1438.                     int neighbourLoop2 = 1;
  1439.                     //seg010_32A8:
  1440.                     while(neighbourLoop2 <= 8) {
  1441.                         //seg010_32B1:
  1442.                         int nnx = alignXinMapRange(nx + RelativeCitySquareX_3[neighbourLoop]);
  1443.                         int nny = ny + RelativeCitySquareY_3[neighbourLoop];
  1444.                         if(inMapRange(nnx, nny) {
  1445.                             //seg010_32EC:
  1446.                             if( (MapVisibility[nnx*50+nny] & civFlag) != 0 ) { // Civ can see neighbour's neighbour
  1447.                                 //seg010_3304:
  1448.                                 if((getTerrainType(nnx, nny) != 0xA)
  1449.                                         ||
  1450.                                         //seg010_331A:
  1451.                                         UnitTypes[unit.typeID].terrainCategory == 2) {
  1452.                                     //seg010_333C:
  1453.                                     neighbourValue += 2;
  1454.                                 }
  1455.                                
  1456.                             }
  1457.                             //seg010_3340:
  1458.                             if(getUnitAt(nnx, nny) != null) {
  1459.                                 //seg010_3354:
  1460.                                 neighbourValue -= 2;
  1461.                             }
  1462.                             //seg010_3358:
  1463.                             if(unitRole == 0) {
  1464.                                 //seg010_3361:
  1465.                                 neighbourValue += TerrainTypes[getTerrainType(nnx, nny)].food;
  1466.                             }
  1467.                         }
  1468.                         //seg010_32E9:
  1469.                         //seg010_337E:
  1470.                         //seg010_32A5: loop
  1471.                         neighbourLoop2 ++;
  1472.                     }
  1473.                 }
  1474.                 //seg010_3381:
  1475.                 if(var_1C != 0) {
  1476.                     //seg010_338A:
  1477.                     if(unit.remainingMoves < 3) {
  1478.                         //seg010_33A4:
  1479.                         neighbourValue = (aggregateUnitStackAttribute(civID, unitID, 1) * neighbourValue) / rangeBound(aggregateUnitStackAttribute(civID, unitID, 3), 1, 99);
  1480.                     }
  1481.                 }
  1482.                 //seg010_33E6:
  1483.                 if(neighbourValue > bestValue) {
  1484.                     //seg010_33F1:
  1485.                     bestValue = neighbourValue;
  1486.                     bestNeighbourID = neighbourLoop;
  1487.                     var_52 = var_1C;
  1488.                 }
  1489.             }
  1490.         }
  1491.         neighbourLoop++;
  1492.     } // loop
  1493.     //seg010_3406:
  1494.     if(var_52 == 0) {
  1495.         //seg010_340F:
  1496.         if(unit.remainingMoves < 3) {
  1497.             //seg010_3429:
  1498.             bestNeighbourID = 0;
  1499.         }
  1500.     }
  1501.     //seg010_342E:
  1502.     unit.unknown9 = bestNeighbourID;
  1503.     return bestNeighbourID;
  1504. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement