1  {$INCLUDE Switches.inc}


2  unit Barbarina;


3 


4  interface


5 


6  uses


7  {$IFDEF DEBUG}SysUtils,{$ENDIF} // necessary for debug exceptions


8  {$IFDEF DEBUG}Names,{$ENDIF}


9  Protocol, ToolAI, CustomAI;


10 


11  const


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)


23 


24 


25  type


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;


32  end;


33 


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;


65  end;


66 


67 


68  implementation


69 


70  uses


71  Pile;


72 


73  type


74  TResearchModel = record


75  Category, Domain, Weight, adStop, FutMStrength: integer;


76  Upgrades: cardinal;


77  Cap: array [0..nFeature  1] of integer;


78  end;


79 


80  const


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;


170 


171 


172  var


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;


178 


179  constructor TBarbarina.Create(Nation: integer);


180  begin


181  inherited;


182  TurnOfMapAnalysis := 1;


183  end;


184 


185  // whether one of the existing models matches a specific research model


186  function TBarbarina.IsModelAvailable(rmix: integer): boolean;


187  var


188  i, mix, MStrength: integer;


189  begin


190  Result := False;


191  with ResearchModel[rmix] do


192  begin


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;


211  end;


212 


213  function TBarbarina.Barbarina_GoHidden: boolean;


214  var


215  V21, Loc1, cix: integer;


216  Radius: TVicinity21Loc;


217  begin


218  if IsResearched(adMassProduction) then


219  begin


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;


233  end


234  else if IsResearched(adGunPowder) then


235  Result := (RO.Tech[adTheRepublic] < tsSeen) and IsResearched(adTheology)


236  else


237  Result := False;


238  end;


239 


240  function TBarbarina.Barbarina_Go: boolean;


241  begin


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


248  begin


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));


255  end;


256 


257  procedure TBarbarina.AnalyzeMap;


258  var


259  Loc, Loc1, V8, f1, p1, cix: integer;


260  Adjacent: TVicinity8Loc;


261  begin


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


273  begin


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);


284  end


285  else


286  begin


287  Inc(OceanSize[f1]);


288  OceanPresence[f1] := OceanPresence[f1] or (1 shl p1);


289  end;


290  end;


291  nfUndiscovered:


292  begin // adjacent formations are not completely discovered


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:


309  begin // nation present in adjacent formations


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;


325  end;


326  end;


327  end;


328 


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;


337  end;


338 


339  procedure TBarbarina.FindBestModels;


340  var


341  i, mix, rmix, cat: integer;


342  begin


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;


391  end;


392 


393  procedure TBarbarina.Barbarina_DoTurn;


394  begin


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;


405  end;


406 


407  // find one unit to destroy each known enemy unit, result in uixAttack


408  procedure TBarbarina.RateAttack(uix: integer);


409  var


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;


416  begin


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;


494  end;


495 


496  function TBarbarina.DoAttack(uix, AttackLoc: integer): boolean;


497  // AttackLoc=maNextCity means bombard only


498  var


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;


506  begin


507  Result := False;


508  IsBombardment := AttackLoc = maNextCity;


509  with MyUnit[uix] do


510  begin


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


524  begin


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;


611  end;


612 


613  function TBarbarina.ProcessMove(uix: integer): boolean;


614  // return true if no new enemy spotted


615  const


616  DistanceScore = 4;


617  var


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 


628  begin


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


697  begin


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:


709  { if (NextTime and $7FFFF000=TestTime and $7FFFF000)


710  or (UnitPresence[TestLoc] and Kind=0)


711  or (Tile and fCity<>0)


712  or (Tile and fTerImp=tiFort) or (Tile and fTerImp=tiBase) then}


713  begin


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;


737  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;


828  end;


829  end


830  else


831  done := True;


832  end; // while not done


833  if Result then


834  Moved[uix] := True;


835  end; // ProcessMove


836 


837  procedure TBarbarina.AttackAndPatrol;


838 


839  procedure SetCityDefenders;


840  var


841  uix, cix, V8, Loc1, Best, uixBest, det: integer;


842  Adjacent: TVicinity8Loc;


843  IsPort: boolean;


844  begin


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


918  begin


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;


972  end;


973  end;


974 


975  procedure ProcessUnload(uix: integer);


976 


977  procedure Unload(Kind, ToLoc: integer);


978  var


979  uix1: integer;


980  begin


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;


1095  end


1096  until False;


1097  end;


1098  end;


1099 


1100  var


1101  uix, euix, Kind, euixBest, AttackLoc: integer;


1102  OldTile: cardinal;


1103  BackToStart, FirstLoop: boolean;


1104  begin


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


1179  begin


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


1202  begin


1203  BackToStart := True;


1204  break;


1205  end


1206  until not BackToStart;


1207  end; // AttackAndPatrol


1208 


1209  procedure TBarbarina.Barbarina_SetCityProduction;


1210 


1211  const


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;


1215 


1216  function LowPriority(cix: integer): boolean;


1217  var


1218  part, cixHighPriority, TestDistance: integer;


1219  begin


1220  Result := False;


1221  for part := 0 to nShipPart  1 do


1222  begin


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;


1234  end;


1235 


1236  function ChooseWonderToBuild(WonderAvailable: integer; AllowCoastal: boolean): integer;


1237  var


1238  Count, iix: integer;


1239  begin


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 nWonder  1 do


1245  begin


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);


1251  end


1252  else


1253  Inc(Count);


1254  end;


1255  Count := Random(Count);


1256  for iix := 0 to nWonder  1 do


1257  begin


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);


1263  end


1264  else


1265  Dec(Count);


1266  if Count < 0 then


1267  begin


1268  Result := iix;


1269  exit;


1270  end;


1271  end;


1272  end;


1273 


1274  var


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,


1283  ImportantCity: boolean;


1284  Radius: TVicinity21Loc;


1285  Report: TCityReportNew;


1286  begin


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 nWonder  1 do


1329  if (Imp[iix].Preq <> preNA) and ((Imp[iix].Preq = preNone) or


1330  IsResearched(Imp[iix].Preq)) and (RO.Wonder[iix].CityID = WonderNotBuiltYet) then


1331  Inc(WonderAvailable, 1 shl iix);


1332  for cix := 0 to RO.nCity  1 do


1333  if MyCity[cix].Loc >= 0 then


1334  begin


1335  iix := City_CurrentImprovementProject(cix);


1336  if (iix >= 0) and (iix < nWonder) then


1337  Inc(WonderInWork, 1 shl iix)


1338  else if iix = imPalace then


1339  cixNewCapital := cix;


1340  end;


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 noncoastal 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;


1373  end;


1374 


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 lowprio 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;


1418  end


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 < nWonder) 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


1442  begin


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 < nWonder) 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


1460  begin


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


1475  begin


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);


1482  end


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


1491  begin


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 = WonderNotBuiltYet) and City_Improvable(cix, woZeus) then


1503  City_StartImprovement(cix, woZeus)


1504  else if (City_CurrentImprovementProject(cix) >= 0) and


1505  (City_CurrentImprovementProject(cix) < nWonder) 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


1523  begin


1524  if City_Improvable(cix, imCourt) then


1525  City_StartImprovement(cix, imCourt)


1526  else


1527  City_StartImprovement(cix, imTownHall);


1528  end


1529  else if not HasSettler and (RO.nUn >= RO.nCity * 4) then


1530  begin


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;


1538  end


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 nWonder  1 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)


1579  {else if (ImportantCity or (Loc mod 11=0)) and (Built[imMissileBat]=0)


1580  and City_Improvable(cix,imMissileBat) then


1581  City_StartImprovement(cix,imMissileBat)}


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 := nWonder 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;


1619  end;


1620 


1621  function TBarbarina.Barbarina_ChooseResearchAdvance: integer;


1622  var


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;


1627 


1628  procedure ChoosePreq(ad: integer);


1629  var


1630  i: integer;


1631  PreqOk: boolean;


1632  begin


1633  assert(RO.Tech[ad] < tsApplicable);


1634  if known[ad] = 0 then


1635  begin


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;


1652  end;


1653 


1654  begin


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


1719  begin


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;


1733  end;


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


1741  begin


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;


1755  end;


1756  end;


1757 


1758  function TBarbarina.Barbarina_WantCheckNegotiation(Nation: integer): boolean;


1759  begin


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;


1766  end;


1767 


1768  procedure TBarbarina.Barbarina_DoCheckNegotiation;


1769  begin


1770  if RO.Tech[adTheRepublic] >= tsSeen then


1771  exit; // default reaction


1772  if MyLastAction = scContact then


1773  begin


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;


1783  end


1784  else if OppoAction = scDipAccept then


1785  else if OppoAction = scDipOffer then


1786  begin


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;


1794  end


1795  else if OppoAction <> scDipBreak then


1796  MyAction := scDipBreak;


1797  end;


1798 


1799  function TBarbarina.Barbarina_WantNegotiation(Nation: integer;


1800  NegoTime: TNegoTime): boolean;


1801  var


1802  uix, TestLoc, V8: integer;


1803  Adjacent: TVicinity8Loc;


1804  begin


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;


1820  end


1821  else if RO.Treaty[Nation] = trPeace then


1822  begin // declare war now?


1823  for uix := 0 to RO.nUn  1 do


1824  with MyUnit[uix] do


1825  if (Loc >= 0) and (MyModel[mix].Attack > 0) then


1826  begin


1827  V8_to_Loc(Loc, Adjacent);


1828  for V8 := 0 to 7 do


1829  begin


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;


1847  end;


1848 


1849  procedure TBarbarina.Barbarina_DoNegotiation;


1850  begin


1851  if OppoAction = scDipStart then


1852  begin


1853  if NegoCause = CancelTreaty then


1854  MyAction := scDipCancelTreaty;


1855  end;


1856  end;


1857 


1858  procedure TBarbarina.MakeColonyShipPlan;


1859  var


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;


1865  begin


1866  for part := 0 to nShipPart  1 do


1867  begin


1868  ColonyShipPlan[part].cixProducing := 1;


1869  ColonyShipPlan[part].nLocResource := 0;


1870  ColonyShipPlan[part].nLocFoundCity := 0;


1871  end;


1872  if RO.Tech[adMassProduction] >= tsApplicable then // able to recognize ressources yet


1873  begin


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


1918  begin


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;


1997  end;


1998  end;


1999  if BestScore > 0 then


2000  Inc(ColonyShipPlan[part].nLocFoundCity);


2001  end;


2002  end;


2003  end;


2004  end;


2005  end;


2006 


2007  end.

