Changeset 33 for trunk


Ignore:
Timestamp:
Jan 8, 2017, 11:42:00 PM (8 years ago)
Author:
chronos
Message:
  • Fixed: Source formatting of some files due missing semicolon before until keyword.
Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/IPQ.pas

    r17 r33  
    1 {binary heap priority queue
    2 code contributed by Rassim Eminli}
     1{ binary heap priority queue
     2  code contributed by Rassim Eminli }
    33
    44{$INCLUDE Switches.pas}
    5 
    65unit IPQ;
    76
     
    109type
    1110
    12 TIntegerArray = array[0..$40000000 div sizeof(integer)] of integer;
    13 PIntegerArray = ^TIntegerArray;
     11  TIntegerArray = array [0 .. $40000000 div sizeof(integer)] of integer;
     12  PIntegerArray = ^TIntegerArray;
    1413
    15 TheapItem = record
    16         Item:   integer;
    17         Value:  integer;
    18 end;
    19 
    20 TItemArray = array[0..$40000000 div sizeof(TheapItem)] of TheapItem;
    21 PItemArray = ^TItemArray;
    22 
    23 TIPQ = class
    24         constructor Create(max: integer);
    25         destructor Destroy; override;
    26         procedure Empty;
    27         function Put(Item, Value: integer): boolean;
    28         function TestPut(Item, Value: integer): boolean;
    29         function Get(var Item, Value: integer): boolean;
    30 private
    31 // n - is the size of the heap.
    32 // fmax - is the max size of the heap.
    33         n, fmax:        integer;
    34 
    35 // bh - stores (Value, Item) pairs of the heap.
    36 // Ix - stores the positions of pairs in the heap bh.
    37         bh:                     PItemArray;
    38         Ix:                     PIntegerArray;
     14  TheapItem = record
     15    Item: integer;
     16    Value: integer;
    3917  end;
    4018
     19  TItemArray = array [0 .. $40000000 div sizeof(TheapItem)] of TheapItem;
     20  PItemArray = ^TItemArray;
     21
     22  TIPQ = class
     23    constructor Create(max: integer);
     24    destructor Destroy; override;
     25    procedure Empty;
     26    function Put(Item, Value: integer): boolean;
     27    function TestPut(Item, Value: integer): boolean;
     28    function Get(var Item, Value: integer): boolean;
     29  private
     30    // n - is the size of the heap.
     31    // fmax - is the max size of the heap.
     32    n, fmax: integer;
     33
     34    // bh - stores (Value, Item) pairs of the heap.
     35    // Ix - stores the positions of pairs in the heap bh.
     36    bh: PItemArray;
     37    Ix: PIntegerArray;
     38  end;
    4139
    4240implementation
     
    4442constructor TIPQ.Create(max: integer);
    4543begin
    46         inherited Create;
    47         fmax := max;
    48         GetMem(bh, fmax*SizeOf(TheapItem));
    49         GetMem(Ix, fmax*SizeOf(integer));
    50         n:=-1;
    51         Empty
     44  inherited Create;
     45  fmax := max;
     46  GetMem(bh, fmax * sizeof(TheapItem));
     47  GetMem(Ix, fmax * sizeof(integer));
     48  n := -1;
     49  Empty
    5250end;
    5351
    5452destructor TIPQ.Destroy;
    5553begin
    56         FreeMem(bh);
    57         FreeMem(Ix);
    58         inherited Destroy;
     54  FreeMem(bh);
     55  FreeMem(Ix);
     56  inherited Destroy;
    5957end;
    6058
    6159procedure TIPQ.Empty;
    6260begin
    63         if n <> 0 then
    64         begin
    65                 FillChar(Ix^, fmax*sizeOf(integer), 255);
    66                 n := 0;
    67         end;
     61  if n <> 0 then
     62  begin
     63    FillChar(Ix^, fmax * sizeof(integer), 255);
     64    n := 0;
     65  end;
    6866end;
    6967
    70 //Parent(i) = (i-1)/2.
    71 function TIPQ.Put(Item, Value: integer): boolean; //O(lg(n))
     68// Parent(i) = (i-1)/2.
     69function TIPQ.Put(Item, Value: integer): boolean; // O(lg(n))
    7270var
    73         i, j:   integer;
    74         lbh:    PItemArray;
    75         lIx:    PIntegerArray;
     71  i, j: integer;
     72  lbh: PItemArray;
     73  lIx: PIntegerArray;
    7674begin
    77         lIx := Ix;
    78         lbh := bh;
    79         i := lIx[Item];
    80         if i >= 0 then
    81         begin
    82                 if lbh[i].Value <= Value then
    83                 begin
    84                         result := False;
    85                         exit;
    86                 end;
    87         end
    88         else
    89         begin
    90                 i := n;
    91                 Inc(n);
    92         end;
     75  lIx := Ix;
     76  lbh := bh;
     77  i := lIx[Item];
     78  if i >= 0 then
     79  begin
     80    if lbh[i].Value <= Value then
     81    begin
     82      result := False;
     83      exit;
     84    end;
     85  end
     86  else
     87  begin
     88    i := n;
     89    Inc(n);
     90  end;
    9391
    94         while i > 0 do
    95         begin
    96                 j := (i-1) shr 1;       //Parent(i) = (i-1)/2
    97                 if Value >= lbh[j].Value then   break;
    98                 lbh[i] := lbh[j];
    99                 lIx[lbh[i].Item] := i;
    100                 i := j;
    101         end;
    102         //      Insert the new Item at the insertion point found.
    103         lbh[i].Value := Value;
    104         lbh[i].Item := Item;
    105         lIx[lbh[i].Item] := i;
    106         result := True;
     92  while i > 0 do
     93  begin
     94    j := (i - 1) shr 1; // Parent(i) = (i-1)/2
     95    if Value >= lbh[j].Value then
     96      break;
     97    lbh[i] := lbh[j];
     98    lIx[lbh[i].Item] := i;
     99    i := j;
     100  end;
     101  // Insert the new Item at the insertion point found.
     102  lbh[i].Value := Value;
     103  lbh[i].Item := Item;
     104  lIx[lbh[i].Item] := i;
     105  result := True;
    107106end;
    108107
    109108function TIPQ.TestPut(Item, Value: integer): boolean;
    110109var
    111         i: integer;
     110  i: integer;
    112111begin
    113         i := Ix[Item];
    114         result := (i < 0) or (bh[i].Value > Value);
     112  i := Ix[Item];
     113  result := (i < 0) or (bh[i].Value > Value);
    115114end;
    116115
    117 //Left(i) = 2*i+1.
    118 //Right(i) = 2*i+2 => Left(i)+1
    119 function TIPQ.Get(var Item, Value: integer): boolean; //O(lg(n))
     116// Left(i) = 2*i+1.
     117// Right(i) = 2*i+2 => Left(i)+1
     118function TIPQ.Get(var Item, Value: integer): boolean; // O(lg(n))
    120119var
    121         i, j:   integer;
    122         last:   TheapItem;
    123         lbh:    PItemArray;
     120  i, j: integer;
     121  last: TheapItem;
     122  lbh: PItemArray;
    124123begin
    125         if n = 0 then
    126         begin
    127                 result := False;
    128                 exit;
    129         end;
     124  if n = 0 then
     125  begin
     126    result := False;
     127    exit;
     128  end;
    130129
    131         lbh := bh;
    132         Item := lbh[0].Item;
    133         Value := lbh[0].Value;
     130  lbh := bh;
     131  Item := lbh[0].Item;
     132  Value := lbh[0].Value;
    134133
    135         Ix[Item] := -1;
     134  Ix[Item] := -1;
    136135
    137         dec(n);
    138         if n > 0 then
    139         begin
    140                 last := lbh[n];
    141                 i := 0;         j := 1;
    142                 while j < n do
    143                 begin
    144                                                                                 //      Right(i) = Left(i)+1
    145                         if(j < n-1) and (lbh[j].Value > lbh[j + 1].Value)then
    146                                 inc(j);
    147                         if last.Value <= lbh[j].Value then              break;
     136  dec(n);
     137  if n > 0 then
     138  begin
     139    last := lbh[n];
     140    i := 0;
     141    j := 1;
     142    while j < n do
     143    begin
     144      // Right(i) = Left(i)+1
     145      if (j < n - 1) and (lbh[j].Value > lbh[j + 1].Value) then
     146        Inc(j);
     147      if last.Value <= lbh[j].Value then
     148        break;
    148149
    149                         lbh[i] := lbh[j];
    150                         Ix[lbh[i].Item] := i;
    151                         i := j;
    152                         j := j shl 1+1; //Left(j) = 2*j+1
    153                 end;
     150      lbh[i] := lbh[j];
     151      Ix[lbh[i].Item] := i;
     152      i := j;
     153      j := j shl 1 + 1; // Left(j) = 2*j+1
     154    end;
    154155
    155                 // Insert the root in the correct place in the heap.
    156                 lbh[i] := last;
    157                 Ix[last.Item] := i;
    158         end;
    159         result := True
     156    // Insert the root in the correct place in the heap.
     157    lbh[i] := last;
     158    Ix[last.Item] := i;
     159  end;
     160  result := True
    160161end;
    161162
    162163end.
    163 
  • trunk/Integrated.lpi

    r32 r33  
    214214        <Filename Value="Direct.pas"/>
    215215        <IsPartOfProject Value="True"/>
    216         <HasResources Value="True"/>
     216        <ComponentName Value="DirectDlg"/>
     217        <HasResources Value="True"/>
     218        <ResourceBaseClass Value="Form"/>
    217219      </Unit9>
    218220      <Unit10>
     
    395397        <Filename Value="LocalPlayer\TechTree.pas"/>
    396398        <IsPartOfProject Value="True"/>
    397         <HasResources Value="True"/>
     399        <ComponentName Value="TechTreeDlg"/>
     400        <HasResources Value="True"/>
     401        <ResourceBaseClass Value="Form"/>
    398402      </Unit40>
    399403      <Unit41>
  • trunk/LocalPlayer/IsoEngine.pas

    r28 r33  
    360360        if Border then
    361361          inc(TSpriteSize[i].Left);
    362       until not Border or
    363         (TSpriteSize[i].Left = xxt * 2 - 1);
     362      until not Border or (TSpriteSize[i].Left = xxt * 2 - 1);
    364363      TSpriteSize[i].Top := 0;
    365364      repeat
     
    371370        if Border then
    372371          inc(TSpriteSize[i].Top);
    373       until not Border or
    374         (TSpriteSize[i].Top = yyt * 3 - 1);
     372      until not Border or (TSpriteSize[i].Top = yyt * 3 - 1);
    375373      TSpriteSize[i].Right := xxt * 2;
    376374      repeat
     
    382380        if Border then
    383381          dec(TSpriteSize[i].Right);
    384       until not Border or
    385         (TSpriteSize[i].Right = TSpriteSize[i].Left);
     382      until not Border or (TSpriteSize[i].Right = TSpriteSize[i].Left);
    386383      TSpriteSize[i].Bottom := yyt * 3;
    387384      repeat
    388385        Border := true;
    389386        for x := 0 to xxt * 2 - 1 do
    390           if MaskLine[TSpriteSize[i].Bottom - 1]^
    391             [1 + xSrc * (xxt * 2 + 1) + x, 0] = 0 then
    392               Border := false;
     387          if MaskLine[TSpriteSize[i].Bottom - 1]^[1 + xSrc * (xxt * 2 + 1) + x,
     388            0] = 0 then
     389            Border := false;
    393390        if Border then
    394391          dec(TSpriteSize[i].Bottom);
    395       until not Border or
    396         (TSpriteSize[i].Bottom = TSpriteSize[i].Top);
     392      until not Border or (TSpriteSize[i].Bottom = TSpriteSize[i].Top);
    397393    end
    398394  end;
     
    409405end;
    410406
    411         procedure Done;
     407procedure Done;
     408begin
     409  NoMap.Free;
     410  NoMap := nil;
     411  LandPatch.Free;
     412  LandPatch := nil;
     413  OceanPatch.Free;
     414  OceanPatch := nil;
     415  Borders.Free;
     416  Borders := nil;
     417end;
     418
     419procedure Reset;
     420begin
     421  BordersOK := 0;
     422end;
     423
     424constructor TIsoMap.Create;
     425begin
     426  inherited;
     427  FLeft := 0;
     428  FTop := 0;
     429  FRight := 0;
     430  FBottom := 0;
     431  AttLoc := -1;
     432  DefLoc := -1;
     433  FAdviceLoc := -1;
     434end;
     435
     436procedure TIsoMap.SetOutput(Output: TBitmap);
     437begin
     438  FOutput := Output;
     439  FLeft := 0;
     440  FTop := 0;
     441  FRight := FOutput.Width;
     442  FBottom := FOutput.Height;
     443end;
     444
     445procedure TIsoMap.SetPaintBounds(Left, Top, Right, Bottom: integer);
     446begin
     447  FLeft := Left;
     448  FTop := Top;
     449  FRight := Right;
     450  FBottom := Bottom;
     451end;
     452
     453procedure TIsoMap.FillRect(x, y, Width, Height, Color: integer);
     454begin
     455  if x < FLeft then
     456  begin
     457    Width := Width - (FLeft - x);
     458    x := FLeft
     459  end;
     460  if y < FTop then
     461  begin
     462    Height := Height - (FTop - y);
     463    y := FTop
     464  end;
     465  if x + Width >= FRight then
     466    Width := FRight - x;
     467  if y + Height >= FBottom then
     468    Height := FBottom - y;
     469  if (Width <= 0) or (Height <= 0) then
     470    exit;
     471
     472  with FOutput.Canvas do
     473  begin
     474    Brush.Color := Color;
     475    FillRect(Rect(x, y, x + Width, y + Height));
     476    Brush.Style := bsClear;
     477  end
     478end;
     479
     480procedure TIsoMap.Textout(x, y, Color: integer; const s: string);
     481begin
     482  FOutput.Canvas.Font.Color := Color;
     483  FOutput.Canvas.TextRect(Rect(FLeft, FTop, FRight, FBottom), x, y, s)
     484end;
     485
     486procedure TIsoMap.BitBlt(Src: TBitmap; x, y, Width, Height, xSrc, ySrc,
     487  Rop: integer);
     488begin
     489  if x < FLeft then
     490  begin
     491    Width := Width - (FLeft - x);
     492    xSrc := xSrc + (FLeft - x);
     493    x := FLeft
     494  end;
     495  if y < FTop then
     496  begin
     497    Height := Height - (FTop - y);
     498    ySrc := ySrc + (FTop - y);
     499    y := FTop
     500  end;
     501  if x + Width >= FRight then
     502    Width := FRight - x;
     503  if y + Height >= FBottom then
     504    Height := FBottom - y;
     505  if (Width <= 0) or (Height <= 0) then
     506    exit;
     507
     508  LCLIntf.BitBlt(FOutput.Canvas.Handle, x, y, Width, Height, Src.Canvas.Handle,
     509    xSrc, ySrc, Rop);
     510end;
     511
     512procedure TIsoMap.Sprite(HGr, xDst, yDst, Width, Height, xGr, yGr: integer);
     513begin
     514  BitBlt(GrExt[HGr].Mask, xDst, yDst, Width, Height, xGr, yGr, SRCAND);
     515  BitBlt(GrExt[HGr].Data, xDst, yDst, Width, Height, xGr, yGr, SRCPAINT);
     516end;
     517
     518procedure TIsoMap.TSprite(xDst, yDst, grix: integer;
     519  PureBlack: boolean = false);
     520var
     521  Width, Height, xSrc, ySrc: integer;
     522begin
     523  Width := TSpriteSize[grix].Right - TSpriteSize[grix].Left;
     524  Height := TSpriteSize[grix].Bottom - TSpriteSize[grix].Top;
     525  xSrc := 1 + grix mod 9 * (xxt * 2 + 1) + TSpriteSize[grix].Left;
     526  ySrc := 1 + grix div 9 * (yyt * 3 + 1) + TSpriteSize[grix].Top;
     527  xDst := xDst + TSpriteSize[grix].Left;
     528  yDst := yDst - yyt + TSpriteSize[grix].Top;
     529  if xDst < FLeft then
     530  begin
     531    Width := Width - (FLeft - xDst);
     532    xSrc := xSrc + (FLeft - xDst);
     533    xDst := FLeft
     534  end;
     535  if yDst < FTop then
     536  begin
     537    Height := Height - (FTop - yDst);
     538    ySrc := ySrc + (FTop - yDst);
     539    yDst := FTop
     540  end;
     541  if xDst + Width >= FRight then
     542    Width := FRight - xDst;
     543  if yDst + Height >= FBottom then
     544    Height := FBottom - yDst;
     545  if (Width <= 0) or (Height <= 0) then
     546    exit;
     547
     548  LCLIntf.BitBlt(OutDC, xDst, yDst, Width, Height, MaskDC, xSrc, ySrc, SRCAND);
     549  if not PureBlack then
     550    LCLIntf.BitBlt(OutDC, xDst, yDst, Width, Height, DataDC, xSrc, ySrc,
     551      SRCPAINT);
     552end;
     553
     554procedure TIsoMap.PaintUnit(x, y: integer; const UnitInfo: TUnitInfo;
     555  Status: integer);
     556var
     557  xsh, ysh, xGr, yGr, j, mixShow: integer;
     558begin
     559  with UnitInfo do
     560    if (Owner = me) or (emix <> $FFFF) then
     561    begin
     562      if Job = jCity then
     563        mixShow := -1 // building site
     564      else
     565        mixShow := mix;
     566      if (Tribe[Owner].ModelPicture[mixShow].HGr = 0) and
     567        (@OnInitEnemyModel <> nil) then
     568        if not OnInitEnemyModel(emix) then
     569          exit;
     570      xsh := Tribe[Owner].ModelPicture[mixShow].xShield;
     571      ysh := Tribe[Owner].ModelPicture[mixShow].yShield;
     572{$IFNDEF SCR} if Status and usStay <> 0 then
     573        j := 19
     574      else if Status and usRecover <> 0 then
     575        j := 16
     576      else if Status and (usGoto or usEnhance) = usGoto or usEnhance then
     577        j := 18
     578      else if Status and usEnhance <> 0 then
     579        j := 17
     580      else if Status and usGoto <> 0 then
     581        j := 20
     582      else {$ENDIF} if Job = jCity then
     583          j := jNone
     584        else
     585          j := Job;
     586      if Flags and unMulti <> 0 then
     587        Sprite(Tribe[Owner].symHGr, x + xsh - 1 + 4, y + ysh - 2, 14, 12,
     588          33 + Tribe[Owner].sympix mod 10 * 65,
     589          1 + Tribe[Owner].sympix div 10 * 49);
     590      Sprite(Tribe[Owner].symHGr, x + xsh - 1, y + ysh - 2, 14, 12,
     591        18 + Tribe[Owner].sympix mod 10 * 65,
     592        1 + Tribe[Owner].sympix div 10 * 49);
     593      FillRect(x + xsh, y + ysh + 5, 1 + Health * 11 div 100, 3,
     594        ColorOfHealth(Health));
     595      if j > 0 then
     596      begin
     597        xGr := 121 + j mod 7 * 9;
     598        yGr := 1 + j div 7 * 9;
     599        BitBlt(GrExt[HGrSystem].Mask, x + xsh + 3, y + ysh + 9, 8, 8, xGr,
     600          yGr, SRCAND);
     601        Sprite(HGrSystem, x + xsh + 2, y + ysh + 8, 8, 8, xGr, yGr);
     602      end;
     603      with Tribe[Owner].ModelPicture[mixShow] do
     604        Sprite(HGr, x, y, 64, 48, pix mod 10 * 65 + 1, pix div 10 * 49 + 1);
     605      if Flags and unFortified <> 0 then
     606      begin
     607        { OutDC:=FOutput.Canvas.Handle;
     608          DataDC:=GrExt[HGrTerrain].Data.Canvas.Handle;
     609          MaskDC:=GrExt[HGrTerrain].Mask.Canvas.Handle;
     610          TSprite(x,y+16,12*9+7); }
     611        Sprite(HGrStdUnits, x, y, xxu * 2, yyu * 2, 1 + 6 * (xxu * 2 + 1), 1);
     612      end
     613    end
     614end; { PaintUnit }
     615
     616procedure TIsoMap.PaintCity(x, y: integer; const CityInfo: TCityInfo;
     617  accessory: boolean);
     618var
     619  age, cHGr, cpix, xGr, xShield, yShield, LabelTextColor, LabelLength: integer;
     620  cpic: TCityPicture;
     621  s: string;
     622begin
     623  age := GetAge(CityInfo.Owner);
     624  if CityInfo.size < 5 then
     625    xGr := 0
     626  else if CityInfo.size < 9 then
     627    xGr := 1
     628  else if CityInfo.size < 13 then
     629    xGr := 2
     630  else
     631    xGr := 3;
     632  Tribe[CityInfo.Owner].InitAge(age);
     633  if age < 2 then
     634  begin
     635    cHGr := Tribe[CityInfo.Owner].cHGr;
     636    cpix := Tribe[CityInfo.Owner].cpix;
     637    if (ciWalled and CityInfo.Flags = 0) or
     638      (GrExt[cHGr].Data.Canvas.Pixels[(xGr + 4) * 65, cpix * 49 + 48] = $00FFFF)
     639    then
     640      Sprite(cHGr, x - xxc, y - 2 * yyc, xxc * 2, yyc * 3,
     641        xGr * (xxc * 2 + 1) + 1, 1 + cpix * (yyc * 3 + 1));
     642    if ciWalled and CityInfo.Flags <> 0 then
     643      Sprite(cHGr, x - xxc, y - 2 * yyc, xxc * 2, yyc * 3,
     644        (xGr + 4) * (xxc * 2 + 1) + 1, 1 + cpix * (yyc * 3 + 1));
     645  end
     646  else
     647  begin
     648    if ciWalled and CityInfo.Flags <> 0 then
     649      Sprite(HGrCities, x - xxt, y - 2 * yyt, 2 * xxt, 3 * yyt,
     650        (xGr + 4) * (2 * xxt + 1) + 1, 1 + (age - 2) * (3 * yyt + 1))
     651    else
     652      Sprite(HGrCities, x - xxt, y - 2 * yyt, 2 * xxt, 3 * yyt,
     653        xGr * (2 * xxt + 1) + 1, 1 + (age - 2) * (3 * yyt + 1));
     654  end;
     655
     656  if not accessory then
     657    exit;
     658
     659  { if ciCapital and CityInfo.Flags<>0 then
     660    Sprite(Tribe[CityInfo.Owner].symHGr,x+cpic.xf,y-13+cpic.yf,13,14,
     661    1+Tribe[CityInfo.Owner].sympix mod 10 *65,
     662    1+Tribe[CityInfo.Owner].sympix div 10 *49); {capital -- paint flag }
     663
     664  if MyMap[CityInfo.Loc] and fObserved <> 0 then
     665  begin
     666    if age < 2 then
     667    begin
     668      cpic := Tribe[CityInfo.Owner].CityPicture[xGr];
     669      xShield := x - xxc + cpic.xShield;
     670      yShield := y - 2 * yyc + cpic.yShield;
     671    end
     672    else
     673    begin
     674      cpic := CitiesPictures[age, xGr];
     675      xShield := x - xxt + cpic.xShield;
     676      yShield := y - 2 * yyt + cpic.yShield;
     677    end;
     678    s := IntToStr(CityInfo.size);
     679    LabelLength := FOutput.Canvas.TextWidth(s);
     680    FillRect(xShield, yShield, LabelLength + 4, 16, $000000);
     681    if MyMap[CityInfo.Loc] and (fUnit or fObserved) = fObserved then
     682      // empty city
     683      LabelTextColor := Tribe[CityInfo.Owner].Color
     684    else
     685    begin
     686      FillRect(xShield + 1, yShield + 1, LabelLength + 2, 14,
     687        Tribe[CityInfo.Owner].Color);
     688      LabelTextColor := $000000;
     689    end;
     690    Textout(xShield + 2, yShield - 1, LabelTextColor, s);
     691  end
     692end; { PaintCity }
     693
     694function PoleTile(Loc: integer): integer;
     695begin { virtual pole tile }
     696  result := fUNKNOWN;
     697  if Loc < -2 * G.lx then
     698  else if Loc < -G.lx then
     699  begin
     700    if (MyMap[dLoc(Loc, 0, 2)] and fTerrain <> fUNKNOWN) and
     701      (MyMap[dLoc(Loc, -2, 2)] and fTerrain <> fUNKNOWN) and
     702      (MyMap[dLoc(Loc, 2, 2)] and fTerrain <> fUNKNOWN) then
     703      result := fArctic;
     704    if (MyMap[dLoc(Loc, 0, 2)] and fObserved <> 0) and
     705      (MyMap[dLoc(Loc, -2, 2)] and fObserved <> 0) and
     706      (MyMap[dLoc(Loc, 2, 2)] and fObserved <> 0) then
     707      result := result or fObserved
     708  end
     709  else if Loc < 0 then
     710  begin
     711    if (MyMap[dLoc(Loc, -1, 1)] and fTerrain <> fUNKNOWN) and
     712      (MyMap[dLoc(Loc, 1, 1)] and fTerrain <> fUNKNOWN) then
     713      result := fArctic;
     714    if (MyMap[dLoc(Loc, -1, 1)] and fObserved <> 0) and
     715      (MyMap[dLoc(Loc, 1, 1)] and fObserved <> 0) then
     716      result := result or fObserved
     717  end
     718  else if Loc < G.lx * (G.ly + 1) then
     719  begin
     720    if (MyMap[dLoc(Loc, -1, -1)] and fTerrain <> fUNKNOWN) and
     721      (MyMap[dLoc(Loc, 1, -1)] and fTerrain <> fUNKNOWN) then
     722      result := fArctic;
     723    if (MyMap[dLoc(Loc, -1, -1)] and fObserved <> 0) and
     724      (MyMap[dLoc(Loc, 1, -1)] and fObserved <> 0) then
     725      result := result or fObserved
     726  end
     727  else if Loc < G.lx * (G.ly + 2) then
     728  begin
     729    if (MyMap[dLoc(Loc, 0, -2)] and fTerrain <> fUNKNOWN) and
     730      (MyMap[dLoc(Loc, -2, -2)] and fTerrain <> fUNKNOWN) and
     731      (MyMap[dLoc(Loc, 2, -2)] and fTerrain <> fUNKNOWN) then
     732      result := fArctic;
     733    if (MyMap[dLoc(Loc, 0, -2)] and fObserved <> 0) and
     734      (MyMap[dLoc(Loc, -2, -2)] and fObserved <> 0) and
     735      (MyMap[dLoc(Loc, 2, -2)] and fObserved <> 0) then
     736      result := result or fObserved
     737  end
     738end;
     739
     740const
     741  Dirx: array [0 .. 7] of integer = (1, 2, 1, 0, -1, -2, -1, 0);
     742  Diry: array [0 .. 7] of integer = (-1, 0, 1, 2, 1, 0, -1, -2);
     743
     744function TIsoMap.Connection4(Loc, Mask, Value: integer): integer;
     745begin
     746  result := 0;
     747  if dLoc(Loc, 1, -1) >= 0 then
     748  begin
     749    if MyMap[dLoc(Loc, 1, -1)] and Mask = Cardinal(Value) then
     750      inc(result, 1);
     751    if MyMap[dLoc(Loc, -1, -1)] and Mask = Cardinal(Value) then
     752      inc(result, 8);
     753  end;
     754  if dLoc(Loc, 1, 1) < G.lx * G.ly then
     755  begin
     756    if MyMap[dLoc(Loc, 1, 1)] and Mask = Cardinal(Value) then
     757      inc(result, 2);
     758    if MyMap[dLoc(Loc, -1, 1)] and Mask = Cardinal(Value) then
     759      inc(result, 4);
     760  end
     761end;
     762
     763function TIsoMap.Connection8(Loc, Mask: integer): integer;
     764var
     765  Dir, ConnLoc: integer;
     766begin
     767  result := 0;
     768  for Dir := 0 to 7 do
     769  begin
     770    ConnLoc := dLoc(Loc, Dirx[Dir], Diry[Dir]);
     771    if (ConnLoc >= 0) and (ConnLoc < G.lx * G.ly) and
     772      (MyMap[ConnLoc] and Mask <> 0) then
     773      inc(result, 1 shl Dir);
     774  end
     775end;
     776
     777function TIsoMap.OceanConnection(Loc: integer): integer;
     778var
     779  Dir, ConnLoc: integer;
     780begin
     781  result := 0;
     782  for Dir := 0 to 7 do
     783  begin
     784    ConnLoc := dLoc(Loc, Dirx[Dir], Diry[Dir]);
     785    if (ConnLoc < 0) or (ConnLoc >= G.lx * G.ly) or
     786      ((MyMap[ConnLoc] - 2) and fTerrain < 13) then
     787      inc(result, 1 shl Dir);
     788  end
     789end;
     790
     791procedure TIsoMap.PaintShore(x, y, Loc: integer);
     792var
     793  Conn, Tile: integer;
     794begin
     795  if (y <= FTop - yyt * 2) or (y > FBottom) or (x <= FLeft - xxt * 2) or
     796    (x > FRight) then
     797    exit;
     798  if (Loc < 0) or (Loc >= G.lx * G.ly) then
     799    exit;
     800  Tile := MyMap[Loc];
     801  if Tile and fTerrain >= fGrass then
     802    exit;
     803  Conn := OceanConnection(Loc);
     804  if Conn = 0 then
     805    exit;
     806
     807  BitBlt(GrExt[HGrTerrain].Data, x + xxt div 2, y, xxt, yyt,
     808    1 + (Conn shr 6 + Conn and 1 shl 2) * (xxt * 2 + 1),
     809    1 + yyt + (16 + Tile and fTerrain) * (yyt * 3 + 1), SRCPAINT);
     810  BitBlt(GrExt[HGrTerrain].Data, x + xxt, y + yyt div 2, xxt, yyt,
     811    1 + (Conn and 7) * (xxt * 2 + 1) + xxt,
     812    1 + yyt * 2 + (16 + Tile and fTerrain) * (yyt * 3 + 1), SRCPAINT);
     813  BitBlt(GrExt[HGrTerrain].Data, x + xxt div 2, y + yyt, xxt, yyt,
     814    1 + (Conn shr 2 and 7) * (xxt * 2 + 1) + xxt,
     815    1 + yyt + (16 + Tile and fTerrain) * (yyt * 3 + 1), SRCPAINT);
     816  BitBlt(GrExt[HGrTerrain].Data, x, y + yyt div 2, xxt, yyt,
     817    1 + (Conn shr 4 and 7) * (xxt * 2 + 1),
     818    1 + yyt * 2 + (16 + Tile and fTerrain) * (yyt * 3 + 1), SRCPAINT);
     819  Conn := Connection4(Loc, fTerrain, fUNKNOWN); { dither to black }
     820  if Conn and 1 <> 0 then
     821    BitBlt(GrExt[HGrTerrain].Mask, x + xxt, y, xxt, yyt, 1 + 7 * (xxt * 2 + 1) +
     822      xxt, 1 + yyt + 15 * (yyt * 3 + 1), SRCAND);
     823  if Conn and 2 <> 0 then
     824    BitBlt(GrExt[HGrTerrain].Mask, x + xxt, y + yyt, xxt, yyt,
     825      1 + 7 * (xxt * 2 + 1) + xxt, 1 + yyt * 2 + 15 * (yyt * 3 + 1), SRCAND);
     826  if Conn and 4 <> 0 then
     827    BitBlt(GrExt[HGrTerrain].Mask, x, y + yyt, xxt, yyt, 1 + 7 * (xxt * 2 + 1),
     828      1 + yyt * 2 + 15 * (yyt * 3 + 1), SRCAND);
     829  if Conn and 8 <> 0 then
     830    BitBlt(GrExt[HGrTerrain].Mask, x, y, xxt, yyt, 1 + 7 * (xxt * 2 + 1),
     831      1 + yyt + 15 * (yyt * 3 + 1), SRCAND);
     832end;
     833
     834procedure TIsoMap.PaintTileExtraTerrain(x, y, Loc: integer);
     835var
     836  Dir, Conn, RRConn, yGr, Tile, yLoc: integer;
     837begin
     838  if (Loc < 0) or (Loc >= G.lx * G.ly) or (y <= -yyt * 2) or
     839    (y > FOutput.Height) or (x <= -xxt * 2) or (x > FOutput.Width) then
     840    exit;
     841  Tile := MyMap[Loc];
     842  if Tile and fTerrain = fForest then
     843  begin
     844    yLoc := Loc div G.lx;
     845    if IsJungle(yLoc) then
     846      yGr := 18
     847    else
     848      yGr := 3;
     849    Conn := Connection4(Loc, fTerrain, Tile and fTerrain);
     850    if (yLoc = (G.ly - 2) div 4) or (G.ly - 1 - yLoc = (G.ly + 2) div 4) then
     851      Conn := Conn and not 6 // no connection to south
     852    else if (yLoc = (G.ly + 2) div 4) or (G.ly - 1 - yLoc = (G.ly - 2) div 4)
     853    then
     854      Conn := Conn and not 9; // no connection to north
     855    TSprite(x, y, Conn mod 8 + (yGr + Conn div 8) * 9);
     856  end
     857  else if Tile and fTerrain in [fHills, fMountains, fForest] then
     858  begin
     859    yGr := 3 + 2 * (Tile and fTerrain - fForest);
     860    Conn := Connection4(Loc, fTerrain, Tile and fTerrain);
     861    TSprite(x, y, Conn mod 8 + (yGr + Conn div 8) * 9);
     862  end
     863  else if Tile and fDeadLands <> 0 then
     864    TSprite(x, y, 2 * 9 + 6);
     865
     866  if ShowObjects then
     867  begin
     868    if Tile and fTerImp = tiFarm then
     869      TSprite(x, y, 109) { farmland }
     870    else if Tile and fTerImp = tiIrrigation then
     871      TSprite(x, y, 108); // irrigation
     872  end;
     873  if Tile and fRiver <> 0 then
     874  begin
     875    Conn := Connection4(Loc, fRiver, fRiver) or
     876      Connection4(Loc, fTerrain, fShore) or Connection4(Loc, fTerrain,
     877      fUNKNOWN);
     878    TSprite(x, y, Conn mod 8 + (13 + Conn div 8) * 9);
     879  end;
     880
     881  if Tile and fTerrain < fGrass then
     882  begin
     883    Conn := Connection4(Loc, fRiver, fRiver);
     884    for Dir := 0 to 3 do
     885      if Conn and (1 shl Dir) <> 0 then { river mouths }
     886        TSprite(x, y, 15 * 9 + Dir);
     887    if ShowObjects then
     888    begin
     889      Conn := Connection8(Loc, fCanal);
     890      for Dir := 0 to 7 do
     891        if Conn and (1 shl Dir) <> 0 then { canal mouths }
     892          TSprite(x, y, 20 * 9 + 1 + Dir);
     893    end
     894  end;
     895
     896  if ShowObjects then
     897  begin
     898    if (Tile and fCanal <> 0) or (Tile and fCity <> 0) then
     899    begin // paint canal connections
     900      Conn := Connection8(Loc, fCanal or fCity);
     901      if Tile and fCanal <> 0 then
     902        Conn := Conn or ($FF - OceanConnection(Loc));
     903      if Conn = 0 then
     904      begin
     905        if Tile and fCanal <> 0 then
     906          TSprite(x, y, 99)
     907      end
     908      else
     909        for Dir := 0 to 7 do
     910          if (1 shl Dir) and Conn <> 0 then
     911            TSprite(x, y, 100 + Dir);
     912    end;
     913    if Tile and (fRR or fCity) <> 0 then
     914      RRConn := Connection8(Loc, fRR or fCity)
     915    else
     916      RRConn := 0;
     917    if Tile and (fRoad or fRR or fCity) <> 0 then
     918    begin // paint road connections
     919      Conn := Connection8(Loc, fRoad or fRR or fCity) and not RRConn;
     920      if (Conn = 0) and (Tile and (fRR or fCity) = 0) then
     921        TSprite(x, y, 81)
     922      else if Conn > 0 then
     923        for Dir := 0 to 7 do
     924          if (1 shl Dir) and Conn <> 0 then
     925            TSprite(x, y, 82 + Dir);
     926    end;
     927    // paint railroad connections
     928    if (Tile and fRR <> 0) and (RRConn = 0) then
     929      TSprite(x, y, 90)
     930    else if RRConn > 0 then
     931      for Dir := 0 to 7 do
     932        if (1 shl Dir) and RRConn <> 0 then
     933          TSprite(x, y, 91 + Dir);
     934  end;
     935end;
     936
     937// (x,y) is top left pixel of (2*xxt,3*yyt) rectangle
     938procedure TIsoMap.PaintTileObjects(x, y, Loc, CityLoc, CityOwner: integer;
     939  UseBlink: boolean);
     940type
     941  TLine = array [0 .. 9 * 65, 0 .. 2] of Byte;
     942var
     943  p1, p2, uix, cix, dy, Loc1, Tile, Multi, Destination: integer;
     944  CityInfo: TCityInfo;
     945  UnitInfo: TUnitInfo;
     946  fog: boolean;
     947
     948  procedure NameCity;
     949  var
     950    cix, xs, w: integer;
     951    BehindCityInfo: TCityInfo;
     952    s: string;
     953    IsCapital: boolean;
     954  begin
     955    BehindCityInfo.Loc := Loc - 2 * G.lx;
     956    if ShowCityNames and (Options and (1 shl moEditMode) = 0) and
     957      (BehindCityInfo.Loc >= 0) and (BehindCityInfo.Loc < G.lx * G.ly) and
     958      (MyMap[BehindCityInfo.Loc] and fCity <> 0) then
     959    begin
     960      GetCityInfo(BehindCityInfo.Loc, cix, BehindCityInfo);
     961      IsCapital := BehindCityInfo.Flags and ciCapital <> 0;
     962      { if Showuix and (cix>=0) then s:=IntToStr(cix)
     963        else } s := CityName(BehindCityInfo.ID);
     964      w := FOutput.Canvas.TextWidth(s);
     965      xs := x + xxt - (w + 1) div 2;
     966      if IsCapital then
     967        FOutput.Canvas.Font.Style := FOutput.Canvas.Font.Style + [fsUnderline];
     968      Textout(xs + 1, y - 9, $000000, s);
     969      Textout(xs, y - 10, $FFFFFF, s);
     970      if IsCapital then
     971        FOutput.Canvas.Font.Style := FOutput.Canvas.Font.Style - [fsUnderline];
     972    end;
     973  end;
     974
     975  procedure ShowSpacePort;
     976  begin
     977    if ShowObjects and (Options and (1 shl moEditMode) = 0) and
     978      (Tile and fCity <> 0) and (CityInfo.Flags and ciSpacePort <> 0) then
     979      TSprite(x + xxt, y - 6, 12 * 9 + 5);
     980  end;
     981
     982  procedure PaintBorder;
     983  var
     984    dx, dy: integer;
     985    Line: ^TLine;
     986  begin
     987    if ShowBorder and (Loc >= 0) and (Loc < G.lx * G.ly) and
     988      (Tile and fTerrain <> fUNKNOWN) then
     989    begin
     990      p1 := MyRO.Territory[Loc];
     991      if (p1 >= 0) and (ShowMyBorder or (p1 <> me)) then
     992      begin
     993        if BordersOK and (1 shl p1) = 0 then
    412994        begin
    413           NoMap.Free;
    414           NoMap := nil;
    415           LandPatch.Free;
    416           LandPatch := nil;
    417           OceanPatch.Free;
    418           OceanPatch := nil;
    419           Borders.Free;
    420           Borders := nil;
     995          LCLIntf.BitBlt(Borders.Canvas.Handle, 0, p1 * (yyt * 2), xxt * 2,
     996            yyt * 2, GrExt[HGrTerrain].Data.Canvas.Handle,
     997            1 + 8 * (xxt * 2 + 1), 1 + yyt + 16 * (yyt * 3 + 1), SRCCOPY);
     998          Borders.BeginUpdate;
     999          for dy := 0 to yyt * 2 - 1 do
     1000          begin
     1001            Line := Borders.ScanLine[p1 * (yyt * 2) + dy];
     1002            for dx := 0 to xxt * 2 - 1 do
     1003              if Line[dx, 0] = 99 then
     1004              begin
     1005                Line[dx, 0] := Tribe[p1].Color shr 16 and $FF;
     1006                Line[dx, 1] := Tribe[p1].Color shr 8 and $FF;
     1007                Line[dx, 2] := Tribe[p1].Color and $FF;
     1008              end
     1009          end;
     1010          Borders.EndUpdate;
     1011          BordersOK := BordersOK or 1 shl p1;
    4211012        end;
    422 
    423         procedure Reset;
     1013        for dy := 0 to 1 do
     1014          for dx := 0 to 1 do
     1015          begin
     1016            Loc1 := dLoc(Loc, dx * 2 - 1, dy * 2 - 1);
     1017            begin
     1018              if (Loc1 < 0) or (Loc1 >= G.lx * G.ly) then
     1019                p2 := -1
     1020              else if MyMap[Loc1] and fTerrain = fUNKNOWN then
     1021                p2 := p1
     1022              else
     1023                p2 := MyRO.Territory[Loc1];
     1024              if p2 <> p1 then
     1025              begin
     1026                BitBlt(GrExt[HGrTerrain].Mask, x + dx * xxt, y + dy * yyt, xxt,
     1027                  yyt, 1 + 8 * (xxt * 2 + 1) + dx * xxt,
     1028                  1 + yyt + 16 * (yyt * 3 + 1) + dy * yyt, SRCAND);
     1029                BitBlt(Borders, x + dx * xxt, y + dy * yyt, xxt, yyt, dx * xxt,
     1030                  p1 * (yyt * 2) + dy * yyt, SRCPAINT);
     1031              end
     1032            end;
     1033          end
     1034      end
     1035    end;
     1036  end;
     1037
     1038begin
     1039  if (Loc < 0) or (Loc >= G.lx * G.ly) then
     1040    Tile := PoleTile(Loc)
     1041  else
     1042    Tile := MyMap[Loc];
     1043  if ShowObjects and (Options and (1 shl moEditMode) = 0) and
     1044    (Tile and fCity <> 0) then
     1045    GetCityInfo(Loc, cix, CityInfo);
     1046  if (y <= FTop - yyt * 2) or (y > FBottom) or (x <= FLeft - xxt * 2) or
     1047    (x > FRight) then
     1048  begin
     1049    NameCity;
     1050    ShowSpacePort;
     1051    exit;
     1052  end;
     1053  if Tile and fTerrain = fUNKNOWN then
     1054  begin
     1055    NameCity;
     1056    ShowSpacePort;
     1057    exit
     1058  end; { square not discovered }
     1059
     1060  if not(FoW and (Tile and fObserved = 0)) then
     1061    PaintBorder;
     1062
     1063  if (Loc >= 0) and (Loc < G.lx * G.ly) and (Loc = FAdviceLoc) then
     1064    TSprite(x, y, 7 + 9 * 2);
     1065
     1066  if (Loc >= 0) and (Loc < G.lx * G.ly) and (Tile and fSpecial <> 0)
     1067  then { special ressources }
     1068  begin
     1069    dy := Loc div G.lx;
     1070    if Tile and fTerrain < fForest then
     1071      TSprite(x, y, Tile and fTerrain + (Tile and fSpecial shr 5) * 9)
     1072    else if (Tile and fTerrain = fForest) and IsJungle(dy) then
     1073      TSprite(x, y, 8 + 17 * 9 + (Tile and fSpecial shr 5) * 9)
     1074    else
     1075      TSprite(x, y, 8 + 2 * 9 + ((Tile and fTerrain - fForest) * 2 + Tile and
     1076        fSpecial shr 5) * 9);
     1077  end;
     1078
     1079  if ShowObjects then
     1080  begin
     1081    if Tile and fTerImp = tiMine then
     1082      TSprite(x, y, 2 + 9 * 12);
     1083    if Tile and fTerImp = tiBase then
     1084      TSprite(x, y, 4 + 9 * 12);
     1085    if Tile and fPoll <> 0 then
     1086      TSprite(x, y, 6 + 9 * 12);
     1087    if Tile and fTerImp = tiFort then
     1088    begin
     1089      TSprite(x, y, 7 + 9 * 12);
     1090      if Tile and fObserved = 0 then
     1091        TSprite(x, y, 3 + 9 * 12);
     1092    end;
     1093  end;
     1094  if Tile and fDeadLands <> 0 then
     1095    TSprite(x, y, (12 + Tile shr 25 and 3) * 9 + 8);
     1096
     1097  if Options and (1 shl moEditMode) <> 0 then
     1098    fog := (Loc < 0) or (Loc >= G.lx * G.ly)
     1099    // else if CityLoc>=0 then
     1100    // fog:= (Loc<0) or (Loc>=G.lx*G.ly) or (Distance(Loc,CityLoc)>5)
     1101  else if ShowGrWall then
     1102    fog := Tile and fGrWall = 0
     1103  else
     1104    fog := FoW and (Tile and fObserved = 0);
     1105  if fog and ShowObjects then
     1106    if Loc < -G.lx then
     1107      Sprite(HGrTerrain, x, y + yyt, xxt * 2, yyt, 1 + 6 * (xxt * 2 + 1),
     1108        1 + yyt * 2 + 15 * (yyt * 3 + 1))
     1109    else if Loc >= G.lx * (G.ly + 1) then
     1110      Sprite(HGrTerrain, x, y, xxt * 2, yyt, 1 + 6 * (xxt * 2 + 1),
     1111        1 + yyt + 15 * (yyt * 3 + 1))
     1112    else
     1113      TSprite(x, y, 6 + 9 * 15, xxt <> 33);
     1114
     1115  if FoW and (Tile and fObserved = 0) then
     1116    PaintBorder;
     1117
     1118{$IFNDEF SCR}
     1119  // paint goto destination mark
     1120  if DestinationMarkON and (CityOwner < 0) and (UnFocus >= 0) and
     1121    (MyUn[UnFocus].Status and usGoto <> 0) then
     1122  begin
     1123    Destination := MyUn[UnFocus].Status shr 16;
     1124    if (Destination = Loc) and (Destination <> MyUn[UnFocus].Loc) then
     1125      if not UseBlink or BlinkOn then
     1126        TSprite(x, y, 8 + 9 * 1)
     1127      else
     1128        TSprite(x, y, 8 + 9 * 2)
     1129  end;
     1130{$ENDIF}
     1131  if Options and (1 shl moEditMode) <> 0 then
     1132  begin
     1133    if Tile and fPrefStartPos <> 0 then
     1134      TSprite(x, y, 0 + 9 * 1)
     1135    else if Tile and fStartPos <> 0 then
     1136      TSprite(x, y, 0 + 9 * 2);
     1137  end
     1138  else if ShowObjects then
     1139  begin
     1140    { if (CityLoc<0) and (UnFocus>=0) and (Loc=MyUn[UnFocus].Loc) then
     1141      if BlinkOn then TSprite(x,y,8+9*0)
     1142      else TSprite(x,y,8+9*1); }
     1143
     1144    NameCity;
     1145    ShowSpacePort;
     1146    if Tile and fCity <> 0 then
     1147      PaintCity(x + xxt, y + yyt, CityInfo, CityOwner < 0);
     1148
     1149    if (Tile and fUnit <> 0) and (Loc <> AttLoc) and
     1150      ((Loc <> DefLoc) or (DefHealth <> 0))
     1151{$IFNDEF SCR} and ((CityOwner >= 0) or (UnFocus < 0) or not UseBlink or
     1152      BlinkOn or (Loc <> MyUn[UnFocus].Loc)){$ENDIF}
     1153      and ((Tile and fCity <> fCity) or (Loc = DefLoc)
     1154{$IFNDEF SCR} or (not UseBlink or BlinkOn) and (UnFocus >= 0) and
     1155      (Loc = MyUn[UnFocus].Loc){$ENDIF}) then
     1156    begin { unit }
     1157      GetUnitInfo(Loc, uix, UnitInfo);
     1158      if (Loc = DefLoc) and (DefHealth >= 0) then
     1159        UnitInfo.Health := DefHealth;
     1160      if (UnitInfo.Owner <> CityOwner) and
     1161        not((CityOwner = me) and (MyRO.Treaty[UnitInfo.Owner] = trAlliance))
     1162      then
     1163{$IFNDEF SCR} if (UnFocus >= 0) and (Loc = MyUn[UnFocus].Loc) then { active unit }
    4241164        begin
    425           BordersOK := 0;
     1165          Multi := UnitInfo.Flags and unMulti;
     1166          MakeUnitInfo(me, MyUn[UnFocus], UnitInfo);
     1167          UnitInfo.Flags := UnitInfo.Flags or Multi;
     1168          PaintUnit(x + (xxt - xxu), y + (yyt - yyu_anchor), UnitInfo,
     1169            MyUn[UnFocus].Status);
     1170        end
     1171        else if UnitInfo.Owner = me then
     1172        begin
     1173          if ClientMode = cMovieTurn then
     1174            PaintUnit(x + (xxt - xxu), y + (yyt - yyu_anchor), UnitInfo, 0)
     1175            // status is not set with precise timing during loading
     1176          else
     1177            PaintUnit(x + (xxt - xxu), y + (yyt - yyu_anchor), UnitInfo,
     1178              MyUn[uix].Status);
     1179          // if Showuix then Textout(x+16,y+5,$80FF00,IntToStr(uix));
     1180        end
     1181        else {$ENDIF} PaintUnit(x + (xxt - xxu), y + (yyt - yyu_anchor), UnitInfo, 0);
     1182    end
     1183    else if Tile and fHiddenUnit <> 0 then
     1184      Sprite(HGrStdUnits, x + (xxt - xxu), y + (yyt - yyu_anchor), xxu * 2,
     1185        yyu * 2, 1 + 5 * (xxu * 2 + 1), 1)
     1186    else if Tile and fStealthUnit <> 0 then
     1187      Sprite(HGrStdUnits, x + (xxt - xxu), y + (yyt - yyu_anchor), xxu * 2,
     1188        yyu * 2, 1 + 5 * (xxu * 2 + 1), 1 + 1 * (yyu * 2 + 1))
     1189  end;
     1190
     1191  if ShowObjects and (Tile and fTerImp = tiFort) and (Tile and fObserved <> 0)
     1192  then
     1193    TSprite(x, y, 3 + 9 * 12);
     1194
     1195  if (Loc >= 0) and (Loc < G.lx * G.ly) then
     1196    if ShowLoc then
     1197      Textout(x + xxt - 16, y + yyt - 9, $FFFF00, IntToStr(Loc))
     1198    else if ShowDebug and (DebugMap <> nil) and (Loc >= 0) and
     1199      (Loc < G.lx * G.ly) and (DebugMap[Loc] <> 0) then
     1200      Textout(x + xxt - 16, y + yyt - 9, $00E0FF,
     1201        IntToStr(integer(DebugMap[Loc])))
     1202end; { PaintTileObjects }
     1203
     1204procedure TIsoMap.PaintGrid(x, y, nx, ny: integer);
     1205
     1206  procedure ClippedLine(dx0, dy0: integer; mirror: boolean);
     1207  var
     1208    x0, x1, dxmin, dymin, dxmax, dymax, n: integer;
     1209  begin
     1210    with FOutput.Canvas do
     1211    begin
     1212      dxmin := (FLeft - x) div xxt;
     1213      dymin := (RealTop - y) div yyt;
     1214      dxmax := (FRight - x - 1) div xxt + 1;
     1215      dymax := (RealBottom - y - 1) div yyt + 1;
     1216      n := dymax - dy0;
     1217      if mirror then
     1218      begin
     1219        if dx0 - dxmin < n then
     1220          n := dx0 - dxmin;
     1221        if dx0 > dxmax then
     1222        begin
     1223          n := n - (dx0 - dxmax);
     1224          dy0 := dy0 + (dx0 - dxmax);
     1225          dx0 := dxmax
    4261226        end;
    427 
    428         constructor TIsoMap.Create;
     1227        if dy0 < dymin then
    4291228        begin
    430           inherited;
    431           FLeft := 0;
    432           FTop := 0;
    433           FRight := 0;
    434           FBottom := 0;
    435           AttLoc := -1;
    436           DefLoc := -1;
    437           FAdviceLoc := -1;
     1229          n := n - (dymin - dy0);
     1230          dx0 := dx0 - (dymin - dy0);
     1231          dy0 := dymin
    4381232        end;
    439 
    440         procedure TIsoMap.SetOutput(Output: TBitmap);
     1233      end
     1234      else
     1235      begin
     1236        if dxmax - dx0 < n then
     1237          n := dxmax - dx0;
     1238        if dx0 < dxmin then
    4411239        begin
    442           FOutput := Output;
    443           FLeft := 0;
    444           FTop := 0;
    445           FRight := FOutput.Width;
    446           FBottom := FOutput.Height;
     1240          n := n - (dxmin - dx0);
     1241          dy0 := dy0 + (dxmin - dx0);
     1242          dx0 := dxmin
    4471243        end;
    448 
    449         procedure TIsoMap.SetPaintBounds(Left, Top, Right, Bottom: integer);
     1244        if dy0 < dymin then
    4501245        begin
    451           FLeft := Left;
    452           FTop := Top;
    453           FRight := Right;
    454           FBottom := Bottom;
     1246          n := n - (dymin - dy0);
     1247          dx0 := dx0 + (dymin - dy0);
     1248          dy0 := dymin
    4551249        end;
    456 
    457         procedure TIsoMap.FillRect(x, y, Width, Height, Color: integer);
    458         begin
    459           if x < FLeft then
     1250      end;
     1251      if n <= 0 then
     1252        exit;
     1253      if mirror then
     1254      begin
     1255        x0 := x + dx0 * xxt - 1;
     1256        x1 := x + (dx0 - n) * xxt - 1;
     1257      end
     1258      else
     1259      begin
     1260        x0 := x + dx0 * xxt;
     1261        x1 := x + (dx0 + n) * xxt;
     1262      end;
     1263      moveto(x0, y + dy0 * yyt);
     1264      lineto(x1, y + (dy0 + n) * yyt);
     1265    end
     1266  end;
     1267
     1268var
     1269  i: integer;
     1270begin
     1271  FOutput.Canvas.pen.Color := $000000; // $FF shl (8*random(3));
     1272  for i := 0 to nx div 2 do
     1273    ClippedLine(i * 2, 0, false);
     1274  for i := 1 to (nx + 1) div 2 do
     1275    ClippedLine(i * 2, 0, true);
     1276  for i := 0 to ny div 2 do
     1277  begin
     1278    ClippedLine(0, 2 * i + 2, false);
     1279    ClippedLine(nx + 1, 2 * i + 1 + nx and 1, true);
     1280  end;
     1281end;
     1282
     1283procedure TIsoMap.Paint(x, y, Loc, nx, ny, CityLoc, CityOwner: integer;
     1284  UseBlink: boolean; CityAllowClick: boolean);
     1285
     1286  function IsShoreTile(Loc: integer): boolean;
     1287  const
     1288    Dirx: array [0 .. 7] of integer = (1, 2, 1, 0, -1, -2, -1, 0);
     1289    Diry: array [0 .. 7] of integer = (-1, 0, 1, 2, 1, 0, -1, -2);
     1290  var
     1291    Dir, ConnLoc: integer;
     1292  begin
     1293    result := false;
     1294    for Dir := 0 to 7 do
     1295    begin
     1296      ConnLoc := dLoc(Loc, Dirx[Dir], Diry[Dir]);
     1297      if (ConnLoc < 0) or (ConnLoc >= G.lx * G.ly) or
     1298        ((MyMap[ConnLoc] - 2) and fTerrain < 13) then
     1299        result := true
     1300    end
     1301  end;
     1302
     1303  procedure ShadeOutside(x0, y0, x1, y1, xm, ym: integer);
     1304  const
     1305    rShade = 3.75;
     1306
     1307    procedure MakeDark(Line: pointer; length: integer);
     1308    type
     1309      TCardArray = array [0 .. 9999] of Cardinal;
     1310      PCardArray = ^TCardArray;
     1311      TByteArray = array [0 .. 9999] of Byte;
     1312      PByteArray = ^TByteArray;
     1313    var
     1314      i, rest: integer;
     1315    begin
     1316      for i := length * 3 div 4 - 1 downto 0 do
     1317        PCardArray(Line)[i] := PCardArray(Line)[i] shr 1 and $7F7F7F7F;
     1318      rest := (length * 3 div 4) * 4;
     1319      for i := length * 3 mod 4 - 1 downto 0 do
     1320        PByteArray(Line)[rest + i] := PByteArray(Line)[rest + i] shr 1 and $7F;
     1321    end;
     1322
     1323  type
     1324    TLine = array [0 .. 99999, 0 .. 2] of Byte;
     1325  var
     1326    y, wBright: integer;
     1327    y_n, w_n: single;
     1328    Line: ^TLine;
     1329  begin
     1330    FOutput.BeginUpdate;
     1331    for y := y0 to y1 - 1 do
     1332    begin
     1333      Line := FOutput.ScanLine[y];
     1334      y_n := (y - ym) / yyt;
     1335      if abs(y_n) < rShade then
     1336      begin
     1337        w_n := sqrt(sqr(rShade) - sqr(y_n));
     1338        wBright := trunc(w_n * xxt + 0.5);
     1339        MakeDark(@Line[x0], xm - x0 - wBright);
     1340        MakeDark(@Line[xm + wBright], x1 - xm - wBright);
     1341      end
     1342      else
     1343        MakeDark(@Line[x0], x1 - x0);
     1344    end;
     1345    FOutput.EndUpdate;
     1346  end;
     1347
     1348  procedure CityGrid(xm, ym: integer);
     1349  var
     1350    i: integer;
     1351  begin
     1352    with FOutput.Canvas do
     1353    begin
     1354      if CityAllowClick then
     1355        pen.Color := $FFFFFF
     1356      else
     1357        pen.Color := $000000;
     1358      pen.Width := 1;
     1359      for i := 0 to 3 do
     1360      begin
     1361        moveto(xm - xxt * (4 - i), ym + yyt * (1 + i));
     1362        lineto(xm + xxt * (1 + i), ym - yyt * (4 - i));
     1363        moveto(xm - xxt * (4 - i), ym - yyt * (1 + i));
     1364        lineto(xm + xxt * (1 + i), ym + yyt * (4 - i));
     1365      end;
     1366      moveto(xm - xxt * 4, ym + yyt * 1);
     1367      lineto(xm - xxt * 1, ym + yyt * 4);
     1368      moveto(xm + xxt * 1, ym + yyt * 4);
     1369      lineto(xm + xxt * 4, ym + yyt * 1);
     1370      moveto(xm - xxt * 4, ym - yyt * 1);
     1371      lineto(xm - xxt * 1, ym - yyt * 4);
     1372      moveto(xm + xxt * 1, ym - yyt * 4);
     1373      lineto(xm + xxt * 4, ym - yyt * 1);
     1374      pen.Width := 1;
     1375    end
     1376  end;
     1377
     1378var
     1379  dx, dy, xm, ym, ALoc, BLoc, ATer, BTer, Aix, bix: integer;
     1380begin
     1381  FoW := true;
     1382  ShowLoc := Options and (1 shl moLocCodes) <> 0;
     1383  ShowDebug := pDebugMap >= 0;
     1384  ShowObjects := (CityOwner >= 0) or (Options and (1 shl moBareTerrain) = 0);
     1385  ShowCityNames := ShowObjects and (CityOwner < 0) and
     1386    (Options and (1 shl moCityNames) <> 0);
     1387  ShowBorder := true;
     1388  ShowMyBorder := CityOwner < 0;
     1389  ShowGrWall := (CityOwner < 0) and (Options and (1 shl moGreatWall) <> 0);
     1390  if ShowDebug then
     1391    Server(sGetDebugMap, me, pDebugMap, DebugMap)
     1392  else
     1393    DebugMap := nil;
     1394  with FOutput.Canvas do
     1395  begin
     1396    RealTop := y - ((Loc + 12345 * G.lx) div G.lx - 12345) * yyt;
     1397    RealBottom := y + (G.ly - ((Loc + 12345 * G.lx) div G.lx - 12345) +
     1398      3) * yyt;
     1399    Brush.Color := EmptySpaceColor;
     1400    if RealTop > FTop then
     1401      FillRect(Rect(FLeft, FTop, FRight, RealTop))
     1402    else
     1403      RealTop := FTop;
     1404    if RealBottom < FBottom then
     1405      FillRect(Rect(FLeft, RealBottom, FRight, FBottom))
     1406    else
     1407      RealBottom := FBottom;
     1408    Brush.Color := $000000;
     1409    FillRect(Rect(FLeft, RealTop, FRight, RealBottom));
     1410    Brush.Style := bsClear;
     1411  end;
     1412
     1413  for dy := 0 to ny + 1 do
     1414    if (Loc + dy * G.lx >= 0) and (Loc + (dy - 3) * G.lx < G.lx * G.ly) then
     1415      for dx := 0 to nx do
     1416      begin
     1417        ALoc := dLoc(Loc, dx - (dy + dx) and 1, dy - 2);
     1418        BLoc := dLoc(Loc, dx - (dy + dx + 1) and 1, dy - 1);
     1419        if (ALoc < 0) or (ALoc >= G.lx * G.ly) then
     1420          ATer := PoleTile(ALoc) and fTerrain
     1421        else
     1422          ATer := MyMap[ALoc] and fTerrain;
     1423        if (BLoc < 0) or (BLoc >= G.lx * G.ly) then
     1424          BTer := PoleTile(BLoc) and fTerrain
     1425        else
     1426          BTer := MyMap[BLoc] and fTerrain;
     1427
     1428        if (ATer <> fUNKNOWN) or (BTer <> fUNKNOWN) then
     1429          if ((ATer < fGrass) or (ATer = fUNKNOWN)) and
     1430            ((BTer < fGrass) or (BTer = fUNKNOWN)) then
    4601431          begin
    461             Width := Width - (FLeft - x);
    462             x := FLeft
    463           end;
    464           if y < FTop then
    465           begin
    466             Height := Height - (FTop - y);
    467             y := FTop
    468           end;
    469           if x + Width >= FRight then
    470             Width := FRight - x;
    471           if y + Height >= FBottom then
    472             Height := FBottom - y;
    473           if (Width <= 0) or (Height <= 0) then
    474             exit;
    475 
    476           with FOutput.Canvas do
    477           begin
    478             Brush.Color := Color;
    479             FillRect(Rect(x, y, x + Width, y + Height));
    480             Brush.Style := bsClear;
    481           end
    482         end;
    483 
    484         procedure TIsoMap.Textout(x, y, Color: integer; const s: string);
    485         begin
    486           FOutput.Canvas.Font.Color := Color;
    487           FOutput.Canvas.TextRect(Rect(FLeft, FTop, FRight, FBottom), x, y, s)
    488         end;
    489 
    490         procedure TIsoMap.BitBlt(Src: TBitmap; x, y, Width, Height, xSrc, ySrc,
    491           Rop: integer);
    492         begin
    493           if x < FLeft then
    494           begin
    495             Width := Width - (FLeft - x);
    496             xSrc := xSrc + (FLeft - x);
    497             x := FLeft
    498           end;
    499           if y < FTop then
    500           begin
    501             Height := Height - (FTop - y);
    502             ySrc := ySrc + (FTop - y);
    503             y := FTop
    504           end;
    505           if x + Width >= FRight then
    506             Width := FRight - x;
    507           if y + Height >= FBottom then
    508             Height := FBottom - y;
    509           if (Width <= 0) or (Height <= 0) then
    510             exit;
    511 
    512           LCLIntf.BitBlt(FOutput.Canvas.Handle, x, y, Width, Height,
    513             Src.Canvas.Handle, xSrc, ySrc, Rop);
    514         end;
    515 
    516         procedure TIsoMap.Sprite(HGr, xDst, yDst, Width, Height, xGr,
    517           yGr: integer);
    518         begin
    519           BitBlt(GrExt[HGr].Mask, xDst, yDst, Width, Height, xGr, yGr, SRCAND);
    520           BitBlt(GrExt[HGr].Data, xDst, yDst, Width, Height, xGr, yGr,
    521             SRCPAINT);
    522         end;
    523 
    524         procedure TIsoMap.TSprite(xDst, yDst, grix: integer;
    525           PureBlack: boolean = false);
    526         var
    527           Width, Height, xSrc, ySrc: integer;
    528         begin
    529           Width := TSpriteSize[grix].Right - TSpriteSize[grix].Left;
    530           Height := TSpriteSize[grix].Bottom - TSpriteSize[grix].Top;
    531           xSrc := 1 + grix mod 9 * (xxt * 2 + 1) + TSpriteSize[grix].Left;
    532           ySrc := 1 + grix div 9 * (yyt * 3 + 1) + TSpriteSize[grix].Top;
    533           xDst := xDst + TSpriteSize[grix].Left;
    534           yDst := yDst - yyt + TSpriteSize[grix].Top;
    535           if xDst < FLeft then
    536           begin
    537             Width := Width - (FLeft - xDst);
    538             xSrc := xSrc + (FLeft - xDst);
    539             xDst := FLeft
    540           end;
    541           if yDst < FTop then
    542           begin
    543             Height := Height - (FTop - yDst);
    544             ySrc := ySrc + (FTop - yDst);
    545             yDst := FTop
    546           end;
    547           if xDst + Width >= FRight then
    548             Width := FRight - xDst;
    549           if yDst + Height >= FBottom then
    550             Height := FBottom - yDst;
    551           if (Width <= 0) or (Height <= 0) then
    552             exit;
    553 
    554           LCLIntf.BitBlt(OutDC, xDst, yDst, Width, Height, MaskDC, xSrc,
    555             ySrc, SRCAND);
    556           if not PureBlack then
    557             LCLIntf.BitBlt(OutDC, xDst, yDst, Width, Height, DataDC, xSrc, ySrc,
    558               SRCPAINT);
    559         end;
    560 
    561         procedure TIsoMap.PaintUnit(x, y: integer; const UnitInfo: TUnitInfo;
    562           Status: integer);
    563         var
    564           xsh, ysh, xGr, yGr, j, mixShow: integer;
    565         begin
    566           with UnitInfo do
    567             if (Owner = me) or (emix <> $FFFF) then
     1432            if ATer = fUNKNOWN then
     1433              Aix := 0
     1434            else if IsShoreTile(ALoc) then
     1435              if ATer = fOcean then
     1436                Aix := -1
     1437              else
     1438                Aix := 1
     1439            else
     1440              Aix := ATer + 2;
     1441            if BTer = fUNKNOWN then
     1442              bix := 0
     1443            else if IsShoreTile(BLoc) then
     1444              if BTer = fOcean then
     1445                bix := -1
     1446              else
     1447                bix := 1
     1448            else
     1449              bix := BTer + 2;
     1450            if (Aix > 1) or (bix > 1) then
    5681451            begin
    569               if Job = jCity then
    570                 mixShow := -1 // building site
    571               else
    572                 mixShow := mix;
    573               if (Tribe[Owner].ModelPicture[mixShow].HGr = 0) and
    574                 (@OnInitEnemyModel <> nil) then
    575                 if not OnInitEnemyModel(emix) then
    576                   exit;
    577               xsh := Tribe[Owner].ModelPicture[mixShow].xShield;
    578               ysh := Tribe[Owner].ModelPicture[mixShow].yShield;
    579 {$IFNDEF SCR} if Status and usStay <> 0 then
    580                 j := 19
    581               else if Status and usRecover <> 0 then
    582                 j := 16
    583               else if Status and (usGoto or usEnhance) = usGoto or usEnhance
    584               then
    585                 j := 18
    586               else if Status and usEnhance <> 0 then
    587                 j := 17
    588               else if Status and usGoto <> 0 then
    589                 j := 20
    590               else {$ENDIF} if Job = jCity then
    591                   j := jNone
     1452              if Aix = -1 then
     1453                if bix = fOcean + 2 then
     1454                begin
     1455                  Aix := 0;
     1456                  bix := 0
     1457                end
    5921458                else
    593                   j := Job;
    594               if Flags and unMulti <> 0 then
    595                 Sprite(Tribe[Owner].symHGr, x + xsh - 1 + 4, y + ysh - 2, 14,
    596                   12, 33 + Tribe[Owner].sympix mod 10 * 65,
    597                   1 + Tribe[Owner].sympix div 10 * 49);
    598               Sprite(Tribe[Owner].symHGr, x + xsh - 1, y + ysh - 2, 14, 12,
    599                 18 + Tribe[Owner].sympix mod 10 * 65,
    600                 1 + Tribe[Owner].sympix div 10 * 49);
    601               FillRect(x + xsh, y + ysh + 5, 1 + Health * 11 div 100, 3,
    602                 ColorOfHealth(Health));
    603               if j > 0 then
    604               begin
    605                 xGr := 121 + j mod 7 * 9;
    606                 yGr := 1 + j div 7 * 9;
    607                 BitBlt(GrExt[HGrSystem].Mask, x + xsh + 3, y + ysh + 9, 8, 8,
    608                   xGr, yGr, SRCAND);
    609                 Sprite(HGrSystem, x + xsh + 2, y + ysh + 8, 8, 8, xGr, yGr);
    610               end;
    611               with Tribe[Owner].ModelPicture[mixShow] do
    612                 Sprite(HGr, x, y, 64, 48, pix mod 10 * 65 + 1,
    613                   pix div 10 * 49 + 1);
    614               if Flags and unFortified <> 0 then
    615               begin
    616                 { OutDC:=FOutput.Canvas.Handle;
    617                   DataDC:=GrExt[HGrTerrain].Data.Canvas.Handle;
    618                   MaskDC:=GrExt[HGrTerrain].Mask.Canvas.Handle;
    619                   TSprite(x,y+16,12*9+7); }
    620                 Sprite(HGrStdUnits, x, y, xxu * 2, yyu * 2,
    621                   1 + 6 * (xxu * 2 + 1), 1);
    622               end
     1459                begin
     1460                  Aix := 0;
     1461                  bix := 1
     1462                end
     1463              else if bix = -1 then
     1464                if Aix = fOcean + 2 then
     1465                begin
     1466                  Aix := 1;
     1467                  bix := 1
     1468                end
     1469                else
     1470                begin
     1471                  Aix := 1;
     1472                  bix := 0
     1473                end;
     1474              BitBlt(OceanPatch, x + dx * xxt, y + dy * yyt, xxt, yyt,
     1475                Aix * (xxt * 2) + (dx + dy + 1) and 1 * xxt, bix * yyt, SRCCOPY)
    6231476            end
    624         end; { PaintUnit }
    625 
    626         procedure TIsoMap.PaintCity(x, y: integer; const CityInfo: TCityInfo;
    627           accessory: boolean);
    628         var
    629           age, cHGr, cpix, xGr, xShield, yShield, LabelTextColor,
    630             LabelLength: integer;
    631           cpic: TCityPicture;
    632           s: string;
    633         begin
    634           age := GetAge(CityInfo.Owner);
    635           if CityInfo.size < 5 then
    636             xGr := 0
    637           else if CityInfo.size < 9 then
    638             xGr := 1
    639           else if CityInfo.size < 13 then
    640             xGr := 2
    641           else
    642             xGr := 3;
    643           Tribe[CityInfo.Owner].InitAge(age);
    644           if age < 2 then
    645           begin
    646             cHGr := Tribe[CityInfo.Owner].cHGr;
    647             cpix := Tribe[CityInfo.Owner].cpix;
    648             if (ciWalled and CityInfo.Flags = 0) or
    649               (GrExt[cHGr].Data.Canvas.Pixels[(xGr + 4) * 65, cpix * 49 + 48]
    650               = $00FFFF) then
    651               Sprite(cHGr, x - xxc, y - 2 * yyc, xxc * 2, yyc * 3,
    652                 xGr * (xxc * 2 + 1) + 1, 1 + cpix * (yyc * 3 + 1));
    653             if ciWalled and CityInfo.Flags <> 0 then
    654               Sprite(cHGr, x - xxc, y - 2 * yyc, xxc * 2, yyc * 3,
    655                 (xGr + 4) * (xxc * 2 + 1) + 1, 1 + cpix * (yyc * 3 + 1));
    6561477          end
    6571478          else
    6581479          begin
    659             if ciWalled and CityInfo.Flags <> 0 then
    660               Sprite(HGrCities, x - xxt, y - 2 * yyt, 2 * xxt, 3 * yyt,
    661                 (xGr + 4) * (2 * xxt + 1) + 1, 1 + (age - 2) * (3 * yyt + 1))
     1480            if ATer = fUNKNOWN then
     1481              Aix := 0
     1482            else if (ALoc >= 0) and (ALoc < G.lx * G.ly) and
     1483              (MyMap[ALoc] and fDeadLands <> 0) then
     1484              Aix := -2
     1485            else if ATer = fOcean then
     1486              Aix := -1
     1487            else if ATer = fShore then
     1488              Aix := 1
     1489            else if ATer >= fForest then
     1490              Aix := 8
    6621491            else
    663               Sprite(HGrCities, x - xxt, y - 2 * yyt, 2 * xxt, 3 * yyt,
    664                 xGr * (2 * xxt + 1) + 1, 1 + (age - 2) * (3 * yyt + 1));
    665           end;
    666 
    667           if not accessory then
    668             exit;
    669 
    670           { if ciCapital and CityInfo.Flags<>0 then
    671             Sprite(Tribe[CityInfo.Owner].symHGr,x+cpic.xf,y-13+cpic.yf,13,14,
    672             1+Tribe[CityInfo.Owner].sympix mod 10 *65,
    673             1+Tribe[CityInfo.Owner].sympix div 10 *49); {capital -- paint flag }
    674 
    675           if MyMap[CityInfo.Loc] and fObserved <> 0 then
    676           begin
    677             if age < 2 then
     1492              Aix := ATer;
     1493            if BTer = fUNKNOWN then
     1494              bix := 0
     1495            else if (BLoc >= 0) and (BLoc < G.lx * G.ly) and
     1496              (MyMap[BLoc] and fDeadLands <> 0) then
     1497              bix := -2
     1498            else if BTer = fOcean then
     1499              bix := -1
     1500            else if BTer = fShore then
     1501              bix := 1
     1502            else if BTer >= fForest then
     1503              bix := 8
     1504            else
     1505              bix := BTer;
     1506            if (Aix = -2) and (bix = -2) then
    6781507            begin
    679               cpic := Tribe[CityInfo.Owner].CityPicture[xGr];
    680               xShield := x - xxc + cpic.xShield;
    681               yShield := y - 2 * yyc + cpic.yShield;
     1508              Aix := fDesert;
     1509              bix := fDesert
    6821510            end
     1511            else if Aix = -2 then
     1512              if bix < 2 then
     1513                Aix := 8
     1514              else
     1515                Aix := bix
     1516            else if bix = -2 then
     1517              if Aix < 2 then
     1518                bix := 8
     1519              else
     1520                bix := Aix;
     1521            if Aix = -1 then
     1522              BitBlt(GrExt[HGrTerrain].Data, x + dx * xxt, y + dy * yyt, xxt,
     1523                yyt, 1 + 6 * (xxt * 2 + 1) + (dx + dy + 1) and 1 * xxt, 1 + yyt,
     1524                SRCCOPY) // arctic <-> ocean
     1525            else if bix = -1 then
     1526              BitBlt(GrExt[HGrTerrain].Data, x + dx * xxt, y + dy * yyt, xxt,
     1527                yyt, 1 + 6 * (xxt * 2 + 1) + xxt - (dx + dy + 1) and 1 * xxt,
     1528                1 + yyt * 2, SRCCOPY) // arctic <-> ocean
    6831529            else
    684             begin
    685               cpic := CitiesPictures[age, xGr];
    686               xShield := x - xxt + cpic.xShield;
    687               yShield := y - 2 * yyt + cpic.yShield;
    688             end;
    689             s := IntToStr(CityInfo.size);
    690             LabelLength := FOutput.Canvas.TextWidth(s);
    691             FillRect(xShield, yShield, LabelLength + 4, 16, $000000);
    692             if MyMap[CityInfo.Loc] and (fUnit or fObserved) = fObserved then
    693               // empty city
    694               LabelTextColor := Tribe[CityInfo.Owner].Color
    695             else
    696             begin
    697               FillRect(xShield + 1, yShield + 1, LabelLength + 2, 14,
    698                 Tribe[CityInfo.Owner].Color);
    699               LabelTextColor := $000000;
    700             end;
    701             Textout(xShield + 2, yShield - 1, LabelTextColor, s);
     1530              BitBlt(LandPatch, x + dx * xxt, y + dy * yyt, xxt, yyt,
     1531                Aix * (xxt * 2) + (dx + dy + 1) and 1 * xxt, bix * yyt, SRCCOPY)
    7021532          end
    703         end; { PaintCity }
    704 
    705         function PoleTile(Loc: integer): integer;
    706         begin { virtual pole tile }
    707           result := fUNKNOWN;
    708           if Loc < -2 * G.lx then
    709           else if Loc < -G.lx then
    710           begin
    711             if (MyMap[dLoc(Loc, 0, 2)] and fTerrain <> fUNKNOWN) and
    712               (MyMap[dLoc(Loc, -2, 2)] and fTerrain <> fUNKNOWN) and
    713               (MyMap[dLoc(Loc, 2, 2)] and fTerrain <> fUNKNOWN) then
    714               result := fArctic;
    715             if (MyMap[dLoc(Loc, 0, 2)] and fObserved <> 0) and
    716               (MyMap[dLoc(Loc, -2, 2)] and fObserved <> 0) and
    717               (MyMap[dLoc(Loc, 2, 2)] and fObserved <> 0) then
    718               result := result or fObserved
    719           end
    720           else if Loc < 0 then
    721           begin
    722             if (MyMap[dLoc(Loc, -1, 1)] and fTerrain <> fUNKNOWN) and
    723               (MyMap[dLoc(Loc, 1, 1)] and fTerrain <> fUNKNOWN) then
    724               result := fArctic;
    725             if (MyMap[dLoc(Loc, -1, 1)] and fObserved <> 0) and
    726               (MyMap[dLoc(Loc, 1, 1)] and fObserved <> 0) then
    727               result := result or fObserved
    728           end
    729           else if Loc < G.lx * (G.ly + 1) then
    730           begin
    731             if (MyMap[dLoc(Loc, -1, -1)] and fTerrain <> fUNKNOWN) and
    732               (MyMap[dLoc(Loc, 1, -1)] and fTerrain <> fUNKNOWN) then
    733               result := fArctic;
    734             if (MyMap[dLoc(Loc, -1, -1)] and fObserved <> 0) and
    735               (MyMap[dLoc(Loc, 1, -1)] and fObserved <> 0) then
    736               result := result or fObserved
    737           end
    738           else if Loc < G.lx * (G.ly + 2) then
    739           begin
    740             if (MyMap[dLoc(Loc, 0, -2)] and fTerrain <> fUNKNOWN) and
    741               (MyMap[dLoc(Loc, -2, -2)] and fTerrain <> fUNKNOWN) and
    742               (MyMap[dLoc(Loc, 2, -2)] and fTerrain <> fUNKNOWN) then
    743               result := fArctic;
    744             if (MyMap[dLoc(Loc, 0, -2)] and fObserved <> 0) and
    745               (MyMap[dLoc(Loc, -2, -2)] and fObserved <> 0) and
    746               (MyMap[dLoc(Loc, 2, -2)] and fObserved <> 0) then
    747               result := result or fObserved
    748           end
     1533      end;
     1534
     1535  OutDC := FOutput.Canvas.Handle;
     1536  DataDC := GrExt[HGrTerrain].Data.Canvas.Handle;
     1537  MaskDC := GrExt[HGrTerrain].Mask.Canvas.Handle;
     1538  for dy := -2 to ny + 1 do
     1539    for dx := -1 to nx do
     1540      if (dx + dy) and 1 = 0 then
     1541        PaintShore(x + xxt * dx, y + yyt + yyt * dy, dLoc(Loc, dx, dy));
     1542  for dy := -2 to ny + 1 do
     1543    for dx := -1 to nx do
     1544      if (dx + dy) and 1 = 0 then
     1545        PaintTileExtraTerrain(x + xxt * dx, y + yyt + yyt * dy,
     1546          dLoc(Loc, dx, dy));
     1547  if CityOwner >= 0 then
     1548  begin
     1549    for dy := -2 to ny + 1 do
     1550      for dx := -2 to nx + 1 do
     1551        if (dx + dy) and 1 = 0 then
     1552        begin
     1553          ALoc := dLoc(Loc, dx, dy);
     1554          if Distance(ALoc, CityLoc) > 5 then
     1555            PaintTileObjects(x + xxt * dx, y + yyt + yyt * dy, ALoc, CityLoc,
     1556              CityOwner, UseBlink);
    7491557        end;
    750 
    751         const
    752           Dirx: array [0 .. 7] of integer = (1, 2, 1, 0, -1, -2, -1, 0);
    753           Diry: array [0 .. 7] of integer = (-1, 0, 1, 2, 1, 0, -1, -2);
    754 
    755         function TIsoMap.Connection4(Loc, Mask, Value: integer): integer;
     1558    dx := ((CityLoc mod G.lx * 2 + CityLoc div G.lx and 1) -
     1559      ((Loc + 666 * G.lx) mod G.lx * 2 + (Loc + 666 * G.lx) div G.lx and 1) + 3
     1560      * G.lx) mod (2 * G.lx) - G.lx;
     1561    dy := CityLoc div G.lx - (Loc + 666 * G.lx) div G.lx + 666;
     1562    xm := x + (dx + 1) * xxt;
     1563    ym := y + (dy + 1) * yyt + yyt;
     1564    ShadeOutside(FLeft, FTop, FRight, FBottom, xm, ym);
     1565    CityGrid(xm, ym);
     1566    for dy := -2 to ny + 1 do
     1567      for dx := -2 to nx + 1 do
     1568        if (dx + dy) and 1 = 0 then
    7561569        begin
    757           result := 0;
    758           if dLoc(Loc, 1, -1) >= 0 then
    759           begin
    760             if MyMap[dLoc(Loc, 1, -1)] and Mask = Cardinal(Value) then
    761               inc(result, 1);
    762             if MyMap[dLoc(Loc, -1, -1)] and Mask = Cardinal(Value) then
    763               inc(result, 8);
    764           end;
    765           if dLoc(Loc, 1, 1) < G.lx * G.ly then
    766           begin
    767             if MyMap[dLoc(Loc, 1, 1)] and Mask = Cardinal(Value) then
    768               inc(result, 2);
    769             if MyMap[dLoc(Loc, -1, 1)] and Mask = Cardinal(Value) then
    770               inc(result, 4);
    771           end
     1570          ALoc := dLoc(Loc, dx, dy);
     1571          if Distance(ALoc, CityLoc) <= 5 then
     1572            PaintTileObjects(x + xxt * dx, y + yyt + yyt * dy, ALoc, CityLoc,
     1573              CityOwner, UseBlink);
    7721574        end;
    773 
    774         function TIsoMap.Connection8(Loc, Mask: integer): integer;
    775         var
    776           Dir, ConnLoc: integer;
    777         begin
    778           result := 0;
    779           for Dir := 0 to 7 do
    780           begin
    781             ConnLoc := dLoc(Loc, Dirx[Dir], Diry[Dir]);
    782             if (ConnLoc >= 0) and (ConnLoc < G.lx * G.ly) and
    783               (MyMap[ConnLoc] and Mask <> 0) then
    784               inc(result, 1 shl Dir);
    785           end
    786         end;
    787 
    788         function TIsoMap.OceanConnection(Loc: integer): integer;
    789         var
    790           Dir, ConnLoc: integer;
    791         begin
    792           result := 0;
    793           for Dir := 0 to 7 do
    794           begin
    795             ConnLoc := dLoc(Loc, Dirx[Dir], Diry[Dir]);
    796             if (ConnLoc < 0) or (ConnLoc >= G.lx * G.ly) or
    797               ((MyMap[ConnLoc] - 2) and fTerrain < 13) then
    798               inc(result, 1 shl Dir);
    799           end
    800         end;
    801 
    802         procedure TIsoMap.PaintShore(x, y, Loc: integer);
    803         var
    804           Conn, Tile: integer;
    805         begin
    806           if (y <= FTop - yyt * 2) or (y > FBottom) or (x <= FLeft - xxt * 2) or
    807             (x > FRight) then
    808             exit;
    809           if (Loc < 0) or (Loc >= G.lx * G.ly) then
    810             exit;
    811           Tile := MyMap[Loc];
    812           if Tile and fTerrain >= fGrass then
    813             exit;
    814           Conn := OceanConnection(Loc);
    815           if Conn = 0 then
    816             exit;
    817 
    818           BitBlt(GrExt[HGrTerrain].Data, x + xxt div 2, y, xxt, yyt,
    819             1 + (Conn shr 6 + Conn and 1 shl 2) * (xxt * 2 + 1),
    820             1 + yyt + (16 + Tile and fTerrain) * (yyt * 3 + 1), SRCPAINT);
    821           BitBlt(GrExt[HGrTerrain].Data, x + xxt, y + yyt div 2, xxt, yyt,
    822             1 + (Conn and 7) * (xxt * 2 + 1) + xxt,
    823             1 + yyt * 2 + (16 + Tile and fTerrain) * (yyt * 3 + 1), SRCPAINT);
    824           BitBlt(GrExt[HGrTerrain].Data, x + xxt div 2, y + yyt, xxt, yyt,
    825             1 + (Conn shr 2 and 7) * (xxt * 2 + 1) + xxt,
    826             1 + yyt + (16 + Tile and fTerrain) * (yyt * 3 + 1), SRCPAINT);
    827           BitBlt(GrExt[HGrTerrain].Data, x, y + yyt div 2, xxt, yyt,
    828             1 + (Conn shr 4 and 7) * (xxt * 2 + 1),
    829             1 + yyt * 2 + (16 + Tile and fTerrain) * (yyt * 3 + 1), SRCPAINT);
    830           Conn := Connection4(Loc, fTerrain, fUNKNOWN); { dither to black }
    831           if Conn and 1 <> 0 then
    832             BitBlt(GrExt[HGrTerrain].Mask, x + xxt, y, xxt, yyt,
    833               1 + 7 * (xxt * 2 + 1) + xxt,
    834               1 + yyt + 15 * (yyt * 3 + 1), SRCAND);
    835           if Conn and 2 <> 0 then
    836             BitBlt(GrExt[HGrTerrain].Mask, x + xxt, y + yyt, xxt, yyt,
    837               1 + 7 * (xxt * 2 + 1) + xxt, 1 + yyt * 2 + 15 *
    838               (yyt * 3 + 1), SRCAND);
    839           if Conn and 4 <> 0 then
    840             BitBlt(GrExt[HGrTerrain].Mask, x, y + yyt, xxt, yyt,
    841               1 + 7 * (xxt * 2 + 1), 1 + yyt * 2 + 15 * (yyt * 3 + 1), SRCAND);
    842           if Conn and 8 <> 0 then
    843             BitBlt(GrExt[HGrTerrain].Mask, x, y, xxt, yyt,
    844               1 + 7 * (xxt * 2 + 1), 1 + yyt + 15 * (yyt * 3 + 1), SRCAND);
    845         end;
    846 
    847         procedure TIsoMap.PaintTileExtraTerrain(x, y, Loc: integer);
    848         var
    849           Dir, Conn, RRConn, yGr, Tile, yLoc: integer;
    850         begin
    851           if (Loc < 0) or (Loc >= G.lx * G.ly) or (y <= -yyt * 2) or
    852             (y > FOutput.Height) or (x <= -xxt * 2) or (x > FOutput.Width) then
    853             exit;
    854           Tile := MyMap[Loc];
    855           if Tile and fTerrain = fForest then
    856           begin
    857             yLoc := Loc div G.lx;
    858             if IsJungle(yLoc) then
    859               yGr := 18
    860             else
    861               yGr := 3;
    862             Conn := Connection4(Loc, fTerrain, Tile and fTerrain);
    863             if (yLoc = (G.ly - 2) div 4) or (G.ly - 1 - yLoc = (G.ly + 2) div 4)
    864             then
    865               Conn := Conn and not 6 // no connection to south
    866             else if (yLoc = (G.ly + 2) div 4) or
    867               (G.ly - 1 - yLoc = (G.ly - 2) div 4) then
    868               Conn := Conn and not 9; // no connection to north
    869             TSprite(x, y, Conn mod 8 + (yGr + Conn div 8) * 9);
    870           end
    871           else if Tile and fTerrain in [fHills, fMountains, fForest] then
    872           begin
    873             yGr := 3 + 2 * (Tile and fTerrain - fForest);
    874             Conn := Connection4(Loc, fTerrain, Tile and fTerrain);
    875             TSprite(x, y, Conn mod 8 + (yGr + Conn div 8) * 9);
    876           end
    877           else if Tile and fDeadLands <> 0 then
    878             TSprite(x, y, 2 * 9 + 6);
    879 
    880           if ShowObjects then
    881           begin
    882             if Tile and fTerImp = tiFarm then
    883               TSprite(x, y, 109) { farmland }
    884             else if Tile and fTerImp = tiIrrigation then
    885               TSprite(x, y, 108); // irrigation
    886           end;
    887           if Tile and fRiver <> 0 then
    888           begin
    889             Conn := Connection4(Loc, fRiver, fRiver) or
    890               Connection4(Loc, fTerrain, fShore) or
    891               Connection4(Loc, fTerrain, fUNKNOWN);
    892             TSprite(x, y, Conn mod 8 + (13 + Conn div 8) * 9);
    893           end;
    894 
    895           if Tile and fTerrain < fGrass then
    896           begin
    897             Conn := Connection4(Loc, fRiver, fRiver);
    898             for Dir := 0 to 3 do
    899               if Conn and (1 shl Dir) <> 0 then { river mouths }
    900                 TSprite(x, y, 15 * 9 + Dir);
    901             if ShowObjects then
    902             begin
    903               Conn := Connection8(Loc, fCanal);
    904               for Dir := 0 to 7 do
    905                 if Conn and (1 shl Dir) <> 0 then { canal mouths }
    906                   TSprite(x, y, 20 * 9 + 1 + Dir);
    907             end
    908           end;
    909 
    910           if ShowObjects then
    911           begin
    912             if (Tile and fCanal <> 0) or (Tile and fCity <> 0) then
    913             begin // paint canal connections
    914               Conn := Connection8(Loc, fCanal or fCity);
    915               if Tile and fCanal <> 0 then
    916                 Conn := Conn or ($FF - OceanConnection(Loc));
    917               if Conn = 0 then
    918               begin
    919                 if Tile and fCanal <> 0 then
    920                   TSprite(x, y, 99)
    921               end
    922               else
    923                 for Dir := 0 to 7 do
    924                   if (1 shl Dir) and Conn <> 0 then
    925                     TSprite(x, y, 100 + Dir);
    926             end;
    927             if Tile and (fRR or fCity) <> 0 then
    928               RRConn := Connection8(Loc, fRR or fCity)
    929             else
    930               RRConn := 0;
    931             if Tile and (fRoad or fRR or fCity) <> 0 then
    932             begin // paint road connections
    933               Conn := Connection8(Loc, fRoad or fRR or fCity) and not RRConn;
    934               if (Conn = 0) and (Tile and (fRR or fCity) = 0) then
    935                 TSprite(x, y, 81)
    936               else if Conn > 0 then
    937                 for Dir := 0 to 7 do
    938                   if (1 shl Dir) and Conn <> 0 then
    939                     TSprite(x, y, 82 + Dir);
    940             end;
    941             // paint railroad connections
    942             if (Tile and fRR <> 0) and (RRConn = 0) then
    943               TSprite(x, y, 90)
    944             else if RRConn > 0 then
    945               for Dir := 0 to 7 do
    946                 if (1 shl Dir) and RRConn <> 0 then
    947                   TSprite(x, y, 91 + Dir);
    948           end;
    949         end;
    950 
    951         // (x,y) is top left pixel of (2*xxt,3*yyt) rectangle
    952         procedure TIsoMap.PaintTileObjects(x, y, Loc, CityLoc,
    953           CityOwner: integer; UseBlink: boolean);
    954         type
    955           TLine = array [0 .. 9 * 65, 0 .. 2] of Byte;
    956         var
    957           p1, p2, uix, cix, dy, Loc1, Tile, Multi, Destination: integer;
    958           CityInfo: TCityInfo;
    959           UnitInfo: TUnitInfo;
    960           fog: boolean;
    961 
    962           procedure NameCity;
    963           var
    964             cix, xs, w: integer;
    965             BehindCityInfo: TCityInfo;
    966             s: string;
    967             IsCapital: boolean;
    968           begin
    969             BehindCityInfo.Loc := Loc - 2 * G.lx;
    970             if ShowCityNames and (Options and (1 shl moEditMode) = 0) and
    971               (BehindCityInfo.Loc >= 0) and (BehindCityInfo.Loc < G.lx * G.ly)
    972               and (MyMap[BehindCityInfo.Loc] and fCity <> 0) then
    973             begin
    974               GetCityInfo(BehindCityInfo.Loc, cix, BehindCityInfo);
    975               IsCapital := BehindCityInfo.Flags and ciCapital <> 0;
    976               { if Showuix and (cix>=0) then s:=IntToStr(cix)
    977                 else } s := CityName(BehindCityInfo.ID);
    978               w := FOutput.Canvas.TextWidth(s);
    979               xs := x + xxt - (w + 1) div 2;
    980               if IsCapital then
    981                 FOutput.Canvas.Font.Style := FOutput.Canvas.Font.Style +
    982                   [fsUnderline];
    983               Textout(xs + 1, y - 9, $000000, s);
    984               Textout(xs, y - 10, $FFFFFF, s);
    985               if IsCapital then
    986                 FOutput.Canvas.Font.Style := FOutput.Canvas.Font.Style -
    987                   [fsUnderline];
    988             end;
    989           end;
    990 
    991           procedure ShowSpacePort;
    992           begin
    993             if ShowObjects and (Options and (1 shl moEditMode) = 0) and
    994               (Tile and fCity <> 0) and (CityInfo.Flags and ciSpacePort <> 0)
    995             then
    996               TSprite(x + xxt, y - 6, 12 * 9 + 5);
    997           end;
    998 
    999           procedure PaintBorder;
    1000           var
    1001             dx, dy: integer;
    1002             Line: ^TLine;
    1003           begin
    1004             if ShowBorder and (Loc >= 0) and (Loc < G.lx * G.ly) and
    1005               (Tile and fTerrain <> fUNKNOWN) then
    1006             begin
    1007               p1 := MyRO.Territory[Loc];
    1008               if (p1 >= 0) and (ShowMyBorder or (p1 <> me)) then
    1009               begin
    1010                 if BordersOK and (1 shl p1) = 0 then
    1011                 begin
    1012                   LCLIntf.BitBlt(Borders.Canvas.Handle, 0, p1 * (yyt * 2),
    1013                     xxt * 2, yyt * 2, GrExt[HGrTerrain].Data.Canvas.Handle,
    1014                     1 + 8 * (xxt * 2 + 1),
    1015                     1 + yyt + 16 * (yyt * 3 + 1), SRCCOPY);
    1016                   Borders.BeginUpdate;
    1017                   for dy := 0 to yyt * 2 - 1 do
    1018                   begin
    1019                     Line := Borders.ScanLine[p1 * (yyt * 2) + dy];
    1020                     for dx := 0 to xxt * 2 - 1 do
    1021                       if Line[dx, 0] = 99 then
    1022                       begin
    1023                         Line[dx, 0] := Tribe[p1].Color shr 16 and $FF;
    1024                         Line[dx, 1] := Tribe[p1].Color shr 8 and $FF;
    1025                         Line[dx, 2] := Tribe[p1].Color and $FF;
    1026                       end
    1027                   end;
    1028                   Borders.EndUpdate;
    1029                   BordersOK := BordersOK or 1 shl p1;
    1030                 end;
    1031                 for dy := 0 to 1 do
    1032                   for dx := 0 to 1 do
    1033                   begin
    1034                     Loc1 := dLoc(Loc, dx * 2 - 1, dy * 2 - 1);
    1035                     begin
    1036                       if (Loc1 < 0) or (Loc1 >= G.lx * G.ly) then
    1037                         p2 := -1
    1038                       else if MyMap[Loc1] and fTerrain = fUNKNOWN then
    1039                         p2 := p1
    1040                       else
    1041                         p2 := MyRO.Territory[Loc1];
    1042                       if p2 <> p1 then
    1043                       begin
    1044                         BitBlt(GrExt[HGrTerrain].Mask, x + dx * xxt,
    1045                           y + dy * yyt, xxt, yyt, 1 + 8 * (xxt * 2 + 1) + dx *
    1046                           xxt, 1 + yyt + 16 * (yyt * 3 + 1) + dy * yyt, SRCAND);
    1047                         BitBlt(Borders, x + dx * xxt, y + dy * yyt, xxt, yyt,
    1048                           dx * xxt, p1 * (yyt * 2) + dy * yyt, SRCPAINT);
    1049                       end
    1050                     end;
    1051                   end
    1052               end
    1053             end;
    1054           end;
    1055 
    1056         begin
    1057           if (Loc < 0) or (Loc >= G.lx * G.ly) then
    1058             Tile := PoleTile(Loc)
    1059           else
    1060             Tile := MyMap[Loc];
    1061           if ShowObjects and (Options and (1 shl moEditMode) = 0) and
    1062             (Tile and fCity <> 0) then
    1063             GetCityInfo(Loc, cix, CityInfo);
    1064           if (y <= FTop - yyt * 2) or (y > FBottom) or (x <= FLeft - xxt * 2) or
    1065             (x > FRight) then
    1066           begin
    1067             NameCity;
    1068             ShowSpacePort;
    1069             exit;
    1070           end;
    1071           if Tile and fTerrain = fUNKNOWN then
    1072           begin
    1073             NameCity;
    1074             ShowSpacePort;
    1075             exit
    1076           end; { square not discovered }
    1077 
    1078           if not(FoW and (Tile and fObserved = 0)) then
    1079             PaintBorder;
    1080 
    1081           if (Loc >= 0) and (Loc < G.lx * G.ly) and (Loc = FAdviceLoc) then
    1082             TSprite(x, y, 7 + 9 * 2);
    1083 
    1084           if (Loc >= 0) and (Loc < G.lx * G.ly) and (Tile and fSpecial <> 0)
    1085           then { special ressources }
    1086           begin
    1087             dy := Loc div G.lx;
    1088             if Tile and fTerrain < fForest then
    1089               TSprite(x, y, Tile and fTerrain + (Tile and fSpecial shr 5) * 9)
    1090             else if (Tile and fTerrain = fForest) and IsJungle(dy) then
    1091               TSprite(x, y, 8 + 17 * 9 + (Tile and fSpecial shr 5) * 9)
    1092             else
    1093               TSprite(x, y, 8 + 2 * 9 + ((Tile and fTerrain - fForest) * 2 +
    1094                 Tile and fSpecial shr 5) * 9);
    1095           end;
    1096 
    1097           if ShowObjects then
    1098           begin
    1099             if Tile and fTerImp = tiMine then
    1100               TSprite(x, y, 2 + 9 * 12);
    1101             if Tile and fTerImp = tiBase then
    1102               TSprite(x, y, 4 + 9 * 12);
    1103             if Tile and fPoll <> 0 then
    1104               TSprite(x, y, 6 + 9 * 12);
    1105             if Tile and fTerImp = tiFort then
    1106             begin
    1107               TSprite(x, y, 7 + 9 * 12);
    1108               if Tile and fObserved = 0 then
    1109                 TSprite(x, y, 3 + 9 * 12);
    1110             end;
    1111           end;
    1112           if Tile and fDeadLands <> 0 then
    1113             TSprite(x, y, (12 + Tile shr 25 and 3) * 9 + 8);
    1114 
    1115           if Options and (1 shl moEditMode) <> 0 then
    1116             fog := (Loc < 0) or (Loc >= G.lx * G.ly)
    1117             // else if CityLoc>=0 then
    1118             // fog:= (Loc<0) or (Loc>=G.lx*G.ly) or (Distance(Loc,CityLoc)>5)
    1119           else if ShowGrWall then
    1120             fog := Tile and fGrWall = 0
    1121           else
    1122             fog := FoW and (Tile and fObserved = 0);
    1123           if fog and ShowObjects then
    1124             if Loc < -G.lx then
    1125               Sprite(HGrTerrain, x, y + yyt, xxt * 2, yyt,
    1126                 1 + 6 * (xxt * 2 + 1), 1 + yyt * 2 + 15 * (yyt * 3 + 1))
    1127             else if Loc >= G.lx * (G.ly + 1) then
    1128               Sprite(HGrTerrain, x, y, xxt * 2, yyt, 1 + 6 * (xxt * 2 + 1),
    1129                 1 + yyt + 15 * (yyt * 3 + 1))
    1130             else
    1131               TSprite(x, y, 6 + 9 * 15, xxt <> 33);
    1132 
    1133           if FoW and (Tile and fObserved = 0) then
    1134             PaintBorder;
    1135 
    1136 {$IFNDEF SCR}
    1137           // paint goto destination mark
    1138           if DestinationMarkON and (CityOwner < 0) and (UnFocus >= 0) and
    1139             (MyUn[UnFocus].Status and usGoto <> 0) then
    1140           begin
    1141             Destination := MyUn[UnFocus].Status shr 16;
    1142             if (Destination = Loc) and (Destination <> MyUn[UnFocus].Loc) then
    1143               if not UseBlink or BlinkOn then
    1144                 TSprite(x, y, 8 + 9 * 1)
    1145               else
    1146                 TSprite(x, y, 8 + 9 * 2)
    1147           end;
    1148 {$ENDIF}
    1149           if Options and (1 shl moEditMode) <> 0 then
    1150           begin
    1151             if Tile and fPrefStartPos <> 0 then
    1152               TSprite(x, y, 0 + 9 * 1)
    1153             else if Tile and fStartPos <> 0 then
    1154               TSprite(x, y, 0 + 9 * 2);
    1155           end
    1156           else if ShowObjects then
    1157           begin
    1158             { if (CityLoc<0) and (UnFocus>=0) and (Loc=MyUn[UnFocus].Loc) then
    1159               if BlinkOn then TSprite(x,y,8+9*0)
    1160               else TSprite(x,y,8+9*1); }
    1161 
    1162             NameCity;
    1163             ShowSpacePort;
    1164             if Tile and fCity <> 0 then
    1165               PaintCity(x + xxt, y + yyt, CityInfo, CityOwner < 0);
    1166 
    1167             if (Tile and fUnit <> 0) and (Loc <> AttLoc) and
    1168               ((Loc <> DefLoc) or (DefHealth <> 0))
    1169 {$IFNDEF SCR} and ((CityOwner >= 0) or (UnFocus < 0) or not UseBlink or
    1170               BlinkOn or (Loc <> MyUn[UnFocus].Loc)){$ENDIF}
    1171               and ((Tile and fCity <> fCity) or (Loc = DefLoc)
    1172 {$IFNDEF SCR} or (not UseBlink or BlinkOn) and (UnFocus >= 0) and
    1173               (Loc = MyUn[UnFocus].Loc){$ENDIF}) then
    1174             begin { unit }
    1175               GetUnitInfo(Loc, uix, UnitInfo);
    1176               if (Loc = DefLoc) and (DefHealth >= 0) then
    1177                 UnitInfo.Health := DefHealth;
    1178               if (UnitInfo.Owner <> CityOwner) and
    1179                 not((CityOwner = me) and
    1180                 (MyRO.Treaty[UnitInfo.Owner] = trAlliance)) then
    1181 {$IFNDEF SCR} if (UnFocus >= 0) and (Loc = MyUn[UnFocus].Loc) then { active unit }
    1182                 begin
    1183                   Multi := UnitInfo.Flags and unMulti;
    1184                   MakeUnitInfo(me, MyUn[UnFocus], UnitInfo);
    1185                   UnitInfo.Flags := UnitInfo.Flags or Multi;
    1186                   PaintUnit(x + (xxt - xxu), y + (yyt - yyu_anchor), UnitInfo,
    1187                     MyUn[UnFocus].Status);
    1188                 end
    1189                 else if UnitInfo.Owner = me then
    1190                 begin
    1191                   if ClientMode = cMovieTurn then
    1192                     PaintUnit(x + (xxt - xxu), y + (yyt - yyu_anchor),
    1193                       UnitInfo, 0)
    1194                     // status is not set with precise timing during loading
    1195                   else
    1196                     PaintUnit(x + (xxt - xxu), y + (yyt - yyu_anchor), UnitInfo,
    1197                       MyUn[uix].Status);
    1198                   // if Showuix then Textout(x+16,y+5,$80FF00,IntToStr(uix));
    1199                 end
    1200                 else {$ENDIF} PaintUnit(x + (xxt - xxu), y + (yyt - yyu_anchor), UnitInfo, 0);
    1201             end
    1202             else if Tile and fHiddenUnit <> 0 then
    1203               Sprite(HGrStdUnits, x + (xxt - xxu), y + (yyt - yyu_anchor),
    1204                 xxu * 2, yyu * 2, 1 + 5 * (xxu * 2 + 1), 1)
    1205             else if Tile and fStealthUnit <> 0 then
    1206               Sprite(HGrStdUnits, x + (xxt - xxu), y + (yyt - yyu_anchor),
    1207                 xxu * 2, yyu * 2, 1 + 5 * (xxu * 2 + 1), 1 + 1 * (yyu * 2 + 1))
    1208           end;
    1209 
    1210           if ShowObjects and (Tile and fTerImp = tiFort) and
    1211             (Tile and fObserved <> 0) then
    1212             TSprite(x, y, 3 + 9 * 12);
    1213 
    1214           if (Loc >= 0) and (Loc < G.lx * G.ly) then
    1215             if ShowLoc then
    1216               Textout(x + xxt - 16, y + yyt - 9, $FFFF00, IntToStr(Loc))
    1217             else if ShowDebug and (DebugMap <> nil) and (Loc >= 0) and
    1218               (Loc < G.lx * G.ly) and (DebugMap[Loc] <> 0) then
    1219               Textout(x + xxt - 16, y + yyt - 9, $00E0FF,
    1220                 IntToStr(integer(DebugMap[Loc])))
    1221         end; { PaintTileObjects }
    1222 
    1223         procedure TIsoMap.PaintGrid(x, y, nx, ny: integer);
    1224 
    1225           procedure ClippedLine(dx0, dy0: integer; mirror: boolean);
    1226           var
    1227             x0, x1, dxmin, dymin, dxmax, dymax, n: integer;
    1228           begin
    1229             with FOutput.Canvas do
    1230             begin
    1231               dxmin := (FLeft - x) div xxt;
    1232               dymin := (RealTop - y) div yyt;
    1233               dxmax := (FRight - x - 1) div xxt + 1;
    1234               dymax := (RealBottom - y - 1) div yyt + 1;
    1235               n := dymax - dy0;
    1236               if mirror then
    1237               begin
    1238                 if dx0 - dxmin < n then
    1239                   n := dx0 - dxmin;
    1240                 if dx0 > dxmax then
    1241                 begin
    1242                   n := n - (dx0 - dxmax);
    1243                   dy0 := dy0 + (dx0 - dxmax);
    1244                   dx0 := dxmax
    1245                 end;
    1246                 if dy0 < dymin then
    1247                 begin
    1248                   n := n - (dymin - dy0);
    1249                   dx0 := dx0 - (dymin - dy0);
    1250                   dy0 := dymin
    1251                 end;
    1252               end
    1253               else
    1254               begin
    1255                 if dxmax - dx0 < n then
    1256                   n := dxmax - dx0;
    1257                 if dx0 < dxmin then
    1258                 begin
    1259                   n := n - (dxmin - dx0);
    1260                   dy0 := dy0 + (dxmin - dx0);
    1261                   dx0 := dxmin
    1262                 end;
    1263                 if dy0 < dymin then
    1264                 begin
    1265                   n := n - (dymin - dy0);
    1266                   dx0 := dx0 + (dymin - dy0);
    1267                   dy0 := dymin
    1268                 end;
    1269               end;
    1270               if n <= 0 then
    1271                 exit;
    1272               if mirror then
    1273               begin
    1274                 x0 := x + dx0 * xxt - 1;
    1275                 x1 := x + (dx0 - n) * xxt - 1;
    1276               end
    1277               else
    1278               begin
    1279                 x0 := x + dx0 * xxt;
    1280                 x1 := x + (dx0 + n) * xxt;
    1281               end;
    1282               moveto(x0, y + dy0 * yyt);
    1283               lineto(x1, y + (dy0 + n) * yyt);
    1284             end
    1285           end;
    1286 
    1287         var
    1288           i: integer;
    1289         begin
    1290           FOutput.Canvas.pen.Color := $000000; // $FF shl (8*random(3));
    1291           for i := 0 to nx div 2 do
    1292             ClippedLine(i * 2, 0, false);
    1293           for i := 1 to (nx + 1) div 2 do
    1294             ClippedLine(i * 2, 0, true);
    1295           for i := 0 to ny div 2 do
    1296           begin
    1297             ClippedLine(0, 2 * i + 2, false);
    1298             ClippedLine(nx + 1, 2 * i + 1 + nx and 1, true);
    1299           end;
    1300         end;
    1301 
    1302         procedure TIsoMap.Paint(x, y, Loc, nx, ny, CityLoc, CityOwner: integer;
    1303           UseBlink: boolean; CityAllowClick: boolean);
    1304 
    1305           function IsShoreTile(Loc: integer): boolean;
    1306           const
    1307             Dirx: array [0 .. 7] of integer = (1, 2, 1, 0, -1, -2, -1, 0);
    1308             Diry: array [0 .. 7] of integer = (-1, 0, 1, 2, 1, 0, -1, -2);
    1309           var
    1310             Dir, ConnLoc: integer;
    1311           begin
    1312             result := false;
    1313             for Dir := 0 to 7 do
    1314             begin
    1315               ConnLoc := dLoc(Loc, Dirx[Dir], Diry[Dir]);
    1316               if (ConnLoc < 0) or (ConnLoc >= G.lx * G.ly) or
    1317                 ((MyMap[ConnLoc] - 2) and fTerrain < 13) then
    1318                 result := true
    1319             end
    1320           end;
    1321 
    1322           procedure ShadeOutside(x0, y0, x1, y1, xm, ym: integer);
    1323           const
    1324             rShade = 3.75;
    1325 
    1326             procedure MakeDark(Line: pointer; length: integer);
    1327             type
    1328               TCardArray = array [0 .. 9999] of Cardinal;
    1329               PCardArray = ^TCardArray;
    1330               TByteArray = array [0 .. 9999] of Byte;
    1331               PByteArray = ^TByteArray;
    1332             var
    1333               i, rest: integer;
    1334             begin
    1335               for i := length * 3 div 4 - 1 downto 0 do
    1336                 PCardArray(Line)[i] := PCardArray(Line)[i] shr 1 and $7F7F7F7F;
    1337               rest := (length * 3 div 4) * 4;
    1338               for i := length * 3 mod 4 - 1 downto 0 do
    1339                 PByteArray(Line)[rest + i] := PByteArray(Line)
    1340                   [rest + i] shr 1 and $7F;
    1341             end;
    1342 
    1343           type
    1344             TLine = array [0 .. 99999, 0 .. 2] of Byte;
    1345           var
    1346             y, wBright: integer;
    1347             y_n, w_n: single;
    1348             Line: ^TLine;
    1349           begin
    1350             FOutput.BeginUpdate;
    1351             for y := y0 to y1 - 1 do
    1352             begin
    1353               Line := FOutput.ScanLine[y];
    1354               y_n := (y - ym) / yyt;
    1355               if abs(y_n) < rShade then
    1356               begin
    1357                 w_n := sqrt(sqr(rShade) - sqr(y_n));
    1358                 wBright := trunc(w_n * xxt + 0.5);
    1359                 MakeDark(@Line[x0], xm - x0 - wBright);
    1360                 MakeDark(@Line[xm + wBright], x1 - xm - wBright);
    1361               end
    1362               else
    1363                 MakeDark(@Line[x0], x1 - x0);
    1364             end;
    1365             FOutput.EndUpdate;
    1366           end;
    1367 
    1368           procedure CityGrid(xm, ym: integer);
    1369           var
    1370             i: integer;
    1371           begin
    1372             with FOutput.Canvas do
    1373             begin
    1374               if CityAllowClick then
    1375                 pen.Color := $FFFFFF
    1376               else
    1377                 pen.Color := $000000;
    1378               pen.Width := 1;
    1379               for i := 0 to 3 do
    1380               begin
    1381                 moveto(xm - xxt * (4 - i), ym + yyt * (1 + i));
    1382                 lineto(xm + xxt * (1 + i), ym - yyt * (4 - i));
    1383                 moveto(xm - xxt * (4 - i), ym - yyt * (1 + i));
    1384                 lineto(xm + xxt * (1 + i), ym + yyt * (4 - i));
    1385               end;
    1386               moveto(xm - xxt * 4, ym + yyt * 1);
    1387               lineto(xm - xxt * 1, ym + yyt * 4);
    1388               moveto(xm + xxt * 1, ym + yyt * 4);
    1389               lineto(xm + xxt * 4, ym + yyt * 1);
    1390               moveto(xm - xxt * 4, ym - yyt * 1);
    1391               lineto(xm - xxt * 1, ym - yyt * 4);
    1392               moveto(xm + xxt * 1, ym - yyt * 4);
    1393               lineto(xm + xxt * 4, ym - yyt * 1);
    1394               pen.Width := 1;
    1395             end
    1396           end;
    1397 
    1398         var
    1399           dx, dy, xm, ym, ALoc, BLoc, ATer, BTer, Aix, bix: integer;
    1400         begin
    1401           FoW := true;
    1402           ShowLoc := Options and (1 shl moLocCodes) <> 0;
    1403           ShowDebug := pDebugMap >= 0;
    1404           ShowObjects := (CityOwner >= 0) or
    1405             (Options and (1 shl moBareTerrain) = 0);
    1406           ShowCityNames := ShowObjects and (CityOwner < 0) and
    1407             (Options and (1 shl moCityNames) <> 0);
    1408           ShowBorder := true;
    1409           ShowMyBorder := CityOwner < 0;
    1410           ShowGrWall := (CityOwner < 0) and
    1411             (Options and (1 shl moGreatWall) <> 0);
    1412           if ShowDebug then
    1413             Server(sGetDebugMap, me, pDebugMap, DebugMap)
    1414           else
    1415             DebugMap := nil;
    1416           with FOutput.Canvas do
    1417           begin
    1418             RealTop := y - ((Loc + 12345 * G.lx) div G.lx - 12345) * yyt;
    1419             RealBottom := y +
    1420               (G.ly - ((Loc + 12345 * G.lx) div G.lx - 12345) + 3) * yyt;
    1421             Brush.Color := EmptySpaceColor;
    1422             if RealTop > FTop then
    1423               FillRect(Rect(FLeft, FTop, FRight, RealTop))
    1424             else
    1425               RealTop := FTop;
    1426             if RealBottom < FBottom then
    1427               FillRect(Rect(FLeft, RealBottom, FRight, FBottom))
    1428             else
    1429               RealBottom := FBottom;
    1430             Brush.Color := $000000;
    1431             FillRect(Rect(FLeft, RealTop, FRight, RealBottom));
    1432             Brush.Style := bsClear;
    1433           end;
    1434 
    1435           for dy := 0 to ny + 1 do
    1436             if (Loc + dy * G.lx >= 0) and (Loc + (dy - 3) * G.lx < G.lx * G.ly)
    1437             then
    1438               for dx := 0 to nx do
    1439               begin
    1440                 ALoc := dLoc(Loc, dx - (dy + dx) and 1, dy - 2);
    1441                 BLoc := dLoc(Loc, dx - (dy + dx + 1) and 1, dy - 1);
    1442                 if (ALoc < 0) or (ALoc >= G.lx * G.ly) then
    1443                   ATer := PoleTile(ALoc) and fTerrain
    1444                 else
    1445                   ATer := MyMap[ALoc] and fTerrain;
    1446                 if (BLoc < 0) or (BLoc >= G.lx * G.ly) then
    1447                   BTer := PoleTile(BLoc) and fTerrain
    1448                 else
    1449                   BTer := MyMap[BLoc] and fTerrain;
    1450 
    1451                 if (ATer <> fUNKNOWN) or (BTer <> fUNKNOWN) then
    1452                   if ((ATer < fGrass) or (ATer = fUNKNOWN)) and
    1453                     ((BTer < fGrass) or (BTer = fUNKNOWN)) then
    1454                   begin
    1455                     if ATer = fUNKNOWN then
    1456                       Aix := 0
    1457                     else if IsShoreTile(ALoc) then
    1458                       if ATer = fOcean then
    1459                         Aix := -1
    1460                       else
    1461                         Aix := 1
    1462                     else
    1463                       Aix := ATer + 2;
    1464                     if BTer = fUNKNOWN then
    1465                       bix := 0
    1466                     else if IsShoreTile(BLoc) then
    1467                       if BTer = fOcean then
    1468                         bix := -1
    1469                       else
    1470                         bix := 1
    1471                     else
    1472                       bix := BTer + 2;
    1473                     if (Aix > 1) or (bix > 1) then
    1474                     begin
    1475                       if Aix = -1 then
    1476                         if bix = fOcean + 2 then
    1477                         begin
    1478                           Aix := 0;
    1479                           bix := 0
    1480                         end
    1481                         else
    1482                         begin
    1483                           Aix := 0;
    1484                           bix := 1
    1485                         end
    1486                       else if bix = -1 then
    1487                         if Aix = fOcean + 2 then
    1488                         begin
    1489                           Aix := 1;
    1490                           bix := 1
    1491                         end
    1492                         else
    1493                         begin
    1494                           Aix := 1;
    1495                           bix := 0
    1496                         end;
    1497                       BitBlt(OceanPatch, x + dx * xxt, y + dy * yyt, xxt, yyt,
    1498                         Aix * (xxt * 2) + (dx + dy + 1) and 1 * xxt,
    1499                         bix * yyt, SRCCOPY)
    1500                     end
    1501                   end
    1502                   else
    1503                   begin
    1504                     if ATer = fUNKNOWN then
    1505                       Aix := 0
    1506                     else if (ALoc >= 0) and (ALoc < G.lx * G.ly) and
    1507                       (MyMap[ALoc] and fDeadLands <> 0) then
    1508                       Aix := -2
    1509                     else if ATer = fOcean then
    1510                       Aix := -1
    1511                     else if ATer = fShore then
    1512                       Aix := 1
    1513                     else if ATer >= fForest then
    1514                       Aix := 8
    1515                     else
    1516                       Aix := ATer;
    1517                     if BTer = fUNKNOWN then
    1518                       bix := 0
    1519                     else if (BLoc >= 0) and (BLoc < G.lx * G.ly) and
    1520                       (MyMap[BLoc] and fDeadLands <> 0) then
    1521                       bix := -2
    1522                     else if BTer = fOcean then
    1523                       bix := -1
    1524                     else if BTer = fShore then
    1525                       bix := 1
    1526                     else if BTer >= fForest then
    1527                       bix := 8
    1528                     else
    1529                       bix := BTer;
    1530                     if (Aix = -2) and (bix = -2) then
    1531                     begin
    1532                       Aix := fDesert;
    1533                       bix := fDesert
    1534                     end
    1535                     else if Aix = -2 then
    1536                       if bix < 2 then
    1537                         Aix := 8
    1538                       else
    1539                         Aix := bix
    1540                     else if bix = -2 then
    1541                       if Aix < 2 then
    1542                         bix := 8
    1543                       else
    1544                         bix := Aix;
    1545                     if Aix = -1 then
    1546                       BitBlt(GrExt[HGrTerrain].Data, x + dx * xxt, y + dy * yyt,
    1547                         xxt, yyt, 1 + 6 * (xxt * 2 + 1) + (dx + dy + 1) and
    1548                         1 * xxt, 1 + yyt, SRCCOPY) // arctic <-> ocean
    1549                     else if bix = -1 then
    1550                       BitBlt(GrExt[HGrTerrain].Data, x + dx * xxt, y + dy * yyt,
    1551                         xxt, yyt, 1 + 6 * (xxt * 2 + 1) + xxt - (dx + dy + 1)
    1552                         and 1 * xxt, 1 + yyt * 2, SRCCOPY) // arctic <-> ocean
    1553                     else
    1554                       BitBlt(LandPatch, x + dx * xxt, y + dy * yyt, xxt, yyt,
    1555                         Aix * (xxt * 2) + (dx + dy + 1) and 1 * xxt,
    1556                         bix * yyt, SRCCOPY)
    1557                   end
    1558               end;
    1559 
    1560           OutDC := FOutput.Canvas.Handle;
    1561           DataDC := GrExt[HGrTerrain].Data.Canvas.Handle;
    1562           MaskDC := GrExt[HGrTerrain].Mask.Canvas.Handle;
    1563           for dy := -2 to ny + 1 do
    1564             for dx := -1 to nx do
    1565               if (dx + dy) and 1 = 0 then
    1566                 PaintShore(x + xxt * dx, y + yyt + yyt * dy, dLoc(Loc, dx, dy));
    1567           for dy := -2 to ny + 1 do
    1568             for dx := -1 to nx do
    1569               if (dx + dy) and 1 = 0 then
    1570                 PaintTileExtraTerrain(x + xxt * dx, y + yyt + yyt * dy,
    1571                   dLoc(Loc, dx, dy));
    1572           if CityOwner >= 0 then
    1573           begin
    1574             for dy := -2 to ny + 1 do
    1575               for dx := -2 to nx + 1 do
    1576                 if (dx + dy) and 1 = 0 then
    1577                 begin
    1578                   ALoc := dLoc(Loc, dx, dy);
    1579                   if Distance(ALoc, CityLoc) > 5 then
    1580                     PaintTileObjects(x + xxt * dx, y + yyt + yyt * dy, ALoc,
    1581                       CityLoc, CityOwner, UseBlink);
    1582                 end;
    1583             dx := ((CityLoc mod G.lx * 2 + CityLoc div G.lx and 1) -
    1584               ((Loc + 666 * G.lx) mod G.lx * 2 + (Loc + 666 * G.lx) div G.lx and
    1585               1) + 3 * G.lx) mod (2 * G.lx) - G.lx;
    1586             dy := CityLoc div G.lx - (Loc + 666 * G.lx) div G.lx + 666;
    1587             xm := x + (dx + 1) * xxt;
    1588             ym := y + (dy + 1) * yyt + yyt;
    1589             ShadeOutside(FLeft, FTop, FRight, FBottom, xm, ym);
    1590             CityGrid(xm, ym);
    1591             for dy := -2 to ny + 1 do
    1592               for dx := -2 to nx + 1 do
    1593                 if (dx + dy) and 1 = 0 then
    1594                 begin
    1595                   ALoc := dLoc(Loc, dx, dy);
    1596                   if Distance(ALoc, CityLoc) <= 5 then
    1597                     PaintTileObjects(x + xxt * dx, y + yyt + yyt * dy, ALoc,
    1598                       CityLoc, CityOwner, UseBlink);
    1599                 end;
    1600           end
    1601           else
    1602           begin
    1603             if ShowLoc or (Options and (1 shl moEditMode) <> 0) or
    1604               (Options and (1 shl moGrid) <> 0) then
    1605               PaintGrid(x, y, nx, ny);
    1606             for dy := -2 to ny + 1 do
    1607               for dx := -2 to nx + 1 do
    1608                 if (dx + dy) and 1 = 0 then
    1609                   PaintTileObjects(x + xxt * dx, y + yyt + yyt * dy,
    1610                     dLoc(Loc, dx, dy), CityLoc, CityOwner, UseBlink);
    1611           end;
    1612 
    1613           // frame(FOutput.Canvas,x+1,y+1,x+nx*33+33-2,y+ny*16+32-2,$FFFF,$FFFF);
    1614         end; { Paint }
    1615 
    1616         procedure TIsoMap.AttackBegin(const ShowMove: TShowMove);
    1617         begin
    1618           AttLoc := ShowMove.FromLoc;
    1619           DefLoc := dLoc(AttLoc, ShowMove.dx, ShowMove.dy);
    1620           DefHealth := -1;
    1621         end;
    1622 
    1623         procedure TIsoMap.AttackEffect(const ShowMove: TShowMove);
    1624         begin
    1625           DefHealth := ShowMove.EndHealthDef;
    1626         end;
    1627 
    1628         procedure TIsoMap.AttackEnd;
    1629         begin
    1630           AttLoc := -1;
    1631           DefLoc := -1;
    1632         end;
     1575  end
     1576  else
     1577  begin
     1578    if ShowLoc or (Options and (1 shl moEditMode) <> 0) or
     1579      (Options and (1 shl moGrid) <> 0) then
     1580      PaintGrid(x, y, nx, ny);
     1581    for dy := -2 to ny + 1 do
     1582      for dx := -2 to nx + 1 do
     1583        if (dx + dy) and 1 = 0 then
     1584          PaintTileObjects(x + xxt * dx, y + yyt + yyt * dy, dLoc(Loc, dx, dy),
     1585            CityLoc, CityOwner, UseBlink);
     1586  end;
     1587
     1588  // frame(FOutput.Canvas,x+1,y+1,x+nx*33+33-2,y+ny*16+32-2,$FFFF,$FFFF);
     1589end; { Paint }
     1590
     1591procedure TIsoMap.AttackBegin(const ShowMove: TShowMove);
     1592begin
     1593  AttLoc := ShowMove.FromLoc;
     1594  DefLoc := dLoc(AttLoc, ShowMove.dx, ShowMove.dy);
     1595  DefHealth := -1;
     1596end;
     1597
     1598procedure TIsoMap.AttackEffect(const ShowMove: TShowMove);
     1599begin
     1600  DefHealth := ShowMove.EndHealthDef;
     1601end;
     1602
     1603procedure TIsoMap.AttackEnd;
     1604begin
     1605  AttLoc := -1;
     1606  DefLoc := -1;
     1607end;
    16331608
    16341609initialization
  • trunk/LocalPlayer/Term.pas

    r29 r33  
    1 {$INCLUDE Switches.pas}
     1{$INCLUDE Switches.pas}
    22unit Term;
    33
     
    55
    66uses
    7   {$IFDEF Windows}
     7{$IFDEF Windows}
    88  Windows,
    9   {$ENDIF}
     9{$ENDIF}
    1010  Protocol, Tribes, PVSB, ClientTools, ScreenTools, BaseWin, Messg, ButtonBase,
    1111
    12   LCLIntf, LCLType, LMessages, Messages, SysUtils, Classes, Graphics, Controls, Forms, Menus,
     12  LCLIntf, LCLType, LMessages, Messages, SysUtils, Classes, Graphics, Controls,
     13  Forms, Menus,
    1314  ExtCtrls, dateutils, Platform,
    1415  ButtonA, ButtonB, ButtonC, EOTButton, Area;
     
    437438
    438439{$R *.lfm}
    439 {TODO {$R Res1.res}
     440{ TODO {$R Res1.res }
    440441
    441442const
     
    737738function CreateTribe(p: integer; FileName: string; Original: boolean): boolean;
    738739begin
    739   if not FileExists(LocalizedFilePath('Tribes' + DirectorySeparator + FileName + '.tribe.txt')) then
     740  if not FileExists(LocalizedFilePath('Tribes' + DirectorySeparator + FileName +
     741    '.tribe.txt')) then
    740742  begin
    741743    result := false;
     
    992994        if DraftDlg.ModalResult <> mrOK then
    993995          Tribe[me].ModelPicture[MyRO.nModel].HGr := 0
     996      end;
     997    until (ChosenResearch <> adMilitary) or (DraftDlg.ModalResult = mrOK);
     998
     999    if ChosenResearch = adMilitary then
     1000      InitMyModel(MyRO.nModel, true)
     1001    else if ChosenResearch = adFar then
     1002    begin
     1003      ModalSelectDlg.ShowNewContent(wmModal, kFarAdvance);
     1004      if ModalSelectDlg.result >= 0 then
     1005        if (ModalSelectDlg.result = adNone) or
     1006          (Server(sSetResearch - sExecute, me, ModalSelectDlg.result, nil^) <
     1007          rExecuted) then
     1008          MyData.FarTech := ModalSelectDlg.result
     1009        else
     1010        begin
     1011          ChosenResearch := ModalSelectDlg.result;
     1012          // can be researched immediately
     1013          MyData.FarTech := adNone
     1014        end;
     1015    end;
     1016  until ChosenResearch <> adFar;
     1017  if ChosenResearch = adNexus then
     1018    MyData.FarTech := adNexus
     1019  else
     1020    Server(sSetResearch, me, ChosenResearch, nil^);
     1021  ListDlg.TechChange;
     1022  result := true;
     1023end;
     1024
     1025(* ** client function handling ** *)
     1026
     1027function TMainScreen.DipCall(Command: integer): integer;
     1028var
     1029  i: integer;
     1030  IsTreatyDeal: boolean;
     1031begin
     1032  result := Server(Command, me, 0, nil^);
     1033  if result >= rExecuted then
     1034  begin
     1035    if Command and $FF0F = scContact then
     1036    begin
     1037      DipMem[me].pContact := Command shr 4 and $F;
     1038      NegoDlg.Initiate;
     1039      DipMem[me].DeliveredPrices := [];
     1040      DipMem[me].ReceivedPrices := [];
     1041    end;
     1042
     1043    DipMem[me].SentCommand := Command;
     1044    DipMem[me].FormerTreaty := MyRO.Treaty[DipMem[me].pContact];
     1045    if Command = scDipCancelTreaty then
     1046      Play('CANCELTREATY')
     1047    else if Command = scDipAccept then
     1048    begin // remember delivered and received prices
     1049      for i := 0 to ReceivedOffer.nDeliver - 1 do
     1050        include(DipMem[me].ReceivedPrices, ReceivedOffer.Price[i] shr 24);
     1051      for i := 0 to ReceivedOffer.nCost - 1 do
     1052        include(DipMem[me].DeliveredPrices,
     1053          ReceivedOffer.Price[ReceivedOffer.nDeliver + i] shr 24);
     1054      IsTreatyDeal := false;
     1055      for i := 0 to ReceivedOffer.nDeliver + ReceivedOffer.nCost - 1 do
     1056        if ReceivedOffer.Price[i] and opMask = opTreaty then
     1057          IsTreatyDeal := true;
     1058      if IsTreatyDeal then
     1059        Play('NEWTREATY')
     1060      else
     1061        Play('ACCEPTOFFER');
     1062    end;
     1063    CityDlg.CloseAction := None;
     1064    if G.RO[DipMem[me].pContact] <> nil then
     1065    begin // close windows for next player
     1066      for i := 0 to Screen.FormCount - 1 do
     1067        if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
     1068        then
     1069          Screen.Forms[i].Close;
     1070    end
     1071    else
     1072    begin
     1073      if CityDlg.Visible then
     1074        CityDlg.Close;
     1075      if UnitStatDlg.Visible then
     1076        UnitStatDlg.Close;
     1077    end
     1078  end
     1079end;
     1080
     1081function TMainScreen.OfferCall(var Offer: TOffer): integer;
     1082var
     1083  i: integer;
     1084begin
     1085  result := Server(scDipOffer, me, 0, Offer);
     1086  if result >= rExecuted then
     1087  begin
     1088    DipMem[me].SentCommand := scDipOffer;
     1089    DipMem[me].FormerTreaty := MyRO.Treaty[DipMem[me].pContact];
     1090    DipMem[me].SentOffer := Offer;
     1091    CityDlg.CloseAction := None;
     1092    if G.RO[DipMem[me].pContact] <> nil then
     1093    begin // close windows for next player
     1094      for i := 0 to Screen.FormCount - 1 do
     1095        if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
     1096        then
     1097          Screen.Forms[i].Close;
     1098    end
     1099    else
     1100    begin
     1101      if CityDlg.Visible then
     1102        CityDlg.Close;
     1103      if UnitStatDlg.Visible then
     1104        UnitStatDlg.Close;
     1105    end
     1106  end
     1107end;
     1108
     1109procedure TMainScreen.SetUnFocus(uix: integer);
     1110var
     1111  Loc0: integer;
     1112begin
     1113  assert(not((uix >= 0) and supervising));
     1114  if uix <> UnFocus then
     1115  begin
     1116    DestinationMarkON := false;
     1117    PaintDestination;
     1118    if uix >= 0 then
     1119      UnStartLoc := MyUn[uix].Loc;
     1120    BlinkON := false;
     1121    BlinkTime := -1;
     1122    if UnFocus >= 0 then
     1123    begin
     1124      Loc0 := MyUn[UnFocus].Loc;
     1125      if (uix < 0) or (Loc0 <> MyUn[uix].Loc) then
     1126      begin
     1127        UnFocus := -1;
     1128        PaintLoc(Loc0);
    9941129      end
    995       until (ChosenResearch <> adMilitary) or (DraftDlg.ModalResult = mrOK);
    996 
    997       if ChosenResearch = adMilitary then
    998         InitMyModel(MyRO.nModel, true)
    999       else if ChosenResearch = adFar then
    1000       begin
    1001         ModalSelectDlg.ShowNewContent(wmModal, kFarAdvance);
    1002         if ModalSelectDlg.result >= 0 then
    1003           if (ModalSelectDlg.result = adNone) or
    1004             (Server(sSetResearch - sExecute, me, ModalSelectDlg.result, nil^) <
    1005             rExecuted) then
    1006             MyData.FarTech := ModalSelectDlg.result
     1130    end;
     1131    UnFocus := uix;
     1132  end;
     1133  UnitInfoBtn.Visible := UnFocus >= 0;
     1134  UnitBtn.Visible := UnFocus >= 0;
     1135  CheckTerrainBtnVisible;
     1136end;
     1137
     1138procedure TMainScreen.CheckTerrainBtnVisible;
     1139var
     1140  Tile: integer;
     1141  mox: ^TModel;
     1142begin
     1143  if UnFocus >= 0 then
     1144  begin
     1145    mox := @MyModel[MyUn[UnFocus].mix];
     1146    Tile := MyMap[MyUn[UnFocus].Loc];
     1147    TerrainBtn.Visible := (Tile and fCity = 0) and (MyUn[UnFocus].Master < 0)
     1148      and ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves) and
     1149      (MyRO.Wonder[woPyramids].EffectiveOwner >= 0));
     1150  end
     1151  else
     1152    TerrainBtn.Visible := false;
     1153end;
     1154
     1155procedure TMainScreen.CheckMovieSpeedBtnState;
     1156begin
     1157  if GameMode = cMovie then
     1158  begin
     1159    MovieSpeed1Btn.Down := MovieSpeed = 1;
     1160    MovieSpeed1Btn.Visible := true;
     1161    MovieSpeed2Btn.Down := MovieSpeed = 2;
     1162    MovieSpeed2Btn.Visible := true;
     1163    MovieSpeed3Btn.Down := MovieSpeed = 3;
     1164    MovieSpeed3Btn.Visible := true;
     1165    MovieSpeed4Btn.Down := MovieSpeed = 4;
     1166    MovieSpeed4Btn.Visible := true;
     1167  end
     1168  else
     1169  begin
     1170    MovieSpeed1Btn.Visible := false;
     1171    MovieSpeed2Btn.Visible := false;
     1172    MovieSpeed3Btn.Visible := false;
     1173    MovieSpeed4Btn.Visible := false;
     1174  end
     1175end;
     1176
     1177procedure TMainScreen.SetMapOptions;
     1178begin
     1179  IsoEngine.Options := MapOptionChecked;
     1180  if ClientMode = cEditMap then
     1181    IsoEngine.Options := IsoEngine.Options or (1 shl moEditMode);
     1182  if mLocCodes.Checked then
     1183    IsoEngine.Options := IsoEngine.Options or (1 shl moLocCodes);
     1184end;
     1185
     1186procedure TMainScreen.UpdateViews(UpdateCityScreen: boolean);
     1187begin
     1188  SumCities(TaxSum, ScienceSum);
     1189  PanelPaint; // TopBar was enough!!!
     1190  ListDlg.EcoChange;
     1191  NatStatDlg.EcoChange;
     1192  if UpdateCityScreen then
     1193    CityDlg.SmartUpdateContent;
     1194end;
     1195
     1196procedure TMainScreen.SetAIName(p: integer; Name: string);
     1197begin
     1198  if Name = '' then
     1199  begin
     1200    if AILogo[p] <> nil then
     1201    begin
     1202      AILogo[p].free;
     1203      AILogo[p] := nil
     1204    end
     1205  end
     1206  else
     1207  begin
     1208    if AILogo[p] = nil then
     1209      AILogo[p] := TBitmap.Create;
     1210    if not LoadGraphicFile(AILogo[p], HomeDir + Name, gfNoError) then
     1211    begin
     1212      AILogo[p].free;
     1213      AILogo[p] := nil
     1214    end
     1215  end
     1216end;
     1217
     1218function TMainScreen.ContactRefused(p: integer; Item: String): boolean;
     1219// return whether treaty was cancelled
     1220var
     1221  s: string;
     1222begin
     1223  assert(MyRO.Treaty[p] >= trPeace);
     1224  s := Tribe[p].TPhrase(Item);
     1225  if MyRO.Turn < MyRO.LastCancelTreaty[p] + CancelTreatyTurns then
     1226  begin
     1227    SimpleMessage(s);
     1228    result := false;
     1229  end
     1230  else
     1231  begin
     1232    case MyRO.Treaty[p] of
     1233      trPeace:
     1234        s := s + ' ' + Phrases.Lookup('FRCANCELQUERY_PEACE');
     1235      trFriendlyContact:
     1236        s := s + ' ' + Phrases.Lookup('FRCANCELQUERY_FRIENDLY');
     1237      trAlliance:
     1238        s := s + ' ' + Phrases.Lookup('FRCANCELQUERY_ALLIANCE');
     1239    end;
     1240    result := SimpleQuery(mkYesNo, s, 'NEGO_REJECTED') = mrOK;
     1241    if result then
     1242    begin
     1243      Play('CANCELTREATY');
     1244      Server(sCancelTreaty, me, 0, nil^);
     1245      if MyRO.Treaty[p] = trNone then
     1246        CityOptimizer_BeginOfTurn;
     1247      // peace treaty was cancelled -- use formerly forbidden tiles
     1248      MapValid := false;
     1249      PaintAllMaps;
     1250    end
     1251  end
     1252end;
     1253
     1254procedure TMainScreen.RememberPeaceViolation;
     1255var
     1256  uix, p1: integer;
     1257begin
     1258  MyData.PeaceEvaHappened := 0;
     1259  for uix := 0 to MyRO.nUn - 1 do
     1260    with MyUn[uix] do
     1261      if Loc >= 0 then
     1262      begin
     1263        p1 := MyRO.Territory[Loc];
     1264        if (p1 <> me) and (p1 >= 0) and
     1265          (MyRO.Turn = MyRO.EvaStart[p1] + (PeaceEvaTurns - 1)) then
     1266          MyData.PeaceEvaHappened := MyData.PeaceEvaHappened or (1 shl p1);
     1267      end;
     1268end;
     1269
     1270procedure TMainScreen.Client(Command, NewPlayer: integer; var Data);
     1271
     1272  procedure GetTribeList;
     1273  var
     1274    SearchRec: TSearchRec;
     1275    Color: TColor;
     1276    Name: string;
     1277    ok: boolean;
     1278  begin
     1279    UnusedTribeFiles.Clear;
     1280    ok := FindFirst(DataDir + 'Localization' + DirectorySeparator + 'Tribes' +
     1281      DirectorySeparator + '*.tribe.txt', faArchive + faReadOnly,
     1282      SearchRec) = 0;
     1283    if not ok then
     1284    begin
     1285      FindClose(SearchRec);
     1286      ok := FindFirst(HomeDir + 'Tribes' + DirectorySeparator + '*.tribe.txt',
     1287        faArchive + faReadOnly, SearchRec) = 0;
     1288    end;
     1289    if ok then
     1290      repeat
     1291        SearchRec.Name := Copy(SearchRec.Name, 1, Length(SearchRec.Name) - 10);
     1292        if GetTribeInfo(SearchRec.Name, Name, Color) then
     1293          UnusedTribeFiles.AddObject(SearchRec.Name, TObject(Color));
     1294      until FindNext(SearchRec) <> 0;
     1295    FindClose(SearchRec);
     1296  end;
     1297
     1298  function ChooseUnusedTribe: integer;
     1299  var
     1300    i, j, ColorDistance, BestColorDistance, TestColorDistance,
     1301      CountBest: integer;
     1302  begin
     1303    assert(UnusedTribeFiles.Count > 0);
     1304    result := -1;
     1305    BestColorDistance := -1;
     1306    for j := 0 to UnusedTribeFiles.Count - 1 do
     1307    begin
     1308      ColorDistance := 250; // consider differences more than this infinite
     1309      for i := 0 to nPl - 1 do
     1310        if Tribe[i] <> nil then
     1311        begin
     1312          TestColorDistance := abs(integer(UnusedTribeFiles.Objects[j])
     1313            shr 16 and $FF - Tribe[i].Color shr 16 and $FF) +
     1314            abs(integer(UnusedTribeFiles.Objects[j]) shr 8 and
     1315            $FF - Tribe[i].Color shr 8 and $FF) * 3 +
     1316            abs(integer(UnusedTribeFiles.Objects[j]) and
     1317            $FF - Tribe[i].Color and $FF) * 2;
     1318          if TestColorDistance < ColorDistance then
     1319            ColorDistance := TestColorDistance
     1320        end;
     1321      if ColorDistance > BestColorDistance then
     1322      begin
     1323        CountBest := 0;
     1324        BestColorDistance := ColorDistance
     1325      end;
     1326      if ColorDistance = BestColorDistance then
     1327      begin
     1328        inc(CountBest);
     1329        if random(CountBest) = 0 then
     1330          result := j
     1331      end
     1332    end;
     1333  end;
     1334
     1335  procedure ShowEnemyShipChange(ShowShipChange: TShowShipChange);
     1336  var
     1337    i, TestCost, MostCost: integer;
     1338    Ship1Plus, Ship2Plus: boolean;
     1339  begin
     1340    with ShowShipChange, MessgExDlg do
     1341    begin
     1342      case Reason of
     1343        scrProduction:
     1344          begin
     1345            OpenSound := 'SHIP_BUILT';
     1346            MessgText := Tribe[Ship1Owner].TPhrase('SHIPBUILT');
     1347            IconKind := mikShip;
     1348            IconIndex := Ship1Owner;
     1349          end;
     1350
     1351        scrDestruction:
     1352          begin
     1353            OpenSound := 'SHIP_DESTROYED';
     1354            MessgText := Tribe[Ship1Owner].TPhrase('SHIPDESTROYED');
     1355            IconKind := mikImp;
     1356          end;
     1357
     1358        scrTrade:
     1359          begin
     1360            OpenSound := 'SHIP_TRADED';
     1361            Ship1Plus := false;
     1362            Ship2Plus := false;
     1363            for i := 0 to nShipPart - 1 do
     1364            begin
     1365              if Ship1Change[i] > 0 then
     1366                Ship1Plus := true;
     1367              if Ship2Change[i] > 0 then
     1368                Ship2Plus := true;
     1369            end;
     1370            if Ship1Plus and Ship2Plus then
     1371              MessgText := Tribe[Ship1Owner].TPhrase('SHIPBITRADE1') + ' ' +
     1372                Tribe[Ship2Owner].TPhrase('SHIPBITRADE2')
     1373            else if Ship1Plus then
     1374              MessgText := Tribe[Ship1Owner].TPhrase('SHIPUNITRADE1') + ' ' +
     1375                Tribe[Ship2Owner].TPhrase('SHIPUNITRADE2')
     1376            else // if Ship2Plus then
     1377              MessgText := Tribe[Ship2Owner].TPhrase('SHIPUNITRADE1') + ' ' +
     1378                Tribe[Ship1Owner].TPhrase('SHIPUNITRADE2');
     1379            IconKind := mikImp;
     1380          end;
     1381
     1382        scrCapture:
     1383          begin
     1384            OpenSound := 'SHIP_CAPTURED';
     1385            MessgText := Tribe[Ship2Owner].TPhrase('SHIPCAPTURE1') + ' ' +
     1386              Tribe[Ship1Owner].TPhrase('SHIPCAPTURE2');
     1387            IconKind := mikShip;
     1388            IconIndex := Ship2Owner;
     1389          end
     1390      end;
     1391
     1392      if IconKind = mikImp then
     1393      begin
     1394        MostCost := 0;
     1395        for i := 0 to nShipPart - 1 do
     1396        begin
     1397          TestCost := abs(Ship1Change[i]) * Imp[imShipComp + i].Cost;
     1398          if TestCost > MostCost then
     1399          begin
     1400            MostCost := TestCost;
     1401            IconIndex := imShipComp + i
     1402          end
     1403        end;
     1404      end;
     1405
     1406      Kind := mkOk;
     1407      ShowModal;
     1408    end;
     1409  end;
     1410
     1411  procedure InitModule;
     1412  var
     1413    x, y, i, j, Domain: integer;
     1414  begin
     1415    { search icons for advances: }
     1416    for i := 0 to nAdv - 1 do
     1417      if i in FutureTech then
     1418        AdvIcon[i] := 96 + i - futResearchTechnology
     1419      else
     1420      begin
     1421        AdvIcon[i] := -1;
     1422        for Domain := 0 to nDomains - 1 do
     1423          for j := 0 to nUpgrade - 1 do
     1424            if upgrade[Domain, j].Preq = i then
     1425              if AdvIcon[i] >= 0 then
     1426                AdvIcon[i] := 85
     1427              else
     1428                AdvIcon[i] := 86 + Domain;
     1429        for j := 0 to nFeature - 1 do
     1430          if Feature[j].Preq = i then
     1431            for Domain := 0 to nDomains - 1 do
     1432              if 1 shl Domain and Feature[j].Domains <> 0 then
     1433                if (AdvIcon[i] >= 0) and (AdvIcon[i] <> 86 + Domain) then
     1434                  AdvIcon[i] := 85
     1435                else
     1436                  AdvIcon[i] := 86 + Domain;
     1437        for j := 28 to nImp - 1 do
     1438          if Imp[j].Preq = i then
     1439            AdvIcon[i] := j;
     1440        for j := 28 to nImp - 1 do
     1441          if (Imp[j].Preq = i) and (Imp[j].Kind <> ikCommon) then
     1442            AdvIcon[i] := j;
     1443        for j := 0 to nJob - 1 do
     1444          if i = JobPreq[j] then
     1445            AdvIcon[i] := 84;
     1446        for j := 0 to 27 do
     1447          if Imp[j].Preq = i then
     1448            AdvIcon[i] := j;
     1449        if AdvIcon[i] < 0 then
     1450          if AdvValue[i] < 1000 then
     1451            AdvIcon[i] := -7
     1452          else
     1453            AdvIcon[i] := 24 + AdvValue[i] div 1000;
     1454        for j := 2 to nGov - 1 do
     1455          if GovPreq[j] = i then
     1456            AdvIcon[i] := j - 8;
     1457      end;
     1458    AdvIcon[adConscription] := 86 + dGround;
     1459
     1460    UnusedTribeFiles := tstringlist.Create;
     1461    UnusedTribeFiles.Sorted := true;
     1462    TribeNames := tstringlist.Create;
     1463
     1464    for x := 0 to 11 do
     1465      for y := 0 to 1 do
     1466        MiniColors[x, y] := GrExt[HGrSystem].Data.Canvas.Pixels[66 + x, 67 + y];
     1467    IsoEngine.Init(InitEnemyModel);
     1468    if not IsoEngine.ApplyTileSize(xxt, yyt) and ((xxt <> 48) or (yyt <> 24))
     1469    then
     1470      ApplyTileSize(48, 24);
     1471    // non-default tile size is missing a file, switch to default
     1472    MainMap := TIsoMap.Create;
     1473    MainMap.SetOutput(offscreen);
     1474
     1475    HGrStdUnits := LoadGraphicSet('StdUnits');
     1476    SmallImp := TBitmap.Create;
     1477    SmallImp.PixelFormat := pf24bit;
     1478    InitSmallImp;
     1479    SoundPreloadDone := 0;
     1480    StartRunning := false;
     1481    StayOnTop_Ensured := false;
     1482
     1483    CreatePVSB(sb, Handle, 100 - 200, 122, 100 + MidPanelHeight - 16 - 200);
     1484  end; { InitModule }
     1485
     1486// sound blocks for preload
     1487const
     1488  sbStart = $01;
     1489  sbWonder = $02;
     1490  sbScience = $04;
     1491  sbContact = $08;
     1492  sbTurn = $10;
     1493  sbAll = $FF;
     1494
     1495  procedure SoundPreload(Check: integer);
     1496  const
     1497    nStartBlock = 27;
     1498    StartBlock: array [0 .. nStartBlock - 1] of string = ('INVALID', 'TURNEND',
     1499      'DISBAND', 'CHEAT', 'MSG_DEFAULT', 'WARNING_DISORDER', 'WARNING_FAMINE',
     1500      'WARNING_LOWSUPPORT', 'WARNING_LOWFUNDS', 'MOVE_MOUNTAIN', 'MOVE_LOAD',
     1501      'MOVE_UNLOAD', 'MOVE_DIE', 'NOMOVE_TIME', 'NOMOVE_DOMAIN',
     1502      'NOMOVE_DEFAULT', 'CITY_SELLIMP', 'CITY_REBUILDIMP', 'CITY_BUYPROJECT',
     1503      'CITY_UTILIZE', 'NEWMODEL_0', 'NEWADVANCE_0', 'AGE_0', 'REVOLUTION',
     1504      'NEWGOV', 'CITY_INVALIDTYPE', 'MSG_GAMEOVER');
     1505
     1506    nWonderBlock = 6;
     1507    WonderBlock: array [0 .. nWonderBlock - 1] of string = ('WONDER_BUILT',
     1508      'WONDER_CAPTURED', 'WONDER_EXPIRED', 'WONDER_DESTROYED', 'MSG_COLDWAR',
     1509      'NEWADVANCE_GRLIB');
     1510
     1511    nScienceBlock = 17;
     1512    ScienceBlock: array [0 .. nScienceBlock - 1] of string = ('MOVE_PARACHUTE',
     1513      'MOVE_PLANESTART', 'MOVE_PLANELANDING', 'MOVE_COVERT', 'NEWMODEL_1',
     1514      'NEWMODEL_2', 'NEWMODEL_3', 'NEWADVANCE_1', 'NEWADVANCE_2',
     1515      'NEWADVANCE_3', 'AGE_1', 'AGE_2', 'AGE_3', 'SHIP_BUILT', 'SHIP_TRADED',
     1516      'SHIP_CAPTURED', 'SHIP_DESTROYED');
     1517
     1518    nContactBlock = 20;
     1519    ContactBlock: array [0 .. nContactBlock - 1] of string = ('NEWTREATY',
     1520      'CANCELTREATY', 'ACCEPTOFFER', 'MSG_WITHDRAW', 'MSG_BANKRUPT',
     1521      'CONTACT_0', 'CONTACT_1', 'CONTACT_2', 'CONTACT_3', 'CONTACT_4',
     1522      'CONTACT_5', 'CONTACT_5', 'CONTACT_6', 'NEGO_REJECTED', 'MOVE_CAPTURE',
     1523      'MOVE_EXPEL', 'NOMOVE_TREATY', 'NOMOVE_ZOC', 'NOMOVE_SUBMARINE',
     1524      'NOMOVE_STEALTH');
     1525
     1526  var
     1527    i, cix, mix: integer;
     1528    need: boolean;
     1529    mi: TModelInfo;
     1530  begin
     1531    if Check and sbStart and not SoundPreloadDone <> 0 then
     1532    begin
     1533      for i := 0 to nStartBlock - 1 do
     1534        PreparePlay(StartBlock[i]);
     1535      SoundPreloadDone := SoundPreloadDone or sbStart;
     1536    end;
     1537    if Check and sbWonder and not SoundPreloadDone <> 0 then
     1538    begin
     1539      need := false;
     1540      for i := 0 to 27 do
     1541        if MyRO.Wonder[i].CityID <> -1 then
     1542          need := true;
     1543      if need then
     1544      begin
     1545        for i := 0 to nWonderBlock - 1 do
     1546          PreparePlay(WonderBlock[i]);
     1547        SoundPreloadDone := SoundPreloadDone or sbWonder;
     1548      end;
     1549    end;
     1550    if (Check and sbScience and not SoundPreloadDone <> 0) and
     1551      (MyRO.Tech[adScience] >= tsApplicable) then
     1552    begin
     1553      for i := 0 to nScienceBlock - 1 do
     1554        PreparePlay(ScienceBlock[i]);
     1555      SoundPreloadDone := SoundPreloadDone or sbScience;
     1556    end;
     1557    if (Check and sbContact and not SoundPreloadDone <> 0) and
     1558      (MyRO.nEnemyModel + MyRO.nEnemyCity > 0) then
     1559    begin
     1560      for i := 0 to nContactBlock - 1 do
     1561        PreparePlay(ContactBlock[i]);
     1562      SoundPreloadDone := SoundPreloadDone or sbContact;
     1563    end;
     1564    if Check and sbTurn <> 0 then
     1565    begin
     1566      if MyRO.Happened and phShipComplete <> 0 then
     1567        PreparePlay('MSG_YOUWIN');
     1568      if MyData.ToldAlive <> MyRO.Alive then
     1569        PreparePlay('MSG_EXTINCT');
     1570      for cix := 0 to MyRO.nCity - 1 do
     1571        with MyCity[cix] do
     1572          if (Loc >= 0) and (Flags and CityRepMask <> 0) then
     1573            for i := 0 to 12 do
     1574              if 1 shl i and Flags and CityRepMask <> 0 then
     1575                PreparePlay(CityEventSoundItem[i]);
     1576      for mix := 0 to MyRO.nModel - 1 do
     1577        with MyModel[mix] do
     1578          if Attack > 0 then
     1579          begin
     1580            MakeModelInfo(me, mix, MyModel[mix], mi);
     1581            PreparePlay(AttackSound(ModelCode(mi)));
     1582          end
     1583    end
     1584  end;
     1585
     1586  procedure InitTurn(p: integer);
     1587  const
     1588    nAdvBookIcon = 16;
     1589    AdvBookIcon: array [0 .. nAdvBookIcon - 1] of record Adv,
     1590      Icon: integer end = ((Adv: adPolyTheism; Icon: woZeus),
     1591      (Adv: adBronzeWorking; Icon: woColossus), (Adv: adMapMaking;
     1592      Icon: woLighthouse), (Adv: adPoetry; Icon: imTheater), (Adv: adMonotheism;
     1593      Icon: woMich), (Adv: adPhilosophy; Icon: woLeo), (Adv: adTheoryOfGravity;
     1594      Icon: woNewton), (Adv: adSteel; Icon: woEiffel), (Adv: adDemocracy;
     1595      Icon: woLiberty), (Adv: adAutomobile; Icon: imHighways),
     1596      (Adv: adSanitation; Icon: imSewer), (Adv: adElectronics; Icon: woHoover),
     1597      (Adv: adNuclearFission; Icon: woManhattan), (Adv: adRecycling;
     1598      Icon: imRecycling), (Adv: adComputers; Icon: imResLab),
     1599      (Adv: adSpaceFlight; Icon: woMIR));
     1600  var
     1601    Domain, p1, i, ad, uix, cix, MoveOptions, MoveResult, Loc1, Dist,
     1602      NewAgeCenterTo, Bankrupt, ShipMore, Winners, NewGovAvailable, dx,
     1603      dy: integer;
     1604    MoveAdviceData: TMoveAdviceData;
     1605    Picture: TModelPictureInfo;
     1606    s, Item, Item2: string;
     1607    UpdatePanel, OwnWonder, ok, Stop, ShowCityList, WondersOnly,
     1608      AllowCityScreen: boolean;
     1609  begin
     1610    if IsMultiPlayerGame and (p <> me) then
     1611    begin
     1612      UnitInfoBtn.Visible := false;
     1613      UnitBtn.Visible := false;
     1614      TerrainBtn.Visible := false;
     1615      EOT.Visible := false;
     1616    end;
     1617    if IsMultiPlayerGame and (p <> me) and
     1618      (G.RO[0].Happened and phShipComplete = 0) then
     1619    begin // inter player screen
     1620      for i := 0 to ControlCount - 1 do
     1621        if Controls[i] is TButtonC then
     1622          Controls[i].Visible := false;
     1623      me := -1;
     1624      SetMainTextureByAge(-1);
     1625      with Panel.Canvas do
     1626      begin
     1627        Brush.Color := $000000;
     1628        FillRect(Rect(0, 0, Panel.width, Panel.height));
     1629        Brush.Style := bsClear;
     1630      end;
     1631      with TopBar.Canvas do
     1632      begin
     1633        Brush.Color := $000000;
     1634        FillRect(Rect(0, 0, TopBar.width, TopBar.height));
     1635        Brush.Style := bsClear;
     1636      end;
     1637      Invalidate;
     1638
     1639      s := TurnToString(G.RO[0].Turn);
     1640      if supervising then
     1641        SimpleMessage(Format(Phrases.Lookup('SUPERTURN'), [s]))
     1642      else
     1643        SimpleMessage(Format(Tribe[NewPlayer].TPhrase('TURN'), [s]));
     1644    end;
     1645    for i := 0 to ControlCount - 1 do
     1646      if Controls[i] is TButtonC then
     1647        Controls[i].Visible := true;
     1648
     1649    ItsMeAgain(p);
     1650    MyData := G.RO[p].Data;
     1651    if not supervising then
     1652      SoundPreload(sbAll);
     1653    if (me = 0) and ((MyRO.Turn = 0) or (ClientMode = cResume)) then
     1654      Invalidate; // colorize empty space
     1655
     1656    if not supervising then
     1657    begin
     1658
     1659      { if MyRO.Happened and phGameEnd<>0 then
     1660        begin
     1661        Age:=3;
     1662        SetMainTextureByAge(-1);
     1663        end
     1664        else }
     1665      begin
     1666        Age := GetAge(me);
     1667        if SetMainTextureByAge(Age) then
     1668          EOT.Invalidate; // has visible background parts in its bounds
     1669      end;
     1670      // age:=MyRO.Turn mod 4; //!!!
     1671      if ClientMode = cMovieTurn then
     1672        EOT.ButtonIndex := eotCancel
     1673      else if ClientMode < scContact then
     1674        EOT.ButtonIndex := eotGray
     1675      else
     1676        EOT.ButtonIndex := eotBackToNego;
     1677    end
     1678    else
     1679    begin
     1680      Age := 0;
     1681      SetMainTextureByAge(-1);
     1682      if ClientMode = cMovieTurn then
     1683        EOT.ButtonIndex := eotCancel
     1684      else
     1685        EOT.ButtonIndex := eotBlinkOn;
     1686    end;
     1687    InitCityMark(MainTexture);
     1688    CityDlg.CheckAge;
     1689    NatStatDlg.CheckAge;
     1690    UnitStatDlg.CheckAge;
     1691    HelpDlg.Difficulty := G.Difficulty[me];
     1692
     1693    UnFocus := -1;
     1694    MarkCityLoc := -1;
     1695    BlinkON := false;
     1696    BlinkTime := -1;
     1697    Tracking := false;
     1698    TurnComplete := false;
     1699
     1700    if (ToldSlavery < 0) or
     1701      ((ToldSlavery = 1) <> (MyRO.Wonder[woPyramids].EffectiveOwner >= 0)) then
     1702    begin
     1703      if MyRO.Wonder[woPyramids].EffectiveOwner >= 0 then
     1704        ToldSlavery := 1
     1705      else
     1706        ToldSlavery := 0;
     1707      for p1 := 0 to nPl - 1 do
     1708        if (Tribe[p1] <> nil) and (Tribe[p1].mixSlaves >= 0) then
     1709          with Picture do
     1710          begin // replace unit picture
     1711            mix := Tribe[p1].mixSlaves;
     1712            if ToldSlavery = 1 then
     1713              pix := pixSlaves
     1714            else
     1715              pix := pixNoSlaves;
     1716            Hash := 0;
     1717            GrName := 'StdUnits';
     1718            Tribe[p1].SetModelPicture(Picture, true);
     1719          end
     1720    end;
     1721
     1722    if not supervising and (ClientMode = cTurn) then
     1723    begin
     1724      for cix := 0 to MyRO.nCity - 1 do
     1725        if (MyCity[cix].Loc >= 0) and
     1726          ((MyRO.Turn = 0) or (MyCity[cix].Flags and chFounded <> 0)) then
     1727          MyCity[cix].Status := MyCity[cix].Status and
     1728            not csResourceWeightsMask or (3 shl 4);
     1729      // new city, set to maximum growth
     1730    end;
     1731    if (ClientMode = cTurn) or (ClientMode = cContinue) then
     1732      CityOptimizer_BeginOfTurn; // maybe peace was made or has ended
     1733    SumCities(TaxSum, ScienceSum);
     1734
     1735    if ClientMode = cMovieTurn then
     1736    begin
     1737      UnitInfoBtn.Visible := false;
     1738      UnitBtn.Visible := false;
     1739      TerrainBtn.Visible := false;
     1740      EOT.Hint := Phrases.Lookup('BTN_STOP');
     1741      EOT.Visible := true;
     1742    end
     1743    else if ClientMode < scContact then
     1744    begin
     1745      UnitInfoBtn.Visible := UnFocus >= 0;
     1746      UnitBtn.Visible := UnFocus >= 0;
     1747      CheckTerrainBtnVisible;
     1748      TurnComplete := supervising;
     1749      EOT.Hint := Phrases.Lookup('BTN_ENDTURN');
     1750      EOT.Visible := Server(sTurn - sExecute, me, 0, nil^) >= rExecuted;
     1751    end
     1752    else
     1753    begin
     1754      UnitInfoBtn.Visible := false;
     1755      UnitBtn.Visible := false;
     1756      TerrainBtn.Visible := false;
     1757      EOT.Hint := Phrases.Lookup('BTN_NEGO');
     1758      EOT.Visible := true;
     1759    end;
     1760    SetTroopLoc(-1);
     1761    MapValid := false;
     1762    NewAgeCenterTo := 0;
     1763    if ((MyRO.Turn = 0) and not supervising or IsMultiPlayerGame or
     1764      (ClientMode = cResume)) and (MyRO.nCity > 0) then
     1765    begin
     1766      Loc1 := MyCity[0].Loc;
     1767      if (ClientMode = cTurn) and (MyRO.Turn = 0) then
     1768      begin // move city out of center to not be covered by welcome screen
     1769        dx := MapWidth div (xxt * 5);
     1770        if dx > 5 then
     1771          dx := 5;
     1772        dy := MapHeight div (yyt * 5);
     1773        if dy > 5 then
     1774          dy := 5;
     1775        if Loc1 >= G.lx * G.ly div 2 then
     1776        begin
     1777          NewAgeCenterTo := -1;
     1778          Loc1 := dLoc(Loc1, -dx, -dy)
     1779        end
     1780        else
     1781        begin
     1782          NewAgeCenterTo := 1;
     1783          Loc1 := dLoc(Loc1, -dx, dy);
     1784        end
     1785      end;
     1786      Centre(Loc1)
     1787    end;
     1788
     1789    for i := 0 to Screen.FormCount - 1 do
     1790      if Screen.Forms[i] is TBufferedDrawDlg then
     1791        Screen.Forms[i].Enabled := true;
     1792
     1793    if ClientMode <> cResume then
     1794    begin
     1795      PaintAll;
     1796      if (MyRO.Happened and phChangeGov <> 0) and (MyRO.NatBuilt[imPalace] > 0)
     1797      then
     1798        ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, imPalace,
     1799          gAnarchy { , GameMode<>cMovie } );
     1800      // first turn after anarchy -- don't show despotism palace!
     1801      Update;
     1802      for i := 0 to Screen.FormCount - 1 do
     1803        if (Screen.Forms[i].Visible) and (Screen.Forms[i] is TBufferedDrawDlg)
     1804        then
     1805        begin
     1806          if @Screen.Forms[i].OnShow <> nil then
     1807            Screen.Forms[i].OnShow(nil);
     1808          Screen.Forms[i].Invalidate;
     1809          Screen.Forms[i].Update;
     1810        end;
     1811
     1812      if MyRO.Happened and phGameEnd <> 0 then
     1813        with MessgExDlg do
     1814        begin // game ended
     1815          if MyRO.Happened and phExtinct <> 0 then
     1816          begin
     1817            OpenSound := 'MSG_GAMEOVER';
     1818            MessgText := Tribe[me].TPhrase('GAMEOVER');
     1819            IconKind := mikBigIcon;
     1820            IconIndex := 8;
     1821          end
     1822          else if MyRO.Happened and phShipComplete <> 0 then
     1823          begin
     1824            Winners := 0;
     1825            for p1 := 0 to nPl - 1 do
     1826              if 1 shl p1 and MyRO.Alive <> 0 then
     1827              begin
     1828                Winners := Winners or 1 shl p1;
     1829                for i := 0 to nShipPart - 1 do
     1830                  if MyRO.Ship[p1].Parts[i] < ShipNeed[i] then
     1831                    Winners := Winners and not(1 shl p1);
     1832              end;
     1833            assert(Winners <> 0);
     1834            if Winners and (1 shl me) <> 0 then
     1835            begin
     1836              s := '';
     1837              for p1 := 0 to nPl - 1 do
     1838                if (p1 <> me) and (1 shl p1 and Winners <> 0) then
     1839                  if s = '' then
     1840                    s := Tribe[p1].TPhrase('SHORTNAME')
     1841                  else
     1842                    s := Format(Phrases.Lookup('SHAREDWIN_CONCAT'),
     1843                      [s, Tribe[p1].TPhrase('SHORTNAME')]);
     1844
     1845              OpenSound := 'MSG_YOUWIN';
     1846              MessgText := Tribe[me].TPhrase('MYSPACESHIP');
     1847              if s <> '' then
     1848                MessgText := MessgText + '\' +
     1849                  Format(Phrases.Lookup('SHAREDWIN'), [s]);
     1850              IconKind := mikBigIcon;
     1851              IconIndex := 9;
     1852            end
     1853            else
     1854            begin
     1855              assert(me = 0);
     1856              OpenSound := 'MSG_GAMEOVER';
     1857              MessgText := '';
     1858              for p1 := 0 to nPl - 1 do
     1859                if Winners and (1 shl p1) <> 0 then
     1860                  MessgText := MessgText + Tribe[p1].TPhrase('SPACESHIP1');
     1861              MessgText := MessgText + '\' + Phrases.Lookup('SPACESHIP2');
     1862              IconKind := mikEnemyShipComplete;
     1863            end
     1864          end
     1865          else { if MyRO.Happened and fTimeUp<>0 then }
     1866          begin
     1867            assert(me = 0);
     1868            OpenSound := 'MSG_GAMEOVER';
     1869            if not supervising then
     1870              MessgText := Tribe[me].TPhrase('TIMEUP')
     1871            else
     1872              MessgText := Phrases.Lookup('TIMEUPSUPER');
     1873            IconKind := mikImp;
     1874            IconIndex := 22;
     1875          end;
     1876          Kind := mkOk;
     1877          ShowModal;
     1878          if MyRO.Happened and phExtinct = 0 then
     1879          begin
     1880            p1 := 0;
     1881            while (p1 < nPl - 1) and (Winners and (1 shl p1) = 0) do
     1882              inc(p1);
     1883            if MyRO.Happened and phShipComplete = 0 then
     1884              DiaDlg.ShowNewContent_Charts(wmModal);
     1885          end;
     1886          TurnComplete := true;
     1887          exit;
     1888        end;
     1889      if not supervising and (1 shl me and MyRO.Alive = 0) then
     1890      begin
     1891        TurnComplete := true;
     1892        exit;
     1893      end;
     1894
     1895      if (ClientMode = cContinue) and
     1896        (DipMem[me].SentCommand and $FF0F = scContact) then
     1897        // contact was refused
     1898        if MyRO.Treaty[DipMem[me].pContact] >= trPeace then
     1899          ContactRefused(DipMem[me].pContact, 'FRREJECTED')
     1900        else
     1901          SoundMessage(Tribe[DipMem[me].pContact].TPhrase('FRREJECTED'),
     1902            'NEGO_REJECTED');
     1903
     1904      if not supervising and (Age > MyData.ToldAge) and
     1905        ((Age > 0) or (ClientMode <> cMovieTurn)) then
     1906        with MessgExDlg do
     1907        begin
     1908          if Age = 0 then
     1909          begin
     1910            if Phrases2FallenBackToEnglish then
     1911            begin
     1912              s := Tribe[me].TPhrase('AGE0');
     1913              MessgText :=
     1914                Format(s, [TurnToString(MyRO.Turn), CityName(MyCity[0].ID)])
     1915            end
     1916            else
     1917            begin
     1918              s := Tribe[me].TString(Phrases2.Lookup('AGE0'));
     1919              MessgText := Format(s, [TurnToString(MyRO.Turn)]);
     1920            end
     1921          end
    10071922          else
    10081923          begin
    1009             ChosenResearch := ModalSelectDlg.result;
    1010             // can be researched immediately
    1011             MyData.FarTech := adNone
     1924            s := Tribe[me].TPhrase('AGE' + char(48 + Age));
     1925            MessgText := Format(s, [TurnToString(MyRO.Turn)]);
     1926          end;
     1927          IconKind := mikAge;
     1928          IconIndex := Age;
     1929          { if age=0 then } Kind := mkOk
     1930          { else begin Kind:=mkOkHelp; HelpKind:=hkAdv; HelpNo:=AgePreq[age]; end };
     1931          CenterTo := NewAgeCenterTo;
     1932          OpenSound := 'AGE_' + char(48 + Age);
     1933          ShowModal;
     1934          MyData.ToldAge := Age;
     1935          if Age > 0 then
     1936            MyData.ToldTech[AgePreq[Age]] := MyRO.Tech[AgePreq[Age]];
     1937        end;
     1938
     1939      if MyData.ToldAlive <> MyRO.Alive then
     1940      begin
     1941        for p1 := 0 to nPl - 1 do
     1942          if (MyData.ToldAlive - MyRO.Alive) and (1 shl p1) <> 0 then
     1943            with MessgExDlg do
     1944            begin
     1945              OpenSound := 'MSG_EXTINCT';
     1946              s := Tribe[p1].TPhrase('EXTINCT');
     1947              MessgText := Format(s, [TurnToString(MyRO.Turn)]);
     1948              if MyRO.Alive = 1 shl me then
     1949                MessgText := MessgText + Phrases.Lookup('EXTINCTALL');
     1950              Kind := mkOk;
     1951              IconKind := mikImp;
     1952              IconIndex := 21;
     1953              ShowModal;
     1954            end;
     1955        if (ClientMode <> cMovieTurn) and not supervising then
     1956          DiaDlg.ShowNewContent_Charts(wmModal);
     1957      end;
     1958
     1959      // tell changes of own credibility
     1960      if not supervising then
     1961      begin
     1962        if RoughCredibility(MyRO.Credibility) <>
     1963          RoughCredibility(MyData.ToldOwnCredibility) then
     1964        begin
     1965          if RoughCredibility(MyRO.Credibility) >
     1966            RoughCredibility(MyData.ToldOwnCredibility) then
     1967            s := Phrases.Lookup('CREDUP')
     1968          else
     1969            s := Phrases.Lookup('CREDDOWN');
     1970          TribeMessage(me, Format(s, [Phrases.Lookup('CREDIBILITY',
     1971            RoughCredibility(MyRO.Credibility))]), '');
     1972        end;
     1973        MyData.ToldOwnCredibility := MyRO.Credibility;
     1974      end;
     1975
     1976      for i := 0 to 27 do
     1977      begin
     1978        OwnWonder := false;
     1979        for cix := 0 to MyRO.nCity - 1 do
     1980          if (MyCity[cix].Loc >= 0) and (MyCity[cix].ID = MyRO.Wonder[i].CityID)
     1981          then
     1982            OwnWonder := true;
     1983        if MyRO.Wonder[i].CityID <> MyData.ToldWonders[i].CityID then
     1984        begin
     1985          if MyRO.Wonder[i].CityID = -2 then
     1986            with MessgExDlg do
     1987            begin { tell about destroyed wonders }
     1988              OpenSound := 'WONDER_DESTROYED';
     1989              MessgText := Format(Phrases.Lookup('WONDERDEST'),
     1990                [Phrases.Lookup('IMPROVEMENTS', i)]);
     1991              Kind := mkOkHelp;
     1992              HelpKind := hkImp;
     1993              HelpNo := i;
     1994              IconKind := mikImp;
     1995              IconIndex := i;
     1996              ShowModal;
     1997            end
     1998          else
     1999          begin
     2000            if i = woManhattan then
     2001              if MyRO.Wonder[i].EffectiveOwner > me then
     2002                MyData.ColdWarStart := MyRO.Turn - 1
     2003              else
     2004                MyData.ColdWarStart := MyRO.Turn;
     2005            if not OwnWonder then
     2006              with MessgExDlg do
     2007              begin { tell about newly built wonders }
     2008                if i = woManhattan then
     2009                begin
     2010                  OpenSound := 'MSG_COLDWAR';
     2011                  s := Tribe[MyRO.Wonder[i].EffectiveOwner].TPhrase('COLDWAR')
     2012                end
     2013                else if MyRO.Wonder[i].EffectiveOwner >= 0 then
     2014                begin
     2015                  OpenSound := 'WONDER_BUILT';
     2016                  s := Tribe[MyRO.Wonder[i].EffectiveOwner]
     2017                    .TPhrase('WONDERBUILT')
     2018                end
     2019                else
     2020                begin
     2021                  OpenSound := 'MSG_DEFAULT';
     2022                  s := Phrases.Lookup('WONDERBUILTEXP');
     2023                  // already expired when built
     2024                end;
     2025                MessgText := Format(s, [Phrases.Lookup('IMPROVEMENTS', i),
     2026                  CityName(MyRO.Wonder[i].CityID)]);
     2027                Kind := mkOkHelp;
     2028                HelpKind := hkImp;
     2029                HelpNo := i;
     2030                IconKind := mikImp;
     2031                IconIndex := i;
     2032                ShowModal;
     2033              end
    10122034          end
    1013       end;
    1014     until ChosenResearch <> adFar;
    1015     if ChosenResearch = adNexus then
    1016       MyData.FarTech := adNexus
     2035        end
     2036        else if (MyRO.Wonder[i].EffectiveOwner <> MyData.ToldWonders[i]
     2037          .EffectiveOwner) and (MyRO.Wonder[i].CityID > -2) then
     2038          if MyRO.Wonder[i].EffectiveOwner < 0 then
     2039          begin
     2040            if i <> woMIR then
     2041              with MessgExDlg do
     2042              begin { tell about expired wonders }
     2043                OpenSound := 'WONDER_EXPIRED';
     2044                MessgText := Format(Phrases.Lookup('WONDEREXP'),
     2045                  [Phrases.Lookup('IMPROVEMENTS', i),
     2046                  CityName(MyRO.Wonder[i].CityID)]);
     2047                Kind := mkOkHelp;
     2048                HelpKind := hkImp;
     2049                HelpNo := i;
     2050                IconKind := mikImp;
     2051                IconIndex := i;
     2052                ShowModal;
     2053              end
     2054          end
     2055          else if (MyData.ToldWonders[i].EffectiveOwner >= 0) and not OwnWonder
     2056          then
     2057            with MessgExDlg do
     2058            begin { tell about capture of wonders }
     2059              OpenSound := 'WONDER_CAPTURED';
     2060              s := Tribe[MyRO.Wonder[i].EffectiveOwner].TPhrase('WONDERCAPT');
     2061              MessgText := Format(s, [Phrases.Lookup('IMPROVEMENTS', i),
     2062                CityName(MyRO.Wonder[i].CityID)]);
     2063              Kind := mkOkHelp;
     2064              HelpKind := hkImp;
     2065              HelpNo := i;
     2066              IconKind := mikImp;
     2067              IconIndex := i;
     2068              ShowModal;
     2069            end;
     2070      end;
     2071
     2072      if MyRO.Turn = MyData.ColdWarStart + ColdWarTurns then
     2073      begin
     2074        SoundMessageEx(Phrases.Lookup('COLDWAREND'), 'MSG_DEFAULT');
     2075        MyData.ColdWarStart := -ColdWarTurns - 1
     2076      end;
     2077
     2078      TellNewModels;
     2079    end; // ClientMode<>cResume
     2080    MyData.ToldAlive := MyRO.Alive;
     2081    move(MyRO.Wonder, MyData.ToldWonders, SizeOf(MyData.ToldWonders));
     2082
     2083    NewGovAvailable := -1;
     2084    if ClientMode <> cResume then
     2085    begin // tell about new techs
     2086      for ad := 0 to nAdv - 1 do
     2087        if (MyRO.TestFlags and tfAllTechs = 0) and
     2088          ((MyRO.Tech[ad] >= tsApplicable) <> (MyData.ToldTech[ad] >=
     2089          tsApplicable)) or (ad in FutureTech) and
     2090          (MyRO.Tech[ad] <> MyData.ToldTech[ad]) then
     2091          with MessgExDlg do
     2092          begin
     2093            Item := 'RESEARCH_GENERAL';
     2094            if GameMode <> cMovie then
     2095              OpenSound := 'NEWADVANCE_' + char(48 + Age);
     2096            Item2 := Phrases.Lookup('ADVANCES', ad);
     2097            if ad in FutureTech then
     2098              Item2 := Item2 + ' ' + IntToStr(MyRO.Tech[ad]);
     2099            MessgText := Format(Phrases.Lookup(Item), [Item2]);
     2100            Kind := mkOkHelp;
     2101            HelpKind := hkAdv;
     2102            HelpNo := ad;
     2103            IconKind := mikBook;
     2104            IconIndex := -1;
     2105            for i := 0 to nAdvBookIcon - 1 do
     2106              if AdvBookIcon[i].Adv = ad then
     2107                IconIndex := AdvBookIcon[i].Icon;
     2108            ShowModal;
     2109            MyData.ToldTech[ad] := MyRO.Tech[ad];
     2110            for i := gMonarchy to nGov - 1 do
     2111              if GovPreq[i] = ad then
     2112                NewGovAvailable := i;
     2113          end;
     2114    end;
     2115
     2116    ShowCityList := false;
     2117    if ClientMode = cTurn then
     2118    begin
     2119      if (MyRO.Happened and phTech <> 0) and (MyData.FarTech <> adNexus) then
     2120        ChooseResearch;
     2121
     2122      UpdatePanel := false;
     2123      if MyRO.Happened and phChangeGov <> 0 then
     2124      begin
     2125        ModalSelectDlg.ShowNewContent(wmModal, kGov);
     2126        Play('NEWGOV');
     2127        Server(sSetGovernment, me, ModalSelectDlg.result, nil^);
     2128        CityOptimizer_BeginOfTurn;
     2129        UpdatePanel := true;
     2130      end;
     2131    end; // ClientMode=cTurn
     2132
     2133    if not supervising and ((ClientMode = cTurn) or (ClientMode = cMovieTurn))
     2134    then
     2135      for cix := 0 to MyRO.nCity - 1 do
     2136        with MyCity[cix] do
     2137          Status := Status and not csToldBombard;
     2138
     2139    if ((ClientMode = cTurn) or (ClientMode = cMovieTurn)) and
     2140      (MyRO.Government <> gAnarchy) then
     2141    begin
     2142      // tell what happened in cities
     2143      for WondersOnly := true downto false do
     2144        for cix := 0 to MyRO.nCity - 1 do
     2145          with MyCity[cix] do
     2146            if (MyRO.Turn > 0) and (Loc >= 0) and (Flags and chCaptured = 0) and
     2147              (WondersOnly = (Flags and chProduction <> 0) and
     2148              (Project0 and cpImp <> 0) and (Project0 and cpIndex < 28)) then
     2149            begin
     2150              if WondersOnly then
     2151                with MessgExDlg do
     2152                begin { tell about newly built wonder }
     2153                  OpenSound := 'WONDER_BUILT';
     2154                  s := Tribe[me].TPhrase('WONDERBUILTOWN');
     2155                  MessgText :=
     2156                    Format(s, [Phrases.Lookup('IMPROVEMENTS',
     2157                    Project0 and cpIndex), CityName(ID)]);
     2158                  Kind := mkOkHelp;
     2159                  HelpKind := hkImp;
     2160                  HelpNo := Project0 and cpIndex;
     2161                  IconKind := mikImp;
     2162                  IconIndex := Project0 and cpIndex;
     2163                  ShowModal;
     2164                end;
     2165              if not supervising and (ClientMode = cTurn) then
     2166              begin
     2167                AllowCityScreen := true;
     2168                if (Status and 7 <> 0) and
     2169                  (Project and (cpImp + cpIndex) = cpImp + imTrGoods) then
     2170                  if (MyData.ImpOrder[Status and 7 - 1, 0] >= 0) then
     2171                  begin
     2172                    if AutoBuild(cix, MyData.ImpOrder[Status and 7 - 1]) then
     2173                      AllowCityScreen := false
     2174                    else if Flags and chProduction <> 0 then
     2175                      Flags := (Flags and not chProduction) or chAllImpsMade
     2176                  end
     2177                  else
     2178                    Flags := Flags or chTypeDel;
     2179                if (Size >= NeedAqueductSize) and
     2180                  (MyRO.Tech[Imp[imAqueduct].Preq] < tsApplicable) or
     2181                  (Size >= NeedSewerSize) and
     2182                  (MyRO.Tech[Imp[imSewer].Preq] < tsApplicable) then
     2183                  Flags := Flags and not chNoGrowthWarning;
     2184                // don't remind of unknown building
     2185                if Flags and chNoSettlerProd = 0 then
     2186                  Status := Status and not csToldDelay
     2187                else if Status and csToldDelay = 0 then
     2188                  Status := Status or csToldDelay
     2189                else
     2190                  Flags := Flags and not chNoSettlerProd;
     2191                if mRepScreens.Checked then
     2192                begin
     2193                  if (Flags and CityRepMask <> 0) and AllowCityScreen then
     2194                  begin { show what happened in cities }
     2195                    SetTroopLoc(MyCity[cix].Loc);
     2196                    MarkCityLoc := MyCity[cix].Loc;
     2197                    PanelPaint;
     2198                    CityDlg.CloseAction := None;
     2199                    CityDlg.ShowNewContent(wmModal, MyCity[cix].Loc,
     2200                      Flags and CityRepMask);
     2201                    UpdatePanel := true;
     2202                  end
     2203                end
     2204                else { if mRepList.Checked then }
     2205                begin
     2206                  if Flags and CityRepMask <> 0 then
     2207                    ShowCityList := true
     2208                end
     2209              end
     2210            end; { city loop }
     2211    end; // ClientMode=cTurn
     2212
     2213    if ClientMode = cTurn then
     2214    begin
     2215      if NewGovAvailable >= 0 then
     2216        with MessgExDlg do
     2217        begin
     2218          MessgText := Format(Phrases.Lookup('AUTOREVOLUTION'),
     2219            [Phrases.Lookup('GOVERNMENT', NewGovAvailable)]);
     2220          Kind := mkYesNo;
     2221          IconKind := mikPureIcon;
     2222          IconIndex := 6 + NewGovAvailable;
     2223          ShowModal;
     2224          if ModalResult = mrOK then
     2225          begin
     2226            Play('REVOLUTION');
     2227            Server(sRevolution, me, 0, nil^);
     2228          end
     2229        end;
     2230    end; // ClientMode=cTurn
     2231
     2232    if (ClientMode = cTurn) or (ClientMode = cMovieTurn) then
     2233    begin
     2234      if MyRO.Happened and phGliderLost <> 0 then
     2235        ContextMessage(Phrases.Lookup('GLIDERLOST'), 'MSG_DEFAULT',
     2236          hkModel, 200);
     2237      if MyRO.Happened and phPlaneLost <> 0 then
     2238        ContextMessage(Phrases.Lookup('PLANELOST'), 'MSG_DEFAULT',
     2239          hkFeature, mcFuel);
     2240      if MyRO.Happened and phPeaceEvacuation <> 0 then
     2241        for p1 := 0 to nPl - 1 do
     2242          if 1 shl p1 and MyData.PeaceEvaHappened <> 0 then
     2243            SoundMessageEx(Tribe[p1].TPhrase('WITHDRAW'), 'MSG_DEFAULT');
     2244      if MyRO.Happened and phPeaceViolation <> 0 then
     2245        for p1 := 0 to nPl - 1 do
     2246          if (1 shl p1 and MyRO.Alive <> 0) and (MyRO.EvaStart[p1] = MyRO.Turn)
     2247          then
     2248            SoundMessageEx(Format(Tribe[p1].TPhrase('VIOLATION'),
     2249              [TurnToString(MyRO.Turn + PeaceEvaTurns - 1)]), 'MSG_WITHDRAW');
     2250      TellNewContacts;
     2251    end;
     2252
     2253    if ClientMode = cMovieTurn then
     2254      Update
     2255    else if ClientMode = cTurn then
     2256    begin
     2257      if UpdatePanel then
     2258        UpdateViews;
     2259      Application.ProcessMessages;
     2260
     2261      if not supervising then
     2262        for uix := 0 to MyRO.nUn - 1 do
     2263          with MyUn[uix] do
     2264            if Loc >= 0 then
     2265            begin
     2266              if Flags and unWithdrawn <> 0 then
     2267                Status := 0;
     2268              if Health = 100 then
     2269                Status := Status and not usRecover;
     2270              if (Master >= 0) or UnitExhausted(uix) then
     2271                Status := Status and not usWaiting
     2272              else
     2273                Status := Status or usWaiting;
     2274              CheckToldNoReturn(uix);
     2275              if Status and usGoto <> 0 then
     2276              begin { continue multi-turn goto }
     2277                SetUnFocus(uix);
     2278                SetTroopLoc(Loc);
     2279                FocusOnLoc(TroopLoc, flRepaintPanel or flImmUpdate);
     2280                if Status shr 16 = $7FFF then
     2281                  MoveResult := GetMoveAdvice(UnFocus, maNextCity,
     2282                    MoveAdviceData)
     2283                else
     2284                  MoveResult := GetMoveAdvice(UnFocus, Status shr 16,
     2285                    MoveAdviceData);
     2286                if MoveResult >= rExecuted then
     2287                begin // !!! Shinkansen
     2288                  MoveResult := eOK;
     2289                  ok := true;
     2290                  for i := 0 to MoveAdviceData.nStep - 1 do
     2291                  begin
     2292                    Loc1 := dLoc(Loc, MoveAdviceData.dx[i],
     2293                      MoveAdviceData.dy[i]);
     2294                    if (MyMap[Loc1] and (fCity or fOwned) = fCity)
     2295                    // don't capture cities during auto move
     2296                      or (MyMap[Loc1] and (fUnit or fOwned) = fUnit) then
     2297                    // don't attack during auto move
     2298                    begin
     2299                      ok := false;
     2300                      Break
     2301                    end
     2302                    else
     2303                    begin
     2304                      if (Loc1 = MoveAdviceData.ToLoc) or
     2305                        (MoveAdviceData.ToLoc = maNextCity) and
     2306                        (MyMap[dLoc(Loc, MoveAdviceData.dx[i],
     2307                        MoveAdviceData.dy[i])] and fCity <> 0) then
     2308                        MoveOptions := muAutoNoWait
     2309                      else
     2310                        MoveOptions := 0;
     2311                      MoveResult := MoveUnit(MoveAdviceData.dx[i],
     2312                        MoveAdviceData.dy[i], MoveOptions);
     2313                      if (MoveResult < rExecuted) or (MoveResult = eEnemySpotted)
     2314                      then
     2315                      begin
     2316                        ok := false;
     2317                        Break
     2318                      end;
     2319                    end
     2320                  end;
     2321                  Stop := not ok or (Loc = MoveAdviceData.ToLoc) or
     2322                    (MoveAdviceData.ToLoc = maNextCity) and
     2323                    (MyMap[Loc] and fCity <> 0)
     2324                end
     2325                else
     2326                begin
     2327                  MoveResult := eOK;
     2328                  Stop := true;
     2329                end;
     2330
     2331                if MoveResult <> eDied then
     2332                  if Stop then
     2333                    Status := Status and ($FFFF - usGoto)
     2334                  else
     2335                    Status := Status and not usWaiting;
     2336              end;
     2337
     2338              if Status and (usEnhance or usGoto) = usEnhance then
     2339              // continue terrain enhancement
     2340              begin
     2341                MoveResult := ProcessEnhancement(uix, MyData.EnhancementJobs);
     2342                if MoveResult <> eDied then
     2343                  if MoveResult = eJobDone then
     2344                    Status := Status and not usEnhance
     2345                  else
     2346                    Status := Status and not usWaiting;
     2347              end
     2348            end;
     2349    end; // ClientMode=cTurn
     2350
     2351    HaveStrategyAdvice := false;
     2352    // (GameMode<>cMovie) and not supervising
     2353    // and AdvisorDlg.HaveStrategyAdvice;
     2354    GoOnPhase := true;
     2355    if supervising or (GameMode = cMovie) then
     2356    begin
     2357      SetTroopLoc(-1);
     2358      PaintAll
     2359    end { supervisor }
     2360    { else if (ClientMode=cTurn) and (MyRO.Turn=0) then
     2361      begin
     2362      SetUnFocus(0);
     2363      ZoomToCity(MyCity[0].Loc)
     2364      end }
    10172365    else
    1018       Server(sSetResearch, me, ChosenResearch, nil^);
    1019     ListDlg.TechChange;
    1020     result := true;
     2366    begin
     2367      if ClientMode >= scContact then
     2368        SetUnFocus(-1)
     2369      else
     2370        NextUnit(-1, false);
     2371      if UnFocus < 0 then
     2372      begin
     2373        UnStartLoc := -1;
     2374        if IsMultiPlayerGame or (ClientMode = cResume) then
     2375          if MyRO.nCity > 0 then
     2376            FocusOnLoc(MyCity[0].Loc)
     2377          else
     2378            FocusOnLoc(G.lx * G.ly div 2);
     2379        SetTroopLoc(-1);
     2380        PanelPaint
     2381      end;
     2382      if ShowCityList then
     2383        ListDlg.ShowNewContent(wmPersistent, kCityEvents);
     2384    end;
     2385  end; { InitTurn }
     2386
     2387var
     2388  i, j, p1, mix, ToLoc, AnimationSpeed, ShowMoveDomain, cix, ecix: integer;
     2389  Color: TColor;
     2390  Name, s: string;
     2391  TribeInfo: TTribeInfo;
     2392  mi: TModelInfo;
     2393  SkipTurn, IsAlpine, IsTreatyDeal: boolean;
     2394
     2395begin { >>>client }
     2396  case Command of
     2397    cTurn, cResume, cContinue, cMovieTurn, scContact, scDipStart .. scDipBreak:
     2398      begin
     2399        supervising := G.Difficulty[NewPlayer] = 0;
     2400        ArrangeMidPanel;
     2401      end
    10212402  end;
    1022 
    1023   (* ** client function handling ** *)
    1024 
    1025   function TMainScreen.DipCall(Command: integer): integer;
    1026   var
    1027     i: integer;
    1028     IsTreatyDeal: boolean;
    1029   begin
    1030     result := Server(Command, me, 0, nil^);
    1031     if result >= rExecuted then
    1032     begin
    1033       if Command and $FF0F = scContact then
    1034       begin
    1035         DipMem[me].pContact := Command shr 4 and $F;
    1036         NegoDlg.Initiate;
    1037         DipMem[me].DeliveredPrices := [];
    1038         DipMem[me].ReceivedPrices := [];
    1039       end;
    1040 
    1041       DipMem[me].SentCommand := Command;
    1042       DipMem[me].FormerTreaty := MyRO.Treaty[DipMem[me].pContact];
    1043       if Command = scDipCancelTreaty then
    1044         Play('CANCELTREATY')
    1045       else if Command = scDipAccept then
    1046       begin // remember delivered and received prices
    1047         for i := 0 to ReceivedOffer.nDeliver - 1 do
    1048           include(DipMem[me].ReceivedPrices, ReceivedOffer.Price[i] shr 24);
    1049         for i := 0 to ReceivedOffer.nCost - 1 do
    1050           include(DipMem[me].DeliveredPrices,
    1051             ReceivedOffer.Price[ReceivedOffer.nDeliver + i] shr 24);
    1052         IsTreatyDeal := false;
    1053         for i := 0 to ReceivedOffer.nDeliver + ReceivedOffer.nCost - 1 do
    1054           if ReceivedOffer.Price[i] and opMask = opTreaty then
    1055             IsTreatyDeal := true;
    1056         if IsTreatyDeal then
    1057           Play('NEWTREATY')
     2403  case Command of
     2404    cDebugMessage:
     2405      LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(@Data));
     2406
     2407    cShowNego:
     2408      with TShowNegoData(Data) do
     2409      begin
     2410        s := Format('P%d to P%d: ', [pSender, pTarget]);
     2411        if (Action = scDipOffer) and (Offer.nDeliver + Offer.nCost > 0) then
     2412        begin
     2413          s := s + 'Offer ';
     2414          for i := 0 to Offer.nDeliver + Offer.nCost - 1 do
     2415          begin
     2416            if i = Offer.nDeliver then
     2417              s := s + ' for '
     2418            else if i > 0 then
     2419              s := s + '+';
     2420            case Offer.Price[i] and opMask of
     2421              opChoose:
     2422                s := s + 'Price of choice';
     2423              opCivilReport:
     2424                s := s + 'State report';
     2425              opMilReport:
     2426                s := s + 'Military report';
     2427              opMap:
     2428                s := s + 'Map';
     2429              opTreaty:
     2430                s := s + 'Treaty';
     2431              opShipParts:
     2432                s := s + 'Ship part';
     2433              opMoney:
     2434                s := s + IntToStr(Offer.Price[i] and $FFFFFF) + 'o';
     2435              opTribute:
     2436                s := s + IntToStr(Offer.Price[i] and $FFFFFF) + 'o tribute';
     2437              opTech:
     2438                s := s + Phrases.Lookup('ADVANCES', Offer.Price[i] and $FFFFFF);
     2439              opAllTech:
     2440                s := s + 'All advances';
     2441              opModel:
     2442                s := s + Tribe[pSender].ModelName[Offer.Price[i] and $FFFFFF];
     2443              opAllModel:
     2444                s := s + 'All models';
     2445            end
     2446          end;
     2447          LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(s));
     2448        end
     2449        else if Action = scDipAccept then
     2450        begin
     2451          s := s + '--- ACCEPTED! ---';
     2452          LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(s));
     2453        end
     2454      end;
     2455
     2456    cInitModule:
     2457      begin
     2458        Server := TInitModuleData(Data).Server;
     2459        // AdvisorDlg.Init;
     2460        InitModule;
     2461        TInitModuleData(Data).DataSize := SizeOf(TPersistentData);
     2462        TInitModuleData(Data).Flags := aiThreaded;
     2463      end;
     2464
     2465    cReleaseModule:
     2466      begin
     2467        SmallImp.free;
     2468        UnusedTribeFiles.free;
     2469        TribeNames.free;
     2470        MainMap.free;
     2471        IsoEngine.Done;
     2472        // AdvisorDlg.DeInit;
     2473      end;
     2474
     2475    cHelpOnly, cStartHelp, cStartCredits:
     2476      begin
     2477        Age := 0;
     2478        if Command = cHelpOnly then
     2479          SetMainTextureByAge(-1);
     2480        Tribes.Init;
     2481        HelpDlg.UserLeft := (Screen.width - HelpDlg.width) div 2;
     2482        HelpDlg.UserTop := (Screen.height - HelpDlg.height) div 2;
     2483        HelpDlg.Difficulty := 0;
     2484        if Command = cStartCredits then
     2485          HelpDlg.ShowNewContent(wmModal, hkMisc, miscCredits)
    10582486        else
    1059           Play('ACCEPTOFFER');
    1060       end;
    1061       CityDlg.CloseAction := None;
    1062       if G.RO[DipMem[me].pContact] <> nil then
    1063       begin // close windows for next player
     2487          HelpDlg.ShowNewContent(wmModal, hkMisc, miscMain);
     2488        Tribes.Done;
     2489      end;
     2490
     2491    cNewGame, cLoadGame, cMovie, cNewMap:
     2492      begin
     2493        { if (Command=cNewGame) or (Command=cLoadGame) then
     2494          AdvisorDlg.NewGame(Data); }
     2495        GenerateNames := mNames.Checked;
     2496        GameOK := true;
     2497        G := TNewGameData(Data);
     2498        me := -1;
     2499        pLogo := -1;
     2500        ClientMode := -1;
     2501        SetMapOptions;
     2502        IsoEngine.pDebugMap := -1;
     2503        idle := false;
     2504        FillChar(Jump, SizeOf(Jump), 0);
     2505        if StartRunning then
     2506          Jump[0] := 999999;
     2507        GameMode := Command;
     2508        for i := 0 to nGrExt - 1 do
     2509          FillChar(GrExt[i].pixUsed, GrExt[i].Data.height div 49 * 10, 0);
     2510        IsoEngine.Reset;
     2511        Tribes.Init;
     2512        GetTribeList;
     2513        for p1 := 0 to nPl - 1 do
     2514          if (G.RO[p1] <> nil) and (G.RO[p1].Data <> nil) then
     2515            with TPersistentData(G.RO[p1].Data^) do
     2516            begin
     2517              FarTech := adNone;
     2518              FillChar(EnhancementJobs, SizeOf(EnhancementJobs), jNone);
     2519              FillChar(ImpOrder, SizeOf(ImpOrder), Byte(-1));
     2520              ColdWarStart := -ColdWarTurns - 1;
     2521              ToldAge := -1;
     2522              ToldModels := 3;
     2523              ToldAlive := 0;
     2524              ToldContact := 0;
     2525              ToldOwnCredibility := InitialCredibility;
     2526              for i := 0 to nPl - 1 do
     2527                if G.Difficulty[i] > 0 then
     2528                  inc(ToldAlive, 1 shl i);
     2529              PeaceEvaHappened := 0;
     2530              for i := 0 to 27 do
     2531                with ToldWonders[i] do
     2532                begin
     2533                  CityID := -1;
     2534                  EffectiveOwner := -1
     2535                end;
     2536              FillChar(ToldTech, SizeOf(ToldTech), Byte(tsNA));
     2537              if G.Difficulty[p1] > 0 then
     2538                SoundPreload(sbStart);
     2539            end;
     2540
     2541        // arrange dialogs
     2542        ListDlg.UserLeft := 8;
     2543        ListDlg.UserTop := TopBarHeight + 8;
     2544        HelpDlg.UserLeft := Screen.width - HelpDlg.width - 8;
     2545        HelpDlg.UserTop := TopBarHeight + 8;
     2546        UnitStatDlg.UserLeft := 397;
     2547        UnitStatDlg.UserTop := TopBarHeight + 64;
     2548        DiaDlg.UserLeft := (Screen.width - DiaDlg.width) div 2;
     2549        DiaDlg.UserTop := (Screen.height - DiaDlg.height) div 2;
     2550        NatStatDlg.UserLeft := Screen.width - NatStatDlg.width - 8;
     2551        NatStatDlg.UserTop := Screen.height - PanelHeight -
     2552          NatStatDlg.height - 8;
     2553        if NatStatDlg.UserTop < 8 then
     2554          NatStatDlg.UserTop := 8;
     2555
     2556        Age := 0;
     2557        MovieSpeed := 1;
     2558        LogDlg.mSlot.Visible := true;
     2559        LogDlg.Host := self;
     2560        HelpDlg.ClearHistory;
     2561        CityDlg.Reset;
     2562
     2563        Mini.width := G.lx * 2;
     2564        Mini.height := G.ly;
     2565        for i := 0 to nPl - 1 do
     2566        begin
     2567          Tribe[i] := nil;
     2568          TribeOriginal[i] := false;
     2569        end;
     2570        ToldSlavery := -1;
     2571        RepaintOnResize := false;
     2572        Closable := false;
     2573        FirstMovieTurn := true;
     2574
     2575        MenuArea.Visible := GameMode <> cMovie;
     2576        TreasuryArea.Visible := GameMode < cMovie;
     2577        ResearchArea.Visible := GameMode < cMovie;
     2578        ManagementArea.Visible := GameMode < cMovie;
     2579      end;
     2580
     2581    cGetReady, cReplay:
     2582      if NewPlayer = 0 then
     2583      begin
     2584        i := 0;
     2585        for p1 := 0 to nPl - 1 do
     2586          if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) then
     2587            inc(i);
     2588        if i > UnusedTribeFiles.Count then
     2589        begin
     2590          GameOK := false;
     2591          SimpleMessage(Phrases.Lookup('TOOFEWTRIBES'));
     2592        end
     2593        else
     2594        begin
     2595          for p1 := 0 to nPl - 1 do
     2596            if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) and (G.RO[p1] <> nil)
     2597            then
     2598            begin // let player select own tribes
     2599              TribeInfo.trix := p1;
     2600              TribeNames.Clear;
     2601              for j := 0 to UnusedTribeFiles.Count - 1 do
     2602              begin
     2603                GetTribeInfo(UnusedTribeFiles[j], Name, Color);
     2604                TribeNames.AddObject(Name, TObject(Color));
     2605              end;
     2606              assert(TribeNames.Count > 0);
     2607              ModalSelectDlg.ShowNewContent(wmModal, kTribe);
     2608              Application.ProcessMessages;
     2609              TribeInfo.FileName := UnusedTribeFiles[ModalSelectDlg.result];
     2610              UnusedTribeFiles.Delete(ModalSelectDlg.result);
     2611
     2612              if GameMode = cLoadGame then
     2613                CreateTribe(TribeInfo.trix, TribeInfo.FileName, false)
     2614              else
     2615                Server(cSetTribe + (Length(TribeInfo.FileName) + 1 + 7) div 4,
     2616                  0, 0, TribeInfo);
     2617            end;
     2618
     2619          for p1 := 0 to nPl - 1 do
     2620            if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) and (G.RO[p1] = nil)
     2621            then
     2622            begin // autoselect enemy tribes
     2623              j := ChooseUnusedTribe;
     2624              TribeInfo.FileName := UnusedTribeFiles[j];
     2625              UnusedTribeFiles.Delete(j);
     2626              TribeInfo.trix := p1;
     2627              if GameMode = cLoadGame then
     2628                CreateTribe(TribeInfo.trix, TribeInfo.FileName, false)
     2629              else
     2630                Server(cSetTribe + (Length(TribeInfo.FileName) + 1 + 7) div 4,
     2631                  0, 0, TribeInfo);
     2632            end;
     2633        end;
     2634        if not mNames.Checked then
     2635          for p1 := 0 to nPl - 1 do
     2636            if Tribe[p1] <> nil then
     2637              Tribe[p1].NumberName := p1;
     2638      end;
     2639
     2640    cBreakGame:
     2641      begin
     2642        SaveSettings;
     2643        CityDlg.CloseAction := None;
    10642644        for i := 0 to Screen.FormCount - 1 do
    10652645          if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
    10662646          then
    10672647            Screen.Forms[i].Close;
    1068       end
    1069       else
    1070       begin
    1071         if CityDlg.Visible then
    1072           CityDlg.Close;
    1073         if UnitStatDlg.Visible then
    1074           UnitStatDlg.Close;
    1075       end
    1076     end
    1077   end;
    1078 
    1079   function TMainScreen.OfferCall(var Offer: TOffer): integer;
    1080   var
    1081     i: integer;
    1082   begin
    1083     result := Server(scDipOffer, me, 0, Offer);
    1084     if result >= rExecuted then
    1085     begin
    1086       DipMem[me].SentCommand := scDipOffer;
    1087       DipMem[me].FormerTreaty := MyRO.Treaty[DipMem[me].pContact];
    1088       DipMem[me].SentOffer := Offer;
    1089       CityDlg.CloseAction := None;
    1090       if G.RO[DipMem[me].pContact] <> nil then
    1091       begin // close windows for next player
    1092         for i := 0 to Screen.FormCount - 1 do
    1093           if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
    1094           then
    1095             Screen.Forms[i].Close;
    1096       end
    1097       else
    1098       begin
    1099         if CityDlg.Visible then
    1100           CityDlg.Close;
    1101         if UnitStatDlg.Visible then
    1102           UnitStatDlg.Close;
    1103       end
    1104     end
    1105   end;
    1106 
    1107   procedure TMainScreen.SetUnFocus(uix: integer);
    1108   var
    1109     Loc0: integer;
    1110   begin
    1111     assert(not((uix >= 0) and supervising));
    1112     if uix <> UnFocus then
    1113     begin
    1114       DestinationMarkON := false;
    1115       PaintDestination;
    1116       if uix >= 0 then
    1117         UnStartLoc := MyUn[uix].Loc;
    1118       BlinkON := false;
    1119       BlinkTime := -1;
    1120       if UnFocus >= 0 then
    1121       begin
    1122         Loc0 := MyUn[UnFocus].Loc;
    1123         if (uix < 0) or (Loc0 <> MyUn[uix].Loc) then
    1124         begin
    1125           UnFocus := -1;
    1126           PaintLoc(Loc0);
    1127         end
    1128       end;
    1129       UnFocus := uix;
    1130     end;
    1131     UnitInfoBtn.Visible := UnFocus >= 0;
    1132     UnitBtn.Visible := UnFocus >= 0;
    1133     CheckTerrainBtnVisible;
    1134   end;
    1135 
    1136   procedure TMainScreen.CheckTerrainBtnVisible;
    1137   var
    1138     Tile: integer;
    1139     mox: ^TModel;
    1140   begin
    1141     if UnFocus >= 0 then
    1142     begin
    1143       mox := @MyModel[MyUn[UnFocus].mix];
    1144       Tile := MyMap[MyUn[UnFocus].Loc];
    1145       TerrainBtn.Visible := (Tile and fCity = 0) and (MyUn[UnFocus].Master < 0)
    1146         and ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves) and
    1147         (MyRO.Wonder[woPyramids].EffectiveOwner >= 0));
    1148     end
    1149     else
    1150       TerrainBtn.Visible := false;
    1151   end;
    1152 
    1153   procedure TMainScreen.CheckMovieSpeedBtnState;
    1154   begin
    1155     if GameMode = cMovie then
    1156     begin
    1157       MovieSpeed1Btn.Down := MovieSpeed = 1;
    1158       MovieSpeed1Btn.Visible := true;
    1159       MovieSpeed2Btn.Down := MovieSpeed = 2;
    1160       MovieSpeed2Btn.Visible := true;
    1161       MovieSpeed3Btn.Down := MovieSpeed = 3;
    1162       MovieSpeed3Btn.Visible := true;
    1163       MovieSpeed4Btn.Down := MovieSpeed = 4;
    1164       MovieSpeed4Btn.Visible := true;
    1165     end
    1166     else
    1167     begin
    1168       MovieSpeed1Btn.Visible := false;
    1169       MovieSpeed2Btn.Visible := false;
    1170       MovieSpeed3Btn.Visible := false;
    1171       MovieSpeed4Btn.Visible := false;
    1172     end
    1173   end;
    1174 
    1175   procedure TMainScreen.SetMapOptions;
    1176   begin
    1177     IsoEngine.Options := MapOptionChecked;
    1178     if ClientMode = cEditMap then
    1179       IsoEngine.Options := IsoEngine.Options or (1 shl moEditMode);
    1180     if mLocCodes.Checked then
    1181       IsoEngine.Options := IsoEngine.Options or (1 shl moLocCodes);
    1182   end;
    1183 
    1184   procedure TMainScreen.UpdateViews(UpdateCityScreen: boolean);
    1185   begin
    1186     SumCities(TaxSum, ScienceSum);
    1187     PanelPaint; // TopBar was enough!!!
    1188     ListDlg.EcoChange;
    1189     NatStatDlg.EcoChange;
    1190     if UpdateCityScreen then
    1191       CityDlg.SmartUpdateContent;
    1192   end;
    1193 
    1194   procedure TMainScreen.SetAIName(p: integer; Name: string);
    1195   begin
    1196     if Name = '' then
    1197     begin
    1198       if AILogo[p] <> nil then
    1199       begin
    1200         AILogo[p].free;
    1201         AILogo[p] := nil
    1202       end
    1203     end
    1204     else
    1205     begin
    1206       if AILogo[p] = nil then
    1207         AILogo[p] := TBitmap.Create;
    1208       if not LoadGraphicFile(AILogo[p], HomeDir + Name, gfNoError) then
    1209       begin
    1210         AILogo[p].free;
    1211         AILogo[p] := nil
    1212       end
    1213     end
    1214   end;
    1215 
    1216   function TMainScreen.ContactRefused(p: integer; Item: String): boolean;
    1217   // return whether treaty was cancelled
    1218   var
    1219     s: string;
    1220   begin
    1221     assert(MyRO.Treaty[p] >= trPeace);
    1222     s := Tribe[p].TPhrase(Item);
    1223     if MyRO.Turn < MyRO.LastCancelTreaty[p] + CancelTreatyTurns then
    1224     begin
    1225       SimpleMessage(s);
    1226       result := false;
    1227     end
    1228     else
    1229     begin
    1230       case MyRO.Treaty[p] of
    1231         trPeace:
    1232           s := s + ' ' + Phrases.Lookup('FRCANCELQUERY_PEACE');
    1233         trFriendlyContact:
    1234           s := s + ' ' + Phrases.Lookup('FRCANCELQUERY_FRIENDLY');
    1235         trAlliance:
    1236           s := s + ' ' + Phrases.Lookup('FRCANCELQUERY_ALLIANCE');
    1237       end;
    1238       result := SimpleQuery(mkYesNo, s, 'NEGO_REJECTED') = mrOK;
    1239       if result then
    1240       begin
    1241         Play('CANCELTREATY');
    1242         Server(sCancelTreaty, me, 0, nil^);
    1243         if MyRO.Treaty[p] = trNone then
    1244           CityOptimizer_BeginOfTurn;
    1245         // peace treaty was cancelled -- use formerly forbidden tiles
    1246         MapValid := false;
    1247         PaintAllMaps;
    1248       end
    1249     end
    1250   end;
    1251 
    1252   procedure TMainScreen.RememberPeaceViolation;
    1253   var
    1254     uix, p1: integer;
    1255   begin
    1256     MyData.PeaceEvaHappened := 0;
    1257     for uix := 0 to MyRO.nUn - 1 do
    1258       with MyUn[uix] do
    1259         if Loc >= 0 then
    1260         begin
    1261           p1 := MyRO.Territory[Loc];
    1262           if (p1 <> me) and (p1 >= 0) and
    1263             (MyRO.Turn = MyRO.EvaStart[p1] + (PeaceEvaTurns - 1)) then
    1264             MyData.PeaceEvaHappened := MyData.PeaceEvaHappened or (1 shl p1);
    1265         end;
    1266   end;
    1267 
    1268   procedure TMainScreen.Client(Command, NewPlayer: integer; var Data);
    1269 
    1270     procedure GetTribeList;
    1271     var
    1272       SearchRec: TSearchRec;
    1273       Color: TColor;
    1274       Name: string;
    1275       ok: boolean;
    1276     begin
    1277       UnusedTribeFiles.Clear;
    1278       ok := FindFirst(DataDir + 'Localization' + DirectorySeparator + 'Tribes' + DirectorySeparator + '*.tribe.txt',
    1279         faArchive + faReadOnly, SearchRec) = 0;
    1280       if not ok then
    1281       begin
    1282         FindClose(SearchRec);
    1283         ok := FindFirst(HomeDir + 'Tribes' + DirectorySeparator + '*.tribe.txt', faArchive + faReadOnly,
    1284           SearchRec) = 0;
    1285       end;
    1286       if ok then
    1287         repeat
    1288           SearchRec.Name := Copy(SearchRec.Name, 1,
    1289             Length(SearchRec.Name) - 10);
    1290           if GetTribeInfo(SearchRec.Name, Name, Color) then
    1291             UnusedTribeFiles.AddObject(SearchRec.Name, TObject(Color));
    1292         until FindNext(SearchRec) <> 0;
    1293       FindClose(SearchRec);
    1294     end;
    1295 
    1296     function ChooseUnusedTribe: integer;
    1297     var
    1298       i, j, ColorDistance, BestColorDistance, TestColorDistance,
    1299         CountBest: integer;
    1300     begin
    1301       assert(UnusedTribeFiles.Count > 0);
    1302       result := -1;
    1303       BestColorDistance := -1;
    1304       for j := 0 to UnusedTribeFiles.Count - 1 do
    1305       begin
    1306         ColorDistance := 250; // consider differences more than this infinite
    1307         for i := 0 to nPl - 1 do
    1308           if Tribe[i] <> nil then
    1309           begin
    1310             TestColorDistance :=
    1311               abs(integer(UnusedTribeFiles.Objects[j]) shr 16 and
    1312               $FF - Tribe[i].Color shr 16 and $FF) +
    1313               abs(integer(UnusedTribeFiles.Objects[j]) shr 8 and
    1314               $FF - Tribe[i].Color shr 8 and $FF) * 3 +
    1315               abs(integer(UnusedTribeFiles.Objects[j]) and
    1316               $FF - Tribe[i].Color and $FF) * 2;
    1317             if TestColorDistance < ColorDistance then
    1318               ColorDistance := TestColorDistance
    1319           end;
    1320         if ColorDistance > BestColorDistance then
    1321         begin
    1322           CountBest := 0;
    1323           BestColorDistance := ColorDistance
    1324         end;
    1325         if ColorDistance = BestColorDistance then
    1326         begin
    1327           inc(CountBest);
    1328           if random(CountBest) = 0 then
    1329             result := j
    1330         end
    1331       end;
    1332     end;
    1333 
    1334     procedure ShowEnemyShipChange(ShowShipChange: TShowShipChange);
    1335     var
    1336       i, TestCost, MostCost: integer;
    1337       Ship1Plus, Ship2Plus: boolean;
    1338     begin
    1339       with ShowShipChange, MessgExDlg do
    1340       begin
    1341         case Reason of
    1342           scrProduction:
    1343             begin
    1344               OpenSound := 'SHIP_BUILT';
    1345               MessgText := Tribe[Ship1Owner].TPhrase('SHIPBUILT');
    1346               IconKind := mikShip;
    1347               IconIndex := Ship1Owner;
    1348             end;
    1349 
    1350           scrDestruction:
    1351             begin
    1352               OpenSound := 'SHIP_DESTROYED';
    1353               MessgText := Tribe[Ship1Owner].TPhrase('SHIPDESTROYED');
    1354               IconKind := mikImp;
    1355             end;
    1356 
    1357           scrTrade:
    1358             begin
    1359               OpenSound := 'SHIP_TRADED';
    1360               Ship1Plus := false;
    1361               Ship2Plus := false;
    1362               for i := 0 to nShipPart - 1 do
    1363               begin
    1364                 if Ship1Change[i] > 0 then
    1365                   Ship1Plus := true;
    1366                 if Ship2Change[i] > 0 then
    1367                   Ship2Plus := true;
    1368               end;
    1369               if Ship1Plus and Ship2Plus then
    1370                 MessgText := Tribe[Ship1Owner].TPhrase('SHIPBITRADE1') + ' ' +
    1371                   Tribe[Ship2Owner].TPhrase('SHIPBITRADE2')
    1372               else if Ship1Plus then
    1373                 MessgText := Tribe[Ship1Owner].TPhrase('SHIPUNITRADE1') + ' ' +
    1374                   Tribe[Ship2Owner].TPhrase('SHIPUNITRADE2')
    1375               else // if Ship2Plus then
    1376                 MessgText := Tribe[Ship2Owner].TPhrase('SHIPUNITRADE1') + ' ' +
    1377                   Tribe[Ship1Owner].TPhrase('SHIPUNITRADE2');
    1378               IconKind := mikImp;
    1379             end;
    1380 
    1381           scrCapture:
    1382             begin
    1383               OpenSound := 'SHIP_CAPTURED';
    1384               MessgText := Tribe[Ship2Owner].TPhrase('SHIPCAPTURE1') + ' ' +
    1385                 Tribe[Ship1Owner].TPhrase('SHIPCAPTURE2');
    1386               IconKind := mikShip;
    1387               IconIndex := Ship2Owner;
    1388             end
    1389         end;
    1390 
    1391         if IconKind = mikImp then
    1392         begin
    1393           MostCost := 0;
    1394           for i := 0 to nShipPart - 1 do
    1395           begin
    1396             TestCost := abs(Ship1Change[i]) * Imp[imShipComp + i].Cost;
    1397             if TestCost > MostCost then
    1398             begin
    1399               MostCost := TestCost;
    1400               IconIndex := imShipComp + i
    1401             end
    1402           end;
    1403         end;
    1404 
    1405         Kind := mkOk;
    1406         ShowModal;
    1407       end;
    1408     end;
    1409 
    1410     procedure InitModule;
    1411     var
    1412       x, y, i, j, Domain: integer;
    1413     begin
    1414       { search icons for advances: }
    1415       for i := 0 to nAdv - 1 do
    1416         if i in FutureTech then
    1417           AdvIcon[i] := 96 + i - futResearchTechnology
    1418         else
    1419         begin
    1420           AdvIcon[i] := -1;
    1421           for Domain := 0 to nDomains - 1 do
    1422             for j := 0 to nUpgrade - 1 do
    1423               if upgrade[Domain, j].Preq = i then
    1424                 if AdvIcon[i] >= 0 then
    1425                   AdvIcon[i] := 85
    1426                 else
    1427                   AdvIcon[i] := 86 + Domain;
    1428           for j := 0 to nFeature - 1 do
    1429             if Feature[j].Preq = i then
    1430               for Domain := 0 to nDomains - 1 do
    1431                 if 1 shl Domain and Feature[j].Domains <> 0 then
    1432                   if (AdvIcon[i] >= 0) and (AdvIcon[i] <> 86 + Domain) then
    1433                     AdvIcon[i] := 85
    1434                   else
    1435                     AdvIcon[i] := 86 + Domain;
    1436           for j := 28 to nImp - 1 do
    1437             if Imp[j].Preq = i then
    1438               AdvIcon[i] := j;
    1439           for j := 28 to nImp - 1 do
    1440             if (Imp[j].Preq = i) and (Imp[j].Kind <> ikCommon) then
    1441               AdvIcon[i] := j;
    1442           for j := 0 to nJob - 1 do
    1443             if i = JobPreq[j] then
    1444               AdvIcon[i] := 84;
    1445           for j := 0 to 27 do
    1446             if Imp[j].Preq = i then
    1447               AdvIcon[i] := j;
    1448           if AdvIcon[i] < 0 then
    1449             if AdvValue[i] < 1000 then
    1450               AdvIcon[i] := -7
    1451             else
    1452               AdvIcon[i] := 24 + AdvValue[i] div 1000;
    1453           for j := 2 to nGov - 1 do
    1454             if GovPreq[j] = i then
    1455               AdvIcon[i] := j - 8;
    1456         end;
    1457       AdvIcon[adConscription] := 86 + dGround;
    1458 
    1459       UnusedTribeFiles := tstringlist.Create;
    1460       UnusedTribeFiles.Sorted := true;
    1461       TribeNames := tstringlist.Create;
    1462 
    1463       for x := 0 to 11 do
    1464         for y := 0 to 1 do
    1465           MiniColors[x, y] := GrExt[HGrSystem].Data.Canvas.Pixels
    1466             [66 + x, 67 + y];
    1467       IsoEngine.Init(InitEnemyModel);
    1468       if not IsoEngine.ApplyTileSize(xxt, yyt) and ((xxt <> 48) or (yyt <> 24))
    1469       then
    1470         ApplyTileSize(48, 24);
    1471       // non-default tile size is missing a file, switch to default
    1472       MainMap := TIsoMap.Create;
    1473       MainMap.SetOutput(offscreen);
    1474 
    1475       HGrStdUnits := LoadGraphicSet('StdUnits');
    1476       SmallImp := TBitmap.Create;
    1477       SmallImp.PixelFormat := pf24bit;
    1478       InitSmallImp;
    1479       SoundPreloadDone := 0;
    1480       StartRunning := false;
    1481       StayOnTop_Ensured := false;
    1482 
    1483       CreatePVSB(sb, Handle, 100 - 200, 122, 100 + MidPanelHeight - 16 - 200);
    1484     end; { InitModule }
    1485 
    1486   // sound blocks for preload
    1487   const
    1488     sbStart = $01;
    1489     sbWonder = $02;
    1490     sbScience = $04;
    1491     sbContact = $08;
    1492     sbTurn = $10;
    1493     sbAll = $FF;
    1494 
    1495     procedure SoundPreload(Check: integer);
    1496     const
    1497       nStartBlock = 27;
    1498       StartBlock: array [0 .. nStartBlock - 1] of string = ('INVALID',
    1499         'TURNEND', 'DISBAND', 'CHEAT', 'MSG_DEFAULT', 'WARNING_DISORDER',
    1500         'WARNING_FAMINE', 'WARNING_LOWSUPPORT', 'WARNING_LOWFUNDS',
    1501         'MOVE_MOUNTAIN', 'MOVE_LOAD', 'MOVE_UNLOAD', 'MOVE_DIE', 'NOMOVE_TIME',
    1502         'NOMOVE_DOMAIN', 'NOMOVE_DEFAULT', 'CITY_SELLIMP', 'CITY_REBUILDIMP',
    1503         'CITY_BUYPROJECT', 'CITY_UTILIZE', 'NEWMODEL_0', 'NEWADVANCE_0',
    1504         'AGE_0', 'REVOLUTION', 'NEWGOV', 'CITY_INVALIDTYPE', 'MSG_GAMEOVER');
    1505 
    1506       nWonderBlock = 6;
    1507       WonderBlock: array [0 .. nWonderBlock - 1] of string = ('WONDER_BUILT',
    1508         'WONDER_CAPTURED', 'WONDER_EXPIRED', 'WONDER_DESTROYED', 'MSG_COLDWAR',
    1509         'NEWADVANCE_GRLIB');
    1510 
    1511       nScienceBlock = 17;
    1512       ScienceBlock: array [0 .. nScienceBlock - 1] of string =
    1513         ('MOVE_PARACHUTE', 'MOVE_PLANESTART', 'MOVE_PLANELANDING',
    1514         'MOVE_COVERT', 'NEWMODEL_1', 'NEWMODEL_2', 'NEWMODEL_3', 'NEWADVANCE_1',
    1515         'NEWADVANCE_2', 'NEWADVANCE_3', 'AGE_1', 'AGE_2', 'AGE_3', 'SHIP_BUILT',
    1516         'SHIP_TRADED', 'SHIP_CAPTURED', 'SHIP_DESTROYED');
    1517 
    1518       nContactBlock = 20;
    1519       ContactBlock: array [0 .. nContactBlock - 1] of string = ('NEWTREATY',
    1520         'CANCELTREATY', 'ACCEPTOFFER', 'MSG_WITHDRAW', 'MSG_BANKRUPT',
    1521         'CONTACT_0', 'CONTACT_1', 'CONTACT_2', 'CONTACT_3', 'CONTACT_4',
    1522         'CONTACT_5', 'CONTACT_5', 'CONTACT_6', 'NEGO_REJECTED', 'MOVE_CAPTURE',
    1523         'MOVE_EXPEL', 'NOMOVE_TREATY', 'NOMOVE_ZOC', 'NOMOVE_SUBMARINE',
    1524         'NOMOVE_STEALTH');
    1525 
    1526     var
    1527       i, cix, mix: integer;
    1528       need: boolean;
    1529       mi: TModelInfo;
    1530     begin
    1531       if Check and sbStart and not SoundPreloadDone <> 0 then
    1532       begin
    1533         for i := 0 to nStartBlock - 1 do
    1534           PreparePlay(StartBlock[i]);
    1535         SoundPreloadDone := SoundPreloadDone or sbStart;
    1536       end;
    1537       if Check and sbWonder and not SoundPreloadDone <> 0 then
    1538       begin
    1539         need := false;
    1540         for i := 0 to 27 do
    1541           if MyRO.Wonder[i].CityID <> -1 then
    1542             need := true;
    1543         if need then
    1544         begin
    1545           for i := 0 to nWonderBlock - 1 do
    1546             PreparePlay(WonderBlock[i]);
    1547           SoundPreloadDone := SoundPreloadDone or sbWonder;
    1548         end;
    1549       end;
    1550       if (Check and sbScience and not SoundPreloadDone <> 0) and
    1551         (MyRO.Tech[adScience] >= tsApplicable) then
    1552       begin
    1553         for i := 0 to nScienceBlock - 1 do
    1554           PreparePlay(ScienceBlock[i]);
    1555         SoundPreloadDone := SoundPreloadDone or sbScience;
    1556       end;
    1557       if (Check and sbContact and not SoundPreloadDone <> 0) and
    1558         (MyRO.nEnemyModel + MyRO.nEnemyCity > 0) then
    1559       begin
    1560         for i := 0 to nContactBlock - 1 do
    1561           PreparePlay(ContactBlock[i]);
    1562         SoundPreloadDone := SoundPreloadDone or sbContact;
    1563       end;
    1564       if Check and sbTurn <> 0 then
    1565       begin
    1566         if MyRO.Happened and phShipComplete <> 0 then
    1567           PreparePlay('MSG_YOUWIN');
    1568         if MyData.ToldAlive <> MyRO.Alive then
    1569           PreparePlay('MSG_EXTINCT');
    1570         for cix := 0 to MyRO.nCity - 1 do
    1571           with MyCity[cix] do
    1572             if (Loc >= 0) and (Flags and CityRepMask <> 0) then
    1573               for i := 0 to 12 do
    1574                 if 1 shl i and Flags and CityRepMask <> 0 then
    1575                   PreparePlay(CityEventSoundItem[i]);
    1576         for mix := 0 to MyRO.nModel - 1 do
    1577           with MyModel[mix] do
    1578             if Attack > 0 then
    1579             begin
    1580               MakeModelInfo(me, mix, MyModel[mix], mi);
    1581               PreparePlay(AttackSound(ModelCode(mi)));
    1582             end
    1583       end
    1584     end;
    1585 
    1586     procedure InitTurn(p: integer);
    1587     const
    1588       nAdvBookIcon = 16;
    1589       AdvBookIcon: array [0 .. nAdvBookIcon - 1] of record Adv,
    1590         Icon: integer end = ((Adv: adPolyTheism; Icon: woZeus),
    1591         (Adv: adBronzeWorking; Icon: woColossus), (Adv: adMapMaking;
    1592         Icon: woLighthouse), (Adv: adPoetry; Icon: imTheater),
    1593         (Adv: adMonotheism; Icon: woMich), (Adv: adPhilosophy; Icon: woLeo),
    1594         (Adv: adTheoryOfGravity; Icon: woNewton), (Adv: adSteel;
    1595         Icon: woEiffel), (Adv: adDemocracy; Icon: woLiberty),
    1596         (Adv: adAutomobile; Icon: imHighways), (Adv: adSanitation;
    1597         Icon: imSewer), (Adv: adElectronics; Icon: woHoover),
    1598         (Adv: adNuclearFission; Icon: woManhattan), (Adv: adRecycling;
    1599         Icon: imRecycling), (Adv: adComputers; Icon: imResLab),
    1600         (Adv: adSpaceFlight; Icon: woMIR));
    1601     var
    1602       Domain, p1, i, ad, uix, cix, MoveOptions, MoveResult, Loc1, Dist,
    1603         NewAgeCenterTo, Bankrupt, ShipMore, Winners, NewGovAvailable, dx,
    1604         dy: integer;
    1605       MoveAdviceData: TMoveAdviceData;
    1606       Picture: TModelPictureInfo;
    1607       s, Item, Item2: string;
    1608       UpdatePanel, OwnWonder, ok, Stop, ShowCityList, WondersOnly,
    1609         AllowCityScreen: boolean;
    1610     begin
    1611       if IsMultiPlayerGame and (p <> me) then
    1612       begin
     2648        if LogDlg.Visible then
     2649          LogDlg.Close;
     2650        LogDlg.List.Clear;
     2651        StartRunning := not idle and (Jump[0] > 0); // AI called Reload
     2652        me := -1;
     2653        idle := false;
     2654        ClientMode := -1;
    16132655        UnitInfoBtn.Visible := false;
    16142656        UnitBtn.Visible := false;
    16152657        TerrainBtn.Visible := false;
     2658        MovieSpeed1Btn.Visible := false;
     2659        MovieSpeed2Btn.Visible := false;
     2660        MovieSpeed3Btn.Visible := false;
     2661        MovieSpeed4Btn.Visible := false;
    16162662        EOT.Visible := false;
    1617       end;
    1618       if IsMultiPlayerGame and (p <> me) and
    1619         (G.RO[0].Happened and phShipComplete = 0) then
    1620       begin // inter player screen
    16212663        for i := 0 to ControlCount - 1 do
    16222664          if Controls[i] is TButtonC then
    16232665            Controls[i].Visible := false;
    1624         me := -1;
    1625         SetMainTextureByAge(-1);
     2666        InitPVSB(sb, 0, 1);
     2667        for p1 := 0 to nPl - 1 do
     2668          if Tribe[p1] <> nil then
     2669            Tribe[p1].free;
     2670        Tribes.Done;
     2671        RepaintOnResize := false;
     2672        Closable := true;
     2673        Close;
     2674        { if (GameMode=cNewGame) or (GameMode=cLoadGame) then
     2675          AdvisorDlg.BreakGame; }
     2676      end;
     2677
     2678    cShowGame:
     2679      begin
    16262680        with Panel.Canvas do
    16272681        begin
     
    16362690          Brush.Style := bsClear;
    16372691        end;
    1638         Invalidate;
    1639 
    1640         s := TurnToString(G.RO[0].Turn);
    1641         if supervising then
    1642           SimpleMessage(Format(Phrases.Lookup('SUPERTURN'), [s]))
    1643         else
    1644           SimpleMessage(Format(Tribe[NewPlayer].TPhrase('TURN'), [s]));
    1645       end;
    1646       for i := 0 to ControlCount - 1 do
    1647         if Controls[i] is TButtonC then
    1648           Controls[i].Visible := true;
    1649 
    1650       ItsMeAgain(p);
    1651       MyData := G.RO[p].Data;
    1652       if not supervising then
    1653         SoundPreload(sbAll);
    1654       if (me = 0) and ((MyRO.Turn = 0) or (ClientMode = cResume)) then
    1655         Invalidate; // colorize empty space
    1656 
    1657       if not supervising then
    1658       begin
    1659 
    1660         { if MyRO.Happened and phGameEnd<>0 then
     2692        FormResize(nil); // place mini map correctly according to its size
     2693        Show;
     2694        Update;
     2695        RepaintOnResize := true;
     2696        xw := 0;
     2697        yw := ywcenter;
     2698        if not StayOnTop_Ensured then
     2699        begin
     2700          StayOnTop_Ensured := true;
     2701          CityDlg.StayOnTop_Workaround;
     2702          CityTypeDlg.StayOnTop_Workaround;
     2703          DiaDlg.StayOnTop_Workaround;
     2704          DraftDlg.StayOnTop_Workaround;
     2705          EnhanceDlg.StayOnTop_Workaround;
     2706          HelpDlg.StayOnTop_Workaround;
     2707          NatStatDlg.StayOnTop_Workaround;
     2708          NegoDlg.StayOnTop_Workaround;
     2709          ModalSelectDlg.StayOnTop_Workaround;
     2710          ListDlg.StayOnTop_Workaround;
     2711          UnitStatDlg.StayOnTop_Workaround;
     2712          WondersDlg.StayOnTop_Workaround;
     2713          RatesDlg.StayOnTop_Workaround;
     2714        end;
     2715      end;
     2716
     2717    cShowTurnChange:
     2718      begin
     2719        if integer(Data) >= 0 then
     2720        begin
     2721          pLogo := integer(Data);
     2722          if G.RO[pLogo] = nil then
    16612723          begin
    1662           Age:=3;
    1663           SetMainTextureByAge(-1);
     2724            if AILogo[pLogo] <> nil then
     2725              BitBlt(Canvas.Handle, (xRightPanel + 10) - (16 + 64),
     2726                ClientHeight - PanelHeight, 64, 64, AILogo[pLogo].Canvas.Handle,
     2727                0, 0, SRCCOPY);
    16642728          end
    1665           else }
     2729        end
     2730      end;
     2731
     2732    cTurn, cResume, cContinue:
     2733      if not GameOK then
     2734        Server(sResign, NewPlayer, 0, nil^)
     2735      else
     2736      begin
     2737        ClientMode := Command;
     2738        pTurn := NewPlayer;
     2739        pLogo := NewPlayer;
     2740
     2741        if Command = cResume then
     2742        begin // init non-original model pictures (maybe tribes not found)
     2743          for p1 := 0 to nPl - 1 do
     2744            if G.RO[p1] <> nil then
     2745            begin
     2746              ItsMeAgain(p1);
     2747              for mix := 0 to MyRO.nModel - 1 do
     2748                if Tribe[me].ModelPicture[mix].HGr = 0 then
     2749                  InitMyModel(mix, true);
     2750            end;
     2751          me := -1;
     2752        end;
     2753
     2754        if Jump[pTurn] > 0 then
     2755          Application.ProcessMessages;
     2756        if Jump[pTurn] > 0 then
     2757          if G.RO[NewPlayer].Happened and phGameEnd <> 0 then
     2758            Jump[pTurn] := 0
     2759          else
     2760            dec(Jump[pTurn]);
     2761        SkipTurn := Jump[pTurn] > 0;
     2762        if SkipTurn then
    16662763        begin
    1667           Age := GetAge(me);
    1668           if SetMainTextureByAge(Age) then
    1669             EOT.Invalidate; // has visible background parts in its bounds
     2764          ItsMeAgain(NewPlayer);
     2765          MyData := G.RO[NewPlayer].Data;
     2766          SetTroopLoc(-1);
     2767          MiniPaint;
     2768          InitAllEnemyModels; // necessary for correct replay
     2769          if not EndTurn(true) then
     2770            SkipTurn := false;
    16702771        end;
    1671         // age:=MyRO.Turn mod 4; //!!!
    1672         if ClientMode = cMovieTurn then
    1673           EOT.ButtonIndex := eotCancel
    1674         else if ClientMode < scContact then
    1675           EOT.ButtonIndex := eotGray
    1676         else
    1677           EOT.ButtonIndex := eotBackToNego;
    1678       end
    1679       else
    1680       begin
    1681         Age := 0;
    1682         SetMainTextureByAge(-1);
    1683         if ClientMode = cMovieTurn then
    1684           EOT.ButtonIndex := eotCancel
    1685         else
    1686           EOT.ButtonIndex := eotBlinkOn;
    1687       end;
    1688       InitCityMark(MainTexture);
    1689       CityDlg.CheckAge;
    1690       NatStatDlg.CheckAge;
    1691       UnitStatDlg.CheckAge;
    1692       HelpDlg.Difficulty := G.Difficulty[me];
    1693 
    1694       UnFocus := -1;
    1695       MarkCityLoc := -1;
    1696       BlinkON := false;
    1697       BlinkTime := -1;
    1698       Tracking := false;
    1699       TurnComplete := false;
    1700 
    1701       if (ToldSlavery < 0) or
    1702         ((ToldSlavery = 1) <> (MyRO.Wonder[woPyramids].EffectiveOwner >= 0))
    1703       then
    1704       begin
    1705         if MyRO.Wonder[woPyramids].EffectiveOwner >= 0 then
    1706           ToldSlavery := 1
    1707         else
    1708           ToldSlavery := 0;
    1709         for p1 := 0 to nPl - 1 do
    1710           if (Tribe[p1] <> nil) and (Tribe[p1].mixSlaves >= 0) then
    1711             with Picture do
    1712             begin // replace unit picture
    1713               mix := Tribe[p1].mixSlaves;
    1714               if ToldSlavery = 1 then
    1715                 pix := pixSlaves
    1716               else
    1717                 pix := pixNoSlaves;
    1718               Hash := 0;
    1719               GrName := 'StdUnits';
    1720               Tribe[p1].SetModelPicture(Picture, true);
     2772        if not SkipTurn then
     2773        begin
     2774          if ((ClientMode < scDipStart) or (ClientMode > scDipBreak)) and
     2775            NegoDlg.Visible then
     2776            NegoDlg.Close;
     2777          skipped := false; // always show my moves during my turn
     2778          idle := true;
     2779          InitTurn(NewPlayer);
     2780          DipMem[me].pContact := -1;
     2781          (* if (me=0) and (MyRO.Alive and (1 shl me)=0)} then
     2782            begin
     2783            if SimpleQuery(Phrases.Lookup('RESIGN'))=mrIgnore then
     2784            Server(sResign,me,0,nil^)
     2785            else Server(sBreak,me,0,nil^)
    17212786            end
    1722       end;
    1723 
    1724       if not supervising and (ClientMode = cTurn) then
    1725       begin
    1726         for cix := 0 to MyRO.nCity - 1 do
    1727           if (MyCity[cix].Loc >= 0) and
    1728             ((MyRO.Turn = 0) or (MyCity[cix].Flags and chFounded <> 0)) then
    1729             MyCity[cix].Status := MyCity[cix].Status and
    1730               not csResourceWeightsMask or (3 shl 4);
    1731         // new city, set to maximum growth
    1732       end;
    1733       if (ClientMode = cTurn) or (ClientMode = cContinue) then
    1734         CityOptimizer_BeginOfTurn; // maybe peace was made or has ended
    1735       SumCities(TaxSum, ScienceSum);
    1736 
    1737       if ClientMode = cMovieTurn then
    1738       begin
     2787            else Play('TURNSTART'); *)
     2788        end;
     2789      end;
     2790
     2791    cMovieTurn:
     2792      begin
     2793        ClientMode := Command;
     2794        pTurn := NewPlayer;
     2795        pLogo := -1;
     2796        skipped := false; // always show my moves during my turn
     2797        idle := true;
     2798        if FirstMovieTurn then
     2799        begin
     2800          CheckMovieSpeedBtnState;
     2801          FirstMovieTurn := false;
     2802        end;
     2803        InitTurn(NewPlayer);
     2804        Application.ProcessMessages;
     2805        if MovieSpeed = 4 then
     2806        begin
     2807          Sleep(75);
     2808          // this break will ensure speed of fast forward does not depend on cpu speed
     2809          Application.ProcessMessages;
     2810        end
     2811      end;
     2812
     2813    cMovieEndTurn:
     2814      begin
     2815        RememberPeaceViolation;
     2816        pTurn := -1;
     2817        pLogo := -1;
     2818        MapValid := false;
     2819        ClientMode := -1;
     2820        idle := false;
     2821        skipped := false;
     2822      end;
     2823
     2824    cEditMap:
     2825      begin
     2826        ClientMode := cEditMap;
     2827        SetMapOptions;
     2828        IsoEngine.pDebugMap := -1;
     2829        ItsMeAgain(0);
     2830        MyData := nil;
    17392831        UnitInfoBtn.Visible := false;
    17402832        UnitBtn.Visible := false;
    17412833        TerrainBtn.Visible := false;
    1742         EOT.Hint := Phrases.Lookup('BTN_STOP');
    1743         EOT.Visible := true;
    1744       end
    1745       else if ClientMode < scContact then
    1746       begin
    1747         UnitInfoBtn.Visible := UnFocus >= 0;
    1748         UnitBtn.Visible := UnFocus >= 0;
    1749         CheckTerrainBtnVisible;
    1750         TurnComplete := supervising;
    1751         EOT.Hint := Phrases.Lookup('BTN_ENDTURN');
    1752         EOT.Visible := Server(sTurn - sExecute, me, 0, nil^) >= rExecuted;
    1753       end
    1754       else
    1755       begin
    1756         UnitInfoBtn.Visible := false;
    1757         UnitBtn.Visible := false;
    1758         TerrainBtn.Visible := false;
    1759         EOT.Hint := Phrases.Lookup('BTN_NEGO');
    1760         EOT.Visible := true;
    1761       end;
    1762       SetTroopLoc(-1);
    1763       MapValid := false;
    1764       NewAgeCenterTo := 0;
    1765       if ((MyRO.Turn = 0) and not supervising or IsMultiPlayerGame or
    1766         (ClientMode = cResume)) and (MyRO.nCity > 0) then
    1767       begin
    1768         Loc1 := MyCity[0].Loc;
    1769         if (ClientMode = cTurn) and (MyRO.Turn = 0) then
    1770         begin // move city out of center to not be covered by welcome screen
    1771           dx := MapWidth div (xxt * 5);
    1772           if dx > 5 then
    1773             dx := 5;
    1774           dy := MapHeight div (yyt * 5);
    1775           if dy > 5 then
    1776             dy := 5;
    1777           if Loc1 >= G.lx * G.ly div 2 then
     2834        MovieSpeed1Btn.Visible := false;
     2835        MovieSpeed2Btn.Visible := false;
     2836        MovieSpeed3Btn.Visible := false;
     2837        MovieSpeed4Btn.Visible := false;
     2838        EOT.Visible := false;
     2839        HelpDlg.Difficulty := 0;
     2840        BrushType := fGrass;
     2841        BrushLoc := -1;
     2842        Edited := false;
     2843        UnFocus := -1;
     2844        MarkCityLoc := -1;
     2845        Tracking := false;
     2846        TurnComplete := false;
     2847        MapValid := false;
     2848        FormResize(nil); // calculate geometrics and paint all
     2849        SetTroopLoc(-1);
     2850        idle := true
     2851      end;
     2852
     2853    (* cNewContact:
     2854      begin
     2855      end;
     2856    *)
     2857
     2858    scContact:
     2859      begin
     2860        DipMem[NewPlayer].pContact := integer(Data);
     2861        if Jump[NewPlayer] > 0 then
     2862          DipCall(scReject)
     2863        else
     2864        begin
     2865          ClientMode := Command;
     2866          InitTurn(NewPlayer);
     2867          MyData.ToldContact := MyData.ToldContact or (1 shl integer(Data));
     2868          // don't tell about new nation when already contacted by them
     2869          with MessgExDlg do
    17782870          begin
    1779             NewAgeCenterTo := -1;
    1780             Loc1 := dLoc(Loc1, -dx, -dy)
     2871            OpenSound := 'CONTACT_' + char(48 + MyRO.EnemyReport[integer(Data)
     2872              ].Attitude);
     2873            MessgText := Tribe[integer(Data)].TPhrase('FRCONTACT');
     2874            Kind := mkYesNo;
     2875            IconKind := mikTribe;
     2876            IconIndex := integer(Data);
     2877            ShowModal;
     2878            if ModalResult = mrOK then
     2879            begin
     2880              NegoDlg.Respond;
     2881              DipMem[me].DeliveredPrices := [];
     2882              DipMem[me].ReceivedPrices := [];
     2883              DipCall(scDipStart)
     2884            end
     2885            else
     2886            begin
     2887              DipCall(scReject);
     2888              EndNego
     2889            end
     2890          end
     2891        end;
     2892      end;
     2893
     2894    scDipStart .. scDipBreak:
     2895      begin
     2896        ClientMode := Command;
     2897        InitTurn(NewPlayer);
     2898        if Command = scDipStart then
     2899          Play('CONTACT_' + char(48 + MyRO.Attitude[DipMem[NewPlayer]
     2900            .pContact]))
     2901        else if Command = scDipCancelTreaty then
     2902          Play('CANCELTREATY')
     2903        else if Command = scDipOffer then
     2904        begin
     2905          ReceivedOffer := TOffer(Data);
     2906          InitAllEnemyModels;
     2907        end
     2908        else if Command = scDipAccept then
     2909        begin // remember delivered and received prices
     2910          for i := 0 to DipMem[me].SentOffer.nDeliver - 1 do
     2911            include(DipMem[me].DeliveredPrices,
     2912              DipMem[me].SentOffer.Price[i] shr 24);
     2913          for i := 0 to DipMem[me].SentOffer.nCost - 1 do
     2914            include(DipMem[me].ReceivedPrices,
     2915              DipMem[me].SentOffer.Price[DipMem[me].SentOffer.nDeliver +
     2916              i] shr 24);
     2917          IsTreatyDeal := false;
     2918          for i := 0 to ReceivedOffer.nDeliver + ReceivedOffer.nCost - 1 do
     2919            if DipMem[me].SentOffer.Price[i] and opMask = opTreaty then
     2920              IsTreatyDeal := true;
     2921          if IsTreatyDeal then
     2922            Play('NEWTREATY')
     2923          else
     2924            Play('ACCEPTOFFER');
     2925        end;
     2926        NegoDlg.Start;
     2927        idle := true
     2928      end;
     2929
     2930    cShowCancelTreaty:
     2931      if not IsMultiPlayerGame then
     2932      begin
     2933        case G.RO[NewPlayer].Treaty[integer(Data)] of
     2934          trPeace:
     2935            s := Tribe[integer(Data)].TPhrase('FRCANCELBYREJECT_PEACE');
     2936          trFriendlyContact:
     2937            s := Tribe[integer(Data)].TPhrase('FRCANCELBYREJECT_FRIENDLY');
     2938          trAlliance:
     2939            s := Tribe[integer(Data)].TPhrase('FRCANCELBYREJECT_ALLIANCE');
     2940        end;
     2941        TribeMessage(integer(Data), s, 'CANCELTREATY');
     2942      end;
     2943
     2944    cShowCancelTreatyByAlliance:
     2945      if idle and (NewPlayer = me) then
     2946        TribeMessage(integer(Data), Tribe[integer(Data)
     2947          ].TPhrase('FRENEMYALLIANCE'), 'CANCELTREATY');
     2948
     2949    cShowSupportAllianceAgainst:
     2950      if not IsMultiPlayerGame and (Jump[0] = 0) then
     2951        TribeMessage(integer(Data) and $F, Tribe[integer(Data) and $F]
     2952          .TPhrase('FRMYALLIANCE1') + ' ' + Tribe[integer(Data) shr 4]
     2953          .TPhrase('FRMYALLIANCE2'), 'CANCELTREATY');
     2954
     2955    cShowPeaceViolation:
     2956      if not IsMultiPlayerGame and (Jump[0] = 0) then
     2957        TribeMessage(integer(Data),
     2958          Format(Tribe[integer(Data)].TPhrase('EVIOLATION'),
     2959          [TurnToString(MyRO.Turn + PeaceEvaTurns - 1)]), 'MSG_WITHDRAW');
     2960
     2961    cShowEndContact:
     2962      EndNego;
     2963
     2964    cShowUnitChanged, cShowCityChanged, cShowAfterMove, cShowAfterAttack:
     2965      if (idle and (NewPlayer = me) or not idle and not skipped) and
     2966        not((GameMode = cMovie) and (MovieSpeed = 4)) then
     2967      begin
     2968        assert(NewPlayer = me);
     2969        if not idle or (GameMode = cMovie) then
     2970          Application.ProcessMessages;
     2971        if Command = cShowCityChanged then
     2972        begin
     2973          CurrentMoveInfo.DoShow := false;
     2974          if idle then
     2975            CurrentMoveInfo.DoShow := true
     2976          else if CurrentMoveInfo.IsAlly then
     2977            CurrentMoveInfo.DoShow := not mAlNoMoves.Checked
     2978          else
     2979            CurrentMoveInfo.DoShow := not mEnNoMoves.Checked
     2980        end
     2981        else if Command = cShowUnitChanged then
     2982        begin
     2983          CurrentMoveInfo.DoShow := false;
     2984          if idle then
     2985            CurrentMoveInfo.DoShow := not mEffectiveMovesOnly.Checked
     2986          else if CurrentMoveInfo.IsAlly then
     2987            CurrentMoveInfo.DoShow :=
     2988              not(mAlNoMoves.Checked or mAlEffectiveMovesOnly.Checked)
     2989          else
     2990            CurrentMoveInfo.DoShow :=
     2991              not(mEnNoMoves.Checked or mEnAttacks.Checked)
     2992        end;
     2993        // else keep DoShow from cShowMove/cShowAttack
     2994
     2995        if CurrentMoveInfo.DoShow then
     2996        begin
     2997          if Command = cShowCityChanged then
     2998            MapValid := false;
     2999          FocusOnLoc(integer(Data), flImmUpdate);
     3000          // OldUnFocus:=UnFocus;
     3001          // UnFocus:=-1;
     3002          if Command = cShowAfterMove then
     3003            PaintLoc(integer(Data), CurrentMoveInfo.AfterMovePaintRadius)
     3004            // show discovered areas
     3005          else
     3006            PaintLoc(integer(Data), 1);
     3007          // UnFocus:=OldUnFocus;
     3008          if (Command = cShowAfterAttack) and
     3009            (CurrentMoveInfo.AfterAttackExpeller >= 0) then
     3010          begin
     3011            SoundMessageEx(Tribe[CurrentMoveInfo.AfterAttackExpeller]
     3012              .TPhrase('EXPEL'), '');
     3013            CurrentMoveInfo.AfterAttackExpeller := -1;
     3014            Update; // remove message box from screen
     3015          end
     3016          else if not idle then
     3017            if Command = cShowCityChanged then
     3018              Sleep(MoveTime * WaitAfterShowMove div 16)
     3019            else if (Command = cShowUnitChanged) and
     3020              (MyMap[integer(Data)] and fUnit <> 0) then
     3021              Sleep(MoveTime * WaitAfterShowMove div 32)
     3022        end // if CurrentMoveInfo.DoShow
     3023        else
     3024          MapValid := false;
     3025      end;
     3026
     3027    cShowMoving, cShowCapturing:
     3028      if (idle and (NewPlayer = me) or not idle and not skipped and
     3029        (TShowMove(Data).emix <> $FFFF)) and
     3030        not((GameMode = cMovie) and (MovieSpeed = 4)) then
     3031      begin
     3032        assert(NewPlayer = me);
     3033        if not idle or (GameMode = cMovie) then
     3034          Application.ProcessMessages;
     3035        with TShowMove(Data) do
     3036        begin
     3037          CurrentMoveInfo.DoShow := false;
     3038          if not idle and (Tribe[Owner].ModelPicture[mix].HGr = 0) then
     3039            InitEnemyModel(emix);
     3040
     3041          ToLoc := dLoc(FromLoc, dx, dy);
     3042          if idle then
     3043          begin // own unit -- make discovered land visible
     3044            assert(Owner = me); // no foreign moves during my turn!
     3045            CurrentMoveInfo.DoShow := not mEffectiveMovesOnly.Checked or
     3046              (Command = cShowCapturing);
     3047            if CurrentMoveInfo.DoShow then
     3048            begin
     3049              if GameMode = cMovie then
     3050              begin
     3051                if MovieSpeed = 3 then
     3052                  AnimationSpeed := 4
     3053                else if MovieSpeed = 2 then
     3054                  AnimationSpeed := 8
     3055                else
     3056                  AnimationSpeed := 16;
     3057              end
     3058              else
     3059              begin
     3060                if mVeryFastMoves.Checked then
     3061                  AnimationSpeed := 4
     3062                else if mFastMoves.Checked then
     3063                  AnimationSpeed := 8
     3064                else
     3065                  AnimationSpeed := 16;
     3066              end;
     3067              with MyModel[mix] do
     3068              begin
     3069                if (Kind = mkDiplomat) or (Domain = dAir) or
     3070                  (Cap[mcRadar] + Cap[mcCarrier] + Cap[mcAcademy] > 0) or
     3071                  (MyMap[ToLoc] and fTerrain = fMountains) or
     3072                  (MyMap[ToLoc] and fTerImp = tiFort) or
     3073                  (MyMap[ToLoc] and fTerImp = tiBase) then
     3074                  CurrentMoveInfo.AfterMovePaintRadius := 2
     3075                else
     3076                  CurrentMoveInfo.AfterMovePaintRadius := 1;
     3077                if (MyRO.Wonder[woShinkansen].EffectiveOwner = me) and
     3078                  (Domain = dGround) and
     3079                  (MyMap[FromLoc] and (fRR or fCity) <> 0) and
     3080                  (MyMap[ToLoc] and (fRR or fCity) <> 0) and
     3081                  (Flags and umPlaneUnloading = 0) then
     3082                  AnimationSpeed := 4;
     3083                ShowMoveDomain := Domain;
     3084                IsAlpine := Cap[mcAlpine] > 0;
     3085              end
     3086            end
    17813087          end
    17823088          else
    17833089          begin
    1784             NewAgeCenterTo := 1;
    1785             Loc1 := dLoc(Loc1, -dx, dy);
    1786           end
    1787         end;
    1788         Centre(Loc1)
    1789       end;
    1790 
    1791       for i := 0 to Screen.FormCount - 1 do
    1792         if Screen.Forms[i] is TBufferedDrawDlg then
    1793           Screen.Forms[i].Enabled := true;
    1794 
    1795       if ClientMode <> cResume then
    1796       begin
    1797         PaintAll;
    1798         if (MyRO.Happened and phChangeGov <> 0) and (MyRO.NatBuilt[imPalace] > 0)
    1799         then
    1800           ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, imPalace,
    1801             gAnarchy { , GameMode<>cMovie } );
    1802         // first turn after anarchy -- don't show despotism palace!
    1803         Update;
    1804         for i := 0 to Screen.FormCount - 1 do
    1805           if (Screen.Forms[i].Visible) and (Screen.Forms[i] is TBufferedDrawDlg)
    1806           then
    1807           begin
    1808             if @Screen.Forms[i].OnShow <> nil then
    1809               Screen.Forms[i].OnShow(nil);
    1810             Screen.Forms[i].Invalidate;
    1811             Screen.Forms[i].Update;
    1812           end;
    1813 
    1814         if MyRO.Happened and phGameEnd <> 0 then
    1815           with MessgExDlg do
    1816           begin // game ended
    1817             if MyRO.Happened and phExtinct <> 0 then
    1818             begin
    1819               OpenSound := 'MSG_GAMEOVER';
    1820               MessgText := Tribe[me].TPhrase('GAMEOVER');
    1821               IconKind := mikBigIcon;
    1822               IconIndex := 8;
    1823             end
    1824             else if MyRO.Happened and phShipComplete <> 0 then
    1825             begin
    1826               Winners := 0;
    1827               for p1 := 0 to nPl - 1 do
    1828                 if 1 shl p1 and MyRO.Alive <> 0 then
    1829                 begin
    1830                   Winners := Winners or 1 shl p1;
    1831                   for i := 0 to nShipPart - 1 do
    1832                     if MyRO.Ship[p1].Parts[i] < ShipNeed[i] then
    1833                       Winners := Winners and not(1 shl p1);
    1834                 end;
    1835               assert(Winners <> 0);
    1836               if Winners and (1 shl me) <> 0 then
    1837               begin
    1838                 s := '';
    1839                 for p1 := 0 to nPl - 1 do
    1840                   if (p1 <> me) and (1 shl p1 and Winners <> 0) then
    1841                     if s = '' then
    1842                       s := Tribe[p1].TPhrase('SHORTNAME')
    1843                     else
    1844                       s := Format(Phrases.Lookup('SHAREDWIN_CONCAT'),
    1845                         [s, Tribe[p1].TPhrase('SHORTNAME')]);
    1846 
    1847                 OpenSound := 'MSG_YOUWIN';
    1848                 MessgText := Tribe[me].TPhrase('MYSPACESHIP');
    1849                 if s <> '' then
    1850                   MessgText := MessgText + '\' +
    1851                     Format(Phrases.Lookup('SHAREDWIN'), [s]);
    1852                 IconKind := mikBigIcon;
    1853                 IconIndex := 9;
    1854               end
    1855               else
    1856               begin
    1857                 assert(me = 0);
    1858                 OpenSound := 'MSG_GAMEOVER';
    1859                 MessgText := '';
    1860                 for p1 := 0 to nPl - 1 do
    1861                   if Winners and (1 shl p1) <> 0 then
    1862                     MessgText := MessgText + Tribe[p1].TPhrase('SPACESHIP1');
    1863                 MessgText := MessgText + '\' + Phrases.Lookup('SPACESHIP2');
    1864                 IconKind := mikEnemyShipComplete;
    1865               end
    1866             end
    1867             else { if MyRO.Happened and fTimeUp<>0 then }
    1868             begin
    1869               assert(me = 0);
    1870               OpenSound := 'MSG_GAMEOVER';
    1871               if not supervising then
    1872                 MessgText := Tribe[me].TPhrase('TIMEUP')
    1873               else
    1874                 MessgText := Phrases.Lookup('TIMEUPSUPER');
    1875               IconKind := mikImp;
    1876               IconIndex := 22;
    1877             end;
    1878             Kind := mkOk;
    1879             ShowModal;
    1880             if MyRO.Happened and phExtinct = 0 then
    1881             begin
    1882               p1 := 0;
    1883               while (p1 < nPl - 1) and (Winners and (1 shl p1) = 0) do
    1884                 inc(p1);
    1885               if MyRO.Happened and phShipComplete = 0 then
    1886                 DiaDlg.ShowNewContent_Charts(wmModal);
    1887             end;
    1888             TurnComplete := true;
    1889             exit;
    1890           end;
    1891         if not supervising and (1 shl me and MyRO.Alive = 0) then
    1892         begin
    1893           TurnComplete := true;
    1894           exit;
    1895         end;
    1896 
    1897         if (ClientMode = cContinue) and
    1898           (DipMem[me].SentCommand and $FF0F = scContact) then
    1899           // contact was refused
    1900           if MyRO.Treaty[DipMem[me].pContact] >= trPeace then
    1901             ContactRefused(DipMem[me].pContact, 'FRREJECTED')
    1902           else
    1903             SoundMessage(Tribe[DipMem[me].pContact].TPhrase('FRREJECTED'),
    1904               'NEGO_REJECTED');
    1905 
    1906         if not supervising and (Age > MyData.ToldAge) and
    1907           ((Age > 0) or (ClientMode <> cMovieTurn)) then
    1908           with MessgExDlg do
    1909           begin
    1910             if Age = 0 then
    1911             begin
    1912               if Phrases2FallenBackToEnglish then
    1913               begin
    1914                 s := Tribe[me].TPhrase('AGE0');
    1915                 MessgText :=
    1916                   Format(s, [TurnToString(MyRO.Turn), CityName(MyCity[0].ID)])
    1917               end
    1918               else
    1919               begin
    1920                 s := Tribe[me].TString(Phrases2.Lookup('AGE0'));
    1921                 MessgText := Format(s, [TurnToString(MyRO.Turn)]);
    1922               end
    1923             end
    1924             else
    1925             begin
    1926               s := Tribe[me].TPhrase('AGE' + char(48 + Age));
    1927               MessgText := Format(s, [TurnToString(MyRO.Turn)]);
    1928             end;
    1929             IconKind := mikAge;
    1930             IconIndex := Age;
    1931             { if age=0 then } Kind := mkOk
    1932             { else begin Kind:=mkOkHelp; HelpKind:=hkAdv; HelpNo:=AgePreq[age]; end };
    1933             CenterTo := NewAgeCenterTo;
    1934             OpenSound := 'AGE_' + char(48 + Age);
    1935             ShowModal;
    1936             MyData.ToldAge := Age;
    1937             if Age > 0 then
    1938               MyData.ToldTech[AgePreq[Age]] := MyRO.Tech[AgePreq[Age]];
    1939           end;
    1940 
    1941         if MyData.ToldAlive <> MyRO.Alive then
    1942         begin
    1943           for p1 := 0 to nPl - 1 do
    1944             if (MyData.ToldAlive - MyRO.Alive) and (1 shl p1) <> 0 then
    1945               with MessgExDlg do
    1946               begin
    1947                 OpenSound := 'MSG_EXTINCT';
    1948                 s := Tribe[p1].TPhrase('EXTINCT');
    1949                 MessgText := Format(s, [TurnToString(MyRO.Turn)]);
    1950                 if MyRO.Alive = 1 shl me then
    1951                   MessgText := MessgText + Phrases.Lookup('EXTINCTALL');
    1952                 Kind := mkOk;
    1953                 IconKind := mikImp;
    1954                 IconIndex := 21;
    1955                 ShowModal;
    1956               end;
    1957           if (ClientMode <> cMovieTurn) and not supervising then
    1958             DiaDlg.ShowNewContent_Charts(wmModal);
    1959         end;
    1960 
    1961         // tell changes of own credibility
    1962         if not supervising then
    1963         begin
    1964           if RoughCredibility(MyRO.Credibility) <>
    1965             RoughCredibility(MyData.ToldOwnCredibility) then
    1966           begin
    1967             if RoughCredibility(MyRO.Credibility) >
    1968               RoughCredibility(MyData.ToldOwnCredibility) then
    1969               s := Phrases.Lookup('CREDUP')
    1970             else
    1971               s := Phrases.Lookup('CREDDOWN');
    1972             TribeMessage(me,
    1973               Format(s, [Phrases.Lookup('CREDIBILITY',
    1974               RoughCredibility(MyRO.Credibility))]), '');
    1975           end;
    1976           MyData.ToldOwnCredibility := MyRO.Credibility;
    1977         end;
    1978 
    1979         for i := 0 to 27 do
    1980         begin
    1981           OwnWonder := false;
    1982           for cix := 0 to MyRO.nCity - 1 do
    1983             if (MyCity[cix].Loc >= 0) and
    1984               (MyCity[cix].ID = MyRO.Wonder[i].CityID) then
    1985               OwnWonder := true;
    1986           if MyRO.Wonder[i].CityID <> MyData.ToldWonders[i].CityID then
    1987           begin
    1988             if MyRO.Wonder[i].CityID = -2 then
    1989               with MessgExDlg do
    1990               begin { tell about destroyed wonders }
    1991                 OpenSound := 'WONDER_DESTROYED';
    1992                 MessgText := Format(Phrases.Lookup('WONDERDEST'),
    1993                   [Phrases.Lookup('IMPROVEMENTS', i)]);
    1994                 Kind := mkOkHelp;
    1995                 HelpKind := hkImp;
    1996                 HelpNo := i;
    1997                 IconKind := mikImp;
    1998                 IconIndex := i;
    1999                 ShowModal;
    2000               end
    2001             else
    2002             begin
    2003               if i = woManhattan then
    2004                 if MyRO.Wonder[i].EffectiveOwner > me then
    2005                   MyData.ColdWarStart := MyRO.Turn - 1
    2006                 else
    2007                   MyData.ColdWarStart := MyRO.Turn;
    2008               if not OwnWonder then
    2009                 with MessgExDlg do
    2010                 begin { tell about newly built wonders }
    2011                   if i = woManhattan then
    2012                   begin
    2013                     OpenSound := 'MSG_COLDWAR';
    2014                     s := Tribe[MyRO.Wonder[i].EffectiveOwner].TPhrase('COLDWAR')
    2015                   end
    2016                   else if MyRO.Wonder[i].EffectiveOwner >= 0 then
    2017                   begin
    2018                     OpenSound := 'WONDER_BUILT';
    2019                     s := Tribe[MyRO.Wonder[i].EffectiveOwner]
    2020                       .TPhrase('WONDERBUILT')
    2021                   end
    2022                   else
    2023                   begin
    2024                     OpenSound := 'MSG_DEFAULT';
    2025                     s := Phrases.Lookup('WONDERBUILTEXP');
    2026                     // already expired when built
    2027                   end;
    2028                   MessgText := Format(s, [Phrases.Lookup('IMPROVEMENTS', i),
    2029                     CityName(MyRO.Wonder[i].CityID)]);
    2030                   Kind := mkOkHelp;
    2031                   HelpKind := hkImp;
    2032                   HelpNo := i;
    2033                   IconKind := mikImp;
    2034                   IconIndex := i;
    2035                   ShowModal;
    2036                 end
    2037             end
    2038           end
    2039           else if (MyRO.Wonder[i].EffectiveOwner <> MyData.ToldWonders[i]
    2040             .EffectiveOwner) and (MyRO.Wonder[i].CityID > -2) then
    2041             if MyRO.Wonder[i].EffectiveOwner < 0 then
    2042             begin
    2043               if i <> woMIR then
    2044                 with MessgExDlg do
    2045                 begin { tell about expired wonders }
    2046                   OpenSound := 'WONDER_EXPIRED';
    2047                   MessgText := Format(Phrases.Lookup('WONDEREXP'),
    2048                     [Phrases.Lookup('IMPROVEMENTS', i),
    2049                     CityName(MyRO.Wonder[i].CityID)]);
    2050                   Kind := mkOkHelp;
    2051                   HelpKind := hkImp;
    2052                   HelpNo := i;
    2053                   IconKind := mikImp;
    2054                   IconIndex := i;
    2055                   ShowModal;
    2056                 end
    2057             end
    2058             else if (MyData.ToldWonders[i].EffectiveOwner >= 0) and not OwnWonder
    2059             then
    2060               with MessgExDlg do
    2061               begin { tell about capture of wonders }
    2062                 OpenSound := 'WONDER_CAPTURED';
    2063                 s := Tribe[MyRO.Wonder[i].EffectiveOwner].TPhrase('WONDERCAPT');
    2064                 MessgText := Format(s, [Phrases.Lookup('IMPROVEMENTS', i),
    2065                   CityName(MyRO.Wonder[i].CityID)]);
    2066                 Kind := mkOkHelp;
    2067                 HelpKind := hkImp;
    2068                 HelpNo := i;
    2069                 IconKind := mikImp;
    2070                 IconIndex := i;
    2071                 ShowModal;
    2072               end;
    2073         end;
    2074 
    2075         if MyRO.Turn = MyData.ColdWarStart + ColdWarTurns then
    2076         begin
    2077           SoundMessageEx(Phrases.Lookup('COLDWAREND'), 'MSG_DEFAULT');
    2078           MyData.ColdWarStart := -ColdWarTurns - 1
    2079         end;
    2080 
    2081         TellNewModels;
    2082       end; // ClientMode<>cResume
    2083       MyData.ToldAlive := MyRO.Alive;
    2084       move(MyRO.Wonder, MyData.ToldWonders, SizeOf(MyData.ToldWonders));
    2085 
    2086       NewGovAvailable := -1;
    2087       if ClientMode <> cResume then
    2088       begin // tell about new techs
    2089         for ad := 0 to nAdv - 1 do
    2090           if (MyRO.TestFlags and tfAllTechs = 0) and
    2091             ((MyRO.Tech[ad] >= tsApplicable) <>
    2092             (MyData.ToldTech[ad] >= tsApplicable)) or (ad in FutureTech) and
    2093             (MyRO.Tech[ad] <> MyData.ToldTech[ad]) then
    2094             with MessgExDlg do
    2095             begin
    2096               Item := 'RESEARCH_GENERAL';
    2097               if GameMode <> cMovie then
    2098                 OpenSound := 'NEWADVANCE_' + char(48 + Age);
    2099               Item2 := Phrases.Lookup('ADVANCES', ad);
    2100               if ad in FutureTech then
    2101                 Item2 := Item2 + ' ' + IntToStr(MyRO.Tech[ad]);
    2102               MessgText := Format(Phrases.Lookup(Item), [Item2]);
    2103               Kind := mkOkHelp;
    2104               HelpKind := hkAdv;
    2105               HelpNo := ad;
    2106               IconKind := mikBook;
    2107               IconIndex := -1;
    2108               for i := 0 to nAdvBookIcon - 1 do
    2109                 if AdvBookIcon[i].Adv = ad then
    2110                   IconIndex := AdvBookIcon[i].Icon;
    2111               ShowModal;
    2112               MyData.ToldTech[ad] := MyRO.Tech[ad];
    2113               for i := gMonarchy to nGov - 1 do
    2114                 if GovPreq[i] = ad then
    2115                   NewGovAvailable := i;
    2116             end;
    2117       end;
    2118 
    2119       ShowCityList := false;
    2120       if ClientMode = cTurn then
    2121       begin
    2122         if (MyRO.Happened and phTech <> 0) and (MyData.FarTech <> adNexus) then
    2123           ChooseResearch;
    2124 
    2125         UpdatePanel := false;
    2126         if MyRO.Happened and phChangeGov <> 0 then
    2127         begin
    2128           ModalSelectDlg.ShowNewContent(wmModal, kGov);
    2129           Play('NEWGOV');
    2130           Server(sSetGovernment, me, ModalSelectDlg.result, nil^);
    2131           CityOptimizer_BeginOfTurn;
    2132           UpdatePanel := true;
    2133         end;
    2134       end; // ClientMode=cTurn
    2135 
    2136       if not supervising and ((ClientMode = cTurn) or (ClientMode = cMovieTurn))
    2137       then
    2138         for cix := 0 to MyRO.nCity - 1 do
    2139           with MyCity[cix] do
    2140             Status := Status and not csToldBombard;
    2141 
    2142       if ((ClientMode = cTurn) or (ClientMode = cMovieTurn)) and
    2143         (MyRO.Government <> gAnarchy) then
    2144       begin
    2145         // tell what happened in cities
    2146         for WondersOnly := true downto false do
    2147           for cix := 0 to MyRO.nCity - 1 do
    2148             with MyCity[cix] do
    2149               if (MyRO.Turn > 0) and (Loc >= 0) and (Flags and chCaptured = 0)
    2150                 and (WondersOnly = (Flags and chProduction <> 0) and
    2151                 (Project0 and cpImp <> 0) and (Project0 and cpIndex < 28)) then
    2152               begin
    2153                 if WondersOnly then
    2154                   with MessgExDlg do
    2155                   begin { tell about newly built wonder }
    2156                     OpenSound := 'WONDER_BUILT';
    2157                     s := Tribe[me].TPhrase('WONDERBUILTOWN');
    2158                     MessgText :=
    2159                       Format(s, [Phrases.Lookup('IMPROVEMENTS',
    2160                       Project0 and cpIndex), CityName(ID)]);
    2161                     Kind := mkOkHelp;
    2162                     HelpKind := hkImp;
    2163                     HelpNo := Project0 and cpIndex;
    2164                     IconKind := mikImp;
    2165                     IconIndex := Project0 and cpIndex;
    2166                     ShowModal;
    2167                   end;
    2168                 if not supervising and (ClientMode = cTurn) then
    2169                 begin
    2170                   AllowCityScreen := true;
    2171                   if (Status and 7 <> 0) and
    2172                     (Project and (cpImp + cpIndex) = cpImp + imTrGoods) then
    2173                     if (MyData.ImpOrder[Status and 7 - 1, 0] >= 0) then
    2174                     begin
    2175                       if AutoBuild(cix, MyData.ImpOrder[Status and 7 - 1]) then
    2176                         AllowCityScreen := false
    2177                       else if Flags and chProduction <> 0 then
    2178                         Flags := (Flags and not chProduction) or chAllImpsMade
    2179                     end
    2180                     else
    2181                       Flags := Flags or chTypeDel;
    2182                   if (Size >= NeedAqueductSize) and
    2183                     (MyRO.Tech[Imp[imAqueduct].Preq] < tsApplicable) or
    2184                     (Size >= NeedSewerSize) and
    2185                     (MyRO.Tech[Imp[imSewer].Preq] < tsApplicable) then
    2186                     Flags := Flags and not chNoGrowthWarning;
    2187                   // don't remind of unknown building
    2188                   if Flags and chNoSettlerProd = 0 then
    2189                     Status := Status and not csToldDelay
    2190                   else if Status and csToldDelay = 0 then
    2191                     Status := Status or csToldDelay
    2192                   else
    2193                     Flags := Flags and not chNoSettlerProd;
    2194                   if mRepScreens.Checked then
    2195                   begin
    2196                     if (Flags and CityRepMask <> 0) and AllowCityScreen then
    2197                     begin { show what happened in cities }
    2198                       SetTroopLoc(MyCity[cix].Loc);
    2199                       MarkCityLoc := MyCity[cix].Loc;
    2200                       PanelPaint;
    2201                       CityDlg.CloseAction := None;
    2202                       CityDlg.ShowNewContent(wmModal, MyCity[cix].Loc,
    2203                         Flags and CityRepMask);
    2204                       UpdatePanel := true;
    2205                     end
    2206                   end
    2207                   else { if mRepList.Checked then }
    2208                   begin
    2209                     if Flags and CityRepMask <> 0 then
    2210                       ShowCityList := true
    2211                   end
    2212                 end
    2213               end; { city loop }
    2214       end; // ClientMode=cTurn
    2215 
    2216       if ClientMode = cTurn then
    2217       begin
    2218         if NewGovAvailable >= 0 then
    2219           with MessgExDlg do
    2220           begin
    2221             MessgText := Format(Phrases.Lookup('AUTOREVOLUTION'),
    2222               [Phrases.Lookup('GOVERNMENT', NewGovAvailable)]);
    2223             Kind := mkYesNo;
    2224             IconKind := mikPureIcon;
    2225             IconIndex := 6 + NewGovAvailable;
    2226             ShowModal;
    2227             if ModalResult = mrOK then
    2228             begin
    2229               Play('REVOLUTION');
    2230               Server(sRevolution, me, 0, nil^);
    2231             end
    2232           end;
    2233       end; // ClientMode=cTurn
    2234 
    2235       if (ClientMode = cTurn) or (ClientMode = cMovieTurn) then
    2236       begin
    2237         if MyRO.Happened and phGliderLost <> 0 then
    2238           ContextMessage(Phrases.Lookup('GLIDERLOST'), 'MSG_DEFAULT',
    2239             hkModel, 200);
    2240         if MyRO.Happened and phPlaneLost <> 0 then
    2241           ContextMessage(Phrases.Lookup('PLANELOST'), 'MSG_DEFAULT',
    2242             hkFeature, mcFuel);
    2243         if MyRO.Happened and phPeaceEvacuation <> 0 then
    2244           for p1 := 0 to nPl - 1 do
    2245             if 1 shl p1 and MyData.PeaceEvaHappened <> 0 then
    2246               SoundMessageEx(Tribe[p1].TPhrase('WITHDRAW'), 'MSG_DEFAULT');
    2247         if MyRO.Happened and phPeaceViolation <> 0 then
    2248           for p1 := 0 to nPl - 1 do
    2249             if (1 shl p1 and MyRO.Alive <> 0) and (MyRO.EvaStart[p1] = MyRO.Turn)
    2250             then
    2251               SoundMessageEx(Format(Tribe[p1].TPhrase('VIOLATION'),
    2252                 [TurnToString(MyRO.Turn + PeaceEvaTurns - 1)]), 'MSG_WITHDRAW');
    2253         TellNewContacts;
    2254       end;
    2255 
    2256       if ClientMode = cMovieTurn then
    2257         Update
    2258       else if ClientMode = cTurn then
    2259       begin
    2260         if UpdatePanel then
    2261           UpdateViews;
    2262         Application.ProcessMessages;
    2263 
    2264         if not supervising then
    2265           for uix := 0 to MyRO.nUn - 1 do
    2266             with MyUn[uix] do
    2267               if Loc >= 0 then
    2268               begin
    2269                 if Flags and unWithdrawn <> 0 then
    2270                   Status := 0;
    2271                 if Health = 100 then
    2272                   Status := Status and not usRecover;
    2273                 if (Master >= 0) or UnitExhausted(uix) then
    2274                   Status := Status and not usWaiting
    2275                 else
    2276                   Status := Status or usWaiting;
    2277                 CheckToldNoReturn(uix);
    2278                 if Status and usGoto <> 0 then
    2279                 begin { continue multi-turn goto }
    2280                   SetUnFocus(uix);
    2281                   SetTroopLoc(Loc);
    2282                   FocusOnLoc(TroopLoc, flRepaintPanel or flImmUpdate);
    2283                   if Status shr 16 = $7FFF then
    2284                     MoveResult := GetMoveAdvice(UnFocus, maNextCity,
    2285                       MoveAdviceData)
    2286                   else
    2287                     MoveResult := GetMoveAdvice(UnFocus, Status shr 16,
    2288                       MoveAdviceData);
    2289                   if MoveResult >= rExecuted then
    2290                   begin // !!! Shinkansen
    2291                     MoveResult := eOK;
    2292                     ok := true;
    2293                     for i := 0 to MoveAdviceData.nStep - 1 do
    2294                     begin
    2295                       Loc1 := dLoc(Loc, MoveAdviceData.dx[i],
    2296                         MoveAdviceData.dy[i]);
    2297                       if (MyMap[Loc1] and (fCity or fOwned) = fCity)
    2298                       // don't capture cities during auto move
    2299                         or (MyMap[Loc1] and (fUnit or fOwned) = fUnit) then
    2300                       // don't attack during auto move
    2301                       begin
    2302                         ok := false;
    2303                         Break
    2304                       end
    2305                       else
    2306                       begin
    2307                         if (Loc1 = MoveAdviceData.ToLoc) or
    2308                           (MoveAdviceData.ToLoc = maNextCity) and
    2309                           (MyMap[dLoc(Loc, MoveAdviceData.dx[i],
    2310                           MoveAdviceData.dy[i])] and fCity <> 0) then
    2311                           MoveOptions := muAutoNoWait
    2312                         else
    2313                           MoveOptions := 0;
    2314                         MoveResult := MoveUnit(MoveAdviceData.dx[i],
    2315                           MoveAdviceData.dy[i], MoveOptions);
    2316                         if (MoveResult < rExecuted) or
    2317                           (MoveResult = eEnemySpotted) then
    2318                         begin
    2319                           ok := false;
    2320                           Break
    2321                         end;
    2322                       end
    2323                     end;
    2324                     Stop := not ok or (Loc = MoveAdviceData.ToLoc) or
    2325                       (MoveAdviceData.ToLoc = maNextCity) and
    2326                       (MyMap[Loc] and fCity <> 0)
    2327                   end
    2328                   else
    2329                   begin
    2330                     MoveResult := eOK;
    2331                     Stop := true;
    2332                   end;
    2333 
    2334                   if MoveResult <> eDied then
    2335                     if Stop then
    2336                       Status := Status and ($FFFF - usGoto)
    2337                     else
    2338                       Status := Status and not usWaiting;
    2339                 end;
    2340 
    2341                 if Status and (usEnhance or usGoto) = usEnhance then
    2342                 // continue terrain enhancement
    2343                 begin
    2344                   MoveResult := ProcessEnhancement(uix, MyData.EnhancementJobs);
    2345                   if MoveResult <> eDied then
    2346                     if MoveResult = eJobDone then
    2347                       Status := Status and not usEnhance
    2348                     else
    2349                       Status := Status and not usWaiting;
    2350                 end
    2351               end;
    2352       end; // ClientMode=cTurn
    2353 
    2354       HaveStrategyAdvice := false;
    2355       // (GameMode<>cMovie) and not supervising
    2356       // and AdvisorDlg.HaveStrategyAdvice;
    2357       GoOnPhase := true;
    2358       if supervising or (GameMode = cMovie) then
    2359       begin
    2360         SetTroopLoc(-1);
    2361         PaintAll
    2362       end { supervisor }
    2363       { else if (ClientMode=cTurn) and (MyRO.Turn=0) then
    2364         begin
    2365         SetUnFocus(0);
    2366         ZoomToCity(MyCity[0].Loc)
    2367         end }
    2368       else
    2369       begin
    2370         if ClientMode >= scContact then
    2371           SetUnFocus(-1)
    2372         else
    2373           NextUnit(-1, false);
    2374         if UnFocus < 0 then
    2375         begin
    2376           UnStartLoc := -1;
    2377           if IsMultiPlayerGame or (ClientMode = cResume) then
    2378             if MyRO.nCity > 0 then
    2379               FocusOnLoc(MyCity[0].Loc)
    2380             else
    2381               FocusOnLoc(G.lx * G.ly div 2);
    2382           SetTroopLoc(-1);
    2383           PanelPaint
    2384         end;
    2385         if ShowCityList then
    2386           ListDlg.ShowNewContent(wmPersistent, kCityEvents);
    2387       end;
    2388     end; { InitTurn }
    2389 
    2390   var
    2391     i, j, p1, mix, ToLoc, AnimationSpeed, ShowMoveDomain, cix, ecix: integer;
    2392     Color: TColor;
    2393     Name, s: string;
    2394     TribeInfo: TTribeInfo;
    2395     mi: TModelInfo;
    2396     SkipTurn, IsAlpine, IsTreatyDeal: boolean;
    2397 
    2398   begin { >>>client }
    2399     case Command of
    2400       cTurn, cResume, cContinue, cMovieTurn, scContact,
    2401         scDipStart .. scDipBreak:
    2402         begin
    2403           supervising := G.Difficulty[NewPlayer] = 0;
    2404           ArrangeMidPanel;
    2405         end
    2406     end;
    2407     case Command of
    2408       cDebugMessage:
    2409         LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(@Data));
    2410 
    2411       cShowNego:
    2412         with TShowNegoData(Data) do
    2413         begin
    2414           s := Format('P%d to P%d: ', [pSender, pTarget]);
    2415           if (Action = scDipOffer) and (Offer.nDeliver + Offer.nCost > 0) then
    2416           begin
    2417             s := s + 'Offer ';
    2418             for i := 0 to Offer.nDeliver + Offer.nCost - 1 do
    2419             begin
    2420               if i = Offer.nDeliver then
    2421                 s := s + ' for '
    2422               else if i > 0 then
    2423                 s := s + '+';
    2424               case Offer.Price[i] and opMask of
    2425                 opChoose:
    2426                   s := s + 'Price of choice';
    2427                 opCivilReport:
    2428                   s := s + 'State report';
    2429                 opMilReport:
    2430                   s := s + 'Military report';
    2431                 opMap:
    2432                   s := s + 'Map';
    2433                 opTreaty:
    2434                   s := s + 'Treaty';
    2435                 opShipParts:
    2436                   s := s + 'Ship part';
    2437                 opMoney:
    2438                   s := s + IntToStr(Offer.Price[i] and $FFFFFF) + 'o';
    2439                 opTribute:
    2440                   s := s + IntToStr(Offer.Price[i] and $FFFFFF) + 'o tribute';
    2441                 opTech:
    2442                   s := s + Phrases.Lookup('ADVANCES',
    2443                     Offer.Price[i] and $FFFFFF);
    2444                 opAllTech:
    2445                   s := s + 'All advances';
    2446                 opModel:
    2447                   s := s + Tribe[pSender].ModelName[Offer.Price[i] and $FFFFFF];
    2448                 opAllModel:
    2449                   s := s + 'All models';
    2450               end
    2451             end;
    2452             LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(s));
    2453           end
    2454           else if Action = scDipAccept then
    2455           begin
    2456             s := s + '--- ACCEPTED! ---';
    2457             LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(s));
    2458           end
    2459         end;
    2460 
    2461       cInitModule:
    2462         begin
    2463           Server := TInitModuleData(Data).Server;
    2464           // AdvisorDlg.Init;
    2465           InitModule;
    2466           TInitModuleData(Data).DataSize := SizeOf(TPersistentData);
    2467           TInitModuleData(Data).Flags := aiThreaded;
    2468         end;
    2469 
    2470       cReleaseModule:
    2471         begin
    2472           SmallImp.free;
    2473           UnusedTribeFiles.free;
    2474           TribeNames.free;
    2475           MainMap.free;
    2476           IsoEngine.Done;
    2477           // AdvisorDlg.DeInit;
    2478         end;
    2479 
    2480       cHelpOnly, cStartHelp, cStartCredits:
    2481         begin
    2482           Age := 0;
    2483           if Command = cHelpOnly then
    2484             SetMainTextureByAge(-1);
    2485           Tribes.Init;
    2486           HelpDlg.UserLeft := (Screen.width - HelpDlg.width) div 2;
    2487           HelpDlg.UserTop := (Screen.height - HelpDlg.height) div 2;
    2488           HelpDlg.Difficulty := 0;
    2489           if Command = cStartCredits then
    2490             HelpDlg.ShowNewContent(wmModal, hkMisc, miscCredits)
    2491           else
    2492             HelpDlg.ShowNewContent(wmModal, hkMisc, miscMain);
    2493           Tribes.Done;
    2494         end;
    2495 
    2496       cNewGame, cLoadGame, cMovie, cNewMap:
    2497         begin
    2498           { if (Command=cNewGame) or (Command=cLoadGame) then
    2499             AdvisorDlg.NewGame(Data); }
    2500           GenerateNames := mNames.Checked;
    2501           GameOK := true;
    2502           G := TNewGameData(Data);
    2503           me := -1;
    2504           pLogo := -1;
    2505           ClientMode := -1;
    2506           SetMapOptions;
    2507           IsoEngine.pDebugMap := -1;
    2508           idle := false;
    2509           FillChar(Jump, SizeOf(Jump), 0);
    2510           if StartRunning then
    2511             Jump[0] := 999999;
    2512           GameMode := Command;
    2513           for i := 0 to nGrExt - 1 do
    2514             FillChar(GrExt[i].pixUsed, GrExt[i].Data.height div 49 * 10, 0);
    2515           IsoEngine.Reset;
    2516           Tribes.Init;
    2517           GetTribeList;
    2518           for p1 := 0 to nPl - 1 do
    2519             if (G.RO[p1] <> nil) and (G.RO[p1].Data <> nil) then
    2520               with TPersistentData(G.RO[p1].Data^) do
    2521               begin
    2522                 FarTech := adNone;
    2523                 FillChar(EnhancementJobs, SizeOf(EnhancementJobs), jNone);
    2524                 FillChar(ImpOrder, SizeOf(ImpOrder), Byte(-1));
    2525                 ColdWarStart := -ColdWarTurns - 1;
    2526                 ToldAge := -1;
    2527                 ToldModels := 3;
    2528                 ToldAlive := 0;
    2529                 ToldContact := 0;
    2530                 ToldOwnCredibility := InitialCredibility;
    2531                 for i := 0 to nPl - 1 do
    2532                   if G.Difficulty[i] > 0 then
    2533                     inc(ToldAlive, 1 shl i);
    2534                 PeaceEvaHappened := 0;
    2535                 for i := 0 to 27 do
    2536                   with ToldWonders[i] do
    2537                   begin
    2538                     CityID := -1;
    2539                     EffectiveOwner := -1
    2540                   end;
    2541                 FillChar(ToldTech, SizeOf(ToldTech), Byte(tsNA));
    2542                 if G.Difficulty[p1] > 0 then
    2543                   SoundPreload(sbStart);
    2544               end;
    2545 
    2546           // arrange dialogs
    2547           ListDlg.UserLeft := 8;
    2548           ListDlg.UserTop := TopBarHeight + 8;
    2549           HelpDlg.UserLeft := Screen.width - HelpDlg.width - 8;
    2550           HelpDlg.UserTop := TopBarHeight + 8;
    2551           UnitStatDlg.UserLeft := 397;
    2552           UnitStatDlg.UserTop := TopBarHeight + 64;
    2553           DiaDlg.UserLeft := (Screen.width - DiaDlg.width) div 2;
    2554           DiaDlg.UserTop := (Screen.height - DiaDlg.height) div 2;
    2555           NatStatDlg.UserLeft := Screen.width - NatStatDlg.width - 8;
    2556           NatStatDlg.UserTop := Screen.height - PanelHeight -
    2557             NatStatDlg.height - 8;
    2558           if NatStatDlg.UserTop < 8 then
    2559             NatStatDlg.UserTop := 8;
    2560 
    2561           Age := 0;
    2562           MovieSpeed := 1;
    2563           LogDlg.mSlot.Visible := true;
    2564           LogDlg.Host := self;
    2565           HelpDlg.ClearHistory;
    2566           CityDlg.Reset;
    2567 
    2568           Mini.width := G.lx * 2;
    2569           Mini.height := G.ly;
    2570           for i := 0 to nPl - 1 do
    2571           begin
    2572             Tribe[i] := nil;
    2573             TribeOriginal[i] := false;
    2574           end;
    2575           ToldSlavery := -1;
    2576           RepaintOnResize := false;
    2577           Closable := false;
    2578           FirstMovieTurn := true;
    2579 
    2580           MenuArea.Visible := GameMode <> cMovie;
    2581           TreasuryArea.Visible := GameMode < cMovie;
    2582           ResearchArea.Visible := GameMode < cMovie;
    2583           ManagementArea.Visible := GameMode < cMovie;
    2584         end;
    2585 
    2586       cGetReady, cReplay:
    2587         if NewPlayer = 0 then
    2588         begin
    2589           i := 0;
    2590           for p1 := 0 to nPl - 1 do
    2591             if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) then
    2592               inc(i);
    2593           if i > UnusedTribeFiles.Count then
    2594           begin
    2595             GameOK := false;
    2596             SimpleMessage(Phrases.Lookup('TOOFEWTRIBES'));
    2597           end
    2598           else
    2599           begin
    2600             for p1 := 0 to nPl - 1 do
    2601               if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) and
    2602                 (G.RO[p1] <> nil) then
    2603               begin // let player select own tribes
    2604                 TribeInfo.trix := p1;
    2605                 TribeNames.Clear;
    2606                 for j := 0 to UnusedTribeFiles.Count - 1 do
    2607                 begin
    2608                   GetTribeInfo(UnusedTribeFiles[j], Name, Color);
    2609                   TribeNames.AddObject(Name, TObject(Color));
    2610                 end;
    2611                 assert(TribeNames.Count > 0);
    2612                 ModalSelectDlg.ShowNewContent(wmModal, kTribe);
    2613                 Application.ProcessMessages;
    2614                 TribeInfo.FileName := UnusedTribeFiles[ModalSelectDlg.result];
    2615                 UnusedTribeFiles.Delete(ModalSelectDlg.result);
    2616 
    2617                 if GameMode = cLoadGame then
    2618                   CreateTribe(TribeInfo.trix, TribeInfo.FileName, false)
    2619                 else
    2620                   Server(cSetTribe + (Length(TribeInfo.FileName) + 1 + 7) div 4,
    2621                     0, 0, TribeInfo);
    2622               end;
    2623 
    2624             for p1 := 0 to nPl - 1 do
    2625               if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) and
    2626                 (G.RO[p1] = nil) then
    2627               begin // autoselect enemy tribes
    2628                 j := ChooseUnusedTribe;
    2629                 TribeInfo.FileName := UnusedTribeFiles[j];
    2630                 UnusedTribeFiles.Delete(j);
    2631                 TribeInfo.trix := p1;
    2632                 if GameMode = cLoadGame then
    2633                   CreateTribe(TribeInfo.trix, TribeInfo.FileName, false)
    2634                 else
    2635                   Server(cSetTribe + (Length(TribeInfo.FileName) + 1 + 7) div 4,
    2636                     0, 0, TribeInfo);
    2637               end;
    2638           end;
    2639           if not mNames.Checked then
    2640             for p1 := 0 to nPl - 1 do
    2641               if Tribe[p1] <> nil then
    2642                 Tribe[p1].NumberName := p1;
    2643         end;
    2644 
    2645       cBreakGame:
    2646         begin
    2647           SaveSettings;
    2648           CityDlg.CloseAction := None;
    2649           for i := 0 to Screen.FormCount - 1 do
    2650             if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
    2651             then
    2652               Screen.Forms[i].Close;
    2653           if LogDlg.Visible then
    2654             LogDlg.Close;
    2655           LogDlg.List.Clear;
    2656           StartRunning := not idle and (Jump[0] > 0); // AI called Reload
    2657           me := -1;
    2658           idle := false;
    2659           ClientMode := -1;
    2660           UnitInfoBtn.Visible := false;
    2661           UnitBtn.Visible := false;
    2662           TerrainBtn.Visible := false;
    2663           MovieSpeed1Btn.Visible := false;
    2664           MovieSpeed2Btn.Visible := false;
    2665           MovieSpeed3Btn.Visible := false;
    2666           MovieSpeed4Btn.Visible := false;
    2667           EOT.Visible := false;
    2668           for i := 0 to ControlCount - 1 do
    2669             if Controls[i] is TButtonC then
    2670               Controls[i].Visible := false;
    2671           InitPVSB(sb, 0, 1);
    2672           for p1 := 0 to nPl - 1 do
    2673             if Tribe[p1] <> nil then
    2674               Tribe[p1].free;
    2675           Tribes.Done;
    2676           RepaintOnResize := false;
    2677           Closable := true;
    2678           Close;
    2679           { if (GameMode=cNewGame) or (GameMode=cLoadGame) then
    2680             AdvisorDlg.BreakGame; }
    2681         end;
    2682 
    2683       cShowGame:
    2684         begin
    2685           with Panel.Canvas do
    2686           begin
    2687             Brush.Color := $000000;
    2688             FillRect(Rect(0, 0, Panel.width, Panel.height));
    2689             Brush.Style := bsClear;
    2690           end;
    2691           with TopBar.Canvas do
    2692           begin
    2693             Brush.Color := $000000;
    2694             FillRect(Rect(0, 0, TopBar.width, TopBar.height));
    2695             Brush.Style := bsClear;
    2696           end;
    2697           FormResize(nil); // place mini map correctly according to its size
    2698           Show;
    2699           Update;
    2700           RepaintOnResize := true;
    2701           xw := 0;
    2702           yw := ywcenter;
    2703           if not StayOnTop_Ensured then
    2704           begin
    2705             StayOnTop_Ensured := true;
    2706             CityDlg.StayOnTop_Workaround;
    2707             CityTypeDlg.StayOnTop_Workaround;
    2708             DiaDlg.StayOnTop_Workaround;
    2709             DraftDlg.StayOnTop_Workaround;
    2710             EnhanceDlg.StayOnTop_Workaround;
    2711             HelpDlg.StayOnTop_Workaround;
    2712             NatStatDlg.StayOnTop_Workaround;
    2713             NegoDlg.StayOnTop_Workaround;
    2714             ModalSelectDlg.StayOnTop_Workaround;
    2715             ListDlg.StayOnTop_Workaround;
    2716             UnitStatDlg.StayOnTop_Workaround;
    2717             WondersDlg.StayOnTop_Workaround;
    2718             RatesDlg.StayOnTop_Workaround;
    2719           end;
    2720         end;
    2721 
    2722       cShowTurnChange:
    2723         begin
    2724           if integer(Data) >= 0 then
    2725           begin
    2726             pLogo := integer(Data);
    2727             if G.RO[pLogo] = nil then
    2728             begin
    2729               if AILogo[pLogo] <> nil then
    2730                 BitBlt(Canvas.Handle, (xRightPanel + 10) - (16 + 64),
    2731                   ClientHeight - PanelHeight, 64, 64,
    2732                   AILogo[pLogo].Canvas.Handle, 0, 0, SRCCOPY);
    2733             end
    2734           end
    2735         end;
    2736 
    2737       cTurn, cResume, cContinue:
    2738         if not GameOK then
    2739           Server(sResign, NewPlayer, 0, nil^)
    2740         else
    2741         begin
    2742           ClientMode := Command;
    2743           pTurn := NewPlayer;
    2744           pLogo := NewPlayer;
    2745 
    2746           if Command = cResume then
    2747           begin // init non-original model pictures (maybe tribes not found)
    2748             for p1 := 0 to nPl - 1 do
    2749               if G.RO[p1] <> nil then
    2750               begin
    2751                 ItsMeAgain(p1);
    2752                 for mix := 0 to MyRO.nModel - 1 do
    2753                   if Tribe[me].ModelPicture[mix].HGr = 0 then
    2754                     InitMyModel(mix, true);
    2755               end;
    2756             me := -1;
    2757           end;
    2758 
    2759           if Jump[pTurn] > 0 then
    2760             Application.ProcessMessages;
    2761           if Jump[pTurn] > 0 then
    2762             if G.RO[NewPlayer].Happened and phGameEnd <> 0 then
    2763               Jump[pTurn] := 0
    2764             else
    2765               dec(Jump[pTurn]);
    2766           SkipTurn := Jump[pTurn] > 0;
    2767           if SkipTurn then
    2768           begin
    2769             ItsMeAgain(NewPlayer);
    2770             MyData := G.RO[NewPlayer].Data;
    2771             SetTroopLoc(-1);
    2772             MiniPaint;
    2773             InitAllEnemyModels; // necessary for correct replay
    2774             if not EndTurn(true) then
    2775               SkipTurn := false;
    2776           end;
    2777           if not SkipTurn then
    2778           begin
    2779             if ((ClientMode < scDipStart) or (ClientMode > scDipBreak)) and
    2780               NegoDlg.Visible then
    2781               NegoDlg.Close;
    2782             skipped := false; // always show my moves during my turn
    2783             idle := true;
    2784             InitTurn(NewPlayer);
    2785             DipMem[me].pContact := -1;
    2786             (* if (me=0) and (MyRO.Alive and (1 shl me)=0)} then
    2787               begin
    2788               if SimpleQuery(Phrases.Lookup('RESIGN'))=mrIgnore then
    2789               Server(sResign,me,0,nil^)
    2790               else Server(sBreak,me,0,nil^)
    2791               end
    2792               else Play('TURNSTART'); *)
    2793           end;
    2794         end;
    2795 
    2796       cMovieTurn:
    2797         begin
    2798           ClientMode := Command;
    2799           pTurn := NewPlayer;
    2800           pLogo := -1;
    2801           skipped := false; // always show my moves during my turn
    2802           idle := true;
    2803           if FirstMovieTurn then
    2804           begin
    2805             CheckMovieSpeedBtnState;
    2806             FirstMovieTurn := false;
    2807           end;
    2808           InitTurn(NewPlayer);
    2809           Application.ProcessMessages;
    2810           if MovieSpeed = 4 then
    2811           begin
    2812             Sleep(75);
    2813             // this break will ensure speed of fast forward does not depend on cpu speed
    2814             Application.ProcessMessages;
    2815           end
    2816         end;
    2817 
    2818       cMovieEndTurn:
    2819         begin
    2820           RememberPeaceViolation;
    2821           pTurn := -1;
    2822           pLogo := -1;
    2823           MapValid := false;
    2824           ClientMode := -1;
    2825           idle := false;
    2826           skipped := false;
    2827         end;
    2828 
    2829       cEditMap:
    2830         begin
    2831           ClientMode := cEditMap;
    2832           SetMapOptions;
    2833           IsoEngine.pDebugMap := -1;
    2834           ItsMeAgain(0);
    2835           MyData := nil;
    2836           UnitInfoBtn.Visible := false;
    2837           UnitBtn.Visible := false;
    2838           TerrainBtn.Visible := false;
    2839           MovieSpeed1Btn.Visible := false;
    2840           MovieSpeed2Btn.Visible := false;
    2841           MovieSpeed3Btn.Visible := false;
    2842           MovieSpeed4Btn.Visible := false;
    2843           EOT.Visible := false;
    2844           HelpDlg.Difficulty := 0;
    2845           BrushType := fGrass;
    2846           BrushLoc := -1;
    2847           Edited := false;
    2848           UnFocus := -1;
    2849           MarkCityLoc := -1;
    2850           Tracking := false;
    2851           TurnComplete := false;
    2852           MapValid := false;
    2853           FormResize(nil); // calculate geometrics and paint all
    2854           SetTroopLoc(-1);
    2855           idle := true
    2856         end;
    2857 
    2858       (* cNewContact:
    2859         begin
    2860         end;
    2861       *)
    2862 
    2863       scContact:
    2864         begin
    2865           DipMem[NewPlayer].pContact := integer(Data);
    2866           if Jump[NewPlayer] > 0 then
    2867             DipCall(scReject)
    2868           else
    2869           begin
    2870             ClientMode := Command;
    2871             InitTurn(NewPlayer);
    2872             MyData.ToldContact := MyData.ToldContact or (1 shl integer(Data));
    2873             // don't tell about new nation when already contacted by them
    2874             with MessgExDlg do
    2875             begin
    2876               OpenSound := 'CONTACT_' + char(48 + MyRO.EnemyReport[integer(Data)
    2877                 ].Attitude);
    2878               MessgText := Tribe[integer(Data)].TPhrase('FRCONTACT');
    2879               Kind := mkYesNo;
    2880               IconKind := mikTribe;
    2881               IconIndex := integer(Data);
    2882               ShowModal;
    2883               if ModalResult = mrOK then
    2884               begin
    2885                 NegoDlg.Respond;
    2886                 DipMem[me].DeliveredPrices := [];
    2887                 DipMem[me].ReceivedPrices := [];
    2888                 DipCall(scDipStart)
    2889               end
    2890               else
    2891               begin
    2892                 DipCall(scReject);
    2893                 EndNego
    2894               end
    2895             end
    2896           end;
    2897         end;
    2898 
    2899       scDipStart .. scDipBreak:
    2900         begin
    2901           ClientMode := Command;
    2902           InitTurn(NewPlayer);
    2903           if Command = scDipStart then
    2904             Play('CONTACT_' + char(48 + MyRO.Attitude[DipMem[NewPlayer]
    2905               .pContact]))
    2906           else if Command = scDipCancelTreaty then
    2907             Play('CANCELTREATY')
    2908           else if Command = scDipOffer then
    2909           begin
    2910             ReceivedOffer := TOffer(Data);
    2911             InitAllEnemyModels;
    2912           end
    2913           else if Command = scDipAccept then
    2914           begin // remember delivered and received prices
    2915             for i := 0 to DipMem[me].SentOffer.nDeliver - 1 do
    2916               include(DipMem[me].DeliveredPrices,
    2917                 DipMem[me].SentOffer.Price[i] shr 24);
    2918             for i := 0 to DipMem[me].SentOffer.nCost - 1 do
    2919               include(DipMem[me].ReceivedPrices,
    2920                 DipMem[me].SentOffer.Price[DipMem[me].SentOffer.nDeliver +
    2921                 i] shr 24);
    2922             IsTreatyDeal := false;
    2923             for i := 0 to ReceivedOffer.nDeliver + ReceivedOffer.nCost - 1 do
    2924               if DipMem[me].SentOffer.Price[i] and opMask = opTreaty then
    2925                 IsTreatyDeal := true;
    2926             if IsTreatyDeal then
    2927               Play('NEWTREATY')
    2928             else
    2929               Play('ACCEPTOFFER');
    2930           end;
    2931           NegoDlg.Start;
    2932           idle := true
    2933         end;
    2934 
    2935       cShowCancelTreaty:
    2936         if not IsMultiPlayerGame then
    2937         begin
    2938           case G.RO[NewPlayer].Treaty[integer(Data)] of
    2939             trPeace:
    2940               s := Tribe[integer(Data)].TPhrase('FRCANCELBYREJECT_PEACE');
    2941             trFriendlyContact:
    2942               s := Tribe[integer(Data)].TPhrase('FRCANCELBYREJECT_FRIENDLY');
    2943             trAlliance:
    2944               s := Tribe[integer(Data)].TPhrase('FRCANCELBYREJECT_ALLIANCE');
    2945           end;
    2946           TribeMessage(integer(Data), s, 'CANCELTREATY');
    2947         end;
    2948 
    2949       cShowCancelTreatyByAlliance:
    2950         if idle and (NewPlayer = me) then
    2951           TribeMessage(integer(Data), Tribe[integer(Data)
    2952             ].TPhrase('FRENEMYALLIANCE'), 'CANCELTREATY');
    2953 
    2954       cShowSupportAllianceAgainst:
    2955         if not IsMultiPlayerGame and (Jump[0] = 0) then
    2956           TribeMessage(integer(Data) and $F,
    2957             Tribe[integer(Data) and $F].TPhrase('FRMYALLIANCE1') + ' ' +
    2958             Tribe[integer(Data) shr 4].TPhrase('FRMYALLIANCE2'),
    2959             'CANCELTREATY');
    2960 
    2961       cShowPeaceViolation:
    2962         if not IsMultiPlayerGame and (Jump[0] = 0) then
    2963           TribeMessage(integer(Data),
    2964             Format(Tribe[integer(Data)].TPhrase('EVIOLATION'),
    2965             [TurnToString(MyRO.Turn + PeaceEvaTurns - 1)]), 'MSG_WITHDRAW');
    2966 
    2967       cShowEndContact:
    2968         EndNego;
    2969 
    2970       cShowUnitChanged, cShowCityChanged, cShowAfterMove, cShowAfterAttack:
    2971         if (idle and (NewPlayer = me) or not idle and not skipped) and
    2972           not((GameMode = cMovie) and (MovieSpeed = 4)) then
    2973         begin
    2974           assert(NewPlayer = me);
    2975           if not idle or (GameMode = cMovie) then
    2976             Application.ProcessMessages;
    2977           if Command = cShowCityChanged then
    2978           begin
    2979             CurrentMoveInfo.DoShow := false;
    2980             if idle then
     3090            CurrentMoveInfo.IsAlly := MyRO.Treaty[Owner] = trAlliance;
     3091            if GameMode = cMovie then
    29813092              CurrentMoveInfo.DoShow := true
    29823093            else if CurrentMoveInfo.IsAlly then
    2983               CurrentMoveInfo.DoShow := not mAlNoMoves.Checked
     3094              CurrentMoveInfo.DoShow := not mAlNoMoves.Checked and
     3095                not(mAlEffectiveMovesOnly.Checked and
     3096                (Command <> cShowCapturing))
    29843097            else
    2985               CurrentMoveInfo.DoShow := not mEnNoMoves.Checked
    2986           end
    2987           else if Command = cShowUnitChanged then
    2988           begin
    2989             CurrentMoveInfo.DoShow := false;
    2990             if idle then
    2991               CurrentMoveInfo.DoShow := not mEffectiveMovesOnly.Checked
    2992             else if CurrentMoveInfo.IsAlly then
    2993               CurrentMoveInfo.DoShow :=
    2994                 not(mAlNoMoves.Checked or mAlEffectiveMovesOnly.Checked)
    2995             else
    2996               CurrentMoveInfo.DoShow :=
    2997                 not(mEnNoMoves.Checked or mEnAttacks.Checked)
    2998           end;
    2999           // else keep DoShow from cShowMove/cShowAttack
    3000 
    3001           if CurrentMoveInfo.DoShow then
    3002           begin
    3003             if Command = cShowCityChanged then
    3004               MapValid := false;
    3005             FocusOnLoc(integer(Data), flImmUpdate);
    3006             // OldUnFocus:=UnFocus;
    3007             // UnFocus:=-1;
    3008             if Command = cShowAfterMove then
    3009               PaintLoc(integer(Data), CurrentMoveInfo.AfterMovePaintRadius)
    3010               // show discovered areas
    3011             else
    3012               PaintLoc(integer(Data), 1);
    3013             // UnFocus:=OldUnFocus;
    3014             if (Command = cShowAfterAttack) and
    3015               (CurrentMoveInfo.AfterAttackExpeller >= 0) then
     3098              CurrentMoveInfo.DoShow := not mEnNoMoves.Checked and
     3099                not(mEnAttacks.Checked and (Command <> cShowCapturing));
     3100            if CurrentMoveInfo.DoShow then
    30163101            begin
    3017               SoundMessageEx(Tribe[CurrentMoveInfo.AfterAttackExpeller]
    3018                 .TPhrase('EXPEL'), '');
    3019               CurrentMoveInfo.AfterAttackExpeller := -1;
    3020               Update; // remove message box from screen
    3021             end
    3022             else if not idle then
    3023               if Command = cShowCityChanged then
    3024                 Sleep(MoveTime * WaitAfterShowMove div 16)
    3025               else if (Command = cShowUnitChanged) and
    3026                 (MyMap[integer(Data)] and fUnit <> 0) then
    3027                 Sleep(MoveTime * WaitAfterShowMove div 32)
    3028           end // if CurrentMoveInfo.DoShow
    3029           else
    3030             MapValid := false;
    3031         end;
    3032 
    3033       cShowMoving, cShowCapturing:
    3034         if (idle and (NewPlayer = me) or not idle and not skipped and
    3035           (TShowMove(Data).emix <> $FFFF)) and
    3036           not((GameMode = cMovie) and (MovieSpeed = 4)) then
    3037         begin
    3038           assert(NewPlayer = me);
    3039           if not idle or (GameMode = cMovie) then
    3040             Application.ProcessMessages;
    3041           with TShowMove(Data) do
    3042           begin
    3043             CurrentMoveInfo.DoShow := false;
    3044             if not idle and (Tribe[Owner].ModelPicture[mix].HGr = 0) then
    3045               InitEnemyModel(emix);
    3046 
    3047             ToLoc := dLoc(FromLoc, dx, dy);
    3048             if idle then
    3049             begin // own unit -- make discovered land visible
    3050               assert(Owner = me); // no foreign moves during my turn!
    3051               CurrentMoveInfo.DoShow := not mEffectiveMovesOnly.Checked or
    3052                 (Command = cShowCapturing);
    3053               if CurrentMoveInfo.DoShow then
    3054               begin
    3055                 if GameMode = cMovie then
    3056                 begin
    3057                   if MovieSpeed = 3 then
    3058                     AnimationSpeed := 4
    3059                   else if MovieSpeed = 2 then
    3060                     AnimationSpeed := 8
    3061                   else
    3062                     AnimationSpeed := 16;
     3102              if Command = cShowCapturing then
     3103              begin // show capture message
     3104                if MyMap[ToLoc] and fOwned <> 0 then
     3105                begin // own city, search
     3106                  cix := MyRO.nCity - 1;
     3107                  while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
     3108                    dec(cix);
     3109                  s := CityName(MyCity[cix].ID);
    30633110                end
    30643111                else
    3065                 begin
    3066                   if mVeryFastMoves.Checked then
    3067                     AnimationSpeed := 4
    3068                   else if mFastMoves.Checked then
    3069                     AnimationSpeed := 8
    3070                   else
    3071                     AnimationSpeed := 16;
     3112                begin // foreign city, search
     3113                  ecix := MyRO.nEnemyCity - 1;
     3114                  while (ecix >= 0) and (MyRO.EnemyCity[ecix].Loc <> ToLoc) do
     3115                    dec(ecix);
     3116                  s := CityName(MyRO.EnemyCity[ecix].ID);
    30723117                end;
    3073                 with MyModel[mix] do
    3074                 begin
    3075                   if (Kind = mkDiplomat) or (Domain = dAir) or
    3076                     (Cap[mcRadar] + Cap[mcCarrier] + Cap[mcAcademy] > 0) or
     3118                TribeMessage(Owner, Format(Tribe[Owner].TPhrase('CAPTURE'),
     3119                  [s]), '');
     3120                Update; // remove message box from screen
     3121              end;
     3122
     3123              if CurrentMoveInfo.IsAlly then
     3124              begin // allied unit -- make discovered land visible
     3125                if mAlFastMoves.Checked then
     3126                  AnimationSpeed := 8
     3127                else
     3128                  AnimationSpeed := 16;
     3129                with MyRO.EnemyModel[emix] do
     3130                  if (Kind = mkDiplomat) or (Domain = dAir) or (ATrans_Fuel > 0)
     3131                    or (Cap and (1 shl (mcRadar - mcFirstNonCap) or
     3132                    1 shl (mcAcademy - mcFirstNonCap)) <> 0) or
    30773133                    (MyMap[ToLoc] and fTerrain = fMountains) or
    30783134                    (MyMap[ToLoc] and fTerImp = tiFort) or
     
    30803136                    CurrentMoveInfo.AfterMovePaintRadius := 2
    30813137                  else
    3082                     CurrentMoveInfo.AfterMovePaintRadius := 1;
    3083                   if (MyRO.Wonder[woShinkansen].EffectiveOwner = me) and
    3084                     (Domain = dGround) and
    3085                     (MyMap[FromLoc] and (fRR or fCity) <> 0) and
    3086                     (MyMap[ToLoc] and (fRR or fCity) <> 0) and
    3087                     (Flags and umPlaneUnloading = 0) then
    3088                     AnimationSpeed := 4;
    3089                   ShowMoveDomain := Domain;
    3090                   IsAlpine := Cap[mcAlpine] > 0;
    3091                 end
     3138                    CurrentMoveInfo.AfterMovePaintRadius := 1
    30923139              end
     3140              else
     3141              begin
     3142                if mEnFastMoves.Checked then
     3143                  AnimationSpeed := 8
     3144                else
     3145                  AnimationSpeed := 16;
     3146                CurrentMoveInfo.AfterMovePaintRadius := 0;
     3147                // enemy unit, nothing discovered
     3148              end;
     3149              if GameMode = cMovie then
     3150              begin
     3151                if MovieSpeed = 3 then
     3152                  AnimationSpeed := 4
     3153                else if MovieSpeed = 2 then
     3154                  AnimationSpeed := 8
     3155                else
     3156                  AnimationSpeed := 16;
     3157              end;
     3158              ShowMoveDomain := MyRO.EnemyModel[emix].Domain;
     3159              IsAlpine := MyRO.EnemyModel[emix].Cap and
     3160                (1 shl (mcAlpine - mcFirstNonCap)) <> 0;
     3161            end
     3162          end;
     3163
     3164          if CurrentMoveInfo.DoShow then
     3165          begin
     3166            if Command = cShowCapturing then
     3167              Play('MOVE_CAPTURE')
     3168            else if EndHealth <= 0 then
     3169              Play('MOVE_DIE')
     3170            else if Flags and umSpyMission <> 0 then
     3171              Play('MOVE_COVERT')
     3172            else if Flags and umShipLoading <> 0 then
     3173              if ShowMoveDomain = dAir then
     3174                Play('MOVE_PLANELANDING')
     3175              else
     3176                Play('MOVE_LOAD')
     3177            else if Flags and umPlaneLoading <> 0 then
     3178              Play('MOVE_LOAD')
     3179            else if Flags and umShipUnloading <> 0 then
     3180              if ShowMoveDomain = dAir then
     3181                Play('MOVE_PLANESTART')
     3182              else
     3183                Play('MOVE_UNLOAD')
     3184            else if Flags and umPlaneUnloading <> 0 then
     3185              if (MyMap[FromLoc] and fCity = 0) and
     3186                (MyMap[FromLoc] and fTerImp <> tiBase) then
     3187                Play('MOVE_PARACHUTE')
     3188              else
     3189                Play('MOVE_UNLOAD')
     3190            else if (ShowMoveDomain = dGround) and not IsAlpine and
     3191              (MyMap[ToLoc] and fTerrain = fMountains) and
     3192              ((MyMap[FromLoc] and (fRoad or fRR or fCity) = 0) or
     3193              (MyMap[ToLoc] and (fRoad or fRR or fCity) = 0)) then
     3194              Play('MOVE_MOUNTAIN');
     3195
     3196            FocusOnLoc(FromLoc, flImmUpdate);
     3197            PaintLoc_BeforeMove(FromLoc);
     3198            if Command = cShowCapturing then
     3199              MoveOnScreen(TShowMove(Data), 1, 32, 32)
     3200            else
     3201              MoveOnScreen(TShowMove(Data), 1, AnimationSpeed, AnimationSpeed)
     3202          end // if CurrentMoveInfo.DoShow
     3203          else
     3204            MapValid := false;
     3205        end
     3206      end;
     3207
     3208    cShowAttacking:
     3209      if (idle and (NewPlayer = me) or not idle and not skipped and
     3210        (TShowMove(Data).emix <> $FFFF)) and
     3211        not((GameMode = cMovie) and (MovieSpeed = 4)) then
     3212      begin
     3213        assert(NewPlayer = me);
     3214        if not idle or (GameMode = cMovie) then
     3215          Application.ProcessMessages;
     3216        with TShowMove(Data) do
     3217        begin
     3218          CurrentMoveInfo.AfterAttackExpeller := -1;
     3219          CurrentMoveInfo.DoShow := false;
     3220          if idle then
     3221            CurrentMoveInfo.DoShow := true // own unit -- always show attacks
     3222          else
     3223          begin
     3224            CurrentMoveInfo.IsAlly := MyRO.Treaty[Owner] = trAlliance;
     3225            if CurrentMoveInfo.IsAlly then
     3226              CurrentMoveInfo.DoShow := not mAlNoMoves.Checked
     3227            else
     3228              CurrentMoveInfo.DoShow := not mEnNoMoves.Checked;
     3229          end;
     3230          if CurrentMoveInfo.DoShow then
     3231          begin
     3232            ToLoc := dLoc(FromLoc, dx, dy);
     3233            if Tribe[Owner].ModelPicture[mix].HGr = 0 then
     3234              InitEnemyModel(emix);
     3235
     3236            if (MyMap[ToLoc] and (fCity or fUnit or fOwned) = fCity or fOwned)
     3237            then
     3238            begin // tell about bombardment
     3239              cix := MyRO.nCity - 1;
     3240              while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
     3241                dec(cix);
     3242              if MyCity[cix].Status and csToldBombard = 0 then
     3243              begin
     3244                if not supervising then
     3245                  MyCity[cix].Status := MyCity[cix].Status or csToldBombard;
     3246                s := CityName(MyCity[cix].ID);
     3247                SoundMessageEx(Format(Tribe[Owner].TPhrase('BOMBARD'),
     3248                  [s]), '');
     3249                Update; // remove message box from screen
     3250              end;
     3251            end
     3252            else if Flags and umExpelling <> 0 then
     3253              CurrentMoveInfo.AfterAttackExpeller := Owner;
     3254
     3255            if Flags and umExpelling <> 0 then
     3256              Play('MOVE_EXPEL')
     3257            else if Owner = me then
     3258            begin
     3259              MakeModelInfo(me, mix, MyModel[mix], mi);
     3260              Play(AttackSound(ModelCode(mi)));
    30933261            end
    30943262            else
     3263              Play(AttackSound(ModelCode(MyRO.EnemyModel[emix])));
     3264
     3265            FocusOnLoc(FromLoc, flImmUpdate);
     3266
     3267            // before combat
     3268            MainMap.AttackBegin(TShowMove(Data));
     3269            if MyMap[ToLoc] and fCity <> 0 then
     3270              PaintLoc(ToLoc);
     3271            PaintLoc(FromLoc);
     3272            MoveOnScreen(TShowMove(Data), 1, 9, 16);
     3273            MoveOnScreen(TShowMove(Data), 17, 12, 32);
     3274            MoveOnScreen(TShowMove(Data), 7, 11, 16);
     3275
     3276            // after combat
     3277            MainMap.AttackEffect(TShowMove(Data));
     3278            PaintLoc(ToLoc);
     3279            if EndHealth > 0 then
    30953280            begin
    3096               CurrentMoveInfo.IsAlly := MyRO.Treaty[Owner] = trAlliance;
    3097               if GameMode = cMovie then
    3098                 CurrentMoveInfo.DoShow := true
    3099               else if CurrentMoveInfo.IsAlly then
    3100                 CurrentMoveInfo.DoShow := not mAlNoMoves.Checked and
    3101                   not(mAlEffectiveMovesOnly.Checked and
    3102                   (Command <> cShowCapturing))
    3103               else
    3104                 CurrentMoveInfo.DoShow := not mEnNoMoves.Checked and
    3105                   not(mEnAttacks.Checked and (Command <> cShowCapturing));
    3106               if CurrentMoveInfo.DoShow then
    3107               begin
    3108                 if Command = cShowCapturing then
    3109                 begin // show capture message
    3110                   if MyMap[ToLoc] and fOwned <> 0 then
    3111                   begin // own city, search
    3112                     cix := MyRO.nCity - 1;
    3113                     while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
    3114                       dec(cix);
    3115                     s := CityName(MyCity[cix].ID);
    3116                   end
    3117                   else
    3118                   begin // foreign city, search
    3119                     ecix := MyRO.nEnemyCity - 1;
    3120                     while (ecix >= 0) and (MyRO.EnemyCity[ecix].Loc <> ToLoc) do
    3121                       dec(ecix);
    3122                     s := CityName(MyRO.EnemyCity[ecix].ID);
    3123                   end;
    3124                   TribeMessage(Owner, Format(Tribe[Owner].TPhrase('CAPTURE'),
    3125                     [s]), '');
    3126                   Update; // remove message box from screen
    3127                 end;
    3128 
    3129                 if CurrentMoveInfo.IsAlly then
    3130                 begin // allied unit -- make discovered land visible
    3131                   if mAlFastMoves.Checked then
    3132                     AnimationSpeed := 8
    3133                   else
    3134                     AnimationSpeed := 16;
    3135                   with MyRO.EnemyModel[emix] do
    3136                     if (Kind = mkDiplomat) or (Domain = dAir) or
    3137                       (ATrans_Fuel > 0) or
    3138                       (Cap and (1 shl (mcRadar - mcFirstNonCap) or
    3139                       1 shl (mcAcademy - mcFirstNonCap)) <> 0) or
    3140                       (MyMap[ToLoc] and fTerrain = fMountains) or
    3141                       (MyMap[ToLoc] and fTerImp = tiFort) or
    3142                       (MyMap[ToLoc] and fTerImp = tiBase) then
    3143                       CurrentMoveInfo.AfterMovePaintRadius := 2
    3144                     else
    3145                       CurrentMoveInfo.AfterMovePaintRadius := 1
    3146                 end
    3147                 else
    3148                 begin
    3149                   if mEnFastMoves.Checked then
    3150                     AnimationSpeed := 8
    3151                   else
    3152                     AnimationSpeed := 16;
    3153                   CurrentMoveInfo.AfterMovePaintRadius := 0;
    3154                   // enemy unit, nothing discovered
    3155                 end;
    3156                 if GameMode = cMovie then
    3157                 begin
    3158                   if MovieSpeed = 3 then
    3159                     AnimationSpeed := 4
    3160                   else if MovieSpeed = 2 then
    3161                     AnimationSpeed := 8
    3162                   else
    3163                     AnimationSpeed := 16;
    3164                 end;
    3165                 ShowMoveDomain := MyRO.EnemyModel[emix].Domain;
    3166                 IsAlpine := MyRO.EnemyModel[emix].Cap and
    3167                   (1 shl (mcAlpine - mcFirstNonCap)) <> 0;
    3168               end
    3169             end;
    3170 
    3171             if CurrentMoveInfo.DoShow then
    3172             begin
    3173               if Command = cShowCapturing then
    3174                 Play('MOVE_CAPTURE')
    3175               else if EndHealth <= 0 then
    3176                 Play('MOVE_DIE')
    3177               else if Flags and umSpyMission <> 0 then
    3178                 Play('MOVE_COVERT')
    3179               else if Flags and umShipLoading <> 0 then
    3180                 if ShowMoveDomain = dAir then
    3181                   Play('MOVE_PLANELANDING')
    3182                 else
    3183                   Play('MOVE_LOAD')
    3184               else if Flags and umPlaneLoading <> 0 then
    3185                 Play('MOVE_LOAD')
    3186               else if Flags and umShipUnloading <> 0 then
    3187                 if ShowMoveDomain = dAir then
    3188                   Play('MOVE_PLANESTART')
    3189                 else
    3190                   Play('MOVE_UNLOAD')
    3191               else if Flags and umPlaneUnloading <> 0 then
    3192                 if (MyMap[FromLoc] and fCity = 0) and
    3193                   (MyMap[FromLoc] and fTerImp <> tiBase) then
    3194                   Play('MOVE_PARACHUTE')
    3195                 else
    3196                   Play('MOVE_UNLOAD')
    3197               else if (ShowMoveDomain = dGround) and not IsAlpine and
    3198                 (MyMap[ToLoc] and fTerrain = fMountains) and
    3199                 ((MyMap[FromLoc] and (fRoad or fRR or fCity) = 0) or
    3200                 (MyMap[ToLoc] and (fRoad or fRR or fCity) = 0)) then
    3201                 Play('MOVE_MOUNTAIN');
    3202 
    3203               FocusOnLoc(FromLoc, flImmUpdate);
    3204               PaintLoc_BeforeMove(FromLoc);
    3205               if Command = cShowCapturing then
    3206                 MoveOnScreen(TShowMove(Data), 1, 32, 32)
    3207               else
    3208                 MoveOnScreen(TShowMove(Data), 1, AnimationSpeed, AnimationSpeed)
    3209             end // if CurrentMoveInfo.DoShow
    3210             else
    3211               MapValid := false;
    3212           end
     3281              Health := EndHealth;
     3282              MoveOnScreen(TShowMove(Data), 10, 0, 16);
     3283            end
     3284            else if not idle then
     3285              Sleep(MoveTime div 2);
     3286            MainMap.AttackEnd;
     3287          end // if CurrentMoveInfo.DoShow
     3288          else
     3289            MapValid := false;
     3290        end
     3291      end;
     3292
     3293    cShowMissionResult:
     3294      if Cardinal(Data) = 0 then
     3295        SoundMessageEx(Phrases.Lookup('NOFOREIGNINFO'), '')
     3296      else
     3297      begin
     3298        s := Phrases.Lookup('FOREIGNINFO');
     3299        for p1 := 0 to nPl - 1 do
     3300          if 3 shl (p1 * 2) and Cardinal(Data) <> 0 then
     3301            s := s + '\' + Tribe[p1].TPhrase('SHORTNAME');
     3302        SoundMessageEx(s, '')
     3303      end;
     3304
     3305    cShowShipChange:
     3306      if not IsMultiPlayerGame and (Jump[0] = 0) then
     3307        ShowEnemyShipChange(TShowShipChange(Data));
     3308
     3309    cShowGreatLibTech:
     3310      if not IsMultiPlayerGame and (Jump[0] = 0) then
     3311        with MessgExDlg do
     3312        begin
     3313          MessgText := Format(Phrases.Lookup('GRLIB_GENERAL'),
     3314            [Phrases.Lookup('ADVANCES', integer(Data))]);
     3315          OpenSound := 'NEWADVANCE_GRLIB';
     3316          Kind := mkOk;
     3317          IconKind := mikImp;
     3318          IconIndex := woGrLibrary;
     3319          ShowModal;
    32133320        end;
    32143321
    3215       cShowAttacking:
    3216         if (idle and (NewPlayer = me) or not idle and not skipped and
    3217           (TShowMove(Data).emix <> $FFFF)) and
    3218           not((GameMode = cMovie) and (MovieSpeed = 4)) then
     3322    cRefreshDebugMap:
     3323      begin
     3324        if integer(Data) = IsoEngine.pDebugMap then
    32193325        begin
    3220           assert(NewPlayer = me);
    3221           if not idle or (GameMode = cMovie) then
    3222             Application.ProcessMessages;
    3223           with TShowMove(Data) do
     3326          MapValid := false;
     3327          MainOffscreenPaint;
     3328          Update;
     3329        end
     3330      end;
     3331
     3332  else
     3333    if Command >= cClientEx then
     3334      case Command and $FFF0 of
     3335
     3336        cSetTribe:
     3337          with TTribeInfo(Data) do
    32243338          begin
    3225             CurrentMoveInfo.AfterAttackExpeller := -1;
    3226             CurrentMoveInfo.DoShow := false;
    3227             if idle then
    3228               CurrentMoveInfo.DoShow := true // own unit -- always show attacks
    3229             else
    3230             begin
    3231               CurrentMoveInfo.IsAlly := MyRO.Treaty[Owner] = trAlliance;
    3232               if CurrentMoveInfo.IsAlly then
    3233                 CurrentMoveInfo.DoShow := not mAlNoMoves.Checked
    3234               else
    3235                 CurrentMoveInfo.DoShow := not mEnNoMoves.Checked;
    3236             end;
    3237             if CurrentMoveInfo.DoShow then
    3238             begin
    3239               ToLoc := dLoc(FromLoc, dx, dy);
    3240               if Tribe[Owner].ModelPicture[mix].HGr = 0 then
    3241                 InitEnemyModel(emix);
    3242 
    3243               if (MyMap[ToLoc] and (fCity or fUnit or fOwned) = fCity or fOwned)
    3244               then
    3245               begin // tell about bombardment
    3246                 cix := MyRO.nCity - 1;
    3247                 while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
    3248                   dec(cix);
    3249                 if MyCity[cix].Status and csToldBombard = 0 then
    3250                 begin
    3251                   if not supervising then
    3252                     MyCity[cix].Status := MyCity[cix].Status or csToldBombard;
    3253                   s := CityName(MyCity[cix].ID);
    3254                   SoundMessageEx(Format(Tribe[Owner].TPhrase('BOMBARD'),
    3255                     [s]), '');
    3256                   Update; // remove message box from screen
    3257                 end;
    3258               end
    3259               else if Flags and umExpelling <> 0 then
    3260                 CurrentMoveInfo.AfterAttackExpeller := Owner;
    3261 
    3262               if Flags and umExpelling <> 0 then
    3263                 Play('MOVE_EXPEL')
    3264               else if Owner = me then
    3265               begin
    3266                 MakeModelInfo(me, mix, MyModel[mix], mi);
    3267                 Play(AttackSound(ModelCode(mi)));
    3268               end
    3269               else
    3270                 Play(AttackSound(ModelCode(MyRO.EnemyModel[emix])));
    3271 
    3272               FocusOnLoc(FromLoc, flImmUpdate);
    3273 
    3274               // before combat
    3275               MainMap.AttackBegin(TShowMove(Data));
    3276               if MyMap[ToLoc] and fCity <> 0 then
    3277                 PaintLoc(ToLoc);
    3278               PaintLoc(FromLoc);
    3279               MoveOnScreen(TShowMove(Data), 1, 9, 16);
    3280               MoveOnScreen(TShowMove(Data), 17, 12, 32);
    3281               MoveOnScreen(TShowMove(Data), 7, 11, 16);
    3282 
    3283               // after combat
    3284               MainMap.AttackEffect(TShowMove(Data));
    3285               PaintLoc(ToLoc);
    3286               if EndHealth > 0 then
    3287               begin
    3288                 Health := EndHealth;
    3289                 MoveOnScreen(TShowMove(Data), 10, 0, 16);
    3290               end
    3291               else if not idle then
    3292                 Sleep(MoveTime div 2);
    3293               MainMap.AttackEnd;
    3294             end // if CurrentMoveInfo.DoShow
    3295             else
    3296               MapValid := false;
    3297           end
    3298         end;
    3299 
    3300       cShowMissionResult:
    3301         if Cardinal(Data) = 0 then
    3302           SoundMessageEx(Phrases.Lookup('NOFOREIGNINFO'), '')
    3303         else
    3304         begin
    3305           s := Phrases.Lookup('FOREIGNINFO');
    3306           for p1 := 0 to nPl - 1 do
    3307             if 3 shl (p1 * 2) and Cardinal(Data) <> 0 then
    3308               s := s + '\' + Tribe[p1].TPhrase('SHORTNAME');
    3309           SoundMessageEx(s, '')
    3310         end;
    3311 
    3312       cShowShipChange:
    3313         if not IsMultiPlayerGame and (Jump[0] = 0) then
    3314           ShowEnemyShipChange(TShowShipChange(Data));
    3315 
    3316       cShowGreatLibTech:
    3317         if not IsMultiPlayerGame and (Jump[0] = 0) then
    3318           with MessgExDlg do
    3319           begin
    3320             MessgText := Format(Phrases.Lookup('GRLIB_GENERAL'),
    3321               [Phrases.Lookup('ADVANCES', integer(Data))]);
    3322             OpenSound := 'NEWADVANCE_GRLIB';
    3323             Kind := mkOk;
    3324             IconKind := mikImp;
    3325             IconIndex := woGrLibrary;
    3326             ShowModal;
     3339            i := UnusedTribeFiles.Count - 1;
     3340            while (i >= 0) and
     3341              (AnsiCompareFileName(UnusedTribeFiles[i], FileName) <> 0) do
     3342              dec(i);
     3343            if i >= 0 then
     3344              UnusedTribeFiles.Delete(i);
     3345            CreateTribe(trix, FileName, true);
    33273346          end;
    33283347
    3329       cRefreshDebugMap:
    3330         begin
    3331           if integer(Data) = IsoEngine.pDebugMap then
    3332           begin
    3333             MapValid := false;
    3334             MainOffscreenPaint;
    3335             Update;
    3336           end
    3337         end;
    3338 
    3339     else
    3340       if Command >= cClientEx then
    3341         case Command and $FFF0 of
    3342 
    3343           cSetTribe:
    3344             with TTribeInfo(Data) do
    3345             begin
    3346               i := UnusedTribeFiles.Count - 1;
    3347               while (i >= 0) and
    3348                 (AnsiCompareFileName(UnusedTribeFiles[i], FileName) <> 0) do
    3349                 dec(i);
    3350               if i >= 0 then
    3351                 UnusedTribeFiles.Delete(i);
    3352               CreateTribe(trix, FileName, true);
    3353             end;
    3354 
    3355           cSetNewModelPicture, cSetModelPicture:
    3356             if TribeOriginal[TModelPictureInfo(Data).trix] then
    3357               Tribe[TModelPictureInfo(Data).trix].SetModelPicture
    3358                 (TModelPictureInfo(Data), Command and
    3359                 $FFF0 = cSetNewModelPicture);
    3360 
    3361           cSetSlaveIndex and $FFF0:
    3362             Tribe[integer(Data) shr 16].mixSlaves := integer(Data) and $FFFF;
    3363 
    3364           cSetCityName:
    3365             with TCityNameInfo(Data) do
    3366               if TribeOriginal[ID shr 12] then
    3367                 Tribe[ID shr 12].SetCityName(ID and $FFF, NewName);
    3368 
    3369           cSetModelName:
    3370             with TModelNameInfo(Data) do
    3371               if TribeOriginal[NewPlayer] then
    3372                 Tribe[NewPlayer].ModelName[mix] := NewName;
    3373         end
    3374     end
    3375   end; { <<<client }
    3376 
    3377   { *** main part *** }
    3378 
    3379   procedure TMainScreen.CreateParams(var p: TCreateParams);
    3380   var
    3381     DefaultOptionChecked: integer;
    3382     Reg: TRegistry;
    3383     doinit: boolean;
    3384   begin
    3385     inherited;
    3386 
    3387     // define which menu settings to save
    3388     SaveOption[0] := mAlEffectiveMovesOnly.Tag;
    3389     SaveOption[1] := mEnMoves.Tag;
    3390     SaveOption[2] := mEnAttacks.Tag;
    3391     SaveOption[3] := mEnNoMoves.Tag;
    3392     SaveOption[4] := mWaitTurn.Tag;
    3393     SaveOption[5] := mEffectiveMovesOnly.Tag;
    3394     SaveOption[6] := mEnFastMoves.Tag;
    3395     SaveOption[7] := mSlowMoves.Tag;
    3396     SaveOption[8] := mFastMoves.Tag;
    3397     SaveOption[9] := mVeryFastMoves.Tag;
    3398     SaveOption[10] := mNames.Tag;
    3399     SaveOption[11] := mRepList.Tag;
    3400     SaveOption[12] := mRepScreens.Tag;
    3401     SaveOption[13] := mSoundOff.Tag;
    3402     SaveOption[14] := mSoundOn.Tag;
    3403     SaveOption[15] := mSoundOnAlt.Tag;
    3404     SaveOption[16] := mScrollSlow.Tag;
    3405     SaveOption[17] := mScrollFast.Tag;
    3406     SaveOption[18] := mScrollOff.Tag;
    3407     SaveOption[19] := mAlSlowMoves.Tag;
    3408     SaveOption[20] := mAlFastMoves.Tag;
    3409     SaveOption[21] := mAlNoMoves.Tag;
    3410     DefaultOptionChecked := 1 shl 1 + 1 shl 7 + 1 shl 10 + 1 shl 12 + 1 shl 14 +
    3411       1 shl 18 + 1 shl 19;
    3412 
    3413     Reg := TRegistry.Create;
    3414     doinit := true;
    3415     if Reg.KeyExists('SOFTWARE\cevo\RegVer9') then
    3416     with Reg do begin
     3348        cSetNewModelPicture, cSetModelPicture:
     3349          if TribeOriginal[TModelPictureInfo(Data).trix] then
     3350            Tribe[TModelPictureInfo(Data).trix].SetModelPicture
     3351              (TModelPictureInfo(Data), Command and
     3352              $FFF0 = cSetNewModelPicture);
     3353
     3354        cSetSlaveIndex and $FFF0:
     3355          Tribe[integer(Data) shr 16].mixSlaves := integer(Data) and $FFFF;
     3356
     3357        cSetCityName:
     3358          with TCityNameInfo(Data) do
     3359            if TribeOriginal[ID shr 12] then
     3360              Tribe[ID shr 12].SetCityName(ID and $FFF, NewName);
     3361
     3362        cSetModelName:
     3363          with TModelNameInfo(Data) do
     3364            if TribeOriginal[NewPlayer] then
     3365              Tribe[NewPlayer].ModelName[mix] := NewName;
     3366      end
     3367  end
     3368end; { <<<client }
     3369
     3370{ *** main part *** }
     3371
     3372procedure TMainScreen.CreateParams(var p: TCreateParams);
     3373var
     3374  DefaultOptionChecked: integer;
     3375  Reg: TRegistry;
     3376  doinit: boolean;
     3377begin
     3378  inherited;
     3379
     3380  // define which menu settings to save
     3381  SaveOption[0] := mAlEffectiveMovesOnly.Tag;
     3382  SaveOption[1] := mEnMoves.Tag;
     3383  SaveOption[2] := mEnAttacks.Tag;
     3384  SaveOption[3] := mEnNoMoves.Tag;
     3385  SaveOption[4] := mWaitTurn.Tag;
     3386  SaveOption[5] := mEffectiveMovesOnly.Tag;
     3387  SaveOption[6] := mEnFastMoves.Tag;
     3388  SaveOption[7] := mSlowMoves.Tag;
     3389  SaveOption[8] := mFastMoves.Tag;
     3390  SaveOption[9] := mVeryFastMoves.Tag;
     3391  SaveOption[10] := mNames.Tag;
     3392  SaveOption[11] := mRepList.Tag;
     3393  SaveOption[12] := mRepScreens.Tag;
     3394  SaveOption[13] := mSoundOff.Tag;
     3395  SaveOption[14] := mSoundOn.Tag;
     3396  SaveOption[15] := mSoundOnAlt.Tag;
     3397  SaveOption[16] := mScrollSlow.Tag;
     3398  SaveOption[17] := mScrollFast.Tag;
     3399  SaveOption[18] := mScrollOff.Tag;
     3400  SaveOption[19] := mAlSlowMoves.Tag;
     3401  SaveOption[20] := mAlFastMoves.Tag;
     3402  SaveOption[21] := mAlNoMoves.Tag;
     3403  DefaultOptionChecked := 1 shl 1 + 1 shl 7 + 1 shl 10 + 1 shl 12 + 1 shl 14 +
     3404    1 shl 18 + 1 shl 19;
     3405
     3406  Reg := TRegistry.Create;
     3407  doinit := true;
     3408  if Reg.KeyExists('SOFTWARE\cevo\RegVer9') then
     3409    with Reg do
     3410    begin
    34173411      doinit := false;
    34183412      OpenKey('SOFTWARE\cevo\RegVer9', false);
    3419       if ValueExists('TileWidth') then xxt := ReadInteger('TileWidth') div 2
    3420         else xxt := 48;
    3421       if ValueExists('TileHeight') then yyt := ReadInteger('TileHeight') div 2
    3422         else yyt := 24;
    3423       if ValueExists('OptionChecked') then OptionChecked := ReadInteger('OptionChecked')
    3424         else OptionChecked := DefaultOptionChecked;
    3425       if ValueExists('MapOptionChecked') then MapOptionChecked := ReadInteger('MapOptionChecked')
    3426         else MapOptionChecked := 1 shl moCityNames;
    3427       if ValueExists('CityMapMask') then CityRepMask := Cardinal(ReadInteger('CityReport'))
    3428         else CityRepMask := Cardinal(not chPopIncrease and not chNoGrowthWarning and
    3429         not chCaptured);
     3413      if ValueExists('TileWidth') then
     3414        xxt := ReadInteger('TileWidth') div 2
     3415      else
     3416        xxt := 48;
     3417      if ValueExists('TileHeight') then
     3418        yyt := ReadInteger('TileHeight') div 2
     3419      else
     3420        yyt := 24;
     3421      if ValueExists('OptionChecked') then
     3422        OptionChecked := ReadInteger('OptionChecked')
     3423      else
     3424        OptionChecked := DefaultOptionChecked;
     3425      if ValueExists('MapOptionChecked') then
     3426        MapOptionChecked := ReadInteger('MapOptionChecked')
     3427      else
     3428        MapOptionChecked := 1 shl moCityNames;
     3429      if ValueExists('CityMapMask') then
     3430        CityRepMask := Cardinal(ReadInteger('CityReport'))
     3431      else
     3432        CityRepMask := Cardinal(not chPopIncrease and not chNoGrowthWarning and
     3433          not chCaptured);
    34303434      CloseKey;
    34313435      if OptionChecked and (7 shl 16) = 0 then
     
    34333437      // old regver with no scrolling
    34343438    end;
    3435     Reg.Free;
    3436 
    3437     if FullScreen then begin
    3438       p.Style := $87000000;
    3439       BorderStyle := bsNone;
    3440       BorderIcons := [];
    3441     end;
    3442 
    3443     if 1 shl 13 and OptionChecked <> 0 then
    3444       SoundMode := smOff
    3445     else if 1 shl 15 and OptionChecked <> 0 then
    3446       SoundMode := smOnAlt
     3439  Reg.free;
     3440
     3441  if FullScreen then
     3442  begin
     3443    p.Style := $87000000;
     3444    BorderStyle := bsNone;
     3445    BorderIcons := [];
     3446  end;
     3447
     3448  if 1 shl 13 and OptionChecked <> 0 then
     3449    SoundMode := smOff
     3450  else if 1 shl 15 and OptionChecked <> 0 then
     3451    SoundMode := smOnAlt
     3452  else
     3453    SoundMode := smOn;
     3454end;
     3455
     3456procedure TMainScreen.FormCreate(Sender: TObject);
     3457var
     3458  i, j: integer;
     3459begin
     3460{$IFDEF WINDOWS}{ TODO }
     3461  Screen.Cursors[crImpDrag] := LoadCursor(HInstance, 'DRAG');
     3462  Screen.Cursors[crFlatHand] := LoadCursor(HInstance, 'FLATHAND');
     3463{$ENDIF}
     3464  // tag-controlled language
     3465  for i := 0 to ComponentCount - 1 do
     3466    if Components[i].Tag and $FF <> 0 then
     3467      if Components[i] is TMenuItem then
     3468      begin
     3469        TMenuItem(Components[i]).Caption := Phrases.Lookup('CONTROLS',
     3470          -1 + Components[i].Tag and $FF);
     3471        for j := 0 to nSaveOption - 1 do
     3472          if Components[i].Tag and $FF = SaveOption[j] then
     3473            TMenuItem(Components[i]).Checked := 1 shl j and OptionChecked <> 0;
     3474      end
     3475      else if Components[i] is TButtonBase then
     3476      begin
     3477        TButtonBase(Components[i]).Hint := Phrases.Lookup('CONTROLS',
     3478          -1 + Components[i].Tag and $FF);
     3479        if (Components[i] is TButtonC) and
     3480          (TButtonC(Components[i]).ButtonIndex <> 1) then
     3481          TButtonC(Components[i]).ButtonIndex :=
     3482            MapOptionChecked shr (Components[i].Tag shr 8) and 1 + 2
     3483      end;
     3484
     3485  // non-tag-controlled language
     3486  mTechTree.Caption := Phrases2.Lookup('MENU_ADVTREE');
     3487  mViewpoint.Caption := Phrases2.Lookup('MENU_VIEWPOINT');
     3488  if not Phrases2FallenBackToEnglish then
     3489  begin
     3490    MenuArea.Hint := Phrases2.Lookup('BTN_MENU');
     3491    TreasuryArea.Hint := Phrases2.Lookup('TIP_TREASURY');
     3492    ResearchArea.Hint := Phrases.Lookup('SCIENCE');
     3493    ManagementArea.Hint := Phrases2.Lookup('BTN_MANAGE');
     3494  end;
     3495  for i := 0 to mRep.Count - 1 do
     3496  begin
     3497    j := mRep[i].Tag shr 8;
     3498    mRep[i].Caption := CityEventName(j);
     3499    mRep[i].Checked := CityRepMask and (1 shl j) <> 0;
     3500  end;
     3501
     3502  Mini := TBitmap.Create;
     3503  Mini.PixelFormat := pf24bit;
     3504  Panel := TBitmap.Create;
     3505  Panel.PixelFormat := pf24bit;
     3506  Panel.Canvas.Font.Assign(UniFont[ftSmall]);
     3507  Panel.Canvas.Brush.Style := bsClear;
     3508  TopBar := TBitmap.Create;
     3509  TopBar.PixelFormat := pf24bit;
     3510  TopBar.Canvas.Font.Assign(UniFont[ftNormal]);
     3511  TopBar.Canvas.Brush.Style := bsClear;
     3512  Buffer := TBitmap.Create;
     3513  Buffer.PixelFormat := pf24bit;
     3514  if 2 * lxmax > 3 * xSizeBig then
     3515    Buffer.width := 2 * lxmax
     3516  else
     3517    Buffer.width := 3 * xSizeBig;
     3518  if lymax > 3 * ySizeBig then
     3519    Buffer.height := lymax
     3520  else
     3521    Buffer.height := 3 * ySizeBig;
     3522  Buffer.Canvas.Font.Assign(UniFont[ftSmall]);
     3523  for i := 0 to nPl - 1 do
     3524    AILogo[i] := nil;
     3525  Canvas.Font.Assign(UniFont[ftSmall]);
     3526  InitButtons();
     3527  EOT.Template := Templates;
     3528end;
     3529
     3530procedure TMainScreen.FormDestroy(Sender: TObject);
     3531var
     3532  i: integer;
     3533begin
     3534  TopBar.free;
     3535  Mini.free;
     3536  Buffer.free;
     3537  Panel.free;
     3538  for i := 0 to nPl - 1 do
     3539    if AILogo[i] <> nil then
     3540      AILogo[i].free;
     3541end;
     3542
     3543procedure TMainScreen.FormResize(Sender: TObject);
     3544var
     3545  MiniFrame, MaxMapWidth: integer;
     3546begin
     3547  SmallScreen := ClientWidth < 1024;
     3548  MaxMapWidth := (G.lx * 2 - 3) * xxt;
     3549  // avoide the same tile being visible left and right
     3550  if ClientWidth <= MaxMapWidth then
     3551  begin
     3552    MapWidth := ClientWidth;
     3553    MapOffset := 0;
     3554  end
     3555  else
     3556  begin
     3557    MapWidth := MaxMapWidth;
     3558    MapOffset := (ClientWidth - MapWidth) div 2;
     3559  end;
     3560  MapHeight := ClientHeight - TopBarHeight - PanelHeight + overlap;
     3561  Panel.width := ClientWidth;
     3562  Panel.height := PanelHeight;
     3563  TopBar.width := ClientWidth;
     3564  TopBar.height := TopBarHeight;
     3565  MiniFrame := (lxmax_xxx - G.ly) div 2;
     3566  xMidPanel := (G.lx + MiniFrame) * 2 + 1;
     3567  xRightPanel := ClientWidth - LeftPanelWidth - 10;
     3568  if ClientMode = cEditMap then
     3569    TrPitch := 2 * xxt
     3570  else
     3571    TrPitch := 66;
     3572  xMini := MiniFrame - 5;
     3573  yMini := (PanelHeight - 26 - lxmax_xxx) div 2 + MiniFrame;
     3574  ywmax := (G.ly - MapHeight div yyt + 1) and not 1;
     3575  ywcenter := -((MapHeight - yyt * (G.ly - 1)) div (4 * yyt)) * 2;
     3576  // only for ywmax<=0
     3577  if ywmax <= 0 then
     3578    yw := ywcenter
     3579  else if yw < 0 then
     3580    yw := 0
     3581  else if yw > ywmax then
     3582    yw := ywmax;
     3583  UnitInfoBtn.Top := ClientHeight - 29;
     3584  UnitInfoBtn.Left := xMidPanel + 7 + 99;
     3585  UnitBtn.Top := ClientHeight - 29;
     3586  UnitBtn.Left := xMidPanel + 7 + 99 + 31;
     3587  TerrainBtn.Top := ClientHeight - 29;
     3588  TerrainBtn.Left := xMidPanel + 7 + 99 + 62;
     3589  MovieSpeed1Btn.Top := ClientHeight - 91;
     3590  MovieSpeed1Btn.Left := ClientWidth div 2 - 62;
     3591  MovieSpeed2Btn.Top := ClientHeight - 91;
     3592  MovieSpeed2Btn.Left := ClientWidth div 2 - 62 + 29;
     3593  MovieSpeed3Btn.Top := ClientHeight - 91;
     3594  MovieSpeed3Btn.Left := ClientWidth div 2 - 62 + 2 * 29;
     3595  MovieSpeed4Btn.Top := ClientHeight - 91;
     3596  MovieSpeed4Btn.Left := ClientWidth div 2 - 62 + 3 * 29 + 12;
     3597  EOT.Top := ClientHeight - 64;
     3598  EOT.Left := ClientWidth - 62;
     3599  SetWindowPos(sb.h, 0, xRightPanel + 10 - 14 - GetSystemMetrics(SM_CXVSCROLL),
     3600    ClientHeight - MidPanelHeight + 8, 0, 0, SWP_NOSIZE or SWP_NOZORDER);
     3601  MapBtn0.Left := xMini + G.lx - 44;
     3602  MapBtn0.Top := ClientHeight - 15;
     3603  MapBtn1.Left := xMini + G.lx - 28;
     3604  MapBtn1.Top := ClientHeight - 15;
     3605  { MapBtn2.Left:=xMini+G.lx-20;
     3606    MapBtn2.Top:=ClientHeight-15;
     3607    MapBtn3.Left:=xMini+G.lx-4;
     3608    MapBtn3.Top:=ClientHeight-15; }
     3609  MapBtn5.Left := xMini + G.lx - 12;
     3610  MapBtn5.Top := ClientHeight - 15;
     3611  MapBtn4.Left := xMini + G.lx + 20;
     3612  MapBtn4.Top := ClientHeight - 15;
     3613  MapBtn6.Left := xMini + G.lx + 36;
     3614  MapBtn6.Top := ClientHeight - 15;
     3615  TreasuryArea.Left := ClientWidth div 2 - 172;
     3616  ResearchArea.Left := ClientWidth div 2;
     3617  ManagementArea.Left := ClientWidth - xPalace;
     3618  ManagementArea.Top := TopBarHeight + MapHeight - overlap + yPalace;
     3619  ArrangeMidPanel;
     3620  if RepaintOnResize then
     3621  begin
     3622    RectInvalidate(0, TopBarHeight, ClientWidth, TopBarHeight + MapHeight);
     3623    MapValid := false;
     3624    PaintAll
     3625  end
     3626end;
     3627
     3628procedure TMainScreen.FormCloseQuery(Sender: TObject; var CanClose: boolean);
     3629begin
     3630  CanClose := Closable;
     3631  if not Closable and idle and (me = 0) and (ClientMode < scContact) then
     3632    MenuClick(mResign)
     3633end;
     3634
     3635procedure TMainScreen.OnScroll(var m: TMessage);
     3636begin
     3637  if ProcessPVSB(sb, m) then
     3638  begin
     3639    PanelPaint;
     3640    Update
     3641  end
     3642end;
     3643
     3644procedure TMainScreen.OnEOT(var Msg: TMessage);
     3645begin
     3646  EndTurn
     3647end;
     3648
     3649procedure TMainScreen.EOTClick(Sender: TObject);
     3650begin
     3651  if GameMode = cMovie then
     3652  begin
     3653    MessgExDlg.CancelMovie;
     3654    Server(sBreak, me, 0, nil^)
     3655  end
     3656  else if ClientMode < 0 then
     3657    skipped := true
     3658  else if ClientMode >= scContact then
     3659    NegoDlg.ShowNewContent(wmPersistent)
     3660  else if Jump[pTurn] > 0 then
     3661  begin
     3662    Jump[pTurn] := 0;
     3663    StartRunning := false
     3664  end
     3665  else
     3666    EndTurn
     3667end;
     3668
     3669// set xTerrain, xTroop, and TrRow
     3670procedure TMainScreen.ArrangeMidPanel;
     3671begin
     3672  if ClientMode = cEditMap then
     3673    xTroop := xMidPanel + 15
     3674  else
     3675  begin
     3676    if supervising then
     3677      xTerrain := xMidPanel + 2 * xxt + 14
     3678    else if ClientWidth < 1280 then
     3679      xTerrain := ClientWidth div 2 + (1280 - ClientWidth) div 3
    34473680    else
    3448       SoundMode := smOn;
     3681      xTerrain := ClientWidth div 2;
     3682    xTroop := xTerrain + 2 * xxt + 12;
     3683    if SmallScreen and not supervising then
     3684      xTroop := xRightPanel + 10 - 3 * 66 -
     3685        GetSystemMetrics(SM_CXVSCROLL) - 19 - 4;
     3686    // not perfect but we assume almost no one is still playing on a 800x600 screen
    34493687  end;
    3450 
    3451   procedure TMainScreen.FormCreate(Sender: TObject);
     3688  TrRow := (xRightPanel + 10 - xTroop - GetSystemMetrics(SM_CXVSCROLL) - 19)
     3689    div TrPitch;
     3690end;
     3691
     3692function TMainScreen.EndTurn(WasSkipped: boolean): boolean;
     3693
     3694  function IsResourceUnused(cix, NeedFood, NeedProd: integer): boolean;
    34523695  var
    3453     i, j: integer;
    3454   begin
    3455     {$IFDEF WINDOWS}{TODO}
    3456     Screen.Cursors[crImpDrag] := LoadCursor(HInstance, 'DRAG');
    3457     Screen.Cursors[crFlatHand] := LoadCursor(HInstance, 'FLATHAND');
    3458     {$ENDIF}
    3459 
    3460     // tag-controlled language
    3461     for i := 0 to ComponentCount - 1 do
    3462       if Components[i].Tag and $FF <> 0 then
    3463         if Components[i] is TMenuItem then
     3696    dx, dy, fix: integer;
     3697    CityAreaInfo: TCityAreaInfo;
     3698    TileInfo: TTileInfo;
     3699  begin
     3700    Server(sGetCityAreaInfo, me, cix, CityAreaInfo);
     3701    for dy := -3 to 3 do
     3702      for dx := -3 to 3 do
     3703        if ((dx + dy) and 1 = 0) and (dx * dx * dy * dy < 81) then
    34643704        begin
    3465           TMenuItem(Components[i]).Caption := Phrases.Lookup('CONTROLS',
    3466             -1 + Components[i].Tag and $FF);
    3467           for j := 0 to nSaveOption - 1 do
    3468             if Components[i].Tag and $FF = SaveOption[j] then
    3469               TMenuItem(Components[i]).Checked := 1 shl j and
    3470                 OptionChecked <> 0;
    3471         end
    3472         else if Components[i] is TButtonBase then
     3705          fix := (dy + 3) shl 2 + (dx + 3) shr 1;
     3706          if (MyCity[cix].Tiles and (1 shl fix) = 0) // not used yet
     3707            and (CityAreaInfo.Available[fix] = faAvailable) then // usable
     3708          begin
     3709            TileInfo.ExplCity := cix;
     3710            Server(sGetHypoCityTileInfo, me, dLoc(MyCity[cix].Loc, dx, dy),
     3711              TileInfo);
     3712            if (TileInfo.Food >= NeedFood) and (TileInfo.Prod >= NeedProd) then
     3713            begin
     3714              result := true;
     3715              exit
     3716            end;
     3717          end
     3718        end;
     3719    result := false;
     3720  end;
     3721
     3722var
     3723  i, p1, uix, cix, CenterLoc: integer;
     3724  MsgItem: string;
     3725  CityReport: TCityReport;
     3726  PlaneReturnData: TPlaneReturnData;
     3727  Zoom: boolean;
     3728begin
     3729  result := false;
     3730  if ClientMode >= scDipOffer then
     3731    exit;
     3732
     3733  if supervising and (me <> 0) then
     3734  begin
     3735    for i := 0 to Screen.FormCount - 1 do
     3736      if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
     3737        Screen.Forms[i].Close; // close windows
     3738    ItsMeAgain(0);
     3739  end;
     3740
     3741  CityOptimizer_EndOfTurn;
     3742
     3743  if not WasSkipped then // check warnings
     3744  begin
     3745    // need to move planes home?
     3746    for uix := 0 to MyRO.nUn - 1 do
     3747      with MyUn[uix] do
     3748        if (Loc >= 0) and (MyModel[mix].Domain = dAir) and
     3749          (Status and usToldNoReturn = 0) and (Master < 0) and
     3750          (MyMap[Loc] and fCity = 0) and (MyMap[Loc] and fTerImp <> tiBase) then
    34733751        begin
    3474           TButtonBase(Components[i]).Hint := Phrases.Lookup('CONTROLS',
    3475             -1 + Components[i].Tag and $FF);
    3476           if (Components[i] is TButtonC) and
    3477             (TButtonC(Components[i]).ButtonIndex <> 1) then
    3478             TButtonC(Components[i]).ButtonIndex :=
    3479               MapOptionChecked shr (Components[i].Tag shr 8) and 1 + 2
     3752          PlaneReturnData.Fuel := Fuel;
     3753          PlaneReturnData.Loc := Loc;
     3754          PlaneReturnData.Movement := 0; // end turn without further movement?
     3755          if Server(sGetPlaneReturn, me, uix, PlaneReturnData) = eNoWay then
     3756          begin
     3757            CenterLoc := Loc + G.lx * 6;
     3758            // centering the unit itself would make it covered by the query dialog
     3759            while CenterLoc >= G.lx * G.ly do
     3760              dec(CenterLoc, G.lx * 2);
     3761            Centre(CenterLoc);
     3762            SetTroopLoc(-1);
     3763            PaintAll;
     3764
     3765            if MyModel[mix].Kind = mkSpecial_Glider then
     3766              MsgItem := 'LOWFUEL_GLIDER'
     3767            else
     3768              MsgItem := 'LOWFUEL';
     3769            if SimpleQuery(mkYesNo, Phrases.Lookup(MsgItem),
     3770              'WARNING_LOWSUPPORT') <> mrOK then
     3771            begin
     3772              SetUnFocus(uix);
     3773              SetTroopLoc(Loc);
     3774              PanelPaint;
     3775              exit;
     3776            end;
     3777            MyUn[uix].Status := MyUn[uix].Status or usToldNoReturn;
     3778          end
    34803779        end;
    34813780
    3482     // non-tag-controlled language
    3483     mTechTree.Caption := Phrases2.Lookup('MENU_ADVTREE');
    3484     mViewpoint.Caption := Phrases2.Lookup('MENU_VIEWPOINT');
    3485     if not Phrases2FallenBackToEnglish then
    3486     begin
    3487       MenuArea.Hint := Phrases2.Lookup('BTN_MENU');
    3488       TreasuryArea.Hint := Phrases2.Lookup('TIP_TREASURY');
    3489       ResearchArea.Hint := Phrases.Lookup('SCIENCE');
    3490       ManagementArea.Hint := Phrases2.Lookup('BTN_MANAGE');
    3491     end;
    3492     for i := 0 to mRep.Count - 1 do
    3493     begin
    3494       j := mRep[i].Tag shr 8;
    3495       mRep[i].Caption := CityEventName(j);
    3496       mRep[i].Checked := CityRepMask and (1 shl j) <> 0;
    3497     end;
    3498 
    3499     Mini := TBitmap.Create;
    3500     Mini.PixelFormat := pf24bit;
    3501     Panel := TBitmap.Create;
    3502     Panel.PixelFormat := pf24bit;
    3503     Panel.Canvas.Font.Assign(UniFont[ftSmall]);
    3504     Panel.Canvas.Brush.Style := bsClear;
    3505     TopBar := TBitmap.Create;
    3506     TopBar.PixelFormat := pf24bit;
    3507     TopBar.Canvas.Font.Assign(UniFont[ftNormal]);
    3508     TopBar.Canvas.Brush.Style := bsClear;
    3509     Buffer := TBitmap.Create;
    3510     Buffer.PixelFormat := pf24bit;
    3511     if 2 * lxmax > 3 * xSizeBig then
    3512       Buffer.width := 2 * lxmax
    3513     else
    3514       Buffer.width := 3 * xSizeBig;
    3515     if lymax > 3 * ySizeBig then
    3516       Buffer.height := lymax
    3517     else
    3518       Buffer.height := 3 * ySizeBig;
    3519     Buffer.Canvas.Font.Assign(UniFont[ftSmall]);
    3520     for i := 0 to nPl - 1 do
    3521       AILogo[i] := nil;
    3522     Canvas.Font.Assign(UniFont[ftSmall]);
    3523     InitButtons();
    3524     EOT.Template := Templates;
    3525   end;
    3526 
    3527   procedure TMainScreen.FormDestroy(Sender: TObject);
    3528   var
    3529     i: integer;
    3530   begin
    3531     TopBar.Free;
    3532     Mini.Free;
    3533     Buffer.Free;
    3534     Panel.Free;
    3535     for i := 0 to nPl - 1 do
    3536       if AILogo[i] <> nil then
    3537         AILogo[i].Free;
    3538   end;
    3539 
    3540   procedure TMainScreen.FormResize(Sender: TObject);
    3541   var
    3542     MiniFrame, MaxMapWidth: integer;
    3543   begin
    3544     SmallScreen := ClientWidth < 1024;
    3545     MaxMapWidth := (G.lx * 2 - 3) * xxt;
    3546     // avoide the same tile being visible left and right
    3547     if ClientWidth <= MaxMapWidth then
    3548     begin
    3549       MapWidth := ClientWidth;
    3550       MapOffset := 0;
    3551     end
    3552     else
    3553     begin
    3554       MapWidth := MaxMapWidth;
    3555       MapOffset := (ClientWidth - MapWidth) div 2;
    3556     end;
    3557     MapHeight := ClientHeight - TopBarHeight - PanelHeight + overlap;
    3558     Panel.width := ClientWidth;
    3559     Panel.height := PanelHeight;
    3560     TopBar.width := ClientWidth;
    3561     TopBar.height := TopBarHeight;
    3562     MiniFrame := (lxmax_xxx - G.ly) div 2;
    3563     xMidPanel := (G.lx + MiniFrame) * 2 + 1;
    3564     xRightPanel := ClientWidth - LeftPanelWidth - 10;
    3565     if ClientMode = cEditMap then
    3566       TrPitch := 2 * xxt
    3567     else
    3568       TrPitch := 66;
    3569     xMini := MiniFrame - 5;
    3570     yMini := (PanelHeight - 26 - lxmax_xxx) div 2 + MiniFrame;
    3571     ywmax := (G.ly - MapHeight div yyt + 1) and not 1;
    3572     ywcenter := -((MapHeight - yyt * (G.ly - 1)) div (4 * yyt)) * 2;
    3573     // only for ywmax<=0
    3574     if ywmax <= 0 then
    3575       yw := ywcenter
    3576     else if yw < 0 then
    3577       yw := 0
    3578     else if yw > ywmax then
    3579       yw := ywmax;
    3580     UnitInfoBtn.Top := ClientHeight - 29;
    3581     UnitInfoBtn.Left := xMidPanel + 7 + 99;
    3582     UnitBtn.Top := ClientHeight - 29;
    3583     UnitBtn.Left := xMidPanel + 7 + 99 + 31;
    3584     TerrainBtn.Top := ClientHeight - 29;
    3585     TerrainBtn.Left := xMidPanel + 7 + 99 + 62;
    3586     MovieSpeed1Btn.Top := ClientHeight - 91;
    3587     MovieSpeed1Btn.Left := ClientWidth div 2 - 62;
    3588     MovieSpeed2Btn.Top := ClientHeight - 91;
    3589     MovieSpeed2Btn.Left := ClientWidth div 2 - 62 + 29;
    3590     MovieSpeed3Btn.Top := ClientHeight - 91;
    3591     MovieSpeed3Btn.Left := ClientWidth div 2 - 62 + 2 * 29;
    3592     MovieSpeed4Btn.Top := ClientHeight - 91;
    3593     MovieSpeed4Btn.Left := ClientWidth div 2 - 62 + 3 * 29 + 12;
    3594     EOT.Top := ClientHeight - 64;
    3595     EOT.Left := ClientWidth - 62;
    3596     SetWindowPos(sb.h, 0, xRightPanel + 10 - 14 -
    3597       GetSystemMetrics(SM_CXVSCROLL), ClientHeight - MidPanelHeight + 8, 0, 0,
    3598       SWP_NOSIZE or SWP_NOZORDER);
    3599     MapBtn0.Left := xMini + G.lx - 44;
    3600     MapBtn0.Top := ClientHeight - 15;
    3601     MapBtn1.Left := xMini + G.lx - 28;
    3602     MapBtn1.Top := ClientHeight - 15;
    3603     { MapBtn2.Left:=xMini+G.lx-20;
    3604       MapBtn2.Top:=ClientHeight-15;
    3605       MapBtn3.Left:=xMini+G.lx-4;
    3606       MapBtn3.Top:=ClientHeight-15; }
    3607     MapBtn5.Left := xMini + G.lx - 12;
    3608     MapBtn5.Top := ClientHeight - 15;
    3609     MapBtn4.Left := xMini + G.lx + 20;
    3610     MapBtn4.Top := ClientHeight - 15;
    3611     MapBtn6.Left := xMini + G.lx + 36;
    3612     MapBtn6.Top := ClientHeight - 15;
    3613     TreasuryArea.Left := ClientWidth div 2 - 172;
    3614     ResearchArea.Left := ClientWidth div 2;
    3615     ManagementArea.Left := ClientWidth - xPalace;
    3616     ManagementArea.Top := TopBarHeight + MapHeight - overlap + yPalace;
    3617     ArrangeMidPanel;
    3618     if RepaintOnResize then
    3619     begin
    3620       RectInvalidate(0, TopBarHeight, ClientWidth, TopBarHeight + MapHeight);
    3621       MapValid := false;
    3622       PaintAll
    3623     end
    3624   end;
    3625 
    3626   procedure TMainScreen.FormCloseQuery(Sender: TObject; var CanClose: boolean);
    3627   begin
    3628     CanClose := Closable;
    3629     if not Closable and idle and (me = 0) and (ClientMode < scContact) then
    3630       MenuClick(mResign)
    3631   end;
    3632 
    3633   procedure TMainScreen.OnScroll(var m: TMessage);
    3634   begin
    3635     if ProcessPVSB(sb, m) then
    3636     begin
    3637       PanelPaint;
    3638       Update
    3639     end
    3640   end;
    3641 
    3642   procedure TMainScreen.OnEOT(var Msg: TMessage);
    3643   begin
    3644     EndTurn
    3645   end;
    3646 
    3647   procedure TMainScreen.EOTClick(Sender: TObject);
    3648   begin
    3649     if GameMode = cMovie then
    3650     begin
    3651       MessgExDlg.CancelMovie;
    3652       Server(sBreak, me, 0, nil^)
    3653     end
    3654     else if ClientMode < 0 then
    3655       skipped := true
    3656     else if ClientMode >= scContact then
    3657       NegoDlg.ShowNewContent(wmPersistent)
    3658     else if Jump[pTurn] > 0 then
    3659     begin
    3660       Jump[pTurn] := 0;
    3661       StartRunning := false
    3662     end
    3663     else
    3664       EndTurn
    3665   end;
    3666 
    3667   // set xTerrain, xTroop, and TrRow
    3668   procedure TMainScreen.ArrangeMidPanel;
    3669   begin
    3670     if ClientMode = cEditMap then
    3671       xTroop := xMidPanel + 15
    3672     else
    3673     begin
    3674       if supervising then
    3675         xTerrain := xMidPanel + 2 * xxt + 14
    3676       else if ClientWidth < 1280 then
    3677         xTerrain := ClientWidth div 2 + (1280 - ClientWidth) div 3
    3678       else
    3679         xTerrain := ClientWidth div 2;
    3680       xTroop := xTerrain + 2 * xxt + 12;
    3681       if SmallScreen and not supervising then
    3682         xTroop := xRightPanel + 10 - 3 * 66 -
    3683           GetSystemMetrics(SM_CXVSCROLL) - 19 - 4;
    3684       // not perfect but we assume almost no one is still playing on a 800x600 screen
    3685     end;
    3686     TrRow := (xRightPanel + 10 - xTroop - GetSystemMetrics(SM_CXVSCROLL) - 19)
    3687       div TrPitch;
    3688   end;
    3689 
    3690   function TMainScreen.EndTurn(WasSkipped: boolean): boolean;
    3691 
    3692     function IsResourceUnused(cix, NeedFood, NeedProd: integer): boolean;
    3693     var
    3694       dx, dy, fix: integer;
    3695       CityAreaInfo: TCityAreaInfo;
    3696       TileInfo: TTileInfo;
    3697     begin
    3698       Server(sGetCityAreaInfo, me, cix, CityAreaInfo);
    3699       for dy := -3 to 3 do
    3700         for dx := -3 to 3 do
    3701           if ((dx + dy) and 1 = 0) and (dx * dx * dy * dy < 81) then
     3781    if not supervising and (MyRO.TestFlags and tfImmImprove = 0) and
     3782      (MyRO.Government <> gAnarchy) and (MyRO.Money + TaxSum < 0) and
     3783      (MyRO.TaxRate < 100) then // low funds!
     3784      with MessgExDlg do
     3785      begin
     3786        OpenSound := 'WARNING_LOWFUNDS';
     3787        MessgText := Phrases.Lookup('LOWFUNDS');
     3788        Kind := mkYesNo;
     3789        IconKind := mikImp;
     3790        IconIndex := imTrGoods;
     3791        ShowModal;
     3792        if ModalResult <> mrOK then
     3793          exit
     3794      end;
     3795
     3796    if MyRO.Government <> gAnarchy then
     3797      for cix := 0 to MyRO.nCity - 1 do
     3798        with MyCity[cix] do
     3799          if (Loc >= 0) and (Flags and chCaptured = 0) then
    37023800          begin
    3703             fix := (dy + 3) shl 2 + (dx + 3) shr 1;
    3704             if (MyCity[cix].Tiles and (1 shl fix) = 0) // not used yet
    3705               and (CityAreaInfo.Available[fix] = faAvailable) then // usable
    3706             begin
    3707               TileInfo.ExplCity := cix;
    3708               Server(sGetHypoCityTileInfo, me, dLoc(MyCity[cix].Loc, dx, dy),
    3709                 TileInfo);
    3710               if (TileInfo.Food >= NeedFood) and (TileInfo.Prod >= NeedProd)
    3711               then
     3801            Zoom := false;
     3802            CityReport.HypoTiles := -1;
     3803            CityReport.HypoTax := -1;
     3804            CityReport.HypoLux := -1;
     3805            Server(sGetCityReport, me, cix, CityReport);
     3806
     3807            if (CityReport.Working - CityReport.Happy > Size shr 1) and
     3808              (Flags and chCaptured <= $10000) then
     3809              with MessgExDlg do
    37123810              begin
    3713                 result := true;
    3714                 exit
     3811                OpenSound := 'WARNING_DISORDER';
     3812                if Status and csResourceWeightsMask = 0 then
     3813                  MsgItem := 'DISORDER'
     3814                else
     3815                  MsgItem := 'DISORDER_UNREST';
     3816                MessgText := Format(Phrases.Lookup(MsgItem), [CityName(ID)]);
     3817                Kind := mkYesNo;
     3818                // BigIcon:=29;
     3819                ShowModal;
     3820                Zoom := ModalResult <> mrOK;
    37153821              end;
     3822            if not Zoom and (Food + CityReport.FoodRep - CityReport.Eaten < 0)
     3823            then
     3824              with MessgExDlg do
     3825              begin
     3826                OpenSound := 'WARNING_FAMINE';
     3827                if Status and csResourceWeightsMask = 0 then
     3828                  MsgItem := 'FAMINE'
     3829                else if (CityReport.Deployed <> 0) and
     3830                  IsResourceUnused(cix, 1, 0) then
     3831                  MsgItem := 'FAMINE_UNREST'
     3832                else
     3833                  MsgItem := 'FAMINE_TILES';
     3834                MessgText := Format(Phrases.Lookup(MsgItem), [CityName(ID)]);
     3835                Kind := mkYesNo;
     3836                IconKind := mikImp;
     3837                IconIndex := 22;
     3838                ShowModal;
     3839                Zoom := ModalResult <> mrOK;
     3840              end;
     3841            if not Zoom and (CityReport.ProdRep < CityReport.Support) then
     3842              with MessgExDlg do
     3843              begin
     3844                OpenSound := 'WARNING_LOWSUPPORT';
     3845                if Status and csResourceWeightsMask = 0 then
     3846                  MsgItem := 'LOWSUPPORT'
     3847                else if (CityReport.Deployed <> 0) and
     3848                  IsResourceUnused(cix, 0, 1) then
     3849                  MsgItem := 'LOWSUPPORT_UNREST'
     3850                else
     3851                  MsgItem := 'LOWSUPPORT_TILES';
     3852                MessgText := Format(Phrases.Lookup(MsgItem), [CityName(ID)]);
     3853                Kind := mkYesNo;
     3854                IconKind := mikImp;
     3855                IconIndex := 29;
     3856                ShowModal;
     3857                Zoom := ModalResult <> mrOK;
     3858              end;
     3859            if Zoom then
     3860            begin // zoom to city
     3861              ZoomToCity(Loc);
     3862              exit
    37163863            end
    37173864          end;
    3718       result := false;
    3719     end;
    3720 
    3721   var
    3722     i, p1, uix, cix, CenterLoc: integer;
    3723     MsgItem: string;
    3724     CityReport: TCityReport;
    3725     PlaneReturnData: TPlaneReturnData;
    3726     Zoom: boolean;
    3727   begin
    3728     result := false;
    3729     if ClientMode >= scDipOffer then
    3730       exit;
    3731 
    3732     if supervising and (me <> 0) then
    3733     begin
    3734       for i := 0 to Screen.FormCount - 1 do
    3735         if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
    3736         then
    3737           Screen.Forms[i].Close; // close windows
    3738       ItsMeAgain(0);
    3739     end;
    3740 
    3741     CityOptimizer_EndOfTurn;
    3742 
    3743     if not WasSkipped then // check warnings
    3744     begin
    3745       // need to move planes home?
    3746       for uix := 0 to MyRO.nUn - 1 do
    3747         with MyUn[uix] do
    3748           if (Loc >= 0) and (MyModel[mix].Domain = dAir) and
    3749             (Status and usToldNoReturn = 0) and (Master < 0) and
    3750             (MyMap[Loc] and fCity = 0) and (MyMap[Loc] and fTerImp <> tiBase)
    3751           then
    3752           begin
    3753             PlaneReturnData.Fuel := Fuel;
    3754             PlaneReturnData.Loc := Loc;
    3755             PlaneReturnData.Movement := 0; // end turn without further movement?
    3756             if Server(sGetPlaneReturn, me, uix, PlaneReturnData) = eNoWay then
    3757             begin
    3758               CenterLoc := Loc + G.lx * 6;
    3759               // centering the unit itself would make it covered by the query dialog
    3760               while CenterLoc >= G.lx * G.ly do
    3761                 dec(CenterLoc, G.lx * 2);
    3762               Centre(CenterLoc);
    3763               SetTroopLoc(-1);
    3764               PaintAll;
    3765 
    3766               if MyModel[mix].Kind = mkSpecial_Glider then
    3767                 MsgItem := 'LOWFUEL_GLIDER'
    3768               else
    3769                 MsgItem := 'LOWFUEL';
    3770               if SimpleQuery(mkYesNo, Phrases.Lookup(MsgItem),
    3771                 'WARNING_LOWSUPPORT') <> mrOK then
    3772               begin
    3773                 SetUnFocus(uix);
    3774                 SetTroopLoc(Loc);
    3775                 PanelPaint;
    3776                 exit;
    3777               end;
    3778               MyUn[uix].Status := MyUn[uix].Status or usToldNoReturn;
    3779             end
    3780           end;
    3781 
    3782       if not supervising and (MyRO.TestFlags and tfImmImprove = 0) and
    3783         (MyRO.Government <> gAnarchy) and (MyRO.Money + TaxSum < 0) and
    3784         (MyRO.TaxRate < 100) then // low funds!
    3785         with MessgExDlg do
    3786         begin
    3787           OpenSound := 'WARNING_LOWFUNDS';
    3788           MessgText := Phrases.Lookup('LOWFUNDS');
    3789           Kind := mkYesNo;
    3790           IconKind := mikImp;
    3791           IconIndex := imTrGoods;
    3792           ShowModal;
    3793           if ModalResult <> mrOK then
    3794             exit
    3795         end;
    3796 
    3797       if MyRO.Government <> gAnarchy then
    3798         for cix := 0 to MyRO.nCity - 1 do
    3799           with MyCity[cix] do
    3800             if (Loc >= 0) and (Flags and chCaptured = 0) then
    3801             begin
    3802               Zoom := false;
    3803               CityReport.HypoTiles := -1;
    3804               CityReport.HypoTax := -1;
    3805               CityReport.HypoLux := -1;
    3806               Server(sGetCityReport, me, cix, CityReport);
    3807 
    3808               if (CityReport.Working - CityReport.Happy > Size shr 1) and
    3809                 (Flags and chCaptured <= $10000) then
    3810                 with MessgExDlg do
    3811                 begin
    3812                   OpenSound := 'WARNING_DISORDER';
    3813                   if Status and csResourceWeightsMask = 0 then
    3814                     MsgItem := 'DISORDER'
    3815                   else
    3816                     MsgItem := 'DISORDER_UNREST';
    3817                   MessgText := Format(Phrases.Lookup(MsgItem), [CityName(ID)]);
    3818                   Kind := mkYesNo;
    3819                   // BigIcon:=29;
    3820                   ShowModal;
    3821                   Zoom := ModalResult <> mrOK;
    3822                 end;
    3823               if not Zoom and (Food + CityReport.FoodRep - CityReport.Eaten < 0)
    3824               then
    3825                 with MessgExDlg do
    3826                 begin
    3827                   OpenSound := 'WARNING_FAMINE';
    3828                   if Status and csResourceWeightsMask = 0 then
    3829                     MsgItem := 'FAMINE'
    3830                   else if (CityReport.Deployed <> 0) and
    3831                     IsResourceUnused(cix, 1, 0) then
    3832                     MsgItem := 'FAMINE_UNREST'
    3833                   else
    3834                     MsgItem := 'FAMINE_TILES';
    3835                   MessgText := Format(Phrases.Lookup(MsgItem), [CityName(ID)]);
    3836                   Kind := mkYesNo;
    3837                   IconKind := mikImp;
    3838                   IconIndex := 22;
    3839                   ShowModal;
    3840                   Zoom := ModalResult <> mrOK;
    3841                 end;
    3842               if not Zoom and (CityReport.ProdRep < CityReport.Support) then
    3843                 with MessgExDlg do
    3844                 begin
    3845                   OpenSound := 'WARNING_LOWSUPPORT';
    3846                   if Status and csResourceWeightsMask = 0 then
    3847                     MsgItem := 'LOWSUPPORT'
    3848                   else if (CityReport.Deployed <> 0) and
    3849                     IsResourceUnused(cix, 0, 1) then
    3850                     MsgItem := 'LOWSUPPORT_UNREST'
    3851                   else
    3852                     MsgItem := 'LOWSUPPORT_TILES';
    3853                   MessgText := Format(Phrases.Lookup(MsgItem), [CityName(ID)]);
    3854                   Kind := mkYesNo;
    3855                   IconKind := mikImp;
    3856                   IconIndex := 29;
    3857                   ShowModal;
    3858                   Zoom := ModalResult <> mrOK;
    3859                 end;
    3860               if Zoom then
    3861               begin // zoom to city
    3862                 ZoomToCity(Loc);
    3863                 exit
    3864               end
    3865             end;
    3866 
    3867       if (MyRO.Happened and phTech <> 0) and (MyRO.ResearchTech < 0) and
    3868         (MyData.FarTech <> adNexus) then
    3869         if not ChooseResearch then
    3870           exit;
    3871     end;
    3872 
    3873     RememberPeaceViolation;
    3874 
    3875     SetUnFocus(-1);
    3876     for uix := 0 to MyRO.nUn - 1 do
    3877       MyUn[uix].Status := MyUn[uix].Status and usPersistent;
    3878 
    3879     CityDlg.CloseAction := None;
    3880     if IsMultiPlayerGame then
    3881     begin // close windows for next player
    3882       for i := 0 to Screen.FormCount - 1 do
    3883         if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
    3884         then
    3885           Screen.Forms[i].Close;
    3886     end
    3887     else
    3888     begin
    3889       if CityDlg.Visible then
    3890         CityDlg.Close;
    3891       if UnitStatDlg.Visible then
    3892         UnitStatDlg.Close;
    3893     end;
     3865
     3866    if (MyRO.Happened and phTech <> 0) and (MyRO.ResearchTech < 0) and
     3867      (MyData.FarTech <> adNexus) then
     3868      if not ChooseResearch then
     3869        exit;
     3870  end;
     3871
     3872  RememberPeaceViolation;
     3873
     3874  SetUnFocus(-1);
     3875  for uix := 0 to MyRO.nUn - 1 do
     3876    MyUn[uix].Status := MyUn[uix].Status and usPersistent;
     3877
     3878  CityDlg.CloseAction := None;
     3879  if IsMultiPlayerGame then
     3880  begin // close windows for next player
    38943881    for i := 0 to Screen.FormCount - 1 do
    38953882      if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
    3896         Screen.Forms[i].Enabled := false;
    3897 
    3898     if Server(sTurn, pTurn, 0, nil^) >= rExecuted then
    3899     begin
    3900       if Jump[pTurn] > 0 then
    3901         EOT.Hint := Phrases.Lookup('BTN_STOP')
    3902       else
    3903         EOT.Hint := Phrases.Lookup('BTN_SKIP');
    3904       result := true;
    3905       SetTroopLoc(-1);
    3906       pTurn := -1;
    3907       pLogo := -1;
    3908       UnitInfoBtn.Visible := false;
    3909       UnitBtn.Visible := false;
    3910       TerrainBtn.Visible := false;
    3911       EOT.ButtonIndex := eotCancel;
    3912       EOT.Visible := true;
    3913       MapValid := false;
    3914       PanelPaint;
    3915       Update;
    3916       ClientMode := -1;
    3917       idle := false;
    3918       skipped := WasSkipped;
    3919       for p1 := 1 to nPl - 1 do
    3920         if G.RO[p1] <> nil then
    3921           skipped := true; // don't show enemy moves in hotseat mode
    3922     end
     3883        Screen.Forms[i].Close;
     3884  end
     3885  else
     3886  begin
     3887    if CityDlg.Visible then
     3888      CityDlg.Close;
     3889    if UnitStatDlg.Visible then
     3890      UnitStatDlg.Close;
     3891  end;
     3892  for i := 0 to Screen.FormCount - 1 do
     3893    if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
     3894      Screen.Forms[i].Enabled := false;
     3895
     3896  if Server(sTurn, pTurn, 0, nil^) >= rExecuted then
     3897  begin
     3898    if Jump[pTurn] > 0 then
     3899      EOT.Hint := Phrases.Lookup('BTN_STOP')
    39233900    else
    3924       PanelPaint
    3925   end; // EndTurn
    3926 
    3927   procedure TMainScreen.EndNego;
    3928   begin
    3929     if NegoDlg.Visible then
    3930       NegoDlg.Close;
    3931     HaveStrategyAdvice := false;
    3932     // AdvisorDlg.HaveStrategyAdvice;
    3933     // negotiation might have changed advices
     3901      EOT.Hint := Phrases.Lookup('BTN_SKIP');
     3902    result := true;
     3903    SetTroopLoc(-1);
     3904    pTurn := -1;
     3905    pLogo := -1;
     3906    UnitInfoBtn.Visible := false;
     3907    UnitBtn.Visible := false;
     3908    TerrainBtn.Visible := false;
    39343909    EOT.ButtonIndex := eotCancel;
    39353910    EOT.Visible := true;
     3911    MapValid := false;
    39363912    PanelPaint;
    39373913    Update;
    39383914    ClientMode := -1;
    39393915    idle := false;
     3916    skipped := WasSkipped;
     3917    for p1 := 1 to nPl - 1 do
     3918      if G.RO[p1] <> nil then
     3919        skipped := true; // don't show enemy moves in hotseat mode
     3920  end
     3921  else
     3922    PanelPaint
     3923end; // EndTurn
     3924
     3925procedure TMainScreen.EndNego;
     3926begin
     3927  if NegoDlg.Visible then
     3928    NegoDlg.Close;
     3929  HaveStrategyAdvice := false;
     3930  // AdvisorDlg.HaveStrategyAdvice;
     3931  // negotiation might have changed advices
     3932  EOT.ButtonIndex := eotCancel;
     3933  EOT.Visible := true;
     3934  PanelPaint;
     3935  Update;
     3936  ClientMode := -1;
     3937  idle := false;
     3938end;
     3939
     3940procedure TMainScreen.ProcessRect(x0, y0, nx, ny, Options: integer);
     3941var
     3942  xs, ys, xl, yl: integer;
     3943begin
     3944  xl := nx * xxt + xxt;
     3945  yl := ny * yyt + yyt * 2;
     3946  xs := (x0 - xw) * (xxt * 2) + y0 and 1 * xxt - G.lx * (xxt * 2);
     3947  // |xs+xl/2-MapWidth/2| -> min
     3948  while abs(2 * (xs + G.lx * (xxt * 2)) + xl - MapWidth) <
     3949    abs(2 * xs + xl - MapWidth) do
     3950    inc(xs, G.lx * (xxt * 2));
     3951  ys := (y0 - yw) * yyt - yyt;
     3952  if xs + xl > MapWidth then
     3953    xl := MapWidth - xs;
     3954  if ys + yl > MapHeight then
     3955    yl := MapHeight - ys;
     3956  if (xl <= 0) or (yl <= 0) then
     3957    exit;
     3958  if Options and prPaint <> 0 then
     3959  begin
     3960    if Options and prAutoBounds <> 0 then
     3961      MainMap.SetPaintBounds(xs, ys, xs + xl, ys + yl);
     3962    MainMap.Paint(xs, ys, x0 + G.lx * y0, nx, ny, -1, -1);
    39403963  end;
    3941 
    3942   procedure TMainScreen.ProcessRect(x0, y0, nx, ny, Options: integer);
    3943   var
    3944     xs, ys, xl, yl: integer;
    3945   begin
    3946     xl := nx * xxt + xxt;
    3947     yl := ny * yyt + yyt * 2;
    3948     xs := (x0 - xw) * (xxt * 2) + y0 and 1 * xxt - G.lx * (xxt * 2);
    3949     // |xs+xl/2-MapWidth/2| -> min
    3950     while abs(2 * (xs + G.lx * (xxt * 2)) + xl - MapWidth) <
    3951       abs(2 * xs + xl - MapWidth) do
    3952       inc(xs, G.lx * (xxt * 2));
    3953     ys := (y0 - yw) * yyt - yyt;
    3954     if xs + xl > MapWidth then
    3955       xl := MapWidth - xs;
    3956     if ys + yl > MapHeight then
    3957       yl := MapHeight - ys;
    3958     if (xl <= 0) or (yl <= 0) then
    3959       exit;
    3960     if Options and prPaint <> 0 then
    3961     begin
    3962       if Options and prAutoBounds <> 0 then
    3963         MainMap.SetPaintBounds(xs, ys, xs + xl, ys + yl);
    3964       MainMap.Paint(xs, ys, x0 + G.lx * y0, nx, ny, -1, -1);
    3965     end;
    3966     if Options and prInvalidate <> 0 then
    3967       RectInvalidate(MapOffset + xs, TopBarHeight + ys, MapOffset + xs + xl,
    3968         TopBarHeight + ys + yl)
     3964  if Options and prInvalidate <> 0 then
     3965    RectInvalidate(MapOffset + xs, TopBarHeight + ys, MapOffset + xs + xl,
     3966      TopBarHeight + ys + yl)
     3967end;
     3968
     3969procedure TMainScreen.PaintLoc(Loc: integer; Radius: integer = 0);
     3970var
     3971  yLoc, x0: integer;
     3972begin
     3973  if MapValid then
     3974  begin
     3975    yLoc := (Loc + G.lx * 1024) div G.lx - 1024;
     3976    x0 := (Loc + (yLoc and 1 - 2 * Radius + G.lx * 1024) div 2) mod G.lx;
     3977    offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
     3978    ProcessRect(x0, yLoc - 2 * Radius, 4 * Radius + 1, 4 * Radius + 1,
     3979      prPaint or prAutoBounds or prInvalidate);
     3980    Update;
     3981  end
     3982end;
     3983
     3984procedure TMainScreen.PaintLocTemp(Loc, Style: integer);
     3985var
     3986  y0, x0, xMap, yMap: integer;
     3987begin
     3988  if not MapValid then
     3989    exit;
     3990  Buffer.Canvas.Font.Assign(UniFont[ftSmall]);
     3991  y0 := Loc div G.lx;
     3992  x0 := Loc mod G.lx;
     3993  xMap := (x0 - xw) * (xxt * 2) + y0 and 1 * xxt - G.lx * (xxt * 2);
     3994  // |xMap+xxt-MapWidth/2| -> min
     3995  while abs(2 * (xMap + G.lx * (xxt * 2)) + 2 * xxt - MapWidth) <
     3996    abs(2 * xMap + 2 * xxt - MapWidth) do
     3997    inc(xMap, G.lx * (xxt * 2));
     3998  yMap := (y0 - yw) * yyt - yyt;
     3999  NoMap.SetOutput(Buffer);
     4000  NoMap.SetPaintBounds(0, 0, 2 * xxt, 3 * yyt);
     4001  NoMap.Paint(0, 0, Loc, 1, 1, -1, -1, Style = pltsBlink);
     4002  PaintBufferToScreen(xMap, yMap, 2 * xxt, 3 * yyt);
     4003end;
     4004
     4005// paint content of buffer directly to screen instead of offscreen
     4006// panel protusions are added
     4007// NoMap must be set to buffer and bounds before
     4008procedure TMainScreen.PaintBufferToScreen(xMap, yMap, width, height: integer);
     4009begin
     4010  if xMap + width > MapWidth then
     4011    width := MapWidth - xMap;
     4012  if yMap + height > MapHeight then
     4013    height := MapHeight - yMap;
     4014  if (width <= 0) or (height <= 0) or (width + xMap <= 0) or (height + yMap <= 0)
     4015  then
     4016    exit;
     4017
     4018  NoMap.BitBlt(Panel, -xMap - MapOffset, -yMap + MapHeight - overlap, xMidPanel,
     4019    overlap, 0, 0, SRCCOPY);
     4020  NoMap.BitBlt(Panel, -xMap - MapOffset + xRightPanel,
     4021    -yMap + MapHeight - overlap, Panel.width - xRightPanel, overlap,
     4022    xRightPanel, 0, SRCCOPY);
     4023  if yMap < 0 then
     4024  begin
     4025    if xMap < 0 then
     4026      BitBlt(Canvas.Handle, MapOffset, TopBarHeight, width + xMap,
     4027        height + yMap, Buffer.Canvas.Handle, -xMap, -yMap, SRCCOPY)
     4028    else
     4029      BitBlt(Canvas.Handle, xMap + MapOffset, TopBarHeight, width,
     4030        height + yMap, Buffer.Canvas.Handle, 0, -yMap, SRCCOPY)
     4031  end
     4032  else
     4033  begin
     4034    if xMap < 0 then
     4035      BitBlt(Canvas.Handle, MapOffset, TopBarHeight + yMap, width + xMap,
     4036        height, Buffer.Canvas.Handle, -xMap, 0, SRCCOPY)
     4037    else
     4038      BitBlt(Canvas.Handle, xMap + MapOffset, TopBarHeight + yMap, width,
     4039        height, Buffer.Canvas.Handle, 0, 0, SRCCOPY);
     4040  end
     4041end;
     4042
     4043procedure TMainScreen.PaintLoc_BeforeMove(FromLoc: integer);
     4044var
     4045  yLoc, x0: integer;
     4046begin
     4047  if MapValid then
     4048  begin
     4049    yLoc := (FromLoc + G.lx * 1024) div G.lx - 1024;
     4050    x0 := (FromLoc + (yLoc and 1 + G.lx * 1024) div 2) mod G.lx;
     4051    offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
     4052    ProcessRect(x0, yLoc, 1, 1, prPaint or prAutoBounds);
     4053  end
     4054end;
     4055
     4056procedure TMainScreen.PaintDestination;
     4057var
     4058  Destination: integer;
     4059begin
     4060  if (UnFocus >= 0) and (MyUn[UnFocus].Status and usGoto <> 0) then
     4061  begin
     4062    Destination := MyUn[UnFocus].Status shr 16;
     4063    if (Destination <> $7FFF) and (Destination <> MyUn[UnFocus].Loc) then
     4064      PaintLocTemp(Destination, pltsBlink);
    39694065  end;
    3970 
    3971   procedure TMainScreen.PaintLoc(Loc: integer; Radius: integer = 0);
    3972   var
    3973     yLoc, x0: integer;
    3974   begin
    3975     if MapValid then
    3976     begin
    3977       yLoc := (Loc + G.lx * 1024) div G.lx - 1024;
    3978       x0 := (Loc + (yLoc and 1 - 2 * Radius + G.lx * 1024) div 2) mod G.lx;
    3979       offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
    3980       ProcessRect(x0, yLoc - 2 * Radius, 4 * Radius + 1, 4 * Radius + 1,
    3981         prPaint or prAutoBounds or prInvalidate);
    3982       Update;
    3983     end
     4066end;
     4067
     4068procedure TMainScreen.MiniPaint;
     4069type
     4070  TLine = array [0 .. 99999999, 0 .. 2] of Byte;
     4071var
     4072  uix, cix, x, y, Loc, i, hw, xm, cm, cmPolOcean, cmPolNone: integer;
     4073  PrevMiniLine, MiniLine: ^TLine;
     4074begin
     4075  cmPolOcean := GrExt[HGrSystem].Data.Canvas.Pixels[101, 67];
     4076  cmPolNone := GrExt[HGrSystem].Data.Canvas.Pixels[102, 67];
     4077  hw := MapWidth div (xxt * 2);
     4078  with Mini.Canvas do
     4079  begin
     4080    Brush.Color := $000000;
     4081    FillRect(Rect(0, 0, Mini.width, Mini.height));
    39844082  end;
    3985 
    3986   procedure TMainScreen.PaintLocTemp(Loc, Style: integer);
    3987   var
    3988     y0, x0, xMap, yMap: integer;
    3989   begin
    3990     if not MapValid then
    3991       exit;
    3992     Buffer.Canvas.Font.Assign(UniFont[ftSmall]);
    3993     y0 := Loc div G.lx;
    3994     x0 := Loc mod G.lx;
    3995     xMap := (x0 - xw) * (xxt * 2) + y0 and 1 * xxt - G.lx * (xxt * 2);
    3996     // |xMap+xxt-MapWidth/2| -> min
    3997     while abs(2 * (xMap + G.lx * (xxt * 2)) + 2 * xxt - MapWidth) <
    3998       abs(2 * xMap + 2 * xxt - MapWidth) do
    3999       inc(xMap, G.lx * (xxt * 2));
    4000     yMap := (y0 - yw) * yyt - yyt;
    4001     NoMap.SetOutput(Buffer);
    4002     NoMap.SetPaintBounds(0, 0, 2 * xxt, 3 * yyt);
    4003     NoMap.Paint(0, 0, Loc, 1, 1, -1, -1, Style = pltsBlink);
    4004     PaintBufferToScreen(xMap, yMap, 2 * xxt, 3 * yyt);
    4005   end;
    4006 
    4007   // paint content of buffer directly to screen instead of offscreen
    4008   // panel protusions are added
    4009   // NoMap must be set to buffer and bounds before
    4010   procedure TMainScreen.PaintBufferToScreen(xMap, yMap, width, height: integer);
    4011   begin
    4012     if xMap + width > MapWidth then
    4013       width := MapWidth - xMap;
    4014     if yMap + height > MapHeight then
    4015       height := MapHeight - yMap;
    4016     if (width <= 0) or (height <= 0) or (width + xMap <= 0) or
    4017       (height + yMap <= 0) then
    4018       exit;
    4019 
    4020     NoMap.BitBlt(Panel, -xMap - MapOffset, -yMap + MapHeight - overlap,
    4021       xMidPanel, overlap, 0, 0, SRCCOPY);
    4022     NoMap.BitBlt(Panel, -xMap - MapOffset + xRightPanel,
    4023       -yMap + MapHeight - overlap, Panel.width - xRightPanel, overlap,
    4024       xRightPanel, 0, SRCCOPY);
    4025     if yMap < 0 then
    4026     begin
    4027       if xMap < 0 then
    4028         BitBlt(Canvas.Handle, MapOffset, TopBarHeight, width + xMap,
    4029           height + yMap, Buffer.Canvas.Handle, -xMap, -yMap, SRCCOPY)
    4030       else
    4031         BitBlt(Canvas.Handle, xMap + MapOffset, TopBarHeight, width,
    4032           height + yMap, Buffer.Canvas.Handle, 0, -yMap, SRCCOPY)
    4033     end
    4034     else
    4035     begin
    4036       if xMap < 0 then
    4037         BitBlt(Canvas.Handle, MapOffset, TopBarHeight + yMap, width + xMap,
    4038           height, Buffer.Canvas.Handle, -xMap, 0, SRCCOPY)
    4039       else
    4040         BitBlt(Canvas.Handle, xMap + MapOffset, TopBarHeight + yMap, width,
    4041           height, Buffer.Canvas.Handle, 0, 0, SRCCOPY);
    4042     end
    4043   end;
    4044 
    4045   procedure TMainScreen.PaintLoc_BeforeMove(FromLoc: integer);
    4046   var
    4047     yLoc, x0: integer;
    4048   begin
    4049     if MapValid then
    4050     begin
    4051       yLoc := (FromLoc + G.lx * 1024) div G.lx - 1024;
    4052       x0 := (FromLoc + (yLoc and 1 + G.lx * 1024) div 2) mod G.lx;
    4053       offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
    4054       ProcessRect(x0, yLoc, 1, 1, prPaint or prAutoBounds);
    4055     end
    4056   end;
    4057 
    4058   procedure TMainScreen.PaintDestination;
    4059   var
    4060     Destination: integer;
    4061   begin
    4062     if (UnFocus >= 0) and (MyUn[UnFocus].Status and usGoto <> 0) then
    4063     begin
    4064       Destination := MyUn[UnFocus].Status shr 16;
    4065       if (Destination <> $7FFF) and (Destination <> MyUn[UnFocus].Loc) then
    4066         PaintLocTemp(Destination, pltsBlink);
    4067     end;
    4068   end;
    4069 
    4070   procedure TMainScreen.MiniPaint;
    4071   type
    4072     TLine = array [0 .. 99999999, 0 .. 2] of Byte;
    4073   var
    4074     uix, cix, x, y, Loc, i, hw, xm, cm, cmPolOcean, cmPolNone: integer;
    4075     PrevMiniLine, MiniLine: ^TLine;
    4076   begin
    4077     cmPolOcean := GrExt[HGrSystem].Data.Canvas.Pixels[101, 67];
    4078     cmPolNone := GrExt[HGrSystem].Data.Canvas.Pixels[102, 67];
    4079     hw := MapWidth div (xxt * 2);
    4080     with Mini.Canvas do
    4081     begin
    4082       Brush.Color := $000000;
    4083       FillRect(Rect(0, 0, Mini.width, Mini.height));
    4084     end;
    4085     MiniLine := nil;
    4086     Mini.BeginUpdate;
    4087     for y := 0 to G.ly - 1 do
    4088     begin
    4089       PrevMiniLine := MiniLine;
    4090       MiniLine := Mini.ScanLine[y];
    4091       for x := 0 to G.lx - 1 do
    4092         if MyMap[x + G.lx * y] and fTerrain <> fUNKNOWN then
     4083  MiniLine := nil;
     4084  Mini.BeginUpdate;
     4085  for y := 0 to G.ly - 1 do
     4086  begin
     4087    PrevMiniLine := MiniLine;
     4088    MiniLine := Mini.ScanLine[y];
     4089    for x := 0 to G.lx - 1 do
     4090      if MyMap[x + G.lx * y] and fTerrain <> fUNKNOWN then
     4091      begin
     4092        Loc := x + G.lx * y;
     4093        for i := 0 to 1 do
    40934094        begin
    4094           Loc := x + G.lx * y;
    4095           for i := 0 to 1 do
     4095          xm := ((x - xwMini) * 2 + i + y and 1 - hw + G.lx * 5) mod (G.lx * 2);
     4096          cm := MiniColors[MyMap[Loc] and fTerrain, i];
     4097          if ClientMode = cEditMap then
    40964098          begin
    4097             xm := ((x - xwMini) * 2 + i + y and 1 - hw + G.lx * 5)
    4098               mod (G.lx * 2);
    4099             cm := MiniColors[MyMap[Loc] and fTerrain, i];
    4100             if ClientMode = cEditMap then
     4099            if MyMap[Loc] and (fPrefStartPos or fStartPos) <> 0 then
     4100              cm := $FFFFFF;
     4101          end
     4102          else if MyMap[Loc] and fCity <> 0 then
     4103          begin
     4104            cix := MyRO.nCity - 1;
     4105            while (cix >= 0) and (MyCity[cix].Loc <> Loc) do
     4106              dec(cix);
     4107            if cix >= 0 then
     4108              cm := Tribe[me].Color
     4109            else
    41014110            begin
    4102               if MyMap[Loc] and (fPrefStartPos or fStartPos) <> 0 then
    4103                 cm := $FFFFFF;
    4104             end
    4105             else if MyMap[Loc] and fCity <> 0 then
    4106             begin
    4107               cix := MyRO.nCity - 1;
    4108               while (cix >= 0) and (MyCity[cix].Loc <> Loc) do
     4111              cix := MyRO.nEnemyCity - 1;
     4112              while (cix >= 0) and (MyRO.EnemyCity[cix].Loc <> Loc) do
    41094113                dec(cix);
    41104114              if cix >= 0 then
    4111                 cm := Tribe[me].Color
    4112               else
    4113               begin
    4114                 cix := MyRO.nEnemyCity - 1;
    4115                 while (cix >= 0) and (MyRO.EnemyCity[cix].Loc <> Loc) do
    4116                   dec(cix);
    4117                 if cix >= 0 then
    4118                   cm := Tribe[MyRO.EnemyCity[cix].Owner].Color
    4119               end;
    4120               cm := $808080 or cm shr 1; { increase brightness }
    4121               if PrevMiniLine <> nil then
    4122               begin // 2x2 city dot covers two scanlines
    4123                 PrevMiniLine[xm, 0] := cm shr 16;
    4124                 PrevMiniLine[xm, 1] := cm shr 8 and $FF;
    4125                 PrevMiniLine[xm, 2] := cm and $FF;
    4126               end
     4115                cm := Tribe[MyRO.EnemyCity[cix].Owner].Color
     4116            end;
     4117            cm := $808080 or cm shr 1; { increase brightness }
     4118            if PrevMiniLine <> nil then
     4119            begin // 2x2 city dot covers two scanlines
     4120              PrevMiniLine[xm, 0] := cm shr 16;
     4121              PrevMiniLine[xm, 1] := cm shr 8 and $FF;
     4122              PrevMiniLine[xm, 2] := cm and $FF;
    41274123            end
    4128             else if (i = 0) and (MyMap[Loc] and fUnit <> 0) then
     4124          end
     4125          else if (i = 0) and (MyMap[Loc] and fUnit <> 0) then
     4126          begin
     4127            uix := MyRO.nUn - 1;
     4128            while (uix >= 0) and (MyUn[uix].Loc <> Loc) do
     4129              dec(uix);
     4130            if uix >= 0 then
     4131              cm := Tribe[me].Color
     4132            else
    41294133            begin
    4130               uix := MyRO.nUn - 1;
    4131               while (uix >= 0) and (MyUn[uix].Loc <> Loc) do
     4134              uix := MyRO.nEnemyUn - 1;
     4135              while (uix >= 0) and (MyRO.EnemyUn[uix].Loc <> Loc) do
    41324136                dec(uix);
    41334137              if uix >= 0 then
    4134                 cm := Tribe[me].Color
    4135               else
    4136               begin
    4137                 uix := MyRO.nEnemyUn - 1;
    4138                 while (uix >= 0) and (MyRO.EnemyUn[uix].Loc <> Loc) do
    4139                   dec(uix);
    4140                 if uix >= 0 then
    4141                   cm := Tribe[MyRO.EnemyUn[uix].Owner].Color
    4142               end;
    4143               cm := $808080 or cm shr 1; { increase brightness }
    4144             end
    4145             else if MapOptionChecked and (1 shl moPolitical) <> 0 then
    4146             begin
    4147               if MyMap[Loc] and fTerrain < fGrass then
    4148                 cm := cmPolOcean
    4149               else if MyRO.Territory[Loc] < 0 then
    4150                 cm := cmPolNone
    4151               else
    4152                 cm := Tribe[MyRO.Territory[Loc]].Color;
     4138                cm := Tribe[MyRO.EnemyUn[uix].Owner].Color
    41534139            end;
    4154             MiniLine[xm, 0] := cm shr 16;
    4155             MiniLine[xm, 1] := cm shr 8 and $FF;
    4156             MiniLine[xm, 2] := cm and $FF;
     4140            cm := $808080 or cm shr 1; { increase brightness }
     4141          end
     4142          else if MapOptionChecked and (1 shl moPolitical) <> 0 then
     4143          begin
     4144            if MyMap[Loc] and fTerrain < fGrass then
     4145              cm := cmPolOcean
     4146            else if MyRO.Territory[Loc] < 0 then
     4147              cm := cmPolNone
     4148            else
     4149              cm := Tribe[MyRO.Territory[Loc]].Color;
    41574150          end;
     4151          MiniLine[xm, 0] := cm shr 16;
     4152          MiniLine[xm, 1] := cm shr 8 and $FF;
     4153          MiniLine[xm, 2] := cm and $FF;
    41584154        end;
     4155      end;
     4156  end;
     4157  Mini.EndUpdate;
     4158end;
     4159
     4160procedure TMainScreen.MainOffscreenPaint;
     4161var
     4162  ProcessOptions: integer;
     4163  rec: TRect;
     4164  DoInvalidate: boolean;
     4165begin
     4166  if me < 0 then
     4167    with offscreen.Canvas do
     4168    begin
     4169      Brush.Color := $000000;
     4170      FillRect(Rect(0, 0, MapWidth, MapHeight));
     4171      Brush.Style := bsClear;
     4172      OffscreenUser := self;
     4173      exit
    41594174    end;
    4160     Mini.EndUpdate;
     4175
     4176  MainMap.SetPaintBounds(0, 0, MapWidth, MapHeight);
     4177  if OffscreenUser <> self then
     4178  begin
     4179    if OffscreenUser <> nil then
     4180      OffscreenUser.Update;
     4181    // complete working with old owner to prevent rebound
     4182    if MapValid and (xwd = xw) and (ywd = yw) then
     4183      MainMap.SetPaintBounds(0, 0, UsedOffscreenWidth, UsedOffscreenHeight);
     4184    MapValid := false;
     4185    OffscreenUser := self;
    41614186  end;
    41624187
    4163   procedure TMainScreen.MainOffscreenPaint;
    4164   var
    4165     ProcessOptions: integer;
    4166     rec: TRect;
    4167     DoInvalidate: boolean;
    4168   begin
    4169     if me < 0 then
    4170       with offscreen.Canvas do
    4171       begin
    4172         Brush.Color := $000000;
    4173         FillRect(Rect(0, 0, MapWidth, MapHeight));
    4174         Brush.Style := bsClear;
    4175         OffscreenUser := self;
    4176         exit
    4177       end;
    4178 
    4179     MainMap.SetPaintBounds(0, 0, MapWidth, MapHeight);
    4180     if OffscreenUser <> self then
    4181     begin
    4182       if OffscreenUser <> nil then
    4183         OffscreenUser.Update;
    4184       // complete working with old owner to prevent rebound
    4185       if MapValid and (xwd = xw) and (ywd = yw) then
    4186         MainMap.SetPaintBounds(0, 0, UsedOffscreenWidth, UsedOffscreenHeight);
    4187       MapValid := false;
    4188       OffscreenUser := self;
    4189     end;
    4190 
    4191     if xw - xwd > G.lx div 2 then
    4192       xwd := xwd + G.lx
    4193     else if xwd - xw > G.lx div 2 then
    4194       xwd := xwd - G.lx;
    4195     if not MapValid or (xw - xwd > MapWidth div (xxt * 2)) or
    4196       (xwd - xw > MapWidth div (xxt * 2)) or (yw - ywd > MapHeight div yyt) or
    4197       (ywd - yw > MapHeight div yyt) then
    4198     begin
    4199       offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
    4200       ProcessRect(xw, yw, MapWidth div xxt, MapHeight div yyt,
    4201         prPaint or prInvalidate)
    4202     end
    4203     else
    4204     begin
    4205       if (xwd = xw) and (ywd = yw) then
    4206         exit; { map window not moved }
    4207       offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
    4208       rec := Rect(0, 0, MapWidth, MapHeight);
    4209       {$IFDEF WINDOWS}{TODO Linux}
    4210       ScrollDC(offscreen.Canvas.Handle, (xwd - xw) * (xxt * 2),
    4211         (ywd - yw) * yyt, rec, rec, 0, nil);
    4212       {$ENDIF}
    4213       for DoInvalidate := false to FastScrolling do
    4214       begin
    4215         if DoInvalidate then
    4216         begin
    4217           rec.Bottom := MapHeight - overlap;
    4218           {$IFDEF WINDOWS}{TODO Linux}
    4219           ScrollDC(Canvas.Handle, (xwd - xw) * (xxt * 2), (ywd - yw) * yyt, rec,
    4220             rec, 0, nil);
    4221           {$ENDIF}
    4222           ProcessOptions := prInvalidate;
    4223         end
    4224         else
    4225           ProcessOptions := prPaint or prAutoBounds;
    4226         if yw < ywd then
    4227         begin
    4228           ProcessRect(xw, yw, MapWidth div xxt, ywd - yw - 1, ProcessOptions);
    4229           if xw < xwd then
    4230             ProcessRect(xw, ywd, (xwd - xw) * 2 - 1, MapHeight div yyt - ywd +
    4231               yw, ProcessOptions)
    4232           else if xw > xwd then
    4233             ProcessRect((xwd + MapWidth div (xxt * 2)) mod G.lx, ywd,
    4234               (xw - xwd) * 2 + 1, MapHeight div yyt - ywd + yw, ProcessOptions)
    4235         end
    4236         else if yw > ywd then
    4237         begin
    4238           if DoInvalidate then
    4239             RectInvalidate(MapOffset, TopBarHeight + MapHeight - overlap -
    4240               (yw - ywd) * yyt, MapOffset + MapWidth, TopBarHeight + MapHeight
    4241               - overlap)
    4242           else
    4243             ProcessRect(xw, (ywd + MapHeight div (yyt * 2) * 2),
    4244               MapWidth div xxt, yw - ywd + 1, ProcessOptions);
    4245           if xw < xwd then
    4246             ProcessRect(xw, yw, (xwd - xw) * 2 - 1, MapHeight div yyt - yw + ywd
    4247               - 2, ProcessOptions)
    4248           else if xw > xwd then
    4249             ProcessRect((xwd + MapWidth div (xxt * 2)) mod G.lx, yw,
    4250               (xw - xwd) * 2 + 1, MapHeight div yyt - yw + ywd - 2,
    4251               ProcessOptions)
    4252         end
    4253         else if xw < xwd then
    4254           ProcessRect(xw, yw, (xwd - xw) * 2 - 1, MapHeight div yyt,
     4188  if xw - xwd > G.lx div 2 then
     4189    xwd := xwd + G.lx
     4190  else if xwd - xw > G.lx div 2 then
     4191    xwd := xwd - G.lx;
     4192  if not MapValid or (xw - xwd > MapWidth div (xxt * 2)) or
     4193    (xwd - xw > MapWidth div (xxt * 2)) or (yw - ywd > MapHeight div yyt) or
     4194    (ywd - yw > MapHeight div yyt) then
     4195  begin
     4196    offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
     4197    ProcessRect(xw, yw, MapWidth div xxt, MapHeight div yyt,
     4198      prPaint or prInvalidate)
     4199  end
     4200  else
     4201  begin
     4202    if (xwd = xw) and (ywd = yw) then
     4203      exit; { map window not moved }
     4204    offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
     4205    rec := Rect(0, 0, MapWidth, MapHeight);
     4206{$IFDEF WINDOWS}{ TODO Linux }
     4207    ScrollDC(offscreen.Canvas.Handle, (xwd - xw) * (xxt * 2), (ywd - yw) * yyt,
     4208      rec, rec, 0, nil);
     4209{$ENDIF}
     4210    for DoInvalidate := false to FastScrolling do
     4211    begin
     4212      if DoInvalidate then
     4213      begin
     4214        rec.Bottom := MapHeight - overlap;
     4215{$IFDEF WINDOWS}{ TODO Linux }
     4216        ScrollDC(Canvas.Handle, (xwd - xw) * (xxt * 2), (ywd - yw) * yyt, rec,
     4217          rec, 0, nil);
     4218{$ENDIF}
     4219        ProcessOptions := prInvalidate;
     4220      end
     4221      else
     4222        ProcessOptions := prPaint or prAutoBounds;
     4223      if yw < ywd then
     4224      begin
     4225        ProcessRect(xw, yw, MapWidth div xxt, ywd - yw - 1, ProcessOptions);
     4226        if xw < xwd then
     4227          ProcessRect(xw, ywd, (xwd - xw) * 2 - 1, MapHeight div yyt - ywd + yw,
    42554228            ProcessOptions)
    42564229        else if xw > xwd then
     4230          ProcessRect((xwd + MapWidth div (xxt * 2)) mod G.lx, ywd,
     4231            (xw - xwd) * 2 + 1, MapHeight div yyt - ywd + yw, ProcessOptions)
     4232      end
     4233      else if yw > ywd then
     4234      begin
     4235        if DoInvalidate then
     4236          RectInvalidate(MapOffset, TopBarHeight + MapHeight - overlap -
     4237            (yw - ywd) * yyt, MapOffset + MapWidth, TopBarHeight + MapHeight
     4238            - overlap)
     4239        else
     4240          ProcessRect(xw, (ywd + MapHeight div (yyt * 2) * 2), MapWidth div xxt,
     4241            yw - ywd + 1, ProcessOptions);
     4242        if xw < xwd then
     4243          ProcessRect(xw, yw, (xwd - xw) * 2 - 1, MapHeight div yyt - yw + ywd -
     4244            2, ProcessOptions)
     4245        else if xw > xwd then
    42574246          ProcessRect((xwd + MapWidth div (xxt * 2)) mod G.lx, yw,
    4258             (xw - xwd) * 2 + 1, MapHeight div yyt, ProcessOptions);
    4259       end;
    4260       if not FastScrolling then
    4261         RectInvalidate(MapOffset, TopBarHeight, MapOffset + MapWidth,
    4262           TopBarHeight + MapHeight - overlap);
    4263       RectInvalidate(xMidPanel, TopBarHeight + MapHeight - overlap, xRightPanel,
    4264         TopBarHeight + MapHeight)
     4247            (xw - xwd) * 2 + 1, MapHeight div yyt - yw + ywd - 2,
     4248            ProcessOptions)
     4249      end
     4250      else if xw < xwd then
     4251        ProcessRect(xw, yw, (xwd - xw) * 2 - 1, MapHeight div yyt,
     4252          ProcessOptions)
     4253      else if xw > xwd then
     4254        ProcessRect((xwd + MapWidth div (xxt * 2)) mod G.lx, yw,
     4255          (xw - xwd) * 2 + 1, MapHeight div yyt, ProcessOptions);
    42654256    end;
    4266     // if (xwd<>xw) or (ywd<>yw) then
    4267     // Server(sChangeSuperView,me,yw*G.lx+xw,nil^); // for synchronizing client side viewer, not used currently
    4268     xwd := xw;
    4269     ywd := yw;
    4270     MapValid := true;
     4257    if not FastScrolling then
     4258      RectInvalidate(MapOffset, TopBarHeight, MapOffset + MapWidth,
     4259        TopBarHeight + MapHeight - overlap);
     4260    RectInvalidate(xMidPanel, TopBarHeight + MapHeight - overlap, xRightPanel,
     4261      TopBarHeight + MapHeight)
    42714262  end;
    4272 
    4273   procedure TMainScreen.PaintAll;
    4274   begin
    4275     MainOffscreenPaint;
    4276     xwMini := xw;
    4277     ywMini := yw;
    4278     MiniPaint;
    4279     PanelPaint;
     4263  // if (xwd<>xw) or (ywd<>yw) then
     4264  // Server(sChangeSuperView,me,yw*G.lx+xw,nil^); // for synchronizing client side viewer, not used currently
     4265  xwd := xw;
     4266  ywd := yw;
     4267  MapValid := true;
     4268end;
     4269
     4270procedure TMainScreen.PaintAll;
     4271begin
     4272  MainOffscreenPaint;
     4273  xwMini := xw;
     4274  ywMini := yw;
     4275  MiniPaint;
     4276  PanelPaint;
     4277end;
     4278
     4279procedure TMainScreen.PaintAllMaps;
     4280begin
     4281  MainOffscreenPaint;
     4282  xwMini := xw;
     4283  ywMini := yw;
     4284  MiniPaint;
     4285  CopyMiniToPanel;
     4286  RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini + 2,
     4287    xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini +
     4288    2 + G.ly);
     4289end;
     4290
     4291procedure TMainScreen.CopyMiniToPanel;
     4292begin
     4293  BitBlt(Panel.Canvas.Handle, xMini + 2, yMini + 2, G.lx * 2, G.ly,
     4294    Mini.Canvas.Handle, 0, 0, SRCCOPY);
     4295  if MarkCityLoc >= 0 then
     4296    Sprite(Panel, HGrSystem, xMini - 2 + (4 * G.lx + 2 * (MarkCityLoc mod G.lx)
     4297      + (G.lx - MapWidth div (xxt * 2)) - 2 * xwd) mod (2 * G.lx) +
     4298      MarkCityLoc div G.lx and 1, yMini - 3 + MarkCityLoc div G.lx, 10,
     4299      10, 77, 47)
     4300  else if ywmax <= 0 then
     4301    Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (xxt * 2), yMini + 2,
     4302      xMini + 1 + G.lx + MapWidth div (xxt * 2), yMini + 2 + G.ly - 1,
     4303      MainTexture.clMark, MainTexture.clMark)
     4304  else
     4305    Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (xxt * 2),
     4306      yMini + 2 + yw, xMini + 1 + G.lx + MapWidth div (xxt * 2),
     4307      yMini + yw + MapHeight div yyt, MainTexture.clMark, MainTexture.clMark);
     4308end;
     4309
     4310procedure TMainScreen.PanelPaint;
     4311
     4312  function MovementToString(var Un: TUn): string;
     4313  begin
     4314    result := ScreenTools.MovementToString(Un.Movement);
     4315    if Un.Master >= 0 then
     4316      result := '(' + result + ')'
     4317    else if (MyModel[Un.mix].Domain = dAir) and
     4318      (MyModel[Un.mix].Kind <> mkSpecial_Glider) then
     4319      result := Format('%s(%d)', [result, Un.Fuel]);
    42804320  end;
    42814321
    4282   procedure TMainScreen.PaintAllMaps;
    4283   begin
    4284     MainOffscreenPaint;
    4285     xwMini := xw;
    4286     ywMini := yw;
    4287     MiniPaint;
     4322var
     4323  i, uix, uixDefender, x, xSrc, ySrc, xSrcBase, ySrcBase, CostFactor, Count,
     4324    mixShow, xTreasurySection, xResearchSection, JobFocus, TrueMoney,
     4325    TrueResearch: integer;
     4326  Tile: Cardinal;
     4327  s: string;
     4328  unx: TUn;
     4329  UnitInfo: TUnitInfo;
     4330  JobProgressData: TJobProgressData;
     4331  Prio: boolean;
     4332begin
     4333  with Panel.Canvas do
     4334  begin
     4335    Fill(Panel.Canvas, 0, 3, xMidPanel + 7 - 10, PanelHeight - 3,
     4336      wMainTexture - (xMidPanel + 7 - 10), hMainTexture - PanelHeight);
     4337    Fill(Panel.Canvas, xRightPanel + 10 - 7, 3, Panel.width - xRightPanel - 10 +
     4338      7, PanelHeight - 3, -(xRightPanel + 10 - 7), hMainTexture - PanelHeight);
     4339    FillLarge(Panel.Canvas, xMidPanel - 2, PanelHeight - MidPanelHeight,
     4340      xRightPanel + 2, PanelHeight, ClientWidth div 2);
     4341
     4342    Brush.Style := bsClear;
     4343    Pen.Color := $000000;
     4344    MoveTo(0, 0);
     4345    LineTo(xMidPanel + 7 - 8, 0);
     4346    LineTo(xMidPanel + 7 - 8, PanelHeight - MidPanelHeight);
     4347    LineTo(xRightPanel, PanelHeight - MidPanelHeight);
     4348    LineTo(xRightPanel, 0);
     4349    LineTo(ClientWidth, 0);
     4350    Pen.Color := MainTexture.clBevelLight;
     4351    MoveTo(xMidPanel + 7 - 9, PanelHeight - MidPanelHeight + 2);
     4352    LineTo(xRightPanel + 10 - 8, PanelHeight - MidPanelHeight + 2);
     4353    Pen.Color := MainTexture.clBevelLight;
     4354    MoveTo(0, 1);
     4355    LineTo(xMidPanel + 7 - 9, 1);
     4356    Pen.Color := MainTexture.clBevelShade;
     4357    LineTo(xMidPanel + 7 - 9, PanelHeight - MidPanelHeight + 1);
     4358    Pen.Color := MainTexture.clBevelLight;
     4359    LineTo(xRightPanel + 10 - 9, PanelHeight - MidPanelHeight + 1);
     4360    Pen.Color := MainTexture.clBevelLight;
     4361    LineTo(xRightPanel + 10 - 9, 1);
     4362    LineTo(ClientWidth, 1);
     4363    MoveTo(ClientWidth, 2);
     4364    LineTo(xRightPanel + 10 - 8, 2);
     4365    LineTo(xRightPanel + 10 - 8, PanelHeight);
     4366    MoveTo(0, 2);
     4367    LineTo(xMidPanel + 7 - 10, 2);
     4368    Pen.Color := MainTexture.clBevelShade;
     4369    LineTo(xMidPanel + 7 - 10, PanelHeight);
     4370    Corner(Panel.Canvas, xMidPanel + 7 - 16, 1, 1, MainTexture);
     4371    Corner(Panel.Canvas, xRightPanel + 10 - 9, 1, 0, MainTexture);
     4372    if ClientMode <> cEditMap then
     4373    begin
     4374      if supervising then
     4375      begin
     4376        ScreenTools.Frame(Panel.Canvas, ClientWidth - xPalace - 1, yPalace - 1,
     4377          ClientWidth - xPalace + xSizeBig, yPalace + ySizeBig,
     4378          $B0B0B0, $FFFFFF);
     4379        RFrame(Panel.Canvas, ClientWidth - xPalace - 2, yPalace - 2,
     4380          ClientWidth - xPalace + xSizeBig + 1, yPalace + ySizeBig + 1,
     4381          $FFFFFF, $B0B0B0);
     4382        BitBlt(Panel.Canvas.Handle, ClientWidth - xPalace, yPalace, xSizeBig,
     4383          ySizeBig, GrExt[HGrSystem2].Data.Canvas.Handle, 70, 123, SRCCOPY);
     4384      end
     4385      else if MyRO.NatBuilt[imPalace] > 0 then
     4386        ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, imPalace, -1,
     4387          GameMode <> cMovie
     4388          { (GameMode<>cMovie) and (MyRO.Government<>gAnarchy) } )
     4389      else
     4390        ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, 21, -1,
     4391          GameMode <> cMovie
     4392          { (GameMode<>cMovie) and (MyRO.Government<>gAnarchy) } );
     4393    end;
     4394
     4395    if GameMode = cMovie then
     4396      ScreenTools.Frame(Panel.Canvas, xMini + 1, yMini + 1,
     4397        xMini + 2 + G.lx * 2, yMini + 2 + G.ly, $000000, $000000)
     4398    else
     4399    begin
     4400      ScreenTools.Frame(Panel.Canvas, xMini + 1, yMini + 1,
     4401        xMini + 2 + G.lx * 2, yMini + 2 + G.ly, $B0B0B0, $FFFFFF);
     4402      RFrame(Panel.Canvas, xMini, yMini, xMini + 3 + G.lx * 2, yMini + 3 + G.ly,
     4403        $FFFFFF, $B0B0B0);
     4404    end;
    42884405    CopyMiniToPanel;
    4289     RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini + 2,
    4290       xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini +
    4291       2 + G.ly);
    4292   end;
    4293 
    4294   procedure TMainScreen.CopyMiniToPanel;
    4295   begin
    4296     BitBlt(Panel.Canvas.Handle, xMini + 2, yMini + 2, G.lx * 2, G.ly,
    4297       Mini.Canvas.Handle, 0, 0, SRCCOPY);
    4298     if MarkCityLoc >= 0 then
    4299       Sprite(Panel, HGrSystem,
    4300         xMini - 2 + (4 * G.lx + 2 * (MarkCityLoc mod G.lx) +
    4301         (G.lx - MapWidth div (xxt * 2)) - 2 * xwd) mod (2 * G.lx) +
    4302         MarkCityLoc div G.lx and 1, yMini - 3 + MarkCityLoc div G.lx, 10,
    4303         10, 77, 47)
    4304     else if ywmax <= 0 then
    4305       Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (xxt * 2), yMini + 2,
    4306         xMini + 1 + G.lx + MapWidth div (xxt * 2), yMini + 2 + G.ly - 1,
    4307         MainTexture.clMark, MainTexture.clMark)
    4308     else
    4309       Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (xxt * 2),
    4310         yMini + 2 + yw, xMini + 1 + G.lx + MapWidth div (xxt * 2),
    4311         yMini + yw + MapHeight div yyt, MainTexture.clMark, MainTexture.clMark);
    4312   end;
    4313 
    4314   procedure TMainScreen.PanelPaint;
    4315 
    4316     function MovementToString(var Un: TUn): string;
    4317     begin
    4318       result := ScreenTools.MovementToString(Un.Movement);
    4319       if Un.Master >= 0 then
    4320         result := '(' + result + ')'
    4321       else if (MyModel[Un.mix].Domain = dAir) and
    4322         (MyModel[Un.mix].Kind <> mkSpecial_Glider) then
    4323         result := Format('%s(%d)', [result, Un.Fuel]);
    4324     end;
    4325 
    4326   var
    4327     i, uix, uixDefender, x, xSrc, ySrc, xSrcBase, ySrcBase, CostFactor, Count,
    4328       mixShow, xTreasurySection, xResearchSection, JobFocus, TrueMoney,
    4329       TrueResearch: integer;
    4330     Tile: Cardinal;
    4331     s: string;
    4332     unx: TUn;
    4333     UnitInfo: TUnitInfo;
    4334     JobProgressData: TJobProgressData;
    4335     Prio: boolean;
    4336   begin
    4337     with Panel.Canvas do
    4338     begin
    4339       Fill(Panel.Canvas, 0, 3, xMidPanel + 7 - 10, PanelHeight - 3,
    4340         wMainTexture - (xMidPanel + 7 - 10), hMainTexture - PanelHeight);
    4341       Fill(Panel.Canvas, xRightPanel + 10 - 7, 3, Panel.width - xRightPanel - 10
    4342         + 7, PanelHeight - 3, -(xRightPanel + 10 - 7),
    4343         hMainTexture - PanelHeight);
    4344       FillLarge(Panel.Canvas, xMidPanel - 2, PanelHeight - MidPanelHeight,
    4345         xRightPanel + 2, PanelHeight, ClientWidth div 2);
    4346 
     4406    if ClientMode <> cEditMap then // MapBtn icons
     4407      for i := 0 to 5 do
     4408        if i <> 3 then
     4409          Dump(Panel, HGrSystem, xMini + G.lx - 42 + 16 * i, PanelHeight - 26,
     4410            8, 8, 121 + i * 9, 61);
     4411
     4412    if ClientMode = cEditMap then
     4413    begin
     4414      for i := 0 to TrRow - 1 do
     4415        trix[i] := -1;
     4416      Count := 0;
     4417      for i := 0 to nBrushTypes - 1 do
     4418      begin // display terrain types
     4419        if (Count >= TrRow * sb.si.npos) and (Count < TrRow * (sb.si.npos + 1))
     4420        then
     4421        begin
     4422          trix[Count - TrRow * sb.si.npos] := BrushTypes[i];
     4423          x := (Count - TrRow * sb.si.npos) * TrPitch;
     4424          xSrcBase := -1;
     4425          case BrushTypes[i] of
     4426            0 .. 8:
     4427              begin
     4428                xSrc := BrushTypes[i];
     4429                ySrc := 0
     4430              end;
     4431            9 .. 30:
     4432              begin
     4433                xSrcBase := 2;
     4434                ySrcBase := 2;
     4435                xSrc := 0;
     4436                ySrc := 2 * integer(BrushTypes[i]) - 15
     4437              end;
     4438            fRiver:
     4439              begin
     4440                xSrc := 7;
     4441                ySrc := 14
     4442              end;
     4443            fRoad:
     4444              begin
     4445                xSrc := 0;
     4446                ySrc := 9
     4447              end;
     4448            fRR:
     4449              begin
     4450                xSrc := 0;
     4451                ySrc := 10
     4452              end;
     4453            fCanal:
     4454              begin
     4455                xSrc := 0;
     4456                ySrc := 11
     4457              end;
     4458            fPoll:
     4459              begin
     4460                xSrc := 6;
     4461                ySrc := 12
     4462              end;
     4463            fDeadLands, fDeadLands or fCobalt, fDeadLands or fUranium,
     4464              fDeadLands or fMercury:
     4465              begin
     4466                xSrcBase := 6;
     4467                ySrcBase := 2;
     4468                xSrc := 8;
     4469                ySrc := 12 + BrushTypes[i] shr 25;
     4470              end;
     4471            tiIrrigation, tiFarm, tiMine, tiBase:
     4472              begin
     4473                xSrc := BrushTypes[i] shr 12 - 1;
     4474                ySrc := 12
     4475              end;
     4476            tiFort:
     4477              begin
     4478                xSrc := 3;
     4479                ySrc := 12;
     4480                xSrcBase := 7;
     4481                ySrcBase := 12
     4482              end;
     4483            fPrefStartPos:
     4484              begin
     4485                xSrc := 0;
     4486                ySrc := 1
     4487              end;
     4488            fStartPos:
     4489              begin
     4490                xSrc := 0;
     4491                ySrc := 2
     4492              end;
     4493          end;
     4494          if xSrcBase >= 0 then
     4495            Sprite(Panel, HGrTerrain, xTroop + 2 + x, yTroop + 9 - yyt, xxt * 2,
     4496              yyt * 3, 1 + xSrcBase * (xxt * 2 + 1),
     4497              1 + ySrcBase * (yyt * 3 + 1));
     4498          Sprite(Panel, HGrTerrain, xTroop + 2 + x, yTroop + 9 - yyt, xxt * 2,
     4499            yyt * 3, 1 + xSrc * (xxt * 2 + 1), 1 + ySrc * (yyt * 3 + 1));
     4500          if BrushTypes[i] = BrushType then
     4501          begin
     4502            ScreenTools.Frame(Panel.Canvas, xTroop + 2 + x,
     4503              yTroop + 7 - yyt div 2, xTroop + 2 * xxt + x,
     4504              yTroop + 2 * yyt + 11, $000000, $000000);
     4505            ScreenTools.Frame(Panel.Canvas, xTroop + 1 + x,
     4506              yTroop + 6 - yyt div 2, xTroop + 2 * xxt - 1 + x,
     4507              yTroop + 2 * yyt + 10, MainTexture.clMark, MainTexture.clMark);
     4508          end
     4509        end;
     4510        inc(Count)
     4511      end;
     4512      case BrushType of
     4513        fDesert, fPrairie, fTundra, fArctic, fSwamp, fHills, fMountains:
     4514          s := Phrases.Lookup('TERRAIN', BrushType);
     4515        fShore:
     4516          s := Format(Phrases.Lookup('TWOTERRAINS'),
     4517            [Phrases.Lookup('TERRAIN', fOcean), Phrases.Lookup('TERRAIN',
     4518            fShore)]);
     4519        fGrass:
     4520          s := Format(Phrases.Lookup('TWOTERRAINS'),
     4521            [Phrases.Lookup('TERRAIN', fGrass), Phrases.Lookup('TERRAIN',
     4522            fGrass + 12)]);
     4523        fForest:
     4524          s := Format(Phrases.Lookup('TWOTERRAINS'),
     4525            [Phrases.Lookup('TERRAIN', fForest), Phrases.Lookup('TERRAIN',
     4526            fJungle)]);
     4527        fRiver:
     4528          s := Phrases.Lookup('RIVER');
     4529        fDeadLands, fDeadLands or fCobalt, fDeadLands or fUranium,
     4530          fDeadLands or fMercury:
     4531          s := Phrases.Lookup('TERRAIN', 3 * 12 + BrushType shr 25);
     4532        fPrefStartPos:
     4533          s := Phrases.Lookup('MAP_PREFSTART');
     4534        fStartPos:
     4535          s := Phrases.Lookup('MAP_START');
     4536        fPoll:
     4537          s := Phrases.Lookup('POLL');
     4538      else // terrain improvements
     4539        begin
     4540          case BrushType of
     4541            fRoad:
     4542              i := 1;
     4543            fRR:
     4544              i := 2;
     4545            tiIrrigation:
     4546              i := 4;
     4547            tiFarm:
     4548              i := 5;
     4549            tiMine:
     4550              i := 7;
     4551            fCanal:
     4552              i := 8;
     4553            tiFort:
     4554              i := 10;
     4555            tiBase:
     4556              i := 12;
     4557          end;
     4558          s := Phrases.Lookup('JOBRESULT', i);
     4559        end
     4560      end;
     4561      LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 1,
     4562        PanelHeight - 19, s);
     4563    end
     4564    else if TroopLoc >= 0 then
     4565    begin
    43474566      Brush.Style := bsClear;
    4348       Pen.Color := $000000;
    4349       MoveTo(0, 0);
    4350       LineTo(xMidPanel + 7 - 8, 0);
    4351       LineTo(xMidPanel + 7 - 8, PanelHeight - MidPanelHeight);
    4352       LineTo(xRightPanel, PanelHeight - MidPanelHeight);
    4353       LineTo(xRightPanel, 0);
    4354       LineTo(ClientWidth, 0);
    4355       Pen.Color := MainTexture.clBevelLight;
    4356       MoveTo(xMidPanel + 7 - 9, PanelHeight - MidPanelHeight + 2);
    4357       LineTo(xRightPanel + 10 - 8, PanelHeight - MidPanelHeight + 2);
    4358       Pen.Color := MainTexture.clBevelLight;
    4359       MoveTo(0, 1);
    4360       LineTo(xMidPanel + 7 - 9, 1);
    4361       Pen.Color := MainTexture.clBevelShade;
    4362       LineTo(xMidPanel + 7 - 9, PanelHeight - MidPanelHeight + 1);
    4363       Pen.Color := MainTexture.clBevelLight;
    4364       LineTo(xRightPanel + 10 - 9, PanelHeight - MidPanelHeight + 1);
    4365       Pen.Color := MainTexture.clBevelLight;
    4366       LineTo(xRightPanel + 10 - 9, 1);
    4367       LineTo(ClientWidth, 1);
    4368       MoveTo(ClientWidth, 2);
    4369       LineTo(xRightPanel + 10 - 8, 2);
    4370       LineTo(xRightPanel + 10 - 8, PanelHeight);
    4371       MoveTo(0, 2);
    4372       LineTo(xMidPanel + 7 - 10, 2);
    4373       Pen.Color := MainTexture.clBevelShade;
    4374       LineTo(xMidPanel + 7 - 10, PanelHeight);
    4375       Corner(Panel.Canvas, xMidPanel + 7 - 16, 1, 1, MainTexture);
    4376       Corner(Panel.Canvas, xRightPanel + 10 - 9, 1, 0, MainTexture);
    4377       if ClientMode <> cEditMap then
    4378       begin
    4379         if supervising then
     4567      if UnFocus >= 0 then
     4568        with MyUn[UnFocus], MyModel[mix] do
     4569        begin { display info about selected unit }
     4570          if Job = jCity then
     4571            mixShow := -1 // building site
     4572          else
     4573            mixShow := mix;
     4574          with Tribe[me].ModelPicture[mixShow] do
     4575          begin
     4576            Sprite(Panel, HGr, xMidPanel + 7 + 12, yTroop + 1, 64, 48,
     4577              pix mod 10 * 65 + 1, pix div 10 * 49 + 1);
     4578            if MyUn[UnFocus].Flags and unFortified <> 0 then
     4579              Sprite(Panel, HGrStdUnits, xMidPanel + 7 + 12, yTroop + 1,
     4580                xxu * 2, yyu * 2, 1 + 6 * (xxu * 2 + 1), 1);
     4581          end;
     4582
     4583          MakeBlue(Panel, xMidPanel + 7 + 12 + 10, yTroop - 13, 44, 12);
     4584          s := MovementToString(MyUn[UnFocus]);
     4585          RisedTextOut(Panel.Canvas, xMidPanel + 7 + 12 + 32 -
     4586            BiColorTextWidth(Panel.Canvas, s) div 2, yTroop - 16, s);
     4587
     4588          s := IntToStr(Health) + '%';
     4589          LightGradient(Panel.Canvas, xMidPanel + 7 + 12 + 7, PanelHeight - 22,
     4590            (Health + 1) div 2, (ColorOfHealth(Health) and $FEFEFE shr 2) * 3);
     4591          if Health < 100 then
     4592            LightGradient(Panel.Canvas, xMidPanel + 7 + 12 + 7 + (Health + 1)
     4593              div 2, PanelHeight - 22, 50 - (Health + 1) div 2, $000000);
     4594          RisedTextOut(Panel.Canvas, xMidPanel + 7 + 12 + 32 -
     4595            BiColorTextWidth(Panel.Canvas, s) div 2, PanelHeight - 23, s);
     4596
     4597          FrameImage(Panel.Canvas, GrExt[HGrSystem].Data,
     4598            xMidPanel + 7 + xUnitText, yTroop + 15, 12, 14,
     4599            121 + Exp div ExpCost * 13, 28);
     4600          if Job = jCity then
     4601            s := Tribe[me].ModelName[-1]
     4602          else
     4603            s := Tribe[me].ModelName[mix];
     4604          if Home >= 0 then
     4605          begin
     4606            LoweredTextOut(Panel.Canvas, -1, MainTexture,
     4607              xMidPanel + 7 + xUnitText + 18, yTroop + 5, s);
     4608            LoweredTextOut(Panel.Canvas, -1, MainTexture,
     4609              xMidPanel + 7 + xUnitText + 18, yTroop + 21,
     4610              '(' + CityName(MyCity[Home].ID) + ')');
     4611          end
     4612          else
     4613            LoweredTextOut(Panel.Canvas, -1, MainTexture,
     4614              xMidPanel + 7 + xUnitText + 18, yTroop + 13, s);
     4615        end;
     4616
     4617      if (UnFocus >= 0) and (MyUn[UnFocus].Loc <> TroopLoc) then
     4618      begin // divide panel
     4619        if SmallScreen and not supervising then
     4620          x := xTroop - 8
     4621        else
     4622          x := xTroop - 152;
     4623        Pen.Color := MainTexture.clBevelShade;
     4624        MoveTo(x - 1, PanelHeight - MidPanelHeight + 2);
     4625        LineTo(x - 1, PanelHeight);
     4626        Pen.Color := MainTexture.clBevelLight;
     4627        MoveTo(x, PanelHeight - MidPanelHeight + 2);
     4628        LineTo(x, PanelHeight);
     4629      end;
     4630
     4631      for i := 0 to 23 do
     4632        trix[i] := -1;
     4633      if MyMap[TroopLoc] and fUnit <> 0 then
     4634      begin
     4635        if MyMap[TroopLoc] and fOwned <> 0 then
    43804636        begin
    4381           ScreenTools.Frame(Panel.Canvas, ClientWidth - xPalace - 1, yPalace - 1,
    4382             ClientWidth - xPalace + xSizeBig, yPalace + ySizeBig,
    4383             $B0B0B0, $FFFFFF);
    4384           RFrame(Panel.Canvas, ClientWidth - xPalace - 2, yPalace - 2,
    4385             ClientWidth - xPalace + xSizeBig + 1, yPalace + ySizeBig + 1,
    4386             $FFFFFF, $B0B0B0);
    4387           BitBlt(Panel.Canvas.Handle, ClientWidth - xPalace, yPalace, xSizeBig,
    4388             ySizeBig, GrExt[HGrSystem2].Data.Canvas.Handle, 70, 123, SRCCOPY);
    4389         end
    4390         else if MyRO.NatBuilt[imPalace] > 0 then
    4391           ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, imPalace, -1,
    4392             GameMode <> cMovie
    4393             { (GameMode<>cMovie) and (MyRO.Government<>gAnarchy) } )
    4394         else
    4395           ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, 21, -1,
    4396             GameMode <> cMovie
    4397             { (GameMode<>cMovie) and (MyRO.Government<>gAnarchy) } );
    4398       end;
    4399 
    4400       if GameMode = cMovie then
    4401         ScreenTools.Frame(Panel.Canvas, xMini + 1, yMini + 1, xMini + 2 + G.lx * 2,
    4402           yMini + 2 + G.ly, $000000, $000000)
    4403       else
    4404       begin
    4405         ScreenTools.Frame(Panel.Canvas, xMini + 1, yMini + 1, xMini + 2 + G.lx * 2,
    4406           yMini + 2 + G.ly, $B0B0B0, $FFFFFF);
    4407         RFrame(Panel.Canvas, xMini, yMini, xMini + 3 + G.lx * 2,
    4408           yMini + 3 + G.ly, $FFFFFF, $B0B0B0);
    4409       end;
    4410       CopyMiniToPanel;
    4411       if ClientMode <> cEditMap then // MapBtn icons
    4412         for i := 0 to 5 do
    4413           if i <> 3 then
    4414             Dump(Panel, HGrSystem, xMini + G.lx - 42 + 16 * i, PanelHeight - 26,
    4415               8, 8, 121 + i * 9, 61);
    4416 
    4417       if ClientMode = cEditMap then
    4418       begin
    4419         for i := 0 to TrRow - 1 do
    4420           trix[i] := -1;
    4421         Count := 0;
    4422         for i := 0 to nBrushTypes - 1 do
    4423         begin // display terrain types
    4424           if (Count >= TrRow * sb.si.npos) and (Count < TrRow * (sb.si.npos + 1))
     4637          if (TrCnt > 1) or (UnFocus < 0) or (MyUn[UnFocus].Loc <> TroopLoc)
    44254638          then
    44264639          begin
    4427             trix[Count - TrRow * sb.si.npos] := BrushTypes[i];
    4428             x := (Count - TrRow * sb.si.npos) * TrPitch;
    4429             xSrcBase := -1;
    4430             case BrushTypes[i] of
    4431               0 .. 8:
    4432                 begin
    4433                   xSrc := BrushTypes[i];
    4434                   ySrc := 0
    4435                 end;
    4436               9 .. 30:
    4437                 begin
    4438                   xSrcBase := 2;
    4439                   ySrcBase := 2;
    4440                   xSrc := 0;
    4441                   ySrc := 2 * integer(BrushTypes[i]) - 15
    4442                 end;
    4443               fRiver:
    4444                 begin
    4445                   xSrc := 7;
    4446                   ySrc := 14
    4447                 end;
    4448               fRoad:
    4449                 begin
    4450                   xSrc := 0;
    4451                   ySrc := 9
    4452                 end;
    4453               fRR:
    4454                 begin
    4455                   xSrc := 0;
    4456                   ySrc := 10
    4457                 end;
    4458               fCanal:
    4459                 begin
    4460                   xSrc := 0;
    4461                   ySrc := 11
    4462                 end;
    4463               fPoll:
    4464                 begin
    4465                   xSrc := 6;
    4466                   ySrc := 12
    4467                 end;
    4468               fDeadLands, fDeadLands or fCobalt, fDeadLands or fUranium,
    4469                 fDeadLands or fMercury:
    4470                 begin
    4471                   xSrcBase := 6;
    4472                   ySrcBase := 2;
    4473                   xSrc := 8;
    4474                   ySrc := 12 + BrushTypes[i] shr 25;
    4475                 end;
    4476               tiIrrigation, tiFarm, tiMine, tiBase:
    4477                 begin
    4478                   xSrc := BrushTypes[i] shr 12 - 1;
    4479                   ySrc := 12
    4480                 end;
    4481               tiFort:
    4482                 begin
    4483                   xSrc := 3;
    4484                   ySrc := 12;
    4485                   xSrcBase := 7;
    4486                   ySrcBase := 12
    4487                 end;
    4488               fPrefStartPos:
    4489                 begin
    4490                   xSrc := 0;
    4491                   ySrc := 1
    4492                 end;
    4493               fStartPos:
    4494                 begin
    4495                   xSrc := 0;
    4496                   ySrc := 2
    4497                 end;
    4498             end;
    4499             if xSrcBase >= 0 then
    4500               Sprite(Panel, HGrTerrain, xTroop + 2 + x, yTroop + 9 - yyt,
    4501                 xxt * 2, yyt * 3, 1 + xSrcBase * (xxt * 2 + 1),
    4502                 1 + ySrcBase * (yyt * 3 + 1));
    4503             Sprite(Panel, HGrTerrain, xTroop + 2 + x, yTroop + 9 - yyt, xxt * 2,
    4504               yyt * 3, 1 + xSrc * (xxt * 2 + 1), 1 + ySrc * (yyt * 3 + 1));
    4505             if BrushTypes[i] = BrushType then
    4506             begin
    4507               ScreenTools.Frame(Panel.Canvas, xTroop + 2 + x, yTroop + 7 - yyt div 2,
    4508                 xTroop + 2 * xxt + x, yTroop + 2 * yyt + 11, $000000, $000000);
    4509               ScreenTools.Frame(Panel.Canvas, xTroop + 1 + x, yTroop + 6 - yyt div 2,
    4510                 xTroop + 2 * xxt - 1 + x, yTroop + 2 * yyt + 10,
    4511                 MainTexture.clMark, MainTexture.clMark);
    4512             end
    4513           end;
    4514           inc(Count)
    4515         end;
    4516         case BrushType of
    4517           fDesert, fPrairie, fTundra, fArctic, fSwamp, fHills, fMountains:
    4518             s := Phrases.Lookup('TERRAIN', BrushType);
    4519           fShore:
    4520             s := Format(Phrases.Lookup('TWOTERRAINS'),
    4521               [Phrases.Lookup('TERRAIN', fOcean), Phrases.Lookup('TERRAIN',
    4522               fShore)]);
    4523           fGrass:
    4524             s := Format(Phrases.Lookup('TWOTERRAINS'),
    4525               [Phrases.Lookup('TERRAIN', fGrass), Phrases.Lookup('TERRAIN',
    4526               fGrass + 12)]);
    4527           fForest:
    4528             s := Format(Phrases.Lookup('TWOTERRAINS'),
    4529               [Phrases.Lookup('TERRAIN', fForest), Phrases.Lookup('TERRAIN',
    4530               fJungle)]);
    4531           fRiver:
    4532             s := Phrases.Lookup('RIVER');
    4533           fDeadLands, fDeadLands or fCobalt, fDeadLands or fUranium,
    4534             fDeadLands or fMercury:
    4535             s := Phrases.Lookup('TERRAIN', 3 * 12 + BrushType shr 25);
    4536           fPrefStartPos:
    4537             s := Phrases.Lookup('MAP_PREFSTART');
    4538           fStartPos:
    4539             s := Phrases.Lookup('MAP_START');
    4540           fPoll:
    4541             s := Phrases.Lookup('POLL');
    4542         else // terrain improvements
    4543           begin
    4544             case BrushType of
    4545               fRoad:
    4546                 i := 1;
    4547               fRR:
    4548                 i := 2;
    4549               tiIrrigation:
    4550                 i := 4;
    4551               tiFarm:
    4552                 i := 5;
    4553               tiMine:
    4554                 i := 7;
    4555               fCanal:
    4556                 i := 8;
    4557               tiFort:
    4558                 i := 10;
    4559               tiBase:
    4560                 i := 12;
    4561             end;
    4562             s := Phrases.Lookup('JOBRESULT', i);
     4640            LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 10,
     4641              PanelHeight - 24, Phrases.Lookup('PRESENT'));
     4642            Server(sGetDefender, me, TroopLoc, uixDefender);
     4643            Count := 0;
     4644            for Prio := true downto false do
     4645              for uix := 0 to MyRO.nUn - 1 do
     4646                if (uix = uixDefender) = Prio then
     4647                begin // display own units
     4648                  unx := MyUn[uix];
     4649                  if unx.Loc = TroopLoc then
     4650                  begin
     4651                    if (Count >= TrRow * sb.si.npos) and
     4652                      (Count < TrRow * (sb.si.npos + 1)) then
     4653                    begin
     4654                      trix[Count - TrRow * sb.si.npos] := uix;
     4655                      MakeUnitInfo(me, unx, UnitInfo);
     4656                      x := (Count - TrRow * sb.si.npos) * TrPitch;
     4657                      if uix = UnFocus then
     4658                      begin
     4659                        ScreenTools.Frame(Panel.Canvas, xTroop + 4 + x,
     4660                          yTroop + 3, xTroop + 64 + x, yTroop + 47,
     4661                          $000000, $000000);
     4662                        ScreenTools.Frame(Panel.Canvas, xTroop + 3 + x,
     4663                          yTroop + 2, xTroop + 63 + x, yTroop + 46,
     4664                          MainTexture.clMark, MainTexture.clMark);
     4665                      end
     4666                      else if (unx.Master >= 0) and (unx.Master = UnFocus) then
     4667                      begin
     4668                        CFrame(Panel.Canvas, xTroop + 4 + x, yTroop + 3,
     4669                          xTroop + 64 + x, yTroop + 47, 8, $000000);
     4670                        CFrame(Panel.Canvas, xTroop + 3 + x, yTroop + 2,
     4671                          xTroop + 63 + x, yTroop + 46, 8, MainTexture.clMark);
     4672                      end;
     4673                      NoMap.SetOutput(Panel);
     4674                      NoMap.PaintUnit(xTroop + 2 + x, yTroop + 1, UnitInfo,
     4675                        unx.Status);
     4676                      if (ClientMode < scContact) and
     4677                        ((unx.Job > jNone) or
     4678                        (unx.Status and (usStay or usRecover or usGoto) <> 0))
     4679                      then
     4680                        Sprite(Panel, HGrSystem, xTroop + 2 + 60 - 20 + x,
     4681                          yTroop + 35, 20, 20, 81, 25);
     4682
     4683                      if not supervising then
     4684                      begin
     4685                        MakeBlue(Panel, xTroop + 2 + 10 + x,
     4686                          yTroop - 13, 44, 12);
     4687                        s := MovementToString(unx);
     4688                        RisedTextOut(Panel.Canvas,
     4689                          xTroop + x + 34 - BiColorTextWidth(Panel.Canvas, s)
     4690                          div 2, yTroop - 16, s);
     4691                      end
     4692                    end;
     4693                    inc(Count)
     4694                  end;
     4695                end; // for uix:=0 to MyRO.nUn-1
     4696            assert(Count = TrCnt);
    45634697          end
    4564         end;
    4565         LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 1,
    4566           PanelHeight - 19, s);
    4567       end
    4568       else if TroopLoc >= 0 then
    4569       begin
    4570         Brush.Style := bsClear;
    4571         if UnFocus >= 0 then
    4572           with MyUn[UnFocus], MyModel[mix] do
    4573           begin { display info about selected unit }
    4574             if Job = jCity then
    4575               mixShow := -1 // building site
    4576             else
    4577               mixShow := mix;
    4578             with Tribe[me].ModelPicture[mixShow] do
    4579             begin
    4580               Sprite(Panel, HGr, xMidPanel + 7 + 12, yTroop + 1, 64, 48,
    4581                 pix mod 10 * 65 + 1, pix div 10 * 49 + 1);
    4582               if MyUn[UnFocus].Flags and unFortified <> 0 then
    4583                 Sprite(Panel, HGrStdUnits, xMidPanel + 7 + 12, yTroop + 1,
    4584                   xxu * 2, yyu * 2, 1 + 6 * (xxu * 2 + 1), 1);
    4585             end;
    4586 
    4587             MakeBlue(Panel, xMidPanel + 7 + 12 + 10, yTroop - 13, 44, 12);
    4588             s := MovementToString(MyUn[UnFocus]);
    4589             RisedTextOut(Panel.Canvas, xMidPanel + 7 + 12 + 32 -
    4590               BiColorTextWidth(Panel.Canvas, s) div 2, yTroop - 16, s);
    4591 
    4592             s := IntToStr(Health) + '%';
    4593             LightGradient(Panel.Canvas, xMidPanel + 7 + 12 + 7,
    4594               PanelHeight - 22, (Health + 1) div 2,
    4595               (ColorOfHealth(Health) and $FEFEFE shr 2) * 3);
    4596             if Health < 100 then
    4597               LightGradient(Panel.Canvas, xMidPanel + 7 + 12 + 7 + (Health + 1)
    4598                 div 2, PanelHeight - 22, 50 - (Health + 1) div 2, $000000);
    4599             RisedTextOut(Panel.Canvas, xMidPanel + 7 + 12 + 32 -
    4600               BiColorTextWidth(Panel.Canvas, s) div 2, PanelHeight - 23, s);
    4601 
    4602             FrameImage(Panel.Canvas, GrExt[HGrSystem].Data,
    4603               xMidPanel + 7 + xUnitText, yTroop + 15, 12, 14,
    4604               121 + Exp div ExpCost * 13, 28);
    4605             if Job = jCity then
    4606               s := Tribe[me].ModelName[-1]
    4607             else
    4608               s := Tribe[me].ModelName[mix];
    4609             if Home >= 0 then
    4610             begin
    4611               LoweredTextOut(Panel.Canvas, -1, MainTexture,
    4612                 xMidPanel + 7 + xUnitText + 18, yTroop + 5, s);
    4613               LoweredTextOut(Panel.Canvas, -1, MainTexture,
    4614                 xMidPanel + 7 + xUnitText + 18, yTroop + 21,
    4615                 '(' + CityName(MyCity[Home].ID) + ')');
    4616             end
    4617             else
    4618               LoweredTextOut(Panel.Canvas, -1, MainTexture,
    4619                 xMidPanel + 7 + xUnitText + 18, yTroop + 13, s);
    4620           end;
    4621 
    4622         if (UnFocus >= 0) and (MyUn[UnFocus].Loc <> TroopLoc) then
    4623         begin // divide panel
    4624           if SmallScreen and not supervising then
    4625             x := xTroop - 8
    4626           else
    4627             x := xTroop - 152;
    4628           Pen.Color := MainTexture.clBevelShade;
    4629           MoveTo(x - 1, PanelHeight - MidPanelHeight + 2);
    4630           LineTo(x - 1, PanelHeight);
    4631           Pen.Color := MainTexture.clBevelLight;
    4632           MoveTo(x, PanelHeight - MidPanelHeight + 2);
    4633           LineTo(x, PanelHeight);
    4634         end;
    4635 
    4636         for i := 0 to 23 do
    4637           trix[i] := -1;
    4638         if MyMap[TroopLoc] and fUnit <> 0 then
    4639         begin
    4640           if MyMap[TroopLoc] and fOwned <> 0 then
    4641           begin
    4642             if (TrCnt > 1) or (UnFocus < 0) or (MyUn[UnFocus].Loc <> TroopLoc)
    4643             then
    4644             begin
    4645               LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 10,
    4646                 PanelHeight - 24, Phrases.Lookup('PRESENT'));
    4647               Server(sGetDefender, me, TroopLoc, uixDefender);
    4648               Count := 0;
    4649               for Prio := true downto false do
    4650                 for uix := 0 to MyRO.nUn - 1 do
    4651                   if (uix = uixDefender) = Prio then
    4652                   begin // display own units
    4653                     unx := MyUn[uix];
    4654                     if unx.Loc = TroopLoc then
    4655                     begin
    4656                       if (Count >= TrRow * sb.si.npos) and
    4657                         (Count < TrRow * (sb.si.npos + 1)) then
    4658                       begin
    4659                         trix[Count - TrRow * sb.si.npos] := uix;
    4660                         MakeUnitInfo(me, unx, UnitInfo);
    4661                         x := (Count - TrRow * sb.si.npos) * TrPitch;
    4662                         if uix = UnFocus then
    4663                         begin
    4664                           ScreenTools.Frame(Panel.Canvas, xTroop + 4 + x, yTroop + 3,
    4665                             xTroop + 64 + x, yTroop + 47, $000000, $000000);
    4666                           ScreenTools.Frame(Panel.Canvas, xTroop + 3 + x, yTroop + 2,
    4667                             xTroop + 63 + x, yTroop + 46, MainTexture.clMark,
    4668                             MainTexture.clMark);
    4669                         end
    4670                         else if (unx.Master >= 0) and (unx.Master = UnFocus)
    4671                         then
    4672                         begin
    4673                           CFrame(Panel.Canvas, xTroop + 4 + x, yTroop + 3,
    4674                             xTroop + 64 + x, yTroop + 47, 8, $000000);
    4675                           CFrame(Panel.Canvas, xTroop + 3 + x, yTroop + 2,
    4676                             xTroop + 63 + x, yTroop + 46, 8,
    4677                             MainTexture.clMark);
    4678                         end;
    4679                         NoMap.SetOutput(Panel);
    4680                         NoMap.PaintUnit(xTroop + 2 + x, yTroop + 1, UnitInfo,
    4681                           unx.Status);
    4682                         if (ClientMode < scContact) and
    4683                           ((unx.Job > jNone) or
    4684                           (unx.Status and (usStay or usRecover or usGoto) <> 0))
    4685                         then
    4686                           Sprite(Panel, HGrSystem, xTroop + 2 + 60 - 20 + x,
    4687                             yTroop + 35, 20, 20, 81, 25);
    4688 
    4689                         if not supervising then
    4690                         begin
    4691                           MakeBlue(Panel, xTroop + 2 + 10 + x,
    4692                             yTroop - 13, 44, 12);
    4693                           s := MovementToString(unx);
    4694                           RisedTextOut(Panel.Canvas,
    4695                             xTroop + x + 34 - BiColorTextWidth(Panel.Canvas, s)
    4696                             div 2, yTroop - 16, s);
    4697                         end
    4698                       end;
    4699                       inc(Count)
    4700                     end;
    4701                   end; // for uix:=0 to MyRO.nUn-1
    4702               assert(Count = TrCnt);
    4703             end
    4704           end
    4705           else
    4706           begin
    4707             LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 8,
    4708               PanelHeight - 24, Phrases.Lookup('PRESENT'));
    4709             Server(sGetUnits, me, TroopLoc, Count);
    4710             for i := 0 to Count - 1 do
    4711               if (i >= TrRow * sb.si.npos) and (i < TrRow * (sb.si.npos + 1))
    4712               then
    4713               begin // display enemy units
    4714                 trix[i - TrRow * sb.si.npos] := i;
    4715                 x := (i - TrRow * sb.si.npos) * TrPitch;
    4716                 NoMap.SetOutput(Panel);
    4717                 NoMap.PaintUnit(xTroop + 2 + x, yTroop + 1,
    4718                   MyRO.EnemyUn[MyRO.nEnemyUn + i], 0);
    4719               end;
    4720           end;
    4721         end;
    4722         if not SmallScreen or supervising then
    4723         begin // show terrain and improvements
    4724           PaintZoomedTile(Panel, xTerrain - xxt * 2, 110 - yyt * 3, TroopLoc);
    4725           if (UnFocus >= 0) and (MyUn[UnFocus].Job <> jNone) then
    4726           begin
    4727             JobFocus := MyUn[UnFocus].Job;
    4728             Server(sGetJobProgress, me, MyUn[UnFocus].Loc, JobProgressData);
    4729             MakeBlue(Panel, xTerrain - 72, 148 - 17, 144, 31);
    4730             PaintRelativeProgressBar(Panel.Canvas, 3, xTerrain - 68, 148 + 3,
    4731               63, JobProgressData[JobFocus].Done,
    4732               JobProgressData[JobFocus].NextTurnPlus,
    4733               JobProgressData[JobFocus].Required, true, MainTexture);
    4734             s := Format('%s/%s',
    4735               [ScreenTools.MovementToString(JobProgressData[JobFocus].Done),
    4736               ScreenTools.MovementToString(JobProgressData[JobFocus]
    4737               .Required)]);
    4738             RisedTextOut(Panel.Canvas, xTerrain + 6, 148 - 3, s);
    4739             Tile := MyMap[MyUn[UnFocus].Loc];
    4740             if (JobFocus = jRoad) and (Tile and fRiver <> 0) then
    4741               JobFocus := nJob + 0
    4742             else if (JobFocus = jRR) and (Tile and fRiver <> 0) then
    4743               JobFocus := nJob + 1
    4744             else if JobFocus = jClear then
    4745             begin
    4746               if Tile and fTerrain = fForest then
    4747                 JobFocus := nJob + 2
    4748               else if Tile and fTerrain = fDesert then
    4749                 JobFocus := nJob + 3
    4750               else
    4751                 JobFocus := nJob + 4
    4752             end;
    4753             s := Phrases.Lookup('JOBRESULT', JobFocus);
    4754             RisedTextOut(Panel.Canvas, xTerrain - BiColorTextWidth(Panel.Canvas,
    4755               s) div 2, 148 - 19, s);
    4756           end;
    4757           if MyMap[TroopLoc] and (fTerrain or fSpecial) = fGrass or fSpecial1
    4758           then
    4759             s := Phrases.Lookup('TERRAIN', fGrass + 12)
    4760           else if MyMap[TroopLoc] and fDeadLands <> 0 then
    4761             s := Phrases.Lookup('TERRAIN', 3 * 12)
    4762           else if (MyMap[TroopLoc] and fTerrain = fForest) and
    4763             IsJungle(TroopLoc div G.lx) then
    4764             s := Phrases.Lookup('TERRAIN', fJungle)
    4765           else
    4766             s := Phrases.Lookup('TERRAIN', MyMap[TroopLoc] and fTerrain);
    4767           RisedTextOut(Panel.Canvas, xTerrain - BiColorTextWidth(Panel.Canvas,
    4768             s) div 2, 99, s);
    4769         end;
    4770 
    4771         if TerrainBtn.Visible then
    4772           with TerrainBtn do
    4773             RFrame(Panel.Canvas, Left - 1, Top - self.ClientHeight +
    4774               (PanelHeight - 1), Left + width, Top + height - self.ClientHeight
    4775               + PanelHeight, MainTexture.clBevelShade, MainTexture.clBevelLight)
    4776       end { if TroopLoc>=0 }
    4777     end;
    4778 
    4779     for i := 0 to ControlCount - 1 do
    4780       if Controls[i] is TButtonB then
    4781         with TButtonB(Controls[i]) do
    4782         begin
    4783           if Visible then
    4784           begin
    4785             Dump(Panel, HGrSystem, Left, Top - self.ClientHeight + PanelHeight,
    4786               25, 25, 169, 243);
    4787             Sprite(Panel, HGrSystem, Left, Top - self.ClientHeight +
    4788               PanelHeight, 25, 25, 1 + 26 * ButtonIndex, 337);
    4789             RFrame(Panel.Canvas, Left - 1, Top - self.ClientHeight +
    4790               (PanelHeight - 1), Left + width, Top + height - self.ClientHeight
    4791               + PanelHeight, MainTexture.clBevelShade,
    4792               MainTexture.clBevelLight);
    4793           end;
    4794         end;
    4795 
    4796     if ClientMode <> cEditMap then
    4797     begin
    4798       for i := 0 to ControlCount - 1 do
    4799         if Controls[i] is TButtonC then
    4800           with TButtonC(Controls[i]) do
    4801           begin
    4802             Dump(Panel, HGrSystem, Left, Top - self.ClientHeight + PanelHeight,
    4803               12, 12, 169, 178 + 13 * ButtonIndex);
    4804             RFrame(Panel.Canvas, Left - 1, Top - self.ClientHeight +
    4805               (PanelHeight - 1), Left + width, Top + height - self.ClientHeight
    4806               + PanelHeight, MainTexture.clBevelShade,
    4807               MainTexture.clBevelLight);
    4808           end
    4809     end;
    4810     EOT.SetBack(Panel.Canvas, EOT.Left, EOT.Top - (ClientHeight - PanelHeight));
    4811     SmartRectInvalidate(0, ClientHeight - PanelHeight, ClientWidth,
    4812       ClientHeight);
    4813 
    4814     // topbar
    4815     xTreasurySection := ClientWidth div 2 - 172;
    4816     xResearchSection := ClientWidth div 2;
    4817     // ClientWidth div 2+68 = maximum to right
    4818     FillLarge(TopBar.Canvas, 0, 0, ClientWidth, TopBarHeight - 3,
    4819       ClientWidth div 2);
    4820     with TopBar.Canvas do
    4821     begin
    4822       Pen.Color := $000000;
    4823       MoveTo(0, TopBarHeight - 1);
    4824       LineTo(ClientWidth, TopBarHeight - 1);
    4825       Pen.Color := MainTexture.clBevelShade;
    4826       MoveTo(0, TopBarHeight - 2);
    4827       LineTo(ClientWidth, TopBarHeight - 2);
    4828       MoveTo(0, TopBarHeight - 3);
    4829       LineTo(ClientWidth, TopBarHeight - 3);
    4830       Pen.Color := MainTexture.clBevelLight;
    4831       ScreenTools.Frame(TopBar.Canvas, 40, -1, xTreasurySection - 1, TopBarHeight - 7,
    4832         MainTexture.clBevelShade, MainTexture.clBevelLight);
    4833       ScreenTools.Frame(TopBar.Canvas, xResearchSection + 332, -1, ClientWidth,
    4834         TopBarHeight - 7, MainTexture.clBevelShade, MainTexture.clBevelLight);
    4835     end;
    4836     if GameMode <> cMovie then
    4837       ImageOp_BCC(TopBar, Templates, 2, 1, 145, 38, 36, 36, $BFBF20, $4040DF);
    4838     if MyRO.nCity > 0 then
    4839     begin
    4840       TrueMoney := MyRO.Money;
    4841       TrueResearch := MyRO.Research;
    4842       if supervising then
    4843       begin // normalize values from after-turn state
    4844         dec(TrueMoney, TaxSum);
    4845         if TrueMoney < 0 then
    4846           TrueMoney := 0; // shouldn't happen
    4847         dec(TrueResearch, ScienceSum);
    4848         if TrueResearch < 0 then
    4849           TrueResearch := 0; // shouldn't happen
    4850       end;
    4851 
    4852       // treasury section
    4853       ImageOp_BCC(TopBar, Templates, xTreasurySection + 8, 1, 145, 1, 36, 36,
    4854         $40A040, $4030C0);
    4855       s := IntToStr(TrueMoney);
    4856       LoweredTextOut(TopBar.Canvas, -1, MainTexture, xTreasurySection + 48, 0,
    4857         s + '%c');
    4858       if MyRO.Government <> gAnarchy then
    4859       begin
    4860         ImageOp_BCC(TopBar, Templates, xTreasurySection + 48, 22, 124, 1, 14,
    4861           14, $0000C0, $0080C0);
    4862         if TaxSum >= 0 then
    4863           s := Format(Phrases.Lookup('MONEYGAINPOS'), [TaxSum])
    4864         else
    4865           s := Format(Phrases.Lookup('MONEYGAINNEG'), [TaxSum]);
    4866         LoweredTextOut(TopBar.Canvas, -1, MainTexture,
    4867           xTreasurySection + 48 + 15, 18, s);
    4868       end;
    4869 
    4870       // research section
    4871       ImageOp_BCC(TopBar, Templates, xResearchSection + 8, 1, 145, 75, 36, 36,
    4872         $FF0000, $00FFE0);
    4873       if MyData.FarTech <> adNexus then
    4874       begin
    4875         if MyRO.ResearchTech < 0 then
    4876           CostFactor := 2
    4877         else if (MyRO.ResearchTech = adMilitary) or
    4878           (MyRO.Tech[MyRO.ResearchTech] = tsSeen) then
    4879           CostFactor := 1
    4880         else if MyRO.ResearchTech in FutureTech then
    4881           if MyRO.Government = gFuture then
    4882             CostFactor := 4
    4883           else
    4884             CostFactor := 8
    4885         else
    4886           CostFactor := 2;
    4887         Server(sGetTechCost, me, 0, i);
    4888         CostFactor := CostFactor * 22; // length of progress bar
    4889         PaintRelativeProgressBar(TopBar.Canvas, 2, xResearchSection + 48 + 1,
    4890           26, CostFactor, TrueResearch, ScienceSum, i, true, MainTexture);
    4891 
    4892         if MyRO.ResearchTech < 0 then
    4893           s := Phrases.Lookup('SCIENCE')
    4894         else if MyRO.ResearchTech = adMilitary then
    4895           s := Phrases.Lookup('INITUNIT')
    4896         else
    4897         begin
    4898           s := Phrases.Lookup('ADVANCES', MyRO.ResearchTech);
    4899           if MyRO.ResearchTech in FutureTech then
    4900             if MyRO.Tech[MyRO.ResearchTech] >= 1 then
    4901               s := s + ' ' + IntToStr(MyRO.Tech[MyRO.ResearchTech] + 1)
    4902             else
    4903               s := s + ' 1';
    4904         end;
    4905         if ScienceSum > 0 then
    4906         begin
    4907           { j:=(i-MyRO.Research-1) div ScienceSum +1;
    4908             if j<1 then j:=1;
    4909             if j>1 then
    4910             s:=Format(Phrases.Lookup('TECHWAIT'),[s,j]); }
    4911           LoweredTextOut(TopBar.Canvas, -1, MainTexture,
    4912             xResearchSection + 48, 0, s);
    4913         end
    4914         else
    4915           LoweredTextOut(TopBar.Canvas, -1, MainTexture,
    4916             xResearchSection + 48, 0, s);
    4917       end
    4918       else
    4919         CostFactor := 0;
    4920       if (MyData.FarTech <> adNexus) and (ScienceSum > 0) then
    4921       begin
    4922         ImageOp_BCC(TopBar, Templates, xResearchSection + 48 + CostFactor + 11,
    4923           22, 124, 1, 14, 14, $0000C0, $0080C0);
    4924         s := Format(Phrases.Lookup('TECHGAIN'), [ScienceSum]);
    4925         LoweredTextOut(TopBar.Canvas, -1, MainTexture, xResearchSection + 48 +
    4926           CostFactor + 26, 18, s);
    4927       end
    4928     end;
    4929     if ClientMode <> cEditMap then
    4930     begin
    4931       TopBar.Canvas.Font.Assign(UniFont[ftCaption]);
    4932       s := TurnToString(MyRO.Turn);
    4933       RisedTextOut(TopBar.Canvas,
    4934         40 + (xTreasurySection - 40 - BiColorTextWidth(TopBar.Canvas, s))
    4935         div 2, 6, s);
    4936       TopBar.Canvas.Font.Assign(UniFont[ftNormal]);
    4937     end;
    4938     RectInvalidate(0, 0, ClientWidth, TopBarHeight);
    4939   end; { PanelPaint }
    4940 
    4941   procedure TMainScreen.FocusOnLoc(Loc: integer; Options: integer = 0);
    4942   var
    4943     dx: integer;
    4944     Outside, Changed: boolean;
    4945   begin
    4946     dx := G.lx + 1 - (xw - Loc + G.lx * 1024 + 1) mod G.lx;
    4947     Outside := (dx >= (MapWidth + 1) div (xxt * 2) - 2) or (ywmax > 0) and
    4948       ((yw > 0) and (Loc div G.lx <= yw + 1) or (yw < ywmax) and
    4949       (Loc div G.lx >= yw + (MapHeight - 1) div yyt - 2));
    4950     Changed := true;
    4951     if Outside then
    4952     begin
    4953       Centre(Loc);
    4954       PaintAllMaps
    4955     end
    4956     else if not MapValid then
    4957       PaintAllMaps
    4958     else
    4959       Changed := false;
    4960     if Options and flRepaintPanel <> 0 then
    4961       PanelPaint;
    4962     if Changed and (Options and flImmUpdate <> 0) then
    4963       Update;
    4964   end;
    4965 
    4966   procedure TMainScreen.NextUnit(NearLoc: integer; AutoTurn: boolean);
    4967   var
    4968     Dist, TestDist: single;
    4969     i, uix, NewFocus: integer;
    4970     GotoOnly: boolean;
    4971   begin
    4972     if ClientMode >= scContact then
    4973       exit;
    4974     DestinationMarkON := false;
    4975     PaintDestination;
    4976     for GotoOnly := GoOnPhase downto false do
    4977     begin
    4978       NewFocus := -1;
    4979       for i := 1 to MyRO.nUn do
    4980       begin
    4981         uix := (UnFocus + i) mod MyRO.nUn;
    4982         if (MyUn[uix].Loc >= 0) and (MyUn[uix].Job = jNone) and
    4983           (MyUn[uix].Status and (usStay or usRecover or usWaiting) = usWaiting)
    4984           and (not GotoOnly or (MyUn[uix].Status and usGoto <> 0)) then
    4985           if NearLoc < 0 then
    4986           begin
    4987             NewFocus := uix;
    4988             Break
    4989           end
    4990           else
    4991           begin
    4992             TestDist := Distance(NearLoc, MyUn[uix].Loc);
    4993             if (NewFocus < 0) or (TestDist < Dist) then
    4994             begin
    4995               NewFocus := uix;
    4996               Dist := TestDist
    4997             end
    4998           end
    4999       end;
    5000       if GotoOnly then
    5001         if NewFocus < 0 then
    5002           GoOnPhase := false
    5003         else
    5004           Break;
    5005     end;
    5006     if NewFocus >= 0 then
    5007     begin
    5008       SetUnFocus(NewFocus);
    5009       SetTroopLoc(MyUn[NewFocus].Loc);
    5010       FocusOnLoc(TroopLoc, flRepaintPanel)
    5011     end
    5012     else if AutoTurn and not mWaitTurn.Checked then
    5013     begin
    5014       TurnComplete := true;
    5015       SetUnFocus(-1);
    5016       SetTroopLoc(-1);
    5017       PostMessage(Handle, WM_EOT, 0, 0)
    5018     end
    5019     else
    5020     begin
    5021       if { (UnFocus>=0) and } not TurnComplete and EOT.Visible then
    5022         Play('TURNEND');
    5023       TurnComplete := true;
    5024       SetUnFocus(-1);
    5025       SetTroopLoc(-1);
    5026       PanelPaint;
    5027     end;
    5028   end; { NextUnit }
    5029 
    5030   procedure TMainScreen.Scroll(dx, dy: integer);
    5031   begin
    5032     xw := (xw + G.lx + dx) mod G.lx;
    5033     if ywmax > 0 then
    5034     begin
    5035       yw := yw + 2 * dy;
    5036       if yw < 0 then
    5037         yw := 0
    5038       else if yw > ywmax then
    5039         yw := ywmax;
    5040     end;
    5041     MainOffscreenPaint;
    5042     xwMini := xw;
    5043     ywMini := yw;
    5044     MiniPaint;
    5045     CopyMiniToPanel;
    5046     RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini + 2,
    5047       xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini +
    5048       2 + G.ly);
    5049     Update;
    5050   end;
    5051 
    5052   procedure TMainScreen.Timer1Timer(Sender: TObject);
    5053   var
    5054     dx, dy, speed: integer;
    5055   begin
    5056     if idle and (me >= 0) and (GameMode <> cMovie) then
    5057       if (fsModal in Screen.ActiveForm.FormState) or
    5058         (Screen.ActiveForm is TBufferedDrawDlg) and
    5059         (TBufferedDrawDlg(Screen.ActiveForm).WindowMode <> wmPersistent) then
    5060       begin
    5061         BlinkTime := BlinkOnTime + BlinkOffTime - 1;
    5062         if not BlinkON then
    5063         begin
    5064           BlinkON := true;
    5065           if UnFocus >= 0 then
    5066             PaintLocTemp(MyUn[UnFocus].Loc)
    5067           else if TurnComplete and not supervising then
    5068             EOT.SetButtonIndexFast(eotBlinkOn)
    5069         end
    5070       end
    5071       else
    5072       begin
    5073         if Application.Active and not mScrollOff.Checked then
    5074         begin
    5075           if mScrollFast.Checked then
    5076             speed := 2
    5077           else
    5078             speed := 1;
    5079           dx := 0;
    5080           dy := 0;
    5081           if Mouse.CursorPos.y < Screen.height - PanelHeight then
    5082             if Mouse.CursorPos.x = 0 then
    5083               dx := -speed // scroll left
    5084             else if Mouse.CursorPos.x = Screen.width - 1 then
    5085               dx := speed; // scroll right
    5086           if Mouse.CursorPos.y = 0 then
    5087             dy := -speed // scroll up
    5088           else if (Mouse.CursorPos.y = Screen.height - 1) and
    5089             (Mouse.CursorPos.x >= TerrainBtn.Left + TerrainBtn.width) and
    5090             (Mouse.CursorPos.x < xRightPanel + 10 - 8) then
    5091             dy := speed; // scroll down
    5092           if (dx <> 0) or (dy <> 0) then
    5093           begin
    5094             if (Screen.ActiveForm <> MainScreen) and
    5095               (@Screen.ActiveForm.OnDeactivate <> nil) then
    5096               Screen.ActiveForm.OnDeactivate(nil);
    5097             Scroll(dx, dy);
    5098           end
    5099         end;
    5100 
    5101         BlinkTime := (BlinkTime + 1) mod (BlinkOnTime + BlinkOffTime);
    5102         BlinkON := BlinkTime >= BlinkOffTime;
    5103         DestinationMarkON := true;
    5104         if UnFocus >= 0 then
    5105         begin
    5106           if (BlinkTime = 0) or (BlinkTime = BlinkOffTime) then
    5107           begin
    5108             PaintLocTemp(MyUn[UnFocus].Loc, pltsBlink);
    5109             PaintDestination;
    5110             // if MoveHintToLoc>=0 then
    5111             // ShowMoveHint(MoveHintToLoc, true);
    5112           end
    5113         end
    5114         else if TurnComplete and not supervising then
    5115         begin
    5116           if BlinkTime = 0 then
    5117             EOT.SetButtonIndexFast(eotBlinkOff)
    5118           else if BlinkTime = BlinkOffTime then
    5119             EOT.SetButtonIndexFast(eotBlinkOn)
    5120         end
    5121       end
    5122   end;
    5123 
    5124   procedure TMainScreen.Centre(Loc: integer);
    5125   begin
    5126     if FastScrolling and MapValid then
    5127       Update;
    5128     // necessary because ScrollDC for form canvas is called after
    5129     xw := (Loc mod G.lx - (MapWidth - xxt * 2 * ((Loc div G.lx) and 1))
    5130       div (xxt * 4) + G.lx) mod G.lx;
    5131     if ywmax <= 0 then
    5132       yw := ywcenter
    5133     else
    5134     begin
    5135       yw := (Loc div G.lx - MapHeight div (yyt * 2) + 1) and not 1;
    5136       if yw < 0 then
    5137         yw := 0
    5138       else if yw > ywmax then
    5139         yw := ywmax;
    5140     end
    5141   end;
    5142 
    5143   function TMainScreen.ZoomToCity(Loc: integer;
    5144     NextUnitOnClose: boolean = false; ShowEvent: integer = 0): boolean;
    5145   begin
    5146     result := MyMap[Loc] and (fOwned or fSpiedOut) <> 0;
    5147     if result then
    5148       with CityDlg do
    5149       begin
    5150         if ClientMode >= scContact then
    5151         begin
    5152           CloseAction := None;
    5153           RestoreUnFocus := -1;
    5154         end
    5155         else if NextUnitOnClose then
    5156         begin
    5157           CloseAction := StepFocus;
    5158           RestoreUnFocus := -1;
    5159         end
    5160         else if not Visible then
    5161         begin
    5162           CloseAction := RestoreFocus;
    5163           RestoreUnFocus := UnFocus;
    5164         end;
    5165         SetUnFocus(-1);
    5166         SetTroopLoc(Loc);
    5167         MarkCityLoc := Loc;
    5168         PanelPaint;
    5169         ShowNewContent(wmPersistent, Loc, ShowEvent);
    5170       end
    5171   end;
    5172 
    5173   function TMainScreen.LocationOfScreenPixel(x, y: integer): integer;
    5174   var
    5175     qx, qy: integer;
    5176   begin
    5177     qx := (x * (yyt * 2) + y * (xxt * 2) + xxt * yyt * 2)
    5178       div (xxt * yyt * 4) - 1;
    5179     qy := (y * (xxt * 2) - x * (yyt * 2) - xxt * yyt * 2 + 4000 * xxt * yyt)
    5180       div (xxt * yyt * 4) - 999;
    5181     result := (xw + (qx - qy + 2048) div 2 - 1024 + G.lx) mod G.lx + G.lx *
    5182       (yw + qx + qy);
    5183   end;
    5184 
    5185   procedure TMainScreen.MapBoxMouseDown(Sender: TObject; Button: TMouseButton;
    5186     Shift: TShiftState; x, y: integer);
    5187   var
    5188     i, uix, emix, p1, dx, dy, MouseLoc: integer;
    5189     EditTileData: TEditTileData;
    5190     m, m2: TMenuItem;
    5191     MoveAdviceData: TMoveAdviceData;
    5192     DoCenter: boolean;
    5193   begin
    5194     if GameMode = cMovie then
    5195       exit;
    5196 
    5197     if CityDlg.Visible then
    5198       CityDlg.Close;
    5199     if UnitStatDlg.Visible then
    5200       UnitStatDlg.Close;
    5201     MouseLoc := LocationOfScreenPixel(x, y);
    5202     if (MouseLoc < 0) or (MouseLoc >= G.lx * G.ly) then
    5203       exit;
    5204     if (Button = mbLeft) and not(ssShift in Shift) then
    5205     begin
    5206       DoCenter := true;
    5207       if ClientMode = cEditMap then
    5208       begin
    5209         DoCenter := false;
    5210         EditTileData.Loc := MouseLoc;
    5211         if ssCtrl in Shift then // toggle special resource
    5212           case MyMap[MouseLoc] and fTerrain of
    5213             fOcean:
    5214               EditTileData.NewTile := MyMap[MouseLoc];
    5215             fGrass, fArctic:
    5216               EditTileData.NewTile := MyMap[MouseLoc] and not fSpecial or
    5217                 ((MyMap[MouseLoc] shr 5 and 3 + 1) mod 2 shl 5);
    5218           else
    5219             EditTileData.NewTile := MyMap[MouseLoc] and not fSpecial or
    5220               ((MyMap[MouseLoc] shr 5 and 3 + 1) mod 3 shl 5)
    5221           end
    5222         else if BrushType <= fTerrain then
    5223           EditTileData.NewTile := MyMap[MouseLoc] and not fTerrain or
    5224             fSpecial or BrushType
    5225         else if BrushType and fDeadLands <> 0 then
    5226           if MyMap[MouseLoc] and (fDeadLands or fModern) = BrushType and
    5227             (fDeadLands or fModern) then
    5228             EditTileData.NewTile := MyMap[MouseLoc] and
    5229               not(fDeadLands or fModern)
    5230           else
    5231             EditTileData.NewTile := MyMap[MouseLoc] and
    5232               not(fDeadLands or fModern) or BrushType
    5233         else if BrushType and fTerImp <> 0 then
    5234           if MyMap[MouseLoc] and fTerImp = BrushType then
    5235             EditTileData.NewTile := MyMap[MouseLoc] and not fTerImp
    5236           else
    5237             EditTileData.NewTile := MyMap[MouseLoc] and not fTerImp or BrushType
    5238         else if BrushType and (fPrefStartPos or fStartPos) <> 0 then
    5239           if MyMap[MouseLoc] and (fPrefStartPos or fStartPos) = BrushType and
    5240             (fPrefStartPos or fStartPos) then
    5241             EditTileData.NewTile := MyMap[MouseLoc] and
    5242               not(fPrefStartPos or fStartPos)
    5243           else
    5244             EditTileData.NewTile := MyMap[MouseLoc] and
    5245               not(fPrefStartPos or fStartPos) or BrushType
    5246         else
    5247           EditTileData.NewTile := MyMap[MouseLoc] xor BrushType;
    5248         Server(sEditTile, me, 0, EditTileData);
    5249         Edited := true;
    5250         BrushLoc := MouseLoc;
    5251         PaintLoc(MouseLoc, 2);
    5252         MiniPaint;
    5253         BitBlt(Panel.Canvas.Handle, xMini + 2, yMini + 2, G.lx * 2, G.ly,
    5254           Mini.Canvas.Handle, 0, 0, SRCCOPY);
    5255         if ywmax <= 0 then
    5256           Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (2 * xxt),
    5257             yMini + 2, xMini + 1 + G.lx + MapWidth div (2 * xxt),
    5258             yMini + 2 + G.ly - 1, MainTexture.clMark, MainTexture.clMark)
    5259         else
    5260           Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (2 * xxt),
    5261             yMini + 2 + yw, xMini + 2 + G.lx + MapWidth div (2 * xxt) - 1,
    5262             yMini + 2 + yw + MapHeight div yyt - 2, MainTexture.clMark,
    5263             MainTexture.clMark);
    5264         RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini +
    5265           2, xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini
    5266           + 2 + G.ly)
    5267       end
    5268       else if MyMap[MouseLoc] and fCity <> 0 then { city clicked }
    5269       begin
    5270         if MyMap[MouseLoc] and (fOwned or fSpiedOut) <> 0 then
    5271         begin
    5272           ZoomToCity(MouseLoc);
    5273           DoCenter := false;
    52744698        end
    52754699        else
    52764700        begin
    5277           UnitStatDlg.ShowNewContent_EnemyCity(wmPersistent, MouseLoc);
    5278           DoCenter := false;
     4701          LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 8,
     4702            PanelHeight - 24, Phrases.Lookup('PRESENT'));
     4703          Server(sGetUnits, me, TroopLoc, Count);
     4704          for i := 0 to Count - 1 do
     4705            if (i >= TrRow * sb.si.npos) and (i < TrRow * (sb.si.npos + 1)) then
     4706            begin // display enemy units
     4707              trix[i - TrRow * sb.si.npos] := i;
     4708              x := (i - TrRow * sb.si.npos) * TrPitch;
     4709              NoMap.SetOutput(Panel);
     4710              NoMap.PaintUnit(xTroop + 2 + x, yTroop + 1,
     4711                MyRO.EnemyUn[MyRO.nEnemyUn + i], 0);
     4712            end;
     4713        end;
     4714      end;
     4715      if not SmallScreen or supervising then
     4716      begin // show terrain and improvements
     4717        PaintZoomedTile(Panel, xTerrain - xxt * 2, 110 - yyt * 3, TroopLoc);
     4718        if (UnFocus >= 0) and (MyUn[UnFocus].Job <> jNone) then
     4719        begin
     4720          JobFocus := MyUn[UnFocus].Job;
     4721          Server(sGetJobProgress, me, MyUn[UnFocus].Loc, JobProgressData);
     4722          MakeBlue(Panel, xTerrain - 72, 148 - 17, 144, 31);
     4723          PaintRelativeProgressBar(Panel.Canvas, 3, xTerrain - 68, 148 + 3, 63,
     4724            JobProgressData[JobFocus].Done,
     4725            JobProgressData[JobFocus].NextTurnPlus,
     4726            JobProgressData[JobFocus].Required, true, MainTexture);
     4727          s := Format('%s/%s',
     4728            [ScreenTools.MovementToString(JobProgressData[JobFocus].Done),
     4729            ScreenTools.MovementToString(JobProgressData[JobFocus].Required)]);
     4730          RisedTextOut(Panel.Canvas, xTerrain + 6, 148 - 3, s);
     4731          Tile := MyMap[MyUn[UnFocus].Loc];
     4732          if (JobFocus = jRoad) and (Tile and fRiver <> 0) then
     4733            JobFocus := nJob + 0
     4734          else if (JobFocus = jRR) and (Tile and fRiver <> 0) then
     4735            JobFocus := nJob + 1
     4736          else if JobFocus = jClear then
     4737          begin
     4738            if Tile and fTerrain = fForest then
     4739              JobFocus := nJob + 2
     4740            else if Tile and fTerrain = fDesert then
     4741              JobFocus := nJob + 3
     4742            else
     4743              JobFocus := nJob + 4
     4744          end;
     4745          s := Phrases.Lookup('JOBRESULT', JobFocus);
     4746          RisedTextOut(Panel.Canvas, xTerrain - BiColorTextWidth(Panel.Canvas,
     4747            s) div 2, 148 - 19, s);
     4748        end;
     4749        if MyMap[TroopLoc] and (fTerrain or fSpecial) = fGrass or fSpecial1 then
     4750          s := Phrases.Lookup('TERRAIN', fGrass + 12)
     4751        else if MyMap[TroopLoc] and fDeadLands <> 0 then
     4752          s := Phrases.Lookup('TERRAIN', 3 * 12)
     4753        else if (MyMap[TroopLoc] and fTerrain = fForest) and
     4754          IsJungle(TroopLoc div G.lx) then
     4755          s := Phrases.Lookup('TERRAIN', fJungle)
     4756        else
     4757          s := Phrases.Lookup('TERRAIN', MyMap[TroopLoc] and fTerrain);
     4758        RisedTextOut(Panel.Canvas, xTerrain - BiColorTextWidth(Panel.Canvas, s)
     4759          div 2, 99, s);
     4760      end;
     4761
     4762      if TerrainBtn.Visible then
     4763        with TerrainBtn do
     4764          RFrame(Panel.Canvas, Left - 1, Top - self.ClientHeight +
     4765            (PanelHeight - 1), Left + width, Top + height - self.ClientHeight +
     4766            PanelHeight, MainTexture.clBevelShade, MainTexture.clBevelLight)
     4767    end { if TroopLoc>=0 }
     4768  end;
     4769
     4770  for i := 0 to ControlCount - 1 do
     4771    if Controls[i] is TButtonB then
     4772      with TButtonB(Controls[i]) do
     4773      begin
     4774        if Visible then
     4775        begin
     4776          Dump(Panel, HGrSystem, Left, Top - self.ClientHeight + PanelHeight,
     4777            25, 25, 169, 243);
     4778          Sprite(Panel, HGrSystem, Left, Top - self.ClientHeight + PanelHeight,
     4779            25, 25, 1 + 26 * ButtonIndex, 337);
     4780          RFrame(Panel.Canvas, Left - 1, Top - self.ClientHeight +
     4781            (PanelHeight - 1), Left + width, Top + height - self.ClientHeight +
     4782            PanelHeight, MainTexture.clBevelShade, MainTexture.clBevelLight);
     4783        end;
     4784      end;
     4785
     4786  if ClientMode <> cEditMap then
     4787  begin
     4788    for i := 0 to ControlCount - 1 do
     4789      if Controls[i] is TButtonC then
     4790        with TButtonC(Controls[i]) do
     4791        begin
     4792          Dump(Panel, HGrSystem, Left, Top - self.ClientHeight + PanelHeight,
     4793            12, 12, 169, 178 + 13 * ButtonIndex);
     4794          RFrame(Panel.Canvas, Left - 1, Top - self.ClientHeight +
     4795            (PanelHeight - 1), Left + width, Top + height - self.ClientHeight +
     4796            PanelHeight, MainTexture.clBevelShade, MainTexture.clBevelLight);
    52794797        end
     4798  end;
     4799  EOT.SetBack(Panel.Canvas, EOT.Left, EOT.Top - (ClientHeight - PanelHeight));
     4800  SmartRectInvalidate(0, ClientHeight - PanelHeight, ClientWidth, ClientHeight);
     4801
     4802  // topbar
     4803  xTreasurySection := ClientWidth div 2 - 172;
     4804  xResearchSection := ClientWidth div 2;
     4805  // ClientWidth div 2+68 = maximum to right
     4806  FillLarge(TopBar.Canvas, 0, 0, ClientWidth, TopBarHeight - 3,
     4807    ClientWidth div 2);
     4808  with TopBar.Canvas do
     4809  begin
     4810    Pen.Color := $000000;
     4811    MoveTo(0, TopBarHeight - 1);
     4812    LineTo(ClientWidth, TopBarHeight - 1);
     4813    Pen.Color := MainTexture.clBevelShade;
     4814    MoveTo(0, TopBarHeight - 2);
     4815    LineTo(ClientWidth, TopBarHeight - 2);
     4816    MoveTo(0, TopBarHeight - 3);
     4817    LineTo(ClientWidth, TopBarHeight - 3);
     4818    Pen.Color := MainTexture.clBevelLight;
     4819    ScreenTools.Frame(TopBar.Canvas, 40, -1, xTreasurySection - 1,
     4820      TopBarHeight - 7, MainTexture.clBevelShade, MainTexture.clBevelLight);
     4821    ScreenTools.Frame(TopBar.Canvas, xResearchSection + 332, -1, ClientWidth,
     4822      TopBarHeight - 7, MainTexture.clBevelShade, MainTexture.clBevelLight);
     4823  end;
     4824  if GameMode <> cMovie then
     4825    ImageOp_BCC(TopBar, Templates, 2, 1, 145, 38, 36, 36, $BFBF20, $4040DF);
     4826  if MyRO.nCity > 0 then
     4827  begin
     4828    TrueMoney := MyRO.Money;
     4829    TrueResearch := MyRO.Research;
     4830    if supervising then
     4831    begin // normalize values from after-turn state
     4832      dec(TrueMoney, TaxSum);
     4833      if TrueMoney < 0 then
     4834        TrueMoney := 0; // shouldn't happen
     4835      dec(TrueResearch, ScienceSum);
     4836      if TrueResearch < 0 then
     4837        TrueResearch := 0; // shouldn't happen
     4838    end;
     4839
     4840    // treasury section
     4841    ImageOp_BCC(TopBar, Templates, xTreasurySection + 8, 1, 145, 1, 36, 36,
     4842      $40A040, $4030C0);
     4843    s := IntToStr(TrueMoney);
     4844    LoweredTextOut(TopBar.Canvas, -1, MainTexture, xTreasurySection + 48, 0,
     4845      s + '%c');
     4846    if MyRO.Government <> gAnarchy then
     4847    begin
     4848      ImageOp_BCC(TopBar, Templates, xTreasurySection + 48, 22, 124, 1, 14, 14,
     4849        $0000C0, $0080C0);
     4850      if TaxSum >= 0 then
     4851        s := Format(Phrases.Lookup('MONEYGAINPOS'), [TaxSum])
     4852      else
     4853        s := Format(Phrases.Lookup('MONEYGAINNEG'), [TaxSum]);
     4854      LoweredTextOut(TopBar.Canvas, -1, MainTexture, xTreasurySection + 48 +
     4855        15, 18, s);
     4856    end;
     4857
     4858    // research section
     4859    ImageOp_BCC(TopBar, Templates, xResearchSection + 8, 1, 145, 75, 36, 36,
     4860      $FF0000, $00FFE0);
     4861    if MyData.FarTech <> adNexus then
     4862    begin
     4863      if MyRO.ResearchTech < 0 then
     4864        CostFactor := 2
     4865      else if (MyRO.ResearchTech = adMilitary) or
     4866        (MyRO.Tech[MyRO.ResearchTech] = tsSeen) then
     4867        CostFactor := 1
     4868      else if MyRO.ResearchTech in FutureTech then
     4869        if MyRO.Government = gFuture then
     4870          CostFactor := 4
     4871        else
     4872          CostFactor := 8
     4873      else
     4874        CostFactor := 2;
     4875      Server(sGetTechCost, me, 0, i);
     4876      CostFactor := CostFactor * 22; // length of progress bar
     4877      PaintRelativeProgressBar(TopBar.Canvas, 2, xResearchSection + 48 + 1, 26,
     4878        CostFactor, TrueResearch, ScienceSum, i, true, MainTexture);
     4879
     4880      if MyRO.ResearchTech < 0 then
     4881        s := Phrases.Lookup('SCIENCE')
     4882      else if MyRO.ResearchTech = adMilitary then
     4883        s := Phrases.Lookup('INITUNIT')
     4884      else
     4885      begin
     4886        s := Phrases.Lookup('ADVANCES', MyRO.ResearchTech);
     4887        if MyRO.ResearchTech in FutureTech then
     4888          if MyRO.Tech[MyRO.ResearchTech] >= 1 then
     4889            s := s + ' ' + IntToStr(MyRO.Tech[MyRO.ResearchTech] + 1)
     4890          else
     4891            s := s + ' 1';
     4892      end;
     4893      if ScienceSum > 0 then
     4894      begin
     4895        { j:=(i-MyRO.Research-1) div ScienceSum +1;
     4896          if j<1 then j:=1;
     4897          if j>1 then
     4898          s:=Format(Phrases.Lookup('TECHWAIT'),[s,j]); }
     4899        LoweredTextOut(TopBar.Canvas, -1, MainTexture,
     4900          xResearchSection + 48, 0, s);
    52804901      end
    5281       else if MyMap[MouseLoc] and fUnit <> 0 then { unit clicked }
    5282         if MyMap[MouseLoc] and fOwned <> 0 then
     4902      else
     4903        LoweredTextOut(TopBar.Canvas, -1, MainTexture,
     4904          xResearchSection + 48, 0, s);
     4905    end
     4906    else
     4907      CostFactor := 0;
     4908    if (MyData.FarTech <> adNexus) and (ScienceSum > 0) then
     4909    begin
     4910      ImageOp_BCC(TopBar, Templates, xResearchSection + 48 + CostFactor + 11,
     4911        22, 124, 1, 14, 14, $0000C0, $0080C0);
     4912      s := Format(Phrases.Lookup('TECHGAIN'), [ScienceSum]);
     4913      LoweredTextOut(TopBar.Canvas, -1, MainTexture, xResearchSection + 48 +
     4914        CostFactor + 26, 18, s);
     4915    end
     4916  end;
     4917  if ClientMode <> cEditMap then
     4918  begin
     4919    TopBar.Canvas.Font.Assign(UniFont[ftCaption]);
     4920    s := TurnToString(MyRO.Turn);
     4921    RisedTextOut(TopBar.Canvas,
     4922      40 + (xTreasurySection - 40 - BiColorTextWidth(TopBar.Canvas, s))
     4923      div 2, 6, s);
     4924    TopBar.Canvas.Font.Assign(UniFont[ftNormal]);
     4925  end;
     4926  RectInvalidate(0, 0, ClientWidth, TopBarHeight);
     4927end; { PanelPaint }
     4928
     4929procedure TMainScreen.FocusOnLoc(Loc: integer; Options: integer = 0);
     4930var
     4931  dx: integer;
     4932  Outside, Changed: boolean;
     4933begin
     4934  dx := G.lx + 1 - (xw - Loc + G.lx * 1024 + 1) mod G.lx;
     4935  Outside := (dx >= (MapWidth + 1) div (xxt * 2) - 2) or (ywmax > 0) and
     4936    ((yw > 0) and (Loc div G.lx <= yw + 1) or (yw < ywmax) and
     4937    (Loc div G.lx >= yw + (MapHeight - 1) div yyt - 2));
     4938  Changed := true;
     4939  if Outside then
     4940  begin
     4941    Centre(Loc);
     4942    PaintAllMaps
     4943  end
     4944  else if not MapValid then
     4945    PaintAllMaps
     4946  else
     4947    Changed := false;
     4948  if Options and flRepaintPanel <> 0 then
     4949    PanelPaint;
     4950  if Changed and (Options and flImmUpdate <> 0) then
     4951    Update;
     4952end;
     4953
     4954procedure TMainScreen.NextUnit(NearLoc: integer; AutoTurn: boolean);
     4955var
     4956  Dist, TestDist: single;
     4957  i, uix, NewFocus: integer;
     4958  GotoOnly: boolean;
     4959begin
     4960  if ClientMode >= scContact then
     4961    exit;
     4962  DestinationMarkON := false;
     4963  PaintDestination;
     4964  for GotoOnly := GoOnPhase downto false do
     4965  begin
     4966    NewFocus := -1;
     4967    for i := 1 to MyRO.nUn do
     4968    begin
     4969      uix := (UnFocus + i) mod MyRO.nUn;
     4970      if (MyUn[uix].Loc >= 0) and (MyUn[uix].Job = jNone) and
     4971        (MyUn[uix].Status and (usStay or usRecover or usWaiting) = usWaiting)
     4972        and (not GotoOnly or (MyUn[uix].Status and usGoto <> 0)) then
     4973        if NearLoc < 0 then
    52834974        begin
    5284           DoCenter := false;
    5285           if not supervising and (ClientMode < scContact) then
    5286           begin // not in negotiation mode
    5287             if (UnFocus >= 0) and (MyUn[UnFocus].Loc = MouseLoc) then
    5288             begin // rotate
    5289               uix := (UnFocus + 1) mod MyRO.nUn;
    5290               i := MyRO.nUn - 1;
    5291               while i > 0 do
    5292               begin
    5293                 if (MyUn[uix].Loc = MouseLoc) and (MyUn[uix].Job = jNone) and
    5294                   (MyUn[uix].Status and (usStay or usRecover or usEnhance or
    5295                   usWaiting) = usWaiting) then
    5296                   Break;
    5297                 dec(i);
    5298                 uix := (uix + 1) mod MyRO.nUn;
    5299               end;
    5300               if i = 0 then
    5301                 uix := UnFocus
    5302             end
    5303             else
    5304               Server(sGetDefender, me, MouseLoc, uix);
    5305             if uix <> UnFocus then
    5306               SetUnFocus(uix);
    5307             TurnComplete := false;
    5308             EOT.ButtonIndex := eotGray;
    5309           end;
    5310           SetTroopLoc(MouseLoc);
    5311           PanelPaint;
    5312         end // own unit
    5313         else if (MyMap[MouseLoc] and fSpiedOut <> 0) and not(ssCtrl in Shift)
    5314         then
    5315         begin
    5316           DoCenter := false;
    5317           SetTroopLoc(MouseLoc);
    5318           PanelPaint;
     4975          NewFocus := uix;
     4976          Break
    53194977        end
    53204978        else
    53214979        begin
    5322           DoCenter := false;
    5323           UnitStatDlg.ShowNewContent_EnemyLoc(wmPersistent, MouseLoc);
    5324         end;
    5325       if DoCenter then
    5326       begin
    5327         Centre(MouseLoc);
    5328         PaintAllMaps
     4980          TestDist := Distance(NearLoc, MyUn[uix].Loc);
     4981          if (NewFocus < 0) or (TestDist < Dist) then
     4982          begin
     4983            NewFocus := uix;
     4984            Dist := TestDist
     4985          end
     4986        end
     4987    end;
     4988    if GotoOnly then
     4989      if NewFocus < 0 then
     4990        GoOnPhase := false
     4991      else
     4992        Break;
     4993  end;
     4994  if NewFocus >= 0 then
     4995  begin
     4996    SetUnFocus(NewFocus);
     4997    SetTroopLoc(MyUn[NewFocus].Loc);
     4998    FocusOnLoc(TroopLoc, flRepaintPanel)
     4999  end
     5000  else if AutoTurn and not mWaitTurn.Checked then
     5001  begin
     5002    TurnComplete := true;
     5003    SetUnFocus(-1);
     5004    SetTroopLoc(-1);
     5005    PostMessage(Handle, WM_EOT, 0, 0)
     5006  end
     5007  else
     5008  begin
     5009    if { (UnFocus>=0) and } not TurnComplete and EOT.Visible then
     5010      Play('TURNEND');
     5011    TurnComplete := true;
     5012    SetUnFocus(-1);
     5013    SetTroopLoc(-1);
     5014    PanelPaint;
     5015  end;
     5016end; { NextUnit }
     5017
     5018procedure TMainScreen.Scroll(dx, dy: integer);
     5019begin
     5020  xw := (xw + G.lx + dx) mod G.lx;
     5021  if ywmax > 0 then
     5022  begin
     5023    yw := yw + 2 * dy;
     5024    if yw < 0 then
     5025      yw := 0
     5026    else if yw > ywmax then
     5027      yw := ywmax;
     5028  end;
     5029  MainOffscreenPaint;
     5030  xwMini := xw;
     5031  ywMini := yw;
     5032  MiniPaint;
     5033  CopyMiniToPanel;
     5034  RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini + 2,
     5035    xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini +
     5036    2 + G.ly);
     5037  Update;
     5038end;
     5039
     5040procedure TMainScreen.Timer1Timer(Sender: TObject);
     5041var
     5042  dx, dy, speed: integer;
     5043begin
     5044  if idle and (me >= 0) and (GameMode <> cMovie) then
     5045    if (fsModal in Screen.ActiveForm.FormState) or
     5046      (Screen.ActiveForm is TBufferedDrawDlg) and
     5047      (TBufferedDrawDlg(Screen.ActiveForm).WindowMode <> wmPersistent) then
     5048    begin
     5049      BlinkTime := BlinkOnTime + BlinkOffTime - 1;
     5050      if not BlinkON then
     5051      begin
     5052        BlinkON := true;
     5053        if UnFocus >= 0 then
     5054          PaintLocTemp(MyUn[UnFocus].Loc)
     5055        else if TurnComplete and not supervising then
     5056          EOT.SetButtonIndexFast(eotBlinkOn)
    53295057      end
    53305058    end
    5331     else if (ClientMode <> cEditMap) and (Button = mbRight) and
    5332       not(ssShift in Shift) then
    5333     begin
    5334       if supervising then
    5335       begin
    5336         EditLoc := MouseLoc;
    5337         Server(sGetModels, me, 0, nil^);
    5338         EmptyMenu(mCreateUnit);
    5339         for p1 := 0 to nPl - 1 do
    5340           if 1 shl p1 and MyRO.Alive <> 0 then
    5341           begin
    5342             m := TMenuItem.Create(mCreateUnit);
    5343             m.Caption := Tribe[p1].TPhrase('SHORTNAME');
    5344             for emix := MyRO.nEnemyModel - 1 downto 0 do
    5345               if (MyRO.EnemyModel[emix].Owner = p1) and
    5346                 (Server(sCreateUnit - sExecute + p1 shl 4, me,
    5347                 MyRO.EnemyModel[emix].mix, MouseLoc) >= rExecuted) then
    5348               begin
    5349                 if Tribe[p1].ModelPicture[MyRO.EnemyModel[emix].mix].HGr = 0
    5350                 then
    5351                   InitEnemyModel(emix);
    5352                 m2 := TMenuItem.Create(m);
    5353                 m2.Caption := Tribe[p1].ModelName[MyRO.EnemyModel[emix].mix];
    5354                 m2.Tag := p1 shl 16 + MyRO.EnemyModel[emix].mix;
    5355                 m2.OnClick := CreateUnitClick;
    5356                 m.Add(m2);
    5357               end;
    5358             m.Visible := m.Count > 0;
    5359             mCreateUnit.Add(m);
    5360           end;
    5361         if FullScreen then
    5362           EditPopup.Popup(Left + x, Top + y)
     5059    else
     5060    begin
     5061      if Application.Active and not mScrollOff.Checked then
     5062      begin
     5063        if mScrollFast.Checked then
     5064          speed := 2
    53635065        else
    5364           EditPopup.Popup(Left + x + 4,
    5365             Top + y + GetSystemMetrics(SM_CYCAPTION) + 4);
     5066          speed := 1;
     5067        dx := 0;
     5068        dy := 0;
     5069        if Mouse.CursorPos.y < Screen.height - PanelHeight then
     5070          if Mouse.CursorPos.x = 0 then
     5071            dx := -speed // scroll left
     5072          else if Mouse.CursorPos.x = Screen.width - 1 then
     5073            dx := speed; // scroll right
     5074        if Mouse.CursorPos.y = 0 then
     5075          dy := -speed // scroll up
     5076        else if (Mouse.CursorPos.y = Screen.height - 1) and
     5077          (Mouse.CursorPos.x >= TerrainBtn.Left + TerrainBtn.width) and
     5078          (Mouse.CursorPos.x < xRightPanel + 10 - 8) then
     5079          dy := speed; // scroll down
     5080        if (dx <> 0) or (dy <> 0) then
     5081        begin
     5082          if (Screen.ActiveForm <> MainScreen) and
     5083            (@Screen.ActiveForm.OnDeactivate <> nil) then
     5084            Screen.ActiveForm.OnDeactivate(nil);
     5085          Scroll(dx, dy);
     5086        end
     5087      end;
     5088
     5089      BlinkTime := (BlinkTime + 1) mod (BlinkOnTime + BlinkOffTime);
     5090      BlinkON := BlinkTime >= BlinkOffTime;
     5091      DestinationMarkON := true;
     5092      if UnFocus >= 0 then
     5093      begin
     5094        if (BlinkTime = 0) or (BlinkTime = BlinkOffTime) then
     5095        begin
     5096          PaintLocTemp(MyUn[UnFocus].Loc, pltsBlink);
     5097          PaintDestination;
     5098          // if MoveHintToLoc>=0 then
     5099          // ShowMoveHint(MoveHintToLoc, true);
     5100        end
    53665101      end
    5367       else if (UnFocus >= 0) and (MyUn[UnFocus].Loc <> MouseLoc) then
    5368         with MyUn[UnFocus] do
    5369         begin
    5370           dx := ((MouseLoc mod G.lx * 2 + MouseLoc div G.lx and 1) -
    5371             (Loc mod G.lx * 2 + Loc div G.lx and 1) + 3 * G.lx)
    5372             mod (2 * G.lx) - G.lx;
    5373           dy := MouseLoc div G.lx - Loc div G.lx;
    5374           if abs(dx) + abs(dy) < 3 then
    5375           begin
    5376             DestinationMarkON := false;
    5377             PaintDestination;
    5378             Status := Status and
    5379               ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
    5380             MoveUnit(dx, dy, muAutoNext) { simple move }
    5381           end
    5382           else if GetMoveAdvice(UnFocus, MouseLoc, MoveAdviceData) >= rExecuted
    5383           then
    5384           begin
    5385             if MyMap[MouseLoc] and (fUnit or fOwned) = fUnit then
    5386             begin // check for suicide mission before movement
    5387               with MyUn[UnFocus], BattleDlg.Forecast do
    5388               begin
    5389                 pAtt := me;
    5390                 mixAtt := mix;
    5391                 HealthAtt := Health;
    5392                 ExpAtt := Exp;
    5393                 FlagsAtt := Flags;
    5394               end;
    5395               BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
    5396               if (Server(sGetBattleForecastEx, me, MouseLoc, BattleDlg.Forecast)
    5397                 >= rExecuted) and (BattleDlg.Forecast.EndHealthAtt <= 0) then
    5398               begin
    5399                 BattleDlg.uix := UnFocus;
    5400                 BattleDlg.ToLoc := MouseLoc;
    5401                 BattleDlg.IsSuicideQuery := true;
    5402                 BattleDlg.ShowModal;
    5403                 if BattleDlg.ModalResult <> mrOK then
    5404                   exit;
    5405               end
    5406             end;
    5407             DestinationMarkON := false;
    5408             PaintDestination;
    5409             Status := Status and not(usStay or usRecover or usEnhance) or
    5410               usWaiting;
    5411             MoveToLoc(MouseLoc, false); { goto }
    5412           end
    5413         end
    5414     end
    5415     else if (Button = mbMiddle) and (UnFocus >= 0) and
    5416       (MyModel[MyUn[UnFocus].mix].Kind in [mkSettler, mkSlaves]) then
    5417     begin
    5418       DestinationMarkON := false;
    5419       PaintDestination;
    5420       MyUn[UnFocus].Status := MyUn[UnFocus].Status and
    5421         ($FFFF - usStay - usRecover - usGoto) or usEnhance;
    5422       uix := UnFocus;
    5423       if MouseLoc <> MyUn[uix].Loc then
    5424         MoveToLoc(MouseLoc, true); { goto }
    5425       if (UnFocus = uix) and (MyUn[uix].Loc = MouseLoc) then
    5426         MenuClick(mEnhance)
    5427     end
    5428     else if (Button = mbLeft) and (ssShift in Shift) and
    5429       (MyMap[MouseLoc] and fTerrain <> fUNKNOWN) then
    5430       HelpOnTerrain(MouseLoc, wmPersistent)
    5431     else if (ClientMode <= cContinue) and (Button = mbRight) and
    5432       (ssShift in Shift) and (UnFocus >= 0) and
    5433       (MyMap[MouseLoc] and (fUnit or fOwned) = fUnit) then
    5434     begin // battle forecast
    5435       with MyUn[UnFocus], BattleDlg.Forecast do
    5436       begin
    5437         pAtt := me;
    5438         mixAtt := mix;
    5439         HealthAtt := Health;
    5440         ExpAtt := Exp;
    5441         FlagsAtt := Flags;
    5442       end;
    5443       BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
    5444       if Server(sGetBattleForecastEx, me, MouseLoc, BattleDlg.Forecast) >= rExecuted
    5445       then
    5446       begin
    5447         BattleDlg.uix := UnFocus;
    5448         BattleDlg.ToLoc := MouseLoc;
    5449         BattleDlg.Left := x - BattleDlg.width div 2;
    5450         if BattleDlg.Left < 0 then
    5451           BattleDlg.Left := 0
    5452         else if BattleDlg.Left + BattleDlg.width > Screen.width then
    5453           BattleDlg.Left := Screen.width - BattleDlg.width;
    5454         BattleDlg.Top := y - BattleDlg.height div 2;
    5455         if BattleDlg.Top < 0 then
    5456           BattleDlg.Top := 0
    5457         else if BattleDlg.Top + BattleDlg.height > Screen.height then
    5458           BattleDlg.Top := Screen.height - BattleDlg.height;
    5459         BattleDlg.IsSuicideQuery := false;
    5460         BattleDlg.Show;
     5102      else if TurnComplete and not supervising then
     5103      begin
     5104        if BlinkTime = 0 then
     5105          EOT.SetButtonIndexFast(eotBlinkOff)
     5106        else if BlinkTime = BlinkOffTime then
     5107          EOT.SetButtonIndexFast(eotBlinkOn)
    54615108      end
    54625109    end
     5110end;
     5111
     5112procedure TMainScreen.Centre(Loc: integer);
     5113begin
     5114  if FastScrolling and MapValid then
     5115    Update;
     5116  // necessary because ScrollDC for form canvas is called after
     5117  xw := (Loc mod G.lx - (MapWidth - xxt * 2 * ((Loc div G.lx) and 1))
     5118    div (xxt * 4) + G.lx) mod G.lx;
     5119  if ywmax <= 0 then
     5120    yw := ywcenter
     5121  else
     5122  begin
     5123    yw := (Loc div G.lx - MapHeight div (yyt * 2) + 1) and not 1;
     5124    if yw < 0 then
     5125      yw := 0
     5126    else if yw > ywmax then
     5127      yw := ywmax;
     5128  end
     5129end;
     5130
     5131function TMainScreen.ZoomToCity(Loc: integer; NextUnitOnClose: boolean = false;
     5132  ShowEvent: integer = 0): boolean;
     5133begin
     5134  result := MyMap[Loc] and (fOwned or fSpiedOut) <> 0;
     5135  if result then
     5136    with CityDlg do
     5137    begin
     5138      if ClientMode >= scContact then
     5139      begin
     5140        CloseAction := None;
     5141        RestoreUnFocus := -1;
     5142      end
     5143      else if NextUnitOnClose then
     5144      begin
     5145        CloseAction := StepFocus;
     5146        RestoreUnFocus := -1;
     5147      end
     5148      else if not Visible then
     5149      begin
     5150        CloseAction := RestoreFocus;
     5151        RestoreUnFocus := UnFocus;
     5152      end;
     5153      SetUnFocus(-1);
     5154      SetTroopLoc(Loc);
     5155      MarkCityLoc := Loc;
     5156      PanelPaint;
     5157      ShowNewContent(wmPersistent, Loc, ShowEvent);
     5158    end
     5159end;
     5160
     5161function TMainScreen.LocationOfScreenPixel(x, y: integer): integer;
     5162var
     5163  qx, qy: integer;
     5164begin
     5165  qx := (x * (yyt * 2) + y * (xxt * 2) + xxt * yyt * 2) div (xxt * yyt * 4) - 1;
     5166  qy := (y * (xxt * 2) - x * (yyt * 2) - xxt * yyt * 2 + 4000 * xxt * yyt)
     5167    div (xxt * yyt * 4) - 999;
     5168  result := (xw + (qx - qy + 2048) div 2 - 1024 + G.lx) mod G.lx + G.lx *
     5169    (yw + qx + qy);
     5170end;
     5171
     5172procedure TMainScreen.MapBoxMouseDown(Sender: TObject; Button: TMouseButton;
     5173  Shift: TShiftState; x, y: integer);
     5174var
     5175  i, uix, emix, p1, dx, dy, MouseLoc: integer;
     5176  EditTileData: TEditTileData;
     5177  m, m2: TMenuItem;
     5178  MoveAdviceData: TMoveAdviceData;
     5179  DoCenter: boolean;
     5180begin
     5181  if GameMode = cMovie then
     5182    exit;
     5183
     5184  if CityDlg.Visible then
     5185    CityDlg.Close;
     5186  if UnitStatDlg.Visible then
     5187    UnitStatDlg.Close;
     5188  MouseLoc := LocationOfScreenPixel(x, y);
     5189  if (MouseLoc < 0) or (MouseLoc >= G.lx * G.ly) then
     5190    exit;
     5191  if (Button = mbLeft) and not(ssShift in Shift) then
     5192  begin
     5193    DoCenter := true;
     5194    if ClientMode = cEditMap then
     5195    begin
     5196      DoCenter := false;
     5197      EditTileData.Loc := MouseLoc;
     5198      if ssCtrl in Shift then // toggle special resource
     5199        case MyMap[MouseLoc] and fTerrain of
     5200          fOcean:
     5201            EditTileData.NewTile := MyMap[MouseLoc];
     5202          fGrass, fArctic:
     5203            EditTileData.NewTile := MyMap[MouseLoc] and not fSpecial or
     5204              ((MyMap[MouseLoc] shr 5 and 3 + 1) mod 2 shl 5);
     5205        else
     5206          EditTileData.NewTile := MyMap[MouseLoc] and not fSpecial or
     5207            ((MyMap[MouseLoc] shr 5 and 3 + 1) mod 3 shl 5)
     5208        end
     5209      else if BrushType <= fTerrain then
     5210        EditTileData.NewTile := MyMap[MouseLoc] and not fTerrain or fSpecial or
     5211          BrushType
     5212      else if BrushType and fDeadLands <> 0 then
     5213        if MyMap[MouseLoc] and (fDeadLands or fModern) = BrushType and
     5214          (fDeadLands or fModern) then
     5215          EditTileData.NewTile := MyMap[MouseLoc] and not(fDeadLands or fModern)
     5216        else
     5217          EditTileData.NewTile := MyMap[MouseLoc] and not(fDeadLands or fModern)
     5218            or BrushType
     5219      else if BrushType and fTerImp <> 0 then
     5220        if MyMap[MouseLoc] and fTerImp = BrushType then
     5221          EditTileData.NewTile := MyMap[MouseLoc] and not fTerImp
     5222        else
     5223          EditTileData.NewTile := MyMap[MouseLoc] and not fTerImp or BrushType
     5224      else if BrushType and (fPrefStartPos or fStartPos) <> 0 then
     5225        if MyMap[MouseLoc] and (fPrefStartPos or fStartPos) = BrushType and
     5226          (fPrefStartPos or fStartPos) then
     5227          EditTileData.NewTile := MyMap[MouseLoc] and
     5228            not(fPrefStartPos or fStartPos)
     5229        else
     5230          EditTileData.NewTile := MyMap[MouseLoc] and
     5231            not(fPrefStartPos or fStartPos) or BrushType
     5232      else
     5233        EditTileData.NewTile := MyMap[MouseLoc] xor BrushType;
     5234      Server(sEditTile, me, 0, EditTileData);
     5235      Edited := true;
     5236      BrushLoc := MouseLoc;
     5237      PaintLoc(MouseLoc, 2);
     5238      MiniPaint;
     5239      BitBlt(Panel.Canvas.Handle, xMini + 2, yMini + 2, G.lx * 2, G.ly,
     5240        Mini.Canvas.Handle, 0, 0, SRCCOPY);
     5241      if ywmax <= 0 then
     5242        Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (2 * xxt),
     5243          yMini + 2, xMini + 1 + G.lx + MapWidth div (2 * xxt),
     5244          yMini + 2 + G.ly - 1, MainTexture.clMark, MainTexture.clMark)
     5245      else
     5246        Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (2 * xxt),
     5247          yMini + 2 + yw, xMini + 2 + G.lx + MapWidth div (2 * xxt) - 1,
     5248          yMini + 2 + yw + MapHeight div yyt - 2, MainTexture.clMark,
     5249          MainTexture.clMark);
     5250      RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini + 2,
     5251        xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini
     5252        + 2 + G.ly)
     5253    end
     5254    else if MyMap[MouseLoc] and fCity <> 0 then { city clicked }
     5255    begin
     5256      if MyMap[MouseLoc] and (fOwned or fSpiedOut) <> 0 then
     5257      begin
     5258        ZoomToCity(MouseLoc);
     5259        DoCenter := false;
     5260      end
     5261      else
     5262      begin
     5263        UnitStatDlg.ShowNewContent_EnemyCity(wmPersistent, MouseLoc);
     5264        DoCenter := false;
     5265      end
     5266    end
     5267    else if MyMap[MouseLoc] and fUnit <> 0 then { unit clicked }
     5268      if MyMap[MouseLoc] and fOwned <> 0 then
     5269      begin
     5270        DoCenter := false;
     5271        if not supervising and (ClientMode < scContact) then
     5272        begin // not in negotiation mode
     5273          if (UnFocus >= 0) and (MyUn[UnFocus].Loc = MouseLoc) then
     5274          begin // rotate
     5275            uix := (UnFocus + 1) mod MyRO.nUn;
     5276            i := MyRO.nUn - 1;
     5277            while i > 0 do
     5278            begin
     5279              if (MyUn[uix].Loc = MouseLoc) and (MyUn[uix].Job = jNone) and
     5280                (MyUn[uix].Status and (usStay or usRecover or usEnhance or
     5281                usWaiting) = usWaiting) then
     5282                Break;
     5283              dec(i);
     5284              uix := (uix + 1) mod MyRO.nUn;
     5285            end;
     5286            if i = 0 then
     5287              uix := UnFocus
     5288          end
     5289          else
     5290            Server(sGetDefender, me, MouseLoc, uix);
     5291          if uix <> UnFocus then
     5292            SetUnFocus(uix);
     5293          TurnComplete := false;
     5294          EOT.ButtonIndex := eotGray;
     5295        end;
     5296        SetTroopLoc(MouseLoc);
     5297        PanelPaint;
     5298      end // own unit
     5299      else if (MyMap[MouseLoc] and fSpiedOut <> 0) and not(ssCtrl in Shift) then
     5300      begin
     5301        DoCenter := false;
     5302        SetTroopLoc(MouseLoc);
     5303        PanelPaint;
     5304      end
     5305      else
     5306      begin
     5307        DoCenter := false;
     5308        UnitStatDlg.ShowNewContent_EnemyLoc(wmPersistent, MouseLoc);
     5309      end;
     5310    if DoCenter then
     5311    begin
     5312      Centre(MouseLoc);
     5313      PaintAllMaps
     5314    end
     5315  end
     5316  else if (ClientMode <> cEditMap) and (Button = mbRight) and
     5317    not(ssShift in Shift) then
     5318  begin
     5319    if supervising then
     5320    begin
     5321      EditLoc := MouseLoc;
     5322      Server(sGetModels, me, 0, nil^);
     5323      EmptyMenu(mCreateUnit);
     5324      for p1 := 0 to nPl - 1 do
     5325        if 1 shl p1 and MyRO.Alive <> 0 then
     5326        begin
     5327          m := TMenuItem.Create(mCreateUnit);
     5328          m.Caption := Tribe[p1].TPhrase('SHORTNAME');
     5329          for emix := MyRO.nEnemyModel - 1 downto 0 do
     5330            if (MyRO.EnemyModel[emix].Owner = p1) and
     5331              (Server(sCreateUnit - sExecute + p1 shl 4, me,
     5332              MyRO.EnemyModel[emix].mix, MouseLoc) >= rExecuted) then
     5333            begin
     5334              if Tribe[p1].ModelPicture[MyRO.EnemyModel[emix].mix].HGr = 0 then
     5335                InitEnemyModel(emix);
     5336              m2 := TMenuItem.Create(m);
     5337              m2.Caption := Tribe[p1].ModelName[MyRO.EnemyModel[emix].mix];
     5338              m2.Tag := p1 shl 16 + MyRO.EnemyModel[emix].mix;
     5339              m2.OnClick := CreateUnitClick;
     5340              m.Add(m2);
     5341            end;
     5342          m.Visible := m.Count > 0;
     5343          mCreateUnit.Add(m);
     5344        end;
     5345      if FullScreen then
     5346        EditPopup.Popup(Left + x, Top + y)
     5347      else
     5348        EditPopup.Popup(Left + x + 4,
     5349          Top + y + GetSystemMetrics(SM_CYCAPTION) + 4);
     5350    end
     5351    else if (UnFocus >= 0) and (MyUn[UnFocus].Loc <> MouseLoc) then
     5352      with MyUn[UnFocus] do
     5353      begin
     5354        dx := ((MouseLoc mod G.lx * 2 + MouseLoc div G.lx and 1) -
     5355          (Loc mod G.lx * 2 + Loc div G.lx and 1) + 3 * G.lx)
     5356          mod (2 * G.lx) - G.lx;
     5357        dy := MouseLoc div G.lx - Loc div G.lx;
     5358        if abs(dx) + abs(dy) < 3 then
     5359        begin
     5360          DestinationMarkON := false;
     5361          PaintDestination;
     5362          Status := Status and ($FFFF - usStay - usRecover - usGoto - usEnhance)
     5363            or usWaiting;
     5364          MoveUnit(dx, dy, muAutoNext) { simple move }
     5365        end
     5366        else if GetMoveAdvice(UnFocus, MouseLoc, MoveAdviceData) >= rExecuted
     5367        then
     5368        begin
     5369          if MyMap[MouseLoc] and (fUnit or fOwned) = fUnit then
     5370          begin // check for suicide mission before movement
     5371            with MyUn[UnFocus], BattleDlg.Forecast do
     5372            begin
     5373              pAtt := me;
     5374              mixAtt := mix;
     5375              HealthAtt := Health;
     5376              ExpAtt := Exp;
     5377              FlagsAtt := Flags;
     5378            end;
     5379            BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
     5380            if (Server(sGetBattleForecastEx, me, MouseLoc, BattleDlg.Forecast)
     5381              >= rExecuted) and (BattleDlg.Forecast.EndHealthAtt <= 0) then
     5382            begin
     5383              BattleDlg.uix := UnFocus;
     5384              BattleDlg.ToLoc := MouseLoc;
     5385              BattleDlg.IsSuicideQuery := true;
     5386              BattleDlg.ShowModal;
     5387              if BattleDlg.ModalResult <> mrOK then
     5388                exit;
     5389            end
     5390          end;
     5391          DestinationMarkON := false;
     5392          PaintDestination;
     5393          Status := Status and not(usStay or usRecover or usEnhance) or
     5394            usWaiting;
     5395          MoveToLoc(MouseLoc, false); { goto }
     5396        end
     5397      end
     5398  end
     5399  else if (Button = mbMiddle) and (UnFocus >= 0) and
     5400    (MyModel[MyUn[UnFocus].mix].Kind in [mkSettler, mkSlaves]) then
     5401  begin
     5402    DestinationMarkON := false;
     5403    PaintDestination;
     5404    MyUn[UnFocus].Status := MyUn[UnFocus].Status and
     5405      ($FFFF - usStay - usRecover - usGoto) or usEnhance;
     5406    uix := UnFocus;
     5407    if MouseLoc <> MyUn[uix].Loc then
     5408      MoveToLoc(MouseLoc, true); { goto }
     5409    if (UnFocus = uix) and (MyUn[uix].Loc = MouseLoc) then
     5410      MenuClick(mEnhance)
     5411  end
     5412  else if (Button = mbLeft) and (ssShift in Shift) and
     5413    (MyMap[MouseLoc] and fTerrain <> fUNKNOWN) then
     5414    HelpOnTerrain(MouseLoc, wmPersistent)
     5415  else if (ClientMode <= cContinue) and (Button = mbRight) and
     5416    (ssShift in Shift) and (UnFocus >= 0) and
     5417    (MyMap[MouseLoc] and (fUnit or fOwned) = fUnit) then
     5418  begin // battle forecast
     5419    with MyUn[UnFocus], BattleDlg.Forecast do
     5420    begin
     5421      pAtt := me;
     5422      mixAtt := mix;
     5423      HealthAtt := Health;
     5424      ExpAtt := Exp;
     5425      FlagsAtt := Flags;
     5426    end;
     5427    BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
     5428    if Server(sGetBattleForecastEx, me, MouseLoc, BattleDlg.Forecast) >= rExecuted
     5429    then
     5430    begin
     5431      BattleDlg.uix := UnFocus;
     5432      BattleDlg.ToLoc := MouseLoc;
     5433      BattleDlg.Left := x - BattleDlg.width div 2;
     5434      if BattleDlg.Left < 0 then
     5435        BattleDlg.Left := 0
     5436      else if BattleDlg.Left + BattleDlg.width > Screen.width then
     5437        BattleDlg.Left := Screen.width - BattleDlg.width;
     5438      BattleDlg.Top := y - BattleDlg.height div 2;
     5439      if BattleDlg.Top < 0 then
     5440        BattleDlg.Top := 0
     5441      else if BattleDlg.Top + BattleDlg.height > Screen.height then
     5442        BattleDlg.Top := Screen.height - BattleDlg.height;
     5443      BattleDlg.IsSuicideQuery := false;
     5444      BattleDlg.Show;
     5445    end
     5446  end
     5447end;
     5448
     5449function TMainScreen.MoveUnit(dx, dy: integer; Options: integer): integer;
     5450// move focused unit to adjacent tile
     5451var
     5452  i, cix, uix, euix, FromLoc, ToLoc, DirCode, UnFocus0, Defender, Mission, p1,
     5453    NewTiles, cixChanged: integer;
     5454  OldToTile: Cardinal;
     5455  CityCaptured, IsAttack, OldUnrest, NewUnrest, NeedEcoUpdate, NeedRepaintPanel,
     5456    ToTransport, ToShip: boolean;
     5457  PlaneReturnData: TPlaneReturnData;
     5458  QueryItem: string;
     5459begin
     5460  result := eInvalid;
     5461  UnFocus0 := UnFocus;
     5462  FromLoc := MyUn[UnFocus].Loc;
     5463  ToLoc := dLoc(FromLoc, dx, dy);
     5464  if (ToLoc < 0) or (ToLoc >= G.lx * G.ly) then
     5465  begin
     5466    result := eInvalid;
     5467    exit;
    54635468  end;
    5464 
    5465   function TMainScreen.MoveUnit(dx, dy: integer; Options: integer): integer;
    5466   // move focused unit to adjacent tile
    5467   var
    5468     i, cix, uix, euix, FromLoc, ToLoc, DirCode, UnFocus0, Defender, Mission, p1,
    5469       NewTiles, cixChanged: integer;
    5470     OldToTile: Cardinal;
    5471     CityCaptured, IsAttack, OldUnrest, NewUnrest, NeedEcoUpdate,
    5472       NeedRepaintPanel, ToTransport, ToShip: boolean;
    5473     PlaneReturnData: TPlaneReturnData;
    5474     QueryItem: string;
    5475   begin
    5476     result := eInvalid;
    5477     UnFocus0 := UnFocus;
    5478     FromLoc := MyUn[UnFocus].Loc;
    5479     ToLoc := dLoc(FromLoc, dx, dy);
    5480     if (ToLoc < 0) or (ToLoc >= G.lx * G.ly) then
     5469  if MyMap[ToLoc] and fStealthUnit <> 0 then
     5470  begin
     5471    SoundMessage(Phrases.Lookup('ATTACKSTEALTH'), '');
     5472    exit;
     5473  end;
     5474  if MyMap[ToLoc] and fHiddenUnit <> 0 then
     5475  begin
     5476    SoundMessage(Phrases.Lookup('ATTACKSUB'), '');
     5477    exit;
     5478  end;
     5479
     5480  if MyMap[ToLoc] and (fUnit or fOwned) = fUnit then
     5481  begin // attack -- search enemy unit
     5482    if (MyModel[MyUn[UnFocus].mix].Attack = 0) and
     5483      not((MyModel[MyUn[UnFocus].mix].Cap[mcBombs] > 0) and
     5484      (MyUn[UnFocus].Flags and unBombsLoaded <> 0)) then
     5485    begin
     5486      SoundMessage(Phrases.Lookup('NOATTACKER'), '');
     5487      exit;
     5488    end;
     5489    euix := MyRO.nEnemyUn - 1;
     5490    while (euix >= 0) and (MyRO.EnemyUn[euix].Loc <> ToLoc) do
     5491      dec(euix);
     5492  end;
     5493
     5494  DirCode := dx and 7 shl 4 + dy and 7 shl 7;
     5495  result := Server(sMoveUnit - sExecute + DirCode, me, UnFocus, nil^);
     5496  if (result < rExecuted) and (MyUn[UnFocus].Job > jNone) then
     5497    Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
     5498  if (result < rExecuted) and (result <> eNoTime_Move) then
     5499  begin
     5500    case result of
     5501      eNoTime_Load:
     5502        if MyModel[MyUn[UnFocus].mix].Domain = dAir then
     5503          SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
     5504        else
     5505          SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
     5506            [MovementToString(MyModel[MyUn[UnFocus].mix].speed)]),
     5507            'NOMOVE_TIME');
     5508      eNoTime_Bombard:
     5509        SoundMessage(Phrases.Lookup('NOTIMEBOMBARD'), 'NOMOVE_TIME');
     5510      eNoTime_Expel:
     5511        SoundMessage(Phrases.Lookup('NOTIMEEXPEL'), 'NOMOVE_TIME');
     5512      eNoRoad:
     5513        SoundMessage(Phrases.Lookup('NOROAD'), 'NOMOVE_DEFAULT');
     5514      eNoNav:
     5515        SoundMessage(Phrases.Lookup('NONAV'), 'NOMOVE_DEFAULT');
     5516      eNoCapturer:
     5517        SoundMessage(Phrases.Lookup('NOCAPTURER'), 'NOMOVE_DEFAULT');
     5518      eNoBombarder:
     5519        SoundMessage(Phrases.Lookup('NOBOMBARDER'), 'NOMOVE_DEFAULT');
     5520      eZOC:
     5521        ContextMessage(Phrases.Lookup('ZOC'), 'NOMOVE_ZOC', hkText,
     5522          HelpDlg.TextIndex('MOVEMENT'));
     5523      eTreaty:
     5524        if MyMap[ToLoc] and (fUnit or fOwned) <> fUnit
     5525        then { no enemy unit -- move }
     5526          SoundMessage(Tribe[MyRO.Territory[ToLoc]].TPhrase('PEACE_NOMOVE'),
     5527            'NOMOVE_TREATY')
     5528        else
     5529          SoundMessage(Tribe[MyRO.EnemyUn[euix].Owner]
     5530            .TPhrase('PEACE_NOATTACK'), 'NOMOVE_TREATY');
     5531      eDomainMismatch:
     5532        begin
     5533          if (MyModel[MyUn[UnFocus].mix].Domain < dSea) and
     5534            (MyMap[ToLoc] and (fUnit or fOwned) = fUnit or fOwned) then
     5535          begin // false load attempt
     5536            ToShip := false;
     5537            ToTransport := false;
     5538            for uix := 0 to MyRO.nUn - 1 do
     5539              if (MyUn[uix].Loc = ToLoc) and
     5540                (MyModel[MyUn[uix].mix].Domain = dSea) then
     5541              begin
     5542                ToShip := true;
     5543                if MyModel[MyUn[uix].mix].Cap[mcSeaTrans] > 0 then
     5544                  ToTransport := true;
     5545              end;
     5546            if ToTransport then
     5547              SoundMessage(Phrases.Lookup('FULLTRANSPORT'), 'NOMOVE_DEFAULT')
     5548            else if ToShip then
     5549              SoundMessage(Phrases.Lookup('NOTRANSPORT'), 'NOMOVE_DEFAULT')
     5550            else
     5551              Play('NOMOVE_DOMAIN');
     5552          end
     5553          else
     5554            Play('NOMOVE_DOMAIN');
     5555        end
     5556    else
     5557      Play('NOMOVE_DEFAULT');
     5558    end;
     5559    exit;
     5560  end;
     5561
     5562  if ((result = eWon) or (result = eLost) or (result = eBloody)) and
     5563    (MyUn[UnFocus].Movement < 100) and
     5564    (MyModel[MyUn[UnFocus].mix].Cap[mcWill] = 0) then
     5565  begin
     5566    if SimpleQuery(mkYesNo, Format(Phrases.Lookup('FASTATTACK'),
     5567      [MyUn[UnFocus].Movement]), 'NOMOVE_TIME') <> mrOK then
    54815568    begin
    54825569      result := eInvalid;
    54835570      exit;
    54845571    end;
    5485     if MyMap[ToLoc] and fStealthUnit <> 0 then
    5486     begin
    5487       SoundMessage(Phrases.Lookup('ATTACKSTEALTH'), '');
    5488       exit;
    5489     end;
    5490     if MyMap[ToLoc] and fHiddenUnit <> 0 then
    5491     begin
    5492       SoundMessage(Phrases.Lookup('ATTACKSUB'), '');
    5493       exit;
    5494     end;
    5495 
    5496     if MyMap[ToLoc] and (fUnit or fOwned) = fUnit then
    5497     begin // attack -- search enemy unit
    5498       if (MyModel[MyUn[UnFocus].mix].Attack = 0) and
    5499         not((MyModel[MyUn[UnFocus].mix].Cap[mcBombs] > 0) and
    5500         (MyUn[UnFocus].Flags and unBombsLoaded <> 0)) then
    5501       begin
    5502         SoundMessage(Phrases.Lookup('NOATTACKER'), '');
    5503         exit;
    5504       end;
    5505       euix := MyRO.nEnemyUn - 1;
    5506       while (euix >= 0) and (MyRO.EnemyUn[euix].Loc <> ToLoc) do
    5507         dec(euix);
    5508     end;
    5509 
    5510     DirCode := dx and 7 shl 4 + dy and 7 shl 7;
    5511     result := Server(sMoveUnit - sExecute + DirCode, me, UnFocus, nil^);
    5512     if (result < rExecuted) and (MyUn[UnFocus].Job > jNone) then
    5513       Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
    5514     if (result < rExecuted) and (result <> eNoTime_Move) then
    5515     begin
    5516       case result of
    5517         eNoTime_Load:
    5518           if MyModel[MyUn[UnFocus].mix].Domain = dAir then
    5519             SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
    5520           else
    5521             SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
    5522               [MovementToString(MyModel[MyUn[UnFocus].mix].speed)]),
    5523               'NOMOVE_TIME');
    5524         eNoTime_Bombard:
    5525           SoundMessage(Phrases.Lookup('NOTIMEBOMBARD'), 'NOMOVE_TIME');
    5526         eNoTime_Expel:
    5527           SoundMessage(Phrases.Lookup('NOTIMEEXPEL'), 'NOMOVE_TIME');
    5528         eNoRoad:
    5529           SoundMessage(Phrases.Lookup('NOROAD'), 'NOMOVE_DEFAULT');
    5530         eNoNav:
    5531           SoundMessage(Phrases.Lookup('NONAV'), 'NOMOVE_DEFAULT');
    5532         eNoCapturer:
    5533           SoundMessage(Phrases.Lookup('NOCAPTURER'), 'NOMOVE_DEFAULT');
    5534         eNoBombarder:
    5535           SoundMessage(Phrases.Lookup('NOBOMBARDER'), 'NOMOVE_DEFAULT');
    5536         eZOC:
    5537           ContextMessage(Phrases.Lookup('ZOC'), 'NOMOVE_ZOC', hkText,
    5538             HelpDlg.TextIndex('MOVEMENT'));
    5539         eTreaty:
    5540           if MyMap[ToLoc] and (fUnit or fOwned) <> fUnit
    5541           then { no enemy unit -- move }
    5542             SoundMessage(Tribe[MyRO.Territory[ToLoc]].TPhrase('PEACE_NOMOVE'),
    5543               'NOMOVE_TREATY')
    5544           else
    5545             SoundMessage(Tribe[MyRO.EnemyUn[euix].Owner]
    5546               .TPhrase('PEACE_NOATTACK'), 'NOMOVE_TREATY');
    5547         eDomainMismatch:
    5548           begin
    5549             if (MyModel[MyUn[UnFocus].mix].Domain < dSea) and
    5550               (MyMap[ToLoc] and (fUnit or fOwned) = fUnit or fOwned) then
    5551             begin // false load attempt
    5552               ToShip := false;
    5553               ToTransport := false;
    5554               for uix := 0 to MyRO.nUn - 1 do
    5555                 if (MyUn[uix].Loc = ToLoc) and
    5556                   (MyModel[MyUn[uix].mix].Domain = dSea) then
    5557                 begin
    5558                   ToShip := true;
    5559                   if MyModel[MyUn[uix].mix].Cap[mcSeaTrans] > 0 then
    5560                     ToTransport := true;
    5561                 end;
    5562               if ToTransport then
    5563                 SoundMessage(Phrases.Lookup('FULLTRANSPORT'), 'NOMOVE_DEFAULT')
    5564               else if ToShip then
    5565                 SoundMessage(Phrases.Lookup('NOTRANSPORT'), 'NOMOVE_DEFAULT')
    5566               else
    5567                 Play('NOMOVE_DOMAIN');
    5568             end
    5569             else
    5570               Play('NOMOVE_DOMAIN');
    5571           end
     5572    Update; // remove message box from screen
     5573  end;
     5574
     5575  OldUnrest := false;
     5576  NewUnrest := false;
     5577  if (result >= rExecuted) and (result and rUnitRemoved = 0) and
     5578    (MyMap[ToLoc] and (fUnit or fOwned) <> fUnit) then
     5579  begin
     5580    OldUnrest := UnrestAtLoc(UnFocus, FromLoc);
     5581    NewUnrest := UnrestAtLoc(UnFocus, ToLoc);
     5582    if NewUnrest > OldUnrest then
     5583    begin
     5584      if MyRO.Government = gDemocracy then
     5585      begin
     5586        QueryItem := 'UNREST_NOTOWN';
     5587        p1 := me;
     5588      end
    55725589      else
    5573         Play('NOMOVE_DEFAULT');
    5574       end;
    5575       exit;
    5576     end;
    5577 
    5578     if ((result = eWon) or (result = eLost) or (result = eBloody)) and
    5579       (MyUn[UnFocus].Movement < 100) and
    5580       (MyModel[MyUn[UnFocus].mix].Cap[mcWill] = 0) then
    5581     begin
    5582       if SimpleQuery(mkYesNo, Format(Phrases.Lookup('FASTATTACK'),
    5583         [MyUn[UnFocus].Movement]), 'NOMOVE_TIME') <> mrOK then
    5584       begin
    5585         result := eInvalid;
    5586         exit;
    5587       end;
    5588       Update; // remove message box from screen
    5589     end;
    5590 
    5591     OldUnrest := false;
    5592     NewUnrest := false;
    5593     if (result >= rExecuted) and (result and rUnitRemoved = 0) and
    5594       (MyMap[ToLoc] and (fUnit or fOwned) <> fUnit) then
    5595     begin
    5596       OldUnrest := UnrestAtLoc(UnFocus, FromLoc);
    5597       NewUnrest := UnrestAtLoc(UnFocus, ToLoc);
    5598       if NewUnrest > OldUnrest then
    5599       begin
    5600         if MyRO.Government = gDemocracy then
    5601         begin
    5602           QueryItem := 'UNREST_NOTOWN';
    5603           p1 := me;
    5604         end
    5605         else
    5606         begin
    5607           QueryItem := 'UNREST_FOREIGN';
    5608           p1 := MyRO.Territory[ToLoc];
    5609         end;
    5610         with MessgExDlg do
    5611         begin
    5612           MessgText := Format(Tribe[p1].TPhrase(QueryItem),
    5613             [Phrases.Lookup('GOVERNMENT', MyRO.Government)]);
    5614           Kind := mkYesNo;
    5615           IconKind := mikImp;
    5616           IconIndex := imPalace;
    5617           ShowModal;
    5618           if ModalResult <> mrOK then
    5619           begin
    5620             result := eInvalid;
    5621             exit;
    5622           end;
    5623         end;
    5624         Update; // remove message box from screen
    5625       end
    5626     end;
    5627 
    5628     if (result >= rExecuted) and (MyModel[MyUn[UnFocus].mix].Domain = dAir) and
    5629       (MyUn[UnFocus].Status and usToldNoReturn = 0) then
    5630     begin // can plane return?
    5631       PlaneReturnData.Fuel := MyUn[UnFocus].Fuel;
    5632       if (MyMap[ToLoc] and (fUnit or fOwned) = fUnit) or
    5633         (MyMap[ToLoc] and (fCity or fOwned) = fCity) then
    5634       begin // attack/expel/bombard -> 100MP
    5635         PlaneReturnData.Loc := FromLoc;
    5636         PlaneReturnData.Movement := MyUn[UnFocus].Movement - 100;
    5637         if PlaneReturnData.Movement < 0 then
    5638           PlaneReturnData.Movement := 0;
    5639       end
    5640       else // move
    5641       begin
    5642         PlaneReturnData.Loc := ToLoc;
    5643         if dx and 1 <> 0 then
    5644           PlaneReturnData.Movement := MyUn[UnFocus].Movement - 100
    5645         else
    5646           PlaneReturnData.Movement := MyUn[UnFocus].Movement - 150;
    5647       end;
    5648       if Server(sGetPlaneReturn, me, UnFocus, PlaneReturnData) = eNoWay then
    5649       begin
    5650         if MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_Glider then
    5651           QueryItem := 'LOWFUEL_GLIDER'
    5652         else
    5653           QueryItem := 'LOWFUEL';
    5654         if SimpleQuery(mkYesNo, Phrases.Lookup(QueryItem), 'WARNING_LOWSUPPORT')
    5655           <> mrOK then
     5590      begin
     5591        QueryItem := 'UNREST_FOREIGN';
     5592        p1 := MyRO.Territory[ToLoc];
     5593      end;
     5594      with MessgExDlg do
     5595      begin
     5596        MessgText := Format(Tribe[p1].TPhrase(QueryItem),
     5597          [Phrases.Lookup('GOVERNMENT', MyRO.Government)]);
     5598        Kind := mkYesNo;
     5599        IconKind := mikImp;
     5600        IconIndex := imPalace;
     5601        ShowModal;
     5602        if ModalResult <> mrOK then
    56565603        begin
    56575604          result := eInvalid;
    56585605          exit;
    56595606        end;
    5660         Update; // remove message box from screen
    5661         MyUn[UnFocus].Status := MyUn[UnFocus].Status or usToldNoReturn;
     5607      end;
     5608      Update; // remove message box from screen
     5609    end
     5610  end;
     5611
     5612  if (result >= rExecuted) and (MyModel[MyUn[UnFocus].mix].Domain = dAir) and
     5613    (MyUn[UnFocus].Status and usToldNoReturn = 0) then
     5614  begin // can plane return?
     5615    PlaneReturnData.Fuel := MyUn[UnFocus].Fuel;
     5616    if (MyMap[ToLoc] and (fUnit or fOwned) = fUnit) or
     5617      (MyMap[ToLoc] and (fCity or fOwned) = fCity) then
     5618    begin // attack/expel/bombard -> 100MP
     5619      PlaneReturnData.Loc := FromLoc;
     5620      PlaneReturnData.Movement := MyUn[UnFocus].Movement - 100;
     5621      if PlaneReturnData.Movement < 0 then
     5622        PlaneReturnData.Movement := 0;
     5623    end
     5624    else // move
     5625    begin
     5626      PlaneReturnData.Loc := ToLoc;
     5627      if dx and 1 <> 0 then
     5628        PlaneReturnData.Movement := MyUn[UnFocus].Movement - 100
     5629      else
     5630        PlaneReturnData.Movement := MyUn[UnFocus].Movement - 150;
     5631    end;
     5632    if Server(sGetPlaneReturn, me, UnFocus, PlaneReturnData) = eNoWay then
     5633    begin
     5634      if MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_Glider then
     5635        QueryItem := 'LOWFUEL_GLIDER'
     5636      else
     5637        QueryItem := 'LOWFUEL';
     5638      if SimpleQuery(mkYesNo, Phrases.Lookup(QueryItem), 'WARNING_LOWSUPPORT')
     5639        <> mrOK then
     5640      begin
     5641        result := eInvalid;
     5642        exit;
     5643      end;
     5644      Update; // remove message box from screen
     5645      MyUn[UnFocus].Status := MyUn[UnFocus].Status or usToldNoReturn;
     5646    end
     5647  end;
     5648
     5649  if result = eMissionDone then
     5650  begin
     5651    ModalSelectDlg.ShowNewContent(wmModal, kMission);
     5652    Update; // dialog still on screen
     5653    Mission := ModalSelectDlg.result;
     5654    if Mission < 0 then
     5655      exit;
     5656    Server(sSetSpyMission + Mission shl 4, me, 0, nil^);
     5657  end;
     5658
     5659  CityCaptured := false;
     5660  if result = eNoTime_Move then
     5661    Play('NOMOVE_TIME')
     5662  else
     5663  begin
     5664    NeedEcoUpdate := false;
     5665    DestinationMarkON := false;
     5666    PaintDestination;
     5667    if result and rUnitRemoved <> 0 then
     5668      CityOptimizer_BeforeRemoveUnit(UnFocus);
     5669    IsAttack := (result = eBombarded) or (result <> eMissionDone) and
     5670      (MyMap[ToLoc] and (fUnit or fOwned) = fUnit);
     5671    if not IsAttack then
     5672    begin // move
     5673      cix := MyRO.nCity - 1; { look for own city at dest location }
     5674      while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
     5675        dec(cix);
     5676      if (result <> eMissionDone) and (MyMap[ToLoc] and fCity <> 0) and (cix < 0)
     5677      then
     5678        CityCaptured := true;
     5679      result := Server(sMoveUnit + DirCode, me, UnFocus, nil^);
     5680      case result of
     5681        eHiddenUnit:
     5682          begin
     5683            Play('NOMOVE_SUBMARINE');
     5684            PaintLoc(ToLoc)
     5685          end;
     5686        eStealthUnit:
     5687          begin
     5688            Play('NOMOVE_STEALTH');
     5689            PaintLoc(ToLoc)
     5690          end;
     5691        eZOC_EnemySpotted:
     5692          begin
     5693            Play('NOMOVE_ZOC');
     5694            PaintLoc(ToLoc, 1)
     5695          end;
     5696        rExecuted .. maxint:
     5697          begin
     5698            if result and rUnitRemoved <> 0 then
     5699              UnFocus := -1 // unit died
     5700            else
     5701            begin
     5702              assert(UnFocus >= 0);
     5703              MyUn[UnFocus].Status := MyUn[UnFocus].Status and
     5704                not(usStay or usRecover);
     5705              for uix := 0 to MyRO.nUn - 1 do
     5706                if MyUn[uix].Master = UnFocus then
     5707                  MyUn[uix].Status := MyUn[uix].Status and not usWaiting;
     5708              if CityCaptured and
     5709                (MyRO.Government in [gRepublic, gDemocracy, gFuture]) then
     5710              begin // borders have moved, unrest might have changed in any city
     5711                CityOptimizer_BeginOfTurn;
     5712                NeedEcoUpdate := true;
     5713              end
     5714              else
     5715              begin
     5716                if OldUnrest <> NewUnrest then
     5717                begin
     5718                  CityOptimizer_CityChange(MyUn[UnFocus].Home);
     5719                  for uix := 0 to MyRO.nUn - 1 do
     5720                    if MyUn[uix].Master = UnFocus then
     5721                      CityOptimizer_CityChange(MyUn[uix].Home);
     5722                  NeedEcoUpdate := true;
     5723                end;
     5724                if (MyRO.Government = gDespotism) and
     5725                  (MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_TownGuard) then
     5726                begin
     5727                  if MyMap[FromLoc] and fCity <> 0 then
     5728                  begin // town guard moved out of city in despotism -- reoptimize!
     5729                    cixChanged := MyRO.nCity - 1;
     5730                    while (cixChanged >= 0) and
     5731                      (MyCity[cixChanged].Loc <> FromLoc) do
     5732                      dec(cixChanged);
     5733                    assert(cixChanged >= 0);
     5734                    if cixChanged >= 0 then
     5735                    begin
     5736                      CityOptimizer_CityChange(cixChanged);
     5737                      NeedEcoUpdate := true;
     5738                    end;
     5739                  end;
     5740                  if (MyMap[ToLoc] and fCity <> 0) and not CityCaptured then
     5741                  begin // town guard moved into city in despotism -- reoptimize!
     5742                    cixChanged := MyRO.nCity - 1;
     5743                    while (cixChanged >= 0) and
     5744                      (MyCity[cixChanged].Loc <> ToLoc) do
     5745                      dec(cixChanged);
     5746                    assert(cixChanged >= 0);
     5747                    if cixChanged >= 0 then
     5748                    begin
     5749                      CityOptimizer_CityChange(cixChanged);
     5750                      NeedEcoUpdate := true;
     5751                    end;
     5752                  end;
     5753                end;
     5754              end;
     5755            end;
     5756          end;
     5757      else
     5758        assert(false);
     5759      end;
     5760      SetTroopLoc(ToLoc);
     5761    end
     5762    else
     5763    begin { enemy unit -- attack }
     5764      if result = eBombarded then
     5765        Defender := MyRO.Territory[ToLoc]
     5766      else
     5767        Defender := MyRO.EnemyUn[euix].Owner;
     5768      { if MyRO.Treaty[Defender]=trCeaseFire then
     5769        if SimpleQuery(mkYesNo,Phrases.Lookup('FRCANCELQUERY_CEASEFIRE'),
     5770        'MSG_DEFAULT')<>mrOK then
     5771        exit; }
     5772      if (Options and muNoSuicideCheck = 0) and (result and rUnitRemoved <> 0)
     5773        and (result <> eMissionDone) then
     5774      begin // suicide query
     5775        with MyUn[UnFocus], BattleDlg.Forecast do
     5776        begin
     5777          pAtt := me;
     5778          mixAtt := mix;
     5779          HealthAtt := Health;
     5780          ExpAtt := Exp;
     5781          FlagsAtt := Flags;
     5782        end;
     5783        BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
     5784        Server(sGetBattleForecastEx, me, ToLoc, BattleDlg.Forecast);
     5785        BattleDlg.uix := UnFocus;
     5786        BattleDlg.ToLoc := ToLoc;
     5787        BattleDlg.IsSuicideQuery := true;
     5788        BattleDlg.ShowModal;
     5789        if BattleDlg.ModalResult <> mrOK then
     5790          exit;
     5791      end;
     5792
     5793      cixChanged := -1;
     5794      if (result and rUnitRemoved <> 0) and (MyRO.Government = gDespotism) and
     5795        (MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_TownGuard) and
     5796        (MyMap[FromLoc] and fCity <> 0) then
     5797      begin // town guard died in city in despotism -- reoptimize!
     5798        cixChanged := MyRO.nCity - 1;
     5799        while (cixChanged >= 0) and (MyCity[cixChanged].Loc <> FromLoc) do
     5800          dec(cixChanged);
     5801        assert(cixChanged >= 0);
     5802      end;
     5803
     5804      for i := 0 to MyRO.nEnemyModel - 1 do
     5805        LostArmy[i] := MyRO.EnemyModel[i].Lost;
     5806      OldToTile := MyMap[ToLoc];
     5807      result := Server(sMoveUnit + DirCode, me, UnFocus, nil^);
     5808      nLostArmy := 0;
     5809      for i := 0 to MyRO.nEnemyModel - 1 do
     5810      begin
     5811        LostArmy[i] := MyRO.EnemyModel[i].Lost - LostArmy[i];
     5812        inc(nLostArmy, LostArmy[i])
     5813      end;
     5814      if result and rUnitRemoved <> 0 then
     5815      begin
     5816        UnFocus := -1;
     5817        SetTroopLoc(FromLoc);
     5818      end;
     5819      if (OldToTile and not MyMap[ToLoc] and fCity <> 0) and
     5820        (MyRO.Government in [gRepublic, gDemocracy, gFuture]) then
     5821      begin // city was destroyed, borders have moved, unrest might have changed in any city
     5822        CityOptimizer_BeginOfTurn;
     5823        NeedEcoUpdate := true;
     5824      end
     5825      else
     5826      begin
     5827        if cixChanged >= 0 then
     5828        begin
     5829          CityOptimizer_CityChange(cixChanged);
     5830          NeedEcoUpdate := true;
     5831        end;
     5832        if (result = eWon) or (result = eBloody) or (result = eExpelled) then
     5833        begin
     5834          CityOptimizer_TileBecomesAvailable(ToLoc);
     5835          NeedEcoUpdate := true;
     5836        end;
     5837      end;
     5838      if nLostArmy > 1 then
     5839      begin
     5840        with MessgExDlg do
     5841        begin
     5842          Kind := mkOk;
     5843          IconKind := mikEnemyArmy;
     5844          MessgText := Tribe[Defender].TString(Phrases.Lookup('ARMYLOST',
     5845            MyRO.EnemyModel[MyRO.EnemyUn[euix].emix].Domain));
     5846          ShowModal;
     5847        end
    56625848      end
    56635849    end;
    5664 
    5665     if result = eMissionDone then
    5666     begin
    5667       ModalSelectDlg.ShowNewContent(wmModal, kMission);
    5668       Update; // dialog still on screen
    5669       Mission := ModalSelectDlg.result;
    5670       if Mission < 0 then
    5671         exit;
    5672       Server(sSetSpyMission + Mission shl 4, me, 0, nil^);
     5850    if result and rUnitRemoved <> 0 then
     5851    begin
     5852      CityOptimizer_AfterRemoveUnit;
     5853      ListDlg.RemoveUnit;
     5854      NeedEcoUpdate := true;
    56735855    end;
    5674 
    5675     CityCaptured := false;
    5676     if result = eNoTime_Move then
    5677       Play('NOMOVE_TIME')
     5856    if NeedEcoUpdate then
     5857    begin
     5858      UpdateViews(true);
     5859      Update
     5860    end
     5861  end;
     5862
     5863  if result = eMissionDone then
     5864  begin
     5865    p1 := MyRO.Territory[ToLoc];
     5866    case Mission of
     5867      smStealMap:
     5868        begin
     5869          MapValid := false;
     5870          PaintAllMaps
     5871        end;
     5872      smStealCivilReport:
     5873        TribeMessage(p1, Tribe[p1].TPhrase('DOSSIER_PREPARED'), '');
     5874      smStealMilReport:
     5875        ListDlg.ShowNewContent_MilReport(wmPersistent, p1);
     5876    end;
     5877  end;
     5878
     5879  if UnFocus >= 0 then
     5880    CheckToldNoReturn(UnFocus);
     5881
     5882  NeedRepaintPanel := false;
     5883  if result >= rExecuted then
     5884  begin
     5885    if CityCaptured and (MyMap[ToLoc] and fCity = 0) then
     5886    begin // city destroyed
     5887      for i := 0 to 27 do { tell about destroyed wonders }
     5888        if (MyRO.Wonder[i].CityID = -2) and (MyData.ToldWonders[i].CityID <> -2)
     5889        then
     5890          with MessgExDlg do
     5891          begin
     5892            if WondersDlg.Visible then
     5893              WondersDlg.SmartUpdateContent(false);
     5894            OpenSound := 'WONDER_DESTROYED';
     5895            MessgText := Format(Phrases.Lookup('WONDERDEST'),
     5896              [Phrases.Lookup('IMPROVEMENTS', i)]);
     5897            Kind := mkOkHelp;
     5898            HelpKind := hkImp;
     5899            HelpNo := i;
     5900            IconKind := mikImp;
     5901            IconIndex := i;
     5902            ShowModal;
     5903            MyData.ToldWonders[i] := MyRO.Wonder[i];
     5904          end
     5905    end;
     5906    if CityCaptured and (MyMap[ToLoc] and fCity <> 0) then
     5907    begin // city captured
     5908      ListDlg.AddCity;
     5909      for i := 0 to 27 do { tell about capture of wonders }
     5910        if MyRO.City[MyRO.nCity - 1].Built[i] > 0 then
     5911          with MessgExDlg do
     5912          begin
     5913            if WondersDlg.Visible then
     5914              WondersDlg.SmartUpdateContent(false);
     5915            OpenSound := 'WONDER_CAPTURED';
     5916            MessgText := Format(Tribe[me].TPhrase('WONDERCAPTOWN'),
     5917              [Phrases.Lookup('IMPROVEMENTS', i)]);
     5918            Kind := mkOkHelp;
     5919            HelpKind := hkImp;
     5920            HelpNo := i;
     5921            IconKind := mikImp;
     5922            IconIndex := i;
     5923            ShowModal;
     5924            MyData.ToldWonders[i] := MyRO.Wonder[i];
     5925          end;
     5926
     5927      if MyRO.Happened and phStealTech <> 0 then
     5928      begin { Temple of Zeus -- choose advance to steal }
     5929        ModalSelectDlg.ShowNewContent(wmModal, kStealTech);
     5930        Server(sStealTech, me, ModalSelectDlg.result, nil^);
     5931      end;
     5932      TellNewModels;
     5933
     5934      cix := MyRO.nCity - 1;
     5935      while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
     5936        dec(cix);
     5937      assert(cix >= 0);
     5938      MyCity[cix].Status := MyCity[cix].Status and not csResourceWeightsMask or
     5939        (3 shl 4);
     5940      // captured city, set to maximum growth
     5941      NewTiles := 1 shl 13; { exploit central tile only }
     5942      Server(sSetCityTiles, me, cix, NewTiles);
     5943    end
    56785944    else
    5679     begin
    5680       NeedEcoUpdate := false;
     5945      NeedRepaintPanel := true;
     5946  end;
     5947  TellNewContacts;
     5948
     5949  if (UnFocus >= 0) and (MyUn[UnFocus].Master >= 0) then
     5950    with MyUn[MyUn[UnFocus].Master] do
     5951      if Status and usStay <> 0 then
     5952      begin
     5953        Status := Status and not usStay;
     5954        if (Movement >= 100) and (Status and (usRecover or usGoto) = 0) then
     5955          Status := Status or usWaiting;
     5956      end;
     5957  if Options and (muAutoNoWait or muAutoNext) <> 0 then
     5958  begin
     5959    if (UnFocus >= 0) and ((result = eNoTime_Move) or UnitExhausted(UnFocus) or
     5960      (MyUn[UnFocus].Master >= 0) or (MyModel[MyUn[UnFocus].mix].Domain = dAir)
     5961      and ((MyMap[MyUn[UnFocus].Loc] and fCity <> 0)
     5962      { aircrafts stop in cities }
     5963      or (MyMap[MyUn[UnFocus].Loc] and fTerImp = tiBase))) then
     5964    begin
     5965      MyUn[UnFocus].Status := MyUn[UnFocus].Status and not usWaiting;
     5966      if Options and muAutoNext <> 0 then
     5967        if CityCaptured and (MyMap[ToLoc] and fCity <> 0) then
     5968        begin
     5969          UnFocus := -1;
     5970          PaintLoc(ToLoc); // don't show unit in city if not selected
     5971        end
     5972        else
     5973          NextUnit(UnStartLoc, true)
     5974    end
     5975    else if (UnFocus < 0) and (Options and muAutoNext <> 0) then
     5976      NextUnit(UnStartLoc, result <> eMissionDone);
     5977  end;
     5978
     5979  if NeedRepaintPanel and (UnFocus = UnFocus0) then
     5980    if IsAttack then
     5981      PanelPaint
     5982    else
     5983    begin
     5984      assert(result <> eMissionDone);
     5985      CheckTerrainBtnVisible;
     5986      FocusOnLoc(ToLoc, flRepaintPanel or flImmUpdate)
     5987    end;
     5988
     5989  if (result >= rExecuted) and CityCaptured and (MyMap[ToLoc] and fCity <> 0)
     5990  then
     5991    ZoomToCity(ToLoc, UnFocus < 0, chCaptured); // show captured city
     5992end; // moveunit
     5993
     5994procedure TMainScreen.MoveOnScreen(ShowMove: TShowMove;
     5995  Step0, Step1, nStep: integer; Restore: boolean = true);
     5996var
     5997  ToLoc, xFromLoc, yFromLoc, xToLoc, yToLoc, xFrom, yFrom, xTo, yTo, xMin, yMin,
     5998    xRange, yRange, xw1, Step, xMoving, yMoving, yl, SliceCount: integer;
     5999  UnitInfo: TUnitInfo;
     6000  Ticks0, Ticks: TDateTime;
     6001begin
     6002  Timer1.Enabled := false;
     6003  Ticks0 := NowPrecise;
     6004  with ShowMove do
     6005  begin
     6006    UnitInfo.Owner := Owner;
     6007    UnitInfo.mix := mix;
     6008    UnitInfo.Health := Health;
     6009    UnitInfo.Job := jNone;
     6010    UnitInfo.Flags := Flags;
     6011    if Owner <> me then
     6012      UnitInfo.emix := emix;
     6013
     6014    ToLoc := dLoc(FromLoc, dx, dy);
     6015    xToLoc := ToLoc mod G.lx;
     6016    yToLoc := ToLoc div G.lx;
     6017    xFromLoc := FromLoc mod G.lx;
     6018    yFromLoc := FromLoc div G.lx;
     6019    if xToLoc > xFromLoc + 2 then
     6020      xToLoc := xToLoc - G.lx
     6021    else if xToLoc < xFromLoc - 2 then
     6022      xToLoc := xToLoc + G.lx;
     6023
     6024    xw1 := xw + G.lx;
     6025    // ((xFromLoc-xw1)*2+yFromLoc and 1+1)*xxt+dx*xxt/2-MapWidth/2 -> min
     6026    while abs(((xFromLoc - xw1 + G.lx) * 2 + yFromLoc and 1 + 1) * xxt * 2 + dx
     6027      * xxt - MapWidth) < abs(((xFromLoc - xw1) * 2 + yFromLoc and 1 + 1) * xxt
     6028      * 2 + dx * xxt - MapWidth) do
     6029      dec(xw1, G.lx);
     6030
     6031    xTo := (xToLoc - xw1) * (xxt * 2) + yToLoc and 1 * xxt + (xxt - xxu);
     6032    yTo := (yToLoc - yw) * yyt + (yyt - yyu_anchor);
     6033    xFrom := (xFromLoc - xw1) * (xxt * 2) + yFromLoc and 1 * xxt + (xxt - xxu);
     6034    yFrom := (yFromLoc - yw) * yyt + (yyt - yyu_anchor);
     6035    if xFrom < xTo then
     6036    begin
     6037      xMin := xFrom;
     6038      xRange := xTo - xFrom
     6039    end
     6040    else
     6041    begin
     6042      xMin := xTo;
     6043      xRange := xFrom - xTo
     6044    end;
     6045    if yFrom < yTo then
     6046    begin
     6047      yMin := yFrom;
     6048      yRange := yTo - yFrom
     6049    end
     6050    else
     6051    begin
     6052      yMin := yTo;
     6053      yRange := yFrom - yTo
     6054    end;
     6055    inc(xRange, xxt * 2);
     6056    inc(yRange, yyt * 3);
     6057
     6058    MainOffscreenPaint;
     6059    NoMap.SetOutput(Buffer);
     6060    NoMap.SetPaintBounds(0, 0, xRange, yRange);
     6061    for Step := 0 to abs(Step1 - Step0) do
     6062    begin
     6063      BitBlt(Buffer.Canvas.Handle, 0, 0, xRange, yRange,
     6064        offscreen.Canvas.Handle, xMin, yMin, SRCCOPY);
     6065      if Step1 <> Step0 then
     6066      begin
     6067        xMoving := xFrom +
     6068          Round((Step0 + Step * (Step1 - Step0) div abs(Step1 - Step0)) *
     6069          (xTo - xFrom) / nStep);
     6070        yMoving := yFrom +
     6071          Round((Step0 + Step * (Step1 - Step0) div abs(Step1 - Step0)) *
     6072          (yTo - yFrom) / nStep);
     6073      end
     6074      else
     6075      begin
     6076        xMoving := xFrom;
     6077        yMoving := yFrom;
     6078      end;
     6079      NoMap.PaintUnit(xMoving - xMin, yMoving - yMin, UnitInfo, 0);
     6080      PaintBufferToScreen(xMin, yMin, xRange, yRange);
     6081
     6082      SliceCount := 0;
     6083      Ticks := Ticks0;
     6084      repeat
     6085        if (SliceCount = 0) or
     6086          (MillisecondOf(Ticks - Ticks0) * 12 * (SliceCount + 1) div SliceCount
     6087          < MoveTime) then
     6088        begin
     6089          if not idle or (GameMode = cMovie) then
     6090            Application.ProcessMessages;
     6091          Sleep(1);
     6092          inc(SliceCount)
     6093        end;
     6094        Ticks := NowPrecise;
     6095      until (Ticks - Ticks0) / OneMillisecond * 12 >= MoveTime;
     6096      Ticks0 := Ticks
     6097    end;
     6098  end;
     6099  if Restore then
     6100  begin
     6101    BitBlt(Buffer.Canvas.Handle, 0, 0, xRange, yRange, offscreen.Canvas.Handle,
     6102      xMin, yMin, SRCCOPY);
     6103    PaintBufferToScreen(xMin, yMin, xRange, yRange);
     6104  end;
     6105  BlinkTime := -1;
     6106  Timer1.Enabled := true;
     6107end;
     6108
     6109procedure TMainScreen.MoveToLoc(Loc: integer; CheckSuicide: boolean);
     6110// path finder: move focused unit to loc, start multi-turn goto if too far
     6111var
     6112  uix, i, MoveOptions, NextLoc, MoveResult: integer;
     6113  MoveAdviceData: TMoveAdviceData;
     6114  StopReason: (None, Arrived, Dead, NoTime, EnemySpotted, MoveError);
     6115begin
     6116  if MyUn[UnFocus].Job > jNone then
     6117    Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
     6118  if GetMoveAdvice(UnFocus, Loc, MoveAdviceData) >= rExecuted then
     6119  begin
     6120    uix := UnFocus;
     6121    StopReason := None;
     6122    repeat
     6123      for i := 0 to MoveAdviceData.nStep - 1 do
     6124      begin
     6125        if i = MoveAdviceData.nStep - 1 then
     6126          MoveOptions := muAutoNext
     6127        else
     6128          MoveOptions := 0;
     6129        NextLoc := dLoc(MyUn[uix].Loc, MoveAdviceData.dx[i],
     6130          MoveAdviceData.dy[i]);
     6131        if (NextLoc = Loc) or (Loc = maNextCity) and
     6132          (MyMap[NextLoc] and fCity <> 0) then
     6133          StopReason := Arrived;
     6134        if not CheckSuicide and (NextLoc = Loc) then
     6135          MoveOptions := MoveOptions or muNoSuicideCheck;
     6136        MoveResult := MoveUnit(MoveAdviceData.dx[i], MoveAdviceData.dy[i],
     6137          MoveOptions);
     6138        if MoveResult < rExecuted then
     6139          StopReason := MoveError
     6140        else if MoveResult and rUnitRemoved <> 0 then
     6141          StopReason := Dead
     6142        else if (StopReason = None) and (MoveResult and rEnemySpotted <> 0) then
     6143          StopReason := EnemySpotted;
     6144        if StopReason <> None then
     6145          Break;
     6146      end;
     6147      if (StopReason = None) and ((MoveAdviceData.nStep < 25) or
     6148        (MyRO.Wonder[woShinkansen].EffectiveOwner <> me)) then
     6149        StopReason := NoTime;
     6150      if StopReason <> None then
     6151        Break;
     6152      if GetMoveAdvice(UnFocus, Loc, MoveAdviceData) < rExecuted then
     6153      begin
     6154        assert(false);
     6155        Break
     6156      end;
     6157    until false;
     6158
     6159    case StopReason of
     6160      None:
     6161        assert(false);
     6162      Arrived:
     6163        MyUn[uix].Status := MyUn[uix].Status and ($FFFF - usGoto);
     6164      Dead:
     6165        if UnFocus < 0 then
     6166          NextUnit(UnStartLoc, false);
     6167    else
     6168      begin // multi-turn goto
     6169        if Loc = maNextCity then
     6170          MyUn[uix].Status := MyUn[uix].Status and ($FFFF - usStay - usRecover)
     6171            or usGoto + $7FFF shl 16
     6172        else
     6173          MyUn[uix].Status := MyUn[uix].Status and ($FFFF - usStay - usRecover)
     6174            or usGoto + Loc shl 16;
     6175        PaintLoc(MyUn[uix].Loc);
     6176        if (StopReason = NoTime) and (UnFocus = uix) then
     6177        begin
     6178          MyUn[uix].Status := MyUn[uix].Status and not usWaiting;
     6179          NextUnit(UnStartLoc, true)
     6180        end;
     6181      end
     6182    end
     6183  end
     6184end;
     6185
     6186procedure TMainScreen.PanelBoxMouseDown(Sender: TObject; Button: TMouseButton;
     6187  Shift: TShiftState; x, y: integer);
     6188var
     6189  i, xMouse, MouseLoc, p1: integer;
     6190begin
     6191  if GameMode = cMovie then
     6192    exit;
     6193
     6194  if Button = mbLeft then
     6195  begin
     6196    if (x >= xMini + 2) and (y >= yMini + 2) and (x < xMini + 2 + 2 * G.lx) and
     6197      (y < yMini + 2 + G.ly) then
     6198      if ssShift in Shift then
     6199      begin
     6200        xMouse := (xwMini + (x - (xMini + 2) + MapWidth div (xxt * 2) + G.lx)
     6201          div 2) mod G.lx;
     6202        MouseLoc := xMouse + G.lx * (y - (yMini + 2));
     6203        if MyMap[MouseLoc] and fTerrain <> fUNKNOWN then
     6204        begin
     6205          p1 := MyRO.Territory[MouseLoc];
     6206          if (p1 = me) or (p1 >= 0) and (MyRO.Treaty[p1] >= trNone) then
     6207            NatStatDlg.ShowNewContent(wmPersistent, p1);
     6208        end
     6209      end
     6210      else
     6211      begin
     6212        if CityDlg.Visible then
     6213          CityDlg.Close;
     6214        if UnitStatDlg.Visible then
     6215          UnitStatDlg.Close;
     6216        Tracking := true;
     6217        PanelBoxMouseMove(Sender, Shift + [ssLeft], x, y);
     6218      end
     6219    else if (ClientMode <> cEditMap) and (x >= ClientWidth - xPalace) and
     6220      (y >= yPalace) and (x < ClientWidth - xPalace + xSizeBig) and
     6221      (y < yPalace + ySizeBig) then
     6222    begin
     6223      InitPopup(StatPopup);
     6224      if FullScreen then
     6225        StatPopup.Popup(Left + ClientWidth - xPalace + xSizeBig + 2,
     6226          Top + ClientHeight - PanelHeight + yPalace - 1)
     6227      else
     6228        StatPopup.Popup(Left + ClientWidth - xPalace + 6,
     6229          Top + ClientHeight - PanelHeight + yPalace + ySizeBig +
     6230          GetSystemMetrics(SM_CYCAPTION) + 3)
     6231    end
     6232    (* else if (x>=xAdvisor-3) and (y>=yAdvisor-3)
     6233      and (x<xAdvisor+16+3) and (y<yAdvisor+16+3) and HaveStrategyAdvice then
     6234      AdviceBtnClick *)
     6235    else if (x >= xTroop + 1) and (y >= yTroop + 1) and
     6236      (x < xTroop + TrRow * TrPitch) and (y <= yTroop + 55) then
     6237    begin
     6238      i := (x - xTroop - 1) div TrPitch;
     6239      if trix[i] >= 0 then
     6240        if ClientMode = cEditMap then
     6241        begin
     6242          BrushType := trix[i];
     6243          PanelPaint
     6244        end
     6245        else if (TroopLoc >= 0) then
     6246          if MyMap[TroopLoc] and fOwned <> 0 then
     6247          begin
     6248            if ssShift in Shift then
     6249              UnitStatDlg.ShowNewContent_OwnModel(wmPersistent,
     6250                MyUn[trix[i]].mix)
     6251            else if not supervising and (ClientMode < scContact) and
     6252              (x - xTroop - 1 - i * TrPitch >= 60 - 20) and (y >= yTroop + 35)
     6253              and ((MyUn[trix[i]].Job > jNone) or (MyUn[trix[i]].Status and
     6254              (usStay or usRecover or usGoto) <> 0)) then
     6255            begin // wake up
     6256              MyUn[trix[i]].Status := MyUn[trix[i]].Status and
     6257                ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
     6258              if MyUn[trix[i]].Job > jNone then
     6259                Server(sStartJob + jNone shl 4, me, trix[i], nil^);
     6260              if (UnFocus < 0) and not CityDlg.Visible then
     6261              begin
     6262                SetUnFocus(trix[i]);
     6263                SetTroopLoc(MyUn[trix[i]].Loc);
     6264                FocusOnLoc(TroopLoc, flRepaintPanel)
     6265              end
     6266              else
     6267              begin
     6268                if CityDlg.Visible and (CityDlg.RestoreUnFocus < 0) then
     6269                  CityDlg.RestoreUnFocus := trix[i];
     6270                PanelPaint;
     6271              end
     6272            end
     6273            else if (ClientMode < scContact) then
     6274            begin
     6275              if supervising then
     6276                UnitStatDlg.ShowNewContent_OwnUnit(wmPersistent, trix[i])
     6277              else if CityDlg.Visible then
     6278              begin
     6279                CityDlg.CloseAction := None;
     6280                CityDlg.Close;
     6281                SumCities(TaxSum, ScienceSum);
     6282                SetUnFocus(trix[i]);
     6283              end
     6284              else
     6285              begin
     6286                DestinationMarkON := false;
     6287                PaintDestination;
     6288                UnFocus := trix[i];
     6289                UnStartLoc := TroopLoc;
     6290                BlinkTime := 0;
     6291                BlinkON := false;
     6292                PaintLoc(TroopLoc);
     6293              end;
     6294              if UnFocus >= 0 then
     6295              begin
     6296                UnitInfoBtn.Visible := true;
     6297                UnitBtn.Visible := true;
     6298                TurnComplete := false;
     6299                EOT.ButtonIndex := eotGray;
     6300              end;
     6301              CheckTerrainBtnVisible;
     6302              PanelPaint;
     6303            end
     6304          end
     6305          else if Server(sGetUnits, me, TroopLoc, TrCnt) >= rExecuted then
     6306            if ssShift in Shift then
     6307              UnitStatDlg.ShowNewContent_EnemyModel(wmPersistent,
     6308                MyRO.EnemyUn[MyRO.nEnemyUn + trix[i]].emix) // model info
     6309            else
     6310              UnitStatDlg.ShowNewContent_EnemyUnit(wmPersistent,
     6311                MyRO.nEnemyUn + trix[i]); // unit info
     6312    end
     6313  end
     6314end;
     6315
     6316procedure TMainScreen.SetTroopLoc(Loc: integer);
     6317var
     6318  trixFocus, uix, uixDefender: integer;
     6319  Prio: boolean;
     6320begin
     6321  TroopLoc := Loc;
     6322  TrRow := (xRightPanel + 10 - xTroop - GetSystemMetrics(SM_CXVSCROLL) - 19)
     6323    div TrPitch;
     6324  TrCnt := 0;
     6325  trixFocus := -1;
     6326  if ClientMode = cEditMap then
     6327    TrCnt := nBrushTypes
     6328  else if (Loc >= 0) and (MyMap[Loc] and fUnit <> 0) then
     6329    if MyMap[Loc] and fOwned <> 0 then
     6330    begin // count own units here
     6331      Server(sGetDefender, me, TroopLoc, uixDefender);
     6332      for Prio := true downto false do
     6333        for uix := 0 to MyRO.nUn - 1 do
     6334          if ((uix = uixDefender) = Prio) and (MyUn[uix].Loc = Loc) then
     6335          begin
     6336            if uix = UnFocus then
     6337              trixFocus := TrCnt;
     6338            inc(TrCnt);
     6339          end
     6340    end
     6341    else // count enemy units here
     6342      Server(sGetUnits, me, Loc, TrCnt);
     6343  if TrCnt = 0 then
     6344    InitPVSB(sb, 0, 1)
     6345  else
     6346  begin
     6347    InitPVSB(sb, (TrCnt + TrRow - 1) div TrRow - 1, 1);
     6348    with sb.si do
     6349      if (nMax >= integer(nPage)) and (trixFocus >= 0) then
     6350      begin
     6351        sb.si.npos := trixFocus div TrRow;
     6352        sb.si.FMask := SIF_POS;
     6353        SetScrollInfo(sb.h, SB_CTL, sb.si, true);
     6354      end
     6355  end
     6356end;
     6357
     6358(* procedure TMainScreen.ShowMoveHint(ToLoc: integer; Force: boolean = false);
     6359  var
     6360  Step,Loc,x0,y0,xs,ys: integer;
     6361  Info: string;
     6362  InfoSize: TSize;
     6363  MoveAdvice: TMoveAdviceData;
     6364  begin
     6365  if (ToLoc<0) or (ToLoc>=G.lx*G.ly)
     6366  or (UnFocus<0) or (MyUn[UnFocus].Loc=ToLoc) then
     6367  ToLoc:=-1
     6368  else
     6369  begin
     6370  MoveAdvice.ToLoc:=ToLoc;
     6371  MoveAdvice.MoreTurns:=0;
     6372  MoveAdvice.MaxHostile_MovementLeft:=MyUn[UnFocus].Health-50;
     6373  if Server(sGetMoveAdvice,me,UnFocus,MoveAdvice)<rExecuted then
     6374  ToLoc:=-1
     6375  end;
     6376  if (ToLoc=MoveHintToLoc) and not Force then exit;
     6377  if (ToLoc<>MoveHintToLoc) and (MoveHintToLoc>=0) then
     6378  begin invalidate; update end; // clear old hint from screen
     6379  MoveHintToLoc:=ToLoc;
     6380  if ToLoc<0 then exit;
     6381
     6382  with canvas do
     6383  begin
     6384  Pen.Color:=$80C0FF;
     6385  Pen.Width:=3;
     6386  Loc:=MyUn[UnFocus].Loc;
     6387  for Step:=0 to MoveAdvice.nStep do
     6388  begin
     6389  y0:=(Loc+G.lx*1024) div G.lx -1024;
     6390  x0:=(Loc+(y0 and 1+G.lx*1024) div 2) mod G.lx;
     6391  xs:=(x0-xw)*66+y0 and 1*33-G.lx*66;
     6392  while abs(2*(xs+G.lx*66)-MapWidth)<abs(2*xs-MapWidth) do
     6393  inc(xs,G.lx*66);
     6394  ys:=(y0-yw)*16;
     6395  if Step=0 then moveto(xs+33,ys+16)
     6396  else lineto(xs+33,ys+16);
     6397  if Step<MoveAdvice.nStep then
     6398  Loc:=dLoc(Loc,MoveAdvice.dx[Step],MoveAdvice.dy[Step]);
     6399  end;
     6400  Brush.Color:=$80C0FF;
     6401  Info:=' '+inttostr(88)+' ';
     6402  InfoSize:=TextExtent(Info);
     6403  TextOut(xs+33-InfoSize.cx div 2, ys+16-InfoSize.cy div 2, Info);
     6404  Brush.Style:=bsClear;
     6405  end
     6406  end; *)
     6407
     6408procedure TMainScreen.SetDebugMap(p: integer);
     6409begin
     6410  IsoEngine.pDebugMap := p;
     6411  IsoEngine.Options := IsoEngine.Options and not(1 shl moLocCodes);
     6412  mLocCodes.Checked := false;
     6413  MapValid := false;
     6414  MainOffscreenPaint;
     6415end;
     6416
     6417procedure TMainScreen.SetViewpoint(p: integer);
     6418var
     6419  i: integer;
     6420begin
     6421  if supervising and (G.RO[0].Turn > 0) and
     6422    ((p = 0) or (1 shl p and G.RO[0].Alive <> 0)) then
     6423  begin
     6424    for i := 0 to Screen.FormCount - 1 do
     6425      if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
     6426        Screen.Forms[i].Close; // close windows
     6427    ItsMeAgain(p);
     6428    SumCities(TaxSum, ScienceSum);
     6429    for i := 0 to MyRO.nModel - 1 do
     6430      if Tribe[me].ModelPicture[i].HGr = 0 then
     6431        InitMyModel(i, true);
     6432
     6433    SetTroopLoc(-1);
     6434    PanelPaint;
     6435    MapValid := false;
     6436    PaintAllMaps;
     6437  end
     6438end;
     6439
     6440procedure TMainScreen.FormKeyDown(Sender: TObject; var Key: word;
     6441  Shift: TShiftState);
     6442
     6443  procedure MenuClick_Check(Popup: TPopupMenu; Item: TMenuItem);
     6444  begin
     6445    InitPopup(Popup);
     6446    if Item.Visible and Item.Enabled then
     6447      MenuClick(Item);
     6448  end;
     6449
     6450var
     6451  dx, dy: integer;
     6452  time0, time1: TDateTime;
     6453begin
     6454  if GameMode = cMovie then
     6455  begin
     6456    case Key of
     6457      VK_F4:
     6458        MenuClick_Check(StatPopup, mScienceStat);
     6459      VK_F6:
     6460        MenuClick_Check(StatPopup, mDiagram);
     6461      VK_F7:
     6462        MenuClick_Check(StatPopup, mWonders);
     6463      VK_F8:
     6464        MenuClick_Check(StatPopup, mShips);
     6465    end;
     6466    exit;
     6467  end;
     6468
     6469  if not idle then
     6470    exit;
     6471
     6472  if ClientMode = cEditMap then
     6473  begin
     6474    if Shift = [ssCtrl] then
     6475      case char(Key) of
     6476        (* 'A':
     6477          begin // auto symmetry
     6478          Server($7F0,me,0,nil^);
     6479          MapValid:=false;
     6480          PaintAll;
     6481          end;
     6482          'B':
     6483          begin // land mass
     6484          dy:=0;
     6485          for dx:=G.lx to G.lx*(G.ly-1)-1 do
     6486          if MyMap[dx] and fTerrain>=fGrass then inc(dy);
     6487          dy:=dy
     6488          end; *)
     6489        'Q':
     6490          MenuClick(mResign);
     6491        'R':
     6492          MenuClick(mRandomMap);
     6493      end
     6494    else if Shift = [] then
     6495      case char(Key) of
     6496        char(VK_F1):
     6497          MenuClick(mHelp);
     6498      end;
     6499    exit;
     6500  end;
     6501
     6502  if Shift = [ssAlt] then
     6503    case char(Key) of
     6504      '0':
     6505        SetDebugMap(-1);
     6506      '1' .. '9':
     6507        SetDebugMap(ord(Key) - 48);
     6508    end
     6509  else if Shift = [ssCtrl] then
     6510    case char(Key) of
     6511      'J':
     6512        MenuClick(mJump);
     6513      'K':
     6514        mShowClick(mDebugMap);
     6515      'L':
     6516        mShowClick(mLocCodes);
     6517      'M':
     6518        if LogDlg.Visible then
     6519          LogDlg.Close
     6520        else
     6521          LogDlg.Show;
     6522      'N':
     6523        mNamesClick(mNames);
     6524      'Q':
     6525        MenuClick_Check(GamePopup, mResign);
     6526      'R':
     6527        MenuClick(mRun);
     6528      '0' .. '9':
     6529        begin
     6530          if ord(Key) - 48 = me then
     6531            SetViewpoint(0)
     6532          else
     6533            SetViewpoint(ord(Key) - 48);
     6534        end;
     6535      ' ':
     6536        begin // test map repaint time
     6537          time0 := NowPrecise;
     6538          MapValid := false;
     6539          MainOffscreenPaint;
     6540          time1 := NowPrecise;
     6541          SimpleMessage(Format('Map repaint time: %.3f ms',
     6542            [MillisecondOf(time1 - time0)]));
     6543        end
     6544    end
     6545  else if Shift = [] then
     6546    case char(Key) of
     6547      char(VK_F1):
     6548        MenuClick(mHelp);
     6549      char(VK_F2):
     6550        MenuClick_Check(StatPopup, mUnitStat);
     6551      char(VK_F3):
     6552        MenuClick_Check(StatPopup, mCityStat);
     6553      char(VK_F4):
     6554        MenuClick_Check(StatPopup, mScienceStat);
     6555      char(VK_F5):
     6556        MenuClick_Check(StatPopup, mEUnitStat);
     6557      char(VK_F6):
     6558        MenuClick_Check(StatPopup, mDiagram);
     6559      char(VK_F7):
     6560        MenuClick_Check(StatPopup, mWonders);
     6561      char(VK_F8):
     6562        MenuClick_Check(StatPopup, mShips);
     6563      char(VK_F9):
     6564        MenuClick_Check(StatPopup, mNations);
     6565      char(VK_F10):
     6566        MenuClick_Check(StatPopup, mEmpire);
     6567      char(VK_ADD):
     6568        EndTurn;
     6569      '1':
     6570        MapBtnClick(MapBtn0);
     6571      '2':
     6572        MapBtnClick(MapBtn1);
     6573      '3':
     6574        MapBtnClick(MapBtn4);
     6575      '4':
     6576        MapBtnClick(MapBtn5);
     6577      '5':
     6578        MapBtnClick(MapBtn6);
     6579      'T':
     6580        MenuClick(mTechTree);
     6581      'W':
     6582        MenuClick(mWait);
     6583    end;
     6584
     6585  if UnFocus >= 0 then
     6586    if Shift = [ssCtrl] then
     6587      case char(Key) of
     6588        'C':
     6589          MenuClick_Check(UnitPopup, mCancel);
     6590        'D':
     6591          MenuClick(mDisband);
     6592        'P':
     6593          MenuClick_Check(UnitPopup, mPillage);
     6594        'T':
     6595          MenuClick_Check(UnitPopup, mSelectTransport);
     6596      end
     6597    else if Shift = [] then
     6598      case char(Key) of
     6599        ' ':
     6600          MenuClick(mNoOrders);
     6601        'A':
     6602          MenuClick_Check(TerrainPopup, mAirBase);
     6603        'B':
     6604          MenuClick_Check(UnitPopup, mCity);
     6605        'C':
     6606          MenuClick(mCentre);
     6607        'E':
     6608          begin
     6609            InitPopup(TerrainPopup);
     6610            if mEnhance.Visible and mEnhance.Enabled then
     6611              MenuClick(mEnhance)
     6612            else
     6613              MenuClick(mEnhanceDef)
     6614          end;
     6615        'F':
     6616          MenuClick_Check(TerrainPopup, mFort);
     6617        'G':
     6618          MenuClick_Check(UnitPopup, mGoOn);
     6619        'H':
     6620          MenuClick_Check(UnitPopup, mHome);
     6621        'I':
     6622          if JobTest(UnFocus, jFarm, [eTreaty]) then
     6623            MenuClick(mFarm)
     6624          else if JobTest(UnFocus, jClear, [eTreaty]) then
     6625            MenuClick(mClear)
     6626          else
     6627            MenuClick_Check(TerrainPopup, mIrrigation);
     6628        'L':
     6629          MenuClick_Check(UnitPopup, mLoad);
     6630        'M':
     6631          if JobTest(UnFocus, jAfforest, [eTreaty]) then
     6632            MenuClick(mAfforest)
     6633          else
     6634            MenuClick_Check(TerrainPopup, mMine);
     6635        'N':
     6636          MenuClick_Check(TerrainPopup, mCanal);
     6637        'O':
     6638          MenuClick_Check(TerrainPopup, MTrans);
     6639        'P':
     6640          MenuClick_Check(TerrainPopup, mPollution);
     6641        'R':
     6642          if JobTest(UnFocus, jRR, [eTreaty]) then
     6643            MenuClick(mRR)
     6644          else
     6645            MenuClick_Check(TerrainPopup, mRoad);
     6646        'S':
     6647          MenuClick(mStay);
     6648        'U':
     6649          MenuClick_Check(UnitPopup, mUnload);
     6650        'V':
     6651          MenuClick_Check(UnitPopup, mRecover);
     6652        'Z':
     6653          MenuClick_Check(UnitPopup, mUtilize);
     6654        #33 .. #40, #97 .. #100, #102 .. #105:
     6655          begin { arrow keys }
     6656            DestinationMarkON := false;
     6657            PaintDestination;
     6658            MyUn[UnFocus].Status := MyUn[UnFocus].Status and
     6659              ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
     6660            case Key of
     6661              VK_NUMPAD1, VK_END:
     6662                begin
     6663                  dx := -1;
     6664                  dy := 1
     6665                end;
     6666              VK_NUMPAD2, VK_DOWN:
     6667                begin
     6668                  dx := 0;
     6669                  dy := 2
     6670                end;
     6671              VK_NUMPAD3, VK_NEXT:
     6672                begin
     6673                  dx := 1;
     6674                  dy := 1
     6675                end;
     6676              VK_NUMPAD4, VK_LEFT:
     6677                begin
     6678                  dx := -2;
     6679                  dy := 0
     6680                end;
     6681              VK_NUMPAD6, VK_RIGHT:
     6682                begin
     6683                  dx := 2;
     6684                  dy := 0
     6685                end;
     6686              VK_NUMPAD7, VK_HOME:
     6687                begin
     6688                  dx := -1;
     6689                  dy := -1
     6690                end;
     6691              VK_NUMPAD8, VK_UP:
     6692                begin
     6693                  dx := 0;
     6694                  dy := -2
     6695                end;
     6696              VK_NUMPAD9, VK_PRIOR:
     6697                begin
     6698                  dx := 1;
     6699                  dy := -1
     6700                end;
     6701            end;
     6702            MoveUnit(dx, dy, muAutoNext)
     6703          end;
     6704      end
     6705end;
     6706
     6707procedure TMainScreen.MenuClick(Sender: TObject);
     6708
     6709  function DoJob(j0: integer): integer;
     6710  var
     6711    Loc0, Movement0: integer;
     6712  begin
     6713    with MyUn[UnFocus] do
     6714    begin
    56816715      DestinationMarkON := false;
    56826716      PaintDestination;
    5683       if result and rUnitRemoved <> 0 then
    5684         CityOptimizer_BeforeRemoveUnit(UnFocus);
    5685       IsAttack := (result = eBombarded) or (result <> eMissionDone) and
    5686         (MyMap[ToLoc] and (fUnit or fOwned) = fUnit);
    5687       if not IsAttack then
    5688       begin // move
    5689         cix := MyRO.nCity - 1; { look for own city at dest location }
    5690         while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
    5691           dec(cix);
    5692         if (result <> eMissionDone) and (MyMap[ToLoc] and fCity <> 0) and
    5693           (cix < 0) then
    5694           CityCaptured := true;
    5695         result := Server(sMoveUnit + DirCode, me, UnFocus, nil^);
    5696         case result of
    5697           eHiddenUnit:
    5698             begin
    5699               Play('NOMOVE_SUBMARINE');
    5700               PaintLoc(ToLoc)
    5701             end;
    5702           eStealthUnit:
    5703             begin
    5704               Play('NOMOVE_STEALTH');
    5705               PaintLoc(ToLoc)
    5706             end;
    5707           eZOC_EnemySpotted:
    5708             begin
    5709               Play('NOMOVE_ZOC');
    5710               PaintLoc(ToLoc, 1)
    5711             end;
    5712           rExecuted .. maxint:
    5713             begin
    5714               if result and rUnitRemoved <> 0 then
    5715                 UnFocus := -1 // unit died
    5716               else
    5717               begin
    5718                 assert(UnFocus >= 0);
    5719                 MyUn[UnFocus].Status := MyUn[UnFocus].Status and
    5720                   not(usStay or usRecover);
    5721                 for uix := 0 to MyRO.nUn - 1 do
    5722                   if MyUn[uix].Master = UnFocus then
    5723                     MyUn[uix].Status := MyUn[uix].Status and not usWaiting;
    5724                 if CityCaptured and
    5725                   (MyRO.Government in [gRepublic, gDemocracy, gFuture]) then
    5726                 begin // borders have moved, unrest might have changed in any city
    5727                   CityOptimizer_BeginOfTurn;
    5728                   NeedEcoUpdate := true;
    5729                 end
    5730                 else
    5731                 begin
    5732                   if OldUnrest <> NewUnrest then
    5733                   begin
    5734                     CityOptimizer_CityChange(MyUn[UnFocus].Home);
    5735                     for uix := 0 to MyRO.nUn - 1 do
    5736                       if MyUn[uix].Master = UnFocus then
    5737                         CityOptimizer_CityChange(MyUn[uix].Home);
    5738                     NeedEcoUpdate := true;
    5739                   end;
    5740                   if (MyRO.Government = gDespotism) and
    5741                     (MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_TownGuard) then
    5742                   begin
    5743                     if MyMap[FromLoc] and fCity <> 0 then
    5744                     begin // town guard moved out of city in despotism -- reoptimize!
    5745                       cixChanged := MyRO.nCity - 1;
    5746                       while (cixChanged >= 0) and
    5747                         (MyCity[cixChanged].Loc <> FromLoc) do
    5748                         dec(cixChanged);
    5749                       assert(cixChanged >= 0);
    5750                       if cixChanged >= 0 then
    5751                       begin
    5752                         CityOptimizer_CityChange(cixChanged);
    5753                         NeedEcoUpdate := true;
    5754                       end;
    5755                     end;
    5756                     if (MyMap[ToLoc] and fCity <> 0) and not CityCaptured then
    5757                     begin // town guard moved into city in despotism -- reoptimize!
    5758                       cixChanged := MyRO.nCity - 1;
    5759                       while (cixChanged >= 0) and
    5760                         (MyCity[cixChanged].Loc <> ToLoc) do
    5761                         dec(cixChanged);
    5762                       assert(cixChanged >= 0);
    5763                       if cixChanged >= 0 then
    5764                       begin
    5765                         CityOptimizer_CityChange(cixChanged);
    5766                         NeedEcoUpdate := true;
    5767                       end
    5768                     end
    5769                   end
    5770                 end
    5771               end;
    5772             end;
     6717      Loc0 := Loc;
     6718      Movement0 := Movement;
     6719      if j0 < 0 then
     6720        result := ProcessEnhancement(UnFocus, MyData.EnhancementJobs)
     6721        // terrain enhancement
     6722      else
     6723        result := Server(sStartJob + j0 shl 4, me, UnFocus, nil^);
     6724      if result >= rExecuted then
     6725      begin
     6726        if result = eDied then
     6727          UnFocus := -1;
     6728        PaintLoc(Loc0);
     6729        if UnFocus >= 0 then
     6730        begin
     6731          if (j0 < 0) and (result <> eJobDone) then
     6732            // multi-turn terrain enhancement
     6733            Status := Status and ($FFFF - usStay - usRecover - usGoto) or
     6734              usEnhance
     6735          else
     6736            Status := Status and
     6737              ($FFFF - usStay - usRecover - usGoto - usEnhance);
     6738          if (Job <> jNone) or (Movement0 < 100) then
     6739          begin
     6740            Status := Status and not usWaiting;
     6741            NextUnit(UnStartLoc, true);
     6742          end
     6743          else
     6744            PanelPaint
     6745        end
    57736746        else
    5774           assert(false);
    5775         end;
    5776         SetTroopLoc(ToLoc);
     6747          NextUnit(UnStartLoc, true);
     6748      end
     6749    end;
     6750    case result of
     6751      eNoBridgeBuilding:
     6752        SoundMessage(Phrases.Lookup('NOBB'), 'INVALID');
     6753      eNoCityTerrain:
     6754        SoundMessage(Phrases.Lookup('NOCITY'), 'INVALID');
     6755      eTreaty:
     6756        SoundMessage(Tribe[MyRO.Territory[Loc0]].TPhrase('PEACE_NOWORK'),
     6757          'NOMOVE_TREATY');
     6758    else
     6759      if result < rExecuted then
     6760        Play('INVALID')
     6761    end
     6762  end;
     6763
     6764var
     6765  i, uix, NewFocus, Loc0, OldMaster, Destination, cix, cixOldHome,
     6766    ServerResult: integer;
     6767  AltGovs, Changed: boolean;
     6768  QueryText: string;
     6769
     6770begin
     6771  if Sender = mResign then
     6772    if ClientMode = cEditMap then
     6773    begin
     6774      if Edited then
     6775      begin
     6776        QueryText := Phrases.Lookup('MAP_CLOSE');
     6777        case SimpleQuery(mkYesNoCancel, QueryText, '') of
     6778          mrIgnore:
     6779            Server(sAbandonMap, me, 0, nil^);
     6780          mrOK:
     6781            Server(sSaveMap, me, 0, nil^);
     6782        end
    57776783      end
    57786784      else
    5779       begin { enemy unit -- attack }
    5780         if result = eBombarded then
    5781           Defender := MyRO.Territory[ToLoc]
     6785        Server(sAbandonMap, me, 0, nil^)
     6786    end
     6787    else
     6788    begin
     6789      if Server(sGetGameChanged, 0, 0, nil^) = eOK then
     6790      begin
     6791        QueryText := Phrases.Lookup('RESIGN');
     6792        case SimpleQuery(mkYesNoCancel, QueryText, '') of
     6793          mrIgnore:
     6794            Server(sResign, 0, 0, nil^);
     6795          mrOK:
     6796            Server(sBreak, 0, 0, nil^)
     6797        end
     6798      end
     6799      else
     6800        Server(sResign, 0, 0, nil^)
     6801    end
     6802  else if Sender = mEmpire then
     6803    RatesDlg.ShowNewContent(wmPersistent)
     6804  else if Sender = mRevolution then
     6805  begin
     6806    AltGovs := false;
     6807    for i := 2 to nGov - 1 do
     6808      if (GovPreq[i] <> preNA) and
     6809        ((GovPreq[i] = preNone) or (MyRO.Tech[GovPreq[i]] >= tsApplicable)) then
     6810        AltGovs := true;
     6811
     6812    if not AltGovs then
     6813      SoundMessage(Phrases.Lookup('NOALTGOVS'), 'MSG_DEFAULT')
     6814    else
     6815    begin
     6816      Changed := false;
     6817      if MyRO.Happened and phChangeGov <> 0 then
     6818      begin
     6819        ModalSelectDlg.ShowNewContent(wmModal, kGov);
     6820        if ModalSelectDlg.result >= 0 then
     6821        begin
     6822          Play('NEWGOV');
     6823          Server(sSetGovernment, me, ModalSelectDlg.result, nil^);
     6824          CityOptimizer_BeginOfTurn;
     6825          Changed := true;
     6826        end
     6827      end
     6828      else
     6829      // TODO with MessgExDlg do
     6830      begin // revolution!
     6831        MessgExDlg.MessgText := Tribe[me].TPhrase('REVOLUTION');
     6832        MessgExDlg.Kind := mkYesNo;
     6833        MessgExDlg.IconKind := mikPureIcon;
     6834        MessgExDlg.IconIndex := 72; // anarchy palace
     6835        MessgExDlg.ShowModal;
     6836        if ModalResult = mrOK then
     6837        begin
     6838          Play('REVOLUTION');
     6839          Server(sRevolution, me, 0, nil^);
     6840          Changed := true;
     6841          if NatStatDlg.Visible then
     6842            NatStatDlg.Close;
     6843          if CityDlg.Visible then
     6844            CityDlg.Close;
     6845        end
     6846      end;
     6847      if Changed then
     6848        UpdateViews(true);
     6849    end
     6850  end
     6851  else if Sender = mWebsite then
     6852    OpenURL('http://c-evo.org') { *Převedeno z ShellExecute* }
     6853  else if Sender = mRandomMap then
     6854  begin
     6855    if not Edited or (SimpleQuery(mkYesNo, Phrases.Lookup('MAP_RANDOM'), '')
     6856      = mrOK) then
     6857    begin
     6858      Server(sRandomMap, me, 0, nil^);
     6859      Edited := true;
     6860      MapValid := false;
     6861      PaintAllMaps;
     6862    end
     6863  end
     6864  else if Sender = mJump then
     6865  begin
     6866    if supervising then
     6867      Jump[0] := 20
     6868    else
     6869      Jump[me] := 20;
     6870    EndTurn(true);
     6871  end
     6872  else if Sender = mRun then
     6873  begin
     6874    if supervising then
     6875      Jump[0] := 999999
     6876    else
     6877      Jump[me] := 999999;
     6878    EndTurn(true);
     6879  end
     6880  else if Sender = mEnhanceDef then
     6881  begin
     6882    if UnFocus >= 0 then
     6883      EnhanceDlg.ShowNewContent(wmPersistent,
     6884        MyMap[MyUn[UnFocus].Loc] and fTerrain)
     6885    else
     6886      EnhanceDlg.ShowNewContent(wmPersistent)
     6887  end
     6888  else if Sender = mCityTypes then
     6889    CityTypeDlg.ShowNewContent(wmModal)
     6890    // must be modal because types are not saved before closing
     6891  else if Sender = mUnitStat then
     6892  begin
     6893    if G.Difficulty[me] > 0 then
     6894      ListDlg.ShowNewContent_MilReport(wmPersistent, me)
     6895    else
     6896    begin
     6897      i := 1;
     6898      while (i < nPl) and (1 shl i and MyRO.Alive = 0) do
     6899        inc(i);
     6900      if i < nPl then
     6901        ListDlg.ShowNewContent_MilReport(wmPersistent, i);
     6902    end;
     6903  end
     6904  else if Sender = mEUnitStat then
     6905  begin
     6906    if MyRO.nEnemyModel > 0 then
     6907      ListDlg.ShowNewContent(wmPersistent, kAllEModels);
     6908  end
     6909  else if Sender = mCityStat then
     6910    ListDlg.ShowNewContent(wmPersistent, kCities)
     6911  else if Sender = mScienceStat then
     6912    ListDlg.ShowNewContent(wmPersistent, kScience)
     6913  else if Sender = mNations then
     6914    NatStatDlg.ShowNewContent(wmPersistent)
     6915  else if Sender = mHelp then
     6916    if ClientMode = cEditMap then
     6917      HelpDlg.ShowNewContent(wmPersistent, hkText, HelpDlg.TextIndex('MAPEDIT'))
     6918    else
     6919      HelpDlg.ShowNewContent(wmPersistent, hkMisc, miscMain)
     6920  else if Sender = mTechTree then
     6921    TechTreeDlg.ShowModal
     6922  else if Sender = mWonders then
     6923    WondersDlg.ShowNewContent(wmPersistent)
     6924  else if Sender = mDiagram then
     6925    DiaDlg.ShowNewContent_Charts(wmPersistent)
     6926  else if Sender = mShips then
     6927    DiaDlg.ShowNewContent_Ship(wmPersistent)
     6928  else if Sender = mWait then
     6929  begin
     6930    if UnFocus >= 0 then
     6931    begin
     6932      DestinationMarkON := false;
     6933      PaintDestination;
     6934      MyUn[UnFocus].Status := MyUn[UnFocus].Status and
     6935        ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
     6936    end;
     6937    NextUnit(-1, false);
     6938  end
     6939  else if UnFocus >= 0 then
     6940    with MyUn[UnFocus] do
     6941      if Sender = mGoOn then
     6942      begin
     6943        if Status shr 16 = $7FFF then
     6944          Destination := maNextCity
    57826945        else
    5783           Defender := MyRO.EnemyUn[euix].Owner;
    5784         { if MyRO.Treaty[Defender]=trCeaseFire then
    5785           if SimpleQuery(mkYesNo,Phrases.Lookup('FRCANCELQUERY_CEASEFIRE'),
    5786           'MSG_DEFAULT')<>mrOK then
    5787           exit; }
    5788         if (Options and muNoSuicideCheck = 0) and (result and rUnitRemoved <> 0)
    5789           and (result <> eMissionDone) then
    5790         begin // suicide query
    5791           with MyUn[UnFocus], BattleDlg.Forecast do
     6946          Destination := Status shr 16;
     6947        Status := Status and not(usStay or usRecover) or usWaiting;
     6948        MoveToLoc(Destination, true);
     6949      end
     6950      else if Sender = mHome then
     6951        if MyMap[Loc] and fCity <> 0 then
     6952        begin
     6953          cixOldHome := Home;
     6954          if Server(sSetUnitHome, me, UnFocus, nil^) >= rExecuted then
    57926955          begin
    5793             pAtt := me;
    5794             mixAtt := mix;
    5795             HealthAtt := Health;
    5796             ExpAtt := Exp;
    5797             FlagsAtt := Flags;
    5798           end;
    5799           BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
    5800           Server(sGetBattleForecastEx, me, ToLoc, BattleDlg.Forecast);
    5801           BattleDlg.uix := UnFocus;
    5802           BattleDlg.ToLoc := ToLoc;
    5803           BattleDlg.IsSuicideQuery := true;
    5804           BattleDlg.ShowModal;
    5805           if BattleDlg.ModalResult <> mrOK then
    5806             exit;
    5807         end;
    5808 
    5809         cixChanged := -1;
    5810         if (result and rUnitRemoved <> 0) and (MyRO.Government = gDespotism) and
    5811           (MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_TownGuard) and
    5812           (MyMap[FromLoc] and fCity <> 0) then
    5813         begin // town guard died in city in despotism -- reoptimize!
    5814           cixChanged := MyRO.nCity - 1;
    5815           while (cixChanged >= 0) and (MyCity[cixChanged].Loc <> FromLoc) do
    5816             dec(cixChanged);
    5817           assert(cixChanged >= 0);
    5818         end;
    5819 
    5820         for i := 0 to MyRO.nEnemyModel - 1 do
    5821           LostArmy[i] := MyRO.EnemyModel[i].Lost;
    5822         OldToTile := MyMap[ToLoc];
    5823         result := Server(sMoveUnit + DirCode, me, UnFocus, nil^);
    5824         nLostArmy := 0;
    5825         for i := 0 to MyRO.nEnemyModel - 1 do
    5826         begin
    5827           LostArmy[i] := MyRO.EnemyModel[i].Lost - LostArmy[i];
    5828           inc(nLostArmy, LostArmy[i])
    5829         end;
    5830         if result and rUnitRemoved <> 0 then
    5831         begin
    5832           UnFocus := -1;
    5833           SetTroopLoc(FromLoc);
    5834         end;
    5835         if (OldToTile and not MyMap[ToLoc] and fCity <> 0) and
    5836           (MyRO.Government in [gRepublic, gDemocracy, gFuture]) then
    5837         begin // city was destroyed, borders have moved, unrest might have changed in any city
    5838           CityOptimizer_BeginOfTurn;
    5839           NeedEcoUpdate := true;
     6956            CityOptimizer_CityChange(cixOldHome);
     6957            CityOptimizer_CityChange(Home);
     6958            UpdateViews(true);
     6959          end
     6960          else
     6961            Play('INVALID');
    58406962        end
    58416963        else
    58426964        begin
    5843           if cixChanged >= 0 then
    5844           begin
    5845             CityOptimizer_CityChange(cixChanged);
    5846             NeedEcoUpdate := true;
    5847           end;
    5848           if (result = eWon) or (result = eBloody) or (result = eExpelled) then
    5849           begin
    5850             CityOptimizer_TileBecomesAvailable(ToLoc);
    5851             NeedEcoUpdate := true;
    5852           end;
    5853         end;
    5854         if nLostArmy > 1 then
    5855         begin
    5856           with MessgExDlg do
    5857           begin
    5858             Kind := mkOk;
    5859             IconKind := mikEnemyArmy;
    5860             MessgText := Tribe[Defender].TString(Phrases.Lookup('ARMYLOST',
    5861               MyRO.EnemyModel[MyRO.EnemyUn[euix].emix].Domain));
    5862             ShowModal;
    5863           end
     6965          Status := Status and not(usStay or usRecover or usEnhance);
     6966          MoveToLoc(maNextCity, true)
    58646967        end
    5865       end;
    5866       if result and rUnitRemoved <> 0 then
    5867       begin
    5868         CityOptimizer_AfterRemoveUnit;
    5869         ListDlg.RemoveUnit;
    5870         NeedEcoUpdate := true;
    5871       end;
    5872       if NeedEcoUpdate then
    5873       begin
    5874         UpdateViews(true);
    5875         Update
     6968      else if Sender = mCentre then
     6969      begin
     6970        Centre(Loc);
     6971        PaintAllMaps
    58766972      end
    5877     end;
    5878 
    5879     if result = eMissionDone then
    5880     begin
    5881       p1 := MyRO.Territory[ToLoc];
    5882       case Mission of
    5883         smStealMap:
     6973      else if Sender = mCity then
     6974      begin
     6975        Loc0 := Loc;
     6976        if MyMap[Loc] and fCity = 0 then
     6977        begin // build city
     6978          if DoJob(jCity) = eCity then
    58846979          begin
    58856980            MapValid := false;
    5886             PaintAllMaps
    5887           end;
    5888         smStealCivilReport:
    5889           TribeMessage(p1, Tribe[p1].TPhrase('DOSSIER_PREPARED'), '');
    5890         smStealMilReport:
    5891           ListDlg.ShowNewContent_MilReport(wmPersistent, p1);
    5892       end;
    5893     end;
    5894 
    5895     if UnFocus >= 0 then
    5896       CheckToldNoReturn(UnFocus);
    5897 
    5898     NeedRepaintPanel := false;
    5899     if result >= rExecuted then
    5900     begin
    5901       if CityCaptured and (MyMap[ToLoc] and fCity = 0) then
    5902       begin // city destroyed
    5903         for i := 0 to 27 do { tell about destroyed wonders }
    5904           if (MyRO.Wonder[i].CityID = -2) and
    5905             (MyData.ToldWonders[i].CityID <> -2) then
    5906             with MessgExDlg do
    5907             begin
    5908               if WondersDlg.Visible then
    5909                 WondersDlg.SmartUpdateContent(false);
    5910               OpenSound := 'WONDER_DESTROYED';
    5911               MessgText := Format(Phrases.Lookup('WONDERDEST'),
    5912                 [Phrases.Lookup('IMPROVEMENTS', i)]);
    5913               Kind := mkOkHelp;
    5914               HelpKind := hkImp;
    5915               HelpNo := i;
    5916               IconKind := mikImp;
    5917               IconIndex := i;
    5918               ShowModal;
    5919               MyData.ToldWonders[i] := MyRO.Wonder[i];
    5920             end
    5921       end;
    5922       if CityCaptured and (MyMap[ToLoc] and fCity <> 0) then
    5923       begin // city captured
    5924         ListDlg.AddCity;
    5925         for i := 0 to 27 do { tell about capture of wonders }
    5926           if MyRO.City[MyRO.nCity - 1].Built[i] > 0 then
    5927             with MessgExDlg do
    5928             begin
    5929               if WondersDlg.Visible then
    5930                 WondersDlg.SmartUpdateContent(false);
    5931               OpenSound := 'WONDER_CAPTURED';
    5932               MessgText := Format(Tribe[me].TPhrase('WONDERCAPTOWN'),
    5933                 [Phrases.Lookup('IMPROVEMENTS', i)]);
    5934               Kind := mkOkHelp;
    5935               HelpKind := hkImp;
    5936               HelpNo := i;
    5937               IconKind := mikImp;
    5938               IconIndex := i;
    5939               ShowModal;
    5940               MyData.ToldWonders[i] := MyRO.Wonder[i];
    5941             end;
    5942 
    5943         if MyRO.Happened and phStealTech <> 0 then
    5944         begin { Temple of Zeus -- choose advance to steal }
    5945           ModalSelectDlg.ShowNewContent(wmModal, kStealTech);
    5946           Server(sStealTech, me, ModalSelectDlg.result, nil^);
    5947         end;
    5948         TellNewModels;
    5949 
    5950         cix := MyRO.nCity - 1;
    5951         while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
    5952           dec(cix);
    5953         assert(cix >= 0);
    5954         MyCity[cix].Status := MyCity[cix].Status and
    5955           not csResourceWeightsMask or (3 shl 4);
    5956         // captured city, set to maximum growth
    5957         NewTiles := 1 shl 13; { exploit central tile only }
    5958         Server(sSetCityTiles, me, cix, NewTiles);
    5959       end
    5960       else
    5961         NeedRepaintPanel := true;
    5962     end;
    5963     TellNewContacts;
    5964 
    5965     if (UnFocus >= 0) and (MyUn[UnFocus].Master >= 0) then
    5966       with MyUn[MyUn[UnFocus].Master] do
    5967         if Status and usStay <> 0 then
    5968         begin
    5969           Status := Status and not usStay;
    5970           if (Movement >= 100) and (Status and (usRecover or usGoto) = 0) then
    5971             Status := Status or usWaiting;
    5972         end;
    5973     if Options and (muAutoNoWait or muAutoNext) <> 0 then
    5974     begin
    5975       if (UnFocus >= 0) and ((result = eNoTime_Move) or UnitExhausted(UnFocus)
    5976         or (MyUn[UnFocus].Master >= 0) or
    5977         (MyModel[MyUn[UnFocus].mix].Domain = dAir) and
    5978         ((MyMap[MyUn[UnFocus].Loc] and fCity <> 0) { aircrafts stop in cities }
    5979         or (MyMap[MyUn[UnFocus].Loc] and fTerImp = tiBase))) then
    5980       begin
    5981         MyUn[UnFocus].Status := MyUn[UnFocus].Status and not usWaiting;
    5982         if Options and muAutoNext <> 0 then
    5983           if CityCaptured and (MyMap[ToLoc] and fCity <> 0) then
    5984           begin
    5985             UnFocus := -1;
    5986             PaintLoc(ToLoc); // don't show unit in city if not selected
     6981            PaintAll;
     6982            ZoomToCity(Loc0, true, chFounded);
    59876983          end
    5988           else
    5989             NextUnit(UnStartLoc, true)
    5990       end
    5991       else if (UnFocus < 0) and (Options and muAutoNext <> 0) then
    5992         NextUnit(UnStartLoc, result <> eMissionDone);
    5993     end;
    5994 
    5995     if NeedRepaintPanel and (UnFocus = UnFocus0) then
    5996       if IsAttack then
    5997         PanelPaint
    5998       else
    5999       begin
    6000         assert(result <> eMissionDone);
    6001         CheckTerrainBtnVisible;
    6002         FocusOnLoc(ToLoc, flRepaintPanel or flImmUpdate)
    6003       end;
    6004 
    6005     if (result >= rExecuted) and CityCaptured and (MyMap[ToLoc] and fCity <> 0)
    6006     then
    6007       ZoomToCity(ToLoc, UnFocus < 0, chCaptured); // show captured city
    6008   end; // moveunit
    6009 
    6010   procedure TMainScreen.MoveOnScreen(ShowMove: TShowMove;
    6011     Step0, Step1, nStep: integer; Restore: boolean = true);
    6012   var
    6013     ToLoc, xFromLoc, yFromLoc, xToLoc, yToLoc, xFrom, yFrom, xTo, yTo, xMin,
    6014       yMin, xRange, yRange, xw1, Step, xMoving, yMoving, yl,
    6015       SliceCount: integer;
    6016     UnitInfo: TUnitInfo;
    6017     Ticks0, Ticks: TDateTime;
    6018   begin
    6019     Timer1.Enabled := false;
    6020     Ticks0 := NowPrecise;
    6021     with ShowMove do
    6022     begin
    6023       UnitInfo.Owner := Owner;
    6024       UnitInfo.mix := mix;
    6025       UnitInfo.Health := Health;
    6026       UnitInfo.Job := jNone;
    6027       UnitInfo.Flags := Flags;
    6028       if Owner <> me then
    6029         UnitInfo.emix := emix;
    6030 
    6031       ToLoc := dLoc(FromLoc, dx, dy);
    6032       xToLoc := ToLoc mod G.lx;
    6033       yToLoc := ToLoc div G.lx;
    6034       xFromLoc := FromLoc mod G.lx;
    6035       yFromLoc := FromLoc div G.lx;
    6036       if xToLoc > xFromLoc + 2 then
    6037         xToLoc := xToLoc - G.lx
    6038       else if xToLoc < xFromLoc - 2 then
    6039         xToLoc := xToLoc + G.lx;
    6040 
    6041       xw1 := xw + G.lx;
    6042       // ((xFromLoc-xw1)*2+yFromLoc and 1+1)*xxt+dx*xxt/2-MapWidth/2 -> min
    6043       while abs(((xFromLoc - xw1 + G.lx) * 2 + yFromLoc and 1 + 1) * xxt * 2 +
    6044         dx * xxt - MapWidth) < abs(((xFromLoc - xw1) * 2 + yFromLoc and 1 + 1) *
    6045         xxt * 2 + dx * xxt - MapWidth) do
    6046         dec(xw1, G.lx);
    6047 
    6048       xTo := (xToLoc - xw1) * (xxt * 2) + yToLoc and 1 * xxt + (xxt - xxu);
    6049       yTo := (yToLoc - yw) * yyt + (yyt - yyu_anchor);
    6050       xFrom := (xFromLoc - xw1) * (xxt * 2) + yFromLoc and 1 * xxt +
    6051         (xxt - xxu);
    6052       yFrom := (yFromLoc - yw) * yyt + (yyt - yyu_anchor);
    6053       if xFrom < xTo then
    6054       begin
    6055         xMin := xFrom;
    6056         xRange := xTo - xFrom
    6057       end
    6058       else
    6059       begin
    6060         xMin := xTo;
    6061         xRange := xFrom - xTo
    6062       end;
    6063       if yFrom < yTo then
    6064       begin
    6065         yMin := yFrom;
    6066         yRange := yTo - yFrom
    6067       end
    6068       else
    6069       begin
    6070         yMin := yTo;
    6071         yRange := yFrom - yTo
    6072       end;
    6073       inc(xRange, xxt * 2);
    6074       inc(yRange, yyt * 3);
    6075 
    6076       MainOffscreenPaint;
    6077       NoMap.SetOutput(Buffer);
    6078       NoMap.SetPaintBounds(0, 0, xRange, yRange);
    6079       for Step := 0 to abs(Step1 - Step0) do
    6080       begin
    6081         BitBlt(Buffer.Canvas.Handle, 0, 0, xRange, yRange,
    6082           offscreen.Canvas.Handle, xMin, yMin, SRCCOPY);
    6083         if Step1 <> Step0 then
    6084         begin
    6085           xMoving := xFrom +
    6086             Round((Step0 + Step * (Step1 - Step0) div abs(Step1 - Step0)) *
    6087             (xTo - xFrom) / nStep);
    6088           yMoving := yFrom +
    6089             Round((Step0 + Step * (Step1 - Step0) div abs(Step1 - Step0)) *
    6090             (yTo - yFrom) / nStep);
    60916984        end
    60926985        else
    60936986        begin
    6094           xMoving := xFrom;
    6095           yMoving := yFrom;
    6096         end;
    6097         NoMap.PaintUnit(xMoving - xMin, yMoving - yMin, UnitInfo, 0);
    6098         PaintBufferToScreen(xMin, yMin, xRange, yRange);
    6099 
    6100         SliceCount := 0;
    6101         Ticks := Ticks0;
    6102         repeat
    6103           if (SliceCount = 0) or (MillisecondOf(Ticks - Ticks0) * 12 * (SliceCount + 1)
    6104             div SliceCount < MoveTime) then
     6987          CityOptimizer_BeforeRemoveUnit(UnFocus);
     6988          ServerResult := Server(sAddToCity, me, UnFocus, nil^);
     6989          if ServerResult >= rExecuted then
    61056990          begin
    6106             if not idle or (GameMode = cMovie) then
    6107               Application.ProcessMessages;
    6108             Sleep(1);
    6109             inc(SliceCount)
    6110           end;
    6111           Ticks := NowPrecise;
    6112         until (Ticks - Ticks0) / OneMillisecond * 12 >= MoveTime;
    6113         Ticks0 := Ticks
    6114       end;
    6115     end;
    6116     if Restore then
    6117     begin
    6118       BitBlt(Buffer.Canvas.Handle, 0, 0, xRange, yRange,
    6119         offscreen.Canvas.Handle, xMin, yMin, SRCCOPY);
    6120       PaintBufferToScreen(xMin, yMin, xRange, yRange);
    6121     end;
    6122     BlinkTime := -1;
    6123     Timer1.Enabled := true;
    6124   end;
    6125 
    6126   procedure TMainScreen.MoveToLoc(Loc: integer; CheckSuicide: boolean);
    6127   // path finder: move focused unit to loc, start multi-turn goto if too far
    6128   var
    6129     uix, i, MoveOptions, NextLoc, MoveResult: integer;
    6130     MoveAdviceData: TMoveAdviceData;
    6131     StopReason: (None, Arrived, Dead, NoTime, EnemySpotted, MoveError);
    6132   begin
    6133     if MyUn[UnFocus].Job > jNone then
    6134       Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
    6135     if GetMoveAdvice(UnFocus, Loc, MoveAdviceData) >= rExecuted then
    6136     begin
    6137       uix := UnFocus;
    6138       StopReason := None;
    6139       repeat
    6140         for i := 0 to MoveAdviceData.nStep - 1 do
    6141         begin
    6142           if i = MoveAdviceData.nStep - 1 then
    6143             MoveOptions := muAutoNext
    6144           else
    6145             MoveOptions := 0;
    6146           NextLoc := dLoc(MyUn[uix].Loc, MoveAdviceData.dx[i],
    6147             MoveAdviceData.dy[i]);
    6148           if (NextLoc = Loc) or (Loc = maNextCity) and
    6149             (MyMap[NextLoc] and fCity <> 0) then
    6150             StopReason := Arrived;
    6151           if not CheckSuicide and (NextLoc = Loc) then
    6152             MoveOptions := MoveOptions or muNoSuicideCheck;
    6153           MoveResult := MoveUnit(MoveAdviceData.dx[i], MoveAdviceData.dy[i],
    6154             MoveOptions);
    6155           if MoveResult < rExecuted then
    6156             StopReason := MoveError
    6157           else if MoveResult and rUnitRemoved <> 0 then
    6158             StopReason := Dead
    6159           else if (StopReason = None) and (MoveResult and rEnemySpotted <> 0)
    6160           then
    6161             StopReason := EnemySpotted;
    6162           if StopReason <> None then
    6163             Break;
    6164         end;
    6165         if (StopReason = None) and
    6166           ((MoveAdviceData.nStep < 25) or
    6167           (MyRO.Wonder[woShinkansen].EffectiveOwner <> me)) then
    6168           StopReason := NoTime;
    6169         if StopReason <> None then
    6170           Break;
    6171         if GetMoveAdvice(UnFocus, Loc, MoveAdviceData) < rExecuted then
    6172         begin
    6173           assert(false);
    6174           Break
    6175         end
    6176         until false;
    6177 
    6178         case StopReason of
    6179           None:
    6180             assert(false);
    6181           Arrived:
    6182             MyUn[uix].Status := MyUn[uix].Status and ($FFFF - usGoto);
    6183           Dead:
    6184             if UnFocus < 0 then
    6185               NextUnit(UnStartLoc, false);
    6186         else
    6187           begin // multi-turn goto
    6188             if Loc = maNextCity then
    6189               MyUn[uix].Status := MyUn[uix].Status and
    6190                 ($FFFF - usStay - usRecover) or usGoto + $7FFF shl 16
    6191             else
    6192               MyUn[uix].Status := MyUn[uix].Status and
    6193                 ($FFFF - usStay - usRecover) or usGoto + Loc shl 16;
    6194             PaintLoc(MyUn[uix].Loc);
    6195             if (StopReason = NoTime) and (UnFocus = uix) then
    6196             begin
    6197               MyUn[uix].Status := MyUn[uix].Status and not usWaiting;
    6198               NextUnit(UnStartLoc, true)
    6199             end;
    6200           end
    6201         end
    6202       end
    6203     end;
    6204 
    6205     procedure TMainScreen.PanelBoxMouseDown(Sender: TObject;
    6206       Button: TMouseButton; Shift: TShiftState; x, y: integer);
    6207     var
    6208       i, xMouse, MouseLoc, p1: integer;
    6209     begin
    6210       if GameMode = cMovie then
    6211         exit;
    6212 
    6213       if Button = mbLeft then
    6214       begin
    6215         if (x >= xMini + 2) and (y >= yMini + 2) and (x < xMini + 2 + 2 * G.lx)
    6216           and (y < yMini + 2 + G.ly) then
    6217           if ssShift in Shift then
    6218           begin
    6219             xMouse := (xwMini + (x - (xMini + 2) + MapWidth div (xxt * 2) +
    6220               G.lx) div 2) mod G.lx;
    6221             MouseLoc := xMouse + G.lx * (y - (yMini + 2));
    6222             if MyMap[MouseLoc] and fTerrain <> fUNKNOWN then
    6223             begin
    6224               p1 := MyRO.Territory[MouseLoc];
    6225               if (p1 = me) or (p1 >= 0) and (MyRO.Treaty[p1] >= trNone) then
    6226                 NatStatDlg.ShowNewContent(wmPersistent, p1);
    6227             end
    6228           end
    6229           else
    6230           begin
    6231             if CityDlg.Visible then
    6232               CityDlg.Close;
    6233             if UnitStatDlg.Visible then
    6234               UnitStatDlg.Close;
    6235             Tracking := true;
    6236             PanelBoxMouseMove(Sender, Shift + [ssLeft], x, y);
    6237           end
    6238         else if (ClientMode <> cEditMap) and (x >= ClientWidth - xPalace) and
    6239           (y >= yPalace) and (x < ClientWidth - xPalace + xSizeBig) and
    6240           (y < yPalace + ySizeBig) then
    6241         begin
    6242           InitPopup(StatPopup);
    6243           if FullScreen then
    6244             StatPopup.Popup(Left + ClientWidth - xPalace + xSizeBig + 2,
    6245               Top + ClientHeight - PanelHeight + yPalace - 1)
    6246           else
    6247             StatPopup.Popup(Left + ClientWidth - xPalace + 6,
    6248               Top + ClientHeight - PanelHeight + yPalace + ySizeBig +
    6249               GetSystemMetrics(SM_CYCAPTION) + 3)
    6250         end
    6251         (* else if (x>=xAdvisor-3) and (y>=yAdvisor-3)
    6252           and (x<xAdvisor+16+3) and (y<yAdvisor+16+3) and HaveStrategyAdvice then
    6253           AdviceBtnClick *)
    6254         else if (x >= xTroop + 1) and (y >= yTroop + 1) and
    6255           (x < xTroop + TrRow * TrPitch) and (y <= yTroop + 55) then
    6256         begin
    6257           i := (x - xTroop - 1) div TrPitch;
    6258           if trix[i] >= 0 then
    6259             if ClientMode = cEditMap then
    6260             begin
    6261               BrushType := trix[i];
    6262               PanelPaint
    6263             end
    6264             else if (TroopLoc >= 0) then
    6265               if MyMap[TroopLoc] and fOwned <> 0 then
    6266               begin
    6267                 if ssShift in Shift then
    6268                   UnitStatDlg.ShowNewContent_OwnModel(wmPersistent,
    6269                     MyUn[trix[i]].mix)
    6270                 else if not supervising and (ClientMode < scContact) and
    6271                   (x - xTroop - 1 - i * TrPitch >= 60 - 20) and
    6272                   (y >= yTroop + 35) and
    6273                   ((MyUn[trix[i]].Job > jNone) or (MyUn[trix[i]].Status and
    6274                   (usStay or usRecover or usGoto) <> 0)) then
    6275                 begin // wake up
    6276                   MyUn[trix[i]].Status := MyUn[trix[i]].Status and
    6277                     ($FFFF - usStay - usRecover - usGoto - usEnhance) or
    6278                     usWaiting;
    6279                   if MyUn[trix[i]].Job > jNone then
    6280                     Server(sStartJob + jNone shl 4, me, trix[i], nil^);
    6281                   if (UnFocus < 0) and not CityDlg.Visible then
    6282                   begin
    6283                     SetUnFocus(trix[i]);
    6284                     SetTroopLoc(MyUn[trix[i]].Loc);
    6285                     FocusOnLoc(TroopLoc, flRepaintPanel)
    6286                   end
    6287                   else
    6288                   begin
    6289                     if CityDlg.Visible and (CityDlg.RestoreUnFocus < 0) then
    6290                       CityDlg.RestoreUnFocus := trix[i];
    6291                     PanelPaint;
    6292                   end
    6293                 end
    6294                 else if (ClientMode < scContact) then
    6295                 begin
    6296                   if supervising then
    6297                     UnitStatDlg.ShowNewContent_OwnUnit(wmPersistent, trix[i])
    6298                   else if CityDlg.Visible then
    6299                   begin
    6300                     CityDlg.CloseAction := None;
    6301                     CityDlg.Close;
    6302                     SumCities(TaxSum, ScienceSum);
    6303                     SetUnFocus(trix[i]);
    6304                   end
    6305                   else
    6306                   begin
    6307                     DestinationMarkON := false;
    6308                     PaintDestination;
    6309                     UnFocus := trix[i];
    6310                     UnStartLoc := TroopLoc;
    6311                     BlinkTime := 0;
    6312                     BlinkON := false;
    6313                     PaintLoc(TroopLoc);
    6314                   end;
    6315                   if UnFocus >= 0 then
    6316                   begin
    6317                     UnitInfoBtn.Visible := true;
    6318                     UnitBtn.Visible := true;
    6319                     TurnComplete := false;
    6320                     EOT.ButtonIndex := eotGray;
    6321                   end;
    6322                   CheckTerrainBtnVisible;
    6323                   PanelPaint;
    6324                 end
    6325               end
    6326               else if Server(sGetUnits, me, TroopLoc, TrCnt) >= rExecuted then
    6327                 if ssShift in Shift then
    6328                   UnitStatDlg.ShowNewContent_EnemyModel(wmPersistent,
    6329                     MyRO.EnemyUn[MyRO.nEnemyUn + trix[i]].emix) // model info
    6330                 else
    6331                   UnitStatDlg.ShowNewContent_EnemyUnit(wmPersistent,
    6332                     MyRO.nEnemyUn + trix[i]); // unit info
    6333         end
    6334       end
    6335     end;
    6336 
    6337     procedure TMainScreen.SetTroopLoc(Loc: integer);
    6338     var
    6339       trixFocus, uix, uixDefender: integer;
    6340       Prio: boolean;
    6341     begin
    6342       TroopLoc := Loc;
    6343       TrRow := (xRightPanel + 10 - xTroop - GetSystemMetrics(SM_CXVSCROLL) - 19)
    6344         div TrPitch;
    6345       TrCnt := 0;
    6346       trixFocus := -1;
    6347       if ClientMode = cEditMap then
    6348         TrCnt := nBrushTypes
    6349       else if (Loc >= 0) and (MyMap[Loc] and fUnit <> 0) then
    6350         if MyMap[Loc] and fOwned <> 0 then
    6351         begin // count own units here
    6352           Server(sGetDefender, me, TroopLoc, uixDefender);
    6353           for Prio := true downto false do
    6354             for uix := 0 to MyRO.nUn - 1 do
    6355               if ((uix = uixDefender) = Prio) and (MyUn[uix].Loc = Loc) then
    6356               begin
    6357                 if uix = UnFocus then
    6358                   trixFocus := TrCnt;
    6359                 inc(TrCnt);
    6360               end
    6361         end
    6362         else // count enemy units here
    6363           Server(sGetUnits, me, Loc, TrCnt);
    6364       if TrCnt = 0 then
    6365         InitPVSB(sb, 0, 1)
    6366       else
    6367       begin
    6368         InitPVSB(sb, (TrCnt + TrRow - 1) div TrRow - 1, 1);
    6369         with sb.si do
    6370           if (nMax >= integer(nPage)) and (trixFocus >= 0) then
    6371           begin
    6372             sb.si.npos := trixFocus div TrRow;
    6373             sb.si.FMask := SIF_POS;
    6374             SetScrollInfo(sb.h, SB_CTL, sb.si, true);
    6375           end
    6376       end
    6377     end;
    6378 
    6379     (* procedure TMainScreen.ShowMoveHint(ToLoc: integer; Force: boolean = false);
    6380       var
    6381       Step,Loc,x0,y0,xs,ys: integer;
    6382       Info: string;
    6383       InfoSize: TSize;
    6384       MoveAdvice: TMoveAdviceData;
    6385       begin
    6386       if (ToLoc<0) or (ToLoc>=G.lx*G.ly)
    6387       or (UnFocus<0) or (MyUn[UnFocus].Loc=ToLoc) then
    6388       ToLoc:=-1
    6389       else
    6390       begin
    6391       MoveAdvice.ToLoc:=ToLoc;
    6392       MoveAdvice.MoreTurns:=0;
    6393       MoveAdvice.MaxHostile_MovementLeft:=MyUn[UnFocus].Health-50;
    6394       if Server(sGetMoveAdvice,me,UnFocus,MoveAdvice)<rExecuted then
    6395       ToLoc:=-1
    6396       end;
    6397       if (ToLoc=MoveHintToLoc) and not Force then exit;
    6398       if (ToLoc<>MoveHintToLoc) and (MoveHintToLoc>=0) then
    6399       begin invalidate; update end; // clear old hint from screen
    6400       MoveHintToLoc:=ToLoc;
    6401       if ToLoc<0 then exit;
    6402 
    6403       with canvas do
    6404       begin
    6405       Pen.Color:=$80C0FF;
    6406       Pen.Width:=3;
    6407       Loc:=MyUn[UnFocus].Loc;
    6408       for Step:=0 to MoveAdvice.nStep do
    6409       begin
    6410       y0:=(Loc+G.lx*1024) div G.lx -1024;
    6411       x0:=(Loc+(y0 and 1+G.lx*1024) div 2) mod G.lx;
    6412       xs:=(x0-xw)*66+y0 and 1*33-G.lx*66;
    6413       while abs(2*(xs+G.lx*66)-MapWidth)<abs(2*xs-MapWidth) do
    6414       inc(xs,G.lx*66);
    6415       ys:=(y0-yw)*16;
    6416       if Step=0 then moveto(xs+33,ys+16)
    6417       else lineto(xs+33,ys+16);
    6418       if Step<MoveAdvice.nStep then
    6419       Loc:=dLoc(Loc,MoveAdvice.dx[Step],MoveAdvice.dy[Step]);
    6420       end;
    6421       Brush.Color:=$80C0FF;
    6422       Info:=' '+inttostr(88)+' ';
    6423       InfoSize:=TextExtent(Info);
    6424       TextOut(xs+33-InfoSize.cx div 2, ys+16-InfoSize.cy div 2, Info);
    6425       Brush.Style:=bsClear;
    6426       end
    6427       end; *)
    6428 
    6429     procedure TMainScreen.SetDebugMap(p: integer);
    6430     begin
    6431       IsoEngine.pDebugMap := p;
    6432       IsoEngine.Options := IsoEngine.Options and not(1 shl moLocCodes);
    6433       mLocCodes.Checked := false;
    6434       MapValid := false;
    6435       MainOffscreenPaint;
    6436     end;
    6437 
    6438     procedure TMainScreen.SetViewpoint(p: integer);
    6439     var
    6440       i: integer;
    6441     begin
    6442       if supervising and (G.RO[0].Turn > 0) and
    6443         ((p = 0) or (1 shl p and G.RO[0].Alive <> 0)) then
    6444       begin
    6445         for i := 0 to Screen.FormCount - 1 do
    6446           if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
    6447           then
    6448             Screen.Forms[i].Close; // close windows
    6449         ItsMeAgain(p);
    6450         SumCities(TaxSum, ScienceSum);
    6451         for i := 0 to MyRO.nModel - 1 do
    6452           if Tribe[me].ModelPicture[i].HGr = 0 then
    6453             InitMyModel(i, true);
    6454 
    6455         SetTroopLoc(-1);
    6456         PanelPaint;
    6457         MapValid := false;
    6458         PaintAllMaps;
    6459       end
    6460     end;
    6461 
    6462     procedure TMainScreen.FormKeyDown(Sender: TObject; var Key: word;
    6463       Shift: TShiftState);
    6464 
    6465       procedure MenuClick_Check(Popup: TPopupMenu; Item: TMenuItem);
    6466       begin
    6467         InitPopup(Popup);
    6468         if Item.Visible and Item.Enabled then
    6469           MenuClick(Item);
    6470       end;
    6471 
    6472     var
    6473       dx, dy: integer;
    6474       time0, time1: TDateTime;
    6475     begin
    6476       if GameMode = cMovie then
    6477       begin
    6478         case Key of
    6479           VK_F4:
    6480             MenuClick_Check(StatPopup, mScienceStat);
    6481           VK_F6:
    6482             MenuClick_Check(StatPopup, mDiagram);
    6483           VK_F7:
    6484             MenuClick_Check(StatPopup, mWonders);
    6485           VK_F8:
    6486             MenuClick_Check(StatPopup, mShips);
    6487         end;
    6488         exit;
    6489       end;
    6490 
    6491       if not idle then
    6492         exit;
    6493 
    6494       if ClientMode = cEditMap then
    6495       begin
    6496         if Shift = [ssCtrl] then
    6497           case char(Key) of
    6498             (* 'A':
    6499               begin // auto symmetry
    6500               Server($7F0,me,0,nil^);
    6501               MapValid:=false;
    6502               PaintAll;
    6503               end;
    6504               'B':
    6505               begin // land mass
    6506               dy:=0;
    6507               for dx:=G.lx to G.lx*(G.ly-1)-1 do
    6508               if MyMap[dx] and fTerrain>=fGrass then inc(dy);
    6509               dy:=dy
    6510               end; *)
    6511             'Q':
    6512               MenuClick(mResign);
    6513             'R':
    6514               MenuClick(mRandomMap);
    6515           end
    6516         else if Shift = [] then
    6517           case char(Key) of
    6518             char(VK_F1):
    6519               MenuClick(mHelp);
    6520           end;
    6521         exit;
    6522       end;
    6523 
    6524       if Shift = [ssAlt] then
    6525         case char(Key) of
    6526           '0':
    6527             SetDebugMap(-1);
    6528           '1' .. '9':
    6529             SetDebugMap(ord(Key) - 48);
    6530         end
    6531       else if Shift = [ssCtrl] then
    6532         case char(Key) of
    6533           'J':
    6534             MenuClick(mJump);
    6535           'K':
    6536             mShowClick(mDebugMap);
    6537           'L':
    6538             mShowClick(mLocCodes);
    6539           'M':
    6540             if LogDlg.Visible then
    6541               LogDlg.Close
    6542             else
    6543               LogDlg.Show;
    6544           'N':
    6545             mNamesClick(mNames);
    6546           'Q':
    6547             MenuClick_Check(GamePopup, mResign);
    6548           'R':
    6549             MenuClick(mRun);
    6550           '0' .. '9':
    6551             begin
    6552               if ord(Key) - 48 = me then
    6553                 SetViewpoint(0)
    6554               else
    6555                 SetViewpoint(ord(Key) - 48);
    6556             end;
    6557           ' ':
    6558             begin // test map repaint time
    6559               time0 := NowPrecise;
    6560               MapValid := false;
    6561               MainOffscreenPaint;
    6562               time1 := NowPrecise;
    6563               SimpleMessage(Format('Map repaint time: %.3f ms',
    6564                 [MillisecondOf(time1 - time0)]));
    6565             end
    6566         end
    6567       else if Shift = [] then
    6568         case char(Key) of
    6569           char(VK_F1):
    6570             MenuClick(mHelp);
    6571           char(VK_F2):
    6572             MenuClick_Check(StatPopup, mUnitStat);
    6573           char(VK_F3):
    6574             MenuClick_Check(StatPopup, mCityStat);
    6575           char(VK_F4):
    6576             MenuClick_Check(StatPopup, mScienceStat);
    6577           char(VK_F5):
    6578             MenuClick_Check(StatPopup, mEUnitStat);
    6579           char(VK_F6):
    6580             MenuClick_Check(StatPopup, mDiagram);
    6581           char(VK_F7):
    6582             MenuClick_Check(StatPopup, mWonders);
    6583           char(VK_F8):
    6584             MenuClick_Check(StatPopup, mShips);
    6585           char(VK_F9):
    6586             MenuClick_Check(StatPopup, mNations);
    6587           char(VK_F10):
    6588             MenuClick_Check(StatPopup, mEmpire);
    6589           char(VK_ADD):
    6590             EndTurn;
    6591           '1':
    6592             MapBtnClick(MapBtn0);
    6593           '2':
    6594             MapBtnClick(MapBtn1);
    6595           '3':
    6596             MapBtnClick(MapBtn4);
    6597           '4':
    6598             MapBtnClick(MapBtn5);
    6599           '5':
    6600             MapBtnClick(MapBtn6);
    6601           'T':
    6602             MenuClick(mTechTree);
    6603           'W':
    6604             MenuClick(mWait);
    6605         end;
    6606 
    6607       if UnFocus >= 0 then
    6608         if Shift = [ssCtrl] then
    6609           case char(Key) of
    6610             'C':
    6611               MenuClick_Check(UnitPopup, mCancel);
    6612             'D':
    6613               MenuClick(mDisband);
    6614             'P':
    6615               MenuClick_Check(UnitPopup, mPillage);
    6616             'T':
    6617               MenuClick_Check(UnitPopup, mSelectTransport);
    6618           end
    6619         else if Shift = [] then
    6620           case char(Key) of
    6621             ' ':
    6622               MenuClick(mNoOrders);
    6623             'A':
    6624               MenuClick_Check(TerrainPopup, mAirBase);
    6625             'B':
    6626               MenuClick_Check(UnitPopup, mCity);
    6627             'C':
    6628               MenuClick(mCentre);
    6629             'E':
    6630               begin
    6631                 InitPopup(TerrainPopup);
    6632                 if mEnhance.Visible and mEnhance.Enabled then
    6633                   MenuClick(mEnhance)
    6634                 else
    6635                   MenuClick(mEnhanceDef)
    6636               end;
    6637             'F':
    6638               MenuClick_Check(TerrainPopup, mFort);
    6639             'G':
    6640               MenuClick_Check(UnitPopup, mGoOn);
    6641             'H':
    6642               MenuClick_Check(UnitPopup, mHome);
    6643             'I':
    6644               if JobTest(UnFocus, jFarm, [eTreaty]) then
    6645                 MenuClick(mFarm)
    6646               else if JobTest(UnFocus, jClear, [eTreaty]) then
    6647                 MenuClick(mClear)
    6648               else
    6649                 MenuClick_Check(TerrainPopup, mIrrigation);
    6650             'L':
    6651               MenuClick_Check(UnitPopup, mLoad);
    6652             'M':
    6653               if JobTest(UnFocus, jAfforest, [eTreaty]) then
    6654                 MenuClick(mAfforest)
    6655               else
    6656                 MenuClick_Check(TerrainPopup, mMine);
    6657             'N':
    6658               MenuClick_Check(TerrainPopup, mCanal);
    6659             'O':
    6660               MenuClick_Check(TerrainPopup, MTrans);
    6661             'P':
    6662               MenuClick_Check(TerrainPopup, mPollution);
    6663             'R':
    6664               if JobTest(UnFocus, jRR, [eTreaty]) then
    6665                 MenuClick(mRR)
    6666               else
    6667                 MenuClick_Check(TerrainPopup, mRoad);
    6668             'S':
    6669               MenuClick(mStay);
    6670             'U':
    6671               MenuClick_Check(UnitPopup, mUnload);
    6672             'V':
    6673               MenuClick_Check(UnitPopup, mRecover);
    6674             'Z':
    6675               MenuClick_Check(UnitPopup, mUtilize);
    6676             #33 .. #40, #97 .. #100, #102 .. #105:
    6677               begin { arrow keys }
    6678                 DestinationMarkON := false;
    6679                 PaintDestination;
    6680                 MyUn[UnFocus].Status := MyUn[UnFocus].Status and
    6681                   ($FFFF - usStay - usRecover - usGoto - usEnhance) or
    6682                   usWaiting;
    6683                 case Key of
    6684                   VK_NUMPAD1, VK_END:
    6685                     begin
    6686                       dx := -1;
    6687                       dy := 1
    6688                     end;
    6689                   VK_NUMPAD2, VK_DOWN:
    6690                     begin
    6691                       dx := 0;
    6692                       dy := 2
    6693                     end;
    6694                   VK_NUMPAD3, VK_NEXT:
    6695                     begin
    6696                       dx := 1;
    6697                       dy := 1
    6698                     end;
    6699                   VK_NUMPAD4, VK_LEFT:
    6700                     begin
    6701                       dx := -2;
    6702                       dy := 0
    6703                     end;
    6704                   VK_NUMPAD6, VK_RIGHT:
    6705                     begin
    6706                       dx := 2;
    6707                       dy := 0
    6708                     end;
    6709                   VK_NUMPAD7, VK_HOME:
    6710                     begin
    6711                       dx := -1;
    6712                       dy := -1
    6713                     end;
    6714                   VK_NUMPAD8, VK_UP:
    6715                     begin
    6716                       dx := 0;
    6717                       dy := -2
    6718                     end;
    6719                   VK_NUMPAD9, VK_PRIOR:
    6720                     begin
    6721                       dx := 1;
    6722                       dy := -1
    6723                     end;
    6724                 end;
    6725                 MoveUnit(dx, dy, muAutoNext)
    6726               end;
    6727           end
    6728     end;
    6729 
    6730     procedure TMainScreen.MenuClick(Sender: TObject);
    6731 
    6732       function DoJob(j0: integer): integer;
    6733       var
    6734         Loc0, Movement0: integer;
    6735       begin
    6736         with MyUn[UnFocus] do
    6737         begin
    6738           DestinationMarkON := false;
    6739           PaintDestination;
    6740           Loc0 := Loc;
    6741           Movement0 := Movement;
    6742           if j0 < 0 then
    6743             result := ProcessEnhancement(UnFocus, MyData.EnhancementJobs)
    6744             // terrain enhancement
    6745           else
    6746             result := Server(sStartJob + j0 shl 4, me, UnFocus, nil^);
    6747           if result >= rExecuted then
    6748           begin
    6749             if result = eDied then
    6750               UnFocus := -1;
    6751             PaintLoc(Loc0);
    6752             if UnFocus >= 0 then
    6753             begin
    6754               if (j0 < 0) and (result <> eJobDone) then
    6755               // multi-turn terrain enhancement
    6756                 Status := Status and ($FFFF - usStay - usRecover - usGoto) or
    6757                   usEnhance
    6758               else
    6759                 Status := Status and
    6760                   ($FFFF - usStay - usRecover - usGoto - usEnhance);
    6761               if (Job <> jNone) or (Movement0 < 100) then
    6762               begin
    6763                 Status := Status and not usWaiting;
    6764                 NextUnit(UnStartLoc, true);
    6765               end
    6766               else
    6767                 PanelPaint
    6768             end
    6769             else
    6770               NextUnit(UnStartLoc, true);
    6771           end
    6772         end;
    6773         case result of
    6774           eNoBridgeBuilding:
    6775             SoundMessage(Phrases.Lookup('NOBB'), 'INVALID');
    6776           eNoCityTerrain:
    6777             SoundMessage(Phrases.Lookup('NOCITY'), 'INVALID');
    6778           eTreaty:
    6779             SoundMessage(Tribe[MyRO.Territory[Loc0]].TPhrase('PEACE_NOWORK'),
    6780               'NOMOVE_TREATY');
    6781         else
    6782           if result < rExecuted then
    6783             Play('INVALID')
    6784         end
    6785       end;
    6786 
    6787     var
    6788       i, uix, NewFocus, Loc0, OldMaster, Destination, cix, cixOldHome,
    6789         ServerResult: integer;
    6790       AltGovs, Changed: boolean;
    6791       QueryText: string;
    6792 
    6793     begin
    6794       if Sender = mResign then
    6795         if ClientMode = cEditMap then
    6796         begin
    6797           if Edited then
    6798           begin
    6799             QueryText := Phrases.Lookup('MAP_CLOSE');
    6800             case SimpleQuery(mkYesNoCancel, QueryText, '') of
    6801               mrIgnore:
    6802                 Server(sAbandonMap, me, 0, nil^);
    6803               mrOK:
    6804                 Server(sSaveMap, me, 0, nil^);
    6805             end
    6806           end
    6807           else
    6808             Server(sAbandonMap, me, 0, nil^)
    6809         end
    6810         else
    6811         begin
    6812           if Server(sGetGameChanged, 0, 0, nil^) = eOK then
    6813           begin
    6814             QueryText := Phrases.Lookup('RESIGN');
    6815             case SimpleQuery(mkYesNoCancel, QueryText, '') of
    6816               mrIgnore:
    6817                 Server(sResign, 0, 0, nil^);
    6818               mrOK:
    6819                 Server(sBreak, 0, 0, nil^)
    6820             end
    6821           end
    6822           else
    6823             Server(sResign, 0, 0, nil^)
    6824         end
    6825       else if Sender = mEmpire then
    6826         RatesDlg.ShowNewContent(wmPersistent)
    6827       else if Sender = mRevolution then
    6828       begin
    6829         AltGovs := false;
    6830         for i := 2 to nGov - 1 do
    6831           if (GovPreq[i] <> preNA) and
    6832             ((GovPreq[i] = preNone) or (MyRO.Tech[GovPreq[i]] >= tsApplicable))
    6833           then
    6834             AltGovs := true;
    6835 
    6836         if not AltGovs then
    6837           SoundMessage(Phrases.Lookup('NOALTGOVS'), 'MSG_DEFAULT')
    6838         else
    6839         begin
    6840           Changed := false;
    6841           if MyRO.Happened and phChangeGov <> 0 then
    6842           begin
    6843             ModalSelectDlg.ShowNewContent(wmModal, kGov);
    6844             if ModalSelectDlg.result >= 0 then
    6845             begin
    6846               Play('NEWGOV');
    6847               Server(sSetGovernment, me, ModalSelectDlg.result, nil^);
    6848               CityOptimizer_BeginOfTurn;
    6849               Changed := true;
    6850             end
    6851           end
    6852           else
    6853             // TODO with MessgExDlg do
    6854             begin // revolution!
    6855               MessgExDlg.MessgText := Tribe[me].TPhrase('REVOLUTION');
    6856               MessgExDlg.Kind := mkYesNo;
    6857               MessgExDlg.IconKind := mikPureIcon;
    6858               MessgExDlg.IconIndex := 72; // anarchy palace
    6859               MessgExDlg.ShowModal;
    6860               if ModalResult = mrOK then
    6861               begin
    6862                 Play('REVOLUTION');
    6863                 Server(sRevolution, me, 0, nil^);
    6864                 Changed := true;
    6865                 if NatStatDlg.Visible then
    6866                   NatStatDlg.Close;
    6867                 if CityDlg.Visible then
    6868                   CityDlg.Close;
    6869               end
    6870             end;
    6871           if Changed then
    6872             UpdateViews(true);
    6873         end
    6874       end
    6875       else if Sender = mWebsite then
    6876         OpenURL('http://c-evo.org'){ *Převedeno z ShellExecute* }
    6877       else if Sender = mRandomMap then
    6878       begin
    6879         if not Edited or (SimpleQuery(mkYesNo, Phrases.Lookup('MAP_RANDOM'), '')
    6880           = mrOK) then
    6881         begin
    6882           Server(sRandomMap, me, 0, nil^);
    6883           Edited := true;
    6884           MapValid := false;
    6885           PaintAllMaps;
    6886         end
    6887       end
    6888       else if Sender = mJump then
    6889       begin
    6890         if supervising then
    6891           Jump[0] := 20
    6892         else
    6893           Jump[me] := 20;
    6894         EndTurn(true);
    6895       end
    6896       else if Sender = mRun then
    6897       begin
    6898         if supervising then
    6899           Jump[0] := 999999
    6900         else
    6901           Jump[me] := 999999;
    6902         EndTurn(true);
    6903       end
    6904       else if Sender = mEnhanceDef then
    6905       begin
    6906         if UnFocus >= 0 then
    6907           EnhanceDlg.ShowNewContent(wmPersistent,
    6908             MyMap[MyUn[UnFocus].Loc] and fTerrain)
    6909         else
    6910           EnhanceDlg.ShowNewContent(wmPersistent)
    6911       end
    6912       else if Sender = mCityTypes then
    6913         CityTypeDlg.ShowNewContent(wmModal)
    6914         // must be modal because types are not saved before closing
    6915       else if Sender = mUnitStat then
    6916       begin
    6917         if G.Difficulty[me] > 0 then
    6918           ListDlg.ShowNewContent_MilReport(wmPersistent, me)
    6919         else
    6920         begin
    6921           i := 1;
    6922           while (i < nPl) and (1 shl i and MyRO.Alive = 0) do
    6923             inc(i);
    6924           if i < nPl then
    6925             ListDlg.ShowNewContent_MilReport(wmPersistent, i);
    6926         end;
    6927       end
    6928       else if Sender = mEUnitStat then
    6929       begin
    6930         if MyRO.nEnemyModel > 0 then
    6931           ListDlg.ShowNewContent(wmPersistent, kAllEModels);
    6932       end
    6933       else if Sender = mCityStat then
    6934         ListDlg.ShowNewContent(wmPersistent, kCities)
    6935       else if Sender = mScienceStat then
    6936         ListDlg.ShowNewContent(wmPersistent, kScience)
    6937       else if Sender = mNations then
    6938         NatStatDlg.ShowNewContent(wmPersistent)
    6939       else if Sender = mHelp then
    6940         if ClientMode = cEditMap then
    6941           HelpDlg.ShowNewContent(wmPersistent, hkText,
    6942             HelpDlg.TextIndex('MAPEDIT'))
    6943         else
    6944           HelpDlg.ShowNewContent(wmPersistent, hkMisc, miscMain)
    6945       else if Sender = mTechTree then
    6946         TechTreeDlg.ShowModal
    6947       else if Sender = mWonders then
    6948         WondersDlg.ShowNewContent(wmPersistent)
    6949       else if Sender = mDiagram then
    6950         DiaDlg.ShowNewContent_Charts(wmPersistent)
    6951       else if Sender = mShips then
    6952         DiaDlg.ShowNewContent_Ship(wmPersistent)
    6953       else if Sender = mWait then
    6954       begin
    6955         if UnFocus >= 0 then
    6956         begin
    6957           DestinationMarkON := false;
    6958           PaintDestination;
    6959           MyUn[UnFocus].Status := MyUn[UnFocus].Status and
    6960             ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
    6961         end;
    6962         NextUnit(-1, false);
    6963       end
    6964       else if UnFocus >= 0 then
    6965         with MyUn[UnFocus] do
    6966           if Sender = mGoOn then
    6967           begin
    6968             if Status shr 16 = $7FFF then
    6969               Destination := maNextCity
    6970             else
    6971               Destination := Status shr 16;
    6972             Status := Status and not(usStay or usRecover) or usWaiting;
    6973             MoveToLoc(Destination, true);
    6974           end
    6975           else if Sender = mHome then
    6976             if MyMap[Loc] and fCity <> 0 then
    6977             begin
    6978               cixOldHome := Home;
    6979               if Server(sSetUnitHome, me, UnFocus, nil^) >= rExecuted then
    6980               begin
    6981                 CityOptimizer_CityChange(cixOldHome);
    6982                 CityOptimizer_CityChange(Home);
    6983                 UpdateViews(true);
    6984               end
    6985               else
    6986                 Play('INVALID');
    6987             end
    6988             else
    6989             begin
    6990               Status := Status and not(usStay or usRecover or usEnhance);
    6991               MoveToLoc(maNextCity, true)
    6992             end
    6993           else if Sender = mCentre then
    6994           begin
    6995             Centre(Loc);
    6996             PaintAllMaps
    6997           end
    6998           else if Sender = mCity then
    6999           begin
    7000             Loc0 := Loc;
    7001             if MyMap[Loc] and fCity = 0 then
    7002             begin // build city
    7003               if DoJob(jCity) = eCity then
    7004               begin
    7005                 MapValid := false;
    7006                 PaintAll;
    7007                 ZoomToCity(Loc0, true, chFounded);
    7008               end
    7009             end
    7010             else
    7011             begin
    7012               CityOptimizer_BeforeRemoveUnit(UnFocus);
    7013               ServerResult := Server(sAddToCity, me, UnFocus, nil^);
    7014               if ServerResult >= rExecuted then
    7015               begin
    7016                 cix := MyRO.nCity - 1;
    7017                 while (cix >= 0) and (MyCity[cix].Loc <> Loc0) do
    7018                   dec(cix);
    7019                 assert(cix >= 0);
    7020                 CityOptimizer_CityChange(cix);
    7021                 CityOptimizer_AfterRemoveUnit; // does nothing here
    7022                 SetTroopLoc(Loc0);
    7023                 UpdateViews(true);
    7024                 DestinationMarkON := false;
    7025                 PaintDestination;
    7026                 UnFocus := -1;
    7027                 PaintLoc(Loc0);
    7028                 NextUnit(UnStartLoc, true);
    7029               end
    7030               else if ServerResult = eMaxSize then
    7031                 SimpleMessage(Phrases.Lookup('ADDTOMAXSIZE'));
    7032             end
    7033           end
    7034           else if Sender = mRoad then
    7035             DoJob(jRoad)
    7036           else if Sender = mRR then
    7037             DoJob(jRR)
    7038           else if Sender = mClear then
    7039             DoJob(jClear)
    7040           else if Sender = mIrrigation then
    7041             DoJob(jIrr)
    7042           else if Sender = mFarm then
    7043             DoJob(jFarm)
    7044           else if Sender = mAfforest then
    7045             DoJob(jAfforest)
    7046           else if Sender = mMine then
    7047             DoJob(jMine)
    7048           else if Sender = mCanal then
    7049             DoJob(jCanal)
    7050           else if Sender = MTrans then
    7051             DoJob(jTrans)
    7052           else if Sender = mFort then
    7053             DoJob(jFort)
    7054           else if Sender = mAirBase then
    7055             DoJob(jBase)
    7056           else if Sender = mPollution then
    7057             DoJob(jPoll)
    7058           else if Sender = mPillage then
    7059             DoJob(jPillage)
    7060           else if Sender = mEnhance then
    7061             DoJob(-1)
    7062           else if Sender = mStay then
    7063           begin
    7064             DestinationMarkON := false;
    7065             PaintDestination;
    7066             Status := Status and ($FFFF - usRecover - usGoto - usEnhance)
    7067               or usStay;
    7068             if Job > jNone then
    7069               Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
    7070             NextUnit(UnStartLoc, true)
    7071           end
    7072           else if Sender = mRecover then
    7073           begin
    7074             DestinationMarkON := false;
    7075             PaintDestination;
    7076             Status := Status and ($FFFF - usStay - usGoto - usEnhance) or
    7077               usRecover;
    7078             if Job > jNone then
    7079               Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
    7080             NextUnit(UnStartLoc, true)
    7081           end
    7082           else if Sender = mNoOrders then
    7083           begin
    7084             Status := Status and not usWaiting;
    7085             NextUnit(UnStartLoc, true)
    7086           end
    7087           else if Sender = mCancel then
    7088           begin
    7089             DestinationMarkON := false;
    7090             PaintDestination;
    7091             Status := Status and ($FFFF - usRecover - usGoto - usEnhance);
    7092             if Job > jNone then
    7093               Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
    7094           end
    7095           else if (Sender = mDisband) or (Sender = mUtilize) then
    7096           begin
    7097             if (Sender = mUtilize) and
    7098               not(Server(sRemoveUnit - sExecute, me, UnFocus, nil^) = eUtilized)
    7099             then
    7100             begin
    7101               SimpleMessage(Phrases2.Lookup('SHIP_UTILIZE'));
    7102               // freight for colony ship is the only case in which the command is
    7103               // available to player though not valid
    7104               exit
    7105             end;
    7106             if (Sender = mUtilize) and (Health < 100) then
    7107               if SimpleQuery(mkYesNo, Phrases.Lookup('DAMAGED_UTILIZE'), '') <> mrOK
    7108               then
    7109                 exit;
    7110             Loc0 := Loc;
    7111             CityOptimizer_BeforeRemoveUnit(UnFocus);
    7112             if Server(sRemoveUnit, me, UnFocus, nil^) = eUtilized then
    7113               Play('CITY_UTILIZE')
    7114             else
    7115               Play('DISBAND');
    7116             CityOptimizer_AfterRemoveUnit;
     6991            cix := MyRO.nCity - 1;
     6992            while (cix >= 0) and (MyCity[cix].Loc <> Loc0) do
     6993              dec(cix);
     6994            assert(cix >= 0);
     6995            CityOptimizer_CityChange(cix);
     6996            CityOptimizer_AfterRemoveUnit; // does nothing here
    71176997            SetTroopLoc(Loc0);
    71186998            UpdateViews(true);
     
    71237003            NextUnit(UnStartLoc, true);
    71247004          end
    7125           else if Sender = mLoad then
     7005          else if ServerResult = eMaxSize then
     7006            SimpleMessage(Phrases.Lookup('ADDTOMAXSIZE'));
     7007        end
     7008      end
     7009      else if Sender = mRoad then
     7010        DoJob(jRoad)
     7011      else if Sender = mRR then
     7012        DoJob(jRR)
     7013      else if Sender = mClear then
     7014        DoJob(jClear)
     7015      else if Sender = mIrrigation then
     7016        DoJob(jIrr)
     7017      else if Sender = mFarm then
     7018        DoJob(jFarm)
     7019      else if Sender = mAfforest then
     7020        DoJob(jAfforest)
     7021      else if Sender = mMine then
     7022        DoJob(jMine)
     7023      else if Sender = mCanal then
     7024        DoJob(jCanal)
     7025      else if Sender = MTrans then
     7026        DoJob(jTrans)
     7027      else if Sender = mFort then
     7028        DoJob(jFort)
     7029      else if Sender = mAirBase then
     7030        DoJob(jBase)
     7031      else if Sender = mPollution then
     7032        DoJob(jPoll)
     7033      else if Sender = mPillage then
     7034        DoJob(jPillage)
     7035      else if Sender = mEnhance then
     7036        DoJob(-1)
     7037      else if Sender = mStay then
     7038      begin
     7039        DestinationMarkON := false;
     7040        PaintDestination;
     7041        Status := Status and ($FFFF - usRecover - usGoto - usEnhance) or usStay;
     7042        if Job > jNone then
     7043          Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
     7044        NextUnit(UnStartLoc, true)
     7045      end
     7046      else if Sender = mRecover then
     7047      begin
     7048        DestinationMarkON := false;
     7049        PaintDestination;
     7050        Status := Status and ($FFFF - usStay - usGoto - usEnhance) or usRecover;
     7051        if Job > jNone then
     7052          Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
     7053        NextUnit(UnStartLoc, true)
     7054      end
     7055      else if Sender = mNoOrders then
     7056      begin
     7057        Status := Status and not usWaiting;
     7058        NextUnit(UnStartLoc, true)
     7059      end
     7060      else if Sender = mCancel then
     7061      begin
     7062        DestinationMarkON := false;
     7063        PaintDestination;
     7064        Status := Status and ($FFFF - usRecover - usGoto - usEnhance);
     7065        if Job > jNone then
     7066          Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
     7067      end
     7068      else if (Sender = mDisband) or (Sender = mUtilize) then
     7069      begin
     7070        if (Sender = mUtilize) and
     7071          not(Server(sRemoveUnit - sExecute, me, UnFocus, nil^) = eUtilized)
     7072        then
     7073        begin
     7074          SimpleMessage(Phrases2.Lookup('SHIP_UTILIZE'));
     7075          // freight for colony ship is the only case in which the command is
     7076          // available to player though not valid
     7077          exit
     7078        end;
     7079        if (Sender = mUtilize) and (Health < 100) then
     7080          if SimpleQuery(mkYesNo, Phrases.Lookup('DAMAGED_UTILIZE'), '') <> mrOK
     7081          then
     7082            exit;
     7083        Loc0 := Loc;
     7084        CityOptimizer_BeforeRemoveUnit(UnFocus);
     7085        if Server(sRemoveUnit, me, UnFocus, nil^) = eUtilized then
     7086          Play('CITY_UTILIZE')
     7087        else
     7088          Play('DISBAND');
     7089        CityOptimizer_AfterRemoveUnit;
     7090        SetTroopLoc(Loc0);
     7091        UpdateViews(true);
     7092        DestinationMarkON := false;
     7093        PaintDestination;
     7094        UnFocus := -1;
     7095        PaintLoc(Loc0);
     7096        NextUnit(UnStartLoc, true);
     7097      end
     7098      else if Sender = mLoad then
     7099      begin
     7100        i := Server(sLoadUnit, me, UnFocus, nil^);
     7101        if i >= rExecuted then
     7102        begin
     7103          if MyModel[mix].Domain = dAir then
     7104            Play('MOVE_PLANELANDING')
     7105          else
     7106            Play('MOVE_LOAD');
     7107          DestinationMarkON := false;
     7108          PaintDestination;
     7109          Status := Status and ($FFFF - usWaiting - usStay - usRecover - usGoto
     7110            - usEnhance);
     7111          NextUnit(UnStartLoc, true);
     7112        end
     7113        else if i = eNoTime_Load then
     7114          if MyModel[mix].Domain = dAir then
     7115            SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
     7116          else
     7117            SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
     7118              [MovementToString(MyModel[mix].speed)]), 'NOMOVE_TIME');
     7119      end
     7120      else if Sender = mUnload then
     7121        if Master >= 0 then
     7122        begin
     7123          OldMaster := Master;
     7124          i := Server(sUnloadUnit, me, UnFocus, nil^);
     7125          if i >= rExecuted then
    71267126          begin
    7127             i := Server(sLoadUnit, me, UnFocus, nil^);
    7128             if i >= rExecuted then
    7129             begin
    7130               if MyModel[mix].Domain = dAir then
    7131                 Play('MOVE_PLANELANDING')
    7132               else
    7133                 Play('MOVE_LOAD');
    7134               DestinationMarkON := false;
    7135               PaintDestination;
    7136               Status := Status and
    7137                 ($FFFF - usWaiting - usStay - usRecover - usGoto - usEnhance);
    7138               NextUnit(UnStartLoc, true);
    7139             end
    7140             else if i = eNoTime_Load then
    7141               if MyModel[mix].Domain = dAir then
    7142                 SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
    7143               else
    7144                 SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
    7145                   [MovementToString(MyModel[mix].speed)]), 'NOMOVE_TIME');
     7127            if MyModel[mix].Domain = dAir then
     7128              Play('MOVE_PLANESTART')
     7129            else if (MyModel[MyUn[OldMaster].mix].Domain = dAir) and
     7130              (MyMap[Loc] and fCity = 0) and (MyMap[Loc] and fTerImp <> tiBase)
     7131            then
     7132              Play('MOVE_PARACHUTE')
     7133            else
     7134              Play('MOVE_UNLOAD');
     7135            Status := Status and not usWaiting;
     7136            if MyModel[mix].Domain <> dAir then
     7137              NextUnit(Loc, true)
     7138            else
     7139              PanelPaint
    71467140          end
    7147           else if Sender = mUnload then
    7148             if Master >= 0 then
    7149             begin
    7150               OldMaster := Master;
    7151               i := Server(sUnloadUnit, me, UnFocus, nil^);
    7152               if i >= rExecuted then
    7153               begin
    7154                 if MyModel[mix].Domain = dAir then
    7155                   Play('MOVE_PLANESTART')
    7156                 else if (MyModel[MyUn[OldMaster].mix].Domain = dAir) and
    7157                   (MyMap[Loc] and fCity = 0) and
    7158                   (MyMap[Loc] and fTerImp <> tiBase) then
    7159                   Play('MOVE_PARACHUTE')
    7160                 else
    7161                   Play('MOVE_UNLOAD');
    7162                 Status := Status and not usWaiting;
    7163                 if MyModel[mix].Domain <> dAir then
    7164                   NextUnit(Loc, true)
    7165                 else
    7166                   PanelPaint
    7167               end
    7168               else if i = eNoTime_Load then
    7169                 if MyModel[mix].Domain = dAir then
    7170                   SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
    7171                 else
    7172                   SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
    7173                     [MovementToString(MyModel[mix].speed)]), 'NOMOVE_TIME');
    7174             end
     7141          else if i = eNoTime_Load then
     7142            if MyModel[mix].Domain = dAir then
     7143              SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
    71757144            else
    7176             begin
    7177               NewFocus := -1;
    7178               uix := UnFocus;
    7179               for i := 1 to MyRO.nUn - 1 do
    7180               begin
    7181                 uix := (uix + MyRO.nUn - 1) mod MyRO.nUn;
    7182                 if (MyUn[uix].Master = UnFocus) and
    7183                   (MyUn[uix].Movement = integer(MyModel[MyUn[uix].mix].speed))
    7184                 then
    7185                 begin
    7186                   MyUn[uix].Status := MyUn[uix].Status or usWaiting;
    7187                   NewFocus := uix
    7188                 end;
    7189               end;
    7190               if NewFocus >= 0 then
    7191               begin
    7192                 SetUnFocus(NewFocus);
    7193                 SetTroopLoc(Loc);
    7194                 PanelPaint
    7195               end
    7196             end
    7197           else if Sender = mSelectTransport then
    7198             Server(sSelectTransport, me, UnFocus, nil^)
    7199     end;
    7200 
    7201     procedure TMainScreen.InitPopup(Popup: TPopupMenu);
    7202     var
    7203       i, p1, Tile, Test: integer;
    7204       NoSuper, extended, Multi, NeedSep, HaveCities: boolean;
    7205       LastSep, m: TMenuItem;
    7206       mox: ^TModel;
    7207     begin
    7208       NoSuper := not supervising and (1 shl me and MyRO.Alive <> 0);
    7209       HaveCities := false;
    7210       for i := 0 to MyRO.nCity - 1 do
    7211         if MyCity[i].Loc >= 0 then
    7212         begin
    7213           HaveCities := true;
    7214           Break
    7215         end;
    7216       if Popup = GamePopup then
    7217       begin
    7218         mTechTree.Visible := ClientMode <> cEditMap;
    7219         mResign.Enabled := supervising or (me = 0) and (ClientMode < scContact);
    7220         mRandomMap.Visible := (ClientMode = cEditMap) and
    7221           (Server(sMapGeneratorRequest, me, 0, nil^) = eOK);
    7222         mOptions.Visible := ClientMode <> cEditMap;
    7223         mManip.Visible := ClientMode <> cEditMap;
    7224         if ClientMode <> cEditMap then
    7225         begin
    7226           mWaitTurn.Visible := NoSuper;
    7227           mRep.Visible := NoSuper;
    7228           mRepList.Visible := NoSuper;
    7229           mRepScreens.Visible := NoSuper;
    7230           N10.Visible := NoSuper;
    7231           mOwnMovement.Visible := NoSuper;
    7232           mAllyMovement.Visible := NoSuper;
    7233           case SoundMode of
    7234             smOff:
    7235               mSoundOff.Checked := true;
    7236             smOn:
    7237               mSoundOn.Checked := true;
    7238             smOnAlt:
    7239               mSoundOnAlt.Checked := true;
    7240           end;
    7241 
    7242           for i := 0 to nTestFlags - 1 do
    7243             mManip[i].Checked := MyRO.TestFlags and (1 shl i) <> 0;
    7244           mManip.Enabled := supervising or (me = 0);
    7245 
    7246           Multi := false;
    7247           for p1 := 1 to nPl - 1 do
    7248             if G.RO[p1] <> nil then
    7249               Multi := true;
    7250           mEnemyMovement.Visible := not Multi;
    7251         end;
    7252         mMacro.Visible := NoSuper and (ClientMode < scContact);
    7253         if NoSuper and (ClientMode < scContact) then
    7254         begin
    7255           mCityTypes.Enabled := false;
    7256           // check if city types already usefull:
    7257           if MyRO.nCity > 0 then
    7258             for i := 28 to nImp - 1 do
    7259               if (i <> imTrGoods) and (Imp[i].Kind = ikCommon) and
    7260                 (Imp[i].Preq <> preNA) and
    7261                 ((Imp[i].Preq = preNone) or
    7262                 (MyRO.Tech[Imp[i].Preq] >= tsApplicable)) then
    7263               begin
    7264                 mCityTypes.Enabled := true;
    7265                 Break
    7266               end;
    7267         end;
    7268         mViewpoint.Visible := (ClientMode <> cEditMap) and supervising;
    7269         mViewpoint.Enabled := G.RO[0].Turn > 0;
    7270         if supervising then
    7271         begin
    7272           EmptyMenu(mViewpoint);
    7273           for p1 := 0 to nPl - 1 do
    7274             if (p1 = 0) or (1 shl p1 and G.RO[0].Alive <> 0) then
    7275             begin
    7276               m := TMenuItem.Create(mViewpoint);
    7277               if p1 = 0 then
    7278                 m.Caption := Phrases.Lookup('SUPER')
    7279               else
    7280                 m.Caption := Tribe[p1].TString(Phrases2.Lookup('BELONG'));
    7281               m.Tag := p1;
    7282               m.OnClick := ViewpointClick;
    7283               if p1 < 10 then
    7284                 m.ShortCut := ShortCut(48 + p1, [ssCtrl]);
    7285               m.RadioItem := true;
    7286               if p1 = me then
    7287                 m.Checked := true;
    7288               mViewpoint.Add(m);
    7289             end
    7290         end;
    7291         mDebugMap.Visible := (ClientMode <> cEditMap) and supervising;
    7292         if supervising then
    7293         begin
    7294           EmptyMenu(mDebugMap);
    7295           for p1 := 0 to nPl - 1 do
    7296             if (p1 = 0) or (1 shl p1 and G.RO[0].Alive <> 0) then
    7297             begin
    7298               m := TMenuItem.Create(mDebugMap);
    7299               if p1 = 0 then
    7300                 m.Caption := Phrases2.Lookup('MENU_DEBUGMAPOFF')
    7301               else
    7302                 m.Caption := Tribe[p1].TString(Phrases2.Lookup('BELONG'));
    7303               if p1 = 0 then
    7304                 m.Tag := -1
    7305               else
    7306                 m.Tag := p1;
    7307               m.OnClick := DebugMapClick;
    7308               if p1 < 10 then
    7309                 m.ShortCut := ShortCut(48 + p1, [ssAlt]);
    7310               m.RadioItem := true;
    7311               if m.Tag = IsoEngine.pDebugMap then
    7312                 m.Checked := true;
    7313               mDebugMap.Add(m);
    7314             end
    7315         end;
    7316         mSmallTiles.Checked := xxt = 33;
    7317         mNormalTiles.Checked := xxt = 48;
    7318       end
    7319       else if Popup = StatPopup then
    7320       begin
    7321         mEmpire.Visible := NoSuper;
    7322         mEmpire.Enabled := MyRO.Government <> gAnarchy;
    7323         mRevolution.Visible := NoSuper;
    7324         mRevolution.Enabled := (MyRO.Government <> gAnarchy) and
    7325           (ClientMode < scContact);
    7326         mUnitStat.Enabled := NoSuper or (MyRO.Turn > 0);
    7327         mCityStat.Visible := 1 shl me and MyRO.Alive <> 0;
    7328         mCityStat.Enabled := HaveCities;
    7329         mScienceStat.Visible := true;
    7330         mScienceStat.Enabled := not NoSuper or (MyRO.ResearchTech >= 0) or
    7331           (MyRO.Happened and phTech <> 0) or (MyRO.Happened and phGameEnd <> 0)
    7332         // no researchtech in case just completed
    7333           or (MyRO.TestFlags and (tfAllTechs or tfUncover or
    7334           tfAllContact) <> 0);
    7335         mEUnitStat.Enabled := MyRO.nEnemyModel > 0;
    7336         { mWonders.Enabled:= false;
    7337           for i:=0 to 27 do if MyRO.Wonder[i].CityID<>-1 then
    7338           mWonders.Enabled:=true; }
    7339         mDiagram.Enabled := MyRO.Turn >= 2;
    7340         mShips.Enabled := false;
    7341         for p1 := 0 to nPl - 1 do
    7342           if MyRO.Ship[p1].Parts[spComp] + MyRO.Ship[p1].Parts[spPow] +
    7343             MyRO.Ship[p1].Parts[spHab] > 0 then
    7344             mShips.Enabled := true;
    7345       end
    7346       else if Popup = UnitPopup then
    7347       begin
    7348         mox := @MyModel[MyUn[UnFocus].mix];
    7349         Tile := MyMap[MyUn[UnFocus].Loc];
    7350         extended := Tile and fCity = 0;
    7351         if extended then
    7352         begin
    7353           mCity.Caption := Phrases.Lookup('BTN_FOUND');
    7354           mHome.Caption := Phrases.Lookup('BTN_MOVEHOME')
     7145              SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
     7146                [MovementToString(MyModel[mix].speed)]), 'NOMOVE_TIME');
    73557147        end
    73567148        else
    73577149        begin
    7358           mCity.Caption := Phrases.Lookup('BTN_ADD');
    7359           mHome.Caption := Phrases.Lookup('BTN_SETHOME')
    7360         end;
    7361 
    7362         extended := extended and
    7363           ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves) and
    7364           (MyRO.Wonder[woPyramids].EffectiveOwner >= 0)) and
    7365           (MyUn[UnFocus].Master < 0) and (Tile and fDeadLands = 0);
    7366         if (mox.Kind = mkFreight) and (Tile and fCity <> 0) and
    7367           not Phrases2FallenBackToEnglish or
    7368           (Server(sRemoveUnit - sExecute, me, UnFocus, nil^) = eUtilized) then
    7369         begin
    7370           mDisband.Visible := false;
    7371           mUtilize.Visible := true;
    7372           if mox.Kind = mkFreight then
    7373             mUtilize.Caption := Phrases.Lookup('UTILIZE')
    7374           else
    7375             mUtilize.Caption := Phrases.Lookup('INTEGRATE')
    7376         end
    7377         else
    7378         begin
    7379           mDisband.Visible := true;
    7380           mUtilize.Visible := false
    7381         end;
    7382         mGoOn.Visible := MyUn[UnFocus].Status and (usGoto or usWaiting)
    7383           = usGoto or usWaiting;
    7384         mHome.Visible := HaveCities;
    7385         mRecover.Visible := (MyUn[UnFocus].Health < 100) and
    7386           (Tile and fTerrain >= fGrass) and
    7387           ((MyRO.Wonder[woGardens].EffectiveOwner = me) or
    7388           (Tile and fTerrain <> fArctic) and (Tile and fTerrain <> fDesert)) and
    7389           not((mox.Domain = dAir) and (Tile and fCity = 0) and
    7390           (Tile and fTerImp <> tiBase));
    7391         mStay.Visible := not((mox.Domain = dAir) and (Tile and fCity = 0) and
    7392           (Tile and fTerImp <> tiBase));
    7393         mCity.Visible := extended and (mox.Kind = mkSettler) or
    7394           (Tile and fCity <> 0) and ((mox.Kind in [mkSettler, mkSlaves]) or
    7395           (MyUn[UnFocus].Flags and unConscripts <> 0));
    7396         mPillage.Visible := (Tile and (fRoad or fRR or fCanal or fTerImp) <> 0)
    7397           and (MyUn[UnFocus].Master < 0) and (mox.Domain = dGround);
    7398         mCancel.Visible := (MyUn[UnFocus].Job > jNone) or
    7399           (MyUn[UnFocus].Status and (usRecover or usGoto) <> 0);
    7400 
    7401         Test := Server(sLoadUnit - sExecute, me, UnFocus, nil^);
    7402         mLoad.Visible := (Test >= rExecuted) or (Test = eNoTime_Load);
    7403         mUnload.Visible := (MyUn[UnFocus].Master >= 0) or
    7404           (MyUn[UnFocus].TroopLoad + MyUn[UnFocus].AirLoad > 0);
    7405         mSelectTransport.Visible := Server(sSelectTransport - sExecute, me,
    7406           UnFocus, nil^) >= rExecuted;
    7407       end
    7408       else { if Popup=TerrainPopup then }
    7409       begin
    7410         mox := @MyModel[MyUn[UnFocus].mix];
    7411         Tile := MyMap[MyUn[UnFocus].Loc];
    7412         extended := Tile and fCity = 0;
    7413 
    7414         if (Tile and fRiver <> 0) and
    7415           (MyRO.Tech[adBridgeBuilding] >= tsApplicable) then
    7416         begin
    7417           mRoad.Caption := Phrases.Lookup('BTN_BUILDBRIDGE');
    7418           mRR.Caption := Phrases.Lookup('BTN_BUILDRRBRIDGE');
    7419         end
    7420         else
    7421         begin
    7422           mRoad.Caption := Phrases.Lookup('BTN_BUILDROAD');
    7423           mRR.Caption := Phrases.Lookup('BTN_BUILDRR');
    7424         end;
    7425         if Tile and fTerrain = fForest then
    7426           mClear.Caption := Phrases.Lookup('BTN_CLEAR')
    7427         else if Tile and fTerrain = fDesert then
    7428           mClear.Caption := Phrases.Lookup('BTN_UNDESERT')
    7429         else
    7430           mClear.Caption := Phrases.Lookup('BTN_DRAIN');
    7431 
    7432         extended := extended and
    7433           ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves) and
    7434           (MyRO.Wonder[woPyramids].EffectiveOwner >= 0)) and
    7435           (MyUn[UnFocus].Master < 0);
    7436         if extended then
    7437         begin
    7438           mRoad.Visible := JobTest(UnFocus, jRoad,
    7439             [eNoBridgeBuilding, eTreaty]);
    7440           mRR.Visible := JobTest(UnFocus, jRR, [eNoBridgeBuilding, eTreaty]);
    7441           mClear.Visible := JobTest(UnFocus, jClear, [eTreaty]);
    7442           mIrrigation.Visible := JobTest(UnFocus, jIrr, [eTreaty]);
    7443           mFarm.Visible := JobTest(UnFocus, jFarm, [eTreaty]);
    7444           mAfforest.Visible := JobTest(UnFocus, jAfforest, [eTreaty]);
    7445           mMine.Visible := JobTest(UnFocus, jMine, [eTreaty]);
    7446           MTrans.Visible := JobTest(UnFocus, jTrans, [eTreaty]);
    7447           mCanal.Visible := JobTest(UnFocus, jCanal, [eTreaty]);
    7448           mFort.Visible := JobTest(UnFocus, jFort, [eTreaty]);
    7449           mAirBase.Visible := JobTest(UnFocus, jBase, [eTreaty]);
    7450           mPollution.Visible := JobTest(UnFocus, jPoll, [eTreaty]);
    7451           mEnhance.Visible := (Tile and fDeadLands = 0) and
    7452             (MyData.EnhancementJobs[MyMap[MyUn[UnFocus].Loc] and fTerrain, 0]
    7453             <> jNone);
    7454         end
    7455         else
    7456         begin
    7457           for i := 0 to Popup.Items.Count - 1 do
    7458             Popup.Items[i].Visible := false;
    7459         end;
    7460       end;
    7461 
    7462       // set menu seperators
    7463       LastSep := nil;
    7464       NeedSep := false;
    7465       for i := 0 to Popup.Items.Count - 1 do
    7466         if Popup.Items[i].Caption = '-' then
    7467         begin
    7468           Popup.Items[i].Visible := NeedSep;
    7469           if NeedSep then
    7470             LastSep := Popup.Items[i];
    7471           NeedSep := false
    7472         end
    7473         else if Popup.Items[i].Visible then
    7474           NeedSep := true;
    7475       if (LastSep <> nil) and not NeedSep then
    7476         LastSep.Visible := false
    7477     end;
    7478 
    7479     procedure TMainScreen.PanelBtnClick(Sender: TObject);
    7480     var
    7481       Popup: TPopupMenu;
    7482     begin
    7483       if Sender = UnitBtn then
    7484         Popup := UnitPopup
    7485       else { if Sender=TerrainBtn then }
    7486         Popup := TerrainPopup;
    7487       InitPopup(Popup);
    7488       if FullScreen then
    7489         Popup.Popup(Left + TControl(Sender).Left, Top + TControl(Sender).Top)
    7490       else
    7491         Popup.Popup(Left + TControl(Sender).Left + 4, Top + TControl(Sender).Top
    7492           + GetSystemMetrics(SM_CYCAPTION) + 4);
    7493     end;
    7494 
    7495     procedure TMainScreen.CityClosed(Activateuix: integer; StepFocus: boolean;
    7496       SelectFocus: boolean);
    7497     begin
    7498       if supervising then
    7499       begin
    7500         SetTroopLoc(-1);
    7501         PanelPaint
    7502       end
    7503       else
    7504       begin
    7505         if Activateuix >= 0 then
    7506         begin
    7507           SetUnFocus(Activateuix);
    7508           SetTroopLoc(MyUn[Activateuix].Loc);
    7509           if SelectFocus then
    7510             FocusOnLoc(TroopLoc, flRepaintPanel)
    7511           else
     7150          NewFocus := -1;
     7151          uix := UnFocus;
     7152          for i := 1 to MyRO.nUn - 1 do
     7153          begin
     7154            uix := (uix + MyRO.nUn - 1) mod MyRO.nUn;
     7155            if (MyUn[uix].Master = UnFocus) and
     7156              (MyUn[uix].Movement = integer(MyModel[MyUn[uix].mix].speed)) then
     7157            begin
     7158              MyUn[uix].Status := MyUn[uix].Status or usWaiting;
     7159              NewFocus := uix
     7160            end;
     7161          end;
     7162          if NewFocus >= 0 then
     7163          begin
     7164            SetUnFocus(NewFocus);
     7165            SetTroopLoc(Loc);
    75127166            PanelPaint
    7513         end
    7514         else if StepFocus then
    7515           NextUnit(TroopLoc, true)
    7516         else
    7517         begin
    7518           SetTroopLoc(-1);
    7519           PanelPaint
    7520         end
    7521       end
    7522     end;
    7523 
    7524     procedure TMainScreen.Toggle(Sender: TObject);
    7525     begin
    7526       TMenuItem(Sender).Checked := not TMenuItem(Sender).Checked
    7527     end;
    7528 
    7529     procedure TMainScreen.PanelBoxMouseMove(Sender: TObject; Shift: TShiftState;
    7530       x, y: integer);
    7531     var
    7532       xCentre, yCentre: integer;
    7533     begin
    7534       if Tracking and (ssLeft in Shift) then
    7535       begin
    7536         if (x >= xMini + 2) and (y >= yMini + 2) and (x < xMini + 2 + 2 * G.lx)
    7537           and (y < yMini + 2 + G.ly) then
    7538         begin
    7539           xCentre := (xwMini + (x - xMini - 2) div 2 + G.lx div 2 +
    7540             MapWidth div (xxt * 4)) mod G.lx;
    7541           yCentre := (y - yMini - 2);
    7542           xw := (xCentre - MapWidth div (xxt * 4) + G.lx) mod G.lx;
    7543           if ywmax <= 0 then
    7544             yw := ywcenter
    7545           else
    7546           begin
    7547             yw := (yCentre - MapHeight div (yyt * 2) + 1) and not 1;
    7548             if yw < 0 then
    7549               yw := 0
    7550             else if yw > ywmax then
    7551               yw := ywmax;
    7552           end;
    7553           BitBlt(Buffer.Canvas.Handle, 0, 0, G.lx * 2, G.ly, Mini.Canvas.Handle,
    7554             0, 0, SRCCOPY);
    7555           if ywmax <= 0 then
    7556             Frame(Buffer.Canvas, x - xMini - 2 - MapWidth div (xxt * 2), 0,
    7557               x - xMini - 2 + MapWidth div (xxt * 2) - 1, G.ly - 1,
    7558               MainTexture.clMark, MainTexture.clMark)
    7559           else
    7560             Frame(Buffer.Canvas, x - xMini - 2 - MapWidth div (xxt * 2), yw,
    7561               x - xMini - 2 + MapWidth div (xxt * 2) - 1,
    7562               yw + MapHeight div yyt - 2, MainTexture.clMark,
    7563               MainTexture.clMark);
    7564           BitBlt(Panel.Canvas.Handle, xMini + 2, yMini + 2, G.lx * 2, G.ly,
    7565             Buffer.Canvas.Handle, 0, 0, SRCCOPY);
    7566           MainOffscreenPaint;
    7567           RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini +
    7568             2, xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini
    7569             + 2 + G.ly);
    7570           Update;
    7571         end
    7572       end
    7573       else
    7574         Tracking := false
    7575     end;
    7576 
    7577     procedure TMainScreen.PanelBoxMouseUp(Sender: TObject; Button: TMouseButton;
    7578       Shift: TShiftState; x, y: integer);
    7579     begin
    7580       if Tracking then
    7581       begin
    7582         Tracking := false;
    7583         xwMini := xw;
    7584         ywMini := yw;
    7585         MiniPaint;
    7586         PanelPaint;
    7587       end
    7588     end;
    7589 
    7590     procedure TMainScreen.MapBoxMouseMove(Sender: TObject; Shift: TShiftState;
    7591       x, y: integer);
    7592     var
    7593       MouseLoc: integer;
    7594     begin
    7595       xMouse := x;
    7596       yMouse := y;
    7597       if (ClientMode = cEditMap) and (ssLeft in Shift) and not Tracking then
    7598       begin
    7599         MouseLoc := LocationOfScreenPixel(x, y);
    7600         if MouseLoc <> BrushLoc then
    7601           MapBoxMouseDown(nil, mbLeft, Shift, x, y);
    7602       end
    7603       (* else if idle and (UnFocus>=0) then
    7604         begin
    7605         qx:=(xMouse*32+yMouse*66+16*66) div(32*66)-1;
    7606         qy:=(yMouse*66-xMouse*32-16*66+2000*33*32) div(32*66)-999;
    7607         MouseLoc:=(xw+(qx-qy+2048) div 2-1024+G.lx) mod G.lx+G.lx*(yw+qx+qy);
    7608         ShowMoveHint(MouseLoc);
    7609         end *)
    7610     end;
    7611 
    7612     procedure TMainScreen.mShowClick(Sender: TObject);
    7613     begin
    7614       TMenuItem(Sender).Checked := not TMenuItem(Sender).Checked;
    7615       SetMapOptions;
    7616       MapValid := false;
    7617       PaintAllMaps;
    7618     end;
    7619 
    7620     procedure TMainScreen.mNamesClick(Sender: TObject);
    7621     var
    7622       p1: integer;
    7623     begin
    7624       mNames.Checked := not mNames.Checked;
    7625       GenerateNames := mNames.Checked;
    7626       for p1 := 0 to nPl - 1 do
    7627         if Tribe[p1] <> nil then
    7628           if GenerateNames then
    7629             Tribe[p1].NumberName := -1
    7630           else
    7631             Tribe[p1].NumberName := p1;
    7632       MapValid := false;
    7633       PaintAll;
    7634     end;
    7635 
    7636     function TMainScreen.IsPanelPixel(x, y: integer): boolean;
    7637     begin
    7638       result := (y >= TopBarHeight + MapHeight) or
    7639         (y >= ClientHeight - PanelHeight) and
    7640         ((x < xMidPanel) or (x >= xRightPanel))
    7641     end;
    7642 
    7643     procedure TMainScreen.FormMouseDown(Sender: TObject; Button: TMouseButton;
    7644       Shift: TShiftState; x, y: integer);
    7645     begin
    7646       if idle then
    7647         if (x < 40) and (y < 40) then
    7648         begin
    7649           if GameMode <> cMovie then
    7650           begin
    7651             InitPopup(GamePopup);
    7652             if FullScreen then
    7653               GamePopup.Popup(Left, Top + TopBarHeight - 1)
    7654             else
    7655               GamePopup.Popup(Left + 4, Top + GetSystemMetrics(SM_CYCAPTION) + 4
    7656                 + TopBarHeight - 1);
    76577167          end
    76587168        end
    7659         else if IsPanelPixel(x, y) then
    7660           PanelBoxMouseDown(Sender, Button, Shift, x,
    7661             y - (ClientHeight - PanelHeight))
    7662         else if (y >= TopBarHeight) and (x >= MapOffset) and
    7663           (x < MapOffset + MapWidth) then
    7664           MapBoxMouseDown(Sender, Button, Shift, x - MapOffset,
    7665             y - TopBarHeight)
     7169      else if Sender = mSelectTransport then
     7170        Server(sSelectTransport, me, UnFocus, nil^)
     7171end;
     7172
     7173procedure TMainScreen.InitPopup(Popup: TPopupMenu);
     7174var
     7175  i, p1, Tile, Test: integer;
     7176  NoSuper, extended, Multi, NeedSep, HaveCities: boolean;
     7177  LastSep, m: TMenuItem;
     7178  mox: ^TModel;
     7179begin
     7180  NoSuper := not supervising and (1 shl me and MyRO.Alive <> 0);
     7181  HaveCities := false;
     7182  for i := 0 to MyRO.nCity - 1 do
     7183    if MyCity[i].Loc >= 0 then
     7184    begin
     7185      HaveCities := true;
     7186      Break
    76667187    end;
    7667 
    7668     procedure TMainScreen.FormMouseMove(Sender: TObject; Shift: TShiftState;
    7669       x, y: integer);
    7670     begin
    7671       if idle then
    7672         if IsPanelPixel(x, y) then
    7673           PanelBoxMouseMove(Sender, Shift, x, y - (ClientHeight - PanelHeight))
    7674         else if (y >= TopBarHeight) and (x >= MapOffset) and
    7675           (x < MapOffset + MapWidth) then
    7676           MapBoxMouseMove(Sender, Shift, x - MapOffset, y - TopBarHeight);
     7188  if Popup = GamePopup then
     7189  begin
     7190    mTechTree.Visible := ClientMode <> cEditMap;
     7191    mResign.Enabled := supervising or (me = 0) and (ClientMode < scContact);
     7192    mRandomMap.Visible := (ClientMode = cEditMap) and
     7193      (Server(sMapGeneratorRequest, me, 0, nil^) = eOK);
     7194    mOptions.Visible := ClientMode <> cEditMap;
     7195    mManip.Visible := ClientMode <> cEditMap;
     7196    if ClientMode <> cEditMap then
     7197    begin
     7198      mWaitTurn.Visible := NoSuper;
     7199      mRep.Visible := NoSuper;
     7200      mRepList.Visible := NoSuper;
     7201      mRepScreens.Visible := NoSuper;
     7202      N10.Visible := NoSuper;
     7203      mOwnMovement.Visible := NoSuper;
     7204      mAllyMovement.Visible := NoSuper;
     7205      case SoundMode of
     7206        smOff:
     7207          mSoundOff.Checked := true;
     7208        smOn:
     7209          mSoundOn.Checked := true;
     7210        smOnAlt:
     7211          mSoundOnAlt.Checked := true;
     7212      end;
     7213
     7214      for i := 0 to nTestFlags - 1 do
     7215        mManip[i].Checked := MyRO.TestFlags and (1 shl i) <> 0;
     7216      mManip.Enabled := supervising or (me = 0);
     7217
     7218      Multi := false;
     7219      for p1 := 1 to nPl - 1 do
     7220        if G.RO[p1] <> nil then
     7221          Multi := true;
     7222      mEnemyMovement.Visible := not Multi;
    76777223    end;
    7678 
    7679     procedure TMainScreen.FormMouseUp(Sender: TObject; Button: TMouseButton;
    7680       Shift: TShiftState; x, y: integer);
    7681     begin
    7682       if idle then
    7683         PanelBoxMouseUp(Sender, Button, Shift, x,
    7684           y - (ClientHeight - PanelHeight));
     7224    mMacro.Visible := NoSuper and (ClientMode < scContact);
     7225    if NoSuper and (ClientMode < scContact) then
     7226    begin
     7227      mCityTypes.Enabled := false;
     7228      // check if city types already usefull:
     7229      if MyRO.nCity > 0 then
     7230        for i := 28 to nImp - 1 do
     7231          if (i <> imTrGoods) and (Imp[i].Kind = ikCommon) and
     7232            (Imp[i].Preq <> preNA) and
     7233            ((Imp[i].Preq = preNone) or (MyRO.Tech[Imp[i].Preq] >= tsApplicable))
     7234          then
     7235          begin
     7236            mCityTypes.Enabled := true;
     7237            Break
     7238          end;
    76857239    end;
    7686 
    7687     procedure TMainScreen.FormPaint(Sender: TObject);
    7688     begin
     7240    mViewpoint.Visible := (ClientMode <> cEditMap) and supervising;
     7241    mViewpoint.Enabled := G.RO[0].Turn > 0;
     7242    if supervising then
     7243    begin
     7244      EmptyMenu(mViewpoint);
     7245      for p1 := 0 to nPl - 1 do
     7246        if (p1 = 0) or (1 shl p1 and G.RO[0].Alive <> 0) then
     7247        begin
     7248          m := TMenuItem.Create(mViewpoint);
     7249          if p1 = 0 then
     7250            m.Caption := Phrases.Lookup('SUPER')
     7251          else
     7252            m.Caption := Tribe[p1].TString(Phrases2.Lookup('BELONG'));
     7253          m.Tag := p1;
     7254          m.OnClick := ViewpointClick;
     7255          if p1 < 10 then
     7256            m.ShortCut := ShortCut(48 + p1, [ssCtrl]);
     7257          m.RadioItem := true;
     7258          if p1 = me then
     7259            m.Checked := true;
     7260          mViewpoint.Add(m);
     7261        end
     7262    end;
     7263    mDebugMap.Visible := (ClientMode <> cEditMap) and supervising;
     7264    if supervising then
     7265    begin
     7266      EmptyMenu(mDebugMap);
     7267      for p1 := 0 to nPl - 1 do
     7268        if (p1 = 0) or (1 shl p1 and G.RO[0].Alive <> 0) then
     7269        begin
     7270          m := TMenuItem.Create(mDebugMap);
     7271          if p1 = 0 then
     7272            m.Caption := Phrases2.Lookup('MENU_DEBUGMAPOFF')
     7273          else
     7274            m.Caption := Tribe[p1].TString(Phrases2.Lookup('BELONG'));
     7275          if p1 = 0 then
     7276            m.Tag := -1
     7277          else
     7278            m.Tag := p1;
     7279          m.OnClick := DebugMapClick;
     7280          if p1 < 10 then
     7281            m.ShortCut := ShortCut(48 + p1, [ssAlt]);
     7282          m.RadioItem := true;
     7283          if m.Tag = IsoEngine.pDebugMap then
     7284            m.Checked := true;
     7285          mDebugMap.Add(m);
     7286        end
     7287    end;
     7288    mSmallTiles.Checked := xxt = 33;
     7289    mNormalTiles.Checked := xxt = 48;
     7290  end
     7291  else if Popup = StatPopup then
     7292  begin
     7293    mEmpire.Visible := NoSuper;
     7294    mEmpire.Enabled := MyRO.Government <> gAnarchy;
     7295    mRevolution.Visible := NoSuper;
     7296    mRevolution.Enabled := (MyRO.Government <> gAnarchy) and
     7297      (ClientMode < scContact);
     7298    mUnitStat.Enabled := NoSuper or (MyRO.Turn > 0);
     7299    mCityStat.Visible := 1 shl me and MyRO.Alive <> 0;
     7300    mCityStat.Enabled := HaveCities;
     7301    mScienceStat.Visible := true;
     7302    mScienceStat.Enabled := not NoSuper or (MyRO.ResearchTech >= 0) or
     7303      (MyRO.Happened and phTech <> 0) or (MyRO.Happened and phGameEnd <> 0)
     7304    // no researchtech in case just completed
     7305      or (MyRO.TestFlags and (tfAllTechs or tfUncover or tfAllContact) <> 0);
     7306    mEUnitStat.Enabled := MyRO.nEnemyModel > 0;
     7307    { mWonders.Enabled:= false;
     7308      for i:=0 to 27 do if MyRO.Wonder[i].CityID<>-1 then
     7309      mWonders.Enabled:=true; }
     7310    mDiagram.Enabled := MyRO.Turn >= 2;
     7311    mShips.Enabled := false;
     7312    for p1 := 0 to nPl - 1 do
     7313      if MyRO.Ship[p1].Parts[spComp] + MyRO.Ship[p1].Parts[spPow] +
     7314        MyRO.Ship[p1].Parts[spHab] > 0 then
     7315        mShips.Enabled := true;
     7316  end
     7317  else if Popup = UnitPopup then
     7318  begin
     7319    mox := @MyModel[MyUn[UnFocus].mix];
     7320    Tile := MyMap[MyUn[UnFocus].Loc];
     7321    extended := Tile and fCity = 0;
     7322    if extended then
     7323    begin
     7324      mCity.Caption := Phrases.Lookup('BTN_FOUND');
     7325      mHome.Caption := Phrases.Lookup('BTN_MOVEHOME')
     7326    end
     7327    else
     7328    begin
     7329      mCity.Caption := Phrases.Lookup('BTN_ADD');
     7330      mHome.Caption := Phrases.Lookup('BTN_SETHOME')
     7331    end;
     7332
     7333    extended := extended and ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves)
     7334      and (MyRO.Wonder[woPyramids].EffectiveOwner >= 0)) and
     7335      (MyUn[UnFocus].Master < 0) and (Tile and fDeadLands = 0);
     7336    if (mox.Kind = mkFreight) and (Tile and fCity <> 0) and
     7337      not Phrases2FallenBackToEnglish or
     7338      (Server(sRemoveUnit - sExecute, me, UnFocus, nil^) = eUtilized) then
     7339    begin
     7340      mDisband.Visible := false;
     7341      mUtilize.Visible := true;
     7342      if mox.Kind = mkFreight then
     7343        mUtilize.Caption := Phrases.Lookup('UTILIZE')
     7344      else
     7345        mUtilize.Caption := Phrases.Lookup('INTEGRATE')
     7346    end
     7347    else
     7348    begin
     7349      mDisband.Visible := true;
     7350      mUtilize.Visible := false
     7351    end;
     7352    mGoOn.Visible := MyUn[UnFocus].Status and (usGoto or usWaiting) = usGoto or
     7353      usWaiting;
     7354    mHome.Visible := HaveCities;
     7355    mRecover.Visible := (MyUn[UnFocus].Health < 100) and
     7356      (Tile and fTerrain >= fGrass) and
     7357      ((MyRO.Wonder[woGardens].EffectiveOwner = me) or
     7358      (Tile and fTerrain <> fArctic) and (Tile and fTerrain <> fDesert)) and
     7359      not((mox.Domain = dAir) and (Tile and fCity = 0) and
     7360      (Tile and fTerImp <> tiBase));
     7361    mStay.Visible := not((mox.Domain = dAir) and (Tile and fCity = 0) and
     7362      (Tile and fTerImp <> tiBase));
     7363    mCity.Visible := extended and (mox.Kind = mkSettler) or
     7364      (Tile and fCity <> 0) and ((mox.Kind in [mkSettler, mkSlaves]) or
     7365      (MyUn[UnFocus].Flags and unConscripts <> 0));
     7366    mPillage.Visible := (Tile and (fRoad or fRR or fCanal or fTerImp) <> 0) and
     7367      (MyUn[UnFocus].Master < 0) and (mox.Domain = dGround);
     7368    mCancel.Visible := (MyUn[UnFocus].Job > jNone) or
     7369      (MyUn[UnFocus].Status and (usRecover or usGoto) <> 0);
     7370
     7371    Test := Server(sLoadUnit - sExecute, me, UnFocus, nil^);
     7372    mLoad.Visible := (Test >= rExecuted) or (Test = eNoTime_Load);
     7373    mUnload.Visible := (MyUn[UnFocus].Master >= 0) or
     7374      (MyUn[UnFocus].TroopLoad + MyUn[UnFocus].AirLoad > 0);
     7375    mSelectTransport.Visible := Server(sSelectTransport - sExecute, me, UnFocus,
     7376      nil^) >= rExecuted;
     7377  end
     7378  else { if Popup=TerrainPopup then }
     7379  begin
     7380    mox := @MyModel[MyUn[UnFocus].mix];
     7381    Tile := MyMap[MyUn[UnFocus].Loc];
     7382    extended := Tile and fCity = 0;
     7383
     7384    if (Tile and fRiver <> 0) and (MyRO.Tech[adBridgeBuilding] >= tsApplicable)
     7385    then
     7386    begin
     7387      mRoad.Caption := Phrases.Lookup('BTN_BUILDBRIDGE');
     7388      mRR.Caption := Phrases.Lookup('BTN_BUILDRRBRIDGE');
     7389    end
     7390    else
     7391    begin
     7392      mRoad.Caption := Phrases.Lookup('BTN_BUILDROAD');
     7393      mRR.Caption := Phrases.Lookup('BTN_BUILDRR');
     7394    end;
     7395    if Tile and fTerrain = fForest then
     7396      mClear.Caption := Phrases.Lookup('BTN_CLEAR')
     7397    else if Tile and fTerrain = fDesert then
     7398      mClear.Caption := Phrases.Lookup('BTN_UNDESERT')
     7399    else
     7400      mClear.Caption := Phrases.Lookup('BTN_DRAIN');
     7401
     7402    extended := extended and ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves)
     7403      and (MyRO.Wonder[woPyramids].EffectiveOwner >= 0)) and
     7404      (MyUn[UnFocus].Master < 0);
     7405    if extended then
     7406    begin
     7407      mRoad.Visible := JobTest(UnFocus, jRoad, [eNoBridgeBuilding, eTreaty]);
     7408      mRR.Visible := JobTest(UnFocus, jRR, [eNoBridgeBuilding, eTreaty]);
     7409      mClear.Visible := JobTest(UnFocus, jClear, [eTreaty]);
     7410      mIrrigation.Visible := JobTest(UnFocus, jIrr, [eTreaty]);
     7411      mFarm.Visible := JobTest(UnFocus, jFarm, [eTreaty]);
     7412      mAfforest.Visible := JobTest(UnFocus, jAfforest, [eTreaty]);
     7413      mMine.Visible := JobTest(UnFocus, jMine, [eTreaty]);
     7414      MTrans.Visible := JobTest(UnFocus, jTrans, [eTreaty]);
     7415      mCanal.Visible := JobTest(UnFocus, jCanal, [eTreaty]);
     7416      mFort.Visible := JobTest(UnFocus, jFort, [eTreaty]);
     7417      mAirBase.Visible := JobTest(UnFocus, jBase, [eTreaty]);
     7418      mPollution.Visible := JobTest(UnFocus, jPoll, [eTreaty]);
     7419      mEnhance.Visible := (Tile and fDeadLands = 0) and
     7420        (MyData.EnhancementJobs[MyMap[MyUn[UnFocus].Loc] and fTerrain, 0]
     7421        <> jNone);
     7422    end
     7423    else
     7424    begin
     7425      for i := 0 to Popup.Items.Count - 1 do
     7426        Popup.Items[i].Visible := false;
     7427    end;
     7428  end;
     7429
     7430  // set menu seperators
     7431  LastSep := nil;
     7432  NeedSep := false;
     7433  for i := 0 to Popup.Items.Count - 1 do
     7434    if Popup.Items[i].Caption = '-' then
     7435    begin
     7436      Popup.Items[i].Visible := NeedSep;
     7437      if NeedSep then
     7438        LastSep := Popup.Items[i];
     7439      NeedSep := false
     7440    end
     7441    else if Popup.Items[i].Visible then
     7442      NeedSep := true;
     7443  if (LastSep <> nil) and not NeedSep then
     7444    LastSep.Visible := false
     7445end;
     7446
     7447procedure TMainScreen.PanelBtnClick(Sender: TObject);
     7448var
     7449  Popup: TPopupMenu;
     7450begin
     7451  if Sender = UnitBtn then
     7452    Popup := UnitPopup
     7453  else { if Sender=TerrainBtn then }
     7454    Popup := TerrainPopup;
     7455  InitPopup(Popup);
     7456  if FullScreen then
     7457    Popup.Popup(Left + TControl(Sender).Left, Top + TControl(Sender).Top)
     7458  else
     7459    Popup.Popup(Left + TControl(Sender).Left + 4, Top + TControl(Sender).Top +
     7460      GetSystemMetrics(SM_CYCAPTION) + 4);
     7461end;
     7462
     7463procedure TMainScreen.CityClosed(Activateuix: integer; StepFocus: boolean;
     7464  SelectFocus: boolean);
     7465begin
     7466  if supervising then
     7467  begin
     7468    SetTroopLoc(-1);
     7469    PanelPaint
     7470  end
     7471  else
     7472  begin
     7473    if Activateuix >= 0 then
     7474    begin
     7475      SetUnFocus(Activateuix);
     7476      SetTroopLoc(MyUn[Activateuix].Loc);
     7477      if SelectFocus then
     7478        FocusOnLoc(TroopLoc, flRepaintPanel)
     7479      else
     7480        PanelPaint
     7481    end
     7482    else if StepFocus then
     7483      NextUnit(TroopLoc, true)
     7484    else
     7485    begin
     7486      SetTroopLoc(-1);
     7487      PanelPaint
     7488    end
     7489  end
     7490end;
     7491
     7492procedure TMainScreen.Toggle(Sender: TObject);
     7493begin
     7494  TMenuItem(Sender).Checked := not TMenuItem(Sender).Checked
     7495end;
     7496
     7497procedure TMainScreen.PanelBoxMouseMove(Sender: TObject; Shift: TShiftState;
     7498  x, y: integer);
     7499var
     7500  xCentre, yCentre: integer;
     7501begin
     7502  if Tracking and (ssLeft in Shift) then
     7503  begin
     7504    if (x >= xMini + 2) and (y >= yMini + 2) and (x < xMini + 2 + 2 * G.lx) and
     7505      (y < yMini + 2 + G.ly) then
     7506    begin
     7507      xCentre := (xwMini + (x - xMini - 2) div 2 + G.lx div 2 +
     7508        MapWidth div (xxt * 4)) mod G.lx;
     7509      yCentre := (y - yMini - 2);
     7510      xw := (xCentre - MapWidth div (xxt * 4) + G.lx) mod G.lx;
     7511      if ywmax <= 0 then
     7512        yw := ywcenter
     7513      else
     7514      begin
     7515        yw := (yCentre - MapHeight div (yyt * 2) + 1) and not 1;
     7516        if yw < 0 then
     7517          yw := 0
     7518        else if yw > ywmax then
     7519          yw := ywmax;
     7520      end;
     7521      BitBlt(Buffer.Canvas.Handle, 0, 0, G.lx * 2, G.ly, Mini.Canvas.Handle, 0,
     7522        0, SRCCOPY);
     7523      if ywmax <= 0 then
     7524        Frame(Buffer.Canvas, x - xMini - 2 - MapWidth div (xxt * 2), 0,
     7525          x - xMini - 2 + MapWidth div (xxt * 2) - 1, G.ly - 1,
     7526          MainTexture.clMark, MainTexture.clMark)
     7527      else
     7528        Frame(Buffer.Canvas, x - xMini - 2 - MapWidth div (xxt * 2), yw,
     7529          x - xMini - 2 + MapWidth div (xxt * 2) - 1, yw + MapHeight div yyt -
     7530          2, MainTexture.clMark, MainTexture.clMark);
     7531      BitBlt(Panel.Canvas.Handle, xMini + 2, yMini + 2, G.lx * 2, G.ly,
     7532        Buffer.Canvas.Handle, 0, 0, SRCCOPY);
    76897533      MainOffscreenPaint;
    7690       if (MapOffset > 0) or (MapOffset + MapWidth < ClientWidth) then
    7691         with Canvas do
    7692         begin // pillarbox, make left and right border black
    7693           if me < 0 then
    7694             Brush.Color := $000000
    7695           else
    7696             Brush.Color := EmptySpaceColor;
    7697           if xMidPanel > MapOffset then
    7698             FillRect(Rect(0, TopBarHeight, MapOffset, TopBarHeight + MapHeight
    7699               - overlap))
    7700           else
    7701           begin
    7702             FillRect(Rect(0, TopBarHeight, xMidPanel, TopBarHeight + MapHeight -
    7703               overlap));
    7704             FillRect(Rect(xMidPanel, TopBarHeight, MapOffset,
    7705               TopBarHeight + MapHeight));
    7706           end;
    7707           if xRightPanel < MapOffset + MapWidth then
    7708             FillRect(Rect(MapOffset + MapWidth, TopBarHeight, ClientWidth,
    7709               TopBarHeight + MapHeight - overlap))
    7710           else
    7711           begin
    7712             FillRect(Rect(MapOffset + MapWidth, TopBarHeight, xRightPanel,
    7713               TopBarHeight + MapHeight));
    7714             FillRect(Rect(xRightPanel, TopBarHeight, ClientWidth,
    7715               TopBarHeight + MapHeight - overlap));
    7716           end;
    7717           Brush.Style := bsClear;
    7718         end;
    7719       BitBlt(Canvas.Handle, MapOffset, TopBarHeight, MapWidth,
    7720         MapHeight - overlap, offscreen.Canvas.Handle, 0, 0, SRCCOPY);
    7721       BitBlt(Canvas.Handle, 0, 0, ClientWidth, TopBarHeight,
    7722         TopBar.Canvas.Handle, 0, 0, SRCCOPY);
    7723       if xMidPanel > MapOffset then
    7724         BitBlt(Canvas.Handle, xMidPanel, TopBarHeight + MapHeight - overlap,
    7725           ClientWidth div 2 - xMidPanel, overlap, offscreen.Canvas.Handle,
    7726           xMidPanel - MapOffset, MapHeight - overlap, SRCCOPY)
     7534      RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini + 2,
     7535        xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini +
     7536        2 + G.ly);
     7537      Update;
     7538    end
     7539  end
     7540  else
     7541    Tracking := false
     7542end;
     7543
     7544procedure TMainScreen.PanelBoxMouseUp(Sender: TObject; Button: TMouseButton;
     7545  Shift: TShiftState; x, y: integer);
     7546begin
     7547  if Tracking then
     7548  begin
     7549    Tracking := false;
     7550    xwMini := xw;
     7551    ywMini := yw;
     7552    MiniPaint;
     7553    PanelPaint;
     7554  end
     7555end;
     7556
     7557procedure TMainScreen.MapBoxMouseMove(Sender: TObject; Shift: TShiftState;
     7558  x, y: integer);
     7559var
     7560  MouseLoc: integer;
     7561begin
     7562  xMouse := x;
     7563  yMouse := y;
     7564  if (ClientMode = cEditMap) and (ssLeft in Shift) and not Tracking then
     7565  begin
     7566    MouseLoc := LocationOfScreenPixel(x, y);
     7567    if MouseLoc <> BrushLoc then
     7568      MapBoxMouseDown(nil, mbLeft, Shift, x, y);
     7569  end
     7570  (* else if idle and (UnFocus>=0) then
     7571    begin
     7572    qx:=(xMouse*32+yMouse*66+16*66) div(32*66)-1;
     7573    qy:=(yMouse*66-xMouse*32-16*66+2000*33*32) div(32*66)-999;
     7574    MouseLoc:=(xw+(qx-qy+2048) div 2-1024+G.lx) mod G.lx+G.lx*(yw+qx+qy);
     7575    ShowMoveHint(MouseLoc);
     7576    end *)
     7577end;
     7578
     7579procedure TMainScreen.mShowClick(Sender: TObject);
     7580begin
     7581  TMenuItem(Sender).Checked := not TMenuItem(Sender).Checked;
     7582  SetMapOptions;
     7583  MapValid := false;
     7584  PaintAllMaps;
     7585end;
     7586
     7587procedure TMainScreen.mNamesClick(Sender: TObject);
     7588var
     7589  p1: integer;
     7590begin
     7591  mNames.Checked := not mNames.Checked;
     7592  GenerateNames := mNames.Checked;
     7593  for p1 := 0 to nPl - 1 do
     7594    if Tribe[p1] <> nil then
     7595      if GenerateNames then
     7596        Tribe[p1].NumberName := -1
    77277597      else
    7728         BitBlt(Canvas.Handle, MapOffset, TopBarHeight + MapHeight - overlap,
    7729           ClientWidth div 2 - MapOffset, overlap, offscreen.Canvas.Handle, 0,
    7730           MapHeight - overlap, SRCCOPY);
    7731       if xRightPanel < MapOffset + MapWidth then
    7732         BitBlt(Canvas.Handle, ClientWidth div 2, TopBarHeight + MapHeight -
    7733           overlap, xRightPanel - ClientWidth div 2, overlap,
    7734           offscreen.Canvas.Handle, ClientWidth div 2 - MapOffset,
    7735           MapHeight - overlap, SRCCOPY)
    7736       else
    7737         BitBlt(Canvas.Handle, ClientWidth div 2, TopBarHeight + MapHeight -
    7738           overlap, MapOffset + MapWidth - ClientWidth div 2, overlap,
    7739           offscreen.Canvas.Handle, ClientWidth div 2 - MapOffset,
    7740           MapHeight - overlap, SRCCOPY);
    7741       BitBlt(Canvas.Handle, 0, TopBarHeight + MapHeight - overlap, xMidPanel,
    7742         overlap, Panel.Canvas.Handle, 0, 0, SRCCOPY);
    7743       BitBlt(Canvas.Handle, xRightPanel, TopBarHeight + MapHeight - overlap,
    7744         Panel.width - xRightPanel, overlap, Panel.Canvas.Handle, xRightPanel,
    7745         0, SRCCOPY);
    7746       BitBlt(Canvas.Handle, 0, TopBarHeight + MapHeight, Panel.width,
    7747         PanelHeight - overlap, Panel.Canvas.Handle, 0, overlap, SRCCOPY);
    7748       if (pLogo >= 0) and (G.RO[pLogo] = nil) and (AILogo[pLogo] <> nil) then
    7749         BitBlt(Canvas.Handle, xRightPanel + 10 - (16 + 64),
    7750           ClientHeight - PanelHeight, 64, 64, AILogo[pLogo].Canvas.Handle, 0, 0,
    7751           SRCCOPY);
    7752     end;
    7753 
    7754     procedure TMainScreen.RectInvalidate(Left, Top, Rigth, Bottom: integer);
    7755     var
    7756       r0: HRgn;
    7757     begin
    7758       r0 := CreateRectRgn(Left, Top, Rigth, Bottom);
    7759       InvalidateRgn(Handle, r0, false);
    7760       DeleteObject(r0);
    7761     end;
    7762 
    7763     procedure TMainScreen.SmartRectInvalidate(Left, Top, Rigth,
    7764       Bottom: integer);
    7765     var
    7766       i: integer;
    7767       r0, r1: HRgn;
    7768     begin
    7769       r0 := CreateRectRgn(Left, Top, Rigth, Bottom);
    7770       for i := 0 to ControlCount - 1 do
    7771         if not(Controls[i] is TArea) and Controls[i].Visible then
    7772         begin
    7773           with Controls[i].BoundsRect do
    7774             r1 := CreateRectRgn(Left, Top, Right, Bottom);
    7775           CombineRgn(r0, r0, r1, RGN_DIFF);
    7776           DeleteObject(r1);
    7777         end;
    7778       InvalidateRgn(Handle, r0, false);
    7779       DeleteObject(r0);
    7780     end;
    7781 
    7782     procedure TMainScreen.mRepClicked(Sender: TObject);
    7783     begin
    7784       with TMenuItem(Sender) do
    7785       begin
    7786         Checked := not Checked;
    7787         if Checked then
    7788           CityRepMask := CityRepMask or (1 shl (Tag shr 8))
    7789         else
    7790           CityRepMask := CityRepMask and not(1 shl (Tag shr 8))
    7791       end
    7792     end;
    7793 
    7794     procedure TMainScreen.mLogClick(Sender: TObject);
    7795     begin
    7796       LogDlg.Show;
    7797     end;
    7798 
    7799     procedure TMainScreen.FormShow(Sender: TObject);
    7800     begin
    7801       Timer1.Enabled := true;
    7802       Left := 0;
    7803       Top := 0;
    7804     end;
    7805 
    7806     procedure TMainScreen.FormClose(Sender: TObject; var Action: TCloseAction);
    7807     begin
    7808       Timer1.Enabled := false;
    7809     end;
    7810 
    7811     procedure TMainScreen.Radio(Sender: TObject);
    7812     begin
    7813       TMenuItem(Sender).Checked := true;
    7814     end;
    7815 
    7816     procedure TMainScreen.mManipClick(Sender: TObject);
    7817     var
    7818       Flag: integer;
    7819     begin
    7820       with TMenuItem(Sender) do
    7821       begin
    7822         Flag := 1 shl (Tag shr 8);
    7823         if Checked then
    7824           Server(sClearTestFlag, 0, Flag, nil^)
    7825         else
    7826         begin
    7827           Server(sSetTestFlag, 0, Flag, nil^);
    7828           Play('CHEAT');
    7829         end;
    7830         if not supervising then
    7831         begin
    7832           if Flag = tfUncover then
    7833           begin
    7834             MapValid := false;
    7835             PaintAllMaps;
    7836           end
    7837           else if Flag = tfAllTechs then
    7838             TellNewModels
    7839         end
    7840       end
    7841     end;
    7842 
    7843     procedure TMainScreen.MapBtnClick(Sender: TObject);
    7844     begin
    7845       with TButtonC(Sender) do
    7846       begin
    7847         MapOptionChecked := MapOptionChecked xor (1 shl (Tag shr 8));
    7848         SetMapOptions;
    7849         ButtonIndex := MapOptionChecked shr (Tag shr 8) and 1 + 2
    7850       end;
    7851       if Sender = MapBtn0 then
    7852       begin
    7853         MiniPaint;
    7854         PanelPaint
    7855       end // update mini map only
    7856       else
    7857       begin
    7858         MapValid := false;
    7859         PaintAllMaps;
    7860       end; // update main map
    7861     end;
    7862 
    7863     procedure TMainScreen.GrWallBtnDownChanged(Sender: TObject);
    7864     begin
    7865       if TButtonBase(Sender).Down then
    7866       begin
    7867         MapOptionChecked := MapOptionChecked or (1 shl moGreatWall);
    7868         TButtonBase(Sender).Hint := '';
    7869       end
    7870       else
    7871       begin
    7872         MapOptionChecked := MapOptionChecked and not(1 shl moGreatWall);
    7873         TButtonBase(Sender).Hint := Phrases.Lookup('CONTROLS',
    7874           -1 + TButtonBase(Sender).Tag and $FF);
    7875       end;
    7876       SetMapOptions;
    7877       MapValid := false;
    7878       PaintAllMaps;
    7879     end;
    7880 
    7881     procedure TMainScreen.BareBtnDownChanged(Sender: TObject);
    7882     begin
    7883       if TButtonBase(Sender).Down then
    7884       begin
    7885         MapOptionChecked := MapOptionChecked or (1 shl moBareTerrain);
    7886         TButtonBase(Sender).Hint := '';
    7887       end
    7888       else
    7889       begin
    7890         MapOptionChecked := MapOptionChecked and not(1 shl moBareTerrain);
    7891         TButtonBase(Sender).Hint := Phrases.Lookup('CONTROLS',
    7892           -1 + TButtonBase(Sender).Tag and $FF);
    7893       end;
    7894       SetMapOptions;
    7895       MapValid := false;
    7896       PaintAllMaps;
    7897     end;
    7898 
    7899     procedure TMainScreen.FormKeyUp(Sender: TObject; var Key: word;
    7900       Shift: TShiftState);
    7901     begin
    7902       if idle and (Key = VK_APPS) then
     7598        Tribe[p1].NumberName := p1;
     7599  MapValid := false;
     7600  PaintAll;
     7601end;
     7602
     7603function TMainScreen.IsPanelPixel(x, y: integer): boolean;
     7604begin
     7605  result := (y >= TopBarHeight + MapHeight) or (y >= ClientHeight - PanelHeight)
     7606    and ((x < xMidPanel) or (x >= xRightPanel))
     7607end;
     7608
     7609procedure TMainScreen.FormMouseDown(Sender: TObject; Button: TMouseButton;
     7610  Shift: TShiftState; x, y: integer);
     7611begin
     7612  if idle then
     7613    if (x < 40) and (y < 40) then
     7614    begin
     7615      if GameMode <> cMovie then
    79037616      begin
    79047617        InitPopup(GamePopup);
     
    79087621          GamePopup.Popup(Left + 4, Top + GetSystemMetrics(SM_CYCAPTION) + 4 +
    79097622            TopBarHeight - 1);
    7910         exit
    7911       end // windows menu button calls game menu
     7623      end
     7624    end
     7625    else if IsPanelPixel(x, y) then
     7626      PanelBoxMouseDown(Sender, Button, Shift, x,
     7627        y - (ClientHeight - PanelHeight))
     7628    else if (y >= TopBarHeight) and (x >= MapOffset) and
     7629      (x < MapOffset + MapWidth) then
     7630      MapBoxMouseDown(Sender, Button, Shift, x - MapOffset, y - TopBarHeight)
     7631end;
     7632
     7633procedure TMainScreen.FormMouseMove(Sender: TObject; Shift: TShiftState;
     7634  x, y: integer);
     7635begin
     7636  if idle then
     7637    if IsPanelPixel(x, y) then
     7638      PanelBoxMouseMove(Sender, Shift, x, y - (ClientHeight - PanelHeight))
     7639    else if (y >= TopBarHeight) and (x >= MapOffset) and
     7640      (x < MapOffset + MapWidth) then
     7641      MapBoxMouseMove(Sender, Shift, x - MapOffset, y - TopBarHeight);
     7642end;
     7643
     7644procedure TMainScreen.FormMouseUp(Sender: TObject; Button: TMouseButton;
     7645  Shift: TShiftState; x, y: integer);
     7646begin
     7647  if idle then
     7648    PanelBoxMouseUp(Sender, Button, Shift, x, y - (ClientHeight - PanelHeight));
     7649end;
     7650
     7651procedure TMainScreen.FormPaint(Sender: TObject);
     7652begin
     7653  MainOffscreenPaint;
     7654  if (MapOffset > 0) or (MapOffset + MapWidth < ClientWidth) then
     7655    with Canvas do
     7656    begin // pillarbox, make left and right border black
     7657      if me < 0 then
     7658        Brush.Color := $000000
     7659      else
     7660        Brush.Color := EmptySpaceColor;
     7661      if xMidPanel > MapOffset then
     7662        FillRect(Rect(0, TopBarHeight, MapOffset, TopBarHeight + MapHeight
     7663          - overlap))
     7664      else
     7665      begin
     7666        FillRect(Rect(0, TopBarHeight, xMidPanel, TopBarHeight + MapHeight -
     7667          overlap));
     7668        FillRect(Rect(xMidPanel, TopBarHeight, MapOffset,
     7669          TopBarHeight + MapHeight));
     7670      end;
     7671      if xRightPanel < MapOffset + MapWidth then
     7672        FillRect(Rect(MapOffset + MapWidth, TopBarHeight, ClientWidth,
     7673          TopBarHeight + MapHeight - overlap))
     7674      else
     7675      begin
     7676        FillRect(Rect(MapOffset + MapWidth, TopBarHeight, xRightPanel,
     7677          TopBarHeight + MapHeight));
     7678        FillRect(Rect(xRightPanel, TopBarHeight, ClientWidth,
     7679          TopBarHeight + MapHeight - overlap));
     7680      end;
     7681      Brush.Style := bsClear;
    79127682    end;
    7913 
    7914     procedure TMainScreen.CreateUnitClick(Sender: TObject);
    7915     var
    7916       p1, mix: integer;
    7917     begin
    7918       p1 := TComponent(Sender).Tag shr 16;
    7919       mix := TComponent(Sender).Tag and $FFFF;
    7920       if Server(sCreateUnit + p1 shl 4, me, mix, EditLoc) >= rExecuted then
    7921         PaintLoc(EditLoc);
     7683  BitBlt(Canvas.Handle, MapOffset, TopBarHeight, MapWidth, MapHeight - overlap,
     7684    offscreen.Canvas.Handle, 0, 0, SRCCOPY);
     7685  BitBlt(Canvas.Handle, 0, 0, ClientWidth, TopBarHeight, TopBar.Canvas.Handle,
     7686    0, 0, SRCCOPY);
     7687  if xMidPanel > MapOffset then
     7688    BitBlt(Canvas.Handle, xMidPanel, TopBarHeight + MapHeight - overlap,
     7689      ClientWidth div 2 - xMidPanel, overlap, offscreen.Canvas.Handle,
     7690      xMidPanel - MapOffset, MapHeight - overlap, SRCCOPY)
     7691  else
     7692    BitBlt(Canvas.Handle, MapOffset, TopBarHeight + MapHeight - overlap,
     7693      ClientWidth div 2 - MapOffset, overlap, offscreen.Canvas.Handle, 0,
     7694      MapHeight - overlap, SRCCOPY);
     7695  if xRightPanel < MapOffset + MapWidth then
     7696    BitBlt(Canvas.Handle, ClientWidth div 2, TopBarHeight + MapHeight - overlap,
     7697      xRightPanel - ClientWidth div 2, overlap, offscreen.Canvas.Handle,
     7698      ClientWidth div 2 - MapOffset, MapHeight - overlap, SRCCOPY)
     7699  else
     7700    BitBlt(Canvas.Handle, ClientWidth div 2, TopBarHeight + MapHeight - overlap,
     7701      MapOffset + MapWidth - ClientWidth div 2, overlap,
     7702      offscreen.Canvas.Handle, ClientWidth div 2 - MapOffset,
     7703      MapHeight - overlap, SRCCOPY);
     7704  BitBlt(Canvas.Handle, 0, TopBarHeight + MapHeight - overlap, xMidPanel,
     7705    overlap, Panel.Canvas.Handle, 0, 0, SRCCOPY);
     7706  BitBlt(Canvas.Handle, xRightPanel, TopBarHeight + MapHeight - overlap,
     7707    Panel.width - xRightPanel, overlap, Panel.Canvas.Handle, xRightPanel,
     7708    0, SRCCOPY);
     7709  BitBlt(Canvas.Handle, 0, TopBarHeight + MapHeight, Panel.width,
     7710    PanelHeight - overlap, Panel.Canvas.Handle, 0, overlap, SRCCOPY);
     7711  if (pLogo >= 0) and (G.RO[pLogo] = nil) and (AILogo[pLogo] <> nil) then
     7712    BitBlt(Canvas.Handle, xRightPanel + 10 - (16 + 64),
     7713      ClientHeight - PanelHeight, 64, 64, AILogo[pLogo].Canvas.Handle, 0,
     7714      0, SRCCOPY);
     7715end;
     7716
     7717procedure TMainScreen.RectInvalidate(Left, Top, Rigth, Bottom: integer);
     7718var
     7719  r0: HRgn;
     7720begin
     7721  r0 := CreateRectRgn(Left, Top, Rigth, Bottom);
     7722  InvalidateRgn(Handle, r0, false);
     7723  DeleteObject(r0);
     7724end;
     7725
     7726procedure TMainScreen.SmartRectInvalidate(Left, Top, Rigth, Bottom: integer);
     7727var
     7728  i: integer;
     7729  r0, r1: HRgn;
     7730begin
     7731  r0 := CreateRectRgn(Left, Top, Rigth, Bottom);
     7732  for i := 0 to ControlCount - 1 do
     7733    if not(Controls[i] is TArea) and Controls[i].Visible then
     7734    begin
     7735      with Controls[i].BoundsRect do
     7736        r1 := CreateRectRgn(Left, Top, Right, Bottom);
     7737      CombineRgn(r0, r0, r1, RGN_DIFF);
     7738      DeleteObject(r1);
    79227739    end;
    7923 
    7924     procedure TMainScreen.mSoundOffClick(Sender: TObject);
    7925     begin
    7926       SoundMode := smOff;
     7740  InvalidateRgn(Handle, r0, false);
     7741  DeleteObject(r0);
     7742end;
     7743
     7744procedure TMainScreen.mRepClicked(Sender: TObject);
     7745begin
     7746  with TMenuItem(Sender) do
     7747  begin
     7748    Checked := not Checked;
     7749    if Checked then
     7750      CityRepMask := CityRepMask or (1 shl (Tag shr 8))
     7751    else
     7752      CityRepMask := CityRepMask and not(1 shl (Tag shr 8))
     7753  end
     7754end;
     7755
     7756procedure TMainScreen.mLogClick(Sender: TObject);
     7757begin
     7758  LogDlg.Show;
     7759end;
     7760
     7761procedure TMainScreen.FormShow(Sender: TObject);
     7762begin
     7763  Timer1.Enabled := true;
     7764  Left := 0;
     7765  Top := 0;
     7766end;
     7767
     7768procedure TMainScreen.FormClose(Sender: TObject; var Action: TCloseAction);
     7769begin
     7770  Timer1.Enabled := false;
     7771end;
     7772
     7773procedure TMainScreen.Radio(Sender: TObject);
     7774begin
     7775  TMenuItem(Sender).Checked := true;
     7776end;
     7777
     7778procedure TMainScreen.mManipClick(Sender: TObject);
     7779var
     7780  Flag: integer;
     7781begin
     7782  with TMenuItem(Sender) do
     7783  begin
     7784    Flag := 1 shl (Tag shr 8);
     7785    if Checked then
     7786      Server(sClearTestFlag, 0, Flag, nil^)
     7787    else
     7788    begin
     7789      Server(sSetTestFlag, 0, Flag, nil^);
     7790      Play('CHEAT');
    79277791    end;
    7928 
    7929     procedure TMainScreen.mSoundOnClick(Sender: TObject);
    7930     begin
    7931       SoundMode := smOn;
    7932     end;
    7933 
    7934     procedure TMainScreen.mSoundOnAltClick(Sender: TObject);
    7935     begin
    7936       SoundMode := smOnAlt;
    7937     end;
    7938 
    7939     { procedure TMainScreen.AdviceBtnClick;
    7940       var
    7941       OldAdviceLoc: integer;
    7942       begin
    7943       DestinationMarkON:=false;
    7944       PaintDestination;
    7945       AdvisorDlg.GiveStrategyAdvice;
    7946       OldAdviceLoc:=MainMap.AdviceLoc;
    7947       MainMap.AdviceLoc:=-1;
    7948       PaintLoc(OldAdviceLoc);
    7949       end; }
    7950 
    7951     { procedure TMainScreen.SetAdviceLoc(Loc: integer; AvoidRect: TRect);
    7952       var
    7953       OldAdviceLoc,x,y: integer;
    7954       begin
    7955       if Loc<>MainMap.AdviceLoc then
    7956       begin
    7957       if Loc>=0 then
    7958       begin // center
    7959       y:=Loc div G.lx;
    7960       x:=(Loc+G.lx - AvoidRect.Right div (2*66)) mod G.lx;
    7961       Centre(y*G.lx+x);
    7962       PaintAllMaps;
    7963       end;
    7964       OldAdviceLoc:=MainMap.AdviceLoc;
    7965       MainMap.AdviceLoc:=Loc;
    7966       PaintLoc(OldAdviceLoc);
    7967       PaintLoc(MainMap.AdviceLoc);
    7968       end;
    7969       end; }
    7970 
    7971     procedure TMainScreen.UnitInfoBtnClick(Sender: TObject);
    7972     begin
    7973       if UnFocus >= 0 then
    7974         UnitStatDlg.ShowNewContent_OwnModel(wmPersistent, MyUn[UnFocus].mix)
    7975     end;
    7976 
    7977     procedure TMainScreen.ViewpointClick(Sender: TObject);
    7978     begin
    7979       SetViewpoint(TMenuItem(Sender).Tag);
    7980     end;
    7981 
    7982     procedure TMainScreen.DebugMapClick(Sender: TObject);
    7983     begin
    7984       SetDebugMap(TMenuItem(Sender).Tag);
    7985     end;
    7986 
    7987     procedure TMainScreen.mSmallTilesClick(Sender: TObject);
    7988     begin
    7989       SetTileSize(33, 16);
    7990     end;
    7991 
    7992     procedure TMainScreen.mNormalTilesClick(Sender: TObject);
    7993     begin
    7994       SetTileSize(48, 24);
    7995     end;
    7996 
    7997     procedure TMainScreen.SetTileSize(x, y: integer);
    7998     var
    7999       i, CenterLoc: integer;
    8000     begin
    8001       CenterLoc := (xw + MapWidth div (xxt * 4)) mod G.lx +
    8002         (yw + MapHeight div (yyt * 2)) * G.lx;
    8003       IsoEngine.ApplyTileSize(x, y);
    8004       FormResize(nil);
    8005       Centre(CenterLoc);
    8006       PaintAllMaps;
    8007       for i := 0 to Screen.FormCount - 1 do
    8008         if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
    8009         then
    8010           TBufferedDrawDlg(Screen.Forms[i]).SmartUpdateContent(false);
    8011     end;
    8012 
    8013     procedure TMainScreen.SaveSettings;
    8014     var
    8015       i, j: integer;
    8016       Reg: TRegistry;
    8017     begin
    8018       OptionChecked := OptionChecked and soExtraMask;
    8019       for i := 0 to ComponentCount - 1 do
    8020         if Components[i] is TMenuItem then
    8021           for j := 0 to nSaveOption - 1 do
    8022             if TMenuItem(Components[i]).Checked and
    8023               (TMenuItem(Components[i]).Tag = SaveOption[j]) then
    8024               inc(OptionChecked, 1 shl j);
    8025 
    8026       Reg := TRegistry.Create;
    8027       Reg.OpenKey('SOFTWARE\cevo\RegVer9', true);
    8028       Reg.WriteInteger('TileWidth', xxt * 2);
    8029       Reg.WriteInteger('TileHeight', yyt * 2);
    8030       Reg.WriteInteger('OptionChecked', OptionChecked);
    8031       Reg.WriteInteger('MapOptionChecked', MapOptionChecked);
    8032       Reg.WriteInteger('CityReport', integer(CityRepMask));
    8033       Reg.closekey;
    8034       Reg.free;
    8035     end;
    8036 
    8037     procedure TMainScreen.MovieSpeedBtnClick(Sender: TObject);
    8038     begin
    8039       MovieSpeed := TButtonB(Sender).Tag shr 8;
    8040       CheckMovieSpeedBtnState;
    8041     end;
     7792    if not supervising then
     7793    begin
     7794      if Flag = tfUncover then
     7795      begin
     7796        MapValid := false;
     7797        PaintAllMaps;
     7798      end
     7799      else if Flag = tfAllTechs then
     7800        TellNewModels
     7801    end
     7802  end
     7803end;
     7804
     7805procedure TMainScreen.MapBtnClick(Sender: TObject);
     7806begin
     7807  with TButtonC(Sender) do
     7808  begin
     7809    MapOptionChecked := MapOptionChecked xor (1 shl (Tag shr 8));
     7810    SetMapOptions;
     7811    ButtonIndex := MapOptionChecked shr (Tag shr 8) and 1 + 2
     7812  end;
     7813  if Sender = MapBtn0 then
     7814  begin
     7815    MiniPaint;
     7816    PanelPaint
     7817  end // update mini map only
     7818  else
     7819  begin
     7820    MapValid := false;
     7821    PaintAllMaps;
     7822  end; // update main map
     7823end;
     7824
     7825procedure TMainScreen.GrWallBtnDownChanged(Sender: TObject);
     7826begin
     7827  if TButtonBase(Sender).Down then
     7828  begin
     7829    MapOptionChecked := MapOptionChecked or (1 shl moGreatWall);
     7830    TButtonBase(Sender).Hint := '';
     7831  end
     7832  else
     7833  begin
     7834    MapOptionChecked := MapOptionChecked and not(1 shl moGreatWall);
     7835    TButtonBase(Sender).Hint := Phrases.Lookup('CONTROLS',
     7836      -1 + TButtonBase(Sender).Tag and $FF);
     7837  end;
     7838  SetMapOptions;
     7839  MapValid := false;
     7840  PaintAllMaps;
     7841end;
     7842
     7843procedure TMainScreen.BareBtnDownChanged(Sender: TObject);
     7844begin
     7845  if TButtonBase(Sender).Down then
     7846  begin
     7847    MapOptionChecked := MapOptionChecked or (1 shl moBareTerrain);
     7848    TButtonBase(Sender).Hint := '';
     7849  end
     7850  else
     7851  begin
     7852    MapOptionChecked := MapOptionChecked and not(1 shl moBareTerrain);
     7853    TButtonBase(Sender).Hint := Phrases.Lookup('CONTROLS',
     7854      -1 + TButtonBase(Sender).Tag and $FF);
     7855  end;
     7856  SetMapOptions;
     7857  MapValid := false;
     7858  PaintAllMaps;
     7859end;
     7860
     7861procedure TMainScreen.FormKeyUp(Sender: TObject; var Key: word;
     7862  Shift: TShiftState);
     7863begin
     7864  if idle and (Key = VK_APPS) then
     7865  begin
     7866    InitPopup(GamePopup);
     7867    if FullScreen then
     7868      GamePopup.Popup(Left, Top + TopBarHeight - 1)
     7869    else
     7870      GamePopup.Popup(Left + 4, Top + GetSystemMetrics(SM_CYCAPTION) + 4 +
     7871        TopBarHeight - 1);
     7872    exit
     7873  end // windows menu button calls game menu
     7874end;
     7875
     7876procedure TMainScreen.CreateUnitClick(Sender: TObject);
     7877var
     7878  p1, mix: integer;
     7879begin
     7880  p1 := TComponent(Sender).Tag shr 16;
     7881  mix := TComponent(Sender).Tag and $FFFF;
     7882  if Server(sCreateUnit + p1 shl 4, me, mix, EditLoc) >= rExecuted then
     7883    PaintLoc(EditLoc);
     7884end;
     7885
     7886procedure TMainScreen.mSoundOffClick(Sender: TObject);
     7887begin
     7888  SoundMode := smOff;
     7889end;
     7890
     7891procedure TMainScreen.mSoundOnClick(Sender: TObject);
     7892begin
     7893  SoundMode := smOn;
     7894end;
     7895
     7896procedure TMainScreen.mSoundOnAltClick(Sender: TObject);
     7897begin
     7898  SoundMode := smOnAlt;
     7899end;
     7900
     7901{ procedure TMainScreen.AdviceBtnClick;
     7902  var
     7903  OldAdviceLoc: integer;
     7904  begin
     7905  DestinationMarkON:=false;
     7906  PaintDestination;
     7907  AdvisorDlg.GiveStrategyAdvice;
     7908  OldAdviceLoc:=MainMap.AdviceLoc;
     7909  MainMap.AdviceLoc:=-1;
     7910  PaintLoc(OldAdviceLoc);
     7911  end; }
     7912
     7913{ procedure TMainScreen.SetAdviceLoc(Loc: integer; AvoidRect: TRect);
     7914  var
     7915  OldAdviceLoc,x,y: integer;
     7916  begin
     7917  if Loc<>MainMap.AdviceLoc then
     7918  begin
     7919  if Loc>=0 then
     7920  begin // center
     7921  y:=Loc div G.lx;
     7922  x:=(Loc+G.lx - AvoidRect.Right div (2*66)) mod G.lx;
     7923  Centre(y*G.lx+x);
     7924  PaintAllMaps;
     7925  end;
     7926  OldAdviceLoc:=MainMap.AdviceLoc;
     7927  MainMap.AdviceLoc:=Loc;
     7928  PaintLoc(OldAdviceLoc);
     7929  PaintLoc(MainMap.AdviceLoc);
     7930  end;
     7931  end; }
     7932
     7933procedure TMainScreen.UnitInfoBtnClick(Sender: TObject);
     7934begin
     7935  if UnFocus >= 0 then
     7936    UnitStatDlg.ShowNewContent_OwnModel(wmPersistent, MyUn[UnFocus].mix)
     7937end;
     7938
     7939procedure TMainScreen.ViewpointClick(Sender: TObject);
     7940begin
     7941  SetViewpoint(TMenuItem(Sender).Tag);
     7942end;
     7943
     7944procedure TMainScreen.DebugMapClick(Sender: TObject);
     7945begin
     7946  SetDebugMap(TMenuItem(Sender).Tag);
     7947end;
     7948
     7949procedure TMainScreen.mSmallTilesClick(Sender: TObject);
     7950begin
     7951  SetTileSize(33, 16);
     7952end;
     7953
     7954procedure TMainScreen.mNormalTilesClick(Sender: TObject);
     7955begin
     7956  SetTileSize(48, 24);
     7957end;
     7958
     7959procedure TMainScreen.SetTileSize(x, y: integer);
     7960var
     7961  i, CenterLoc: integer;
     7962begin
     7963  CenterLoc := (xw + MapWidth div (xxt * 4)) mod G.lx +
     7964    (yw + MapHeight div (yyt * 2)) * G.lx;
     7965  IsoEngine.ApplyTileSize(x, y);
     7966  FormResize(nil);
     7967  Centre(CenterLoc);
     7968  PaintAllMaps;
     7969  for i := 0 to Screen.FormCount - 1 do
     7970    if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
     7971      TBufferedDrawDlg(Screen.Forms[i]).SmartUpdateContent(false);
     7972end;
     7973
     7974procedure TMainScreen.SaveSettings;
     7975var
     7976  i, j: integer;
     7977  Reg: TRegistry;
     7978begin
     7979  OptionChecked := OptionChecked and soExtraMask;
     7980  for i := 0 to ComponentCount - 1 do
     7981    if Components[i] is TMenuItem then
     7982      for j := 0 to nSaveOption - 1 do
     7983        if TMenuItem(Components[i]).Checked and
     7984          (TMenuItem(Components[i]).Tag = SaveOption[j]) then
     7985          inc(OptionChecked, 1 shl j);
     7986
     7987  Reg := TRegistry.Create;
     7988  Reg.OpenKey('SOFTWARE\cevo\RegVer9', true);
     7989  Reg.WriteInteger('TileWidth', xxt * 2);
     7990  Reg.WriteInteger('TileHeight', yyt * 2);
     7991  Reg.WriteInteger('OptionChecked', OptionChecked);
     7992  Reg.WriteInteger('MapOptionChecked', MapOptionChecked);
     7993  Reg.WriteInteger('CityReport', integer(CityRepMask));
     7994  Reg.CloseKey;
     7995  Reg.free;
     7996end;
     7997
     7998procedure TMainScreen.MovieSpeedBtnClick(Sender: TObject);
     7999begin
     8000  MovieSpeed := TButtonB(Sender).Tag shr 8;
     8001  CheckMovieSpeedBtnState;
     8002end;
    80428003
    80438004initialization
Note: See TracChangeset for help on using the changeset viewer.