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

Legend:

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

    r124 r160  
    55
    66uses
    7 {$IFDEF DEBUG}SysUtils, {$ENDIF} // necessary for debug exceptions
     7{$IFDEF DEBUG}SysUtils,{$ENDIF} // necessary for debug exceptions
    88  Protocol;
    99
    1010type
    11   TNegoTime = (BeginOfTurn, EndOfTurn, EnemyCalled);
    12 
    13   TCustomAI = class
    14   public
    15     procedure Process(Command: integer; var Data);
    16 
    17     // overridables
    18     constructor Create(Nation: integer); virtual;
    19     destructor Destroy; override;
    20     procedure SetDataDefaults; virtual;
    21     procedure SetDataRandom; virtual;
    22     procedure OnBeforeEnemyAttack(UnitInfo: TUnitInfo;
    23       ToLoc, EndHealth, EndHealthDef: integer); virtual;
    24     procedure OnBeforeEnemyCapture(UnitInfo: TUnitInfo;
    25       ToLoc: integer); virtual;
    26     procedure OnAfterEnemyAttack; virtual;
    27     procedure OnAfterEnemyCapture; virtual;
    28 
    29   protected
    30     me: integer; // index of the controlled nation
    31     RO: ^TPlayerContext;
    32     Map: ^TTileList;
    33     MyUnit: ^TUnList;
    34     MyCity: ^TCityList;
    35     MyModel: ^TModelList;
    36 
    37     cixStateImp: array [imPalace .. imSpacePort] of integer;
    38 
    39     // negotiation
    40     Opponent: integer;
    41     // nation i'm in negotiation with, -1 indicates no-negotiation mode
    42     MyAction, MyLastAction, OppoAction: integer;
    43     MyOffer, MyLastOffer, OppoOffer: TOffer;
    44 
    45     // overridables
    46     procedure DoTurn; virtual;
    47     procedure DoNegotiation; virtual;
    48     function ChooseResearchAdvance: integer; virtual;
    49     function ChooseStealAdvance: integer; virtual;
    50     function ChooseGovernment: integer; virtual;
    51     function WantNegotiation(Nation: integer; NegoTime: TNegoTime)
    52       : boolean; virtual;
    53     function OnNegoRejected_CancelTreaty: boolean; virtual;
    54 
    55     // general functions
    56     function IsResearched(Advance: integer): boolean;
    57     function ResearchCost: integer;
    58     function ChangeAttitude(Nation, Attitude: integer): integer;
    59     function Revolution: integer;
    60     function ChangeRates(Tax, Lux: integer): integer;
    61     function PrepareNewModel(Domain: integer): integer;
    62     function SetNewModelFeature(F, Count: integer): integer;
    63     function AdvanceResearchable(Advance: integer): boolean;
    64     function AdvanceStealable(Advance: integer): boolean;
    65     function GetJobProgress(Loc: integer;
    66       var JobProgress: TJobProgressData): boolean;
    67     function DebugMessage(Level: integer; Text: string): boolean;
    68     function SetDebugMap(var DebugMap): boolean;
    69 
    70     // unit functions
    71     procedure Unit_FindMyDefender(Loc: integer; var uix: integer);
    72     procedure Unit_FindEnemyDefender(Loc: integer; var euix: integer);
    73     function Unit_Move(uix, ToLoc: integer): integer;
    74     function Unit_Step(uix, ToLoc: integer): integer;
    75     function Unit_Attack(uix, ToLoc: integer): integer;
    76     function Unit_DoMission(uix, MissionType, ToLoc: integer): integer;
    77     function Unit_MoveForecast(uix, ToLoc: integer;
    78       var RemainingMovement: integer): boolean;
    79     function Unit_AttackForecast(uix, ToLoc, AttackMovement: integer;
    80       var RemainingHealth: integer): boolean;
    81     function Unit_DefenseForecast(euix, ToLoc: integer;
    82       var RemainingHealth: integer): boolean;
    83     function Unit_Disband(uix: integer): integer;
    84     function Unit_StartJob(uix, NewJob: integer): integer;
    85     function Unit_SetHomeHere(uix: integer): integer;
    86     function Unit_Load(uix: integer): integer;
    87     function Unit_Unload(uix: integer): integer;
    88     function Unit_SelectTransport(uix: integer): integer;
    89     function Unit_AddToCity(uix: integer): integer;
    90 
    91     // city functions
    92     procedure City_FindMyCity(Loc: integer; var cix: integer);
    93     procedure City_FindEnemyCity(Loc: integer; var ecix: integer);
    94     function City_HasProject(cix: integer): boolean;
    95     function City_CurrentImprovementProject(cix: integer): integer;
    96     function City_CurrentUnitProject(cix: integer): integer;
    97     function City_GetTileInfo(cix, TileLoc: integer;
    98       var TileInfo: TTileInfo): integer;
    99     function City_GetReport(cix: integer; var Report: TCityReport): integer;
    100     function City_GetHypoReport(cix, HypoTiles, HypoTax, HypoLux: integer;
    101       var Report: TCityReport): integer;
    102     function City_GetReportNew(cix: integer;
    103       var Report: TCityReportNew): integer;
    104     function City_GetHypoReportNew(cix, HypoTiles, HypoTaxRate,
    105       HypoLuxuryRate: integer; var Report: TCityReportNew): integer;
    106     function City_GetAreaInfo(cix: integer;
    107       var AreaInfo: TCityAreaInfo): integer;
    108     function City_StartUnitProduction(cix, mix: integer): integer;
    109     function City_StartEmigration(cix, mix: integer;
    110       AllowDisbandCity, AsConscripts: boolean): integer;
    111     function City_StartImprovement(cix, iix: integer): integer;
    112     function City_Improvable(cix, iix: integer): boolean;
    113     function City_StopProduction(cix: integer): integer;
    114     function City_BuyProject(cix: integer): integer;
    115     function City_SellImprovement(cix, iix: integer): integer;
    116     function City_RebuildImprovement(cix, iix: integer): integer;
    117     function City_SetTiles(cix, NewTiles: integer): integer;
    118     procedure City_OptimizeTiles(cix: integer;
    119       ResourceWeights: integer = rwMaxGrowth);
    120 
    121     // negotiation
    122     function Nego_CheckMyAction: integer;
    123 
    124   private
    125     HaveTurned: boolean;
    126     UnwantedNego: set of 0 .. nPl - 1;
    127     Contacted: set of 0 .. nPl - 1;
    128     procedure StealAdvance;
     11TNegoTime=(BeginOfTurn, EndOfTurn, EnemyCalled);
     12
     13TCustomAI=class
     14public
     15  procedure Process(Command: integer; var Data);
     16
     17  // overridables
     18  constructor Create(Nation: integer); virtual;
     19  destructor Destroy; override;
     20  procedure SetDataDefaults; virtual;
     21  procedure SetDataRandom; virtual;
     22  procedure OnBeforeEnemyAttack(UnitInfo: TUnitInfo;
     23    ToLoc, EndHealth, EndHealthDef: integer); virtual;
     24  procedure OnBeforeEnemyCapture(UnitInfo: TUnitInfo; ToLoc: integer); virtual;
     25  procedure OnAfterEnemyAttack; virtual;
     26  procedure OnAfterEnemyCapture; virtual;
     27
     28protected
     29  me: integer; // index of the controlled nation
     30  RO: ^TPlayerContext;
     31  Map: ^TTileList;
     32  MyUnit: ^TUnList;
     33  MyCity: ^TCityList;
     34  MyModel: ^TModelList;
     35
     36  cixStateImp: array[imPalace..imSpacePort] of integer;
     37
     38  // negotiation
     39  Opponent: integer; // nation i'm in negotiation with, -1 indicates no-negotiation mode
     40  MyAction, MyLastAction, OppoAction: integer;
     41  MyOffer, MyLastOffer, OppoOffer: TOffer;
     42
     43  // overridables
     44  procedure DoTurn; virtual;
     45  procedure DoNegotiation; virtual;
     46  function ChooseResearchAdvance: integer; virtual;
     47  function ChooseStealAdvance: integer; virtual;
     48  function ChooseGovernment: integer; virtual;
     49  function WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean; virtual;
     50  function OnNegoRejected_CancelTreaty: boolean; virtual;
     51
     52  // general functions
     53  function IsResearched(Advance: integer): boolean;
     54  function ResearchCost: integer;
     55  function ChangeAttitude(Nation, Attitude: integer): integer;
     56  function Revolution: integer;
     57  function ChangeRates(Tax,Lux: integer): integer;
     58  function PrepareNewModel(Domain: integer): integer;
     59  function SetNewModelFeature(F, Count: integer): integer;
     60  function AdvanceResearchable(Advance: integer): boolean;
     61  function AdvanceStealable(Advance: integer): boolean;
     62  function GetJobProgress(Loc: integer; var JobProgress: TJobProgressData): boolean;
     63  function DebugMessage(Level: integer; Text: string): boolean;
     64  function SetDebugMap(var DebugMap): boolean;
     65
     66  // unit functions
     67  procedure Unit_FindMyDefender(Loc: integer; var uix: integer);
     68  procedure Unit_FindEnemyDefender(Loc: integer; var euix: integer);
     69  function Unit_Move(uix,ToLoc: integer): integer;
     70  function Unit_Step(uix,ToLoc: integer): integer;
     71  function Unit_Attack(uix,ToLoc: integer): integer;
     72  function Unit_DoMission(uix,MissionType,ToLoc: integer): integer;
     73  function Unit_MoveForecast(uix,ToLoc: integer; var RemainingMovement: integer): boolean;
     74  function Unit_AttackForecast(uix,ToLoc,AttackMovement: integer; var RemainingHealth: integer): boolean;
     75  function Unit_DefenseForecast(euix,ToLoc: integer; var RemainingHealth: integer): boolean;
     76  function Unit_Disband(uix: integer): integer;
     77  function Unit_StartJob(uix,NewJob: integer): integer;
     78  function Unit_SetHomeHere(uix: integer): integer;
     79  function Unit_Load(uix: integer): integer;
     80  function Unit_Unload(uix: integer): integer;
     81  function Unit_SelectTransport(uix: integer): integer;
     82  function Unit_AddToCity(uix: integer): integer;
     83
     84  // city functions
     85  procedure City_FindMyCity(Loc: integer; var cix: integer);
     86  procedure City_FindEnemyCity(Loc: integer; var ecix: integer);
     87  function City_HasProject(cix: integer): boolean;
     88  function City_CurrentImprovementProject(cix: integer): integer;
     89  function City_CurrentUnitProject(cix: integer): integer;
     90  function City_GetTileInfo(cix,TileLoc: integer; var TileInfo: TTileInfo): integer;
     91  function City_GetReport(cix: integer; var Report: TCityReport): integer;
     92  function City_GetHypoReport(cix, HypoTiles, HypoTax, HypoLux: integer; var Report: TCityReport): integer;
     93  function City_GetReportNew(cix: integer; var Report: TCityReportNew): integer;
     94  function City_GetHypoReportNew(cix, HypoTiles, HypoTaxRate, HypoLuxuryRate: integer; var Report: TCityReportNew): integer;
     95  function City_GetAreaInfo(cix: integer; var AreaInfo: TCityAreaInfo): integer;
     96  function City_StartUnitProduction(cix,mix: integer): integer;
     97  function City_StartEmigration(cix,mix: integer; AllowDisbandCity, AsConscripts: boolean): integer;
     98  function City_StartImprovement(cix,iix: integer): integer;
     99  function City_Improvable(cix,iix: integer): boolean;
     100  function City_StopProduction(cix: integer): integer;
     101  function City_BuyProject(cix: integer): integer;
     102  function City_SellImprovement(cix,iix: integer): integer;
     103  function City_RebuildImprovement(cix,iix: integer): integer;
     104  function City_SetTiles(cix,NewTiles: integer): integer;
     105  procedure City_OptimizeTiles(cix: integer; ResourceWeights: cardinal = rwMaxGrowth);
     106
     107  // negotiation
     108  function Nego_CheckMyAction: integer;
     109
     110private
     111  HaveTurned: boolean;
     112  UnwantedNego: set of 0..nPl-1;
     113  Contacted: set of 0..nPl-1;
     114  procedure StealAdvance;
    129115  end;
    130116
    131 var
    132   Server: TServerCall;
    133   G: TNewGameData;
    134   RWDataSize, MapSize: integer;
    135   decompose24: cardinal;
    136   nodata: pointer;
     117
     118var
     119Server: TServerCall;
     120G: TNewGameData;
     121RWDataSize, MapSize: integer;
     122decompose24: cardinal;
     123nodata: pointer;
    137124
    138125const
    139   CityOwnTile = 13; // = ab_to_V21(0,0)
    140 
    141   // additional return codes
    142   rLocationReached = $00010000;
    143   // Unit_Move: move was not interrupted, location reached
    144   rMoreTurns = $00020000;
    145   // Unit_Move: move was not interrupted, location not reached yet
     126CityOwnTile = 13; // = ab_to_V21(0,0)
     127
     128// additional return codes
     129rLocationReached=       $00010000; // Unit_Move: move was not interrupted, location reached
     130rMoreTurns=             $00020000; // Unit_Move: move was not interrupted, location not reached yet
    146131
    147132type
    148   TVicinity8Loc = array [0 .. 7] of integer;
    149   TVicinity21Loc = array [0 .. 27] of integer;
     133TVicinity8Loc=array[0..7] of integer;
     134TVicinity21Loc=array[0..27] of integer;
     135
    150136
    151137procedure Init(NewGameData: TNewGameData);
    152138
    153 procedure ab_to_Loc(Loc0, a, b: integer; var Loc: integer);
    154 procedure Loc_to_ab(Loc0, Loc: integer; var a, b: integer);
    155 procedure ab_to_V8(a, b: integer; var V8: integer);
    156 procedure V8_to_ab(V8: integer; var a, b: integer);
    157 procedure ab_to_V21(a, b: integer; var V21: integer);
    158 procedure V21_to_ab(V21: integer; var a, b: integer);
     139procedure ab_to_Loc(Loc0,a,b: integer; var Loc: integer);
     140procedure Loc_to_ab(Loc0,Loc: integer; var a,b: integer);
     141procedure ab_to_V8(a,b: integer; var V8: integer);
     142procedure V8_to_ab(V8: integer; var a,b: integer);
     143procedure ab_to_V21(a,b: integer; var V21: integer);
     144procedure V21_to_ab(V21: integer; var a,b: integer);
    159145procedure V8_to_Loc(Loc0: integer; var VicinityLoc: TVicinity8Loc);
    160146procedure V21_to_Loc(Loc0: integer; var VicinityLoc: TVicinity21Loc);
     147function Distance(Loc0,Loc1: integer): integer;
     148
    161149
    162150implementation
    163151
    164152const
    165   ab_v8: array [-4 .. 4] of integer = (5, 6, 7, 4, -1, 0, 3, 2, 1);
    166   v8_a: array [0 .. 7] of integer = (1, 1, 0, -1, -1, -1, 0, 1);
    167   v8_b: array [0 .. 7] of integer = (0, 1, 1, 1, 0, -1, -1, -1);
    168 
    169 procedure ab_to_Loc(Loc0, a, b: integer; var Loc: integer);
    170 { relative location from Loc0 }
    171 var
    172   y0: integer;
    173 begin
    174   assert((Loc0 >= 0) and (Loc0 < MapSize) and (a - b + G.lx >= 0));
    175   y0 := cardinal(Loc0) * decompose24 shr 24;
    176   Loc := (Loc0 + (a - b + y0 and 1 + G.lx + G.lx) shr 1) mod G.lx + G.lx *
    177     (y0 + a + b);
    178   if Loc >= MapSize then
    179     Loc := -$1000
    180 end;
    181 
    182 procedure Loc_to_ab(Loc0, Loc: integer; var a, b: integer);
     153ab_v8: array[-4..4] of integer = (5,6,7,4,-1,0,3,2,1);
     154v8_a: array[0..7] of integer = (1,1,0,-1,-1,-1,0,1);
     155v8_b: array[0..7] of integer = (0,1,1,1,0,-1,-1,-1);
     156
     157
     158procedure ab_to_Loc(Loc0,a,b: integer; var Loc: integer);
     159{relative location from Loc0}
     160var
     161y0: integer;
     162begin
     163assert((Loc0>=0) and (Loc0<MapSize) and (a-b+G.lx>=0));
     164y0:=cardinal(Loc0)*decompose24 shr 24;
     165Loc:=(Loc0+(a-b+y0 and 1+G.lx+G.lx) shr 1) mod G.lx +G.lx*(y0+a+b);
     166if Loc>=MapSize then Loc:=-$1000
     167end;
     168
     169procedure Loc_to_ab(Loc0,Loc: integer; var a,b: integer);
    183170{$IFDEF FPC} // freepascal
    184171var
    185   dx, dy: integer;
    186 begin
    187   dx := ((Loc mod G.lx * 2 + Loc div G.lx and 1) -
    188     (Loc0 mod G.lx * 2 + Loc0 div G.lx and 1) + 3 * G.lx) mod (2 * G.lx) - G.lx;
    189   dy := Loc div G.lx - Loc0 div G.lx;
    190   a := (dx + dy) div 2;
    191   b := (dy - dx) div 2;
     172dx,dy: integer;
     173begin
     174dx:=((Loc mod G.lx *2 +Loc div G.lx and 1)
     175  -(Loc0 mod G.lx *2 +Loc0 div G.lx and 1)+3*G.lx) mod (2*G.lx) -G.lx;
     176dy:=Loc div G.lx-Loc0 div G.lx;
     177a:=(dx+dy) div 2;
     178b:=(dy-dx) div 2;
    192179end;
    193180{$ELSE} // delphi
    194181register;
    195182asm
    196   push ebx
    197 
    198   // calculate
    199   push ecx
    200   div byte ptr [G]
    201   xor ebx,ebx
    202   mov bl,ah  // ebx:=Loc0 mod G.lx
    203   mov ecx,eax
    204   and ecx,$000000FF // ecx:=Loc0 div G.lx
    205   mov eax,edx
    206   div byte ptr [G]
    207   xor edx,edx
    208   mov dl,ah // edx:=Loc mod G.lx
    209   and eax,$000000FF // eax:=Loc div G.lx
    210   sub edx,ebx // edx:=Loc mod G.lx-Loc0 mod G.lx
    211   mov ebx,eax
    212   sub ebx,ecx // ebx:=dy
    213   and eax,1
    214   and ecx,1
    215   add edx,edx
    216   add eax,edx
    217   sub eax,ecx // eax:=dx, not normalized
    218   pop ecx
    219 
    220   // normalize
    221   mov edx,dword ptr [G]
    222   cmp eax,edx
    223   jl @a
     183push ebx
     184
     185// calculate
     186push ecx
     187div byte ptr [G]
     188xor ebx,ebx
     189mov bl,ah  // ebx:=Loc0 mod G.lx
     190mov ecx,eax
     191and ecx,$000000FF // ecx:=Loc0 div G.lx
     192mov eax,edx
     193div byte ptr [G]
     194xor edx,edx
     195mov dl,ah // edx:=Loc mod G.lx
     196and eax,$000000FF // eax:=Loc div G.lx
     197sub edx,ebx // edx:=Loc mod G.lx-Loc0 mod G.lx
     198mov ebx,eax
     199sub ebx,ecx // ebx:=dy
     200and eax,1
     201and ecx,1
     202add edx,edx
     203add eax,edx
     204sub eax,ecx // eax:=dx, not normalized
     205pop ecx
     206
     207// normalize
     208mov edx,dword ptr [G]
     209cmp eax,edx
     210jl @a
    224211  sub eax,edx
    225212  sub eax,edx
    226213  jmp @ok
    227214@a:
    228   neg edx
    229   cmp eax,edx
    230   jnl @ok
     215neg edx
     216cmp eax,edx
     217jnl @ok
    231218  sub eax,edx
    232219  sub eax,edx
    233220
    234   // return results
     221// return results
    235222@ok:
    236   mov edx,ebx
    237   sub edx,eax
    238   add eax,ebx
    239   sar edx,1 // edx:=b
    240   mov ebx,[b]
    241   mov [ebx],edx
    242   sar eax,1 // eax:=a
    243   mov [a],eax
    244 
    245   pop ebx
     223mov edx,ebx
     224sub edx,eax
     225add eax,ebx
     226sar edx,1 // edx:=b
     227mov ebx,[b]
     228mov [ebx],edx
     229sar eax,1 // eax:=a
     230mov [a],eax
     231
     232pop ebx
    246233end;
    247234{$ENDIF}
    248235
    249 procedure ab_to_V8(a, b: integer; var V8: integer);
    250 begin
    251   assert((abs(a) <= 1) and (abs(b) <= 1) and ((a <> 0) or (b <> 0)));
    252   V8 := ab_v8[2 * b + b + a];
    253 end;
    254 
    255 procedure V8_to_ab(V8: integer; var a, b: integer);
    256 begin
    257   a := v8_a[V8];
    258   b := v8_b[V8];
    259 end;
    260 
    261 procedure ab_to_V21(a, b: integer; var V21: integer);
    262 begin
    263   V21 := (a + b + 3) shl 2 + (a - b + 3) shr 1;
    264 end;
    265 
    266 procedure V21_to_ab(V21: integer; var a, b: integer);
    267 var
    268   dx, dy: integer;
    269 begin
    270   dy := V21 shr 2 - 3;
    271   dx := V21 and 3 shl 1 - 3 + (dy + 3) and 1;
    272   a := (dx + dy) div 2;
    273   b := (dy - dx) div 2;
     236procedure ab_to_V8(a,b: integer; var V8: integer);
     237begin
     238assert((abs(a)<=1) and (abs(b)<=1) and ((a<>0) or (b<>0)));
     239V8:=ab_v8[2*b+b+a];
     240end;
     241
     242procedure V8_to_ab(V8: integer; var a,b: integer);
     243begin
     244a:=v8_a[V8]; b:=V8_b[V8];
     245end;
     246
     247procedure ab_to_V21(a,b: integer; var V21: integer);
     248begin
     249V21:=(a+b+3) shl 2+(a-b+3) shr 1;
     250end;
     251
     252procedure V21_to_ab(V21: integer; var a,b: integer);
     253var
     254dx,dy: integer;
     255begin
     256dy:=V21 shr 2-3;
     257dx:=V21 and 3 shl 1 -3 + (dy+3) and 1;
     258a:=(dx+dy) div 2;
     259b:=(dy-dx) div 2;
    274260end;
    275261
    276262procedure V8_to_Loc(Loc0: integer; var VicinityLoc: TVicinity8Loc);
    277263var
    278   x0, y0, lx: integer;
    279 begin
    280   lx := G.lx;
    281   y0 := cardinal(Loc0) * decompose24 shr 24;
    282   x0 := Loc0 - y0 * lx; // Loc0 mod lx;
    283   VicinityLoc[1] := Loc0 + lx * 2;
    284   VicinityLoc[3] := Loc0 - 1;
    285   VicinityLoc[5] := Loc0 - lx * 2;
    286   VicinityLoc[7] := Loc0 + 1;
    287   inc(Loc0, y0 and 1);
    288   VicinityLoc[0] := Loc0 + lx;
    289   VicinityLoc[2] := Loc0 + lx - 1;
    290   VicinityLoc[4] := Loc0 - lx - 1;
    291   VicinityLoc[6] := Loc0 - lx;
    292 
    293   // world is round!
    294   if x0 < lx - 1 then
     264x0,y0,lx: integer;
     265begin
     266lx:=G.lx;
     267y0:=cardinal(Loc0)*decompose24 shr 24;
     268x0:=Loc0-y0*lx; // Loc0 mod lx;
     269VicinityLoc[1]:=Loc0+lx*2;
     270VicinityLoc[3]:=Loc0-1;
     271VicinityLoc[5]:=Loc0-lx*2;
     272VicinityLoc[7]:=Loc0+1;
     273inc(Loc0,y0 and 1);
     274VicinityLoc[0]:=Loc0+lx;
     275VicinityLoc[2]:=Loc0+lx-1;
     276VicinityLoc[4]:=Loc0-lx-1;
     277VicinityLoc[6]:=Loc0-lx;
     278
     279// world is round!
     280if x0<lx-1 then
    295281  begin
    296     if x0 = 0 then
     282  if x0=0 then
    297283    begin
    298       inc(VicinityLoc[3], lx);
    299       if y0 and 1 = 0 then
     284    inc(VicinityLoc[3],lx);
     285    if y0 and 1=0 then
    300286      begin
    301         inc(VicinityLoc[2], lx);
    302         inc(VicinityLoc[4], lx);
     287      inc(VicinityLoc[2],lx);
     288      inc(VicinityLoc[4],lx);
    303289      end
    304290    end
    305291  end
    306   else
     292else
    307293  begin
    308     dec(VicinityLoc[7], lx);
    309     if y0 and 1 = 1 then
     294  dec(VicinityLoc[7],lx);
     295  if y0 and 1=1 then
    310296    begin
    311       dec(VicinityLoc[0], lx);
    312       dec(VicinityLoc[6], lx);
     297    dec(VicinityLoc[0],lx);
     298    dec(VicinityLoc[6],lx);
    313299    end
    314300  end;
    315301
    316   // check south pole
    317   case G.ly - y0 of
    318     1:
     302// check south pole
     303case G.ly-y0 of
     304  1:
     305    begin
     306    VicinityLoc[0]:=-$1000;
     307    VicinityLoc[1]:=-$1000;
     308    VicinityLoc[2]:=-$1000;
     309    end;
     310  2: VicinityLoc[1]:=-$1000;
     311  end
     312end;
     313
     314procedure V21_to_Loc(Loc0: integer; var VicinityLoc: TVicinity21Loc);
     315var
     316dx,dy,bit,y0,xComp,yComp,xComp0,xCompSwitch: integer;
     317dst: ^integer;
     318begin
     319y0:=cardinal(Loc0)*decompose24 shr 24;
     320xComp0:=Loc0-y0*G.lx-1; // Loc0 mod G.lx -1
     321xCompSwitch:=xComp0-1+y0 and 1;
     322if xComp0<0 then inc(xComp0,G.lx);
     323if xCompSwitch<0 then inc(xCompSwitch,G.lx);
     324xCompSwitch:=xCompSwitch xor xComp0;
     325yComp:=G.lx*(y0-3);
     326dst:=@VicinityLoc;
     327bit:=1;
     328for dy:=0 to 6 do
     329  if yComp<MapSize then
     330    begin
     331    xComp0:=xComp0 xor xCompSwitch;
     332    xComp:=xComp0;
     333    for dx:=0 to 3 do
    319334      begin
    320         VicinityLoc[0] := -$1000;
    321         VicinityLoc[1] := -$1000;
    322         VicinityLoc[2] := -$1000;
     335      if bit and $67F7F76<>0 then dst^:=xComp+yComp
     336      else dst^:=-1;
     337      inc(xComp);
     338      if xComp>=G.lx then dec(xComp, G.lx);
     339      inc(dst);
     340      bit:=bit shl 1;
    323341      end;
    324     2:
    325       VicinityLoc[1] := -$1000;
    326   end
    327 end;
    328 
    329 procedure V21_to_Loc(Loc0: integer; var VicinityLoc: TVicinity21Loc);
    330 var
    331   dx, dy, bit, y0, xComp, yComp, xComp0, xCompSwitch: integer;
    332   dst: ^integer;
    333 begin
    334   y0 := cardinal(Loc0) * decompose24 shr 24;
    335   xComp0 := Loc0 - y0 * G.lx - 1; // Loc0 mod G.lx -1
    336   xCompSwitch := xComp0 - 1 + y0 and 1;
    337   if xComp0 < 0 then
    338     inc(xComp0, G.lx);
    339   if xCompSwitch < 0 then
    340     inc(xCompSwitch, G.lx);
    341   xCompSwitch := xCompSwitch xor xComp0;
    342   yComp := G.lx * (y0 - 3);
    343   dst := @VicinityLoc;
    344   bit := 1;
    345   for dy := 0 to 6 do
    346     if yComp < MapSize then
     342    inc(yComp,G.lx);
     343    end
     344  else
    347345    begin
    348       xComp0 := xComp0 xor xCompSwitch;
    349       xComp := xComp0;
    350       for dx := 0 to 3 do
     346    for dx:=0 to 3 do
     347      begin dst^:=-$1000; inc(dst); end;
     348    end
     349end;
     350
     351function Distance(Loc0,Loc1: integer): integer;
     352var
     353a,b,dx,dy: integer;
     354begin
     355Loc_to_ab(Loc0,Loc1,a,b);
     356dx:=abs(a-b);
     357dy:=abs(a+b);
     358result:=dx+dy+abs(dx-dy) shr 1;
     359end;
     360
     361
     362procedure Init(NewGameData: TNewGameData);
     363{$IFDEF DEBUG}var Loc: integer;{$ENDIF}
     364begin
     365G:=NewGameData;
     366MapSize:=G.lx*G.ly;
     367decompose24:=(1 shl 24-1) div G.lx +1;
     368{$IFDEF DEBUG}for Loc:=0 to MapSize-1 do assert(cardinal(Loc)*decompose24 shr 24=cardinal(Loc div G.lx));{$ENDIF}
     369end;
     370
     371
     372constructor TCustomAI.Create(Nation: integer);
     373begin
     374inherited Create;
     375me:=Nation;
     376RO:=pointer(G.RO[Nation]);
     377Map:=pointer(RO.Map);
     378MyUnit:=pointer(RO.Un);
     379MyCity:=pointer(RO.City);
     380MyModel:=pointer(RO.Model);
     381Opponent:=-1;
     382end;
     383
     384destructor TCustomAI.Destroy;
     385begin
     386Server(sSetDebugMap,me,0,nodata^);
     387end;
     388
     389
     390procedure TCustomAI.Process(Command: integer; var Data);
     391var
     392Nation,NewResearch,NewGov,count,ad,cix,iix: integer;
     393NegoTime: TNegoTime;
     394begin
     395case Command of
     396  cTurn, cContinue:
     397    begin
     398    if RO.Alive and (1 shl me)=0 then
     399      begin // I'm dead, huhu
     400      Server(sTurn,me,0,nodata^);
     401      exit
     402      end;
     403    if Command=cTurn then
    351404      begin
    352         if bit and $67F7F76 <> 0 then
    353           dst^ := xComp + yComp
    354         else
    355           dst^ := -1;
    356         inc(xComp);
    357         if xComp >= G.lx then
    358           dec(xComp, G.lx);
    359         inc(dst);
    360         bit := bit shl 1;
     405      fillchar(cixStateImp, sizeof(cixStateImp), $FF);
     406      for cix:=0 to RO.nCity-1 do if MyCity[cix].Loc>=0 then
     407        for iix:=imPalace to imSpacePort do
     408          if MyCity[cix].Built[iix]>0 then
     409            cixStateImp[iix]:=cix;
     410      if RO.Happened and phChangeGov<>0 then
     411        begin
     412        NewGov:=ChooseGovernment;
     413        if NewGov>gAnarchy then
     414          Server(sSetGovernment,me,NewGov,nodata^);
     415        end;
     416      HaveTurned:=false;
     417      Contacted:=[];
    361418      end;
    362       inc(yComp, G.lx);
    363     end
     419    if (Command=cContinue) and (MyAction=scContact) then
     420      begin
     421      if OnNegoRejected_CancelTreaty then
     422        if RO.Treaty[Opponent]>=trPeace then
     423          if Server(sCancelTreaty,me,0,nodata^)<rExecuted then
     424            assert(false)
     425      end
     426    else UnwantedNego:=[];
     427    Opponent:=-1;
     428    repeat
     429      if HaveTurned then NegoTime:=EndOfTurn
     430      else NegoTime:=BeginOfTurn;
     431      if RO.Government<>gAnarchy then
     432        for Nation:=0 to nPl-1 do
     433           if (Nation<>me) and (1 shl Nation and RO.Alive<>0)
     434             and (RO.Treaty[Nation]>=trNone)
     435             and not (Nation in Contacted) and not (Nation in UnwantedNego)
     436             and (Server(scContact-sExecute + Nation shl 4, me, 0, nodata^)>=rExecuted) then
     437             if WantNegotiation(Nation, NegoTime) then
     438               begin
     439               if Server(scContact + Nation shl 4, me, 0, nodata^)>=rExecuted then
     440                 begin
     441                 include(Contacted, Nation);
     442                 Opponent:=Nation;
     443                 MyAction:=scContact;
     444                 exit;
     445                 end;
     446               end
     447             else include(UnwantedNego,Nation);
     448      if NegoTime=BeginOfTurn then
     449        begin
     450        DoTurn;
     451        HaveTurned:=true;
     452        Contacted:=[];
     453        UnwantedNego:=[];
     454        end
     455      else break;
     456    until false;
     457    if RO.Happened and phTech<>0 then
     458      begin
     459      NewResearch:=ChooseResearchAdvance;
     460      if NewResearch<0 then
     461        begin // choose random research
     462        count:=0;
     463        for ad:=0 to nAdv-1 do if AdvanceResearchable(ad) then
     464          begin inc(count); if random(count)=0 then NewResearch:=ad end
     465        end;
     466      Server(sSetResearch,me,NewResearch,nodata^)
     467      end;
     468    if Server(sTurn,me,0,nodata^)<rExecuted then
     469      assert(false);
     470    end;
     471  scContact:
     472    if WantNegotiation(integer(Data), EnemyCalled) then
     473      begin
     474      if Server(scDipStart, me, 0, nodata^)<rExecuted then
     475        assert(false);
     476      Opponent:=integer(Data);
     477      MyAction:=scDipStart;
     478      end
    364479    else
     480      begin
     481      if Server(scReject, me, 0, nodata^)<rExecuted then
     482        assert(false);
     483      end;
     484  scDipStart, scDipNotice, scDipAccept, scDipCancelTreaty, scDipOffer, scDipBreak:
    365485    begin
    366       for dx := 0 to 3 do
     486    OppoAction:=Command;
     487    if Command=scDipOffer then OppoOffer:=TOffer(Data);
     488    if Command=scDipStart then
     489      MyLastAction:=scContact
     490    else
    367491      begin
    368         dst^ := -$1000;
    369         inc(dst);
     492      MyLastAction:=MyAction;
     493      MyLastOffer:=MyOffer;
    370494      end;
    371     end
    372 end;
    373 
    374 procedure Init(NewGameData: TNewGameData);
    375 {$IFDEF DEBUG}var
    376   Loc: integer; {$ENDIF}
    377 begin
    378   G := NewGameData;
    379   MapSize := G.lx * G.ly;
    380   decompose24 := (1 shl 24 - 1) div G.lx + 1;
    381 {$IFDEF DEBUG} for Loc := 0 to MapSize - 1 do
    382     assert(cardinal(Loc) * decompose24 shr 24 = cardinal(Loc div G.lx));
    383   {$ENDIF}
    384 end;
    385 
    386 constructor TCustomAI.Create(Nation: integer);
    387 begin
    388   inherited Create;
    389   me := Nation;
    390   RO := pointer(G.RO[Nation]);
    391   Map := pointer(RO.Map);
    392   MyUnit := pointer(RO.Un);
    393   MyCity := pointer(RO.City);
    394   MyModel := pointer(RO.Model);
    395   Opponent := -1;
    396 end;
    397 
    398 destructor TCustomAI.Destroy;
    399 begin
    400   Server(sSetDebugMap, me, 0, nodata^);
    401 end;
    402 
    403 procedure TCustomAI.Process(Command: integer; var Data);
    404 var
    405   Nation, NewResearch, NewGov, Count, ad, cix, iix: integer;
    406   NegoTime: TNegoTime;
    407 begin
    408   case Command of
    409     cTurn, cContinue:
    410       begin
    411         if RO.Alive and (1 shl me) = 0 then
    412         begin // I'm dead, huhu
    413           Server(sTurn, me, 0, nodata^);
    414           exit
    415         end;
    416         if Command = cTurn then
    417         begin
    418           fillchar(cixStateImp, sizeof(cixStateImp), $FF);
    419           for cix := 0 to RO.nCity - 1 do
    420             if MyCity[cix].Loc >= 0 then
    421               for iix := imPalace to imSpacePort do
    422                 if MyCity[cix].Built[iix] > 0 then
    423                   cixStateImp[iix] := cix;
    424           if RO.Happened and phChangeGov <> 0 then
    425           begin
    426             NewGov := ChooseGovernment;
    427             if NewGov > gAnarchy then
    428               Server(sSetGovernment, me, NewGov, nodata^);
    429           end;
    430           HaveTurned := false;
    431           Contacted := [];
    432         end;
    433         if (Command = cContinue) and (MyAction = scContact) then
    434         begin
    435           if OnNegoRejected_CancelTreaty then
    436             if RO.Treaty[Opponent] >= trPeace then
    437               if Server(sCancelTreaty, me, 0, nodata^) < rExecuted then
    438                 assert(false)
    439         end
    440         else
    441           UnwantedNego := [];
    442         Opponent := -1;
    443         repeat
    444           if HaveTurned then
    445             NegoTime := EndOfTurn
    446           else
    447             NegoTime := BeginOfTurn;
    448           if RO.Government <> gAnarchy then
    449             for Nation := 0 to nPl - 1 do
    450               if (Nation <> me) and (1 shl Nation and RO.Alive <> 0) and
    451                 (RO.Treaty[Nation] >= trNone) and not(Nation in Contacted) and
    452                 not(Nation in UnwantedNego) and
    453                 (Server(scContact - sExecute + Nation shl 4, me, 0, nodata^) >=
    454                 rExecuted) then
    455                 if WantNegotiation(Nation, NegoTime) then
    456                 begin
    457                   if Server(scContact + Nation shl 4, me, 0, nodata^) >= rExecuted
    458                   then
    459                   begin
    460                     include(Contacted, Nation);
    461                     Opponent := Nation;
    462                     MyAction := scContact;
    463                     exit;
    464                   end;
    465                 end
    466                 else
    467                   include(UnwantedNego, Nation);
    468           if NegoTime = BeginOfTurn then
    469           begin
    470             DoTurn;
    471             HaveTurned := true;
    472             Contacted := [];
    473             UnwantedNego := [];
    474           end
    475           else
    476             break;
    477         until false;
    478         if RO.Happened and phTech <> 0 then
    479         begin
    480           NewResearch := ChooseResearchAdvance;
    481           if NewResearch < 0 then
    482           begin // choose random research
    483             Count := 0;
    484             for ad := 0 to nAdv - 1 do
    485               if AdvanceResearchable(ad) then
    486               begin
    487                 inc(Count);
    488                 if random(Count) = 0 then
    489                   NewResearch := ad
    490               end
    491           end;
    492           Server(sSetResearch, me, NewResearch, nodata^)
    493         end;
    494         if Server(sTurn, me, 0, nodata^) < rExecuted then
    495           assert(false);
    496       end;
    497     scContact:
    498       if WantNegotiation(integer(Data), EnemyCalled) then
    499       begin
    500         if Server(scDipStart, me, 0, nodata^) < rExecuted then
    501           assert(false);
    502         Opponent := integer(Data);
    503         MyAction := scDipStart;
    504       end
    505       else
    506       begin
    507         if Server(scReject, me, 0, nodata^) < rExecuted then
    508           assert(false);
    509       end;
    510     scDipStart, scDipNotice, scDipAccept, scDipCancelTreaty, scDipOffer,
    511       scDipBreak:
    512       begin
    513         OppoAction := Command;
    514         if Command = scDipOffer then
    515           OppoOffer := TOffer(Data);
    516         if Command = scDipStart then
    517           MyLastAction := scContact
    518         else
    519         begin
    520           MyLastAction := MyAction;
    521           MyLastOffer := MyOffer;
    522         end;
    523         if (OppoAction = scDipCancelTreaty) or (OppoAction = scDipBreak) then
    524           MyAction := scDipNotice
    525         else
    526         begin
    527           MyAction := scDipOffer;
    528           MyOffer.nDeliver := 0;
    529           MyOffer.nCost := 0;
    530         end;
    531         DoNegotiation;
    532         assert((MyAction = scDipNotice) or (MyAction = scDipAccept) or
    533           (MyAction = scDipCancelTreaty) or (MyAction = scDipOffer) or
    534           (MyAction = scDipBreak));
    535         if MyAction = scDipOffer then
    536           Server(MyAction, me, 0, MyOffer)
    537         else
    538           Server(MyAction, me, 0, nodata^);
    539       end;
    540     cShowEndContact:
    541       Opponent := -1;
     495    if (OppoAction=scDipCancelTreaty) or (OppoAction=scDipBreak) then
     496      MyAction:=scDipNotice
     497    else begin MyAction:=scDipOffer; MyOffer.nDeliver:=0; MyOffer.nCost:=0; end;
     498    DoNegotiation;
     499    assert((MyAction=scDipNotice) or (MyAction=scDipAccept)
     500      or (MyAction=scDipCancelTreaty) or (MyAction=scDipOffer)
     501      or (MyAction=scDipBreak));
     502    if MyAction=scDipOffer then Server(MyAction, me, 0, MyOffer)
     503    else Server(MyAction, me, 0, nodata^);
     504    end;
     505  cShowEndContact:
     506    Opponent:=-1;
    542507  end;
    543508end;
    544509
    545510{$HINTS OFF}
    546 
    547511procedure TCustomAI.SetDataDefaults;
    548512begin
     
    561525end;
    562526
    563 procedure TCustomAI.OnBeforeEnemyAttack(UnitInfo: TUnitInfo;
    564   ToLoc, EndHealth, EndHealthDef: integer);
     527procedure TCustomAI.OnBeforeEnemyAttack(UnitInfo: TUnitInfo; ToLoc, EndHealth,
     528  EndHealthDef: integer);
    565529begin
    566530end;
     
    580544function TCustomAI.ChooseResearchAdvance: integer;
    581545begin
    582   result := -1
     546result:=-1
    583547end;
    584548
    585549function TCustomAI.ChooseStealAdvance: integer;
    586550begin
    587   result := -1
     551result:=-1
    588552end;
    589553
    590554function TCustomAI.ChooseGovernment: integer;
    591555begin
    592   result := gDespotism
    593 end;
    594 
    595 function TCustomAI.WantNegotiation(Nation: integer;
    596   NegoTime: TNegoTime): boolean;
    597 begin
    598   result := false;
     556result:=gDespotism
     557end;
     558
     559function TCustomAI.WantNegotiation(Nation: integer; NegoTime: TNegoTime): boolean;
     560begin
     561result:=false;
    599562end;
    600563
    601564function TCustomAI.OnNegoRejected_CancelTreaty: boolean;
    602565begin
    603   result := false;
     566result:=false;
    604567end;
    605568{$HINTS ON}
     
    607570procedure TCustomAI.StealAdvance;
    608571var
    609   Steal, ad, Count: integer;
    610 begin
    611   Steal := ChooseStealAdvance;
    612   if Steal < 0 then
     572Steal, ad, count: integer;
     573begin
     574Steal:=ChooseStealAdvance;
     575if Steal<0 then
    613576  begin // choose random advance
    614     Count := 0;
    615     for ad := 0 to nAdv - 1 do
    616       if AdvanceStealable(ad) then
    617       begin
    618         inc(Count);
    619         if random(Count) = 0 then
    620           Steal := ad
    621       end
     577  count:=0;
     578  for ad:=0 to nAdv-1 do if AdvanceStealable(ad) then
     579    begin inc(count); if random(count)=0 then Steal:=ad end
    622580  end;
    623   if Steal >= 0 then
    624     Server(sStealTech, me, Steal, nodata^);
    625   RO.Happened := RO.Happened and not phStealTech
     581if Steal>=0 then Server(sStealTech,me,Steal,nodata^);
     582RO.Happened:=RO.Happened and not phStealTech
    626583end;
    627584
    628585function TCustomAI.IsResearched(Advance: integer): boolean;
    629586begin
    630   result := RO.Tech[Advance] >= tsApplicable
     587result:= (Advance=preNone)
     588  or (Advance<>preNA) and (RO.Tech[Advance]>=tsApplicable)
    631589end;
    632590
    633591function TCustomAI.ResearchCost: integer;
    634592begin
    635   Server(sGetTechCost, me, 0, result)
     593Server(sGetTechCost,me,0,result)
    636594end;
    637595
    638596function TCustomAI.ChangeAttitude(Nation, Attitude: integer): integer;
    639597begin
    640   result := Server(sSetAttitude + Nation shl 4, me, Attitude, nodata^)
     598result:=Server(sSetAttitude+Nation shl 4,me,Attitude,nodata^)
    641599end;
    642600
    643601function TCustomAI.Revolution: integer;
    644602begin
    645   result := Server(sRevolution, me, 0, nodata^);
    646 end;
    647 
    648 function TCustomAI.ChangeRates(Tax, Lux: integer): integer;
    649 begin
    650   result := Server(sSetRates, me, Tax div 10 and $F + Lux div 10 and
    651     $F shl 4, nodata^)
     603result:=Server(sRevolution,me,0,nodata^);
     604end;
     605
     606function TCustomAI.ChangeRates(Tax,Lux: integer): integer;
     607begin
     608result:=Server(sSetRates,me,Tax div 10 and $f+Lux div 10 and $f shl 4,nodata^)
    652609end;
    653610
    654611function TCustomAI.PrepareNewModel(Domain: integer): integer;
    655612begin
    656   result := Server(sCreateDevModel, me, Domain, nodata^);
     613result:=Server(sCreateDevModel,me,Domain,nodata^);
    657614end;
    658615
    659616function TCustomAI.SetNewModelFeature(F, Count: integer): integer;
    660617begin
    661   result := Server(sSetDevModelCap + Count shl 4, me, F, nodata^)
     618result:=Server(sSetDevModelCap+Count shl 4,me,F,nodata^)
    662619end;
    663620
    664621function TCustomAI.AdvanceResearchable(Advance: integer): boolean;
    665622begin
    666   result := Server(sSetResearch - sExecute, me, Advance, nodata^) >= rExecuted;
     623result:= Server(sSetResearch-sExecute,me,Advance,nodata^)>=rExecuted;
    667624end;
    668625
    669626function TCustomAI.AdvanceStealable(Advance: integer): boolean;
    670627begin
    671   result := Server(sStealTech - sExecute, me, Advance, nodata^) >= rExecuted;
    672 end;
    673 
    674 function TCustomAI.GetJobProgress(Loc: integer;
    675   var JobProgress: TJobProgressData): boolean;
    676 begin
    677   result := Server(sGetJobProgress, me, Loc, JobProgress) >= rExecuted;
     628result:= Server(sStealTech-sExecute,me,Advance,nodata^)>=rExecuted;
     629end;
     630
     631function TCustomAI.GetJobProgress(Loc: integer; var JobProgress: TJobProgressData): boolean;
     632begin
     633result:= Server(sGetJobProgress,me,Loc,JobProgress)>=rExecuted;
    678634end;
    679635
    680636function TCustomAI.DebugMessage(Level: integer; Text: string): boolean;
    681637begin
    682   Text := copy('P' + char(48 + me) + ' ' + Text, 1, 254);
    683   Server(sMessage, me, Level, pchar(Text)^);
    684 
    685   result := true;
     638Text:=copy('P'+char(48+me)+' '+Text,1,254);
     639Server(sMessage,me,Level,pchar(Text)^);
     640
     641result:=true;
    686642  // always returns true so that it can be used like
    687643  // "assert(DebugMessage(...));" -> not compiled in release build
     
    690646function TCustomAI.SetDebugMap(var DebugMap): boolean;
    691647begin
    692   Server(sSetDebugMap, me, 0, DebugMap);
    693 
    694   result := true;
     648Server(sSetDebugMap, me, 0, DebugMap);
     649
     650result:=true;
    695651  // always returns true so that it can be used like
    696652  // "assert(SetDebugMap(...));" -> not compiled in release build
     
    699655procedure TCustomAI.Unit_FindMyDefender(Loc: integer; var uix: integer);
    700656begin
    701   if Server(sGetDefender, me, Loc, uix) < rExecuted then
    702     uix := -1
     657if Server(sGetDefender,me,Loc,uix)<rExecuted then uix:=-1
    703658end;
    704659
    705660procedure TCustomAI.Unit_FindEnemyDefender(Loc: integer; var euix: integer);
    706661begin
    707   euix := RO.nEnemyUn - 1;
    708   while (euix >= 0) and (RO.EnemyUn[euix].Loc <> Loc) do
    709     dec(euix);
    710 end;
    711 
    712 function TCustomAI.Unit_Move(uix, ToLoc: integer): integer;
    713 var
    714   Step: integer;
    715   DestinationReached: boolean;
    716   Advice: TMoveAdviceData;
    717 begin
    718   assert((uix >= 0) and (uix < RO.nUn) and (MyUnit[uix].Loc >= 0)); // is a unit
    719   { Loc_to_ab(MyUnit[uix].Loc,ToLoc,a,b);
    720     assert((a<>0) or (b<>0));
    721     if (a>=-1) and (a<=1) and (b>=-1) and (b<=1) then
    722     begin // move to adjacent tile
    723     !!!problem: if move is invalid, return codes are not consistent with other branch (eNoWay)
    724     Advice.nStep:=1;
    725     Advice.dx[0]:=a-b;
    726     Advice.dy[0]:=a+b;
    727     Advice.MoreTurns:=0;
    728     Advice.MaxHostile_MovementLeft:=MyUnit[uix].Movement;
    729     result:=eOK;
     662euix:=RO.nEnemyUn-1;
     663while (euix>=0) and (RO.EnemyUn[euix].Loc<>Loc) do
     664  dec(euix);
     665end;
     666
     667function TCustomAI.Unit_Move(uix,ToLoc: integer): integer;
     668var
     669Step: integer;
     670DestinationReached: boolean;
     671Advice: TMoveAdviceData;
     672begin
     673assert((uix>=0) and (uix<RO.nUn) and (MyUnit[uix].Loc>=0)); // is a unit
     674{Loc_to_ab(MyUnit[uix].Loc,ToLoc,a,b);
     675assert((a<>0) or (b<>0));
     676if (a>=-1) and (a<=1) and (b>=-1) and (b<=1) then
     677  begin // move to adjacent tile
     678  !!!problem: if move is invalid, return codes are not consistent with other branch (eNoWay)
     679  Advice.nStep:=1;
     680  Advice.dx[0]:=a-b;
     681  Advice.dy[0]:=a+b;
     682  Advice.MoreTurns:=0;
     683  Advice.MaxHostile_MovementLeft:=MyUnit[uix].Movement;
     684  result:=eOK;
     685  end
     686else}
     687  begin // move to non-adjacent tile, find shortest path
     688  Advice.ToLoc:=ToLoc;
     689  Advice.MoreTurns:=9999;
     690  Advice.MaxHostile_MovementLeft:=100;
     691  result:=Server(sGetMoveAdvice,me,uix,Advice);
     692  end;
     693if result=eOk then
     694  begin
     695  DestinationReached:=false;
     696  Step:=0;
     697  repeat
     698    if result and (rExecuted or rUnitRemoved)=rExecuted then // check if destination reached
     699      if (ToLoc>=0) and (Advice.MoreTurns=0) and (Step=Advice.nStep-1)
     700        and ((Map[ToLoc] and (fUnit or fOwned)=fUnit) // attack
     701          or (Map[ToLoc] and (fCity or fOwned)=fCity)
     702          and ((MyModel[MyUnit[uix].mix].Domain<>dGround) // bombardment
     703            or (MyModel[MyUnit[uix].mix].Flags and mdCivil<>0))) then // can't capture
     704        begin DestinationReached:=true; break end // stop next to destination
     705      else if Step=Advice.nStep then
     706        DestinationReached:=true; // normal move -- stop at destination
     707
     708    if (Step=Advice.nStep) or (result<>eOK) and (result<>eLoaded) then
     709      break;
     710
     711    result:=Server(sMoveUnit+(Advice.dx[Step] and 7) shl 4 +(Advice.dy[Step] and 7) shl 7,
     712      me,uix,nodata^);
     713    inc(Step);
     714    if RO.Happened and phStealTech<>0 then StealAdvance;
     715  until false;
     716  if DestinationReached then
     717    if Advice.nStep=25 then
     718      result:=Unit_Move(uix,ToLoc) // Shinkansen
     719    else if Advice.MoreTurns=0 then
     720      result:=result or rLocationReached
     721    else result:=result or rMoreTurns;
     722  end
     723end;
     724
     725function TCustomAI.Unit_Step(uix,ToLoc: integer): integer;
     726var
     727a,b: integer;
     728begin
     729Loc_to_ab(MyUnit[uix].Loc, ToLoc, a, b);
     730assert(((a<>0) or (b<>0)) and (a>=-1) and (a<=1) and (b>=-1) and (b<=1));
     731result:=Server(sMoveUnit+((a-b) and 7) shl 4 +((a+b) and 7) shl 7, me, uix, nodata^);
     732if RO.Happened and phStealTech<>0 then StealAdvance;
     733end;
     734
     735function TCustomAI.Unit_Attack(uix,ToLoc: integer): integer;
     736var
     737a,b: integer;
     738begin
     739assert((uix>=0) and (uix<RO.nUn) and (MyUnit[uix].Loc>=0) // is a unit
     740  and ((Map[ToLoc] and (fUnit or fOwned)=fUnit) // is an attack
     741  or (Map[ToLoc] and (fCity or fOwned)=fCity)
     742  and (MyModel[MyUnit[uix].mix].Domain<>dGround))); // is a bombardment
     743Loc_to_ab(MyUnit[uix].Loc,ToLoc,a,b);
     744assert(((a<>0) or (b<>0)) and (a>=-1) and (a<=1) and (b>=-1) and (b<=1)); // attack to adjacent tile
     745result:=Server(sMoveUnit+(a-b) and 7 shl 4 +(a+b) and 7 shl 7,me,uix,nodata^);
     746end;
     747
     748function TCustomAI.Unit_DoMission(uix,MissionType,ToLoc: integer): integer;
     749var
     750a,b: integer;
     751begin
     752result:=Server(sSetSpyMission + MissionType shl 4,me,0,nodata^);
     753if result>=rExecuted then
     754  begin
     755  assert((uix>=0) and (uix<RO.nUn) and (MyUnit[uix].Loc>=0) // is a unit
     756    and (MyModel[MyUnit[uix].mix].Kind=mkDiplomat)); // is a commando
     757  Loc_to_ab(MyUnit[uix].Loc,ToLoc,a,b);
     758  assert(((a<>0) or (b<>0)) and (a>=-1) and (a<=1) and (b>=-1) and (b<=1)); // city must be adjacent
     759  result:=Server(sMoveUnit-sExecute+(a-b) and 7 shl 4 +(a+b) and 7 shl 7,me,uix,nodata^);
     760  if result=eMissionDone then
     761    result:=Server(sMoveUnit+(a-b) and 7 shl 4 +(a+b) and 7 shl 7,me,uix,nodata^)
     762  else if (result<>eNoTime_Move) and (result<>eTreaty) and (result<>eNoTurn) then
     763    result:=eInvalid // not a special commando mission!
     764  end
     765end;
     766
     767function TCustomAI.Unit_MoveForecast(uix,ToLoc: integer;
     768  var RemainingMovement: integer): boolean;
     769var
     770Advice: TMoveAdviceData;
     771begin
     772assert((uix>=0) and (uix<RO.nUn) and (MyUnit[uix].Loc>=0)); // is a unit
     773Advice.ToLoc:=ToLoc;
     774Advice.MoreTurns:=0;
     775Advice.MaxHostile_MovementLeft:=100;
     776if Server(sGetMoveAdvice,me,uix,Advice)=eOk then
     777  begin
     778  RemainingMovement:=Advice.MaxHostile_MovementLeft;
     779  result:=true
     780  end
     781else
     782  begin
     783  RemainingMovement:=-1;
     784  result:=false
     785  end
     786end;
     787
     788// negative RemainingHealth is remaining helth of defender if lost
     789function TCustomAI.Unit_AttackForecast(uix,ToLoc,AttackMovement: integer;
     790  var RemainingHealth: integer): boolean;
     791var
     792BattleForecast: TBattleForecast;
     793begin
     794assert((uix>=0) and (uix<RO.nUn) and (MyUnit[uix].Loc>=0) // is a unit
     795  and (Map[ToLoc] and (fUnit or fOwned)=fUnit)); // is an attack
     796RemainingHealth:=-$100;
     797result:=false;
     798if AttackMovement>=0 then with MyUnit[uix] do
     799  begin
     800  BattleForecast.pAtt:=me;
     801  BattleForecast.mixAtt:=mix;
     802  BattleForecast.HealthAtt:=Health;
     803  BattleForecast.ExpAtt:=Exp;
     804  BattleForecast.FlagsAtt:=Flags;
     805  BattleForecast.Movement:=AttackMovement;
     806  if Server(sGetBattleForecast,me,ToLoc,BattleForecast)>=rExecuted then
     807    begin
     808    if BattleForecast.EndHealthAtt>0 then
     809      RemainingHealth:=BattleForecast.EndHealthAtt
     810    else RemainingHealth:=-BattleForecast.EndHealthDef;
     811    result:=true
    730812    end
    731     else }
    732   begin // move to non-adjacent tile, find shortest path
    733     Advice.ToLoc := ToLoc;
    734     Advice.MoreTurns := 9999;
    735     Advice.MaxHostile_MovementLeft := 100;
    736     result := Server(sGetMoveAdvice, me, uix, Advice);
    737   end;
    738   if result = eOk then
     813  end
     814end;
     815
     816function TCustomAI.Unit_DefenseForecast(euix,ToLoc: integer;
     817  var RemainingHealth: integer): boolean;
     818var
     819BattleForecast: TBattleForecast;
     820begin
     821assert((euix>=0) and (euix<RO.nEnemyUn) and (RO.EnemyUn[euix].Loc>=0) // is an enemy unit
     822  and (Map[ToLoc] and (fUnit or fOwned)=(fUnit or fOwned))); // is an attack
     823RemainingHealth:=$100;
     824result:=false;
     825with RO.EnemyUn[euix] do
    739826  begin
    740     DestinationReached := false;
    741     Step := 0;
    742     repeat
    743       if result and (rExecuted or rUnitRemoved) = rExecuted then
    744       // check if destination reached
    745         if (ToLoc >= 0) and (Advice.MoreTurns = 0) and (Step = Advice.nStep - 1)
    746           and ((Map[ToLoc] and (fUnit or fOwned) = fUnit) // attack
    747           or (Map[ToLoc] and (fCity or fOwned) = fCity) and
    748           ((MyModel[MyUnit[uix].mix].Domain <> dGround) // bombardment
    749           or (MyModel[MyUnit[uix].mix].Flags and mdCivil <> 0))) then
    750         // can't capture
    751         begin
    752           DestinationReached := true;
    753           break
    754         end // stop next to destination
    755         else if Step = Advice.nStep then
    756           DestinationReached := true; // normal move -- stop at destination
    757 
    758       if (Step = Advice.nStep) or (result <> eOk) and (result <> eLoaded) then
    759         break;
    760 
    761       result := Server(sMoveUnit + (Advice.dx[Step] and 7) shl 4 +
    762         (Advice.dy[Step] and 7) shl 7, me, uix, nodata^);
    763       inc(Step);
    764       if RO.Happened and phStealTech <> 0 then
    765         StealAdvance;
    766     until false;
    767     if DestinationReached then
    768       if Advice.nStep = 25 then
    769         result := Unit_Move(uix, ToLoc) // Shinkansen
    770       else if Advice.MoreTurns = 0 then
    771         result := result or rLocationReached
    772       else
    773         result := result or rMoreTurns;
    774   end
    775 end;
    776 
    777 function TCustomAI.Unit_Step(uix, ToLoc: integer): integer;
    778 var
    779   a, b: integer;
    780 begin
    781   Loc_to_ab(MyUnit[uix].Loc, ToLoc, a, b);
    782   assert(((a <> 0) or (b <> 0)) and (a >= -1) and (a <= 1) and (b >= -1) and
    783     (b <= 1));
    784   result := Server(sMoveUnit + ((a - b) and 7) shl 4 + ((a + b) and 7) shl 7,
    785     me, uix, nodata^);
    786   if RO.Happened and phStealTech <> 0 then
    787     StealAdvance;
    788 end;
    789 
    790 function TCustomAI.Unit_Attack(uix, ToLoc: integer): integer;
    791 var
    792   a, b: integer;
    793 begin
    794   assert((uix >= 0) and (uix < RO.nUn) and (MyUnit[uix].Loc >= 0) // is a unit
    795     and ((Map[ToLoc] and (fUnit or fOwned) = fUnit) // is an attack
    796     or (Map[ToLoc] and (fCity or fOwned) = fCity) and
    797     (MyModel[MyUnit[uix].mix].Domain <> dGround))); // is a bombardment
    798   Loc_to_ab(MyUnit[uix].Loc, ToLoc, a, b);
    799   assert(((a <> 0) or (b <> 0)) and (a >= -1) and (a <= 1) and (b >= -1) and
    800     (b <= 1)); // attack to adjacent tile
    801   result := Server(sMoveUnit + (a - b) and 7 shl 4 + (a + b) and 7 shl 7, me,
    802     uix, nodata^);
    803 end;
    804 
    805 function TCustomAI.Unit_DoMission(uix, MissionType, ToLoc: integer): integer;
    806 var
    807   a, b: integer;
    808 begin
    809   result := Server(sSetSpyMission + MissionType shl 4, me, 0, nodata^);
    810   if result >= rExecuted then
     827  BattleForecast.pAtt:=Owner;
     828  BattleForecast.mixAtt:=mix;
     829  BattleForecast.HealthAtt:=Health;
     830  BattleForecast.ExpAtt:=Exp;
     831  BattleForecast.FlagsAtt:=Flags;
     832  BattleForecast.Movement:=100;
     833  if Server(sGetBattleForecast,me,ToLoc,BattleForecast)>=rExecuted then
     834    begin
     835    if BattleForecast.EndHealthDef>0 then
     836      RemainingHealth:=BattleForecast.EndHealthDef
     837    else RemainingHealth:=-BattleForecast.EndHealthAtt;
     838    result:=true
     839    end
     840  end
     841end;
     842
     843function TCustomAI.Unit_Disband(uix: integer): integer;
     844begin
     845result:=Server(sRemoveUnit,me,uix,nodata^)
     846end;
     847
     848function TCustomAI.Unit_StartJob(uix,NewJob: integer): integer;
     849begin
     850result:=Server(sStartJob+NewJob shl 4,me,uix,nodata^)
     851end;
     852
     853function TCustomAI.Unit_SetHomeHere(uix: integer): integer;
     854begin
     855result:=Server(sSetUnitHome,me,uix,nodata^)
     856end;
     857
     858function TCustomAI.Unit_Load(uix: integer): integer;
     859begin
     860result:=Server(sLoadUnit,me,uix,nodata^)
     861end;
     862
     863function TCustomAI.Unit_Unload(uix: integer): integer;
     864begin
     865result:=Server(sUnloadUnit,me,uix,nodata^)
     866end;
     867
     868function TCustomAI.Unit_AddToCity(uix: integer): integer;
     869begin
     870result:=Server(sAddToCity,me,uix,nodata^)
     871end;
     872
     873function TCustomAI.Unit_SelectTransport(uix: integer): integer;
     874begin
     875result:=Server(sSelectTransport,me,uix,nodata^)
     876end;
     877
     878
     879procedure TCustomAI.City_FindMyCity(Loc: integer; var cix: integer);
     880begin
     881if Map[Loc] and (fCity or fOwned)<>fCity or fOwned then
     882  cix:=-1
     883else
    811884  begin
    812     assert((uix >= 0) and (uix < RO.nUn) and (MyUnit[uix].Loc >= 0) // is a unit
    813       and (MyModel[MyUnit[uix].mix].Kind = mkDiplomat)); // is a commando
    814     Loc_to_ab(MyUnit[uix].Loc, ToLoc, a, b);
    815     assert(((a <> 0) or (b <> 0)) and (a >= -1) and (a <= 1) and (b >= -1) and
    816       (b <= 1)); // city must be adjacent
    817     result := Server(sMoveUnit - sExecute + (a - b) and 7 shl 4 + (a + b) and
    818       7 shl 7, me, uix, nodata^);
    819     if result = eMissionDone then
    820       result := Server(sMoveUnit + (a - b) and 7 shl 4 + (a + b) and 7 shl 7,
    821         me, uix, nodata^)
    822     else if (result <> eNoTime_Move) and (result <> eTreaty) and
    823       (result <> eNoTurn) then
    824       result := eInvalid // not a special commando mission!
    825   end
    826 end;
    827 
    828 function TCustomAI.Unit_MoveForecast(uix, ToLoc: integer;
    829   var RemainingMovement: integer): boolean;
    830 var
    831   Advice: TMoveAdviceData;
    832 begin
    833   assert((uix >= 0) and (uix < RO.nUn) and (MyUnit[uix].Loc >= 0)); // is a unit
    834   Advice.ToLoc := ToLoc;
    835   Advice.MoreTurns := 0;
    836   Advice.MaxHostile_MovementLeft := 100;
    837   if Server(sGetMoveAdvice, me, uix, Advice) = eOk then
     885  cix:=RO.nCity-1;
     886  while (cix>=0) and (MyCity[cix].Loc<>Loc) do
     887    dec(cix);
     888  end
     889end;
     890
     891procedure TCustomAI.City_FindEnemyCity(Loc: integer; var ecix: integer);
     892begin
     893if Map[Loc] and (fCity or fOwned)<>fCity then
     894  ecix:=-1
     895else
    838896  begin
    839     RemainingMovement := Advice.MaxHostile_MovementLeft;
    840     result := true
    841   end
    842   else
     897  ecix:=RO.nEnemyCity-1;
     898  while (ecix>=0) and (RO.EnemyCity[ecix].Loc<>Loc) do
     899    dec(ecix);
     900  end
     901end;
     902
     903function TCustomAI.City_HasProject(cix: integer): boolean;
     904begin
     905result:= MyCity[cix].Project and (cpImp+cpIndex)<>cpImp+imTrGoods
     906end;
     907
     908function TCustomAI.City_CurrentImprovementProject(cix: integer): integer;
     909begin
     910if MyCity[cix].Project and cpImp=0 then result:=-1
     911else
    843912  begin
    844     RemainingMovement := -1;
    845     result := false
    846   end
    847 end;
    848 
    849 function TCustomAI.Unit_AttackForecast(uix, ToLoc, AttackMovement: integer;
    850   var RemainingHealth: integer): boolean;
    851 var
    852   BattleForecast: TBattleForecast;
    853 begin
    854   assert((uix >= 0) and (uix < RO.nUn) and (MyUnit[uix].Loc >= 0) // is a unit
    855     and (Map[ToLoc] and (fUnit or fOwned) = fUnit)); // is an attack
    856   RemainingHealth := -$100;
    857   result := false;
    858   if AttackMovement >= 0 then
    859     with MyUnit[uix] do
    860     begin
    861       BattleForecast.pAtt := me;
    862       BattleForecast.mixAtt := mix;
    863       BattleForecast.HealthAtt := Health;
    864       BattleForecast.ExpAtt := Exp;
    865       BattleForecast.FlagsAtt := Flags;
    866       BattleForecast.Movement := AttackMovement;
    867       if Server(sGetBattleForecast, me, ToLoc, BattleForecast) >= rExecuted then
    868       begin
    869         if BattleForecast.EndHealthAtt > 0 then
    870           RemainingHealth := BattleForecast.EndHealthAtt
    871         else
    872           RemainingHealth := -BattleForecast.EndHealthDef;
    873         result := true
    874       end
    875     end
    876 end;
    877 
    878 function TCustomAI.Unit_DefenseForecast(euix, ToLoc: integer;
    879   var RemainingHealth: integer): boolean;
    880 var
    881   BattleForecast: TBattleForecast;
    882 begin
    883   assert((euix >= 0) and (euix < RO.nEnemyUn) and (RO.EnemyUn[euix].Loc >= 0)
    884     // is an enemy unit
    885     and (Map[ToLoc] and (fUnit or fOwned) = (fUnit or fOwned))); // is an attack
    886   RemainingHealth := $100;
    887   result := false;
    888   with RO.EnemyUn[euix] do
    889   begin
    890     BattleForecast.pAtt := Owner;
    891     BattleForecast.mixAtt := mix;
    892     BattleForecast.HealthAtt := Health;
    893     BattleForecast.ExpAtt := Exp;
    894     BattleForecast.FlagsAtt := Flags;
    895     BattleForecast.Movement := 100;
    896     if Server(sGetBattleForecast, me, ToLoc, BattleForecast) >= rExecuted then
    897     begin
    898       if BattleForecast.EndHealthDef > 0 then
    899         RemainingHealth := BattleForecast.EndHealthDef
    900       else
    901         RemainingHealth := -BattleForecast.EndHealthAtt;
    902       result := true
    903     end
    904   end
    905 end;
    906 
    907 function TCustomAI.Unit_Disband(uix: integer): integer;
    908 begin
    909   result := Server(sRemoveUnit, me, uix, nodata^)
    910 end;
    911 
    912 function TCustomAI.Unit_StartJob(uix, NewJob: integer): integer;
    913 begin
    914   result := Server(sStartJob + NewJob shl 4, me, uix, nodata^)
    915 end;
    916 
    917 function TCustomAI.Unit_SetHomeHere(uix: integer): integer;
    918 begin
    919   result := Server(sSetUnitHome, me, uix, nodata^)
    920 end;
    921 
    922 function TCustomAI.Unit_Load(uix: integer): integer;
    923 begin
    924   result := Server(sLoadUnit, me, uix, nodata^)
    925 end;
    926 
    927 function TCustomAI.Unit_Unload(uix: integer): integer;
    928 begin
    929   result := Server(sUnloadUnit, me, uix, nodata^)
    930 end;
    931 
    932 function TCustomAI.Unit_AddToCity(uix: integer): integer;
    933 begin
    934   result := Server(sAddToCity, me, uix, nodata^)
    935 end;
    936 
    937 function TCustomAI.Unit_SelectTransport(uix: integer): integer;
    938 begin
    939   result := Server(sSelectTransport, me, uix, nodata^)
    940 end;
    941 
    942 procedure TCustomAI.City_FindMyCity(Loc: integer; var cix: integer);
    943 begin
    944   if Map[Loc] and (fCity or fOwned) <> fCity or fOwned then
    945     cix := -1
    946   else
    947   begin
    948     cix := RO.nCity - 1;
    949     while (cix >= 0) and (MyCity[cix].Loc <> Loc) do
    950       dec(cix);
    951   end
    952 end;
    953 
    954 procedure TCustomAI.City_FindEnemyCity(Loc: integer; var ecix: integer);
    955 begin
    956   if Map[Loc] and (fCity or fOwned) <> fCity then
    957     ecix := -1
    958   else
    959   begin
    960     ecix := RO.nEnemyCity - 1;
    961     while (ecix >= 0) and (RO.EnemyCity[ecix].Loc <> Loc) do
    962       dec(ecix);
    963   end
    964 end;
    965 
    966 function TCustomAI.City_HasProject(cix: integer): boolean;
    967 begin
    968   result := MyCity[cix].Project and (cpImp + cpIndex) <> cpImp + imTrGoods
    969 end;
    970 
    971 function TCustomAI.City_CurrentImprovementProject(cix: integer): integer;
    972 begin
    973   if MyCity[cix].Project and cpImp = 0 then
    974     result := -1
    975   else
    976   begin
    977     result := MyCity[cix].Project and cpIndex;
    978     if result = imTrGoods then
    979       result := -1
     913  result:=MyCity[cix].Project and cpIndex;
     914  if result=imTrGoods then result:=-1
    980915  end
    981916end;
     
    983918function TCustomAI.City_CurrentUnitProject(cix: integer): integer;
    984919begin
    985   if MyCity[cix].Project and cpImp <> 0 then
    986     result := -1
    987   else
    988     result := MyCity[cix].Project and cpIndex;
    989 end;
    990 
    991 function TCustomAI.City_GetTileInfo(cix, TileLoc: integer;
    992   var TileInfo: TTileInfo): integer;
    993 begin
    994   TileInfo.ExplCity := cix;
    995   result := Server(sGetHypoCityTileInfo, me, TileLoc, TileInfo)
    996 end;
    997 
    998 function TCustomAI.City_GetReport(cix: integer;
    999   var Report: TCityReport): integer;
    1000 begin
    1001   Report.HypoTiles := -1;
    1002   Report.HypoTax := -1;
    1003   Report.HypoLux := -1;
    1004   result := Server(sGetCityReport, me, cix, Report)
     920if MyCity[cix].Project and cpImp<>0 then result:=-1
     921else result:=MyCity[cix].Project and cpIndex;
     922end;
     923
     924function TCustomAI.City_GetTileInfo(cix,TileLoc: integer; var TileInfo: TTileInfo): integer;
     925begin
     926TileInfo.ExplCity:=cix;
     927result:=Server(sGetHypoCityTileInfo,me,TileLoc,TileInfo)
     928end;
     929
     930function TCustomAI.City_GetReport(cix: integer; var Report: TCityReport): integer;
     931begin
     932Report.HypoTiles:=-1;
     933Report.HypoTax:=-1;
     934Report.HypoLux:=-1;
     935result:=Server(sGetCityReport,me,cix,Report)
    1005936end;
    1006937
     
    1008939  var Report: TCityReport): integer;
    1009940begin
    1010   Report.HypoTiles := HypoTiles;
    1011   Report.HypoTax := HypoTax;
    1012   Report.HypoLux := HypoLux;
    1013   result := Server(sGetCityReport, me, cix, Report)
    1014 end;
    1015 
    1016 function TCustomAI.City_GetReportNew(cix: integer;
     941Report.HypoTiles:=HypoTiles;
     942Report.HypoTax:=HypoTax;
     943Report.HypoLux:=HypoLux;
     944result:=Server(sGetCityReport,me,cix,Report)
     945end;
     946
     947function TCustomAI.City_GetReportNew(cix: integer; var Report: TCityReportNew): integer;
     948begin
     949Report.HypoTiles:=-1;
     950Report.HypoTaxRate:=-1;
     951Report.HypoLuxuryRate:=-1;
     952result:=Server(sGetCityReportNew,me,cix,Report)
     953end;
     954
     955function TCustomAI.City_GetHypoReportNew(cix, HypoTiles, HypoTaxRate, HypoLuxuryRate: integer;
    1017956  var Report: TCityReportNew): integer;
    1018957begin
    1019   Report.HypoTiles := -1;
    1020   Report.HypoTaxRate := -1;
    1021   Report.HypoLuxuryRate := -1;
    1022   result := Server(sGetCityReportNew, me, cix, Report)
    1023 end;
    1024 
    1025 function TCustomAI.City_GetHypoReportNew(cix, HypoTiles, HypoTaxRate,
    1026   HypoLuxuryRate: integer; var Report: TCityReportNew): integer;
    1027 begin
    1028   Report.HypoTiles := HypoTiles;
    1029   Report.HypoTaxRate := HypoTaxRate;
    1030   Report.HypoLuxuryRate := HypoLuxuryRate;
    1031   result := Server(sGetCityReportNew, me, cix, Report)
    1032 end;
    1033 
    1034 function TCustomAI.City_GetAreaInfo(cix: integer;
    1035   var AreaInfo: TCityAreaInfo): integer;
    1036 begin
    1037   result := Server(sGetCityAreaInfo, me, cix, AreaInfo)
    1038 end;
    1039 
    1040 function TCustomAI.City_StartUnitProduction(cix, mix: integer): integer;
    1041 begin
    1042   result := Server(sSetCityProject, me, cix, mix)
    1043 end;
    1044 
    1045 function TCustomAI.City_StartEmigration(cix, mix: integer;
     958Report.HypoTiles:=HypoTiles;
     959Report.HypoTaxRate:=HypoTaxRate;
     960Report.HypoLuxuryRate:=HypoLuxuryRate;
     961result:=Server(sGetCityReportNew,me,cix,Report)
     962end;
     963
     964function TCustomAI.City_GetAreaInfo(cix: integer; var AreaInfo: TCityAreaInfo): integer;
     965begin
     966result:=Server(sGetCityAreaInfo,me,cix,AreaInfo)
     967end;
     968
     969function TCustomAI.City_StartUnitProduction(cix,mix: integer): integer;
     970begin
     971if (MyCity[cix].Project and (cpImp+cpIndex)<>mix) then
     972  // not already producing that
     973  result:=Server(sSetCityProject,me,cix,mix)
     974end;
     975
     976function TCustomAI.City_StartEmigration(cix,mix: integer;
    1046977  AllowDisbandCity, AsConscripts: boolean): integer;
    1047978var
    1048   NewProject: integer;
    1049 begin
    1050   NewProject := mix;
    1051   if AllowDisbandCity then
    1052     NewProject := NewProject or cpDisbandCity;
    1053   if AsConscripts then
    1054     NewProject := NewProject or cpConscripts;
    1055   result := Server(sSetCityProject, me, cix, NewProject)
    1056 end;
    1057 
    1058 function TCustomAI.City_StartImprovement(cix, iix: integer): integer;
    1059 var
    1060   NewProject: integer;
    1061 begin
    1062   NewProject := iix + cpImp;
    1063   result := Server(sSetCityProject, me, cix, NewProject)
    1064 end;
    1065 
    1066 function TCustomAI.City_Improvable(cix, iix: integer): boolean;
    1067 var
    1068   NewProject: integer;
    1069 begin
    1070   NewProject := iix + cpImp;
    1071   result := Server(sSetCityProject - sExecute, me, cix, NewProject) >=
    1072     rExecuted;
     979NewProject: integer;
     980begin
     981NewProject:=mix;
     982if AllowDisbandCity then NewProject:=NewProject or cpDisbandCity;
     983if AsConscripts then NewProject:=NewProject or cpConscripts;
     984result:=Server(sSetCityProject,me,cix,NewProject)
     985end;
     986
     987function TCustomAI.City_StartImprovement(cix,iix: integer): integer;
     988var
     989NewProject: integer;
     990begin
     991NewProject:=iix+cpImp;
     992if (MyCity[cix].Project and (cpImp+cpIndex)<>NewProject) then
     993  // not already producing that
     994  result:=Server(sSetCityProject,me,cix,NewProject)
     995end;
     996
     997function TCustomAI.City_Improvable(cix,iix: integer): boolean;
     998var
     999NewProject: integer;
     1000begin
     1001NewProject:=iix+cpImp;
     1002result:= Server(sSetCityProject-sExecute,me,cix,NewProject)>=rExecuted;
    10731003end;
    10741004
    10751005function TCustomAI.City_StopProduction(cix: integer): integer;
    10761006var
    1077   NewProject: integer;
    1078 begin
    1079   NewProject := imTrGoods + cpImp;
    1080   result := Server(sSetCityProject, me, cix, NewProject)
     1007NewProject: integer;
     1008begin
     1009NewProject:=imTrGoods+cpImp;
     1010result:=Server(sSetCityProject,me,cix,NewProject)
    10811011end;
    10821012
    10831013function TCustomAI.City_BuyProject(cix: integer): integer;
    10841014begin
    1085   result := Server(sBuyCityProject, me, cix, nodata^)
    1086 end;
    1087 
    1088 function TCustomAI.City_SellImprovement(cix, iix: integer): integer;
    1089 begin
    1090   result := Server(sSellCityImprovement, me, cix, iix)
    1091 end;
    1092 
    1093 function TCustomAI.City_RebuildImprovement(cix, iix: integer): integer;
    1094 begin
    1095   result := Server(sRebuildCityImprovement, me, cix, iix)
    1096 end;
    1097 
    1098 function TCustomAI.City_SetTiles(cix, NewTiles: integer): integer;
    1099 begin
    1100   result := Server(sSetCityTiles, me, cix, NewTiles)
    1101 end;
    1102 
    1103 procedure TCustomAI.City_OptimizeTiles(cix: integer; ResourceWeights: integer);
    1104 var
    1105   Advice: TCityTileAdviceData;
    1106 begin
    1107   Advice.ResourceWeights := ResourceWeights;
    1108   Server(sGetCityTileAdvice, me, cix, Advice);
    1109   City_SetTiles(cix, Advice.Tiles);
    1110 end;
     1015result:=Server(sBuyCityProject,me,cix,nodata^)
     1016end;
     1017
     1018function TCustomAI.City_SellImprovement(cix,iix: integer): integer;
     1019begin
     1020result:=Server(sSellCityImprovement,me,cix,iix)
     1021end;
     1022
     1023function TCustomAI.City_RebuildImprovement(cix,iix: integer): integer;
     1024begin
     1025result:=Server(sRebuildCityImprovement,me,cix,iix)
     1026end;
     1027
     1028function TCustomAI.City_SetTiles(cix,NewTiles: integer): integer;
     1029begin
     1030result:=Server(sSetCityTiles,me,cix,NewTiles)
     1031end;
     1032
     1033procedure TCustomAI.City_OptimizeTiles(cix: integer; ResourceWeights: cardinal);
     1034var
     1035Advice: TCityTileAdviceData;
     1036begin
     1037Advice.ResourceWeights:=ResourceWeights;
     1038Server(sGetCityTileAdvice, me, cix, Advice);
     1039City_SetTiles(cix, Advice.Tiles);
     1040end;
     1041
    11111042
    11121043// negotiation
    11131044function TCustomAI.Nego_CheckMyAction: integer;
    11141045begin
    1115   assert(Opponent >= 0); // only allowed in negotiation mode
    1116   assert((MyAction = scDipNotice) or (MyAction = scDipAccept) or
    1117     (MyAction = scDipCancelTreaty) or (MyAction = scDipOffer) or
    1118     (MyAction = scDipBreak));
    1119   if MyAction = scDipOffer then
    1120     result := Server(MyAction - sExecute, me, 0, MyOffer)
    1121   else
    1122     result := Server(MyAction - sExecute, me, 0, nodata^);
    1123 end;
     1046assert(Opponent>=0); // only allowed in negotiation mode
     1047assert((MyAction=scDipNotice) or (MyAction=scDipAccept)
     1048  or (MyAction=scDipCancelTreaty) or (MyAction=scDipOffer)
     1049  or (MyAction=scDipBreak));
     1050if MyAction=scDipOffer then result:=Server(MyAction-sExecute, me, 0, MyOffer)
     1051else result:=Server(MyAction-sExecute, me, 0, nodata^);
     1052end;
     1053
    11241054
    11251055initialization
    1126 
    1127 nodata := pointer(0);
    1128 RWDataSize := 0;
     1056nodata:=pointer(0);
     1057RWDataSize:=0;
    11291058
    11301059end.
     1060
Note: See TracChangeset for help on using the changeset viewer.