Ignore:
Timestamp:
Mar 9, 2021, 9:19:49 AM (4 years ago)
Author:
chronos
Message:
  • Modified: Synced code with current trunk version.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/highdpi/AI/StdAI/Barbarina.pas

    r210 r303  
    77{$IFDEF DEBUG}SysUtils,{$ENDIF} // necessary for debug exceptions
    88{$IFDEF DEBUG}Names,{$ENDIF}
    9 Protocol, ToolAI, CustomAI;
    10 
     9  Protocol, ToolAI, CustomAI;
    1110
    1211const
    13 nModelCategory=4;
    14 ctGroundSlow=0; ctGroundFast=1; ctSeaTrans=2; ctSeaArt=3;
    15 
    16 maxCOD=256;
    17 
    18 maxModern=16;
    19   // maximum number of modern resources of one type being managed
    20   // (for designed maps only, number is 2 in standard game)
     12  nModelCategory = 4;
     13  ctGroundSlow = 0;
     14  ctGroundFast = 1;
     15  ctSeaTrans = 2;
     16  ctSeaArt = 3;
     17
     18  maxCOD = 256;
     19
     20  maxModern = 16;
     21// maximum number of modern resources of one type being managed
     22// (for designed maps only, number is 2 in standard game)
    2123
    2224
    2325type
    24 TColonyShipPlan = array[0..nShipPart-1] of record
    25   cixProducing: integer;
    26   LocResource: array[0..maxModern-1] of integer;
    27   nLocResource: integer;
    28   LocFoundCity: array[0..maxModern-1] of integer;
    29   nLocFoundCity: integer;
     26  TColonyShipPlan = array[0..nShipPart - 1] of record
     27    cixProducing: integer;
     28    LocResource: array[0..maxModern - 1] of integer;
     29    nLocResource: integer;
     30    LocFoundCity: array[0..maxModern - 1] of integer;
     31    nLocFoundCity: integer;
    3032  end;
    3133
    32 TBarbarina = class(TToolAI)
    33   constructor Create(Nation: integer); override;
    34 
    35 protected
    36   ColonyShipPlan: TColonyShipPlan;
    37   function Barbarina_GoHidden: boolean; // whether we should prepare for barbarina mode
    38   function Barbarina_Go: boolean; // whether we should switch to barbarina mode now
    39   procedure Barbarina_DoTurn;
    40   procedure Barbarina_SetCityProduction;
    41   function Barbarina_ChooseResearchAdvance: integer;
    42   function Barbarina_WantCheckNegotiation(Nation: integer): boolean;
    43   procedure Barbarina_DoCheckNegotiation;
    44   function Barbarina_WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean;
    45   procedure Barbarina_DoNegotiation;
    46   procedure MakeColonyShipPlan;
    47 
    48 private
    49   TurnOfMapAnalysis, Neighbours: integer;
    50   ContinentPresence: array[0..maxCOD-1] of integer;
    51   OceanPresence: array[0..maxCOD-1] of integer;
    52   ContinentSize: array[0..maxCOD-1] of integer;
    53   OceanSize: array[0..maxCOD-1] of integer;
    54   mixBest: array[0..nModelCategory-1] of integer;
    55   NegoCause: (CancelTreaty);
    56   function IsModelAvailable(rmix: integer): boolean;
    57   procedure FindBestModels;
    58   procedure AnalyzeMap;
    59   procedure RateAttack(uix: integer);
    60   function DoAttack(uix,AttackLoc: integer): boolean;
    61   function ProcessMove(uix: integer): boolean;
    62   procedure AttackAndPatrol;
     34  TBarbarina = class(TToolAI)
     35    constructor Create(Nation: integer); override;
     36
     37  protected
     38    ColonyShipPlan: TColonyShipPlan;
     39    function Barbarina_GoHidden: boolean; // whether we should prepare for barbarina mode
     40    function Barbarina_Go: boolean; // whether we should switch to barbarina mode now
     41    procedure Barbarina_DoTurn;
     42    procedure Barbarina_SetCityProduction;
     43    function Barbarina_ChooseResearchAdvance: integer;
     44    function Barbarina_WantCheckNegotiation(Nation: integer): boolean;
     45    procedure Barbarina_DoCheckNegotiation;
     46    function Barbarina_WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean;
     47    procedure Barbarina_DoNegotiation;
     48    procedure MakeColonyShipPlan;
     49
     50  private
     51    TurnOfMapAnalysis, Neighbours: integer;
     52    ContinentPresence: array[0..maxCOD - 1] of integer;
     53    OceanPresence: array[0..maxCOD - 1] of integer;
     54    ContinentSize: array[0..maxCOD - 1] of integer;
     55    OceanSize: array[0..maxCOD - 1] of integer;
     56    mixBest: array[0..nModelCategory - 1] of integer;
     57    NegoCause: (CancelTreaty);
     58    function IsModelAvailable(rmix: integer): boolean;
     59    procedure FindBestModels;
     60    procedure AnalyzeMap;
     61    procedure RateAttack(uix: integer);
     62    function DoAttack(uix, AttackLoc: integer): boolean;
     63    function ProcessMove(uix: integer): boolean;
     64    procedure AttackAndPatrol;
    6365  end;
    6466
     
    6769
    6870uses
    69 Pile;
     71  Pile;
    7072
    7173type
    72 TResearchModel=record
    73   Category,Domain,Weight,adStop,FutMStrength: integer;
    74   Upgrades: cardinal;
    75   Cap: array [0..nFeature-1] of integer;
     74  TResearchModel = record
     75    Category, Domain, Weight, adStop, FutMStrength: integer;
     76    Upgrades: cardinal;
     77    Cap: array [0..nFeature - 1] of integer;
    7678  end;
    7779
    7880const
    79 //UnitKind
    80 ukSlow=$01; ukFast=$02;
    81 
    82 neumax=4096;
    83 mixTownGuard=2;
    84 
    85 PresenceUnknown=$10000;
    86 
    87 WonderProductionThreshold=15;
    88 WonderInclination=24.0; // higher value means lower probability of building wonder
    89 ReduceDefense=16; // if this is x, 1/x of all units is used to defend cities
    90 
    91 nResearchOrder=40;
    92 ResearchOrder: array[0..nResearchOrder-1] of integer=
    93 (adBronzeWorking,-adMapMaking,adChivalry,adMonotheism,adIronWorking,
    94 adGunPowder,adTheology,adConstruction,adCodeOfLaws,-adEngineering,-adSeafaring,
    95 -adNavigation,adMetallurgy,adBallistics,adScience,adExplosives,
    96 adTactics,adSteel,-adSteamEngine,-adAmphibiousWarfare,-adMagnetism,adRadio,
    97 adAutomobile,adMobileWarfare,adRailroad,adCommunism,adDemocracy,
    98 adTheCorporation,adMassProduction,adIndustrialization,adRobotics,adComposites,
    99 adTheLaser,adFlight,adAdvancedFlight,adSpaceFlight,
    100 adSyntheticFood,adTransstellarColonization,adElectronics,adSmartWeapons);
    101 
    102 nResearchModel=16;
    103 ResearchModel: array[0..nResearchModel-1] of TResearchModel=
    104 //       Wea Arm Mob Sea Car Tur Bom Fue Air Nav Rad Sub Art Alp Sup Ove Air Spy SE  NP  Jet Ste Fan Fir Wil Aca Lin
    105 ((Category:ctGroundSlow; Domain:dGround;Weight: 7;adStop:adIronWorking;Upgrades:$0003;
    106     Cap:(  3,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    107  (Category:ctGroundFast; Domain:dGround;Weight: 7;adStop:adIronWorking;Upgrades:$0003;
    108     Cap:(  3,  1,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    109  (Category:ctGroundSlow; Domain:dGround;Weight: 7;adStop:adExplosives;Upgrades:$003F;
    110     Cap:(  3,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    111  (Category:ctGroundFast; Domain:dGround;Weight: 7;adStop:adExplosives;Upgrades:$003F;
    112     Cap:(  3,  1,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    113  (Category:ctSeaTrans;   Domain:dSea;   Weight: 7;adStop:adExplosives;Upgrades:$000F;
    114     Cap:(  0,  3,  0,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    115  (Category:ctSeaArt;     Domain:dSea;   Weight: 7;adStop:adExplosives;Upgrades:$000F;
    116     Cap:(  4,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    117  (Category:ctGroundSlow; Domain:dGround;Weight: 7;adStop:adAutomobile;Upgrades:$00FF;
    118     Cap:(  1,  3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    119  (Category:ctGroundFast; Domain:dGround;Weight: 7;adStop:adAutomobile;Upgrades:$00FF;
    120     Cap:(  3,  1,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    121  (Category:ctSeaTrans;   Domain:dSea;   Weight: 9;adStop:-1;Upgrades:$00FF;
    122     Cap:(  0,  4,  0,  2,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    123  (Category:ctSeaArt;     Domain:dSea;   Weight: 9;adStop:-1;Upgrades:$00FF;
    124     Cap:(  5,  3,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    125  (Category:ctGroundSlow; Domain:dGround;Weight: 10;adStop:adCommunism;Upgrades:$05FF;
    126     Cap:(  3,  3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    127  (Category:ctGroundFast; Domain:dGround;Weight: 10;adStop:adCommunism;Upgrades:$05FF;
    128     Cap:(  5,  1,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0)),
    129  (Category:ctGroundSlow; Domain:dGround;Weight: 10;adStop:adComposites;Upgrades:$07FF;
    130     Cap:(  3,  3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1)),
    131  (Category:ctGroundFast; Domain:dGround;Weight: 10;adStop:adComposites;Upgrades:$07FF;
    132     Cap:(  5,  1,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1)),
    133  (Category:ctGroundSlow; Domain:dGround;Weight: 10;adStop:-1;Upgrades:$3FFF;
    134     Cap:(  3,  3,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1)),
    135  (Category:ctGroundFast; Domain:dGround;Weight: 10;adStop:-1;Upgrades:$3FFF;
    136     Cap:(  5,  1,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1)));
    137 EntryModel_Base=1;
    138 EntryModel_GunPowder=3;
    139 EntryModel_MassProduction=13;
     81  //UnitKind
     82  ukSlow = $01;
     83  ukFast = $02;
     84
     85  neumax = 4096;
     86  mixTownGuard = 2;
     87
     88  PresenceUnknown = $10000;
     89
     90  WonderProductionThreshold = 15;
     91  WonderInclination = 24.0; // higher value means lower probability of building wonder
     92  ReduceDefense = 16; // if this is x, 1/x of all units is used to defend cities
     93
     94  nResearchOrder = 40;
     95  ResearchOrder: array[0..nResearchOrder - 1] of integer =
     96    (adBronzeWorking, -adMapMaking, adChivalry, adMonotheism, adIronWorking,
     97    adGunPowder, adTheology, adConstruction, adCodeOfLaws, -adEngineering,
     98    -adSeafaring, -adNavigation, adMetallurgy, adBallistics, adScience, adExplosives,
     99    adTactics, adSteel, -adSteamEngine, -adAmphibiousWarfare, -adMagnetism, adRadio,
     100    adAutomobile, adMobileWarfare, adRailroad, adCommunism, adDemocracy,
     101    adTheCorporation, adMassProduction, adIndustrialization, adRobotics, adComposites,
     102    adTheLaser, adFlight, adAdvancedFlight, adSpaceFlight,
     103    adSyntheticFood, adTransstellarColonization, adElectronics, adSmartWeapons);
     104
     105  nResearchModel = 16;
     106  ResearchModel: array[0..nResearchModel - 1] of TResearchModel =
     107    //       Wea Arm Mob Sea Car Tur Bom Fue Air Nav Rad Sub Art Alp Sup Ove Air Spy SE  NP  Jet Ste Fan Fir Wil Aca Lin
     108    ((Category: ctGroundSlow; Domain: dGround; Weight: 7; adStop: adIronWorking;
     109    Upgrades: $0003;
     110    Cap: (3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     111    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     112    (Category: ctGroundFast; Domain: dGround; Weight: 7; adStop: adIronWorking;
     113    Upgrades: $0003;
     114    Cap: (3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     115    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     116    (Category: ctGroundSlow; Domain: dGround; Weight: 7; adStop: adExplosives;
     117    Upgrades: $003F;
     118    Cap: (3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     119    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     120    (Category: ctGroundFast; Domain: dGround; Weight: 7; adStop: adExplosives;
     121    Upgrades: $003F;
     122    Cap: (3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     123    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     124    (Category: ctSeaTrans; Domain: dSea; Weight: 7; adStop: adExplosives;
     125    Upgrades: $000F;
     126    Cap: (0, 3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     127    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     128    (Category: ctSeaArt; Domain: dSea; Weight: 7; adStop: adExplosives; Upgrades: $000F;
     129    Cap: (4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
     130    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     131    (Category: ctGroundSlow; Domain: dGround; Weight: 7; adStop: adAutomobile;
     132    Upgrades: $00FF;
     133    Cap: (1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     134    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     135    (Category: ctGroundFast; Domain: dGround; Weight: 7; adStop: adAutomobile;
     136    Upgrades: $00FF;
     137    Cap: (3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     138    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     139    (Category: ctSeaTrans; Domain: dSea; Weight: 9; adStop: -1; Upgrades: $00FF;
     140    Cap: (0, 4, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
     141    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     142    (Category: ctSeaArt; Domain: dSea; Weight: 9; adStop: -1; Upgrades: $00FF;
     143    Cap: (5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,
     144    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     145    (Category: ctGroundSlow; Domain: dGround; Weight: 10; adStop: adCommunism;
     146    Upgrades: $05FF;
     147    Cap: (3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
     148    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     149    (Category: ctGroundFast; Domain: dGround; Weight: 10; adStop: adCommunism;
     150    Upgrades: $05FF;
     151    Cap: (5, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
     152    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)),
     153    (Category: ctGroundSlow; Domain: dGround; Weight: 10; adStop: adComposites;
     154    Upgrades: $07FF;
     155    Cap: (3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
     156    0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1)),
     157    (Category: ctGroundFast; Domain: dGround; Weight: 10; adStop: adComposites;
     158    Upgrades: $07FF;
     159    Cap: (5, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
     160    0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1)),
     161    (Category: ctGroundSlow; Domain: dGround; Weight: 10; adStop: -1; Upgrades: $3FFF;
     162    Cap: (3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
     163    0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1)),
     164    (Category: ctGroundFast; Domain: dGround; Weight: 10; adStop: -1; Upgrades: $3FFF;
     165    Cap: (5, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
     166    0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1)));
     167  EntryModel_Base = 1;
     168  EntryModel_GunPowder = 3;
     169  EntryModel_MassProduction = 13;
    140170
    141171
    142172var
    143 Moved: array[0..numax-1] of boolean;
    144 UnitPresence: array[0..lxmax*lymax-1] of byte;
    145 euixMap: array[0..lxmax*lymax-1] of smallint;
    146 uixAttack: array[0..neumax-1] of smallint;
    147 AttackScore: array[0..neumax-1] of integer;
     173  Moved: array[0..numax - 1] of boolean;
     174  UnitPresence: array[0..lxmax * lymax - 1] of byte;
     175  euixMap: array[0..lxmax * lymax - 1] of smallint;
     176  uixAttack: array[0..neumax - 1] of smallint;
     177  AttackScore: array[0..neumax - 1] of integer;
    148178
    149179constructor TBarbarina.Create(Nation: integer);
    150180begin
    151 inherited;
    152 TurnOfMapAnalysis:=-1;
     181  inherited;
     182  TurnOfMapAnalysis := -1;
    153183end;
    154184
     
    156186function TBarbarina.IsModelAvailable(rmix: integer): boolean;
    157187var
    158 i,mix,MStrength: integer;
     188  i, mix, MStrength: integer;
    159189begin
    160 result:=false;
    161 with ResearchModel[rmix] do
     190  Result := False;
     191  with ResearchModel[rmix] do
    162192  begin
    163   MStrength:=CurrentMStrength(Domain);
    164   for mix:=3 to RO.nModel-1 do
    165     if ((MyModel[mix].kind=mkSelfDeveloped) or (MyModel[mix].kind=mkEnemyDeveloped))
    166       and (MyModel[mix].Domain=Domain)
    167       and (Upgrades and not MyModel[mix].Upgrades=0) then
    168       begin
    169       result:= MStrength<(MyModel[mix].MStrength*3) div 2; // for future techs: don't count model available if 50% stronger possible
    170       for i:=0 to nFeature-1 do if MyModel[mix].Cap[i]<Cap[i] then
    171         begin result:=false; break end;
    172       if result then break;
    173       end;
    174   end
     193    MStrength := CurrentMStrength(Domain);
     194    for mix := 3 to RO.nModel - 1 do
     195      if ((MyModel[mix].kind = mkSelfDeveloped) or
     196        (MyModel[mix].kind = mkEnemyDeveloped)) and (MyModel[mix].Domain = Domain) and
     197        (Upgrades and not MyModel[mix].Upgrades = 0) then
     198      begin
     199        Result := MStrength < (MyModel[mix].MStrength * 3) div 2;
     200        // for future techs: don't count model available if 50% stronger possible
     201        for i := 0 to nFeature - 1 do
     202          if MyModel[mix].Cap[i] < Cap[i] then
     203          begin
     204            Result := False;
     205            break;
     206          end;
     207        if Result then
     208          break;
     209      end;
     210  end;
    175211end;
    176212
    177213function TBarbarina.Barbarina_GoHidden: boolean;
    178214var
    179 V21,Loc1,cix: integer;
    180 Radius: TVicinity21Loc;
     215  V21, Loc1, cix: integer;
     216  Radius: TVicinity21Loc;
    181217begin
    182 if IsResearched(adMassProduction) then
     218  if IsResearched(adMassProduction) then
    183219  begin
    184   result:=true;
    185   for cix:=0 to RO.nCity-1 do with MyCity[cix] do if Loc>=0 then
    186     begin // search for modern resource
    187     V21_to_Loc(Loc, Radius);
    188     for V21:=1 to 26 do
    189       begin
    190       Loc1:=Radius[V21];
    191       if (Loc1>=0) and (RO.Map[Loc1] and fModern<>0) then
    192         result:=false;
    193       end
    194     end
     220    Result := True;
     221    for cix := 0 to RO.nCity - 1 do
     222      with MyCity[cix] do
     223        if Loc >= 0 then
     224        begin // search for modern resource
     225          V21_to_Loc(Loc, Radius);
     226          for V21 := 1 to 26 do
     227          begin
     228            Loc1 := Radius[V21];
     229            if (Loc1 >= 0) and (RO.Map[Loc1] and fModern <> 0) then
     230              Result := False;
     231          end;
     232        end;
    195233  end
    196 else if IsResearched(adGunPowder) then
    197   result:=(RO.Tech[adTheRepublic]<tsSeen) and IsResearched(adTheology)
    198 else result:=false;
     234  else if IsResearched(adGunPowder) then
     235    Result := (RO.Tech[adTheRepublic] < tsSeen) and IsResearched(adTheology)
     236  else
     237    Result := False;
    199238end;
    200239
    201240function TBarbarina.Barbarina_Go: boolean;
    202241begin
    203 if IsResearched(adMassProduction) then
    204   result:= IsResearched(adTheology)
    205     and IsModelAvailable(EntryModel_MassProduction)
    206 else if IsResearched(adGunPowder) then
    207   result:= IsResearched(adTheology) and IsResearched(adMapMaking)
    208     and IsModelAvailable(EntryModel_GunPowder)
    209 else
     242  if IsResearched(adMassProduction) then
     243    Result := IsResearched(adTheology) and IsModelAvailable(EntryModel_MassProduction)
     244  else if IsResearched(adGunPowder) then
     245    Result := IsResearched(adTheology) and IsResearched(adMapMaking) and
     246      IsModelAvailable(EntryModel_GunPowder)
     247  else
    210248  begin
    211   result:=(RO.nCity>=3) and IsResearched(adMapMaking)
    212     and IsModelAvailable(EntryModel_Base);
    213   exit
    214   end; 
    215 result:=result and ((RO.nUn>=RO.nCity*3) or (RO.Wonder[woZeus].EffectiveOwner=me));
     249    Result := (RO.nCity >= 3) and IsResearched(adMapMaking) and
     250      IsModelAvailable(EntryModel_Base);
     251    exit;
     252  end;
     253  Result := Result and ((RO.nUn >= RO.nCity * 3) or
     254    (RO.Wonder[woZeus].EffectiveOwner = me));
    216255end;
    217256
    218257procedure TBarbarina.AnalyzeMap;
    219258var
    220 Loc,Loc1,V8,f1,p1,cix: integer;
    221 Adjacent: TVicinity8Loc;
     259  Loc, Loc1, V8, f1, p1, cix: integer;
     260  Adjacent: TVicinity8Loc;
    222261begin
    223 if TurnOfMapAnalysis=RO.Turn then exit;
    224 
    225 // inherited AnalyzeMap;
    226 
    227 // collect nation presence information for continents and oceans
    228 fillchar(ContinentPresence, sizeof(ContinentPresence), 0);
    229 fillchar(OceanPresence, sizeof(OceanPresence), 0);
    230 fillchar(ContinentSize, sizeof(ContinentSize), 0);
    231 fillchar(OceanSize, sizeof(OceanSize), 0);
    232 for Loc:=0 to MapSize-1 do
     262  if TurnOfMapAnalysis = RO.Turn then
     263    exit;
     264
     265  // inherited;
     266
     267  // collect nation presence information for continents and oceans
     268  fillchar(ContinentPresence, sizeof(ContinentPresence), 0);
     269  fillchar(OceanPresence, sizeof(OceanPresence), 0);
     270  fillchar(ContinentSize, sizeof(ContinentSize), 0);
     271  fillchar(OceanSize, sizeof(OceanSize), 0);
     272  for Loc := 0 to MapSize - 1 do
    233273  begin
    234   f1:=Formation[Loc];
    235   case f1 of
    236     0..maxCOD-1:
    237       begin
    238       p1:=RO.Territory[Loc];
    239       if p1>=0 then
    240         if Map[Loc] and fTerrain>=fGrass then
    241           begin
    242           inc(ContinentSize[f1]);
    243           ContinentPresence[f1]:=ContinentPresence[f1] or (1 shl p1)
     274    f1 := Formation[Loc];
     275    case f1 of
     276      0..maxCOD - 1:
     277      begin
     278        p1 := RO.Territory[Loc];
     279        if p1 >= 0 then
     280          if Map[Loc] and fTerrain >= fGrass then
     281          begin
     282            Inc(ContinentSize[f1]);
     283            ContinentPresence[f1] := ContinentPresence[f1] or (1 shl p1);
    244284          end
    245         else
    246           begin
    247           inc(OceanSize[f1]);
    248           OceanPresence[f1]:=OceanPresence[f1] or (1 shl p1);
    249           end
    250       end;
    251     nfUndiscovered:
     285          else
     286          begin
     287            Inc(OceanSize[f1]);
     288            OceanPresence[f1] := OceanPresence[f1] or (1 shl p1);
     289          end;
     290      end;
     291      nfUndiscovered:
    252292      begin // adjacent formations are not completely discovered
    253       V8_to_Loc(Loc,Adjacent);
    254       for V8:=0 to 7 do
    255         begin
    256         Loc1:=Adjacent[V8];
    257         if Loc1>=0 then
    258           begin
    259           f1:=Formation[Loc1];
    260           if (f1>=0) and (f1<maxCOD) then
    261             if Map[Loc1] and fTerrain>=fGrass then
    262               ContinentPresence[f1]:=ContinentPresence[f1] or PresenceUnknown
    263             else OceanPresence[f1]:=OceanPresence[f1] or PresenceUnknown
    264           end
    265         end
    266       end;
    267     nfPeace:
     293        V8_to_Loc(Loc, Adjacent);
     294        for V8 := 0 to 7 do
     295        begin
     296          Loc1 := Adjacent[V8];
     297          if Loc1 >= 0 then
     298          begin
     299            f1 := Formation[Loc1];
     300            if (f1 >= 0) and (f1 < maxCOD) then
     301              if Map[Loc1] and fTerrain >= fGrass then
     302                ContinentPresence[f1] := ContinentPresence[f1] or PresenceUnknown
     303              else
     304                OceanPresence[f1] := OceanPresence[f1] or PresenceUnknown;
     305          end;
     306        end;
     307      end;
     308      nfPeace:
    268309      begin // nation present in adjacent formations
    269       V8_to_Loc(Loc,Adjacent);
    270       for V8:=0 to 7 do
    271         begin
    272         Loc1:=Adjacent[V8];
    273         if Loc1>=0 then
    274           begin
    275           f1:=Formation[Loc1];
    276           if (f1>=0) and (f1<maxCOD) then
    277             if Map[Loc1] and fTerrain>=fGrass then
    278               ContinentPresence[f1]:=ContinentPresence[f1]
    279                 or (1 shl RO.Territory[Loc])
    280             else OceanPresence[f1]:=OceanPresence[f1]
    281               or (1 shl RO.Territory[Loc])
    282           end
    283         end
     310        V8_to_Loc(Loc, Adjacent);
     311        for V8 := 0 to 7 do
     312        begin
     313          Loc1 := Adjacent[V8];
     314          if Loc1 >= 0 then
     315          begin
     316            f1 := Formation[Loc1];
     317            if (f1 >= 0) and (f1 < maxCOD) then
     318              if Map[Loc1] and fTerrain >= fGrass then
     319                ContinentPresence[f1] :=
     320                  ContinentPresence[f1] or (1 shl RO.Territory[Loc])
     321              else
     322                OceanPresence[f1] := OceanPresence[f1] or (1 shl RO.Territory[Loc]);
     323          end;
     324        end;
    284325      end;
    285326    end;
    286327  end;
    287328
    288 Neighbours:=0;
    289 for cix:=0 to RO.nCity-1 do with MyCity[cix] do
    290   if (Loc>=0) and (Formation[Loc]>=0) and (Formation[Loc]<maxCOD) then
    291     Neighbours:=Neighbours or ContinentPresence[Formation[Loc]];
    292 Neighbours:= Neighbours and not PresenceUnknown;
    293 
    294 TurnOfMapAnalysis:=RO.Turn;
     329  Neighbours := 0;
     330  for cix := 0 to RO.nCity - 1 do
     331    with MyCity[cix] do
     332      if (Loc >= 0) and (Formation[Loc] >= 0) and (Formation[Loc] < maxCOD) then
     333        Neighbours := Neighbours or ContinentPresence[Formation[Loc]];
     334  Neighbours := Neighbours and not PresenceUnknown;
     335
     336  TurnOfMapAnalysis := RO.Turn;
    295337end;
    296338
    297339procedure TBarbarina.FindBestModels;
    298340var
    299 i,mix,rmix,cat: integer;
     341  i, mix, rmix, cat: integer;
    300342begin
    301 for i:=0 to nModelCategory-1 do mixBest[i]:=-1;
    302 for rmix:=nResearchModel-1 downto 0 do with ResearchModel[rmix] do
    303   if mixBest[Category]<0 then
    304       for mix:=3 to RO.nModel-1 do
    305         if (MyModel[mix].Domain=Domain)
    306           and (Upgrades and not MyModel[mix].Upgrades=0) then
    307           begin
    308           mixBest[Category]:=mix;
    309           for i:=0 to nFeature-1 do if MyModel[mix].Cap[i]<Cap[i] then
    310             begin mixBest[Category]:=-1; break end;
    311           if mixBest[Category]>=0 then break;
    312           end;
    313 for mix:=3 to RO.nModel-1 do with MyModel[mix] do if Kind<=mkEnemyDeveloped then
    314   begin
    315   cat:=-1;
    316   case Domain of
    317     dGround:
    318       if Speed>=250 then cat:=ctGroundFast
    319       else cat:=ctGroundSlow;
    320     dSea:
    321       if Cap[mcSeaTrans]>0 then cat:=ctSeaTrans
    322       else if Cap[mcArtillery]>0 then cat:=ctSeaArt;
    323     end;
    324   if (cat>=0) and (mix<>mixBest[cat])
    325     and ((mixBest[cat]<0) or (Weight*MStrength
    326     >MyModel[mixBest[cat]].Weight+MyModel[mixBest[cat]].MStrength)) then
    327     mixBest[cat]:=mix;
    328   end;
    329 if (mixBest[ctSeaTrans]<0) and not IsResearched(adExplosives) then // longboat?
    330   for mix:=3 to RO.nModel-1 do if MyModel[mix].Cap[mcSeaTrans]>0 then
    331     begin mixBest[ctSeaTrans]:=mix; break end;
     343  for i := 0 to nModelCategory - 1 do
     344    mixBest[i] := -1;
     345  for rmix := nResearchModel - 1 downto 0 do
     346    with ResearchModel[rmix] do
     347      if mixBest[Category] < 0 then
     348        for mix := 3 to RO.nModel - 1 do
     349          if (MyModel[mix].Domain = Domain) and
     350            (Upgrades and not MyModel[mix].Upgrades = 0) then
     351          begin
     352            mixBest[Category] := mix;
     353            for i := 0 to nFeature - 1 do
     354              if MyModel[mix].Cap[i] < Cap[i] then
     355              begin
     356                mixBest[Category] := -1;
     357                break;
     358              end;
     359            if mixBest[Category] >= 0 then
     360              break;
     361          end;
     362  for mix := 3 to RO.nModel - 1 do
     363    with MyModel[mix] do
     364      if Kind <= mkEnemyDeveloped then
     365      begin
     366        cat := -1;
     367        case Domain of
     368          dGround:
     369            if Speed >= 250 then
     370              cat := ctGroundFast
     371            else
     372              cat := ctGroundSlow;
     373          dSea:
     374            if Cap[mcSeaTrans] > 0 then
     375              cat := ctSeaTrans
     376            else if Cap[mcArtillery] > 0 then
     377              cat := ctSeaArt;
     378        end;
     379        if (cat >= 0) and (mix <> mixBest[cat]) and
     380          ((mixBest[cat] < 0) or (Weight * MStrength > MyModel[mixBest[cat]].Weight +
     381          MyModel[mixBest[cat]].MStrength)) then
     382          mixBest[cat] := mix;
     383      end;
     384  if (mixBest[ctSeaTrans] < 0) and not IsResearched(adExplosives) then // longboat?
     385    for mix := 3 to RO.nModel - 1 do
     386      if MyModel[mix].Cap[mcSeaTrans] > 0 then
     387      begin
     388        mixBest[ctSeaTrans] := mix;
     389        break;
     390      end;
    332391end;
    333392
    334393procedure TBarbarina.Barbarina_DoTurn;
    335394begin
    336 if (RO.Government in [gRepublic,gDemocracy,gFuture])
    337   or (RO.Government<>gFundamentalism) and (RO.Government<>gAnarchy)
    338   and IsResearched(adTheology) then
    339   Revolution;
    340 
    341 AnalyzeMap;
    342 
    343 FindBestModels;
    344 
    345 AttackAndPatrol;
     395  if (RO.Government in [gRepublic, gDemocracy, gFuture]) or
     396    (RO.Government <> gFundamentalism) and (RO.Government <> gAnarchy) and
     397    IsResearched(adTheology) then
     398    Revolution;
     399
     400  AnalyzeMap;
     401
     402  FindBestModels;
     403
     404  AttackAndPatrol;
    346405end;
    347406
     
    349408procedure TBarbarina.RateAttack(uix: integer);
    350409var
    351 MoveStyle,TestLoc,TestTime,NextLoc,NextTime,V8,RemHealth,RecoverTurns,
    352   Score,BestScore,euixBest,uixOld: integer;
    353 NextTile: cardinal;
    354 Adjacent: TVicinity8Loc;
    355 Defense: ^TUnitInfo;
    356 Reached: array[0..lxmax*lymax-1] of boolean;
     410  MoveStyle, TestLoc, TestTime, NextLoc, NextTime, V8, RemHealth,
     411  RecoverTurns, Score, BestScore, euixBest, uixOld: integer;
     412  NextTile: cardinal;
     413  Adjacent: TVicinity8Loc;
     414  Defense: ^TUnitInfo;
     415  Reached: array[0..lxmax * lymax - 1] of boolean;
    357416begin
    358 with MyUnit[uix] do if Movement>0 then
     417  with MyUnit[uix] do
     418    if Movement > 0 then
     419    begin
     420      BestScore := 0;
     421      fillchar(Reached, MapSize, False);
     422      MoveStyle := GetMyMoveStyle(mix, Health);
     423      Pile.Create(MapSize);
     424      Pile.Put(Loc, $800 - Movement);
     425      while Pile.Get(TestLoc, TestTime) do
     426      begin
     427        Reached[TestLoc] := True;
     428        V8_to_Loc(TestLoc, Adjacent);
     429        for V8 := 0 to 7 do
     430        begin
     431          NextLoc := Adjacent[V8];
     432          if (NextLoc >= 0) and not Reached[NextLoc] then
     433          begin
     434            NextTile := Map[NextLoc];
     435            if euixMap[NextLoc] >= 0 then
     436            begin // check attack
     437              Defense := @RO.EnemyUn[euixMap[NextLoc]];
     438              if Unit_AttackForecast(uix, NextLoc, $800 - TestTime, RemHealth) then
     439              begin
     440                if RemHealth <= 0 then // send unit into death?
     441                begin
     442                  Score := 0;
     443                  if ($800 - TestTime >= 100) and
     444                    ((MyModel[mix].Domain = dGround) and
     445                    (NextTile and fTerrain >= fGrass) or
     446                    (MyModel[mix].Domain = dSea) and (NextTile and
     447                    fTerrain < fGrass)) and
     448                    (MyModel[mix].Attack > MyModel[mix].Defense) then
     449                  begin
     450                    Score := (Defense.Health + RemHealth) *
     451                      RO.EnemyModel[Defense.emix].Cost * 2 div MyModel[mix].Cost;
     452                    if NextTile and fCity <> 0 then
     453                      Score := Score * 4;
     454                  end;
     455                end
     456                else
     457                  Score := RO.EnemyModel[Defense.emix].Cost * 25 -
     458                    (Health - RemHealth) * MyModel[mix].Cost shr 4;
     459                if (Score > BestScore) and (Score > AttackScore[euixMap[NextLoc]]) then
     460                begin
     461                  BestScore := Score;
     462                  euixBest := euixMap[NextLoc];
     463                end;
     464              end;
     465            end
     466            else if (NextTile and (fUnit or fCity) = 0) or
     467              (NextTile and fOwned <> 0) then
     468              case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime,
     469                  RecoverTurns, Map[TestLoc], NextTile, True) of
     470                csOk:
     471                  if NextTime < $800 then
     472                    Pile.Put(NextLoc, NextTime);
     473                csForbiddenTile:
     474                  Reached[NextLoc] := True; // don't check moving there again
     475                csCheckTerritory:
     476                  if (NextTime < $800) and (RO.Territory[NextLoc] =
     477                    RO.Territory[TestLoc]) then
     478                    Pile.Put(NextLoc, NextTime);
     479              end;
     480          end;
     481        end;
     482      end;
     483      Pile.Free;
     484
     485      if BestScore > 0 then
     486      begin
     487        uixOld := uixAttack[euixBest];
     488        AttackScore[euixBest] := BestScore;
     489        uixAttack[euixBest] := uix;
     490        if uixOld >= 0 then
     491          RateAttack(uixOld);
     492      end;
     493    end;
     494end;
     495
     496function TBarbarina.DoAttack(uix, AttackLoc: integer): boolean;
     497  // AttackLoc=maNextCity means bombard only
     498var
     499  MoveResult, Kind, Temp, MoveStyle, TestLoc, TestTime, NextLoc,
     500  NextTime, V8, RecoverTurns, ecix: integer;
     501  NextTile: cardinal;
     502  AttackPositionReached, IsBombardment: boolean;
     503  Adjacent: TVicinity8Loc;
     504  PreLoc: array[0..lxmax * lymax - 1] of word;
     505  Reached: array[0..lxmax * lymax - 1] of boolean;
     506begin
     507  Result := False;
     508  IsBombardment := AttackLoc = maNextCity;
     509  with MyUnit[uix] do
    359510  begin
    360   BestScore:=0;
    361   fillchar(Reached, MapSize, false);
    362   MoveStyle:=GetMyMoveStyle(mix, Health);
    363   Pile.Create(MapSize);
    364   Pile.Put(Loc, $800-Movement);
    365   while Pile.Get(TestLoc, TestTime) do
     511    if (MyModel[mix].Domain = dGround) and (MyModel[mix].Attack > 0) then
     512      if MyModel[mix].Speed >= 250 then
     513        Kind := ukFast
     514      else
     515        Kind := ukSlow
     516    else
     517      Kind := 0;
     518    fillchar(Reached, MapSize, False);
     519    AttackPositionReached := False;
     520    MoveStyle := GetMyMoveStyle(mix, Health);
     521    Pile.Create(MapSize);
     522    Pile.Put(Loc, $800 - Movement);
     523    while Pile.Get(TestLoc, TestTime) do
    366524    begin
    367     Reached[TestLoc]:=true;
    368     V8_to_Loc(TestLoc, Adjacent);
    369     for V8:=0 to 7 do
    370       begin
    371       NextLoc:=Adjacent[V8];
    372       if (NextLoc>=0) and not Reached[NextLoc] then
    373         begin
    374         NextTile:=Map[NextLoc];
    375         if euixMap[NextLoc]>=0 then
    376           begin // check attack
    377           Defense:=@RO.EnemyUn[euixMap[NextLoc]];
    378           if Unit_AttackForecast(uix, NextLoc, $800-TestTime, RemHealth) then
     525      if (TestTime >= $800) or (AttackLoc = maNextCity) and (TestTime > $800 - 100) then
     526        break;
     527      Reached[TestLoc] := True;
     528      V8_to_Loc(TestLoc, Adjacent);
     529      for V8 := 0 to 7 do
     530      begin
     531        NextLoc := Adjacent[V8];
     532        if NextLoc >= 0 then
     533        begin
     534          if IsBombardment and (Map[NextLoc] and (fCity or
     535            fUnit or fOwned or fObserved) = fCity or fObserved) and
     536            (RO.Treaty[RO.Territory[NextLoc]] < trPeace) then
     537          begin
     538            City_FindEnemyCity(NextLoc, ecix);
     539            assert(ecix >= 0);
     540            with RO.EnemyCity[ecix] do
     541              if (Size > 2) and (Flags and ciCoastalFort = 0) then
     542                AttackLoc := NextLoc;
     543          end;
     544          if (NextLoc = AttackLoc) and ((MyModel[mix].Domain <> dSea) or
     545            (Map[TestLoc] and fTerrain < fGrass)) then
     546            // ships can only attack from water
     547          begin
     548            AttackPositionReached := True;
     549            break;
     550          end
     551          else if not Reached[NextLoc] then
     552          begin
     553            NextTile := Map[NextLoc];
     554            if (NextTile and (fUnit or fCity) = 0) or
     555              (NextTile and fOwned <> 0) then
     556              case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime,
     557                  RecoverTurns, Map[TestLoc], NextTile, True) of
     558                csOk:
     559                  if Pile.Put(NextLoc, NextTime) then
     560                    PreLoc[NextLoc] := TestLoc;
     561                csForbiddenTile:
     562                  Reached[NextLoc] := True; // don't check moving there again
     563                csCheckTerritory:
     564                  if RO.Territory[NextLoc] = RO.Territory[TestLoc] then
     565                    if Pile.Put(NextLoc, NextTime) then
     566                      PreLoc[NextLoc] := TestLoc;
     567              end;
     568          end;
     569        end;
     570      end;
     571      if AttackPositionReached then
     572      begin
     573        PreLoc[NextLoc] := TestLoc;
     574        break;
     575      end;
     576    end;
     577    Pile.Free;
     578    if not AttackPositionReached then
     579      exit;
     580
     581    TestLoc := AttackLoc;
     582    NextLoc := PreLoc[TestLoc];
     583    while TestLoc <> Loc do
     584    begin
     585      Temp := TestLoc;
     586      TestLoc := NextLoc;
     587      NextLoc := PreLoc[TestLoc];
     588      PreLoc[TestLoc] := Temp;
     589    end;
     590
     591    UnitPresence[Loc] := UnitPresence[Loc] and not Kind;
     592    // assume unit was only one of kind here
     593    repeat
     594      NextLoc := PreLoc[Loc];
     595      MoveResult := Unit_Step(uix, NextLoc);
     596    until (NextLoc = AttackLoc) or (MoveResult and rExecuted = 0) or
     597      (MoveResult and rUnitRemoved <> 0);
     598    Result := (NextLoc = AttackLoc) and (MoveResult and rExecuted <> 0);
     599
     600    if IsBombardment and Result then
     601    begin
     602      City_FindEnemyCity(AttackLoc, ecix);
     603      assert(ecix >= 0);
     604      while (Movement >= 100) and (RO.EnemyCity[ecix].Size > 2) do
     605        Unit_Step(uix, AttackLoc);
     606    end;
     607
     608    if Loc >= 0 then
     609      UnitPresence[Loc] := UnitPresence[Loc] or Kind;
     610  end;
     611end;
     612
     613function TBarbarina.ProcessMove(uix: integer): boolean;
     614  // return true if no new enemy spotted
     615const
     616  DistanceScore = 4;
     617var
     618  PatrolScore, BestCount, PatrolLoc, TestLoc, NextLoc, TestTime, V8,
     619  TestScore, MoveResult, MoveStyle, NextTime, TerrOwner, Kind, Temp,
     620  RecoverTurns, MaxScore: integer;
     621  Tile, NextTile: cardinal;
     622  CaptureOnly, PeaceBorder, done, NextToEnemyCity: boolean;
     623  Adjacent: TVicinity8Loc;
     624  AdjacentUnknown: array[0..lxmax * lymax - 1] of shortint;
     625  PreLoc: array[0..lxmax * lymax - 1] of word;
     626  MoreTurn: array[0..lxmax * lymax - 1] of byte;
     627
     628begin
     629  Result := True;
     630  done := False;
     631  while not done do
     632    with MyUnit[uix] do
     633    begin
     634      if (MyModel[mix].Domain = dSea) and (Health < 100) and
     635        ((Health < 34) or (MyModel[mix].Cap[mcSeaTrans] > 0)) then
     636      begin
     637        if Map[Loc] and fCity = 0 then
     638          Unit_MoveEx(uix, maNextCity);
     639        exit;
     640      end;
     641
     642      if (MyModel[mix].Domain = dGround) and (MyModel[mix].Attack > 0) then
     643        if MyModel[mix].Speed >= 250 then
     644          Kind := ukFast
     645        else
     646          Kind := ukSlow
     647      else
     648        Kind := 0;
     649      CaptureOnly := (Health < 100) and ((Map[Loc] and fCity <> 0) or
     650        ((100 - Health) * Terrain[Map[Loc] and fTerrain].Defense > 60) and
     651        not (Map[Loc] and fTerrain in [fOcean, fShore, fArctic, fDesert]));
     652      MoveStyle := GetMyMoveStyle(mix, Health);
     653
     654      if MyModel[mix].Attack > 0 then
     655        MaxScore := $400
     656      else
     657        MaxScore := $400 - 32 + 5;
     658      PatrolScore := -999999;
     659      PatrolLoc := -1;
     660      FillChar(AdjacentUnknown, MapSize, $FF); // -1, indicates tiles not checked yet
     661      Pile.Create(MapSize);
     662      Pile.Put(Loc, $800 - Movement);
     663      while Pile.Get(TestLoc, TestTime) do
     664      begin
     665        if (MaxScore * $1000 - DistanceScore * TestTime <= PatrolScore)
     666          // assume a score of $400 is the best achievable
     667          or CaptureOnly and (TestTime >= $1000) then
     668          break;
     669
     670        TestScore := 0;
     671        Tile := Map[TestLoc];
     672        assert(Tile and (fUnit or fOwned) <> fUnit);
     673        TerrOwner := RO.Territory[TestLoc];
     674        AdjacentUnknown[TestLoc] := 0;
     675        PeaceBorder := False;
     676        NextToEnemyCity := False;
     677
     678        if ((Tile and fCity) <> 0) and ((Tile and fOwned) = 0) then
     679        begin
     680          if (MyModel[mix].Domain = dGround) and (MyModel[mix].Attack > 0) and
     681            ((TerrOwner < 0)
     682            // happens only for unobserved cities of extinct tribes, new owner unknown
     683            or (RO.Treaty[TerrOwner] < trPeace)) then
     684            if (Tile and fObserved <> 0) and (Tile and fUnit = 0) then
     685              TestScore := $400 // unfriendly undefended city -- capture!
     686            else
     687              TestScore := $400 - 14; // unfriendly city, not observed or defended
     688        end
     689
     690        else
     691        begin // no enemy city or unit here
     692          V8_to_Loc(TestLoc, Adjacent);
     693          for V8 := 0 to 7 do
     694          begin
     695            NextLoc := Adjacent[V8];
     696            if (NextLoc >= 0) and (AdjacentUnknown[NextLoc] < 0) then
    379697            begin
    380             if RemHealth<=0 then // send unit into death?
    381               begin
    382               Score:=0;
    383               if ($800-TestTime>=100)
    384                 and ((MyModel[mix].Domain=dGround) and (NextTile and fTerrain>=fGrass)
    385                   or (MyModel[mix].Domain=dSea) and (NextTile and fTerrain<fGrass))
    386                 and (MyModel[mix].Attack>MyModel[mix].Defense) then
    387                 begin
    388                 Score:=(Defense.Health+RemHealth)
    389                   *RO.EnemyModel[Defense.emix].Cost*2 div MyModel[mix].Cost;
    390                 if NextTile and fCity<>0 then
    391                   Score:=Score*4;
    392                 end
    393               end
    394             else Score:=RO.EnemyModel[Defense.emix].Cost*25-(Health-RemHealth)*MyModel[mix].Cost shr 4;
    395             if (Score>BestScore) and (Score>AttackScore[euixMap[NextLoc]]) then
    396               begin
    397               BestScore:=Score;
    398               euixBest:=euixMap[NextLoc]
    399               end
    400             end
    401           end
    402         else if (NextTile and (fUnit or fCity)=0)
    403           or (NextTile and fOwned<>0) then
    404           case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime,
    405             RecoverTurns, Map[TestLoc], NextTile, true) of
    406             csOk:
    407               if NextTime<$800 then
    408                 Pile.Put(NextLoc, NextTime);
    409             csForbiddenTile:
    410               Reached[NextLoc]:=true; // don't check moving there again
    411             csCheckTerritory:
    412               if (NextTime<$800) and (RO.Territory[NextLoc]=RO.Territory[TestLoc]) then
    413                 Pile.Put(NextLoc, NextTime);
    414             end
    415         end
    416       end;
    417     end;
    418   Pile.Free;
    419 
    420   if BestScore>0 then
    421     begin
    422     uixOld:=uixAttack[euixBest];
    423     AttackScore[euixBest]:=BestScore;
    424     uixAttack[euixBest]:=uix;
    425     if uixOld>=0 then
    426       RateAttack(uixOld);
    427     end
    428   end
    429 end;
    430 
    431 function TBarbarina.DoAttack(uix,AttackLoc: integer): boolean;
    432 // AttackLoc=maNextCity means bombard only
    433 var
    434 MoveResult,Kind,Temp,MoveStyle,TestLoc,TestTime,NextLoc,NextTime,V8,
    435   RecoverTurns,ecix: integer;
    436 NextTile: cardinal;
    437 AttackPositionReached, IsBombardment: boolean;
    438 Adjacent: TVicinity8Loc;
    439 PreLoc: array[0..lxmax*lymax-1] of word;
    440 Reached: array[0..lxmax*lymax-1] of boolean;
    441 begin
    442 result:=false;
    443 IsBombardment:= AttackLoc=maNextCity;
    444 with MyUnit[uix] do
    445   begin
    446   if (MyModel[mix].Domain=dGround) and (MyModel[mix].Attack>0) then
    447     if MyModel[mix].Speed>=250 then Kind:=ukFast
    448     else Kind:=ukSlow
    449   else Kind:=0;
    450   fillchar(Reached, MapSize, false);
    451   AttackPositionReached:=false;
    452   MoveStyle:=GetMyMoveStyle(mix, Health);
    453   Pile.Create(MapSize);
    454   Pile.Put(Loc, $800-Movement);
    455   while Pile.Get(TestLoc, TestTime) do
    456     begin
    457     if (TestTime>=$800) or (AttackLoc=maNextCity) and (TestTime>$800-100) then
    458       break;
    459     Reached[TestLoc]:=true;
    460     V8_to_Loc(TestLoc, Adjacent);
    461     for V8:=0 to 7 do
    462       begin
    463       NextLoc:=Adjacent[V8];
    464       if NextLoc>=0 then
    465         begin
    466         if IsBombardment and (Map[NextLoc] and
    467           (fCity or fUnit or fOwned or fObserved)=fCity or fObserved)
    468           and (RO.Treaty[RO.Territory[NextLoc]]<trPeace) then
    469           begin
    470           City_FindEnemyCity(NextLoc, ecix);
    471           assert(ecix>=0);
    472           with RO.EnemyCity[ecix] do
    473             if (Size>2) and (Flags and ciCoastalFort=0) then
    474               AttackLoc:=NextLoc
    475           end;
    476         if (NextLoc=AttackLoc)
    477           and ((MyModel[mix].Domain<>dSea) or (Map[TestLoc] and fTerrain<fGrass)) then
    478             // ships can only attack from water
    479           begin AttackPositionReached:=true; break end
    480         else if not Reached[NextLoc] then
    481           begin
    482           NextTile:=Map[NextLoc];
    483           if (NextTile and (fUnit or fCity)=0)
    484             or (NextTile and fOwned<>0) then
    485             case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime,
    486               RecoverTurns, Map[TestLoc], NextTile, true) of
    487               csOk:
    488                 if Pile.Put(NextLoc, NextTime) then
    489                   PreLoc[NextLoc]:=TestLoc;
    490               csForbiddenTile:
    491                 Reached[NextLoc]:=true; // don't check moving there again
    492               csCheckTerritory:
    493                 if RO.Territory[NextLoc]=RO.Territory[TestLoc] then
    494                   if Pile.Put(NextLoc, NextTime) then
    495                     PreLoc[NextLoc]:=TestLoc;
    496               end
    497           end
    498         end
    499       end;
    500     if AttackPositionReached then
    501       begin
    502       PreLoc[NextLoc]:=TestLoc;
    503       break
    504       end
    505     end;
    506   Pile.Free;
    507   if not AttackPositionReached then exit;
    508 
    509   TestLoc:=AttackLoc;
    510   NextLoc:=PreLoc[TestLoc];
    511   while TestLoc<>Loc do
    512     begin
    513     Temp:=TestLoc;
    514     TestLoc:=NextLoc;
    515     NextLoc:=PreLoc[TestLoc];
    516     PreLoc[TestLoc]:=Temp;
    517     end;
    518 
    519   UnitPresence[Loc]:=UnitPresence[Loc] and not Kind; // assume unit was only one of kind here
    520   repeat
    521     NextLoc:=PreLoc[Loc];
    522     MoveResult:=Unit_Step(uix, NextLoc);
    523   until (NextLoc=AttackLoc) or (MoveResult and rExecuted=0)
    524     or (MoveResult and rUnitRemoved<>0);
    525   result:= (NextLoc=AttackLoc) and (MoveResult and rExecuted<>0);
    526 
    527   if IsBombardment and result then
    528     begin
    529     City_FindEnemyCity(AttackLoc, ecix);
    530     assert(ecix>=0);
    531     while (Movement>=100) and (RO.EnemyCity[ecix].Size>2) do
    532       Unit_Step(uix, AttackLoc);
    533     end;
    534 
    535   if Loc>=0 then
    536     UnitPresence[Loc]:=UnitPresence[Loc] or Kind;
    537   end
    538 end;
    539 
    540 function TBarbarina.ProcessMove(uix: integer): boolean;
    541 // return true if no new enemy spotted
    542 const
    543 DistanceScore=4;
    544 var
    545 PatrolScore,BestCount,PatrolLoc,TestLoc,NextLoc,TestTime,V8,
    546   TestScore,MoveResult,MoveStyle,NextTime,TerrOwner,Kind,Temp,RecoverTurns,
    547   MaxScore: integer;
    548 Tile,NextTile: cardinal;
    549 CaptureOnly,PeaceBorder, done, NextToEnemyCity: boolean;
    550 Adjacent: TVicinity8Loc;
    551 AdjacentUnknown: array[0..lxmax*lymax-1] of shortint;
    552 PreLoc: array[0..lxmax*lymax-1] of word;
    553 MoreTurn: array[0..lxmax*lymax-1] of byte;
    554 
    555 begin
    556 result:=true;
    557 done:=false;
    558 while not done do with MyUnit[uix] do
    559   begin
    560   if (MyModel[mix].Domain=dSea) and (Health<100)
    561     and ((Health<34) or (MyModel[mix].Cap[mcSeaTrans]>0)) then
    562     begin
    563     if Map[Loc] and fCity=0 then
    564       Unit_MoveEx(uix,maNextCity);
    565     exit;
    566     end;
    567 
    568   if (MyModel[mix].Domain=dGround) and (MyModel[mix].Attack>0) then
    569     if MyModel[mix].Speed>=250 then Kind:=ukFast
    570     else Kind:=ukSlow
    571   else Kind:=0;
    572   CaptureOnly:=(Health<100)
    573     and ((Map[Loc] and fCity<>0)
    574     or ((100-Health)*Terrain[Map[Loc] and fTerrain].Defense>60)
    575       and not (Map[Loc] and fTerrain in [fOcean, fShore, fArctic, fDesert]));
    576   MoveStyle:=GetMyMoveStyle(mix, Health);
    577 
    578   if MyModel[mix].Attack>0 then MaxScore:=$400
    579   else MaxScore:=$400-32+5;
    580   PatrolScore:=-999999;
    581   PatrolLoc:=-1;
    582   FillChar(AdjacentUnknown,MapSize,$FF); // -1, indicates tiles not checked yet
    583   Pile.Create(MapSize);
    584   Pile.Put(Loc, $800-Movement);
    585   while Pile.Get(TestLoc,TestTime) do
    586     begin
    587     if (MaxScore*$1000-DistanceScore*TestTime<=PatrolScore) // assume a score of $400 is the best achievable
    588       or CaptureOnly and (TestTime>=$1000) then
    589       break;
    590 
    591     TestScore:=0;
    592     Tile:=Map[TestLoc];
    593     assert(Tile and (fUnit or fOwned)<>fUnit);
    594     TerrOwner:=RO.Territory[TestLoc];
    595     AdjacentUnknown[TestLoc]:=0;
    596     PeaceBorder:=false;
    597     NextToEnemyCity:=false;
    598 
    599     if ((Tile and fCity)<>0) and ((Tile and fOwned)=0) then
    600       begin
    601       if (MyModel[mix].Domain=dGround) and (MyModel[mix].Attack>0)
    602         and ((TerrOwner<0) // happens only for unobserved cities of extinct tribes, new owner unknown
    603           or (RO.Treaty[TerrOwner]<trPeace)) then
    604         if (Tile and fObserved<>0) and (Tile and fUnit=0) then
    605           TestScore:=$400 // unfriendly undefended city -- capture!
    606         else TestScore:=$400-14 // unfriendly city, not observed or defended
    607       end
    608 
    609     else
    610       begin // no enemy city or unit here
    611       V8_to_Loc(TestLoc,Adjacent);
    612       for V8:=0 to 7 do
    613         begin
    614         NextLoc:=Adjacent[V8];
    615         if (NextLoc>=0) and (AdjacentUnknown[NextLoc]<0) then
    616           begin
    617           NextTile:=Map[NextLoc];
    618           if NextTile and fTerrain=fUNKNOWN then
    619             inc(AdjacentUnknown[TestLoc])
    620           else if NextTile and fTerrain=fArctic then
    621           else if NextTile and (fCity or fUnit or fOwned or fObserved)=
    622             fCity or fUnit or fObserved then
    623             NextToEnemyCity:=true
    624           else case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime, RecoverTurns, Tile, NextTile, true) of
    625             csOk:
     698              NextTile := Map[NextLoc];
     699              if NextTile and fTerrain = fUNKNOWN then
     700                Inc(AdjacentUnknown[TestLoc])
     701              else if NextTile and fTerrain = fArctic then
     702              else if NextTile and (fCity or fUnit or fOwned or fObserved) =
     703                fCity or fUnit or fObserved then
     704                NextToEnemyCity := True
     705              else
     706                case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime,
     707                    RecoverTurns, Tile, NextTile, True) of
     708                  csOk:
    626709{              if (NextTime and $7FFFF000=TestTime and $7FFFF000)
    627710                or (UnitPresence[TestLoc] and Kind=0)
    628711                or (Tile and fCity<>0)
    629712                or (Tile and fTerImp=tiFort) or (Tile and fTerImp=tiBase) then}
    630                 begin
    631                 if Pile.Put(NextLoc, NextTime+RecoverTurns*$1000) then
    632713                  begin
    633                   PreLoc[NextLoc]:=TestLoc;
    634                   MoreTurn[NextLoc]:=NextTime shr 12 and $FFF;
    635                   end
     714                    if Pile.Put(NextLoc, NextTime + RecoverTurns * $1000) then
     715                    begin
     716                      PreLoc[NextLoc] := TestLoc;
     717                      MoreTurn[NextLoc] := NextTime shr 12 and $FFF;
     718                    end;
     719                  end;
     720                  csForbiddenTile:
     721                  begin
     722                    AdjacentUnknown[NextLoc] := 0; // don't check moving there again
     723                    if NextTile and fPeace <> 0 then
     724                      PeaceBorder := True;
     725                  end;
     726                  csCheckTerritory:
     727                    if RO.Territory[NextLoc] = TerrOwner then
     728                    begin
     729                      if Pile.Put(NextLoc, NextTime + RecoverTurns * $1000) then
     730                      begin
     731                        PreLoc[NextLoc] := TestLoc;
     732                        MoreTurn[NextLoc] := NextTime shr 12 and $FFF;
     733                      end;
     734                    end
     735                    else
     736                      PeaceBorder := True;
    636737                end;
    637             csForbiddenTile:
    638               begin
    639               AdjacentUnknown[NextLoc]:=0; // don't check moving there again
    640               if NextTile and fPeace<>0 then PeaceBorder:=true;
    641               end;
    642             csCheckTerritory:
    643               if RO.Territory[NextLoc]=TerrOwner then
    644                 begin
    645                 if Pile.Put(NextLoc, NextTime+RecoverTurns*$1000) then
    646                   begin
    647                   PreLoc[NextLoc]:=TestLoc;
    648                   MoreTurn[NextLoc]:=NextTime shr 12 and $FFF;
    649                   end
    650                 end
    651               else PeaceBorder:=true;
    652             end
    653           end
    654         end;
    655       if not CaptureOnly then
    656         if NextToEnemyCity and (MyModel[mix].Attack>0)
    657           and (MyModel[mix].Domain=dGround) then
    658           TestScore:=$400-14
    659         else if AdjacentUnknown[TestLoc]>0 then
    660           if PeaceBorder or (TerrOwner>=0) and (TerrOwner<>me)
    661             and (RO.Treaty[TerrOwner]<trPeace) then
    662             TestScore:=$400-32+AdjacentUnknown[TestLoc]
    663           else TestScore:=$400-64+AdjacentUnknown[TestLoc]
    664         else if PeaceBorder then TestScore:=$400-32
    665         else TestScore:=(RO.Turn-RO.MapObservedLast[TestLoc]) div 16;
    666       end; // no enemy city or unit here
    667 
    668     if TestScore>0 then
    669       begin
    670       TestScore:=TestScore*$1000-DistanceScore*TestTime;
    671       if TestScore>PatrolScore then
    672         BestCount:=0;
    673       if TestScore>=PatrolScore then
    674         begin
    675         inc(BestCount);
    676         if random(BestCount)=0 then
    677           begin
    678           PatrolScore:=TestScore;
    679           PatrolLoc:=TestLoc;
    680           end
     738            end;
     739          end;
     740          if not CaptureOnly then
     741            if NextToEnemyCity and (MyModel[mix].Attack > 0) and
     742              (MyModel[mix].Domain = dGround) then
     743              TestScore := $400 - 14
     744            else if AdjacentUnknown[TestLoc] > 0 then
     745              if PeaceBorder or (TerrOwner >= 0) and (TerrOwner <> me) and
     746                (RO.Treaty[TerrOwner] < trPeace) then
     747                TestScore := $400 - 32 + AdjacentUnknown[TestLoc]
     748              else
     749                TestScore := $400 - 64 + AdjacentUnknown[TestLoc]
     750            else if PeaceBorder then
     751              TestScore := $400 - 32
     752            else
     753              TestScore := (RO.Turn - RO.MapObservedLast[TestLoc]) div 16;
     754        end; // no enemy city or unit here
     755
     756        if TestScore > 0 then
     757        begin
     758          TestScore := TestScore * $1000 - DistanceScore * TestTime;
     759          if TestScore > PatrolScore then
     760            BestCount := 0;
     761          if TestScore >= PatrolScore then
     762          begin
     763            Inc(BestCount);
     764            if random(BestCount) = 0 then
     765            begin
     766              PatrolScore := TestScore;
     767              PatrolLoc := TestLoc;
     768            end;
     769          end;
     770        end;
     771      end; // while Pile.Get
     772      Pile.Free;
     773
     774      if (PatrolLoc >= 0) and (PatrolLoc <> Loc) then
     775      begin // capture/discover/patrol task found, execute it
     776        while (PatrolLoc <> Loc) and (MoreTurn[PatrolLoc] > 0) and
     777          ((MoreTurn[PatrolLoc] > 1) or not (Map[PatrolLoc] and fTerrain in
     778            [fMountains, fDesert, fArctic])) do
     779        begin
     780          PatrolLoc := PreLoc[PatrolLoc];
     781          done := True; // no effect if enemy spotted
     782        end;
     783        while (PatrolLoc <> Loc) and (UnitPresence[PatrolLoc] and Kind <> 0) and
     784          (Map[PatrolLoc] and fCity = 0) and (Map[PatrolLoc] and fTerImp <> tiFort) and
     785          (Map[PatrolLoc] and fTerImp <> tiBase) and not
     786          (Map[PreLoc[PatrolLoc]] and fTerrain in [fDesert, fArctic]) do
     787        begin
     788          PatrolLoc := PreLoc[PatrolLoc];
     789          done := True; // no effect if enemy spotted
     790        end;
     791        if PatrolLoc = Loc then
     792          exit;
     793        TestLoc := PatrolLoc;
     794        NextLoc := PreLoc[TestLoc];
     795        while TestLoc <> Loc do
     796        begin
     797          Temp := TestLoc;
     798          TestLoc := NextLoc;
     799          NextLoc := PreLoc[TestLoc];
     800          PreLoc[TestLoc] := Temp;
     801        end;
     802
     803        UnitPresence[Loc] := UnitPresence[Loc] and not Kind;
     804        // assume unit was only one of kind here
     805        while Loc <> PatrolLoc do
     806        begin
     807          NextLoc := PreLoc[Loc];
     808          MoveResult := Unit_Step(uix, NextLoc);
     809          if (MoveResult and (rUnitRemoved or rEnemySpotted) <> 0) or
     810            (MoveResult and rExecuted = 0) then
     811          begin
     812            if MoveResult and rExecuted = 0 then
     813              Moved[uix] := True;
     814            Result := MoveResult and rEnemySpotted = 0;
     815            done := True;
     816            break;
     817          end;
     818          assert(Loc = NextLoc);
     819        end;
     820        if Loc >= 0 then
     821        begin
     822          UnitPresence[Loc] := UnitPresence[Loc] or Kind;
     823          if Map[Loc] and fCity <> 0 then
     824          begin
     825            Moved[uix] := True;
     826            done := True; // stay in captured city as defender
     827          end;
    681828        end;
    682829      end
    683     end; // while Pile.Get
    684   Pile.Free;
    685 
    686   if (PatrolLoc>=0) and (PatrolLoc<>Loc) then
    687     begin // capture/discover/patrol task found, execute it
    688     while (PatrolLoc<>Loc) and (MoreTurn[PatrolLoc]>0)
    689       and ((MoreTurn[PatrolLoc]>1)
    690         or not (Map[PatrolLoc] and fTerrain in [fMountains,fDesert,fArctic])) do
    691       begin
    692       PatrolLoc:=PreLoc[PatrolLoc];
    693       done:=true // no effect if enemy spotted
    694       end;
    695     while (PatrolLoc<>Loc) and (UnitPresence[PatrolLoc] and Kind<>0)
    696       and (Map[PatrolLoc] and fCity=0)
    697       and (Map[PatrolLoc] and fTerImp<>tiFort)
    698       and (Map[PatrolLoc] and fTerImp<>tiBase)
    699       and not (Map[PreLoc[PatrolLoc]] and fTerrain in [fDesert,fArctic]) do
    700       begin
    701       PatrolLoc:=PreLoc[PatrolLoc];
    702       done:=true // no effect if enemy spotted
    703       end;
    704     if PatrolLoc=Loc then exit;
    705     TestLoc:=PatrolLoc;
    706     NextLoc:=PreLoc[TestLoc];
    707     while TestLoc<>Loc do
    708       begin
    709       Temp:=TestLoc;
    710       TestLoc:=NextLoc;
    711       NextLoc:=PreLoc[TestLoc];
    712       PreLoc[TestLoc]:=Temp;
    713       end;
    714 
    715     UnitPresence[Loc]:=UnitPresence[Loc] and not Kind; // assume unit was only one of kind here
    716     while Loc<>PatrolLoc do
    717       begin
    718       NextLoc:=PreLoc[Loc];
    719       MoveResult:=Unit_Step(uix, NextLoc);
    720       if (MoveResult and (rUnitRemoved or rEnemySpotted)<>0)
    721         or (MoveResult and rExecuted=0) then
    722         begin
    723         if MoveResult and rExecuted=0 then Moved[uix]:=true;
    724         result:= MoveResult and rEnemySpotted=0;
    725         done:=true;
    726         break
    727         end;
    728       assert(Loc=NextLoc);
    729       end;
    730     if Loc>=0 then
    731       begin
    732       UnitPresence[Loc]:=UnitPresence[Loc] or Kind;
    733       if Map[Loc] and fCity<>0 then
    734         begin
    735         Moved[uix]:=true;
    736         done:=true; // stay in captured city as defender
    737         end
    738       end 
    739     end
    740   else done:=true;
    741   end; // while not done
    742 if result then Moved[uix]:=true;
     830      else
     831        done := True;
     832    end; // while not done
     833  if Result then
     834    Moved[uix] := True;
    743835end; // ProcessMove
    744836
     
    747839  procedure SetCityDefenders;
    748840  var
    749   uix,cix,V8,Loc1,Best,uixBest,det: integer;
    750   Adjacent: TVicinity8Loc;
    751   IsPort: boolean;
     841    uix, cix, V8, Loc1, Best, uixBest, det: integer;
     842    Adjacent: TVicinity8Loc;
     843    IsPort: boolean;
    752844  begin
    753   for cix:=0 to RO.nCity-1 do with MyCity[cix] do if Loc>=0 then
     845    for cix := 0 to RO.nCity - 1 do
     846      with MyCity[cix] do
     847        if Loc >= 0 then
     848        begin
     849          IsPort := False;
     850          V8_to_Loc(Loc, Adjacent);
     851          for V8 := 0 to 7 do
     852          begin
     853            Loc1 := Adjacent[V8];
     854            if (Loc1 >= 0) and (Map[Loc1] and fTerrain < fGrass) and
     855              (Formation[Loc1] >= 0) and (Formation[Loc1] < maxCOD) and
     856              (OceanPresence[Formation[Loc1]] and not Neighbours <> 0) then
     857              IsPort := True;
     858          end;
     859          Best := -1;
     860          for uix := 0 to RO.nUn - 1 do
     861            if MyUnit[uix].Loc = Loc then
     862              with MyUnit[uix] do
     863                if (MyModel[mix].Domain = dGround) and (MyModel[mix].Attack > 0) then
     864                begin
     865                  if (mix = 2) and (RO.Government = gDespotism) then
     866                  begin
     867                    det := 1 shl 16;
     868                    Moved[uix] := True;
     869                  end // town guard
     870                  else if IsPort then
     871                    det := MyModel[mix].Defense shl 8 + Flags and
     872                      unFortified shl 7 - health
     873                  else
     874                    det := MyModel[mix].Speed shl 8 + Flags and
     875                      unFortified shl 7 - health;
     876                  if det > Best then
     877                  begin
     878                    Best := det;
     879                    uixBest := uix;
     880                  end;
     881                end;
     882          if Best >= 0 then
     883            Moved[uixBest] := True;
     884        end;
     885  end;
     886
     887  procedure ProcessSeaTransport;
     888  var
     889    i, f, uix, Loc1, a, b: integer;
     890    ready, go: boolean;
     891    TransportPlan: TGroupTransportPlan;
     892  begin
     893    go := False;
     894    for f := 0 to maxCOD - 1 do
     895      if (f < nContinent) and (ContinentPresence[f] and not
     896        (1 shl me or PresenceUnknown) <> 0) then
     897        go := True; // any enemy island known?
     898    if not go then
     899      exit;
     900
     901    SeaTransport_BeginInitialize;
     902    go := False;
     903    for uix := 0 to RO.nUn - 1 do
     904      if not Moved[uix] then
     905        with MyUnit[uix] do
     906          if (Loc >= 0) and (MyModel[mix].Domain = dGround) and
     907            (MyModel[mix].Attack > 0) and (Map[Loc] and fTerrain >= fGrass) then
     908          begin
     909            f := Formation[Loc];
     910            if (f >= 0) and (f < maxCOD) and (ContinentPresence[f] and
     911              not (1 shl me) = 0) then
     912            begin
     913              go := True;
     914              SeaTransport_AddLoad(uix);
     915            end;
     916          end;
     917    if go then
    754918    begin
    755     IsPort:=false;
    756     V8_to_Loc(Loc,Adjacent);
    757     for V8:=0 to 7 do
    758       begin
    759       Loc1:=Adjacent[V8];
    760       if (Loc1>=0) and (Map[Loc1] and fTerrain<fGrass)
    761         and (Formation[Loc1]>=0) and (Formation[Loc1]<maxCOD)
    762         and (OceanPresence[Formation[Loc1]] and not Neighbours<>0) then
    763         IsPort:=true
    764       end;
    765     Best:=-1;
    766     for uix:=0 to RO.nUn-1 do if MyUnit[uix].Loc=Loc then
    767       with MyUnit[uix] do
    768         if (MyModel[mix].Domain=dGround) and (MyModel[mix].Attack>0) then
    769           begin
    770           if (mix=2) and (RO.Government=gDespotism) then
    771             begin det:=1 shl 16; Moved[uix]:=true end // town guard
    772           else if IsPort then det:=MyModel[mix].Defense shl 8+Flags and unFortified shl 7-health
    773           else det:=MyModel[mix].Speed shl 8+Flags and unFortified shl 7-health;
    774           if det>Best then
    775             begin Best:=det; uixBest:=uix end
    776           end;
    777     if Best>=0 then Moved[uixBest]:=true
     919      go := False;
     920      for uix := 0 to RO.nUn - 1 do
     921        if not Moved[uix] then
     922          with MyUnit[uix] do
     923            if (Loc >= 0) and (mix = mixBest[ctSeaTrans]) and
     924              (TroopLoad = 0) and (Health = 100) then
     925            begin
     926              go := True;
     927              SeaTransport_AddTransport(uix);
     928            end;
     929    end;
     930    if go then
     931      for Loc1 := 0 to MapSize - 1 do
     932        if Map[Loc1] and fTerrain >= fGrass then
     933        begin
     934          f := Formation[Loc1];
     935          if (f >= 0) and (f < maxCOD) and (ContinentPresence[f] and
     936            not (1 shl me or PresenceUnknown) <> 0) then
     937            SeaTransport_AddDestination(Loc1);
     938        end;
     939    SeaTransport_EndInitialize;
     940    while SeaTransport_MakeGroupPlan(TransportPlan) do
     941    begin
     942      Moved[TransportPlan.uixTransport] := True;
     943      ready := MyUnit[TransportPlan.uixTransport].Loc = TransportPlan.LoadLoc;
     944      if not ready then
     945      begin
     946        Unit_MoveEx(TransportPlan.uixTransport, TransportPlan.LoadLoc);
     947        ready := MyUnit[TransportPlan.uixTransport].Loc = TransportPlan.LoadLoc;
     948      end;
     949      if ready then
     950        for i := 0 to TransportPlan.nLoad - 1 do
     951        begin
     952          Loc_to_ab(TransportPlan.LoadLoc,
     953            MyUnit[TransportPlan.uixLoad[i]].Loc, a, b);
     954          ready := ready and (abs(a) <= 1) and (abs(b) <= 1);
     955        end;
     956      if ready then
     957      begin
     958        for i := 0 to TransportPlan.nLoad - 1 do
     959        begin
     960          Unit_Step(TransportPlan.uixLoad[i], TransportPlan.LoadLoc);
     961          Moved[TransportPlan.uixLoad[i]] := True;
     962        end;
     963      end
     964      else
     965      begin
     966        for i := 0 to TransportPlan.nLoad - 1 do
     967        begin
     968          Unit_MoveEx(TransportPlan.uixLoad[i], TransportPlan.LoadLoc, mxAdjacent);
     969          Moved[TransportPlan.uixLoad[i]] := True;
     970        end;
     971      end;
    778972    end;
    779973  end;
    780974
    781   procedure ProcessSeaTransport;
    782   var
    783   i,f,uix,Loc1,a,b: integer;
    784   ready,go: boolean;
    785   TransportPlan: TGroupTransportPlan;
    786   begin
    787   go:=false;
    788   for f:=0 to maxCOD-1 do
    789     if (f<nContinent) and (ContinentPresence[f] and not (1 shl me or PresenceUnknown)<>0) then
    790       go:=true; // any enemy island known?
    791   if not go then exit;
    792 
    793   SeaTransport_BeginInitialize;
    794   go:=false;
    795   for uix:=0 to RO.nUn-1 do if not Moved[uix] then with MyUnit[uix] do
    796     if (Loc>=0) and (MyModel[mix].Domain=dGround)
    797       and (MyModel[mix].Attack>0) and (Map[Loc] and fTerrain>=fGrass) then
    798       begin
    799       f:=Formation[Loc];
    800       if (f>=0) and (f<maxCOD) and (ContinentPresence[f] and not (1 shl me)=0) then
    801         begin go:=true; SeaTransport_AddLoad(uix); end;
    802       end;
    803   if go then
    804     begin
    805     go:=false;
    806     for uix:=0 to RO.nUn-1 do if not Moved[uix] then with MyUnit[uix] do
    807       if (Loc>=0) and (mix=mixBest[ctSeaTrans]) and (TroopLoad=0)
    808         and (Health=100) then
    809         begin go:=true; SeaTransport_AddTransport(uix) end;
    810     end;
    811   if go then
    812     for Loc1:=0 to MapSize-1 do if Map[Loc1] and fTerrain>=fGrass then
    813       begin
    814       f:=Formation[Loc1];
    815       if (f>=0) and (f<maxCOD)
    816         and (ContinentPresence[f] and not (1 shl me or PresenceUnknown)<>0) then
    817         SeaTransport_AddDestination(Loc1);
    818       end;
    819   SeaTransport_EndInitialize;
    820   while SeaTransport_MakeGroupPlan(TransportPlan) do
    821     begin
    822     Moved[TransportPlan.uixTransport]:=true;
    823     ready:=MyUnit[TransportPlan.uixTransport].Loc=TransportPlan.LoadLoc;
    824     if not ready then
    825       begin
    826       Unit_MoveEx(TransportPlan.uixTransport, TransportPlan.LoadLoc);
    827       ready:=MyUnit[TransportPlan.uixTransport].Loc=TransportPlan.LoadLoc;
    828       end;
    829     if ready then
    830       for i:=0 to TransportPlan.nLoad-1 do
    831         begin
    832         Loc_to_ab(TransportPlan.LoadLoc,
    833           MyUnit[TransportPlan.uixLoad[i]].Loc, a, b);
    834         ready:=ready and (abs(a)<=1) and (abs(b)<=1);
    835         end;
    836     if ready then
    837       begin
    838       for i:=0 to TransportPlan.nLoad-1 do
    839         begin
    840         Unit_Step(TransportPlan.uixLoad[i], TransportPlan.LoadLoc);
    841         Moved[TransportPlan.uixLoad[i]]:=true;
    842         end
    843       end
    844     else
    845       begin
    846       for i:=0 to TransportPlan.nLoad-1 do
    847         begin
    848         Unit_MoveEx(TransportPlan.uixLoad[i], TransportPlan.LoadLoc, mxAdjacent);
    849         Moved[TransportPlan.uixLoad[i]]:=true;
    850         end
    851       end;
    852     end
    853   end;
    854 
    855975  procedure ProcessUnload(uix: integer);
    856976
    857977    procedure Unload(Kind, ToLoc: integer);
    858978    var
    859     uix1: integer;
     979      uix1: integer;
    860980    begin
    861     for uix1:=0 to RO.nUn-1 do with MyUnit[uix1] do
    862       if (Loc>=0) and (Master=uix)
    863         and (MyModel[mix].Domain=dGround) and (MyModel[mix].Attack>0)
    864         and (Movement=MyModel[mix].Speed)
    865         and ((MyModel[mix].Speed>=250)=(Kind=ukFast)) then
    866         begin
    867         Unit_Step(uix1,ToLoc);
    868         UnitPresence[ToLoc]:=UnitPresence[ToLoc] or Kind;
    869         break
     981      for uix1 := 0 to RO.nUn - 1 do
     982        with MyUnit[uix1] do
     983          if (Loc >= 0) and (Master = uix) and (MyModel[mix].Domain = dGround) and
     984            (MyModel[mix].Attack > 0) and (Movement = MyModel[mix].Speed) and
     985            ((MyModel[mix].Speed >= 250) = (Kind = ukFast)) then
     986          begin
     987            Unit_Step(uix1, ToLoc);
     988            UnitPresence[ToLoc] := UnitPresence[ToLoc] or Kind;
     989            break;
     990          end;
     991    end;
     992
     993  var
     994    uix1, MoveStyle, TestLoc, TestTime, NextLoc, NextTime, V8,
     995    RecoverTurns, nSlow, nFast, SlowUnloadLoc, FastUnloadLoc, EndLoc, f: integer;
     996    NextTile: cardinal;
     997    Adjacent: TVicinity8Loc;
     998    Reached: array[0..lxmax * lymax - 1] of boolean;
     999  begin
     1000    // inventory
     1001    nSlow := 0;
     1002    nFast := 0;
     1003    for uix1 := 0 to RO.nUn - 1 do
     1004      with MyUnit[uix1] do
     1005        if (Loc >= 0) and (Master = uix) and (MyModel[mix].Domain = dGround) and
     1006          (MyModel[mix].Attack > 0) then
     1007          if MyModel[mix].Speed >= 250 then
     1008            Inc(nFast)
     1009          else
     1010            Inc(nSlow);
     1011
     1012    with MyUnit[uix] do
     1013    begin
     1014      MoveStyle := GetMyMoveStyle(mix, Health);
     1015      repeat
     1016        SlowUnloadLoc := -1;
     1017        FastUnloadLoc := -1;
     1018        EndLoc := -1;
     1019        fillchar(Reached, MapSize, False);
     1020        Pile.Create(MapSize);
     1021        Pile.Put(Loc, $800 - Movement);
     1022        while (SlowUnloadLoc < 0) and (FastUnloadLoc < 0) and
     1023          Pile.Get(TestLoc, TestTime) do
     1024        begin
     1025          Reached[TestLoc] := True;
     1026          V8_to_Loc(TestLoc, Adjacent);
     1027          for V8 := 0 to 7 do
     1028          begin
     1029            NextLoc := Adjacent[V8];
     1030            if (NextLoc >= 0) and not Reached[NextLoc] then
     1031            begin
     1032              NextTile := Map[NextLoc];
     1033              if NextTile and fTerrain = fUnknown then
     1034              else if NextTile and fTerrain >= fGrass then
     1035              begin
     1036                f := Formation[NextLoc];
     1037                if (f >= 0) and (f < maxCOD) and
     1038                  (ContinentPresence[f] and not (1 shl me or PresenceUnknown) <> 0) and
     1039                  (NextTile and (fUnit or fOwned) <> fUnit) then
     1040                begin
     1041                  if (nSlow > 0) and (UnitPresence[NextLoc] and
     1042                    ukSlow = 0) and ((SlowUnloadLoc < 0) or
     1043                    (Terrain[Map[NextLoc] and fTerrain].Defense >
     1044                    Terrain[Map[SlowUnloadLoc] and fTerrain].Defense)) then
     1045                  begin
     1046                    EndLoc := TestLoc;
     1047                    SlowUnloadLoc := NextLoc;
     1048                  end;
     1049                  if (nFast > 0) and (UnitPresence[NextLoc] and
     1050                    ukFast = 0) and ((FastUnloadLoc < 0) or
     1051                    (Terrain[Map[NextLoc] and fTerrain].Defense >
     1052                    Terrain[Map[FastUnloadLoc] and fTerrain].Defense)) then
     1053                  begin
     1054                    EndLoc := TestLoc;
     1055                    FastUnloadLoc := NextLoc;
     1056                  end;
     1057                end;
     1058              end
     1059              else if EndLoc < 0 then
     1060                case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime,
     1061                    RecoverTurns, Map[TestLoc], NextTile, True) of
     1062                  csOk:
     1063                    Pile.Put(NextLoc, NextTime);
     1064                  csForbiddenTile:
     1065                    Reached[NextLoc] := True; // don't check moving there again
     1066                  csCheckTerritory:
     1067                    if RO.Territory[NextLoc] = RO.Territory[TestLoc] then
     1068                      Pile.Put(NextLoc, NextTime);
     1069                end;
     1070            end;
     1071          end;
     1072        end;
     1073        Pile.Free;
     1074
     1075        if EndLoc < 0 then
     1076          exit;
     1077        if Loc <> EndLoc then
     1078          Unit_MoveEx(uix, EndLoc);
     1079        if Loc <> EndLoc then
     1080          exit;
     1081        if SlowUnloadLoc >= 0 then
     1082        begin
     1083          Unload(ukSlow, SlowUnloadLoc);
     1084          Dec(nSlow);
     1085        end;
     1086        if FastUnloadLoc >= 0 then
     1087        begin
     1088          Unload(ukFast, FastUnloadLoc);
     1089          Dec(nFast);
     1090        end;
     1091        if TroopLoad = 0 then
     1092        begin
     1093          Moved[uix] := False;
     1094          exit;
    8701095        end
     1096      until False;
    8711097    end;
    872 
    873   var
    874   uix1,MoveStyle,TestLoc,TestTime,NextLoc,NextTime,V8,
    875     RecoverTurns,nSlow,nFast,SlowUnloadLoc,FastUnloadLoc,EndLoc,f: integer;
    876   NextTile: cardinal;
    877   Adjacent: TVicinity8Loc;
    878   Reached: array[0..lxmax*lymax-1] of boolean;
    879   begin
    880   // inventory
    881   nSlow:=0;
    882   nFast:=0;
    883   for uix1:=0 to RO.nUn-1 do with MyUnit[uix1] do
    884     if (Loc>=0) and (Master=uix)
    885       and (MyModel[mix].Domain=dGround) and (MyModel[mix].Attack>0) then
    886       if MyModel[mix].Speed>=250 then inc(nFast)
    887       else inc(nSlow);
    888 
    889   with MyUnit[uix] do
     1098  end;
     1099
     1100var
     1101  uix, euix, Kind, euixBest, AttackLoc: integer;
     1102  OldTile: cardinal;
     1103  BackToStart, FirstLoop: boolean;
     1104begin
     1105  fillchar(UnitPresence, MapSize, 0);
     1106  for uix := 0 to RO.nUn - 1 do
     1107    with MyUnit[uix] do
     1108      if (Loc >= 0) and (MyModel[mix].Domain = dGround) and
     1109        (MyModel[mix].Attack > 0) then
     1110      begin
     1111        if MyModel[mix].Speed >= 250 then
     1112          Kind := ukFast
     1113        else
     1114          Kind := ukSlow;
     1115        UnitPresence[Loc] := UnitPresence[Loc] or Kind;
     1116      end;
     1117
     1118  fillchar(Moved, RO.nUn, False);
     1119  for uix := 0 to RO.nUn - 1 do
     1120    if (MyUnit[uix].Master >= 0) or (MyUnit[uix].TroopLoad > 0) then
     1121      Moved[uix] := True;
     1122
     1123  FirstLoop := True;
     1124  repeat
     1125    // ATTACK
     1126    repeat
     1127      BackToStart := False;
     1128      if RO.nEnemyUn > 0 then
     1129      begin
     1130        fillchar(euixMap, MapSize * 2, $FF);
     1131        fillchar(AttackScore, RO.nEnemyUn * 4, 0);
     1132        for euix := 0 to RO.nEnemyUn - 1 do
     1133          with RO.EnemyUn[euix] do
     1134            if (Loc >= 0) and (RO.Treaty[Owner] < trPeace) then
     1135            begin
     1136              BackToStart := True;
     1137              euixMap[Loc] := euix;
     1138              uixAttack[euix] := -1;
     1139            end;
     1140      end;
     1141      if not BackToStart then
     1142        break;
     1143
     1144      for uix := 0 to RO.nUn - 1 do
     1145        with MyUnit[uix] do
     1146          if (Loc >= 0) and (Master < 0) and (MyModel[mix].Attack > 0) then
     1147            RateAttack(uix);
     1148
     1149      BackToStart := False;
     1150      repeat
     1151        euixBest := -1;
     1152        for euix := 0 to RO.nEnemyUn - 1 do
     1153          if (AttackScore[euix] > 0) and ((euixBest < 0) or
     1154            (AttackScore[euix] > AttackScore[euixBest])) then
     1155            euixBest := euix;
     1156        if euixBest < 0 then
     1157          break;
     1158        uix := uixAttack[euixBest];
     1159        AttackLoc := RO.EnemyUn[euixBest].Loc;
     1160        OldTile := Map[AttackLoc];
     1161        if (AttackLoc < 0)
     1162          // only happens when city was destroyd with attack and enemy units have disappeared
     1163          or (DoAttack(uix, AttackLoc) and
     1164          ((Map[AttackLoc] and fUnit <> 0) or (OldTile and fCity <> 0) and
     1165          (Map[AttackLoc] and fCity = 0))) then
     1166          BackToStart := True // new situation, rethink
     1167        else
     1168        begin
     1169          euixMap[AttackLoc] := -1;
     1170          AttackScore[euixBest] := 0;
     1171          uixAttack[euixBest] := -1;
     1172          if MyUnit[uix].Loc >= 0 then
     1173            RateAttack(uix);
     1174        end
     1175      until BackToStart
     1176    until not BackToStart;
     1177
     1178    if FirstLoop then
    8901179    begin
    891     MoveStyle:=GetMyMoveStyle(mix, Health);
    892     repeat
    893       SlowUnloadLoc:=-1;
    894       FastUnloadLoc:=-1;
    895       EndLoc:=-1;
    896       fillchar(Reached, MapSize, false);
    897       Pile.Create(MapSize);
    898       Pile.Put(Loc, $800-Movement);
    899       while (SlowUnloadLoc<0) and (FastUnloadLoc<0)
    900         and Pile.Get(TestLoc, TestTime) do
    901         begin
    902         Reached[TestLoc]:=true;
    903         V8_to_Loc(TestLoc, Adjacent);
    904         for V8:=0 to 7 do
    905           begin
    906           NextLoc:=Adjacent[V8];
    907           if (NextLoc>=0) and not Reached[NextLoc] then
     1180      SetCityDefenders;
     1181      ProcessSeaTransport;
     1182      for uix := 0 to RO.nUn - 1 do
     1183        with MyUnit[uix] do
     1184          if (Loc >= 0) and (TroopLoad > 0) then
     1185            ProcessUnload(uix);
     1186    end;
     1187    FirstLoop := False;
     1188
     1189    for uix := 0 to RO.nUn - 1 do
     1190      with MyUnit[uix], MyModel[mix] do
     1191        if not Moved[uix] and (Loc >= 0) and (Domain = dSea) and
     1192          (Attack > 0) and (Cap[mcArtillery] > 0) then
     1193          DoAttack(uix, maNextCity); // check bombardments
     1194
     1195    // MOVE
     1196    for uix := 0 to RO.nUn - 1 do
     1197      if not Moved[uix] then
     1198        with MyUnit[uix] do
     1199          if (Loc >= 0) and ((MyModel[mix].Attack > 0) or
     1200            (MyModel[mix].Domain = dSea)) then
     1201            if not ProcessMove(uix) then
    9081202            begin
    909             NextTile:=Map[NextLoc];
    910             if NextTile and fTerrain=fUnknown then
    911             else if NextTile and fTerrain>=fGrass then
    912               begin
    913               f:=Formation[NextLoc];
    914               if (f>=0) and (f<maxCOD)
    915                 and (ContinentPresence[f] and not (1 shl me or PresenceUnknown)<>0)
    916                 and (NextTile and (fUnit or fOwned)<>fUnit) then
    917                 begin
    918                 if (nSlow>0) and (UnitPresence[NextLoc] and ukSlow=0)
    919                   and ((SlowUnloadLoc<0) or (Terrain[Map[NextLoc] and fTerrain].Defense
    920                     >Terrain[Map[SlowUnloadLoc] and fTerrain].Defense)) then
    921                   begin EndLoc:=TestLoc; SlowUnloadLoc:=NextLoc end;
    922                 if (nFast>0) and (UnitPresence[NextLoc] and ukFast=0)
    923                   and ((FastUnloadLoc<0) or (Terrain[Map[NextLoc] and fTerrain].Defense
    924                     >Terrain[Map[FastUnloadLoc] and fTerrain].Defense)) then
    925                   begin EndLoc:=TestLoc; FastUnloadLoc:=NextLoc end;
    926                 end
    927               end
    928             else if EndLoc<0 then
    929               case CheckStep(MoveStyle, TestTime, V8 and 1, NextTime,
    930                 RecoverTurns, Map[TestLoc], NextTile, true) of
    931                 csOk:
    932                   Pile.Put(NextLoc, NextTime);
    933                 csForbiddenTile:
    934                   Reached[NextLoc]:=true; // don't check moving there again
    935                 csCheckTerritory:
    936                   if RO.Territory[NextLoc]=RO.Territory[TestLoc] then
    937                     Pile.Put(NextLoc, NextTime);
    938                 end
     1203              BackToStart := True;
     1204              break;
    9391205            end
    940           end;
    941         end;
    942       Pile.Free;
    943 
    944       if EndLoc<0 then exit;
    945       if Loc<>EndLoc then
    946         Unit_MoveEx(uix,EndLoc);
    947       if Loc<>EndLoc then exit;
    948       if SlowUnloadLoc>=0 then
    949         begin Unload(ukSlow,SlowUnloadLoc); dec(nSlow) end;
    950       if FastUnloadLoc>=0 then
    951         begin Unload(ukFast,FastUnloadLoc); dec(nFast) end;
    952       if TroopLoad=0 then
    953         begin Moved[uix]:=false; exit end
    954     until false
    955     end
    956   end;
    957 
    958 var
    959 uix,euix,Kind,euixBest,AttackLoc: integer;
    960 OldTile: cardinal;
    961 BackToStart,FirstLoop: boolean;
    962 begin
    963 fillchar(UnitPresence, MapSize, 0);
    964 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do
    965   if (Loc>=0) and (MyModel[mix].Domain=dGround) and (MyModel[mix].Attack>0) then
    966     begin
    967     if MyModel[mix].Speed>=250 then Kind:=ukFast
    968     else Kind:=ukSlow;
    969     UnitPresence[Loc]:=UnitPresence[Loc] or Kind
    970     end;
    971 
    972 fillchar(Moved, RO.nUn, false);
    973 for uix:=0 to RO.nUn-1 do
    974   if (MyUnit[uix].Master>=0) or (MyUnit[uix].TroopLoad>0) then
    975     Moved[uix]:=true;
    976 
    977 FirstLoop:=true;
    978 repeat
    979   // ATTACK
    980   repeat
    981     BackToStart:=false;
    982     if RO.nEnemyUn>0 then
    983       begin
    984       fillchar(euixMap, MapSize*2, $FFFF);
    985       fillchar(AttackScore,RO.nEnemyUn*4,0);
    986       for euix:=0 to RO.nEnemyUn-1 do with RO.EnemyUn[euix] do
    987         if (Loc>=0) and (RO.Treaty[Owner]<trPeace) then
    988           begin
    989           BackToStart:=true;
    990           euixMap[Loc]:=euix;
    991           uixAttack[euix]:=-1;
    992           end;
    993       end;
    994     if not BackToStart then break;
    995 
    996     for uix:=0 to RO.nUn-1 do with MyUnit[uix] do
    997       if (Loc>=0) and (Master<0) and (MyModel[mix].Attack>0) then
    998         RateAttack(uix);
    999 
    1000     BackToStart:=false;
    1001     repeat
    1002       euixBest:=-1;
    1003       for euix:=0 to RO.nEnemyUn-1 do
    1004         if (AttackScore[euix]>0)
    1005           and ((euixBest<0) or (AttackScore[euix]>AttackScore[euixBest])) then
    1006           euixBest:=euix;
    1007       if euixBest<0 then break;
    1008       uix:=uixAttack[euixBest];
    1009       AttackLoc:=RO.EnemyUn[euixBest].Loc;
    1010       OldTile:=Map[AttackLoc];
    1011       if (AttackLoc<0) // only happens when city was destroyd with attack and enemy units have disappeared
    1012         or (DoAttack(uix,AttackLoc)
    1013           and ((Map[AttackLoc] and fUnit<>0)
    1014             or (OldTile and fCity<>0) and (Map[AttackLoc] and fCity=0))) then
    1015         BackToStart:=true // new situation, rethink
    1016       else
    1017         begin
    1018         euixMap[AttackLoc]:=-1;
    1019         AttackScore[euixBest]:=0;
    1020         uixAttack[euixBest]:=-1;
    1021         if MyUnit[uix].Loc>=0 then
    1022           RateAttack(uix);
    1023         end
    1024     until BackToStart
    10251206  until not BackToStart;
    1026 
    1027   if FirstLoop then
    1028     begin
    1029     SetCityDefenders;
    1030     ProcessSeaTransport;
    1031     for uix:=0 to RO.nUn-1 do with MyUnit[uix] do
    1032       if (Loc>=0) and (TroopLoad>0) then
    1033         ProcessUnload(uix);
    1034     end;
    1035   FirstLoop:=false;
    1036 
    1037   for uix:=0 to RO.nUn-1 do with MyUnit[uix],MyModel[mix] do
    1038     if not Moved[uix] and (Loc>=0) and (Domain=dSea) and (Attack>0)
    1039       and (Cap[mcArtillery]>0) then
    1040       DoAttack(uix,maNextCity); // check bombardments
    1041 
    1042   // MOVE
    1043   for uix:=0 to RO.nUn-1 do if not Moved[uix] then with MyUnit[uix] do
    1044     if (Loc>=0) and ((MyModel[mix].Attack>0) or (MyModel[mix].Domain=dSea)) then
    1045       if not ProcessMove(uix) then
    1046         begin BackToStart:=true; break end
    1047 until not BackToStart;
    10481207end; // AttackAndPatrol
    10491208
     
    10511210
    10521211const
    1053 CoastalWonder=1 shl woLighthouse + 1 shl woMagellan;
    1054 PrimeWonder=1 shl woColossus + 1 shl woGrLibrary + 1 shl woSun
    1055   + 1 shl woMagellan + 1 shl woEiffel + 1 shl woLiberty + 1 shl woShinkansen;
     1212  CoastalWonder = 1 shl woLighthouse + 1 shl woMagellan;
     1213  PrimeWonder = 1 shl woColossus + 1 shl woGrLibrary + 1 shl woSun +
     1214    1 shl woMagellan + 1 shl woEiffel + 1 shl woLiberty + 1 shl woShinkansen;
    10561215
    10571216  function LowPriority(cix: integer): boolean;
    10581217  var
    1059   part,cixHighPriority,TestDistance: integer;
     1218    part, cixHighPriority, TestDistance: integer;
    10601219  begin
    1061   result:=false;
    1062   for part:=0 to nShipPart-1 do
     1220    Result := False;
     1221    for part := 0 to nShipPart - 1 do
    10631222    begin
    1064     cixHighPriority:=ColonyShipPlan[part].cixProducing;
    1065     if (cixHighPriority>=0) and (cixHighPriority<>cix) then
    1066       begin
    1067       TestDistance:=Distance(MyCity[cix].Loc,MyCity[cixHighPriority].Loc);
    1068       if TestDistance<11 then
    1069         begin result:=true; exit end
    1070       end
    1071     end
     1223      cixHighPriority := ColonyShipPlan[part].cixProducing;
     1224      if (cixHighPriority >= 0) and (cixHighPriority <> cix) then
     1225      begin
     1226        TestDistance := Distance(MyCity[cix].Loc, MyCity[cixHighPriority].Loc);
     1227        if TestDistance < 11 then
     1228        begin
     1229          Result := True;
     1230          exit;
     1231        end;
     1232      end;
     1233    end;
    10721234  end;
    10731235
    10741236  function ChooseWonderToBuild(WonderAvailable: integer; AllowCoastal: boolean): integer;
    10751237  var
    1076   Count,iix: integer;
     1238    Count, iix: integer;
    10771239  begin
    1078   if (WonderAvailable and PrimeWonder>0)
    1079     and (AllowCoastal or (WonderAvailable and PrimeWonder and not CoastalWonder>0)) then
    1080     WonderAvailable:=WonderAvailable and PrimeWonder; // alway prefer prime wonders
    1081   Count:=0;
    1082   for iix:=0 to 27 do
     1240    if (WonderAvailable and PrimeWonder > 0) and (AllowCoastal or
     1241      (WonderAvailable and PrimeWonder and not CoastalWonder > 0)) then
     1242      WonderAvailable := WonderAvailable and PrimeWonder; // alway prefer prime wonders
     1243    Count := 0;
     1244    for iix := 0 to 27 do
    10831245    begin
    1084     if (1 shl iix) and WonderAvailable<>0 then
    1085       if (1 shl iix) and CoastalWonder<>0 then
    1086         begin
    1087         if AllowCoastal then inc(Count,2)
     1246      if (1 shl iix) and WonderAvailable <> 0 then
     1247        if (1 shl iix) and CoastalWonder <> 0 then
     1248        begin
     1249          if AllowCoastal then
     1250            Inc(Count, 2);
    10881251        end
    1089       else inc(Count);
     1252        else
     1253          Inc(Count);
    10901254    end;
    1091   Count:=Random(Count);
    1092   for iix:=0 to 27 do
     1255    Count := Random(Count);
     1256    for iix := 0 to 27 do
    10931257    begin
    1094     if (1 shl iix) and WonderAvailable<>0 then
    1095       if (1 shl iix) and CoastalWonder<>0 then
    1096         begin
    1097         if AllowCoastal then dec(Count,2)
     1258      if (1 shl iix) and WonderAvailable <> 0 then
     1259        if (1 shl iix) and CoastalWonder <> 0 then
     1260        begin
     1261          if AllowCoastal then
     1262            Dec(Count, 2);
    10981263        end
    1099       else dec(Count);
    1100     if Count<0 then
    1101       begin
    1102       result:=iix;
    1103       exit
    1104       end
    1105     end
     1264        else
     1265          Dec(Count);
     1266      if Count < 0 then
     1267      begin
     1268        Result := iix;
     1269        exit;
     1270      end;
     1271    end;
    11061272  end;
    11071273
    11081274var
    1109 i,iix,cix,mix,uix,mixProduce,mixShip,V8,V21,Loc1,TotalPop,AlonePop,f,f1,
    1110   nTownGuard,ShipPart,ProduceShipPart,TestDistance,part,WonderAvailable,
    1111   WonderInWork,cixNewCapital,Center,Score,BestScore: integer;
    1112 mixCount: array[0..nmmax-1] of integer;
    1113 //RareLoc: array[0..5] of integer;
    1114 Adjacent: TVicinity8Loc;
    1115 IsCoastal,IsPort,IsUnitProjectObsolete,HasSettler,SpezializeShipProduction,
    1116   AlgaeAvailable,ProjectComplete,DoLowPriority,WillProduceColonyShip,
     1275  i, iix, cix, mix, uix, mixProduce, mixShip, V8, V21, Loc1, TotalPop,
     1276  AlonePop, f, f1, nTownGuard, ShipPart, ProduceShipPart, TestDistance,
     1277  part, WonderAvailable, WonderInWork, cixNewCapital, Center, Score, BestScore: integer;
     1278  mixCount: array[0..nmmax - 1] of integer;
     1279  //RareLoc: array[0..5] of integer;
     1280  Adjacent: TVicinity8Loc;
     1281  IsCoastal, IsPort, IsUnitProjectObsolete, HasSettler, SpezializeShipProduction,
     1282  AlgaeAvailable, ProjectComplete, DoLowPriority, WillProduceColonyShip,
    11171283  ImportantCity: boolean;
    1118 Radius: TVicinity21Loc;
    1119 Report: TCityReportNew;
     1284  Radius: TVicinity21Loc;
     1285  Report: TCityReportNew;
    11201286begin
    1121 AnalyzeMap;
    1122 
    1123 FindBestModels;
    1124 
    1125 fillchar(mixCount, RO.nModel*4, 0);
    1126 for uix:=0 to RO.nUn-1 do with MyUnit[uix] do
    1127   if Loc>=0 then inc(mixCount[mix]);
    1128 if (mixBest[ctGroundSlow]>=0)
    1129   and ((mixBest[ctGroundFast]<0)
    1130   or (mixCount[mixBest[ctGroundSlow]]<mixCount[mixBest[ctGroundFast]])) then
    1131   mixProduce:=mixBest[ctGroundSlow]
    1132 else mixProduce:=mixBest[ctGroundFast];
    1133 if (mixBest[ctSeaTrans]>=0)
    1134   and ((mixBest[ctSeaArt]<0)
    1135   or (mixCount[mixBest[ctSeaTrans]]<mixCount[mixBest[ctSeaArt]])) then
    1136   mixShip:=mixBest[ctSeaTrans]
    1137 else mixShip:=mixBest[ctSeaArt];
    1138 if (mixProduce>=0) and (mixBest[ctSeaTrans]>=0) 
    1139   and (mixCount[mixShip]*RO.Model[mixBest[ctSeaTrans]].Cap[mcSeaTrans]
    1140     *RO.Model[mixBest[ctSeaTrans]].MTrans div 2>=mixCount[mixProduce]) then
    1141   mixShip:=-1;
    1142 
    1143 // produce ships only on certain continents?
    1144 TotalPop:=0;
    1145 AlonePop:=0;
    1146 for cix:=0 to RO.nCity-1 do with MyCity[cix] do
    1147   if (Loc>=0) and (Flags and chCaptured=0) then
     1287  AnalyzeMap;
     1288
     1289  FindBestModels;
     1290
     1291  fillchar(mixCount, RO.nModel * 4, 0);
     1292  for uix := 0 to RO.nUn - 1 do
     1293    with MyUnit[uix] do
     1294      if Loc >= 0 then
     1295        Inc(mixCount[mix]);
     1296  if (mixBest[ctGroundSlow] >= 0) and ((mixBest[ctGroundFast] < 0) or
     1297    (mixCount[mixBest[ctGroundSlow]] < mixCount[mixBest[ctGroundFast]])) then
     1298    mixProduce := mixBest[ctGroundSlow]
     1299  else
     1300    mixProduce := mixBest[ctGroundFast];
     1301  if (mixBest[ctSeaTrans] >= 0) and ((mixBest[ctSeaArt] < 0) or
     1302    (mixCount[mixBest[ctSeaTrans]] < mixCount[mixBest[ctSeaArt]])) then
     1303    mixShip := mixBest[ctSeaTrans]
     1304  else
     1305    mixShip := mixBest[ctSeaArt];
     1306  if (mixProduce >= 0) and (mixBest[ctSeaTrans] >= 0) and
     1307    (mixCount[mixShip] * RO.Model[mixBest[ctSeaTrans]].Cap[mcSeaTrans] *
     1308    RO.Model[mixBest[ctSeaTrans]].MTrans div 2 >= mixCount[mixProduce]) then
     1309    mixShip := -1;
     1310
     1311  // produce ships only on certain continents?
     1312  TotalPop := 0;
     1313  AlonePop := 0;
     1314  for cix := 0 to RO.nCity - 1 do
     1315    with MyCity[cix] do
     1316      if (Loc >= 0) and (Flags and chCaptured = 0) then
     1317      begin
     1318        Inc(TotalPop, Size);
     1319        f := Formation[Loc];
     1320        if (f < 0) or (f >= maxCOD) or (ContinentPresence[f] = 1 shl me) then
     1321          Inc(AlonePop, Size);
     1322      end;
     1323  SpezializeShipProduction := AlonePop * 2 >= TotalPop;
     1324
     1325  cixNewCapital := -1;
     1326  WonderAvailable := 0;
     1327  WonderInWork := 0;
     1328  for iix := 0 to 27 do
     1329    if (Imp[iix].Preq <> preNA) and ((Imp[iix].Preq = preNone) or
     1330      IsResearched(Imp[iix].Preq)) and (RO.Wonder[iix].CityID = -1) then
     1331      Inc(WonderAvailable, 1 shl iix);
     1332  for cix := 0 to RO.nCity - 1 do
     1333    if MyCity[cix].Loc >= 0 then
    11481334    begin
    1149     inc(TotalPop, Size);
    1150     f:=Formation[Loc];
    1151     if (f<0) or (f>=maxCOD) or (ContinentPresence[f]=1 shl me) then
    1152       inc(AlonePop, Size);
     1335      iix := City_CurrentImprovementProject(cix);
     1336      if (iix >= 0) and (iix < 28) then
     1337        Inc(WonderInWork, 1 shl iix)
     1338      else if iix = imPalace then
     1339        cixNewCapital := cix;
    11531340    end;
    1154 SpezializeShipProduction:= AlonePop*2>=TotalPop;
    1155 
    1156 cixNewCapital:=-1;
    1157 WonderAvailable:=0;
    1158 WonderInWork:=0;
    1159 for iix:=0 to 27 do
    1160   if (Imp[iix].Preq<>preNA)
    1161     and ((Imp[iix].Preq=preNone) or IsResearched(Imp[iix].Preq))
    1162     and (RO.Wonder[iix].CityID=-1) then
    1163     inc(WonderAvailable,1 shl iix);
    1164 for cix:=0 to RO.nCity-1 do if MyCity[cix].Loc>=0 then
    1165   begin
    1166   iix:=City_CurrentImprovementProject(cix);
    1167   if (iix>=0) and (iix<28) then
    1168     inc(WonderInWork,1 shl iix)
    1169   else if iix=imPalace then
    1170     cixNewCapital:=cix;
     1341
     1342  if (RO.NatBuilt[imPalace] = 0) and (cixNewCapital < 0) then
     1343  begin // palace was destroyed, build new one
     1344    Center := CenterOfEmpire;
     1345    BestScore := 0;
     1346    for cix := 0 to RO.nCity - 1 do
     1347      with MyCity[cix] do
     1348        if (Loc >= 0) and (Flags and chCaptured = 0) then
     1349        begin // evaluate city as new capital
     1350          Score := Size * 12 + 512 - Distance(Loc, Center);
     1351          V8_to_Loc(Loc, Adjacent);
     1352          for V8 := 0 to 7 do
     1353          begin
     1354            Loc1 := Adjacent[V8];
     1355            if (Loc1 >= 0) and (Map[Loc1] and fTerrain < fGrass) then
     1356            begin
     1357              f1 := Formation[Loc1];
     1358              if (f1 >= 0) and (f1 < maxCOD) and
     1359                ((OceanSize[f1] >= 8) or (OceanPresence[f1] and not
     1360                (1 shl me) <> 0)) then
     1361              begin // prefer non-coastal cities
     1362                Dec(Score, 18);
     1363                break;
     1364              end;
     1365            end;
     1366          end;
     1367          if Score > BestScore then
     1368          begin
     1369            BestScore := Score;
     1370            cixNewCapital := cix;
     1371          end;
     1372        end;
    11711373  end;
    11721374
    1173 if (RO.NatBuilt[imPalace]=0) and (cixNewCapital<0) then
    1174   begin // palace was destroyed, build new one
    1175   Center:=CenterOfEmpire;
    1176   BestScore:=0;
    1177   for cix:=0 to RO.nCity-1 do with MyCity[cix] do
    1178     if (Loc>=0) and (Flags and chCaptured=0) then
    1179       begin // evaluate city as new capital
    1180       Score:=Size*12 + 512-Distance(Loc,Center);
    1181       V8_to_Loc(Loc,Adjacent);
    1182       for V8:=0 to 7 do
    1183         begin
    1184         Loc1:=Adjacent[V8];
    1185         if (Loc1>=0) and (Map[Loc1] and fTerrain<fGrass) then
    1186           begin
    1187           f1:=Formation[Loc1];
    1188           if (f1>=0) and (f1<maxCOD)
    1189             and ((OceanSize[f1]>=8) or (OceanPresence[f1] and not (1 shl me)<>0)) then
    1190             begin // prefer non-coastal cities
    1191             dec(Score,18);
    1192             break
    1193             end
     1375  AlgaeAvailable := (RO.NatBuilt[imAlgae] = 0) and
     1376    (RO.Tech[Imp[imAlgae].Preq] >= tsApplicable);
     1377  for cix := 0 to RO.nCity - 1 do
     1378    with MyCity[cix] do
     1379      if (Loc >= 0) and (Project and (cpImp + cpIndex) = cpImp + imAlgae) then
     1380        AlgaeAvailable := False;
     1381
     1382  for cix := 0 to RO.nCity - 1 do
     1383    with MyCity[cix] do
     1384      if (Loc >= 0) and (Flags and chCaptured = 0) and LowPriority(cix) then
     1385        City_SetTiles(cix, 1 shl CityOwnTile); // free all tiles of low-prio cities
     1386  for DoLowPriority := False to True do
     1387    for cix := 0 to RO.nCity - 1 do
     1388      with MyCity[cix] do
     1389        if (Loc >= 0) and (Flags and chCaptured = 0) and
     1390          (LowPriority(cix) = DoLowPriority) then
     1391        begin
     1392          f := Formation[Loc];
     1393          IsCoastal := False;
     1394          IsPort := False;
     1395          V8_to_Loc(Loc, Adjacent);
     1396          for V8 := 0 to 7 do
     1397          begin
     1398            Loc1 := Adjacent[V8];
     1399            if (Loc1 >= 0) and (Map[Loc1] and fTerrain < fGrass) then
     1400            begin
     1401              IsCoastal := True;
     1402              f1 := Formation[Loc1];
     1403              if (f1 >= 0) and (f1 < maxCOD) and (OceanSize[f1] >= 8) and
     1404                (OceanPresence[f1] and not (1 shl me) <> 0) then
     1405              begin
     1406                IsPort := True;
     1407                break;
     1408              end;
     1409            end;
     1410          end;
     1411          if (City_CurrentUnitProject(cix) >= 0) and
     1412            (RO.Model[City_CurrentUnitProject(cix)].Kind <> mkSettler) then
     1413          begin
     1414            i := nModelCategory - 1;
     1415            while (i >= 0) and (City_CurrentUnitProject(cix) <> mixBest[i]) do
     1416              Dec(i);
     1417            IsUnitProjectObsolete := i < 0;
    11941418          end
    1195         end;
    1196       if Score>BestScore then
    1197         begin
    1198         BestScore:=Score;
    1199         cixNewCapital:=cix
    1200         end
    1201       end
    1202   end;
    1203 
    1204 AlgaeAvailable:= (RO.NatBuilt[imAlgae]=0) and (RO.Tech[Imp[imAlgae].Preq]>=tsApplicable);
    1205 for cix:=0 to RO.nCity-1 do with MyCity[cix] do
    1206   if (Loc>=0) and (Project and (cpImp+cpIndex)=cpImp+imAlgae) then
    1207     AlgaeAvailable:=false;
    1208 
    1209 for cix:=0 to RO.nCity-1 do with MyCity[cix] do
    1210   if (Loc>=0) and (Flags and chCaptured=0) and LowPriority(cix) then
    1211     City_SetTiles(cix,1 shl CityOwnTile); // free all tiles of low-prio cities
    1212 for DoLowPriority:=false to true do
    1213   for cix:=0 to RO.nCity-1 do with MyCity[cix] do
    1214     if (Loc>=0) and (Flags and chCaptured=0) and (LowPriority(cix)=DoLowPriority) then
    1215       begin
    1216       f:=Formation[Loc];
    1217       IsCoastal:=false;
    1218       IsPort:=false;
    1219       V8_to_Loc(Loc,Adjacent);
    1220       for V8:=0 to 7 do
    1221         begin
    1222         Loc1:=Adjacent[V8];
    1223         if (Loc1>=0) and (Map[Loc1] and fTerrain<fGrass) then
    1224           begin
    1225           IsCoastal:=true;
    1226           f1:=Formation[Loc1];
    1227           if (f1>=0) and (f1<maxCOD) and (OceanSize[f1]>=8)
    1228             and (OceanPresence[f1] and not (1 shl me)<>0) then
     1419          else
     1420            IsUnitProjectObsolete := False;
     1421          if RO.Government = gDespotism then
     1422          begin
     1423            nTownGuard := 0;
     1424            for uix := 0 to RO.nUn - 1 do
     1425              if (MyUnit[uix].mix = mixTownGuard) and (MyUnit[uix].Loc = Loc) then
     1426                Inc(nTownGuard);
     1427          end;
     1428
     1429          iix := City_CurrentImprovementProject(cix);
     1430          if (iix >= 0) and (iix < 28) or (iix = imPalace) or
     1431            (iix = imShipComp) or (iix = imShipPow) or (iix = imShipHab) then
     1432            City_OptimizeTiles(cix, rwMaxProd)
     1433          else if size < 8 then
     1434            City_OptimizeTiles(cix, rwMaxGrowth)
     1435          else
     1436            City_OptimizeTiles(cix, rwForceProd);
     1437
     1438          WillProduceColonyShip := False;
     1439          ProduceShipPart := -1;
     1440          for part := 0 to nShipPart - 1 do
     1441            if ColonyShipPlan[part].cixProducing = cix then
    12291442            begin
    1230             IsPort:=true;
    1231             break;
    1232             end
    1233           end
    1234         end;
    1235       if (City_CurrentUnitProject(cix)>=0)
    1236         and (RO.Model[City_CurrentUnitProject(cix)].Kind<>mkSettler) then
    1237         begin
    1238         i:=nModelCategory-1;
    1239         while (i>=0) and (City_CurrentUnitProject(cix)<>mixBest[i]) do
    1240           dec(i);
    1241         IsUnitProjectObsolete:= i<0;
    1242         end
    1243       else IsUnitProjectObsolete:=false;
    1244       if RO.Government=gDespotism then
    1245         begin
    1246         nTownGuard:=0;
    1247         for uix:=0 to RO.nUn-1 do
    1248           if (MyUnit[uix].mix=mixTownGuard) and (MyUnit[uix].Loc=Loc) then
    1249             inc(nTownGuard);
    1250         end;
    1251 
    1252       iix:=City_CurrentImprovementProject(cix);
    1253       if (iix>=0) and (iix<28)
    1254         or (iix=imPalace) or (iix=imShipComp) or (iix=imShipPow) or (iix=imShipHab) then
    1255         City_OptimizeTiles(cix,rwMaxProd)
    1256       else if size<8 then
    1257         City_OptimizeTiles(cix,rwMaxGrowth)
    1258       else City_OptimizeTiles(cix,rwForceProd);
    1259 
    1260       WillProduceColonyShip:=false;
    1261       ProduceShipPart:=-1;
    1262       for part:=0 to nShipPart-1 do
    1263         if ColonyShipPlan[part].cixProducing=cix then
    1264           begin
    1265           WillProduceColonyShip:=true;
    1266           ProduceShipPart:=ShipImpIndex[part];
    1267           end;
    1268 
    1269       if cix=cixNewCapital then
    1270         City_StartImprovement(cix,imPalace)
    1271       else if (iix>=0) and (iix<28) and ((1 shl iix) and WonderAvailable<>0) then
    1272         // complete wonder production first
    1273       else if (mixProduce>=0) and (City_CurrentUnitProject(cix)>=0)
    1274         and not IsUnitProjectObsolete
    1275         and ((Flags and chProduction=0)
    1276           or (RO.Model[City_CurrentUnitProject(cix)].Cap[mcLine]>0)
    1277           and (mixCount[City_CurrentUnitProject(cix)]<RO.nCity*(2+cix and 3))) then
    1278         // complete unit production first
    1279       else
    1280         begin
    1281         if ProduceShipPart>=0 then
    1282           begin
    1283           if (Built[imGranary]=0) and (Size<10) and City_Improvable(cix,imGranary) then
    1284             City_StartImprovement(cix,imGranary)
    1285           else if (Built[imAqueduct]=0) and City_Improvable(cix,imAqueduct) then
    1286             City_StartImprovement(cix,imAqueduct)
    1287           else if (Built[imAqueduct]>0) and (Size<12)
    1288             and (AlgaeAvailable or (Project and (cpImp+cpIndex)=cpImp+imAlgae)) then
    1289             City_StartImprovement(cix,imAlgae)
    1290           else if (Built[imFactory]=0) and City_Improvable(cix,imFactory) then
    1291             City_StartImprovement(cix,imFactory)
    1292           else if (Built[imPower]+Built[imHydro]+Built[imNuclear]=0)
    1293             and (City_Improvable(cix,imPower)
    1294               or City_Improvable(cix,imHydro)
    1295               or City_Improvable(cix,imNuclear)) then
     1443              WillProduceColonyShip := True;
     1444              ProduceShipPart := ShipImpIndex[part];
     1445            end;
     1446
     1447          if cix = cixNewCapital then
     1448            City_StartImprovement(cix, imPalace)
     1449          else if (iix >= 0) and (iix < 28) and ((1 shl iix) and
     1450            WonderAvailable <> 0) then
     1451          // complete wonder production first
     1452          else if (mixProduce >= 0) and (City_CurrentUnitProject(cix) >= 0) and
     1453            not IsUnitProjectObsolete and ((Flags and chProduction = 0) or
     1454            (RO.Model[City_CurrentUnitProject(cix)].Cap[mcLine] > 0) and
     1455            (mixCount[City_CurrentUnitProject(cix)] < RO.nCity * (2 + cix and 3))) then
     1456          // complete unit production first
     1457          else
     1458          begin
     1459            if ProduceShipPart >= 0 then
    12961460            begin
    1297             if City_Improvable(cix,imHydro) then
    1298               City_StartImprovement(cix,imHydro)
    1299             else if City_Improvable(cix,imPower) then
    1300               City_StartImprovement(cix,imPower)
    1301             else City_StartImprovement(cix,imNuclear)
    1302             end
    1303           else if (Built[imMfgPlant]=0) and City_Improvable(cix,imMfgPlant) then
    1304             City_StartImprovement(cix,imMfgPlant)
    1305           else if City_Improvable(cix, ProduceShipPart) then
    1306             City_StartImprovement(cix,ProduceShipPart)
    1307           else ProduceShipPart:=-1;
    1308           end;
    1309         if ProduceShipPart<0 then
    1310           begin
    1311           ProjectComplete:= not City_HasProject(cix) or (Flags and chProduction<>0);
    1312           HasSettler:=false;
    1313           for uix:=0 to RO.nUn-1 do with MyUnit[uix] do
    1314             if (Loc>=0) and (Home=cix)
    1315               and (MyModel[mix].Kind=mkSettler) then
    1316               HasSettler:=true;
    1317           if ((RO.Government<>gDespotism) or (RO.nUn>=RO.nCity*4))
    1318             and not IsResearched(adMassProduction)
    1319             and (Built[imPalace]>0) and (RO.Wonder[woZeus].CityID=-1)
    1320             and City_Improvable(cix,woZeus) then
    1321             City_StartImprovement(cix,woZeus)
    1322           else if (City_CurrentImprovementProject(cix)>=0)
    1323             and (City_CurrentImprovementProject(cix)<28) then
    1324             begin// wonder already built, try to switch to different one
    1325             if (WonderAvailable and not WonderInWork>0)
    1326               and (IsCoastal or (WonderAvailable and not WonderInWork and not CoastalWonder>0)) then
     1461              if (Built[imGranary] = 0) and (Size < 10) and
     1462                City_Improvable(cix, imGranary) then
     1463                City_StartImprovement(cix, imGranary)
     1464              else if (Built[imAqueduct] = 0) and City_Improvable(cix, imAqueduct) then
     1465                City_StartImprovement(cix, imAqueduct)
     1466              else if (Built[imAqueduct] > 0) and (Size < 12) and
     1467                (AlgaeAvailable or (Project and (cpImp + cpIndex) =
     1468                cpImp + imAlgae)) then
     1469                City_StartImprovement(cix, imAlgae)
     1470              else if (Built[imFactory] = 0) and City_Improvable(cix, imFactory) then
     1471                City_StartImprovement(cix, imFactory)
     1472              else if (Built[imPower] + Built[imHydro] + Built[imNuclear] = 0) and
     1473                (City_Improvable(cix, imPower) or
     1474                City_Improvable(cix, imHydro) or City_Improvable(cix, imNuclear)) then
    13271475              begin
    1328               iix:=ChooseWonderToBuild(WonderAvailable and not WonderInWork,IsCoastal);
    1329               City_StartImprovement(cix,iix);
    1330               WonderInWork:=WonderInWork or (1 shl iix);
     1476                if City_Improvable(cix, imHydro) then
     1477                  City_StartImprovement(cix, imHydro)
     1478                else if City_Improvable(cix, imPower) then
     1479                  City_StartImprovement(cix, imPower)
     1480                else
     1481                  City_StartImprovement(cix, imNuclear);
    13311482              end
    1332             else City_StopProduction(cix); 
    1333             end
    1334           else if (Built[imPalace]>0) and (RO.NatBuilt[imSpacePort]=0)
    1335             and City_Improvable(cix,imSpacePort) then
    1336             City_StartImprovement(cix,imSpacePort)
    1337           else if Built[imPalace]+Built[imCourt]+Built[imTownHall]=0 then
     1483              else if (Built[imMfgPlant] = 0) and City_Improvable(cix, imMfgPlant) then
     1484                City_StartImprovement(cix, imMfgPlant)
     1485              else if City_Improvable(cix, ProduceShipPart) then
     1486                City_StartImprovement(cix, ProduceShipPart)
     1487              else
     1488                ProduceShipPart := -1;
     1489            end;
     1490            if ProduceShipPart < 0 then
    13381491            begin
    1339             if City_Improvable(cix,imCourt) then
    1340               City_StartImprovement(cix,imCourt)
    1341             else City_StartImprovement(cix,imTownHall);
    1342             end
    1343           else if not HasSettler and (RO.nUn>=RO.nCity*4) then
    1344             begin
    1345             if ProjectComplete and (City_CurrentUnitProject(cix)<>0) then
     1492              ProjectComplete :=
     1493                not City_HasProject(cix) or (Flags and chProduction <> 0);
     1494              HasSettler := False;
     1495              for uix := 0 to RO.nUn - 1 do
     1496                with MyUnit[uix] do
     1497                  if (Loc >= 0) and (Home = cix) and
     1498                    (MyModel[mix].Kind = mkSettler) then
     1499                    HasSettler := True;
     1500              if ((RO.Government <> gDespotism) or (RO.nUn >= RO.nCity * 4)) and
     1501                not IsResearched(adMassProduction) and (Built[imPalace] > 0) and
     1502                (RO.Wonder[woZeus].CityID = -1) and City_Improvable(cix, woZeus) then
     1503                City_StartImprovement(cix, woZeus)
     1504              else if (City_CurrentImprovementProject(cix) >= 0) and
     1505                (City_CurrentImprovementProject(cix) < 28) then
     1506              begin// wonder already built, try to switch to different one
     1507                if (WonderAvailable and not WonderInWork > 0) and
     1508                  (IsCoastal or (WonderAvailable and not WonderInWork and
     1509                  not CoastalWonder > 0)) then
     1510                begin
     1511                  iix := ChooseWonderToBuild(WonderAvailable and not
     1512                    WonderInWork, IsCoastal);
     1513                  City_StartImprovement(cix, iix);
     1514                  WonderInWork := WonderInWork or (1 shl iix);
     1515                end
     1516                else
     1517                  City_StopProduction(cix);
     1518              end
     1519              else if (Built[imPalace] > 0) and (RO.NatBuilt[imSpacePort] = 0) and
     1520                City_Improvable(cix, imSpacePort) then
     1521                City_StartImprovement(cix, imSpacePort)
     1522              else if Built[imPalace] + Built[imCourt] + Built[imTownHall] = 0 then
    13461523              begin
    1347               mix:=RO.nModel-1;
    1348               while RO.Model[mix].Kind<>mkSettler do dec(mix);
    1349               City_StartUnitProduction(cix,mix)
     1524                if City_Improvable(cix, imCourt) then
     1525                  City_StartImprovement(cix, imCourt)
     1526                else
     1527                  City_StartImprovement(cix, imTownHall);
    13501528              end
    1351             end
    1352           else if (RO.Government=gDespotism) and (nTownGuard<2)
    1353             and (nTownGuard*2+3<Size) then
    1354             begin
    1355             if ProjectComplete then
    1356               City_StartUnitProduction(cix,2)
    1357             end
    1358           else if (RO.Government=gFundamentalism)
    1359             and (Size>=8) and (Built[imAqueduct]=0)
    1360             and City_Improvable(cix,imAqueduct) and (RO.nUn>=RO.nCity*4) then
    1361             begin
    1362             if ProjectComplete then
    1363               City_StartImprovement(cix,imAqueduct)
    1364             end
    1365           else if ProjectComplete then
    1366             begin // low prio projects
    1367             ImportantCity:=WillProduceColonyShip or (Built[imPalace]>0);
    1368             for iix:=0 to 27 do if Built[iix]>0 then
    1369               ImportantCity:=true;
    1370             City_GetReportNew(cix, Report);
    1371             if (Report.Corruption>=6) and (RO.nUn>=RO.nCity*4)
    1372               and City_Improvable(cix,imCourt) then
    1373               City_StartImprovement(cix,imCourt)
    1374             else if (Report.Production>=WonderProductionThreshold)
    1375               and (WonderAvailable and not WonderInWork>0)
    1376               and (IsCoastal or (WonderAvailable and not WonderInWork and not CoastalWonder>0))
    1377               and (Random>=(1+WonderInclination)/(RO.nCity+WonderInclination)) then
     1529              else if not HasSettler and (RO.nUn >= RO.nCity * 4) then
    13781530              begin
    1379               iix:=ChooseWonderToBuild(WonderAvailable and not WonderInWork,IsCoastal);
    1380               City_StartImprovement(cix,iix);
    1381               WonderInWork:=WonderInWork or (1 shl iix);
     1531                if ProjectComplete and (City_CurrentUnitProject(cix) <> 0) then
     1532                begin
     1533                  mix := RO.nModel - 1;
     1534                  while RO.Model[mix].Kind <> mkSettler do
     1535                    Dec(mix);
     1536                  City_StartUnitProduction(cix, mix);
     1537                end;
    13821538              end
    1383             else if (ImportantCity or (Loc mod 9=0)) and (Built[imWalls]=0)
    1384               and City_Improvable(cix,imWalls) then
    1385               City_StartImprovement(cix,imWalls)
    1386             else if IsPort and (ImportantCity or (Loc mod 7=0))
    1387               and (Built[imCoastalFort]=0)
    1388               and City_Improvable(cix,imCoastalFort) then
    1389               City_StartImprovement(cix,imCoastalFort)
     1539              else if (RO.Government = gDespotism) and (nTownGuard < 2) and
     1540                (nTownGuard * 2 + 3 < Size) then
     1541              begin
     1542                if ProjectComplete then
     1543                  City_StartUnitProduction(cix, 2);
     1544              end
     1545              else if (RO.Government = gFundamentalism) and
     1546                (Size >= 8) and (Built[imAqueduct] = 0) and
     1547                City_Improvable(cix, imAqueduct) and (RO.nUn >= RO.nCity * 4) then
     1548              begin
     1549                if ProjectComplete then
     1550                  City_StartImprovement(cix, imAqueduct);
     1551              end
     1552              else if ProjectComplete then
     1553              begin // low prio projects
     1554                ImportantCity := WillProduceColonyShip or (Built[imPalace] > 0);
     1555                for iix := 0 to 27 do
     1556                  if Built[iix] > 0 then
     1557                    ImportantCity := True;
     1558                City_GetReportNew(cix, Report);
     1559                if (Report.Corruption >= 6) and (RO.nUn >= RO.nCity * 4) and
     1560                  City_Improvable(cix, imCourt) then
     1561                  City_StartImprovement(cix, imCourt)
     1562                else if (Report.Production >= WonderProductionThreshold) and
     1563                  (WonderAvailable and not WonderInWork > 0) and
     1564                  (IsCoastal or (WonderAvailable and not WonderInWork and
     1565                  not CoastalWonder > 0)) and (Random >=
     1566                  (1 + WonderInclination) / (RO.nCity + WonderInclination)) then
     1567                begin
     1568                  iix := ChooseWonderToBuild(WonderAvailable and not
     1569                    WonderInWork, IsCoastal);
     1570                  City_StartImprovement(cix, iix);
     1571                  WonderInWork := WonderInWork or (1 shl iix);
     1572                end
     1573                else if (ImportantCity or (Loc mod 9 = 0)) and
     1574                  (Built[imWalls] = 0) and City_Improvable(cix, imWalls) then
     1575                  City_StartImprovement(cix, imWalls)
     1576                else if IsPort and (ImportantCity or (Loc mod 7 = 0)) and
     1577                  (Built[imCoastalFort] = 0) and City_Improvable(cix, imCoastalFort) then
     1578                  City_StartImprovement(cix, imCoastalFort)
    13901579            {else if (ImportantCity or (Loc mod 11=0)) and (Built[imMissileBat]=0)
    13911580              and City_Improvable(cix,imMissileBat) then
    13921581              City_StartImprovement(cix,imMissileBat)}
    1393             else if IsPort and (not SpezializeShipProduction or (f<0)
    1394                 or (f>=maxCOD) or (ContinentPresence[f]=1 shl me))
    1395               and (Built[imDockyard]=0)
    1396               and City_Improvable(cix,imDockyard) then
    1397               City_StartImprovement(cix,imDockyard)
    1398             else if IsPort and (mixShip>=0) and
    1399               (not SpezializeShipProduction or (f<0) or (f>=maxCOD) or
    1400                 (ContinentPresence[f]=1 shl me)) then
    1401               City_StartUnitProduction(cix,mixShip)
    1402             else if (Built[imBarracks]+Built[imMilAcademy]=0)
    1403               and City_Improvable(cix,imBarracks) then
    1404               City_StartImprovement(cix,imBarracks)
    1405             else if mixProduce>=0 then
    1406               City_StartUnitProduction(cix,mixProduce)
    1407             else if City_HasProject(cix) then
    1408               City_StopProduction(cix);
    1409             end
    1410           end;
    1411         end;
    1412       if (City_CurrentImprovementProject(cix)=imCourt)
    1413         and (Built[imTownHall]>0)
    1414         and (prod>=imp[imCourt].cost*BuildCostMod[G.Difficulty[me]] div 12
    1415           -(imp[imTownHall].cost*BuildCostMod[G.Difficulty[me]] div 12)*2 div 3) then
    1416         City_RebuildImprovement(cix,imTownHall)
    1417       else if (RO.Government=gFundamentalism) and not WillProduceColonyShip then
    1418         for iix:=28 to nImp-1 do
    1419           if (Built[iix]>0)
    1420             and ((iix in [imTemple,imTheater,imCathedral,imColosseum,imLibrary,
    1421               imUniversity,imResLab,imHarbor,imSuperMarket])
    1422               or (iix in [imFactory,imMfgPlant,imPower,imHydro,imNuclear])
    1423                 and (Built[imRecycling]=0)) then
    1424             begin
    1425             if City_RebuildImprovement(cix,iix)<rExecuted then
    1426               City_SellImprovement(cix,iix);
    1427             break
    1428             end
    1429       end
     1582                else if IsPort and (not SpezializeShipProduction or
     1583                  (f < 0) or (f >= maxCOD) or (ContinentPresence[f] = 1 shl me)) and
     1584                  (Built[imDockyard] = 0) and City_Improvable(cix, imDockyard) then
     1585                  City_StartImprovement(cix, imDockyard)
     1586                else if IsPort and (mixShip >= 0) and
     1587                  (not SpezializeShipProduction or (f < 0) or
     1588                  (f >= maxCOD) or (ContinentPresence[f] = 1 shl me)) then
     1589                  City_StartUnitProduction(cix, mixShip)
     1590                else if (Built[imBarracks] + Built[imMilAcademy] = 0) and
     1591                  City_Improvable(cix, imBarracks) then
     1592                  City_StartImprovement(cix, imBarracks)
     1593                else if mixProduce >= 0 then
     1594                  City_StartUnitProduction(cix, mixProduce)
     1595                else if City_HasProject(cix) then
     1596                  City_StopProduction(cix);
     1597              end;
     1598            end;
     1599          end;
     1600          if (City_CurrentImprovementProject(cix) = imCourt) and
     1601            (Built[imTownHall] > 0) and (prod >= imp[imCourt].cost *
     1602            BuildCostMod[G.Difficulty[me]] div 12 -
     1603            (imp[imTownHall].cost * BuildCostMod[G.Difficulty[me]] div 12) *
     1604            2 div 3) then
     1605            City_RebuildImprovement(cix, imTownHall)
     1606          else if (RO.Government = gFundamentalism) and not WillProduceColonyShip then
     1607            for iix := 28 to nImp - 1 do
     1608              if (Built[iix] > 0) and
     1609                ((iix in [imTemple, imTheater, imCathedral, imColosseum,
     1610                imLibrary, imUniversity, imResLab, imHarbor, imSuperMarket]) or
     1611                (iix in [imFactory, imMfgPlant, imPower, imHydro, imNuclear]) and
     1612                (Built[imRecycling] = 0)) then
     1613              begin
     1614                if City_RebuildImprovement(cix, iix) < rExecuted then
     1615                  City_SellImprovement(cix, iix);
     1616                break;
     1617              end;
     1618        end;
    14301619end;
    14311620
    14321621function TBarbarina.Barbarina_ChooseResearchAdvance: integer;
    14331622var
    1434 nPreq,rmix,rmixChosen,i,MaxWeight,MaxDefense,ChosenPreq: integer;
    1435 NeedSeaUnits,ready: boolean;
    1436 ModelExists: set of 0..nModelCategory-1;
    1437 known: array[0..nAdv-1] of integer;
     1623  nPreq, rmix, rmixChosen, i, MaxWeight, MaxDefense, ChosenPreq: integer;
     1624  NeedSeaUnits, ready: boolean;
     1625  ModelExists: set of 0..nModelCategory - 1;
     1626  known: array[0..nAdv - 1] of integer;
    14381627
    14391628  procedure ChoosePreq(ad: integer);
    14401629  var
    1441   i: integer;
    1442   PreqOk: boolean;
     1630    i: integer;
     1631    PreqOk: boolean;
    14431632  begin
    1444   assert(RO.Tech[ad]<tsApplicable);
    1445   if known[ad]=0 then
     1633    assert(RO.Tech[ad] < tsApplicable);
     1634    if known[ad] = 0 then
    14461635    begin
    1447     known[ad]:=1;
    1448     PreqOk:=true;
    1449     if not (ad in [adScience,adMassProduction]) and (RO.Tech[ad]<tsSeen) then
    1450       for i:=0 to 1 do
    1451         if (AdvPreq[ad,i]>=0) and (RO.Tech[AdvPreq[ad,i]]<tsApplicable) then
    1452           begin
    1453           PreqOk:=false;
    1454           ChoosePreq(AdvPreq[ad,i]);
    1455           end;
    1456     if PreqOk then
    1457       begin
    1458       inc(nPreq);
    1459       if random(nPreq)=0 then ChosenPreq:=ad
    1460       end
    1461     end
     1636      known[ad] := 1;
     1637      PreqOk := True;
     1638      if not (ad in [adScience, adMassProduction]) and (RO.Tech[ad] < tsSeen) then
     1639        for i := 0 to 1 do
     1640          if (AdvPreq[ad, i] >= 0) and (RO.Tech[AdvPreq[ad, i]] < tsApplicable) then
     1641          begin
     1642            PreqOk := False;
     1643            ChoosePreq(AdvPreq[ad, i]);
     1644          end;
     1645      if PreqOk then
     1646      begin
     1647        Inc(nPreq);
     1648        if random(nPreq) = 0 then
     1649          ChosenPreq := ad;
     1650      end;
     1651    end;
    14621652  end;
    14631653
    14641654begin
    1465 // check military research
    1466 rmixChosen:=-1;
    1467 ModelExists:=[];
    1468 for rmix:=nResearchModel-1 downto 0 do with ResearchModel[rmix] do
    1469   if not (Category in ModelExists)
    1470     and ((adStop<0) or not IsResearched(adStop)) then
     1655  // check military research
     1656  rmixChosen := -1;
     1657  ModelExists := [];
     1658  for rmix := nResearchModel - 1 downto 0 do
     1659    with ResearchModel[rmix] do
     1660      if not (Category in ModelExists) and ((adStop < 0) or not
     1661        IsResearched(adStop)) then
     1662      begin
     1663        MaxWeight := 0;
     1664        case Domain of
     1665          dGround:
     1666          begin
     1667            if IsResearched(adWarriorCode) then
     1668              MaxWeight := 5;
     1669            if IsResearched(adHorsebackRiding) then
     1670              MaxWeight := 7;
     1671            if IsResearched(adAutomobile) then
     1672              MaxWeight := 10;
     1673          end;
     1674          dSea:
     1675          begin
     1676            if IsResearched(adMapMaking) then
     1677              MaxWeight := 5;
     1678            if IsResearched(adSeaFaring) then
     1679              MaxWeight := 7;
     1680            if IsResearched(adSteel) then
     1681              MaxWeight := 9;
     1682          end;
     1683          dAir:
     1684          begin
     1685            if IsResearched(adFlight) then
     1686              MaxWeight := 5;
     1687            if IsResearched(adAdvancedFlight) then
     1688              MaxWeight := 7;
     1689          end;
     1690        end;
     1691        if Domain = dGround then
     1692          MaxDefense := 2
     1693        else
     1694          MaxDefense := 3;
     1695        if IsResearched(adSteel) then
     1696          Inc(MaxDefense);
     1697        ready := (MaxWeight >= Weight) and (MaxDefense >= Cap[mcDefense]);
     1698        if ready then
     1699          for i := 0 to nFeature - 1 do
     1700            if (Cap[i] > 0) and (Feature[i].Preq <> preNone) and
     1701              ((Feature[i].Preq < 0) or not IsResearched(Feature[i].Preq)) then
     1702              ready := False;
     1703        if ready then
     1704        begin
     1705          for i := 0 to nUpgrade - 1 do
     1706            if (Upgrades and (1 shl i) <> 0) and not
     1707              IsResearched(Upgrade[Domain, i].Preq) then
     1708              ready := False;
     1709        end;
     1710        if ready then
     1711        begin
     1712          include(ModelExists, Category);
     1713          if not IsModelAvailable(rmix) then
     1714            rmixChosen := rmix;
     1715        end;
     1716      end;
     1717  if rmixChosen >= 0 then
     1718    with ResearchModel[rmixChosen] do
    14711719    begin
    1472     MaxWeight:=0;
    1473     case Domain of
    1474       dGround:
    1475         begin
    1476         if IsResearched(adWarriorCode) then MaxWeight:=5;
    1477         if IsResearched(adHorsebackRiding) then MaxWeight:=7;
    1478         if IsResearched(adAutomobile) then MaxWeight:=10;
    1479         end;
    1480       dSea:
    1481         begin
    1482         if IsResearched(adMapMaking) then MaxWeight:=5;
    1483         if IsResearched(adSeaFaring) then MaxWeight:=7;
    1484         if IsResearched(adSteel) then MaxWeight:=9;
    1485         end;
    1486       dAir:
    1487         begin
    1488         if IsResearched(adFlight) then MaxWeight:=5;
    1489         if IsResearched(adAdvancedFlight) then MaxWeight:=7;
    1490         end;
    1491       end;
    1492     if Domain=dGround then MaxDefense:=2
    1493     else MaxDefense:=3;
    1494     if IsResearched(adSteel) then inc(MaxDefense);
    1495     ready:= (MaxWeight>=Weight) and (MaxDefense>=Cap[mcDefense]);
    1496     if ready then
    1497       for i:=0 to nFeature-1 do
    1498         if (Cap[i]>0) and (Feature[i].Preq<>preNone)
    1499           and ((Feature[i].Preq<0) or not IsResearched(Feature[i].Preq)) then
    1500           ready:=false;
    1501     if ready then
    1502       begin
    1503       for i:=0 to nUpgrade-1 do
    1504         if (Upgrades and (1 shl i)<>0) and not IsResearched(Upgrade[Domain,i].Preq) then
    1505           ready:=false;
    1506       end;
    1507     if ready then
    1508       begin
    1509       include(ModelExists,Category);
    1510       if not IsModelAvailable(rmix) then
    1511         rmixChosen:=rmix;
    1512       end
     1720      PrepareNewModel(Domain);
     1721      for i := 0 to nFeature - 1 do
     1722        if (i < 2) or (Cap[i] > 0) then
     1723          SetNewModelFeature(i, Cap[i]);
     1724      if RO.Wonder[woSun].EffectiveOwner = me then
     1725      begin
     1726        //if Cap[mcWeapons]>=2*Cap[mcArmor] then
     1727        //  SetNewModelFeature(mcFirst,1);
     1728        if Cap[mcWeapons] >= Cap[mcArmor] then
     1729          SetNewModelFeature(mcWill, 1);
     1730      end;
     1731      Result := adMilitary;
     1732      exit;
    15131733    end;
    1514 if rmixChosen>=0 then with ResearchModel[rmixChosen] do
     1734
     1735  NeedSeaUnits := True;
     1736  i := 0;
     1737  while (i < nResearchOrder) and (not NeedSeaUnits and (ResearchOrder[i] < 0) or
     1738      IsResearched(abs(ResearchOrder[i]))) do
     1739    Inc(i);
     1740  if i >= nResearchOrder then // list done, continue with future tech
    15151741  begin
    1516   PrepareNewModel(Domain);
    1517   for i:=0 to nFeature-1 do if (i<2) or (Cap[i]>0) then
    1518     SetNewModelFeature(i,Cap[i]);
    1519   if RO.Wonder[woSun].EffectiveOwner=me then
    1520     begin
    1521     //if Cap[mcWeapons]>=2*Cap[mcArmor] then
    1522     //  SetNewModelFeature(mcFirst,1);
    1523     if Cap[mcWeapons]>=Cap[mcArmor] then
    1524       SetNewModelFeature(mcWill,1);
    1525     end;
    1526   result:=adMilitary;
    1527   exit;
     1742    if random(2) = 1 then
     1743      Result := futArtificialIntelligence
     1744    else
     1745      Result := futMaterialTechnology;
     1746  end
     1747  else
     1748  begin
     1749    FillChar(known, SizeOf(known), 0);
     1750    nPreq := 0;
     1751    ChosenPreq := -1;
     1752    ChoosePreq(abs(ResearchOrder[i]));
     1753    assert(nPreq > 0);
     1754    Result := ChosenPreq;
    15281755  end;
    1529 
    1530 NeedSeaUnits:=true;
    1531 i:=0;
    1532 while (i<nResearchOrder)
    1533   and (not NeedSeaUnits and (ResearchOrder[i]<0)
    1534     or IsResearched(abs(ResearchOrder[i]))) do
    1535   inc(i);
    1536 if i>=nResearchOrder then // list done, continue with future tech
    1537   begin
    1538   if random(2)=1 then
    1539     result:=futArtificialIntelligence
    1540   else result:=futMaterialTechnology;
    1541   end
    1542 else
    1543   begin
    1544   FillChar(known,SizeOf(known),0);
    1545   nPreq:=0;
    1546   ChosenPreq:=-1;
    1547   ChoosePreq(abs(ResearchOrder[i]));
    1548   assert(nPreq>0);
    1549   result:=ChosenPreq
    1550   end
    15511756end;
    15521757
    15531758function TBarbarina.Barbarina_WantCheckNegotiation(Nation: integer): boolean;
    15541759begin
    1555 if (RO.Tech[adTheRepublic]<tsSeen) and (RO.Tech[adTheology]>=tsApplicable)
    1556   and (RO.Tech[adGunPowder]>=tsApplicable)
    1557   and (RO.EnemyReport[Nation].Tech[adTheRepublic]>=tsApplicable) then
    1558   result:=true
    1559 else result:=false;
     1760  if (RO.Tech[adTheRepublic] < tsSeen) and (RO.Tech[adTheology] >= tsApplicable) and
     1761    (RO.Tech[adGunPowder] >= tsApplicable) and
     1762    (RO.EnemyReport[Nation].Tech[adTheRepublic] >= tsApplicable) then
     1763    Result := True
     1764  else
     1765    Result := False;
    15601766end;
    15611767
    15621768procedure TBarbarina.Barbarina_DoCheckNegotiation;
    15631769begin
    1564 if RO.Tech[adTheRepublic]>=tsSeen then exit; // default reaction
    1565 if MyLastAction=scContact then
     1770  if RO.Tech[adTheRepublic] >= tsSeen then
     1771    exit; // default reaction
     1772  if MyLastAction = scContact then
    15661773  begin
    1567   MyAction:=scDipOffer;
    1568   MyOffer.nDeliver:=1;
    1569   MyOffer.nCost:=1;
    1570   if (RO.Tech[adTheology]>=tsApplicable)
    1571     and (RO.EnemyReport[Opponent].Tech[adTheology]<tsSeen) then
    1572     MyOffer.Price[0]:=opTech+adTheology
    1573   else MyOffer.Price[0]:=opChoose;
    1574   MyOffer.Price[1]:=opTech+adTheRepublic;
     1774    MyAction := scDipOffer;
     1775    MyOffer.nDeliver := 1;
     1776    MyOffer.nCost := 1;
     1777    if (RO.Tech[adTheology] >= tsApplicable) and
     1778      (RO.EnemyReport[Opponent].Tech[adTheology] < tsSeen) then
     1779      MyOffer.Price[0] := opTech + adTheology
     1780    else
     1781      MyOffer.Price[0] := opChoose;
     1782    MyOffer.Price[1] := opTech + adTheRepublic;
    15751783  end
    1576 else if OppoAction=scDipAccept then
    1577 else if OppoAction=scDipOffer then
     1784  else if OppoAction = scDipAccept then
     1785  else if OppoAction = scDipOffer then
    15781786  begin
    1579   if (OppoOffer.nDeliver=1) and (OppoOffer.Price[0]=opTech+adTheRepublic)
    1580     and ((OppoOffer.nCost=0)
    1581       or (OppoOffer.nCost=1)
    1582       and (OppoOffer.Price[1] and opMask=opTech)
    1583       and (RO.Tech[OppoOffer.Price[1]-opTech]>=tsApplicable)) then
    1584     MyAction:=scDipAccept
    1585   else MyAction:=scDipBreak
     1787    if (OppoOffer.nDeliver = 1) and (OppoOffer.Price[0] = opTech + adTheRepublic) and
     1788      ((OppoOffer.nCost = 0) or (OppoOffer.nCost = 1) and
     1789      (OppoOffer.Price[1] and opMask = opTech) and
     1790      (RO.Tech[OppoOffer.Price[1] - opTech] >= tsApplicable)) then
     1791      MyAction := scDipAccept
     1792    else
     1793      MyAction := scDipBreak;
    15861794  end
    1587 else if OppoAction<>scDipBreak then
    1588   MyAction:=scDipBreak
     1795  else if OppoAction <> scDipBreak then
     1796    MyAction := scDipBreak;
    15891797end;
    15901798
    1591 function TBarbarina.Barbarina_WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean;
     1799function TBarbarina.Barbarina_WantNegotiation(Nation: integer;
     1800  NegoTime: TNegoTime): boolean;
    15921801var
    1593 uix,TestLoc,V8: integer;
    1594 Adjacent: TVicinity8Loc;
     1802  uix, TestLoc, V8: integer;
     1803  Adjacent: TVicinity8Loc;
    15951804begin
    1596 result:=false;
    1597 case NegoTime of
    1598   EnemyCalled:
    1599     result:=false;
    1600   EndOfTurn:
    1601     result:=false;
    1602   BeginOfTurn:
    1603     if RO.Turn>=RO.LastCancelTreaty[Nation]+CancelTreatyTurns then
    1604       begin
    1605       if (RO.Turn and 3=(Nation+$F-me) and 3) and (RO.Treaty[Nation]>trPeace) then
    1606         begin
    1607         DebugMessage(1, 'End alliance/friendly contact with P'+char(48+Nation));
    1608         NegoCause:=CancelTreaty;
    1609         result:=true
     1805  Result := False;
     1806  case NegoTime of
     1807    EnemyCalled:
     1808      Result := False;
     1809    EndOfTurn:
     1810      Result := False;
     1811    BeginOfTurn:
     1812      if RO.Turn >= RO.LastCancelTreaty[Nation] + CancelTreatyTurns then
     1813      begin
     1814        if (RO.Turn and 3 = (Nation + $F - me) and 3) and
     1815          (RO.Treaty[Nation] > trPeace) then
     1816        begin
     1817          DebugMessage(1, 'End alliance/friendly contact with P' + char(48 + Nation));
     1818          NegoCause := CancelTreaty;
     1819          Result := True;
    16101820        end
    1611       else if RO.Treaty[Nation]=trPeace then
     1821        else if RO.Treaty[Nation] = trPeace then
    16121822        begin // declare war now?
    1613         for uix:=0 to RO.nUn-1 do with MyUnit[uix] do
    1614           if (Loc>=0) and (MyModel[mix].Attack>0) then
    1615             begin
    1616             V8_to_Loc(Loc,Adjacent);
    1617             for V8:=0 to 7 do
     1823          for uix := 0 to RO.nUn - 1 do
     1824            with MyUnit[uix] do
     1825              if (Loc >= 0) and (MyModel[mix].Attack > 0) then
    16181826              begin
    1619               TestLoc:=Adjacent[V8];
    1620               if (TestLoc>=0) and (RO.Territory[TestLoc]=Nation)
    1621                 and ((Map[TestLoc] and fTerrain>=fGrass) or (Master>=0)
    1622                   or (MyModel[mix].Domain<>dGround))
    1623                 and ((Map[TestLoc] and fTerrain<fGrass) or (MyModel[mix].Domain<>dSea)) then
     1827                V8_to_Loc(Loc, Adjacent);
     1828                for V8 := 0 to 7 do
    16241829                begin
    1625                 DebugMessage(1, 'Declare war on P'+char(48+Nation));
    1626                 NegoCause:=CancelTreaty;
    1627                 result:=true;
    1628                 exit;
    1629                 end
    1630               end
    1631             end
    1632         end
    1633       end;
    1634   end
     1830                  TestLoc := Adjacent[V8];
     1831                  if (TestLoc >= 0) and (RO.Territory[TestLoc] = Nation) and
     1832                    ((Map[TestLoc] and fTerrain >= fGrass) or
     1833                    (Master >= 0) or (MyModel[mix].Domain <> dGround)) and
     1834                    ((Map[TestLoc] and fTerrain < fGrass) or
     1835                    (MyModel[mix].Domain <> dSea)) then
     1836                  begin
     1837                    DebugMessage(1, 'Declare war on P' + char(48 + Nation));
     1838                    NegoCause := CancelTreaty;
     1839                    Result := True;
     1840                    exit;
     1841                  end;
     1842                end;
     1843              end;
     1844        end;
     1845      end;
     1846  end;
    16351847end;
    16361848
    16371849procedure TBarbarina.Barbarina_DoNegotiation;
    16381850begin
    1639 if OppoAction=scDipStart then
     1851  if OppoAction = scDipStart then
    16401852  begin
    1641   if NegoCause=CancelTreaty then
    1642     MyAction:=scDipCancelTreaty
    1643   end
     1853    if NegoCause = CancelTreaty then
     1854      MyAction := scDipCancelTreaty;
     1855  end;
    16441856end;
    16451857
    16461858procedure TBarbarina.MakeColonyShipPlan;
    16471859var
    1648 i,V21,V21C,CityLoc,Loc1,part,cix,BestValue,TestValue,FoodCount,ProdCount,
    1649   ProdExtra,Score,BestScore: integer;
    1650 Tile: cardinal;
    1651 ok,check: boolean;
    1652 Radius,RadiusC: TVicinity21Loc;
     1860  i, V21, V21C, CityLoc, Loc1, part, cix, BestValue, TestValue, FoodCount,
     1861  ProdCount, ProdExtra, Score, BestScore: integer;
     1862  Tile: cardinal;
     1863  ok, check: boolean;
     1864  Radius, RadiusC: TVicinity21Loc;
    16531865begin
    1654 for part:=0 to nShipPart-1 do
     1866  for part := 0 to nShipPart - 1 do
    16551867  begin
    1656   ColonyShipPlan[part].cixProducing:=-1;
    1657   ColonyShipPlan[part].nLocResource:=0;
    1658   ColonyShipPlan[part].nLocFoundCity:=0;
     1868    ColonyShipPlan[part].cixProducing := -1;
     1869    ColonyShipPlan[part].nLocResource := 0;
     1870    ColonyShipPlan[part].nLocFoundCity := 0;
    16591871  end;
    1660 if RO.Tech[adMassProduction]>=tsApplicable then // able to recognize ressources yet
     1872  if RO.Tech[adMassProduction] >= tsApplicable then // able to recognize ressources yet
    16611873  begin
    1662   // check already existing cities
    1663   for cix:=0 to RO.nCity-1 do with MyCity[cix] do if Loc>=0 then
     1874    // check already existing cities
     1875    for cix := 0 to RO.nCity - 1 do
     1876      with MyCity[cix] do
     1877        if Loc >= 0 then
     1878        begin
     1879          V21_to_Loc(Loc, Radius);
     1880          for V21 := 1 to 26 do
     1881          begin
     1882            Loc1 := Radius[V21];
     1883            if Loc1 >= 0 then
     1884            begin
     1885              Tile := RO.Map[Loc1];
     1886              if Tile and fModern <> 0 then
     1887              begin
     1888                part := (Tile and fModern) shr 25 - 1;
     1889                if RO.Ship[me].Parts[part] < ShipNeed[part] then
     1890                  // not enough of this kind already
     1891                begin
     1892                  ok := True;
     1893                  if ColonyShipPlan[part].cixProducing >= 0 then
     1894                  begin // another city is already assigned to this ship part, choose one of the two
     1895                    TestValue := (ID and $FFF) shl 4 + ((ID shr 12) + 15 - me) and $F;
     1896                    BestValue :=
     1897                      (MyCity[ColonyShipPlan[part].cixProducing].ID and $FFF) shl
     1898                      4 + ((MyCity[ColonyShipPlan[part].cixProducing].ID shr 12) +
     1899                      15 - me) and $F;
     1900                    if TestValue <= BestValue then
     1901                      ok := False;
     1902                  end;
     1903                  if ok then
     1904                    ColonyShipPlan[part].cixProducing := cix;
     1905                end;
     1906              end;
     1907            end;
     1908          end;
     1909        end;
     1910
     1911    // for parts without existing city, look for location of city to found
     1912    check := False;
     1913    for part := 0 to nShipPart - 1 do
     1914      if (RO.Ship[me].Parts[part] < ShipNeed[part]) // not enough of this kind already
     1915        and (ColonyShipPlan[part].cixProducing < 0) then // no city to produce
     1916        check := True;
     1917    if check then
    16641918    begin
    1665     V21_to_Loc(Loc, Radius);
    1666     for V21:=1 to 26 do
    1667       begin
    1668       Loc1:=Radius[V21];
    1669       if Loc1>=0 then
    1670         begin
    1671         Tile:=RO.Map[Loc1];
    1672         if Tile and fModern<>0 then
    1673           begin
    1674           part:=(Tile and fModern) shr 25 -1;
    1675           if RO.Ship[me].Parts[part]<ShipNeed[part] then // not enough of this kind already
    1676             begin
    1677             ok:=true;
    1678             if ColonyShipPlan[part].cixProducing>=0 then
    1679               begin // another city is already assigned to this ship part, choose one of the two
    1680               TestValue:=(ID and $FFF) shl 4
    1681                 + ((ID shr 12)+15-me) and $F;
    1682               BestValue:=(MyCity[ColonyShipPlan[part].cixProducing].ID and $FFF) shl 4
    1683                 + ((MyCity[ColonyShipPlan[part].cixProducing].ID shr 12)+15-me) and $F;
    1684               if TestValue<=BestValue then
    1685                 ok:=false;
     1919      for Loc1 := 0 to MapSize - 1 do
     1920      begin
     1921        Tile := RO.Map[Loc1];
     1922        if Tile and fModern <> 0 then
     1923        begin
     1924          part := (Tile and fModern) shr 25 - 1;
     1925          if ColonyShipPlan[part].nLocResource < maxModern then
     1926          begin
     1927            ColonyShipPlan[part].LocResource[ColonyShipPlan[part].nLocResource] := Loc1;
     1928            Inc(ColonyShipPlan[part].nLocResource);
     1929          end;
     1930        end;
     1931      end;
     1932      for part := 0 to nShipPart - 1 do
     1933        if (RO.Ship[me].Parts[part] < ShipNeed[part]) // not enough of this kind already
     1934          and (ColonyShipPlan[part].cixProducing < 0) // no city to produce
     1935          and (ColonyShipPlan[part].nLocResource > 0) then // resource is known
     1936        begin
     1937          for i := 0 to ColonyShipPlan[part].nLocResource - 1 do
     1938          begin
     1939            BestScore := 0;
     1940            V21_to_Loc(ColonyShipPlan[part].LocResource[i], Radius);
     1941            for V21 := 1 to 26 do
     1942            begin // check all potential cities in range
     1943              CityLoc := Radius[V21];
     1944              if CityLoc >= 0 then
     1945              begin
     1946                Tile := RO.Map[CityLoc];
     1947                if (Tile and fTerrain <> fUNKNOWN) and
     1948                  ((Tile and fTerrain = fForest) or
     1949                  (Tile and fTerrain = fSwamp) or
     1950                  (Terrain[Tile and fTerrain].IrrEff > 0)) then
     1951                begin
     1952                  FoodCount := 0;
     1953                  ProdCount := 0;
     1954                  ProdExtra := 0;
     1955                  V21_to_Loc(CityLoc, RadiusC);
     1956                  for V21C := 1 to 26 do
     1957                  begin
     1958                    Loc1 := RadiusC[V21C];
     1959                    if Loc1 >= 0 then
     1960                    begin
     1961                      case RO.Map[Loc1] and (fTerrain or fSpecial) of
     1962                        fGrass, fGrass + fSpecial1, fSwamp: Inc(FoodCount);
     1963                        fHills, fHills + fSpecial1: Inc(ProdCount);
     1964                        fShore + fSpecial1, fDesert + fSpecial1, fPrairie + fSpecial1,
     1965                        fForest + fSpecial1:
     1966                          Inc(FoodCount, 2);
     1967                        fSwamp + fSpecial1, fShore + fSpecial2, fDesert + fSpecial2,
     1968                        fPrairie + fSpecial2, fTundra + fSpecial2, fArctic + fSpecial1,
     1969                        fHills + fSpecial2, fMountains + fSpecial1:
     1970                        begin
     1971                          Inc(ProdCount);
     1972                          Inc(ProdExtra);
     1973                        end;
     1974                      end;
     1975                    end;
     1976                  end;
     1977                  if FoodCount = 0 then
     1978                    Score := 0
     1979                  else
     1980                  begin
     1981                    if ProdCount > 7 then
     1982                      ProdCount := 7;
     1983                    if FoodCount < 5 then
     1984                      Dec(ProdCount, 5 - FoodCount);
     1985                    Score := ProdCount * 4 + ProdExtra * 8 + FoodCount;
     1986                    Score := Score shl 8 + ((CityLoc xor me) * 4567) mod 251;
     1987                    // some unexactness, random but always the same for this tile
     1988                  end;
     1989                  if Score > BestScore then
     1990                  begin
     1991                    BestScore := Score;
     1992                    ColonyShipPlan[part].LocFoundCity[
     1993                      ColonyShipPlan[part].nLocFoundCity] :=
     1994                      CityLoc;
     1995                  end;
     1996                end;
    16861997              end;
    1687             if ok then
    1688               ColonyShipPlan[part].cixProducing:=cix;
    1689             end
    1690           end
    1691         end
    1692       end
     1998            end;
     1999            if BestScore > 0 then
     2000              Inc(ColonyShipPlan[part].nLocFoundCity);
     2001          end;
     2002        end;
    16932003    end;
    1694 
    1695   // for parts without existing city, look for location of city to found
    1696   check:=false;
    1697   for part:=0 to nShipPart-1 do
    1698     if (RO.Ship[me].Parts[part]<ShipNeed[part]) // not enough of this kind already
    1699       and (ColonyShipPlan[part].cixProducing<0) then // no city to produce
    1700       check:=true;
    1701   if check then
    1702     begin
    1703     for Loc1:=0 to MapSize-1 do
    1704       begin
    1705       Tile:=RO.Map[Loc1];
    1706       if Tile and fModern<>0 then
    1707         begin
    1708         part:=(Tile and fModern) shr 25 -1;
    1709         if ColonyShipPlan[part].nLocResource<maxModern then
    1710           begin
    1711           ColonyShipPlan[part].LocResource[ColonyShipPlan[part].nLocResource]:=Loc1;
    1712           inc(ColonyShipPlan[part].nLocResource);
    1713           end;
    1714         end
    1715       end;
    1716     for part:=0 to nShipPart-1 do
    1717       if (RO.Ship[me].Parts[part]<ShipNeed[part]) // not enough of this kind already
    1718         and (ColonyShipPlan[part].cixProducing<0) // no city to produce
    1719         and (ColonyShipPlan[part].nLocResource>0) then // resource is known
    1720         begin
    1721         for i:=0 to ColonyShipPlan[part].nLocResource-1 do
    1722           begin
    1723           BestScore:=0;
    1724           V21_to_Loc(ColonyShipPlan[part].LocResource[i],Radius);
    1725           for V21:=1 to 26 do
    1726             begin // check all potential cities in range
    1727             CityLoc:=Radius[V21];
    1728             if CityLoc>=0 then
    1729               begin
    1730               Tile:=RO.Map[CityLoc];
    1731               if (Tile and fTerrain<>fUNKNOWN)
    1732                 and ((Tile and fTerrain=fForest)
    1733                   or (Tile and fTerrain=fSwamp)
    1734                   or (Terrain[Tile and fTerrain].IrrEff>0)) then
    1735                 begin
    1736                 FoodCount:=0;
    1737                 ProdCount:=0;
    1738                 ProdExtra:=0;
    1739                 V21_to_Loc(CityLoc,RadiusC);
    1740                 for V21C:=1 to 26 do
    1741                   begin
    1742                   Loc1:=RadiusC[V21C];
    1743                   if Loc1>=0 then
    1744                     begin
    1745                     case RO.Map[Loc1] and (fTerrain or fSpecial) of
    1746                       fGrass, fGrass+fSpecial1, fSwamp: inc(FoodCount);
    1747                       fHills, fHills+fSpecial1: inc(ProdCount);
    1748                       fShore+fSpecial1, fDesert+fSpecial1, fPrairie+fSpecial1,
    1749                         fForest+fSpecial1:
    1750                         inc(FoodCount,2);
    1751                       fSwamp+fSpecial1, fShore+fSpecial2, fDesert+fSpecial2,
    1752                       fPrairie+fSpecial2, fTundra+fSpecial2, fArctic+fSpecial1,
    1753                       fHills+fSpecial2, fMountains+fSpecial1:
    1754                         begin
    1755                         inc(ProdCount);
    1756                         inc(ProdExtra);
    1757                         end;
    1758                       end
    1759                     end
    1760                   end;
    1761                 if FoodCount=0 then
    1762                   Score:=0
    1763                 else
    1764                   begin
    1765                   if ProdCount>7 then
    1766                     ProdCount:=7;
    1767                   if FoodCount<5 then
    1768                     dec(ProdCount, 5-FoodCount);
    1769                   Score:=ProdCount*4+ProdExtra*8+FoodCount;
    1770                   Score:=Score shl 8 + ((CityLoc xor me)*4567) mod 251;
    1771                     // some unexactness, random but always the same for this tile
    1772                   end; 
    1773                 if Score>BestScore then
    1774                   begin
    1775                   BestScore:=Score;
    1776                   ColonyShipPlan[part].LocFoundCity[ColonyShipPlan[part].nLocFoundCity]:=CityLoc;
    1777                   end
    1778                 end
    1779               end
    1780             end;
    1781           if BestScore>0 then
    1782             inc(ColonyShipPlan[part].nLocFoundCity);
    1783           end;
    1784         end
    1785     end
    1786   end
     2004  end;
    17872005end;
    17882006
    17892007end.
    1790 
Note: See TracChangeset for help on using the changeset viewer.