Ignore:
Timestamp:
Jan 7, 2017, 11:32:14 AM (7 years ago)
Author:
chronos
Message:
  • Modified: Formated all project source files using Delphi formatter as original indentation and other formatting was really bad.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/LocalPlayer/ClientTools.pas

    r2 r6  
    11{$INCLUDE switches}
    2 
    32unit ClientTools;
    43
     
    98
    109const
    11 nOfferedResourceWeights=6;
    12 OfferedResourceWeights: array[0..nOfferedResourceWeights-1] of cardinal=
    13 (rwOff, rwMaxScience, rwForceScience, rwMaxGrowth, rwForceProd, rwMaxProd);
     10  nOfferedResourceWeights = 6;
     11  OfferedResourceWeights: array [0 .. nOfferedResourceWeights - 1] of cardinal =
     12    (rwOff, rwMaxScience, rwForceScience, rwMaxGrowth, rwForceProd, rwMaxProd);
    1413
    1514type
    16 TImpOrder=array[0..(nImp+4) div 4 *4 -1] of ShortInt;
    17 TEnhancementJobs=array[0..11,0..7] of Byte;
    18 JobResultSet=set of 0..39;
     15  TImpOrder = array [0 .. (nImp + 4) div 4 * 4 - 1] of ShortInt;
     16  TEnhancementJobs = array [0 .. 11, 0 .. 7] of Byte;
     17  JobResultSet = set of 0 .. 39;
    1918
    2019var
    21 Server: TServerCall;
    22 G: TNewGameData;
    23 me: integer;
    24 MyRO: ^TPlayerContext;
    25 MyMap: ^TTileList;
    26 MyUn: ^TUnList;
    27 MyCity: ^TCityList;
    28 MyModel: ^TModelList;
    29 
    30 AdvValue: array[0..nAdv-1] of integer;
    31 
    32 
    33 function dLoc(Loc,dx,dy: integer): integer;
    34 function Distance(Loc0,Loc1: integer): integer;
    35 function UnrestAtLoc(uix,Loc: integer): boolean;
     20  Server: TServerCall;
     21  G: TNewGameData;
     22  me: integer;
     23  MyRO: ^TPlayerContext;
     24  MyMap: ^TTileList;
     25  MyUn: ^TUnList;
     26  MyCity: ^TCityList;
     27  MyModel: ^TModelList;
     28
     29  AdvValue: array [0 .. nAdv - 1] of integer;
     30
     31function dLoc(Loc, dx, dy: integer): integer;
     32function Distance(Loc0, Loc1: integer): integer;
     33function UnrestAtLoc(uix, Loc: integer): boolean;
    3634function GetMoveAdvice(uix, ToLoc: integer;
    3735  var MoveAdviceData: TMoveAdviceData): integer;
     
    4341function IsMilReportNew(Enemy: integer): boolean;
    4442function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean;
    45   gov,size: integer): integer;
    46 function CityTaxBalance(cix: integer; const CityReport: TCityReportNew): integer;
     43  gov, size: integer): integer;
     44function CityTaxBalance(cix: integer; const CityReport: TCityReportNew)
     45  : integer;
    4746procedure SumCities(var TaxSum, ScienceSum: integer);
    48 function JobTest(uix,Job: integer; IgnoreResults: JobResultSet = []): boolean;
     47function JobTest(uix, Job: integer; IgnoreResults: JobResultSet = []): boolean;
    4948procedure GetUnitInfo(Loc: integer; var uix: integer; var UnitInfo: TUnitInfo);
    5049procedure GetCityInfo(Loc: integer; var cix: integer; var CityInfo: TCityInfo);
    5150function UnitExhausted(uix: integer): boolean;
    5251function ModelHash(const ModelInfo: TModelInfo): integer;
    53 function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs): integer;
     52function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs)
     53  : integer;
    5454function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean;
    5555procedure DebugMessage(Level: integer; Text: string);
     
    6262procedure CityOptimizer_EndOfTurn;
    6363
    64 
    6564implementation
    6665
    6766var
    68 CityNeedsOptimize: array[0..ncmax-1] of boolean;
    69 
    70 
    71 function dLoc(Loc,dx,dy: integer): integer;
     67  CityNeedsOptimize: array [0 .. ncmax - 1] of boolean;
     68
     69function dLoc(Loc, dx, dy: integer): integer;
    7270var
    73 y0: integer;
     71  y0: integer;
    7472begin
    75 y0:=(Loc+G.lx*1024) div G.lx -1024;
    76 result:=(Loc+(dx+y0 and 1+G.lx*1024) shr 1) mod G.lx +G.lx*(y0+dy)
     73  y0 := (Loc + G.lx * 1024) div G.lx - 1024;
     74  result := (Loc + (dx + y0 and 1 + G.lx * 1024) shr 1) mod G.lx + G.lx
     75    * (y0 + dy)
    7776end;
    7877
    79 function Distance(Loc0,Loc1: integer): integer;
     78function Distance(Loc0, Loc1: integer): integer;
    8079var
    81 dx,dy: integer;
     80  dx, dy: integer;
    8281begin
    83 inc(Loc0,G.lx*1024);
    84 inc(Loc1,G.lx*1024);
    85 dx:=abs(((Loc1 mod G.lx *2 +Loc1 div G.lx and 1)
    86   -(Loc0 mod G.lx *2 +Loc0 div G.lx and 1)+3*G.lx) mod (2*G.lx) -G.lx);
    87 dy:=abs(Loc1 div G.lx-Loc0 div G.lx);
    88 result:=dx+dy+abs(dx-dy) shr 1;
     82  inc(Loc0, G.lx * 1024);
     83  inc(Loc1, G.lx * 1024);
     84  dx := abs(((Loc1 mod G.lx * 2 + Loc1 div G.lx and 1) - (Loc0 mod G.lx * 2 +
     85    Loc0 div G.lx and 1) + 3 * G.lx) mod (2 * G.lx) - G.lx);
     86  dy := abs(Loc1 div G.lx - Loc0 div G.lx);
     87  result := dx + dy + abs(dx - dy) shr 1;
    8988end;
    9089
    91 function UnrestAtLoc(uix,Loc: integer): boolean;
     90function UnrestAtLoc(uix, Loc: integer): boolean;
    9291var
    93 uix1: integer;
     92  uix1: integer;
    9493begin
    95 result:=false;
    96 if MyModel[MyUn[uix].mix].Flags and mdCivil=0 then
    97   case MyRO.Government of
    98     gRepublic, gFuture:
    99       result:=(MyRO.Territory[Loc]>=0) and (MyRO.Territory[Loc]<>me)
    100         and (MyRO.Treaty[MyRO.Territory[Loc]]<trAlliance);
    101     gDemocracy:
    102       result:=(MyRO.Territory[Loc]<0) or (MyRO.Territory[Loc]<>me)
    103         and (MyRO.Treaty[MyRO.Territory[Loc]]<trAlliance);
     94  result := false;
     95  if MyModel[MyUn[uix].mix].Flags and mdCivil = 0 then
     96    case MyRO.Government of
     97      gRepublic, gFuture:
     98        result := (MyRO.Territory[Loc] >= 0) and (MyRO.Territory[Loc] <> me) and
     99          (MyRO.Treaty[MyRO.Territory[Loc]] < trAlliance);
     100      gDemocracy:
     101        result := (MyRO.Territory[Loc] < 0) or (MyRO.Territory[Loc] <> me) and
     102          (MyRO.Treaty[MyRO.Territory[Loc]] < trAlliance);
    104103    end;
    105 with MyModel[MyUn[uix].mix] do
    106   if Cap[mcSeaTrans]+Cap[mcAirTrans]+Cap[mcCarrier]>0 then
    107     for uix1:=0 to MyRO.nUn-1 do // check transported units too
    108       if (MyUn[uix1].Loc>=0) and (MyUn[uix1].Master=uix) then
    109         result:=result or UnrestAtLoc(uix1,Loc);
     104  with MyModel[MyUn[uix].mix] do
     105    if Cap[mcSeaTrans] + Cap[mcAirTrans] + Cap[mcCarrier] > 0 then
     106      for uix1 := 0 to MyRO.nUn - 1 do // check transported units too
     107        if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) then
     108          result := result or UnrestAtLoc(uix1, Loc);
    110109end;
    111110
    112 function GetMoveAdvice(uix, ToLoc: integer; var MoveAdviceData: TMoveAdviceData): integer;
     111function GetMoveAdvice(uix, ToLoc: integer;
     112  var MoveAdviceData: TMoveAdviceData): integer;
    113113var
    114 MinEndHealth: integer;
     114  MinEndHealth: integer;
    115115begin
    116 if MyModel[MyUn[uix].mix].Domain=dGround then MinEndHealth:=100
    117 else MinEndHealth:=1; // resistent to hostile terrain -- don't consider
    118 repeat
    119   if MyUn[uix].Health>=MinEndHealth then
    120     begin
    121     MoveAdviceData.ToLoc:=ToLoc;
    122     MoveAdviceData.MoreTurns:=999;
    123     MoveAdviceData.MaxHostile_MovementLeft:=MyUn[uix].Health-MinEndHealth;
    124     result:=Server(sGetMoveAdvice,me,uix,MoveAdviceData);
    125     if (MinEndHealth<=1) or (result<>eNoWay) then exit;
     116  if MyModel[MyUn[uix].mix].Domain = dGround then
     117    MinEndHealth := 100
     118  else
     119    MinEndHealth := 1; // resistent to hostile terrain -- don't consider
     120  repeat
     121    if MyUn[uix].Health >= MinEndHealth then
     122    begin
     123      MoveAdviceData.ToLoc := ToLoc;
     124      MoveAdviceData.MoreTurns := 999;
     125      MoveAdviceData.MaxHostile_MovementLeft := MyUn[uix].Health - MinEndHealth;
     126      result := Server(sGetMoveAdvice, me, uix, MoveAdviceData);
     127      if (MinEndHealth <= 1) or (result <> eNoWay) then
     128        exit;
    126129    end;
    127   case MinEndHealth of
    128     100: MinEndHealth:=50;
    129     50: MinEndHealth:=25;
    130     25: MinEndHealth:=12;
    131     else MinEndHealth:=1
     130    case MinEndHealth of
     131      100:
     132        MinEndHealth := 50;
     133      50:
     134        MinEndHealth := 25;
     135      25:
     136        MinEndHealth := 12;
     137    else
     138      MinEndHealth := 1
    132139    end;
    133 until false
    134 end;
    135 
    136 function ColorOfHealth(Health: integer): integer;
    137 var
    138 red,green: integer;
    139 begin
    140 green:=400*Health div 100; if green>200 then green:=200;
    141 red:=510*(100-Health) div 100; if red>255 then red:=255;
    142 result:=green shl 8 + red
    143 end;
    144 
    145 function IsMultiPlayerGame: boolean;
    146 var
    147 p1: integer;
    148 begin
    149 result:=false;
    150 for p1:=1 to nPl-1 do
    151   if G.RO[p1]<>nil then result:=true;
    152 end;
    153 
    154 procedure ItsMeAgain(p: integer);
    155 begin
    156 if G.RO[p]<>nil then
    157   MyRO:=pointer(G.RO[p])
    158 else if G.SuperVisorRO[p]<>nil then
    159   MyRO:=pointer(G.SuperVisorRO[p])
    160 else exit;
    161 me:=p;
    162 MyMap:=pointer(MyRO.Map);
    163 MyUn:=pointer(MyRO.Un);
    164 MyCity:=pointer(MyRO.City);
    165 MyModel:=pointer(MyRO.Model);
    166 end;
    167 
    168 function GetAge(p: integer): integer;
    169 var
    170 i: integer;
    171 begin
    172 if p=me then
    173   begin
    174   result:=0;
    175   for i:=1 to 3 do
    176     if MyRO.Tech[AgePreq[i]]>=tsApplicable then result:=i;
    177   end
    178 else
    179   begin
    180   result:=0;
    181   for i:=1 to 3 do
    182     if MyRO.EnemyReport[p].Tech[AgePreq[i]]>=tsApplicable then result:=i;
    183   end
    184 end;
    185 
    186 function IsCivilReportNew(Enemy: integer): boolean;
    187 var
    188 i: integer;
    189 begin
    190 assert(Enemy<>me);
    191 i:=MyRO.EnemyReport[Enemy].TurnOfCivilReport;
    192 result:= (i=MyRO.Turn) or (i=MyRO.Turn-1) and (Enemy>me);
    193 end;
    194 
    195 function IsMilReportNew(Enemy: integer): boolean;
    196 var
    197 i: integer;
    198 begin
    199 assert(Enemy<>me);
    200 i:=MyRO.EnemyReport[Enemy].TurnOfMilReport;
    201 result:= (i=MyRO.Turn) or (i=MyRO.Turn-1) and (Enemy>me);
    202 end;
    203 
    204 function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean;
    205   gov,size: integer): integer;
    206 begin
    207 result:=FoodSurplus;
    208 if not IsCityAlive
    209   or (result>0)
    210      and ((gov=gFuture)
    211        or (size>=NeedAqueductSize) and (result<2)) then
    212   result:=0; {no growth}
    213 end;
    214 
    215 function CityTaxBalance(cix: integer; const CityReport: TCityReportNew): integer;
    216 var
    217 i: integer;
    218 begin
    219 result:=0;
    220 if (CityReport.HappinessBalance>=0) {no disorder}
    221   and (MyCity[cix].Flags and chCaptured=0) then // not captured
    222   begin
    223   inc(result, CityReport.Tax);
    224   if (MyCity[cix].Project and (cpImp+cpIndex)=cpImp+imTrGoods)
    225     and (CityReport.Production>0) then
    226     inc(result, CityReport.Production);
    227   if ((MyRO.Government=gFuture)
    228       or (MyCity[cix].Size>=NeedAqueductSize)
    229       and (CityReport.FoodSurplus<2))
    230     and (CityReport.FoodSurplus>0) then
    231     inc(result, CityReport.FoodSurplus);
    232   end;
    233 for i:=28 to nImp-1 do if MyCity[cix].Built[i]>0 then
    234   dec(result, Imp[i].Maint);
    235 end;
    236 
    237 procedure SumCities(var TaxSum, ScienceSum: integer);
    238 var
    239 cix: integer;
    240 CityReport: TCityReportNew;
    241 begin
    242 TaxSum:=MyRO.OracleIncome;
    243 ScienceSum:=0;
    244 if MyRO.Government=gAnarchy then exit;
    245 for cix:=0 to MyRO.nCity-1 do if MyCity[cix].Loc>=0 then
    246   begin
    247   CityReport.HypoTiles:=-1;
    248   CityReport.HypoTaxRate:=-1;
    249   CityReport.HypoLuxuryRate:=-1;
    250   Server(sGetCityReportNew,me,cix,CityReport);
    251   if (CityReport.HappinessBalance>=0) {no disorder}
    252     and (MyCity[cix].Flags and chCaptured=0) then // not captured
    253     ScienceSum:=ScienceSum+CityReport.Science;
    254   TaxSum:=TaxSum+CityTaxBalance(cix, CityReport);
    255   end;
    256 end;
    257 
    258 function JobTest(uix,Job: integer; IgnoreResults: JobResultSet): boolean;
    259 var
    260 Test: integer;
    261 begin
    262 Test:=Server(sStartJob+Job shl 4-sExecute,me,uix,nil^);
    263 result:= (Test>=rExecuted) or (Test in IgnoreResults);
    264 end;
    265 
    266 procedure GetUnitInfo(Loc: integer; var uix: integer; var UnitInfo: TUnitInfo);
    267 var
    268 i,Cnt: integer;
    269 begin
    270 if MyMap[Loc] and fOwned<>0 then
    271   begin
    272   Server(sGetDefender,me,Loc,uix);
    273   Cnt:=0;
    274   for i:=0 to MyRO.nUn-1 do
    275     if MyUn[i].Loc=Loc then inc(Cnt);
    276   MakeUnitInfo(me,MyUn[uix],UnitInfo);
    277   if Cnt>1 then UnitInfo.Flags:=UnitInfo.Flags or unMulti;
    278   end
    279 else
    280   begin
    281   uix:=MyRO.nEnemyUn-1;
    282   while (uix>=0) and (MyRO.EnemyUn[uix].Loc<>Loc) do dec(uix);
    283   UnitInfo:=MyRO.EnemyUn[uix];
    284   end
    285 end;{GetUnitInfo}
    286 
    287 procedure GetCityInfo(Loc: integer; var cix: integer; var CityInfo: TCityInfo);
    288 begin
    289 if MyMap[Loc] and fOwned<>0 then
    290   begin
    291   CityInfo.Loc:=Loc;
    292   cix:=MyRO.nCity-1;
    293   while (cix>=0) and (MyCity[cix].Loc<>Loc) do dec(cix);
    294   with CityInfo do
    295     begin
    296     Owner:=me;
    297     ID:=MyCity[cix].ID;
    298     Size:=MyCity[cix].Size;
    299     Flags:=0;
    300     if MyCity[cix].Built[imPalace]>0 then inc(Flags,ciCapital);
    301     if (MyCity[cix].Built[imWalls]>0)
    302       or (MyMap[MyCity[cix].Loc] and fGrWall<>0) then inc(Flags,ciWalled);
    303     if MyCity[cix].Built[imCoastalFort]>0 then inc(Flags,ciCoastalFort);
    304     if MyCity[cix].Built[imMissileBat]>0 then inc(Flags,ciMissileBat);
    305     if MyCity[cix].Built[imBunker]>0 then inc(Flags,ciBunker);
    306     if MyCity[cix].Built[imSpacePort]>0 then inc(Flags,ciSpacePort);
     140  until false end;
     141
     142  function ColorOfHealth(Health: integer): integer;
     143  var
     144    red, green: integer;
     145  begin
     146    green := 400 * Health div 100;
     147    if green > 200 then
     148      green := 200;
     149    red := 510 * (100 - Health) div 100;
     150    if red > 255 then
     151      red := 255;
     152    result := green shl 8 + red
     153  end;
     154
     155  function IsMultiPlayerGame: boolean;
     156  var
     157    p1: integer;
     158  begin
     159    result := false;
     160    for p1 := 1 to nPl - 1 do
     161      if G.RO[p1] <> nil then
     162        result := true;
     163  end;
     164
     165  procedure ItsMeAgain(p: integer);
     166  begin
     167    if G.RO[p] <> nil then
     168      MyRO := pointer(G.RO[p])
     169    else if G.SuperVisorRO[p] <> nil then
     170      MyRO := pointer(G.SuperVisorRO[p])
     171    else
     172      exit;
     173    me := p;
     174    MyMap := pointer(MyRO.Map);
     175    MyUn := pointer(MyRO.Un);
     176    MyCity := pointer(MyRO.City);
     177    MyModel := pointer(MyRO.Model);
     178  end;
     179
     180  function GetAge(p: integer): integer;
     181  var
     182    i: integer;
     183  begin
     184    if p = me then
     185    begin
     186      result := 0;
     187      for i := 1 to 3 do
     188        if MyRO.Tech[AgePreq[i]] >= tsApplicable then
     189          result := i;
    307190    end
    308   end
    309 else
    310   begin
    311   cix:=MyRO.nEnemyCity-1;
    312   while (cix>=0) and (MyRO.EnemyCity[cix].Loc<>Loc) do dec(cix);
    313   CityInfo:=MyRO.EnemyCity[cix];
    314   end
    315 end;
    316 
    317 function UnitExhausted(uix: integer): boolean;
    318 // check if another move of this unit is still possible
    319 var
    320 dx, dy: integer;
    321 begin
    322 result:=true;
    323 if (MyUn[uix].Movement>0) or (MyRO.Wonder[woShinkansen].EffectiveOwner=me) then
    324   if (MyUn[uix].Movement>=100) or ((MyModel[MyUn[uix].mix].Kind=mkCaravan)
    325     and (MyMap[MyUn[uix].Loc] and fCity<>0)) then
    326     result:=false
    327   else for dx:=-2 to 2 do for dy:=-2 to 2 do if abs(dx)+abs(dy)=2 then
    328     if Server(sMoveUnit-sExecute+dx and 7 shl 4+dy and 7 shl 7,me,uix,nil^)>=rExecuted then
    329       result:=false;
    330 end;
    331 
    332 function ModelHash(const ModelInfo: TModelInfo): integer;
    333 var
    334 i,FeatureCode,Hash1,Hash2,Hash2r,d: cardinal;
    335 begin
    336 with ModelInfo do
    337   if Kind>mkEnemyDeveloped then
    338     result:=integer($C0000000+Speed div 50+Kind shl 8)
    339   else
    340     begin
    341     FeatureCode:=0;
    342     for i:=mcFirstNonCap to nFeature-1 do
    343       if 1 shl Domain and Feature[i].Domains<>0 then
    344         begin
    345         FeatureCode:=FeatureCode*2;
    346         if 1 shl (i-mcFirstNonCap)<>0 then
    347           inc(FeatureCode);
    348         end;
    349     case Domain of
    350       dGround:
    351         begin
    352         assert(FeatureCode<1 shl 8);
    353         assert(Attack<5113);
    354         assert(Defense<2273);
    355         assert(Cost<1611);
    356         Hash1:=(Attack*2273+Defense)*9+(Speed-150) div 50;
    357         Hash2:=FeatureCode*1611+Cost;
    358         end;
    359       dSea:
    360         begin
    361         assert(FeatureCode<1 shl 9);
    362         assert(Attack<12193);
    363         assert(Defense<6097);
    364         assert(Cost<4381);
    365         Hash1:=((Attack*6097+Defense)*5+(Speed-350) div 100)*2;
    366         if Weight>=6 then inc(Hash1);
    367         Hash2:=((TTrans*17+ATrans_Fuel) shl 9+FeatureCode)*4381+Cost;
    368         end;
    369       dAir:
    370         begin
    371         assert(FeatureCode<1 shl 5);
    372         assert(Attack<2407);
    373         assert(Defense<1605);
    374         assert(Bombs<4813);
    375         assert(Cost<2089);
    376         Hash1:=(Attack*1605+Defense) shl 5+FeatureCode;
    377         Hash2:=((Bombs*7+ATrans_Fuel)*4+TTrans)*2089+Cost;
    378         end;
    379       end;
    380     Hash2r:=0;
    381     for i:=0 to 7 do
    382       begin
    383       Hash2r:=Hash2r*13;
    384       d:=Hash2 div 13;
    385       inc(Hash2r,Hash2-d*13);
    386       Hash2:=d
    387       end;
    388     result:=integer(Domain shl 30+Hash1 xor Hash2r)
     191    else
     192    begin
     193      result := 0;
     194      for i := 1 to 3 do
     195        if MyRO.EnemyReport[p].Tech[AgePreq[i]] >= tsApplicable then
     196          result := i;
    389197    end
    390 end;
    391 
    392 function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs): integer;
    393 { return values:
    394 eJobDone - all applicable jobs done
    395 eOK - enhancement not complete
    396 eDied - job done and died (thurst) }
    397 var
    398 stage, NextJob, Tile: integer;
    399 Done: Set of jNone..jTrans;
    400 begin
    401 Done:=[];
    402 Tile:=MyMap[MyUn[uix].Loc];
    403 if Tile and fRoad<>0 then include(Done,jRoad);
    404 if Tile and fRR<>0 then include(Done,jRR);
    405 if (Tile and fTerImp=tiIrrigation) or (Tile and fTerImp=tiFarm) then
    406   include(Done,jIrr);
    407 if Tile and fTerImp=tiFarm then include(Done,jFarm);
    408 if Tile and fTerImp=tiMine then include(Done,jMine);
    409 if Tile and fPoll=0 then include(Done,jPoll);
    410 
    411 if MyUn[uix].Job=jNone then result:=eJobDone
    412 else result:=eOK;
    413 while (result<>eOK) and (result<>eDied) do
    414   begin
    415   stage:=-1;
    416   repeat
    417     if stage=-1 then NextJob:=jPoll
    418     else NextJob:=Jobs[Tile and fTerrain,stage];
    419     if (NextJob=jNone) or not (NextJob in Done) then Break;
    420     inc(stage);
    421   until stage=5;
    422   if (stage=5) or (NextJob=jNone) then
    423     begin result:=eJobDone; Break; end; // tile enhancement complete
    424   result:=Server(sStartJob+NextJob shl 4,me,uix,nil^);
    425   include(Done,NextJob)
    426   end;
    427 end;
    428 
    429 function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean;
    430 var
    431 i,NewProject: integer;
    432 begin
    433 result:=false;
    434 if (MyCity[cix].Project and (cpImp+cpIndex)=cpImp+imTrGoods)
    435   or (MyCity[cix].Flags and chProduction<>0) then
    436   begin
    437   i:=0;
    438   repeat
    439     while (ImpOrder[i]>=0) and (MyCity[cix].Built[ImpOrder[i]]>0) do inc(i);
    440     if ImpOrder[i]<0 then Break;
    441     assert(i<nImp);
    442     NewProject:=cpImp+ImpOrder[i];
    443     if Server(sSetCityProject,me,cix,NewProject)>=rExecuted then
    444       begin
    445       result:=true;
    446       CityOptimizer_CityChange(cix);
    447       Break;
    448       end;
    449     inc(i);
    450   until false
    451   end
    452 end;
    453 
    454 procedure CalculateAdvValues;
    455 var
    456 i,j: integer;
    457 known: array[0..nAdv-1] of integer;
    458 
    459   procedure MarkPreqs(i: integer);
    460   begin
    461   if known[i]=0 then
    462     begin
    463     known[i]:=1;
    464     if (i<>adScience) and (i<>adMassProduction) then
    465       begin
    466       if (AdvPreq[i,0]>=0) then MarkPreqs(AdvPreq[i,0]);
    467       if (AdvPreq[i,1]>=0) then MarkPreqs(AdvPreq[i,1]);
     198  end;
     199
     200  function IsCivilReportNew(Enemy: integer): boolean;
     201  var
     202    i: integer;
     203  begin
     204    assert(Enemy <> me);
     205    i := MyRO.EnemyReport[Enemy].TurnOfCivilReport;
     206    result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me);
     207  end;
     208
     209  function IsMilReportNew(Enemy: integer): boolean;
     210  var
     211    i: integer;
     212  begin
     213    assert(Enemy <> me);
     214    i := MyRO.EnemyReport[Enemy].TurnOfMilReport;
     215    result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me);
     216  end;
     217
     218  function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean;
     219    gov, size: integer): integer;
     220  begin
     221    result := FoodSurplus;
     222    if not IsCityAlive or (result > 0) and
     223      ((gov = gFuture) or (size >= NeedAqueductSize) and (result < 2)) then
     224      result := 0; { no growth }
     225  end;
     226
     227  function CityTaxBalance(cix: integer;
     228    const CityReport: TCityReportNew): integer;
     229  var
     230    i: integer;
     231  begin
     232    result := 0;
     233    if (CityReport.HappinessBalance >= 0) { no disorder }
     234      and (MyCity[cix].Flags and chCaptured = 0) then // not captured
     235    begin
     236      inc(result, CityReport.Tax);
     237      if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) and
     238        (CityReport.Production > 0) then
     239        inc(result, CityReport.Production);
     240      if ((MyRO.Government = gFuture) or (MyCity[cix].size >= NeedAqueductSize)
     241        and (CityReport.FoodSurplus < 2)) and (CityReport.FoodSurplus > 0) then
     242        inc(result, CityReport.FoodSurplus);
     243    end;
     244    for i := 28 to nImp - 1 do
     245      if MyCity[cix].Built[i] > 0 then
     246        dec(result, Imp[i].Maint);
     247  end;
     248
     249  procedure SumCities(var TaxSum, ScienceSum: integer);
     250  var
     251    cix: integer;
     252    CityReport: TCityReportNew;
     253  begin
     254    TaxSum := MyRO.OracleIncome;
     255    ScienceSum := 0;
     256    if MyRO.Government = gAnarchy then
     257      exit;
     258    for cix := 0 to MyRO.nCity - 1 do
     259      if MyCity[cix].Loc >= 0 then
     260      begin
     261        CityReport.HypoTiles := -1;
     262        CityReport.HypoTaxRate := -1;
     263        CityReport.HypoLuxuryRate := -1;
     264        Server(sGetCityReportNew, me, cix, CityReport);
     265        if (CityReport.HappinessBalance >= 0) { no disorder }
     266          and (MyCity[cix].Flags and chCaptured = 0) then // not captured
     267          ScienceSum := ScienceSum + CityReport.Science;
     268        TaxSum := TaxSum + CityTaxBalance(cix, CityReport);
     269      end;
     270  end;
     271
     272  function JobTest(uix, Job: integer; IgnoreResults: JobResultSet): boolean;
     273  var
     274    Test: integer;
     275  begin
     276    Test := Server(sStartJob + Job shl 4 - sExecute, me, uix, nil^);
     277    result := (Test >= rExecuted) or (Test in IgnoreResults);
     278  end;
     279
     280  procedure GetUnitInfo(Loc: integer; var uix: integer;
     281    var UnitInfo: TUnitInfo);
     282  var
     283    i, Cnt: integer;
     284  begin
     285    if MyMap[Loc] and fOwned <> 0 then
     286    begin
     287      Server(sGetDefender, me, Loc, uix);
     288      Cnt := 0;
     289      for i := 0 to MyRO.nUn - 1 do
     290        if MyUn[i].Loc = Loc then
     291          inc(Cnt);
     292      MakeUnitInfo(me, MyUn[uix], UnitInfo);
     293      if Cnt > 1 then
     294        UnitInfo.Flags := UnitInfo.Flags or unMulti;
     295    end
     296    else
     297    begin
     298      uix := MyRO.nEnemyUn - 1;
     299      while (uix >= 0) and (MyRO.EnemyUn[uix].Loc <> Loc) do
     300        dec(uix);
     301      UnitInfo := MyRO.EnemyUn[uix];
     302    end
     303  end; { GetUnitInfo }
     304
     305  procedure GetCityInfo(Loc: integer; var cix: integer;
     306    var CityInfo: TCityInfo);
     307  begin
     308    if MyMap[Loc] and fOwned <> 0 then
     309    begin
     310      CityInfo.Loc := Loc;
     311      cix := MyRO.nCity - 1;
     312      while (cix >= 0) and (MyCity[cix].Loc <> Loc) do
     313        dec(cix);
     314      with CityInfo do
     315      begin
     316        Owner := me;
     317        ID := MyCity[cix].ID;
     318        size := MyCity[cix].size;
     319        Flags := 0;
     320        if MyCity[cix].Built[imPalace] > 0 then
     321          inc(Flags, ciCapital);
     322        if (MyCity[cix].Built[imWalls] > 0) or
     323          (MyMap[MyCity[cix].Loc] and fGrWall <> 0) then
     324          inc(Flags, ciWalled);
     325        if MyCity[cix].Built[imCoastalFort] > 0 then
     326          inc(Flags, ciCoastalFort);
     327        if MyCity[cix].Built[imMissileBat] > 0 then
     328          inc(Flags, ciMissileBat);
     329        if MyCity[cix].Built[imBunker] > 0 then
     330          inc(Flags, ciBunker);
     331        if MyCity[cix].Built[imSpacePort] > 0 then
     332          inc(Flags, ciSpacePort);
    468333      end
    469334    end
    470   end;
    471 
    472 begin
    473 FillChar(AdvValue,SizeOf(AdvValue),0);
    474 for i:=0 to nAdv-1 do
    475   begin
    476   FillChar(known,SizeOf(known),0);
    477   MarkPreqs(i);
    478   for j:=0 to nAdv-1 do if known[j]>0 then inc(AdvValue[i]);
    479   if i in FutureTech then inc(AdvValue[i],3000)
    480   else if known[adMassProduction]>0 then inc(AdvValue[i],2000)
    481   else if known[adScience]>0 then inc(AdvValue[i],1000)
    482   end;
    483 end;
    484 
    485 procedure DebugMessage(Level: integer; Text: string);
    486 begin
    487 Server(sMessage,me,Level,pchar(Text)^)
    488 end;
    489 
    490 function MarkCitiesAround(Loc,cixExcept: integer): boolean;
    491 // return whether a city was marked
    492 var
    493 cix: integer;
    494 begin
    495 result:=false;
    496 for cix:=0 to MyRO.nCity-1 do
    497   if (cix<>cixExcept) and (MyCity[cix].Loc>=0)
    498     and (MyCity[cix].Flags and chCaptured=0)
    499     and (Distance(MyCity[cix].Loc,Loc)<=5) then
    500     begin
    501     CityNeedsOptimize[cix]:=true;
    502     result:=true;
     335    else
     336    begin
     337      cix := MyRO.nEnemyCity - 1;
     338      while (cix >= 0) and (MyRO.EnemyCity[cix].Loc <> Loc) do
     339        dec(cix);
     340      CityInfo := MyRO.EnemyCity[cix];
    503341    end
    504 end;
    505 
    506 procedure OptimizeCities(CheckOnly: boolean);
    507 var
    508 cix,fix,dx,dy,Loc1,OptiType: integer;
    509 done: boolean;
    510 Advice: TCityTileAdviceData;
    511 begin
    512 repeat
    513   done:=true;
    514   for cix:=0 to MyRO.nCity-1 do if CityNeedsOptimize[cix] then
    515     begin
    516     OptiType:=MyCity[cix].Status shr 4 and $0F;
    517     if OptiType<>0 then
    518       begin
    519       Advice.ResourceWeights:=OfferedResourceWeights[OptiType];
    520       Server(sGetCityTileAdvice,me,cix,Advice);
    521       if Advice.Tiles<>MyCity[cix].Tiles then
    522         if CheckOnly then
    523           assert(false)
     342  end;
     343
     344  function UnitExhausted(uix: integer): boolean;
     345  // check if another move of this unit is still possible
     346  var
     347    dx, dy: integer;
     348  begin
     349    result := true;
     350    if (MyUn[uix].Movement > 0) or
     351      (MyRO.Wonder[woShinkansen].EffectiveOwner = me) then
     352      if (MyUn[uix].Movement >= 100) or
     353        ((MyModel[MyUn[uix].mix].Kind = mkCaravan) and
     354        (MyMap[MyUn[uix].Loc] and fCity <> 0)) then
     355        result := false
     356      else
     357        for dx := -2 to 2 do
     358          for dy := -2 to 2 do
     359            if abs(dx) + abs(dy) = 2 then
     360              if Server(sMoveUnit - sExecute + dx and 7 shl 4 + dy and 7 shl 7,
     361                me, uix, nil^) >= rExecuted then
     362                result := false;
     363  end;
     364
     365  function ModelHash(const ModelInfo: TModelInfo): integer;
     366  var
     367    i, FeatureCode, Hash1, Hash2, Hash2r, d: cardinal;
     368  begin
     369    with ModelInfo do
     370      if Kind > mkEnemyDeveloped then
     371        result := integer($C0000000 + Speed div 50 + Kind shl 8)
     372      else
     373      begin
     374        FeatureCode := 0;
     375        for i := mcFirstNonCap to nFeature - 1 do
     376          if 1 shl Domain and Feature[i].Domains <> 0 then
     377          begin
     378            FeatureCode := FeatureCode * 2;
     379            if 1 shl (i - mcFirstNonCap) <> 0 then
     380              inc(FeatureCode);
     381          end;
     382        case Domain of
     383          dGround:
     384            begin
     385              assert(FeatureCode < 1 shl 8);
     386              assert(Attack < 5113);
     387              assert(Defense < 2273);
     388              assert(Cost < 1611);
     389              Hash1 := (Attack * 2273 + Defense) * 9 + (Speed - 150) div 50;
     390              Hash2 := FeatureCode * 1611 + Cost;
     391            end;
     392          dSea:
     393            begin
     394              assert(FeatureCode < 1 shl 9);
     395              assert(Attack < 12193);
     396              assert(Defense < 6097);
     397              assert(Cost < 4381);
     398              Hash1 := ((Attack * 6097 + Defense) * 5 + (Speed - 350)
     399                div 100) * 2;
     400              if Weight >= 6 then
     401                inc(Hash1);
     402              Hash2 := ((TTrans * 17 + ATrans_Fuel) shl 9 + FeatureCode) *
     403                4381 + Cost;
     404            end;
     405          dAir:
     406            begin
     407              assert(FeatureCode < 1 shl 5);
     408              assert(Attack < 2407);
     409              assert(Defense < 1605);
     410              assert(Bombs < 4813);
     411              assert(Cost < 2089);
     412              Hash1 := (Attack * 1605 + Defense) shl 5 + FeatureCode;
     413              Hash2 := ((Bombs * 7 + ATrans_Fuel) * 4 + TTrans) * 2089 + Cost;
     414            end;
     415        end;
     416        Hash2r := 0;
     417        for i := 0 to 7 do
     418        begin
     419          Hash2r := Hash2r * 13;
     420          d := Hash2 div 13;
     421          inc(Hash2r, Hash2 - d * 13);
     422          Hash2 := d
     423        end;
     424        result := integer(Domain shl 30 + Hash1 xor Hash2r)
     425      end
     426  end;
     427
     428  function ProcessEnhancement(uix: integer;
     429    const Jobs: TEnhancementJobs): integer;
     430  { return values:
     431    eJobDone - all applicable jobs done
     432    eOK - enhancement not complete
     433    eDied - job done and died (thurst) }
     434  var
     435    stage, NextJob, Tile: integer;
     436    Done: Set of jNone .. jTrans;
     437  begin
     438    Done := [];
     439    Tile := MyMap[MyUn[uix].Loc];
     440    if Tile and fRoad <> 0 then
     441      include(Done, jRoad);
     442    if Tile and fRR <> 0 then
     443      include(Done, jRR);
     444    if (Tile and fTerImp = tiIrrigation) or (Tile and fTerImp = tiFarm) then
     445      include(Done, jIrr);
     446    if Tile and fTerImp = tiFarm then
     447      include(Done, jFarm);
     448    if Tile and fTerImp = tiMine then
     449      include(Done, jMine);
     450    if Tile and fPoll = 0 then
     451      include(Done, jPoll);
     452
     453    if MyUn[uix].Job = jNone then
     454      result := eJobDone
     455    else
     456      result := eOK;
     457    while (result <> eOK) and (result <> eDied) do
     458    begin
     459      stage := -1;
     460      repeat
     461        if stage = -1 then
     462          NextJob := jPoll
    524463        else
     464          NextJob := Jobs[Tile and fTerrain, stage];
     465        if (NextJob = jNone) or not(NextJob in Done) then
     466          Break;
     467        inc(stage);
     468      until stage = 5;
     469      if (stage = 5) or (NextJob = jNone) then
     470      begin
     471        result := eJobDone;
     472        Break;
     473      end; // tile enhancement complete
     474      result := Server(sStartJob + NextJob shl 4, me, uix, nil^);
     475      include(Done, NextJob)
     476    end;
     477  end;
     478
     479  function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean;
     480  var
     481    i, NewProject: integer;
     482  begin
     483    result := false;
     484    if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) or
     485      (MyCity[cix].Flags and chProduction <> 0) then
     486    begin
     487      i := 0;
     488      repeat
     489        while (ImpOrder[i] >= 0) and (MyCity[cix].Built[ImpOrder[i]] > 0) do
     490          inc(i);
     491        if ImpOrder[i] < 0 then
     492          Break;
     493        assert(i < nImp);
     494        NewProject := cpImp + ImpOrder[i];
     495        if Server(sSetCityProject, me, cix, NewProject) >= rExecuted then
     496        begin
     497          result := true;
     498          CityOptimizer_CityChange(cix);
     499          Break;
     500        end;
     501        inc(i);
     502      until false end end;
     503
     504      procedure CalculateAdvValues;
     505      var
     506        i, j: integer;
     507        known: array [0 .. nAdv - 1] of integer;
     508
     509        procedure MarkPreqs(i: integer);
     510        begin
     511          if known[i] = 0 then
    525512          begin
    526           for fix:=1 to 26 do
    527             if MyCity[cix].Tiles and not Advice.Tiles and (1 shl fix)<>0 then
    528               begin // tile no longer used by this city -- check using it by another
    529               dy:=fix shr 2-3; dx:=fix and 3 shl 1 -3 + (dy+3) and 1;
    530               Loc1:=dLoc(MyCity[cix].Loc,dx,dy);
    531               if MarkCitiesAround(Loc1,cix) then
    532                 done:=false;
     513            known[i] := 1;
     514            if (i <> adScience) and (i <> adMassProduction) then
     515            begin
     516              if (AdvPreq[i, 0] >= 0) then
     517                MarkPreqs(AdvPreq[i, 0]);
     518              if (AdvPreq[i, 1] >= 0) then
     519                MarkPreqs(AdvPreq[i, 1]);
     520            end
     521          end
     522        end;
     523
     524      begin
     525        FillChar(AdvValue, SizeOf(AdvValue), 0);
     526        for i := 0 to nAdv - 1 do
     527        begin
     528          FillChar(known, SizeOf(known), 0);
     529          MarkPreqs(i);
     530          for j := 0 to nAdv - 1 do
     531            if known[j] > 0 then
     532              inc(AdvValue[i]);
     533          if i in FutureTech then
     534            inc(AdvValue[i], 3000)
     535          else if known[adMassProduction] > 0 then
     536            inc(AdvValue[i], 2000)
     537          else if known[adScience] > 0 then
     538            inc(AdvValue[i], 1000)
     539        end;
     540      end;
     541
     542      procedure DebugMessage(Level: integer; Text: string);
     543      begin
     544        Server(sMessage, me, Level, pchar(Text)^)
     545      end;
     546
     547      function MarkCitiesAround(Loc, cixExcept: integer): boolean;
     548      // return whether a city was marked
     549      var
     550        cix: integer;
     551      begin
     552        result := false;
     553        for cix := 0 to MyRO.nCity - 1 do
     554          if (cix <> cixExcept) and (MyCity[cix].Loc >= 0) and
     555            (MyCity[cix].Flags and chCaptured = 0) and
     556            (Distance(MyCity[cix].Loc, Loc) <= 5) then
     557          begin
     558            CityNeedsOptimize[cix] := true;
     559            result := true;
     560          end
     561      end;
     562
     563      procedure OptimizeCities(CheckOnly: boolean);
     564      var
     565        cix, fix, dx, dy, Loc1, OptiType: integer;
     566        Done: boolean;
     567        Advice: TCityTileAdviceData;
     568      begin
     569        repeat
     570          Done := true;
     571          for cix := 0 to MyRO.nCity - 1 do
     572            if CityNeedsOptimize[cix] then
     573            begin
     574              OptiType := MyCity[cix].Status shr 4 and $0F;
     575              if OptiType <> 0 then
     576              begin
     577                Advice.ResourceWeights := OfferedResourceWeights[OptiType];
     578                Server(sGetCityTileAdvice, me, cix, Advice);
     579                if Advice.Tiles <> MyCity[cix].Tiles then
     580                  if CheckOnly then
     581                    assert(false)
     582                  else
     583                  begin
     584                    for fix := 1 to 26 do
     585                      if MyCity[cix].Tiles and not Advice.Tiles and
     586                        (1 shl fix) <> 0 then
     587                      begin // tile no longer used by this city -- check using it by another
     588                        dy := fix shr 2 - 3;
     589                        dx := fix and 3 shl 1 - 3 + (dy + 3) and 1;
     590                        Loc1 := dLoc(MyCity[cix].Loc, dx, dy);
     591                        if MarkCitiesAround(Loc1, cix) then
     592                          Done := false;
     593                      end;
     594                    Server(sSetCityTiles, me, cix, Advice.Tiles);
     595                  end;
    533596              end;
    534           Server(sSetCityTiles,me,cix,Advice.Tiles);
    535           end;
    536       end;
    537     CityNeedsOptimize[cix]:=false;
    538     end;
    539 until done;
    540 end;
    541 
    542 procedure CityOptimizer_BeginOfTurn;
    543 var
    544 cix: integer;
    545 begin
    546 fillchar(CityNeedsOptimize,MyRO.nCity-1,0); //false
    547 if MyRO.Government<>gAnarchy then
    548   begin
    549   for cix:=0 to MyRO.nCity-1 do
    550     if (MyCity[cix].Loc>=0) and (MyCity[cix].Flags and chCaptured=0) then
    551       CityNeedsOptimize[cix]:=true;
    552   OptimizeCities(false); // optimize all cities
    553   end
    554 end;
    555 
    556 procedure CityOptimizer_CityChange(cix: integer);
    557 begin
    558 if (MyRO.Government<>gAnarchy) and (MyCity[cix].Flags and chCaptured=0) then
    559   begin
    560   CityNeedsOptimize[cix]:=true;
    561   OptimizeCities(false);
    562   end
    563 end;
    564 
    565 procedure CityOptimizer_TileBecomesAvailable(Loc: integer);
    566 begin
    567 if (MyRO.Government<>gAnarchy) and MarkCitiesAround(Loc,-1) then
    568   OptimizeCities(false);
    569 end;
    570 
    571 procedure CityOptimizer_ReleaseCityTiles(cix, ReleasedTiles: integer);
    572 var
    573 fix,dx,dy,Loc1: integer;
    574 done: boolean;
    575 begin
    576 if (MyRO.Government<>gAnarchy) and (ReleasedTiles<>0) then
    577   begin
    578   done:=true;
    579   for fix:=1 to 26 do if ReleasedTiles and (1 shl fix)<>0 then
    580     begin
    581     dy:=fix shr 2-3; dx:=fix and 3 shl 1 -3 + (dy+3) and 1;
    582     Loc1:=dLoc(MyCity[cix].Loc,dx,dy);
    583     if MarkCitiesAround(Loc1,cix) then
    584       done:=false;
    585     end;
    586   if not done then
    587     OptimizeCities(false);
    588   end
    589 end;
    590 
    591 procedure CityOptimizer_BeforeRemoveUnit(uix: integer);
    592 var
    593 uix1: integer;
    594 begin
    595 if MyRO.Government<>gAnarchy then
    596   begin
    597   if MyUn[uix].Home>=0 then
    598     CityNeedsOptimize[MyUn[uix].Home]:=true;
    599 
    600   // transported units are also removed
    601   for uix1:=0 to MyRO.nUn-1 do
    602     if (MyUn[uix1].Loc>=0) and (MyUn[uix1].Master=uix)
    603       and (MyUn[uix1].Home>=0) then
    604       CityNeedsOptimize[MyUn[uix1].Home]:=true;
    605   end
    606 end;
    607 
    608 procedure CityOptimizer_AfterRemoveUnit;
    609 begin
    610 if MyRO.Government<>gAnarchy then
    611   OptimizeCities(false);
    612 end;
    613 
    614 procedure CityOptimizer_EndOfTurn;
    615 // all cities should already be optimized here -- only check this
    616 var
    617 cix: integer;
    618 begin
     597              CityNeedsOptimize[cix] := false;
     598            end;
     599        until Done;
     600      end;
     601
     602      procedure CityOptimizer_BeginOfTurn;
     603      var
     604        cix: integer;
     605      begin
     606        FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false
     607        if MyRO.Government <> gAnarchy then
     608        begin
     609          for cix := 0 to MyRO.nCity - 1 do
     610            if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0)
     611            then
     612              CityNeedsOptimize[cix] := true;
     613          OptimizeCities(false); // optimize all cities
     614        end
     615      end;
     616
     617      procedure CityOptimizer_CityChange(cix: integer);
     618      begin
     619        if (MyRO.Government <> gAnarchy) and
     620          (MyCity[cix].Flags and chCaptured = 0) then
     621        begin
     622          CityNeedsOptimize[cix] := true;
     623          OptimizeCities(false);
     624        end
     625      end;
     626
     627      procedure CityOptimizer_TileBecomesAvailable(Loc: integer);
     628      begin
     629        if (MyRO.Government <> gAnarchy) and MarkCitiesAround(Loc, -1) then
     630          OptimizeCities(false);
     631      end;
     632
     633      procedure CityOptimizer_ReleaseCityTiles(cix, ReleasedTiles: integer);
     634      var
     635        fix, dx, dy, Loc1: integer;
     636        Done: boolean;
     637      begin
     638        if (MyRO.Government <> gAnarchy) and (ReleasedTiles <> 0) then
     639        begin
     640          Done := true;
     641          for fix := 1 to 26 do
     642            if ReleasedTiles and (1 shl fix) <> 0 then
     643            begin
     644              dy := fix shr 2 - 3;
     645              dx := fix and 3 shl 1 - 3 + (dy + 3) and 1;
     646              Loc1 := dLoc(MyCity[cix].Loc, dx, dy);
     647              if MarkCitiesAround(Loc1, cix) then
     648                Done := false;
     649            end;
     650          if not Done then
     651            OptimizeCities(false);
     652        end
     653      end;
     654
     655      procedure CityOptimizer_BeforeRemoveUnit(uix: integer);
     656      var
     657        uix1: integer;
     658      begin
     659        if MyRO.Government <> gAnarchy then
     660        begin
     661          if MyUn[uix].Home >= 0 then
     662            CityNeedsOptimize[MyUn[uix].Home] := true;
     663
     664          // transported units are also removed
     665          for uix1 := 0 to MyRO.nUn - 1 do
     666            if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) and
     667              (MyUn[uix1].Home >= 0) then
     668              CityNeedsOptimize[MyUn[uix1].Home] := true;
     669        end
     670      end;
     671
     672      procedure CityOptimizer_AfterRemoveUnit;
     673      begin
     674        if MyRO.Government <> gAnarchy then
     675          OptimizeCities(false);
     676      end;
     677
     678      procedure CityOptimizer_EndOfTurn;
     679      // all cities should already be optimized here -- only check this
     680      var
     681        cix: integer;
     682      begin
    619683{$IFOPT O-}
    620 if MyRO.Government<>gAnarchy then
    621   begin
    622   fillchar(CityNeedsOptimize,MyRO.nCity-1,0); //false
    623   for cix:=0 to MyRO.nCity-1 do
    624     if (MyCity[cix].Loc>=0) and (MyCity[cix].Flags and chCaptured=0) then
    625       CityNeedsOptimize[cix]:=true;
    626   OptimizeCities(true); // check all cities
    627   end;
     684        if MyRO.Government <> gAnarchy then
     685        begin
     686          FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false
     687          for cix := 0 to MyRO.nCity - 1 do
     688            if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0)
     689            then
     690              CityNeedsOptimize[cix] := true;
     691          OptimizeCities(true); // check all cities
     692        end;
    628693{$ENDIF}
    629 end;
    630 
     694      end;
    631695
    632696initialization
    633 assert(nImp<128);
     697
     698assert(nImp < 128);
    634699CalculateAdvValues;
    635700
    636701end.
    637 
Note: See TracChangeset for help on using the changeset viewer.