Ignore:
Timestamp:
Mar 6, 2019, 8:10:23 AM (5 years ago)
Author:
chronos
Message:
  • Added: StdAI from original game. Previously used only AI dev kit.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/AI/StdAI/ToolAI.pas

    r124 r160  
    55
    66uses
    7 {$IFDEF DEBUG}SysUtils, {$ENDIF} // necessary for debug exceptions
    8 {$IFDEF DEBUG}Names, {$ENDIF}
    9   Protocol, CustomAI;
     7{$IFDEF DEBUG}SysUtils,{$ENDIF} // necessary for debug exceptions
     8Math,
     9{$IFDEF DEBUG}Names,{$ENDIF}
     10Protocol, CustomAI;
     11
    1012
    1113type
    12   TGroupTransportPlan = record
    13     LoadLoc, uixTransport, nLoad, TurnsEmpty, TurnsLoaded: integer;
    14     uixLoad: array [0 .. 15] of integer;
    15   end;
    16 
    17   TToolAI = class(TCustomAI)
    18   protected
    19 {$IFDEF DEBUG}DebugMap: array [0 .. lxmax * lymax - 1] of integer; {$ENDIF}
    20     function CityTaxBalance(cix: integer;
    21       const CityReport: TCityReport): integer;
     14TGroupTransportPlan=record
     15  LoadLoc, uixTransport, nLoad, TurnsEmpty, TurnsLoaded: integer;
     16  uixLoad: array[0..15] of integer;
     17  end;
     18
     19
     20TToolAI = class(TCustomAI)
     21protected
     22  {$IFDEF DEBUG}DebugMap: array[0..lxmax*lymax-1] of integer;{$ENDIF}
     23
     24  function CenterOfEmpire: integer;
     25    // tile that is in the middle of all own cities
     26
     27  function CityTaxBalance(cix: integer; const CityReport: TCityReport): integer;
    2228    // calculates exact difference of income and maintenance cost for a single city
    2329    // positive result = income higher than maintenance
     
    2531    // respects production and food converted to gold
    2632    // CityReport must have been prepared before
    27     procedure SumCities(TaxRate: integer; var TaxSum, ScienceSum: integer);
     33  procedure SumCities(TaxRate: integer; var TaxSum, ScienceSum: integer);
    2834    // calculates exact total tax and science income
    2935    // tax is reduced by maintenance (so might be negative)
    3036    // luxury not supported
    3137
    32     procedure OptimizeCityTiles;
     38  procedure OptimizeCityTiles;
    3339    // obsolete; use City_OptimizeTiles instead
    3440
    35     procedure GetCityProdPotential;
     41  procedure GetCityProdPotential;
    3642    // calculates potential collected production resources of a city
    3743    // result: list for all cities in CityResult
    38     procedure GetCityTradePotential;
     44  procedure GetCityTradePotential;
    3945    // calculates potential collected trade resources of a city
    4046    // result: list for all cities in CityResult
    4147
    42     procedure JobAssignment_Initialize;
     48  procedure JobAssignment_Initialize;
    4349    // initialization, must be called first of the JobAssignment functions
    44     procedure JobAssignment_AddJob(Loc, Job, Score: integer);
     50  procedure JobAssignment_AddJob(Loc, Job, Score: integer);
    4551    // add job for settlers with certain score
    4652    // jobs include founding cities!
    47     procedure JobAssignment_AddUnit(uix: integer);
     53  procedure JobAssignment_AddUnit(uix: integer);
    4854    // add a settler unit to do jobs
    49     procedure JobAssignment_Go;
     55  procedure JobAssignment_Go;
    5056    // to be called after all jobs and the settlers for them have been added
    5157    // assigns each job to one settler, moves the settlers and makes them work
     
    5359    // starting a job one turn earlier counts the same as 4 points of score
    5460    // function does not cancel jobs that are already started
    55     function JobAssignment_GotJob(uix: integer): boolean;
     61  function JobAssignment_GotJob(uix: integer): boolean;
    5662    // can be called after JobAssignment_Go to find out whether
    5763    // a certain settler has been assigned a job to
    5864
    59     procedure AnalyzeMap;
     65  procedure AnalyzeMap;
    6066    // calculates formations and districts
    6167
    62     function CheckStep(MoveStyle, TimeBeforeStep, CrossCorner: integer;
    63       var TimeAfterStep, RecoverTurns: integer;
    64       FromTile, ToTile: integer): integer;
     68  function CheckStep(MoveStyle, TimeBeforeStep, CrossCorner: integer;
     69    var TimeAfterStep, RecoverTurns: integer; FromTile, ToTile: integer; IsCapture: boolean): integer;
    6570    // forecast single unit move between adjacent tiles
    6671    // format of TimeBeforeStep and TimeAfterStep: $1000*number of turns + $800-MP left
    6772    // RecoverTurns: number of turns needed to rest outside city in order to
    68     // recover from damage taken in this move (rounded up)
     73    //   recover from damage taken in this move (rounded up)
    6974    // FromTile and ToTile must be Map[FromLoc] and Map[ToLoc], no location codes
    7075    // CrossCorner=1 for long moves that cross the tile corner, =0 for short ones that don't
    7176
    72     function GetMyMoveStyle(mix, Health: integer): integer;
    73 
    74     function Unit_MoveEx(uix, ToLoc: integer; Options: integer = 0): integer;
    75 
    76     procedure SeaTransport_BeginInitialize;
    77     procedure SeaTransport_EndInitialize;
     77  function GetMyMoveStyle(mix,Health: integer): integer;
     78
     79  function Unit_MoveEx(uix,ToLoc: integer; Options: integer = 0): integer;
     80
     81  procedure SeaTransport_BeginInitialize;
     82  procedure SeaTransport_EndInitialize;
    7883    // sea transport, obligatory call order:
    7984    // 1. BeginInitialize
     
    8691    // - all transports have same capacity
    8792    // - no transport is damaged
    88     procedure SeaTransport_AddLoad(uix: integer);
    89     procedure SeaTransport_AddTransport(uix: integer);
    90     procedure SeaTransport_AddDestination(Loc: integer);
    91     function SeaTransport_MakeGroupPlan(var TransportPlan
    92       : TGroupTransportPlan): boolean;
     93  procedure SeaTransport_AddLoad(uix: integer);
     94  procedure SeaTransport_AddTransport(uix: integer);
     95  procedure SeaTransport_AddDestination(Loc: integer);
     96  function SeaTransport_MakeGroupPlan(var TransportPlan: TGroupTransportPlan): boolean;
    9397    // make plan for group of units to transport from a single loading location by a single transport
    9498    // the plan optimizes:
     
    97101    // - time for the transport to move to one of the destination locations
    98102    // after the plan is made, units and transport are removed from the pool, so that
    99     // subsequent calls to MakeGroupPlan result in plans that may be executed parallel
     103    //   subsequent calls to MakeGroupPlan result in plans that may be executed parallel
    100104    // function returns false if no more transports are possible
    101105
    102   end;
     106  function CurrentMStrength(Domain: integer): integer;
     107  end;
     108
    103109
    104110const
    105   // no-formations
    106   nfUndiscovered = -1;
    107   nfPole = -2;
    108   nfPeace = -3;
    109 
    110   // return codes of CheckStep
    111   csOk = 0;
     111// no-formations
     112nfUndiscovered=-1; nfPole=-2; nfPeace=-3;
     113
     114// return codes of CheckStep
     115csOk=0;
    112116  // step is valid
    113117  // TimeAfterMove has been calculated
    114   csForbiddenTile = 1;
     118csForbiddenTile=1;
    115119  // unit can not move onto this tile
    116120  // TimeAfterMove not calculated
    117   csForbiddenStep = 2;
     121csForbiddenStep=2;
    118122  // (ZoC unit only) unit can not do this step because of ZoC violation
    119123  // maybe tile can be reached using another way
    120124  // TimeAfterMove not calculated
    121   csCheckTerritory = 3;
     125csCheckTerritory=3;
    122126  // move within other nations's territory shortly after making peace
    123127  // step is only possible if RO.Territory is the same for both tiles
    124128  // TimeAfterMove has been calculated
    125129
    126   // Unit_MoveEx
    127   mxAdjacent = $00000001;
    128 
    129 var
    130   nContinent, nOcean, nDistrict: integer;
    131   Formation: array [0 .. lxmax * lymax - 1] of integer;
     130// Unit_MoveEx
     131mxAdjacent=$00000001;
     132
     133
     134var
     135nContinent, nOcean, nDistrict: integer;
     136Formation: array[0..lxmax*lymax-1] of integer;
    132137  // water: ocean index, land: continent index, sorted by size
    133138  // territory unpassable due to peace treaty divides a continent
    134   District: array [0 .. lxmax * lymax - 1] of integer;
     139District: array[0..lxmax*lymax-1] of integer;
    135140  // index of coherent own territory, sorted by size
    136   CityResult: array [0 .. nCmax - 1] of integer;
    137 
    138   Advancedness: array [0 .. nAdv - 1] of integer;
    139   // total number of prerequisites for each advance
     141CityResult: array[0..nCmax-1] of integer;
     142
     143Advancedness: array[0..nAdv-1] of integer; // total number of prerequisites for each advance
     144
    140145
    141146implementation
    142147
    143148uses
    144   Pile;
     149Pile;
    145150
    146151type
    147   pinteger = ^integer;
    148 
    149 var
    150   // for JobAssignment
    151   MaxScore: integer;
    152   TileJob, TileJobScore: array [0 .. lxmax * lymax - 1] of byte;
    153   JobLocOfSettler: array [0 .. nUmax - 1] of integer; // ToAssign = find job
    154 
    155   // for Transport
    156   TransportMoveStyle, TransportCapacity, nTransportLoad: integer;
    157   InitComplete, HaveDestinations: boolean;
    158   uixTransportLoad, TransportAvailable: array [0 .. nUmax - 1] of integer;
    159   TurnsAfterLoad: array [0 .. lxmax * lymax - 1] of shortint;
    160 
    161 procedure ReplaceD(Start, Stop: pinteger; Raider, Twix: integer);
    162 begin
    163   while Start <> Stop do
    164   begin
    165     if Start^ = Raider then
    166       Start^ := Twix;
    167     inc(Start)
     152pinteger=^integer;
     153
     154var
     155// for JobAssignment
     156MaxScore: integer;
     157TileJob,TileJobScore: array[0..lxmax*lymax-1] of byte;
     158JobLocOfSettler: array[0..nUmax-1] of integer; // ToAssign = find job
     159
     160// for Transport
     161TransportMoveStyle, TransportCapacity, nTransportLoad: integer;
     162InitComplete, HaveDestinations: boolean;
     163uixTransportLoad, TransportAvailable: array[0..nUmax-1] of integer;
     164TurnsAfterLoad: array[0..lxmax*lymax-1] of shortint;
     165
     166
     167procedure ReplaceD(Start, Stop: pinteger; Raider,Twix: integer);
     168begin
     169while Start<>Stop do
     170  begin
     171  if Start^=Raider then Start^:=Twix;
     172  inc(Start)
    168173  end;
    169174end;
     
    171176function NextZero(Start, Stop: pinteger; Mask: cardinal): pinteger;
    172177begin
    173   while (Start <> Stop) and (Start^ and Mask <> 0) do
    174     inc(Start);
    175   result := Start;
    176 end;
    177 
    178 function TToolAI.CityTaxBalance(cix: integer;
    179   const CityReport: TCityReport): integer;
    180 var
    181   i: integer;
    182 begin
    183   result := 0;
    184   if (CityReport.Working - CityReport.Happy <= MyCity[cix].Size shr 1)
    185   { no disorder }
    186     and (MyCity[cix].Flags and chCaptured = 0) then // not captured
    187   begin
    188     inc(result, CityReport.Tax);
    189     if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) and
    190       (CityReport.ProdRep > CityReport.Support) then
    191       inc(result, CityReport.ProdRep - CityReport.Support);
    192     if ((RO.Government = gLybertarianism) or
    193       (MyCity[cix].Size >= NeedAqueductSize) and
    194       (CityReport.FoodRep < CityReport.Eaten + 2)) and
    195       (CityReport.FoodRep > CityReport.Eaten) then
    196       inc(result, CityReport.FoodRep - CityReport.Eaten);
    197   end;
    198   for i := 28 to nImp - 1 do
    199     if MyCity[cix].Built[i] > 0 then
    200       dec(result, Imp[i].Maint);
     178while (Start<>Stop) and (Start^ and Mask<>0) do inc(Start);
     179result:=Start;
     180end;
     181
     182
     183function TToolAI.CenterOfEmpire: integer;
     184var
     185cix,Loc,x,y,sy,n: integer;
     186a,su,sv: double;
     187begin
     188n:=0;
     189sy:=0;
     190su:=0;
     191sv:=0;
     192for cix:=0 to RO.nCity-1 do
     193  begin
     194  Loc:=MyCity[cix].Loc;
     195  if Loc>=0 then
     196    begin
     197    y:=Loc div G.lx;
     198    x:=Loc-y*G.lx;
     199    inc(sy,y);
     200    a:=2*pi*x/G.lx;
     201    su:=su+cos(a);
     202    sv:=sv+sin(a);
     203    inc(n);
     204    end;
     205  end;
     206a:=arctan2(sv,su);
     207x:=round(G.lx*a/(2*pi));
     208while x>=G.lx do
     209  dec(x,G.lx);
     210while x<0 do
     211  inc(x,G.lx);
     212result:=((2*sy+n) div (2*n))*G.lx + x;
     213end;
     214
     215function TToolAI.CityTaxBalance(cix: integer; const CityReport: TCityReport): integer;
     216var
     217i: integer;
     218begin
     219result:=0;
     220if (CityReport.Working-CityReport.Happy<=MyCity[cix].Size shr 1) {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.ProdRep>CityReport.Support) then
     226    inc(result, CityReport.ProdRep-CityReport.Support);
     227  if ((RO.Government=gLybertarianism)
     228      or (MyCity[cix].Size>=NeedAqueductSize)
     229      and (CityReport.FoodRep<CityReport.Eaten+2))
     230    and (CityReport.FoodRep>CityReport.Eaten) then
     231    inc(result, CityReport.FoodRep-CityReport.Eaten);
     232  end;
     233for i:=28 to nImp-1 do if MyCity[cix].Built[i]>0 then
     234  dec(result, Imp[i].Maint);
    201235end;
    202236
    203237procedure TToolAI.SumCities(TaxRate: integer; var TaxSum, ScienceSum: integer);
    204238var
    205   cix, p1: integer;
    206   CityReport: TCityReport;
    207 begin
    208   TaxSum := 0;
    209   ScienceSum := 0;
    210   if RO.Government = gAnarchy then
    211     exit;
    212   for p1 := 0 to nPl - 1 do
    213     if RO.Tribute[p1] <= RO.TributePaid[p1] then
    214     // don't rely on tribute from bankrupt nations
    215       TaxSum := TaxSum + RO.Tribute[p1];
    216   for cix := 0 to RO.nCity - 1 do
    217     if MyCity[cix].Loc >= 0 then
    218     begin
    219       City_GetHypoReport(cix, -1, TaxRate, 0, CityReport);
    220       if (CityReport.Working - CityReport.Happy <= MyCity[cix].Size shr 1)
    221       { no disorder }
    222         and (MyCity[cix].Flags and chCaptured = 0) then // not captured
    223         ScienceSum := ScienceSum + CityReport.Science;
    224       TaxSum := TaxSum + CityTaxBalance(cix, CityReport);
    225     end;
    226 end;
    227 
    228 
    229 // ------------------------------------------------------------------------------
     239cix,p1: integer;
     240CityReport: TCityReport;
     241begin
     242TaxSum:=0; ScienceSum:=0;
     243if RO.Government=gAnarchy then exit;
     244for p1:=0 to nPl-1 do
     245  if RO.Tribute[p1]<=RO.TributePaid[p1] then // don't rely on tribute from bankrupt nations
     246    TaxSum:=TaxSum+RO.Tribute[p1];
     247for cix:=0 to RO.nCity-1 do if MyCity[cix].Loc>=0 then
     248  begin
     249  City_GetHypoReport(cix,-1,TaxRate,0,CityReport);
     250  if (CityReport.Working-CityReport.Happy<=MyCity[cix].Size shr 1) {no disorder}
     251    and (MyCity[cix].Flags and chCaptured=0) then // not captured
     252    ScienceSum:=ScienceSum+CityReport.Science;
     253  TaxSum:=TaxSum+CityTaxBalance(cix, CityReport);
     254  end;
     255end;
     256
     257
     258//------------------------------------------------------------------------------
    230259// City Tiles Processing
    231260
    232261const
    233   pctOptimize = 0;
    234   pctGetProdPotential = 1;
    235   pctGetTradePotential = 2;
     262pctOptimize=0; pctGetProdPotential=1; pctGetTradePotential=2;
    236263
    237264procedure TToolAI.OptimizeCityTiles;
    238265var
    239   cix: integer;
    240 begin
    241   for cix := 0 to RO.nCity - 1 do
    242     with MyCity[cix] do
    243       if Loc >= 0 then
    244         City_OptimizeTiles(cix);
     266cix: integer;
     267begin
     268for cix:=0 to RO.nCity-1 do with MyCity[cix] do if Loc>=0 then
     269  City_OptimizeTiles(cix);
    245270end;
    246271
    247272procedure TToolAI.GetCityProdPotential;
    248273var
    249   cix: integer;
    250   Advice: TCityTileAdviceData;
    251 begin
    252   for cix := 0 to RO.nCity - 1 do
    253     with MyCity[cix] do
    254       if Loc >= 0 then
    255       begin
    256         Advice.ResourceWeights := rwMaxProd;
    257         Server(sGetCityTileAdvice, me, cix, Advice);
    258         CityResult[cix] := Advice.CityReport.ProdRep;
    259         // considers factory, but shouldn't
    260       end;
     274cix: integer;
     275Advice: TCityTileAdviceData;
     276begin
     277for cix:=0 to RO.nCity-1 do with MyCity[cix] do if Loc>=0 then
     278  begin
     279  Advice.ResourceWeights:=rwMaxProd;
     280  Server(sGetCityTileAdvice, me, cix, Advice);
     281  CityResult[cix]:=Advice.CityReport.ProdRep; // considers factory, but shouldn't
     282  end;
    261283end;
    262284
    263285procedure TToolAI.GetCityTradePotential;
    264286var
    265   cix: integer;
    266   Advice: TCityTileAdviceData;
    267 begin
    268   for cix := 0 to RO.nCity - 1 do
    269     with MyCity[cix] do
    270       if Loc >= 0 then
    271       begin
    272         Advice.ResourceWeights := rwMaxScience;
    273         Server(sGetCityTileAdvice, me, cix, Advice);
    274         CityResult[cix] := Advice.CityReport.Trade;
    275       end;
    276 end;
    277 
    278 
    279 // ------------------------------------------------------------------------------
     287cix: integer;
     288Advice: TCityTileAdviceData;
     289begin
     290for cix:=0 to RO.nCity-1 do with MyCity[cix] do if Loc>=0 then
     291  begin
     292  Advice.ResourceWeights:=rwMaxScience;
     293  Server(sGetCityTileAdvice, me, cix, Advice);
     294  CityResult[cix]:=Advice.CityReport.Trade;
     295  end;
     296end;
     297
     298
     299//------------------------------------------------------------------------------
    280300// JobAssignment
    281301
    282302const
    283   ToAssign = lxmax * lymax;
     303ToAssign=lxmax*lymax;
    284304
    285305procedure TToolAI.JobAssignment_Initialize;
    286306begin
    287   fillchar(JobLocOfSettler, RO.nUn * sizeof(integer), $FF); // -1
    288   fillchar(TileJob, MapSize, jNone);
    289   fillchar(TileJobScore, MapSize, 0);
    290   MaxScore := 0;
     307fillchar(JobLocOfSettler, RO.nUn*sizeof(integer), $FF); // -1
     308fillchar(TileJob, MapSize, jNone);
     309fillchar(TileJobScore, MapSize, 0);
     310MaxScore:=0;
    291311end;
    292312
    293313procedure TToolAI.JobAssignment_AddJob(Loc, Job, Score: integer);
    294314begin
    295   if Score > 255 then
    296     Score := 255;
    297   if Score > TileJobScore[Loc] then
    298   begin
    299     TileJob[Loc] := Job;
    300     TileJobScore[Loc] := Score;
    301     if Score > MaxScore then
    302       MaxScore := Score
     315if Score>255 then Score:=255;
     316if Score>TileJobScore[Loc] then
     317  begin
     318  TileJob[Loc]:=Job;
     319  TileJobScore[Loc]:=Score;
     320  if Score>MaxScore then MaxScore:=Score
    303321  end;
    304322end;
     
    306324procedure TToolAI.JobAssignment_AddUnit(uix: integer);
    307325begin
    308   assert(MyModel[MyUnit[uix].mix].Kind in [mkSettler, mkSlaves]);
    309   JobLocOfSettler[uix] := ToAssign
     326assert(MyModel[MyUnit[uix].mix].Kind in [mkSettler,mkSlaves]);
     327JobLocOfSettler[uix]:=ToAssign
    310328end;
    311329
    312330function TToolAI.JobAssignment_GotJob(uix: integer): boolean;
    313331begin
    314   result := JobLocOfSettler[uix] >= 0;
     332result:=JobLocOfSettler[uix]>=0;
    315333end;
    316334
    317335procedure TToolAI.JobAssignment_Go;
    318336const
    319   DistanceScore = 4;
    320   StepSizeByTerrain: array [0 .. 11] of integer = (0, 0, 1, 2, 1, 1, 0, 1,
    321     0, 1, 1, 2);
    322   // Oc-Sh-Gr-De-Pr-Tu-Ar-Sw-XX-Fo-Hi-Mo
    323 var
    324   uix, BestScore, BestCount, BestLoc, BestJob, BestDistance, TestLoc, NextLoc,
    325     TestDistance, V8, TestScore, StepSize, MoveResult: integer;
    326   UnitsToAssign: boolean;
    327   Adjacent: TVicinity8Loc;
    328   SettlerOfJobLoc, DistToLoc: array [0 .. lxmax * lymax - 1] of smallint;
     337DistanceScore=4;
     338StepSizeByTerrain: array[0..11] of integer=
     339( 0, 0, 1, 2, 1, 1, 0, 1, 0, 1, 1, 2);
     340//Oc-Sh-Gr-De-Pr-Tu-Ar-Sw-XX-Fo-Hi-Mo
     341var
     342uix,BestScore,BestCount,BestLoc,BestJob,BestDistance,TestLoc,NextLoc,
     343TestDistance,V8,TestScore,StepSize,MoveResult: integer;
     344UnitsToAssign: boolean;
     345Adjacent: TVicinity8Loc;
     346SettlerOfJobLoc,DistToLoc: array[0..lxmax*lymax-1] of smallint;
    329347  // DistToLoc is only defined where SettlerOfJobLoc>=0
    330   TileChecked: array [0 .. lxmax * lymax - 1] of boolean;
    331 begin
    332   fillchar(SettlerOfJobLoc, MapSize * 2, $FF); // -1
    333 
    334   // keep up jobs that are already started
    335   for uix := 0 to RO.nUn - 1 do
    336     if (MyUnit[uix].Loc >= 0) and (MyUnit[uix].Job > jNone) then
    337     begin
    338       JobLocOfSettler[uix] := MyUnit[uix].Loc;
    339       SettlerOfJobLoc[MyUnit[uix].Loc] := uix;
    340       DistToLoc[MyUnit[uix].Loc] := 0
    341     end;
    342 
    343   // assign remaining jobs to remaining settlers
    344   UnitsToAssign := true;
    345   while UnitsToAssign do
    346   begin
    347     UnitsToAssign := false;
    348     for uix := 0 to RO.nUn - 1 do
    349       if JobLocOfSettler[uix] = ToAssign then
    350       begin
    351         BestJob := jNone;
    352         BestScore := -999999;
    353         fillchar(TileChecked, MapSize * sizeof(boolean), false);
    354         Pile.Create(MapSize);
    355         Pile.Put(MyUnit[uix].Loc, 0);
    356         // start search for new job at current location
    357         while Pile.Get(TestLoc, TestDistance) do
     348TileChecked: array[0..lxmax*lymax-1] of boolean;
     349begin
     350fillchar(SettlerOfJobLoc, MapSize*2, $FF); // -1
     351
     352// keep up jobs that are already started
     353for uix:=0 to RO.nUn-1 do
     354  if (MyUnit[uix].Loc>=0) and (MyUnit[uix].Job>jNone) then
     355    begin
     356    JobLocOfSettler[uix]:=MyUnit[uix].Loc;
     357    SettlerOfJobLoc[MyUnit[uix].Loc]:=uix;
     358    DistToLoc[MyUnit[uix].Loc]:=0
     359    end;
     360
     361// assign remaining jobs to remaining settlers
     362UnitsToAssign:=true;
     363while UnitsToAssign do
     364  begin
     365  UnitsToAssign:=false;
     366  for uix:=0 to RO.nUn-1 do if JobLocOfSettler[uix]=ToAssign then
     367    begin
     368    BestJob:=jNone;
     369    BestScore:=-999999;
     370    FillChar(TileChecked,MapSize*sizeof(boolean),false);
     371    Pile.Create(MapSize);
     372    Pile.Put(MyUnit[uix].Loc,0); // start search for new job at current location
     373    while Pile.Get(TestLoc,TestDistance) do
     374      begin
     375      // add surrounding tiles to queue, but only if there's a chance to beat BestScore
     376      if MaxScore-DistanceScore*(TestDistance+1)>=BestScore then
    358377        begin
    359           // add surrounding tiles to queue, but only if there's a chance to beat BestScore
    360           if MaxScore - DistanceScore * (TestDistance + 1) >= BestScore then
     378        V8_to_Loc(TestLoc,Adjacent);
     379        for V8:=0 to 7 do
    361380          begin
    362             V8_to_Loc(TestLoc, Adjacent);
    363             for V8 := 0 to 7 do
     381          NextLoc:=Adjacent[V8];
     382          if (NextLoc>=0) and not TileChecked[NextLoc]
     383            and (Map[NextLoc] and fTerrain<>fUNKNOWN) then
    364384            begin
    365               NextLoc := Adjacent[V8];
    366               if (NextLoc >= 0) and not TileChecked[NextLoc] and
    367                 (Map[NextLoc] and fTerrain <> fUNKNOWN) then
    368               begin
    369                 StepSize := StepSizeByTerrain[Map[NextLoc] and fTerrain];
    370                 if (StepSize > 0) // no water or arctic tile
    371                   and (Map[NextLoc] and (fUnit or fOwned) <> fUnit)
    372                 // no foreign unit
    373                   and ((RO.Territory[NextLoc] < 0) or
    374                   (RO.Territory[NextLoc] = me)) // no foreign territory
    375                   and (Map[TestLoc] and Map[NextLoc] and fInEnemyZoC = 0) then
    376                 // move not prevented by ZoC
    377                   Pile.Put(NextLoc, TestDistance + StepSize)
    378                   // simplification, only optimal for 150 mp units in land with no roads
    379               end;
     385            StepSize:=StepSizeByTerrain[Map[NextLoc] and fTerrain];
     386            if (StepSize>0) // no water or arctic tile
     387              and (Map[NextLoc] and (fUnit or fOwned)<>fUnit) // no foreign unit
     388              and ((RO.Territory[NextLoc]<0) or (RO.Territory[NextLoc]=me)) // no foreign territory
     389              and (Map[TestLoc] and Map[NextLoc] and fInEnemyZoC=0) then // move not prevented by ZoC
     390              Pile.Put(NextLoc,TestDistance+StepSize)
     391              // simplification, only optimal for 150 mp units in land with no roads
    380392            end;
    381393          end;
    382 
    383           // check tile for job
    384           if (TileJob[TestLoc] > jNone) and
    385             ((MyModel[MyUnit[uix].mix].Kind <> mkSlaves) or
    386             (TileJob[TestLoc] <> jCity)) and
    387             ((SettlerOfJobLoc[TestLoc] < 0) or
    388             (DistToLoc[TestLoc] > TestDistance)) then
     394        end;
     395
     396      // check tile for job
     397      if (TileJob[TestLoc]>jNone)
     398        and ((MyModel[MyUnit[uix].mix].Kind<>mkSlaves)
     399          or (TileJob[TestLoc]<>jCity))
     400        and ((SettlerOfJobLoc[TestLoc]<0) or (DistToLoc[TestLoc]>TestDistance)) then
     401        begin
     402        TestScore:=integer(TileJobScore[TestLoc])-DistanceScore*TestDistance;
     403        if TestScore>BestScore then
     404          BestCount:=0;
     405        if TestScore>=BestScore then
    389406          begin
    390             TestScore := integer(TileJobScore[TestLoc]) - DistanceScore *
    391               TestDistance;
    392             if TestScore > BestScore then
    393               BestCount := 0;
    394             if TestScore >= BestScore then
     407          inc(BestCount);
     408          if random(BestCount)=0 then
    395409            begin
    396               inc(BestCount);
    397               if random(BestCount) = 0 then
    398               begin
    399                 BestScore := TestScore;
    400                 BestLoc := TestLoc;
    401                 BestJob := TileJob[TestLoc];
    402                 BestDistance := TestDistance
    403               end
    404             end;
     410            BestScore:=TestScore;
     411            BestLoc:=TestLoc;
     412            BestJob:=TileJob[TestLoc];
     413            BestDistance:=TestDistance
     414            end
    405415          end;
    406           TileChecked[TestLoc] := true;
    407416        end;
    408         Pile.Free;
    409 
    410         if BestJob > jNone then
    411         begin // new job found for this unit
    412           if SettlerOfJobLoc[BestLoc] >= 0 then
    413           begin // another unit was already assigned to this job, but is not as close -- reassign that unit!
    414             JobLocOfSettler[SettlerOfJobLoc[BestLoc]] := ToAssign;
    415             UnitsToAssign := true;
    416           end;
    417           JobLocOfSettler[uix] := BestLoc;
    418           SettlerOfJobLoc[BestLoc] := uix;
    419           DistToLoc[BestLoc] := BestDistance
    420         end
    421         else
    422           JobLocOfSettler[uix] := -1; // no jobs for this settler
    423       end; // for uix
    424   end;
    425 
    426   // move settlers and start new jobs
    427   for uix := 0 to RO.nUn - 1 do
    428     with MyUnit[uix] do
    429       if (Loc >= 0) and (Job = jNone) and (JobLocOfSettler[uix] >= 0) then
    430       begin
    431         if Loc <> JobLocOfSettler[uix] then
    432           repeat
    433             MoveResult := Unit_Move(uix, JobLocOfSettler[uix])
    434           until (MoveResult < rExecuted) or
    435             (MoveResult and (rLocationReached or rMoreTurns or
    436             rUnitRemoved) <> 0);
    437         if (Loc = JobLocOfSettler[uix]) and (Movement >= 100) then
    438           Unit_StartJob(uix, TileJob[JobLocOfSettler[uix]]);
     417      TileChecked[TestLoc]:=true;
    439418      end;
     419    Pile.Free;
     420
     421    if BestJob>jNone then
     422      begin // new job found for this unit
     423      if SettlerOfJobLoc[BestLoc]>=0 then
     424        begin // another unit was already assigned to this job, but is not as close -- reassign that unit!
     425        JobLocOfSettler[SettlerOfJobLoc[BestLoc]]:=ToAssign;
     426        UnitsToAssign:=true;
     427        end;
     428      JobLocOfSettler[uix]:=BestLoc;
     429      SettlerOfJobLoc[BestLoc]:=uix;
     430      DistToLoc[BestLoc]:=BestDistance
     431      end
     432    else JobLocOfSettler[uix]:=-1; // no jobs for this settler
     433    end; // for uix
     434  end;
     435
     436// move settlers and start new jobs
     437for uix:=0 to RO.nUn-1 do with MyUnit[uix] do
     438  if (Loc>=0) and (Job=jNone) and (JobLocOfSettler[uix]>=0) then
     439    begin
     440    if Loc<>JobLocOfSettler[uix] then
     441      repeat
     442        MoveResult:=Unit_Move(uix,JobLocOfSettler[uix])
     443      until (MoveResult<rExecuted)
     444        or (MoveResult and (rLocationReached or rMoreTurns or rUnitRemoved)<>0);
     445    if (Loc=JobLocOfSettler[uix]) and (Movement>=100) then
     446      Unit_StartJob(uix,TileJob[JobLocOfSettler[uix]]);
     447    end;
    440448end; // JobAssignment_Go
    441449
    442450
    443 // ------------------------------------------------------------------------------
     451//------------------------------------------------------------------------------
    444452// Map Analysis
    445453
    446454procedure TToolAI.AnalyzeMap;
    447455var
    448   i, j, Loc, Loc1, V8, Count, Kind, MostIndex: integer;
    449   Adjacent: TVicinity8Loc;
    450   IndexOfID: array [0 .. lxmax * lymax - 1] of smallint;
    451   IDOfIndex: array [0 .. lxmax * lymax div 2 - 1] of smallint;
    452 begin
    453   fillchar(District, MapSize * 4, $FF);
    454   for Loc := 0 to MapSize - 1 do
    455     if Map[Loc] and fTerrain = fUNKNOWN then
    456       Formation[Loc] := nfUndiscovered
    457     else if Map[Loc] and fTerrain = fArctic then
    458       Formation[Loc] := nfPole
    459     else if Map[Loc] and fPeace <> 0 then
    460       Formation[Loc] := nfPeace
    461     else
    462     begin
    463       Formation[Loc] := Loc;
    464       V8_to_Loc(Loc, Adjacent);
    465       for V8 := 0 to 7 do
    466       begin
    467         Loc1 := Adjacent[V8];
    468         if (Loc1 < Loc) and (Loc1 >= 0) and (Formation[Loc1] >= 0) and
    469           ((Map[Loc1] and fTerrain >= fGrass) = (Map[Loc] and fTerrain >=
    470           fGrass)) then
    471           if Formation[Loc] = Loc then
    472             Formation[Loc] := Formation[Loc1]
    473           else if Formation[Loc] < Formation[Loc1] then
    474             ReplaceD(@Formation[Formation[Loc1]], @Formation[Loc + 1],
    475               Formation[Loc1], Formation[Loc])
    476           else if Formation[Loc] > Formation[Loc1] then
    477             ReplaceD(@Formation[Formation[Loc]], @Formation[Loc + 1],
    478               Formation[Loc], Formation[Loc1]);
     456i,j,Loc,Loc1,V8,Count,Kind,MostIndex: integer;
     457Adjacent: TVicinity8Loc;
     458IndexOfID: array[0..lxmax*lymax-1] of smallint;
     459IDOfIndex: array[0..lxmax*lymax div 2 -1] of smallint;
     460begin
     461fillchar(District, MapSize*4, $FF);
     462for Loc:=0 to MapSize-1 do
     463  if Map[Loc] and fTerrain=fUNKNOWN then Formation[Loc]:=nfUndiscovered
     464  else if Map[Loc] and fTerrain=fArctic then Formation[Loc]:=nfPole
     465  else if Map[Loc] and fPeace<>0 then Formation[Loc]:=nfPeace
     466  else
     467    begin
     468    Formation[Loc]:=Loc;
     469    V8_to_Loc(Loc, Adjacent);
     470    for V8:=0 to 7 do
     471      begin
     472      Loc1:=Adjacent[V8];
     473      if (Loc1<Loc) and (Loc1>=0) and (Formation[Loc1]>=0)
     474        and ((Map[Loc1] and fTerrain>=fGrass) = (Map[Loc] and fTerrain>=fGrass)) then
     475        if Formation[Loc]=Loc then Formation[Loc]:=Formation[Loc1]
     476        else if Formation[Loc]<Formation[Loc1] then
     477          ReplaceD(@Formation[Formation[Loc1]],@Formation[Loc+1],Formation[Loc1],Formation[Loc])
     478        else if Formation[Loc]>Formation[Loc1] then
     479          ReplaceD(@Formation[Formation[Loc]],@Formation[Loc+1],Formation[Loc],Formation[Loc1]);
    479480      end;
    480       if (RO.Territory[Loc] = me) and (Map[Loc] and fTerrain >= fGrass) then
    481       begin
    482         District[Loc] := Loc;
    483         for V8 := 0 to 7 do
     481    if (RO.Territory[Loc]=me) and (Map[Loc] and fTerrain>=fGrass) then
     482      begin
     483      District[Loc]:=Loc;
     484      for V8:=0 to 7 do
    484485        begin
    485           Loc1 := Adjacent[V8];
    486           if (Loc1 < Loc) and (Loc1 >= 0) and (District[Loc1] >= 0) then
    487             if District[Loc] = Loc then
    488               District[Loc] := District[Loc1]
    489             else if District[Loc] < District[Loc1] then
    490               ReplaceD(@District[District[Loc1]], @District[Loc + 1],
    491                 District[Loc1], District[Loc])
    492             else if District[Loc] > District[Loc1] then
    493               ReplaceD(@District[District[Loc]], @District[Loc + 1],
    494                 District[Loc], District[Loc1]);
     486        Loc1:=Adjacent[V8];
     487        if (Loc1<Loc) and (Loc1>=0) and (District[Loc1]>=0) then
     488          if District[Loc]=Loc then District[Loc]:=District[Loc1]
     489          else if District[Loc]<District[Loc1] then
     490            ReplaceD(@District[District[Loc1]],@District[Loc+1],District[Loc1],District[Loc])
     491          else if District[Loc]>District[Loc1] then
     492            ReplaceD(@District[District[Loc]],@District[Loc+1],District[Loc],District[Loc1]);
    495493        end
    496494      end
    497495    end;
    498496
    499   // sort continents, oceans and districts by size
    500   for Kind := 0 to 2 do
    501   begin
    502     fillchar(IndexOfID, MapSize * 2, 0);
    503     case Kind of
    504       0: // continents
    505         for Loc := 0 to MapSize - 1 do
    506           if (Formation[Loc] >= 0) and (Map[Loc] and fTerrain >= fGrass) then
    507             inc(IndexOfID[Formation[Loc]]);
    508       1: // oceans
    509         for Loc := 0 to MapSize - 1 do
    510           if (Formation[Loc] >= 0) and (Map[Loc] and fTerrain < fGrass) then
    511             inc(IndexOfID[Formation[Loc]]);
    512       2: // districts
    513         for Loc := 0 to MapSize - 1 do
    514           if District[Loc] >= 0 then
    515             inc(IndexOfID[District[Loc]]);
    516     end;
    517 
    518     Count := 0;
    519     for Loc := 0 to MapSize - 1 do
    520       if IndexOfID[Loc] > 0 then
    521       begin
    522         IDOfIndex[Count] := Loc;
    523         inc(Count);
     497// sort continents, oceans and districts by size
     498for Kind:=0 to 2 do
     499  begin
     500  FillChar(IndexOfID,MapSize*2,0);
     501  case Kind of
     502    0: // continents
     503      for Loc:=0 to MapSize-1 do
     504        if (Formation[Loc]>=0) and (Map[Loc] and fTerrain>=fGrass) then
     505          inc(IndexOfID[Formation[Loc]]);
     506    1: // oceans
     507      for Loc:=0 to MapSize-1 do
     508        if (Formation[Loc]>=0) and (Map[Loc] and fTerrain<fGrass) then
     509          inc(IndexOfID[Formation[Loc]]);
     510    2: // districts
     511      for Loc:=0 to MapSize-1 do
     512        if District[Loc]>=0 then
     513          inc(IndexOfID[District[Loc]]);
     514    end;
     515
     516  Count:=0;
     517  for Loc:=0 to MapSize-1 do if IndexOfID[Loc]>0 then
     518    begin
     519    IDOfIndex[Count]:=Loc;
     520    inc(Count);
     521    end;
     522  for i:=0 to Count-2 do
     523    begin
     524    MostIndex:=i;
     525    for j:=i+1 to Count-1 do
     526      if IndexOfID[IDOfIndex[j]]>IndexOfID[IDOfIndex[MostIndex]] then MostIndex:=j;
     527    if MostIndex<>i then
     528      begin
     529      j:=IDOfIndex[i];
     530      IDOfIndex[i]:=IDOfIndex[MostIndex];
     531      IDOfIndex[MostIndex]:=j;
     532      end
     533    end;
     534  for i:=0 to Count-1 do
     535    IndexOfID[IDOfIndex[i]]:=i;
     536
     537  case Kind of
     538    0: // continents
     539      begin
     540      nContinent:=Count;
     541      for Loc:=0 to MapSize-1 do
     542        if (Formation[Loc]>=0) and (Map[Loc] and fTerrain>=fGrass) then
     543          Formation[Loc]:=IndexOfID[Formation[Loc]];
    524544      end;
    525     for i := 0 to Count - 2 do
    526     begin
    527       MostIndex := i;
    528       for j := i + 1 to Count - 1 do
    529         if IndexOfID[IDOfIndex[j]] > IndexOfID[IDOfIndex[MostIndex]] then
    530           MostIndex := j;
    531       if MostIndex <> i then
    532       begin
    533         j := IDOfIndex[i];
    534         IDOfIndex[i] := IDOfIndex[MostIndex];
    535         IDOfIndex[MostIndex] := j;
    536       end
    537     end;
    538     for i := 0 to Count - 1 do
    539       IndexOfID[IDOfIndex[i]] := i;
    540 
    541     case Kind of
    542       0: // continents
    543         begin
    544           nContinent := Count;
    545           for Loc := 0 to MapSize - 1 do
    546             if (Formation[Loc] >= 0) and (Map[Loc] and fTerrain >= fGrass) then
    547               Formation[Loc] := IndexOfID[Formation[Loc]];
    548         end;
    549       1: // oceans
    550         begin
    551           nOcean := Count;
    552           for Loc := 0 to MapSize - 1 do
    553             if (Formation[Loc] >= 0) and (Map[Loc] and fTerrain < fGrass) then
    554               Formation[Loc] := IndexOfID[Formation[Loc]];
    555         end;
    556       2: // districts
    557         begin
    558           nDistrict := Count;
    559           for Loc := 0 to MapSize - 1 do
    560             if District[Loc] >= 0 then
    561               District[Loc] := IndexOfID[District[Loc]];
    562         end;
     545    1: // oceans
     546      begin
     547      nOcean:=Count;
     548      for Loc:=0 to MapSize-1 do
     549        if (Formation[Loc]>=0) and (Map[Loc] and fTerrain<fGrass) then
     550          Formation[Loc]:=IndexOfID[Formation[Loc]];
     551      end;
     552    2: // districts
     553      begin
     554      nDistrict:=Count;
     555      for Loc:=0 to MapSize-1 do
     556        if District[Loc]>=0 then
     557          District[Loc]:=IndexOfID[District[Loc]];
     558      end;
    563559    end
    564560  end;
     
    566562
    567563
    568 // ------------------------------------------------------------------------------
     564//------------------------------------------------------------------------------
    569565// Path Finding
    570566
    571567const
    572   // basic move styles
    573   msGround = $00000000;
    574   msNoGround = $10000000;
    575   msAlpine = $20000000;
    576   msOver = $40000000;
    577   msSpy = $50000000;
    578 
    579   // other
    580   msHostile = $08000000;
    581 
    582   // bits:   |31|30|29|28|27|26 .. 16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
    583   // ground: |   Basic   |Ho| Speed  |       HeavyCost       |        RailCost       |
    584   // other:  |   Basic   | 0| Speed  |              X X X             | MaxTerrType  |
    585 
    586 function TToolAI.GetMyMoveStyle(mix, Health: integer): integer;
    587 begin
    588   with MyModel[mix] do
    589   begin
    590     result := Speed shl 16;
    591     case Domain of
    592       dGround:
    593         begin
    594           inc(result, (50 + (Speed - 150) * 13 shr 7) shl 8); // HeavyCost
    595           if RO.Wonder[woShinkansen].EffectiveOwner <> me then
    596             inc(result, Speed * (4 * 1311) shr 17); // RailCost
    597           if RO.Wonder[woGardens].EffectiveOwner <> me then
    598             inc(result, msHostile);
    599           if Kind = mkDiplomat then
    600             inc(result, msSpy)
    601           else if Cap[mcOver] > 0 then
    602             inc(result, msOver)
    603           else if Cap[mcAlpine] > 0 then
    604             inc(result, msAlpine)
    605           else
    606             inc(result, msGround);
    607         end;
    608       dSea:
    609         begin
    610           result := Speed;
    611           if RO.Wonder[woMagellan].EffectiveOwner = me then
    612             inc(result, 200);
    613           if Health < 100 then
    614             result := ((result - 250) * Health div 5000) * 50 + 250;
    615           result := result shl 16;
    616           inc(result, msNoGround);
    617           if Cap[mcNav] > 0 then
    618             inc(result);
    619         end;
    620       dAir:
    621         inc(result, msNoGround + fUNKNOWN xor 1 - 1);
     568// basic move styles
     569msGround=        $00000000;
     570msNoGround=      $10000000;
     571msAlpine=        $20000000;
     572msOver=          $40000000;
     573msSpy=           $50000000;
     574
     575// other
     576msHostile=       $08000000;
     577
     578// bits:   |31|30|29|28|27|26 .. 16|15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
     579// ground: |   Basic   |Ho| Speed  |       HeavyCost       |        RailCost       |
     580// other:  |   Basic   | 0| Speed  |              X X X             | MaxTerrType  |
     581
     582function TToolAI.GetMyMoveStyle(mix,Health: integer): integer;
     583begin
     584with MyModel[mix] do
     585  begin
     586  result:=Speed shl 16;
     587  case Domain of
     588    dGround:
     589      begin
     590      inc(result, (50+(Speed-150)*13 shr 7) shl 8); //HeavyCost
     591      if RO.Wonder[woShinkansen].EffectiveOwner<>me then
     592        inc(result, Speed*(4*1311) shr 17); // RailCost
     593      if (RO.Wonder[woGardens].EffectiveOwner<>me)
     594        or (Kind=mkSettler) and (Speed>=200) then
     595        inc(result, msHostile);
     596      if Kind=mkDiplomat then
     597        inc(result,msSpy)
     598      else if Cap[mcOver]>0 then
     599        inc(result,msOver)
     600      else if Cap[mcAlpine]>0 then
     601        inc(result,msAlpine)
     602      else inc(result,msGround);
     603      end;
     604    dSea:
     605      begin
     606      result:=Speed;
     607      if RO.Wonder[woMagellan].EffectiveOwner=me then inc(result,200);
     608      if Health<100 then result:=((result-250)*Health div 5000)*50+250;
     609      result:=result shl 16;
     610      inc(result,msNoGround);
     611      if Cap[mcNav]>0 then inc(result);
     612      end;
     613    dAir:
     614      inc(result,msNoGround+fUNKNOWN xor 1 -1);
    622615    end;
    623616  end
     
    625618
    626619function TToolAI.CheckStep(MoveStyle, TimeBeforeStep, CrossCorner: integer;
    627   var TimeAfterStep, RecoverTurns: integer; FromTile, ToTile: integer): integer;
    628 var
    629   MoveCost, RecoverCost: integer;
    630 begin
    631   assert(((FromTile and fTerrain <= fMountains) or
    632     (FromTile and fTerrain = fUNKNOWN)) and ((ToTile and fTerrain <= fMountains)
    633     or (ToTile and fTerrain = fUNKNOWN)));
     620  var TimeAfterStep, RecoverTurns: integer; FromTile, ToTile: integer; IsCapture: boolean): integer;
     621var
     622MoveCost,RecoverCost: integer;
     623begin
     624//IsCapture:=true;
     625assert(((FromTile and fTerrain<=fMountains) or (FromTile and fTerrain=fUNKNOWN))
     626  and ((ToTile and fTerrain<=fMountains) or (ToTile and fTerrain=fUNKNOWN)));
    634627  // do not pass location codes for FromTile and ToTile!
    635   RecoverTurns := 0;
    636   if MoveStyle < msGround + $10000000 then
     628RecoverTurns:=0;
     629if MoveStyle<msGround+$10000000 then
    637630  begin // common ground units
    638     if (ToTile + 1) and fTerrain < fGrass + 1 then
    639       result := csForbiddenTile
    640     else if (ToTile and not FromTile and fPeace = 0) and
    641       (ToTile and (fUnit or fOwned) <> fUnit) then
    642       if (FromTile and fCity <> 0) or (ToTile and (fCity or fOwned) = fCity or
    643         fOwned) or (ToTile and FromTile and (fInEnemyZoC or fOwnZoCUnit) <>
    644         fInEnemyZoC) then
     631  if (ToTile+1) and fTerrain<fGrass+1 then
     632    result:=csForbiddenTile
     633  else if (ToTile and not FromTile and fPeace=0)
     634    and (ToTile and (fUnit or fOwned)<>fUnit)
     635    and (IsCapture or (ToTile and (fCity or fOwned)<>fCity)) then
     636    if (FromTile and fCity<>0) or (ToTile and (fCity or fOwned)=fCity or fOwned)
     637      or (ToTile and FromTile and (fInEnemyZoc or fOwnZoCUnit)<>fInEnemyZoc) then
    645638      begin // ZoC is ok
    646         if (ToTile and (fRR or fCity) = 0) or (FromTile and (fRR or fCity) = 0)
    647         then
     639      if (ToTile and (fRR or fCity)=0) or (FromTile and (fRR or fCity)=0) then
    648640        begin // no railroad
    649           if (ToTile and (fRoad or fRR or fCity) <> 0) and
    650             (FromTile and (fRoad or fRR or fCity) <> 0) or
    651             (FromTile and ToTile and (fRiver or fCanal) <> 0) then
    652             MoveCost := 20 // move along road, river or canal
    653           else
     641        if (ToTile and (fRoad or fRR or fCity)<>0)
     642          and (FromTile and (fRoad or fRR or fCity)<>0)
     643          or (FromTile and ToTile and (fRiver or fCanal)<>0) then
     644          MoveCost:=20 //move along road, river or canal
     645        else
    654646          begin
    655             case Terrain[ToTile and fTerrain].MoveCost of
    656               1:
    657                 MoveCost := 50; // plain terrain
    658               2:
    659                 MoveCost := MoveStyle shr 8 and $FF; // heavy terrain
     647          case Terrain[ToTile and fTerrain].MoveCost of
     648            1: MoveCost:=50; // plain terrain
     649            2: MoveCost:=MoveStyle shr 8 and $FF; // heavy terrain
    660650            else // mountains
    661651              begin
    662                 if TimeBeforeStep and $FFF + MoveStyle shr 16 and $7FF <= $800
    663                 then
    664                   TimeAfterStep := TimeBeforeStep and $7FFFF000 + $1800
    665                 else
    666                   TimeAfterStep := TimeBeforeStep and $7FFFF000 + $2800;
    667                 // must wait for next turn
    668                 if (MoveStyle and msHostile <> 0) and
    669                   ((FromTile and (fTerrain or fSpecial1) = fDesert) or
    670                   (FromTile and fTerrain = fArctic)) and
    671                   (FromTile and (fCity or fRiver or fCanal) = 0) then
     652              if TimeBeforeStep and $FFF+MoveStyle shr 16 and $7FF<=$800 then
     653                TimeAfterStep:=TimeBeforeStep and $7FFFF000+$1800
     654              else TimeAfterStep:=TimeBeforeStep and $7FFFF000+$2800; // must wait for next turn
     655              if (MoveStyle and msHostile<>0)
     656                and ((FromTile and (fTerrain or fSpecial1)=fDesert)
     657                  or (FromTile and fTerrain=fArctic))
     658                and (FromTile and (fCity or fRiver or fCanal)=0) then
    672659                begin
    673                   RecoverCost := ($800 - TimeBeforeStep and $FFF) * 5 shr 1;
    674                   while RecoverCost > 0 do
     660                RecoverCost:=($800-TimeBeforeStep and $FFF)*5 shr 1;
     661                while RecoverCost>0 do
    675662                  begin
    676                     inc(RecoverTurns);
    677                     dec(RecoverCost, MoveStyle shr 16 and $7FF);
     663                  inc(RecoverTurns);
     664                  dec(RecoverCost, MoveStyle shr 16 and $7FF);
    678665                  end;
    679                 end;
    680                 result := csOk;
    681                 if ToTile and fPeace <> 0 then
    682                   result := csCheckTerritory;
    683                 exit
     666                end; 
     667              result:=csOk;
     668              if ToTile and fPeace<>0 then
     669                result:=csCheckTerritory;
     670              exit
    684671              end;
    685672            end
    686673          end
    687674        end
    688         else
    689           MoveCost := MoveStyle and $FF; // move along railroad
    690 
    691         inc(MoveCost, MoveCost shl CrossCorner);
    692         if (MoveStyle and msHostile = 0) or
    693           (ToTile and (fTerrain or fSpecial1) <> fDesert) and
    694           (ToTile and fTerrain <> fArctic) or
    695           (ToTile and (fCity or fRiver or fCanal) <> 0) then
    696           RecoverCost := 0
    697         else
    698           RecoverCost := (MoveCost * 5) shr 1;
    699         // damage from movement: MoveCost*DesertThurst/NoCityRecovery
    700         if (TimeBeforeStep and $FFF + MoveCost <= $800) and
    701           (TimeBeforeStep and $FFF < $800) then
    702           TimeAfterStep := TimeBeforeStep + MoveCost
    703         else
     675      else MoveCost:=MoveStyle and $FF; //move along railroad
     676
     677      inc(MoveCost,MoveCost shl CrossCorner);
     678      if (MoveStyle and msHostile=0)
     679        or (ToTile and (fTerrain or fSpecial1)<>fDesert)
     680          and (ToTile and fTerrain<>fArctic)
     681        or (ToTile and (fCity or fRiver or fCanal)<>0)
     682        or (ToTile and fTerImp=tiBase) then
     683        RecoverCost:=0
     684      else RecoverCost:=(MoveCost*5) shr 1; // damage from movement: MoveCost*DesertThurst/NoCityRecovery
     685      if (TimeBeforeStep and $FFF+MoveCost<=$800) and (TimeBeforeStep and $FFF<$800) then
     686        TimeAfterStep:=TimeBeforeStep+MoveCost
     687      else
    704688        begin
    705           TimeAfterStep := TimeBeforeStep and $7FFFF000 + $1800 -
    706             MoveStyle shr 16 and $7FF + MoveCost; // must wait for next turn
    707           if (MoveStyle and msHostile <> 0) and
    708             ((FromTile and (fTerrain or fSpecial1) = fDesert) or
    709             (FromTile and fTerrain = fArctic)) and
    710             (FromTile and (fCity or fRiver or fCanal) = 0) then
    711             inc(RecoverCost, ($800 - TimeBeforeStep and $FFF) * 5 shr 1);
     689        TimeAfterStep:=TimeBeforeStep and $7FFFF000+$1800-MoveStyle shr 16 and $7FF+MoveCost; // must wait for next turn
     690        if (MoveStyle and msHostile<>0)
     691          and ((FromTile and (fTerrain or fSpecial1)=fDesert)
     692            or (FromTile and fTerrain=fArctic))
     693          and (FromTile and (fCity or fRiver or fCanal)=0)
     694          and (FromTile and fTerImp<>tiBase) then
     695          inc(RecoverCost, ($800-TimeBeforeStep and $FFF)*5 shr 1);
    712696        end;
    713         while RecoverCost > 0 do
     697      while RecoverCost>0 do
    714698        begin
    715           inc(RecoverTurns);
    716           dec(RecoverCost, MoveStyle shr 16 and $7FF);
     699        inc(RecoverTurns);
     700        dec(RecoverCost, MoveStyle shr 16 and $7FF);
    717701        end;
    718         result := csOk;
    719         if ToTile and fPeace <> 0 then
    720           result := csCheckTerritory
     702      result:=csOk;
     703      if ToTile and fPeace<>0 then
     704        result:=csCheckTerritory
    721705      end
    722       else
    723         result := csForbiddenStep // ZoC violation
    724     else
    725       result := csForbiddenTile
     706    else result:=csForbiddenStep // ZoC violation
     707  else result:=csForbiddenTile
    726708  end
    727709
    728   else if MoveStyle < msNoGround + $10000000 then
     710else if MoveStyle<msNoGround+$10000000 then
    729711  begin // ships and aircraft
    730     if ((ToTile and fTerrain xor 1 > MoveStyle and fTerrain) and
    731       (ToTile and (fCity or fCanal) = 0)) or
    732       (ToTile and not FromTile and fPeace <> 0) or
    733       (ToTile and (fUnit or fOwned) = fUnit) then
    734       result := csForbiddenTile
    735     else
    736     begin
    737       MoveCost := 50 shl CrossCorner + 50;
    738       if TimeBeforeStep and $FFF + MoveCost <= $800 then
    739         TimeAfterStep := TimeBeforeStep + MoveCost
    740       else
    741         TimeAfterStep := TimeBeforeStep and $7FFFF000 + $1800 -
    742           MoveStyle shr 16 and $7FF + MoveCost; // must wait for next turn
    743       result := csOk;
    744       if ToTile and fPeace <> 0 then
    745         result := csCheckTerritory
     712  if ((ToTile and fTerrain xor 1>MoveStyle and fTerrain)
     713      and (ToTile and (fCity or fCanal)=0))
     714    or (ToTile and not FromTile and fPeace<>0)
     715    or (ToTile and (fUnit or fOwned)=fUnit)
     716    or (ToTile and (fCity or fOwned)=fCity) then
     717    result:=csForbiddenTile
     718  else
     719    begin
     720    MoveCost:=50 shl CrossCorner+50;
     721    if TimeBeforeStep and $FFF+MoveCost<=$800 then
     722      TimeAfterStep:=TimeBeforeStep+MoveCost
     723    else TimeAfterStep:=TimeBeforeStep and $7FFFF000+$1800-MoveStyle shr 16 and $7FF+MoveCost; // must wait for next turn
     724    result:=csOk;
     725    if ToTile and fPeace<>0 then
     726      result:=csCheckTerritory
    746727    end
    747728  end
    748729
    749   else if MoveStyle < msAlpine + $10000000 then
     730else if MoveStyle<msAlpine+$10000000 then
    750731  begin // alpine
    751     if (ToTile + 1) and fTerrain < fGrass + 1 then
    752       result := csForbiddenTile
    753     else if (ToTile and not FromTile and fPeace = 0) and
    754       (ToTile and (fUnit or fOwned) <> fUnit) then
    755       if (FromTile and fCity <> 0) or (ToTile and (fCity or fOwned) = fCity or
    756         fOwned) or (ToTile and FromTile and (fInEnemyZoC or fOwnZoCUnit) <>
    757         fInEnemyZoC) then
    758       begin
    759         if (ToTile and (fRR or fCity) = 0) or (FromTile and (fRR or fCity) = 0)
    760         then
    761           MoveCost := 20 // no railroad
    762         else
    763           MoveCost := MoveStyle and $FF; // move along railroad
    764         inc(MoveCost, MoveCost shl CrossCorner);
    765         if (TimeBeforeStep and $FFF + MoveCost <= $800) and
    766           (TimeBeforeStep and $FFF < $800) then
    767           TimeAfterStep := TimeBeforeStep + MoveCost
    768         else
    769           TimeAfterStep := TimeBeforeStep and $7FFFF000 + $1800 -
    770             MoveStyle shr 16 and $7FF + MoveCost; // must wait for next turn
    771         result := csOk;
    772         if ToTile and fPeace <> 0 then
    773           result := csCheckTerritory
     732  if (ToTile+1) and fTerrain<fGrass+1 then
     733    result:=csForbiddenTile
     734  else if (ToTile and not FromTile and fPeace=0)
     735    and (ToTile and (fUnit or fOwned)<>fUnit)
     736    and (IsCapture or (ToTile and (fCity or fOwned)<>fCity)) then
     737    if (FromTile and fCity<>0) or (ToTile and (fCity or fOwned)=fCity or fOwned)
     738      or (ToTile and FromTile and (fInEnemyZoc or fOwnZoCUnit)<>fInEnemyZoc) then
     739      begin
     740      if (ToTile and (fRR or fCity)=0) or (FromTile and (fRR or fCity)=0) then
     741        MoveCost:=20 // no railroad
     742      else MoveCost:=MoveStyle and $FF; //move along railroad
     743      inc(MoveCost,MoveCost shl CrossCorner);
     744      if (TimeBeforeStep and $FFF+MoveCost<=$800) and (TimeBeforeStep and $FFF<$800) then
     745        TimeAfterStep:=TimeBeforeStep+MoveCost
     746      else TimeAfterStep:=TimeBeforeStep and $7FFFF000+$1800-MoveStyle shr 16 and $7FF+MoveCost; // must wait for next turn
     747      result:=csOk;
     748      if ToTile and fPeace<>0 then
     749        result:=csCheckTerritory
    774750      end
     751    else result:=csForbiddenStep // ZoC violation
     752  else result:=csForbiddenTile
     753  end
     754
     755else if MoveStyle<msOver+$10000000 then
     756  begin // overweight
     757  if (ToTile+1) and fTerrain<fGrass+1 then
     758    result:=csForbiddenTile
     759  else if (ToTile and not FromTile and fPeace=0)
     760    and (ToTile and (fUnit or fOwned)<>fUnit)
     761    and (IsCapture or (ToTile and (fCity or fOwned)<>fCity)) then
     762    if (FromTile and fCity<>0) or (ToTile and (fCity or fOwned)=fCity or fOwned)
     763      or (ToTile and FromTile and (fInEnemyZoc or fOwnZoCUnit)<>fInEnemyZoc) then
     764      begin
     765      if (ToTile and (fRR or fCity)=0) or (FromTile and (fRR or fCity)=0) then
     766        begin // no railroad
     767        if (ToTile and (fRoad or fRR or fCity)<>0)
     768          and (FromTile and (fRoad or fRR or fCity)<>0)
     769          or (FromTile and ToTile and (fRiver or fCanal)<>0) then
     770          MoveCost:=40 //move along road, river or canal
     771        else begin result:=csForbiddenTile; exit end
     772        end
     773      else MoveCost:=MoveStyle and $FF; //move along railroad
     774      inc(MoveCost,MoveCost shl CrossCorner);
     775      if (TimeBeforeStep and $FFF+MoveCost<=$800) and (TimeBeforeStep and $FFF<$800) then
     776        TimeAfterStep:=TimeBeforeStep+MoveCost
     777      else TimeAfterStep:=TimeBeforeStep and $7FFFF000+$1800-MoveStyle shr 16 and $7FF+MoveCost; // must wait for next turn
     778      result:=csOk;
     779      if ToTile and fPeace<>0 then
     780        result:=csCheckTerritory
     781      end
     782    else result:=csForbiddenStep // ZoC violation
     783  else result:=csForbiddenTile
     784  end
     785
     786else {if MoveStyle<msSpy+$10000000 then}
     787  begin // spies
     788  if (ToTile+1) and fTerrain<fGrass+1 then
     789    result:=csForbiddenTile
     790  else if (ToTile and (fUnit or fOwned)<>fUnit)
     791    and (IsCapture or (ToTile and (fCity or fOwned)<>fCity)) then
     792    begin
     793    if (ToTile and (fRR or fCity)=0) or (FromTile and (fRR or fCity)=0) then
     794      begin // no railroad
     795      if (ToTile and (fRoad or fRR or fCity)<>0)
     796        and (FromTile and (fRoad or fRR or fCity)<>0)
     797        or (FromTile and ToTile and (fRiver or fCanal)<>0) then
     798        MoveCost:=20 //move along road, river or canal
    775799      else
    776         result := csForbiddenStep // ZoC violation
    777     else
    778       result := csForbiddenTile
    779   end
    780 
    781   else if MoveStyle < msOver + $10000000 then
    782   begin // overweight
    783     if (ToTile + 1) and fTerrain < fGrass + 1 then
    784       result := csForbiddenTile
    785     else if (ToTile and not FromTile and fPeace = 0) and
    786       (ToTile and (fUnit or fOwned) <> fUnit) then
    787       if (FromTile and fCity <> 0) or (ToTile and (fCity or fOwned) = fCity or
    788         fOwned) or (ToTile and FromTile and (fInEnemyZoC or fOwnZoCUnit) <>
    789         fInEnemyZoC) then
    790       begin
    791         if (ToTile and (fRR or fCity) = 0) or (FromTile and (fRR or fCity) = 0)
    792         then
    793         begin // no railroad
    794           if (ToTile and (fRoad or fRR or fCity) <> 0) and
    795             (FromTile and (fRoad or fRR or fCity) <> 0) or
    796             (FromTile and ToTile and (fRiver or fCanal) <> 0) then
    797             MoveCost := 40 // move along road, river or canal
    798           else
    799           begin
    800             result := csForbiddenTile;
    801             exit
    802           end
    803         end
    804         else
    805           MoveCost := MoveStyle and $FF; // move along railroad
    806         inc(MoveCost, MoveCost shl CrossCorner);
    807         if (TimeBeforeStep and $FFF + MoveCost <= $800) and
    808           (TimeBeforeStep and $FFF < $800) then
    809           TimeAfterStep := TimeBeforeStep + MoveCost
    810         else
    811           TimeAfterStep := TimeBeforeStep and $7FFFF000 + $1800 -
    812             MoveStyle shr 16 and $7FF + MoveCost; // must wait for next turn
    813         result := csOk;
    814         if ToTile and fPeace <> 0 then
    815           result := csCheckTerritory
    816       end
    817       else
    818         result := csForbiddenStep // ZoC violation
    819     else
    820       result := csForbiddenTile
    821   end
    822 
    823   else { if MoveStyle<msSpy+$10000000 then }
    824   begin // spies
    825     if (ToTile + 1) and fTerrain < fGrass + 1 then
    826       result := csForbiddenTile
    827     else if ToTile and (fUnit or fOwned) <> fUnit then
    828     begin
    829       if (ToTile and (fRR or fCity) = 0) or (FromTile and (fRR or fCity) = 0)
    830       then
    831       begin // no railroad
    832         if (ToTile and (fRoad or fRR or fCity) <> 0) and
    833           (FromTile and (fRoad or fRR or fCity) <> 0) or
    834           (FromTile and ToTile and (fRiver or fCanal) <> 0) then
    835           MoveCost := 20 // move along road, river or canal
    836         else
    837800        begin
    838           case Terrain[ToTile and fTerrain].MoveCost of
    839             1:
    840               MoveCost := 50; // plain terrain
    841             2:
    842               MoveCost := MoveStyle shr 8 and $FF; // heavy terrain
     801        case Terrain[ToTile and fTerrain].MoveCost of
     802          1: MoveCost:=50; // plain terrain
     803          2: MoveCost:=MoveStyle shr 8 and $FF; // heavy terrain
    843804          else // mountains
    844805            begin
    845               if TimeBeforeStep and $FFF + MoveStyle shr 16 and $7FF <= $800
    846               then
    847                 TimeAfterStep := TimeBeforeStep and $7FFFF000 + $1800
    848               else
    849                 TimeAfterStep := TimeBeforeStep and $7FFFF000 + $2800;
    850               // must wait for next turn
    851               result := csOk;
    852               exit
     806            if TimeBeforeStep and $FFF+MoveStyle shr 16 and $7FF<=$800 then
     807              TimeAfterStep:=TimeBeforeStep and $7FFFF000+$1800
     808            else TimeAfterStep:=TimeBeforeStep and $7FFFF000+$2800; // must wait for next turn
     809            result:=csOk;
     810            exit
    853811            end;
    854812          end
    855813        end
    856814      end
    857       else
    858         MoveCost := MoveStyle and $FF; // move along railroad
    859       inc(MoveCost, MoveCost shl CrossCorner);
    860       if (TimeBeforeStep and $FFF + MoveCost <= $800) and
    861         (TimeBeforeStep and $FFF < $800) then
    862         TimeAfterStep := TimeBeforeStep + MoveCost
    863       else
    864         TimeAfterStep := TimeBeforeStep and $7FFFF000 + $1800 -
    865           MoveStyle shr 16 and $7FF + MoveCost; // must wait for next turn
    866       result := csOk;
     815    else MoveCost:=MoveStyle and $FF; //move along railroad
     816    inc(MoveCost,MoveCost shl CrossCorner);
     817    if (TimeBeforeStep and $FFF+MoveCost<=$800) and (TimeBeforeStep and $FFF<$800) then
     818      TimeAfterStep:=TimeBeforeStep+MoveCost
     819    else TimeAfterStep:=TimeBeforeStep and $7FFFF000+$1800-MoveStyle shr 16 and $7FF+MoveCost; // must wait for next turn
     820    result:=csOk;
    867821    end
    868     else
    869       result := csForbiddenTile
     822  else result:=csForbiddenTile
    870823  end;
    871824end; // CheckStep
    872825
    873826(*
    874   -------- Pathfinding Reference Implementation --------
    875   var
    876   MoveStyle,V8,Loc,Time,NextLoc,NextTime,RecoverTurns: integer;
    877   Adjacent: TVicinity8Loc;
    878   Reached: array[0..lxmax*lymax-1] of boolean;
    879   begin
    880   fillchar(Reached, MapSize, false);
    881   MoveStyle:=GetMyMoveStyle(MyUnit[uix].mix, MyUnit[uix].Health);
    882   Pile.Create(MapSize);
    883   Pile.Put(MyUnit[uix].Loc, $800-MyUnit[uix].Movement);
    884   while Pile.Get(Loc, Time) do
     827-------- Pathfinding Reference Implementation --------
     828var
     829MoveStyle,V8,Loc,Time,NextLoc,NextTime,RecoverTurns: integer;
     830Adjacent: TVicinity8Loc;
     831Reached: array[0..lxmax*lymax-1] of boolean;
     832begin
     833fillchar(Reached, MapSize, false);
     834MoveStyle:=GetMyMoveStyle(MyUnit[uix].mix, MyUnit[uix].Health);
     835Pile.Create(MapSize);
     836Pile.Put(MyUnit[uix].Loc, $800-MyUnit[uix].Movement);
     837while Pile.Get(Loc, Time) do
    885838  begin
    886839  // todo: check exit condition, e.g. whether destination reached
     
    889842  V8_to_Loc(Loc, Adjacent);
    890843  for V8:=0 to 7 do
    891   begin
    892   NextLoc:=Adjacent[V8];
    893   if (NextLoc>=0) and not Reached[NextLoc] then
    894   case CheckStep(MoveStyle, Time, V8 and 1, NextTime, RecoverTurns, Map[Loc], Map[NextLoc]) of
    895   csOk:
    896   Pile.Put(NextLoc, NextTime+RecoverTurns*$1000);
    897   csForbiddenTile:
    898   Reached[NextLoc]:=true; // don't check moving there again
    899   csCheckTerritory:
    900   if RO.Territory[NextLoc]=RO.Territory[Loc] then
    901   Pile.Put(NextLoc, NextTime+RecoverTurns*$1000);
     844    begin
     845    NextLoc:=Adjacent[V8];
     846    if (NextLoc>=0) and not Reached[NextLoc] then
     847      case CheckStep(MoveStyle, Time, V8 and 1, NextTime, RecoverTurns, Map[Loc], Map[NextLoc]) of
     848        csOk:
     849          Pile.Put(NextLoc, NextTime+RecoverTurns*$1000);
     850        csForbiddenTile:
     851          Reached[NextLoc]:=true; // don't check moving there again
     852        csCheckTerritory:
     853          if RO.Territory[NextLoc]=RO.Territory[Loc] then
     854            Pile.Put(NextLoc, NextTime+RecoverTurns*$1000);
     855        end
     856    end;
     857  end;
     858Pile.Free;
     859end;
     860*)
     861
     862function TToolAI.Unit_MoveEx(uix,ToLoc: integer; Options: integer): integer;
     863var
     864Loc,NextLoc,Temp,FromLoc,EndLoc,Time,V8,MoveResult,RecoverTurns,NextTime,
     865  MoveStyle: integer;
     866Adjacent: TVicinity8Loc;
     867PreLoc: array[0..lxmax*lymax-1] of integer;
     868Reached: array[0..lxmax*lymax-1] of boolean;
     869begin
     870result:=eOk;
     871FromLoc:=MyUnit[uix].Loc;
     872if FromLoc=ToLoc then exit;
     873
     874FillChar(Reached,MapSize,false);
     875MoveStyle:=GetMyMoveStyle(MyUnit[uix].mix, MyUnit[uix].Health);
     876EndLoc:=-1;
     877Pile.Create(MapSize);
     878Pile.Put(FromLoc, $800-MyUnit[uix].Movement);
     879while Pile.Get(Loc,Time) do
     880  begin
     881  if (Loc=ToLoc)
     882    or (ToLoc=maNextCity) and (Map[Loc] and fCity<>0)
     883    and (Map[Loc] and fOwned<>0) then
     884    begin EndLoc:=Loc; Break; end;
     885  Reached[Loc]:=true;
     886  V8_to_Loc(Loc,Adjacent);
     887  for V8:=0 to 7 do
     888    begin
     889    NextLoc:=Adjacent[V8];
     890    if NextLoc>=0 then
     891      if (NextLoc=ToLoc) and (Options and mxAdjacent<>0) then
     892        begin EndLoc:=Loc; Break end
     893      else if not Reached[NextLoc] then
     894        begin
     895        case CheckStep(MoveStyle, Time, V8 and 1, NextTime, RecoverTurns,
     896          Map[Loc], Map[NextLoc], NextLoc=ToLoc) of
     897          csOk:
     898            if Pile.Put(NextLoc, NextTime+RecoverTurns*$1000) then
     899              PreLoc[NextLoc]:=Loc;
     900          csForbiddenTile:
     901            Reached[NextLoc]:=true; // don't check moving there again
     902          csCheckTerritory:
     903            if RO.Territory[NextLoc]=RO.Territory[Loc] then
     904              if Pile.Put(NextLoc, NextTime+RecoverTurns*$1000) then
     905                PreLoc[NextLoc]:=Loc;
     906          end
     907        end
     908    end;
     909  if EndLoc>=0 then Break;
     910  end;
     911Pile.Free;
     912
     913if EndLoc>=0 then
     914  begin
     915  Loc:=EndLoc;
     916  NextLoc:=PreLoc[Loc];
     917  while Loc<>FromLoc do
     918    begin // invert meaning of PreLoc
     919    Temp:=Loc;
     920    Loc:=NextLoc;
     921    NextLoc:=PreLoc[Loc];
     922    PreLoc[Loc]:=Temp;
     923    end;
     924  while Loc<>EndLoc do
     925    begin
     926    Loc:=PreLoc[Loc];
     927    MoveResult:=Unit_Step(uix, Loc);
     928    if (MoveResult<>eOK) and (MoveResult<>eLoaded) then
     929      begin result:=MoveResult; break end;
     930    end;
    902931  end
    903   end;
    904   end;
    905   Pile.Free;
    906   end;
    907 *)
    908 
    909 function TToolAI.Unit_MoveEx(uix, ToLoc: integer; Options: integer): integer;
    910 var
    911   Loc, NextLoc, Temp, FromLoc, EndLoc, Time, V8, MoveResult, RecoverTurns,
    912     NextTime, MoveStyle: integer;
    913   Adjacent: TVicinity8Loc;
    914   PreLoc: array [0 .. lxmax * lymax - 1] of integer;
    915   Reached: array [0 .. lxmax * lymax - 1] of boolean;
    916 begin
    917   result := eOk;
    918   FromLoc := MyUnit[uix].Loc;
    919   if FromLoc = ToLoc then
    920     exit;
    921 
    922   fillchar(Reached, MapSize, false);
    923   MoveStyle := GetMyMoveStyle(MyUnit[uix].mix, MyUnit[uix].Health);
    924   EndLoc := -1;
    925   Pile.Create(MapSize);
    926   Pile.Put(FromLoc, $800 - MyUnit[uix].Movement);
    927   while Pile.Get(Loc, Time) do
    928   begin
    929     if (Loc = ToLoc) or (ToLoc = maNextCity) and (Map[Loc] and fCity <> 0) and
    930       (Map[Loc] and fOwned <> 0) then
    931     begin
    932       EndLoc := Loc;
    933       Break;
    934     end;
    935     Reached[Loc] := true;
    936     V8_to_Loc(Loc, Adjacent);
    937     for V8 := 0 to 7 do
    938     begin
    939       NextLoc := Adjacent[V8];
    940       if NextLoc >= 0 then
    941         if (NextLoc = ToLoc) and (Options and mxAdjacent <> 0) then
     932else result:=eNoWay;
     933end;
     934
     935
     936//------------------------------------------------------------------------------
     937// Oversea Transport
     938
     939procedure TToolAI.SeaTransport_BeginInitialize;
     940begin
     941fillchar(TransportAvailable, RO.nUn*sizeof(integer), $FF); // -1
     942InitComplete:=false;
     943HaveDestinations:=false;
     944nTransportLoad:=0;
     945TransportMoveStyle:=0;
     946TransportCapacity:=$100;
     947Pile.Create(MapSize);
     948end;
     949
     950procedure TToolAI.SeaTransport_AddLoad(uix: integer);
     951var
     952i: integer;
     953begin
     954assert(not InitComplete); // call order violation!
     955if Map[MyUnit[uix].Loc] and fTerrain<fGrass then exit;
     956for i:=0 to nTransportLoad-1 do
     957  if uix=uixTransportLoad[i] then exit;
     958uixTransportLoad[nTransportLoad]:=uix;
     959inc(nTransportLoad);
     960end;
     961
     962procedure TToolAI.SeaTransport_AddTransport(uix: integer);
     963var
     964MoveStyle: integer;
     965begin
     966assert(not InitComplete); // call order violation!
     967assert(MyModel[MyUnit[uix].mix].Cap[mcSeaTrans]>0);
     968TransportAvailable[uix]:=1;
     969with MyModel[MyUnit[uix].mix] do
     970  begin
     971  if MTrans*Cap[mcSeaTrans]<TransportCapacity then
     972    TransportCapacity:=MTrans*Cap[mcSeaTrans];
     973  MoveStyle:=GetMyMoveStyle(MyUnit[uix].mix, 100);
     974  if (TransportMoveStyle=0)
     975    or (MoveStyle<TransportMoveStyle)
     976      and (MoveStyle and not TransportMoveStyle and 1=0)
     977    or (not MoveStyle and TransportMoveStyle and 1<>0) then
     978    TransportMoveStyle:=MoveStyle;
     979  end
     980end;
     981
     982procedure TToolAI.SeaTransport_AddDestination(Loc: integer);
     983begin
     984assert(not InitComplete); // call order violation!
     985Pile.Put(Loc, $800);
     986HaveDestinations:=true;
     987end;
     988
     989procedure TToolAI.SeaTransport_EndInitialize;
     990var
     991Loc0,Time0,V8,Loc1,ArriveTime,RecoverTurns: integer;
     992Adjacent: TVicinity8Loc;
     993begin
     994assert(not InitComplete); // call order violation!
     995InitComplete:=true;
     996if HaveDestinations then
     997  begin // calculate TurnsAfterLoad from destination locs
     998  fillchar(TurnsAfterLoad, MapSize, $FF); // -1
     999  while Pile.Get(Loc0, Time0) do
     1000    begin // search backward
     1001    if Time0=$800 then TurnsAfterLoad[Loc0]:=1
     1002    else TurnsAfterLoad[Loc0]:=Time0 shr 12;
     1003    V8_to_Loc(Loc0, Adjacent);
     1004    for V8:=0 to 7 do
     1005      begin
     1006      Loc1:=Adjacent[V8];
     1007      if (Loc1>=0) and (TurnsAfterLoad[Loc1]=-1) then
    9421008        begin
    943           EndLoc := Loc;
    944           Break
    945         end
    946         else if not Reached[NextLoc] then
    947           case CheckStep(MoveStyle, Time, V8 and 1, NextTime, RecoverTurns,
    948             Map[Loc], Map[NextLoc]) of
    949             csOk:
    950               if Pile.Put(NextLoc, NextTime + RecoverTurns * $1000) then
    951                 PreLoc[NextLoc] := Loc;
    952             csForbiddenTile:
    953               Reached[NextLoc] := true; // don't check moving there again
    954             csCheckTerritory:
    955               if RO.Territory[NextLoc] = RO.Territory[Loc] then
    956                 if Pile.Put(NextLoc, NextTime + RecoverTurns * $1000) then
    957                   PreLoc[NextLoc] := Loc;
    958           end
    959     end;
    960     if EndLoc >= 0 then
    961       Break;
    962   end;
    963   Pile.Free;
    964 
    965   if EndLoc >= 0 then
    966   begin
    967     Loc := EndLoc;
    968     NextLoc := PreLoc[Loc];
    969     while Loc <> FromLoc do
    970     begin // invert meaning of PreLoc
    971       Temp := Loc;
    972       Loc := NextLoc;
    973       NextLoc := PreLoc[Loc];
    974       PreLoc[Loc] := Temp;
    975     end;
    976     while Loc <> EndLoc do
    977     begin
    978       Loc := PreLoc[Loc];
    979       MoveResult := Unit_Step(uix, Loc);
    980       if (MoveResult <> eOk) and (MoveResult <> eLoaded) then
    981       begin
    982         result := MoveResult;
    983         Break
    984       end;
    985     end;
    986   end
    987   else
    988     result := eNoWay;
    989 end;
    990 
    991 
    992 // ------------------------------------------------------------------------------
    993 // Oversea Transport
    994 
    995 procedure TToolAI.SeaTransport_BeginInitialize;
    996 begin
    997   fillchar(TransportAvailable, RO.nUn * sizeof(integer), $FF); // -1
    998   InitComplete := false;
    999   HaveDestinations := false;
    1000   nTransportLoad := 0;
    1001   TransportMoveStyle := 0;
    1002   TransportCapacity := $100;
    1003   Pile.Create(MapSize);
    1004 end;
    1005 
    1006 procedure TToolAI.SeaTransport_AddLoad(uix: integer);
    1007 var
    1008   i: integer;
    1009 begin
    1010   assert(not InitComplete); // call order violation!
    1011   if Map[MyUnit[uix].Loc] and fTerrain < fGrass then
    1012     exit;
    1013   for i := 0 to nTransportLoad - 1 do
    1014     if uix = uixTransportLoad[i] then
    1015       exit;
    1016   uixTransportLoad[nTransportLoad] := uix;
    1017   inc(nTransportLoad);
    1018 end;
    1019 
    1020 procedure TToolAI.SeaTransport_AddTransport(uix: integer);
    1021 var
    1022   MoveStyle: integer;
    1023 begin
    1024   assert(not InitComplete); // call order violation!
    1025   assert(MyModel[MyUnit[uix].mix].Cap[mcSeaTrans] > 0);
    1026   TransportAvailable[uix] := 1;
    1027   with MyModel[MyUnit[uix].mix] do
    1028   begin
    1029     if MTrans * Cap[mcSeaTrans] < TransportCapacity then
    1030       TransportCapacity := MTrans * Cap[mcSeaTrans];
    1031     MoveStyle := GetMyMoveStyle(MyUnit[uix].mix, 100);
    1032     if (TransportMoveStyle = 0) or (MoveStyle < TransportMoveStyle) and
    1033       (MoveStyle and not TransportMoveStyle and 1 = 0) or
    1034       (not MoveStyle and TransportMoveStyle and 1 <> 0) then
    1035       TransportMoveStyle := MoveStyle;
    1036   end
    1037 end;
    1038 
    1039 procedure TToolAI.SeaTransport_AddDestination(Loc: integer);
    1040 begin
    1041   assert(not InitComplete); // call order violation!
    1042   Pile.Put(Loc, $800);
    1043   HaveDestinations := true;
    1044 end;
    1045 
    1046 procedure TToolAI.SeaTransport_EndInitialize;
    1047 var
    1048   Loc0, Time0, V8, Loc1, ArriveTime, RecoverTurns: integer;
    1049   Adjacent: TVicinity8Loc;
    1050 begin
    1051   assert(not InitComplete); // call order violation!
    1052   InitComplete := true;
    1053   if HaveDestinations then
    1054   begin // calculate TurnsAfterLoad from destination locs
    1055     fillchar(TurnsAfterLoad, MapSize, $FF); // -1
    1056     while Pile.Get(Loc0, Time0) do
    1057     begin // search backward
    1058       if Time0 = $800 then
    1059         TurnsAfterLoad[Loc0] := 1
    1060       else
    1061         TurnsAfterLoad[Loc0] := Time0 shr 12;
    1062       V8_to_Loc(Loc0, Adjacent);
    1063       for V8 := 0 to 7 do
    1064       begin
    1065         Loc1 := Adjacent[V8];
    1066         if (Loc1 >= 0) and (TurnsAfterLoad[Loc1] = -1) then
    1067         begin
    1068           case CheckStep(TransportMoveStyle, Time0, V8 and 1, ArriveTime,
    1069             RecoverTurns, Map[Loc0], Map[Loc1]) of
    1070             csOk:
    1071               Pile.Put(Loc1, ArriveTime);
    1072             csForbiddenStep:
    1073               TurnsAfterLoad[Loc1] := -2;
     1009        case CheckStep(TransportMoveStyle, Time0, V8 and 1, ArriveTime,
     1010          RecoverTurns, Map[Loc0], Map[Loc1], false) of
     1011          csOk: Pile.Put(Loc1, ArriveTime);
     1012          csForbiddenStep: TurnsAfterLoad[Loc1]:=-2;
    10741013          end;
    10751014        end
     
    10771016    end;
    10781017  end;
    1079   Pile.Free;
    1080 end;
    1081 
    1082 function TToolAI.SeaTransport_MakeGroupPlan(var TransportPlan
    1083   : TGroupTransportPlan): boolean;
    1084 var
    1085   V8, i, j, iPicked, uix, Loc0, Time0, Loc1, RecoverTurns, MoveStyle,
    1086     TurnsLoaded, TurnCount, tuix, tuix1, ArriveTime, TotalDelay, BestTotalDelay,
    1087     GroupCount, BestGroupCount, BestLoadLoc, FullMovementLoc, nSelectedLoad, f,
    1088     OriginContinent, a, b: integer;
    1089   CompleteFlag, NotReachedFlag, ContinueUnit: cardinal;
    1090   IsComplete, ok, IsFirstLoc: boolean;
    1091   StartLocPtr, ArrivedEnd: pinteger;
    1092   Adjacent: TVicinity8Loc;
    1093   uixSelectedLoad: array [0 .. 15] of integer;
    1094   tuixSelectedLoad: array [0 .. 15] of integer;
    1095   Arrived: array [0 .. lxmax * lymax] of cardinal;
    1096   ResponsibleTransport: array [0 .. lxmax * lymax - 1] of smallint;
    1097   TurnsBeforeLoad: array [0 .. lxmax * lymax - 1] of shortint;
    1098   GroupComplete: array [0 .. lxmax * lymax - 1] of boolean;
    1099 begin
    1100   assert(InitComplete); // call order violation!
    1101 
    1102   if HaveDestinations and (nTransportLoad > 0) then
     1018Pile.Free;
     1019end;
     1020
     1021
     1022function TToolAI.SeaTransport_MakeGroupPlan(var TransportPlan: TGroupTransportPlan): boolean;
     1023var
     1024V8,i,j,iPicked,uix,Loc0,Time0,Loc1,RecoverTurns,MoveStyle, TurnsLoaded,
     1025  TurnCount, tuix, tuix1, ArriveTime, TotalDelay, BestTotalDelay, GroupCount,
     1026  BestGroupCount, BestLoadLoc, FullMovementLoc, nSelectedLoad, f,
     1027  OriginContinent,a,b: integer;
     1028CompleteFlag, NotReachedFlag, ContinueUnit: Cardinal;
     1029IsComplete,ok,IsFirstLoc: boolean;
     1030StartLocPtr, ArrivedEnd: pinteger;
     1031Adjacent: TVicinity8Loc;
     1032uixSelectedLoad: array[0..15] of integer;
     1033tuixSelectedLoad: array[0..15] of integer;
     1034Arrived: array[0..lxmax*lymax] of cardinal;
     1035ResponsibleTransport: array[0..lxmax*lymax-1] of smallint;
     1036TurnsBeforeLoad: array[0..lxmax*lymax-1] of shortint;
     1037GroupComplete: array[0..lxmax*lymax-1] of boolean;
     1038begin
     1039assert(InitComplete); // call order violation!
     1040
     1041if HaveDestinations and (nTransportLoad>0) then
    11031042  begin // transport and units already adjacent?
    1104     for uix := 0 to RO.nUn - 1 do
    1105       if (TransportAvailable[uix] > 0) and
    1106         (Map[MyUnit[uix].Loc] and fTerrain = fShore) then
    1107       begin
    1108         GroupCount := 0;
    1109         for tuix := 0 to nTransportLoad - 1 do
     1043  for uix:=0 to RO.nUn-1 do
     1044    if (TransportAvailable[uix]>0)
     1045      and (Map[MyUnit[uix].Loc] and fTerrain=fShore) then
     1046      begin
     1047      GroupCount:=0;
     1048      for tuix:=0 to nTransportLoad-1 do
    11101049        begin
    1111           Loc_to_ab(MyUnit[uix].Loc, MyUnit[uixTransportLoad[tuix]].Loc, a, b);
    1112           if (abs(a) <= 1) and (abs(b) <= 1) then
     1050        Loc_to_ab(MyUnit[uix].Loc, MyUnit[uixTransportLoad[tuix]].Loc, a, b);
     1051        if (abs(a)<=1) and (abs(b)<=1) then
    11131052          begin
    1114             assert((a <> 0) or (b <> 0));
    1115             inc(GroupCount);
     1053          assert((a<>0) or (b<>0));
     1054          inc(GroupCount);
    11161055          end
    11171056        end;
    1118         if (GroupCount = nTransportLoad) or (GroupCount >= TransportCapacity)
    1119         then
     1057      if (GroupCount=nTransportLoad) or (GroupCount>=TransportCapacity) then
    11201058        begin
    1121           TransportPlan.LoadLoc := MyUnit[uix].Loc;
    1122           TransportPlan.uixTransport := uix;
    1123           TransportAvailable[uix] := 0;
    1124           TransportPlan.TurnsEmpty := 0;
    1125           TransportPlan.TurnsLoaded := TurnsAfterLoad[TransportPlan.LoadLoc];
    1126           TransportPlan.nLoad := 0;
    1127           for tuix := nTransportLoad - 1 downto 0 do
     1059        TransportPlan.LoadLoc:=MyUnit[uix].Loc;
     1060        TransportPlan.uixTransport:=uix;
     1061        TransportAvailable[uix]:=0;
     1062        TransportPlan.TurnsEmpty:=0;
     1063        TransportPlan.TurnsLoaded:=TurnsAfterLoad[TransportPlan.LoadLoc];
     1064        TransportPlan.nLoad:=0;
     1065        for tuix:=nTransportLoad-1 downto 0 do
    11281066          begin
    1129             Loc_to_ab(TransportPlan.LoadLoc, MyUnit[uixTransportLoad[tuix]]
    1130               .Loc, a, b);
    1131             if (abs(a) <= 1) and (abs(b) <= 1) then
     1067          Loc_to_ab(TransportPlan.LoadLoc, MyUnit[uixTransportLoad[tuix]].Loc, a, b);
     1068          if (abs(a)<=1) and (abs(b)<=1) then
    11321069            begin
    1133               TransportPlan.uixLoad[TransportPlan.nLoad] :=
    1134                 uixTransportLoad[tuix];
    1135               uixTransportLoad[tuix] := uixTransportLoad[nTransportLoad - 1];
    1136               dec(nTransportLoad);
    1137               inc(TransportPlan.nLoad);
    1138               if TransportPlan.nLoad = TransportCapacity then
    1139                 Break;
     1070            TransportPlan.uixLoad[TransportPlan.nLoad]:=uixTransportLoad[tuix];
     1071            uixTransportLoad[tuix]:=uixTransportLoad[nTransportLoad-1];
     1072            dec(nTransportLoad);
     1073            inc(TransportPlan.nLoad);
     1074            if TransportPlan.nLoad=TransportCapacity then break;
    11401075            end;
    11411076          end;
    1142           result := true;
    1143           exit;
     1077        result:=true;
     1078        exit;
    11441079        end
    11451080      end
    11461081  end;
    11471082
    1148   while HaveDestinations and (nTransportLoad > 0) do
    1149   begin
    1150     // select units from same continent
    1151     fillchar(Arrived, 4 * nContinent, 0); // misuse Arrived as counter
    1152     for tuix := 0 to nTransportLoad - 1 do
    1153     begin
    1154       assert(Map[MyUnit[uixTransportLoad[tuix]].Loc] and fTerrain >= fGrass);
    1155       f := Formation[MyUnit[uixTransportLoad[tuix]].Loc];
    1156       if f >= 0 then
    1157         inc(Arrived[f]);
    1158     end;
    1159     OriginContinent := 0;
    1160     for f := 1 to nContinent - 1 do
    1161       if Arrived[f] > Arrived[OriginContinent] then
    1162         OriginContinent := f;
    1163     nSelectedLoad := 0;
    1164     for tuix := 0 to nTransportLoad - 1 do
    1165       if Formation[MyUnit[uixTransportLoad[tuix]].Loc] = OriginContinent then
    1166       begin
    1167         tuixSelectedLoad[nSelectedLoad] := tuix;
    1168         uixSelectedLoad[nSelectedLoad] := uixTransportLoad[tuix];
    1169         inc(nSelectedLoad);
    1170         if nSelectedLoad = 16 then
    1171           Break;
     1083while HaveDestinations and (nTransportLoad>0) do
     1084  begin
     1085  // select units from same continent
     1086  fillchar(Arrived, 4*nContinent, 0); // misuse Arrived as counter
     1087  for tuix:=0 to nTransportLoad-1 do
     1088    begin
     1089    assert(Map[MyUnit[uixTransportLoad[tuix]].Loc] and fTerrain>=fGrass);
     1090    f:=Formation[MyUnit[uixTransportLoad[tuix]].Loc];
     1091    if f>=0 then inc(Arrived[f]);
     1092    end;
     1093  OriginContinent:=0;
     1094  for f:=1 to nContinent-1 do
     1095    if Arrived[f]>Arrived[OriginContinent] then OriginContinent:=f;
     1096  nSelectedLoad:=0;
     1097  for tuix:=0 to nTransportLoad-1 do
     1098    if Formation[MyUnit[uixTransportLoad[tuix]].Loc]=OriginContinent then
     1099      begin
     1100      tuixSelectedLoad[nSelectedLoad]:=tuix;
     1101      uixSelectedLoad[nSelectedLoad]:=uixTransportLoad[tuix];
     1102      inc(nSelectedLoad);
     1103      if nSelectedLoad=16 then break;
    11721104      end;
    11731105
    1174     Pile.Create(MapSize);
    1175     fillchar(ResponsibleTransport, MapSize * 2, $FF); // -1
    1176     fillchar(TurnsBeforeLoad, MapSize, $FF); // -1
    1177     ok := false;
    1178     for uix := 0 to RO.nUn - 1 do
    1179       if TransportAvailable[uix] > 0 then
    1180       begin
    1181         ok := true;
    1182         Pile.Put(MyUnit[uix].Loc, ($800 - MyUnit[uix].Movement) shl 12 + uix);
    1183       end;
    1184     if not ok then // no transports
    1185     begin
    1186       TransportPlan.LoadLoc := -1;
    1187       result := false;
    1188       Pile.Free;
    1189       exit
    1190     end;
    1191     while Pile.Get(Loc0, Time0) do
    1192     begin
    1193       uix := Time0 and $FFF;
    1194       Time0 := Time0 shr 12;
    1195       ResponsibleTransport[Loc0] := uix;
    1196       TurnsBeforeLoad[Loc0] := Time0 shr 12;
    1197       V8_to_Loc(Loc0, Adjacent);
    1198       for V8 := 0 to 7 do
    1199       begin
    1200         Loc1 := Adjacent[V8];
    1201         if (Loc1 >= 0) and (ResponsibleTransport[Loc1] < 0) then
    1202           case CheckStep(GetMyMoveStyle(MyUnit[uix].mix, MyUnit[uix].Health),
    1203             Time0, V8 and 1, ArriveTime, RecoverTurns, Map[Loc0], Map[Loc1]) of
    1204             csOk:
    1205               Pile.Put(Loc1, ArriveTime shl 12 + uix);
    1206             csForbiddenTile:
    1207               ResponsibleTransport[Loc1] := RO.nUn; // don't check again
     1106  Pile.Create(MapSize);
     1107  fillchar(ResponsibleTransport, MapSize*2, $FF); // -1
     1108  fillchar(TurnsBeforeLoad, MapSize, $FF); // -1
     1109  ok:=false;
     1110  for uix:=0 to RO.nUn-1 do if TransportAvailable[uix]>0 then
     1111    begin
     1112    ok:=true;
     1113    Pile.Put(MyUnit[uix].Loc, ($800-MyUnit[uix].Movement) shl 12 + uix);
     1114    end;
     1115  if not ok then // no transports
     1116    begin TransportPlan.LoadLoc:=-1; result:=false; Pile.Free; exit end;
     1117  while Pile.Get(Loc0, Time0) do
     1118    begin
     1119    uix:=Time0 and $FFF;
     1120    Time0:=Time0 shr 12;
     1121    ResponsibleTransport[Loc0]:=uix;
     1122    TurnsBeforeLoad[Loc0]:=Time0 shr 12;
     1123    V8_to_Loc(Loc0, Adjacent);
     1124    for V8:=0 to 7 do
     1125      begin
     1126      Loc1:=Adjacent[V8];
     1127      if (Loc1>=0) and (ResponsibleTransport[Loc1]<0) then
     1128        case CheckStep(GetMyMoveStyle(MyUnit[uix].mix, MyUnit[uix].Health),
     1129          Time0, V8 and 1, ArriveTime, RecoverTurns, Map[Loc0], Map[Loc1], false) of
     1130          csOk: Pile.Put(Loc1, ArriveTime shl 12 + uix);
     1131          csForbiddenTile: ResponsibleTransport[Loc1]:=RO.nUn; // don't check again
    12081132          end
    12091133      end
    12101134    end;
    12111135
    1212     fillchar(Arrived, MapSize * 4, $55); // set NotReachedFlag for all tiles
    1213     fillchar(GroupComplete, MapSize, false);
    1214     BestLoadLoc := -1;
    1215 
    1216     // check direct loading
    1217     for tuix := 0 to nSelectedLoad - 1 do
    1218     begin
    1219       uix := uixSelectedLoad[tuix];
    1220       if MyUnit[uix].Movement = integer(MyModel[MyUnit[uix].mix].Speed) then
    1221       begin
    1222         NotReachedFlag := 1 shl (2 * tuix);
    1223         CompleteFlag := NotReachedFlag shl 1;
    1224         V8_to_Loc(MyUnit[uix].Loc, Adjacent);
    1225         for V8 := 0 to 7 do
     1136  fillchar(Arrived, MapSize*4, $55); // set NotReachedFlag for all tiles
     1137  fillchar(GroupComplete, MapSize, false);
     1138  BestLoadLoc:=-1;
     1139
     1140  // check direct loading
     1141  for tuix:=0 to nSelectedLoad-1 do
     1142    begin
     1143    uix:=uixSelectedLoad[tuix];
     1144    if MyUnit[uix].Movement=integer(MyModel[MyUnit[uix].mix].Speed) then
     1145      begin
     1146      NotReachedFlag:=1 shl (2*tuix);
     1147      CompleteFlag:=NotReachedFlag shl 1;
     1148      V8_to_Loc(MyUnit[uix].Loc, Adjacent);
     1149      for V8:=0 to 7 do
    12261150        begin
    1227           Loc1 := Adjacent[V8];
    1228           if (Loc1 >= 0) and (Map[Loc1] and fTerrain < fGrass) and
    1229             not GroupComplete[Loc1] then
     1151        Loc1:=Adjacent[V8];
     1152        if (Loc1>=0) and (Map[Loc1] and fTerrain<fGrass)
     1153          and not GroupComplete[Loc1] then
    12301154          begin // possible transport start location
    1231             Arrived[Loc1] := (Arrived[Loc1] or CompleteFlag) and
    1232               not NotReachedFlag;
    1233             if (TurnsBeforeLoad[Loc1] >= 0) and (TurnsAfterLoad[Loc1] >= 0) then
     1155          Arrived[Loc1]:=(Arrived[Loc1] or CompleteFlag) and not NotReachedFlag;
     1156          if (TurnsBeforeLoad[Loc1]>=0) and (TurnsAfterLoad[Loc1]>=0) then
    12341157            begin
    1235               i := 1;
    1236               GroupCount := 0;
    1237               for tuix1 := 0 to nSelectedLoad - 1 do
     1158            i:=1;
     1159            GroupCount:=0;
     1160            for tuix1:=0 to nSelectedLoad-1 do
    12381161              begin
    1239                 if Arrived[Loc1] and i = 0 then
    1240                   inc(GroupCount);
    1241                 i := i shl 2;
     1162              if Arrived[loc1] and i=0 then inc(GroupCount);
     1163              i:=i shl 2;
    12421164              end;
    1243               assert(GroupCount <= TransportCapacity);
    1244               if (GroupCount = TransportCapacity) or (GroupCount = nSelectedLoad)
    1245               then
    1246                 GroupComplete[Loc1] := true;
    1247               TotalDelay := TurnsBeforeLoad[Loc1] + TurnsAfterLoad[Loc1];
    1248               if (BestLoadLoc < 0) or
    1249                 (GroupCount shl 16 - TotalDelay > BestGroupCount shl 16 -
    1250                 BestTotalDelay) then
     1165            assert(GroupCount<=TransportCapacity);
     1166            if (GroupCount=TransportCapacity) or (GroupCount=nSelectedLoad) then
     1167              GroupComplete[loc1]:=true;
     1168            TotalDelay:=TurnsBeforeLoad[Loc1]+TurnsAfterLoad[Loc1];
     1169            if (BestLoadLoc<0)
     1170              or (GroupCount shl 16-TotalDelay
     1171                >BestGroupCount shl 16-BestTotalDelay) then
    12511172              begin
    1252                 BestLoadLoc := Loc1;
    1253                 BestGroupCount := GroupCount;
    1254                 BestTotalDelay := TotalDelay
     1173              BestLoadLoc:=Loc1;
     1174              BestGroupCount:=GroupCount;
     1175              BestTotalDelay:=TotalDelay
    12551176              end
    12561177            end
     
    12601181    end;
    12611182
    1262     TurnCount := 0;
    1263     ArrivedEnd := @Arrived[MapSize];
    1264 
    1265     // check moving+loading
    1266     ContinueUnit := 1 shl nSelectedLoad - 1;
    1267     while (ContinueUnit > 0) and
    1268       ((BestLoadLoc < 0) or (TurnCount < BestTotalDelay - 2)) do
    1269     begin
    1270       for tuix := 0 to nSelectedLoad - 1 do
    1271         if 1 shl tuix and ContinueUnit <> 0 then
     1183  TurnCount:=0;
     1184  ArrivedEnd:=@Arrived[MapSize];
     1185
     1186  // check moving+loading
     1187  ContinueUnit:=1 shl nSelectedLoad-1;
     1188  while (ContinueUnit>0) and ((BestLoadLoc<0) or (TurnCount<BestTotalDelay-2)) do
     1189    begin
     1190    for tuix:=0 to nSelectedLoad-1 do if 1 shl tuix and ContinueUnit<>0 then
     1191      begin
     1192      uix:=uixSelectedLoad[tuix];
     1193      MoveStyle:=GetMyMoveStyle(MyUnit[uix].mix, MyUnit[uix].Health);
     1194      NotReachedFlag:=1 shl (2*tuix);
     1195      CompleteFlag:=NotReachedFlag shl 1;
     1196      FullMovementLoc:=-1;
     1197
     1198      Pile.Empty;
     1199      if TurnCount=0 then
    12721200        begin
    1273           uix := uixSelectedLoad[tuix];
    1274           MoveStyle := GetMyMoveStyle(MyUnit[uix].mix, MyUnit[uix].Health);
    1275           NotReachedFlag := 1 shl (2 * tuix);
    1276           CompleteFlag := NotReachedFlag shl 1;
    1277           FullMovementLoc := -1;
    1278 
    1279           Pile.Empty;
    1280           if TurnCount = 0 then
     1201        Pile.Put(MyUnit[uix].Loc, $1800-MyUnit[uix].Movement);
     1202        if MyUnit[uix].Movement=integer(MyModel[MyUnit[uix].mix].Speed) then
     1203          FullMovementLoc:=MyUnit[uix].Loc; // surrounding tiles can be loaded immediately
     1204        StartLocPtr:=ArrivedEnd;
     1205        end
     1206      else StartLocPtr:=@Arrived;
     1207      IsFirstLoc:=true;
     1208
     1209      repeat
     1210        if StartLocPtr<>ArrivedEnd then // search next movement start location for this turn
     1211          StartLocPtr:=NextZero(StartLocPtr, ArrivedEnd, CompleteFlag or NotReachedFlag);
     1212        if StartLocPtr<>ArrivedEnd then
    12811213          begin
    1282             Pile.Put(MyUnit[uix].Loc, $1800 - MyUnit[uix].Movement);
    1283             if MyUnit[uix].Movement = integer(MyModel[MyUnit[uix].mix].Speed)
    1284             then
    1285               FullMovementLoc := MyUnit[uix].Loc;
    1286             // surrounding tiles can be loaded immediately
    1287             StartLocPtr := ArrivedEnd;
     1214          Loc0:=(integer(StartLocPtr)-integer(@Arrived)) shr 2;
     1215          inc(StartLocPtr);
     1216          Time0:=$800
    12881217          end
    1289           else
    1290             StartLocPtr := @Arrived;
    1291           IsFirstLoc := true;
    1292 
    1293           repeat
    1294             if StartLocPtr <> ArrivedEnd then
    1295             // search next movement start location for this turn
    1296               StartLocPtr := NextZero(StartLocPtr, ArrivedEnd, CompleteFlag or
    1297                 NotReachedFlag);
    1298             if StartLocPtr <> ArrivedEnd then
     1218        else if not Pile.Get(Loc0, Time0) then
     1219          begin
     1220          if IsFirstLoc then ContinueUnit:=ContinueUnit and not (1 shl tuix);
     1221          break;
     1222          end;
     1223        IsFirstLoc:=false;
     1224
     1225        Arrived[Loc0]:=Arrived[Loc0] and not NotReachedFlag;
     1226        if not GroupComplete[Loc0] and (Map[Loc0] and fTerrain<>fMountains) then
     1227          begin // check whether group complete -- no mountains because complete flag might be faked there
     1228          i:=1;
     1229          GroupCount:=0;
     1230          for tuix1:=0 to nSelectedLoad-1 do
    12991231            begin
    1300               Loc0 := (integer(StartLocPtr) - integer(@Arrived)) shr 2;
    1301               inc(StartLocPtr);
    1302               Time0 := $800
    1303             end
    1304             else if not Pile.Get(Loc0, Time0) then
    1305             begin
    1306               if IsFirstLoc then
    1307                 ContinueUnit := ContinueUnit and not(1 shl tuix);
    1308               Break;
     1232            if Arrived[Loc0] and i=0 then inc(GroupCount);
     1233            i:=i shl 2;
    13091234            end;
    1310             IsFirstLoc := false;
    1311 
    1312             Arrived[Loc0] := Arrived[Loc0] and not NotReachedFlag;
    1313             if not GroupComplete[Loc0] and (Map[Loc0] and fTerrain <> fMountains)
    1314             then
    1315             begin // check whether group complete -- no mountains because complete flag might be faked there
    1316               i := 1;
    1317               GroupCount := 0;
    1318               for tuix1 := 0 to nSelectedLoad - 1 do
     1235          assert(GroupCount<=TransportCapacity);
     1236          if (GroupCount=TransportCapacity) or (GroupCount=nSelectedLoad) then
     1237            GroupComplete[Loc0]:=true
     1238          end;
     1239
     1240        V8_to_Loc(Loc0, Adjacent);
     1241        IsComplete:=true;
     1242        for V8:=0 to 7 do
     1243          begin
     1244          Loc1:=Adjacent[V8];
     1245          if (Loc1<G.ly) or (Loc1>=MapSize-G.ly) then
     1246            Adjacent[V8]:=-1 // pole, don't consider moving here
     1247          else if Arrived[Loc1] and NotReachedFlag=0 then
     1248            Adjacent[V8]:=-1 // unit has already arrived this tile
     1249          else if GroupComplete[Loc1] then
     1250            Adjacent[V8]:=-1 // already other group complete
     1251          else if Map[Loc1] and fTerrain<fGrass then
     1252            begin // possible transport start location
     1253            Arrived[Loc1]:=(Arrived[Loc1] or CompleteFlag) and not NotReachedFlag;
     1254            Adjacent[V8]:=-1;
     1255            if (TurnsBeforeLoad[Loc1]>=0) and (TurnsAfterLoad[Loc1]>=0) then
    13191256              begin
    1320                 if Arrived[Loc0] and i = 0 then
    1321                   inc(GroupCount);
    1322                 i := i shl 2;
    1323               end;
    1324               assert(GroupCount <= TransportCapacity);
    1325               if (GroupCount = TransportCapacity) or (GroupCount = nSelectedLoad)
    1326               then
    1327                 GroupComplete[Loc0] := true
    1328             end;
    1329 
    1330             V8_to_Loc(Loc0, Adjacent);
    1331             IsComplete := true;
    1332             for V8 := 0 to 7 do
    1333             begin
    1334               Loc1 := Adjacent[V8];
    1335               if (Loc1 < G.ly) or (Loc1 >= MapSize - G.ly) then
    1336                 Adjacent[V8] := -1 // pole, don't consider moving here
    1337               else if Arrived[Loc1] and NotReachedFlag = 0 then
    1338                 Adjacent[V8] := -1 // unit has already arrived this tile
    1339               else if GroupComplete[Loc1] then
    1340                 Adjacent[V8] := -1 // already other group complete
    1341               else if Map[Loc1] and fTerrain < fGrass then
    1342               begin // possible transport start location
    1343                 Arrived[Loc1] := (Arrived[Loc1] or CompleteFlag) and
    1344                   not NotReachedFlag;
    1345                 Adjacent[V8] := -1;
    1346                 if (TurnsBeforeLoad[Loc1] >= 0) and (TurnsAfterLoad[Loc1] >= 0)
    1347                 then
     1257              i:=1;
     1258              GroupCount:=0;
     1259              for tuix1:=0 to nSelectedLoad-1 do
    13481260                begin
    1349                   i := 1;
    1350                   GroupCount := 0;
    1351                   for tuix1 := 0 to nSelectedLoad - 1 do
    1352                   begin
    1353                     if Arrived[Loc1] and i = 0 then
    1354                       inc(GroupCount);
    1355                     i := i shl 2;
    1356                   end;
    1357                   assert(GroupCount <= TransportCapacity);
    1358                   if (GroupCount = TransportCapacity) or
    1359                     (GroupCount = nSelectedLoad) then
    1360                     GroupComplete[Loc1] := true;
    1361                   if TurnsBeforeLoad[Loc1] > TurnCount + 1 then
    1362                     TotalDelay := TurnsBeforeLoad[Loc1] + TurnsAfterLoad[Loc1]
    1363                   else
    1364                     TotalDelay := TurnCount + 1 + TurnsAfterLoad[Loc1];
    1365                   if (BestLoadLoc < 0) or
    1366                     (GroupCount shl 16 - TotalDelay > BestGroupCount shl 16 -
    1367                     BestTotalDelay) then
    1368                   begin
    1369                     BestLoadLoc := Loc1;
    1370                     BestGroupCount := GroupCount;
    1371                     BestTotalDelay := TotalDelay
    1372                   end
     1261                if Arrived[loc1] and i=0 then inc(GroupCount);
     1262                i:=i shl 2;
     1263                end;
     1264              assert(GroupCount<=TransportCapacity);
     1265              if (GroupCount=TransportCapacity) or (GroupCount=nSelectedLoad) then
     1266                GroupComplete[loc1]:=true;
     1267              if TurnsBeforeLoad[Loc1]>TurnCount+1 then
     1268                TotalDelay:=TurnsBeforeLoad[Loc1]+TurnsAfterLoad[Loc1]
     1269              else TotalDelay:=TurnCount+1+TurnsAfterLoad[Loc1];
     1270              if (BestLoadLoc<0)
     1271                or (GroupCount shl 16-TotalDelay
     1272                  >BestGroupCount shl 16-BestTotalDelay) then
     1273                begin
     1274                BestLoadLoc:=Loc1;
     1275                BestGroupCount:=GroupCount;
     1276                BestTotalDelay:=TotalDelay
    13731277                end
    13741278              end
    1375               else if (Map[Loc1] and fTerrain = fMountains) and
    1376                 ((Map[Loc0] and (fRoad or fRR or fCity) = 0) or
    1377                 (Map[Loc1] and (fRoad or fRR or fCity) = 0)) and
    1378                 (Map[Loc0] and Map[Loc1] and (fRiver or fCanal) = 0) then
    1379               begin // mountain delay too complicated for this algorithm
    1380                 Arrived[Loc1] := (Arrived[Loc1] or CompleteFlag) and
    1381                   not NotReachedFlag;
    1382                 Adjacent[V8] := -1;
    1383               end
    1384               else
    1385                 IsComplete := false;
    1386             end;
    1387             if IsComplete then
     1279            end
     1280          else if (Map[Loc1] and fTerrain=fMountains)
     1281            and ((Map[Loc0] and (fRoad or fRR or fCity)=0)
     1282              or (Map[Loc1] and (fRoad or fRR or fCity)=0))
     1283            and (Map[Loc0] and Map[Loc1] and (fRiver or fCanal)=0) then
     1284            begin // mountain delay too complicated for this algorithm
     1285            Arrived[Loc1]:=(Arrived[Loc1] or CompleteFlag) and not NotReachedFlag;
     1286            Adjacent[V8]:=-1;
     1287            end
     1288          else IsComplete:=false;
     1289          end;
     1290        if IsComplete then
     1291          begin
     1292          Arrived[Loc0]:=(Arrived[Loc0] or CompleteFlag) and not NotReachedFlag;
     1293          continue
     1294          end;
     1295        IsComplete:=true;
     1296        for V8:=0 to 7 do
     1297          begin
     1298          Loc1:=Adjacent[V8];
     1299          if Loc1>=0 then
    13881300            begin
    1389               Arrived[Loc0] := (Arrived[Loc0] or CompleteFlag) and
    1390                 not NotReachedFlag;
    1391               continue
    1392             end;
    1393             IsComplete := true;
    1394             for V8 := 0 to 7 do
    1395             begin
    1396               Loc1 := Adjacent[V8];
    1397               if Loc1 >= 0 then
    1398               begin
    1399                 ok := false;
    1400                 case CheckStep(MoveStyle, Time0, V8 and 1, ArriveTime,
    1401                   RecoverTurns, Map[Loc0], Map[Loc1]) of
    1402                   csOk:
    1403                     ok := true;
    1404                   csForbiddenTile:
    1405                     ; // !!! don't check moving there again
    1406                   csCheckTerritory:
    1407                     ok := RO.Territory[Loc1] = RO.Territory[Loc0];
    1408                 end;
    1409                 if ok and Pile.TestPut(Loc1, ArriveTime) then
    1410                   if ArriveTime < $2000 then
    1411                     Pile.Put(Loc1, ArriveTime)
    1412                   else
    1413                     IsComplete := false
    1414               end
    1415             end;
    1416             if IsComplete then
    1417               Arrived[Loc0] := (Arrived[Loc0] or CompleteFlag) and
    1418                 not NotReachedFlag;
    1419           until false;
     1301            ok:=false;
     1302            case CheckStep(MoveStyle, Time0, V8 and 1, ArriveTime, RecoverTurns,
     1303              Map[Loc0], Map[Loc1],false) of
     1304              csOk: ok:=true;
     1305              csForbiddenTile:
     1306                ;// !!! don't check moving there again
     1307              csCheckTerritory:
     1308                ok:= RO.Territory[Loc1]=RO.Territory[Loc0];
     1309              end;
     1310            if ok and Pile.TestPut(Loc1, ArriveTime) then
     1311              if ArriveTime<$2000 then Pile.Put(Loc1, ArriveTime)
     1312              else IsComplete:=false
     1313            end
     1314          end;
     1315        if IsComplete then
     1316          Arrived[Loc0]:=(Arrived[Loc0] or CompleteFlag) and not NotReachedFlag;
     1317      until false;
     1318      end;
     1319
     1320    inc(TurnCount);
     1321    end;
     1322  Pile.Free;
     1323
     1324  if BestLoadLoc>=0 then
     1325    begin
     1326    TransportPlan.LoadLoc:=BestLoadLoc;
     1327    TransportPlan.uixTransport:=ResponsibleTransport[BestLoadLoc];
     1328    TransportAvailable[TransportPlan.uixTransport]:=0;
     1329    TransportPlan.TurnsEmpty:=BestTotalDelay-TurnsAfterLoad[BestLoadLoc];
     1330    TransportPlan.TurnsLoaded:=TurnsAfterLoad[BestLoadLoc];
     1331    TransportPlan.nLoad:=0;
     1332    for tuix:=nSelectedLoad-1 downto 0 do
     1333      if 1 shl (2*tuix) and Arrived[BestLoadLoc]=0 then
     1334        begin
     1335        assert(uixTransportLoad[tuixSelectedLoad[tuix]]=uixSelectedLoad[tuix]);
     1336        TransportPlan.uixLoad[TransportPlan.nLoad]:=uixSelectedLoad[tuix];
     1337        uixTransportLoad[tuixSelectedLoad[tuix]]:=
     1338          uixTransportLoad[nTransportLoad-1];
     1339        dec(nTransportLoad);
     1340        inc(TransportPlan.nLoad)
    14201341        end;
    1421 
    1422       inc(TurnCount);
    1423     end;
    1424     Pile.Free;
    1425 
    1426     if BestLoadLoc >= 0 then
    1427     begin
    1428       TransportPlan.LoadLoc := BestLoadLoc;
    1429       TransportPlan.uixTransport := ResponsibleTransport[BestLoadLoc];
    1430       TransportAvailable[TransportPlan.uixTransport] := 0;
    1431       TransportPlan.TurnsEmpty := BestTotalDelay - TurnsAfterLoad[BestLoadLoc];
    1432       TransportPlan.TurnsLoaded := TurnsAfterLoad[BestLoadLoc];
    1433       TransportPlan.nLoad := 0;
    1434       for tuix := nSelectedLoad - 1 downto 0 do
    1435         if 1 shl (2 * tuix) and Arrived[BestLoadLoc] = 0 then
    1436         begin
    1437           assert(uixTransportLoad[tuixSelectedLoad[tuix]]
    1438             = uixSelectedLoad[tuix]);
    1439           TransportPlan.uixLoad[TransportPlan.nLoad] := uixSelectedLoad[tuix];
    1440           uixTransportLoad[tuixSelectedLoad[tuix]] :=
    1441             uixTransportLoad[nTransportLoad - 1];
    1442           dec(nTransportLoad);
    1443           inc(TransportPlan.nLoad)
    1444         end;
    1445       result := true;
    1446       exit
    1447     end;
    1448 
    1449     // no loading location for a single of these units -- remove all
    1450     // should be pretty rare case
    1451     for tuix := nSelectedLoad - 1 downto 0 do
    1452     begin
    1453       assert(uixTransportLoad[tuixSelectedLoad[tuix]] = uixSelectedLoad[tuix]);
    1454       uixTransportLoad[tuixSelectedLoad[tuix]] := uixTransportLoad
    1455         [nTransportLoad - 1];
    1456       dec(nTransportLoad);
    1457     end;
    1458   end;
    1459   TransportPlan.LoadLoc := -1;
    1460   result := false;
    1461 end;
    1462 
    1463 
    1464 // ------------------------------------------------------------------------------
     1342    result:=true;
     1343    exit
     1344    end;
     1345
     1346  // no loading location for a single of these units -- remove all
     1347  // should be pretty rare case
     1348  for tuix:=nSelectedLoad-1 downto 0 do
     1349    begin
     1350    assert(uixTransportLoad[tuixSelectedLoad[tuix]]=uixSelectedLoad[tuix]);
     1351    uixTransportLoad[tuixSelectedLoad[tuix]]:=
     1352      uixTransportLoad[nTransportLoad-1];
     1353    dec(nTransportLoad);
     1354    end;
     1355  end;
     1356TransportPlan.LoadLoc:=-1;
     1357result:=false;
     1358end;
     1359
     1360
     1361//------------------------------------------------------------------------------
     1362// Misc
     1363
     1364function TToolAI.CurrentMStrength(Domain: integer): integer;
     1365var
     1366i: integer;
     1367begin
     1368result:=0;
     1369for i:=0 to nUpgrade-1 do with upgrade[Domain,i] do
     1370  if (Preq=preNone)
     1371    or (Preq>=0) and ((RO.Tech[Preq]>=tsApplicable)
     1372    or (Preq in FutureTech) and (RO.Tech[Preq]>=0)) then
     1373    begin
     1374    if Preq in FutureTech then
     1375      inc(result,RO.Tech[Preq]*Strength)
     1376    else inc(result,Strength);
     1377    end;
     1378end;
     1379
     1380
     1381//------------------------------------------------------------------------------
    14651382
    14661383procedure SetAdvancedness;
    14671384var
    1468   ad, j, Reduction, AgeThreshold: integer;
    1469   known: array [0 .. nAdv - 1] of integer;
     1385ad,j,Reduction,AgeThreshold: integer;
     1386known: array[0..nAdv-1] of integer;
    14701387  procedure MarkPreqs(ad: integer);
    14711388  var
    1472     i: integer;
    1473   begin
    1474     if known[ad] = 0 then
    1475     begin
    1476       known[ad] := 1;
    1477       for i := 0 to 2 do
    1478         if AdvPreq[ad, i] >= 0 then
    1479           MarkPreqs(AdvPreq[ad, i]);
     1389  i: integer;
     1390  begin
     1391  if known[ad]=0 then
     1392    begin
     1393    known[ad]:=1;
     1394    for i:=0 to 2 do
     1395      if AdvPreq[ad,i]>=0 then MarkPreqs(AdvPreq[ad,i]);
    14801396    end
    14811397  end;
    1482 
    1483 begin
    1484   fillchar(Advancedness, sizeof(Advancedness), 0);
    1485   for ad := 0 to nAdv - 1 do
    1486   begin
    1487     fillchar(known, sizeof(known), 0);
    1488     MarkPreqs(ad);
    1489     for j := 0 to nAdv - 1 do
    1490       if known[j] > 0 then
    1491         inc(Advancedness[ad]);
    1492   end;
    1493   AgeThreshold := Advancedness[adScience];
    1494   Reduction := Advancedness[adScience] div 3;
    1495   for ad := 0 to nAdv - 5 do
    1496     if Advancedness[ad] >= AgeThreshold then
    1497       dec(Advancedness[ad], Reduction);
    1498   AgeThreshold := Advancedness[adMassProduction];
    1499   Reduction := (Advancedness[adMassProduction] - Advancedness[adScience]) div 3;
    1500   for ad := 0 to nAdv - 5 do
    1501     if Advancedness[ad] >= AgeThreshold then
    1502       dec(Advancedness[ad], Reduction)
    1503 end;
     1398begin
     1399FillChar(Advancedness,SizeOf(Advancedness),0);
     1400for ad:=0 to nAdv-1 do
     1401  begin
     1402  FillChar(known,SizeOf(known),0);
     1403  MarkPreqs(ad);
     1404  for j:=0 to nAdv-1 do if known[j]>0 then inc(Advancedness[ad]);
     1405  end;
     1406AgeThreshold:=Advancedness[adScience];
     1407Reduction:=Advancedness[adScience] div 3;
     1408for ad:=0 to nAdv-5 do
     1409  if Advancedness[ad]>=AgeThreshold then
     1410    dec(Advancedness[ad], Reduction);
     1411AgeThreshold:=Advancedness[adMassProduction];
     1412Reduction:=(Advancedness[adMassProduction]-Advancedness[adScience]) div 3;
     1413for ad:=0 to nAdv-5 do
     1414  if Advancedness[ad]>=AgeThreshold then
     1415    dec(Advancedness[ad], Reduction)
     1416end;
     1417
    15041418
    15051419initialization
    1506 
    15071420SetAdvancedness;
    15081421
    15091422end.
     1423
Note: See TracChangeset for help on using the changeset viewer.