Advertisement
Guest User

CivLogic.java (Java RE-port of Civ 1 for DOS)

a guest
Oct 30th, 2014
291
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 83.68 KB | None | 0 0
  1. /*
  2.  * This is a development version of a JCivED source file, reverse-engineered and
  3.  * back-ported from CIV.EXE assembly to Java (from Sid Meier's Civilization for MS-DOS)
  4.  * It covers an incomplete set of utility game functions called throughout the game.
  5.  * darkpandaman @ gmail.com - 31/10/2014
  6.  */
  7.  
  8. package dd.civ.logic.port;
  9.  
  10. import java.awt.Color;
  11. import java.awt.Graphics2D;
  12. import java.awt.geom.Point2D;
  13. import java.awt.image.BufferedImage;
  14. import java.nio.ByteBuffer;
  15. import java.util.Arrays;
  16. import java.util.Collection;
  17.  
  18. import dd.civ.data.game.model.generic.Entity;
  19. import dd.civ.data.game.model.generic.AbstractGameState;
  20. import dd.civ.data.game.model.generic.Map;
  21. import dd.civ.data.game.model.generic.MapLocation;
  22. import dd.civ.data.game.model.generic.City;
  23. import dd.civ.data.game.model.generic.Civ;
  24. import dd.civ.data.game.model.generic.Unit;
  25. import dd.civ.data.game.model.generic.UnitType;
  26. import dd.civ.data.game.model.generic.impl.AbstractCity;
  27. import dd.civ.data.game.model.sve.SVECity;
  28. import dd.civ.data.game.model.sve.SVECiv;
  29. import dd.civ.data.game.model.sve.SVEMapEntity;
  30. import dd.civ.data.game.model.sve.SVEUnit;
  31. import dd.civ.data.game.model.sve.SVEUnitType;
  32. import dd.civ.data.game.model.sve.impl.AbstractSVEUnit;
  33. import dd.civ.data.game.model.sve.impl.CivDosGameState;
  34. import dd.civ.data.game.types.Advance;
  35. import dd.civ.data.game.types.CityImprovement;
  36. import dd.civ.data.game.types.CityStatus;
  37. import dd.civ.data.game.types.DifficultyLevel;
  38. import dd.civ.data.game.types.DiplomaticAttitude;
  39. import dd.civ.data.game.types.ExpansionAttitude;
  40. import dd.civ.data.game.types.MilitaryAttitude;
  41. import dd.civ.data.game.types.TerrainImprovementType;
  42. import dd.civ.data.game.types.TerrainType;
  43. import dd.civ.data.game.types.UnitCategory;
  44. import dd.civ.data.game.types.UnitStatus;
  45. import dd.civ.data.game.types.VisibilityType;
  46. import dd.civ.data.game.types.WonderType;
  47. import dd.civ.graphics.CivDosRenderer;
  48. import dd.civ.logic.CivUtils;
  49. import dd.commons.util.Utils;
  50. import dd.jcived.util.ImageUtils;
  51. import dd.jcived.util.Palette;
  52. import dd.jcived.util.ResourceManager;
  53.  
  54. public class CivLogic {
  55.  
  56.     public static Object[][] defaultAttitudes = {
  57.         { DiplomaticAttitude.get(0), ExpansionAttitude.get(0), MilitaryAttitude.get(0) },
  58.  
  59.         { DiplomaticAttitude.get( 0), ExpansionAttitude.get( 1), MilitaryAttitude.get( 1) },//Caesar
  60.         { DiplomaticAttitude.get(-1), ExpansionAttitude.get(-1), MilitaryAttitude.get( 1) },//Hammurabi
  61.         { DiplomaticAttitude.get( 1), ExpansionAttitude.get(-1), MilitaryAttitude.get( 1) },//Frederick
  62.         { DiplomaticAttitude.get( 0), ExpansionAttitude.get( 0), MilitaryAttitude.get( 1) },//Ramesses
  63.         { DiplomaticAttitude.get(-1), ExpansionAttitude.get( 0), MilitaryAttitude.get( 1) },//Abe Lincoln
  64.         { DiplomaticAttitude.get( 0), ExpansionAttitude.get( 1), MilitaryAttitude.get(-1) },//Alexander
  65.         { DiplomaticAttitude.get(-1), ExpansionAttitude.get(-1), MilitaryAttitude.get( 0) },//M.Gandhi
  66.  
  67.         { DiplomaticAttitude.get(0), ExpansionAttitude.get(0), MilitaryAttitude.get(0) },
  68.  
  69.         { DiplomaticAttitude.get( 1), ExpansionAttitude.get( 0), MilitaryAttitude.get(-1) },//Stalin
  70.         { DiplomaticAttitude.get( 1), ExpansionAttitude.get( 0), MilitaryAttitude.get( 0) },//Shaka
  71.         { DiplomaticAttitude.get( 1), ExpansionAttitude.get( 1), MilitaryAttitude.get( 1) },//Napoleon
  72.         { DiplomaticAttitude.get( 0), ExpansionAttitude.get(-1), MilitaryAttitude.get( 1) },//Montezuma
  73.         { DiplomaticAttitude.get( 0), ExpansionAttitude.get( 0), MilitaryAttitude.get( 1) },//Mao Tse Tung
  74.         { DiplomaticAttitude.get( 0), ExpansionAttitude.get( 1), MilitaryAttitude.get( 0) },//Elizabeth I
  75.         { DiplomaticAttitude.get( 1), ExpansionAttitude.get( 1), MilitaryAttitude.get(-1) } //Genghis Khan
  76.  
  77.     };
  78.  
  79.     public static int getNormalizedSign(int n) {
  80.         return n>0?1:n<0?-1:0;
  81.     }
  82.     public static int moveUnitGoto(AbstractSVEUnit unit) {
  83.         if(unit!=null) {
  84.             int gmux = unit.getDestination().x() - unit.getLocation().x();
  85.             int gmuy = unit.getDestination().y() - unit.getLocation().y();
  86.             if(unit.owner().equals(((Entity)unit).gamesave().player())
  87.                     && Math.abs(gmux)<=1
  88.                     && Math.abs(gmuy)<=1) {
  89.                 if(Math.abs(gmux)>=40) {
  90.                     gmux = -getNormalizedSign(gmux);
  91.                 } else {
  92.                     gmux = getNormalizedSign(gmux);
  93.                 }
  94.                 gmuy = getNormalizedSign(gmuy);
  95.                 unit.setPropertyValue("gotox", (Short)(short)0xFF);
  96.                 int nid = 1;
  97.                 while(nid<=8) {
  98.                     if(gmux==CivUtils.relCitySquareX3[nid]
  99.                             && gmuy==CivUtils.relCitySquareY3[nid]) {
  100.                         return nid;
  101.                     }
  102.                 }
  103.                 return 0;
  104.             } else {
  105.                 if(!unit.category().equals(UnitCategory.AIR)) {
  106.                     int var_E = 0;
  107.                     if((Math.abs(gmux)<7||Math.abs(gmux)>73)
  108.                             && Math.abs(gmuy)<7) {
  109.                         int var_next = CivLogic.findNextPathSquare(unit, 999, unit.getDestination().x(), unit.getDestination().y());
  110.                         if(var_next != -1) {
  111.                             return var_next;
  112.                         }
  113.                         var_E = 1;
  114.                     }
  115.                     // seg016_1CE
  116.                     if(hasReachableGoto(unit)||(var_E==0)) {
  117.                         int var_next = CivLogic.findNextPathSquare(unit, 999, unit.getDestination().x(), unit.getDestination().y());
  118.                         if(var_next != -1) {
  119.                             return var_next;
  120.                         }
  121.                     }
  122.                 } else {
  123.                 }
  124.                 // seg016_1FE
  125.                 int di = Math.abs(gmuy);
  126.                 int agmux = Math.abs(gmux);
  127.                 int agmuy = Math.abs(gmuy);
  128.                 int distanceToGoTo = Math.abs(Math.abs(gmux)<=agmuy?agmuy:agmux)+agmux+di;
  129.                 if(gmux==0&&gmuy==0) {
  130.                     unit.setPropertyValue("goto_next_direction", (Short)(short)0xFF);
  131.                     unit.setPropertyValue("gotox", (Short)(short)0xFF);
  132.                     unit.setPropertyValue("remaining_moves", (Short)(short)0);
  133.                     return -1;
  134.                 }
  135.                 // seg016_298
  136.                 int bestMoveScore = 9999;
  137.                 int next = 0;
  138.  
  139.                 boolean roadUnderUnit = ((Entity)unit).gamesave().hasTerrainImprovement(unit.getLocation().x(), unit.getLocation().y(), false, TerrainImprovementType.ROAD);
  140.  
  141.                 boolean unitNextToEnemy = checkSquareNextToEnemyUnit(unit.owner(), unit.getLocation().x(), unit.getLocation().y());
  142.  
  143.                 for(int nid=1;nid<9;nid++) {
  144.                     //seg016_323
  145.                     int nx = unit.getLocation().x() + CivUtils.relCitySquareX3[nid];
  146.                     int ny = unit.getLocation().y() + CivUtils.relCitySquareY3[nid];
  147.                     int gmux2 = gmux - CivUtils.relCitySquareX3[nid];
  148.                     int gmuy2 = gmuy - CivUtils.relCitySquareY3[nid];
  149.                     agmuy = Math.abs(gmuy2);
  150.                     agmux = Math.abs(gmux2);
  151.                     int agmuy2 = Math.abs(gmuy2);
  152.                     int distanceFromNeighbourToGoTo = Math.abs(Math.abs(gmux2)>agmuy2?gmux2:gmuy2)+agmux+agmuy;
  153.                     // If Civ is AI (not human), or distance from neighbour to Goto is smaller than from current square
  154.                     if(!unit.owner().equals(((Entity)unit).gamesave().player())||distanceFromNeighbourToGoTo<=distanceToGoTo) {
  155.                         TerrainType ntt = ((Entity)unit).gamesave().getTerrain(nx, ny);
  156.                         Civ nciv = CivLogic.whatCivOccupies(((Entity)unit).gamesave(), nx, ny);
  157.                         if(
  158.                                 (
  159.                                         (
  160.                                                 // if no Civ on next square, or same as current unit's Civ
  161.                                                 ( nciv==null || nciv.equals(unit.owner()) )
  162.                                                 &&
  163.                                                 // and neighbour terrain matches unit category
  164.                                                 ((((!ntt.equals(TerrainType.OCEAN)^unit.category().equals(UnitCategory.SEA))
  165.                                                         // and unit has no enemy unit nearby, or neighbour square has no unit nearby
  166.                                                         && (!unitNextToEnemy || !CivLogic.checkSquareNextToEnemyUnit(unit.owner(), nx, ny))
  167.                                                         ))
  168.                                                         // or the unit category is AIR, so it can ignore enemy units
  169.                                                         || (unit.category().equals(UnitCategory.AIR)))
  170.                                                 )
  171.                                                 ||
  172.                                                 // or the neighbour square contains a City belonging to the same Civ as the unit
  173.                                                 (
  174.                                                         ((Entity)unit).gamesave().hasTerrainImprovement(nx, ny, false, TerrainImprovementType.CITY)
  175.                                                         &&
  176.                                                         ((Entity)unit).gamesave().owner(nx,ny).equals(((Entity)unit).gamesave().player())
  177.                                                         )
  178.                                         )
  179.                                         &&
  180.                                         // neighbour is not an ocean, or at least size 5 or bigger
  181.                                         (!ntt.equals(TerrainType.OCEAN)^(getContinentOrOceanSizeAt(((Entity)unit).gamesave(),nx,ny)>=5))
  182.                                 ) {
  183.                             int movescore = 0;
  184.                             if(!roadUnderUnit || !((Entity)unit).gamesave().hasTerrainImprovement(nx, ny, false, TerrainImprovementType.ROAD)) {
  185.                                 movescore = unit.getType().totalMoves()<=1?3:3*ntt.movementCost(false);
  186.                             } else {
  187.                                 // No code for railroad !
  188.                                 movescore = 1;
  189.                             }
  190.                             movescore += Math.abs(gmux2) + Math.abs(gmuy2) +  distanceFromNeighbourToGoTo*4;
  191.                             agmuy2 = ((Short)((Entity)unit).getValue("unkown_unitbyte9")&0xFF);
  192.                             int var_6 = 0;
  193.                             if(agmuy2!=0xFF) {
  194.                                 var_6 = Math.abs(agmuy2 - nid);
  195.                                 if(var_6>4) {
  196.                                     var_6 = var_6 - 8;
  197.                                 }
  198.                                 movescore += var_6*var_6;
  199.                             }
  200.                             if(movescore<bestMoveScore) {
  201.                                 next = nid;
  202.                                 bestMoveScore = movescore;
  203.                             }
  204.                         }
  205.                     }
  206.                 }
  207.                 if(((Short)unit.getValue("unkown_unitbyte9")&0xFF)!=0xFF) {
  208.                     if(
  209.                             ((
  210.                                     (Short)unit.getValue("unkown_unitbyte9")
  211.                                     &
  212.                                     0xFF
  213.                                     )^4)
  214.                                     ==
  215.                                     next
  216.                             ) {
  217.                         unit.setPropertyValue("remaining_moves", (Short)(short)0);
  218.                     }
  219.                 }
  220.                 if(next==0) {
  221.                     unit.setPropertyValue("gotox", (Short)(short)0xFF);
  222.                     unit.setPropertyValue("unknown9", (Short)(short)0xFF);
  223.                     next = -1;
  224.                 } else {
  225.                     unit.setPropertyValue("unknown9", (Short)(short)next);
  226.                 }
  227.                 return next;
  228.             }
  229.         }
  230.         return -1;
  231.     }
  232.  
  233.     public static int getContinentOrOceanSizeAt(AbstractGameState gs, int x, int y) {
  234.         TerrainType tt = gs.getTerrain(x, y);
  235.         String s = tt.equals(TerrainType.OCEAN)?"ocean":"continent";
  236.         int id = gs.landMassID(new MapLocation(x,y));
  237.         return (Short)gs.getValue(""+s+""+id+".size");
  238.     }
  239.     public static boolean checkSquareNextToEnemyUnit(Civ civ, int x, int y) {
  240.         if(!((Entity)civ).gamesave().hasTerrainImprovement(x, y, false, TerrainImprovementType.CITY)) {
  241.             return checkSquareNextToEnemyUnitOrCity(civ, x, y);
  242.         } else {
  243.             return false;
  244.         }
  245.     }
  246.     public static boolean checkSquareNextToEnemyUnitOrCity(Civ civ, int x, int y) {
  247.         TerrainType tt = ((Entity)civ).gamesave().getTerrain(x, y);
  248.         for(int var_loop=1;var_loop<9;var_loop++) {
  249.             int nx = CivLogic.alignXinMapRange(x+CivUtils.relCitySquareX3[var_loop]);
  250.             int ny = y+CivUtils.relCitySquareY3[var_loop];
  251.             TerrainType ntt = ((Entity)civ).gamesave().getTerrain(nx, ny);
  252.             if(!(tt.equals(TerrainType.OCEAN)^ntt.equals(TerrainType.OCEAN))
  253.                     && CivLogic.whatCivOccupies(((Entity)civ).gamesave(), nx, ny)!=null
  254.                     && !CivLogic.whatCivOccupies(((Entity)civ).gamesave(), nx, ny).equals(civ)){
  255.                 if(civ.equals(((Entity)civ).gamesave().player())) {
  256.                     AbstractSVEUnit u = (AbstractSVEUnit) CivLogic.getUnitAt(((Entity)civ).gamesave(), nx, ny);
  257.                     if(u!=null) {
  258.                         if(!((Entity)civ).gamesave().player().canSee(u)) {
  259.                             ((Entity)civ).gamesave().setVisibility(((Entity)civ).gamesave().player(), nx, ny, 1, 1, VisibilityType.VISIBLE);
  260.                             // Skipped: redraw Map sqaure terain and units at nx,ny
  261.                         }
  262.                         if(((Entity)civ).gamesave().hasTerrainImprovement(nx, ny, false, TerrainImprovementType.CITY)) {
  263.                             City city = ((Entity)civ).gamesave().getCityAt(nx, ny);
  264.                             city.visibleSize(city.actualSize());
  265.                             ((Entity)civ).gamesave().actualizeVisibleImprovements(nx,  ny,  1,  1);
  266.                             ((Entity)civ).gamesave().setVisibility(((Entity)civ).gamesave().player(), nx, ny, 1, 1, VisibilityType.VISIBLE);
  267.                             // Skipped: redraw Map sqaure terain and units at nx,ny
  268.                         }
  269.                     }
  270.                 }
  271.                 return true;
  272.             }
  273.         }
  274.         return false;
  275.     }
  276.  
  277.     public static boolean hasReachableGoto(AbstractSVEUnit _SVEUnit) {
  278.         ByteBuffer bb = (ByteBuffer)((Entity)_SVEUnit).gamesave().getValue("land_pathfind");
  279.         byte[] pathfind = Arrays.copyOfRange(bb.array(), bb.position(), bb.limit());
  280.  
  281.         int x = _SVEUnit.getLocation().x();
  282.         int y = _SVEUnit.getLocation().y();
  283.  
  284.         int destx = _SVEUnit.getDestination().x();
  285.         int desty = _SVEUnit.getDestination().y();
  286.  
  287.         // seg016_628
  288.         int ntid = findClosestConnected4x4Tile(((Entity)_SVEUnit).gamesave(), x, y, !_SVEUnit.category().equals(UnitCategory.SEA));
  289.         if(ntid != -1) {
  290.             x = (x/4)+CivUtils.relCitySquareX3[ntid];
  291.             y = (y/4)+CivUtils.relCitySquareY3[ntid];
  292.  
  293.             int ntid2 = findClosestConnected4x4Tile(((Entity)_SVEUnit).gamesave(), _SVEUnit.getDestination().x(), _SVEUnit.getDestination().y(), !_SVEUnit.category().equals(UnitCategory.SEA));
  294.             int[] pathFind3 = new int[260];
  295.  
  296.             int var_2 = 0;
  297.             int var_4 = 0;
  298.             int[] x99 = new int[99];
  299.             int[] y99 = new int[99];
  300.             x99[0] = _SVEUnit.getDestination().x()/4+CivUtils.relCitySquareX3[ntid2];
  301.             y99[0] = _SVEUnit.getDestination().y()/4+CivUtils.relCitySquareY3[ntid2];
  302.             var_2++;
  303.  
  304.             pathFind3[x99[0]*13+y99[0]] = 1;
  305.  
  306.             int varc = 0;
  307.             int var_16 = (_SVEUnit.category().equals(UnitCategory.SEA)?1:0);
  308.  
  309.             int var_A = 0; // ???
  310.             do {
  311.                 int var_x99 = x99[var_4];
  312.                 int var_y99 = y99[var_4];
  313.                 if(var_x99!=x || var_y99!=y) {
  314.                     var_A = pathFind3[var_y99+13*var_x99];
  315.                     var_4++;
  316.                     int var_10 = pathfind[var_y99+13*var_x99+(var_16*0x40)];
  317.                     int var_2E = 1;
  318.                     do {
  319.                         if((var_10&(1<<(var_2E-1)))!=0) {
  320.                             int var_30 = var_x99+CivUtils.relCitySquareX3[var_2E];
  321.                             if(var_30==20) {
  322.                                 var_30=0;
  323.                             }
  324.                             if(var_30==-1) {
  325.                                 var_30 = 19;
  326.                             }
  327.                             int var_34 = var_y99 + CivUtils.relCitySquareY3[var_2E];
  328.                             if(pathFind3[var_30*13+var_34]==0) {
  329.                                 pathFind3[var_30*13+var_34] = var_A;
  330.                                 x99[var_2] = var_30;
  331.                                 y99[var_2] = var_34;
  332.                                 var_2++;
  333.                             }
  334.                         }
  335.                         var_2E++;
  336.                     } while(var_2E<=8);
  337.                 } else {
  338.                     varc = 1;
  339.                     break;
  340.                 }
  341.             } while(var_4!=var_2 && varc==0);
  342.             destx = -1;
  343.             if(varc!=0) {
  344.                 int var_8 = 99;
  345.                 int var_E = -1;
  346.                 int var_10 = pathfind[x+13*y+((_SVEUnit.category().equals(UnitCategory.SEA)?1:0)*0x40)];
  347.                 int var_2E = 1;
  348.                 while(var_2E<=8) {
  349.  
  350.                     if((var_10&(1<<(var_2E-1)))!=0) {
  351.                         int var_30 = x+CivUtils.relCitySquareX3[var_2E];
  352.                         if(var_30==20) {
  353.                             var_30=0;
  354.                         }
  355.                         if(var_30==-1) {
  356.                             var_30 = 19;
  357.                         }
  358.                         int var_34 = y + CivUtils.relCitySquareY3[var_2E];
  359.                         int var_6 = pathFind3[var_30*13+var_34];
  360.                         if(var_6!=0) {
  361.                             if(var_6>=var_8) {
  362.                                 if(var_6==var_8) {
  363.                                     int var_12 = CivLogic.distance(_SVEUnit.getDestination().x(), var_30*4+1, _SVEUnit.getDestination().y(), var_34*4+1);
  364.                                     if(var_12<var_A) {
  365.                                         var_E = var_2E;
  366.                                         var_A = var_12;
  367.                                     }
  368.                                 }
  369.                             } else { // var_6 < var_8
  370.                                 var_8 = var_6;
  371.                                 var_E = var_2E;
  372.                                 var_A = CivLogic.distance(_SVEUnit.getDestination().x(), var_30*4+1, _SVEUnit.getDestination().y(), var_34*4+1);
  373.                             }
  374.                         }
  375.                     }
  376.                     var_2E++;
  377.                 }
  378.                 // seg016_977
  379.                 if(var_E != -1) {
  380.                     destx = CivLogic.alignXinMapRange(4*(x+CivUtils.relCitySquareX3[var_E])+1);
  381.                     desty = (4*(y+CivUtils.relCitySquareY3[var_E])+1);
  382.  
  383.                     if(var_16 != (((Entity)_SVEUnit).gamesave().getTerrain(destx, desty).equals(TerrainType.OCEAN)?1:0)) {
  384.                         destx++;
  385.                         if(var_16 != (((Entity)_SVEUnit).gamesave().getTerrain(destx, desty).equals(TerrainType.OCEAN)?1:0)) {
  386.                             desty++;
  387.                         }
  388.                     }
  389.                 }
  390.             }
  391.             if(destx==-1) {
  392.                 destx = _SVEUnit.getDestination().x();
  393.                 desty = _SVEUnit.getDestination().y();
  394.             }
  395.             return (varc==1);
  396.         } else {
  397.             destx = _SVEUnit.getDestination().x();
  398.             desty = _SVEUnit.getDestination().y();
  399.             return false; // ????
  400.         }
  401.     }
  402.  
  403.     public static int findClosestConnected4x4Tile(AbstractGameState gs, int x, int y, boolean land) {
  404.         int tileX = x/4;
  405.         int tileY = y/4;
  406.         int bestNeighbour = -1;
  407.         ByteBuffer bb = (ByteBuffer)gs.getValue("land_pathfind");
  408.         byte[] pathfind = Arrays.copyOfRange(bb.array(), bb.position(), bb.limit());
  409.         if(pathfind[13*tileX+tileY+(land?0:0x40)]!=0) {
  410.             bestNeighbour = 0;
  411.         }
  412.         if(bestNeighbour==-1) {
  413.             int bestDist = 99;
  414.             int nid = 1;
  415.             while(nid<=8) {
  416.                 int ntileX = tileX+CivUtils.relCitySquareX3[nid];
  417.                 int ntileY = tileY+CivUtils.relCitySquareY3[nid];
  418.  
  419.                 if( (!land && pathfind[13*ntileX+ntileY+0x40]!=0)
  420.                         || (land && pathfind[13*ntileX+ntileY]!=0)) {
  421.                     int currentDist = CivLogic.distanceSub(x-4*ntileX-1, y-4*ntileY-1);
  422.                     if(currentDist<bestDist) {
  423.                         int nx = 4*ntileX;
  424.                         int ny = 4*ntileY;
  425.                         if(!(land^gs.getTerrain(nx, ny).equals(TerrainType.OCEAN))) {
  426.                             nx++;
  427.                             if(!(land^gs.getTerrain(nx, ny).equals(TerrainType.OCEAN))) {
  428.                                 ny++;
  429.                                 if(!(land^gs.getTerrain(nx, ny).equals(TerrainType.OCEAN))) {
  430.                                     nx--;
  431.                                     if(!(land^gs.getTerrain(nx, ny).equals(TerrainType.OCEAN))) {
  432.                                         continue;
  433.                                     }
  434.                                 }
  435.                             }
  436.                         }
  437.                         if(findPathLength(gs, nx, ny, x, y, land, 18)!=-1) {
  438.                             bestDist = currentDist;
  439.                             bestNeighbour = nid;
  440.                         }
  441.                     }
  442.                 }
  443.                 nid++;
  444.             }
  445.         }
  446.         // Normally, CIV returns 0-false or 1-true, and if true
  447.         // it stores the next tile X and Y in global vars
  448.         // dseg_6512 and dseg_6514 (destX and destY)
  449.         // too cumbersome here, we simply return the resulting
  450.         // neighbour tile ID, and -1 if there is none...
  451.         return bestNeighbour;
  452.     }
  453.  
  454.     public static void addReplayEntry(byte[] data, int type, int blen, int b0, int b1, int b2, int b3) {
  455.         int currentSize = Utils.shortLE(data[0], data[1]);
  456.         if(currentSize+blen+2<=data.length-2) {
  457.  
  458.         }
  459.     }
  460.  
  461.     public static Civ whatCivOccupies(AbstractGameState gs, int x, int y) {
  462.         if(gs.isOccupied(x, y)) {
  463.             return gs.owner(x, y);
  464.         } else {
  465.             return null;
  466.         }
  467.     }
  468.  
  469.     public static AbstractSVEUnit createUnit(Civ c, UnitType type, int x, int y) {
  470.         int var_unitID = 0;
  471.         SVECiv civ = (SVECiv)c;
  472.  
  473.         while(var_unitID<127) {
  474.             if(!civ.unit(var_unitID).exists()) {
  475.                 AbstractSVEUnit sveUnit = (AbstractSVEUnit) civ.unit(var_unitID);
  476.  
  477.                 sveUnit.setPropertyValue("position_x", (short)-1);
  478.                 sveUnit.setPropertyValue("next_unit_in_stack", (short)-1);
  479.  
  480.                 CivLogic.assignSquareToCiv(civ, x, y);
  481.  
  482.  
  483.                 AbstractGameState gs = ((Entity)civ).gamesave();
  484.                 gs.setVisibility(civ, x, y, 1, 1, VisibilityType.VISIBLE);
  485.                 sveUnit.setPropertyValue("status_flag", 0);
  486.                 sveUnit.setPropertyValue("position_x", x);
  487.                 sveUnit.setPropertyValue("position_y", y);
  488.                 sveUnit.setPropertyValue("type", ((SVEUnitType) type).getID());
  489.  
  490.                 CivLogic.putUnitAt(sveUnit, x, y);
  491.  
  492.                 sveUnit.setPropertyValue("visible_by_flag", (1<<civ.getID()));
  493.                 sveUnit.setPropertyValue("gotox", -1);
  494.                 sveUnit.setPropertyValue("goto_next_direction", -1);
  495.                 sveUnit.setRemaining_moves(type.totalMoves()); // NOT FOLLOWING ORIGINAL CIV LOGIC!
  496.                 sveUnit.setPropertyValue("special_moves", (type.turnsOutdoors()==0?0:type.turnsOutdoors()-1));
  497.                 int nearestCityID = CivLogic.findNearestCityID(gs, x, y);
  498.                 if(gs.city(nearestCityID).owner().equals(civ)) {
  499.                     sveUnit.setPropertyValue("home_city_id", nearestCityID);
  500.                 } else {
  501.                     sveUnit.setPropertyValue("home_city_id", -1);
  502.                 }
  503.  
  504.                 int au = (Short)gs.getValue("civ"+civ.getID()+".active_units"+((SVEUnitType) type).getID());
  505.                 gs.setPropertyValue("civ"+civ.getID()+".active_units"+((SVEUnitType) type).getID(),au+1);
  506.  
  507.                 //if(dseg_20F4)
  508.                 //if(cheat enabled ||
  509.                 if(civ.equals(gs.player())||gs.player().canSee(sveUnit)) {
  510.                     // TODO: draw map square and units
  511.                     //JCivLogic.drawMapTerrainSquare(map, x, nearestCityID, bi, imgx, imgy, showAll, mode, drawLand, drawSpecial, drawRoad, drawImpr, drawPollution, drawHuts, drawShadow, drawCity)
  512.                 }
  513.  
  514.                 return sveUnit;
  515.             }
  516.             var_unitID++;
  517.         }
  518.  
  519.         return null;
  520.     }
  521.  
  522.     public static int nextCityName(Civ civ) {
  523.         CivDosGameState gs = (CivDosGameState) civ.gamesave();
  524.  
  525.         int who = (short) ((Entity) civ).getValue("who");
  526.         int cityNameID = -1;
  527.         cityNameID = who - (who<8?1:2);
  528.         if(who == -1 || civ.getID() == 0) { // if Barbarians,
  529.             cityNameID = 14; // directly start in additional city names
  530.         }
  531.         cityNameID = cityNameID<<4; // *16
  532.         int var_cityBaseID = cityNameID;
  533.         boolean var_loopStop = true;
  534.  
  535.         do {
  536.             var_loopStop = true;
  537.             int _cvid = cityNameID/16;
  538.             String prefix = "civ"+_cvid+".city"+(cityNameID%16)+".";
  539.             byte _x = (Byte)gs.getValue(prefix+"position_X");
  540.             if(_x!=-1) {
  541.                 var_loopStop = false;
  542.                 cityNameID++;
  543.                 if(cityNameID==var_cityBaseID+16) {
  544.                     cityNameID = 224;
  545.                 }
  546.                 if(cityNameID==256) {
  547.                     cityNameID=0;
  548.                     if( var_cityBaseID == 999 ) {
  549.                         var_loopStop = true;
  550.                         return -1;
  551.                     }
  552.                     var_cityBaseID = 999;
  553.                 }
  554.             }
  555.         }while(!var_loopStop);
  556.  
  557.         return cityNameID;
  558.     }
  559.  
  560.     public static int buildCity(Civ civ, int x, int y, int initSize, int arg1,String name) {
  561.         if(civ!=null) {
  562.             AbstractGameState gs = ((Entity)civ).gamesave();
  563.             if(gs!=null) {
  564.                 for(int var_loop=0;var_loop<128;var_loop++) {
  565.                     if(!((SVEMapEntity) gs.city(var_loop)).exists()) {
  566.  
  567.                         // routine for next city name extracted to separate
  568.                         // function for reusability
  569.                         int cityNameID = nextCityName(civ);
  570.  
  571.                         int _cvid = cityNameID/16;
  572.                         String prefix0 = "civ"+_cvid+".city"+(cityNameID%16)+".";
  573.                         AbstractCity newCity = (AbstractCity) gs.city(var_loop);
  574.                         newCity.setPropertyValue("city_name_id", (short)cityNameID);
  575.                         gs.setPropertyValue(prefix0+"position_X", (byte)x);
  576.                         gs.setPropertyValue(prefix0+"position_Y", (byte)y);
  577.  
  578.                         // Skipped: only ask for city name if Civ is player
  579.                         if(name==null) {
  580.                             return -1;
  581.                         }
  582.                         String prefix1 = "civ"+_cvid+".city_name"+(cityNameID%16)+"";
  583.                         gs.setPropertyValue(prefix1, name);
  584.  
  585.                         /* TODO: Write Replay Entry */
  586.  
  587.                         // Remove mining and fortress
  588.                         gs.removeTerrainImprovement(x, y, true, TerrainImprovementType.FORTRESS);
  589.                         gs.removeTerrainImprovement(x, y, true, TerrainImprovementType.MINING);
  590.  
  591.                         // Set terrain improvement flags city and road
  592.                         gs.addTerrainImprovement(x, y, true, TerrainImprovementType.CITY);
  593.                         gs.addTerrainImprovement(x, y, true, TerrainImprovementType.ROAD);
  594.                         //                      int imps = gs.getTerrainImprovementsFlag(x, y, true);
  595.                         //                      imps = ((imps&0b11110000)|0b1001);
  596.                         //                      gs.setTerrainImprovementFlag(x, y, 1, 1, true, imps);
  597.  
  598.                         TerrainType tt = gs.getTerrain(x, y);
  599.                         if(tt.irrigationEffect(false)<-1) {
  600.                             gs.addTerrainImprovement(x, y, true, TerrainImprovementType.IRRIGATION);
  601.                         }
  602.  
  603.                         newCity.setPropertyValue("status_flag", (byte)0);
  604.                         newCity.setPropertyValue("position_x", (byte)x);
  605.                         newCity.setPropertyValue("position_y", (byte)y);
  606.                         newCity.setPropertyValue("actual_size", (byte)initSize);
  607.                         newCity.setPropertyValue("visible_size", (byte)0);
  608.                         newCity.setPropertyValue("workers_flag0", (byte)0);
  609.                         newCity.setPropertyValue("workers_flag1", (byte)0);
  610.                         newCity.setPropertyValue("workers_flag2", (byte)0);
  611.                         newCity.setPropertyValue("workers_flag3", (byte)0);
  612.                         newCity.setPropertyValue("base_trade", (byte)0);
  613.                         newCity.setPropertyValue("food_count", (short)0);
  614.                         newCity.setPropertyValue("shields_count", (short)0);
  615.  
  616.                         newCity.setPropertyValue("buildings_flag0", (byte)0);
  617.                         newCity.setPropertyValue("buildings_flag1", (byte)0);
  618.                         newCity.setPropertyValue("buildings_flag2", (byte)0);
  619.                         newCity.setPropertyValue("buildings_flag3", (byte)0);
  620.  
  621.                         newCity.setPropertyValue("current_prod_id", (short)1); // militia
  622.                         if(civ.knows(Advance.GUNPOWDER)) {
  623.                             newCity.setPropertyValue("current_prod_id", (short)4); // musketeer
  624.                         }
  625.                         if(civ.knows(Advance.CONSCRIPTION)) {
  626.                             newCity.setPropertyValue("current_prod_id", (short)5); // riflemen
  627.                         }
  628.                         newCity.setPropertyValue("unknown_cb27", (byte)0xFF);
  629.                         newCity.setPropertyValue("unknown_cb28", (byte)0xFF);
  630.  
  631.                         boolean firstCity = true;
  632.                         for(int var_loop2 = 0; var_loop2<128;var_loop2++) {
  633.                             if(gs.city(var_loop2).owner().equals(civ) && !newCity.equals(gs.city(var_loop2))) {
  634.                                 firstCity = false;
  635.                             }
  636.                         }
  637.                         if(firstCity) {
  638.                             newCity.add(CityImprovement.PALACE);
  639.                         }
  640.  
  641.                         newCity.setPropertyValue("base_trade", (byte)0);
  642.                         newCity.setPropertyValue("owning_civ", (byte)((SVECiv) civ).getID());
  643.  
  644.                         newCity.setPropertyValue("trade_city1", (short)0xFF);
  645.                         newCity.setPropertyValue("trade_city2", (short)0xFF);
  646.                         newCity.setPropertyValue("trade_city3", (short)0xFF);
  647.  
  648.                         newCity.setPropertyValue("workers_flag4", (byte)0); // specialists
  649.                         newCity.setPropertyValue("workers_flag5", (byte)0);
  650.  
  651.                         for(int var_loop2=1;var_loop2<=8;var_loop2++) {
  652.                             TerrainType nt = gs.getTerrain(x+CivUtils.relCitySquareX3[var_loop2], y+CivUtils.relCitySquareY3[var_loop2]);
  653.  
  654.                             if(nt.equals(TerrainType.OCEAN)) {
  655.                                 // TODO: Check if neighbour is mega-ocean OR belongs to player
  656.                                 //newCity.setValue("status_flagbit1", (boolean)true); // coastal city
  657.                                 newCity.set(CityStatus.COASTAL, true);
  658.                             }
  659.                             if(nt.equals(TerrainType.RIVER) || nt.equals(TerrainType.MOUNTAINS)) {
  660.                                 //newCity.setValue("status_flagbit3", (boolean)true); // can build hydro-plant
  661.                                 newCity.set(CityStatus.HYDRO_AVAILABLE, true);
  662.                             }
  663.                         }
  664.                         // skipped: if first city, ONLINE help is displayed
  665.  
  666.                         // Painting current land values and improvements
  667.                         for(int var_loop2=0;var_loop2<45;var_loop2++) {
  668.                             int nx = CivLogic.alignXinMapRange(x+CivUtils.relCitySquareX3[var_loop2]);
  669.                             int ny = y+CivUtils.relCitySquareY3[var_loop2];
  670.                             if(var_loop2>20) {
  671.                                 int val = gs.getTerrainValue(nx, ny, false);
  672.                                 if(val>=8) {
  673.                                     gs.setTerrainValue(nx, ny, false, 8);
  674.                                 }
  675.                             } else {
  676.                                 gs.setTerrainValue(nx, ny, false, ((SVECiv) civ).getID());
  677.                             }
  678.                             if(civ.equals(gs.player())
  679.                                     && var_loop2<=24
  680.                                     && gs.hasTerrainImprovement(nx, ny, false, TerrainImprovementType.CITY)
  681.                                     && gs.owner(nx, ny).equals(gs.player())) {
  682.                                 // update visible improvements from actual improvements
  683.                                 newCity.setPropertyValue("visible_size", (byte)1);
  684.                                 gs.actualizeVisibleImprovements(x, y, 1, 1);
  685.                                 //int imps2 = gs.getMap().getTerrainImprovementsFlag(x, y, true);
  686.                                 //gs.getMap().setTerrainImprovementFlag(x, y, 1, 1, false, imps2);
  687.                             }
  688.                         }
  689.  
  690.                         if(civ.equals(gs.player())) {
  691.                             // Skipped: if built by player and game settings allow, trigger animation
  692.                         } else {
  693.                             if(isWonderApplicable(gs.player(),WonderType.APOLLO_PROGRAM)) {
  694.                                 //                              int imps2 = gs.getTerrainImprovementsFlag(x, y, true);
  695.                                 //                              gs.setTerrainImprovementFlag(x, y, 1, 1, false, imps2);
  696.                                 gs.actualizeVisibleImprovements(x, y, 1, 1);
  697.                             }
  698.                         }
  699.                         return var_loop;
  700.                     }
  701.                     // Ending loop without returning: no city slot available!
  702.  
  703.                     // Skipped: inform player that the maximum city limit is reached
  704.                 }
  705.             }
  706.         }
  707.  
  708.  
  709.  
  710.         return -1;
  711.     }
  712.  
  713.     public static boolean isWonderApplicable(Civ civ, WonderType w) {
  714.         if(w.getDeprecatingAdvance()!=null) {
  715.             for(int i=0;i<8;i++) {
  716.                 if(civ.gamesave().civ(i) != null
  717.                         &&
  718.                         civ.gamesave().civ(i).knows(w.getDeprecatingAdvance())) {
  719.                     return false;
  720.                 }
  721.             }
  722.         }
  723.         if(((Entity)civ).gamesave().wonder(w.getId()-1).getHostCity()!=null
  724.                 && ((Entity)civ).gamesave().wonder(w.getId()-1).getHostCity().owner().equals(((Entity)civ).gamesave().player())) {
  725.             return true;
  726.         }
  727.         return false;
  728.     }
  729.  
  730.     public static int getLandOccupation(Map wm, int x, int y) {
  731.         if(wm.isOccupied(x, y)) {
  732.             return ((SVECiv) wm.owner(x, y)).getID();
  733.         } else {
  734.             return -1;
  735.         }
  736.     }
  737.     public static int distanceSub(int x, int y) {
  738.         return (Math.max(Math.abs(x), Math.abs(y)) + Math.min(Math.abs(x), Math.abs(y))/2);
  739.     }
  740.  
  741.     public static int distance(int x1, int x2, int y1, int y2) {
  742.         int x = Math.abs(x1-x2);
  743.         if(x>40) x = 80-x; // HARDCODED
  744.         int y = Math.abs(y1-y2);
  745.         return distanceSub(x,y);
  746.     }
  747.  
  748.     public static int findNearestCityID(AbstractGameState gs, int x, int y) {
  749.         int nearestCity = -1;
  750.         int bestDistance = 999;
  751.         for(City c : gs.getAllCities()) {
  752.             if(c!=null && ((SVEMapEntity) c).exists()) {
  753.                 int d = distance(x,c.getLocation().x(),y,c.getLocation().y());
  754.                 if(d<bestDistance) {
  755.                     bestDistance = d; // MEM:To be stored in memory
  756.                     nearestCity = ((SVECity) c).getID();
  757.                 }
  758.             }
  759.         }
  760.         return nearestCity;
  761.     }
  762.  
  763.     public static void assignSquareToCiv(Civ civ, int x, int y) {
  764.         if(civ!=null && ((Entity)civ).gamesave() !=null && ((Entity)civ).gamesave()!=null) {
  765.             Map map = ((Entity)civ).gamesave();
  766.             map.setOwner(x, y, civ);
  767.         }
  768.     }
  769.  
  770.     // TODO: start
  771.     public static int dseg_2496_cityViewActiveTab;
  772.     static int dseg_2494;
  773.     static int dseg_F2E2;
  774.     static int dseg_EA62;
  775.  
  776.     static int dseg_2F4E;
  777.     static int dseg_C108_openCityScreenFlag;
  778.  
  779.     static int currentProcessingCity_dseg_64C2;
  780.     static int dseg_6AB0_distanceToCapital;
  781.     static int[] dseg = new int[0xFFFF];
  782.     static int cityOwner_dseg_64CA;
  783.     static int neighbourSquareCount_dseg_64C4 = 0;
  784.     static int pollutionFactor_dseg_C7A2;
  785.     static int citySpecialistCount_dseg_F7D8;
  786.  
  787.     static int dseg_64C8_away_unit_counter;
  788.    
  789.     static int dseg_EDD6;
  790.     static int dseg_EDD8_unk27_28_counter;
  791.     static int dseg_E216_unitShieldMaintenanceCost;
  792.     static int dseg_F2E6_settler_counter;
  793.     static int dseg_7068_playerTrespassingAIcityFlag;
  794.     static int cityFoodProd_dseg_705A;
  795.     static int cityShieldProd_dseg_705C;
  796.     static int cityTradeProd_dseg_705E;
  797.     static int dseg_E200_corruption;
  798.     static int cityLuxuryProd_dseg_7060;
  799.     static int dseg_6C18_cityPowerType;
  800.  
  801.  
  802.     static void drawResourcesOnCityMapSquare(AbstractGameState gs, BufferedImage bi, int arg_cityID, int var_neighbourID,int arg_display) {
  803.         City city = gs.city(arg_cityID);
  804.         Civ cityOwner = city.owner();
  805.         Graphics2D gfx = bi.createGraphics();
  806.         int dx = CivUtils.relCityX[var_neighbourID];
  807.         int dy = CivUtils.relCityY[var_neighbourID];
  808.         int var_neighbourX = city.getLocation().x() + dx;
  809.         int var_neighbourY = city.getLocation().y() + dy;
  810.         int var_iconSpace = 8;
  811.         int var_iconX;
  812.         int var_iconY;
  813.         int var_resType;
  814.         int var_squareScore = 0;
  815.         //System.out.println("== drawing resources: cityID: "+arg_cityID+" ["+city.getName()+"] at ("+city.getPosition_x()+","+city.getPosition_y()+"); neighbourID = "+var_neighbourID+" relative:("+dx+","+dy+"), absolute:("+var_neighbourX+","+var_neighbourY+")");
  816.         if(arg_display==1) {
  817.             ImageUtils.drawMapTerrainSquare(gs, var_neighbourX, var_neighbourY, bi, 80+(5+dx)*16,8+(3+dy)*16, gs.getRandomSeed(), 1, true,true,true,true,true,true,true,true);
  818.             var_squareScore = 0;
  819.             var_resType = 0;
  820.             while(var_resType<3) {
  821.                 //System.out.println("   resource ID: "+var_resType);
  822.                 int _rs = computeMapSquareResources(gs, var_neighbourX, var_neighbourY, var_resType);
  823.                 //System.out.println("        amount: "+_rs);
  824.  
  825.                 var_squareScore += _rs;
  826.                 var_resType++;
  827.             }
  828.             //System.out.println(" total square resources:"+var_squareScore);
  829.             if(var_squareScore>4) {
  830.                 if(var_squareScore>6) {
  831.                     var_iconSpace = 3;
  832.                 } else {
  833.                     var_iconSpace = 5;
  834.                 }
  835.             } else {
  836.                 var_iconSpace = 8;
  837.             }
  838.         }
  839.  
  840.         var_iconY = 0;
  841.         var_iconX = 0;
  842.         var_resType = 0;
  843.  
  844.         String debug = "DEBUG: central square resources: ";
  845.         while(var_resType<3) {
  846.             if(dx==0 && dy ==0) {
  847.                 String cp = "checkpoint";
  848.             }
  849.             int var_resCount = computeMapSquareResources(gs, var_neighbourX, var_neighbourY, var_resType);
  850.  
  851.             if(dx==0 && dy ==0) {
  852.                 debug += var_resCount+" "+(var_resType==0?"food, ":var_resType==1?"shields, ":"trade");
  853.             }
  854.             switch(var_resType) {
  855.             case 0:
  856.                 cityFoodProd_dseg_705A += var_resCount;
  857.                 break;
  858.             case 1:
  859.                 cityShieldProd_dseg_705C += var_resCount;
  860.                 break;
  861.             case 2:
  862.                 cityTradeProd_dseg_705E += var_resCount;
  863.                 break;
  864.             default:
  865.                 break;
  866.             }
  867.             //dseg_705A_resourceCounters[var_resType] += var_resCount;
  868.  
  869.             if(arg_display == 1) {
  870.                 while(var_resCount>0) {
  871.                     int rimgx = CivUtils.relCityX[var_neighbourID]*16+var_iconX+161;
  872.                     int rimgy = CivUtils.relCityY[var_neighbourID]*16+var_iconY+57;
  873.  
  874.                     String restype = var_resType==0?"food":var_resType==1?"shield":var_resType==2?"trade":null;
  875.                     if(restype!=null) {
  876.                         BufferedImage resicon = ResourceManager.getSprite("city.resource."+restype+".");
  877.                         gfx.drawImage(resicon, rimgx, rimgy, null);
  878.                     }
  879.  
  880.                     if(var_iconX<8) {
  881.                         var_iconX += var_iconSpace;
  882.                     } else {
  883.                         var_iconX = 0;
  884.                         var_iconY += 8;
  885.                     }
  886.                     var_resCount--;
  887.                 }
  888.             }
  889.             var_resType++;
  890.         }
  891.         if(dx==0 && dy==0) System.out.println(debug);
  892.  
  893.         if(var_squareScore==0) {
  894.             if(arg_display==1) {
  895.                 // Draw sad face icon (13) at relative offset (61,165)
  896.             }
  897.         }
  898.  
  899.         dseg_2494 = 0;
  900.         gfx.dispose();
  901.     }
  902.  
  903.     public static int computeMapSquareResources(AbstractGameState gs, int x, int y, int resType) {
  904.         if(CivLogic.isInMap(x, y)) {
  905.             // resType: 0-food, 1-shields, 2-trade
  906.             TerrainType tt = gs.getTerrain(x, y);
  907.             boolean special = CivLogic.isSpecialResource(x, y, gs.getRandomSeed());
  908.             int var_prod = resType==0?tt.food(special):
  909.                 resType==1?tt.shields(special):
  910.                     resType==2?tt.trade(special):0;
  911.                     //tt..getAttributes(special)[2+resType];
  912.                     boolean showAll = true;
  913.                     Map wm = gs;
  914.                     //int var_impr = gs.getTerrainImprovementsFlag(x, y, showAll);
  915.                     // if DebugSwitch contains 0x10 skip below...
  916.                     //      int ax;
  917.                     //      if(tt.above(TerrainType.GRASSLANDS)) {
  918.                     //          var_impr = 2;
  919.                     //      } else {
  920.                     //          var_impr = 4;
  921.                     //      }
  922.                     //      if(tt.equals(TerrainType.PLAINS)) {
  923.                     //          var_impr |= 0b1000;
  924.                     //      }
  925.  
  926.                     if(!tt.equals(TerrainType.OCEAN)) {
  927.                         if(resType == 0) { // food
  928.                             if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.IRRIGATION)) {
  929.                                 var_prod += (-1 - tt.irrigationEffect(special));
  930.                             }
  931.                         }
  932.                         if(resType == 1) { // shields
  933.                             if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.MINING)) {
  934.                                 var_prod += (-1 - tt.miningEffect(special));
  935.                             }
  936.                         }
  937.                         if(resType == 2) { // trade
  938.                             if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.ROAD)) {
  939.                                 if(tt.equals(TerrainType.DESERT)
  940.                                         || tt.equals(TerrainType.GRASSLANDS)
  941.                                         || tt.equals(TerrainType.PLAINS)) {
  942.                                     var_prod ++;
  943.                                 }
  944.                             }
  945.                         }
  946.                     }
  947.                     if(resType==1) {
  948.                         if(tt.equals(TerrainType.GRASSLANDS)||tt.equals(TerrainType.RIVER)) {
  949.                             if(((7*x+11*y) & 0b10) != 0) { // special formula
  950.                                 var_prod = 0;
  951.                             }
  952.                         }
  953.                     }
  954.                     if(var_prod!=0) {
  955.                         if(resType==2) {
  956.                             int host = gs.wonder(WonderType.COLOSSUS.getId()-1).getHostCityID();
  957.                             if(host==currentProcessingCity_dseg_64C2) {
  958.                                 var_prod++;
  959.                             }
  960.                         }
  961.                     }
  962.                     if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.RAILROAD)) {
  963.                         var_prod += (var_prod>>1); // adds 50% of everything
  964.                     }
  965.                     if(var_prod>2) {
  966.                         if(!gs.city(currentProcessingCity_dseg_64C2).has(CityStatus.RAPTURE_2)) { //
  967.                             if((Short)((Entity) gs.civ(cityOwner_dseg_64CA)).getValue("government")<=1) {
  968.                                 var_prod--;
  969.                             }
  970.                             if(dseg_2494!=0) {
  971.                                 dseg_F2E2 -= 2;
  972.                             }
  973.                         }
  974.                     }
  975.                     if(var_prod!=0) {
  976.                         if(resType==2) {
  977.                             if(dseg_2494!=0) {
  978.                                 dseg_EA62++;
  979.                             }
  980.                             int _ax;
  981.                             if(gs.city(currentProcessingCity_dseg_64C2).has(CityStatus.RAPTURE_2)) {
  982.                                 _ax = 2;
  983.                             } else {
  984.                                 _ax = 4;
  985.                             }
  986.                             if(_ax<=(Short)((Entity) gs.civ(cityOwner_dseg_64CA)).getValue("government")) {
  987.                                 var_prod++;
  988.                             }
  989.                         }
  990.                     }
  991.                     if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.POLLUTION)) {
  992.                         var_prod = (var_prod+1)>>1; // pollution divides by 2
  993.                     }
  994.                     return Math.max(0, var_prod);
  995.         }
  996.         return 0;
  997.     }
  998.  
  999.     public static int getHostCityOfWonder(AbstractGameState gs, int wonderID) {
  1000.         return gs.wonder(wonderID).getHostCityID();
  1001.     }
  1002.  
  1003.     public static String populationString(int pop) {
  1004.         String s = "";
  1005.         if(pop>=100) {
  1006.             s += pop/100;
  1007.             s += ",";
  1008.             if(pop%100<10) {
  1009.                 s += "0";
  1010.             }
  1011.         }
  1012.         s += pop%100;
  1013.         s += "0,000";
  1014.         return s;
  1015.     }
  1016.  
  1017.     public static boolean isSpecialResource(int x, int y, int TMW) {
  1018.         //      if(x==0xA && y==0x12) {
  1019.         //          int g = 0;
  1020.         //      }
  1021.         //
  1022.         //      CivRandom cr  = new CivRandom(TMW);
  1023.         //      cr.ds5BDC = (short) 0xBABE;
  1024.         //      int base = y*TMW+x*0xBABE;
  1025.         //      int n = cr.next(y*TMW+x*0xBABE);
  1026.         //      //int n = cr.next(y+x);
  1027.         //     
  1028.         //      int xn = (n^0xCAFE)&0xFFFF;
  1029.         //      int xnm = xn%5;
  1030.         //     
  1031.         //      return (xnm==0);
  1032.  
  1033.         return (y>1 && y<48 &&
  1034.                 (((x&3)<<2) + (y&3)) == (((((x>>2)*13) + ((y>>2)*11)) + TMW ) & 0xF ));
  1035.     }
  1036.     public static boolean isHut(int x, int y, int TMW, boolean activeOnly, AbstractGameState gs) {
  1037.         if(activeOnly && gs!=null) {
  1038.             return (y>1 && y<48 &&
  1039.                     !gs.getTerrain(x, y).equals(TerrainType.OCEAN) &&
  1040.                     !gs.civ(0).canSee(new MapLocation(x, y)) &&
  1041.                     (((x&3)<<2) + (y&3)) ==  (((((x>>2)*13) + ((y>>2)*11)) + TMW + 8) & 0x1F ));
  1042.         } else {
  1043.             return (y>1 && y<48 &&
  1044.                     (((x&3)<<2) + (y&3)) == (((((x>>2)*13) + ((y>>2)*11)) + TMW + 8) & 0x1F ));
  1045.         }
  1046.     }
  1047.  
  1048.     public static int rangeBound(int val, int min, int max) {
  1049.         return Math.min(Math.max(val, min), max);
  1050.     }
  1051.  
  1052.     public static void drawUnits(AbstractGameState gs, int x, int y, BufferedImage bi, BufferedImage gotobi, int imgx, int imgy, int mode, boolean showGoto) {
  1053.         if(!gs.getUnitsAt(x, y).isEmpty()) {
  1054.             Unit _SVEUnit = gs.getUnitsAt(x, y).iterator().next();
  1055.             _SVEUnit = CivLogic.determineUnitToDraw(gs, x, y, (SVEUnit) _SVEUnit);
  1056.             drawUnit((SVEUnit) _SVEUnit,bi,imgx,imgy,mode);
  1057.  
  1058.             if(showGoto && gotobi!=null) {
  1059.                 // Draw GoTo arrows! Yeah!
  1060.                 Collection<? extends Unit> units = gs.getUnitsAt(x, y);
  1061.                 for(Unit unit : units) {
  1062.                     // TODO: deal with "world is round"
  1063.                     if(unit.getDestination()!=null) {
  1064.                         Point2D start = new Point2D.Double(imgx+8, imgy+8);
  1065.                         MapLocation dest = unit.getDestination();
  1066.                         int destimgx = imgx + (dest.x()-x)*16;
  1067.                         int destimgy = imgy + (dest.y()-y)*16;
  1068.                         Point2D end = new Point2D.Double(destimgx+8, destimgy+8);
  1069.                         if(Math.abs(dest.x()-x)>40) {
  1070.                             // Take shortest route, by the other side:
  1071.                             // Need to draw 2 partial arrows
  1072.                             if(x>=40) { // start is in the East, dest in the West
  1073.                                 int fakedestx = dest.x() + 80;
  1074.                                 int fakedestimgx = imgx + 16*fakedestx;
  1075.                                 Point2D fakeend = new Point2D.Double(fakedestimgx+8, destimgy+8);
  1076.                                 ImageUtils.drawArrow(start, fakeend, gotobi, ImageUtils.civColors[unit.owner().getID()][0]);
  1077.  
  1078.                                 //int fakestartx = x - 80;
  1079.                                 int fakestartimgx = imgx - 80*16;
  1080.                                 Point2D fakestart = new Point2D.Double(fakestartimgx+8, imgy+8);
  1081.                                 ImageUtils.drawArrow(fakestart, end, gotobi, ImageUtils.civColors[unit.owner().getID()][0]);
  1082.                             } else { // dest is in the East, start in the West
  1083.                                 int fakedestx = dest.x() - 80;
  1084.                                 int fakedestimgx = imgx + 16*fakedestx;
  1085.                                 Point2D fakeend = new Point2D.Double(fakedestimgx+8, destimgy+8);
  1086.                                 ImageUtils.drawArrow(start, fakeend, gotobi, ImageUtils.civColors[unit.owner().getID()][0]);
  1087.  
  1088.                                 //int fakestartx = x - 80;
  1089.                                 int fakestartimgx = imgx + 80*16;
  1090.                                 Point2D fakestart = new Point2D.Double(fakestartimgx+8, imgy+8);
  1091.                                 ImageUtils.drawArrow(fakestart, end, gotobi, ImageUtils.civColors[unit.owner().getID()][0]);
  1092.                             }
  1093.                         } else {
  1094.                             ImageUtils.drawArrow(start, end, gotobi, ImageUtils.civColors[unit.owner().getID()][0]);
  1095.                         }
  1096.                     }
  1097.                 }
  1098.             }
  1099.         }
  1100.     }
  1101.     public static void drawUnit(SVEUnit _SVEUnit, BufferedImage bi, int imgx, int imgy, int mode) {
  1102.         drawUnit(_SVEUnit, bi, imgx, imgy, mode, true);
  1103.     }
  1104.     public static void drawUnit(SVEUnit _SVEUnit, BufferedImage bi, int imgx, int imgy, int mode, boolean force) {
  1105.         Graphics2D gfx = bi.createGraphics();
  1106.         AbstractGameState gs = ((Entity)_SVEUnit).gamesave();
  1107.         Map map = gs;
  1108.         int x = _SVEUnit.getLocation().x();
  1109.         int y = _SVEUnit.getLocation().y();
  1110.         boolean modeT = false;
  1111.         if(mode==0) {
  1112.             // seg012_EA4:
  1113.             // skipped: Theoretical "imgx" is computed as "imgx = (map_viewport_x - x) * 16 + 80"
  1114.             // skipped: Theoretical "imgy" is computed as "imgy = (map_viewport_y - y) * 16 + 8"
  1115.             // skipped: target imgx and imgy are tested to be within the "MAP" window of CIV screen:
  1116.             //     80 <= imgx < 320
  1117.             //      8 <= imgx < 192
  1118.  
  1119.             TerrainType tt = map.getTerrain(x, y);
  1120.             if(!tt.equals(TerrainType.OCEAN)
  1121.                     || !_SVEUnit.getStatus().equals(UnitStatus.SENTRY)
  1122.                     || _SVEUnit.getType().category().equals(UnitCategory.SEA)
  1123.                     || force) {
  1124.                 BufferedImage unitIcon = ImageUtils.getCivUnitIcon(_SVEUnit);
  1125.                 if(_SVEUnit.hasNextInStack()) {
  1126.                     gfx.drawImage(unitIcon,imgx+1,imgy+1,null);
  1127.                 }
  1128.                 gfx.drawImage(unitIcon,imgx,imgy,null);
  1129.                 // Status overlays
  1130.                 char status = 0;
  1131.                 if(_SVEUnit.getStatus().equals(UnitStatus.FORTIFIED)/*||u.hasStatus(UnitStatus.JUST_FORTIFIED)*/) {
  1132.                     gfx.drawImage(ResourceManager.getSprite("terrain.overlay.citywalls."), imgx,imgy,null);
  1133.                 }
  1134.                 if(_SVEUnit.getStatus().equals(UnitStatus.ROADBUILDING))            status = 'R';
  1135.                 if(_SVEUnit.getStatus().equals(UnitStatus.IRRIGATING))          status = 'I';
  1136.                 if(_SVEUnit.getStatus().equals(UnitStatus.MINING))              status = 'M';
  1137.                 if(_SVEUnit.getStatus().equals(UnitStatus.BUILDING_FORTRESS))   status = 'F';
  1138.                 if(_SVEUnit.getStatus().equals(UnitStatus.JUST_FORTIFIED))      status = 'F';
  1139.                 if(_SVEUnit.getStatus().equals(UnitStatus.DEPOLLUTING))         status = 'P';
  1140.                 if(_SVEUnit.getDestination()!=null)                 status = 'G';
  1141.                 if(status!=0) {
  1142.                     CivDosRenderer.drawString(""+status, gfx, 0, Palette.defaultColors.get(0), imgx+4, imgy+7+8+1);
  1143.                     Color lightCol = Palette.defaultColors.get(((SVECiv) _SVEUnit.owner()).getID()==1?9:15);
  1144.                     CivDosRenderer.drawString(""+status, gfx, 0, lightCol, imgx+4, imgy+7+8);
  1145.                     gfx.setColor(Palette.defaultColors.get(7)); // very surprised by this gray frame, never noticed...
  1146.                     gfx.drawRect(imgx-1, imgy-1, 15, 15);
  1147.                 }
  1148.             }
  1149.         } else {
  1150.             Color backCol = Palette.defaultColors.get(0);
  1151.             Color lightCol = ImageUtils.civColors[((SVECiv) _SVEUnit.owner()).getID()][0];
  1152.             if(_SVEUnit.typeID()==0) {
  1153.                 backCol = Palette.defaultColors.get(6);
  1154.             }
  1155.             gfx.setColor(backCol);
  1156.             gfx.fillRect(imgx*4+1, imgy*4+1, 3, 3);
  1157.             gfx.setColor(lightCol);
  1158.             gfx.fillRect(imgx*4, imgy*4, 3, 3);
  1159.         }
  1160.     }
  1161.  
  1162.     public static void drawCity(City city /*GameSave gs,*//*, int x, int y, */, BufferedImage bi, BufferedImage namebi, int imgx, int imgy, boolean showAll, boolean showName) {
  1163.         //if(gs.getCityAt(x, y)!=null &&
  1164.         //      (gs.getCityAt(x, y).owner().equals(gs.getPlayerCiv()) ||
  1165.         //              gs.getCityAt(x, y).getVisibleSize()>0) || showAll) {
  1166.         Color lightCol = ImageUtils.civColors[((SVECiv) city.owner()).getID()][0];
  1167.         Color darkCol = ImageUtils.civColors[((SVECiv) city.owner()).getID()][1];
  1168.         boolean inRiot = city.has(CityStatus.RIOT);
  1169.         int size = city.getVisibleSize();
  1170.         if(city.owner().equals(((Entity)city).gamesave().player()) || showAll) {
  1171.             size = city.actualSize();
  1172.         }
  1173.         boolean hasUnits = city.hasUnits() || (((Short)((Entity) city).getValue("unknown_cb27"))&0xFF)!=0xFF;
  1174.         boolean hasWalls = city.has(CityImprovement.CITY_WALLS);
  1175.         String name = (showName?city.getName():null);
  1176.  
  1177.         CivDosRenderer.drawCity(bi,namebi,imgx,imgy,lightCol, darkCol, inRiot,hasUnits,hasWalls,size,name);
  1178.         //}
  1179.     }
  1180.  
  1181.     public static void drawMapTerrainSquare(Map wm, /*GameSave gs, */int x, int y, BufferedImage bi, int imgx, int imgy, boolean showAll, int mode,
  1182.             boolean drawLand, boolean drawSpecial, boolean drawRoad, boolean drawImpr, boolean drawPollution, boolean drawHuts,
  1183.             boolean drawShadow, boolean drawCity) {
  1184.         /*WorldMap map = gs.getMap();*/
  1185.         //GameSave gs = map.getGameSave();
  1186.  
  1187.         Graphics2D gfx = bi.createGraphics();
  1188.         boolean modeT = false;
  1189.         if(mode==0) {
  1190.  
  1191.             // seg012_427:
  1192.             // skipped: Theoretical "imgx" is computed as "imgx = (map_viewport_x - x) * 16 + 80"
  1193.             // skipped: Theoretical "imgy" is computed as "imgy = (map_viewport_y - y) * 16 + 8"
  1194.             // skipped: target imgx and imgy are tested to be within the "MAP" window of CIV screen:
  1195.             //     80 <= imgx < 320
  1196.             //      8 <= imgx < 192
  1197.  
  1198.  
  1199.             TerrainType var_terrainType = wm.getTerrain(x, y);
  1200.             //int var_impr = wm.getTerrainImprovementsFlag(x, y, showAll);
  1201.  
  1202.             if(var_terrainType.equals(TerrainType.OCEAN) && drawLand) {
  1203.                 // skipped: if(EGA or VGA); only dealing with VGA 256 color
  1204.                 int var_neighboursFlag = 0;
  1205.  
  1206.                 // seg012_540
  1207.                 for(int var_neighbourID = 1; var_neighbourID<9; var_neighbourID++) {
  1208.                     var_neighboursFlag = (var_neighboursFlag >> 1);
  1209.  
  1210.                     int nx = alignXinMapRange(x+CivUtils.relCitySquareX3[var_neighbourID]);
  1211.                     int ny = y+CivUtils.relCitySquareY3[var_neighbourID];
  1212.  
  1213.                     if(isInMap(nx,ny)) {
  1214.                         TerrainType var_neighbourType = wm.getTerrain(nx,ny);
  1215.                         if(!var_neighbourType.equals(TerrainType.OCEAN)) {
  1216.                             var_neighboursFlag |= 0b10000000;
  1217.                         }
  1218.                     }
  1219.                 }
  1220.  
  1221.                 int varCitySize = var_neighboursFlag;
  1222.  
  1223.                 // [1] The block below shifts the 2 highest bits to the 2 lowest positions         
  1224.                 int ax = var_neighboursFlag;
  1225.                 ax = (ax>>6);
  1226.                 ax = (ax&3);
  1227.                 int cx = var_neighboursFlag;
  1228.                 cx = (cx<<2);
  1229.                 cx = cx+ax;
  1230.                 var_neighboursFlag = cx;
  1231.                 // end of [1]
  1232.  
  1233.                 for(int var_neighbourID = 0; var_neighbourID<4; var_neighbourID++) {
  1234.                     int coast_special_id = 0;
  1235.                     int _x = 0;
  1236.                     int _y = 0;
  1237.                     if(var_neighbourID<2) {
  1238.                         int si = var_neighboursFlag;
  1239.                         cx = var_neighbourID;
  1240.                         cx = (cx<<1);  // cx = 2 * var_neighbourID
  1241.                         si = (si>>cx); // si = (var_neighboursFlag >> (2 * var_neighbourID) )
  1242.                         si = (si&7);   // si = (var_neighboursFlag >> (2 * var_neighbourID) ) & 0b111
  1243.                         si = (si<<3);  // si = ( (var_neighboursFlag >> (2 * var_neighbourID) ) & 0b111 ) << 3
  1244.  
  1245.                         int bx = var_neighbourID*2;
  1246.  
  1247.                         coast_special_id = (bx+si)/2;
  1248.  
  1249.                         _y = imgy;
  1250.                         _x = imgx + (var_neighbourID&1)*8;
  1251.                     } else {
  1252.                         int si = var_neighboursFlag;
  1253.                         cx = var_neighbourID;
  1254.                         cx = (cx<<1);  // cx = 2 * var_neighbourID
  1255.                         si = (si>>cx); // si = (var_neighboursFlag >> (2 * var_neighbourID) )
  1256.                         si = (si&7);   // si = (var_neighboursFlag >> (2 * var_neighbourID) ) & 0b111
  1257.                         si = (si<<3);  // si = ( (var_neighboursFlag >> (2 * var_neighbourID) ) & 0b111 ) << 3
  1258.  
  1259.                         int bx = var_neighbourID*2;
  1260.  
  1261.                         coast_special_id = (bx+si)/2;
  1262.  
  1263.                         _y = imgy +8;
  1264.                         _x = imgx - (var_neighbourID&1)*8 +8;
  1265.  
  1266.                     }
  1267.                     BufferedImage coastelem = ResourceManager.getSprite("terrain.overlay.coast_special."+coast_special_id+".");
  1268.                     gfx.drawImage(coastelem, _x, _y, null);
  1269.                 }
  1270.  
  1271.                 BufferedImage coastelem = null;
  1272.                 if(varCitySize == 0x1C) coastelem = ResourceManager.getSprite("terrain.overlay.coast_special.0x1C.");
  1273.                 if(varCitySize == 0xC1) coastelem = ResourceManager.getSprite("terrain.overlay.coast_special.0xC1.");
  1274.                 if(varCitySize == 0x07) coastelem = ResourceManager.getSprite("terrain.overlay.coast_special.0x07.");
  1275.                 if(varCitySize == 0x70) coastelem = ResourceManager.getSprite("terrain.overlay.coast_special.0x70.");
  1276.                 if(varCitySize == 0x8F) coastelem = ResourceManager.getSprite("terrain.overlay.coast_special.0x8F.");
  1277.                 if(varCitySize == 0xF8) coastelem = ResourceManager.getSprite("terrain.overlay.coast_special.0xF8.");
  1278.                 if(coastelem!=null) gfx.drawImage(coastelem, imgx, imgy, null);
  1279.  
  1280.  
  1281.                 for(int var_neighbourID = 1; var_neighbourID<9; var_neighbourID+=2) {
  1282.                     int nx = alignXinMapRange(x+CivUtils.relCitySquareX3[var_neighbourID]);
  1283.                     int ny = y+CivUtils.relCitySquareY3[var_neighbourID];
  1284.  
  1285.                     if(isInMap(nx,ny)) {
  1286.                         TerrainType var_neighbourType = wm.getTerrain(nx,ny);
  1287.                         if(var_neighbourType.equals(TerrainType.RIVER)) {
  1288.                             BufferedImage rivermouth = ResourceManager.getSprite("terrain.overlay.river."+(32 + var_neighbourID/2)+".");
  1289.                             gfx.drawImage(rivermouth, imgx, imgy, null);
  1290.                         }
  1291.                     }
  1292.                 }
  1293.             }
  1294.  
  1295.             if(!var_terrainType.equals(TerrainType.OCEAN) && drawLand) {
  1296.                 BufferedImage landbase = ResourceManager.getSprite("terrain.base.land.1.");
  1297.                 gfx.drawImage(landbase, imgx, imgy, null);
  1298.             }
  1299.  
  1300.             if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.IRRIGATION)
  1301.                     && !var_terrainType.equals(TerrainType.OCEAN)
  1302.                     && !modeT
  1303.                     && !wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.CITY)
  1304.                     && drawImpr) {
  1305.                 BufferedImage irrig = ResourceManager.getSprite("terrain.overlay.irrigation.");
  1306.                 gfx.drawImage(irrig, imgx, imgy, null);
  1307.             }
  1308.  
  1309.             if(var_terrainType.equals(TerrainType.RIVER) && drawLand) {
  1310.                 int var_neighboursFlag = 0;
  1311.                 int var_neighbourID = 1;
  1312.                 while(var_neighbourID<9) {
  1313.                     var_neighboursFlag = var_neighboursFlag >> 1;
  1314.                 int nx = alignXinMapRange(x+CivUtils.relCitySquareX3[var_neighbourID]);
  1315.                 int ny = y+CivUtils.relCitySquareY3[var_neighbourID];
  1316.                 if(isInMap(nx,ny)) {
  1317.                     TerrainType var_neighbourType = wm.getTerrain(nx,ny);
  1318.                     if(var_neighbourType.equals(TerrainType.RIVER)
  1319.                             || var_neighbourType.equals(TerrainType.OCEAN)) {
  1320.                         var_neighboursFlag |= 0b1000; // 0x8
  1321.                     }
  1322.                 }
  1323.                 var_neighbourID += 2;
  1324.                 }
  1325.  
  1326.                 if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.SPECIAL_RIVER)) {        
  1327.                     var_neighboursFlag += (0x10 - 1);
  1328.                 }
  1329.  
  1330.                 BufferedImage river = ResourceManager.getSprite("terrain.overlay.river."+(var_neighboursFlag+1)+".");
  1331.                 gfx.drawImage(river, imgx, imgy, null);
  1332.             }
  1333.  
  1334.             if(!var_terrainType.equals(TerrainType.OCEAN)
  1335.                     &&!var_terrainType.equals(TerrainType.RIVER)
  1336.                     && drawLand) {
  1337.                 int var_neighboursFlag = 0;
  1338.                 int var_neighbourID = 1;
  1339.                 while(var_neighbourID<9) {
  1340.                     var_neighboursFlag = var_neighboursFlag >> 1;
  1341.                 int nx = alignXinMapRange(x+CivUtils.relCitySquareX3[var_neighbourID]);
  1342.                 int ny = y+CivUtils.relCitySquareY3[var_neighbourID];
  1343.                 if(isInMap(nx,ny)) {
  1344.                     TerrainType var_neighbourType = wm.getTerrain(nx,ny);
  1345.                     if(var_neighbourType.equals(var_terrainType)) {
  1346.                         var_neighboursFlag |= 0b1000; // 0x8
  1347.                     }
  1348.                 }
  1349.                 var_neighbourID += 2;
  1350.                 }
  1351.                 String tcode = var_terrainType.getCode();
  1352.                 BufferedImage overlay = ResourceManager.getSprite("terrain.overlay."+tcode+"."+(var_neighboursFlag+1)+".");
  1353.                 gfx.drawImage(overlay, imgx, imgy, null);
  1354.             }
  1355.  
  1356.             if(var_terrainType.equals(TerrainType.GRASSLANDS) && drawLand) {
  1357.                 if(((7*x + 11*y)&0x2) == 0) {
  1358.                     BufferedImage overlay = ResourceManager.getSprite("city.resource.grassland.");
  1359.                     gfx.drawImage(overlay, imgx+4, imgy+4, null);
  1360.                 }
  1361.             }
  1362.  
  1363.             if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.POLLUTION) && drawPollution) {
  1364.                 BufferedImage overlay = ResourceManager.getSprite("terrain.overlay.pollution.");
  1365.                 gfx.drawImage(overlay, imgx, imgy, null);
  1366.             }
  1367.  
  1368.             if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.ROAD) && drawRoad) {
  1369.                 int var_20 = 6;
  1370.                 if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.RAILROAD)) {
  1371.                     var_20 = 0;
  1372.                 }
  1373.                 for(int var_neighbourID=1;var_neighbourID<=8;var_neighbourID++) {
  1374.                     int nx = alignXinMapRange(x+CivUtils.relCitySquareX3[var_neighbourID]);
  1375.                     int ny = y+CivUtils.relCitySquareY3[var_neighbourID];
  1376.                     if(wm.hasTerrainImprovement(nx, ny, showAll, TerrainImprovementType.ROAD)) {
  1377.                         var_20 = -1;
  1378.                         if((wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.RAILROAD)||
  1379.                                 wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.CITY))
  1380.                                 &&
  1381.                                 (wm.hasTerrainImprovement(nx, ny, showAll, TerrainImprovementType.RAILROAD)||
  1382.                                         wm.hasTerrainImprovement(nx, ny, showAll, TerrainImprovementType.CITY))) {
  1383.                             BufferedImage overlay = ResourceManager.getSprite("terrain.overlay.railroad."+var_neighbourID+".");
  1384.                             gfx.drawImage(overlay, imgx, imgy, null);
  1385.                         } else {
  1386.                             BufferedImage overlay = ResourceManager.getSprite("terrain.overlay.road."+var_neighbourID+".");
  1387.                             gfx.drawImage(overlay, imgx, imgy, null);
  1388.                         }
  1389.                     }
  1390.                 }
  1391.                 if(var_20!=-1) {
  1392.                     gfx.setColor(Palette.defaultColors.get(var_20));
  1393.                     gfx.fillRect(imgx+7, imgy+7, 2, 2);
  1394.                 }
  1395.             }
  1396.  
  1397.             if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.MINING)
  1398.                     && !modeT
  1399.                     && drawImpr) {
  1400.                 BufferedImage irrig = ResourceManager.getSprite("terrain.overlay.mining.");
  1401.                 gfx.drawImage(irrig, imgx, imgy, null);
  1402.             }
  1403.  
  1404.             if(wm.getGameSave()!=null) {
  1405.                 AbstractGameState gs = wm.getGameSave();
  1406.                 if(drawSpecial && isSpecialResource(x,y,gs.getRandomSeed())) {
  1407.                     BufferedImage irrig = ResourceManager.getSprite("terrain.overlay."+var_terrainType.getCode()+".special.");
  1408.                     gfx.drawImage(irrig, imgx, imgy, null);
  1409.                 }
  1410.  
  1411.                 if(drawHuts && isHut(x,y,gs.getRandomSeed(),false,null)) {
  1412.                     BufferedImage irrig = ResourceManager.getSprite("terrain.overlay.hut.");
  1413.                     gfx.drawImage(irrig, imgx, imgy, null);
  1414.                     if(wm.getTerrain(x, y).equals(TerrainType.OCEAN)) {
  1415.                         gfx.setColor(new Color(84, 72, 160, 191));
  1416.                         gfx.fillRect(imgx+1, imgy+1, 14, 13);
  1417.                     } else if(gs.civ(0).canSee(new MapLocation(x,y))) {
  1418.                         gfx.setColor(new Color(192,0,0,127));
  1419.                         gfx.fillRect(imgx+1, imgy+1, 14, 13);
  1420.                     }
  1421.                 }
  1422.             }
  1423.  
  1424.             if(drawImpr && wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.FORTRESS)) {
  1425.                 BufferedImage fortress = ResourceManager.getSprite("terrain.overlay.fortress.");
  1426.                 gfx.drawImage(fortress, imgx, imgy, null);
  1427.             }
  1428.  
  1429.             if(wm.getGameSave()!=null) {
  1430.                 AbstractGameState gs = wm.getGameSave();
  1431.                 if(/*!showAll &&*/ drawShadow) {
  1432.                     for(int var_neighbourID = 1; var_neighbourID<=8; var_neighbourID+=2) {
  1433.                         int nx = CivLogic.alignXinMapRange(x+CivUtils.relCitySquareX3[var_neighbourID]);
  1434.                         int ny = y+CivUtils.relCitySquareY3[var_neighbourID];
  1435.                         //if(!gs.getPlayerCiv().canSee(nx, ny)) {
  1436.                         if(!gs.player().canSee(new MapLocation(nx, ny))) {
  1437.                             BufferedImage border = ResourceManager.getSprite("terrain.overlay.border."+(var_neighbourID+1)/2+".");
  1438.                             gfx.drawImage(border, imgx, imgy, null);
  1439.                         }
  1440.                     }
  1441.                 }
  1442.  
  1443.                 /* DRAW CITY */
  1444.                 if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.CITY)
  1445.                         && !modeT
  1446.                         && drawCity) {
  1447.                     drawCity(gs.getCityAt(x, y),/* x, y,*/ bi, bi, imgx, imgy, showAll, false);
  1448.                 }
  1449.             }
  1450.         } else {
  1451.             if(wm.hasTerrainImprovement(x, y, showAll, TerrainImprovementType.CITY)) {
  1452.                 int owner = ((SVECiv) wm.owner(x, y)).getID();
  1453.                 gfx.setColor(ImageUtils.civColors[owner][0]);
  1454.             } else {
  1455.                 if(wm.getTerrain(x, y).equals(TerrainType.OCEAN)) {
  1456.                     gfx.setColor(Palette.defaultColors.get(1));
  1457.                 } else {
  1458.                     gfx.setColor(Palette.defaultColors.get(2));
  1459.                 }
  1460.             }
  1461.             gfx.fillRect(imgx, imgy, 4, 4);
  1462.         }
  1463.     }
  1464.  
  1465.     public static int alignXinMapRange(int x) {
  1466.         if(x>=0) {
  1467.             if(x<80) {
  1468.                 return x;
  1469.             } else{
  1470.                 return x-80; // only works if x<160
  1471.             }
  1472.         } else {
  1473.             return x+80; // only works if x>=-80
  1474.         }
  1475.     }
  1476.     public static boolean isInMap(int x, int y) {
  1477.         return (x>=0&&x<80&&y>=0&&y<50);
  1478.     }
  1479.  
  1480.     public static void colorReplace(BufferedImage bi, int x, int y, int w, int h, Color oldcol, Color newcol){
  1481.         for(int a=x;a<x+w;a++) {
  1482.             for(int b=y;b<y+h;b++) {
  1483.                 if(bi.getRGB(a, b)==oldcol.getRGB()) {
  1484.                     bi.setRGB(a, b, newcol.getRGB());
  1485.                 }
  1486.             }
  1487.         }
  1488.     }
  1489.  
  1490.     public static SVEUnit determineUnitToDraw(AbstractGameState gs, int x, int y, SVEUnit _SVEUnit) {
  1491.         SVEUnit result = null;
  1492.  
  1493.         if(!gs.getTerrain(x, y).equals(TerrainType.OCEAN)
  1494.                 || !_SVEUnit.hasNextInStack()
  1495.                 || _SVEUnit.getType().category().equals(UnitCategory.SEA)) {
  1496.             result = (AbstractSVEUnit)computeBestDefenseInUnitStack(gs,x,y,_SVEUnit)[0];
  1497.         } else {
  1498.             SVEUnit nextUnit = _SVEUnit;
  1499.             SVEUnit startUnit = _SVEUnit;
  1500.             do {
  1501.                 nextUnit = nextUnit.nextInStack();
  1502.                 if(nextUnit.getType().category().equals(UnitCategory.SEA)) {
  1503.                     result = nextUnit;
  1504.                 }
  1505.                 //System.out.println("1");
  1506.             } while(result == null && !nextUnit.equals(startUnit));
  1507.             if(result==null) {
  1508.                 result = startUnit;
  1509.             }
  1510.         }
  1511.         return result;
  1512.     }
  1513.  
  1514.     // function below returns { Unit, Integer }, for best unit and corresponding defense value
  1515.     public static Object[] computeBestDefenseInUnitStack(AbstractGameState gs, int x, int y, SVEUnit _SVEUnit) {
  1516.         Object[] result = { _SVEUnit, -1 };
  1517.         int startUnitID = _SVEUnit.getID();
  1518.         int counter = 0;
  1519.         do {
  1520.  
  1521.             TerrainType tt = gs.getTerrain(x, y);
  1522.             if(!tt.equals(TerrainType.OCEAN) || _SVEUnit.getType().category().equals(UnitCategory.SEA)) {
  1523.                 if(_SVEUnit.getType()!=null) {
  1524.                     int def = _SVEUnit.getType().defense();
  1525.                     if(_SVEUnit.getType().category().equals(UnitCategory.LAND)) {
  1526.                         if(_SVEUnit.getStatus().equals(UnitStatus.FORTIFIED)) {
  1527.                             def *= 3;
  1528.                         } else {
  1529.                             def *= 2;
  1530.                         }
  1531.                         def *= tt.getAttributes(CivLogic.isSpecialResource(x, y, gs.getRandomSeed()))[1];
  1532.                         def = def<<3;
  1533.                     } else {
  1534.                         def = def<<4;
  1535.                     }
  1536.                     if(_SVEUnit.isVeteran()) {
  1537.                         def = (def+(def>>2));
  1538.                     }
  1539.                     if(def>(Integer)result[1]) {
  1540.                         result[1] = def;
  1541.                         result[0] = _SVEUnit;
  1542.                     }
  1543.                 }
  1544.             }
  1545.  
  1546.             _SVEUnit = _SVEUnit.nextInStack();
  1547.             counter++;
  1548.             //System.out.println("0");
  1549.         } while(_SVEUnit!=null && _SVEUnit.getID()!=startUnitID && counter<10);
  1550.  
  1551.         return result;
  1552.     }
  1553.     public static Object[] computeBestDefenseInUnitStack(AbstractGameState gs, int x, int y, int civid, int unitid) {
  1554.         return computeBestDefenseInUnitStack(gs,x,y,((SVECiv) gs.civ(civid)).unit(unitid));
  1555.     }
  1556.  
  1557.     public static void resetStrategicLocations(Civ civ, int originalStatus, int x, int y, int range) {
  1558.         if(civ!=null) {
  1559.             AbstractGameState gs = ((Entity)civ).gamesave();
  1560.             if(gs!=null) {
  1561.                 for(int i=0;i<16;i++) {
  1562.                     int s = (Byte)((Entity) civ).getValue("geostrategy"+i+".active");
  1563.                     int sx = (Short)((Entity) civ).getValue("geostrategy"+i+".position_x");
  1564.                     int sy = (Short)((Entity) civ).getValue("geostrategy"+i+".position_y");
  1565.                     if(s==originalStatus) {
  1566.                         if(CivLogic.distance(x, sx, y, sy)<=range) {
  1567.                             ((Entity) civ).setPropertyValue("geostrategy"+i+".active",(byte)0xFF);
  1568.                         }
  1569.                     }
  1570.                 }
  1571.             }
  1572.         }
  1573.     }
  1574.  
  1575.     public static void putUnitAt(AbstractSVEUnit _SVEUnit, int x, int y) {
  1576.         AbstractGameState gs = ((Entity) _SVEUnit.owner()).gamesave();
  1577.         Map map = gs;
  1578.         SVEUnit unit0 = getUnitAt(gs,x, y);
  1579.         insertUnitInStack(_SVEUnit,unit0);
  1580.         map.setOwner(x, y, _SVEUnit.owner());
  1581.         map.setOccupied(x, y, true);
  1582.     }
  1583.  
  1584.     public static SVEUnit getUnitAt(AbstractGameState gs, int x, int y) {
  1585.         Civ owner = CivLogic.whatCivOccupies(gs, x, y);
  1586.         if(owner!=null) {
  1587.             for(int var_unitID=0;var_unitID<128;var_unitID++) {
  1588.                 SVEUnit u = ((SVECiv) owner).unit(var_unitID);
  1589.                 if(u.exists() && u.getLocation().x()==x && u.getLocation().y()==y) {
  1590.                     return u;
  1591.                 }
  1592.             }
  1593.         }
  1594.         return null;
  1595.     }
  1596.  
  1597.     public static void insertUnitInStack(AbstractSVEUnit added, SVEUnit unit0) {
  1598.         if(unit0!=null) {
  1599.             if(!unit0.hasNextInStack()) {
  1600.                 unit0.setNextInStack(added);
  1601.                 added.setNextInStack(unit0);
  1602.             } else {
  1603.                 SVEUnit next = unit0.nextInStack();
  1604.                 unit0.setNextInStack(added);
  1605.                 added.setNextInStack(next);
  1606.             }
  1607.         } else {
  1608.             added.setNextInStack(null);
  1609.         }
  1610.     }
  1611.  
  1612.     public static int dseg_6716_len = 0;
  1613.     public static int countCityTaxCollected_dseg_F09A;
  1614.     public static int countCityResearchBulbs_dseg_7066;
  1615.     public static int city_happyCitizenCount_dseg_7062;
  1616.     public static int city_unhappyCitizenCount_dseg_7064;
  1617.     public static int dseg_8F98;
  1618.  
  1619.     //seg007_6CE6:
  1620.     public static int adjustCitizenHappiness(City city, int specialistCount) {
  1621.         //seg007_6CE6:
  1622.         city_happyCitizenCount_dseg_7062 = rangeBound(city_happyCitizenCount_dseg_7062, 0, city.actualSize());
  1623.        
  1624.         while(true) {
  1625.             //seg007_6D3A:
  1626.             city_unhappyCitizenCount_dseg_7064 = rangeBound(city_unhappyCitizenCount_dseg_7064, 0, city.actualSize());
  1627.  
  1628.             if(rangeBound(city.actualSize()-specialistCount,0,99)>=city_happyCitizenCount_dseg_7062+city_unhappyCitizenCount_dseg_7064) return rangeBound(city.actualSize()-specialistCount,0,99);
  1629.  
  1630.             city_happyCitizenCount_dseg_7062--;
  1631.             city_happyCitizenCount_dseg_7062 = rangeBound(city_happyCitizenCount_dseg_7062, 0, city.actualSize());
  1632.            
  1633.             city_unhappyCitizenCount_dseg_7064--;
  1634.         }
  1635.     }
  1636.     public static int findPathLength(Map wm, int x1, int y1, int x2, int y2, boolean land, int maxmoves) {
  1637.         if(Math.abs(x1-x2)<7
  1638.                 ||Math.abs(y1-y2)<7) {
  1639.             // Create a fake militia or sail at (x1,y1)
  1640.             Civ civ0 = wm.getGameSave().civ(0);
  1641.             SVEUnit u127 = ((SVECiv) civ0).unit(127);
  1642.  
  1643.             ((Entity) civ0).setPropertyValue("unit127.position_x", (Short)(short)x1);
  1644.             ((Entity) civ0).setPropertyValue("unit127.position_y", (Short)(short)y1);
  1645.             ((Entity) civ0).setPropertyValue("unit127.type", (Short)(short)(land?1:16));
  1646.  
  1647.             int next = findNextPathSquare(u127,maxmoves,x2,y2);
  1648.  
  1649.             ((Entity) civ0).setPropertyValue("unit127.type", (Short)(short)(0xFF));
  1650.  
  1651.             if(next==-1) {
  1652.                 return -1;
  1653.             } else {
  1654.                 return dseg_6716_len;
  1655.             }
  1656.         } else {
  1657.             return -1;
  1658.         }
  1659.     }
  1660.  
  1661.     public static int findNextPathSquare(SVEUnit u127, int maxmoves, int destx, int desty) {
  1662.         int[] dseg_6516_unkX99 = new int[1000];
  1663.         int[] dseg_6616_unkY99 = new int[1000];
  1664.  
  1665.         dseg_6716_len = 0;
  1666.         int dseg_6718_unkx = 0;
  1667.         int dseg_671A_unky = 0;
  1668.         int[] dsegc6A0_grid16x16 = new int[16*16];
  1669.  
  1670.         int startX = u127.getLocation().x();
  1671.         int startY = u127.getLocation().y();
  1672.  
  1673.         int topleftX = destx-8;
  1674.         int topleftY = desty-8;
  1675.  
  1676.         if(destx!=dseg_6718_unkx
  1677.                 || desty!=dseg_671A_unky
  1678.                 || dsegc6A0_grid16x16[16*(startX-topleftX)+(startY-topleftY)]==0) {
  1679.             // seg016c7F
  1680.             dseg_6718_unkx = destx;
  1681.             dseg_671A_unky = desty;
  1682.             Arrays.fill(dsegc6A0_grid16x16,0);
  1683.             int var_2 = 0;
  1684.             int var_4 = 0;
  1685.             dseg_6516_unkX99[0] = destx;
  1686.             var_2++;
  1687.             dseg_6616_unkY99[0] = desty;
  1688.  
  1689.             dsegc6A0_grid16x16[16*(destx-topleftX)+desty-topleftY] = 1;
  1690.  
  1691.             int var_14 = 0;
  1692.             dseg_6716_len = maxmoves;
  1693.  
  1694.             int var_landOrSeaUnit = (u127.getType().category().equals(UnitCategory.SEA)?1:0);
  1695.             int var_totalMovesFlag = (u127.getType().totalMoves()==1?1:0);
  1696.  
  1697.             do{
  1698.                 int var_unkX_9 = dseg_6516_unkX99[var_4];
  1699.                 int var_unkY_9 = dseg_6616_unkY99[var_4];
  1700.                 var_4++;
  1701.                 int var_E = dsegc6A0_grid16x16[(var_unkX_9-topleftX)*16+var_unkY_9-topleftY];
  1702.  
  1703.                 int var_1A = -1;
  1704.                 if(var_E<=dseg_6716_len) {
  1705.                     if(alignXinMapRange(var_unkX_9)!=startX
  1706.                             ||var_unkY_9!=startY) {
  1707.                         //int var_impr = ((Entity)unit).gamesave().getTerrainImprovementsFlag(alignXinMapRange(var_unkX_9), var_unkY_9, true);
  1708.                         int var_nid = 1;
  1709.                         while(var_nid<=8) {
  1710.                             int nx = var_unkX_9+CivUtils.relCitySquareX3[var_nid];
  1711.                             if(Math.abs(nx-destx)<8) {
  1712.                                 int anx = alignXinMapRange(nx);
  1713.                                 int ny = var_unkY_9+CivUtils.relCitySquareY3[var_nid];
  1714.                                 if(Math.abs(ny-desty)<8) {
  1715.                                     if(isInMap(anx, ny)) {
  1716.                                         TerrainType ntt = ((Entity)u127).gamesave().getTerrain(anx, ny);
  1717.                                         if(var_landOrSeaUnit==(ntt.equals(TerrainType.OCEAN)?1:0)
  1718.                                                 || ((Entity)u127).gamesave().hasTerrainImprovement(anx, ny, false, TerrainImprovementType.CITY)) {
  1719.                                             if(((Entity)u127).gamesave().getAllImprovements(alignXinMapRange(var_unkX_9), var_unkY_9, true).size()==0
  1720.                                                     || ((Entity)u127).gamesave().getAllImprovements(anx, ny, true).size()==0) {
  1721.                                                 if(var_totalMovesFlag==0) {
  1722.                                                     var_1A = var_E + 3*ntt.movementCost(false);
  1723.                                                 } else {
  1724.                                                     var_1A = var_E + 3;
  1725.                                                 }
  1726.                                             } else {
  1727.                                                 var_1A = var_E+1;
  1728.                                             }
  1729.                                             int var_38 = dsegc6A0_grid16x16[(nx-topleftX)*16+ny-topleftY];
  1730.                                             if(var_38==0
  1731.                                                     || var_38>var_1A) {
  1732.                                                 dsegc6A0_grid16x16[(nx-topleftX)*16+ny-topleftY] = var_1A;
  1733.                                                 dseg_6516_unkX99[var_2] = nx;
  1734.                                                 dseg_6616_unkY99[var_2] = ny;
  1735.                                                 var_2++;
  1736.                                             }
  1737.                                         }
  1738.                                     }
  1739.                                 }
  1740.                             }
  1741.                             var_nid++;
  1742.                         }
  1743.                     } else {
  1744.                         dseg_6716_len = var_E;
  1745.                     }
  1746.                 }
  1747.             } while(var_2!=var_4 && var_4<225);
  1748.         }
  1749.         int var_lengthToNext = -1;
  1750.         int var_1A = -1;
  1751.         int var_next = -1;
  1752.         if(maxmoves>dseg_6716_len) {
  1753.             int var_A = 99;
  1754.             int nid = 1;
  1755.             while(nid<=8) {
  1756.                 int nx = startX+CivUtils.relCitySquareX3[nid];
  1757.                 if(Math.abs(nx-destx)>=72) {
  1758.                     if(nx<=destx) {
  1759.                         nx += 80;
  1760.                     } else {
  1761.                         nx -= 80;
  1762.                     }
  1763.                 }
  1764.                 if(Math.abs(nx-destx)<8) {
  1765.                     int anx = alignXinMapRange(nx);
  1766.                     int ny = startY + CivUtils.relCitySquareY3[nid];
  1767.                     if(Math.abs(ny-desty)<8) {
  1768.                         if(
  1769.                                 //(unit.getGameSave().getMap().getTerrain(anx, ny).equals(TerrainType.OCEAN)?1:0)
  1770.                                 //==
  1771.                                 //(unit.category().equals(UnitCategory.SEA)?1:0)
  1772.                                 !
  1773.                                 (((Entity)u127).gamesave().getTerrain(anx, ny).equals(TerrainType.OCEAN)
  1774.                                         ^
  1775.                                         u127.getType().category().equals(UnitCategory.SEA))
  1776.                                         || ((Entity)u127).gamesave().hasTerrainImprovement(anx, ny, false, TerrainImprovementType.CITY)
  1777.                                 ) {
  1778.                             int var_6 = dsegc6A0_grid16x16[(nx-topleftX)*16+ny-topleftY];
  1779.                             if(var_6!=0) {
  1780.                                 if(var_6<var_A) {
  1781.                                     var_A = var_6;
  1782.                                     var_next = nx;
  1783.                                     //Object[] var_12 = JCivLogic.getUnitAt(unit.getGameSave(), anx, ny);
  1784.                                     //if(var_12==null) {
  1785.                                     var_lengthToNext = 0;
  1786.                                     //} else {
  1787.                                     //  var_lengthToNext = 16; // unit count *4
  1788.                                     //}
  1789.                                     var_lengthToNext += distance(destx, anx, desty, ny);
  1790.                                 }
  1791.                                 if(var_6 == var_A) {
  1792.                                     //Object[] var_12 = JCivLogic.getUnitAt(unit.getGameSave(), anx, ny);
  1793.                                     //if(var_12==null) {
  1794.                                     var_1A = 0;
  1795.                                     //} else {
  1796.                                     //  var_1A = 16; // unit count *4
  1797.                                     //}
  1798.                                     var_1A += distance(destx, anx, desty, ny);
  1799.                                     if(var_1A<var_lengthToNext) {
  1800.                                         var_next = nid;
  1801.                                         var_lengthToNext = var_1A;
  1802.                                     }
  1803.                                 }
  1804.                             }
  1805.                         }
  1806.                     }
  1807.                 }
  1808.                 nid++;
  1809.             }
  1810.             if(var_next!=-1) {
  1811.                 return var_next;
  1812.             }
  1813.         }
  1814.         if(var_next==-1) {
  1815.             destx = (Short)((Entity) u127).getValue("gotox");
  1816.             desty = (Short)((Entity) u127).getValue("gotoy");
  1817.         }
  1818.         return -1;
  1819.     }
  1820.  
  1821.     public static byte[] computePathFind(Map wm, boolean land) {
  1822.         byte[] unknown25 = new byte[260];
  1823.         Arrays.fill(unknown25,(byte)0);
  1824.  
  1825.         //int ax=0;
  1826.  
  1827.         for(int tileX=0;tileX<20;tileX++) {
  1828.             for(int tileY=0;tileY<13;tileY++) {
  1829.                 int x = (tileX<<2)+1;
  1830.                 int y = (tileY<<2)+1;
  1831.                 int cid = -1;
  1832.  
  1833.                 int x2 = -1;
  1834.                 int y2 = -1;
  1835.                 if(land^wm.getTerrain(x, y).equals(TerrainType.OCEAN)) {
  1836.                     cid = wm.landMassID(x, y);
  1837.                     x2 = x;
  1838.                     y2 = y;
  1839.                 } else if (land^wm.getTerrain(x+1, y).equals(TerrainType.OCEAN)) {
  1840.                     cid = wm.landMassID( x+1, y);
  1841.                     x2 = x+1;
  1842.                     y2 = y;
  1843.                 } else if (land^wm.getTerrain(x, y+1).equals(TerrainType.OCEAN)) {
  1844.                     cid = wm.landMassID( x, y+1);
  1845.                     x2 = x;
  1846.                     y2 = y+1;
  1847.                 } else if (land^wm.getTerrain(x+1, y+1).equals(TerrainType.OCEAN)) {
  1848.                     cid = wm.landMassID( x+1, y+1);
  1849.                     x2 = x+1;
  1850.                     y2 = y+1;
  1851.                 }
  1852.  
  1853.                 if(cid!=-1 && ((x2>1 && x2<78 && y2>1 && y2<48)||!land)) {
  1854.                     for(int a=1;a<=4;a++) {
  1855.                         int rx = CivUtils.relCitySquareX3[a];
  1856.                         int ry = CivUtils.relCitySquareY3[a];
  1857.                         int x4 = x + 4*rx;
  1858.                         int y4 = y + 4*ry;
  1859.                         int cid2 = -1;
  1860.  
  1861.                         int x3 = -1;
  1862.                         int y3 = -1;
  1863.                         if(land^wm.getTerrain(x4, y4).equals(TerrainType.OCEAN)) {
  1864.                             cid2 = wm.landMassID( x4, y4);
  1865.                             x3 = x4;
  1866.                             y3 = y4;
  1867.                         } else if(land^wm.getTerrain(x4+1, y4).equals(TerrainType.OCEAN)) {
  1868.                             cid2 = wm.landMassID( x4+1, y4);
  1869.                             x3 = x4+1;
  1870.                             y3 = y4;
  1871.                         } else if(land^wm.getTerrain(x4, y4+1).equals(TerrainType.OCEAN)) {
  1872.                             cid2 = wm.landMassID( x4, y4+1);
  1873.                             x3 = x4;
  1874.                             y3 = y4+1;
  1875.                         } else if(land^wm.getTerrain(x4+1, y4+1).equals(TerrainType.OCEAN)) {
  1876.                             cid2 = wm.landMassID( x4+1, y4+1);
  1877.                             x3 = x4+1;
  1878.                             y3 = y4+1;
  1879.                         }
  1880.  
  1881.                         if(cid==cid2 && (( x3>1 && x3<78 && y3>1 && y3<48)||!land)) {
  1882.                             int pathLength = findPathLength(wm, x2, y2, x3, y3, land, 20);
  1883.                             if(pathLength!=-1 && pathLength<20) {
  1884.                                 unknown25[((tileY+13)%13)+13*((tileX+20)%20)] |= (1<<(a-1));
  1885.                                 unknown25[((tileY+CivUtils.relCitySquareY3[a]+13)%13)
  1886.                                           +13*((tileX+CivUtils.relCitySquareX3[a]+20)%20)] |= (1<<((a+3)&7));
  1887.                             }
  1888.                         }
  1889.                     }
  1890.                 }
  1891.             }
  1892.         }
  1893.  
  1894.         return unknown25;
  1895.     }
  1896.  
  1897.  
  1898.     public static void manageUnitArrival(AbstractSVEUnit _SVEUnit, int x, int y, int mode0) {
  1899.         AbstractGameState gs = ((Entity)_SVEUnit).gamesave();
  1900.         Civ player = gs.player();
  1901.         Map map = gs;
  1902.         Civ civ = _SVEUnit.owner();
  1903.         TerrainType tt = map.getTerrain(x, y);
  1904.         if(civ.equals(player)) {
  1905.             for(int nid = 0; nid<25; nid++) {
  1906.                 int nx = CivLogic.alignXinMapRange(x+CivUtils.relCitySquareX3[nid]);
  1907.                 int ny = y+CivUtils.relCitySquareY3[nid];
  1908.                 if(
  1909.                         nid<9 // inner ring, 8 first squares
  1910.                         ||
  1911.                         ((_SVEUnit.sightRange()&2)!=0 // has far sight (can see outer ring)
  1912.                         && ( !_SVEUnit.category().equals(UnitCategory.SEA) // is not maritime
  1913.                                 || map.getTerrain(nx,  ny).equals(TerrainType.OCEAN)) // or on ocean and maritime
  1914.                                 )
  1915.                         ) {
  1916.                     if(CivLogic.isInMap(nx, ny)) {
  1917.                         gs.setVisibility(civ, nx, ny, 1, 1, VisibilityType.VISIBLE);
  1918.                         map.actualizeVisibleImprovements(nx, ny, 1, 1);
  1919.                     }
  1920.                 }
  1921.             }
  1922.         }
  1923.         //int impr = map.getTerrainImprovementsFlag(x, y, true);
  1924.         for(int nid = 1; nid<9; nid++) {
  1925.             int nx = CivLogic.alignXinMapRange(x+CivUtils.relCitySquareX3[nid]);
  1926.             int ny = y+CivUtils.relCitySquareY3[nid];
  1927.             if(CivLogic.isInMap(nx, ny)) {
  1928.                 if(!civ.equals(gs.civ(0))) { // Barbarians do not reveal shadow
  1929.                     gs.setVisibility(civ, nx, ny, 1, 1, VisibilityType.VISIBLE);
  1930.                 }
  1931.                 //int nimpr = map.getTerrainImprovementsFlag(nx, ny, true);
  1932.                 if(map.hasTerrainImprovement(nx,  ny,  true, TerrainImprovementType.CITY)
  1933.                         &&(!gs.owner(nx,ny).equals(civ))) {
  1934.                     //seg005_3FF
  1935.                     Civ nowner = gs.owner(nx, ny);
  1936.                     City ncity = gs.getCityAt(nx, ny);
  1937.  
  1938.                     unkCityProcess27_28(ncity);
  1939.  
  1940.                     if(civ.equals(player)) {
  1941.                         ncity.visibleSize(ncity.actualSize());
  1942.                     }
  1943.  
  1944.                     if(_SVEUnit.category().equals(UnitCategory.LAND)) {
  1945.                         _SVEUnit.setVisibleBy(nowner,true);
  1946.                     }
  1947.                     int diplo = nowner.diplomaticStatusWith(civ);
  1948.                     if((diplo&2)==0) { // Not at war?
  1949.                         // TODO: strategic position update
  1950.                         seg010_34C8(nowner,nx,ny,1,4);
  1951.                         seg010_34C8(nowner,nx,ny,2,2);
  1952.                     }
  1953.                 }
  1954.                 SVEUnit nunit = getUnitAt(gs,nx,ny);
  1955.                 if(nunit!=null) {
  1956.                     Civ nciv = nunit.owner();
  1957.                     if(nciv!=null&&!nciv.equals(civ)) {
  1958.                         if(!map.hasTerrainImprovement(x,  y,  true, TerrainImprovementType.CITY)) {
  1959.                             _SVEUnit.setVisibleBy(nciv, true);
  1960.                         }
  1961.                         // TODO: wake sentried units on neighbour square
  1962.                         TerrainType ntt = map.getTerrain(nx, ny);
  1963.                         if(ntt.equals(TerrainType.OCEAN)||!tt.equals(TerrainType.OCEAN)) {
  1964.                             ((Entity) nunit).setPropertyValue("gotox",(Short)(short)0xFF);
  1965.                         }
  1966.                         if(ntt.equals(TerrainType.OCEAN)||!tt.equals(TerrainType.OCEAN)
  1967.                                 ||_SVEUnit.category().equals(UnitCategory.AIR)) {
  1968.                             _SVEUnit.setPropertyValue("gotox",(Short)(short)0xFF);
  1969.                         }
  1970.  
  1971.                         if(!map.hasTerrainImprovement(nx,  ny,  true, TerrainImprovementType.CITY)) {
  1972.                             nunit.setVisibleBy(civ, true);
  1973.                         }
  1974.                         if(_SVEUnit.category().equals(UnitCategory.LAND)
  1975.                                 && !tt.equals(TerrainType.OCEAN)
  1976.                                 && !ntt.equals(TerrainType.OCEAN)
  1977.                                 && !nunit.getType().category().equals(UnitCategory.AIR)) {
  1978.                             //IN PROGRESS - WIP
  1979.                         }
  1980.                     }
  1981.                 }
  1982.             }
  1983.         }
  1984.  
  1985.     }
  1986.  
  1987.     public static void seg010_34C8(Civ civ, int x, int y, int n1, int n2) {
  1988.         for(int loop=0;loop<32;loop++) {
  1989.             //TODO: things related with non-SVE data "unkown 32", a set of 32 strategic positions...
  1990.         }
  1991.     }
  1992.  
  1993.     public static void unkCityProcess27_28(City city) {
  1994.         if(city.owner().equals(((Entity)city).gamesave().player())) {
  1995.             // Skipped: unknown flag set to 1, at dseg_20F4
  1996.             for(String sb : new String[]{"27", "28"} ) {
  1997.                 int ub = ((Short)((Entity) city).getValue("unknown_cb"+sb))&0xFF;
  1998.                 if(ub!=0xFF) {
  1999.                     int tid = ub&0b111111;
  2000.                     AbstractSVEUnit _SVEUnit = CivLogic.createUnit(city.owner(), ((Entity)city).gamesave().unitType(tid), city.getLocation().x(), city.getLocation().y());
  2001.                     if(_SVEUnit!=null) {
  2002.                         _SVEUnit.setStatus(UnitStatus.FORTIFIED);
  2003.                         if((ub&0b1000000)!=0) {
  2004.                             _SVEUnit.setVeteran(true);
  2005.                         }
  2006.                         ((Entity) city).setPropertyValue("unknown_cb"+sb,(Short)(short)0xFF);
  2007.                     }
  2008.                 }
  2009.             }
  2010.             // Skipped: unknown flag set to 0, at dseg_20F4
  2011.             city.set(CityStatus.RAPTURE_1, true);
  2012.         }
  2013.     }
  2014.  
  2015.  
  2016.     public static void diplomacy(Civ civAI, int x, int y, int arg6, int arg2BE) {
  2017.         AbstractGameState gs = ((Entity)civAI).gamesave();
  2018.         Map map = gs;
  2019.         Civ player = gs.player();
  2020.         map.actualizeVisibleImprovements(x, y, 1, 1);
  2021.         // Skipped: draw map square terrain and units
  2022.         // Skipped: if English use "Queen" or "Empress" instead of "King" or "Emperor"
  2023.         int nextContact = (Integer)((Entity) civAI).getValue("contact_player_countdown");
  2024.         if(arg6==0) {
  2025.             ((Entity) civAI).setPropertyValue("contact_player_countdown", (Short)(short)(int)(Integer)gs.getValue("game_turn"));
  2026.         }
  2027.         int unk0 = 0;
  2028.         int var_24 = 0;
  2029.         int unk1 = arg6;
  2030.         int var_2E = 0;
  2031.         int hostility = 0;
  2032.         int var_8 = 1;
  2033.         int unk2 = 0;
  2034.  
  2035.         for(int cid=01;cid<15;cid++) {
  2036.             if((Short)((Entity)civAI).getValue("continent"+cid+"_city_count")<=((Short)((Entity)civAI).getValue("city_count")>1?1:0)
  2037.                     ||(Short)((Entity)player).getValue("continent"+cid+"_attack")<=(Short)((Entity)civAI).getValue("continent"+cid+"_defense"))
  2038.             {
  2039.                 if((Short)((Entity)player).getValue("continent"+cid+"_defense")!=0
  2040.                         &&(Short)((Entity)civAI).getValue("continent"+cid+"_defense")!=0) {
  2041.                     var_24 = 1;
  2042.                 }
  2043.                 if((Short)((Entity)player).getValue("continent"+cid+"_city_count")==0) {
  2044.                     if((Short)((Entity)civAI).getValue("continent"+cid+"_city_count")==0) {
  2045.                         hostility += ((Short)((Entity)civAI).getValue("continent"+cid+"_attack")-(Short)((Entity)player).getValue("continent"+cid+"_attack"))/4;
  2046.                     } else {
  2047.                         hostility += ((Short)((Entity)player).getValue("continent"+cid+"_defense")-(Short)((Entity)player).getValue("continent"+cid+"_attack"))/2;
  2048.                     }
  2049.                 } else {
  2050.                     if((Short)((Entity)civAI).getValue("continent"+cid+"_city_count")<=1) {
  2051.                         hostility += (Short)((Entity)civAI).getValue("continent"+cid+"_attack");
  2052.                     } else {
  2053.                         hostility += ((Short)((Entity)civAI).getValue("continent"+cid+"_attack")-(Short)((Entity)player).getValue("continent"+cid+"_attack"));
  2054.                     }
  2055.                 }
  2056.             } else {
  2057.                 var_2E += (!gs.getDifficultyLevel().equals(DifficultyLevel.CHIEFTAIN)?2:4)*
  2058.                         (Short)((Entity)player).getValue("continent"+cid+"_attack")/(1+(Short)((Entity)civAI).getValue("continent"+cid+"_defense"));
  2059.             }
  2060.         }
  2061.  
  2062.         int var_4 = 0;
  2063.         if((Short)((Entity)player).getValue("ranking")==7 // player is the best Civ in the world
  2064.                 && (Short)((Entity)player).getValue("city_count")>4 // player has more than 4 cities
  2065.                 && (Short)((Entity)civAI).getValue("city_count")>1 // AI has more than 1 city
  2066.                 && (Short)((Entity)player).getValue("active_units25")==0 // player does NOT have nukes
  2067.                 && (Integer)((Entity)gs).getValue("game_turn")>200 // after 1000 AD ?
  2068.                 ) {
  2069.             var_4 = 1;
  2070.         }
  2071.         if(var_4!=0
  2072.                 ||
  2073.                 ((((Integer)civAI.diplomaticStatusWith(player))&8)!=0 // vendetta
  2074.                 && (3*(Short)((Entity)civAI).getValue("military_power"))<=(Short)((Entity)player).getValue("military_power"))
  2075.                 ) {
  2076.             if((Short)((Entity)player).getValue("active_units25")==0) {
  2077.                 var_24 = 1;
  2078.                 hostility = CivLogic.rangeBound(hostility, 10*(short)((Entity)civAI).getValue("ranking"), 9999);
  2079.                 var_2E = 0;
  2080.             }
  2081.         }
  2082.         // ovr06_2A0
  2083.         if((Short)((Entity)civAI).getValue("active_units25")!=0) {
  2084.             int sflag = civAI.diplomaticStatusWith(player);
  2085.             civAI.setDiplomaticStatusWith(player, sflag | 0x80);
  2086.         }
  2087.         // ovr06_2C1
  2088.         if((Short)((Entity)civAI).getValue("active_units25")!=0
  2089.                 &&((Short)((Entity)player).getValue("active_units25")==0)) {
  2090.             var_24 = 1;
  2091.             hostility = CivLogic.rangeBound(hostility, 100, 9999);
  2092.         }
  2093.         // ovr06_2FB
  2094.         if((Short)((Entity)player).getValue("active_units25")!=0) {
  2095.             if((Short)((Entity)civAI).getValue("active_units25")!=0) {
  2096.                 hostility = (Short)((Entity)civAI).getValue("active_units25")*(hostility/2)/(Short)((Entity)player).getValue("active_units25");
  2097.             } else {
  2098.                 var_2E = 4;
  2099.             }
  2100.         }
  2101.         // ovr06_34C
  2102.         if(var_2E!=0) {
  2103.             var_24 = 0;
  2104.             var_8 = 0;
  2105.         }
  2106.         // ovr06_35C
  2107.         if(CivLogic.isWonderApplicable(player, WonderType.GREAT_WALL)
  2108.                 || CivLogic.isWonderApplicable(player, WonderType.UNITED_NATIONS)) {
  2109.             var_4 = 0;
  2110.             var_24 = 0;
  2111.             if((nextContact&0xFFFF)==0xFFFE) {
  2112.                 nextContact = 0xFFFF;
  2113.             }
  2114.         }
  2115.         //ovr06_397
  2116.         if((civAI.diplomaticStatusWith(player)&8)==0) { // no vendetta ?
  2117.             if((nextContact&0xFFFF)==0xFFFE) {
  2118.                 hostility = hostility/4;
  2119.             }
  2120.         } else {
  2121.             hostility = hostility *2;
  2122.         }
  2123.         //ovr06_3C2
  2124.         hostility = 50*CivLogic.rangeBound((hostility*(gs.getDifficultyLevel().getID()+1))/32,0,20);
  2125.         if(hostility>(Short)((Entity)player).getValue("cash")
  2126.                 && hostility<=2*(Short)((Entity)player).getValue("cash")
  2127.                 && (Short)((Entity)player).getValue("cash")>=50) {
  2128.  
  2129.         }
  2130.         //ovr06_417
  2131.         if((Short)((Entity)civAI).getValue("active_units25")!=0) {
  2132.             if(((Integer)civAI.diplomaticStatusWith(player)&0x80)==0
  2133.                     && (Short)((Entity)player).getValue("cash")<hostility) {
  2134.                 hostility = ((Short)((Entity)player).getValue("cash")/50)*50;
  2135.             }
  2136.             //over06_452
  2137.             int sflag = civAI.diplomaticStatusWith(player);
  2138.             civAI.setDiplomaticStatusWith(player, sflag | 0x80);
  2139.         }
  2140.         // ovr06_464
  2141.         if(hostility==0
  2142.                 || (3*(Short)((Entity)civAI).getValue("military_power"))<(Short)((Entity)player).getValue("military_power")) {
  2143.             var_24 = 0;
  2144.         }
  2145.         //ovr06_487
  2146.         if(var_24!=0) {
  2147.             var_8 = 2;
  2148.         }
  2149.         if(var_24==0
  2150.                 && (civAI.diplomaticStatusWith(player)&0x4)!=0) {
  2151.             var_8 = 0;
  2152.         }
  2153.         //ovr06_4B1
  2154.         int var_10 = var_24;
  2155.         int var_2A = 0;
  2156.         if((civAI.diplomaticStatusWith(player)&8)!=0) {
  2157.             var_2A = -2;
  2158.         }
  2159.         int var_30 = -1;
  2160.         int loopCivID = 1;
  2161.         do {
  2162.             Civ loopCiv = gs.civ(loopCivID);
  2163.             if(loopCivID!=((SVECiv) player).getID()
  2164.                     && (civAI.diplomaticStatusWith(gs.civ(loopCivID))&0x3)==1) {
  2165.                 if((Short)((Entity)loopCiv).getValue("military_power")*4>(Short)((Entity)civAI).getValue("military_power")) {
  2166.                     var_2A++;
  2167.                 }
  2168.                 if((Short)((Entity)loopCiv).getValue("military_power")>(Short)((Entity)civAI).getValue("military_power")) {
  2169.                     var_2A++;
  2170.                 }
  2171.                 if((player.diplomaticStatusWith(loopCiv)&0x2)!=0) {
  2172.                     var_30 = loopCivID; // here, var_30 is the ID of a Civ in peace with player, and at war with AI civ
  2173.                 }
  2174.             }
  2175.             loopCivID++;
  2176.         }while(loopCivID<8);
  2177.  
  2178.         //ovr06_54D (no name in IDA)
  2179.         var_2A = var_2A - civAI.diplomaticAttitude().id();
  2180.  
  2181.         if((Short)((Entity)player).getValue("military_power")<(Short)((Entity)civAI).getValue("military_power")) {
  2182.             var_2A--;
  2183.         }
  2184.  
  2185.         //ovr06_575
  2186.         //if(civAI.diplomaticStatusWith(player)&0x2)
  2187.     }
  2188.  
  2189.     public static int refreshLandValues(Map map, boolean useCivLogic) {
  2190.         //int[] vals1 = new int[(78-2)*(48-2)];
  2191.         //int[] vals3 = new int[(78-2)*(48-2)];
  2192.         int totalWorldValue = 0;
  2193.         //      int[] nvals = new int[80*50];
  2194.         //      Arrays.fill(nvals,-1);
  2195.         //int[] nvals = null;
  2196.         for(int x=2;x<78;x++) {
  2197.             for(int y=2;y<48;y++) {
  2198.                 int TMW = 0x10000;
  2199.                 if(map.getGameSave()!=null) TMW = map.getGameSave().getRandomSeed();
  2200.                 int landValue = CivLogic.computeLandValue(x, y, map, TMW, useCivLogic);
  2201.                 //vals3[(y-2)*76+(x-2)] = landValue;
  2202.                 map.setTerrainValue(x, y, true, landValue);
  2203.                 totalWorldValue += landValue;
  2204.  
  2205.                 //              int c = this.getRawLayerValue(1, x, y);
  2206.                 //              if(c==0||c>=8) {
  2207.                 //                  if(c==8) { // possibly a "city shroud"
  2208.                 boolean city = false;
  2209.                 for(int i=0;i<45&&!city;i++) {
  2210.                     int dx = CivUtils.relCitySquareX3[i];
  2211.                     int dy = CivUtils.relCitySquareY3[i];
  2212.                     int nx = CivLogic.alignXinMapRange(x+dx);
  2213.                     int ny = y+dy;
  2214.                     if(CivLogic.isInMap(nx, ny) && map.hasTerrainImprovement(nx, ny, true, TerrainImprovementType.CITY)) {
  2215.                         city=true;
  2216.                     }
  2217.                 }
  2218.                 if(!city) {
  2219.                     //vals1[(y-2)*76+(x-2)] = landValue;
  2220.                     map.setTerrainValue(x, y, false, landValue);
  2221.                 } else {
  2222.                     //vals1[(y-2)*76+(x-2)] = map.getRawLayerValue(1, x, y);
  2223.                     map.setTerrainValue(x, y, false, map.getTerrainValue(x, y, false));
  2224.                 }
  2225.                 //                  }
  2226.                 //                 
  2227.                 //              } else {
  2228.                 //                  vals1[(y-2)*76+(x-2)] = c;
  2229.                 //              }
  2230.             }
  2231.         }
  2232.         //map.setLayerValues(2, 2, 76, 46, 1, vals1);
  2233.         //map.setLayerValues(2, 2, 76, 46, 3, vals3);
  2234.         return totalWorldValue;
  2235.     }
  2236.     public static int computeLandValue(int x, int y, Map wm, int TMW, boolean useCivLogic) {
  2237.         boolean debug=false&&(x==48&&y==32);
  2238.  
  2239.         if(debug)       System.out.println("Compute land value: x="+x+", y="+y);
  2240.         short value = 0;
  2241.  
  2242.         TerrainType terrain = wm.getTerrain(x, y);
  2243.         if(debug)       System.out.println("   terrain is "+terrain.toString());
  2244.         if(terrain!=TerrainType.RIVER
  2245.                 && terrain!=TerrainType.GRASSLANDS
  2246.                 && terrain!=TerrainType.PLAINS) {
  2247.             value = 0;
  2248.         } else {
  2249.             // Process neighbour "city" squares
  2250.             short relValue = 0;
  2251.             for(int i=0;i<=20;i++) {
  2252.                 relValue = 0;
  2253.                 if(debug)       System.out.println("      checking neighbour "+i+" ("+CivUtils.relCityX[i]+","+CivUtils.relCityY[i]+")");
  2254.                 int relX = x+CivUtils.relCityX[i];
  2255.                 int relY = y+CivUtils.relCityY[i];
  2256.  
  2257.                 //              if(neighbourCache!=null && neighbourCache[relY*80+relX]!=-1) {
  2258.                 //                  relValue = (short) neighbourCache[relY*80+relX];
  2259.                 //              } else {
  2260.                 TerrainType relT = wm.getTerrain(relX, relY);
  2261.                 if(debug)       System.out.print("         neighbour type: "+relT);
  2262.  
  2263.                 boolean special = false;
  2264.                 //int statsId = relT.getMsgID();
  2265.                 if(relT==TerrainType.RIVER || relT==TerrainType.GRASSLANDS) {
  2266.                     if(debug)       System.out.println("");
  2267.                     if (((relX+relY)%4) == 0 || ((relX+relY)%4) == 3) {
  2268.                         relValue += 2;
  2269.                         if(debug)       System.out.println("         special river/grassland -> +2 -> relVal = "+relValue);
  2270.                     }
  2271.                 } else if(TMW<Short.MAX_VALUE) if (isSpecialResource(relX, relY, TMW)){
  2272.                     //relValue += 12;
  2273.                     //System.out.println("         special resource -> +12 -> relVal = "+relValue);
  2274.                     if(debug)       System.out.print(" + SEPCIAL");
  2275.                     if(debug)       System.out.println("");
  2276.  
  2277.                     //statsId += 12;
  2278.                     special = true;
  2279.                 } else {
  2280.                     if(debug)       System.out.println("");
  2281.                 }
  2282.  
  2283.  
  2284.  
  2285.                 relValue += relT.getScore(special);
  2286.                 if(debug)       System.out.println("         terrainScore -> +"+relT.getScore(special)+" ("+relT.getMsgID()+") -> relVal = "+relValue);
  2287.  
  2288.                 if( (i<9 && useCivLogic) || (i<8 && !useCivLogic) ) { // inner circle
  2289.                     relValue *= 2;
  2290.                     if(debug)       System.out.println("         inner circle -> x2 -> relVal = "+relValue);
  2291.                 }
  2292.                 if( (i==0 && useCivLogic) || (i==20 && !useCivLogic) ) {
  2293.                     relValue *= 2;
  2294.                     if(!useCivLogic) relValue *= 2;
  2295.                     if(debug)       System.out.println("         i == 0 (?) -> x2 -> relVal = "+relValue);
  2296.                 }
  2297.                 //                  if(neighbourCache!=null) neighbourCache[relY*80+relX] = relValue;
  2298.                 //              }
  2299.  
  2300.                 value += relValue;
  2301.                 if(debug)       System.out.println("   TOTAL VALUE so far: "+Utils.dhInt(value));
  2302.             }
  2303.  
  2304.             if(terrain==TerrainType.RIVER || terrain==TerrainType.GRASSLANDS) {
  2305.                 if (!(((x+y)%4) == 0 || ((x+y)%4) == 3)) {
  2306.                     value -= 16;
  2307.                     if(debug)       System.out.println("   Central terrain is grassland/river but NOT special -> -16 -> value = "+value);
  2308.                 }
  2309.             }
  2310.  
  2311.             int dxax = value - 120;
  2312.             short _ax = (short)dxax;
  2313.             short _dx = (short)(dxax>>16);
  2314.             _ax = (short) (_ax ^ _dx);
  2315.             _ax -= _dx;
  2316.             if(debug)       System.out.println("   abs(value -120) -> value = "+Utils.dbhInt(_ax));
  2317.  
  2318.             _ax >>= 3;
  2319.                 _ax = (short) (_ax ^ _dx);
  2320.                 _ax -= _dx;
  2321.                 if(debug)       System.out.println("   abs(value/8) -> value = "+Utils.dbhInt(_ax));
  2322.  
  2323.                 value = (_ax<1?1:_ax>15?15:_ax);
  2324.                 if(debug)       System.out.println("   range bound to [1..15] -> value = "+value);
  2325.  
  2326.                 relValue = (short) (((value+(value<0?1:0))>>1)+8);
  2327.                 if(debug)       System.out.println("   final compute -> += (value+(value<0?1:0))/2+8 -> value = "+relValue);
  2328.                 //relValue = Math.abs(relValue)/2+8;
  2329.  
  2330.                 value = relValue;
  2331.         }
  2332.  
  2333.  
  2334.         return value;
  2335.     }
  2336.  
  2337.  
  2338. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement