Ignore:
Timestamp:
Jan 7, 2017, 11:32:14 AM (7 years ago)
Author:
chronos
Message:
  • Modified: Formated all project source files using Delphi formatter as original indentation and other formatting was really bad.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/LocalPlayer/Term.pas

    r2 r6  
    11{$INCLUDE switches}
    2 
    32unit Term;
    43
     
    65
    76uses
    8   Protocol,Tribes,PVSB,ClientTools,ScreenTools,BaseWin,Messg,ButtonBase,
    9 
    10   Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Menus,ExtCtrls,
    11   ButtonA,ButtonB, ButtonC, EOTButton, Area;
     7  Protocol, Tribes, PVSB, ClientTools, ScreenTools, BaseWin, Messg, ButtonBase,
     8
     9  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Menus,
     10  ExtCtrls,
     11  ButtonA, ButtonB, ButtonC, EOTButton, Area;
    1212
    1313const
    14 WM_EOT=WM_USER;
    15 
    16 pltsNormal=0; pltsBlink=1;
     14  WM_EOT = WM_USER;
     15
     16  pltsNormal = 0;
     17  pltsBlink = 1;
    1718
    1819type
    1920  TMainScreen = class(TDrawDlg)
    20     Timer1:TTimer;
     21    Timer1: TTimer;
    2122    GamePopup: TPopupMenu;
    22     UnitPopup:TPopupMenu;
    23     mIrrigation:TMenuItem;
    24     mCity:TMenuItem;
    25     mRoad:TMenuItem;
    26     mMine:TMenuItem;
    27     mPollution:TMenuItem;
    28     mHome:TMenuItem;
     23    UnitPopup: TPopupMenu;
     24    mIrrigation: TMenuItem;
     25    mCity: TMenuItem;
     26    mRoad: TMenuItem;
     27    mMine: TMenuItem;
     28    mPollution: TMenuItem;
     29    mHome: TMenuItem;
    2930    mStay: TMenuItem;
    30     mDisband:TMenuItem;
    31     mWait:TMenuItem;
    32     mNoOrders:TMenuItem;
    33     MTrans:TMenuItem;
     31    mDisband: TMenuItem;
     32    mWait: TMenuItem;
     33    mNoOrders: TMenuItem;
     34    MTrans: TMenuItem;
    3435    UnitBtn: TButtonB;
    3536    mResign: TMenuItem;
     
    163164    N12: TMenuItem;
    164165    mRep14: TMenuItem;
    165     procedure FormCreate(Sender:TObject);
    166     procedure FormDestroy(Sender:TObject);
    167     procedure Timer1Timer(Sender:TObject);
    168     procedure MapBoxMouseDown(Sender:TObject;Button:TMouseButton;
    169       Shift:TShiftState;x,y:integer);
    170     procedure EOTClick(Sender:TObject);
    171     procedure PanelBoxMouseDown(Sender:TObject;Button:TMouseButton;
    172       Shift:TShiftState;x,y:integer);
    173     procedure FormKeyDown(Sender:TObject;var Key:word;
    174       Shift:TShiftState);
    175     procedure MenuClick(Sender:TObject);
    176     procedure FormResize(Sender:TObject);
     166    procedure FormCreate(Sender: TObject);
     167    procedure FormDestroy(Sender: TObject);
     168    procedure Timer1Timer(Sender: TObject);
     169    procedure MapBoxMouseDown(Sender: TObject; Button: TMouseButton;
     170      Shift: TShiftState; x, y: integer);
     171    procedure EOTClick(Sender: TObject);
     172    procedure PanelBoxMouseDown(Sender: TObject; Button: TMouseButton;
     173      Shift: TShiftState; x, y: integer);
     174    procedure FormKeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
     175    procedure MenuClick(Sender: TObject);
     176    procedure FormResize(Sender: TObject);
    177177    procedure PanelBtnClick(Sender: TObject);
    178178    procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
    179179    procedure Toggle(Sender: TObject);
    180     procedure PanelBoxMouseMove(Sender: TObject; Shift: TShiftState; x,
    181       y: integer);
     180    procedure PanelBoxMouseMove(Sender: TObject; Shift: TShiftState;
     181      x, y: integer);
    182182    procedure PanelBoxMouseUp(Sender: TObject; Button: TMouseButton;
    183183      Shift: TShiftState; x, y: integer);
    184     procedure MapBoxMouseMove(Sender: TObject; Shift: TShiftState; x,
    185       y: integer);
     184    procedure MapBoxMouseMove(Sender: TObject; Shift: TShiftState;
     185      x, y: integer);
    186186    procedure mShowClick(Sender: TObject);
    187187    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
    188188      Shift: TShiftState; x, y: integer);
    189     procedure FormMouseMove(Sender: TObject; Shift: TShiftState; x,
    190       y: integer);
     189    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; x, y: integer);
    191190    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
    192191      Shift: TShiftState; x, y: integer);
     
    200199    procedure mNamesClick(Sender: TObject);
    201200    procedure MapBtnClick(Sender: TObject);
    202     procedure FormKeyUp(Sender: TObject; var Key: Word;
    203       Shift: TShiftState);
     201    procedure FormKeyUp(Sender: TObject; var Key: word; Shift: TShiftState);
    204202    procedure CreateUnitClick(Sender: TObject);
    205203    procedure mSoundOffClick(Sender: TObject);
     
    217215  public
    218216    procedure CreateParams(var p: TCreateParams); override;
    219     procedure Client(Command,NewPlayer:integer;var Data);
     217    procedure Client(Command, NewPlayer: integer; var Data);
    220218    procedure SetAIName(p: integer; Name: string);
    221219    function ZoomToCity(Loc: integer; NextUnitOnClose: boolean = false;
     
    229227
    230228  private
    231     xw,yw,xwd,ywd,xwMini,ywMini,xMidPanel,xRightPanel,xTroop,xTerrain,xMini,
    232       yMini,ywmax,ywcenter,TroopLoc,TrCnt,TrRow,TrPitch,MapWidth,MapOffset,
    233       MapHeight,BlinkTime,BrushLoc,EditLoc,xMouse,yMouse: integer;
     229    xw, yw, xwd, ywd, xwMini, ywMini, xMidPanel, xRightPanel, xTroop, xTerrain,
     230      xMini, yMini, ywmax, ywcenter, TroopLoc, TrCnt, TrRow, TrPitch, MapWidth,
     231      MapOffset, MapHeight, BlinkTime, BrushLoc, EditLoc, xMouse,
     232      yMouse: integer;
    234233    BrushType: Cardinal;
    235     trix:array[0..63] of integer;
    236     AILogo: array[0..nPl-1] of TBitmap;
    237     Mini,Panel,TopBar: TBitmap;
    238     sb:TPVScrollbar;
    239     Closable,RepaintOnResize,Tracking,TurnComplete,Edited,GoOnPhase,
     234    trix: array [0 .. 63] of integer;
     235    AILogo: array [0 .. nPl - 1] of TBitmap;
     236    Mini, Panel, TopBar: TBitmap;
     237    sb: TPVScrollbar;
     238    Closable, RepaintOnResize, Tracking, TurnComplete, Edited, GoOnPhase,
    240239      HaveStrategyAdvice, FirstMovieTurn: boolean;
    241240    procedure ArrangeMidPanel;
     
    246245    procedure CopyMiniToPanel;
    247246    procedure PanelPaint;
    248     procedure NextUnit(NearLoc:integer;AutoTurn:boolean);
    249     procedure Scroll(dx,dy: integer);
    250     procedure Centre(Loc:integer);
    251     procedure SetTroopLoc(Loc:integer);
    252     procedure ProcessRect(x0,y0,nx,ny,Options: integer);
     247    procedure NextUnit(NearLoc: integer; AutoTurn: boolean);
     248    procedure Scroll(dx, dy: integer);
     249    procedure Centre(Loc: integer);
     250    procedure SetTroopLoc(Loc: integer);
     251    procedure ProcessRect(x0, y0, nx, ny, Options: integer);
    253252    procedure PaintLoc(Loc: integer; Radius: integer = 0);
    254253    procedure PaintLoc_BeforeMove(FromLoc: integer);
    255254    procedure PaintLocTemp(Loc: integer; Style: integer = pltsNormal);
    256     procedure PaintBufferToScreen(xMap,yMap,width,height: integer);
     255    procedure PaintBufferToScreen(xMap, yMap, width, height: integer);
    257256    procedure PaintDestination;
    258     procedure SetUnFocus(uix:integer);
    259     function MoveUnit(dx,dy:integer; Options: integer = 0): integer;
     257    procedure SetUnFocus(uix: integer);
     258    function MoveUnit(dx, dy: integer; Options: integer = 0): integer;
    260259    procedure MoveToLoc(Loc: integer; CheckSuicide: boolean);
    261     procedure MoveOnScreen(ShowMove: TShowMove; Step0,Step1,nStep: integer;
     260    procedure MoveOnScreen(ShowMove: TShowMove; Step0, Step1, nStep: integer;
    262261      Restore: boolean = true);
    263     procedure FocusOnLoc(Loc:integer; Options: integer = 0);
     262    procedure FocusOnLoc(Loc: integer; Options: integer = 0);
    264263    function EndTurn(WasSkipped: boolean = false): boolean;
    265264    procedure EndNego;
    266     function IsPanelPixel(x,y: integer): boolean;
     265    function IsPanelPixel(x, y: integer): boolean;
    267266    procedure InitPopup(Popup: TPopupMenu);
    268267    procedure SetMapOptions;
     
    272271    procedure SetDebugMap(p: integer);
    273272    procedure SetViewpoint(p: integer);
    274     function LocationOfScreenPixel(x,y: integer): integer;
    275     procedure SetTileSize(x,y: integer);
    276     procedure RectInvalidate(Left,Top,Rigth,Bottom: integer);
    277     procedure SmartRectInvalidate(Left,Top,Rigth,Bottom: integer);
     273    function LocationOfScreenPixel(x, y: integer): integer;
     274    procedure SetTileSize(x, y: integer);
     275    procedure RectInvalidate(Left, Top, Rigth, Bottom: integer);
     276    procedure SmartRectInvalidate(Left, Top, Rigth, Bottom: integer);
    278277    procedure SaveSettings;
    279     procedure OnScroll(var m:TMessage); message WM_VSCROLL;
    280     procedure OnEOT(var Msg:TMessage); message WM_EOT;
     278    procedure OnScroll(var m: TMessage); message WM_VSCROLL;
     279    procedure OnEOT(var Msg: TMessage); message WM_EOT;
    281280  end;
    282281
    283282var
    284 MainScreen:TMainScreen;
     283  MainScreen: TMainScreen;
    285284
    286285type
    287 TTribeInfo=record
    288   trix: integer;
    289   FileName: ShortString;
     286  TTribeInfo = record
     287    trix: integer;
     288    FileName: ShortString;
    290289  end;
    291 TCityNameInfo=record
    292   ID: integer;
    293   NewName: ShortString
    294   end;
    295 TModelNameInfo=record
    296   mix: integer;
    297   NewName: ShortString
    298   end;
    299 TPriceSet=Set of $00..$FF;
    300 
    301 const
    302 crImpDrag=2;
    303 crFlatHand=3;
    304 
    305 xxu=32; yyu=24; // half of unit slot size x/y
    306 yyu_anchor=32;
    307 xxc=32; yyc=16; // 1/2 of city slot size in x, 1/2 of ground tile size in y (=1/3 of slot)
    308 
    309 // layout
    310 TopBarHeight=41;
    311 PanelHeight=168;
    312 MidPanelHeight=120; // TopBarHeight+MidPanelHeight should be same as BaseWin.yUnused
    313 MapCenterUp=(MidPanelHeight-TopBarHeight) div 2;
    314 
    315 nCityType=4;
    316 
    317 {client exclusive commands:}
    318 cSetTribe=$9000;cSetNewModelPicture=$9100;cSetModelName=$9110;
    319 cSetModelPicture=$9120;cSetSlaveIndex=$9131;
    320 cSetCityName=$9200;
    321 
    322 // city status flags
    323 csTypeMask=$0007; csToldDelay=$0008; csResourceWeightsMask=$00F0;
    324 csToldBombard=$0100;
    325 
    326 {unit status flags}
    327 usStay=$01; usWaiting=$02; usGoto=$04; usEnhance=$08; usRecover=$10;
    328 usToldNoReturn=$100;
    329 usPersistent=usStay or usGoto or usEnhance or usRecover or integer($FFFF0000);
    330 
    331 {model status flags}
    332 msObsolete=$1; msAllowConscripts=$2;
    333 
    334 {additional city happened flags}
    335 chTypeDel=$8000; chAllImpsMade=$4000;
    336 
    337 adNone=$801; adFar=$802; adNexus=$803;
    338 
    339 SpecialModelPictureCode: array[0..nSpecialModel-1] of integer=
    340 (10,11,40,41,21,30,{50,51,}64,74,{71,}73);
    341 
    342 pixSlaves=0; pixNoSlaves=1; // index of slaves in StdUnits
    343 
    344 // icons.bmp properties
    345 xSizeSmall=36; ySizeSmall=20;
    346 SystemIconLines=2; // lines of system icons in icons.bmp before improvements
    347 
    348 // save options apart from what's defined by SaveOption
    349 soTellAI=30;
    350 soExtraMask=$40000000;
    351 
    352 nCityEventPriority=16;
    353 CityEventPriority: array[0..nCityEventPriority-1] of integer=
    354 (chDisorder,chImprovementLost,chUnitLost,chAllImpsMade,chProduction,
    355 chOldWonder,chNoSettlerProd,chPopDecrease,chProductionSabotaged,
    356 chNoGrowthWarning,chPollution,chTypeDel,chFounded,chSiege,chAfterCapture,
    357 chPopIncrease);
    358 
    359 CityEventSoundItem: array[0..15] of string=
    360 ('CITY_DISORDER','','CITY_POPPLUS','CITY_POPMINUS','CITY_UNITLOST',
    361 'CITY_IMPLOST','CITY_SABOTAGE','CITY_GROWTHNEEDSIMP','CITY_POLLUTION',
    362 'CITY_SIEGE','CITY_WONDEREX','CITY_EMDELAY','CITY_FOUNDED','CITY_FOUNDED','',
    363 'CITY_INVALIDTYPE');
    364 
    365 type
    366 TPersistentData=record
    367   FarTech, ToldAge, ToldModels, ToldAlive, ToldContact, ToldOwnCredibility,
    368     ColdWarStart, PeaceEvaHappened: integer;
    369   EnhancementJobs: TEnhancementJobs;
    370   ImpOrder: array[0..nCityType-1] of TImpOrder;
    371   ToldWonders: array[0..27] of TWonderInfo;
    372   ToldTech: array[0..nAdv-1] of ShortInt;
    373   end;
    374 
    375 var
    376 MyData: ^TPersistentData;
    377 AdvIcon:array[0..nAdv-1] of integer; {icons displayed with the technologies}
    378 xxt,yyt, // half of tile size x/y
    379   GameMode,ClientMode,Age,UnFocus,OptionChecked,MapOptionChecked,nLostArmy,
    380   ScienceSum,TaxSum,SoundPreloadDone,MarkCityLoc,HGrTerrain,HGrCities,
    381   MovieSpeed: integer;
    382 CityRepMask: cardinal;
    383 ReceivedOffer: TOffer;
    384 Buffer,SmallImp: TBitmap;
    385 BlinkON,DestinationMarkON,StartRunning,StayOnTop_Ensured,supervising: boolean;
    386 UnusedTribeFiles, TribeNames: tstringlist;
    387 TribeOriginal: array[0..nPl-1] of boolean;
    388 LostArmy: array[0..nPl*nMmax-1] of integer;
    389 DipMem: array[0..nPl-1] of record
    390   pContact, SentCommand, FormerTreaty: integer;
    391   SentOffer: TOffer;
    392   DeliveredPrices, ReceivedPrices: TPriceSet;
     290
     291  TCityNameInfo = record
     292    ID: integer;
     293    NewName: ShortString end;
     294    TModelNameInfo = record mix: integer;
     295    NewName: ShortString end;
     296    TPriceSet = Set of $00 .. $FF;
     297
     298  const
     299    crImpDrag = 2;
     300    crFlatHand = 3;
     301
     302    xxu = 32;
     303    yyu = 24; // half of unit slot size x/y
     304    yyu_anchor = 32;
     305    xxc = 32;
     306    yyc = 16; // 1/2 of city slot size in x, 1/2 of ground tile size in y (=1/3 of slot)
     307
     308    // layout
     309    TopBarHeight = 41;
     310    PanelHeight = 168;
     311    MidPanelHeight = 120;
     312    // TopBarHeight+MidPanelHeight should be same as BaseWin.yUnused
     313    MapCenterUp = (MidPanelHeight - TopBarHeight) div 2;
     314
     315    nCityType = 4;
     316
     317    { client exclusive commands: }
     318    cSetTribe = $9000;
     319    cSetNewModelPicture = $9100;
     320    cSetModelName = $9110;
     321    cSetModelPicture = $9120;
     322    cSetSlaveIndex = $9131;
     323    cSetCityName = $9200;
     324
     325    // city status flags
     326    csTypeMask = $0007;
     327    csToldDelay = $0008;
     328    csResourceWeightsMask = $00F0;
     329    csToldBombard = $0100;
     330
     331    { unit status flags }
     332    usStay = $01;
     333    usWaiting = $02;
     334    usGoto = $04;
     335    usEnhance = $08;
     336    usRecover = $10;
     337    usToldNoReturn = $100;
     338    usPersistent = usStay or usGoto or usEnhance or usRecover or
     339      integer($FFFF0000);
     340
     341    { model status flags }
     342    msObsolete = $1;
     343    msAllowConscripts = $2;
     344
     345    { additional city happened flags }
     346    chTypeDel = $8000;
     347    chAllImpsMade = $4000;
     348
     349    adNone = $801;
     350    adFar = $802;
     351    adNexus = $803;
     352
     353    SpecialModelPictureCode: array [0 .. nSpecialModel - 1] of integer = (10,
     354      11, 40, 41, 21, 30, { 50,51, } 64, 74, { 71, } 73);
     355
     356    pixSlaves = 0;
     357    pixNoSlaves = 1; // index of slaves in StdUnits
     358
     359    // icons.bmp properties
     360    xSizeSmall = 36;
     361    ySizeSmall = 20;
     362    SystemIconLines = 2;
     363    // lines of system icons in icons.bmp before improvements
     364
     365    // save options apart from what's defined by SaveOption
     366    soTellAI = 30;
     367    soExtraMask = $40000000;
     368
     369    nCityEventPriority = 16;
     370    CityEventPriority: array [0 .. nCityEventPriority - 1] of integer =
     371      (chDisorder, chImprovementLost, chUnitLost, chAllImpsMade, chProduction,
     372      chOldWonder, chNoSettlerProd, chPopDecrease, chProductionSabotaged,
     373      chNoGrowthWarning, chPollution, chTypeDel, chFounded, chSiege,
     374      chAfterCapture, chPopIncrease);
     375
     376    CityEventSoundItem: array [0 .. 15] of string = ('CITY_DISORDER', '',
     377      'CITY_POPPLUS', 'CITY_POPMINUS', 'CITY_UNITLOST', 'CITY_IMPLOST',
     378      'CITY_SABOTAGE', 'CITY_GROWTHNEEDSIMP', 'CITY_POLLUTION', 'CITY_SIEGE',
     379      'CITY_WONDEREX', 'CITY_EMDELAY', 'CITY_FOUNDED', 'CITY_FOUNDED', '',
     380      'CITY_INVALIDTYPE');
     381
     382  type
     383    TPersistentData = record
     384      FarTech, ToldAge, ToldModels, ToldAlive, ToldContact, ToldOwnCredibility,
     385        ColdWarStart, PeaceEvaHappened: integer;
     386      EnhancementJobs: TEnhancementJobs;
     387      ImpOrder: array [0 .. nCityType - 1] of TImpOrder;
     388      ToldWonders: array [0 .. 27] of TWonderInfo;
     389      ToldTech: array [0 .. nAdv - 1] of ShortInt;
     390    end;
     391
     392  var
     393    MyData: ^TPersistentData;
     394    AdvIcon: array [0 .. nAdv - 1] of integer;
     395    { icons displayed with the technologies }
     396    xxt, yyt, // half of tile size x/y
     397    GameMode, ClientMode, Age, UnFocus, OptionChecked, MapOptionChecked,
     398      nLostArmy, ScienceSum, TaxSum, SoundPreloadDone, MarkCityLoc, HGrTerrain,
     399      HGrCities, MovieSpeed: integer;
     400    CityRepMask: Cardinal;
     401    ReceivedOffer: TOffer;
     402    Buffer, SmallImp: TBitmap;
     403    BlinkON, DestinationMarkON, StartRunning, StayOnTop_Ensured,
     404      supervising: boolean;
     405    UnusedTribeFiles, TribeNames: tstringlist;
     406    TribeOriginal: array [0 .. nPl - 1] of boolean;
     407    LostArmy: array [0 .. nPl * nMmax - 1] of integer;
     408    DipMem: array [0 .. nPl - 1] of record pContact, SentCommand,
     409      FormerTreaty: integer;
     410    SentOffer: TOffer;
     411    DeliveredPrices, ReceivedPrices: TPriceSet;
    393412  end;
    394413
     
    400419procedure InitMyModel(mix: integer; final: boolean);
    401420
    402 procedure ImpImage(ca: TCanvas; x,y,iix: integer; Government: integer = -1;
     421procedure ImpImage(ca: TCanvas; x, y, iix: integer; Government: integer = -1;
    403422  IsControl: boolean = false);
    404423procedure HelpOnTerrain(Loc, NewMode: integer);
    405424
    406 
    407425implementation
    408426
    409427uses
    410   Directories,IsoEngine,CityScreen,Draft,MessgEx,Select,CityType,Help,
    411   UnitStat,Diplomacy,Inp,log,Diagram,NatStat,Wonders,Enhance,Nego,Battle,Rates,
     428  Directories, IsoEngine, CityScreen, Draft, MessgEx, Select, CityType, Help,
     429  UnitStat, Diplomacy, Inp, log, Diagram, NatStat, Wonders, Enhance, Nego,
     430  Battle, Rates,
    412431  TechTree,
    413432
    414   Registry,ShellAPI;
    415 
     433  Registry, ShellAPI;
    416434
    417435{$R *.DFM}
     
    419437
    420438const
    421 lxmax_xxx=130;
    422 LeftPanelWidth=70;
    423 LeftPanelWidth_Editor=46;
    424 overlap=PanelHeight-MidPanelHeight;
    425 yTroop=PanelHeight-83;
    426 xPalace=66; yPalace=24; //120;
    427 xAdvisor=108; yAdvisor=48;
    428 xUnitText=80;
    429 PaperShade=3;
    430 BlinkOnTime=12; BlinkOffTime=6;
    431 MoveTime=300; // {time for moving a unit in ms}
    432 WaitAfterShowMove=32;
    433 FastScrolling=false; // causes problems with overlapping windows
    434 
    435 nBrushTypes=26;
    436 BrushTypes: array[0..nBrushTypes-1] of Cardinal=
    437 (fPrefStartPos,fStartPos,
    438 fShore,fGrass,fTundra,fPrairie,fDesert,fSwamp,fForest,fHills,fMountains,fArctic,
    439 fDeadLands,fDeadLands or fCobalt,fDeadLands or fUranium,
    440 fDeadLands or fMercury,fRiver,
    441 fRoad,fRR,fCanal,tiIrrigation,tiFarm,tiMine,fPoll,tiFort,tiBase);
    442 
    443 // MoveUnit options:
    444 muAutoNoWait=$0001; muAutoNext=$0002; muNoSuicideCheck=$0004;
    445 
    446 // ProcessRect options:
    447 prPaint=$0001; prAutoBounds=$0002; prInvalidate=$0004;
    448 
    449 // FocusOnLoc options:
    450 flRepaintPanel=$0001; flImmUpdate=$0002;
    451 
    452 nSaveOption=22;
     439  lxmax_xxx = 130;
     440  LeftPanelWidth = 70;
     441  LeftPanelWidth_Editor = 46;
     442  overlap = PanelHeight - MidPanelHeight;
     443  yTroop = PanelHeight - 83;
     444  xPalace = 66;
     445  yPalace = 24; // 120;
     446  xAdvisor = 108;
     447  yAdvisor = 48;
     448  xUnitText = 80;
     449  PaperShade = 3;
     450  BlinkOnTime = 12;
     451  BlinkOffTime = 6;
     452  MoveTime = 300; // {time for moving a unit in ms}
     453  WaitAfterShowMove = 32;
     454  FastScrolling = false; // causes problems with overlapping windows
     455
     456  nBrushTypes = 26;
     457  BrushTypes: array [0 .. nBrushTypes - 1] of Cardinal = (fPrefStartPos,
     458    fStartPos, fShore, fGrass, fTundra, fPrairie, fDesert, fSwamp, fForest,
     459    fHills, fMountains, fArctic, fDeadLands, fDeadLands or fCobalt,
     460    fDeadLands or fUranium, fDeadLands or fMercury, fRiver, fRoad, fRR, fCanal,
     461    tiIrrigation, tiFarm, tiMine, fPoll, tiFort, tiBase);
     462
     463  // MoveUnit options:
     464  muAutoNoWait = $0001;
     465  muAutoNext = $0002;
     466  muNoSuicideCheck = $0004;
     467
     468  // ProcessRect options:
     469  prPaint = $0001;
     470  prAutoBounds = $0002;
     471  prInvalidate = $0004;
     472
     473  // FocusOnLoc options:
     474  flRepaintPanel = $0001;
     475  flImmUpdate = $0002;
     476
     477  nSaveOption = 22;
    453478
    454479var
    455 Jump: array[0..nPl-1] of integer;
    456 pTurn,pLogo,UnStartLoc,ToldSlavery: integer;
    457 PerfFreq: int64;
    458 SmallScreen, GameOK, MapValid, skipped, idle: boolean;
    459 
    460 SaveOption: array[0..nSaveOption-1] of integer;
    461 MiniColors: array[0..11,0..1] of TColor;
    462 MainMap: TIsoMap;
    463 CurrentMoveInfo: record
    464   AfterMovePaintRadius,AfterAttackExpeller: integer;
    465   DoShow,IsAlly: boolean;
    466   end;
    467 
     480  Jump: array [0 .. nPl - 1] of integer;
     481  pTurn, pLogo, UnStartLoc, ToldSlavery: integer;
     482  PerfFreq: int64;
     483  SmallScreen, GameOK, MapValid, skipped, idle: boolean;
     484
     485  SaveOption: array [0 .. nSaveOption - 1] of integer;
     486  MiniColors: array [0 .. 11, 0 .. 1] of TColor;
     487  MainMap: TIsoMap;
     488  CurrentMoveInfo: record AfterMovePaintRadius, AfterAttackExpeller: integer;
     489  DoShow, IsAlly: boolean;
     490end;
    468491
    469492function CityEventName(i: integer): string;
    470493begin
    471 if i=14 then // chAllImpsMade
    472   if not Phrases2FallenBackToEnglish then
    473     result:=Phrases2.Lookup('CITYEVENT_ALLIMPSMADE')
    474   else result:=Phrases.Lookup('CITYEVENTS',1)
    475 else result:=Phrases.Lookup('CITYEVENTS',i);
     494  if i = 14 then // chAllImpsMade
     495    if not Phrases2FallenBackToEnglish then
     496      result := Phrases2.Lookup('CITYEVENT_ALLIMPSMADE')
     497    else
     498      result := Phrases.Lookup('CITYEVENTS', 1)
     499  else
     500    result := Phrases.Lookup('CITYEVENTS', i);
    476501end;
    477502
    478503procedure InitSmallImp;
    479504const
    480 cut=4;
    481 Sharpen=80;
     505  cut = 4;
     506  Sharpen = 80;
    482507type
    483 TLine=array[0..99999,0..2] of Byte;
    484 TBuffer=array[0..99999,0..2] of integer;
     508  TLine = array [0 .. 99999, 0 .. 2] of Byte;
     509  TBuffer = array [0 .. 99999, 0 .. 2] of integer;
    485510var
    486 sum,Cnt,dx,dy,nx,ny,ix,iy,ir,x,y,c,ch,xdivider,ydivider: integer;
    487 resampled: ^TBuffer;
    488 line: ^TLine;
     511  sum, Cnt, dx, dy, nx, ny, ix, iy, ir, x, y, c, ch, xdivider,
     512    ydivider: integer;
     513  resampled: ^TBuffer;
     514  line: ^TLine;
    489515begin
    490 nx:=BigImp.Width div xSizeBig *xSizeSmall;
    491 ny:=BigImp.Height div ySizeBig *ySizeSmall;
    492 
    493 // resample icons
    494 GetMem(resampled,nx*ny*12);
    495 FillChar(resampled^,nx*ny*12,0);
    496 for ix:=0 to BigImp.Width div xSizeBig-1 do for iy:=0 to BigImp.Height div ySizeBig-1 do
    497   for y:=0 to ySizeBig-2*cut-1 do
    498     begin
    499     ydivider:=(y*ySizeSmall div (ySizeBig-2*cut)+1)*(ySizeBig-2*cut)-y*ySizeSmall;
    500     if ydivider>ySizeSmall then ydivider:=ySizeSmall;
    501     line:=BigImp.ScanLine[cut+iy*ySizeBig+y];
    502     for x:=0 to xSizeBig-1 do
    503       begin
    504       ir:=ix*xSizeSmall+iy*nx*ySizeSmall
    505         +x*xSizeSmall div xSizeBig + y*ySizeSmall div (ySizeBig-2*cut) *nx;
    506       xdivider:=(x*xSizeSmall div xSizeBig+1)*xSizeBig-x*xSizeSmall;
    507       if xdivider>xSizeSmall then xdivider:=xSizeSmall;
    508       for ch:=0 to 2 do
    509         begin
    510         c:=line[ix*xSizeBig+x,ch];
    511         inc(resampled[ir,ch],c*xdivider*ydivider);
    512         if xdivider<xSizeSmall then
    513           inc(resampled[ir+1,ch],c*(xSizeSmall-xdivider)*ydivider);
    514         if ydivider<ySizeSmall then
    515           inc(resampled[ir+nx,ch],c*xdivider*(ySizeSmall-ydivider));
    516         if (xdivider<xSizeSmall) and (ydivider<ySizeSmall) then
    517           inc(resampled[ir+nx+1,ch],c*(xSizeSmall-xdivider)*(ySizeSmall-ydivider));
     516  nx := BigImp.width div xSizeBig * xSizeSmall;
     517  ny := BigImp.height div ySizeBig * ySizeSmall;
     518
     519  // resample icons
     520  GetMem(resampled, nx * ny * 12);
     521  FillChar(resampled^, nx * ny * 12, 0);
     522  for ix := 0 to BigImp.width div xSizeBig - 1 do
     523    for iy := 0 to BigImp.height div ySizeBig - 1 do
     524      for y := 0 to ySizeBig - 2 * cut - 1 do
     525      begin
     526        ydivider := (y * ySizeSmall div (ySizeBig - 2 * cut) + 1) *
     527          (ySizeBig - 2 * cut) - y * ySizeSmall;
     528        if ydivider > ySizeSmall then
     529          ydivider := ySizeSmall;
     530        line := BigImp.ScanLine[cut + iy * ySizeBig + y];
     531        for x := 0 to xSizeBig - 1 do
     532        begin
     533          ir := ix * xSizeSmall + iy * nx * ySizeSmall + x *
     534            xSizeSmall div xSizeBig + y *
     535            ySizeSmall div (ySizeBig - 2 * cut) * nx;
     536          xdivider := (x * xSizeSmall div xSizeBig + 1) * xSizeBig - x *
     537            xSizeSmall;
     538          if xdivider > xSizeSmall then
     539            xdivider := xSizeSmall;
     540          for ch := 0 to 2 do
     541          begin
     542            c := line[ix * xSizeBig + x, ch];
     543            inc(resampled[ir, ch], c * xdivider * ydivider);
     544            if xdivider < xSizeSmall then
     545              inc(resampled[ir + 1, ch], c * (xSizeSmall - xdivider) *
     546                ydivider);
     547            if ydivider < ySizeSmall then
     548              inc(resampled[ir + nx, ch],
     549                c * xdivider * (ySizeSmall - ydivider));
     550            if (xdivider < xSizeSmall) and (ydivider < ySizeSmall) then
     551              inc(resampled[ir + nx + 1, ch], c * (xSizeSmall - xdivider) *
     552                (ySizeSmall - ydivider));
     553          end
    518554        end
    519       end
    520     end;
    521 
    522 // sharpen resampled icons
    523 SmallImp.Width:=nx; SmallImp.Height:=ny;
    524 for y:=0 to ny-1 do
     555      end;
     556
     557  // sharpen resampled icons
     558  SmallImp.width := nx;
     559  SmallImp.height := ny;
     560  for y := 0 to ny - 1 do
    525561  begin
    526   line:=SmallImp.ScanLine[y];
    527   for x:=0 to nx-1 do
    528     for ch:=0 to 2 do
    529       begin
    530       sum:=0;
    531       Cnt:=0;
    532       for dy:=-1 to 1 do
    533         if ((dy>=0) or (y mod ySizeSmall>0)) and ((dy<=0) or (y mod ySizeSmall<ySizeSmall-1)) then
    534           for dx:=-1 to 1 do
    535             if ((dx>=0) or (x mod xSizeSmall>0)) and ((dx<=0) or (x mod xSizeSmall<xSizeSmall-1)) then
     562    line := SmallImp.ScanLine[y];
     563    for x := 0 to nx - 1 do
     564      for ch := 0 to 2 do
     565      begin
     566        sum := 0;
     567        Cnt := 0;
     568        for dy := -1 to 1 do
     569          if ((dy >= 0) or (y mod ySizeSmall > 0)) and
     570            ((dy <= 0) or (y mod ySizeSmall < ySizeSmall - 1)) then
     571            for dx := -1 to 1 do
     572              if ((dx >= 0) or (x mod xSizeSmall > 0)) and
     573                ((dx <= 0) or (x mod xSizeSmall < xSizeSmall - 1)) then
    536574              begin
    537               inc(sum,resampled[x+dx+nx*(y+dy),ch]);
    538               inc(Cnt);
     575                inc(sum, resampled[x + dx + nx * (y + dy), ch]);
     576                inc(Cnt);
    539577              end;
    540       sum:=((Cnt*Sharpen+800)*resampled[x+nx*y,ch]-sum*Sharpen) div (800*xSizeBig*(ySizeBig-2*cut));
    541       if sum<0 then sum:=0;
    542       if sum>255 then sum:=255;
    543       line[x][ch]:=sum;
     578        sum := ((Cnt * Sharpen + 800) * resampled[x + nx * y, ch] - sum *
     579          Sharpen) div (800 * xSizeBig * (ySizeBig - 2 * cut));
     580        if sum < 0 then
     581          sum := 0;
     582        if sum > 255 then
     583          sum := 255;
     584        line[x][ch] := sum;
    544585      end;
    545586  end;
    546 FreeMem(resampled);
    547 //smallimp.savetofile(homedir+'smallimp.bmp'); //!!!
     587  FreeMem(resampled);
     588  // smallimp.savetofile(homedir+'smallimp.bmp'); //!!!
    548589end;
    549590
    550 procedure ImpImage(ca: TCanvas; x,y,iix: integer; Government: integer;
     591procedure ImpImage(ca: TCanvas; x, y, iix: integer; Government: integer;
    551592  IsControl: boolean);
    552593begin
    553 if Government<0 then
    554   Government:=MyRO.Government;
    555 if (iix=imPalace) and (Government<>gAnarchy) then
    556   iix:=Government-8;
    557 FrameImage(ca, BigImp, x, y, xSizeBig, ySizeBig,
    558   (iix+SystemIconLines*7) mod 7*xSizeBig,
    559   (iix+SystemIconLines*7) div 7*ySizeBig, IsControl);
     594  if Government < 0 then
     595    Government := MyRO.Government;
     596  if (iix = imPalace) and (Government <> gAnarchy) then
     597    iix := Government - 8;
     598  FrameImage(ca, BigImp, x, y, xSizeBig, ySizeBig, (iix + SystemIconLines * 7)
     599    mod 7 * xSizeBig, (iix + SystemIconLines * 7) div 7 * ySizeBig, IsControl);
    560600end;
    561601
    562602procedure HelpOnTerrain(Loc, NewMode: integer);
    563603begin
    564 if MyMap[Loc] and fDeadLands<>0 then
    565   HelpDlg.ShowNewContent(NewMode, hkTer, 3*12)
    566 else if (MyMap[Loc] and fTerrain=fForest) and IsJungle(Loc div G.lx) then
    567   HelpDlg.ShowNewContent(NewMode, hkTer, fJungle + (MyMap[Loc] shr 5 and 3)*12)
    568 else HelpDlg.ShowNewContent(NewMode, hkTer,
    569   MyMap[Loc] and fTerrain + (MyMap[Loc] shr 5 and 3)*12);
     604  if MyMap[Loc] and fDeadLands <> 0 then
     605    HelpDlg.ShowNewContent(NewMode, hkTer, 3 * 12)
     606  else if (MyMap[Loc] and fTerrain = fForest) and IsJungle(Loc div G.lx) then
     607    HelpDlg.ShowNewContent(NewMode, hkTer,
     608      fJungle + (MyMap[Loc] shr 5 and 3) * 12)
     609  else
     610    HelpDlg.ShowNewContent(NewMode, hkTer, MyMap[Loc] and fTerrain +
     611      (MyMap[Loc] shr 5 and 3) * 12);
    570612end;
    571613
    572 
    573 {*** tribe management procedures ***}
     614{ *** tribe management procedures *** }
    574615
    575616function RoughCredibility(Credibility: integer): integer;
    576617begin
    577 case Credibility of
    578   0..69: result:=0; 70..89: result:=1; 90..99: result:=2; 100: result:=3 end;
    579 end;
    580 
    581 procedure ChooseModelPicture(p,mix,code,Hash,Turn: integer;
    582   ForceNew,final: boolean);
    583 var
    584 i: integer;
    585 Picture: TModelPictureInfo;
    586 IsNew: boolean;
    587 begin
    588 Picture.trix:=p;
    589 Picture.mix:=mix;
    590 if code=74 then
    591   begin // use correct pictures for slaves
    592   if Tribe[p].mixSlaves<0 then
    593     if not TribeOriginal[p] then Tribe[p].mixSlaves:=mix
    594     else begin i:=mix+p shl 16; Server(cSetSlaveIndex,0,0,i); end;
    595   if ToldSlavery=1 then Picture.pix:=pixSlaves else Picture.pix:=pixNoSlaves;
    596   Picture.Hash:=0;
    597   Picture.GrName:='StdUnits';
    598   IsNew:=true;
    599   end
    600 else
    601   begin
    602   Picture.Hash:=Hash;
    603   IsNew:=Tribe[p].ChooseModelPicture(Picture,code,Turn,ForceNew);
    604   end;
    605 if final then
    606   if not TribeOriginal[p] then
    607     Tribe[p].SetModelPicture(Picture, IsNew)
    608   else if IsNew then
    609     Server(cSetNewModelPicture+(Length(Picture.GrName)+1+16+3) div 4,0,
    610       0,Picture)
    611   else Server(cSetModelPicture+(Length(Picture.GrName)+1+16+3) div 4,0,
    612     0,Picture)
    613 else with Tribe[p].ModelPicture[mix] do
    614   begin
    615   HGr:=LoadGraphicSet(Picture.GrName);
    616   pix:=Picture.pix;
     618  case Credibility of
     619    0 .. 69:
     620      result := 0;
     621    70 .. 89:
     622      result := 1;
     623    90 .. 99:
     624      result := 2;
     625    100:
     626      result := 3
    617627  end;
    618628end;
    619629
     630procedure ChooseModelPicture(p, mix, code, Hash, Turn: integer;
     631  ForceNew, final: boolean);
     632var
     633  i: integer;
     634  Picture: TModelPictureInfo;
     635  IsNew: boolean;
     636begin
     637  Picture.trix := p;
     638  Picture.mix := mix;
     639  if code = 74 then
     640  begin // use correct pictures for slaves
     641    if Tribe[p].mixSlaves < 0 then
     642      if not TribeOriginal[p] then
     643        Tribe[p].mixSlaves := mix
     644      else
     645      begin
     646        i := mix + p shl 16;
     647        Server(cSetSlaveIndex, 0, 0, i);
     648      end;
     649    if ToldSlavery = 1 then
     650      Picture.pix := pixSlaves
     651    else
     652      Picture.pix := pixNoSlaves;
     653    Picture.Hash := 0;
     654    Picture.GrName := 'StdUnits';
     655    IsNew := true;
     656  end
     657  else
     658  begin
     659    Picture.Hash := Hash;
     660    IsNew := Tribe[p].ChooseModelPicture(Picture, code, Turn, ForceNew);
     661  end;
     662  if final then
     663    if not TribeOriginal[p] then
     664      Tribe[p].SetModelPicture(Picture, IsNew)
     665    else if IsNew then
     666      Server(cSetNewModelPicture + (Length(Picture.GrName) + 1 + 16 + 3) div 4,
     667        0, 0, Picture)
     668    else
     669      Server(cSetModelPicture + (Length(Picture.GrName) + 1 + 16 + 3) div 4, 0,
     670        0, Picture)
     671  else
     672    with Tribe[p].ModelPicture[mix] do
     673    begin
     674      HGr := LoadGraphicSet(Picture.GrName);
     675      pix := Picture.pix;
     676    end;
     677end;
     678
    620679function InitEnemyModel(emix: integer): boolean;
    621680begin
    622 if GameMode=cMovie then
    623   begin result:=false; exit end;
    624 with MyRO.EnemyModel[emix] do
    625   ChooseModelPicture(Owner, mix, ModelCode(MyRO.EnemyModel[emix]),
    626     ModelHash(MyRO.EnemyModel[emix]), MyRO.Turn, false, true);
    627 result:=true
     681  if GameMode = cMovie then
     682  begin
     683    result := false;
     684    exit
     685  end;
     686  with MyRO.EnemyModel[emix] do
     687    ChooseModelPicture(Owner, mix, ModelCode(MyRO.EnemyModel[emix]),
     688      ModelHash(MyRO.EnemyModel[emix]), MyRO.Turn, false, true);
     689  result := true
    628690end;
    629691
    630692procedure InitAllEnemyModels;
    631693var
    632 emix: integer;
     694  emix: integer;
    633695begin
    634 for emix:=0 to MyRO.nEnemyModel-1 do
    635   with MyRO.EnemyModel[emix] do
    636     if Tribe[Owner].ModelPicture[mix].HGr=0 then
    637       InitEnemyModel(emix);
     696  for emix := 0 to MyRO.nEnemyModel - 1 do
     697    with MyRO.EnemyModel[emix] do
     698      if Tribe[Owner].ModelPicture[mix].HGr = 0 then
     699        InitEnemyModel(emix);
    638700end;
    639701
    640702procedure InitMyModel(mix: integer; final: boolean);
    641703var
    642 mi: TModelInfo;
     704  mi: TModelInfo;
    643705begin
    644 if (GameMode=cMovie) and (MyModel[mix].Kind<$08) then exit;
     706  if (GameMode = cMovie) and (MyModel[mix].Kind < $08) then
     707    exit;
    645708  // don't exit for special units because cSetModelPicture comes after TellNewModels
    646 MakeModelInfo(me,mix,MyModel[mix],mi);
    647 ChooseModelPicture(me, mix, ModelCode(mi), ModelHash(mi), MyRO.Turn, false,
    648   final);
     709  MakeModelInfo(me, mix, MyModel[mix], mi);
     710  ChooseModelPicture(me, mix, ModelCode(mi), ModelHash(mi), MyRO.Turn,
     711    false, final);
    649712end;
    650713
    651714function AttackSound(code: integer): string;
    652715begin
    653 result:='ATTACK_'+char(48+code div 100 mod 10)+char(48+code div 10 mod 10)
    654   +char(48+code mod 10);
     716  result := 'ATTACK_' + char(48 + code div 100 mod 10) +
     717    char(48 + code div 10 mod 10) + char(48 + code mod 10);
    655718end;
    656719
     
    658721// check whether aircraft survived low-fuel warning
    659722begin
    660 assert(not supervising);
    661 with MyUn[uix] do
    662   if (Status and usToldNoReturn<>0)
    663     and ((MyMap[Loc] and fCity<>0) or (MyMap[Loc] and fTerImp=tiBase)
    664       or (Master>=0)) then
    665     Status:=Status and not usToldNoReturn;
     723  assert(not supervising);
     724  with MyUn[uix] do
     725    if (Status and usToldNoReturn <> 0) and
     726      ((MyMap[Loc] and fCity <> 0) or (MyMap[Loc] and fTerImp = tiBase) or
     727      (Master >= 0)) then
     728      Status := Status and not usToldNoReturn;
    666729end;
    667730
    668 function CreateTribe(p:integer; FileName:string; Original: boolean): boolean;
     731function CreateTribe(p: integer; FileName: string; Original: boolean): boolean;
    669732begin
    670 if not FileExists(LocalizedFilePath('Tribes\'+FileName+'.tribe.txt')) then
    671   begin result:=false; exit end;
    672 
    673 TribeOriginal[p]:=Original;
    674 Tribe[p]:=TTribe.Create(FileName);
    675 with Tribe[p] do
     733  if not FileExists(LocalizedFilePath('Tribes\' + FileName + '.tribe.txt')) then
    676734  begin
    677   if (GameMode=cNewGame) or not Original then
    678     begin
    679     Term.ChooseModelPicture(p,0,010,1,0,true,true);
    680     Term.ChooseModelPicture(p,1,040,1,0,true,true);
    681     Term.ChooseModelPicture(p,2,041,1,0,true,true);
    682     Term.ChooseModelPicture(p,-1,017,1,0,true,true);
    683     end;
    684   DipMem[p].pContact:=-1;
     735    result := false;
     736    exit
    685737  end;
    686 result:=true;
     738
     739  TribeOriginal[p] := Original;
     740  Tribe[p] := TTribe.Create(FileName);
     741  with Tribe[p] do
     742  begin
     743    if (GameMode = cNewGame) or not Original then
     744    begin
     745      Term.ChooseModelPicture(p, 0, 010, 1, 0, true, true);
     746      Term.ChooseModelPicture(p, 1, 040, 1, 0, true, true);
     747      Term.ChooseModelPicture(p, 2, 041, 1, 0, true, true);
     748      Term.ChooseModelPicture(p, -1, 017, 1, 0, true, true);
     749    end;
     750    DipMem[p].pContact := -1;
     751  end;
     752  result := true;
    687753end;
    688754
    689755procedure TellNewContacts;
    690756var
    691 p1: integer;
     757  p1: integer;
    692758begin
    693 if not supervising then
    694   for p1:=0 to nPl-1 do
    695     if (p1<>me) and (1 shl p1 and MyData.ToldContact=0)
    696       and (1 shl p1 and MyRO.Alive<>0) and (MyRO.Treaty[p1]>trNoContact) then
    697       begin
    698       TribeMessage(p1, Tribe[p1].TPhrase('FRNEWNATION'), '');
    699       MyData.ToldContact:=MyData.ToldContact or (1 shl p1);
     759  if not supervising then
     760    for p1 := 0 to nPl - 1 do
     761      if (p1 <> me) and (1 shl p1 and MyData.ToldContact = 0) and
     762        (1 shl p1 and MyRO.Alive <> 0) and (MyRO.Treaty[p1] > trNoContact) then
     763      begin
     764        TribeMessage(p1, Tribe[p1].TPhrase('FRNEWNATION'), '');
     765        MyData.ToldContact := MyData.ToldContact or (1 shl p1);
    700766      end
    701767end;
     
    703769procedure TellNewModels;
    704770var
    705 mix: integer;
    706 ModelNameInfo: TModelNameInfo;
     771  mix: integer;
     772  ModelNameInfo: TModelNameInfo;
    707773begin
    708 if supervising then
    709   exit;
    710 with Tribe[me] do while MyData.ToldModels<MyRO.nModel do
    711   begin {new Unit class available}
    712   if (ModelPicture[MyData.ToldModels].HGr>0)
    713     and (MyModel[MyData.ToldModels].Kind<>mkSelfDeveloped) then
    714     begin // save picture of DevModel
    715     ModelPicture[MyData.ToldModels+1]:=ModelPicture[MyData.ToldModels];
    716     ModelName[MyData.ToldModels+1]:=ModelName[MyData.ToldModels];
    717     ModelPicture[MyData.ToldModels].HGr:=0
    718     end;
    719   if ModelPicture[MyData.ToldModels].HGr=0 then
    720     InitMyModel(MyData.ToldModels,true); {only run if no researched model}
    721   with MessgExDlg do
    722     begin
    723 {    MakeModelInfo(me,MyData.ToldModels,MyModel[MyData.ToldModels],mi);
    724     if mi.Attack=0 then OpenSound:='MSG_DEFAULT'
    725     else OpenSound:=AttackSound(ModelCode(mi));}
    726     if MyModel[MyData.ToldModels].Kind=mkSelfDeveloped then
    727       OpenSound:='NEWMODEL_'+char(48+Age);
    728     MessgText:=Phrases.Lookup('MODELAVAILABLE');
    729     if GameMode=cMovie then
    730       begin
    731       Kind:=mkOkHelp; // doesn't matter
    732       MessgText:=MessgText+'\'+ModelName[MyData.ToldModels];
     774  if supervising then
     775    exit;
     776  with Tribe[me] do
     777    while MyData.ToldModels < MyRO.nModel do
     778    begin { new Unit class available }
     779      if (ModelPicture[MyData.ToldModels].HGr > 0) and
     780        (MyModel[MyData.ToldModels].Kind <> mkSelfDeveloped) then
     781      begin // save picture of DevModel
     782        ModelPicture[MyData.ToldModels + 1] := ModelPicture[MyData.ToldModels];
     783        ModelName[MyData.ToldModels + 1] := ModelName[MyData.ToldModels];
     784        ModelPicture[MyData.ToldModels].HGr := 0
     785      end;
     786      if ModelPicture[MyData.ToldModels].HGr = 0 then
     787        InitMyModel(MyData.ToldModels, true);
     788      { only run if no researched model }
     789      with MessgExDlg do
     790      begin
     791        { MakeModelInfo(me,MyData.ToldModels,MyModel[MyData.ToldModels],mi);
     792          if mi.Attack=0 then OpenSound:='MSG_DEFAULT'
     793          else OpenSound:=AttackSound(ModelCode(mi)); }
     794        if MyModel[MyData.ToldModels].Kind = mkSelfDeveloped then
     795          OpenSound := 'NEWMODEL_' + char(48 + Age);
     796        MessgText := Phrases.Lookup('MODELAVAILABLE');
     797        if GameMode = cMovie then
     798        begin
     799          Kind := mkOkHelp; // doesn't matter
     800          MessgText := MessgText + '\' + ModelName[MyData.ToldModels];
     801        end
     802        else
     803        begin
     804          Kind := mkModel;
     805          EInput.Text := ModelName[MyData.ToldModels];
     806        end;
     807        IconKind := mikModel;
     808        IconIndex := MyData.ToldModels;
     809        ShowModal;
     810        if (EInput.Text <> '') and (EInput.Text <> ModelName[MyData.ToldModels])
     811        then
     812        begin // user renamed model
     813          ModelNameInfo.mix := MyData.ToldModels;
     814          ModelNameInfo.NewName := EInput.Text;
     815          Server(cSetModelName + (Length(ModelNameInfo.NewName) + 1 + 4 + 3)
     816            div 4, me, 0, ModelNameInfo);
     817        end
     818      end;
     819      if MyModel[MyData.ToldModels].Kind = mkSettler then
     820      begin // engineers make settlers obsolete
     821        for mix := 0 to MyData.ToldModels - 1 do
     822          if MyModel[mix].Kind = mkSettler then
     823            MyModel[mix].Status := MyModel[mix].Status or msObsolete;
     824      end;
     825      inc(MyData.ToldModels)
     826    end;
     827end;
     828
     829procedure PaintZoomedTile(dst: TBitmap; x, y, Loc: integer);
     830
     831  procedure TSprite(xDst, yDst, xSrc, ySrc: integer);
     832  begin
     833    Sprite(dst, HGrTerrain, x + xDst, y + yDst, xxt * 2, yyt * 3,
     834      1 + xSrc * (xxt * 2 + 1), 1 + ySrc * (yyt * 3 + 1));
     835  end;
     836
     837  procedure TSprite4(xSrc, ySrc: integer);
     838  begin
     839    Sprite(dst, HGrTerrain, x + xxt, y + yyt + 2, xxt * 2, yyt * 2 - 2,
     840      1 + xSrc * (xxt * 2 + 1), 3 + yyt + ySrc * (yyt * 3 + 1));
     841    Sprite(dst, HGrTerrain, x + 4, y + 2 * yyt, xxt * 2 - 4, yyt * 2,
     842      5 + xSrc * (xxt * 2 + 1), 1 + yyt + ySrc * (yyt * 3 + 1));
     843    Sprite(dst, HGrTerrain, x + xxt * 2, y + 2 * yyt, xxt * 2 - 4, yyt * 2,
     844      1 + xSrc * (xxt * 2 + 1), 1 + yyt + ySrc * (yyt * 3 + 1));
     845    Sprite(dst, HGrTerrain, x + xxt, y + yyt * 3, xxt * 2, yyt * 2 - 2,
     846      1 + xSrc * (xxt * 2 + 1), 1 + yyt + ySrc * (yyt * 3 + 1));
     847  end;
     848
     849var
     850  cix, ySrc, Tile: integer;
     851begin
     852  Tile := MyMap[Loc];
     853  if Tile and fCity <> 0 then
     854  begin
     855    if MyRO.Tech[adRailroad] >= tsApplicable then
     856      Tile := Tile or fRR
     857    else
     858      Tile := Tile or fRoad;
     859    if Tile and fOwned <> 0 then
     860    begin
     861      cix := MyRO.nCity - 1;
     862      while (cix >= 0) and (MyCity[cix].Loc <> Loc) do
     863        dec(cix);
     864      assert(cix >= 0);
     865      if MyCity[cix].Built[imSupermarket] > 0 then
     866        Tile := Tile or tiFarm
     867      else
     868        Tile := Tile or tiIrrigation;
     869    end
     870    else
     871      Tile := Tile or tiIrrigation;
     872  end;
     873
     874  if Tile and fTerrain >= fForest then
     875    TSprite4(2, 2)
     876  else
     877    TSprite4(Tile and fTerrain, 0);
     878  if Tile and fTerrain >= fForest then
     879  begin
     880    if (Tile and fTerrain = fForest) and IsJungle(Loc div G.lx) then
     881      ySrc := 18
     882    else
     883      ySrc := 3 + 2 * (Tile and fTerrain - fForest);
     884    TSprite(xxt, 0, 6, ySrc);
     885    TSprite(0, yyt, 3, ySrc);
     886    TSprite((xxt * 2), yyt, 4, ySrc + 1);
     887    TSprite(xxt, (yyt * 2), 1, ySrc + 1);
     888  end;
     889
     890  // irrigation
     891  case Tile and fTerImp of
     892    tiIrrigation:
     893      begin
     894        TSprite(xxt, 0, 0, 12);
     895        TSprite(xxt * 2, yyt, 0, 12);
     896      end;
     897    tiFarm:
     898      begin
     899        TSprite(xxt, 0, 1, 12);
     900        TSprite(xxt * 2, yyt, 1, 12);
    733901      end
     902  end;
     903
     904  // river/canal/road/railroad
     905  if Tile and fRiver <> 0 then
     906  begin
     907    TSprite(0, yyt, 2, 14);
     908    TSprite(xxt, (yyt * 2), 2, 14);
     909  end;
     910  if Tile and fCanal <> 0 then
     911  begin
     912    TSprite(xxt, 0, 7, 11);
     913    TSprite(xxt, 0, 3, 11);
     914    TSprite(xxt * 2, yyt, 7, 11);
     915    TSprite(xxt * 2, yyt, 3, 11);
     916  end;
     917  if Tile and fRR <> 0 then
     918  begin
     919    TSprite((xxt * 2), yyt, 1, 10);
     920    TSprite((xxt * 2), yyt, 5, 10);
     921    TSprite(xxt, (yyt * 2), 1, 10);
     922    TSprite(xxt, (yyt * 2), 5, 10);
     923  end
     924  else if Tile and fRoad <> 0 then
     925  begin
     926    TSprite((xxt * 2), yyt, 8, 9);
     927    TSprite((xxt * 2), yyt, 5, 9);
     928    TSprite(xxt, (yyt * 2), 1, 9);
     929    TSprite(xxt, (yyt * 2), 5, 9);
     930  end;
     931
     932  if Tile and fPoll <> 0 then
     933    TSprite(xxt, (yyt * 2), 6, 12);
     934
     935  // special
     936  if Tile and (fTerrain or fSpecial) = fGrass or fSpecial1 then
     937    TSprite4(2, 1)
     938  else if Tile and fSpecial <> 0 then
     939    if Tile and fTerrain < fForest then
     940      TSprite(0, yyt, Tile and fTerrain, Tile and fSpecial shr 5)
     941    else if (Tile and fTerrain = fForest) and IsJungle(Loc div G.lx) then
     942      TSprite(0, yyt, 8, 17 + Tile and fSpecial shr 5)
    734943    else
    735       begin
    736       Kind:=mkModel;
    737       EInput.Text:=ModelName[MyData.ToldModels];
     944      TSprite(0, yyt, 8, 2 + (Tile and fTerrain - fForest) * 2 + Tile and
     945        fSpecial shr 5)
     946  else if Tile and fDeadLands <> 0 then
     947  begin
     948    TSprite4(6, 2);
     949    TSprite(xxt, yyt, 8, 12 + Tile shr 25 and 3);
     950  end;
     951
     952  // other improvements
     953  case Tile and fTerImp of
     954    tiMine:
     955      TSprite(xxt, 0, 2, 12);
     956    tiFort:
     957      begin
     958        TSprite(xxt, 0, 7, 12);
     959        TSprite(xxt, 0, 3, 12);
    738960      end;
    739     IconKind:=mikModel;
    740     IconIndex:=MyData.ToldModels;
    741     ShowModal;
    742     if (EInput.Text<>'') and (EInput.Text<>ModelName[MyData.ToldModels]) then
    743       begin // user renamed model
    744       ModelNameInfo.mix:=MyData.ToldModels;
    745       ModelNameInfo.NewName:=EInput.Text;
    746       Server(cSetModelName+(Length(ModelNameInfo.NewName)+1+4+3) div 4,
    747         me,0,ModelNameInfo);
    748       end
    749     end;
    750   if MyModel[MyData.ToldModels].kind=mkSettler then
    751     begin // engineers make settlers obsolete
    752     for mix:=0 to MyData.ToldModels-1 do
    753       if MyModel[mix].Kind=mkSettler then
    754         MyModel[mix].Status:=MyModel[mix].Status or msObsolete;
    755     end;
    756   inc(MyData.ToldModels)
     961    tiBase:
     962      TSprite(xxt, 0, 4, 12);
    757963  end;
    758964end;
    759965
    760 procedure PaintZoomedTile(dst: TBitmap; x,y,Loc: integer);
    761 
    762   procedure TSprite(xDst, yDst, xSrc, ySrc: integer);
     966function ChooseResearch: boolean;
     967var
     968  ChosenResearch: integer;
     969begin
     970  if (MyData.FarTech <> adNone) and (MyRO.Tech[MyData.FarTech] >= tsApplicable)
     971  then
     972    MyData.FarTech := adNone;
     973  repeat
     974    { research complete -- select new }
     975    repeat
     976      ModalSelectDlg.ShowNewContent(wmModal, kAdvance);
     977      if ModalSelectDlg.result < 0 then
     978      begin
     979        result := false;
     980        exit
     981      end;
     982      ChosenResearch := ModalSelectDlg.result;
     983      if ChosenResearch = adMilitary then
     984      begin
     985        DraftDlg.ShowNewContent(wmModal);
     986        if DraftDlg.ModalResult <> mrOK then
     987          Tribe[me].ModelPicture[MyRO.nModel].HGr := 0
     988      end
     989      until (ChosenResearch <> adMilitary) or (DraftDlg.ModalResult = mrOK);
     990
     991      if ChosenResearch = adMilitary then
     992        InitMyModel(MyRO.nModel, true)
     993      else if ChosenResearch = adFar then
     994      begin
     995        ModalSelectDlg.ShowNewContent(wmModal, kFarAdvance);
     996        if ModalSelectDlg.result >= 0 then
     997          if (ModalSelectDlg.result = adNone) or
     998            (Server(sSetResearch - sExecute, me, ModalSelectDlg.result, nil^) <
     999            rExecuted) then
     1000            MyData.FarTech := ModalSelectDlg.result
     1001          else
     1002          begin
     1003            ChosenResearch := ModalSelectDlg.result;
     1004            // can be researched immediately
     1005            MyData.FarTech := adNone
     1006          end
     1007      end;
     1008    until ChosenResearch <> adFar;
     1009    if ChosenResearch = adNexus then
     1010      MyData.FarTech := adNexus
     1011    else
     1012      Server(sSetResearch, me, ChosenResearch, nil^);
     1013    ListDlg.TechChange;
     1014    result := true;
     1015  end;
     1016
     1017  (* ** client function handling ** *)
     1018
     1019  function TMainScreen.DipCall(Command: integer): integer;
     1020  var
     1021    i: integer;
     1022    IsTreatyDeal: boolean;
    7631023  begin
    764   Sprite(dst, HGrTerrain, x+xDst, y+yDst, xxt*2, yyt*3, 1+xSrc*(xxt*2+1),
    765     1+ySrc*(yyt*3+1));
    766   end;
    767 
    768   procedure TSprite4(xSrc, ySrc: integer);
    769   begin
    770   Sprite(dst, HGrTerrain, x+xxt, y+yyt+2, xxt*2, yyt*2-2, 1+xSrc*(xxt*2+1),
    771     3+yyt+ySrc*(yyt*3+1));
    772   Sprite(dst, HGrTerrain, x+4, y+2*yyt, xxt*2-4, yyt*2, 5+xSrc*(xxt*2+1),
    773     1+yyt+ySrc*(yyt*3+1));
    774   Sprite(dst, HGrTerrain, x+xxt*2, y+2*yyt, xxt*2-4, yyt*2, 1+xSrc*(xxt*2+1),
    775     1+yyt+ySrc*(yyt*3+1));
    776   Sprite(dst, HGrTerrain, x+xxt, y+yyt*3, xxt*2, yyt*2-2, 1+xSrc*(xxt*2+1),
    777     1+yyt+ySrc*(yyt*3+1));
    778   end;
    779 
    780 var
    781 cix, ySrc, Tile: integer;
    782 begin
    783 Tile:=MyMap[Loc];
    784 if Tile and fCity<>0 then
    785   begin
    786   if MyRO.Tech[adRailroad]>=tsApplicable then
    787     Tile:=Tile or fRR
    788   else Tile:=Tile or fRoad;
    789   if Tile and fOwned<>0 then
    790     begin
    791     cix:=MyRO.nCity-1;
    792     while (cix>=0) and (MyCity[cix].Loc<>Loc) do dec(cix);
    793     assert(cix>=0);
    794     if MyCity[cix].Built[imSupermarket]>0 then
    795       Tile:=Tile or tiFarm
    796     else Tile:=Tile or tiIrrigation;
    797     end
    798   else Tile:=Tile or tiIrrigation;
    799   end;
    800 
    801 if Tile and fTerrain>=fForest then TSprite4(2,2)
    802 else TSprite4(Tile and fTerrain,0);
    803 if Tile and fTerrain>=fForest then
    804   begin
    805   if (Tile and fTerrain=fForest) and IsJungle(Loc div G.lx) then ySrc:=18
    806   else ySrc:=3+2*(Tile and fTerrain-fForest);
    807   TSprite(xxt, 0, 6, ySrc);
    808   TSprite(0, yyt, 3, ySrc);
    809   TSprite((xxt*2), yyt, 4, ySrc+1);
    810   TSprite(xxt, (yyt*2), 1, ySrc+1);
    811   end;
    812 
    813 // irrigation
    814 case Tile and fTerImp of
    815   tiIrrigation:
    816     begin
    817     TSprite(xxt,0,0,12);
    818     TSprite(xxt*2,yyt,0,12);
    819     end;
    820   tiFarm:
    821     begin
    822     TSprite(xxt,0,1,12);
    823     TSprite(xxt*2,yyt,1,12);
     1024    result := Server(Command, me, 0, nil^);
     1025    if result >= rExecuted then
     1026    begin
     1027      if Command and $FF0F = scContact then
     1028      begin
     1029        DipMem[me].pContact := Command shr 4 and $F;
     1030        NegoDlg.Initiate;
     1031        DipMem[me].DeliveredPrices := [];
     1032        DipMem[me].ReceivedPrices := [];
     1033      end;
     1034
     1035      DipMem[me].SentCommand := Command;
     1036      DipMem[me].FormerTreaty := MyRO.Treaty[DipMem[me].pContact];
     1037      if Command = scDipCancelTreaty then
     1038        Play('CANCELTREATY')
     1039      else if Command = scDipAccept then
     1040      begin // remember delivered and received prices
     1041        for i := 0 to ReceivedOffer.nDeliver - 1 do
     1042          include(DipMem[me].ReceivedPrices, ReceivedOffer.Price[i] shr 24);
     1043        for i := 0 to ReceivedOffer.nCost - 1 do
     1044          include(DipMem[me].DeliveredPrices,
     1045            ReceivedOffer.Price[ReceivedOffer.nDeliver + i] shr 24);
     1046        IsTreatyDeal := false;
     1047        for i := 0 to ReceivedOffer.nDeliver + ReceivedOffer.nCost - 1 do
     1048          if ReceivedOffer.Price[i] and opMask = opTreaty then
     1049            IsTreatyDeal := true;
     1050        if IsTreatyDeal then
     1051          Play('NEWTREATY')
     1052        else
     1053          Play('ACCEPTOFFER');
     1054      end;
     1055      CityDlg.CloseAction := None;
     1056      if G.RO[DipMem[me].pContact] <> nil then
     1057      begin // close windows for next player
     1058        for i := 0 to Screen.FormCount - 1 do
     1059          if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
     1060          then
     1061            Screen.Forms[i].Close;
     1062      end
     1063      else
     1064      begin
     1065        if CityDlg.Visible then
     1066          CityDlg.Close;
     1067        if UnitStatDlg.Visible then
     1068          UnitStatDlg.Close;
     1069      end
    8241070    end
    8251071  end;
    8261072
    827 // river/canal/road/railroad
    828 if Tile and fRiver<>0 then
     1073  function TMainScreen.OfferCall(var Offer: TOffer): integer;
     1074  var
     1075    i: integer;
    8291076  begin
    830   TSprite(0, yyt, 2, 14);
    831   TSprite(xxt, (yyt*2), 2, 14);
     1077    result := Server(scDipOffer, me, 0, Offer);
     1078    if result >= rExecuted then
     1079    begin
     1080      DipMem[me].SentCommand := scDipOffer;
     1081      DipMem[me].FormerTreaty := MyRO.Treaty[DipMem[me].pContact];
     1082      DipMem[me].SentOffer := Offer;
     1083      CityDlg.CloseAction := None;
     1084      if G.RO[DipMem[me].pContact] <> nil then
     1085      begin // close windows for next player
     1086        for i := 0 to Screen.FormCount - 1 do
     1087          if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
     1088          then
     1089            Screen.Forms[i].Close;
     1090      end
     1091      else
     1092      begin
     1093        if CityDlg.Visible then
     1094          CityDlg.Close;
     1095        if UnitStatDlg.Visible then
     1096          UnitStatDlg.Close;
     1097      end
     1098    end
    8321099  end;
    833 if Tile and fCanal<>0 then
     1100
     1101  procedure TMainScreen.SetUnFocus(uix: integer);
     1102  var
     1103    Loc0: integer;
    8341104  begin
    835   TSprite(xxt, 0, 7, 11);
    836   TSprite(xxt, 0, 3, 11);
    837   TSprite(xxt*2,yyt,7,11);
    838   TSprite(xxt*2,yyt,3,11);
    839   end;
    840 if Tile and fRR<>0 then
    841   begin
    842   TSprite((xxt*2), yyt, 1, 10);
    843   TSprite((xxt*2), yyt, 5, 10);
    844   TSprite(xxt, (yyt*2), 1, 10);
    845   TSprite(xxt, (yyt*2), 5, 10);
    846   end
    847 else if Tile and fRoad<>0 then
    848   begin
    849   TSprite((xxt*2), yyt, 8, 9);
    850   TSprite((xxt*2), yyt, 5, 9);
    851   TSprite(xxt, (yyt*2), 1, 9);
    852   TSprite(xxt, (yyt*2), 5, 9);
    853   end;
    854 
    855 if Tile and fPoll<>0 then
    856   TSprite(xxt,(yyt*2),6,12);
    857 
    858 // special
    859 if Tile and (fTerrain or fSpecial)=fGrass or fSpecial1 then
    860   TSprite4(2,1)
    861 else if Tile and fSpecial<>0 then
    862   if Tile and fTerrain<fForest then
    863     TSprite(0, yyt, Tile and fTerrain, Tile and fSpecial shr 5)
    864   else if (Tile and fTerrain=fForest) and IsJungle(Loc div G.lx) then
    865     TSprite(0, yyt, 8, 17+Tile and fSpecial shr 5)
    866   else TSprite(0, yyt, 8, 2+(Tile and fTerrain-fForest)*2+Tile and fSpecial shr 5)
    867 else if Tile and fDeadLands<>0 then
    868   begin
    869   TSprite4(6,2);
    870   TSprite(xxt, yyt, 8, 12+Tile shr 25 and 3);
    871   end;
    872 
    873 // other improvements
    874 case Tile and fTerImp of
    875   tiMine: TSprite(xxt, 0, 2, 12);
    876   tiFort: begin TSprite(xxt, 0, 7, 12); TSprite(xxt, 0, 3, 12); end;
    877   tiBase: TSprite(xxt, 0, 4, 12);
    878   end;
    879 end;
    880 
    881 function ChooseResearch: boolean;
    882 var
    883 ChosenResearch: integer;
    884 begin
    885 if (MyData.FarTech<>adNone) and (MyRO.Tech[MyData.FarTech]>=tsApplicable) then
    886   MyData.FarTech:=adNone;
    887 repeat
    888   {research complete -- select new}
    889   repeat
    890     ModalSelectDlg.ShowNewContent(wmModal,kAdvance);
    891     if ModalSelectDlg.result<0 then
    892       begin result:=false; exit end;
    893     ChosenResearch:=ModalSelectDlg.result;
    894     if ChosenResearch=adMilitary then
    895       begin
    896       DraftDlg.ShowNewContent(wmModal);
    897       if DraftDlg.ModalResult<>mrOK then
    898         Tribe[me].ModelPicture[MyRO.nModel].HGr:=0
    899       end
    900   until (ChosenResearch<>adMilitary) or (DraftDlg.ModalResult=mrOK);
    901 
    902   if ChosenResearch=adMilitary then InitMyModel(MyRO.nModel,true)
    903   else if ChosenResearch=adFar then
    904     begin
    905     ModalSelectDlg.ShowNewContent(wmModal,kFarAdvance);
    906     if ModalSelectDlg.result>=0 then
    907       if (ModalSelectDlg.Result=adNone) or
    908         (Server(sSetResearch-sExecute,me,ModalSelectDlg.Result,nil^)<rExecuted) then
    909         MyData.FarTech:=ModalSelectDlg.result
    910       else
    911         begin
    912         ChosenResearch:=ModalSelectDlg.result; // can be researched immediately
    913         MyData.FarTech:=adNone
    914         end
    915     end;
    916 until ChosenResearch<>adFar;
    917 if ChosenResearch=adNexus then MyData.FarTech:=adNexus
    918 else Server(sSetResearch,me,ChosenResearch,nil^);
    919 ListDlg.TechChange;
    920 result:=true;
    921 end;
    922 
    923 
    924 (*** client function handling ***)
    925 
    926 function TMainScreen.DipCall(Command: integer): integer;
    927 var
    928 i: integer;
    929 IsTreatyDeal: boolean;
    930 begin
    931 result:=Server(Command,me,0,nil^);
    932 if result>=rExecuted then
    933   begin
    934   if Command and $FF0F=scContact then
    935     begin
    936     DipMem[me].pContact:=Command shr 4 and $f;
    937     NegoDlg.Initiate;
    938     DipMem[me].DeliveredPrices:=[];
    939     DipMem[me].ReceivedPrices:=[];
    940     end;
    941 
    942   DipMem[me].SentCommand:=Command;
    943   DipMem[me].FormerTreaty:=MyRO.Treaty[DipMem[me].pContact];
    944   if Command=scDipCancelTreaty then Play('CANCELTREATY')
    945   else if Command=scDipAccept then
    946     begin // remember delivered and received prices
    947     for i:=0 to ReceivedOffer.nDeliver-1 do
    948       include(DipMem[me].ReceivedPrices,ReceivedOffer.Price[i] shr 24);
    949     for i:=0 to ReceivedOffer.nCost-1 do
    950       include(DipMem[me].DeliveredPrices,
    951         ReceivedOffer.Price[ReceivedOffer.nDeliver+i] shr 24);
    952     IsTreatyDeal:=false;
    953     for i:=0 to ReceivedOffer.nDeliver+ReceivedOffer.nCost-1 do
    954       if ReceivedOffer.Price[i] and opMask=opTreaty then
    955         IsTreatyDeal:=true;
    956     if IsTreatyDeal then Play('NEWTREATY')
    957     else Play('ACCEPTOFFER');     
    958     end;
    959   CityDlg.CloseAction:=None;
    960   if G.RO[DipMem[me].pContact]<>nil then
    961     begin // close windows for next player
    962     for i:=0 to Screen.FormCount-1 do
    963       if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
    964         Screen.Forms[i].Close;
    965     end
    966   else
    967     begin
    968     if CityDlg.Visible then CityDlg.Close;
    969     if UnitStatDlg.Visible then UnitStatDlg.Close;
    970     end
    971   end
    972 end;
    973 
    974 function TMainScreen.OfferCall(var Offer: TOffer): integer;
    975 var
    976 i: integer;
    977 begin
    978 result:=Server(scDipOffer,me,0,Offer);
    979 if result>=rExecuted then
    980   begin
    981   DipMem[me].SentCommand:=scDipOffer;
    982   DipMem[me].FormerTreaty:=MyRO.Treaty[DipMem[me].pContact];
    983   DipMem[me].SentOffer:=Offer;
    984   CityDlg.CloseAction:=None;
    985   if G.RO[DipMem[me].pContact]<>nil then
    986     begin // close windows for next player
    987     for i:=0 to Screen.FormCount-1 do
    988       if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
    989         Screen.Forms[i].Close;
    990     end
    991   else
    992     begin
    993     if CityDlg.Visible then CityDlg.Close;
    994     if UnitStatDlg.Visible then UnitStatDlg.Close;
    995     end
    996   end
    997 end;
    998 
    999 procedure TMainScreen.SetUnFocus(uix:integer);
    1000 var
    1001 Loc0: integer;
    1002 begin
    1003 assert(not ((uix>=0) and supervising));
    1004 if uix<>UnFocus then
    1005   begin
    1006   DestinationMarkON:=false;
    1007   PaintDestination;
    1008   if uix>=0 then UnStartLoc:=MyUn[uix].Loc;
    1009   BlinkON:=false;
    1010   BlinkTime:=-1;
    1011   if UnFocus>=0 then
    1012     begin
    1013     Loc0:=MyUn[UnFocus].Loc;
    1014     if (uix<0) or (Loc0<>MyUn[uix].Loc) then
    1015       begin
    1016       UnFocus:=-1;
    1017       PaintLoc(Loc0);
    1018       end
    1019     end;
    1020   UnFocus:=uix;
    1021   end;
    1022 UnitInfoBtn.Visible:= UnFocus>=0;
    1023 UnitBtn.Visible:= UnFocus>=0;
    1024 CheckTerrainBtnVisible;
    1025 end;
    1026 
    1027 procedure TMainScreen.CheckTerrainBtnVisible;
    1028 var
    1029 Tile: integer;
    1030 mox: ^TModel;
    1031 begin
    1032 if UnFocus>=0 then
    1033   begin
    1034   mox:=@MyModel[MyUn[UnFocus].mix];
    1035   Tile:=MyMap[MyUn[UnFocus].Loc];
    1036   TerrainBtn.Visible:= (Tile and fCity=0) and (MyUn[UnFocus].Master<0)
    1037     and ((mox.Kind=mkSettler) or (mox.Kind=mkSlaves) and (MyRO.Wonder[woPyramids].EffectiveOwner>=0));
    1038   end
    1039 else TerrainBtn.Visible:=false;
    1040 end;
    1041 
    1042 procedure TMainScreen.CheckMovieSpeedBtnState;
    1043 begin
    1044 if GameMode=cMovie then
    1045   begin
    1046   MovieSpeed1Btn.Down:= MovieSpeed=1;
    1047   MovieSpeed1Btn.Visible:=true;
    1048   MovieSpeed2Btn.Down:= MovieSpeed=2;
    1049   MovieSpeed2Btn.Visible:=true;
    1050   MovieSpeed3Btn.Down:= MovieSpeed=3;
    1051   MovieSpeed3Btn.Visible:=true;
    1052   MovieSpeed4Btn.Down:= MovieSpeed=4;
    1053   MovieSpeed4Btn.Visible:=true;
    1054   end
    1055 else
    1056   begin
    1057   MovieSpeed1Btn.Visible:=false;
    1058   MovieSpeed2Btn.Visible:=false;
    1059   MovieSpeed3Btn.Visible:=false;
    1060   MovieSpeed4Btn.Visible:=false;
    1061   end
    1062 end;
    1063 
    1064 procedure TMainScreen.SetMapOptions;
    1065 begin
    1066 IsoEngine.Options:=MapOptionChecked;
    1067 if ClientMode=cEditMap then
    1068   IsoEngine.Options:=IsoEngine.Options or (1 shl moEditMode);
    1069 if mLocCodes.Checked then
    1070   IsoEngine.Options:=IsoEngine.Options or (1 shl moLocCodes);
    1071 end;
    1072 
    1073 procedure TMainScreen.UpdateViews(UpdateCityScreen: boolean);
    1074 begin
    1075 SumCities(TaxSum,ScienceSum);
    1076 PanelPaint; // TopBar was enough!!!
    1077 ListDlg.EcoChange;
    1078 NatStatDlg.EcoChange;
    1079 if UpdateCityScreen then
    1080   CityDlg.SmartUpdateContent;
    1081 end;
    1082 
    1083 procedure TMainScreen.SetAIName(p: integer; Name: string);
    1084 begin
    1085 if Name='' then
    1086   begin
    1087   if AILogo[p]<>nil then
    1088     begin AILogo[p].free; AILogo[p]:=nil end
    1089   end
    1090 else
    1091   begin
    1092   if AILogo[p]=nil then
    1093     AILogo[p]:=TBitmap.Create;
    1094   if not LoadGraphicFile(AILogo[p], HomeDir+Name, gfNoError) then
    1095     begin AILogo[p].free; AILogo[p]:=nil end
    1096   end
    1097 end;
    1098 
    1099 function TMainScreen.ContactRefused(p: integer; Item: String): boolean;
    1100 // return whether treaty was cancelled
    1101 var
    1102 s: string;
    1103 begin
    1104 assert(MyRO.Treaty[p]>=trPeace);
    1105 s:=Tribe[p].TPhrase(Item);
    1106 if MyRO.Turn<MyRO.LastCancelTreaty[p]+CancelTreatyTurns then
    1107   begin
    1108   SimpleMessage(s);
    1109   result:=false;
    1110   end
    1111 else
    1112   begin
    1113   case MyRO.Treaty[p] of
    1114     trPeace: s:=s+' '+Phrases.Lookup('FRCANCELQUERY_PEACE');
    1115     trFriendlyContact: s:=s+' '+Phrases.Lookup('FRCANCELQUERY_FRIENDLY');
    1116     trAlliance: s:=s+' '+Phrases.Lookup('FRCANCELQUERY_ALLIANCE');
    1117     end;
    1118   result:= SimpleQuery(mkYesNo,s,'NEGO_REJECTED')=mrOK;
    1119   if result then
    1120     begin
    1121     Play('CANCELTREATY');
    1122     Server(sCancelTreaty,me,0,nil^);
    1123     if MyRO.Treaty[p]=trNone then
    1124       CityOptimizer_BeginOfTurn; // peace treaty was cancelled -- use formerly forbidden tiles
    1125     MapValid:=false;
    1126     PaintAllMaps;
    1127     end
    1128   end
    1129 end;
    1130 
    1131 procedure TMainScreen.RememberPeaceViolation;
    1132 var
    1133 uix,p1: integer;
    1134 begin
    1135 MyData.PeaceEvaHappened:=0;
    1136 for uix:=0 to MyRO.nUn-1 do with MyUn[uix] do if Loc>=0 then
    1137   begin
    1138   p1:=MyRO.Territory[Loc];
    1139   if (p1<>me) and (p1>=0) and (MyRO.Turn=MyRO.EvaStart[p1]+(PeaceEvaTurns-1)) then
    1140     MyData.PeaceEvaHappened:=MyData.PeaceEvaHappened or (1 shl p1);
    1141   end;
    1142 end;
    1143 
    1144 procedure TMainScreen.Client(Command,NewPlayer:integer;var Data);
    1145 
    1146   procedure GetTribeList;
    1147   var
    1148   SearchRec: TSearchRec;
    1149   Color: TColor;
    1150   Name: string;
    1151   ok: boolean;
    1152   begin
    1153   UnusedTribeFiles.Clear;
    1154   ok:= FindFirst(DataDir+'Localization\'+'Tribes\*.tribe.txt',
    1155     faArchive+faReadOnly,SearchRec)=0;
    1156   if not ok then
    1157     begin
    1158     FindClose(SearchRec);
    1159     ok:= FindFirst(HomeDir+'Tribes\*.tribe.txt',
    1160       faArchive+faReadOnly,SearchRec)=0;
    1161     end;
    1162   if ok then
    1163     repeat
    1164       SearchRec.Name:=Copy(SearchRec.Name,1,Length(SearchRec.Name)-10);
    1165       if GetTribeInfo(SearchRec.Name,Name,Color) then
    1166         UnusedTribeFiles.AddObject(SearchRec.Name, TObject(Color));
    1167     until FindNext(SearchRec)<>0;
    1168   FindClose(SearchRec);
    1169   end;
    1170 
    1171   function ChooseUnusedTribe: integer;
    1172   var
    1173   i,j,ColorDistance, BestColorDistance, TestColorDistance, CountBest: integer;
    1174   begin
    1175   Assert(UnusedTribeFiles.Count>0);
    1176   result:=-1;
    1177   BestColorDistance:=-1;
    1178   for j:=0 to UnusedTribeFiles.Count-1 do
    1179     begin
    1180     ColorDistance:=250; // consider differences more than this infinite
    1181     for i:=0 to nPl-1 do if Tribe[i]<>nil then
    1182       begin
    1183       TestColorDistance:=abs(integer(UnusedTribeFiles.Objects[j]) shr 16 and $FF - Tribe[i].Color shr 16 and $FF)
    1184         +abs(integer(UnusedTribeFiles.Objects[j]) shr 8 and $FF - Tribe[i].Color shr 8 and $FF)*3
    1185         +abs(integer(UnusedTribeFiles.Objects[j]) and $FF - Tribe[i].Color and $FF)*2;
    1186       if TestColorDistance<ColorDistance then
    1187         ColorDistance:=TestColorDistance
    1188       end;
    1189     if ColorDistance>BestColorDistance then
    1190       begin CountBest:=0; BestColorDistance:=ColorDistance end;
    1191     if ColorDistance=BestColorDistance then
    1192       begin inc(CountBest); if random(CountBest)=0 then result:=j end
    1193     end;
    1194   end;
    1195 
    1196   procedure ShowEnemyShipChange(ShowShipChange: TShowShipChange);
    1197   var
    1198   i,TestCost,MostCost: integer;
    1199   Ship1Plus,Ship2Plus: boolean;
    1200   begin
    1201   with ShowShipChange, MessgExDlg do
    1202     begin
    1203     case Reason of
    1204       scrProduction:
    1205         begin
    1206         OpenSound:='SHIP_BUILT';
    1207         MessgText:=Tribe[Ship1Owner].TPhrase('SHIPBUILT');
    1208         IconKind:=mikShip;
    1209         IconIndex:=Ship1Owner;
    1210         end;
    1211 
    1212       scrDestruction:
    1213         begin
    1214         OpenSound:='SHIP_DESTROYED';
    1215         MessgText:=Tribe[Ship1Owner].TPhrase('SHIPDESTROYED');
    1216         IconKind:=mikImp;
    1217         end;
    1218 
    1219       scrTrade:
    1220         begin
    1221         OpenSound:='SHIP_TRADED';
    1222         Ship1Plus:=false;
    1223         Ship2Plus:=false;
    1224         for i:=0 to nShipPart-1 do
    1225           begin
    1226           if Ship1Change[i]>0 then Ship1Plus:=true;
    1227           if Ship2Change[i]>0 then Ship2Plus:=true;
    1228           end;
    1229         if Ship1Plus and Ship2Plus then
    1230           MessgText:=Tribe[Ship1Owner].TPhrase('SHIPBITRADE1')
    1231             +' '+Tribe[Ship2Owner].TPhrase('SHIPBITRADE2')
    1232         else if Ship1Plus then
    1233           MessgText:=Tribe[Ship1Owner].TPhrase('SHIPUNITRADE1')
    1234             +' '+Tribe[Ship2Owner].TPhrase('SHIPUNITRADE2')
    1235         else //if Ship2Plus then
    1236           MessgText:=Tribe[Ship2Owner].TPhrase('SHIPUNITRADE1')
    1237             +' '+Tribe[Ship1Owner].TPhrase('SHIPUNITRADE2');
    1238         IconKind:=mikImp;
    1239         end;
    1240 
    1241       scrCapture:
    1242         begin
    1243         OpenSound:='SHIP_CAPTURED';
    1244         MessgText:=Tribe[Ship2Owner].TPhrase('SHIPCAPTURE1')
    1245           +' '+Tribe[Ship1Owner].TPhrase('SHIPCAPTURE2');
    1246         IconKind:=mikShip;
    1247         IconIndex:=Ship2Owner;
     1105    assert(not((uix >= 0) and supervising));
     1106    if uix <> UnFocus then
     1107    begin
     1108      DestinationMarkON := false;
     1109      PaintDestination;
     1110      if uix >= 0 then
     1111        UnStartLoc := MyUn[uix].Loc;
     1112      BlinkON := false;
     1113      BlinkTime := -1;
     1114      if UnFocus >= 0 then
     1115      begin
     1116        Loc0 := MyUn[UnFocus].Loc;
     1117        if (uix < 0) or (Loc0 <> MyUn[uix].Loc) then
     1118        begin
     1119          UnFocus := -1;
     1120          PaintLoc(Loc0);
    12481121        end
    12491122      end;
    1250 
    1251     if IconKind=mikImp then
    1252       begin
    1253       MostCost:=0;
    1254       for i:=0 to nShipPart-1 do
    1255         begin
    1256         TestCost:=abs(Ship1Change[i])*Imp[imShipComp+i].Cost;
    1257         if TestCost>MostCost then
    1258           begin MostCost:=TestCost; IconIndex:=imShipComp+i end
    1259         end;
     1123      UnFocus := uix;
     1124    end;
     1125    UnitInfoBtn.Visible := UnFocus >= 0;
     1126    UnitBtn.Visible := UnFocus >= 0;
     1127    CheckTerrainBtnVisible;
     1128  end;
     1129
     1130  procedure TMainScreen.CheckTerrainBtnVisible;
     1131  var
     1132    Tile: integer;
     1133    mox: ^TModel;
     1134  begin
     1135    if UnFocus >= 0 then
     1136    begin
     1137      mox := @MyModel[MyUn[UnFocus].mix];
     1138      Tile := MyMap[MyUn[UnFocus].Loc];
     1139      TerrainBtn.Visible := (Tile and fCity = 0) and (MyUn[UnFocus].Master < 0)
     1140        and ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves) and
     1141        (MyRO.Wonder[woPyramids].EffectiveOwner >= 0));
     1142    end
     1143    else
     1144      TerrainBtn.Visible := false;
     1145  end;
     1146
     1147  procedure TMainScreen.CheckMovieSpeedBtnState;
     1148  begin
     1149    if GameMode = cMovie then
     1150    begin
     1151      MovieSpeed1Btn.Down := MovieSpeed = 1;
     1152      MovieSpeed1Btn.Visible := true;
     1153      MovieSpeed2Btn.Down := MovieSpeed = 2;
     1154      MovieSpeed2Btn.Visible := true;
     1155      MovieSpeed3Btn.Down := MovieSpeed = 3;
     1156      MovieSpeed3Btn.Visible := true;
     1157      MovieSpeed4Btn.Down := MovieSpeed = 4;
     1158      MovieSpeed4Btn.Visible := true;
     1159    end
     1160    else
     1161    begin
     1162      MovieSpeed1Btn.Visible := false;
     1163      MovieSpeed2Btn.Visible := false;
     1164      MovieSpeed3Btn.Visible := false;
     1165      MovieSpeed4Btn.Visible := false;
     1166    end
     1167  end;
     1168
     1169  procedure TMainScreen.SetMapOptions;
     1170  begin
     1171    IsoEngine.Options := MapOptionChecked;
     1172    if ClientMode = cEditMap then
     1173      IsoEngine.Options := IsoEngine.Options or (1 shl moEditMode);
     1174    if mLocCodes.Checked then
     1175      IsoEngine.Options := IsoEngine.Options or (1 shl moLocCodes);
     1176  end;
     1177
     1178  procedure TMainScreen.UpdateViews(UpdateCityScreen: boolean);
     1179  begin
     1180    SumCities(TaxSum, ScienceSum);
     1181    PanelPaint; // TopBar was enough!!!
     1182    ListDlg.EcoChange;
     1183    NatStatDlg.EcoChange;
     1184    if UpdateCityScreen then
     1185      CityDlg.SmartUpdateContent;
     1186  end;
     1187
     1188  procedure TMainScreen.SetAIName(p: integer; Name: string);
     1189  begin
     1190    if Name = '' then
     1191    begin
     1192      if AILogo[p] <> nil then
     1193      begin
     1194        AILogo[p].free;
     1195        AILogo[p] := nil
     1196      end
     1197    end
     1198    else
     1199    begin
     1200      if AILogo[p] = nil then
     1201        AILogo[p] := TBitmap.Create;
     1202      if not LoadGraphicFile(AILogo[p], HomeDir + Name, gfNoError) then
     1203      begin
     1204        AILogo[p].free;
     1205        AILogo[p] := nil
     1206      end
     1207    end
     1208  end;
     1209
     1210  function TMainScreen.ContactRefused(p: integer; Item: String): boolean;
     1211  // return whether treaty was cancelled
     1212  var
     1213    s: string;
     1214  begin
     1215    assert(MyRO.Treaty[p] >= trPeace);
     1216    s := Tribe[p].TPhrase(Item);
     1217    if MyRO.Turn < MyRO.LastCancelTreaty[p] + CancelTreatyTurns then
     1218    begin
     1219      SimpleMessage(s);
     1220      result := false;
     1221    end
     1222    else
     1223    begin
     1224      case MyRO.Treaty[p] of
     1225        trPeace:
     1226          s := s + ' ' + Phrases.Lookup('FRCANCELQUERY_PEACE');
     1227        trFriendlyContact:
     1228          s := s + ' ' + Phrases.Lookup('FRCANCELQUERY_FRIENDLY');
     1229        trAlliance:
     1230          s := s + ' ' + Phrases.Lookup('FRCANCELQUERY_ALLIANCE');
    12601231      end;
    1261 
    1262     Kind:=mkOk;
    1263     ShowModal;
    1264     end;
     1232      result := SimpleQuery(mkYesNo, s, 'NEGO_REJECTED') = mrOK;
     1233      if result then
     1234      begin
     1235        Play('CANCELTREATY');
     1236        Server(sCancelTreaty, me, 0, nil^);
     1237        if MyRO.Treaty[p] = trNone then
     1238          CityOptimizer_BeginOfTurn;
     1239        // peace treaty was cancelled -- use formerly forbidden tiles
     1240        MapValid := false;
     1241        PaintAllMaps;
     1242      end
     1243    end
    12651244  end;
    12661245
    1267   procedure InitModule;
     1246  procedure TMainScreen.RememberPeaceViolation;
    12681247  var
    1269   x,y,i,j,Domain:integer;
     1248    uix, p1: integer;
    12701249  begin
    1271   {search icons for advances:}
    1272   for i:=0 to nAdv-1 do
    1273     if i in FutureTech then AdvIcon[i]:=96+i-futResearchTechnology
    1274     else
    1275       begin
    1276       AdvIcon[i]:=-1;
    1277       for Domain:=0 to nDomains-1 do
    1278         for j:=0 to nUpgrade-1 do if upgrade[Domain,j].Preq=i then
    1279           if AdvIcon[i]>=0 then AdvIcon[i]:=85
    1280           else AdvIcon[i]:=86+Domain;
    1281       for j:=0 to nFeature-1 do if Feature[j].Preq=i then
    1282         for Domain:=0 to nDomains-1 do
    1283           if 1 shl Domain and Feature[j].Domains<>0 then
    1284             if (AdvIcon[i]>=0) and (AdvIcon[i]<>86+Domain) then AdvIcon[i]:=85
    1285             else AdvIcon[i]:=86+Domain;
    1286       for j:=28 to nImp-1 do if Imp[j].Preq=i then AdvIcon[i]:=j;
    1287       for j:=28 to nImp-1 do
    1288         if (Imp[j].Preq=i) and (Imp[j].Kind<>ikCommon) then AdvIcon[i]:=j;
    1289       for j:=0 to nJob-1 do if i=JobPreq[j] then AdvIcon[i]:=84;
    1290       for j:=0 to 27 do if Imp[j].Preq=i then AdvIcon[i]:=j;
    1291       if AdvIcon[i]<0 then
    1292         if AdvValue[i]<1000 then AdvIcon[i]:=-7
    1293         else AdvIcon[i]:=24+AdvValue[i] div 1000;
    1294       for j:=2 to nGov-1 do if GovPreq[j]=i then AdvIcon[i]:=j-8;
     1250    MyData.PeaceEvaHappened := 0;
     1251    for uix := 0 to MyRO.nUn - 1 do
     1252      with MyUn[uix] do
     1253        if Loc >= 0 then
     1254        begin
     1255          p1 := MyRO.Territory[Loc];
     1256          if (p1 <> me) and (p1 >= 0) and
     1257            (MyRO.Turn = MyRO.EvaStart[p1] + (PeaceEvaTurns - 1)) then
     1258            MyData.PeaceEvaHappened := MyData.PeaceEvaHappened or (1 shl p1);
     1259        end;
     1260  end;
     1261
     1262  procedure TMainScreen.Client(Command, NewPlayer: integer; var Data);
     1263
     1264    procedure GetTribeList;
     1265    var
     1266      SearchRec: TSearchRec;
     1267      Color: TColor;
     1268      Name: string;
     1269      ok: boolean;
     1270    begin
     1271      UnusedTribeFiles.Clear;
     1272      ok := FindFirst(DataDir + 'Localization\' + 'Tribes\*.tribe.txt',
     1273        faArchive + faReadOnly, SearchRec) = 0;
     1274      if not ok then
     1275      begin
     1276        FindClose(SearchRec);
     1277        ok := FindFirst(HomeDir + 'Tribes\*.tribe.txt', faArchive + faReadOnly,
     1278          SearchRec) = 0;
    12951279      end;
    1296   AdvIcon[adConscription]:=86+dGround;
    1297 
    1298   UnusedTribeFiles:=tstringlist.Create;
    1299   UnusedTribeFiles.Sorted:=true;
    1300   TribeNames:=tstringlist.Create;
    1301 
    1302   for x:=0 to 11 do for y:=0 to 1 do
    1303     MiniColors[x,y]:=GrExt[HGrSystem].Data.Canvas.Pixels[66+x,67+y];
    1304   IsoEngine.Init(InitEnemyModel);
    1305   if not IsoEngine.ApplyTileSize(xxt,yyt) and ((xxt<>48) or (yyt<>24)) then
    1306     ApplyTileSize(48,24); // non-default tile size is missing a file, switch to default
    1307   MainMap:=TIsoMap.Create;
    1308   MainMap.SetOutput(offscreen);
    1309 
    1310   HGrStdUnits:=LoadGraphicSet('StdUnits');
    1311   SmallImp:=TBitmap.Create;
    1312   SmallImp.PixelFormat:=pf24bit;
    1313   InitSmallImp;
    1314   SoundPreloadDone:=0;
    1315   StartRunning:=false;
    1316   StayOnTop_Ensured:=false;
    1317 
    1318   CreatePVSB(sb,Handle,100-200,122,100+MidPanelHeight-16-200);
    1319   end;{InitModule}
     1280      if ok then
     1281        repeat
     1282          SearchRec.Name := Copy(SearchRec.Name, 1,
     1283            Length(SearchRec.Name) - 10);
     1284          if GetTribeInfo(SearchRec.Name, Name, Color) then
     1285            UnusedTribeFiles.AddObject(SearchRec.Name, TObject(Color));
     1286        until FindNext(SearchRec) <> 0;
     1287      FindClose(SearchRec);
     1288    end;
     1289
     1290    function ChooseUnusedTribe: integer;
     1291    var
     1292      i, j, ColorDistance, BestColorDistance, TestColorDistance,
     1293        CountBest: integer;
     1294    begin
     1295      assert(UnusedTribeFiles.Count > 0);
     1296      result := -1;
     1297      BestColorDistance := -1;
     1298      for j := 0 to UnusedTribeFiles.Count - 1 do
     1299      begin
     1300        ColorDistance := 250; // consider differences more than this infinite
     1301        for i := 0 to nPl - 1 do
     1302          if Tribe[i] <> nil then
     1303          begin
     1304            TestColorDistance :=
     1305              abs(integer(UnusedTribeFiles.Objects[j]) shr 16 and
     1306              $FF - Tribe[i].Color shr 16 and $FF) +
     1307              abs(integer(UnusedTribeFiles.Objects[j]) shr 8 and
     1308              $FF - Tribe[i].Color shr 8 and $FF) * 3 +
     1309              abs(integer(UnusedTribeFiles.Objects[j]) and
     1310              $FF - Tribe[i].Color and $FF) * 2;
     1311            if TestColorDistance < ColorDistance then
     1312              ColorDistance := TestColorDistance
     1313          end;
     1314        if ColorDistance > BestColorDistance then
     1315        begin
     1316          CountBest := 0;
     1317          BestColorDistance := ColorDistance
     1318        end;
     1319        if ColorDistance = BestColorDistance then
     1320        begin
     1321          inc(CountBest);
     1322          if random(CountBest) = 0 then
     1323            result := j
     1324        end
     1325      end;
     1326    end;
     1327
     1328    procedure ShowEnemyShipChange(ShowShipChange: TShowShipChange);
     1329    var
     1330      i, TestCost, MostCost: integer;
     1331      Ship1Plus, Ship2Plus: boolean;
     1332    begin
     1333      with ShowShipChange, MessgExDlg do
     1334      begin
     1335        case Reason of
     1336          scrProduction:
     1337            begin
     1338              OpenSound := 'SHIP_BUILT';
     1339              MessgText := Tribe[Ship1Owner].TPhrase('SHIPBUILT');
     1340              IconKind := mikShip;
     1341              IconIndex := Ship1Owner;
     1342            end;
     1343
     1344          scrDestruction:
     1345            begin
     1346              OpenSound := 'SHIP_DESTROYED';
     1347              MessgText := Tribe[Ship1Owner].TPhrase('SHIPDESTROYED');
     1348              IconKind := mikImp;
     1349            end;
     1350
     1351          scrTrade:
     1352            begin
     1353              OpenSound := 'SHIP_TRADED';
     1354              Ship1Plus := false;
     1355              Ship2Plus := false;
     1356              for i := 0 to nShipPart - 1 do
     1357              begin
     1358                if Ship1Change[i] > 0 then
     1359                  Ship1Plus := true;
     1360                if Ship2Change[i] > 0 then
     1361                  Ship2Plus := true;
     1362              end;
     1363              if Ship1Plus and Ship2Plus then
     1364                MessgText := Tribe[Ship1Owner].TPhrase('SHIPBITRADE1') + ' ' +
     1365                  Tribe[Ship2Owner].TPhrase('SHIPBITRADE2')
     1366              else if Ship1Plus then
     1367                MessgText := Tribe[Ship1Owner].TPhrase('SHIPUNITRADE1') + ' ' +
     1368                  Tribe[Ship2Owner].TPhrase('SHIPUNITRADE2')
     1369              else // if Ship2Plus then
     1370                MessgText := Tribe[Ship2Owner].TPhrase('SHIPUNITRADE1') + ' ' +
     1371                  Tribe[Ship1Owner].TPhrase('SHIPUNITRADE2');
     1372              IconKind := mikImp;
     1373            end;
     1374
     1375          scrCapture:
     1376            begin
     1377              OpenSound := 'SHIP_CAPTURED';
     1378              MessgText := Tribe[Ship2Owner].TPhrase('SHIPCAPTURE1') + ' ' +
     1379                Tribe[Ship1Owner].TPhrase('SHIPCAPTURE2');
     1380              IconKind := mikShip;
     1381              IconIndex := Ship2Owner;
     1382            end
     1383        end;
     1384
     1385        if IconKind = mikImp then
     1386        begin
     1387          MostCost := 0;
     1388          for i := 0 to nShipPart - 1 do
     1389          begin
     1390            TestCost := abs(Ship1Change[i]) * Imp[imShipComp + i].Cost;
     1391            if TestCost > MostCost then
     1392            begin
     1393              MostCost := TestCost;
     1394              IconIndex := imShipComp + i
     1395            end
     1396          end;
     1397        end;
     1398
     1399        Kind := mkOk;
     1400        ShowModal;
     1401      end;
     1402    end;
     1403
     1404    procedure InitModule;
     1405    var
     1406      x, y, i, j, Domain: integer;
     1407    begin
     1408      { search icons for advances: }
     1409      for i := 0 to nAdv - 1 do
     1410        if i in FutureTech then
     1411          AdvIcon[i] := 96 + i - futResearchTechnology
     1412        else
     1413        begin
     1414          AdvIcon[i] := -1;
     1415          for Domain := 0 to nDomains - 1 do
     1416            for j := 0 to nUpgrade - 1 do
     1417              if upgrade[Domain, j].Preq = i then
     1418                if AdvIcon[i] >= 0 then
     1419                  AdvIcon[i] := 85
     1420                else
     1421                  AdvIcon[i] := 86 + Domain;
     1422          for j := 0 to nFeature - 1 do
     1423            if Feature[j].Preq = i then
     1424              for Domain := 0 to nDomains - 1 do
     1425                if 1 shl Domain and Feature[j].Domains <> 0 then
     1426                  if (AdvIcon[i] >= 0) and (AdvIcon[i] <> 86 + Domain) then
     1427                    AdvIcon[i] := 85
     1428                  else
     1429                    AdvIcon[i] := 86 + Domain;
     1430          for j := 28 to nImp - 1 do
     1431            if Imp[j].Preq = i then
     1432              AdvIcon[i] := j;
     1433          for j := 28 to nImp - 1 do
     1434            if (Imp[j].Preq = i) and (Imp[j].Kind <> ikCommon) then
     1435              AdvIcon[i] := j;
     1436          for j := 0 to nJob - 1 do
     1437            if i = JobPreq[j] then
     1438              AdvIcon[i] := 84;
     1439          for j := 0 to 27 do
     1440            if Imp[j].Preq = i then
     1441              AdvIcon[i] := j;
     1442          if AdvIcon[i] < 0 then
     1443            if AdvValue[i] < 1000 then
     1444              AdvIcon[i] := -7
     1445            else
     1446              AdvIcon[i] := 24 + AdvValue[i] div 1000;
     1447          for j := 2 to nGov - 1 do
     1448            if GovPreq[j] = i then
     1449              AdvIcon[i] := j - 8;
     1450        end;
     1451      AdvIcon[adConscription] := 86 + dGround;
     1452
     1453      UnusedTribeFiles := tstringlist.Create;
     1454      UnusedTribeFiles.Sorted := true;
     1455      TribeNames := tstringlist.Create;
     1456
     1457      for x := 0 to 11 do
     1458        for y := 0 to 1 do
     1459          MiniColors[x, y] := GrExt[HGrSystem].Data.Canvas.Pixels
     1460            [66 + x, 67 + y];
     1461      IsoEngine.Init(InitEnemyModel);
     1462      if not IsoEngine.ApplyTileSize(xxt, yyt) and ((xxt <> 48) or (yyt <> 24))
     1463      then
     1464        ApplyTileSize(48, 24);
     1465      // non-default tile size is missing a file, switch to default
     1466      MainMap := TIsoMap.Create;
     1467      MainMap.SetOutput(offscreen);
     1468
     1469      HGrStdUnits := LoadGraphicSet('StdUnits');
     1470      SmallImp := TBitmap.Create;
     1471      SmallImp.PixelFormat := pf24bit;
     1472      InitSmallImp;
     1473      SoundPreloadDone := 0;
     1474      StartRunning := false;
     1475      StayOnTop_Ensured := false;
     1476
     1477      CreatePVSB(sb, Handle, 100 - 200, 122, 100 + MidPanelHeight - 16 - 200);
     1478    end; { InitModule }
    13201479
    13211480  // sound blocks for preload
    13221481  const
    1323   sbStart=$01; sbWonder=$02; sbScience=$04; sbContact=$08;
    1324   sbTurn=$10; sbAll=$FF;
    1325 
    1326   procedure SoundPreload(Check: integer);
    1327   const
    1328   nStartBlock=27;
    1329   StartBlock: array[0..nStartBlock-1] of string=
    1330   ('INVALID','TURNEND','DISBAND','CHEAT','MSG_DEFAULT','WARNING_DISORDER',
    1331   'WARNING_FAMINE','WARNING_LOWSUPPORT','WARNING_LOWFUNDS','MOVE_MOUNTAIN',
    1332   'MOVE_LOAD','MOVE_UNLOAD','MOVE_DIE','NOMOVE_TIME','NOMOVE_DOMAIN',
    1333   'NOMOVE_DEFAULT','CITY_SELLIMP','CITY_REBUILDIMP','CITY_BUYPROJECT',
    1334   'CITY_UTILIZE','NEWMODEL_0','NEWADVANCE_0','AGE_0','REVOLUTION','NEWGOV',
    1335   'CITY_INVALIDTYPE','MSG_GAMEOVER');
    1336 
    1337   nWonderBlock=6;
    1338   WonderBlock: array[0..nWonderBlock-1] of string=
    1339   ('WONDER_BUILT','WONDER_CAPTURED','WONDER_EXPIRED','WONDER_DESTROYED',
    1340   'MSG_COLDWAR','NEWADVANCE_GRLIB');
    1341 
    1342   nScienceBlock=17;
    1343   ScienceBlock: array[0..nScienceBlock-1] of string=
    1344   ('MOVE_PARACHUTE','MOVE_PLANESTART','MOVE_PLANELANDING','MOVE_COVERT',
    1345   'NEWMODEL_1','NEWMODEL_2','NEWMODEL_3','NEWADVANCE_1','NEWADVANCE_2',
    1346   'NEWADVANCE_3','AGE_1','AGE_2','AGE_3','SHIP_BUILT','SHIP_TRADED',
    1347   'SHIP_CAPTURED','SHIP_DESTROYED');
    1348 
    1349   nContactBlock=20;
    1350   ContactBlock: array[0..nContactBlock-1] of string=
    1351   ('NEWTREATY','CANCELTREATY','ACCEPTOFFER','MSG_WITHDRAW','MSG_BANKRUPT',
    1352   'CONTACT_0','CONTACT_1','CONTACT_2','CONTACT_3','CONTACT_4','CONTACT_5',
    1353   'CONTACT_5','CONTACT_6','NEGO_REJECTED','MOVE_CAPTURE','MOVE_EXPEL',
    1354   'NOMOVE_TREATY','NOMOVE_ZOC','NOMOVE_SUBMARINE','NOMOVE_STEALTH');
    1355 
    1356   var
    1357   i,cix,mix: integer;
    1358   need: boolean;
    1359   mi: TModelInfo;
    1360   begin
    1361   if Check and sbStart and not SoundPreloadDone<>0 then
    1362     begin
    1363     for i:=0 to nStartBlock-1 do PreparePlay(StartBlock[i]);
    1364     SoundPreloadDone:=SoundPreloadDone or sbStart;
    1365     end;
    1366   if Check and sbWonder and not SoundPreloadDone<>0 then
    1367     begin
    1368     need:=false;
    1369     for i:=0 to 27 do if MyRO.Wonder[i].CityID<>-1 then need:=true;
    1370     if need then
    1371       begin
    1372       for i:=0 to nWonderBlock-1 do PreparePlay(WonderBlock[i]);
    1373       SoundPreloadDone:=SoundPreloadDone or sbWonder;
     1482    sbStart = $01;
     1483    sbWonder = $02;
     1484    sbScience = $04;
     1485    sbContact = $08;
     1486    sbTurn = $10;
     1487    sbAll = $FF;
     1488
     1489    procedure SoundPreload(Check: integer);
     1490    const
     1491      nStartBlock = 27;
     1492      StartBlock: array [0 .. nStartBlock - 1] of string = ('INVALID',
     1493        'TURNEND', 'DISBAND', 'CHEAT', 'MSG_DEFAULT', 'WARNING_DISORDER',
     1494        'WARNING_FAMINE', 'WARNING_LOWSUPPORT', 'WARNING_LOWFUNDS',
     1495        'MOVE_MOUNTAIN', 'MOVE_LOAD', 'MOVE_UNLOAD', 'MOVE_DIE', 'NOMOVE_TIME',
     1496        'NOMOVE_DOMAIN', 'NOMOVE_DEFAULT', 'CITY_SELLIMP', 'CITY_REBUILDIMP',
     1497        'CITY_BUYPROJECT', 'CITY_UTILIZE', 'NEWMODEL_0', 'NEWADVANCE_0',
     1498        'AGE_0', 'REVOLUTION', 'NEWGOV', 'CITY_INVALIDTYPE', 'MSG_GAMEOVER');
     1499
     1500      nWonderBlock = 6;
     1501      WonderBlock: array [0 .. nWonderBlock - 1] of string = ('WONDER_BUILT',
     1502        'WONDER_CAPTURED', 'WONDER_EXPIRED', 'WONDER_DESTROYED', 'MSG_COLDWAR',
     1503        'NEWADVANCE_GRLIB');
     1504
     1505      nScienceBlock = 17;
     1506      ScienceBlock: array [0 .. nScienceBlock - 1] of string =
     1507        ('MOVE_PARACHUTE', 'MOVE_PLANESTART', 'MOVE_PLANELANDING',
     1508        'MOVE_COVERT', 'NEWMODEL_1', 'NEWMODEL_2', 'NEWMODEL_3', 'NEWADVANCE_1',
     1509        'NEWADVANCE_2', 'NEWADVANCE_3', 'AGE_1', 'AGE_2', 'AGE_3', 'SHIP_BUILT',
     1510        'SHIP_TRADED', 'SHIP_CAPTURED', 'SHIP_DESTROYED');
     1511
     1512      nContactBlock = 20;
     1513      ContactBlock: array [0 .. nContactBlock - 1] of string = ('NEWTREATY',
     1514        'CANCELTREATY', 'ACCEPTOFFER', 'MSG_WITHDRAW', 'MSG_BANKRUPT',
     1515        'CONTACT_0', 'CONTACT_1', 'CONTACT_2', 'CONTACT_3', 'CONTACT_4',
     1516        'CONTACT_5', 'CONTACT_5', 'CONTACT_6', 'NEGO_REJECTED', 'MOVE_CAPTURE',
     1517        'MOVE_EXPEL', 'NOMOVE_TREATY', 'NOMOVE_ZOC', 'NOMOVE_SUBMARINE',
     1518        'NOMOVE_STEALTH');
     1519
     1520    var
     1521      i, cix, mix: integer;
     1522      need: boolean;
     1523      mi: TModelInfo;
     1524    begin
     1525      if Check and sbStart and not SoundPreloadDone <> 0 then
     1526      begin
     1527        for i := 0 to nStartBlock - 1 do
     1528          PreparePlay(StartBlock[i]);
     1529        SoundPreloadDone := SoundPreloadDone or sbStart;
    13741530      end;
    1375     end;
    1376   if (Check and sbScience and not SoundPreloadDone<>0)
    1377     and (MyRO.Tech[adScience]>=tsApplicable) then
    1378     begin
    1379     for i:=0 to nScienceBlock-1 do PreparePlay(ScienceBlock[i]);
    1380     SoundPreloadDone:=SoundPreloadDone or sbScience;
    1381     end;
    1382   if (Check and sbContact and not SoundPreloadDone<>0)
    1383     and (MyRO.nEnemyModel+MyRO.nEnemyCity>0) then
    1384     begin
    1385     for i:=0 to nContactBlock-1 do PreparePlay(ContactBlock[i]);
    1386     SoundPreloadDone:=SoundPreloadDone or sbContact;
    1387     end;
    1388   if Check and sbTurn<>0 then
    1389     begin
    1390     if MyRO.Happened and phShipComplete<>0 then
    1391       PreparePlay('MSG_YOUWIN');
    1392     if MyData.ToldAlive<>MyRO.Alive then PreparePlay('MSG_EXTINCT');
    1393     for cix:=0 to MyRO.nCity-1 do with MyCity[cix] do
    1394       if (Loc>=0) and (Flags and CityRepMask<>0) then
    1395         for i:=0 to 12 do if 1 shl i and Flags and CityRepMask<>0 then
    1396           PreparePlay(CityEventSoundItem[i]);
    1397      for mix:=0 to MyRO.nModel-1 do with MyModel[mix] do if Attack>0 then
    1398        begin
    1399        MakeModelInfo(me,mix,MyModel[mix],mi);
    1400        PreparePlay(AttackSound(ModelCode(mi)));
    1401        end
    1402      end
    1403   end;
    1404 
    1405   procedure InitTurn(p: integer);
    1406   const
    1407   nAdvBookIcon=16;
    1408   AdvBookIcon: array[0..nAdvBookIcon-1] of record Adv,Icon: integer end=
    1409   ((Adv:adPolyTheism;Icon:woZeus),(Adv:adBronzeWorking;Icon:woColossus),
    1410   (Adv:adMapMaking;Icon:woLighthouse),(Adv:adPoetry;Icon:imTheater),
    1411   (Adv:adMonotheism;Icon:woMich),(Adv:adPhilosophy;Icon:woLeo),
    1412   (Adv:adTheoryOfGravity;Icon:woNewton),(Adv:adSteel;Icon:woEiffel),
    1413   (Adv:adDemocracy;Icon:woLiberty),(Adv:adAutomobile;Icon:imHighways),
    1414   (Adv:adSanitation;Icon:imSewer),(Adv:adElectronics;Icon:woHoover),
    1415   (Adv:adNuclearFission;Icon:woManhattan),(Adv:adRecycling;Icon:imRecycling),
    1416   (Adv:adComputers;Icon:imResLab),(Adv:adSpaceFlight;Icon:woMIR));
    1417   var
    1418   Domain,p1,i,ad,uix,cix,MoveOptions,MoveResult,Loc1,Dist,NewAgeCenterTo,
    1419     Bankrupt,ShipMore,Winners,NewGovAvailable,dx,dy:integer;
    1420   MoveAdviceData: TMoveAdviceData;
    1421   Picture: TModelPictureInfo;
    1422   s, Item, Item2: string;
    1423   UpdatePanel, OwnWonder, ok, Stop, ShowCityList, WondersOnly,AllowCityScreen: boolean;
    1424   begin
    1425   if IsMultiPlayerGame and (p<>me) then
    1426     begin
    1427     UnitInfoBtn.Visible:=false;
    1428     UnitBtn.Visible:=false;
    1429     TerrainBtn.Visible:=false;
    1430     EOT.Visible:=false;
    1431     end;
    1432   if IsMultiPlayerGame and (p<>me) and (G.RO[0].Happened and phShipComplete=0) then
    1433     begin //inter player screen
    1434     for i:=0 to ControlCount-1 do if Controls[i] is TButtonC then
    1435       Controls[i].visible:=false;
    1436     me:=-1;
    1437     SetMainTextureByAge(-1);
    1438     with Panel.Canvas do
    1439       begin
    1440       Brush.Color:=$000000;
    1441       FillRect(Rect(0,0,Panel.Width,Panel.Height));
    1442       Brush.Style:=bsClear;
     1531      if Check and sbWonder and not SoundPreloadDone <> 0 then
     1532      begin
     1533        need := false;
     1534        for i := 0 to 27 do
     1535          if MyRO.Wonder[i].CityID <> -1 then
     1536            need := true;
     1537        if need then
     1538        begin
     1539          for i := 0 to nWonderBlock - 1 do
     1540            PreparePlay(WonderBlock[i]);
     1541          SoundPreloadDone := SoundPreloadDone or sbWonder;
     1542        end;
    14431543      end;
    1444     with TopBar.Canvas do
    1445       begin
    1446       Brush.Color:=$000000;
    1447       FillRect(Rect(0,0,TopBar.Width,TopBar.Height));
    1448       Brush.Style:=bsClear;
     1544      if (Check and sbScience and not SoundPreloadDone <> 0) and
     1545        (MyRO.Tech[adScience] >= tsApplicable) then
     1546      begin
     1547        for i := 0 to nScienceBlock - 1 do
     1548          PreparePlay(ScienceBlock[i]);
     1549        SoundPreloadDone := SoundPreloadDone or sbScience;
    14491550      end;
    1450     Invalidate;
    1451 
    1452     s:=TurnToString(G.RO[0].Turn);
    1453     if supervising then
    1454       SimpleMessage(Format(Phrases.Lookup('SUPERTURN'),[s]))
    1455     else SimpleMessage(Format(Tribe[NewPlayer].TPhrase('TURN'),[s]));
    1456     end;
    1457   for i:=0 to ControlCount-1 do if Controls[i] is TButtonC then
    1458     Controls[i].visible:=true;
    1459 
    1460   ItsMeAgain(p);
    1461   MyData:=G.RO[p].Data;
    1462   if not supervising then
    1463     SoundPreload(sbAll);
    1464   if (me=0) and ((MyRO.Turn=0) or (ClientMode=cResume)) then
    1465     Invalidate; // colorize empty space
    1466 
    1467   if not supervising then
    1468     begin
    1469 {    if MyRO.Happened and phGameEnd<>0 then
    1470       begin
    1471       Age:=3;
    1472       SetMainTextureByAge(-1);
     1551      if (Check and sbContact and not SoundPreloadDone <> 0) and
     1552        (MyRO.nEnemyModel + MyRO.nEnemyCity > 0) then
     1553      begin
     1554        for i := 0 to nContactBlock - 1 do
     1555          PreparePlay(ContactBlock[i]);
     1556        SoundPreloadDone := SoundPreloadDone or sbContact;
     1557      end;
     1558      if Check and sbTurn <> 0 then
     1559      begin
     1560        if MyRO.Happened and phShipComplete <> 0 then
     1561          PreparePlay('MSG_YOUWIN');
     1562        if MyData.ToldAlive <> MyRO.Alive then
     1563          PreparePlay('MSG_EXTINCT');
     1564        for cix := 0 to MyRO.nCity - 1 do
     1565          with MyCity[cix] do
     1566            if (Loc >= 0) and (Flags and CityRepMask <> 0) then
     1567              for i := 0 to 12 do
     1568                if 1 shl i and Flags and CityRepMask <> 0 then
     1569                  PreparePlay(CityEventSoundItem[i]);
     1570        for mix := 0 to MyRO.nModel - 1 do
     1571          with MyModel[mix] do
     1572            if Attack > 0 then
     1573            begin
     1574              MakeModelInfo(me, mix, MyModel[mix], mi);
     1575              PreparePlay(AttackSound(ModelCode(mi)));
     1576            end
    14731577      end
    1474     else}
    1475       begin
    1476       Age:=GetAge(me);
    1477       if SetMainTextureByAge(Age) then
    1478         EOT.Invalidate; // has visible background parts in its bounds
     1578    end;
     1579
     1580    procedure InitTurn(p: integer);
     1581    const
     1582      nAdvBookIcon = 16;
     1583      AdvBookIcon: array [0 .. nAdvBookIcon - 1] of record Adv,
     1584        Icon: integer end = ((Adv: adPolyTheism; Icon: woZeus),
     1585        (Adv: adBronzeWorking; Icon: woColossus), (Adv: adMapMaking;
     1586        Icon: woLighthouse), (Adv: adPoetry; Icon: imTheater),
     1587        (Adv: adMonotheism; Icon: woMich), (Adv: adPhilosophy; Icon: woLeo),
     1588        (Adv: adTheoryOfGravity; Icon: woNewton), (Adv: adSteel;
     1589        Icon: woEiffel), (Adv: adDemocracy; Icon: woLiberty),
     1590        (Adv: adAutomobile; Icon: imHighways), (Adv: adSanitation;
     1591        Icon: imSewer), (Adv: adElectronics; Icon: woHoover),
     1592        (Adv: adNuclearFission; Icon: woManhattan), (Adv: adRecycling;
     1593        Icon: imRecycling), (Adv: adComputers; Icon: imResLab),
     1594        (Adv: adSpaceFlight; Icon: woMIR));
     1595    var
     1596      Domain, p1, i, ad, uix, cix, MoveOptions, MoveResult, Loc1, Dist,
     1597        NewAgeCenterTo, Bankrupt, ShipMore, Winners, NewGovAvailable, dx,
     1598        dy: integer;
     1599      MoveAdviceData: TMoveAdviceData;
     1600      Picture: TModelPictureInfo;
     1601      s, Item, Item2: string;
     1602      UpdatePanel, OwnWonder, ok, Stop, ShowCityList, WondersOnly,
     1603        AllowCityScreen: boolean;
     1604    begin
     1605      if IsMultiPlayerGame and (p <> me) then
     1606      begin
     1607        UnitInfoBtn.Visible := false;
     1608        UnitBtn.Visible := false;
     1609        TerrainBtn.Visible := false;
     1610        EOT.Visible := false;
    14791611      end;
    1480 //    age:=MyRO.Turn mod 4; //!!!
    1481     if ClientMode=cMovieTurn then
    1482       EOT.ButtonIndex:=eotCancel
    1483     else if ClientMode<scContact then
    1484       EOT.ButtonIndex:=eotGray
    1485     else EOT.ButtonIndex:=eotBackToNego;
    1486     end
    1487   else
    1488     begin
    1489     Age:=0;
    1490     SetMainTextureByAge(-1);
    1491     if ClientMode=cMovieTurn then
    1492       EOT.ButtonIndex:=eotCancel
    1493     else EOT.ButtonIndex:=eotBlinkOn;
    1494     end;
    1495   InitCityMark(MainTexture);
    1496   CityDlg.CheckAge;
    1497   NatStatDlg.CheckAge;
    1498   UnitStatDlg.CheckAge;
    1499   HelpDlg.Difficulty:=G.Difficulty[me];
    1500 
    1501   UnFocus:=-1;
    1502   MarkCityLoc:=-1;
    1503   BlinkON:=false;
    1504   BlinkTime:=-1;
    1505   Tracking:=false;
    1506   TurnComplete:=false;
    1507 
    1508   if (ToldSlavery<0)
    1509     or ((ToldSlavery=1)<>(MyRO.Wonder[woPyramids].EffectiveOwner>=0)) then
    1510     begin
    1511     if MyRO.Wonder[woPyramids].EffectiveOwner>=0 then ToldSlavery:=1
    1512     else ToldSlavery:=0;
    1513     for p1:=0 to nPl-1 do
    1514       if (Tribe[p1]<>nil) and (Tribe[p1].mixSlaves>=0) then
    1515         with Picture do
    1516           begin // replace unit picture
    1517           mix:=Tribe[p1].mixSlaves;
    1518           if ToldSlavery=1 then pix:=pixSlaves else pix:=pixNoSlaves;
    1519           Hash:=0;
    1520           GrName:='StdUnits';
    1521           Tribe[p1].SetModelPicture(Picture, true);
     1612      if IsMultiPlayerGame and (p <> me) and
     1613        (G.RO[0].Happened and phShipComplete = 0) then
     1614      begin // inter player screen
     1615        for i := 0 to ControlCount - 1 do
     1616          if Controls[i] is TButtonC then
     1617            Controls[i].Visible := false;
     1618        me := -1;
     1619        SetMainTextureByAge(-1);
     1620        with Panel.Canvas do
     1621        begin
     1622          Brush.Color := $000000;
     1623          FillRect(Rect(0, 0, Panel.width, Panel.height));
     1624          Brush.Style := bsClear;
     1625        end;
     1626        with TopBar.Canvas do
     1627        begin
     1628          Brush.Color := $000000;
     1629          FillRect(Rect(0, 0, TopBar.width, TopBar.height));
     1630          Brush.Style := bsClear;
     1631        end;
     1632        Invalidate;
     1633
     1634        s := TurnToString(G.RO[0].Turn);
     1635        if supervising then
     1636          SimpleMessage(Format(Phrases.Lookup('SUPERTURN'), [s]))
     1637        else
     1638          SimpleMessage(Format(Tribe[NewPlayer].TPhrase('TURN'), [s]));
     1639      end;
     1640      for i := 0 to ControlCount - 1 do
     1641        if Controls[i] is TButtonC then
     1642          Controls[i].Visible := true;
     1643
     1644      ItsMeAgain(p);
     1645      MyData := G.RO[p].Data;
     1646      if not supervising then
     1647        SoundPreload(sbAll);
     1648      if (me = 0) and ((MyRO.Turn = 0) or (ClientMode = cResume)) then
     1649        Invalidate; // colorize empty space
     1650
     1651      if not supervising then
     1652      begin
     1653
     1654        { if MyRO.Happened and phGameEnd<>0 then
     1655          begin
     1656          Age:=3;
     1657          SetMainTextureByAge(-1);
    15221658          end
    1523     end;
    1524 
    1525   if not supervising and (ClientMode=cTurn) then
    1526     begin
    1527     for cix:=0 to MyRO.nCity-1 do
    1528       if (MyCity[cix].Loc>=0)
    1529         and ((MyRO.Turn=0) or (MyCity[cix].Flags and chFounded<>0)) then
    1530         MyCity[cix].Status:=MyCity[cix].Status
    1531           and not csResourceWeightsMask or (3 shl 4); // new city, set to maximum growth
    1532     end;
    1533   if (ClientMode=cTurn) or (ClientMode=cContinue) then
    1534     CityOptimizer_BeginOfTurn; // maybe peace was made or has ended
    1535   SumCities(TaxSum,ScienceSum);
    1536 
    1537   if ClientMode=cMovieTurn then
    1538     begin
    1539     UnitInfoBtn.Visible:=false;
    1540     UnitBtn.Visible:=false;
    1541     TerrainBtn.Visible:=false;
    1542     EOT.Hint:=Phrases.Lookup('BTN_STOP');
    1543     EOT.Visible:=true;
    1544     end
    1545   else if ClientMode<scContact then
    1546     begin
    1547     UnitInfoBtn.Visible:= UnFocus>=0;
    1548     UnitBtn.Visible:= UnFocus>=0;
    1549     CheckTerrainBtnVisible;
    1550     TurnComplete:=supervising;
    1551     EOT.Hint:=Phrases.Lookup('BTN_ENDTURN');
    1552     EOT.Visible:= Server(sTurn-sExecute,me,0,nil^)>=rExecuted;
    1553     end
    1554   else
    1555     begin
    1556     UnitInfoBtn.Visible:=false;
    1557     UnitBtn.Visible:=false;
    1558     TerrainBtn.Visible:=false;
    1559     EOT.Hint:=Phrases.Lookup('BTN_NEGO');
    1560     EOT.Visible:=true;
    1561     end;
    1562   SetTroopLoc(-1);
    1563   MapValid:=false;
    1564   NewAgeCenterTo:=0;
    1565   if ((MyRO.Turn=0) and not supervising or IsMultiPlayerGame
    1566     or (ClientMode=cResume)) and (MyRO.nCity>0) then
    1567     begin
    1568     Loc1:=MyCity[0].Loc;
    1569     if (ClientMode=cTurn) and (MyRO.Turn=0) then
    1570       begin // move city out of center to not be covered by welcome screen
    1571       dx:=MapWidth div (xxt*5);
    1572       if dx>5 then
    1573         dx:=5;
    1574       dy:=MapHeight div (yyt*5);
    1575       if dy>5 then
    1576         dy:=5;
    1577       if Loc1>=G.lx*G.ly div 2 then
    1578         begin
    1579         NewAgeCenterTo:=-1;
    1580         Loc1:=dLoc(Loc1,-dx,-dy)
    1581         end
     1659          else }
     1660        begin
     1661          Age := GetAge(me);
     1662          if SetMainTextureByAge(Age) then
     1663            EOT.Invalidate; // has visible background parts in its bounds
     1664        end;
     1665        // age:=MyRO.Turn mod 4; //!!!
     1666        if ClientMode = cMovieTurn then
     1667          EOT.ButtonIndex := eotCancel
     1668        else if ClientMode < scContact then
     1669          EOT.ButtonIndex := eotGray
     1670        else
     1671          EOT.ButtonIndex := eotBackToNego;
     1672      end
    15821673      else
    1583         begin
    1584         NewAgeCenterTo:=1;
    1585         Loc1:=dLoc(Loc1,-dx,dy);
    1586         end
     1674      begin
     1675        Age := 0;
     1676        SetMainTextureByAge(-1);
     1677        if ClientMode = cMovieTurn then
     1678          EOT.ButtonIndex := eotCancel
     1679        else
     1680          EOT.ButtonIndex := eotBlinkOn;
    15871681      end;
    1588     Centre(Loc1)
    1589     end;
    1590 
    1591   for i:=0 to Screen.FormCount-1 do
    1592     if Screen.Forms[i] is TBufferedDrawDlg then
    1593       Screen.Forms[i].Enabled:=true;
    1594 
    1595   if ClientMode<>cResume then
    1596     begin
    1597     PaintAll;
    1598     if (MyRO.Happened and phChangeGov<>0) and (MyRO.NatBuilt[imPalace]>0) then
    1599       ImpImage(Panel.Canvas, ClientWidth-xPalace, yPalace, imPalace, gAnarchy{, GameMode<>cMovie});
    1600       // first turn after anarchy -- don't show despotism palace!
    1601     Update;
    1602     for i:=0 to Screen.FormCount-1 do
    1603       if (Screen.Forms[i].Visible) and (Screen.Forms[i] is TBufferedDrawDlg) then
    1604         begin
    1605         if @Screen.Forms[i].OnShow<>nil then
    1606           Screen.Forms[i].OnShow(nil);
    1607         Screen.Forms[i].Invalidate;
    1608         Screen.Forms[i].Update;
    1609         end;
    1610 
    1611     if MyRO.Happened and phGameEnd<>0 then
    1612       with MessgExDlg do
    1613         begin // game ended
    1614         if MyRO.Happened and phExtinct<>0 then
     1682      InitCityMark(MainTexture);
     1683      CityDlg.CheckAge;
     1684      NatStatDlg.CheckAge;
     1685      UnitStatDlg.CheckAge;
     1686      HelpDlg.Difficulty := G.Difficulty[me];
     1687
     1688      UnFocus := -1;
     1689      MarkCityLoc := -1;
     1690      BlinkON := false;
     1691      BlinkTime := -1;
     1692      Tracking := false;
     1693      TurnComplete := false;
     1694
     1695      if (ToldSlavery < 0) or
     1696        ((ToldSlavery = 1) <> (MyRO.Wonder[woPyramids].EffectiveOwner >= 0))
     1697      then
     1698      begin
     1699        if MyRO.Wonder[woPyramids].EffectiveOwner >= 0 then
     1700          ToldSlavery := 1
     1701        else
     1702          ToldSlavery := 0;
     1703        for p1 := 0 to nPl - 1 do
     1704          if (Tribe[p1] <> nil) and (Tribe[p1].mixSlaves >= 0) then
     1705            with Picture do
     1706            begin // replace unit picture
     1707              mix := Tribe[p1].mixSlaves;
     1708              if ToldSlavery = 1 then
     1709                pix := pixSlaves
     1710              else
     1711                pix := pixNoSlaves;
     1712              Hash := 0;
     1713              GrName := 'StdUnits';
     1714              Tribe[p1].SetModelPicture(Picture, true);
     1715            end
     1716      end;
     1717
     1718      if not supervising and (ClientMode = cTurn) then
     1719      begin
     1720        for cix := 0 to MyRO.nCity - 1 do
     1721          if (MyCity[cix].Loc >= 0) and
     1722            ((MyRO.Turn = 0) or (MyCity[cix].Flags and chFounded <> 0)) then
     1723            MyCity[cix].Status := MyCity[cix].Status and
     1724              not csResourceWeightsMask or (3 shl 4);
     1725        // new city, set to maximum growth
     1726      end;
     1727      if (ClientMode = cTurn) or (ClientMode = cContinue) then
     1728        CityOptimizer_BeginOfTurn; // maybe peace was made or has ended
     1729      SumCities(TaxSum, ScienceSum);
     1730
     1731      if ClientMode = cMovieTurn then
     1732      begin
     1733        UnitInfoBtn.Visible := false;
     1734        UnitBtn.Visible := false;
     1735        TerrainBtn.Visible := false;
     1736        EOT.Hint := Phrases.Lookup('BTN_STOP');
     1737        EOT.Visible := true;
     1738      end
     1739      else if ClientMode < scContact then
     1740      begin
     1741        UnitInfoBtn.Visible := UnFocus >= 0;
     1742        UnitBtn.Visible := UnFocus >= 0;
     1743        CheckTerrainBtnVisible;
     1744        TurnComplete := supervising;
     1745        EOT.Hint := Phrases.Lookup('BTN_ENDTURN');
     1746        EOT.Visible := Server(sTurn - sExecute, me, 0, nil^) >= rExecuted;
     1747      end
     1748      else
     1749      begin
     1750        UnitInfoBtn.Visible := false;
     1751        UnitBtn.Visible := false;
     1752        TerrainBtn.Visible := false;
     1753        EOT.Hint := Phrases.Lookup('BTN_NEGO');
     1754        EOT.Visible := true;
     1755      end;
     1756      SetTroopLoc(-1);
     1757      MapValid := false;
     1758      NewAgeCenterTo := 0;
     1759      if ((MyRO.Turn = 0) and not supervising or IsMultiPlayerGame or
     1760        (ClientMode = cResume)) and (MyRO.nCity > 0) then
     1761      begin
     1762        Loc1 := MyCity[0].Loc;
     1763        if (ClientMode = cTurn) and (MyRO.Turn = 0) then
     1764        begin // move city out of center to not be covered by welcome screen
     1765          dx := MapWidth div (xxt * 5);
     1766          if dx > 5 then
     1767            dx := 5;
     1768          dy := MapHeight div (yyt * 5);
     1769          if dy > 5 then
     1770            dy := 5;
     1771          if Loc1 >= G.lx * G.ly div 2 then
    16151772          begin
    1616           OpenSound:='MSG_GAMEOVER';
    1617           MessgText:=Tribe[me].TPhrase('GAMEOVER');
    1618           IconKind:=mikBigIcon;
    1619           IconIndex:=8;
     1773            NewAgeCenterTo := -1;
     1774            Loc1 := dLoc(Loc1, -dx, -dy)
    16201775          end
    1621         else if MyRO.Happened and phShipComplete<>0 then
     1776          else
    16221777          begin
    1623           Winners:=0;
    1624           for p1:=0 to nPl-1 do if 1 shl p1 and MyRO.Alive<>0 then
     1778            NewAgeCenterTo := 1;
     1779            Loc1 := dLoc(Loc1, -dx, dy);
     1780          end
     1781        end;
     1782        Centre(Loc1)
     1783      end;
     1784
     1785      for i := 0 to Screen.FormCount - 1 do
     1786        if Screen.Forms[i] is TBufferedDrawDlg then
     1787          Screen.Forms[i].Enabled := true;
     1788
     1789      if ClientMode <> cResume then
     1790      begin
     1791        PaintAll;
     1792        if (MyRO.Happened and phChangeGov <> 0) and (MyRO.NatBuilt[imPalace] > 0)
     1793        then
     1794          ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, imPalace,
     1795            gAnarchy { , GameMode<>cMovie } );
     1796        // first turn after anarchy -- don't show despotism palace!
     1797        Update;
     1798        for i := 0 to Screen.FormCount - 1 do
     1799          if (Screen.Forms[i].Visible) and (Screen.Forms[i] is TBufferedDrawDlg)
     1800          then
     1801          begin
     1802            if @Screen.Forms[i].OnShow <> nil then
     1803              Screen.Forms[i].OnShow(nil);
     1804            Screen.Forms[i].Invalidate;
     1805            Screen.Forms[i].Update;
     1806          end;
     1807
     1808        if MyRO.Happened and phGameEnd <> 0 then
     1809          with MessgExDlg do
     1810          begin // game ended
     1811            if MyRO.Happened and phExtinct <> 0 then
    16251812            begin
    1626             Winners:=Winners or 1 shl p1;
    1627             for i:=0 to nShipPart-1 do
    1628               if MyRO.Ship[p1].Parts[i]<ShipNeed[i] then
    1629                 Winners:=Winners and not (1 shl p1);
     1813              OpenSound := 'MSG_GAMEOVER';
     1814              MessgText := Tribe[me].TPhrase('GAMEOVER');
     1815              IconKind := mikBigIcon;
     1816              IconIndex := 8;
     1817            end
     1818            else if MyRO.Happened and phShipComplete <> 0 then
     1819            begin
     1820              Winners := 0;
     1821              for p1 := 0 to nPl - 1 do
     1822                if 1 shl p1 and MyRO.Alive <> 0 then
     1823                begin
     1824                  Winners := Winners or 1 shl p1;
     1825                  for i := 0 to nShipPart - 1 do
     1826                    if MyRO.Ship[p1].Parts[i] < ShipNeed[i] then
     1827                      Winners := Winners and not(1 shl p1);
     1828                end;
     1829              assert(Winners <> 0);
     1830              if Winners and (1 shl me) <> 0 then
     1831              begin
     1832                s := '';
     1833                for p1 := 0 to nPl - 1 do
     1834                  if (p1 <> me) and (1 shl p1 and Winners <> 0) then
     1835                    if s = '' then
     1836                      s := Tribe[p1].TPhrase('SHORTNAME')
     1837                    else
     1838                      s := Format(Phrases.Lookup('SHAREDWIN_CONCAT'),
     1839                        [s, Tribe[p1].TPhrase('SHORTNAME')]);
     1840
     1841                OpenSound := 'MSG_YOUWIN';
     1842                MessgText := Tribe[me].TPhrase('MYSPACESHIP');
     1843                if s <> '' then
     1844                  MessgText := MessgText + '\' +
     1845                    Format(Phrases.Lookup('SHAREDWIN'), [s]);
     1846                IconKind := mikBigIcon;
     1847                IconIndex := 9;
     1848              end
     1849              else
     1850              begin
     1851                assert(me = 0);
     1852                OpenSound := 'MSG_GAMEOVER';
     1853                MessgText := '';
     1854                for p1 := 0 to nPl - 1 do
     1855                  if Winners and (1 shl p1) <> 0 then
     1856                    MessgText := MessgText + Tribe[p1].TPhrase('SPACESHIP1');
     1857                MessgText := MessgText + '\' + Phrases.Lookup('SPACESHIP2');
     1858                IconKind := mikEnemyShipComplete;
     1859              end
     1860            end
     1861            else { if MyRO.Happened and fTimeUp<>0 then }
     1862            begin
     1863              assert(me = 0);
     1864              OpenSound := 'MSG_GAMEOVER';
     1865              if not supervising then
     1866                MessgText := Tribe[me].TPhrase('TIMEUP')
     1867              else
     1868                MessgText := Phrases.Lookup('TIMEUPSUPER');
     1869              IconKind := mikImp;
     1870              IconIndex := 22;
    16301871            end;
    1631           assert(Winners<>0);
    1632           if Winners and (1 shl me)<>0 then
     1872            Kind := mkOk;
     1873            ShowModal;
     1874            if MyRO.Happened and phExtinct = 0 then
    16331875            begin
    1634             s:='';
    1635             for p1:=0 to nPl-1 do
    1636               if (p1<>me) and (1 shl p1 and Winners<>0) then
    1637                 if s='' then s:=Tribe[p1].TPhrase('SHORTNAME')
    1638                 else s:=Format(Phrases.Lookup('SHAREDWIN_CONCAT'),
    1639                   [s,Tribe[p1].TPhrase('SHORTNAME')]);
    1640 
    1641             OpenSound:='MSG_YOUWIN';
    1642             MessgText:=Tribe[me].TPhrase('MYSPACESHIP');
    1643             if s<>'' then
    1644               MessgText:=MessgText+'\'+Format(Phrases.Lookup('SHAREDWIN'),[s]);
    1645             IconKind:=mikBigIcon;
    1646             IconIndex:=9;
     1876              p1 := 0;
     1877              while (p1 < nPl - 1) and (Winners and (1 shl p1) = 0) do
     1878                inc(p1);
     1879              if MyRO.Happened and phShipComplete = 0 then
     1880                DiaDlg.ShowNewContent_Charts(wmModal);
     1881            end;
     1882            TurnComplete := true;
     1883            exit;
     1884          end;
     1885        if not supervising and (1 shl me and MyRO.Alive = 0) then
     1886        begin
     1887          TurnComplete := true;
     1888          exit;
     1889        end;
     1890
     1891        if (ClientMode = cContinue) and
     1892          (DipMem[me].SentCommand and $FF0F = scContact) then
     1893          // contact was refused
     1894          if MyRO.Treaty[DipMem[me].pContact] >= trPeace then
     1895            ContactRefused(DipMem[me].pContact, 'FRREJECTED')
     1896          else
     1897            SoundMessage(Tribe[DipMem[me].pContact].TPhrase('FRREJECTED'),
     1898              'NEGO_REJECTED');
     1899
     1900        if not supervising and (Age > MyData.ToldAge) and
     1901          ((Age > 0) or (ClientMode <> cMovieTurn)) then
     1902          with MessgExDlg do
     1903          begin
     1904            if Age = 0 then
     1905            begin
     1906              if Phrases2FallenBackToEnglish then
     1907              begin
     1908                s := Tribe[me].TPhrase('AGE0');
     1909                MessgText :=
     1910                  Format(s, [TurnToString(MyRO.Turn), CityName(MyCity[0].ID)])
     1911              end
     1912              else
     1913              begin
     1914                s := Tribe[me].TString(Phrases2.Lookup('AGE0'));
     1915                MessgText := Format(s, [TurnToString(MyRO.Turn)]);
     1916              end
    16471917            end
    1648           else
     1918            else
    16491919            begin
    1650             assert(me=0);
    1651             OpenSound:='MSG_GAMEOVER';
    1652             MessgText:='';
    1653             for p1:=0 to nPl-1 do if Winners and (1 shl p1)<>0 then
    1654               MessgText:=MessgText+Tribe[p1].TPhrase('SPACESHIP1');
    1655             MessgText:=MessgText+'\'+Phrases.Lookup('SPACESHIP2');
    1656             IconKind:=mikEnemyShipComplete;
     1920              s := Tribe[me].TPhrase('AGE' + char(48 + Age));
     1921              MessgText := Format(s, [TurnToString(MyRO.Turn)]);
     1922            end;
     1923            IconKind := mikAge;
     1924            IconIndex := Age;
     1925            { if age=0 then } Kind := mkOk
     1926            { else begin Kind:=mkOkHelp; HelpKind:=hkAdv; HelpNo:=AgePreq[age]; end };
     1927            CenterTo := NewAgeCenterTo;
     1928            OpenSound := 'AGE_' + char(48 + Age);
     1929            ShowModal;
     1930            MyData.ToldAge := Age;
     1931            if Age > 0 then
     1932              MyData.ToldTech[AgePreq[Age]] := MyRO.Tech[AgePreq[Age]];
     1933          end;
     1934
     1935        if MyData.ToldAlive <> MyRO.Alive then
     1936        begin
     1937          for p1 := 0 to nPl - 1 do
     1938            if (MyData.ToldAlive - MyRO.Alive) and (1 shl p1) <> 0 then
     1939              with MessgExDlg do
     1940              begin
     1941                OpenSound := 'MSG_EXTINCT';
     1942                s := Tribe[p1].TPhrase('EXTINCT');
     1943                MessgText := Format(s, [TurnToString(MyRO.Turn)]);
     1944                if MyRO.Alive = 1 shl me then
     1945                  MessgText := MessgText + Phrases.Lookup('EXTINCTALL');
     1946                Kind := mkOk;
     1947                IconKind := mikImp;
     1948                IconIndex := 21;
     1949                ShowModal;
     1950              end;
     1951          if (ClientMode <> cMovieTurn) and not supervising then
     1952            DiaDlg.ShowNewContent_Charts(wmModal);
     1953        end;
     1954
     1955        // tell changes of own credibility
     1956        if not supervising then
     1957        begin
     1958          if RoughCredibility(MyRO.Credibility) <>
     1959            RoughCredibility(MyData.ToldOwnCredibility) then
     1960          begin
     1961            if RoughCredibility(MyRO.Credibility) >
     1962              RoughCredibility(MyData.ToldOwnCredibility) then
     1963              s := Phrases.Lookup('CREDUP')
     1964            else
     1965              s := Phrases.Lookup('CREDDOWN');
     1966            TribeMessage(me,
     1967              Format(s, [Phrases.Lookup('CREDIBILITY',
     1968              RoughCredibility(MyRO.Credibility))]), '');
     1969          end;
     1970          MyData.ToldOwnCredibility := MyRO.Credibility;
     1971        end;
     1972
     1973        for i := 0 to 27 do
     1974        begin
     1975          OwnWonder := false;
     1976          for cix := 0 to MyRO.nCity - 1 do
     1977            if (MyCity[cix].Loc >= 0) and
     1978              (MyCity[cix].ID = MyRO.Wonder[i].CityID) then
     1979              OwnWonder := true;
     1980          if MyRO.Wonder[i].CityID <> MyData.ToldWonders[i].CityID then
     1981          begin
     1982            if MyRO.Wonder[i].CityID = -2 then
     1983              with MessgExDlg do
     1984              begin { tell about destroyed wonders }
     1985                OpenSound := 'WONDER_DESTROYED';
     1986                MessgText := Format(Phrases.Lookup('WONDERDEST'),
     1987                  [Phrases.Lookup('IMPROVEMENTS', i)]);
     1988                Kind := mkOkHelp;
     1989                HelpKind := hkImp;
     1990                HelpNo := i;
     1991                IconKind := mikImp;
     1992                IconIndex := i;
     1993                ShowModal;
     1994              end
     1995            else
     1996            begin
     1997              if i = woManhattan then
     1998                if MyRO.Wonder[i].EffectiveOwner > me then
     1999                  MyData.ColdWarStart := MyRO.Turn - 1
     2000                else
     2001                  MyData.ColdWarStart := MyRO.Turn;
     2002              if not OwnWonder then
     2003                with MessgExDlg do
     2004                begin { tell about newly built wonders }
     2005                  if i = woManhattan then
     2006                  begin
     2007                    OpenSound := 'MSG_COLDWAR';
     2008                    s := Tribe[MyRO.Wonder[i].EffectiveOwner].TPhrase('COLDWAR')
     2009                  end
     2010                  else if MyRO.Wonder[i].EffectiveOwner >= 0 then
     2011                  begin
     2012                    OpenSound := 'WONDER_BUILT';
     2013                    s := Tribe[MyRO.Wonder[i].EffectiveOwner]
     2014                      .TPhrase('WONDERBUILT')
     2015                  end
     2016                  else
     2017                  begin
     2018                    OpenSound := 'MSG_DEFAULT';
     2019                    s := Phrases.Lookup('WONDERBUILTEXP');
     2020                    // already expired when built
     2021                  end;
     2022                  MessgText := Format(s, [Phrases.Lookup('IMPROVEMENTS', i),
     2023                    CityName(MyRO.Wonder[i].CityID)]);
     2024                  Kind := mkOkHelp;
     2025                  HelpKind := hkImp;
     2026                  HelpNo := i;
     2027                  IconKind := mikImp;
     2028                  IconIndex := i;
     2029                  ShowModal;
     2030                end
    16572031            end
    16582032          end
    1659         else {if MyRO.Happened and fTimeUp<>0 then}
     2033          else if (MyRO.Wonder[i].EffectiveOwner <> MyData.ToldWonders[i]
     2034            .EffectiveOwner) and (MyRO.Wonder[i].CityID > -2) then
     2035            if MyRO.Wonder[i].EffectiveOwner < 0 then
     2036            begin
     2037              if i <> woMIR then
     2038                with MessgExDlg do
     2039                begin { tell about expired wonders }
     2040                  OpenSound := 'WONDER_EXPIRED';
     2041                  MessgText := Format(Phrases.Lookup('WONDEREXP'),
     2042                    [Phrases.Lookup('IMPROVEMENTS', i),
     2043                    CityName(MyRO.Wonder[i].CityID)]);
     2044                  Kind := mkOkHelp;
     2045                  HelpKind := hkImp;
     2046                  HelpNo := i;
     2047                  IconKind := mikImp;
     2048                  IconIndex := i;
     2049                  ShowModal;
     2050                end
     2051            end
     2052            else if (MyData.ToldWonders[i].EffectiveOwner >= 0) and not OwnWonder
     2053            then
     2054              with MessgExDlg do
     2055              begin { tell about capture of wonders }
     2056                OpenSound := 'WONDER_CAPTURED';
     2057                s := Tribe[MyRO.Wonder[i].EffectiveOwner].TPhrase('WONDERCAPT');
     2058                MessgText := Format(s, [Phrases.Lookup('IMPROVEMENTS', i),
     2059                  CityName(MyRO.Wonder[i].CityID)]);
     2060                Kind := mkOkHelp;
     2061                HelpKind := hkImp;
     2062                HelpNo := i;
     2063                IconKind := mikImp;
     2064                IconIndex := i;
     2065                ShowModal;
     2066              end;
     2067        end;
     2068
     2069        if MyRO.Turn = MyData.ColdWarStart + ColdWarTurns then
     2070        begin
     2071          SoundMessageEx(Phrases.Lookup('COLDWAREND'), 'MSG_DEFAULT');
     2072          MyData.ColdWarStart := -ColdWarTurns - 1
     2073        end;
     2074
     2075        TellNewModels;
     2076      end; // ClientMode<>cResume
     2077      MyData.ToldAlive := MyRO.Alive;
     2078      move(MyRO.Wonder, MyData.ToldWonders, SizeOf(MyData.ToldWonders));
     2079
     2080      NewGovAvailable := -1;
     2081      if ClientMode <> cResume then
     2082      begin // tell about new techs
     2083        for ad := 0 to nAdv - 1 do
     2084          if (MyRO.TestFlags and tfAllTechs = 0) and
     2085            ((MyRO.Tech[ad] >= tsApplicable) <>
     2086            (MyData.ToldTech[ad] >= tsApplicable)) or (ad in FutureTech) and
     2087            (MyRO.Tech[ad] <> MyData.ToldTech[ad]) then
     2088            with MessgExDlg do
     2089            begin
     2090              Item := 'RESEARCH_GENERAL';
     2091              if GameMode <> cMovie then
     2092                OpenSound := 'NEWADVANCE_' + char(48 + Age);
     2093              Item2 := Phrases.Lookup('ADVANCES', ad);
     2094              if ad in FutureTech then
     2095                Item2 := Item2 + ' ' + IntToStr(MyRO.Tech[ad]);
     2096              MessgText := Format(Phrases.Lookup(Item), [Item2]);
     2097              Kind := mkOkHelp;
     2098              HelpKind := hkAdv;
     2099              HelpNo := ad;
     2100              IconKind := mikBook;
     2101              IconIndex := -1;
     2102              for i := 0 to nAdvBookIcon - 1 do
     2103                if AdvBookIcon[i].Adv = ad then
     2104                  IconIndex := AdvBookIcon[i].Icon;
     2105              ShowModal;
     2106              MyData.ToldTech[ad] := MyRO.Tech[ad];
     2107              for i := gMonarchy to nGov - 1 do
     2108                if GovPreq[i] = ad then
     2109                  NewGovAvailable := i;
     2110            end;
     2111      end;
     2112
     2113      ShowCityList := false;
     2114      if ClientMode = cTurn then
     2115      begin
     2116        if (MyRO.Happened and phTech <> 0) and (MyData.FarTech <> adNexus) then
     2117          ChooseResearch;
     2118
     2119        UpdatePanel := false;
     2120        if MyRO.Happened and phChangeGov <> 0 then
     2121        begin
     2122          ModalSelectDlg.ShowNewContent(wmModal, kGov);
     2123          Play('NEWGOV');
     2124          Server(sSetGovernment, me, ModalSelectDlg.result, nil^);
     2125          CityOptimizer_BeginOfTurn;
     2126          UpdatePanel := true;
     2127        end;
     2128      end; // ClientMode=cTurn
     2129
     2130      if not supervising and ((ClientMode = cTurn) or (ClientMode = cMovieTurn))
     2131      then
     2132        for cix := 0 to MyRO.nCity - 1 do
     2133          with MyCity[cix] do
     2134            Status := Status and not csToldBombard;
     2135
     2136      if ((ClientMode = cTurn) or (ClientMode = cMovieTurn)) and
     2137        (MyRO.Government <> gAnarchy) then
     2138      begin
     2139        // tell what happened in cities
     2140        for WondersOnly := true downto false do
     2141          for cix := 0 to MyRO.nCity - 1 do
     2142            with MyCity[cix] do
     2143              if (MyRO.Turn > 0) and (Loc >= 0) and (Flags and chCaptured = 0)
     2144                and (WondersOnly = (Flags and chProduction <> 0) and
     2145                (Project0 and cpImp <> 0) and (Project0 and cpIndex < 28)) then
     2146              begin
     2147                if WondersOnly then
     2148                  with MessgExDlg do
     2149                  begin { tell about newly built wonder }
     2150                    OpenSound := 'WONDER_BUILT';
     2151                    s := Tribe[me].TPhrase('WONDERBUILTOWN');
     2152                    MessgText :=
     2153                      Format(s, [Phrases.Lookup('IMPROVEMENTS',
     2154                      Project0 and cpIndex), CityName(ID)]);
     2155                    Kind := mkOkHelp;
     2156                    HelpKind := hkImp;
     2157                    HelpNo := Project0 and cpIndex;
     2158                    IconKind := mikImp;
     2159                    IconIndex := Project0 and cpIndex;
     2160                    ShowModal;
     2161                  end;
     2162                if not supervising and (ClientMode = cTurn) then
     2163                begin
     2164                  AllowCityScreen := true;
     2165                  if (Status and 7 <> 0) and
     2166                    (Project and (cpImp + cpIndex) = cpImp + imTrGoods) then
     2167                    if (MyData.ImpOrder[Status and 7 - 1, 0] >= 0) then
     2168                    begin
     2169                      if AutoBuild(cix, MyData.ImpOrder[Status and 7 - 1]) then
     2170                        AllowCityScreen := false
     2171                      else if Flags and chProduction <> 0 then
     2172                        Flags := (Flags and not chProduction) or chAllImpsMade
     2173                    end
     2174                    else
     2175                      Flags := Flags or chTypeDel;
     2176                  if (Size >= NeedAqueductSize) and
     2177                    (MyRO.Tech[Imp[imAqueduct].Preq] < tsApplicable) or
     2178                    (Size >= NeedSewerSize) and
     2179                    (MyRO.Tech[Imp[imSewer].Preq] < tsApplicable) then
     2180                    Flags := Flags and not chNoGrowthWarning;
     2181                  // don't remind of unknown building
     2182                  if Flags and chNoSettlerProd = 0 then
     2183                    Status := Status and not csToldDelay
     2184                  else if Status and csToldDelay = 0 then
     2185                    Status := Status or csToldDelay
     2186                  else
     2187                    Flags := Flags and not chNoSettlerProd;
     2188                  if mRepScreens.Checked then
     2189                  begin
     2190                    if (Flags and CityRepMask <> 0) and AllowCityScreen then
     2191                    begin { show what happened in cities }
     2192                      SetTroopLoc(MyCity[cix].Loc);
     2193                      MarkCityLoc := MyCity[cix].Loc;
     2194                      PanelPaint;
     2195                      CityDlg.CloseAction := None;
     2196                      CityDlg.ShowNewContent(wmModal, MyCity[cix].Loc,
     2197                        Flags and CityRepMask);
     2198                      UpdatePanel := true;
     2199                    end
     2200                  end
     2201                  else { if mRepList.Checked then }
     2202                  begin
     2203                    if Flags and CityRepMask <> 0 then
     2204                      ShowCityList := true
     2205                  end
     2206                end
     2207              end; { city loop }
     2208      end; // ClientMode=cTurn
     2209
     2210      if ClientMode = cTurn then
     2211      begin
     2212        if NewGovAvailable >= 0 then
     2213          with MessgExDlg do
    16602214          begin
    1661           assert(me=0);
    1662           OpenSound:='MSG_GAMEOVER';
    1663           if not supervising then MessgText:=Tribe[me].TPhrase('TIMEUP')
    1664           else MessgText:=Phrases.Lookup('TIMEUPSUPER');
    1665           IconKind:=mikImp;
    1666           IconIndex:=22;
     2215            MessgText := Format(Phrases.Lookup('AUTOREVOLUTION'),
     2216              [Phrases.Lookup('GOVERNMENT', NewGovAvailable)]);
     2217            Kind := mkYesNo;
     2218            IconKind := mikPureIcon;
     2219            IconIndex := 6 + NewGovAvailable;
     2220            ShowModal;
     2221            if ModalResult = mrOK then
     2222            begin
     2223              Play('REVOLUTION');
     2224              Server(sRevolution, me, 0, nil^);
     2225            end
    16672226          end;
    1668         Kind:=mkOK;
    1669         ShowModal;
    1670         if MyRO.Happened and phExtinct=0 then
     2227      end; // ClientMode=cTurn
     2228
     2229      if (ClientMode = cTurn) or (ClientMode = cMovieTurn) then
     2230      begin
     2231        if MyRO.Happened and phGliderLost <> 0 then
     2232          ContextMessage(Phrases.Lookup('GLIDERLOST'), 'MSG_DEFAULT',
     2233            hkModel, 200);
     2234        if MyRO.Happened and phPlaneLost <> 0 then
     2235          ContextMessage(Phrases.Lookup('PLANELOST'), 'MSG_DEFAULT',
     2236            hkFeature, mcFuel);
     2237        if MyRO.Happened and phPeaceEvacuation <> 0 then
     2238          for p1 := 0 to nPl - 1 do
     2239            if 1 shl p1 and MyData.PeaceEvaHappened <> 0 then
     2240              SoundMessageEx(Tribe[p1].TPhrase('WITHDRAW'), 'MSG_DEFAULT');
     2241        if MyRO.Happened and phPeaceViolation <> 0 then
     2242          for p1 := 0 to nPl - 1 do
     2243            if (1 shl p1 and MyRO.Alive <> 0) and (MyRO.EvaStart[p1] = MyRO.Turn)
     2244            then
     2245              SoundMessageEx(Format(Tribe[p1].TPhrase('VIOLATION'),
     2246                [TurnToString(MyRO.Turn + PeaceEvaTurns - 1)]), 'MSG_WITHDRAW');
     2247        TellNewContacts;
     2248      end;
     2249
     2250      if ClientMode = cMovieTurn then
     2251        Update
     2252      else if ClientMode = cTurn then
     2253      begin
     2254        if UpdatePanel then
     2255          UpdateViews;
     2256        Application.ProcessMessages;
     2257
     2258        if not supervising then
     2259          for uix := 0 to MyRO.nUn - 1 do
     2260            with MyUn[uix] do
     2261              if Loc >= 0 then
     2262              begin
     2263                if Flags and unWithdrawn <> 0 then
     2264                  Status := 0;
     2265                if Health = 100 then
     2266                  Status := Status and not usRecover;
     2267                if (Master >= 0) or UnitExhausted(uix) then
     2268                  Status := Status and not usWaiting
     2269                else
     2270                  Status := Status or usWaiting;
     2271                CheckToldNoReturn(uix);
     2272                if Status and usGoto <> 0 then
     2273                begin { continue multi-turn goto }
     2274                  SetUnFocus(uix);
     2275                  SetTroopLoc(Loc);
     2276                  FocusOnLoc(TroopLoc, flRepaintPanel or flImmUpdate);
     2277                  if Status shr 16 = $7FFF then
     2278                    MoveResult := GetMoveAdvice(UnFocus, maNextCity,
     2279                      MoveAdviceData)
     2280                  else
     2281                    MoveResult := GetMoveAdvice(UnFocus, Status shr 16,
     2282                      MoveAdviceData);
     2283                  if MoveResult >= rExecuted then
     2284                  begin // !!! Shinkansen
     2285                    MoveResult := eOK;
     2286                    ok := true;
     2287                    for i := 0 to MoveAdviceData.nStep - 1 do
     2288                    begin
     2289                      Loc1 := dLoc(Loc, MoveAdviceData.dx[i],
     2290                        MoveAdviceData.dy[i]);
     2291                      if (MyMap[Loc1] and (fCity or fOwned) = fCity)
     2292                      // don't capture cities during auto move
     2293                        or (MyMap[Loc1] and (fUnit or fOwned) = fUnit) then
     2294                      // don't attack during auto move
     2295                      begin
     2296                        ok := false;
     2297                        Break
     2298                      end
     2299                      else
     2300                      begin
     2301                        if (Loc1 = MoveAdviceData.ToLoc) or
     2302                          (MoveAdviceData.ToLoc = maNextCity) and
     2303                          (MyMap[dLoc(Loc, MoveAdviceData.dx[i],
     2304                          MoveAdviceData.dy[i])] and fCity <> 0) then
     2305                          MoveOptions := muAutoNoWait
     2306                        else
     2307                          MoveOptions := 0;
     2308                        MoveResult := MoveUnit(MoveAdviceData.dx[i],
     2309                          MoveAdviceData.dy[i], MoveOptions);
     2310                        if (MoveResult < rExecuted) or
     2311                          (MoveResult = eEnemySpotted) then
     2312                        begin
     2313                          ok := false;
     2314                          Break
     2315                        end;
     2316                      end
     2317                    end;
     2318                    Stop := not ok or (Loc = MoveAdviceData.ToLoc) or
     2319                      (MoveAdviceData.ToLoc = maNextCity) and
     2320                      (MyMap[Loc] and fCity <> 0)
     2321                  end
     2322                  else
     2323                  begin
     2324                    MoveResult := eOK;
     2325                    Stop := true;
     2326                  end;
     2327
     2328                  if MoveResult <> eDied then
     2329                    if Stop then
     2330                      Status := Status and ($FFFF - usGoto)
     2331                    else
     2332                      Status := Status and not usWaiting;
     2333                end;
     2334
     2335                if Status and (usEnhance or usGoto) = usEnhance then
     2336                // continue terrain enhancement
     2337                begin
     2338                  MoveResult := ProcessEnhancement(uix, MyData.EnhancementJobs);
     2339                  if MoveResult <> eDied then
     2340                    if MoveResult = eJobDone then
     2341                      Status := Status and not usEnhance
     2342                    else
     2343                      Status := Status and not usWaiting;
     2344                end
     2345              end;
     2346      end; // ClientMode=cTurn
     2347
     2348      HaveStrategyAdvice := false;
     2349      // (GameMode<>cMovie) and not supervising
     2350      // and AdvisorDlg.HaveStrategyAdvice;
     2351      GoOnPhase := true;
     2352      if supervising or (GameMode = cMovie) then
     2353      begin
     2354        SetTroopLoc(-1);
     2355        PaintAll
     2356      end { supervisor }
     2357      { else if (ClientMode=cTurn) and (MyRO.Turn=0) then
     2358        begin
     2359        SetUnFocus(0);
     2360        ZoomToCity(MyCity[0].Loc)
     2361        end }
     2362      else
     2363      begin
     2364        if ClientMode >= scContact then
     2365          SetUnFocus(-1)
     2366        else
     2367          NextUnit(-1, false);
     2368        if UnFocus < 0 then
     2369        begin
     2370          UnStartLoc := -1;
     2371          if IsMultiPlayerGame or (ClientMode = cResume) then
     2372            if MyRO.nCity > 0 then
     2373              FocusOnLoc(MyCity[0].Loc)
     2374            else
     2375              FocusOnLoc(G.lx * G.ly div 2);
     2376          SetTroopLoc(-1);
     2377          PanelPaint
     2378        end;
     2379        if ShowCityList then
     2380          ListDlg.ShowNewContent(wmPersistent, kCityEvents);
     2381      end;
     2382    end; { InitTurn }
     2383
     2384  var
     2385    i, j, p1, mix, ToLoc, AnimationSpeed, ShowMoveDomain, cix, ecix: integer;
     2386    Color: TColor;
     2387    Name, s: string;
     2388    TribeInfo: TTribeInfo;
     2389    mi: TModelInfo;
     2390    SkipTurn, IsAlpine, IsTreatyDeal: boolean;
     2391
     2392  begin { >>>client }
     2393    case Command of
     2394      cTurn, cResume, cContinue, cMovieTurn, scContact,
     2395        scDipStart .. scDipBreak:
     2396        begin
     2397          supervising := G.Difficulty[NewPlayer] = 0;
     2398          ArrangeMidPanel;
     2399        end
     2400    end;
     2401    case Command of
     2402      cDebugMessage:
     2403        LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(@Data));
     2404
     2405      cShowNego:
     2406        with TShowNegoData(Data) do
     2407        begin
     2408          s := Format('P%d to P%d: ', [pSender, pTarget]);
     2409          if (Action = scDipOffer) and (Offer.nDeliver + Offer.nCost > 0) then
    16712410          begin
    1672           p1:=0;
    1673           while (p1<nPl-1) and (Winners and (1 shl p1)=0) do inc(p1);
    1674           if MyRO.Happened and phShipComplete=0 then
    1675             DiaDlg.ShowNewContent_Charts(wmModal);
     2411            s := s + 'Offer ';
     2412            for i := 0 to Offer.nDeliver + Offer.nCost - 1 do
     2413            begin
     2414              if i = Offer.nDeliver then
     2415                s := s + ' for '
     2416              else if i > 0 then
     2417                s := s + '+';
     2418              case Offer.Price[i] and opMask of
     2419                opChoose:
     2420                  s := s + 'Price of choice';
     2421                opCivilReport:
     2422                  s := s + 'State report';
     2423                opMilReport:
     2424                  s := s + 'Military report';
     2425                opMap:
     2426                  s := s + 'Map';
     2427                opTreaty:
     2428                  s := s + 'Treaty';
     2429                opShipParts:
     2430                  s := s + 'Ship part';
     2431                opMoney:
     2432                  s := s + IntToStr(Offer.Price[i] and $FFFFFF) + 'o';
     2433                opTribute:
     2434                  s := s + IntToStr(Offer.Price[i] and $FFFFFF) + 'o tribute';
     2435                opTech:
     2436                  s := s + Phrases.Lookup('ADVANCES',
     2437                    Offer.Price[i] and $FFFFFF);
     2438                opAllTech:
     2439                  s := s + 'All advances';
     2440                opModel:
     2441                  s := s + Tribe[pSender].ModelName[Offer.Price[i] and $FFFFFF];
     2442                opAllModel:
     2443                  s := s + 'All models';
     2444              end
     2445            end;
     2446            LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(s));
     2447          end
     2448          else if Action = scDipAccept then
     2449          begin
     2450            s := s + '--- ACCEPTED! ---';
     2451            LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(s));
     2452          end
     2453        end;
     2454
     2455      cInitModule:
     2456        begin
     2457          Server := TInitModuleData(Data).Server;
     2458          // AdvisorDlg.Init;
     2459          InitModule;
     2460          TInitModuleData(Data).DataSize := SizeOf(TPersistentData);
     2461          TInitModuleData(Data).Flags := aiThreaded;
     2462        end;
     2463
     2464      cReleaseModule:
     2465        begin
     2466          SmallImp.free;
     2467          UnusedTribeFiles.free;
     2468          TribeNames.free;
     2469          MainMap.free;
     2470          IsoEngine.Done;
     2471          // AdvisorDlg.DeInit;
     2472        end;
     2473
     2474      cHelpOnly, cStartHelp, cStartCredits:
     2475        begin
     2476          Age := 0;
     2477          if Command = cHelpOnly then
     2478            SetMainTextureByAge(-1);
     2479          Tribes.Init;
     2480          HelpDlg.UserLeft := (Screen.width - HelpDlg.width) div 2;
     2481          HelpDlg.UserTop := (Screen.height - HelpDlg.height) div 2;
     2482          HelpDlg.Difficulty := 0;
     2483          if Command = cStartCredits then
     2484            HelpDlg.ShowNewContent(wmModal, hkMisc, miscCredits)
     2485          else
     2486            HelpDlg.ShowNewContent(wmModal, hkMisc, miscMain);
     2487          Tribes.Done;
     2488        end;
     2489
     2490      cNewGame, cLoadGame, cMovie, cNewMap:
     2491        begin
     2492          { if (Command=cNewGame) or (Command=cLoadGame) then
     2493            AdvisorDlg.NewGame(Data); }
     2494          GenerateNames := mNames.Checked;
     2495          GameOK := true;
     2496          G := TNewGameData(Data);
     2497          me := -1;
     2498          pLogo := -1;
     2499          ClientMode := -1;
     2500          SetMapOptions;
     2501          IsoEngine.pDebugMap := -1;
     2502          idle := false;
     2503          FillChar(Jump, SizeOf(Jump), 0);
     2504          if StartRunning then
     2505            Jump[0] := 999999;
     2506          GameMode := Command;
     2507          for i := 0 to nGrExt - 1 do
     2508            FillChar(GrExt[i].pixUsed, GrExt[i].Data.height div 49 * 10, 0);
     2509          IsoEngine.Reset;
     2510          Tribes.Init;
     2511          GetTribeList;
     2512          for p1 := 0 to nPl - 1 do
     2513            if (G.RO[p1] <> nil) and (G.RO[p1].Data <> nil) then
     2514              with TPersistentData(G.RO[p1].Data^) do
     2515              begin
     2516                FarTech := adNone;
     2517                FillChar(EnhancementJobs, SizeOf(EnhancementJobs), jNone);
     2518                FillChar(ImpOrder, SizeOf(ImpOrder), -1);
     2519                ColdWarStart := -ColdWarTurns - 1;
     2520                ToldAge := -1;
     2521                ToldModels := 3;
     2522                ToldAlive := 0;
     2523                ToldContact := 0;
     2524                ToldOwnCredibility := InitialCredibility;
     2525                for i := 0 to nPl - 1 do
     2526                  if G.Difficulty[i] > 0 then
     2527                    inc(ToldAlive, 1 shl i);
     2528                PeaceEvaHappened := 0;
     2529                for i := 0 to 27 do
     2530                  with ToldWonders[i] do
     2531                  begin
     2532                    CityID := -1;
     2533                    EffectiveOwner := -1
     2534                  end;
     2535                FillChar(ToldTech, SizeOf(ToldTech), tsNA);
     2536                if G.Difficulty[p1] > 0 then
     2537                  SoundPreload(sbStart);
     2538              end;
     2539
     2540          // arrange dialogs
     2541          ListDlg.UserLeft := 8;
     2542          ListDlg.UserTop := TopBarHeight + 8;
     2543          HelpDlg.UserLeft := Screen.width - HelpDlg.width - 8;
     2544          HelpDlg.UserTop := TopBarHeight + 8;
     2545          UnitStatDlg.UserLeft := 397;
     2546          UnitStatDlg.UserTop := TopBarHeight + 64;
     2547          DiaDlg.UserLeft := (Screen.width - DiaDlg.width) div 2;
     2548          DiaDlg.UserTop := (Screen.height - DiaDlg.height) div 2;
     2549          NatStatDlg.UserLeft := Screen.width - NatStatDlg.width - 8;
     2550          NatStatDlg.UserTop := Screen.height - PanelHeight -
     2551            NatStatDlg.height - 8;
     2552          if NatStatDlg.UserTop < 8 then
     2553            NatStatDlg.UserTop := 8;
     2554
     2555          Age := 0;
     2556          MovieSpeed := 1;
     2557          LogDlg.mSlot.Visible := true;
     2558          LogDlg.Host := self;
     2559          HelpDlg.ClearHistory;
     2560          CityDlg.Reset;
     2561
     2562          Mini.width := G.lx * 2;
     2563          Mini.height := G.ly;
     2564          for i := 0 to nPl - 1 do
     2565          begin
     2566            Tribe[i] := nil;
     2567            TribeOriginal[i] := false;
    16762568          end;
    1677         TurnComplete:=true;
    1678         exit;
    1679         end;
    1680     if not supervising and (1 shl me and MyRO.Alive=0) then
    1681       begin TurnComplete:=true; exit; end;
    1682 
    1683     if (ClientMode=cContinue) and (DipMem[me].SentCommand and $FF0F=scContact) then
    1684       // contact was refused
    1685       if MyRO.Treaty[DipMem[me].pContact]>=trPeace then
    1686         ContactRefused(DipMem[me].pContact, 'FRREJECTED')
    1687       else SoundMessage(Tribe[DipMem[me].pContact].TPhrase('FRREJECTED'),'NEGO_REJECTED');
    1688 
    1689     if not supervising and (Age>MyData.ToldAge)
    1690       and ((Age>0) or (ClientMode<>cMovieTurn)) then with MessgExDlg do
    1691       begin
    1692       if Age=0 then
    1693         begin
    1694         if Phrases2FallenBackToEnglish then
     2569          ToldSlavery := -1;
     2570          RepaintOnResize := false;
     2571          Closable := false;
     2572          FirstMovieTurn := true;
     2573
     2574          MenuArea.Visible := GameMode <> cMovie;
     2575          TreasuryArea.Visible := GameMode < cMovie;
     2576          ResearchArea.Visible := GameMode < cMovie;
     2577          ManagementArea.Visible := GameMode < cMovie;
     2578        end;
     2579
     2580      cGetReady, cReplay:
     2581        if NewPlayer = 0 then
     2582        begin
     2583          i := 0;
     2584          for p1 := 0 to nPl - 1 do
     2585            if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) then
     2586              inc(i);
     2587          if i > UnusedTribeFiles.Count then
    16952588          begin
    1696           s:=Tribe[me].TPhrase('AGE0');
    1697           MessgText:=Format(s,[TurnToString(MyRO.Turn),CityName(MyCity[0].ID)])
     2589            GameOK := false;
     2590            SimpleMessage(Phrases.Lookup('TOOFEWTRIBES'));
    16982591          end
     2592          else
     2593          begin
     2594            for p1 := 0 to nPl - 1 do
     2595              if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) and
     2596                (G.RO[p1] <> nil) then
     2597              begin // let player select own tribes
     2598                TribeInfo.trix := p1;
     2599                TribeNames.Clear;
     2600                for j := 0 to UnusedTribeFiles.Count - 1 do
     2601                begin
     2602                  GetTribeInfo(UnusedTribeFiles[j], Name, Color);
     2603                  TribeNames.AddObject(Name, TObject(Color));
     2604                end;
     2605                assert(TribeNames.Count > 0);
     2606                ModalSelectDlg.ShowNewContent(wmModal, kTribe);
     2607                Application.ProcessMessages;
     2608                TribeInfo.FileName := UnusedTribeFiles[ModalSelectDlg.result];
     2609                UnusedTribeFiles.Delete(ModalSelectDlg.result);
     2610
     2611                if GameMode = cLoadGame then
     2612                  CreateTribe(TribeInfo.trix, TribeInfo.FileName, false)
     2613                else
     2614                  Server(cSetTribe + (Length(TribeInfo.FileName) + 1 + 7) div 4,
     2615                    0, 0, TribeInfo);
     2616              end;
     2617
     2618            for p1 := 0 to nPl - 1 do
     2619              if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) and
     2620                (G.RO[p1] = nil) then
     2621              begin // autoselect enemy tribes
     2622                j := ChooseUnusedTribe;
     2623                TribeInfo.FileName := UnusedTribeFiles[j];
     2624                UnusedTribeFiles.Delete(j);
     2625                TribeInfo.trix := p1;
     2626                if GameMode = cLoadGame then
     2627                  CreateTribe(TribeInfo.trix, TribeInfo.FileName, false)
     2628                else
     2629                  Server(cSetTribe + (Length(TribeInfo.FileName) + 1 + 7) div 4,
     2630                    0, 0, TribeInfo);
     2631              end;
     2632          end;
     2633          if not mNames.Checked then
     2634            for p1 := 0 to nPl - 1 do
     2635              if Tribe[p1] <> nil then
     2636                Tribe[p1].NumberName := p1;
     2637        end;
     2638
     2639      cBreakGame:
     2640        begin
     2641          SaveSettings;
     2642          CityDlg.CloseAction := None;
     2643          for i := 0 to Screen.FormCount - 1 do
     2644            if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
     2645            then
     2646              Screen.Forms[i].Close;
     2647          if LogDlg.Visible then
     2648            LogDlg.Close;
     2649          LogDlg.List.Clear;
     2650          StartRunning := not idle and (Jump[0] > 0); // AI called Reload
     2651          me := -1;
     2652          idle := false;
     2653          ClientMode := -1;
     2654          UnitInfoBtn.Visible := false;
     2655          UnitBtn.Visible := false;
     2656          TerrainBtn.Visible := false;
     2657          MovieSpeed1Btn.Visible := false;
     2658          MovieSpeed2Btn.Visible := false;
     2659          MovieSpeed3Btn.Visible := false;
     2660          MovieSpeed4Btn.Visible := false;
     2661          EOT.Visible := false;
     2662          for i := 0 to ControlCount - 1 do
     2663            if Controls[i] is TButtonC then
     2664              Controls[i].Visible := false;
     2665          InitPVSB(sb, 0, 1);
     2666          for p1 := 0 to nPl - 1 do
     2667            if Tribe[p1] <> nil then
     2668              Tribe[p1].free;
     2669          Tribes.Done;
     2670          RepaintOnResize := false;
     2671          Closable := true;
     2672          Close;
     2673          { if (GameMode=cNewGame) or (GameMode=cLoadGame) then
     2674            AdvisorDlg.BreakGame; }
     2675        end;
     2676
     2677      cShowGame:
     2678        begin
     2679          with Panel.Canvas do
     2680          begin
     2681            Brush.Color := $000000;
     2682            FillRect(Rect(0, 0, Panel.width, Panel.height));
     2683            Brush.Style := bsClear;
     2684          end;
     2685          with TopBar.Canvas do
     2686          begin
     2687            Brush.Color := $000000;
     2688            FillRect(Rect(0, 0, TopBar.width, TopBar.height));
     2689            Brush.Style := bsClear;
     2690          end;
     2691          FormResize(nil); // place mini map correctly according to its size
     2692          Show;
     2693          Update;
     2694          RepaintOnResize := true;
     2695          xw := 0;
     2696          yw := ywcenter;
     2697          if not StayOnTop_Ensured then
     2698          begin
     2699            StayOnTop_Ensured := true;
     2700            CityDlg.StayOnTop_Workaround;
     2701            CityTypeDlg.StayOnTop_Workaround;
     2702            DiaDlg.StayOnTop_Workaround;
     2703            DraftDlg.StayOnTop_Workaround;
     2704            EnhanceDlg.StayOnTop_Workaround;
     2705            HelpDlg.StayOnTop_Workaround;
     2706            NatStatDlg.StayOnTop_Workaround;
     2707            NegoDlg.StayOnTop_Workaround;
     2708            ModalSelectDlg.StayOnTop_Workaround;
     2709            ListDlg.StayOnTop_Workaround;
     2710            UnitStatDlg.StayOnTop_Workaround;
     2711            WondersDlg.StayOnTop_Workaround;
     2712            RatesDlg.StayOnTop_Workaround;
     2713          end;
     2714        end;
     2715
     2716      cShowTurnChange:
     2717        begin
     2718          if integer(Data) >= 0 then
     2719          begin
     2720            pLogo := integer(Data);
     2721            if G.RO[pLogo] = nil then
     2722            begin
     2723              if AILogo[pLogo] <> nil then
     2724                BitBlt(Canvas.Handle, (xRightPanel + 10) - (16 + 64),
     2725                  ClientHeight - PanelHeight, 64, 64,
     2726                  AILogo[pLogo].Canvas.Handle, 0, 0, SRCCOPY);
     2727            end
     2728          end
     2729        end;
     2730
     2731      cTurn, cResume, cContinue:
     2732        if not GameOK then
     2733          Server(sResign, NewPlayer, 0, nil^)
    16992734        else
     2735        begin
     2736          ClientMode := Command;
     2737          pTurn := NewPlayer;
     2738          pLogo := NewPlayer;
     2739
     2740          if Command = cResume then
     2741          begin // init non-original model pictures (maybe tribes not found)
     2742            for p1 := 0 to nPl - 1 do
     2743              if G.RO[p1] <> nil then
     2744              begin
     2745                ItsMeAgain(p1);
     2746                for mix := 0 to MyRO.nModel - 1 do
     2747                  if Tribe[me].ModelPicture[mix].HGr = 0 then
     2748                    InitMyModel(mix, true);
     2749              end;
     2750            me := -1;
     2751          end;
     2752
     2753          if Jump[pTurn] > 0 then
     2754            Application.ProcessMessages;
     2755          if Jump[pTurn] > 0 then
     2756            if G.RO[NewPlayer].Happened and phGameEnd <> 0 then
     2757              Jump[pTurn] := 0
     2758            else
     2759              dec(Jump[pTurn]);
     2760          SkipTurn := Jump[pTurn] > 0;
     2761          if SkipTurn then
    17002762          begin
    1701           s:=Tribe[me].TString(Phrases2.Lookup('AGE0'));
    1702           MessgText:=Format(s,[TurnToString(MyRO.Turn)]);
     2763            ItsMeAgain(NewPlayer);
     2764            MyData := G.RO[NewPlayer].Data;
     2765            SetTroopLoc(-1);
     2766            MiniPaint;
     2767            InitAllEnemyModels; // necessary for correct replay
     2768            if not EndTurn(true) then
     2769              SkipTurn := false;
     2770          end;
     2771          if not SkipTurn then
     2772          begin
     2773            if ((ClientMode < scDipStart) or (ClientMode > scDipBreak)) and
     2774              NegoDlg.Visible then
     2775              NegoDlg.Close;
     2776            skipped := false; // always show my moves during my turn
     2777            idle := true;
     2778            InitTurn(NewPlayer);
     2779            DipMem[me].pContact := -1;
     2780            (* if (me=0) and (MyRO.Alive and (1 shl me)=0)} then
     2781              begin
     2782              if SimpleQuery(Phrases.Lookup('RESIGN'))=mrIgnore then
     2783              Server(sResign,me,0,nil^)
     2784              else Server(sBreak,me,0,nil^)
     2785              end
     2786              else Play('TURNSTART'); *)
     2787          end;
     2788        end;
     2789
     2790      cMovieTurn:
     2791        begin
     2792          ClientMode := Command;
     2793          pTurn := NewPlayer;
     2794          pLogo := -1;
     2795          skipped := false; // always show my moves during my turn
     2796          idle := true;
     2797          if FirstMovieTurn then
     2798          begin
     2799            CheckMovieSpeedBtnState;
     2800            FirstMovieTurn := false;
     2801          end;
     2802          InitTurn(NewPlayer);
     2803          Application.ProcessMessages;
     2804          if MovieSpeed = 4 then
     2805          begin
     2806            Sleep(75);
     2807            // this break will ensure speed of fast forward does not depend on cpu speed
     2808            Application.ProcessMessages;
     2809          end
     2810        end;
     2811
     2812      cMovieEndTurn:
     2813        begin
     2814          RememberPeaceViolation;
     2815          pTurn := -1;
     2816          pLogo := -1;
     2817          MapValid := false;
     2818          ClientMode := -1;
     2819          idle := false;
     2820          skipped := false;
     2821        end;
     2822
     2823      cEditMap:
     2824        begin
     2825          ClientMode := cEditMap;
     2826          SetMapOptions;
     2827          IsoEngine.pDebugMap := -1;
     2828          ItsMeAgain(0);
     2829          MyData := nil;
     2830          UnitInfoBtn.Visible := false;
     2831          UnitBtn.Visible := false;
     2832          TerrainBtn.Visible := false;
     2833          MovieSpeed1Btn.Visible := false;
     2834          MovieSpeed2Btn.Visible := false;
     2835          MovieSpeed3Btn.Visible := false;
     2836          MovieSpeed4Btn.Visible := false;
     2837          EOT.Visible := false;
     2838          HelpDlg.Difficulty := 0;
     2839          BrushType := fGrass;
     2840          BrushLoc := -1;
     2841          Edited := false;
     2842          UnFocus := -1;
     2843          MarkCityLoc := -1;
     2844          Tracking := false;
     2845          TurnComplete := false;
     2846          MapValid := false;
     2847          FormResize(nil); // calculate geometrics and paint all
     2848          SetTroopLoc(-1);
     2849          idle := true
     2850        end;
     2851
     2852      (* cNewContact:
     2853        begin
     2854        end;
     2855      *)
     2856
     2857      scContact:
     2858        begin
     2859          DipMem[NewPlayer].pContact := integer(Data);
     2860          if Jump[NewPlayer] > 0 then
     2861            DipCall(scReject)
     2862          else
     2863          begin
     2864            ClientMode := Command;
     2865            InitTurn(NewPlayer);
     2866            MyData.ToldContact := MyData.ToldContact or (1 shl integer(Data));
     2867            // don't tell about new nation when already contacted by them
     2868            with MessgExDlg do
     2869            begin
     2870              OpenSound := 'CONTACT_' + char(48 + MyRO.EnemyReport[integer(Data)
     2871                ].Attitude);
     2872              MessgText := Tribe[integer(Data)].TPhrase('FRCONTACT');
     2873              Kind := mkYesNo;
     2874              IconKind := mikTribe;
     2875              IconIndex := integer(Data);
     2876              ShowModal;
     2877              if ModalResult = mrOK then
     2878              begin
     2879                NegoDlg.Respond;
     2880                DipMem[me].DeliveredPrices := [];
     2881                DipMem[me].ReceivedPrices := [];
     2882                DipCall(scDipStart)
     2883              end
     2884              else
     2885              begin
     2886                DipCall(scReject);
     2887                EndNego
     2888              end
     2889            end
     2890          end;
     2891        end;
     2892
     2893      scDipStart .. scDipBreak:
     2894        begin
     2895          ClientMode := Command;
     2896          InitTurn(NewPlayer);
     2897          if Command = scDipStart then
     2898            Play('CONTACT_' + char(48 + MyRO.Attitude[DipMem[NewPlayer]
     2899              .pContact]))
     2900          else if Command = scDipCancelTreaty then
     2901            Play('CANCELTREATY')
     2902          else if Command = scDipOffer then
     2903          begin
     2904            ReceivedOffer := TOffer(Data);
     2905            InitAllEnemyModels;
     2906          end
     2907          else if Command = scDipAccept then
     2908          begin // remember delivered and received prices
     2909            for i := 0 to DipMem[me].SentOffer.nDeliver - 1 do
     2910              include(DipMem[me].DeliveredPrices,
     2911                DipMem[me].SentOffer.Price[i] shr 24);
     2912            for i := 0 to DipMem[me].SentOffer.nCost - 1 do
     2913              include(DipMem[me].ReceivedPrices,
     2914                DipMem[me].SentOffer.Price[DipMem[me].SentOffer.nDeliver +
     2915                i] shr 24);
     2916            IsTreatyDeal := false;
     2917            for i := 0 to ReceivedOffer.nDeliver + ReceivedOffer.nCost - 1 do
     2918              if DipMem[me].SentOffer.Price[i] and opMask = opTreaty then
     2919                IsTreatyDeal := true;
     2920            if IsTreatyDeal then
     2921              Play('NEWTREATY')
     2922            else
     2923              Play('ACCEPTOFFER');
     2924          end;
     2925          NegoDlg.Start;
     2926          idle := true
     2927        end;
     2928
     2929      cShowCancelTreaty:
     2930        if not IsMultiPlayerGame then
     2931        begin
     2932          case G.RO[NewPlayer].Treaty[integer(Data)] of
     2933            trPeace:
     2934              s := Tribe[integer(Data)].TPhrase('FRCANCELBYREJECT_PEACE');
     2935            trFriendlyContact:
     2936              s := Tribe[integer(Data)].TPhrase('FRCANCELBYREJECT_FRIENDLY');
     2937            trAlliance:
     2938              s := Tribe[integer(Data)].TPhrase('FRCANCELBYREJECT_ALLIANCE');
     2939          end;
     2940          TribeMessage(integer(Data), s, 'CANCELTREATY');
     2941        end;
     2942
     2943      cShowCancelTreatyByAlliance:
     2944        if idle and (NewPlayer = me) then
     2945          TribeMessage(integer(Data), Tribe[integer(Data)
     2946            ].TPhrase('FRENEMYALLIANCE'), 'CANCELTREATY');
     2947
     2948      cShowSupportAllianceAgainst:
     2949        if not IsMultiPlayerGame and (Jump[0] = 0) then
     2950          TribeMessage(integer(Data) and $F,
     2951            Tribe[integer(Data) and $F].TPhrase('FRMYALLIANCE1') + ' ' +
     2952            Tribe[integer(Data) shr 4].TPhrase('FRMYALLIANCE2'),
     2953            '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
     3087            end
     3088            else
     3089            begin
     3090              CurrentMoveInfo.IsAlly := MyRO.Treaty[Owner] = trAlliance;
     3091              if GameMode = cMovie then
     3092                CurrentMoveInfo.DoShow := true
     3093              else if CurrentMoveInfo.IsAlly then
     3094                CurrentMoveInfo.DoShow := not mAlNoMoves.Checked and
     3095                  not(mAlEffectiveMovesOnly.Checked and
     3096                  (Command <> cShowCapturing))
     3097              else
     3098                CurrentMoveInfo.DoShow := not mEnNoMoves.Checked and
     3099                  not(mEnAttacks.Checked and (Command <> cShowCapturing));
     3100              if CurrentMoveInfo.DoShow then
     3101              begin
     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);
     3110                  end
     3111                  else
     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);
     3117                  end;
     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
     3131                      (ATrans_Fuel > 0) or
     3132                      (Cap and (1 shl (mcRadar - mcFirstNonCap) or
     3133                      1 shl (mcAcademy - mcFirstNonCap)) <> 0) or
     3134                      (MyMap[ToLoc] and fTerrain = fMountains) or
     3135                      (MyMap[ToLoc] and fTerImp = tiFort) or
     3136                      (MyMap[ToLoc] and fTerImp = tiBase) then
     3137                      CurrentMoveInfo.AfterMovePaintRadius := 2
     3138                    else
     3139                      CurrentMoveInfo.AfterMovePaintRadius := 1
     3140                end
     3141                else
     3142                begin
     3143                  if mEnFastMoves.Checked then
     3144                    AnimationSpeed := 8
     3145                  else
     3146                    AnimationSpeed := 16;
     3147                  CurrentMoveInfo.AfterMovePaintRadius := 0;
     3148                  // enemy unit, nothing discovered
     3149                end;
     3150                if GameMode = cMovie then
     3151                begin
     3152                  if MovieSpeed = 3 then
     3153                    AnimationSpeed := 4
     3154                  else if MovieSpeed = 2 then
     3155                    AnimationSpeed := 8
     3156                  else
     3157                    AnimationSpeed := 16;
     3158                end;
     3159                ShowMoveDomain := MyRO.EnemyModel[emix].Domain;
     3160                IsAlpine := MyRO.EnemyModel[emix].Cap and
     3161                  (1 shl (mcAlpine - mcFirstNonCap)) <> 0;
     3162              end
     3163            end;
     3164
     3165            if CurrentMoveInfo.DoShow then
     3166            begin
     3167              if Command = cShowCapturing then
     3168                Play('MOVE_CAPTURE')
     3169              else if EndHealth <= 0 then
     3170                Play('MOVE_DIE')
     3171              else if Flags and umSpyMission <> 0 then
     3172                Play('MOVE_COVERT')
     3173              else if Flags and umShipLoading <> 0 then
     3174                if ShowMoveDomain = dAir then
     3175                  Play('MOVE_PLANELANDING')
     3176                else
     3177                  Play('MOVE_LOAD')
     3178              else if Flags and umPlaneLoading <> 0 then
     3179                Play('MOVE_LOAD')
     3180              else if Flags and umShipUnloading <> 0 then
     3181                if ShowMoveDomain = dAir then
     3182                  Play('MOVE_PLANESTART')
     3183                else
     3184                  Play('MOVE_UNLOAD')
     3185              else if Flags and umPlaneUnloading <> 0 then
     3186                if (MyMap[FromLoc] and fCity = 0) and
     3187                  (MyMap[FromLoc] and fTerImp <> tiBase) then
     3188                  Play('MOVE_PARACHUTE')
     3189                else
     3190                  Play('MOVE_UNLOAD')
     3191              else if (ShowMoveDomain = dGround) and not IsAlpine and
     3192                (MyMap[ToLoc] and fTerrain = fMountains) and
     3193                ((MyMap[FromLoc] and (fRoad or fRR or fCity) = 0) or
     3194                (MyMap[ToLoc] and (fRoad or fRR or fCity) = 0)) then
     3195                Play('MOVE_MOUNTAIN');
     3196
     3197              FocusOnLoc(FromLoc, flImmUpdate);
     3198              PaintLoc_BeforeMove(FromLoc);
     3199              if Command = cShowCapturing then
     3200                MoveOnScreen(TShowMove(Data), 1, 32, 32)
     3201              else
     3202                MoveOnScreen(TShowMove(Data), 1, AnimationSpeed, AnimationSpeed)
     3203            end // if CurrentMoveInfo.DoShow
     3204            else
     3205              MapValid := false;
     3206          end
     3207        end;
     3208
     3209      cShowAttacking:
     3210        if (idle and (NewPlayer = me) or not idle and not skipped and
     3211          (TShowMove(Data).emix <> $FFFF)) and
     3212          not((GameMode = cMovie) and (MovieSpeed = 4)) then
     3213        begin
     3214          assert(NewPlayer = me);
     3215          if not idle or (GameMode = cMovie) then
     3216            Application.ProcessMessages;
     3217          with TShowMove(Data) do
     3218          begin
     3219            CurrentMoveInfo.AfterAttackExpeller := -1;
     3220            CurrentMoveInfo.DoShow := false;
     3221            if idle then
     3222              CurrentMoveInfo.DoShow := true // own unit -- always show attacks
     3223            else
     3224            begin
     3225              CurrentMoveInfo.IsAlly := MyRO.Treaty[Owner] = trAlliance;
     3226              if CurrentMoveInfo.IsAlly then
     3227                CurrentMoveInfo.DoShow := not mAlNoMoves.Checked
     3228              else
     3229                CurrentMoveInfo.DoShow := not mEnNoMoves.Checked;
     3230            end;
     3231            if CurrentMoveInfo.DoShow then
     3232            begin
     3233              ToLoc := dLoc(FromLoc, dx, dy);
     3234              if Tribe[Owner].ModelPicture[mix].HGr = 0 then
     3235                InitEnemyModel(emix);
     3236
     3237              if (MyMap[ToLoc] and (fCity or fUnit or fOwned) = fCity or fOwned)
     3238              then
     3239              begin // tell about bombardment
     3240                cix := MyRO.nCity - 1;
     3241                while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
     3242                  dec(cix);
     3243                if MyCity[cix].Status and csToldBombard = 0 then
     3244                begin
     3245                  if not supervising then
     3246                    MyCity[cix].Status := MyCity[cix].Status or csToldBombard;
     3247                  s := CityName(MyCity[cix].ID);
     3248                  SoundMessageEx(Format(Tribe[Owner].TPhrase('BOMBARD'),
     3249                    [s]), '');
     3250                  Update; // remove message box from screen
     3251                end;
     3252              end
     3253              else if Flags and umExpelling <> 0 then
     3254                CurrentMoveInfo.AfterAttackExpeller := Owner;
     3255
     3256              if Flags and umExpelling <> 0 then
     3257                Play('MOVE_EXPEL')
     3258              else if Owner = me then
     3259              begin
     3260                MakeModelInfo(me, mix, MyModel[mix], mi);
     3261                Play(AttackSound(ModelCode(mi)));
     3262              end
     3263              else
     3264                Play(AttackSound(ModelCode(MyRO.EnemyModel[emix])));
     3265
     3266              FocusOnLoc(FromLoc, flImmUpdate);
     3267
     3268              // before combat
     3269              MainMap.AttackBegin(TShowMove(Data));
     3270              if MyMap[ToLoc] and fCity <> 0 then
     3271                PaintLoc(ToLoc);
     3272              PaintLoc(FromLoc);
     3273              MoveOnScreen(TShowMove(Data), 1, 9, 16);
     3274              MoveOnScreen(TShowMove(Data), 17, 12, 32);
     3275              MoveOnScreen(TShowMove(Data), 7, 11, 16);
     3276
     3277              // after combat
     3278              MainMap.AttackEffect(TShowMove(Data));
     3279              PaintLoc(ToLoc);
     3280              if EndHealth > 0 then
     3281              begin
     3282                Health := EndHealth;
     3283                MoveOnScreen(TShowMove(Data), 10, 0, 16);
     3284              end
     3285              else if not idle then
     3286                Sleep(MoveTime div 2);
     3287              MainMap.AttackEnd;
     3288            end // if CurrentMoveInfo.DoShow
     3289            else
     3290              MapValid := false;
     3291          end
     3292        end;
     3293
     3294      cShowMissionResult:
     3295        if Cardinal(Data) = 0 then
     3296          SoundMessageEx(Phrases.Lookup('NOFOREIGNINFO'), '')
     3297        else
     3298        begin
     3299          s := Phrases.Lookup('FOREIGNINFO');
     3300          for p1 := 0 to nPl - 1 do
     3301            if 3 shl (p1 * 2) and Cardinal(Data) <> 0 then
     3302              s := s + '\' + Tribe[p1].TPhrase('SHORTNAME');
     3303          SoundMessageEx(s, '')
     3304        end;
     3305
     3306      cShowShipChange:
     3307        if not IsMultiPlayerGame and (Jump[0] = 0) then
     3308          ShowEnemyShipChange(TShowShipChange(Data));
     3309
     3310      cShowGreatLibTech:
     3311        if not IsMultiPlayerGame and (Jump[0] = 0) then
     3312          with MessgExDlg do
     3313          begin
     3314            MessgText := Format(Phrases.Lookup('GRLIB_GENERAL'),
     3315              [Phrases.Lookup('ADVANCES', integer(Data))]);
     3316            OpenSound := 'NEWADVANCE_GRLIB';
     3317            Kind := mkOk;
     3318            IconKind := mikImp;
     3319            IconIndex := woGrLibrary;
     3320            ShowModal;
     3321          end;
     3322
     3323      cRefreshDebugMap:
     3324        begin
     3325          if integer(Data) = IsoEngine.pDebugMap then
     3326          begin
     3327            MapValid := false;
     3328            MainOffscreenPaint;
     3329            Update;
     3330          end
     3331        end;
     3332
     3333    else
     3334      if Command >= cClientEx then
     3335        case Command and $FFF0 of
     3336
     3337          cSetTribe:
     3338            with TTribeInfo(Data) do
     3339            begin
     3340              i := UnusedTribeFiles.Count - 1;
     3341              while (i >= 0) and
     3342                (AnsiCompareFileName(UnusedTribeFiles[i], FileName) <> 0) do
     3343                dec(i);
     3344              if i >= 0 then
     3345                UnusedTribeFiles.Delete(i);
     3346              CreateTribe(trix, FileName, true);
     3347            end;
     3348
     3349          cSetNewModelPicture, cSetModelPicture:
     3350            if TribeOriginal[TModelPictureInfo(Data).trix] then
     3351              Tribe[TModelPictureInfo(Data).trix].SetModelPicture
     3352                (TModelPictureInfo(Data), Command and
     3353                $FFF0 = cSetNewModelPicture);
     3354
     3355          cSetSlaveIndex and $FFF0:
     3356            Tribe[integer(Data) shr 16].mixSlaves := integer(Data) and $FFFF;
     3357
     3358          cSetCityName:
     3359            with TCityNameInfo(Data) do
     3360              if TribeOriginal[ID shr 12] then
     3361                Tribe[ID shr 12].SetCityName(ID and $FFF, NewName);
     3362
     3363          cSetModelName:
     3364            with TModelNameInfo(Data) do
     3365              if TribeOriginal[NewPlayer] then
     3366                Tribe[NewPlayer].ModelName[mix] := NewName;
     3367        end
     3368    end
     3369  end; { <<<client }
     3370
     3371  { *** main part *** }
     3372
     3373  procedure TMainScreen.CreateParams(var p: TCreateParams);
     3374  var
     3375    DefaultOptionChecked: integer;
     3376    Reg: TRegistry;
     3377    doinit: boolean;
     3378  begin
     3379    inherited;
     3380
     3381    // define which menu settings to save
     3382    SaveOption[0] := mAlEffectiveMovesOnly.Tag;
     3383    SaveOption[1] := mEnMoves.Tag;
     3384    SaveOption[2] := mEnAttacks.Tag;
     3385    SaveOption[3] := mEnNoMoves.Tag;
     3386    SaveOption[4] := mWaitTurn.Tag;
     3387    SaveOption[5] := mEffectiveMovesOnly.Tag;
     3388    SaveOption[6] := mEnFastMoves.Tag;
     3389    SaveOption[7] := mSlowMoves.Tag;
     3390    SaveOption[8] := mFastMoves.Tag;
     3391    SaveOption[9] := mVeryFastMoves.Tag;
     3392    SaveOption[10] := mNames.Tag;
     3393    SaveOption[11] := mRepList.Tag;
     3394    SaveOption[12] := mRepScreens.Tag;
     3395    SaveOption[13] := mSoundOff.Tag;
     3396    SaveOption[14] := mSoundOn.Tag;
     3397    SaveOption[15] := mSoundOnAlt.Tag;
     3398    SaveOption[16] := mScrollSlow.Tag;
     3399    SaveOption[17] := mScrollFast.Tag;
     3400    SaveOption[18] := mScrollOff.Tag;
     3401    SaveOption[19] := mAlSlowMoves.Tag;
     3402    SaveOption[20] := mAlFastMoves.Tag;
     3403    SaveOption[21] := mAlNoMoves.Tag;
     3404    DefaultOptionChecked := 1 shl 1 + 1 shl 7 + 1 shl 10 + 1 shl 12 + 1 shl 14 +
     3405      1 shl 18 + 1 shl 19;
     3406
     3407    Reg := TRegistry.Create;
     3408    doinit := true;
     3409    if Reg.KeyExists('SOFTWARE\cevo\RegVer9') then
     3410    begin
     3411      doinit := false;
     3412      Reg.OpenKey('SOFTWARE\cevo\RegVer9', false);
     3413      try
     3414        xxt := Reg.ReadInteger('TileWidth') div 2;
     3415        yyt := Reg.ReadInteger('TileHeight') div 2;
     3416        OptionChecked := Reg.ReadInteger('OptionChecked');
     3417        MapOptionChecked := Reg.ReadInteger('MapOptionChecked');
     3418        CityRepMask := Cardinal(Reg.ReadInteger('CityReport'));
     3419      except
     3420        doinit := true;
     3421      end;
     3422      Reg.closekey;
     3423      if OptionChecked and (7 shl 16) = 0 then
     3424        OptionChecked := OptionChecked or (1 shl 16);
     3425      // old regver with no scrolling
     3426    end;
     3427    Reg.free;
     3428    if doinit then
     3429    begin
     3430      xxt := 48;
     3431      yyt := 24;
     3432      OptionChecked := DefaultOptionChecked;
     3433      MapOptionChecked := 1 shl moCityNames;
     3434      CityRepMask := Cardinal(not chPopIncrease and not chNoGrowthWarning and
     3435        not chCaptured);
     3436    end;
     3437
     3438    if FullScreen then
     3439    begin
     3440      p.Style := $87000000;
     3441      BorderStyle := bsNone;
     3442      BorderIcons := [];
     3443    end;
     3444
     3445    if 1 shl 13 and OptionChecked <> 0 then
     3446      SoundMode := smOff
     3447    else if 1 shl 15 and OptionChecked <> 0 then
     3448      SoundMode := smOnAlt
     3449    else
     3450      SoundMode := smOn
     3451  end;
     3452
     3453  procedure TMainScreen.FormCreate(Sender: TObject);
     3454  var
     3455    i, j: integer;
     3456  begin
     3457    Screen.Cursors[crImpDrag] := LoadCursor(HInstance, 'DRAG');
     3458    Screen.Cursors[crFlatHand] := LoadCursor(HInstance, 'FLATHAND');
     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
     3464        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
     3473        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
     3480        end;
     3481
     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    Mini.free;
     3532    Buffer.free;
     3533    Panel.free;
     3534    for i := 0 to nPl - 1 do
     3535      if AILogo[i] <> nil then
     3536        AILogo[i].free;
     3537  end;
     3538
     3539  procedure TMainScreen.FormResize(Sender: TObject);
     3540  var
     3541    MiniFrame, MaxMapWidth: integer;
     3542  begin
     3543    SmallScreen := ClientWidth < 1024;
     3544    MaxMapWidth := (G.lx * 2 - 3) * xxt;
     3545    // avoide the same tile being visible left and right
     3546    if ClientWidth <= MaxMapWidth then
     3547    begin
     3548      MapWidth := ClientWidth;
     3549      MapOffset := 0;
     3550    end
     3551    else
     3552    begin
     3553      MapWidth := MaxMapWidth;
     3554      MapOffset := (ClientWidth - MapWidth) div 2;
     3555    end;
     3556    MapHeight := ClientHeight - TopBarHeight - PanelHeight + overlap;
     3557    Panel.width := ClientWidth;
     3558    Panel.height := PanelHeight;
     3559    TopBar.width := ClientWidth;
     3560    TopBar.height := TopBarHeight;
     3561    MiniFrame := (lxmax_xxx - G.ly) div 2;
     3562    xMidPanel := (G.lx + MiniFrame) * 2 + 1;
     3563    xRightPanel := ClientWidth - LeftPanelWidth - 10;
     3564    if ClientMode = cEditMap then
     3565      TrPitch := 2 * xxt
     3566    else
     3567      TrPitch := 66;
     3568    xMini := MiniFrame - 5;
     3569    yMini := (PanelHeight - 26 - lxmax_xxx) div 2 + MiniFrame;
     3570    ywmax := (G.ly - MapHeight div yyt + 1) and not 1;
     3571    ywcenter := -((MapHeight - yyt * (G.ly - 1)) div (4 * yyt)) * 2;
     3572    // only for ywmax<=0
     3573    if ywmax <= 0 then
     3574      yw := ywcenter
     3575    else if yw < 0 then
     3576      yw := 0
     3577    else if yw > ywmax then
     3578      yw := ywmax;
     3579    UnitInfoBtn.Top := ClientHeight - 29;
     3580    UnitInfoBtn.Left := xMidPanel + 7 + 99;
     3581    UnitBtn.Top := ClientHeight - 29;
     3582    UnitBtn.Left := xMidPanel + 7 + 99 + 31;
     3583    TerrainBtn.Top := ClientHeight - 29;
     3584    TerrainBtn.Left := xMidPanel + 7 + 99 + 62;
     3585    MovieSpeed1Btn.Top := ClientHeight - 91;
     3586    MovieSpeed1Btn.Left := ClientWidth div 2 - 62;
     3587    MovieSpeed2Btn.Top := ClientHeight - 91;
     3588    MovieSpeed2Btn.Left := ClientWidth div 2 - 62 + 29;
     3589    MovieSpeed3Btn.Top := ClientHeight - 91;
     3590    MovieSpeed3Btn.Left := ClientWidth div 2 - 62 + 2 * 29;
     3591    MovieSpeed4Btn.Top := ClientHeight - 91;
     3592    MovieSpeed4Btn.Left := ClientWidth div 2 - 62 + 3 * 29 + 12;
     3593    EOT.Top := ClientHeight - 64;
     3594    EOT.Left := ClientWidth - 62;
     3595    SetWindowPos(sb.h, 0, xRightPanel + 10 - 14 -
     3596      GetSystemMetrics(SM_CXVSCROLL), ClientHeight - MidPanelHeight + 8, 0, 0,
     3597      SWP_NOSIZE or SWP_NOZORDER);
     3598    MapBtn0.Left := xMini + G.lx - 44;
     3599    MapBtn0.Top := ClientHeight - 15;
     3600    MapBtn1.Left := xMini + G.lx - 28;
     3601    MapBtn1.Top := ClientHeight - 15;
     3602    { MapBtn2.Left:=xMini+G.lx-20;
     3603      MapBtn2.Top:=ClientHeight-15;
     3604      MapBtn3.Left:=xMini+G.lx-4;
     3605      MapBtn3.Top:=ClientHeight-15; }
     3606    MapBtn5.Left := xMini + G.lx - 12;
     3607    MapBtn5.Top := ClientHeight - 15;
     3608    MapBtn4.Left := xMini + G.lx + 20;
     3609    MapBtn4.Top := ClientHeight - 15;
     3610    MapBtn6.Left := xMini + G.lx + 36;
     3611    MapBtn6.Top := ClientHeight - 15;
     3612    TreasuryArea.Left := ClientWidth div 2 - 172;
     3613    ResearchArea.Left := ClientWidth div 2;
     3614    ManagementArea.Left := ClientWidth - xPalace;
     3615    ManagementArea.Top := TopBarHeight + MapHeight - overlap + yPalace;
     3616    ArrangeMidPanel;
     3617    if RepaintOnResize then
     3618    begin
     3619      RectInvalidate(0, TopBarHeight, ClientWidth, TopBarHeight + MapHeight);
     3620      MapValid := false;
     3621      PaintAll
     3622    end
     3623  end;
     3624
     3625  procedure TMainScreen.FormCloseQuery(Sender: TObject; var CanClose: boolean);
     3626  begin
     3627    CanClose := Closable;
     3628    if not Closable and idle and (me = 0) and (ClientMode < scContact) then
     3629      MenuClick(mResign)
     3630  end;
     3631
     3632  procedure TMainScreen.OnScroll(var m: TMessage);
     3633  begin
     3634    if ProcessPVSB(sb, m) then
     3635    begin
     3636      PanelPaint;
     3637      Update
     3638    end
     3639  end;
     3640
     3641  procedure TMainScreen.OnEOT(var Msg: TMessage);
     3642  begin
     3643    EndTurn
     3644  end;
     3645
     3646  procedure TMainScreen.EOTClick(Sender: TObject);
     3647  begin
     3648    if GameMode = cMovie then
     3649    begin
     3650      MessgExDlg.CancelMovie;
     3651      Server(sBreak, me, 0, nil^)
     3652    end
     3653    else if ClientMode < 0 then
     3654      skipped := true
     3655    else if ClientMode >= scContact then
     3656      NegoDlg.ShowNewContent(wmPersistent)
     3657    else if Jump[pTurn] > 0 then
     3658    begin
     3659      Jump[pTurn] := 0;
     3660      StartRunning := false
     3661    end
     3662    else
     3663      EndTurn
     3664  end;
     3665
     3666  // set xTerrain, xTroop, and TrRow
     3667  procedure TMainScreen.ArrangeMidPanel;
     3668  begin
     3669    if ClientMode = cEditMap then
     3670      xTroop := xMidPanel + 15
     3671    else
     3672    begin
     3673      if supervising then
     3674        xTerrain := xMidPanel + 2 * xxt + 14
     3675      else if ClientWidth < 1280 then
     3676        xTerrain := ClientWidth div 2 + (1280 - ClientWidth) div 3
     3677      else
     3678        xTerrain := ClientWidth div 2;
     3679      xTroop := xTerrain + 2 * xxt + 12;
     3680      if SmallScreen and not supervising then
     3681        xTroop := xRightPanel + 10 - 3 * 66 -
     3682          GetSystemMetrics(SM_CXVSCROLL) - 19 - 4;
     3683      // not perfect but we assume almost no one is still playing on a 800x600 screen
     3684    end;
     3685    TrRow := (xRightPanel + 10 - xTroop - GetSystemMetrics(SM_CXVSCROLL) - 19)
     3686      div TrPitch;
     3687  end;
     3688
     3689  function TMainScreen.EndTurn(WasSkipped: boolean): boolean;
     3690
     3691    function IsResourceUnused(cix, NeedFood, NeedProd: integer): boolean;
     3692    var
     3693      dx, dy, fix: integer;
     3694      CityAreaInfo: TCityAreaInfo;
     3695      TileInfo: TTileInfo;
     3696    begin
     3697      Server(sGetCityAreaInfo, me, cix, CityAreaInfo);
     3698      for dy := -3 to 3 do
     3699        for dx := -3 to 3 do
     3700          if ((dx + dy) and 1 = 0) and (dx * dx * dy * dy < 81) then
     3701          begin
     3702            fix := (dy + 3) shl 2 + (dx + 3) shr 1;
     3703            if (MyCity[cix].Tiles and (1 shl fix) = 0) // not used yet
     3704              and (CityAreaInfo.Available[fix] = faAvailable) then // usable
     3705            begin
     3706              TileInfo.ExplCity := cix;
     3707              Server(sGetHypoCityTileInfo, me, dLoc(MyCity[cix].Loc, dx, dy),
     3708                TileInfo);
     3709              if (TileInfo.Food >= NeedFood) and (TileInfo.Prod >= NeedProd)
     3710              then
     3711              begin
     3712                result := true;
     3713                exit
     3714              end;
     3715            end
     3716          end;
     3717      result := false;
     3718    end;
     3719
     3720  var
     3721    i, p1, uix, cix, CenterLoc: integer;
     3722    MsgItem: string;
     3723    CityReport: TCityReport;
     3724    PlaneReturnData: TPlaneReturnData;
     3725    Zoom: boolean;
     3726  begin
     3727    result := false;
     3728    if ClientMode >= scDipOffer then
     3729      exit;
     3730
     3731    if supervising and (me <> 0) then
     3732    begin
     3733      for i := 0 to Screen.FormCount - 1 do
     3734        if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
     3735        then
     3736          Screen.Forms[i].Close; // close windows
     3737      ItsMeAgain(0);
     3738    end;
     3739
     3740    CityOptimizer_EndOfTurn;
     3741
     3742    if not WasSkipped then // check warnings
     3743    begin
     3744      // need to move planes home?
     3745      for uix := 0 to MyRO.nUn - 1 do
     3746        with MyUn[uix] do
     3747          if (Loc >= 0) and (MyModel[mix].Domain = dAir) and
     3748            (Status and usToldNoReturn = 0) and (Master < 0) and
     3749            (MyMap[Loc] and fCity = 0) and (MyMap[Loc] and fTerImp <> tiBase)
     3750          then
     3751          begin
     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
     3779          end;
     3780
     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
     3800            begin
     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
     3810                begin
     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;
     3821                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
     3863              end
     3864            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
     3881      for i := 0 to Screen.FormCount - 1 do
     3882        if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
     3883        then
     3884          Screen.Forms[i].Close;
     3885    end
     3886    else
     3887    begin
     3888      if CityDlg.Visible then
     3889        CityDlg.Close;
     3890      if UnitStatDlg.Visible then
     3891        UnitStatDlg.Close;
     3892    end;
     3893    for i := 0 to Screen.FormCount - 1 do
     3894      if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
     3895        Screen.Forms[i].Enabled := false;
     3896
     3897    if Server(sTurn, pTurn, 0, nil^) >= rExecuted then
     3898    begin
     3899      if Jump[pTurn] > 0 then
     3900        EOT.Hint := Phrases.Lookup('BTN_STOP')
     3901      else
     3902        EOT.Hint := Phrases.Lookup('BTN_SKIP');
     3903      result := true;
     3904      SetTroopLoc(-1);
     3905      pTurn := -1;
     3906      pLogo := -1;
     3907      UnitInfoBtn.Visible := false;
     3908      UnitBtn.Visible := false;
     3909      TerrainBtn.Visible := false;
     3910      EOT.ButtonIndex := eotCancel;
     3911      EOT.Visible := true;
     3912      MapValid := false;
     3913      PanelPaint;
     3914      Update;
     3915      ClientMode := -1;
     3916      idle := false;
     3917      skipped := WasSkipped;
     3918      for p1 := 1 to nPl - 1 do
     3919        if G.RO[p1] <> nil then
     3920          skipped := true; // don't show enemy moves in hotseat mode
     3921    end
     3922    else
     3923      PanelPaint
     3924  end; // EndTurn
     3925
     3926  procedure TMainScreen.EndNego;
     3927  begin
     3928    if NegoDlg.Visible then
     3929      NegoDlg.Close;
     3930    HaveStrategyAdvice := false;
     3931    // AdvisorDlg.HaveStrategyAdvice;
     3932    // negotiation might have changed advices
     3933    EOT.ButtonIndex := eotCancel;
     3934    EOT.Visible := true;
     3935    PanelPaint;
     3936    Update;
     3937    ClientMode := -1;
     3938    idle := false;
     3939  end;
     3940
     3941  procedure TMainScreen.ProcessRect(x0, y0, nx, ny, Options: integer);
     3942  var
     3943    xs, ys, xl, yl: integer;
     3944  begin
     3945    xl := nx * xxt + xxt;
     3946    yl := ny * yyt + yyt * 2;
     3947    xs := (x0 - xw) * (xxt * 2) + y0 and 1 * xxt - G.lx * (xxt * 2);
     3948    // |xs+xl/2-MapWidth/2| -> min
     3949    while abs(2 * (xs + G.lx * (xxt * 2)) + xl - MapWidth) <
     3950      abs(2 * xs + xl - MapWidth) do
     3951      inc(xs, G.lx * (xxt * 2));
     3952    ys := (y0 - yw) * yyt - yyt;
     3953    if xs + xl > MapWidth then
     3954      xl := MapWidth - xs;
     3955    if ys + yl > MapHeight then
     3956      yl := MapHeight - ys;
     3957    if (xl <= 0) or (yl <= 0) then
     3958      exit;
     3959    if Options and prPaint <> 0 then
     3960    begin
     3961      if Options and prAutoBounds <> 0 then
     3962        MainMap.SetPaintBounds(xs, ys, xs + xl, ys + yl);
     3963      MainMap.Paint(xs, ys, x0 + G.lx * y0, nx, ny, -1, -1);
     3964    end;
     3965    if Options and prInvalidate <> 0 then
     3966      RectInvalidate(MapOffset + xs, TopBarHeight + ys, MapOffset + xs + xl,
     3967        TopBarHeight + ys + yl)
     3968  end;
     3969
     3970  procedure TMainScreen.PaintLoc(Loc: integer; Radius: integer = 0);
     3971  var
     3972    yLoc, x0: integer;
     3973  begin
     3974    if MapValid then
     3975    begin
     3976      yLoc := (Loc + G.lx * 1024) div G.lx - 1024;
     3977      x0 := (Loc + (yLoc and 1 - 2 * Radius + G.lx * 1024) div 2) mod G.lx;
     3978      offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
     3979      ProcessRect(x0, yLoc - 2 * Radius, 4 * Radius + 1, 4 * Radius + 1,
     3980        prPaint or prAutoBounds or prInvalidate);
     3981      Update;
     3982    end
     3983  end;
     3984
     3985  procedure TMainScreen.PaintLocTemp(Loc, Style: integer);
     3986  var
     3987    y0, x0, xMap, yMap: integer;
     3988  begin
     3989    if not MapValid then
     3990      exit;
     3991    Buffer.Canvas.Font.Assign(UniFont[ftSmall]);
     3992    y0 := Loc div G.lx;
     3993    x0 := Loc mod G.lx;
     3994    xMap := (x0 - xw) * (xxt * 2) + y0 and 1 * xxt - G.lx * (xxt * 2);
     3995    // |xMap+xxt-MapWidth/2| -> min
     3996    while abs(2 * (xMap + G.lx * (xxt * 2)) + 2 * xxt - MapWidth) <
     3997      abs(2 * xMap + 2 * xxt - MapWidth) do
     3998      inc(xMap, G.lx * (xxt * 2));
     3999    yMap := (y0 - yw) * yyt - yyt;
     4000    NoMap.SetOutput(Buffer);
     4001    NoMap.SetPaintBounds(0, 0, 2 * xxt, 3 * yyt);
     4002    NoMap.Paint(0, 0, Loc, 1, 1, -1, -1, Style = pltsBlink);
     4003    PaintBufferToScreen(xMap, yMap, 2 * xxt, 3 * yyt);
     4004  end;
     4005
     4006  // paint content of buffer directly to screen instead of offscreen
     4007  // panel protusions are added
     4008  // NoMap must be set to buffer and bounds before
     4009  procedure TMainScreen.PaintBufferToScreen(xMap, yMap, width, height: integer);
     4010  begin
     4011    if xMap + width > MapWidth then
     4012      width := MapWidth - xMap;
     4013    if yMap + height > MapHeight then
     4014      height := MapHeight - yMap;
     4015    if (width <= 0) or (height <= 0) or (width + xMap <= 0) or
     4016      (height + yMap <= 0) then
     4017      exit;
     4018
     4019    NoMap.BitBlt(Panel, -xMap - MapOffset, -yMap + MapHeight - overlap,
     4020      xMidPanel, overlap, 0, 0, SRCCOPY);
     4021    NoMap.BitBlt(Panel, -xMap - MapOffset + xRightPanel,
     4022      -yMap + MapHeight - overlap, Panel.width - xRightPanel, overlap,
     4023      xRightPanel, 0, SRCCOPY);
     4024    if yMap < 0 then
     4025    begin
     4026      if xMap < 0 then
     4027        BitBlt(Canvas.Handle, MapOffset, TopBarHeight, width + xMap,
     4028          height + yMap, Buffer.Canvas.Handle, -xMap, -yMap, SRCCOPY)
     4029      else
     4030        BitBlt(Canvas.Handle, xMap + MapOffset, TopBarHeight, width,
     4031          height + yMap, Buffer.Canvas.Handle, 0, -yMap, SRCCOPY)
     4032    end
     4033    else
     4034    begin
     4035      if xMap < 0 then
     4036        BitBlt(Canvas.Handle, MapOffset, TopBarHeight + yMap, width + xMap,
     4037          height, Buffer.Canvas.Handle, -xMap, 0, SRCCOPY)
     4038      else
     4039        BitBlt(Canvas.Handle, xMap + MapOffset, TopBarHeight + yMap, width,
     4040          height, Buffer.Canvas.Handle, 0, 0, SRCCOPY);
     4041    end
     4042  end;
     4043
     4044  procedure TMainScreen.PaintLoc_BeforeMove(FromLoc: integer);
     4045  var
     4046    yLoc, x0: integer;
     4047  begin
     4048    if MapValid then
     4049    begin
     4050      yLoc := (FromLoc + G.lx * 1024) div G.lx - 1024;
     4051      x0 := (FromLoc + (yLoc and 1 + G.lx * 1024) div 2) mod G.lx;
     4052      offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
     4053      ProcessRect(x0, yLoc, 1, 1, prPaint or prAutoBounds);
     4054    end
     4055  end;
     4056
     4057  procedure TMainScreen.PaintDestination;
     4058  var
     4059    Destination: integer;
     4060  begin
     4061    if (UnFocus >= 0) and (MyUn[UnFocus].Status and usGoto <> 0) then
     4062    begin
     4063      Destination := MyUn[UnFocus].Status shr 16;
     4064      if (Destination <> $7FFF) and (Destination <> MyUn[UnFocus].Loc) then
     4065        PaintLocTemp(Destination, pltsBlink);
     4066    end;
     4067  end;
     4068
     4069  procedure TMainScreen.MiniPaint;
     4070  type
     4071    TLine = array [0 .. 99999999, 0 .. 2] of Byte;
     4072  var
     4073    uix, cix, x, y, Loc, i, hw, xm, cm, cmPolOcean, cmPolNone: integer;
     4074    PrevMiniLine, MiniLine: ^TLine;
     4075  begin
     4076    cmPolOcean := GrExt[HGrSystem].Data.Canvas.Pixels[101, 67];
     4077    cmPolNone := GrExt[HGrSystem].Data.Canvas.Pixels[102, 67];
     4078    hw := MapWidth div (xxt * 2);
     4079    with Mini.Canvas do
     4080    begin
     4081      Brush.Color := $000000;
     4082      FillRect(Rect(0, 0, Mini.width, Mini.height));
     4083    end;
     4084    MiniLine := nil;
     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
     4094          begin
     4095            xm := ((x - xwMini) * 2 + i + y and 1 - hw + G.lx * 5)
     4096              mod (G.lx * 2);
     4097            cm := MiniColors[MyMap[Loc] and fTerrain, i];
     4098            if ClientMode = cEditMap then
     4099            begin
     4100              if MyMap[Loc] and (fPrefStartPos or fStartPos) <> 0 then
     4101                cm := $FFFFFF;
     4102            end
     4103            else if MyMap[Loc] and fCity <> 0 then
     4104            begin
     4105              cix := MyRO.nCity - 1;
     4106              while (cix >= 0) and (MyCity[cix].Loc <> Loc) do
     4107                dec(cix);
     4108              if cix >= 0 then
     4109                cm := Tribe[me].Color
     4110              else
     4111              begin
     4112                cix := MyRO.nEnemyCity - 1;
     4113                while (cix >= 0) and (MyRO.EnemyCity[cix].Loc <> Loc) do
     4114                  dec(cix);
     4115                if cix >= 0 then
     4116                  cm := Tribe[MyRO.EnemyCity[cix].Owner].Color
     4117              end;
     4118              cm := $808080 or cm shr 1; { increase brightness }
     4119              if PrevMiniLine <> nil then
     4120              begin // 2x2 city dot covers two scanlines
     4121                PrevMiniLine[xm, 0] := cm shr 16;
     4122                PrevMiniLine[xm, 1] := cm shr 8 and $FF;
     4123                PrevMiniLine[xm, 2] := cm and $FF;
     4124              end
     4125            end
     4126            else if (i = 0) and (MyMap[Loc] and fUnit <> 0) then
     4127            begin
     4128              uix := MyRO.nUn - 1;
     4129              while (uix >= 0) and (MyUn[uix].Loc <> Loc) do
     4130                dec(uix);
     4131              if uix >= 0 then
     4132                cm := Tribe[me].Color
     4133              else
     4134              begin
     4135                uix := MyRO.nEnemyUn - 1;
     4136                while (uix >= 0) and (MyRO.EnemyUn[uix].Loc <> Loc) do
     4137                  dec(uix);
     4138                if uix >= 0 then
     4139                  cm := Tribe[MyRO.EnemyUn[uix].Owner].Color
     4140              end;
     4141              cm := $808080 or cm shr 1; { increase brightness }
     4142            end
     4143            else if MapOptionChecked and (1 shl moPolitical) <> 0 then
     4144            begin
     4145              if MyMap[Loc] and fTerrain < fGrass then
     4146                cm := cmPolOcean
     4147              else if MyRO.Territory[Loc] < 0 then
     4148                cm := cmPolNone
     4149              else
     4150                cm := Tribe[MyRO.Territory[Loc]].Color;
     4151            end;
     4152            MiniLine[xm, 0] := cm shr 16;
     4153            MiniLine[xm, 1] := cm shr 8 and $FF;
     4154            MiniLine[xm, 2] := cm and $FF;
     4155          end;
     4156        end
     4157    end;
     4158  end;
     4159
     4160  procedure TMainScreen.MainOffscreenPaint;
     4161  var
     4162    ProcessOptions: integer;
     4163    rec: TRect;
     4164    DoInvalidate: boolean;
     4165  begin
     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
     4174      end;
     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;
     4186    end;
     4187
     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      ScrollDC(offscreen.Canvas.Handle, (xwd - xw) * (xxt * 2),
     4207        (ywd - yw) * yyt, rec, rec, 0, nil);
     4208      for DoInvalidate := false to FastScrolling do
     4209      begin
     4210        if DoInvalidate then
     4211        begin
     4212          rec.Bottom := MapHeight - overlap;
     4213          ScrollDC(Canvas.Handle, (xwd - xw) * (xxt * 2), (ywd - yw) * yyt, rec,
     4214            rec, 0, nil);
     4215          ProcessOptions := prInvalidate;
     4216        end
     4217        else
     4218          ProcessOptions := prPaint or prAutoBounds;
     4219        if yw < ywd then
     4220        begin
     4221          ProcessRect(xw, yw, MapWidth div xxt, ywd - yw - 1, ProcessOptions);
     4222          if xw < xwd then
     4223            ProcessRect(xw, ywd, (xwd - xw) * 2 - 1, MapHeight div yyt - ywd +
     4224              yw, ProcessOptions)
     4225          else if xw > xwd then
     4226            ProcessRect((xwd + MapWidth div (xxt * 2)) mod G.lx, ywd,
     4227              (xw - xwd) * 2 + 1, MapHeight div yyt - ywd + yw, ProcessOptions)
     4228        end
     4229        else if yw > ywd then
     4230        begin
     4231          if DoInvalidate then
     4232            RectInvalidate(MapOffset, TopBarHeight + MapHeight - overlap -
     4233              (yw - ywd) * yyt, MapOffset + MapWidth, TopBarHeight + MapHeight
     4234              - overlap)
     4235          else
     4236            ProcessRect(xw, (ywd + MapHeight div (yyt * 2) * 2),
     4237              MapWidth div xxt, yw - ywd + 1, ProcessOptions);
     4238          if xw < xwd then
     4239            ProcessRect(xw, yw, (xwd - xw) * 2 - 1, MapHeight div yyt - yw + ywd
     4240              - 2, ProcessOptions)
     4241          else if xw > xwd then
     4242            ProcessRect((xwd + MapWidth div (xxt * 2)) mod G.lx, yw,
     4243              (xw - xwd) * 2 + 1, MapHeight div yyt - yw + ywd - 2,
     4244              ProcessOptions)
     4245        end
     4246        else if xw < xwd then
     4247          ProcessRect(xw, yw, (xwd - xw) * 2 - 1, MapHeight div yyt,
     4248            ProcessOptions)
     4249        else if xw > xwd then
     4250          ProcessRect((xwd + MapWidth div (xxt * 2)) mod G.lx, yw,
     4251            (xw - xwd) * 2 + 1, MapHeight div yyt, ProcessOptions);
     4252      end;
     4253      if not FastScrolling then
     4254        RectInvalidate(MapOffset, TopBarHeight, MapOffset + MapWidth,
     4255          TopBarHeight + MapHeight - overlap);
     4256      RectInvalidate(xMidPanel, TopBarHeight + MapHeight - overlap, xRightPanel,
     4257        TopBarHeight + MapHeight)
     4258    end;
     4259    // if (xwd<>xw) or (ywd<>yw) then
     4260    // Server(sChangeSuperView,me,yw*G.lx+xw,nil^); // for synchronizing client side viewer, not used currently
     4261    xwd := xw;
     4262    ywd := yw;
     4263    MapValid := true;
     4264  end;
     4265
     4266  procedure TMainScreen.PaintAll;
     4267  begin
     4268    MainOffscreenPaint;
     4269    xwMini := xw;
     4270    ywMini := yw;
     4271    MiniPaint;
     4272    PanelPaint;
     4273  end;
     4274
     4275  procedure TMainScreen.PaintAllMaps;
     4276  begin
     4277    MainOffscreenPaint;
     4278    xwMini := xw;
     4279    ywMini := yw;
     4280    MiniPaint;
     4281    CopyMiniToPanel;
     4282    RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini + 2,
     4283      xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini +
     4284      2 + G.ly);
     4285  end;
     4286
     4287  procedure TMainScreen.CopyMiniToPanel;
     4288  begin
     4289    BitBlt(Panel.Canvas.Handle, xMini + 2, yMini + 2, G.lx * 2, G.ly,
     4290      Mini.Canvas.Handle, 0, 0, SRCCOPY);
     4291    if MarkCityLoc >= 0 then
     4292      Sprite(Panel, HGrSystem,
     4293        xMini - 2 + (4 * G.lx + 2 * (MarkCityLoc mod G.lx) +
     4294        (G.lx - MapWidth div (xxt * 2)) - 2 * xwd) mod (2 * G.lx) +
     4295        MarkCityLoc div G.lx and 1, yMini - 3 + MarkCityLoc div G.lx, 10,
     4296        10, 77, 47)
     4297    else if ywmax <= 0 then
     4298      Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (xxt * 2), yMini + 2,
     4299        xMini + 1 + G.lx + MapWidth div (xxt * 2), yMini + 2 + G.ly - 1,
     4300        MainTexture.clMark, MainTexture.clMark)
     4301    else
     4302      Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (xxt * 2),
     4303        yMini + 2 + yw, xMini + 1 + G.lx + MapWidth div (xxt * 2),
     4304        yMini + yw + MapHeight div yyt, MainTexture.clMark, MainTexture.clMark);
     4305  end;
     4306
     4307  procedure TMainScreen.PanelPaint;
     4308
     4309    function MovementToString(var Un: TUn): string;
     4310    begin
     4311      result := ScreenTools.MovementToString(Un.Movement);
     4312      if Un.Master >= 0 then
     4313        result := '(' + result + ')'
     4314      else if (MyModel[Un.mix].Domain = dAir) and
     4315        (MyModel[Un.mix].Kind <> mkSpecial_Glider) then
     4316        result := Format('%s(%d)', [result, Un.Fuel]);
     4317    end;
     4318
     4319  var
     4320    i, uix, uixDefender, x, xSrc, ySrc, xSrcBase, ySrcBase, CostFactor, Count,
     4321      mixShow, xTreasurySection, xResearchSection, JobFocus, TrueMoney,
     4322      TrueResearch: integer;
     4323    Tile: Cardinal;
     4324    s: string;
     4325    unx: TUn;
     4326    UnitInfo: TUnitInfo;
     4327    JobProgressData: TJobProgressData;
     4328    Prio: boolean;
     4329  begin
     4330    with Panel.Canvas do
     4331    begin
     4332      Fill(Panel.Canvas, 0, 3, xMidPanel + 7 - 10, PanelHeight - 3,
     4333        wMainTexture - (xMidPanel + 7 - 10), hMainTexture - PanelHeight);
     4334      Fill(Panel.Canvas, xRightPanel + 10 - 7, 3, Panel.width - xRightPanel - 10
     4335        + 7, PanelHeight - 3, -(xRightPanel + 10 - 7),
     4336        hMainTexture - PanelHeight);
     4337      FillLarge(Panel.Canvas, xMidPanel - 2, PanelHeight - MidPanelHeight,
     4338        xRightPanel + 2, PanelHeight, ClientWidth div 2);
     4339
     4340      Brush.Style := bsClear;
     4341      Pen.Color := $000000;
     4342      MoveTo(0, 0);
     4343      LineTo(xMidPanel + 7 - 8, 0);
     4344      LineTo(xMidPanel + 7 - 8, PanelHeight - MidPanelHeight);
     4345      LineTo(xRightPanel, PanelHeight - MidPanelHeight);
     4346      LineTo(xRightPanel, 0);
     4347      LineTo(ClientWidth, 0);
     4348      Pen.Color := MainTexture.clBevelLight;
     4349      MoveTo(xMidPanel + 7 - 9, PanelHeight - MidPanelHeight + 2);
     4350      LineTo(xRightPanel + 10 - 8, PanelHeight - MidPanelHeight + 2);
     4351      Pen.Color := MainTexture.clBevelLight;
     4352      MoveTo(0, 1);
     4353      LineTo(xMidPanel + 7 - 9, 1);
     4354      Pen.Color := MainTexture.clBevelShade;
     4355      LineTo(xMidPanel + 7 - 9, PanelHeight - MidPanelHeight + 1);
     4356      Pen.Color := MainTexture.clBevelLight;
     4357      LineTo(xRightPanel + 10 - 9, PanelHeight - MidPanelHeight + 1);
     4358      Pen.Color := MainTexture.clBevelLight;
     4359      LineTo(xRightPanel + 10 - 9, 1);
     4360      LineTo(ClientWidth, 1);
     4361      MoveTo(ClientWidth, 2);
     4362      LineTo(xRightPanel + 10 - 8, 2);
     4363      LineTo(xRightPanel + 10 - 8, PanelHeight);
     4364      MoveTo(0, 2);
     4365      LineTo(xMidPanel + 7 - 10, 2);
     4366      Pen.Color := MainTexture.clBevelShade;
     4367      LineTo(xMidPanel + 7 - 10, PanelHeight);
     4368      Corner(Panel.Canvas, xMidPanel + 7 - 16, 1, 1, MainTexture);
     4369      Corner(Panel.Canvas, xRightPanel + 10 - 9, 1, 0, MainTexture);
     4370      if ClientMode <> cEditMap then
     4371      begin
     4372        if supervising then
     4373        begin
     4374          Frame(Panel.Canvas, ClientWidth - xPalace - 1, yPalace - 1,
     4375            ClientWidth - xPalace + xSizeBig, yPalace + ySizeBig,
     4376            $B0B0B0, $FFFFFF);
     4377          RFrame(Panel.Canvas, ClientWidth - xPalace - 2, yPalace - 2,
     4378            ClientWidth - xPalace + xSizeBig + 1, yPalace + ySizeBig + 1,
     4379            $FFFFFF, $B0B0B0);
     4380          BitBlt(Panel.Canvas.Handle, ClientWidth - xPalace, yPalace, xSizeBig,
     4381            ySizeBig, GrExt[HGrSystem2].Data.Canvas.Handle, 70, 123, SRCCOPY);
     4382        end
     4383        else if MyRO.NatBuilt[imPalace] > 0 then
     4384          ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, imPalace, -1,
     4385            GameMode <> cMovie
     4386            { (GameMode<>cMovie) and (MyRO.Government<>gAnarchy) } )
     4387        else
     4388          ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, 21, -1,
     4389            GameMode <> cMovie
     4390            { (GameMode<>cMovie) and (MyRO.Government<>gAnarchy) } );
     4391      end;
     4392
     4393      if GameMode = cMovie then
     4394        Frame(Panel.Canvas, xMini + 1, yMini + 1, xMini + 2 + G.lx * 2,
     4395          yMini + 2 + G.ly, $000000, $000000)
     4396      else
     4397      begin
     4398        Frame(Panel.Canvas, xMini + 1, yMini + 1, xMini + 2 + G.lx * 2,
     4399          yMini + 2 + G.ly, $B0B0B0, $FFFFFF);
     4400        RFrame(Panel.Canvas, xMini, yMini, xMini + 3 + G.lx * 2,
     4401          yMini + 3 + G.ly, $FFFFFF, $B0B0B0);
     4402      end;
     4403      CopyMiniToPanel;
     4404      if ClientMode <> cEditMap then // MapBtn icons
     4405        for i := 0 to 5 do
     4406          if i <> 3 then
     4407            Dump(Panel, HGrSystem, xMini + G.lx - 42 + 16 * i, PanelHeight - 26,
     4408              8, 8, 121 + i * 9, 61);
     4409
     4410      if ClientMode = cEditMap then
     4411      begin
     4412        for i := 0 to TrRow - 1 do
     4413          trix[i] := -1;
     4414        Count := 0;
     4415        for i := 0 to nBrushTypes - 1 do
     4416        begin // display terrain types
     4417          if (Count >= TrRow * sb.si.npos) and (Count < TrRow * (sb.si.npos + 1))
     4418          then
     4419          begin
     4420            trix[Count - TrRow * sb.si.npos] := BrushTypes[i];
     4421            x := (Count - TrRow * sb.si.npos) * TrPitch;
     4422            xSrcBase := -1;
     4423            case BrushTypes[i] of
     4424              0 .. 8:
     4425                begin
     4426                  xSrc := BrushTypes[i];
     4427                  ySrc := 0
     4428                end;
     4429              9 .. 30:
     4430                begin
     4431                  xSrcBase := 2;
     4432                  ySrcBase := 2;
     4433                  xSrc := 0;
     4434                  ySrc := 2 * integer(BrushTypes[i]) - 15
     4435                end;
     4436              fRiver:
     4437                begin
     4438                  xSrc := 7;
     4439                  ySrc := 14
     4440                end;
     4441              fRoad:
     4442                begin
     4443                  xSrc := 0;
     4444                  ySrc := 9
     4445                end;
     4446              fRR:
     4447                begin
     4448                  xSrc := 0;
     4449                  ySrc := 10
     4450                end;
     4451              fCanal:
     4452                begin
     4453                  xSrc := 0;
     4454                  ySrc := 11
     4455                end;
     4456              fPoll:
     4457                begin
     4458                  xSrc := 6;
     4459                  ySrc := 12
     4460                end;
     4461              fDeadLands, fDeadLands or fCobalt, fDeadLands or fUranium,
     4462                fDeadLands or fMercury:
     4463                begin
     4464                  xSrcBase := 6;
     4465                  ySrcBase := 2;
     4466                  xSrc := 8;
     4467                  ySrc := 12 + BrushTypes[i] shr 25;
     4468                end;
     4469              tiIrrigation, tiFarm, tiMine, tiBase:
     4470                begin
     4471                  xSrc := BrushTypes[i] shr 12 - 1;
     4472                  ySrc := 12
     4473                end;
     4474              tiFort:
     4475                begin
     4476                  xSrc := 3;
     4477                  ySrc := 12;
     4478                  xSrcBase := 7;
     4479                  ySrcBase := 12
     4480                end;
     4481              fPrefStartPos:
     4482                begin
     4483                  xSrc := 0;
     4484                  ySrc := 1
     4485                end;
     4486              fStartPos:
     4487                begin
     4488                  xSrc := 0;
     4489                  ySrc := 2
     4490                end;
     4491            end;
     4492            if xSrcBase >= 0 then
     4493              Sprite(Panel, HGrTerrain, xTroop + 2 + x, yTroop + 9 - yyt,
     4494                xxt * 2, yyt * 3, 1 + xSrcBase * (xxt * 2 + 1),
     4495                1 + ySrcBase * (yyt * 3 + 1));
     4496            Sprite(Panel, HGrTerrain, xTroop + 2 + x, yTroop + 9 - yyt, xxt * 2,
     4497              yyt * 3, 1 + xSrc * (xxt * 2 + 1), 1 + ySrc * (yyt * 3 + 1));
     4498            if BrushTypes[i] = BrushType then
     4499            begin
     4500              Frame(Panel.Canvas, xTroop + 2 + x, yTroop + 7 - yyt div 2,
     4501                xTroop + 2 * xxt + x, yTroop + 2 * yyt + 11, $000000, $000000);
     4502              Frame(Panel.Canvas, xTroop + 1 + x, yTroop + 6 - yyt div 2,
     4503                xTroop + 2 * xxt - 1 + x, yTroop + 2 * yyt + 10,
     4504                MainTexture.clMark, MainTexture.clMark);
     4505            end
     4506          end;
     4507          inc(Count)
     4508        end;
     4509        case BrushType of
     4510          fDesert, fPrairie, fTundra, fArctic, fSwamp, fHills, fMountains:
     4511            s := Phrases.Lookup('TERRAIN', BrushType);
     4512          fShore:
     4513            s := Format(Phrases.Lookup('TWOTERRAINS'),
     4514              [Phrases.Lookup('TERRAIN', fOcean), Phrases.Lookup('TERRAIN',
     4515              fShore)]);
     4516          fGrass:
     4517            s := Format(Phrases.Lookup('TWOTERRAINS'),
     4518              [Phrases.Lookup('TERRAIN', fGrass), Phrases.Lookup('TERRAIN',
     4519              fGrass + 12)]);
     4520          fForest:
     4521            s := Format(Phrases.Lookup('TWOTERRAINS'),
     4522              [Phrases.Lookup('TERRAIN', fForest), Phrases.Lookup('TERRAIN',
     4523              fJungle)]);
     4524          fRiver:
     4525            s := Phrases.Lookup('RIVER');
     4526          fDeadLands, fDeadLands or fCobalt, fDeadLands or fUranium,
     4527            fDeadLands or fMercury:
     4528            s := Phrases.Lookup('TERRAIN', 3 * 12 + BrushType shr 25);
     4529          fPrefStartPos:
     4530            s := Phrases.Lookup('MAP_PREFSTART');
     4531          fStartPos:
     4532            s := Phrases.Lookup('MAP_START');
     4533          fPoll:
     4534            s := Phrases.Lookup('POLL');
     4535        else // terrain improvements
     4536          begin
     4537            case BrushType of
     4538              fRoad:
     4539                i := 1;
     4540              fRR:
     4541                i := 2;
     4542              tiIrrigation:
     4543                i := 4;
     4544              tiFarm:
     4545                i := 5;
     4546              tiMine:
     4547                i := 7;
     4548              fCanal:
     4549                i := 8;
     4550              tiFort:
     4551                i := 10;
     4552              tiBase:
     4553                i := 12;
     4554            end;
     4555            s := Phrases.Lookup('JOBRESULT', i);
     4556          end
     4557        end;
     4558        LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 1,
     4559          PanelHeight - 19, s);
     4560      end
     4561      else if TroopLoc >= 0 then
     4562      begin
     4563        Brush.Style := bsClear;
     4564        if UnFocus >= 0 then
     4565          with MyUn[UnFocus], MyModel[mix] do
     4566          begin { display info about selected unit }
     4567            if Job = jCity then
     4568              mixShow := -1 // building site
     4569            else
     4570              mixShow := mix;
     4571            with Tribe[me].ModelPicture[mixShow] do
     4572            begin
     4573              Sprite(Panel, HGr, xMidPanel + 7 + 12, yTroop + 1, 64, 48,
     4574                pix mod 10 * 65 + 1, pix div 10 * 49 + 1);
     4575              if MyUn[UnFocus].Flags and unFortified <> 0 then
     4576                Sprite(Panel, HGrStdUnits, xMidPanel + 7 + 12, yTroop + 1,
     4577                  xxu * 2, yyu * 2, 1 + 6 * (xxu * 2 + 1), 1);
     4578            end;
     4579
     4580            MakeBlue(Panel, xMidPanel + 7 + 12 + 10, yTroop - 13, 44, 12);
     4581            s := MovementToString(MyUn[UnFocus]);
     4582            RisedTextOut(Panel.Canvas, xMidPanel + 7 + 12 + 32 -
     4583              BiColorTextWidth(Panel.Canvas, s) div 2, yTroop - 16, s);
     4584
     4585            s := IntToStr(Health) + '%';
     4586            LightGradient(Panel.Canvas, xMidPanel + 7 + 12 + 7,
     4587              PanelHeight - 22, (Health + 1) div 2,
     4588              (ColorOfHealth(Health) and $FEFEFE shr 2) * 3);
     4589            if Health < 100 then
     4590              LightGradient(Panel.Canvas, xMidPanel + 7 + 12 + 7 + (Health + 1)
     4591                div 2, PanelHeight - 22, 50 - (Health + 1) div 2, $000000);
     4592            RisedTextOut(Panel.Canvas, xMidPanel + 7 + 12 + 32 -
     4593              BiColorTextWidth(Panel.Canvas, s) div 2, PanelHeight - 23, s);
     4594
     4595            FrameImage(Panel.Canvas, GrExt[HGrSystem].Data,
     4596              xMidPanel + 7 + xUnitText, yTroop + 15, 12, 14,
     4597              121 + Exp div ExpCost * 13, 28);
     4598            if Job = jCity then
     4599              s := Tribe[me].ModelName[-1]
     4600            else
     4601              s := Tribe[me].ModelName[mix];
     4602            if Home >= 0 then
     4603            begin
     4604              LoweredTextOut(Panel.Canvas, -1, MainTexture,
     4605                xMidPanel + 7 + xUnitText + 18, yTroop + 5, s);
     4606              LoweredTextOut(Panel.Canvas, -1, MainTexture,
     4607                xMidPanel + 7 + xUnitText + 18, yTroop + 21,
     4608                '(' + CityName(MyCity[Home].ID) + ')');
     4609            end
     4610            else
     4611              LoweredTextOut(Panel.Canvas, -1, MainTexture,
     4612                xMidPanel + 7 + xUnitText + 18, yTroop + 13, s);
     4613          end;
     4614
     4615        if (UnFocus >= 0) and (MyUn[UnFocus].Loc <> TroopLoc) then
     4616        begin // divide panel
     4617          if SmallScreen and not supervising then
     4618            x := xTroop - 8
     4619          else
     4620            x := xTroop - 152;
     4621          Pen.Color := MainTexture.clBevelShade;
     4622          MoveTo(x - 1, PanelHeight - MidPanelHeight + 2);
     4623          LineTo(x - 1, PanelHeight);
     4624          Pen.Color := MainTexture.clBevelLight;
     4625          MoveTo(x, PanelHeight - MidPanelHeight + 2);
     4626          LineTo(x, PanelHeight);
     4627        end;
     4628
     4629        for i := 0 to 23 do
     4630          trix[i] := -1;
     4631        if MyMap[TroopLoc] and fUnit <> 0 then
     4632        begin
     4633          if MyMap[TroopLoc] and fOwned <> 0 then
     4634          begin
     4635            if (TrCnt > 1) or (UnFocus < 0) or (MyUn[UnFocus].Loc <> TroopLoc)
     4636            then
     4637            begin
     4638              LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 10,
     4639                PanelHeight - 24, Phrases.Lookup('PRESENT'));
     4640              Server(sGetDefender, me, TroopLoc, uixDefender);
     4641              Count := 0;
     4642              for Prio := true downto false do
     4643                for uix := 0 to MyRO.nUn - 1 do
     4644                  if (uix = uixDefender) = Prio then
     4645                  begin // display own units
     4646                    unx := MyUn[uix];
     4647                    if unx.Loc = TroopLoc then
     4648                    begin
     4649                      if (Count >= TrRow * sb.si.npos) and
     4650                        (Count < TrRow * (sb.si.npos + 1)) then
     4651                      begin
     4652                        trix[Count - TrRow * sb.si.npos] := uix;
     4653                        MakeUnitInfo(me, unx, UnitInfo);
     4654                        x := (Count - TrRow * sb.si.npos) * TrPitch;
     4655                        if uix = UnFocus then
     4656                        begin
     4657                          Frame(Panel.Canvas, xTroop + 4 + x, yTroop + 3,
     4658                            xTroop + 64 + x, yTroop + 47, $000000, $000000);
     4659                          Frame(Panel.Canvas, xTroop + 3 + x, yTroop + 2,
     4660                            xTroop + 63 + x, yTroop + 46, MainTexture.clMark,
     4661                            MainTexture.clMark);
     4662                        end
     4663                        else if (unx.Master >= 0) and (unx.Master = UnFocus)
     4664                        then
     4665                        begin
     4666                          CFrame(Panel.Canvas, xTroop + 4 + x, yTroop + 3,
     4667                            xTroop + 64 + x, yTroop + 47, 8, $000000);
     4668                          CFrame(Panel.Canvas, xTroop + 3 + x, yTroop + 2,
     4669                            xTroop + 63 + x, yTroop + 46, 8,
     4670                            MainTexture.clMark);
     4671                        end;
     4672                        NoMap.SetOutput(Panel);
     4673                        NoMap.PaintUnit(xTroop + 2 + x, yTroop + 1, UnitInfo,
     4674                          unx.Status);
     4675                        if (ClientMode < scContact) and
     4676                          ((unx.Job > jNone) or
     4677                          (unx.Status and (usStay or usRecover or usGoto) <> 0))
     4678                        then
     4679                          Sprite(Panel, HGrSystem, xTroop + 2 + 60 - 20 + x,
     4680                            yTroop + 35, 20, 20, 81, 25);
     4681
     4682                        if not supervising then
     4683                        begin
     4684                          MakeBlue(Panel, xTroop + 2 + 10 + x,
     4685                            yTroop - 13, 44, 12);
     4686                          s := MovementToString(unx);
     4687                          RisedTextOut(Panel.Canvas,
     4688                            xTroop + x + 34 - BiColorTextWidth(Panel.Canvas, s)
     4689                            div 2, yTroop - 16, s);
     4690                        end
     4691                      end;
     4692                      inc(Count)
     4693                    end;
     4694                  end; // for uix:=0 to MyRO.nUn-1
     4695              assert(Count = TrCnt);
     4696            end
     4697          end
     4698          else
     4699          begin
     4700            LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 8,
     4701              PanelHeight - 24, Phrases.Lookup('PRESENT'));
     4702            Server(sGetUnits, me, TroopLoc, Count);
     4703            for i := 0 to Count - 1 do
     4704              if (i >= TrRow * sb.si.npos) and (i < TrRow * (sb.si.npos + 1))
     4705              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,
     4724              63, 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]
     4730              .Required)]);
     4731            RisedTextOut(Panel.Canvas, xTerrain + 6, 148 - 3, s);
     4732            Tile := MyMap[MyUn[UnFocus].Loc];
     4733            if (JobFocus = jRoad) and (Tile and fRiver <> 0) then
     4734              JobFocus := nJob + 0
     4735            else if (JobFocus = jRR) and (Tile and fRiver <> 0) then
     4736              JobFocus := nJob + 1
     4737            else if JobFocus = jClear then
     4738            begin
     4739              if Tile and fTerrain = fForest then
     4740                JobFocus := nJob + 2
     4741              else if Tile and fTerrain = fDesert then
     4742                JobFocus := nJob + 3
     4743              else
     4744                JobFocus := nJob + 4
     4745            end;
     4746            s := Phrases.Lookup('JOBRESULT', JobFocus);
     4747            RisedTextOut(Panel.Canvas, xTerrain - BiColorTextWidth(Panel.Canvas,
     4748              s) div 2, 148 - 19, s);
     4749          end;
     4750          if MyMap[TroopLoc] and (fTerrain or fSpecial) = fGrass or fSpecial1
     4751          then
     4752            s := Phrases.Lookup('TERRAIN', fGrass + 12)
     4753          else if MyMap[TroopLoc] and fDeadLands <> 0 then
     4754            s := Phrases.Lookup('TERRAIN', 3 * 12)
     4755          else if (MyMap[TroopLoc] and fTerrain = fForest) and
     4756            IsJungle(TroopLoc div G.lx) then
     4757            s := Phrases.Lookup('TERRAIN', fJungle)
     4758          else
     4759            s := Phrases.Lookup('TERRAIN', MyMap[TroopLoc] and fTerrain);
     4760          RisedTextOut(Panel.Canvas, xTerrain - BiColorTextWidth(Panel.Canvas,
     4761            s) div 2, 99, s);
     4762        end;
     4763
     4764        if TerrainBtn.Visible then
     4765          with TerrainBtn do
     4766            RFrame(Panel.Canvas, Left - 1, Top - self.ClientHeight +
     4767              (PanelHeight - 1), Left + width, Top + height - self.ClientHeight
     4768              + PanelHeight, MainTexture.clBevelShade, MainTexture.clBevelLight)
     4769      end { if TroopLoc>=0 }
     4770    end;
     4771
     4772    for i := 0 to ControlCount - 1 do
     4773      if Controls[i] is TButtonB then
     4774        with TButtonB(Controls[i]) do
     4775        begin
     4776          if Visible then
     4777          begin
     4778            Dump(Panel, HGrSystem, Left, Top - self.ClientHeight + PanelHeight,
     4779              25, 25, 169, 243);
     4780            Sprite(Panel, HGrSystem, Left, Top - self.ClientHeight +
     4781              PanelHeight, 25, 25, 1 + 26 * ButtonIndex, 337);
     4782            RFrame(Panel.Canvas, Left - 1, Top - self.ClientHeight +
     4783              (PanelHeight - 1), Left + width, Top + height - self.ClientHeight
     4784              + PanelHeight, MainTexture.clBevelShade,
     4785              MainTexture.clBevelLight);
     4786          end;
     4787        end;
     4788
     4789    if ClientMode <> cEditMap then
     4790    begin
     4791      for i := 0 to ControlCount - 1 do
     4792        if Controls[i] is TButtonC then
     4793          with TButtonC(Controls[i]) do
     4794          begin
     4795            Dump(Panel, HGrSystem, Left, Top - self.ClientHeight + PanelHeight,
     4796              12, 12, 169, 178 + 13 * ButtonIndex);
     4797            RFrame(Panel.Canvas, Left - 1, Top - self.ClientHeight +
     4798              (PanelHeight - 1), Left + width, Top + height - self.ClientHeight
     4799              + PanelHeight, MainTexture.clBevelShade,
     4800              MainTexture.clBevelLight);
     4801          end
     4802    end;
     4803    EOT.SetBack(Panel.Canvas, EOT.Left, EOT.Top - (ClientHeight - PanelHeight));
     4804    SmartRectInvalidate(0, ClientHeight - PanelHeight, ClientWidth,
     4805      ClientHeight);
     4806
     4807    // topbar
     4808    xTreasurySection := ClientWidth div 2 - 172;
     4809    xResearchSection := ClientWidth div 2;
     4810    // ClientWidth div 2+68 = maximum to right
     4811    FillLarge(TopBar.Canvas, 0, 0, ClientWidth, TopBarHeight - 3,
     4812      ClientWidth div 2);
     4813    with TopBar.Canvas do
     4814    begin
     4815      Pen.Color := $000000;
     4816      MoveTo(0, TopBarHeight - 1);
     4817      LineTo(ClientWidth, TopBarHeight - 1);
     4818      Pen.Color := MainTexture.clBevelShade;
     4819      MoveTo(0, TopBarHeight - 2);
     4820      LineTo(ClientWidth, TopBarHeight - 2);
     4821      MoveTo(0, TopBarHeight - 3);
     4822      LineTo(ClientWidth, TopBarHeight - 3);
     4823      Pen.Color := MainTexture.clBevelLight;
     4824      Frame(TopBar.Canvas, 40, -1, xTreasurySection - 1, TopBarHeight - 7,
     4825        MainTexture.clBevelShade, MainTexture.clBevelLight);
     4826      Frame(TopBar.Canvas, xResearchSection + 332, -1, ClientWidth,
     4827        TopBarHeight - 7, MainTexture.clBevelShade, MainTexture.clBevelLight);
     4828    end;
     4829    if GameMode <> cMovie then
     4830      ImageOp_BCC(TopBar, Templates, 2, 1, 145, 38, 36, 36, $BFBF20, $4040DF);
     4831    if MyRO.nCity > 0 then
     4832    begin
     4833      TrueMoney := MyRO.Money;
     4834      TrueResearch := MyRO.Research;
     4835      if supervising then
     4836      begin // normalize values from after-turn state
     4837        dec(TrueMoney, TaxSum);
     4838        if TrueMoney < 0 then
     4839          TrueMoney := 0; // shouldn't happen
     4840        dec(TrueResearch, ScienceSum);
     4841        if TrueResearch < 0 then
     4842          TrueResearch := 0; // shouldn't happen
     4843      end;
     4844
     4845      // treasury section
     4846      ImageOp_BCC(TopBar, Templates, xTreasurySection + 8, 1, 145, 1, 36, 36,
     4847        $40A040, $4030C0);
     4848      s := IntToStr(TrueMoney);
     4849      LoweredTextOut(TopBar.Canvas, -1, MainTexture, xTreasurySection + 48, 0,
     4850        s + '%c');
     4851      if MyRO.Government <> gAnarchy then
     4852      begin
     4853        ImageOp_BCC(TopBar, Templates, xTreasurySection + 48, 22, 124, 1, 14,
     4854          14, $0000C0, $0080C0);
     4855        if TaxSum >= 0 then
     4856          s := Format(Phrases.Lookup('MONEYGAINPOS'), [TaxSum])
     4857        else
     4858          s := Format(Phrases.Lookup('MONEYGAINNEG'), [TaxSum]);
     4859        LoweredTextOut(TopBar.Canvas, -1, MainTexture,
     4860          xTreasurySection + 48 + 15, 18, s);
     4861      end;
     4862
     4863      // research section
     4864      ImageOp_BCC(TopBar, Templates, xResearchSection + 8, 1, 145, 75, 36, 36,
     4865        $FF0000, $00FFE0);
     4866      if MyData.FarTech <> adNexus then
     4867      begin
     4868        if MyRO.ResearchTech < 0 then
     4869          CostFactor := 2
     4870        else if (MyRO.ResearchTech = adMilitary) or
     4871          (MyRO.Tech[MyRO.ResearchTech] = tsSeen) then
     4872          CostFactor := 1
     4873        else if MyRO.ResearchTech in FutureTech then
     4874          if MyRO.Government = gFuture then
     4875            CostFactor := 4
     4876          else
     4877            CostFactor := 8
     4878        else
     4879          CostFactor := 2;
     4880        Server(sGetTechCost, me, 0, i);
     4881        CostFactor := CostFactor * 22; // length of progress bar
     4882        PaintRelativeProgressBar(TopBar.Canvas, 2, xResearchSection + 48 + 1,
     4883          26, CostFactor, TrueResearch, ScienceSum, i, true, MainTexture);
     4884
     4885        if MyRO.ResearchTech < 0 then
     4886          s := Phrases.Lookup('SCIENCE')
     4887        else if MyRO.ResearchTech = adMilitary then
     4888          s := Phrases.Lookup('INITUNIT')
     4889        else
     4890        begin
     4891          s := Phrases.Lookup('ADVANCES', MyRO.ResearchTech);
     4892          if MyRO.ResearchTech in FutureTech then
     4893            if MyRO.Tech[MyRO.ResearchTech] >= 1 then
     4894              s := s + ' ' + IntToStr(MyRO.Tech[MyRO.ResearchTech] + 1)
     4895            else
     4896              s := s + ' 1';
     4897        end;
     4898        if ScienceSum > 0 then
     4899        begin
     4900          { j:=(i-MyRO.Research-1) div ScienceSum +1;
     4901            if j<1 then j:=1;
     4902            if j>1 then
     4903            s:=Format(Phrases.Lookup('TECHWAIT'),[s,j]); }
     4904          LoweredTextOut(TopBar.Canvas, -1, MainTexture,
     4905            xResearchSection + 48, 0, s);
     4906        end
     4907        else
     4908          LoweredTextOut(TopBar.Canvas, -1, MainTexture,
     4909            xResearchSection + 48, 0, s);
     4910      end
     4911      else
     4912        CostFactor := 0;
     4913      if (MyData.FarTech <> adNexus) and (ScienceSum > 0) then
     4914      begin
     4915        ImageOp_BCC(TopBar, Templates, xResearchSection + 48 + CostFactor + 11,
     4916          22, 124, 1, 14, 14, $0000C0, $0080C0);
     4917        s := Format(Phrases.Lookup('TECHGAIN'), [ScienceSum]);
     4918        LoweredTextOut(TopBar.Canvas, -1, MainTexture, xResearchSection + 48 +
     4919          CostFactor + 26, 18, s);
     4920      end
     4921    end;
     4922    if ClientMode <> cEditMap then
     4923    begin
     4924      TopBar.Canvas.Font.Assign(UniFont[ftCaption]);
     4925      s := TurnToString(MyRO.Turn);
     4926      RisedTextOut(TopBar.Canvas,
     4927        40 + (xTreasurySection - 40 - BiColorTextWidth(TopBar.Canvas, s))
     4928        div 2, 6, s);
     4929      TopBar.Canvas.Font.Assign(UniFont[ftNormal]);
     4930    end;
     4931    RectInvalidate(0, 0, ClientWidth, TopBarHeight);
     4932  end; { PanelPaint }
     4933
     4934  procedure TMainScreen.FocusOnLoc(Loc: integer; Options: integer = 0);
     4935  var
     4936    dx: integer;
     4937    Outside, Changed: boolean;
     4938  begin
     4939    dx := G.lx + 1 - (xw - Loc + G.lx * 1024 + 1) mod G.lx;
     4940    Outside := (dx >= (MapWidth + 1) div (xxt * 2) - 2) or (ywmax > 0) and
     4941      ((yw > 0) and (Loc div G.lx <= yw + 1) or (yw < ywmax) and
     4942      (Loc div G.lx >= yw + (MapHeight - 1) div yyt - 2));
     4943    Changed := true;
     4944    if Outside then
     4945    begin
     4946      Centre(Loc);
     4947      PaintAllMaps
     4948    end
     4949    else if not MapValid then
     4950      PaintAllMaps
     4951    else
     4952      Changed := false;
     4953    if Options and flRepaintPanel <> 0 then
     4954      PanelPaint;
     4955    if Changed and (Options and flImmUpdate <> 0) then
     4956      Update;
     4957  end;
     4958
     4959  procedure TMainScreen.NextUnit(NearLoc: integer; AutoTurn: boolean);
     4960  var
     4961    Dist, TestDist: single;
     4962    i, uix, NewFocus: integer;
     4963    GotoOnly: boolean;
     4964  begin
     4965    if ClientMode >= scContact then
     4966      exit;
     4967    DestinationMarkON := false;
     4968    PaintDestination;
     4969    for GotoOnly := GoOnPhase downto false do
     4970    begin
     4971      NewFocus := -1;
     4972      for i := 1 to MyRO.nUn do
     4973      begin
     4974        uix := (UnFocus + i) mod MyRO.nUn;
     4975        if (MyUn[uix].Loc >= 0) and (MyUn[uix].Job = jNone) and
     4976          (MyUn[uix].Status and (usStay or usRecover or usWaiting) = usWaiting)
     4977          and (not GotoOnly or (MyUn[uix].Status and usGoto <> 0)) then
     4978          if NearLoc < 0 then
     4979          begin
     4980            NewFocus := uix;
     4981            Break
     4982          end
     4983          else
     4984          begin
     4985            TestDist := Distance(NearLoc, MyUn[uix].Loc);
     4986            if (NewFocus < 0) or (TestDist < Dist) then
     4987            begin
     4988              NewFocus := uix;
     4989              Dist := TestDist
     4990            end
     4991          end
     4992      end;
     4993      if GotoOnly then
     4994        if NewFocus < 0 then
     4995          GoOnPhase := false
     4996        else
     4997          Break;
     4998    end;
     4999    if NewFocus >= 0 then
     5000    begin
     5001      SetUnFocus(NewFocus);
     5002      SetTroopLoc(MyUn[NewFocus].Loc);
     5003      FocusOnLoc(TroopLoc, flRepaintPanel)
     5004    end
     5005    else if AutoTurn and not mWaitTurn.Checked then
     5006    begin
     5007      TurnComplete := true;
     5008      SetUnFocus(-1);
     5009      SetTroopLoc(-1);
     5010      PostMessage(Handle, WM_EOT, 0, 0)
     5011    end
     5012    else
     5013    begin
     5014      if { (UnFocus>=0) and } not TurnComplete and EOT.Visible then
     5015        Play('TURNEND');
     5016      TurnComplete := true;
     5017      SetUnFocus(-1);
     5018      SetTroopLoc(-1);
     5019      PanelPaint;
     5020    end;
     5021  end; { NextUnit }
     5022
     5023  procedure TMainScreen.Scroll(dx, dy: integer);
     5024  begin
     5025    xw := (xw + G.lx + dx) mod G.lx;
     5026    if ywmax > 0 then
     5027    begin
     5028      yw := yw + 2 * dy;
     5029      if yw < 0 then
     5030        yw := 0
     5031      else if yw > ywmax then
     5032        yw := ywmax;
     5033    end;
     5034    MainOffscreenPaint;
     5035    xwMini := xw;
     5036    ywMini := yw;
     5037    MiniPaint;
     5038    CopyMiniToPanel;
     5039    RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini + 2,
     5040      xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini +
     5041      2 + G.ly);
     5042    Update;
     5043  end;
     5044
     5045  procedure TMainScreen.Timer1Timer(Sender: TObject);
     5046  var
     5047    dx, dy, speed: integer;
     5048  begin
     5049    if idle and (me >= 0) and (GameMode <> cMovie) then
     5050      if (fsModal in Screen.ActiveForm.FormState) or
     5051        (Screen.ActiveForm is TBufferedDrawDlg) and
     5052        (TBufferedDrawDlg(Screen.ActiveForm).WindowMode <> wmPersistent) then
     5053      begin
     5054        BlinkTime := BlinkOnTime + BlinkOffTime - 1;
     5055        if not BlinkON then
     5056        begin
     5057          BlinkON := true;
     5058          if UnFocus >= 0 then
     5059            PaintLocTemp(MyUn[UnFocus].Loc)
     5060          else if TurnComplete and not supervising then
     5061            EOT.SetButtonIndexFast(eotBlinkOn)
     5062        end
     5063      end
     5064      else
     5065      begin
     5066        if Application.Active and not mScrollOff.Checked then
     5067        begin
     5068          if mScrollFast.Checked then
     5069            speed := 2
     5070          else
     5071            speed := 1;
     5072          dx := 0;
     5073          dy := 0;
     5074          if Mouse.CursorPos.y < Screen.height - PanelHeight then
     5075            if Mouse.CursorPos.x = 0 then
     5076              dx := -speed // scroll left
     5077            else if Mouse.CursorPos.x = Screen.width - 1 then
     5078              dx := speed; // scroll right
     5079          if Mouse.CursorPos.y = 0 then
     5080            dy := -speed // scroll up
     5081          else if (Mouse.CursorPos.y = Screen.height - 1) and
     5082            (Mouse.CursorPos.x >= TerrainBtn.Left + TerrainBtn.width) and
     5083            (Mouse.CursorPos.x < xRightPanel + 10 - 8) then
     5084            dy := speed; // scroll down
     5085          if (dx <> 0) or (dy <> 0) then
     5086          begin
     5087            if (Screen.ActiveForm <> MainScreen) and
     5088              (@Screen.ActiveForm.OnDeactivate <> nil) then
     5089              Screen.ActiveForm.OnDeactivate(nil);
     5090            Scroll(dx, dy);
     5091          end
     5092        end;
     5093
     5094        BlinkTime := (BlinkTime + 1) mod (BlinkOnTime + BlinkOffTime);
     5095        BlinkON := BlinkTime >= BlinkOffTime;
     5096        DestinationMarkON := true;
     5097        if UnFocus >= 0 then
     5098        begin
     5099          if (BlinkTime = 0) or (BlinkTime = BlinkOffTime) then
     5100          begin
     5101            PaintLocTemp(MyUn[UnFocus].Loc, pltsBlink);
     5102            PaintDestination;
     5103            // if MoveHintToLoc>=0 then
     5104            // ShowMoveHint(MoveHintToLoc, true);
    17035105          end
    17045106        end
    1705       else
    1706         begin
    1707         s:=Tribe[me].TPhrase('AGE'+char(48+Age));
    1708         MessgText:=Format(s,[TurnToString(MyRO.Turn)]);
    1709         end;
    1710       IconKind:=mikAge;
    1711       IconIndex:=Age;
    1712       {if age=0 then} Kind:=mkOK
    1713       {else begin Kind:=mkOkHelp; HelpKind:=hkAdv; HelpNo:=AgePreq[age]; end};
    1714       CenterTo:=NewAgeCenterTo;
    1715       OpenSound:='AGE_'+char(48+Age);
    1716       ShowModal;
    1717       MyData.ToldAge:=Age;
    1718       if Age>0 then
    1719         MyData.ToldTech[AgePreq[Age]]:=MyRO.Tech[AgePreq[Age]];
    1720       end;
    1721 
    1722     if MyData.ToldAlive<>MyRO.Alive then
    1723       begin
    1724       for p1:=0 to nPl-1 do
    1725         if (MyData.ToldAlive-MyRO.Alive) and (1 shl p1)<>0 then
    1726           with MessgExDlg do
    1727             begin
    1728             OpenSound:='MSG_EXTINCT';
    1729             s:=Tribe[p1].TPhrase('EXTINCT');
    1730             MessgText:=Format(s,[TurnToString(MyRO.Turn)]);
    1731             if MyRO.Alive=1 shl me then
    1732               MessgText:=MessgText+Phrases.Lookup('EXTINCTALL');
    1733             Kind:=mkOK;
    1734             IconKind:=mikImp;
    1735             IconIndex:=21;
    1736             ShowModal;
     5107        else if TurnComplete and not supervising then
     5108        begin
     5109          if BlinkTime = 0 then
     5110            EOT.SetButtonIndexFast(eotBlinkOff)
     5111          else if BlinkTime = BlinkOffTime then
     5112            EOT.SetButtonIndexFast(eotBlinkOn)
     5113        end
     5114      end
     5115  end;
     5116
     5117  procedure TMainScreen.Centre(Loc: integer);
     5118  begin
     5119    if FastScrolling and MapValid then
     5120      Update;
     5121    // necessary because ScrollDC for form canvas is called after
     5122    xw := (Loc mod G.lx - (MapWidth - xxt * 2 * ((Loc div G.lx) and 1))
     5123      div (xxt * 4) + G.lx) mod G.lx;
     5124    if ywmax <= 0 then
     5125      yw := ywcenter
     5126    else
     5127    begin
     5128      yw := (Loc div G.lx - MapHeight div (yyt * 2) + 1) and not 1;
     5129      if yw < 0 then
     5130        yw := 0
     5131      else if yw > ywmax then
     5132        yw := ywmax;
     5133    end
     5134  end;
     5135
     5136  function TMainScreen.ZoomToCity(Loc: integer;
     5137    NextUnitOnClose: boolean = false; ShowEvent: integer = 0): boolean;
     5138  begin
     5139    result := MyMap[Loc] and (fOwned or fSpiedOut) <> 0;
     5140    if result then
     5141      with CityDlg do
     5142      begin
     5143        if ClientMode >= scContact then
     5144        begin
     5145          CloseAction := None;
     5146          RestoreUnFocus := -1;
     5147        end
     5148        else if NextUnitOnClose then
     5149        begin
     5150          CloseAction := StepFocus;
     5151          RestoreUnFocus := -1;
     5152        end
     5153        else if not Visible then
     5154        begin
     5155          CloseAction := RestoreFocus;
     5156          RestoreUnFocus := UnFocus;
     5157        end;
     5158        SetUnFocus(-1);
     5159        SetTroopLoc(Loc);
     5160        MarkCityLoc := Loc;
     5161        PanelPaint;
     5162        ShowNewContent(wmPersistent, Loc, ShowEvent);
     5163      end
     5164  end;
     5165
     5166  function TMainScreen.LocationOfScreenPixel(x, y: integer): integer;
     5167  var
     5168    qx, qy: integer;
     5169  begin
     5170    qx := (x * (yyt * 2) + y * (xxt * 2) + xxt * yyt * 2)
     5171      div (xxt * yyt * 4) - 1;
     5172    qy := (y * (xxt * 2) - x * (yyt * 2) - xxt * yyt * 2 + 4000 * xxt * yyt)
     5173      div (xxt * yyt * 4) - 999;
     5174    result := (xw + (qx - qy + 2048) div 2 - 1024 + G.lx) mod G.lx + G.lx *
     5175      (yw + qx + qy);
     5176  end;
     5177
     5178  procedure TMainScreen.MapBoxMouseDown(Sender: TObject; Button: TMouseButton;
     5179    Shift: TShiftState; x, y: integer);
     5180  var
     5181    i, uix, emix, p1, dx, dy, MouseLoc: integer;
     5182    EditTileData: TEditTileData;
     5183    m, m2: TMenuItem;
     5184    MoveAdviceData: TMoveAdviceData;
     5185    DoCenter: boolean;
     5186  begin
     5187    if GameMode = cMovie then
     5188      exit;
     5189
     5190    if CityDlg.Visible then
     5191      CityDlg.Close;
     5192    if UnitStatDlg.Visible then
     5193      UnitStatDlg.Close;
     5194    MouseLoc := LocationOfScreenPixel(x, y);
     5195    if (MouseLoc < 0) or (MouseLoc >= G.lx * G.ly) then
     5196      exit;
     5197    if (Button = mbLeft) and not(ssShift in Shift) then
     5198    begin
     5199      DoCenter := true;
     5200      if ClientMode = cEditMap then
     5201      begin
     5202        DoCenter := false;
     5203        EditTileData.Loc := MouseLoc;
     5204        if ssCtrl in Shift then // toggle special resource
     5205          case MyMap[MouseLoc] and fTerrain of
     5206            fOcean:
     5207              EditTileData.NewTile := MyMap[MouseLoc];
     5208            fGrass, fArctic:
     5209              EditTileData.NewTile := MyMap[MouseLoc] and not fSpecial or
     5210                ((MyMap[MouseLoc] shr 5 and 3 + 1) mod 2 shl 5);
     5211          else
     5212            EditTileData.NewTile := MyMap[MouseLoc] and not fSpecial or
     5213              ((MyMap[MouseLoc] shr 5 and 3 + 1) mod 3 shl 5)
     5214          end
     5215        else if BrushType <= fTerrain then
     5216          EditTileData.NewTile := MyMap[MouseLoc] and not fTerrain or
     5217            fSpecial or BrushType
     5218        else if BrushType and fDeadLands <> 0 then
     5219          if MyMap[MouseLoc] and (fDeadLands or fModern) = BrushType and
     5220            (fDeadLands or fModern) then
     5221            EditTileData.NewTile := MyMap[MouseLoc] and
     5222              not(fDeadLands or fModern)
     5223          else
     5224            EditTileData.NewTile := MyMap[MouseLoc] and
     5225              not(fDeadLands or fModern) or BrushType
     5226        else if BrushType and fTerImp <> 0 then
     5227          if MyMap[MouseLoc] and fTerImp = BrushType then
     5228            EditTileData.NewTile := MyMap[MouseLoc] and not fTerImp
     5229          else
     5230            EditTileData.NewTile := MyMap[MouseLoc] and not fTerImp or BrushType
     5231        else if BrushType and (fPrefStartPos or fStartPos) <> 0 then
     5232          if MyMap[MouseLoc] and (fPrefStartPos or fStartPos) = BrushType and
     5233            (fPrefStartPos or fStartPos) then
     5234            EditTileData.NewTile := MyMap[MouseLoc] and
     5235              not(fPrefStartPos or fStartPos)
     5236          else
     5237            EditTileData.NewTile := MyMap[MouseLoc] and
     5238              not(fPrefStartPos or fStartPos) or BrushType
     5239        else
     5240          EditTileData.NewTile := MyMap[MouseLoc] xor BrushType;
     5241        Server(sEditTile, me, 0, EditTileData);
     5242        Edited := true;
     5243        BrushLoc := MouseLoc;
     5244        PaintLoc(MouseLoc, 2);
     5245        MiniPaint;
     5246        BitBlt(Panel.Canvas.Handle, xMini + 2, yMini + 2, G.lx * 2, G.ly,
     5247          Mini.Canvas.Handle, 0, 0, SRCCOPY);
     5248        if ywmax <= 0 then
     5249          Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (2 * xxt),
     5250            yMini + 2, xMini + 1 + G.lx + MapWidth div (2 * xxt),
     5251            yMini + 2 + G.ly - 1, MainTexture.clMark, MainTexture.clMark)
     5252        else
     5253          Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (2 * xxt),
     5254            yMini + 2 + yw, xMini + 2 + G.lx + MapWidth div (2 * xxt) - 1,
     5255            yMini + 2 + yw + MapHeight div yyt - 2, MainTexture.clMark,
     5256            MainTexture.clMark);
     5257        RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini +
     5258          2, xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini
     5259          + 2 + G.ly)
     5260      end
     5261      else if MyMap[MouseLoc] and fCity <> 0 then { city clicked }
     5262      begin
     5263        if MyMap[MouseLoc] and (fOwned or fSpiedOut) <> 0 then
     5264        begin
     5265          ZoomToCity(MouseLoc);
     5266          DoCenter := false;
     5267        end
     5268        else
     5269        begin
     5270          UnitStatDlg.ShowNewContent_EnemyCity(wmPersistent, MouseLoc);
     5271          DoCenter := false;
     5272        end
     5273      end
     5274      else if MyMap[MouseLoc] and fUnit <> 0 then { unit clicked }
     5275        if MyMap[MouseLoc] and fOwned <> 0 then
     5276        begin
     5277          DoCenter := false;
     5278          if not supervising and (ClientMode < scContact) then
     5279          begin // not in negotiation mode
     5280            if (UnFocus >= 0) and (MyUn[UnFocus].Loc = MouseLoc) then
     5281            begin // rotate
     5282              uix := (UnFocus + 1) mod MyRO.nUn;
     5283              i := MyRO.nUn - 1;
     5284              while i > 0 do
     5285              begin
     5286                if (MyUn[uix].Loc = MouseLoc) and (MyUn[uix].Job = jNone) and
     5287                  (MyUn[uix].Status and (usStay or usRecover or usEnhance or
     5288                  usWaiting) = usWaiting) then
     5289                  Break;
     5290                dec(i);
     5291                uix := (uix + 1) mod MyRO.nUn;
     5292              end;
     5293              if i = 0 then
     5294                uix := UnFocus
     5295            end
     5296            else
     5297              Server(sGetDefender, me, MouseLoc, uix);
     5298            if uix <> UnFocus then
     5299              SetUnFocus(uix);
     5300            TurnComplete := false;
     5301            EOT.ButtonIndex := eotGray;
     5302          end;
     5303          SetTroopLoc(MouseLoc);
     5304          PanelPaint;
     5305        end // own unit
     5306        else if (MyMap[MouseLoc] and fSpiedOut <> 0) and not(ssCtrl in Shift)
     5307        then
     5308        begin
     5309          DoCenter := false;
     5310          SetTroopLoc(MouseLoc);
     5311          PanelPaint;
     5312        end
     5313        else
     5314        begin
     5315          DoCenter := false;
     5316          UnitStatDlg.ShowNewContent_EnemyLoc(wmPersistent, MouseLoc);
     5317        end;
     5318      if DoCenter then
     5319      begin
     5320        Centre(MouseLoc);
     5321        PaintAllMaps
     5322      end
     5323    end
     5324    else if (ClientMode <> cEditMap) and (Button = mbRight) and
     5325      not(ssShift in Shift) then
     5326    begin
     5327      if supervising then
     5328      begin
     5329        EditLoc := MouseLoc;
     5330        Server(sGetModels, me, 0, nil^);
     5331        EmptyMenu(mCreateUnit);
     5332        for p1 := 0 to nPl - 1 do
     5333          if 1 shl p1 and MyRO.Alive <> 0 then
     5334          begin
     5335            m := TMenuItem.Create(mCreateUnit);
     5336            m.Caption := Tribe[p1].TPhrase('SHORTNAME');
     5337            for emix := MyRO.nEnemyModel - 1 downto 0 do
     5338              if (MyRO.EnemyModel[emix].Owner = p1) and
     5339                (Server(sCreateUnit - sExecute + p1 shl 4, me,
     5340                MyRO.EnemyModel[emix].mix, MouseLoc) >= rExecuted) then
     5341              begin
     5342                if Tribe[p1].ModelPicture[MyRO.EnemyModel[emix].mix].HGr = 0
     5343                then
     5344                  InitEnemyModel(emix);
     5345                m2 := TMenuItem.Create(m);
     5346                m2.Caption := Tribe[p1].ModelName[MyRO.EnemyModel[emix].mix];
     5347                m2.Tag := p1 shl 16 + MyRO.EnemyModel[emix].mix;
     5348                m2.OnClick := CreateUnitClick;
     5349                m.Add(m2);
     5350              end;
     5351            m.Visible := m.Count > 0;
     5352            mCreateUnit.Add(m);
     5353          end;
     5354        if FullScreen then
     5355          EditPopup.Popup(Left + x, Top + y)
     5356        else
     5357          EditPopup.Popup(Left + x + 4,
     5358            Top + y + GetSystemMetrics(SM_CYCAPTION) + 4);
     5359      end
     5360      else if (UnFocus >= 0) and (MyUn[UnFocus].Loc <> MouseLoc) then
     5361        with MyUn[UnFocus] do
     5362        begin
     5363          dx := ((MouseLoc mod G.lx * 2 + MouseLoc div G.lx and 1) -
     5364            (Loc mod G.lx * 2 + Loc div G.lx and 1) + 3 * G.lx)
     5365            mod (2 * G.lx) - G.lx;
     5366          dy := MouseLoc div G.lx - Loc div G.lx;
     5367          if abs(dx) + abs(dy) < 3 then
     5368          begin
     5369            DestinationMarkON := false;
     5370            PaintDestination;
     5371            Status := Status and
     5372              ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
     5373            MoveUnit(dx, dy, muAutoNext) { simple move }
     5374          end
     5375          else if GetMoveAdvice(UnFocus, MouseLoc, MoveAdviceData) >= rExecuted
     5376          then
     5377          begin
     5378            if MyMap[MouseLoc] and (fUnit or fOwned) = fUnit then
     5379            begin // check for suicide mission before movement
     5380              with MyUn[UnFocus], BattleDlg.Forecast do
     5381              begin
     5382                pAtt := me;
     5383                mixAtt := mix;
     5384                HealthAtt := Health;
     5385                ExpAtt := Exp;
     5386                FlagsAtt := Flags;
     5387              end;
     5388              BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
     5389              if (Server(sGetBattleForecastEx, me, MouseLoc, BattleDlg.Forecast)
     5390                >= rExecuted) and (BattleDlg.Forecast.EndHealthAtt <= 0) then
     5391              begin
     5392                BattleDlg.uix := UnFocus;
     5393                BattleDlg.ToLoc := MouseLoc;
     5394                BattleDlg.IsSuicideQuery := true;
     5395                BattleDlg.ShowModal;
     5396                if BattleDlg.ModalResult <> mrOK then
     5397                  exit;
     5398              end
    17375399            end;
    1738       if (ClientMode<>cMovieTurn) and not supervising then
    1739         DiaDlg.ShowNewContent_Charts(wmModal);
    1740       end;
    1741 
    1742     // tell changes of own credibility
    1743     if not supervising then
    1744       begin
    1745       if RoughCredibility(MyRO.Credibility)
    1746         <>RoughCredibility(MyData.ToldOwnCredibility) then
    1747         begin
    1748         if RoughCredibility(MyRO.Credibility)
    1749           >RoughCredibility(MyData.ToldOwnCredibility) then
    1750           s:=Phrases.Lookup('CREDUP')
    1751         else s:=Phrases.Lookup('CREDDOWN');
    1752         TribeMessage(me, Format(s,[Phrases.Lookup('CREDIBILITY',
    1753           RoughCredibility(MyRO.Credibility))]), '');
    1754         end;
    1755       MyData.ToldOwnCredibility:=MyRO.Credibility;
    1756       end;
    1757 
    1758     for i:=0 to 27 do
    1759       begin
    1760       OwnWonder:=false;
    1761       for cix:=0 to MyRO.nCity-1 do
    1762         if (MyCity[cix].Loc>=0) and (MyCity[cix].ID=MyRO.Wonder[i].CityID) then
    1763           OwnWonder:=true;
    1764       if MyRO.Wonder[i].CityID<>MyData.ToldWonders[i].CityID then
    1765         begin
    1766         if MyRO.Wonder[i].CityID=-2 then with MessgExDlg do
    1767           begin {tell about destroyed wonders}
    1768           OpenSound:='WONDER_DESTROYED';
    1769           MessgText:=Format(Phrases.Lookup('WONDERDEST'),
    1770             [Phrases.Lookup('IMPROVEMENTS',i)]);
    1771           Kind:=mkOkHelp;
    1772           HelpKind:=hkImp;
    1773           HelpNo:=i;
    1774           IconKind:=mikImp;
    1775           IconIndex:=i;
    1776           ShowModal;
    1777           end
    1778         else
    1779           begin
    1780           if i=woManhattan then
    1781             if MyRO.Wonder[i].EffectiveOwner>me then
    1782               MyData.ColdWarStart:=MyRO.Turn-1
    1783             else MyData.ColdWarStart:=MyRO.Turn;
    1784           if not OwnWonder then with MessgExDlg do
    1785             begin {tell about newly built wonders}
    1786             if i=woManhattan then
    1787               begin
    1788               OpenSound:='MSG_COLDWAR';
    1789               s:=Tribe[MyRO.Wonder[i].EffectiveOwner].TPhrase('COLDWAR')
    1790               end
    1791             else if MyRO.Wonder[i].EffectiveOwner>=0 then
    1792               begin
    1793               OpenSound:='WONDER_BUILT';
    1794               s:=Tribe[MyRO.Wonder[i].EffectiveOwner].TPhrase('WONDERBUILT')
    1795               end
    1796             else
    1797               begin
    1798               OpenSound:='MSG_DEFAULT';
    1799               s:=Phrases.Lookup('WONDERBUILTEXP'); // already expired when built
    1800               end;
    1801             MessgText:=Format(s, [Phrases.Lookup('IMPROVEMENTS',i),
    1802               CityName(MyRO.Wonder[i].CityID)]);
    1803             Kind:=mkOkHelp;
    1804             HelpKind:=hkImp;
    1805             HelpNo:=i;
    1806             IconKind:=mikImp;
    1807             IconIndex:=i;
    1808             ShowModal;
    1809             end
     5400            DestinationMarkON := false;
     5401            PaintDestination;
     5402            Status := Status and not(usStay or usRecover or usEnhance) or
     5403              usWaiting;
     5404            MoveToLoc(MouseLoc, false); { goto }
    18105405          end
    18115406        end
    1812       else if (MyRO.Wonder[i].EffectiveOwner<>MyData.ToldWonders[i].EffectiveOwner)
    1813         and (MyRO.Wonder[i].CityID>-2) then
    1814         if MyRO.Wonder[i].EffectiveOwner<0 then
     5407    end
     5408    else if (Button = mbMiddle) and (UnFocus >= 0) and
     5409      (MyModel[MyUn[UnFocus].mix].Kind in [mkSettler, mkSlaves]) then
     5410    begin
     5411      DestinationMarkON := false;
     5412      PaintDestination;
     5413      MyUn[UnFocus].Status := MyUn[UnFocus].Status and
     5414        ($FFFF - usStay - usRecover - usGoto) or usEnhance;
     5415      uix := UnFocus;
     5416      if MouseLoc <> MyUn[uix].Loc then
     5417        MoveToLoc(MouseLoc, true); { goto }
     5418      if (UnFocus = uix) and (MyUn[uix].Loc = MouseLoc) then
     5419        MenuClick(mEnhance)
     5420    end
     5421    else if (Button = mbLeft) and (ssShift in Shift) and
     5422      (MyMap[MouseLoc] and fTerrain <> fUNKNOWN) then
     5423      HelpOnTerrain(MouseLoc, wmPersistent)
     5424    else if (ClientMode <= cContinue) and (Button = mbRight) and
     5425      (ssShift in Shift) and (UnFocus >= 0) and
     5426      (MyMap[MouseLoc] and (fUnit or fOwned) = fUnit) then
     5427    begin // battle forecast
     5428      with MyUn[UnFocus], BattleDlg.Forecast do
     5429      begin
     5430        pAtt := me;
     5431        mixAtt := mix;
     5432        HealthAtt := Health;
     5433        ExpAtt := Exp;
     5434        FlagsAtt := Flags;
     5435      end;
     5436      BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
     5437      if Server(sGetBattleForecastEx, me, MouseLoc, BattleDlg.Forecast) >= rExecuted
     5438      then
     5439      begin
     5440        BattleDlg.uix := UnFocus;
     5441        BattleDlg.ToLoc := MouseLoc;
     5442        BattleDlg.Left := x - BattleDlg.width div 2;
     5443        if BattleDlg.Left < 0 then
     5444          BattleDlg.Left := 0
     5445        else if BattleDlg.Left + BattleDlg.width > Screen.width then
     5446          BattleDlg.Left := Screen.width - BattleDlg.width;
     5447        BattleDlg.Top := y - BattleDlg.height div 2;
     5448        if BattleDlg.Top < 0 then
     5449          BattleDlg.Top := 0
     5450        else if BattleDlg.Top + BattleDlg.height > Screen.height then
     5451          BattleDlg.Top := Screen.height - BattleDlg.height;
     5452        BattleDlg.IsSuicideQuery := false;
     5453        BattleDlg.Show;
     5454      end
     5455    end
     5456  end;
     5457
     5458  function TMainScreen.MoveUnit(dx, dy: integer; Options: integer): integer;
     5459  // move focused unit to adjacent tile
     5460  var
     5461    i, cix, uix, euix, FromLoc, ToLoc, DirCode, UnFocus0, Defender, Mission, p1,
     5462      NewTiles, cixChanged: integer;
     5463    OldToTile: Cardinal;
     5464    CityCaptured, IsAttack, OldUnrest, NewUnrest, NeedEcoUpdate,
     5465      NeedRepaintPanel, ToTransport, ToShip: boolean;
     5466    PlaneReturnData: TPlaneReturnData;
     5467    QueryItem: string;
     5468  begin
     5469    result := eInvalid;
     5470    UnFocus0 := UnFocus;
     5471    FromLoc := MyUn[UnFocus].Loc;
     5472    ToLoc := dLoc(FromLoc, dx, dy);
     5473    if (ToLoc < 0) or (ToLoc >= G.lx * G.ly) then
     5474    begin
     5475      result := eInvalid;
     5476      exit;
     5477    end;
     5478    if MyMap[ToLoc] and fStealthUnit <> 0 then
     5479    begin
     5480      SoundMessage(Phrases.Lookup('ATTACKSTEALTH'), '');
     5481      exit;
     5482    end;
     5483    if MyMap[ToLoc] and fHiddenUnit <> 0 then
     5484    begin
     5485      SoundMessage(Phrases.Lookup('ATTACKSUB'), '');
     5486      exit;
     5487    end;
     5488
     5489    if MyMap[ToLoc] and (fUnit or fOwned) = fUnit then
     5490    begin // attack -- search enemy unit
     5491      if (MyModel[MyUn[UnFocus].mix].Attack = 0) and
     5492        not((MyModel[MyUn[UnFocus].mix].Cap[mcBombs] > 0) and
     5493        (MyUn[UnFocus].Flags and unBombsLoaded <> 0)) then
     5494      begin
     5495        SoundMessage(Phrases.Lookup('NOATTACKER'), '');
     5496        exit;
     5497      end;
     5498      euix := MyRO.nEnemyUn - 1;
     5499      while (euix >= 0) and (MyRO.EnemyUn[euix].Loc <> ToLoc) do
     5500        dec(euix);
     5501    end;
     5502
     5503    DirCode := dx and 7 shl 4 + dy and 7 shl 7;
     5504    result := Server(sMoveUnit - sExecute + DirCode, me, UnFocus, nil^);
     5505    if (result < rExecuted) and (MyUn[UnFocus].Job > jNone) then
     5506      Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
     5507    if (result < rExecuted) and (result <> eNoTime_Move) then
     5508    begin
     5509      case result of
     5510        eNoTime_Load:
     5511          if MyModel[MyUn[UnFocus].mix].Domain = dAir then
     5512            SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
     5513          else
     5514            SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
     5515              [MovementToString(MyModel[MyUn[UnFocus].mix].speed)]),
     5516              'NOMOVE_TIME');
     5517        eNoTime_Bombard:
     5518          SoundMessage(Phrases.Lookup('NOTIMEBOMBARD'), 'NOMOVE_TIME');
     5519        eNoTime_Expel:
     5520          SoundMessage(Phrases.Lookup('NOTIMEEXPEL'), 'NOMOVE_TIME');
     5521        eNoRoad:
     5522          SoundMessage(Phrases.Lookup('NOROAD'), 'NOMOVE_DEFAULT');
     5523        eNoNav:
     5524          SoundMessage(Phrases.Lookup('NONAV'), 'NOMOVE_DEFAULT');
     5525        eNoCapturer:
     5526          SoundMessage(Phrases.Lookup('NOCAPTURER'), 'NOMOVE_DEFAULT');
     5527        eNoBombarder:
     5528          SoundMessage(Phrases.Lookup('NOBOMBARDER'), 'NOMOVE_DEFAULT');
     5529        eZOC:
     5530          ContextMessage(Phrases.Lookup('ZOC'), 'NOMOVE_ZOC', hkText,
     5531            HelpDlg.TextIndex('MOVEMENT'));
     5532        eTreaty:
     5533          if MyMap[ToLoc] and (fUnit or fOwned) <> fUnit
     5534          then { no enemy unit -- move }
     5535            SoundMessage(Tribe[MyRO.Territory[ToLoc]].TPhrase('PEACE_NOMOVE'),
     5536              'NOMOVE_TREATY')
     5537          else
     5538            SoundMessage(Tribe[MyRO.EnemyUn[euix].Owner]
     5539              .TPhrase('PEACE_NOATTACK'), 'NOMOVE_TREATY');
     5540        eDomainMismatch:
    18155541          begin
    1816           if i<>woMir then with MessgExDlg do
    1817             begin {tell about expired wonders}
    1818             OpenSound:='WONDER_EXPIRED';
    1819             MessgText:=Format(Phrases.Lookup('WONDEREXP'),
    1820               [Phrases.Lookup('IMPROVEMENTS',i),
    1821               CityName(MyRO.Wonder[i].CityID)]);
    1822             Kind:=mkOkHelp;
    1823             HelpKind:=hkImp;
    1824             HelpNo:=i;
    1825             IconKind:=mikImp;
    1826             IconIndex:=i;
    1827             ShowModal;
     5542            if (MyModel[MyUn[UnFocus].mix].Domain < dSea) and
     5543              (MyMap[ToLoc] and (fUnit or fOwned) = fUnit or fOwned) then
     5544            begin // false load attempt
     5545              ToShip := false;
     5546              ToTransport := false;
     5547              for uix := 0 to MyRO.nUn - 1 do
     5548                if (MyUn[uix].Loc = ToLoc) and
     5549                  (MyModel[MyUn[uix].mix].Domain = dSea) then
     5550                begin
     5551                  ToShip := true;
     5552                  if MyModel[MyUn[uix].mix].Cap[mcSeaTrans] > 0 then
     5553                    ToTransport := true;
     5554                end;
     5555              if ToTransport then
     5556                SoundMessage(Phrases.Lookup('FULLTRANSPORT'), 'NOMOVE_DEFAULT')
     5557              else if ToShip then
     5558                SoundMessage(Phrases.Lookup('NOTRANSPORT'), 'NOMOVE_DEFAULT')
     5559              else
     5560                Play('NOMOVE_DOMAIN');
    18285561            end
     5562            else
     5563              Play('NOMOVE_DOMAIN');
    18295564          end
    1830         else if (MyData.ToldWonders[i].EffectiveOwner>=0) and not OwnWonder then
    1831           with MessgExDlg do
    1832             begin {tell about capture of wonders}
    1833             OpenSound:='WONDER_CAPTURED';
    1834             s:=Tribe[MyRO.Wonder[i].EffectiveOwner].TPhrase('WONDERCAPT');
    1835             MessgText:=Format(s, [Phrases.Lookup('IMPROVEMENTS',i),
    1836               CityName(MyRO.Wonder[i].CityID)]);
    1837             Kind:=mkOkHelp;
    1838             HelpKind:=hkImp;
    1839             HelpNo:=i;
    1840             IconKind:=mikImp;
    1841             IconIndex:=i;
    1842             ShowModal;
     5565      else
     5566        Play('NOMOVE_DEFAULT');
     5567      end;
     5568      exit;
     5569    end;
     5570
     5571    if ((result = eWon) or (result = eLost) or (result = eBloody)) and
     5572      (MyUn[UnFocus].Movement < 100) and
     5573      (MyModel[MyUn[UnFocus].mix].Cap[mcWill] = 0) then
     5574    begin
     5575      if SimpleQuery(mkYesNo, Format(Phrases.Lookup('FASTATTACK'),
     5576        [MyUn[UnFocus].Movement]), 'NOMOVE_TIME') <> mrOK then
     5577      begin
     5578        result := eInvalid;
     5579        exit;
     5580      end;
     5581      Update; // remove message box from screen
     5582    end;
     5583
     5584    OldUnrest := false;
     5585    NewUnrest := false;
     5586    if (result >= rExecuted) and (result and rUnitRemoved = 0) and
     5587      (MyMap[ToLoc] and (fUnit or fOwned) <> fUnit) then
     5588    begin
     5589      OldUnrest := UnrestAtLoc(UnFocus, FromLoc);
     5590      NewUnrest := UnrestAtLoc(UnFocus, ToLoc);
     5591      if NewUnrest > OldUnrest then
     5592      begin
     5593        if MyRO.Government = gDemocracy then
     5594        begin
     5595          QueryItem := 'UNREST_NOTOWN';
     5596          p1 := me;
     5597        end
     5598        else
     5599        begin
     5600          QueryItem := 'UNREST_FOREIGN';
     5601          p1 := MyRO.Territory[ToLoc];
     5602        end;
     5603        with MessgExDlg do
     5604        begin
     5605          MessgText := Format(Tribe[p1].TPhrase(QueryItem),
     5606            [Phrases.Lookup('GOVERNMENT', MyRO.Government)]);
     5607          Kind := mkYesNo;
     5608          IconKind := mikImp;
     5609          IconIndex := imPalace;
     5610          ShowModal;
     5611          if ModalResult <> mrOK then
     5612          begin
     5613            result := eInvalid;
     5614            exit;
     5615          end;
     5616        end;
     5617        Update; // remove message box from screen
     5618      end
     5619    end;
     5620
     5621    if (result >= rExecuted) and (MyModel[MyUn[UnFocus].mix].Domain = dAir) and
     5622      (MyUn[UnFocus].Status and usToldNoReturn = 0) then
     5623    begin // can plane return?
     5624      PlaneReturnData.Fuel := MyUn[UnFocus].Fuel;
     5625      if (MyMap[ToLoc] and (fUnit or fOwned) = fUnit) or
     5626        (MyMap[ToLoc] and (fCity or fOwned) = fCity) then
     5627      begin // attack/expel/bombard -> 100MP
     5628        PlaneReturnData.Loc := FromLoc;
     5629        PlaneReturnData.Movement := MyUn[UnFocus].Movement - 100;
     5630        if PlaneReturnData.Movement < 0 then
     5631          PlaneReturnData.Movement := 0;
     5632      end
     5633      else // move
     5634      begin
     5635        PlaneReturnData.Loc := ToLoc;
     5636        if dx and 1 <> 0 then
     5637          PlaneReturnData.Movement := MyUn[UnFocus].Movement - 100
     5638        else
     5639          PlaneReturnData.Movement := MyUn[UnFocus].Movement - 150;
     5640      end;
     5641      if Server(sGetPlaneReturn, me, UnFocus, PlaneReturnData) = eNoWay then
     5642      begin
     5643        if MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_Glider then
     5644          QueryItem := 'LOWFUEL_GLIDER'
     5645        else
     5646          QueryItem := 'LOWFUEL';
     5647        if SimpleQuery(mkYesNo, Phrases.Lookup(QueryItem), 'WARNING_LOWSUPPORT')
     5648          <> mrOK then
     5649        begin
     5650          result := eInvalid;
     5651          exit;
     5652        end;
     5653        Update; // remove message box from screen
     5654        MyUn[UnFocus].Status := MyUn[UnFocus].Status or usToldNoReturn;
     5655      end
     5656    end;
     5657
     5658    if result = eMissionDone then
     5659    begin
     5660      ModalSelectDlg.ShowNewContent(wmModal, kMission);
     5661      Update; // dialog still on screen
     5662      Mission := ModalSelectDlg.result;
     5663      if Mission < 0 then
     5664        exit;
     5665      Server(sSetSpyMission + Mission shl 4, me, 0, nil^);
     5666    end;
     5667
     5668    CityCaptured := false;
     5669    if result = eNoTime_Move then
     5670      Play('NOMOVE_TIME')
     5671    else
     5672    begin
     5673      NeedEcoUpdate := false;
     5674      DestinationMarkON := false;
     5675      PaintDestination;
     5676      if result and rUnitRemoved <> 0 then
     5677        CityOptimizer_BeforeRemoveUnit(UnFocus);
     5678      IsAttack := (result = eBombarded) or (result <> eMissionDone) and
     5679        (MyMap[ToLoc] and (fUnit or fOwned) = fUnit);
     5680      if not IsAttack then
     5681      begin // move
     5682        cix := MyRO.nCity - 1; { look for own city at dest location }
     5683        while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
     5684          dec(cix);
     5685        if (result <> eMissionDone) and (MyMap[ToLoc] and fCity <> 0) and
     5686          (cix < 0) then
     5687          CityCaptured := true;
     5688        result := Server(sMoveUnit + DirCode, me, UnFocus, nil^);
     5689        case result of
     5690          eHiddenUnit:
     5691            begin
     5692              Play('NOMOVE_SUBMARINE');
     5693              PaintLoc(ToLoc)
    18435694            end;
    1844       end;
    1845 
    1846     if MyRO.Turn=MyData.ColdWarStart+ColdWarTurns then
    1847       begin
    1848       SoundMessageEx(Phrases.Lookup('COLDWAREND'),'MSG_DEFAULT');
    1849       MyData.ColdWarStart:=-ColdWarTurns-1
    1850       end;
    1851 
    1852     TellNewModels;
    1853     end; // ClientMode<>cResume
    1854   MyData.ToldAlive:=MyRO.Alive;
    1855   move(MyRO.Wonder,MyData.ToldWonders,SizeOf(MyData.ToldWonders));
    1856 
    1857   NewGovAvailable:=-1;
    1858   if ClientMode<>cResume then
    1859     begin // tell about new techs
    1860     for ad:=0 to nAdv-1 do
    1861       if (MyRO.TestFlags and tfAllTechs=0)
    1862           and ((MyRO.Tech[ad]>=tsApplicable)<>(MyData.ToldTech[ad]>=tsApplicable))
    1863         or (ad in FutureTech ) and (MyRO.Tech[ad]<>MyData.ToldTech[ad]) then
    1864         with MessgExDlg do
    1865           begin
    1866           Item:='RESEARCH_GENERAL';
    1867           if GameMode<>cMovie then
    1868             OpenSound:='NEWADVANCE_'+char(48+Age);
    1869           Item2:=Phrases.Lookup('ADVANCES',ad);
    1870           if ad in FutureTech then Item2:=Item2+' '+IntToStr(MyRO.Tech[ad]);
    1871           MessgText:=Format(Phrases.Lookup(Item),[Item2]);
    1872           Kind:=mkOkHelp;
    1873           HelpKind:=hkAdv;
    1874           HelpNo:=ad;
    1875           IconKind:=mikBook;
    1876           IconIndex:=-1;
    1877           for i:=0 to nAdvBookIcon-1 do if AdvBookIcon[i].Adv=ad then
    1878             IconIndex:=AdvBookIcon[i].Icon;
    1879           ShowModal;
    1880           MyData.ToldTech[ad]:=MyRO.Tech[ad];
    1881           for i:=gMonarchy to nGov-1 do if GovPreq[i]=ad then
    1882             NewGovAvailable:=i;
    1883           end;
    1884     end;
    1885 
    1886   ShowCityList:=false;
    1887   if ClientMode=cTurn then
    1888     begin
    1889     if (MyRO.Happened and phTech<>0) and (MyData.FarTech<>adNexus) then
    1890       ChooseResearch;
    1891 
    1892     UpdatePanel:=false;
    1893     if MyRO.Happened and phChangeGov<>0 then
    1894       begin
    1895       ModalSelectDlg.ShowNewContent(wmModal,kGov);
    1896       Play('NEWGOV');
    1897       Server(sSetGovernment,me,ModalSelectDlg.result,nil^);
    1898       CityOptimizer_BeginOfTurn;
    1899       UpdatePanel:=true;
    1900       end;
    1901     end; // ClientMode=cTurn
    1902 
    1903   if not supervising and ((ClientMode=cTurn) or (ClientMode=cMovieTurn)) then
    1904     for cix:=0 to MyRO.nCity-1 do with MyCity[cix] do
    1905       Status:=Status and not csToldBombard;
    1906 
    1907   if ((ClientMode=cTurn) or (ClientMode=cMovieTurn))
    1908     and (MyRO.Government<>gAnarchy) then
    1909     begin
    1910     // tell what happened in cities
    1911     for WondersOnly:=true downto false do
    1912       for cix:=0 to MyRO.nCity-1 do with MyCity[cix] do
    1913         if (MyRO.Turn>0) and (Loc>=0) and (Flags and chCaptured=0)
    1914           and (WondersOnly=(Flags and chProduction<>0)
    1915             and (Project0 and cpImp<>0) and (Project0 and cpIndex<28)) then
    1916           begin
    1917           if WondersOnly then with MessgExDlg do
    1918             begin {tell about newly built wonder}
    1919             OpenSound:='WONDER_BUILT';
    1920             s:=Tribe[me].TPhrase('WONDERBUILTOWN');
    1921             MessgText:=Format(s, [Phrases.Lookup('IMPROVEMENTS',Project0 and cpIndex),
    1922               CityName(ID)]);
    1923             Kind:=mkOkHelp;
    1924             HelpKind:=hkImp;
    1925             HelpNo:=Project0 and cpIndex;
    1926             IconKind:=mikImp;
    1927             IconIndex:=Project0 and cpIndex;
    1928             ShowModal;
     5695          eStealthUnit:
     5696            begin
     5697              Play('NOMOVE_STEALTH');
     5698              PaintLoc(ToLoc)
    19295699            end;
    1930           if not supervising and (ClientMode=cTurn) then
     5700          eZOC_EnemySpotted:
    19315701            begin
    1932             AllowCityScreen:=true;
    1933             if (Status and 7<>0) and (Project and (cpImp+cpIndex)=cpImp+imTrGoods) then
    1934               if (MyData.ImpOrder[Status and 7-1,0]>=0) then
     5702              Play('NOMOVE_ZOC');
     5703              PaintLoc(ToLoc, 1)
     5704            end;
     5705          rExecuted .. maxint:
     5706            begin
     5707              if result and rUnitRemoved <> 0 then
     5708                UnFocus := -1 // unit died
     5709              else
     5710              begin
     5711                assert(UnFocus >= 0);
     5712                MyUn[UnFocus].Status := MyUn[UnFocus].Status and
     5713                  not(usStay or usRecover);
     5714                for uix := 0 to MyRO.nUn - 1 do
     5715                  if MyUn[uix].Master = UnFocus then
     5716                    MyUn[uix].Status := MyUn[uix].Status and not usWaiting;
     5717                if CityCaptured and
     5718                  (MyRO.Government in [gRepublic, gDemocracy, gFuture]) then
     5719                begin // borders have moved, unrest might have changed in any city
     5720                  CityOptimizer_BeginOfTurn;
     5721                  NeedEcoUpdate := true;
     5722                end
     5723                else
    19355724                begin
    1936                 if AutoBuild(cix,MyData.ImpOrder[Status and 7-1]) then
    1937                   AllowCityScreen:=false
    1938                 else if Flags and chProduction<>0 then
    1939                   Flags:=(Flags and not chProduction) or chAllImpsMade
    1940                 end
    1941               else Flags:=Flags or chTypeDel;
    1942             if (Size>=NeedAqueductSize) and (MyRO.Tech[Imp[imAqueduct].Preq]<tsApplicable)
    1943               or (Size>=NeedSewerSize) and (MyRO.Tech[Imp[imSewer].Preq]<tsApplicable) then
    1944               Flags:=Flags and not chNoGrowthWarning; // don't remind of unknown building
    1945             if Flags and chNoSettlerProd=0 then
    1946               Status:=Status and not csToldDelay
    1947             else if Status and csToldDelay=0 then
    1948               Status:=Status or csToldDelay
    1949             else Flags:=Flags and not chNoSettlerProd;
    1950             if mRepScreens.Checked then
    1951               begin
    1952               if (Flags and CityRepMask<>0) and AllowCityScreen then
    1953                 begin {show what happened in cities}
    1954                 SetTroopLoc(MyCity[cix].Loc);
    1955                 MarkCityLoc:=MyCity[cix].Loc;
    1956                 PanelPaint;
    1957                 CityDlg.CloseAction:=None;
    1958                 CityDlg.ShowNewContent(wmModal, MyCity[cix].Loc, Flags and CityRepMask);
    1959                 UpdatePanel:=true;
    1960                 end
    1961               end
    1962             else {if mRepList.Checked then}
    1963               begin
    1964               if Flags and CityRepMask<>0 then
    1965                 ShowCityList:=true
    1966               end
    1967             end
    1968           end; {city loop}
    1969     end; // ClientMode=cTurn
    1970 
    1971   if ClientMode=cTurn then
    1972     begin
    1973     if NewGovAvailable>=0 then with MessgExDlg do
    1974       begin
    1975       MessgText:=Format(Phrases.Lookup('AUTOREVOLUTION'),
    1976         [Phrases.Lookup('GOVERNMENT',NewGovAvailable)]);
    1977       Kind:=mkYesNo;
    1978       IconKind:=mikPureIcon;
    1979       IconIndex:=6+NewGovAvailable;
    1980       ShowModal;
    1981       if ModalResult=mrOK then
    1982         begin
    1983         Play('REVOLUTION');
    1984         Server(sRevolution,me,0,nil^);
    1985         end
    1986       end;
    1987     end; // ClientMode=cTurn
    1988 
    1989   if (ClientMode=cTurn) or (ClientMode=cMovieTurn) then
    1990     begin
    1991     if MyRO.Happened and phGliderLost<>0 then
    1992       ContextMessage(Phrases.Lookup('GLIDERLOST'), 'MSG_DEFAULT', hkModel, 200);
    1993     if MyRO.Happened and phPlaneLost<>0 then
    1994       ContextMessage(Phrases.Lookup('PLANELOST'), 'MSG_DEFAULT', hkFeature,
    1995         mcFuel);
    1996     if MyRO.Happened and phPeaceEvacuation<>0 then
    1997       for p1:=0 to nPl-1 do if 1 shl p1 and MyData.PeaceEvaHappened<>0 then
    1998         SoundMessageEx(Tribe[p1].TPhrase('WITHDRAW'), 'MSG_DEFAULT');
    1999     if MyRO.Happened and phPeaceViolation<>0 then
    2000       for p1:=0 to nPl-1 do
    2001         if (1 shl p1 and MyRO.Alive<>0) and (MyRO.EvaStart[p1]=MyRO.Turn) then
    2002           SoundMessageEx(Format(Tribe[p1].TPhrase('VIOLATION'),
    2003             [TurnToString(MyRO.Turn+PeaceEvaTurns-1)]), 'MSG_WITHDRAW');
    2004     TellNewContacts;
    2005     end;
    2006 
    2007   if ClientMode=cMovieTurn then Update
    2008   else if ClientMode=cTurn then
    2009     begin
    2010     if UpdatePanel then UpdateViews;
    2011     Application.ProcessMessages;
    2012 
    2013     if not supervising then
    2014       for uix:=0 to MyRO.nUn-1 do with MyUn[uix] do if Loc>=0 then
    2015         begin
    2016         if Flags and unWithdrawn<>0 then Status:=0;
    2017         if Health=100 then
    2018           Status:=Status and not usRecover;
    2019         if (Master>=0) or UnitExhausted(uix) then
    2020           Status:=Status and not usWaiting
    2021         else Status:=Status or usWaiting;
    2022         CheckToldNoReturn(uix);
    2023         if Status and usGoto<>0 then
    2024           begin {continue multi-turn goto}
    2025           SetUnFocus(uix);
    2026           SetTroopLoc(Loc);
    2027           FocusOnLoc(TroopLoc,flRepaintPanel or flImmUpdate);
    2028           if Status shr 16=$7FFF then
    2029             MoveResult:=GetMoveAdvice(UnFocus,maNextCity,MoveAdviceData)
    2030           else MoveResult:=GetMoveAdvice(UnFocus,Status shr 16,MoveAdviceData);
    2031           if MoveResult>=rExecuted then
    2032             begin // !!! Shinkansen
    2033             MoveResult:=eOK;
    2034             ok:=true;
    2035             for i:=0 to MoveAdviceData.nStep-1 do
    2036               begin
    2037               Loc1:=dLoc(Loc,MoveAdviceData.dx[i],MoveAdviceData.dy[i]);
    2038               if (MyMap[Loc1] and (fCity or fOwned)=fCity) // don't capture cities during auto move
    2039                 or (MyMap[Loc1] and (fUnit or fOwned)=fUnit) then // don't attack during auto move
    2040                 begin ok:=false; Break end
    2041               else
    2042                 begin
    2043                 if (Loc1=MoveAdviceData.ToLoc) or (MoveAdviceData.ToLoc=maNextCity)
    2044                   and (MyMap[dLoc(Loc,MoveAdviceData.dx[i],MoveAdviceData.dy[i])] and fCity<>0) then
    2045                   MoveOptions:=muAutoNoWait
    2046                 else MoveOptions:=0;
    2047                 MoveResult:=MoveUnit(MoveAdviceData.dx[i],MoveAdviceData.dy[i],MoveOptions);
    2048                 if (MoveResult<rExecuted) or (MoveResult=eEnemySpotted) then
    2049                   begin ok:=false; Break end;
     5725                  if OldUnrest <> NewUnrest then
     5726                  begin
     5727                    CityOptimizer_CityChange(MyUn[UnFocus].Home);
     5728                    for uix := 0 to MyRO.nUn - 1 do
     5729                      if MyUn[uix].Master = UnFocus then
     5730                        CityOptimizer_CityChange(MyUn[uix].Home);
     5731                    NeedEcoUpdate := true;
     5732                  end;
     5733                  if (MyRO.Government = gDespotism) and
     5734                    (MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_TownGuard) then
     5735                  begin
     5736                    if MyMap[FromLoc] and fCity <> 0 then
     5737                    begin // town guard moved out of city in despotism -- reoptimize!
     5738                      cixChanged := MyRO.nCity - 1;
     5739                      while (cixChanged >= 0) and
     5740                        (MyCity[cixChanged].Loc <> FromLoc) do
     5741                        dec(cixChanged);
     5742                      assert(cixChanged >= 0);
     5743                      if cixChanged >= 0 then
     5744                      begin
     5745                        CityOptimizer_CityChange(cixChanged);
     5746                        NeedEcoUpdate := true;
     5747                      end;
     5748                    end;
     5749                    if (MyMap[ToLoc] and fCity <> 0) and not CityCaptured then
     5750                    begin // town guard moved into city in despotism -- reoptimize!
     5751                      cixChanged := MyRO.nCity - 1;
     5752                      while (cixChanged >= 0) and
     5753                        (MyCity[cixChanged].Loc <> ToLoc) do
     5754                        dec(cixChanged);
     5755                      assert(cixChanged >= 0);
     5756                      if cixChanged >= 0 then
     5757                      begin
     5758                        CityOptimizer_CityChange(cixChanged);
     5759                        NeedEcoUpdate := true;
     5760                      end
     5761                    end
     5762                  end
    20505763                end
    20515764              end;
    2052             Stop:=not ok or (Loc=MoveAdviceData.ToLoc)
    2053               or (MoveAdviceData.ToLoc=maNextCity) and (MyMap[Loc] and fCity<>0)
    2054             end
    2055           else
    2056             begin
    2057             MoveResult:=eOK;
    2058             Stop:=true;
    20595765            end;
    2060 
    2061           if MoveResult<>eDied then
    2062             if Stop then Status:=Status and ($FFFF-usGoto)
    2063             else Status:=Status and not usWaiting;
     5766        else
     5767          assert(false);
     5768        end;
     5769        SetTroopLoc(ToLoc);
     5770      end
     5771      else
     5772      begin { enemy unit -- attack }
     5773        if result = eBombarded then
     5774          Defender := MyRO.Territory[ToLoc]
     5775        else
     5776          Defender := MyRO.EnemyUn[euix].Owner;
     5777        { if MyRO.Treaty[Defender]=trCeaseFire then
     5778          if SimpleQuery(mkYesNo,Phrases.Lookup('FRCANCELQUERY_CEASEFIRE'),
     5779          'MSG_DEFAULT')<>mrOK then
     5780          exit; }
     5781        if (Options and muNoSuicideCheck = 0) and (result and rUnitRemoved <> 0)
     5782          and (result <> eMissionDone) then
     5783        begin // suicide query
     5784          with MyUn[UnFocus], BattleDlg.Forecast do
     5785          begin
     5786            pAtt := me;
     5787            mixAtt := mix;
     5788            HealthAtt := Health;
     5789            ExpAtt := Exp;
     5790            FlagsAtt := Flags;
    20645791          end;
    2065 
    2066         if Status and (usEnhance or usGoto)=usEnhance then
    2067           // continue terrain enhancement
     5792          BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
     5793          Server(sGetBattleForecastEx, me, ToLoc, BattleDlg.Forecast);
     5794          BattleDlg.uix := UnFocus;
     5795          BattleDlg.ToLoc := ToLoc;
     5796          BattleDlg.IsSuicideQuery := true;
     5797          BattleDlg.ShowModal;
     5798          if BattleDlg.ModalResult <> mrOK then
     5799            exit;
     5800        end;
     5801
     5802        cixChanged := -1;
     5803        if (result and rUnitRemoved <> 0) and (MyRO.Government = gDespotism) and
     5804          (MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_TownGuard) and
     5805          (MyMap[FromLoc] and fCity <> 0) then
     5806        begin // town guard died in city in despotism -- reoptimize!
     5807          cixChanged := MyRO.nCity - 1;
     5808          while (cixChanged >= 0) and (MyCity[cixChanged].Loc <> FromLoc) do
     5809            dec(cixChanged);
     5810          assert(cixChanged >= 0);
     5811        end;
     5812
     5813        for i := 0 to MyRO.nEnemyModel - 1 do
     5814          LostArmy[i] := MyRO.EnemyModel[i].Lost;
     5815        OldToTile := MyMap[ToLoc];
     5816        result := Server(sMoveUnit + DirCode, me, UnFocus, nil^);
     5817        nLostArmy := 0;
     5818        for i := 0 to MyRO.nEnemyModel - 1 do
     5819        begin
     5820          LostArmy[i] := MyRO.EnemyModel[i].Lost - LostArmy[i];
     5821          inc(nLostArmy, LostArmy[i])
     5822        end;
     5823        if result and rUnitRemoved <> 0 then
     5824        begin
     5825          UnFocus := -1;
     5826          SetTroopLoc(FromLoc);
     5827        end;
     5828        if (OldToTile and not MyMap[ToLoc] and fCity <> 0) and
     5829          (MyRO.Government in [gRepublic, gDemocracy, gFuture]) then
     5830        begin // city was destroyed, borders have moved, unrest might have changed in any city
     5831          CityOptimizer_BeginOfTurn;
     5832          NeedEcoUpdate := true;
     5833        end
     5834        else
     5835        begin
     5836          if cixChanged >= 0 then
    20685837          begin
    2069           MoveResult:=ProcessEnhancement(uix,MyData.EnhancementJobs);
    2070           if MoveResult<>eDied then
    2071             if MoveResult=eJobDone then Status:=Status and not usEnhance
    2072             else Status:=Status and not usWaiting;
    2073           end
    2074         end;
    2075     end; // ClientMode=cTurn
    2076 
    2077   HaveStrategyAdvice:= false;
    2078 //    (GameMode<>cMovie) and not supervising
    2079 //    and AdvisorDlg.HaveStrategyAdvice;
    2080   GoOnPhase:=true;
    2081   if supervising or (GameMode=cMovie) then
    2082     begin SetTroopLoc(-1); PaintAll end {supervisor}
    2083 {  else if (ClientMode=cTurn) and (MyRO.Turn=0) then
    2084     begin
    2085     SetUnFocus(0);
    2086     ZoomToCity(MyCity[0].Loc)
    2087     end}
    2088   else
    2089     begin
    2090     if ClientMode>=scContact then SetUnFocus(-1)
    2091     else NextUnit(-1,false);
    2092     if UnFocus<0 then
    2093       begin
    2094       UnStartLoc:=-1;
    2095       if IsMultiPlayerGame or (ClientMode=cResume) then
    2096         if MyRO.nCity>0 then FocusOnLoc(MyCity[0].Loc)
    2097         else FocusOnLoc(G.lx*G.ly div 2);
    2098       SetTroopLoc(-1);
    2099       PanelPaint
    2100       end;
    2101     if ShowCityList then
    2102       ListDlg.ShowNewContent(wmPersistent,kCityEvents);
    2103     end;
    2104   end;{InitTurn}
    2105 
    2106 var
    2107 i,j,p1,mix,ToLoc,AnimationSpeed,ShowMoveDomain,cix,ecix: integer;
    2108 Color: TColor;
    2109 Name,s: string;
    2110 TribeInfo: TTribeInfo;
    2111 mi: TModelInfo;
    2112 SkipTurn,IsAlpine,IsTreatyDeal: boolean;
    2113 
    2114 begin {>>>client}
    2115 case command of
    2116   cTurn,cResume,cContinue,cMovieTurn,scContact,scDipStart..scDipBreak:
    2117     begin
    2118     supervising:= G.Difficulty[NewPlayer]=0;
    2119     ArrangeMidPanel;
    2120     end
    2121   end; 
    2122 case Command of
    2123   cDebugMessage:
    2124     LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(@Data));
    2125 
    2126   cShowNego: with TShowNegoData(Data) do
    2127     begin
    2128     s:=Format('P%d to P%d: ',[pSender,pTarget]);
    2129     if (Action=scDipOffer) and (Offer.nDeliver+Offer.nCost>0) then
    2130       begin
    2131       s:=s+'Offer ';
    2132       for i:=0 to Offer.nDeliver+Offer.nCost-1 do
    2133         begin
    2134         if i=Offer.nDeliver then s:=s+' for '
    2135         else if i>0 then s:=s+'+';
    2136         case Offer.Price[i] and opMask of
    2137           opChoose: s:=s+'Price of choice';
    2138           opCivilReport: s:=s+'State report';
    2139           opMilReport: s:=s+'Military report';
    2140           opMap: s:=s+'Map';
    2141           opTreaty: s:=s+'Treaty';
    2142           opShipParts: s:=s+'Ship part';
    2143           opMoney: s:=s+InttoStr(Offer.Price[i] and $FFFFFF)+'o';
    2144           opTribute: s:=s+InttoStr(Offer.Price[i] and $FFFFFF)+'o tribute';
    2145           opTech: s:=s+Phrases.Lookup('ADVANCES', Offer.Price[i] and $FFFFFF);
    2146           opAllTech: s:=s+'All advances';
    2147           opModel: s:=s+Tribe[pSender].ModelName[Offer.Price[i] and $FFFFFF];
    2148           opAllModel: s:=s+'All models';
    2149           end
    2150         end;
    2151       LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(s));
    2152       end
    2153     else if Action=scDipAccept then
    2154       begin
    2155       s:=s+'--- ACCEPTED! ---';
    2156       LogDlg.Add(NewPlayer, G.RO[0].Turn, pchar(s));
    2157       end
    2158     end;
    2159 
    2160   cInitModule:
    2161     begin
    2162     Server:=TInitModuleData(Data).Server;
    2163     //AdvisorDlg.Init;
    2164     InitModule;
    2165     TInitModuleData(Data).DataSize:=SizeOf(TPersistentData);
    2166     TInitModuleData(Data).Flags:=aiThreaded;
    2167     end;
    2168 
    2169   cReleaseModule:
    2170     begin
    2171     SmallImp.Free;
    2172     UnusedTribeFiles.Free;
    2173     TribeNames.Free;
    2174     MainMap.Free;
    2175     IsoEngine.Done;
    2176     //AdvisorDlg.DeInit;
    2177     end;
    2178 
    2179   cHelpOnly,cStartHelp,cStartCredits:
    2180     begin
    2181     Age:=0;
    2182     if Command=cHelpOnly then
    2183       SetMainTextureByAge(-1);
    2184     Tribes.Init;
    2185     HelpDlg.UserLeft:=(Screen.Width-HelpDlg.Width) div 2;
    2186     HelpDlg.UserTop:=(Screen.Height-HelpDlg.Height) div 2;
    2187     HelpDlg.Difficulty:=0;
    2188     if Command=cStartCredits then
    2189       HelpDlg.ShowNewContent(wmModal, hkMisc, miscCredits)
    2190     else HelpDlg.ShowNewContent(wmModal, hkMisc, miscMain);
    2191     Tribes.Done;
    2192     end;
    2193 
    2194   cNewGame,cLoadGame,cMovie,cNewMap:
    2195     begin
    2196     {if (Command=cNewGame) or (Command=cLoadGame) then
    2197       AdvisorDlg.NewGame(Data);}
    2198     GenerateNames:=mNames.Checked;
    2199     GameOK:=true;
    2200     G:=TNewGameData(Data);
    2201     me:=-1;
    2202     pLogo:=-1;
    2203     ClientMode:=-1;
    2204     SetMapOptions;
    2205     IsoEngine.pDebugMap:=-1;
    2206     idle:=false;
    2207     FillChar(Jump,SizeOf(Jump),0);
    2208     if StartRunning then Jump[0]:=999999;
    2209     GameMode:=Command;
    2210     for i:=0 to nGrExt-1 do
    2211       FillChar(GrExt[i].pixUsed,GrExt[i].Data.Height div 49 *10,0);
    2212     IsoEngine.Reset;
    2213     Tribes.Init;
    2214     GetTribeList;
    2215     for p1:=0 to nPl-1 do if (G.RO[p1]<>nil) and (G.RO[p1].Data<>nil) then
    2216       with TPersistentData(G.RO[p1].Data^) do
    2217         begin
    2218         FarTech:=adNone;
    2219         FillChar(EnhancementJobs,SizeOf(EnhancementJobs),jNone);
    2220         FillChar(ImpOrder,SizeOf(ImpOrder),-1);
    2221         ColdWarStart:=-ColdWarTurns-1;
    2222         ToldAge:=-1;
    2223         ToldModels:=3;
    2224         ToldAlive:=0;
    2225         ToldContact:=0;
    2226         ToldOwnCredibility:=InitialCredibility;
    2227         for i:=0 to nPl-1 do if G.Difficulty[i]>0 then inc(ToldAlive,1 shl i);
    2228         PeaceEvaHappened:=0;
    2229         for i:=0 to 27 do with ToldWonders[i] do
    2230           begin CityID:=-1; EffectiveOwner:=-1 end;
    2231         FillChar(ToldTech,SizeOf(ToldTech),tsNA);
    2232         if G.Difficulty[p1]>0 then
    2233           SoundPreload(sbStart);
    2234         end;
    2235 
    2236     // arrange dialogs
    2237     ListDlg.UserLeft:=8;
    2238     ListDlg.UserTop:=TopBarHeight+8;
    2239     HelpDlg.UserLeft:=Screen.Width-HelpDlg.Width-8;
    2240     HelpDlg.UserTop:=TopBarHeight+8;
    2241     UnitStatDlg.UserLeft:=397;
    2242     UnitStatDlg.UserTop:=TopBarHeight+64;
    2243     DiaDlg.UserLeft:=(Screen.Width-DiaDlg.Width) div 2;
    2244     DiaDlg.UserTop:=(Screen.Height-DiaDlg.Height) div 2;
    2245     NatStatDlg.UserLeft:=Screen.Width-NatStatDlg.Width-8;
    2246     NatStatDlg.UserTop:=Screen.Height-PanelHeight-NatStatDlg.Height-8;
    2247     if NatStatDlg.UserTop<8 then
    2248       NatStatDlg.UserTop:=8;
    2249 
    2250     Age:=0;
    2251     MovieSpeed:=1;
    2252     LogDlg.mSlot.Visible:=true;
    2253     LogDlg.Host:=self;
    2254     HelpDlg.ClearHistory;
    2255     CityDlg.Reset;
    2256 
    2257     Mini.Width:=G.lx*2; Mini.Height:=G.ly;
    2258     for i:=0 to nPl-1 do
    2259       begin Tribe[i]:=nil; TribeOriginal[i]:=false; end;
    2260     ToldSlavery:=-1;
    2261     RepaintOnResize:=false;
    2262     Closable:=false;
    2263     FirstMovieTurn:=true;
    2264 
    2265     MenuArea.Visible:= GameMode<>cMovie;
    2266     TreasuryArea.Visible:= GameMode<cMovie;
    2267     ResearchArea.Visible:= GameMode<cMovie;
    2268     ManagementArea.Visible:= GameMode<cMovie;
    2269     end;
    2270 
    2271   cGetReady,cReplay: if NewPlayer=0 then
    2272     begin
    2273     i:=0;
    2274     for p1:=0 to nPl-1 do
    2275       if (G.Difficulty[p1]>0) and (Tribe[p1]=nil) then inc(i);
    2276     if i>UnusedTribeFiles.Count then
    2277       begin
    2278       GameOK:=false;
    2279       SimpleMessage(Phrases.Lookup('TOOFEWTRIBES'));
    2280       end
    2281     else
    2282       begin
    2283       for p1:=0 to nPl-1 do
    2284         if (G.Difficulty[p1]>0) and (Tribe[p1]=nil) and (G.RO[p1]<>nil) then
    2285           begin // let player select own tribes
    2286           TribeInfo.trix:=p1;
    2287           TribeNames.Clear;
    2288           for j:=0 to UnusedTribeFiles.Count-1 do
    2289             begin
    2290             GetTribeInfo(UnusedTribeFiles[j], Name, Color);
    2291             TribeNames.AddObject(Name,TObject(Color));
    2292             end;
    2293           assert(TribeNames.Count>0);
    2294           ModalSelectDlg.ShowNewContent(wmModal,kTribe);
    2295           Application.ProcessMessages;
    2296           TribeInfo.FileName:=UnusedTribeFiles[ModalSelectDlg.result];
    2297           UnusedTribeFiles.Delete(ModalSelectDlg.result);
    2298 
    2299           if GameMode=cLoadGame then
    2300             CreateTribe(TribeInfo.trix,TribeInfo.FileName,false)
    2301           else Server(cSetTribe+(Length(TribeInfo.FileName)+1+7) div 4,
    2302             0,0,TribeInfo);
     5838            CityOptimizer_CityChange(cixChanged);
     5839            NeedEcoUpdate := true;
    23035840          end;
    2304 
    2305       for p1:=0 to nPl-1 do
    2306         if (G.Difficulty[p1]>0) and (Tribe[p1]=nil) and (G.RO[p1]=nil) then
    2307           begin // autoselect enemy tribes
    2308           j:=ChooseUnusedTribe;
    2309           TribeInfo.FileName:=UnusedTribeFiles[j];
    2310           UnusedTribeFiles.Delete(j);
    2311           TribeInfo.trix:=p1;
    2312           if GameMode=cLoadGame then
    2313             CreateTribe(TribeInfo.trix,TribeInfo.FileName,false)
    2314           else Server(cSetTribe+(Length(TribeInfo.FileName)+1+7) div 4,
    2315             0,0,TribeInfo);
     5841          if (result = eWon) or (result = eBloody) or (result = eExpelled) then
     5842          begin
     5843            CityOptimizer_TileBecomesAvailable(ToLoc);
     5844            NeedEcoUpdate := true;
    23165845          end;
    2317       end;
    2318     if not mNames.Checked then
    2319       for p1:=0 to nPl-1 do if Tribe[p1]<>nil then
    2320         Tribe[p1].NumberName:=p1;
    2321     end;
    2322 
    2323   cBreakGame:
    2324     begin
    2325     SaveSettings;
    2326     CityDlg.CloseAction:=None;
    2327     for i:=0 to Screen.FormCount-1 do
    2328       if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
    2329         Screen.Forms[i].Close;
    2330     if LogDlg.Visible then LogDlg.Close;
    2331     LogDlg.List.Clear;
    2332     StartRunning:=not idle and (Jump[0]>0); // AI called Reload
    2333     me:=-1;
    2334     idle:=false;
    2335     ClientMode:=-1;
    2336     UnitInfoBtn.Visible:=false;
    2337     UnitBtn.Visible:=false;
    2338     TerrainBtn.Visible:=false;
    2339     MovieSpeed1Btn.Visible:=false;
    2340     MovieSpeed2Btn.Visible:=false;
    2341     MovieSpeed3Btn.Visible:=false;
    2342     MovieSpeed4Btn.Visible:=false;
    2343     EOT.Visible:=false;
    2344     for i:=0 to ControlCount-1 do if Controls[i] is TButtonC then
    2345       Controls[i].visible:=false;
    2346     InitPVSB(sb,0,1);
    2347     for p1:=0 to nPl-1 do if Tribe[p1]<>nil then Tribe[p1].Free;
    2348     Tribes.Done;
    2349     RepaintOnResize:=false;
    2350     Closable:=true; Close;
    2351     {if (GameMode=cNewGame) or (GameMode=cLoadGame) then
    2352       AdvisorDlg.BreakGame;}
    2353     end;
    2354 
    2355   cShowGame:
    2356     begin
    2357     with Panel.Canvas do
    2358       begin
    2359       Brush.Color:=$000000;
    2360       FillRect(Rect(0,0,Panel.Width,Panel.Height));
    2361       Brush.Style:=bsClear;
    2362       end;
    2363     with TopBar.Canvas do
    2364       begin
    2365       Brush.Color:=$000000;
    2366       FillRect(Rect(0,0,TopBar.Width,TopBar.Height));
    2367       Brush.Style:=bsClear;
    2368       end;
    2369     FormResize(nil); // place mini map correctly according to its size
    2370     Show;
    2371     Update;
    2372     RepaintOnResize:=true;
    2373     xw:=0; yw:=ywcenter;
    2374     if not StayOnTop_Ensured then
    2375       begin
    2376       StayOnTop_Ensured:=true;
    2377       CityDlg.StayOnTop_Workaround;
    2378       CityTypeDlg.StayOnTop_Workaround;
    2379       DiaDlg.StayOnTop_Workaround;
    2380       DraftDlg.StayOnTop_Workaround;
    2381       EnhanceDlg.StayOnTop_Workaround;
    2382       HelpDlg.StayOnTop_Workaround;
    2383       NatStatDlg.StayOnTop_Workaround;
    2384       NegoDlg.StayOnTop_Workaround;
    2385       ModalSelectDlg.StayOnTop_Workaround;
    2386       ListDlg.StayOnTop_Workaround;
    2387       UnitStatDlg.StayOnTop_Workaround;
    2388       WondersDlg.StayOnTop_Workaround;
    2389       RatesDlg.StayOnTop_Workaround;
    2390       end;
    2391     end;
    2392 
    2393   cShowTurnChange:
    2394     begin
    2395     if integer(data)>=0 then
    2396       begin
    2397       pLogo:=integer(data);
    2398       if G.RO[pLogo]=nil then
    2399         begin
    2400         if AILogo[pLogo]<>nil then
    2401           BitBlt(Canvas.Handle, (xRightPanel+10)-(16+64), ClientHeight-PanelHeight, 64,64,
    2402             AILogo[pLogo].Canvas.Handle,0,0,SRCCOPY);
    2403         end
    2404       end 
    2405     end;
    2406 
    2407   cTurn,cResume,cContinue:
    2408     if not GameOK then Server(sResign,NewPlayer,0,nil^)
    2409     else
    2410       begin
    2411       ClientMode:=Command;
    2412       pTurn:=NewPlayer;
    2413       pLogo:=NewPlayer;
    2414 
    2415       if Command=cResume then
    2416         begin // init non-original model pictures (maybe tribes not found)
    2417         for p1:=0 to nPl-1 do if G.RO[p1]<>nil then
     5846        end;
     5847        if nLostArmy > 1 then
     5848        begin
     5849          with MessgExDlg do
    24185850          begin
    2419           ItsMeAgain(p1);
    2420           for mix:=0 to MyRO.nModel-1 do
    2421             if Tribe[me].ModelPicture[mix].HGr=0 then
    2422               InitMyModel(mix, true);
    2423           end;
    2424         me:=-1;
    2425         end;
    2426 
    2427       if Jump[pTurn]>0 then
    2428         Application.ProcessMessages;
    2429       if Jump[pTurn]>0 then
    2430         if G.RO[NewPlayer].Happened and phGameEnd<>0 then Jump[pTurn]:=0
    2431         else dec(Jump[pTurn]);
    2432       SkipTurn:= Jump[pTurn]>0;
    2433       if SkipTurn then
    2434         begin
    2435         ItsMeAgain(NewPlayer);
    2436         MyData:=G.RO[NewPlayer].Data;
    2437         SetTroopLoc(-1);
    2438         MiniPaint;
    2439         InitAllEnemyModels; // necessary for correct replay
    2440         if not EndTurn(true) then SkipTurn:=false;
    2441         end;
    2442       if not SkipTurn then
    2443         begin
    2444         if ((ClientMode<scDipStart) or (ClientMode>scDipBreak))
    2445           and NegoDlg.Visible then
    2446           NegoDlg.Close;
    2447         skipped:=false; // always show my moves during my turn
    2448         idle:=true;
    2449         InitTurn(NewPlayer);
    2450         DipMem[me].pContact:=-1;
    2451   (*      if (me=0) and (MyRO.Alive and (1 shl me)=0)} then
    2452           begin
    2453           if SimpleQuery(Phrases.Lookup('RESIGN'))=mrIgnore then
    2454             Server(sResign,me,0,nil^)
    2455           else Server(sBreak,me,0,nil^)
    2456           end
    2457         else Play('TURNSTART');*)
    2458         end;
    2459       end;
    2460 
    2461   cMovieTurn:
    2462     begin
    2463     ClientMode:=Command;
    2464     pTurn:=NewPlayer;
    2465     pLogo:=-1;
    2466     skipped:=false; // always show my moves during my turn
    2467     idle:=true;
    2468     if FirstMovieTurn then
    2469       begin
    2470       CheckMovieSpeedBtnState;
    2471       FirstMovieTurn:=false;
    2472       end;
    2473     InitTurn(NewPlayer);
    2474     Application.ProcessMessages;
    2475     if MovieSpeed=4 then
    2476       begin
    2477       Sleep(75); // this break will ensure speed of fast forward does not depend on cpu speed
    2478       Application.ProcessMessages;
    2479       end
    2480     end;
    2481 
    2482   cMovieEndTurn:
    2483     begin
    2484     RememberPeaceViolation;
    2485     pTurn:=-1;
    2486     pLogo:=-1;
    2487     MapValid:=false;
    2488     ClientMode:=-1;
    2489     idle:=false;
    2490     skipped:=false;
    2491     end;
    2492 
    2493   cEditMap:
    2494     begin
    2495     ClientMode:=cEditMap;
    2496     SetMapOptions;
    2497     IsoEngine.pDebugMap:=-1;
    2498     ItsMeAgain(0);
    2499     MyData:=nil;
    2500     UnitInfoBtn.Visible:=false;
    2501     UnitBtn.Visible:=false;
    2502     TerrainBtn.Visible:=false;
    2503     MovieSpeed1Btn.Visible:=false;
    2504     MovieSpeed2Btn.Visible:=false;
    2505     MovieSpeed3Btn.Visible:=false;
    2506     MovieSpeed4Btn.Visible:=false;
    2507     EOT.Visible:=false;
    2508     HelpDlg.Difficulty:=0;
    2509     BrushType:=fGrass;
    2510     BrushLoc:=-1;
    2511     Edited:=false;
    2512     UnFocus:=-1;
    2513     MarkCityLoc:=-1;
    2514     Tracking:=false;
    2515     TurnComplete:=false;
    2516     MapValid:=false;
    2517     FormResize(nil); // calculate geometrics and paint all
    2518     SetTroopLoc(-1);
    2519     idle:=true
    2520     end;
    2521 
    2522 (*  cNewContact:
    2523     begin
    2524     end;
    2525 *)
    2526 
    2527   scContact:
    2528     begin
    2529     DipMem[NewPlayer].pContact:=integer(Data);
    2530     if Jump[NewPlayer]>0 then DipCall(scReject)
    2531     else
    2532       begin
    2533       ClientMode:=Command;
    2534       InitTurn(NewPlayer);
    2535       MyData.ToldContact:=MyData.ToldContact or (1 shl integer(Data));
    2536         // don't tell about new nation when already contacted by them
    2537       with MessgExDlg do
    2538         begin
    2539         OpenSound:='CONTACT_'+char(48+MyRO.EnemyReport[integer(Data)].Attitude);
    2540         MessgText:=Tribe[integer(Data)].TPhrase('FRCONTACT');
    2541         Kind:=mkYesNo;
    2542         IconKind:=mikTribe;
    2543         IconIndex:=integer(Data);
    2544         ShowModal;
    2545         if ModalResult=mrOK then
    2546           begin
    2547           NegoDlg.Respond;
    2548           DipMem[me].DeliveredPrices:=[];
    2549           DipMem[me].ReceivedPrices:=[];
    2550           DipCall(scDipStart)
    2551           end
    2552         else
    2553           begin
    2554           DipCall(scReject);
    2555           EndNego
     5851            Kind := mkOk;
     5852            IconKind := mikEnemyArmy;
     5853            MessgText := Tribe[Defender].TString(Phrases.Lookup('ARMYLOST',
     5854              MyRO.EnemyModel[MyRO.EnemyUn[euix].emix].Domain));
     5855            ShowModal;
    25565856          end
    25575857        end
    25585858      end;
    2559     end;
    2560 
    2561   scDipStart..scDipBreak:
    2562     begin
    2563     ClientMode:=Command;
    2564     InitTurn(NewPlayer);
    2565     if Command=scDipStart then
    2566       Play('CONTACT_'+char(48+MyRO.Attitude[DipMem[NewPlayer].pContact]))
    2567     else if Command=scDipCancelTreaty then
    2568       Play('CANCELTREATY')
    2569     else if Command=scDipOffer then
    2570       begin
    2571       ReceivedOffer:=TOffer(Data);
    2572       InitAllEnemyModels;
     5859      if result and rUnitRemoved <> 0 then
     5860      begin
     5861        CityOptimizer_AfterRemoveUnit;
     5862        ListDlg.RemoveUnit;
     5863        NeedEcoUpdate := true;
     5864      end;
     5865      if NeedEcoUpdate then
     5866      begin
     5867        UpdateViews(true);
     5868        Update
    25735869      end
    2574     else if Command=scDipAccept then
    2575       begin // remember delivered and received prices
    2576       for i:=0 to DipMem[me].SentOffer.nDeliver-1 do
    2577         include(DipMem[me].DeliveredPrices,DipMem[me].SentOffer.Price[i] shr 24);
    2578       for i:=0 to DipMem[me].SentOffer.nCost-1 do
    2579         include(DipMem[me].ReceivedPrices,
    2580           DipMem[me].SentOffer.Price[DipMem[me].SentOffer.nDeliver+i] shr 24);
    2581       IsTreatyDeal:=false;
    2582       for i:=0 to ReceivedOffer.nDeliver+ReceivedOffer.nCost-1 do
    2583         if DipMem[me].SentOffer.Price[i] and opMask=opTreaty then
    2584           IsTreatyDeal:=true;
    2585       if IsTreatyDeal then Play('NEWTREATY')
    2586       else Play('ACCEPTOFFER');
     5870    end;
     5871
     5872    if result = eMissionDone then
     5873    begin
     5874      p1 := MyRO.Territory[ToLoc];
     5875      case Mission of
     5876        smStealMap:
     5877          begin
     5878            MapValid := false;
     5879            PaintAllMaps
     5880          end;
     5881        smStealCivilReport:
     5882          TribeMessage(p1, Tribe[p1].TPhrase('DOSSIER_PREPARED'), '');
     5883        smStealMilReport:
     5884          ListDlg.ShowNewContent_MilReport(wmPersistent, p1);
    25875885      end;
    2588     NegoDlg.Start;
    2589     idle:=true
    2590     end;
    2591 
    2592   cShowCancelTreaty:
    2593     if not IsMultiPlayerGame then
    2594       begin
    2595       case G.RO[NewPlayer].Treaty[integer(data)] of
    2596         trPeace: s:=Tribe[integer(data)].TPhrase('FRCANCELBYREJECT_PEACE');
    2597         trFriendlyContact: s:=Tribe[integer(data)].TPhrase('FRCANCELBYREJECT_FRIENDLY');
    2598         trAlliance: s:=Tribe[integer(data)].TPhrase('FRCANCELBYREJECT_ALLIANCE');
    2599         end;
    2600       TribeMessage(integer(data), s, 'CANCELTREATY');
     5886    end;
     5887
     5888    if UnFocus >= 0 then
     5889      CheckToldNoReturn(UnFocus);
     5890
     5891    NeedRepaintPanel := false;
     5892    if result >= rExecuted then
     5893    begin
     5894      if CityCaptured and (MyMap[ToLoc] and fCity = 0) then
     5895      begin // city destroyed
     5896        for i := 0 to 27 do { tell about destroyed wonders }
     5897          if (MyRO.Wonder[i].CityID = -2) and
     5898            (MyData.ToldWonders[i].CityID <> -2) then
     5899            with MessgExDlg do
     5900            begin
     5901              if WondersDlg.Visible then
     5902                WondersDlg.SmartUpdateContent(false);
     5903              OpenSound := 'WONDER_DESTROYED';
     5904              MessgText := Format(Phrases.Lookup('WONDERDEST'),
     5905                [Phrases.Lookup('IMPROVEMENTS', i)]);
     5906              Kind := mkOkHelp;
     5907              HelpKind := hkImp;
     5908              HelpNo := i;
     5909              IconKind := mikImp;
     5910              IconIndex := i;
     5911              ShowModal;
     5912              MyData.ToldWonders[i] := MyRO.Wonder[i];
     5913            end
    26015914      end;
    2602 
    2603   cShowCancelTreatyByAlliance:
    2604     if idle and (NewPlayer=me) then
    2605       TribeMessage(integer(data), Tribe[integer(data)].TPhrase('FRENEMYALLIANCE'),
    2606         'CANCELTREATY');
    2607 
    2608   cShowSupportAllianceAgainst:
    2609     if not IsMultiPlayerGame and (Jump[0]=0) then
    2610       TribeMessage(integer(data) and $F,
    2611         Tribe[integer(data) and $F].TPhrase('FRMYALLIANCE1')
    2612           +' '+Tribe[integer(data) shr 4].TPhrase('FRMYALLIANCE2'),
    2613         'CANCELTREATY');
    2614 
    2615   cShowPeaceViolation:
    2616     if not IsMultiPlayerGame and (Jump[0]=0) then
    2617       TribeMessage(integer(data), Format(Tribe[integer(data)].TPhrase('EVIOLATION'),
    2618         [TurnToString(MyRO.Turn+PeaceEvaTurns-1)]), 'MSG_WITHDRAW');
    2619 
    2620   cShowEndContact: EndNego;
    2621 
    2622   cShowUnitChanged,cShowCityChanged,cShowAfterMove,cShowAfterAttack:
    2623     if (idle and (NewPlayer=me) or not idle and not skipped)
    2624       and not ((GameMode=cMovie) and (MovieSpeed=4)) then
    2625       begin
    2626       assert(NewPlayer=me);
    2627       if not idle or (GameMode=cMovie) then
    2628         Application.ProcessMessages;
    2629       if Command=cShowCityChanged then
    2630         begin
    2631         CurrentMoveInfo.DoShow:=false;
    2632         if idle then
    2633           CurrentMoveInfo.DoShow:=true
    2634         else if CurrentMoveInfo.IsAlly then
    2635           CurrentMoveInfo.DoShow:=not mAlNoMoves.Checked
    2636         else CurrentMoveInfo.DoShow:=not mEnNoMoves.Checked
     5915      if CityCaptured and (MyMap[ToLoc] and fCity <> 0) then
     5916      begin // city captured
     5917        ListDlg.AddCity;
     5918        for i := 0 to 27 do { tell about capture of wonders }
     5919          if MyRO.City[MyRO.nCity - 1].Built[i] > 0 then
     5920            with MessgExDlg do
     5921            begin
     5922              if WondersDlg.Visible then
     5923                WondersDlg.SmartUpdateContent(false);
     5924              OpenSound := 'WONDER_CAPTURED';
     5925              MessgText := Format(Tribe[me].TPhrase('WONDERCAPTOWN'),
     5926                [Phrases.Lookup('IMPROVEMENTS', i)]);
     5927              Kind := mkOkHelp;
     5928              HelpKind := hkImp;
     5929              HelpNo := i;
     5930              IconKind := mikImp;
     5931              IconIndex := i;
     5932              ShowModal;
     5933              MyData.ToldWonders[i] := MyRO.Wonder[i];
     5934            end;
     5935
     5936        if MyRO.Happened and phStealTech <> 0 then
     5937        begin { Temple of Zeus -- choose advance to steal }
     5938          ModalSelectDlg.ShowNewContent(wmModal, kStealTech);
     5939          Server(sStealTech, me, ModalSelectDlg.result, nil^);
     5940        end;
     5941        TellNewModels;
     5942
     5943        cix := MyRO.nCity - 1;
     5944        while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
     5945          dec(cix);
     5946        assert(cix >= 0);
     5947        MyCity[cix].Status := MyCity[cix].Status and
     5948          not csResourceWeightsMask or (3 shl 4);
     5949        // captured city, set to maximum growth
     5950        NewTiles := 1 shl 13; { exploit central tile only }
     5951        Server(sSetCityTiles, me, cix, NewTiles);
     5952      end
     5953      else
     5954        NeedRepaintPanel := true;
     5955    end;
     5956    TellNewContacts;
     5957
     5958    if (UnFocus >= 0) and (MyUn[UnFocus].Master >= 0) then
     5959      with MyUn[MyUn[UnFocus].Master] do
     5960        if Status and usStay <> 0 then
     5961        begin
     5962          Status := Status and not usStay;
     5963          if (Movement >= 100) and (Status and (usRecover or usGoto) = 0) then
     5964            Status := Status or usWaiting;
     5965        end;
     5966    if Options and (muAutoNoWait or muAutoNext) <> 0 then
     5967    begin
     5968      if (UnFocus >= 0) and ((result = eNoTime_Move) or UnitExhausted(UnFocus)
     5969        or (MyUn[UnFocus].Master >= 0) or
     5970        (MyModel[MyUn[UnFocus].mix].Domain = dAir) and
     5971        ((MyMap[MyUn[UnFocus].Loc] and fCity <> 0) { aircrafts stop in cities }
     5972        or (MyMap[MyUn[UnFocus].Loc] and fTerImp = tiBase))) then
     5973      begin
     5974        MyUn[UnFocus].Status := MyUn[UnFocus].Status and not usWaiting;
     5975        if Options and muAutoNext <> 0 then
     5976          if CityCaptured and (MyMap[ToLoc] and fCity <> 0) then
     5977          begin
     5978            UnFocus := -1;
     5979            PaintLoc(ToLoc); // don't show unit in city if not selected
     5980          end
     5981          else
     5982            NextUnit(UnStartLoc, true)
     5983      end
     5984      else if (UnFocus < 0) and (Options and muAutoNext <> 0) then
     5985        NextUnit(UnStartLoc, result <> eMissionDone);
     5986    end;
     5987
     5988    if NeedRepaintPanel and (UnFocus = UnFocus0) then
     5989      if IsAttack then
     5990        PanelPaint
     5991      else
     5992      begin
     5993        assert(result <> eMissionDone);
     5994        CheckTerrainBtnVisible;
     5995        FocusOnLoc(ToLoc, flRepaintPanel or flImmUpdate)
     5996      end;
     5997
     5998    if (result >= rExecuted) and CityCaptured and (MyMap[ToLoc] and fCity <> 0)
     5999    then
     6000      ZoomToCity(ToLoc, UnFocus < 0, chCaptured); // show captured city
     6001  end; // moveunit
     6002
     6003  procedure TMainScreen.MoveOnScreen(ShowMove: TShowMove;
     6004    Step0, Step1, nStep: integer; Restore: boolean = true);
     6005  var
     6006    ToLoc, xFromLoc, yFromLoc, xToLoc, yToLoc, xFrom, yFrom, xTo, yTo, xMin,
     6007      yMin, xRange, yRange, xw1, Step, xMoving, yMoving, yl,
     6008      SliceCount: integer;
     6009    UnitInfo: TUnitInfo;
     6010    Ticks0, Ticks: int64;
     6011  begin
     6012    Timer1.Enabled := false;
     6013    QueryPerformanceCounter(Ticks0);
     6014    with ShowMove do
     6015    begin
     6016      UnitInfo.Owner := Owner;
     6017      UnitInfo.mix := mix;
     6018      UnitInfo.Health := Health;
     6019      UnitInfo.Job := jNone;
     6020      UnitInfo.Flags := Flags;
     6021      if Owner <> me then
     6022        UnitInfo.emix := emix;
     6023
     6024      ToLoc := dLoc(FromLoc, dx, dy);
     6025      xToLoc := ToLoc mod G.lx;
     6026      yToLoc := ToLoc div G.lx;
     6027      xFromLoc := FromLoc mod G.lx;
     6028      yFromLoc := FromLoc div G.lx;
     6029      if xToLoc > xFromLoc + 2 then
     6030        xToLoc := xToLoc - G.lx
     6031      else if xToLoc < xFromLoc - 2 then
     6032        xToLoc := xToLoc + G.lx;
     6033
     6034      xw1 := xw + G.lx;
     6035      // ((xFromLoc-xw1)*2+yFromLoc and 1+1)*xxt+dx*xxt/2-MapWidth/2 -> min
     6036      while abs(((xFromLoc - xw1 + G.lx) * 2 + yFromLoc and 1 + 1) * xxt * 2 +
     6037        dx * xxt - MapWidth) < abs(((xFromLoc - xw1) * 2 + yFromLoc and 1 + 1) *
     6038        xxt * 2 + dx * xxt - MapWidth) do
     6039        dec(xw1, G.lx);
     6040
     6041      xTo := (xToLoc - xw1) * (xxt * 2) + yToLoc and 1 * xxt + (xxt - xxu);
     6042      yTo := (yToLoc - yw) * yyt + (yyt - yyu_anchor);
     6043      xFrom := (xFromLoc - xw1) * (xxt * 2) + yFromLoc and 1 * xxt +
     6044        (xxt - xxu);
     6045      yFrom := (yFromLoc - yw) * yyt + (yyt - yyu_anchor);
     6046      if xFrom < xTo then
     6047      begin
     6048        xMin := xFrom;
     6049        xRange := xTo - xFrom
     6050      end
     6051      else
     6052      begin
     6053        xMin := xTo;
     6054        xRange := xFrom - xTo
     6055      end;
     6056      if yFrom < yTo then
     6057      begin
     6058        yMin := yFrom;
     6059        yRange := yTo - yFrom
     6060      end
     6061      else
     6062      begin
     6063        yMin := yTo;
     6064        yRange := yFrom - yTo
     6065      end;
     6066      inc(xRange, xxt * 2);
     6067      inc(yRange, yyt * 3);
     6068
     6069      MainOffscreenPaint;
     6070      NoMap.SetOutput(Buffer);
     6071      NoMap.SetPaintBounds(0, 0, xRange, yRange);
     6072      for Step := 0 to abs(Step1 - Step0) do
     6073      begin
     6074        BitBlt(Buffer.Canvas.Handle, 0, 0, xRange, yRange,
     6075          offscreen.Canvas.Handle, xMin, yMin, SRCCOPY);
     6076        if Step1 <> Step0 then
     6077        begin
     6078          xMoving := xFrom +
     6079            Round((Step0 + Step * (Step1 - Step0) div abs(Step1 - Step0)) *
     6080            (xTo - xFrom) / nStep);
     6081          yMoving := yFrom +
     6082            Round((Step0 + Step * (Step1 - Step0) div abs(Step1 - Step0)) *
     6083            (yTo - yFrom) / nStep);
    26376084        end
    2638       else if Command=cShowUnitChanged then
    2639         begin
    2640         CurrentMoveInfo.DoShow:=false;
    2641         if idle then
    2642           CurrentMoveInfo.DoShow:=not mEffectiveMovesOnly.Checked
    2643         else if CurrentMoveInfo.IsAlly then
    2644           CurrentMoveInfo.DoShow:=not (mAlNoMoves.Checked or mAlEffectiveMovesOnly.Checked)
    2645         else CurrentMoveInfo.DoShow:=not (mEnNoMoves.Checked or mEnAttacks.Checked)
    2646         end;
    2647       // else keep DoShow from cShowMove/cShowAttack
    2648 
    2649       if CurrentMoveInfo.DoShow then
    2650         begin
    2651         if Command=cShowCityChanged then MapValid:=false;
    2652         FocusOnLoc(integer(Data),flImmUpdate);
    2653 //        OldUnFocus:=UnFocus;
    2654 //        UnFocus:=-1;
    2655         if Command=cShowAfterMove then
    2656           PaintLoc(integer(Data),CurrentMoveInfo.AfterMovePaintRadius) // show discovered areas
    2657         else PaintLoc(integer(Data),1);
    2658 //        UnFocus:=OldUnFocus;
    2659         if (Command=cShowAfterAttack) and (CurrentMoveInfo.AfterAttackExpeller>=0) then
     6085        else
     6086        begin
     6087          xMoving := xFrom;
     6088          yMoving := yFrom;
     6089        end;
     6090        NoMap.PaintUnit(xMoving - xMin, yMoving - yMin, UnitInfo, 0);
     6091        PaintBufferToScreen(xMin, yMin, xRange, yRange);
     6092
     6093        SliceCount := 0;
     6094        Ticks := Ticks0;
     6095        repeat
     6096          if (SliceCount = 0) or ((Ticks - Ticks0) * 12000 * (SliceCount + 1)
     6097            div SliceCount < MoveTime * PerfFreq) then
    26606098          begin
    2661           SoundMessageEx(Tribe[CurrentMoveInfo.AfterAttackExpeller].TPhrase('EXPEL'),'');
    2662           CurrentMoveInfo.AfterAttackExpeller:=-1;
    2663           Update; // remove message box from screen
     6099            if not idle or (GameMode = cMovie) then
     6100              Application.ProcessMessages;
     6101            Sleep(1);
     6102            inc(SliceCount)
     6103          end;
     6104          QueryPerformanceCounter(Ticks);
     6105        until (Ticks - Ticks0) * 12000 >= MoveTime * PerfFreq;
     6106        Ticks0 := Ticks
     6107      end;
     6108    end;
     6109    if Restore then
     6110    begin
     6111      BitBlt(Buffer.Canvas.Handle, 0, 0, xRange, yRange,
     6112        offscreen.Canvas.Handle, xMin, yMin, SRCCOPY);
     6113      PaintBufferToScreen(xMin, yMin, xRange, yRange);
     6114    end;
     6115    BlinkTime := -1;
     6116    Timer1.Enabled := true;
     6117  end;
     6118
     6119  procedure TMainScreen.MoveToLoc(Loc: integer; CheckSuicide: boolean);
     6120  // path finder: move focused unit to loc, start multi-turn goto if too far
     6121  var
     6122    uix, i, MoveOptions, NextLoc, MoveResult: integer;
     6123    MoveAdviceData: TMoveAdviceData;
     6124    StopReason: (None, Arrived, Dead, NoTime, EnemySpotted, MoveError);
     6125  begin
     6126    if MyUn[UnFocus].Job > jNone then
     6127      Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
     6128    if GetMoveAdvice(UnFocus, Loc, MoveAdviceData) >= rExecuted then
     6129    begin
     6130      uix := UnFocus;
     6131      StopReason := None;
     6132      repeat
     6133        for i := 0 to MoveAdviceData.nStep - 1 do
     6134        begin
     6135          if i = MoveAdviceData.nStep - 1 then
     6136            MoveOptions := muAutoNext
     6137          else
     6138            MoveOptions := 0;
     6139          NextLoc := dLoc(MyUn[uix].Loc, MoveAdviceData.dx[i],
     6140            MoveAdviceData.dy[i]);
     6141          if (NextLoc = Loc) or (Loc = maNextCity) and
     6142            (MyMap[NextLoc] and fCity <> 0) then
     6143            StopReason := Arrived;
     6144          if not CheckSuicide and (NextLoc = Loc) then
     6145            MoveOptions := MoveOptions or muNoSuicideCheck;
     6146          MoveResult := MoveUnit(MoveAdviceData.dx[i], MoveAdviceData.dy[i],
     6147            MoveOptions);
     6148          if MoveResult < rExecuted then
     6149            StopReason := MoveError
     6150          else if MoveResult and rUnitRemoved <> 0 then
     6151            StopReason := Dead
     6152          else if (StopReason = None) and (MoveResult and rEnemySpotted <> 0)
     6153          then
     6154            StopReason := EnemySpotted;
     6155          if StopReason <> None then
     6156            Break;
     6157        end;
     6158        if (StopReason = None) and
     6159          ((MoveAdviceData.nStep < 25) or
     6160          (MyRO.Wonder[woShinkansen].EffectiveOwner <> me)) then
     6161          StopReason := NoTime;
     6162        if StopReason <> None then
     6163          Break;
     6164        if GetMoveAdvice(UnFocus, Loc, MoveAdviceData) < rExecuted then
     6165        begin
     6166          assert(false);
     6167          Break
     6168        end
     6169        until false;
     6170
     6171        case StopReason of
     6172          None:
     6173            assert(false);
     6174          Arrived:
     6175            MyUn[uix].Status := MyUn[uix].Status and ($FFFF - usGoto);
     6176          Dead:
     6177            if UnFocus < 0 then
     6178              NextUnit(UnStartLoc, false);
     6179        else
     6180          begin // multi-turn goto
     6181            if Loc = maNextCity then
     6182              MyUn[uix].Status := MyUn[uix].Status and
     6183                ($FFFF - usStay - usRecover) or usGoto + $7FFF shl 16
     6184            else
     6185              MyUn[uix].Status := MyUn[uix].Status and
     6186                ($FFFF - usStay - usRecover) or usGoto + Loc shl 16;
     6187            PaintLoc(MyUn[uix].Loc);
     6188            if (StopReason = NoTime) and (UnFocus = uix) then
     6189            begin
     6190              MyUn[uix].Status := MyUn[uix].Status and not usWaiting;
     6191              NextUnit(UnStartLoc, true)
     6192            end;
    26646193          end
    2665         else if not idle then
    2666           if Command=cShowCityChanged then
    2667             Sleep(MoveTime*WaitAfterShowMove div 16)
    2668           else if (Command=cShowUnitChanged)
    2669             and (MyMap[integer(Data)] and fUnit<>0) then
    2670             Sleep(MoveTime*WaitAfterShowMove div 32)
    2671         end // if CurrentMoveInfo.DoShow
    2672       else MapValid:=false;
     6194        end
     6195      end
     6196    end;
     6197
     6198    procedure TMainScreen.PanelBoxMouseDown(Sender: TObject;
     6199      Button: TMouseButton; Shift: TShiftState; x, y: integer);
     6200    var
     6201      i, xMouse, MouseLoc, p1: integer;
     6202    begin
     6203      if GameMode = cMovie then
     6204        exit;
     6205
     6206      if Button = mbLeft then
     6207      begin
     6208        if (x >= xMini + 2) and (y >= yMini + 2) and (x < xMini + 2 + 2 * G.lx)
     6209          and (y < yMini + 2 + G.ly) then
     6210          if ssShift in Shift then
     6211          begin
     6212            xMouse := (xwMini + (x - (xMini + 2) + MapWidth div (xxt * 2) +
     6213              G.lx) div 2) mod G.lx;
     6214            MouseLoc := xMouse + G.lx * (y - (yMini + 2));
     6215            if MyMap[MouseLoc] and fTerrain <> fUNKNOWN then
     6216            begin
     6217              p1 := MyRO.Territory[MouseLoc];
     6218              if (p1 = me) or (p1 >= 0) and (MyRO.Treaty[p1] >= trNone) then
     6219                NatStatDlg.ShowNewContent(wmPersistent, p1);
     6220            end
     6221          end
     6222          else
     6223          begin
     6224            if CityDlg.Visible then
     6225              CityDlg.Close;
     6226            if UnitStatDlg.Visible then
     6227              UnitStatDlg.Close;
     6228            Tracking := true;
     6229            PanelBoxMouseMove(Sender, Shift + [ssLeft], x, y);
     6230          end
     6231        else if (ClientMode <> cEditMap) and (x >= ClientWidth - xPalace) and
     6232          (y >= yPalace) and (x < ClientWidth - xPalace + xSizeBig) and
     6233          (y < yPalace + ySizeBig) then
     6234        begin
     6235          InitPopup(StatPopup);
     6236          if FullScreen then
     6237            StatPopup.Popup(Left + ClientWidth - xPalace + xSizeBig + 2,
     6238              Top + ClientHeight - PanelHeight + yPalace - 1)
     6239          else
     6240            StatPopup.Popup(Left + ClientWidth - xPalace + 6,
     6241              Top + ClientHeight - PanelHeight + yPalace + ySizeBig +
     6242              GetSystemMetrics(SM_CYCAPTION) + 3)
     6243        end
     6244        (* else if (x>=xAdvisor-3) and (y>=yAdvisor-3)
     6245          and (x<xAdvisor+16+3) and (y<yAdvisor+16+3) and HaveStrategyAdvice then
     6246          AdviceBtnClick *)
     6247        else if (x >= xTroop + 1) and (y >= yTroop + 1) and
     6248          (x < xTroop + TrRow * TrPitch) and (y <= yTroop + 55) then
     6249        begin
     6250          i := (x - xTroop - 1) div TrPitch;
     6251          if trix[i] >= 0 then
     6252            if ClientMode = cEditMap then
     6253            begin
     6254              BrushType := trix[i];
     6255              PanelPaint
     6256            end
     6257            else if (TroopLoc >= 0) then
     6258              if MyMap[TroopLoc] and fOwned <> 0 then
     6259              begin
     6260                if ssShift in Shift then
     6261                  UnitStatDlg.ShowNewContent_OwnModel(wmPersistent,
     6262                    MyUn[trix[i]].mix)
     6263                else if not supervising and (ClientMode < scContact) and
     6264                  (x - xTroop - 1 - i * TrPitch >= 60 - 20) and
     6265                  (y >= yTroop + 35) and
     6266                  ((MyUn[trix[i]].Job > jNone) or (MyUn[trix[i]].Status and
     6267                  (usStay or usRecover or usGoto) <> 0)) then
     6268                begin // wake up
     6269                  MyUn[trix[i]].Status := MyUn[trix[i]].Status and
     6270                    ($FFFF - usStay - usRecover - usGoto - usEnhance) or
     6271                    usWaiting;
     6272                  if MyUn[trix[i]].Job > jNone then
     6273                    Server(sStartJob + jNone shl 4, me, trix[i], nil^);
     6274                  if (UnFocus < 0) and not CityDlg.Visible then
     6275                  begin
     6276                    SetUnFocus(trix[i]);
     6277                    SetTroopLoc(MyUn[trix[i]].Loc);
     6278                    FocusOnLoc(TroopLoc, flRepaintPanel)
     6279                  end
     6280                  else
     6281                  begin
     6282                    if CityDlg.Visible and (CityDlg.RestoreUnFocus < 0) then
     6283                      CityDlg.RestoreUnFocus := trix[i];
     6284                    PanelPaint;
     6285                  end
     6286                end
     6287                else if (ClientMode < scContact) then
     6288                begin
     6289                  if supervising then
     6290                    UnitStatDlg.ShowNewContent_OwnUnit(wmPersistent, trix[i])
     6291                  else if CityDlg.Visible then
     6292                  begin
     6293                    CityDlg.CloseAction := None;
     6294                    CityDlg.Close;
     6295                    SumCities(TaxSum, ScienceSum);
     6296                    SetUnFocus(trix[i]);
     6297                  end
     6298                  else
     6299                  begin
     6300                    DestinationMarkON := false;
     6301                    PaintDestination;
     6302                    UnFocus := trix[i];
     6303                    UnStartLoc := TroopLoc;
     6304                    BlinkTime := 0;
     6305                    BlinkON := false;
     6306                    PaintLoc(TroopLoc);
     6307                  end;
     6308                  if UnFocus >= 0 then
     6309                  begin
     6310                    UnitInfoBtn.Visible := true;
     6311                    UnitBtn.Visible := true;
     6312                    TurnComplete := false;
     6313                    EOT.ButtonIndex := eotGray;
     6314                  end;
     6315                  CheckTerrainBtnVisible;
     6316                  PanelPaint;
     6317                end
     6318              end
     6319              else if Server(sGetUnits, me, TroopLoc, TrCnt) >= rExecuted then
     6320                if ssShift in Shift then
     6321                  UnitStatDlg.ShowNewContent_EnemyModel(wmPersistent,
     6322                    MyRO.EnemyUn[MyRO.nEnemyUn + trix[i]].emix) // model info
     6323                else
     6324                  UnitStatDlg.ShowNewContent_EnemyUnit(wmPersistent,
     6325                    MyRO.nEnemyUn + trix[i]); // unit info
     6326        end
     6327      end
     6328    end;
     6329
     6330    procedure TMainScreen.SetTroopLoc(Loc: integer);
     6331    var
     6332      trixFocus, uix, uixDefender: integer;
     6333      Prio: boolean;
     6334    begin
     6335      TroopLoc := Loc;
     6336      TrRow := (xRightPanel + 10 - xTroop - GetSystemMetrics(SM_CXVSCROLL) - 19)
     6337        div TrPitch;
     6338      TrCnt := 0;
     6339      trixFocus := -1;
     6340      if ClientMode = cEditMap then
     6341        TrCnt := nBrushTypes
     6342      else if (Loc >= 0) and (MyMap[Loc] and fUnit <> 0) then
     6343        if MyMap[Loc] and fOwned <> 0 then
     6344        begin // count own units here
     6345          Server(sGetDefender, me, TroopLoc, uixDefender);
     6346          for Prio := true downto false do
     6347            for uix := 0 to MyRO.nUn - 1 do
     6348              if ((uix = uixDefender) = Prio) and (MyUn[uix].Loc = Loc) then
     6349              begin
     6350                if uix = UnFocus then
     6351                  trixFocus := TrCnt;
     6352                inc(TrCnt);
     6353              end
     6354        end
     6355        else // count enemy units here
     6356          Server(sGetUnits, me, Loc, TrCnt);
     6357      if TrCnt = 0 then
     6358        InitPVSB(sb, 0, 1)
     6359      else
     6360      begin
     6361        InitPVSB(sb, (TrCnt + TrRow - 1) div TrRow - 1, 1);
     6362        with sb.si do
     6363          if (nMax >= integer(nPage)) and (trixFocus >= 0) then
     6364          begin
     6365            sb.si.npos := trixFocus div TrRow;
     6366            sb.si.FMask := SIF_POS;
     6367            SetScrollInfo(sb.h, SB_CTL, sb.si, true);
     6368          end
     6369      end
     6370    end;
     6371
     6372    (* procedure TMainScreen.ShowMoveHint(ToLoc: integer; Force: boolean = false);
     6373      var
     6374      Step,Loc,x0,y0,xs,ys: integer;
     6375      Info: string;
     6376      InfoSize: TSize;
     6377      MoveAdvice: TMoveAdviceData;
     6378      begin
     6379      if (ToLoc<0) or (ToLoc>=G.lx*G.ly)
     6380      or (UnFocus<0) or (MyUn[UnFocus].Loc=ToLoc) then
     6381      ToLoc:=-1
     6382      else
     6383      begin
     6384      MoveAdvice.ToLoc:=ToLoc;
     6385      MoveAdvice.MoreTurns:=0;
     6386      MoveAdvice.MaxHostile_MovementLeft:=MyUn[UnFocus].Health-50;
     6387      if Server(sGetMoveAdvice,me,UnFocus,MoveAdvice)<rExecuted then
     6388      ToLoc:=-1
    26736389      end;
    2674 
    2675   cShowMoving,cShowCapturing:
    2676     if (idle and (NewPlayer=me)
    2677       or not idle and not skipped and (TShowMove(Data).emix<>$FFFF))
    2678       and not ((GameMode=cMovie) and (MovieSpeed=4)) then
    2679       begin
    2680       assert(NewPlayer=me);
    2681       if not idle or (GameMode=cMovie) then
    2682         Application.ProcessMessages;
    2683       with TShowMove(Data) do
    2684         begin
    2685         CurrentMoveInfo.DoShow:=false;
    2686         if not idle and (Tribe[Owner].ModelPicture[mix].HGr=0) then
    2687           InitEnemyModel(emix);
    2688 
    2689         ToLoc:=dLoc(FromLoc,dx,dy);
    2690         if idle then
    2691           begin // own unit -- make discovered land visible
    2692           assert(Owner=me); // no foreign moves during my turn!
    2693           CurrentMoveInfo.DoShow:=not mEffectiveMovesOnly.Checked
    2694             or (Command=cShowCapturing);
    2695           if CurrentMoveInfo.DoShow then
     6390      if (ToLoc=MoveHintToLoc) and not Force then exit;
     6391      if (ToLoc<>MoveHintToLoc) and (MoveHintToLoc>=0) then
     6392      begin invalidate; update end; // clear old hint from screen
     6393      MoveHintToLoc:=ToLoc;
     6394      if ToLoc<0 then exit;
     6395
     6396      with canvas do
     6397      begin
     6398      Pen.Color:=$80C0FF;
     6399      Pen.Width:=3;
     6400      Loc:=MyUn[UnFocus].Loc;
     6401      for Step:=0 to MoveAdvice.nStep do
     6402      begin
     6403      y0:=(Loc+G.lx*1024) div G.lx -1024;
     6404      x0:=(Loc+(y0 and 1+G.lx*1024) div 2) mod G.lx;
     6405      xs:=(x0-xw)*66+y0 and 1*33-G.lx*66;
     6406      while abs(2*(xs+G.lx*66)-MapWidth)<abs(2*xs-MapWidth) do
     6407      inc(xs,G.lx*66);
     6408      ys:=(y0-yw)*16;
     6409      if Step=0 then moveto(xs+33,ys+16)
     6410      else lineto(xs+33,ys+16);
     6411      if Step<MoveAdvice.nStep then
     6412      Loc:=dLoc(Loc,MoveAdvice.dx[Step],MoveAdvice.dy[Step]);
     6413      end;
     6414      Brush.Color:=$80C0FF;
     6415      Info:=' '+inttostr(88)+' ';
     6416      InfoSize:=TextExtent(Info);
     6417      TextOut(xs+33-InfoSize.cx div 2, ys+16-InfoSize.cy div 2, Info);
     6418      Brush.Style:=bsClear;
     6419      end
     6420      end; *)
     6421
     6422    procedure TMainScreen.SetDebugMap(p: integer);
     6423    begin
     6424      IsoEngine.pDebugMap := p;
     6425      IsoEngine.Options := IsoEngine.Options and not(1 shl moLocCodes);
     6426      mLocCodes.Checked := false;
     6427      MapValid := false;
     6428      MainOffscreenPaint;
     6429    end;
     6430
     6431    procedure TMainScreen.SetViewpoint(p: integer);
     6432    var
     6433      i: integer;
     6434    begin
     6435      if supervising and (G.RO[0].Turn > 0) and
     6436        ((p = 0) or (1 shl p and G.RO[0].Alive <> 0)) then
     6437      begin
     6438        for i := 0 to Screen.FormCount - 1 do
     6439          if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
     6440          then
     6441            Screen.Forms[i].Close; // close windows
     6442        ItsMeAgain(p);
     6443        SumCities(TaxSum, ScienceSum);
     6444        for i := 0 to MyRO.nModel - 1 do
     6445          if Tribe[me].ModelPicture[i].HGr = 0 then
     6446            InitMyModel(i, true);
     6447
     6448        SetTroopLoc(-1);
     6449        PanelPaint;
     6450        MapValid := false;
     6451        PaintAllMaps;
     6452      end
     6453    end;
     6454
     6455    procedure TMainScreen.FormKeyDown(Sender: TObject; var Key: word;
     6456      Shift: TShiftState);
     6457
     6458      procedure MenuClick_Check(Popup: TPopupMenu; Item: TMenuItem);
     6459      begin
     6460        InitPopup(Popup);
     6461        if Item.Visible and Item.Enabled then
     6462          MenuClick(Item);
     6463      end;
     6464
     6465    var
     6466      dx, dy: integer;
     6467      time0, time1: int64;
     6468    begin
     6469      if GameMode = cMovie then
     6470      begin
     6471        case Key of
     6472          VK_F4:
     6473            MenuClick_Check(StatPopup, mScienceStat);
     6474          VK_F6:
     6475            MenuClick_Check(StatPopup, mDiagram);
     6476          VK_F7:
     6477            MenuClick_Check(StatPopup, mWonders);
     6478          VK_F8:
     6479            MenuClick_Check(StatPopup, mShips);
     6480        end;
     6481        exit;
     6482      end;
     6483
     6484      if not idle then
     6485        exit;
     6486
     6487      if ClientMode = cEditMap then
     6488      begin
     6489        if Shift = [ssCtrl] then
     6490          case char(Key) of
     6491            (* 'A':
     6492              begin // auto symmetry
     6493              Server($7F0,me,0,nil^);
     6494              MapValid:=false;
     6495              PaintAll;
     6496              end;
     6497              'B':
     6498              begin // land mass
     6499              dy:=0;
     6500              for dx:=G.lx to G.lx*(G.ly-1)-1 do
     6501              if MyMap[dx] and fTerrain>=fGrass then inc(dy);
     6502              dy:=dy
     6503              end; *)
     6504            'Q':
     6505              MenuClick(mResign);
     6506            'R':
     6507              MenuClick(mRandomMap);
     6508          end
     6509        else if Shift = [] then
     6510          case char(Key) of
     6511            char(VK_F1):
     6512              MenuClick(mHelp);
     6513          end;
     6514        exit;
     6515      end;
     6516
     6517      if Shift = [ssAlt] then
     6518        case char(Key) of
     6519          '0':
     6520            SetDebugMap(-1);
     6521          '1' .. '9':
     6522            SetDebugMap(ord(Key) - 48);
     6523        end
     6524      else if Shift = [ssCtrl] then
     6525        case char(Key) of
     6526          'J':
     6527            MenuClick(mJump);
     6528          'K':
     6529            mShowClick(mDebugMap);
     6530          'L':
     6531            mShowClick(mLocCodes);
     6532          'M':
     6533            if LogDlg.Visible then
     6534              LogDlg.Close
     6535            else
     6536              LogDlg.Show;
     6537          'N':
     6538            mNamesClick(mNames);
     6539          'Q':
     6540            MenuClick_Check(GamePopup, mResign);
     6541          'R':
     6542            MenuClick(mRun);
     6543          '0' .. '9':
    26966544            begin
    2697             if GameMode=cMovie then
     6545              if ord(Key) - 48 = me then
     6546                SetViewpoint(0)
     6547              else
     6548                SetViewpoint(ord(Key) - 48);
     6549            end;
     6550          ' ':
     6551            begin // test map repaint time
     6552              QueryPerformanceCounter(time0);
     6553              MapValid := false;
     6554              MainOffscreenPaint;
     6555              QueryPerformanceCounter(time1);
     6556              SimpleMessage(Format('Map repaint time: %.3f ms',
     6557                [{$IFDEF VER100}(time1.LowPart - time0.LowPart)
     6558{$ELSE}(time1 - time0){$ENDIF} * 1000.0 / PerfFreq]));
     6559            end
     6560        end
     6561      else if Shift = [] then
     6562        case char(Key) of
     6563          char(VK_F1):
     6564            MenuClick(mHelp);
     6565          char(VK_F2):
     6566            MenuClick_Check(StatPopup, mUnitStat);
     6567          char(VK_F3):
     6568            MenuClick_Check(StatPopup, mCityStat);
     6569          char(VK_F4):
     6570            MenuClick_Check(StatPopup, mScienceStat);
     6571          char(VK_F5):
     6572            MenuClick_Check(StatPopup, mEUnitStat);
     6573          char(VK_F6):
     6574            MenuClick_Check(StatPopup, mDiagram);
     6575          char(VK_F7):
     6576            MenuClick_Check(StatPopup, mWonders);
     6577          char(VK_F8):
     6578            MenuClick_Check(StatPopup, mShips);
     6579          char(VK_F9):
     6580            MenuClick_Check(StatPopup, mNations);
     6581          char(VK_F10):
     6582            MenuClick_Check(StatPopup, mEmpire);
     6583          char(VK_ADD):
     6584            EndTurn;
     6585          '1':
     6586            MapBtnClick(MapBtn0);
     6587          '2':
     6588            MapBtnClick(MapBtn1);
     6589          '3':
     6590            MapBtnClick(MapBtn4);
     6591          '4':
     6592            MapBtnClick(MapBtn5);
     6593          '5':
     6594            MapBtnClick(MapBtn6);
     6595          'T':
     6596            MenuClick(mTechTree);
     6597          'W':
     6598            MenuClick(mWait);
     6599        end;
     6600
     6601      if UnFocus >= 0 then
     6602        if Shift = [ssCtrl] then
     6603          case char(Key) of
     6604            'C':
     6605              MenuClick_Check(UnitPopup, mCancel);
     6606            'D':
     6607              MenuClick(mDisband);
     6608            'P':
     6609              MenuClick_Check(UnitPopup, mPillage);
     6610            'T':
     6611              MenuClick_Check(UnitPopup, mSelectTransport);
     6612          end
     6613        else if Shift = [] then
     6614          case char(Key) of
     6615            ' ':
     6616              MenuClick(mNoOrders);
     6617            'A':
     6618              MenuClick_Check(TerrainPopup, mAirBase);
     6619            'B':
     6620              MenuClick_Check(UnitPopup, mCity);
     6621            'C':
     6622              MenuClick(mCentre);
     6623            'E':
    26986624              begin
    2699               if MovieSpeed=3 then AnimationSpeed:=4
    2700               else if MovieSpeed=2 then AnimationSpeed:=8
    2701               else AnimationSpeed:=16;
     6625                InitPopup(TerrainPopup);
     6626                if mEnhance.Visible and mEnhance.Enabled then
     6627                  MenuClick(mEnhance)
     6628                else
     6629                  MenuClick(mEnhanceDef)
     6630              end;
     6631            'F':
     6632              MenuClick_Check(TerrainPopup, mFort);
     6633            'G':
     6634              MenuClick_Check(UnitPopup, mGoOn);
     6635            'H':
     6636              MenuClick_Check(UnitPopup, mHome);
     6637            'I':
     6638              if JobTest(UnFocus, jFarm, [eTreaty]) then
     6639                MenuClick(mFarm)
     6640              else if JobTest(UnFocus, jClear, [eTreaty]) then
     6641                MenuClick(mClear)
     6642              else
     6643                MenuClick_Check(TerrainPopup, mIrrigation);
     6644            'L':
     6645              MenuClick_Check(UnitPopup, mLoad);
     6646            'M':
     6647              if JobTest(UnFocus, jAfforest, [eTreaty]) then
     6648                MenuClick(mAfforest)
     6649              else
     6650                MenuClick_Check(TerrainPopup, mMine);
     6651            'N':
     6652              MenuClick_Check(TerrainPopup, mCanal);
     6653            'O':
     6654              MenuClick_Check(TerrainPopup, MTrans);
     6655            'P':
     6656              MenuClick_Check(TerrainPopup, mPollution);
     6657            'R':
     6658              if JobTest(UnFocus, jRR, [eTreaty]) then
     6659                MenuClick(mRR)
     6660              else
     6661                MenuClick_Check(TerrainPopup, mRoad);
     6662            'S':
     6663              MenuClick(mStay);
     6664            'U':
     6665              MenuClick_Check(UnitPopup, mUnload);
     6666            'V':
     6667              MenuClick_Check(UnitPopup, mRecover);
     6668            'Z':
     6669              MenuClick_Check(UnitPopup, mUtilize);
     6670            #33 .. #40, #97 .. #100, #102 .. #105:
     6671              begin { arrow keys }
     6672                DestinationMarkON := false;
     6673                PaintDestination;
     6674                MyUn[UnFocus].Status := MyUn[UnFocus].Status and
     6675                  ($FFFF - usStay - usRecover - usGoto - usEnhance) or
     6676                  usWaiting;
     6677                case Key of
     6678                  VK_NUMPAD1, VK_END:
     6679                    begin
     6680                      dx := -1;
     6681                      dy := 1
     6682                    end;
     6683                  VK_NUMPAD2, VK_DOWN:
     6684                    begin
     6685                      dx := 0;
     6686                      dy := 2
     6687                    end;
     6688                  VK_NUMPAD3, VK_NEXT:
     6689                    begin
     6690                      dx := 1;
     6691                      dy := 1
     6692                    end;
     6693                  VK_NUMPAD4, VK_LEFT:
     6694                    begin
     6695                      dx := -2;
     6696                      dy := 0
     6697                    end;
     6698                  VK_NUMPAD6, VK_RIGHT:
     6699                    begin
     6700                      dx := 2;
     6701                      dy := 0
     6702                    end;
     6703                  VK_NUMPAD7, VK_HOME:
     6704                    begin
     6705                      dx := -1;
     6706                      dy := -1
     6707                    end;
     6708                  VK_NUMPAD8, VK_UP:
     6709                    begin
     6710                      dx := 0;
     6711                      dy := -2
     6712                    end;
     6713                  VK_NUMPAD9, VK_PRIOR:
     6714                    begin
     6715                      dx := 1;
     6716                      dy := -1
     6717                    end;
     6718                end;
     6719                MoveUnit(dx, dy, muAutoNext)
     6720              end;
     6721          end
     6722    end;
     6723
     6724    procedure TMainScreen.MenuClick(Sender: TObject);
     6725
     6726      function DoJob(j0: integer): integer;
     6727      var
     6728        Loc0, Movement0: integer;
     6729      begin
     6730        with MyUn[UnFocus] do
     6731        begin
     6732          DestinationMarkON := false;
     6733          PaintDestination;
     6734          Loc0 := Loc;
     6735          Movement0 := Movement;
     6736          if j0 < 0 then
     6737            result := ProcessEnhancement(UnFocus, MyData.EnhancementJobs)
     6738            // terrain enhancement
     6739          else
     6740            result := Server(sStartJob + j0 shl 4, me, UnFocus, nil^);
     6741          if result >= rExecuted then
     6742          begin
     6743            if result = eDied then
     6744              UnFocus := -1;
     6745            PaintLoc(Loc0);
     6746            if UnFocus >= 0 then
     6747            begin
     6748              if (j0 < 0) and (result <> eJobDone) then
     6749              // multi-turn terrain enhancement
     6750                Status := Status and ($FFFF - usStay - usRecover - usGoto) or
     6751                  usEnhance
     6752              else
     6753                Status := Status and
     6754                  ($FFFF - usStay - usRecover - usGoto - usEnhance);
     6755              if (Job <> jNone) or (Movement0 < 100) then
     6756              begin
     6757                Status := Status and not usWaiting;
     6758                NextUnit(UnStartLoc, true);
    27026759              end
     6760              else
     6761                PanelPaint
     6762            end
    27036763            else
     6764              NextUnit(UnStartLoc, true);
     6765          end
     6766        end;
     6767        case result of
     6768          eNoBridgeBuilding:
     6769            SoundMessage(Phrases.Lookup('NOBB'), 'INVALID');
     6770          eNoCityTerrain:
     6771            SoundMessage(Phrases.Lookup('NOCITY'), 'INVALID');
     6772          eTreaty:
     6773            SoundMessage(Tribe[MyRO.Territory[Loc0]].TPhrase('PEACE_NOWORK'),
     6774              'NOMOVE_TREATY');
     6775        else
     6776          if result < rExecuted then
     6777            Play('INVALID')
     6778        end
     6779      end;
     6780
     6781    var
     6782      i, uix, NewFocus, Loc0, OldMaster, Destination, cix, cixOldHome,
     6783        ServerResult: integer;
     6784      AltGovs, Changed: boolean;
     6785      QueryText: string;
     6786
     6787    begin
     6788      if Sender = mResign then
     6789        if ClientMode = cEditMap then
     6790        begin
     6791          if Edited then
     6792          begin
     6793            QueryText := Phrases.Lookup('MAP_CLOSE');
     6794            case SimpleQuery(mkYesNoCancel, QueryText, '') of
     6795              mrIgnore:
     6796                Server(sAbandonMap, me, 0, nil^);
     6797              mrOK:
     6798                Server(sSaveMap, me, 0, nil^);
     6799            end
     6800          end
     6801          else
     6802            Server(sAbandonMap, me, 0, nil^)
     6803        end
     6804        else
     6805        begin
     6806          if Server(sGetGameChanged, 0, 0, nil^) = eOK then
     6807          begin
     6808            QueryText := Phrases.Lookup('RESIGN');
     6809            case SimpleQuery(mkYesNoCancel, QueryText, '') of
     6810              mrIgnore:
     6811                Server(sResign, 0, 0, nil^);
     6812              mrOK:
     6813                Server(sBreak, 0, 0, nil^)
     6814            end
     6815          end
     6816          else
     6817            Server(sResign, 0, 0, nil^)
     6818        end
     6819      else if Sender = mEmpire then
     6820        RatesDlg.ShowNewContent(wmPersistent)
     6821      else if Sender = mRevolution then
     6822      begin
     6823        AltGovs := false;
     6824        for i := 2 to nGov - 1 do
     6825          if (GovPreq[i] <> preNA) and
     6826            ((GovPreq[i] = preNone) or (MyRO.Tech[GovPreq[i]] >= tsApplicable))
     6827          then
     6828            AltGovs := true;
     6829
     6830        if not AltGovs then
     6831          SoundMessage(Phrases.Lookup('NOALTGOVS'), 'MSG_DEFAULT')
     6832        else
     6833        begin
     6834          Changed := false;
     6835          if MyRO.Happened and phChangeGov <> 0 then
     6836          begin
     6837            ModalSelectDlg.ShowNewContent(wmModal, kGov);
     6838            if ModalSelectDlg.result >= 0 then
     6839            begin
     6840              Play('NEWGOV');
     6841              Server(sSetGovernment, me, ModalSelectDlg.result, nil^);
     6842              CityOptimizer_BeginOfTurn;
     6843              Changed := true;
     6844            end
     6845          end
     6846          else
     6847            with MessgExDlg do
     6848            begin // revolution!
     6849              MessgText := Tribe[me].TPhrase('REVOLUTION');
     6850              Kind := mkYesNo;
     6851              IconKind := mikPureIcon;
     6852              IconIndex := 72; // anarchy palace
     6853              ShowModal;
     6854              if ModalResult = mrOK then
    27046855              begin
    2705               if mVeryFastMoves.Checked then AnimationSpeed:=4
    2706               else if mFastMoves.Checked then AnimationSpeed:=8
    2707               else AnimationSpeed:=16;
    2708               end;
    2709             with MyModel[mix] do
     6856                Play('REVOLUTION');
     6857                Server(sRevolution, me, 0, nil^);
     6858                Changed := true;
     6859                if NatStatDlg.Visible then
     6860                  NatStatDlg.Close;
     6861                if CityDlg.Visible then
     6862                  CityDlg.Close;
     6863              end
     6864            end;
     6865          if Changed then
     6866            UpdateViews(true);
     6867        end
     6868      end
     6869      else if Sender = mWebsite then
     6870        ShellExecute(Handle, 'open', 'http://c-evo.org', '', '', SW_SHOWNORMAL)
     6871      else if Sender = mRandomMap then
     6872      begin
     6873        if not Edited or (SimpleQuery(mkYesNo, Phrases.Lookup('MAP_RANDOM'), '')
     6874          = mrOK) then
     6875        begin
     6876          Server(sRandomMap, me, 0, nil^);
     6877          Edited := true;
     6878          MapValid := false;
     6879          PaintAllMaps;
     6880        end
     6881      end
     6882      else if Sender = mJump then
     6883      begin
     6884        if supervising then
     6885          Jump[0] := 20
     6886        else
     6887          Jump[me] := 20;
     6888        EndTurn(true);
     6889      end
     6890      else if Sender = mRun then
     6891      begin
     6892        if supervising then
     6893          Jump[0] := 999999
     6894        else
     6895          Jump[me] := 999999;
     6896        EndTurn(true);
     6897      end
     6898      else if Sender = mEnhanceDef then
     6899      begin
     6900        if UnFocus >= 0 then
     6901          EnhanceDlg.ShowNewContent(wmPersistent,
     6902            MyMap[MyUn[UnFocus].Loc] and fTerrain)
     6903        else
     6904          EnhanceDlg.ShowNewContent(wmPersistent)
     6905      end
     6906      else if Sender = mCityTypes then
     6907        CityTypeDlg.ShowNewContent(wmModal)
     6908        // must be modal because types are not saved before closing
     6909      else if Sender = mUnitStat then
     6910      begin
     6911        if G.Difficulty[me] > 0 then
     6912          ListDlg.ShowNewContent_MilReport(wmPersistent, me)
     6913        else
     6914        begin
     6915          i := 1;
     6916          while (i < nPl) and (1 shl i and MyRO.Alive = 0) do
     6917            inc(i);
     6918          if i < nPl then
     6919            ListDlg.ShowNewContent_MilReport(wmPersistent, i);
     6920        end;
     6921      end
     6922      else if Sender = mEUnitStat then
     6923      begin
     6924        if MyRO.nEnemyModel > 0 then
     6925          ListDlg.ShowNewContent(wmPersistent, kAllEModels);
     6926      end
     6927      else if Sender = mCityStat then
     6928        ListDlg.ShowNewContent(wmPersistent, kCities)
     6929      else if Sender = mScienceStat then
     6930        ListDlg.ShowNewContent(wmPersistent, kScience)
     6931      else if Sender = mNations then
     6932        NatStatDlg.ShowNewContent(wmPersistent)
     6933      else if Sender = mHelp then
     6934        if ClientMode = cEditMap then
     6935          HelpDlg.ShowNewContent(wmPersistent, hkText,
     6936            HelpDlg.TextIndex('MAPEDIT'))
     6937        else
     6938          HelpDlg.ShowNewContent(wmPersistent, hkMisc, miscMain)
     6939      else if Sender = mTechTree then
     6940        TechTreeDlg.ShowModal
     6941      else if Sender = mWonders then
     6942        WondersDlg.ShowNewContent(wmPersistent)
     6943      else if Sender = mDiagram then
     6944        DiaDlg.ShowNewContent_Charts(wmPersistent)
     6945      else if Sender = mShips then
     6946        DiaDlg.ShowNewContent_Ship(wmPersistent)
     6947      else if Sender = mWait then
     6948      begin
     6949        if UnFocus >= 0 then
     6950        begin
     6951          DestinationMarkON := false;
     6952          PaintDestination;
     6953          MyUn[UnFocus].Status := MyUn[UnFocus].Status and
     6954            ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
     6955        end;
     6956        NextUnit(-1, false);
     6957      end
     6958      else if UnFocus >= 0 then
     6959        with MyUn[UnFocus] do
     6960          if Sender = mGoOn then
     6961          begin
     6962            if Status shr 16 = $7FFF then
     6963              Destination := maNextCity
     6964            else
     6965              Destination := Status shr 16;
     6966            Status := Status and not(usStay or usRecover) or usWaiting;
     6967            MoveToLoc(Destination, true);
     6968          end
     6969          else if Sender = mHome then
     6970            if MyMap[Loc] and fCity <> 0 then
     6971            begin
     6972              cixOldHome := Home;
     6973              if Server(sSetUnitHome, me, UnFocus, nil^) >= rExecuted then
    27106974              begin
    2711               if (Kind=mkDiplomat) or (Domain=dAir)
    2712                 or (Cap[mcRadar]+Cap[mcCarrier]+Cap[mcAcademy]>0)
    2713                 or (MyMap[ToLoc] and fTerrain=fMountains)
    2714                 or (MyMap[ToLoc] and fTerImp=tiFort)
    2715                 or (MyMap[ToLoc] and fTerImp=tiBase) then
    2716                 CurrentMoveInfo.AfterMovePaintRadius:=2
    2717               else CurrentMoveInfo.AfterMovePaintRadius:=1;
    2718               if (MyRO.Wonder[woShinkansen].EffectiveOwner=me)
    2719                 and (Domain=dGround)
    2720                 and (MyMap[FromLoc] and (fRR or fCity)<>0)
    2721                 and (MyMap[ToLoc] and (fRR or fCity)<>0)
    2722                 and (Flags and umPlaneUnloading=0) then
    2723                 AnimationSpeed:=4;
    2724               ShowMoveDomain:=Domain;
    2725               IsAlpine:= Cap[mcAlpine]>0;
     6975                CityOptimizer_CityChange(cixOldHome);
     6976                CityOptimizer_CityChange(Home);
     6977                UpdateViews(true);
     6978              end
     6979              else
     6980                Play('INVALID');
     6981            end
     6982            else
     6983            begin
     6984              Status := Status and not(usStay or usRecover or usEnhance);
     6985              MoveToLoc(maNextCity, true)
     6986            end
     6987          else if Sender = mCentre then
     6988          begin
     6989            Centre(Loc);
     6990            PaintAllMaps
     6991          end
     6992          else if Sender = mCity then
     6993          begin
     6994            Loc0 := Loc;
     6995            if MyMap[Loc] and fCity = 0 then
     6996            begin // build city
     6997              if DoJob(jCity) = eCity then
     6998              begin
     6999                MapValid := false;
     7000                PaintAll;
     7001                ZoomToCity(Loc0, true, chFounded);
    27267002              end
    27277003            end
     7004            else
     7005            begin
     7006              CityOptimizer_BeforeRemoveUnit(UnFocus);
     7007              ServerResult := Server(sAddToCity, me, UnFocus, nil^);
     7008              if ServerResult >= rExecuted then
     7009              begin
     7010                cix := MyRO.nCity - 1;
     7011                while (cix >= 0) and (MyCity[cix].Loc <> Loc0) do
     7012                  dec(cix);
     7013                assert(cix >= 0);
     7014                CityOptimizer_CityChange(cix);
     7015                CityOptimizer_AfterRemoveUnit; // does nothing here
     7016                SetTroopLoc(Loc0);
     7017                UpdateViews(true);
     7018                DestinationMarkON := false;
     7019                PaintDestination;
     7020                UnFocus := -1;
     7021                PaintLoc(Loc0);
     7022                NextUnit(UnStartLoc, true);
     7023              end
     7024              else if ServerResult = eMaxSize then
     7025                SimpleMessage(Phrases.Lookup('ADDTOMAXSIZE'));
     7026            end
    27287027          end
     7028          else if Sender = mRoad then
     7029            DoJob(jRoad)
     7030          else if Sender = mRR then
     7031            DoJob(jRR)
     7032          else if Sender = mClear then
     7033            DoJob(jClear)
     7034          else if Sender = mIrrigation then
     7035            DoJob(jIrr)
     7036          else if Sender = mFarm then
     7037            DoJob(jFarm)
     7038          else if Sender = mAfforest then
     7039            DoJob(jAfforest)
     7040          else if Sender = mMine then
     7041            DoJob(jMine)
     7042          else if Sender = mCanal then
     7043            DoJob(jCanal)
     7044          else if Sender = MTrans then
     7045            DoJob(jTrans)
     7046          else if Sender = mFort then
     7047            DoJob(jFort)
     7048          else if Sender = mAirBase then
     7049            DoJob(jBase)
     7050          else if Sender = mPollution then
     7051            DoJob(jPoll)
     7052          else if Sender = mPillage then
     7053            DoJob(jPillage)
     7054          else if Sender = mEnhance then
     7055            DoJob(-1)
     7056          else if Sender = mStay then
     7057          begin
     7058            DestinationMarkON := false;
     7059            PaintDestination;
     7060            Status := Status and ($FFFF - usRecover - usGoto - usEnhance)
     7061              or usStay;
     7062            if Job > jNone then
     7063              Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
     7064            NextUnit(UnStartLoc, true)
     7065          end
     7066          else if Sender = mRecover then
     7067          begin
     7068            DestinationMarkON := false;
     7069            PaintDestination;
     7070            Status := Status and ($FFFF - usStay - usGoto - usEnhance) or
     7071              usRecover;
     7072            if Job > jNone then
     7073              Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
     7074            NextUnit(UnStartLoc, true)
     7075          end
     7076          else if Sender = mNoOrders then
     7077          begin
     7078            Status := Status and not usWaiting;
     7079            NextUnit(UnStartLoc, true)
     7080          end
     7081          else if Sender = mCancel then
     7082          begin
     7083            DestinationMarkON := false;
     7084            PaintDestination;
     7085            Status := Status and ($FFFF - usRecover - usGoto - usEnhance);
     7086            if Job > jNone then
     7087              Server(sStartJob + jNone shl 4, me, UnFocus, nil^);
     7088          end
     7089          else if (Sender = mDisband) or (Sender = mUtilize) then
     7090          begin
     7091            if (Sender = mUtilize) and
     7092              not(Server(sRemoveUnit - sExecute, me, UnFocus, nil^) = eUtilized)
     7093            then
     7094            begin
     7095              SimpleMessage(Phrases2.Lookup('SHIP_UTILIZE'));
     7096              // freight for colony ship is the only case in which the command is
     7097              // available to player though not valid
     7098              exit
     7099            end;
     7100            if (Sender = mUtilize) and (Health < 100) then
     7101              if SimpleQuery(mkYesNo, Phrases.Lookup('DAMAGED_UTILIZE'), '') <> mrOK
     7102              then
     7103                exit;
     7104            Loc0 := Loc;
     7105            CityOptimizer_BeforeRemoveUnit(UnFocus);
     7106            if Server(sRemoveUnit, me, UnFocus, nil^) = eUtilized then
     7107              Play('CITY_UTILIZE')
     7108            else
     7109              Play('DISBAND');
     7110            CityOptimizer_AfterRemoveUnit;
     7111            SetTroopLoc(Loc0);
     7112            UpdateViews(true);
     7113            DestinationMarkON := false;
     7114            PaintDestination;
     7115            UnFocus := -1;
     7116            PaintLoc(Loc0);
     7117            NextUnit(UnStartLoc, true);
     7118          end
     7119          else if Sender = mLoad then
     7120          begin
     7121            i := Server(sLoadUnit, me, UnFocus, nil^);
     7122            if i >= rExecuted then
     7123            begin
     7124              if MyModel[mix].Domain = dAir then
     7125                Play('MOVE_PLANELANDING')
     7126              else
     7127                Play('MOVE_LOAD');
     7128              DestinationMarkON := false;
     7129              PaintDestination;
     7130              Status := Status and
     7131                ($FFFF - usWaiting - usStay - usRecover - usGoto - usEnhance);
     7132              NextUnit(UnStartLoc, true);
     7133            end
     7134            else if i = eNoTime_Load then
     7135              if MyModel[mix].Domain = dAir then
     7136                SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
     7137              else
     7138                SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
     7139                  [MovementToString(MyModel[mix].speed)]), 'NOMOVE_TIME');
     7140          end
     7141          else if Sender = mUnload then
     7142            if Master >= 0 then
     7143            begin
     7144              OldMaster := Master;
     7145              i := Server(sUnloadUnit, me, UnFocus, nil^);
     7146              if i >= rExecuted then
     7147              begin
     7148                if MyModel[mix].Domain = dAir then
     7149                  Play('MOVE_PLANESTART')
     7150                else if (MyModel[MyUn[OldMaster].mix].Domain = dAir) and
     7151                  (MyMap[Loc] and fCity = 0) and
     7152                  (MyMap[Loc] and fTerImp <> tiBase) then
     7153                  Play('MOVE_PARACHUTE')
     7154                else
     7155                  Play('MOVE_UNLOAD');
     7156                Status := Status and not usWaiting;
     7157                if MyModel[mix].Domain <> dAir then
     7158                  NextUnit(Loc, true)
     7159                else
     7160                  PanelPaint
     7161              end
     7162              else if i = eNoTime_Load then
     7163                if MyModel[mix].Domain = dAir then
     7164                  SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
     7165                else
     7166                  SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
     7167                    [MovementToString(MyModel[mix].speed)]), 'NOMOVE_TIME');
     7168            end
     7169            else
     7170            begin
     7171              NewFocus := -1;
     7172              uix := UnFocus;
     7173              for i := 1 to MyRO.nUn - 1 do
     7174              begin
     7175                uix := (uix + MyRO.nUn - 1) mod MyRO.nUn;
     7176                if (MyUn[uix].Master = UnFocus) and
     7177                  (MyUn[uix].Movement = integer(MyModel[MyUn[uix].mix].speed))
     7178                then
     7179                begin
     7180                  MyUn[uix].Status := MyUn[uix].Status or usWaiting;
     7181                  NewFocus := uix
     7182                end;
     7183              end;
     7184              if NewFocus >= 0 then
     7185              begin
     7186                SetUnFocus(NewFocus);
     7187                SetTroopLoc(Loc);
     7188                PanelPaint
     7189              end
     7190            end
     7191          else if Sender = mSelectTransport then
     7192            Server(sSelectTransport, me, UnFocus, nil^)
     7193    end;
     7194
     7195    procedure TMainScreen.InitPopup(Popup: TPopupMenu);
     7196    var
     7197      i, p1, Tile, Test: integer;
     7198      NoSuper, extended, Multi, NeedSep, HaveCities: boolean;
     7199      LastSep, m: TMenuItem;
     7200      mox: ^TModel;
     7201    begin
     7202      NoSuper := not supervising and (1 shl me and MyRO.Alive <> 0);
     7203      HaveCities := false;
     7204      for i := 0 to MyRO.nCity - 1 do
     7205        if MyCity[i].Loc >= 0 then
     7206        begin
     7207          HaveCities := true;
     7208          Break
     7209        end;
     7210      if Popup = GamePopup then
     7211      begin
     7212        mTechTree.Visible := ClientMode <> cEditMap;
     7213        mResign.Enabled := supervising or (me = 0) and (ClientMode < scContact);
     7214        mRandomMap.Visible := (ClientMode = cEditMap) and
     7215          (Server(sMapGeneratorRequest, me, 0, nil^) = eOK);
     7216        mOptions.Visible := ClientMode <> cEditMap;
     7217        mManip.Visible := ClientMode <> cEditMap;
     7218        if ClientMode <> cEditMap then
     7219        begin
     7220          mWaitTurn.Visible := NoSuper;
     7221          mRep.Visible := NoSuper;
     7222          mRepList.Visible := NoSuper;
     7223          mRepScreens.Visible := NoSuper;
     7224          N10.Visible := NoSuper;
     7225          mOwnMovement.Visible := NoSuper;
     7226          mAllyMovement.Visible := NoSuper;
     7227          case SoundMode of
     7228            smOff:
     7229              mSoundOff.Checked := true;
     7230            smOn:
     7231              mSoundOn.Checked := true;
     7232            smOnAlt:
     7233              mSoundOnAlt.Checked := true;
     7234          end;
     7235
     7236          for i := 0 to nTestFlags - 1 do
     7237            mManip[i].Checked := MyRO.TestFlags and (1 shl i) <> 0;
     7238          mManip.Enabled := supervising or (me = 0);
     7239
     7240          Multi := false;
     7241          for p1 := 1 to nPl - 1 do
     7242            if G.RO[p1] <> nil then
     7243              Multi := true;
     7244          mEnemyMovement.Visible := not Multi;
     7245        end;
     7246        mMacro.Visible := NoSuper and (ClientMode < scContact);
     7247        if NoSuper and (ClientMode < scContact) then
     7248        begin
     7249          mCityTypes.Enabled := false;
     7250          // check if city types already usefull:
     7251          if MyRO.nCity > 0 then
     7252            for i := 28 to nImp - 1 do
     7253              if (i <> imTrGoods) and (Imp[i].Kind = ikCommon) and
     7254                (Imp[i].Preq <> preNA) and
     7255                ((Imp[i].Preq = preNone) or
     7256                (MyRO.Tech[Imp[i].Preq] >= tsApplicable)) then
     7257              begin
     7258                mCityTypes.Enabled := true;
     7259                Break
     7260              end;
     7261        end;
     7262        mViewpoint.Visible := (ClientMode <> cEditMap) and supervising;
     7263        mViewpoint.Enabled := G.RO[0].Turn > 0;
     7264        if supervising then
     7265        begin
     7266          EmptyMenu(mViewpoint);
     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(mViewpoint);
     7271              if p1 = 0 then
     7272                m.Caption := Phrases.Lookup('SUPER')
     7273              else
     7274                m.Caption := Tribe[p1].TString(Phrases2.Lookup('BELONG'));
     7275              m.Tag := p1;
     7276              m.OnClick := ViewpointClick;
     7277              if p1 < 10 then
     7278                m.ShortCut := ShortCut(48 + p1, [ssCtrl]);
     7279              m.RadioItem := true;
     7280              if p1 = me then
     7281                m.Checked := true;
     7282              mViewpoint.Add(m);
     7283            end
     7284        end;
     7285        mDebugMap.Visible := (ClientMode <> cEditMap) and supervising;
     7286        if supervising then
     7287        begin
     7288          EmptyMenu(mDebugMap);
     7289          for p1 := 0 to nPl - 1 do
     7290            if (p1 = 0) or (1 shl p1 and G.RO[0].Alive <> 0) then
     7291            begin
     7292              m := TMenuItem.Create(mDebugMap);
     7293              if p1 = 0 then
     7294                m.Caption := Phrases2.Lookup('MENU_DEBUGMAPOFF')
     7295              else
     7296                m.Caption := Tribe[p1].TString(Phrases2.Lookup('BELONG'));
     7297              if p1 = 0 then
     7298                m.Tag := -1
     7299              else
     7300                m.Tag := p1;
     7301              m.OnClick := DebugMapClick;
     7302              if p1 < 10 then
     7303                m.ShortCut := ShortCut(48 + p1, [ssAlt]);
     7304              m.RadioItem := true;
     7305              if m.Tag = IsoEngine.pDebugMap then
     7306                m.Checked := true;
     7307              mDebugMap.Add(m);
     7308            end
     7309        end;
     7310        mSmallTiles.Checked := xxt = 33;
     7311        mNormalTiles.Checked := xxt = 48;
     7312      end
     7313      else if Popup = StatPopup then
     7314      begin
     7315        mEmpire.Visible := NoSuper;
     7316        mEmpire.Enabled := MyRO.Government <> gAnarchy;
     7317        mRevolution.Visible := NoSuper;
     7318        mRevolution.Enabled := (MyRO.Government <> gAnarchy) and
     7319          (ClientMode < scContact);
     7320        mUnitStat.Enabled := NoSuper or (MyRO.Turn > 0);
     7321        mCityStat.Visible := 1 shl me and MyRO.Alive <> 0;
     7322        mCityStat.Enabled := HaveCities;
     7323        mScienceStat.Visible := true;
     7324        mScienceStat.Enabled := not NoSuper or (MyRO.ResearchTech >= 0) or
     7325          (MyRO.Happened and phTech <> 0) or (MyRO.Happened and phGameEnd <> 0)
     7326        // no researchtech in case just completed
     7327          or (MyRO.TestFlags and (tfAllTechs or tfUncover or
     7328          tfAllContact) <> 0);
     7329        mEUnitStat.Enabled := MyRO.nEnemyModel > 0;
     7330        { mWonders.Enabled:= false;
     7331          for i:=0 to 27 do if MyRO.Wonder[i].CityID<>-1 then
     7332          mWonders.Enabled:=true; }
     7333        mDiagram.Enabled := MyRO.Turn >= 2;
     7334        mShips.Enabled := false;
     7335        for p1 := 0 to nPl - 1 do
     7336          if MyRO.Ship[p1].Parts[spComp] + MyRO.Ship[p1].Parts[spPow] +
     7337            MyRO.Ship[p1].Parts[spHab] > 0 then
     7338            mShips.Enabled := true;
     7339      end
     7340      else if Popup = UnitPopup then
     7341      begin
     7342        mox := @MyModel[MyUn[UnFocus].mix];
     7343        Tile := MyMap[MyUn[UnFocus].Loc];
     7344        extended := Tile and fCity = 0;
     7345        if extended then
     7346        begin
     7347          mCity.Caption := Phrases.Lookup('BTN_FOUND');
     7348          mHome.Caption := Phrases.Lookup('BTN_MOVEHOME')
     7349        end
    27297350        else
     7351        begin
     7352          mCity.Caption := Phrases.Lookup('BTN_ADD');
     7353          mHome.Caption := Phrases.Lookup('BTN_SETHOME')
     7354        end;
     7355
     7356        extended := extended and
     7357          ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves) and
     7358          (MyRO.Wonder[woPyramids].EffectiveOwner >= 0)) and
     7359          (MyUn[UnFocus].Master < 0) and (Tile and fDeadLands = 0);
     7360        if (mox.Kind = mkFreight) and (Tile and fCity <> 0) and
     7361          not Phrases2FallenBackToEnglish or
     7362          (Server(sRemoveUnit - sExecute, me, UnFocus, nil^) = eUtilized) then
     7363        begin
     7364          mDisband.Visible := false;
     7365          mUtilize.Visible := true;
     7366          if mox.Kind = mkFreight then
     7367            mUtilize.Caption := Phrases.Lookup('UTILIZE')
     7368          else
     7369            mUtilize.Caption := Phrases.Lookup('INTEGRATE')
     7370        end
     7371        else
     7372        begin
     7373          mDisband.Visible := true;
     7374          mUtilize.Visible := false
     7375        end;
     7376        mGoOn.Visible := MyUn[UnFocus].Status and (usGoto or usWaiting)
     7377          = usGoto or usWaiting;
     7378        mHome.Visible := HaveCities;
     7379        mRecover.Visible := (MyUn[UnFocus].Health < 100) and
     7380          (Tile and fTerrain >= fGrass) and
     7381          ((MyRO.Wonder[woGardens].EffectiveOwner = me) or
     7382          (Tile and fTerrain <> fArctic) and (Tile and fTerrain <> fDesert)) and
     7383          not((mox.Domain = dAir) and (Tile and fCity = 0) and
     7384          (Tile and fTerImp <> tiBase));
     7385        mStay.Visible := not((mox.Domain = dAir) and (Tile and fCity = 0) and
     7386          (Tile and fTerImp <> tiBase));
     7387        mCity.Visible := extended and (mox.Kind = mkSettler) or
     7388          (Tile and fCity <> 0) and ((mox.Kind in [mkSettler, mkSlaves]) or
     7389          (MyUn[UnFocus].Flags and unConscripts <> 0));
     7390        mPillage.Visible := (Tile and (fRoad or fRR or fCanal or fTerImp) <> 0)
     7391          and (MyUn[UnFocus].Master < 0) and (mox.Domain = dGround);
     7392        mCancel.Visible := (MyUn[UnFocus].Job > jNone) or
     7393          (MyUn[UnFocus].Status and (usRecover or usGoto) <> 0);
     7394
     7395        Test := Server(sLoadUnit - sExecute, me, UnFocus, nil^);
     7396        mLoad.Visible := (Test >= rExecuted) or (Test = eNoTime_Load);
     7397        mUnload.Visible := (MyUn[UnFocus].Master >= 0) or
     7398          (MyUn[UnFocus].TroopLoad + MyUn[UnFocus].AirLoad > 0);
     7399        mSelectTransport.Visible := Server(sSelectTransport - sExecute, me,
     7400          UnFocus, nil^) >= rExecuted;
     7401      end
     7402      else { if Popup=TerrainPopup then }
     7403      begin
     7404        mox := @MyModel[MyUn[UnFocus].mix];
     7405        Tile := MyMap[MyUn[UnFocus].Loc];
     7406        extended := Tile and fCity = 0;
     7407
     7408        if (Tile and fRiver <> 0) and
     7409          (MyRO.Tech[adBridgeBuilding] >= tsApplicable) then
     7410        begin
     7411          mRoad.Caption := Phrases.Lookup('BTN_BUILDBRIDGE');
     7412          mRR.Caption := Phrases.Lookup('BTN_BUILDRRBRIDGE');
     7413        end
     7414        else
     7415        begin
     7416          mRoad.Caption := Phrases.Lookup('BTN_BUILDROAD');
     7417          mRR.Caption := Phrases.Lookup('BTN_BUILDRR');
     7418        end;
     7419        if Tile and fTerrain = fForest then
     7420          mClear.Caption := Phrases.Lookup('BTN_CLEAR')
     7421        else if Tile and fTerrain = fDesert then
     7422          mClear.Caption := Phrases.Lookup('BTN_UNDESERT')
     7423        else
     7424          mClear.Caption := Phrases.Lookup('BTN_DRAIN');
     7425
     7426        extended := extended and
     7427          ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves) and
     7428          (MyRO.Wonder[woPyramids].EffectiveOwner >= 0)) and
     7429          (MyUn[UnFocus].Master < 0);
     7430        if extended then
     7431        begin
     7432          mRoad.Visible := JobTest(UnFocus, jRoad,
     7433            [eNoBridgeBuilding, eTreaty]);
     7434          mRR.Visible := JobTest(UnFocus, jRR, [eNoBridgeBuilding, eTreaty]);
     7435          mClear.Visible := JobTest(UnFocus, jClear, [eTreaty]);
     7436          mIrrigation.Visible := JobTest(UnFocus, jIrr, [eTreaty]);
     7437          mFarm.Visible := JobTest(UnFocus, jFarm, [eTreaty]);
     7438          mAfforest.Visible := JobTest(UnFocus, jAfforest, [eTreaty]);
     7439          mMine.Visible := JobTest(UnFocus, jMine, [eTreaty]);
     7440          MTrans.Visible := JobTest(UnFocus, jTrans, [eTreaty]);
     7441          mCanal.Visible := JobTest(UnFocus, jCanal, [eTreaty]);
     7442          mFort.Visible := JobTest(UnFocus, jFort, [eTreaty]);
     7443          mAirBase.Visible := JobTest(UnFocus, jBase, [eTreaty]);
     7444          mPollution.Visible := JobTest(UnFocus, jPoll, [eTreaty]);
     7445          mEnhance.Visible := (Tile and fDeadLands = 0) and
     7446            (MyData.EnhancementJobs[MyMap[MyUn[UnFocus].Loc] and fTerrain, 0]
     7447            <> jNone);
     7448        end
     7449        else
     7450        begin
     7451          for i := 0 to Popup.Items.Count - 1 do
     7452            Popup.Items[i].Visible := false;
     7453        end;
     7454      end;
     7455
     7456      // set menu seperators
     7457      LastSep := nil;
     7458      NeedSep := false;
     7459      for i := 0 to Popup.Items.Count - 1 do
     7460        if Popup.Items[i].Caption = '-' then
     7461        begin
     7462          Popup.Items[i].Visible := NeedSep;
     7463          if NeedSep then
     7464            LastSep := Popup.Items[i];
     7465          NeedSep := false
     7466        end
     7467        else if Popup.Items[i].Visible then
     7468          NeedSep := true;
     7469      if (LastSep <> nil) and not NeedSep then
     7470        LastSep.Visible := false
     7471    end;
     7472
     7473    procedure TMainScreen.PanelBtnClick(Sender: TObject);
     7474    var
     7475      Popup: TPopupMenu;
     7476    begin
     7477      if Sender = UnitBtn then
     7478        Popup := UnitPopup
     7479      else { if Sender=TerrainBtn then }
     7480        Popup := TerrainPopup;
     7481      InitPopup(Popup);
     7482      if FullScreen then
     7483        Popup.Popup(Left + TControl(Sender).Left, Top + TControl(Sender).Top)
     7484      else
     7485        Popup.Popup(Left + TControl(Sender).Left + 4, Top + TControl(Sender).Top
     7486          + GetSystemMetrics(SM_CYCAPTION) + 4);
     7487    end;
     7488
     7489    procedure TMainScreen.CityClosed(Activateuix: integer; StepFocus: boolean;
     7490      SelectFocus: boolean);
     7491    begin
     7492      if supervising then
     7493      begin
     7494        SetTroopLoc(-1);
     7495        PanelPaint
     7496      end
     7497      else
     7498      begin
     7499        if Activateuix >= 0 then
     7500        begin
     7501          SetUnFocus(Activateuix);
     7502          SetTroopLoc(MyUn[Activateuix].Loc);
     7503          if SelectFocus then
     7504            FocusOnLoc(TroopLoc, flRepaintPanel)
     7505          else
     7506            PanelPaint
     7507        end
     7508        else if StepFocus then
     7509          NextUnit(TroopLoc, true)
     7510        else
     7511        begin
     7512          SetTroopLoc(-1);
     7513          PanelPaint
     7514        end
     7515      end
     7516    end;
     7517
     7518    procedure TMainScreen.Toggle(Sender: TObject);
     7519    begin
     7520      TMenuItem(Sender).Checked := not TMenuItem(Sender).Checked
     7521    end;
     7522
     7523    procedure TMainScreen.PanelBoxMouseMove(Sender: TObject; Shift: TShiftState;
     7524      x, y: integer);
     7525    var
     7526      xCentre, yCentre: integer;
     7527    begin
     7528      if Tracking and (ssLeft in Shift) then
     7529      begin
     7530        if (x >= xMini + 2) and (y >= yMini + 2) and (x < xMini + 2 + 2 * G.lx)
     7531          and (y < yMini + 2 + G.ly) then
     7532        begin
     7533          xCentre := (xwMini + (x - xMini - 2) div 2 + G.lx div 2 +
     7534            MapWidth div (xxt * 4)) mod G.lx;
     7535          yCentre := (y - yMini - 2);
     7536          xw := (xCentre - MapWidth div (xxt * 4) + G.lx) mod G.lx;
     7537          if ywmax <= 0 then
     7538            yw := ywcenter
     7539          else
    27307540          begin
    2731           CurrentMoveInfo.IsAlly:= MyRO.Treaty[Owner]=trAlliance;
    2732           if GameMode=cMovie then
    2733             CurrentMoveInfo.DoShow:=true
    2734           else if CurrentMoveInfo.IsAlly then
    2735             CurrentMoveInfo.DoShow:=not mAlNoMoves.Checked
    2736               and not(mAlEffectiveMovesOnly.Checked and (Command<>cShowCapturing))
    2737           else CurrentMoveInfo.DoShow:=not mEnNoMoves.Checked
    2738             and not(mEnAttacks.Checked and (Command<>cShowCapturing));
    2739           if CurrentMoveInfo.DoShow then
    2740             begin
    2741             if Command=cShowCapturing then
    2742               begin // show capture message
    2743               if MyMap[ToLoc] and fOwned<>0 then
    2744                 begin // own city, search
    2745                 cix:=MyRO.nCity-1;
    2746                 while (cix>=0) and (MyCity[cix].Loc<>ToLoc) do
    2747                   dec(cix);
    2748                 s:=CityName(MyCity[cix].ID);
    2749                 end
    2750               else
    2751                 begin // foreign city, search
    2752                 ecix:=MyRO.nEnemyCity-1;
    2753                 while (ecix>=0) and (MyRO.EnemyCity[ecix].Loc<>ToLoc) do
    2754                   dec(ecix);
    2755                 s:=CityName(MyRO.EnemyCity[ecix].ID);
    2756                 end;
    2757               TribeMessage(Owner, Format(Tribe[Owner].TPhrase('CAPTURE'),[s]), '');
    2758               Update; // remove message box from screen
    2759               end;
    2760 
    2761             if CurrentMoveInfo.IsAlly then
    2762               begin // allied unit -- make discovered land visible
    2763               if mAlFastMoves.Checked then AnimationSpeed:=8
    2764               else AnimationSpeed:=16;
    2765               with MyRO.EnemyModel[emix] do
    2766                 if (Kind=mkDiplomat) or (Domain=dAir) or (ATrans_Fuel>0)
    2767                   or (Cap and (1 shl (mcRadar-mcFirstNonCap) or 1 shl (mcAcademy-mcFirstNonCap))<>0)
    2768                   or (MyMap[ToLoc] and fTerrain=fMountains)
    2769                   or (MyMap[ToLoc] and fTerImp=tiFort)
    2770                   or (MyMap[ToLoc] and fTerImp=tiBase) then
    2771                   CurrentMoveInfo.AfterMovePaintRadius:=2
    2772                 else CurrentMoveInfo.AfterMovePaintRadius:=1
    2773               end
     7541            yw := (yCentre - MapHeight div (yyt * 2) + 1) and not 1;
     7542            if yw < 0 then
     7543              yw := 0
     7544            else if yw > ywmax then
     7545              yw := ywmax;
     7546          end;
     7547          BitBlt(Buffer.Canvas.Handle, 0, 0, G.lx * 2, G.ly, Mini.Canvas.Handle,
     7548            0, 0, SRCCOPY);
     7549          if ywmax <= 0 then
     7550            Frame(Buffer.Canvas, x - xMini - 2 - MapWidth div (xxt * 2), 0,
     7551              x - xMini - 2 + MapWidth div (xxt * 2) - 1, G.ly - 1,
     7552              MainTexture.clMark, MainTexture.clMark)
     7553          else
     7554            Frame(Buffer.Canvas, x - xMini - 2 - MapWidth div (xxt * 2), yw,
     7555              x - xMini - 2 + MapWidth div (xxt * 2) - 1,
     7556              yw + MapHeight div yyt - 2, MainTexture.clMark,
     7557              MainTexture.clMark);
     7558          BitBlt(Panel.Canvas.Handle, xMini + 2, yMini + 2, G.lx * 2, G.ly,
     7559            Buffer.Canvas.Handle, 0, 0, SRCCOPY);
     7560          MainOffscreenPaint;
     7561          RectInvalidate(xMini + 2, TopBarHeight + MapHeight - overlap + yMini +
     7562            2, xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - overlap + yMini
     7563            + 2 + G.ly);
     7564          Update;
     7565        end
     7566      end
     7567      else
     7568        Tracking := false
     7569    end;
     7570
     7571    procedure TMainScreen.PanelBoxMouseUp(Sender: TObject; Button: TMouseButton;
     7572      Shift: TShiftState; x, y: integer);
     7573    begin
     7574      if Tracking then
     7575      begin
     7576        Tracking := false;
     7577        xwMini := xw;
     7578        ywMini := yw;
     7579        MiniPaint;
     7580        PanelPaint;
     7581      end
     7582    end;
     7583
     7584    procedure TMainScreen.MapBoxMouseMove(Sender: TObject; Shift: TShiftState;
     7585      x, y: integer);
     7586    var
     7587      MouseLoc: integer;
     7588    begin
     7589      xMouse := x;
     7590      yMouse := y;
     7591      if (ClientMode = cEditMap) and (ssLeft in Shift) and not Tracking then
     7592      begin
     7593        MouseLoc := LocationOfScreenPixel(x, y);
     7594        if MouseLoc <> BrushLoc then
     7595          MapBoxMouseDown(nil, mbLeft, Shift, x, y);
     7596      end
     7597      (* else if idle and (UnFocus>=0) then
     7598        begin
     7599        qx:=(xMouse*32+yMouse*66+16*66) div(32*66)-1;
     7600        qy:=(yMouse*66-xMouse*32-16*66+2000*33*32) div(32*66)-999;
     7601        MouseLoc:=(xw+(qx-qy+2048) div 2-1024+G.lx) mod G.lx+G.lx*(yw+qx+qy);
     7602        ShowMoveHint(MouseLoc);
     7603        end *)
     7604    end;
     7605
     7606    procedure TMainScreen.mShowClick(Sender: TObject);
     7607    begin
     7608      TMenuItem(Sender).Checked := not TMenuItem(Sender).Checked;
     7609      SetMapOptions;
     7610      MapValid := false;
     7611      PaintAllMaps;
     7612    end;
     7613
     7614    procedure TMainScreen.mNamesClick(Sender: TObject);
     7615    var
     7616      p1: integer;
     7617    begin
     7618      mNames.Checked := not mNames.Checked;
     7619      GenerateNames := mNames.Checked;
     7620      for p1 := 0 to nPl - 1 do
     7621        if Tribe[p1] <> nil then
     7622          if GenerateNames then
     7623            Tribe[p1].NumberName := -1
     7624          else
     7625            Tribe[p1].NumberName := p1;
     7626      MapValid := false;
     7627      PaintAll;
     7628    end;
     7629
     7630    function TMainScreen.IsPanelPixel(x, y: integer): boolean;
     7631    begin
     7632      result := (y >= TopBarHeight + MapHeight) or
     7633        (y >= ClientHeight - PanelHeight) and
     7634        ((x < xMidPanel) or (x >= xRightPanel))
     7635    end;
     7636
     7637    procedure TMainScreen.FormMouseDown(Sender: TObject; Button: TMouseButton;
     7638      Shift: TShiftState; x, y: integer);
     7639    begin
     7640      if idle then
     7641        if (x < 40) and (y < 40) then
     7642        begin
     7643          if GameMode <> cMovie then
     7644          begin
     7645            InitPopup(GamePopup);
     7646            if FullScreen then
     7647              GamePopup.Popup(Left, Top + TopBarHeight - 1)
    27747648            else
    2775               begin
    2776               if mEnFastMoves.Checked then AnimationSpeed:=8
    2777               else AnimationSpeed:=16;
    2778               CurrentMoveInfo.AfterMovePaintRadius:=0; // enemy unit, nothing discovered
    2779               end;
    2780             if GameMode=cMovie then
    2781               begin
    2782               if MovieSpeed=3 then AnimationSpeed:=4
    2783               else if MovieSpeed=2 then AnimationSpeed:=8
    2784               else AnimationSpeed:=16;
    2785               end;
    2786             ShowMoveDomain:=MyRO.EnemyModel[emix].Domain;
    2787             IsAlpine:= MyRO.EnemyModel[emix].Cap and (1 shl (mcAlpine-mcFirstNonCap))<>0;
    2788             end
    2789           end;
    2790 
    2791         if CurrentMoveInfo.DoShow then
    2792           begin
    2793           if Command=cShowCapturing then Play('MOVE_CAPTURE')
    2794           else if EndHealth<=0 then Play('MOVE_DIE')
    2795           else if Flags and umSpyMission<>0 then Play('MOVE_COVERT')
    2796           else if Flags and umShipLoading<>0 then
    2797             if ShowMoveDomain=dAir then Play('MOVE_PLANELANDING')
    2798             else Play('MOVE_LOAD')
    2799           else if Flags and umPlaneLoading<>0 then Play('MOVE_LOAD')
    2800           else if Flags and umShipUnloading<>0 then
    2801             if ShowMoveDomain=dAir then Play('MOVE_PLANESTART')
    2802             else Play('MOVE_UNLOAD')
    2803           else if Flags and umPlaneUnloading<>0 then
    2804             if (MyMap[FromLoc] and fCity=0)
    2805               and (MyMap[FromLoc] and fTerImp<>tiBase) then
    2806               Play('MOVE_PARACHUTE')
    2807             else Play('MOVE_UNLOAD')
    2808           else if (ShowMoveDomain=dGround) and not IsAlpine
    2809             and (MyMap[ToLoc] and fTerrain=fMountains)
    2810             and ((MyMap[FromLoc] and (fRoad or fRR or fCity)=0)
    2811               or (MyMap[ToLoc] and (fRoad or fRR or fCity)=0)) then
    2812             Play('MOVE_MOUNTAIN');
    2813 
    2814           FocusOnLoc(FromLoc,flImmUpdate);
    2815           PaintLoc_BeforeMove(FromLoc);
    2816           if Command=cShowCapturing then
    2817             MoveOnScreen(TShowMove(Data),1,32,32)
    2818           else MoveOnScreen(TShowMove(Data),1,AnimationSpeed,AnimationSpeed)
    2819           end // if CurrentMoveInfo.DoShow
    2820         else MapValid:=false;
    2821         end
    2822       end;
    2823 
    2824   cShowAttacking:
    2825     if (idle and (NewPlayer=me)
    2826       or not idle and not skipped and (TShowMove(Data).emix<>$FFFF))
    2827       and not ((GameMode=cMovie) and (MovieSpeed=4)) then
    2828       begin
    2829       assert(NewPlayer=me);
    2830       if not idle or (GameMode=cMovie) then
    2831         Application.ProcessMessages;
    2832       with TShowMove(Data) do
    2833         begin
    2834         CurrentMoveInfo.AfterAttackExpeller:=-1;
    2835         CurrentMoveInfo.DoShow:=false;
    2836         if idle then
    2837           CurrentMoveInfo.DoShow:=true // own unit -- always show attacks
    2838         else
    2839           begin
    2840           CurrentMoveInfo.IsAlly:= MyRO.Treaty[Owner]=trAlliance;
    2841           if CurrentMoveInfo.IsAlly then
    2842             CurrentMoveInfo.DoShow:=not mAlNoMoves.Checked
    2843           else CurrentMoveInfo.DoShow:=not mEnNoMoves.Checked;
    2844           end;
    2845         if CurrentMoveInfo.DoShow then
    2846           begin
    2847           ToLoc:=dLoc(FromLoc,dx,dy);
    2848           if Tribe[Owner].ModelPicture[mix].HGr=0 then
    2849             InitEnemyModel(emix);
    2850 
    2851           if (MyMap[ToLoc] and (fCity or fUnit or fOwned) = fCity or fOwned) then
    2852             begin // tell about bombardment
    2853             cix:=MyRO.nCity-1;
    2854             while (cix>=0) and (MyCity[cix].Loc<>ToLoc) do
    2855               dec(cix);
    2856             if MyCity[cix].Status and csToldBombard=0 then
    2857               begin
    2858               if not supervising then
    2859                 MyCity[cix].Status:=MyCity[cix].Status or csToldBombard;
    2860               s:=CityName(MyCity[cix].ID);
    2861               SoundMessageEx(Format(Tribe[Owner].TPhrase('BOMBARD'),[s]),'');
    2862               Update; // remove message box from screen
    2863               end;
    2864             end
    2865           else if Flags and umExpelling<>0 then
    2866             CurrentMoveInfo.AfterAttackExpeller:=Owner;
    2867 
    2868           if Flags and umExpelling<>0 then Play('MOVE_EXPEL')
    2869           else if Owner=me then
    2870             begin
    2871             MakeModelInfo(me,mix,MyModel[mix],mi);
    2872             Play(AttackSound(ModelCode(mi)));
    2873             end
    2874           else Play(AttackSound(ModelCode(MyRO.EnemyModel[emix])));
    2875 
    2876           FocusOnLoc(FromLoc,flImmUpdate);
    2877 
    2878           // before combat
    2879           MainMap.AttackBegin(TShowMove(Data));
    2880           if MyMap[ToLoc] and fCity<>0 then PaintLoc(ToLoc);
    2881           PaintLoc(FromLoc);
    2882           MoveOnScreen(TShowMove(Data),1,9,16);
    2883           MoveOnScreen(TShowMove(Data),17,12,32);
    2884           MoveOnScreen(TShowMove(Data),7,11,16);
    2885 
    2886           // after combat
    2887           MainMap.AttackEffect(TShowMove(Data));
    2888           PaintLoc(ToLoc);
    2889           if EndHealth>0 then
    2890             begin
    2891             Health:=EndHealth;
    2892             MoveOnScreen(TShowMove(Data),10,0,16);
    2893             end
    2894           else if not idle then
    2895             Sleep(MoveTime div 2);
    2896           MainMap.AttackEnd;
    2897           end // if CurrentMoveInfo.DoShow
    2898         else MapValid:=false;
    2899         end
    2900       end;
    2901 
    2902   cShowMissionResult:
    2903     if Cardinal(Data)=0 then
    2904       SoundMessageEx(Phrases.Lookup('NOFOREIGNINFO'),'')
    2905     else
    2906       begin
    2907       s:=Phrases.Lookup('FOREIGNINFO');
    2908       for p1:=0 to nPl-1 do if 3 shl (p1*2) and Cardinal(Data)<>0 then
    2909         s:=s+'\'+Tribe[p1].TPhrase('SHORTNAME');
    2910       SoundMessageEx(s,'')
    2911       end;
    2912 
    2913   cShowShipChange:
    2914     if not IsMultiPlayerGame and (Jump[0]=0) then
    2915       ShowEnemyShipChange(TShowShipChange(Data));
    2916 
    2917   cShowGreatLibTech:
    2918     if not IsMultiPlayerGame and (Jump[0]=0) then with MessgExDlg do
    2919       begin
    2920       MessgText:=Format(Phrases.Lookup('GRLIB_GENERAL'),
    2921         [Phrases.Lookup('ADVANCES',integer(Data))]);
    2922       OpenSound:='NEWADVANCE_GRLIB';
    2923       Kind:=mkOK;
    2924       IconKind:=mikImp;
    2925       IconIndex:=woGrLibrary;
    2926       ShowModal;
    2927       end;
    2928 
    2929   cRefreshDebugMap:
    2930     begin
    2931     if integer(data)=IsoEngine.pDebugMap then
    2932       begin
    2933       MapValid:=false;
    2934       MainOffscreenPaint;
    2935       Update;
    2936       end
    2937     end;
    2938 
    2939   else if Command>=cClientEx then case Command and $FFF0 of
    2940 
    2941     cSetTribe: with TTribeInfo(Data) do
    2942       begin
    2943       i:=UnusedTribeFiles.Count-1;
    2944       while (i>=0) and (AnsiCompareFileName(UnusedTribeFiles[i],FileName)<>0) do
    2945         dec(i);
    2946       if i>=0 then UnusedTribeFiles.Delete(i);
    2947       CreateTribe(trix,FileName,true);
    2948       end;
    2949 
    2950     cSetNewModelPicture, cSetModelPicture:
    2951       if TribeOriginal[TModelPictureInfo(Data).trix] then
    2952         Tribe[TModelPictureInfo(Data).trix].SetModelPicture(
    2953           TModelPictureInfo(Data),Command and $FFF0=cSetNewModelPicture);
    2954 
    2955     cSetSlaveIndex and $FFF0:
    2956       Tribe[integer(data) shr 16].mixSlaves:=integer(data) and $FFFF;
    2957 
    2958     cSetCityName: with TCityNameInfo(Data) do
    2959       if TribeOriginal[ID shr 12] then
    2960         Tribe[ID shr 12].SetCityName(ID and $FFF,NewName);
    2961 
    2962     cSetModelName: with TModelNameInfo(Data) do
    2963       if TribeOriginal[NewPlayer] then
    2964         Tribe[NewPlayer].ModelName[mix]:=NewName;
    2965     end
    2966   end
    2967 end;{<<<client}
    2968 
    2969 {*** main part ***}
    2970 
    2971 procedure TMainScreen.CreateParams (var p: TCreateParams);
    2972 var
    2973 DefaultOptionChecked: integer;
    2974 Reg: TRegistry;
    2975 doinit: boolean;
    2976 begin
    2977 inherited;
    2978 
    2979 // define which menu settings to save
    2980 SaveOption[0]:=mAlEffectiveMovesOnly.Tag;
    2981 SaveOption[1]:=mEnMoves.Tag;
    2982 SaveOption[2]:=mEnAttacks.Tag;
    2983 SaveOption[3]:=mEnNoMoves.Tag;
    2984 SaveOption[4]:=mWaitTurn.Tag;
    2985 SaveOption[5]:=mEffectiveMovesOnly.Tag;
    2986 SaveOption[6]:=mEnFastMoves.Tag;
    2987 SaveOption[7]:=mSlowMoves.Tag;
    2988 SaveOption[8]:=mFastMoves.Tag;
    2989 SaveOption[9]:=mVeryFastMoves.Tag;
    2990 SaveOption[10]:=mNames.Tag;
    2991 SaveOption[11]:=mRepList.Tag;
    2992 SaveOption[12]:=mRepScreens.Tag;
    2993 SaveOption[13]:=mSoundOff.Tag;
    2994 SaveOption[14]:=mSoundOn.Tag;
    2995 SaveOption[15]:=mSoundOnAlt.Tag;
    2996 SaveOption[16]:=mScrollSlow.Tag;
    2997 SaveOption[17]:=mScrollFast.Tag;
    2998 SaveOption[18]:=mScrollOff.Tag;
    2999 SaveOption[19]:=mAlSlowMoves.Tag;
    3000 SaveOption[20]:=mAlFastMoves.Tag;
    3001 SaveOption[21]:=mAlNoMoves.Tag;
    3002 DefaultOptionChecked:= 1 shl 1 + 1 shl 7 + 1 shl 10 + 1 shl 12 + 1 shl 14 + 1 shl 18 + 1 shl 19;
    3003 
    3004 Reg:=TRegistry.Create;
    3005 doinit:=true;
    3006 if Reg.KeyExists('SOFTWARE\cevo\RegVer9') then
    3007   begin
    3008   doinit:=false;
    3009   Reg.OpenKey('SOFTWARE\cevo\RegVer9',false);
    3010   try
    3011     xxt:=Reg.ReadInteger('TileWidth') div 2;
    3012     yyt:=Reg.ReadInteger('TileHeight') div 2;
    3013     OptionChecked:=Reg.ReadInteger('OptionChecked');
    3014     MapOptionChecked:=Reg.ReadInteger('MapOptionChecked');
    3015     CityRepMask:=cardinal(Reg.ReadInteger('CityReport'));
    3016   except
    3017     doinit:=true;
    3018     end;
    3019   Reg.closekey;
    3020   if OptionChecked and (7 shl 16)=0 then
    3021     OptionChecked:=OptionChecked or (1 shl 16); // old regver with no scrolling
    3022   end;
    3023 Reg.Free;
    3024 if doinit then
    3025   begin
    3026   xxt:=48;
    3027   yyt:=24;
    3028   OptionChecked:=DefaultOptionChecked;
    3029   MapOptionChecked:=1 shl moCityNames;
    3030   CityRepMask:=cardinal(not chPopIncrease and not chNoGrowthWarning and not chCaptured);
    3031   end;
    3032 
    3033 if FullScreen then
    3034   begin
    3035   p.Style:=$87000000;
    3036   BorderStyle:=bsNone;
    3037   BorderIcons:=[];
    3038   end;
    3039 
    3040 if 1 shl 13 and OptionChecked<>0 then SoundMode:=smOff
    3041 else if 1 shl 15 and OptionChecked<>0 then SoundMode:=smOnAlt
    3042 else SoundMode:=smOn
    3043 end;
    3044 
    3045 procedure TMainScreen.FormCreate(Sender:TObject);
    3046 var
    3047 i,j: integer;
    3048 begin
    3049 Screen.Cursors[crImpDrag]:=LoadCursor(HInstance,'DRAG');
    3050 Screen.Cursors[crFlatHand]:=LoadCursor(HInstance,'FLATHAND');
    3051 
    3052 // tag-controlled language
    3053 for i:=0 to ComponentCount-1 do
    3054   if Components[i].Tag and $FF<>0 then
    3055     if Components[i] is TMenuItem then
    3056       begin
    3057       TMenuItem(Components[i]).Caption:=
    3058         Phrases.Lookup('CONTROLS',-1+Components[i].Tag and $FF);
    3059       for j:=0 to nSaveOption-1 do
    3060         if Components[i].Tag and $FF=SaveOption[j] then
    3061           TMenuItem(Components[i]).Checked:= 1 shl j and OptionChecked<>0;
    3062       end
    3063     else if Components[i] is TButtonBase then
    3064       begin
    3065       TButtonBase(Components[i]).Hint:=
    3066         Phrases.Lookup('CONTROLS',-1+Components[i].Tag and $FF);
    3067       if (Components[i] is TButtonC) and (TButtonC(Components[i]).ButtonIndex<>1) then
    3068         TButtonC(Components[i]).ButtonIndex:=
    3069           MapOptionChecked shr (Components[i].Tag shr 8) and 1 +2
    3070       end;
    3071 
    3072 // non-tag-controlled language
    3073 mTechTree.Caption:=Phrases2.Lookup('MENU_ADVTREE');
    3074 mViewpoint.Caption:=Phrases2.Lookup('MENU_VIEWPOINT');
    3075 if not Phrases2FallenBackToEnglish then
    3076   begin
    3077   MenuArea.Hint:=Phrases2.Lookup('BTN_MENU');
    3078   TreasuryArea.Hint:=Phrases2.Lookup('TIP_TREASURY');
    3079   ResearchArea.Hint:=Phrases.Lookup('SCIENCE');
    3080   ManagementArea.Hint:=Phrases2.Lookup('BTN_MANAGE');
    3081   end;
    3082 for i:=0 to mRep.Count-1 do
    3083   begin
    3084   j:=mRep[i].Tag shr 8;
    3085   mRep[i].Caption:=CityEventName(j);
    3086   mRep[i].Checked:= CityRepMask and (1 shl j)<>0;
    3087   end;
    3088 
    3089 Mini:=TBitmap.Create;
    3090 Mini.PixelFormat:=pf24bit;
    3091 Panel:=TBitmap.Create;
    3092 Panel.PixelFormat:=pf24bit;
    3093 Panel.Canvas.Font.Assign(UniFont[ftSmall]);
    3094 Panel.Canvas.Brush.Style:=bsClear;
    3095 TopBar:=TBitmap.Create;
    3096 TopBar.PixelFormat:=pf24bit;
    3097 TopBar.Canvas.Font.Assign(UniFont[ftNormal]);
    3098 TopBar.Canvas.Brush.Style:=bsClear;
    3099 Buffer:=TBitmap.Create;
    3100 Buffer.PixelFormat:=pf24bit;
    3101 if 2*lxmax>3*xSizeBig then
    3102   Buffer.Width:=2*lxmax
    3103 else Buffer.Width:=3*xSizeBig;
    3104 if lymax>3*ySizeBig then
    3105   Buffer.Height:=lymax
    3106 else Buffer.Height:=3*ySizeBig;
    3107 Buffer.Canvas.Font.Assign(UniFont[ftSmall]);
    3108 for i:=0 to nPl-1 do AILogo[i]:=nil;
    3109 Canvas.Font.Assign(UniFont[ftSmall]);
    3110 InitButtons();
    3111 EOT.Template:=Templates;
    3112 end;
    3113 
    3114 procedure TMainScreen.FormDestroy(Sender:TObject);
    3115 var
    3116 i: integer;
    3117 begin
    3118 Mini.Free;Buffer.Free;Panel.Free;
    3119 for i:=0 to nPl-1 do if AILogo[i]<>nil then
    3120   AILogo[i].Free;
    3121 end;
    3122 
    3123 procedure TMainScreen.FormResize(Sender:TObject);
    3124 var
    3125 MiniFrame,MaxMapWidth: integer;
    3126 begin
    3127 SmallScreen:= ClientWidth<1024;
    3128 MaxMapWidth:=(G.lx*2-3)*xxt; // avoide the same tile being visible left and right
    3129 if ClientWidth<=MaxMapWidth then
    3130   begin
    3131   MapWidth:=ClientWidth;
    3132   MapOffset:=0;
    3133   end
    3134 else
    3135   begin
    3136   MapWidth:=MaxMapWidth;
    3137   MapOffset:=(ClientWidth-MapWidth) div 2;
    3138   end;
    3139 MapHeight:=ClientHeight-TopBarHeight-PanelHeight+overlap;
    3140 Panel.Width:=ClientWidth; Panel.Height:=PanelHeight;
    3141 TopBar.Width:=ClientWidth; TopBar.Height:=TopBarHeight;
    3142 MiniFrame:=(lxmax_xxx-G.ly) div 2;
    3143 xMidPanel:=(G.lx+MiniFrame)*2+1;
    3144 xRightPanel:=ClientWidth-LeftPanelWidth-10;
    3145 if ClientMode=cEditMap then
    3146   TrPitch:=2*xxt
    3147 else TrPitch:=66;
    3148 xMini:=MiniFrame-5; yMini:=(PanelHeight-26-lxmax_xxx) div 2+MiniFrame;
    3149 ywmax:=(G.ly-MapHeight div yyt+1) and not 1;
    3150 ywcenter:=-((MapHeight-yyt*(G.ly-1)) div (4*yyt))*2; // only for ywmax<=0
    3151 if ywmax<=0 then yw:=ywcenter
    3152 else if yw<0 then yw:=0
    3153 else if yw>ywmax then yw:=ywmax;
    3154 UnitInfoBtn.Top:=ClientHeight-29;
    3155 UnitInfoBtn.Left:=xMidPanel+7+99;
    3156 UnitBtn.Top:=ClientHeight-29;
    3157 UnitBtn.Left:=xMidPanel+7+99+31;
    3158 TerrainBtn.Top:=ClientHeight-29;
    3159 TerrainBtn.Left:=xMidPanel+7+99+62;
    3160 MovieSpeed1Btn.Top:=ClientHeight-91;
    3161 MovieSpeed1Btn.Left:=ClientWidth div 2-62;
    3162 MovieSpeed2Btn.Top:=ClientHeight-91;
    3163 MovieSpeed2Btn.Left:=ClientWidth div 2-62+29;
    3164 MovieSpeed3Btn.Top:=ClientHeight-91;
    3165 MovieSpeed3Btn.Left:=ClientWidth div 2-62+2*29;
    3166 MovieSpeed4Btn.Top:=ClientHeight-91;
    3167 MovieSpeed4Btn.Left:=ClientWidth div 2-62+3*29+12;
    3168 EOT.Top:=ClientHeight-64;
    3169 EOT.Left:=ClientWidth-62;
    3170 SetWindowPos(sb.h,0,xRightPanel+10-14-GetSystemMetrics(SM_CXVSCROLL),
    3171   ClientHeight-MidPanelHeight+8,0,0,SWP_NOSIZE or SWP_NOZORDER);
    3172 MapBtn0.Left:=xMini+G.lx-44;
    3173 MapBtn0.Top:=ClientHeight-15;
    3174 MapBtn1.Left:=xMini+G.lx-28;
    3175 MapBtn1.Top:=ClientHeight-15;
    3176 {MapBtn2.Left:=xMini+G.lx-20;
    3177 MapBtn2.Top:=ClientHeight-15;
    3178 MapBtn3.Left:=xMini+G.lx-4;
    3179 MapBtn3.Top:=ClientHeight-15;}
    3180 MapBtn5.Left:=xMini+G.lx-12;
    3181 MapBtn5.Top:=ClientHeight-15;
    3182 MapBtn4.Left:=xMini+G.lx+20;
    3183 MapBtn4.Top:=ClientHeight-15;
    3184 MapBtn6.Left:=xMini+G.lx+36;
    3185 MapBtn6.Top:=ClientHeight-15;
    3186 TreasuryArea.Left:=ClientWidth div 2-172;
    3187 ResearchArea.Left:=ClientWidth div 2;
    3188 ManagementArea.Left:=ClientWidth-xPalace;
    3189 ManagementArea.Top:=TopBarHeight+MapHeight-overlap+yPalace;
    3190 ArrangeMidPanel;
    3191 if RepaintOnResize then
    3192   begin
    3193   RectInvalidate(0,TopBarHeight,ClientWidth,TopBarHeight+MapHeight);
    3194   MapValid:=false;
    3195   PaintAll
    3196   end
    3197 end;
    3198 
    3199 procedure TMainScreen.FormCloseQuery(Sender: TObject; var CanClose: boolean);
    3200 begin
    3201 CanClose:=Closable;
    3202 if not Closable and idle and (me=0) and (ClientMode<scContact) then
    3203   MenuClick(mResign)
    3204 end;
    3205 
    3206 procedure TMainScreen.OnScroll(var m:TMessage);
    3207 begin
    3208 if ProcessPVSB(sb,m) then begin PanelPaint; Update end
    3209 end;
    3210 
    3211 procedure TMainScreen.OnEOT(var Msg:TMessage);
    3212 begin
    3213 EndTurn
    3214 end;
    3215 
    3216 procedure TMainScreen.EOTClick(Sender:TObject);
    3217 begin
    3218 if GameMode=cMovie then
    3219   begin
    3220   MessgExDlg.CancelMovie;
    3221   Server(sBreak,me,0,nil^)
    3222   end
    3223 else if ClientMode<0 then
    3224   skipped:=true
    3225 else if ClientMode>=scContact then
    3226   NegoDlg.ShowNewContent(wmPersistent)
    3227 else if Jump[pTurn]>0 then
    3228   begin Jump[pTurn]:=0; StartRunning:=false end
    3229 else EndTurn
    3230 end;
    3231 
    3232 // set xTerrain, xTroop, and TrRow
    3233 procedure TMainScreen.ArrangeMidPanel;
    3234 begin
    3235 if ClientMode=cEditMap then
    3236   xTroop:=xMidPanel+15
    3237 else
    3238   begin
    3239   if supervising then
    3240     xTerrain:=xMidPanel+2*xxt+14
    3241   else if ClientWidth<1280 then
    3242     xTerrain:=ClientWidth div 2+(1280-ClientWidth) div 3
    3243   else xTerrain:=ClientWidth div 2;
    3244   xTroop:=xTerrain+2*xxt+12;
    3245   if SmallScreen and not supervising then
    3246     xTroop:=xRightPanel+10-3*66-GetSystemMetrics(SM_CXVSCROLL)-19-4;
    3247     // not perfect but we assume almost no one is still playing on a 800x600 screen
    3248   end;
    3249 TrRow:=(xRightPanel+10-xTroop-GetSystemMetrics(SM_CXVSCROLL)-19) div TrPitch;
    3250 end;
    3251 
    3252 function TMainScreen.EndTurn(WasSkipped: boolean): boolean;
    3253 
    3254   function IsResourceUnused(cix, NeedFood, NeedProd: integer): boolean;
    3255   var
    3256   dx,dy,fix: integer;
    3257   CityAreaInfo: TCityAreaInfo;
    3258   TileInfo: TTileInfo;
    3259   begin
    3260   Server(sGetCityAreaInfo,me,cix,CityAreaInfo);
    3261   for dy:=-3 to 3 do for dx:=-3 to 3 do
    3262     if ((dx+dy) and 1=0) and (dx*dx*dy*dy<81) then
    3263       begin
    3264       fix:=(dy+3) shl 2+(dx+3) shr 1;
    3265       if (MyCity[cix].Tiles and (1 shl fix)=0) // not used yet
    3266         and (CityAreaInfo.Available[fix]=faAvailable) then // usable
    3267         begin
    3268         TileInfo.ExplCity:=cix;
    3269         Server(sGetHypoCityTileInfo, me, dLoc(MyCity[cix].Loc,dx,dy), TileInfo);
    3270         if (TileInfo.Food>=NeedFood) and (TileInfo.Prod>=NeedProd) then
    3271           begin result:=true; exit end;
    3272         end
    3273       end;
    3274   result:=false;
    3275   end;
    3276 
    3277 var
    3278 i,p1,uix,cix,CenterLoc: integer;
    3279 MsgItem: string;
    3280 CityReport: TCityReport;
    3281 PlaneReturnData: TPlaneReturnData;
    3282 Zoom: boolean;
    3283 begin
    3284 result:=false;
    3285 if ClientMode>=scDipOffer then exit;
    3286 
    3287 if supervising and (me<>0) then
    3288   begin
    3289   for i:=0 to Screen.FormCount-1 do
    3290     if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
    3291       Screen.Forms[i].Close; // close windows
    3292   ItsMeAgain(0);
    3293   end;
    3294 
    3295 CityOptimizer_EndOfTurn;
    3296 
    3297 if not WasSkipped then // check warnings
    3298   begin
    3299   // need to move planes home?
    3300   for uix:=0 to MyRO.nUn-1 do with MyUn[uix] do
    3301     if (Loc>=0) and (MyModel[mix].Domain=dAir)
    3302       and (Status and usToldNoReturn=0) and (Master<0)
    3303       and (MyMap[Loc] and fCity=0) and (MyMap[Loc] and fTerImp<>tiBase) then
    3304       begin
    3305       PlaneReturnData.Fuel:=Fuel;
    3306       PlaneReturnData.Loc:=Loc;
    3307       PlaneReturnData.Movement:=0; // end turn without further movement?
    3308       if Server(sGetPlaneReturn, me, uix, PlaneReturnData)=eNoWay then
    3309         begin
    3310         CenterLoc:=Loc+G.lx*6; // centering the unit itself would make it covered by the query dialog
    3311         while CenterLoc>=G.lx*G.ly do
    3312           dec(CenterLoc, G.lx*2);
    3313         Centre(CenterLoc);
    3314         SetTroopLoc(-1);
    3315         PaintAll;
    3316 
    3317         if MyModel[mix].Kind=mkSpecial_Glider then
    3318           MsgItem:='LOWFUEL_GLIDER'
    3319         else MsgItem:='LOWFUEL';
    3320         if SimpleQuery(mkYesNo,Phrases.Lookup(MsgItem),'WARNING_LOWSUPPORT')<>mrOk then
    3321           begin
    3322           SetUnFocus(uix);
    3323           SetTroopLoc(Loc);
    3324           PanelPaint;
    3325           exit;
    3326           end;
    3327         MyUn[uix].Status:=MyUn[uix].Status or usToldNoReturn;
    3328         end
    3329       end;
    3330 
    3331   if not supervising and (MyRO.TestFlags and tfImmImprove=0)
    3332     and (MyRO.Government<>gAnarchy)
    3333     and (MyRO.Money+TaxSum<0) and (MyRO.TaxRate<100) then // low funds!
    3334     with MessgExDlg do
    3335       begin
    3336       OpenSound:='WARNING_LOWFUNDS';
    3337       MessgText:=Phrases.Lookup('LOWFUNDS');
    3338       Kind:=mkYesNo;
    3339       IconKind:=mikImp;
    3340       IconIndex:=imTrGoods;
    3341       ShowModal;
    3342       if ModalResult<>mrOK then exit
    3343       end;
    3344 
    3345   if MyRO.Government<>gAnarchy then
    3346     for cix:=0 to MyRO.nCity-1 do with MyCity[cix] do
    3347       if (Loc>=0) and (Flags and chCaptured=0) then
    3348         begin
    3349         Zoom:=false;
    3350         CityReport.HypoTiles:=-1;
    3351         CityReport.HypoTax:=-1;
    3352         CityReport.HypoLux:=-1;
    3353         Server(sGetCityReport,me,cix,CityReport);
    3354 
    3355         if (CityReport.Working-CityReport.Happy>Size shr 1)
    3356           and (Flags and chCaptured<=$10000) then
    3357           with MessgExDlg do
    3358             begin
    3359             OpenSound:='WARNING_DISORDER';
    3360             if Status and csResourceWeightsMask=0 then
    3361               MsgItem:='DISORDER'
    3362             else MsgItem:='DISORDER_UNREST';
    3363             MessgText:=Format(Phrases.Lookup(MsgItem),[CityName(ID)]);
    3364             Kind:=mkYesNo;
    3365       //      BigIcon:=29;
    3366             ShowModal;
    3367             Zoom:= ModalResult<>mrOK;
    3368             end;
    3369         if not Zoom and (Food+CityReport.FoodRep-CityReport.Eaten<0) then
    3370           with MessgExDlg do
    3371             begin
    3372             OpenSound:='WARNING_FAMINE';
    3373             if Status and csResourceWeightsMask=0 then
    3374               MsgItem:='FAMINE'
    3375             else if (CityReport.Deployed<>0) and IsResourceUnused(cix,1,0) then
    3376               MsgItem:='FAMINE_UNREST'
    3377             else MsgItem:='FAMINE_TILES';
    3378             MessgText:=Format(Phrases.Lookup(MsgItem),[CityName(ID)]);
    3379             Kind:=mkYesNo;
    3380             IconKind:=mikImp;
    3381             IconIndex:=22;
    3382             ShowModal;
    3383             Zoom:= ModalResult<>mrOK;
    3384             end;
    3385         if not Zoom and (CityReport.ProdRep<CityReport.Support) then
    3386           with MessgExDlg do
    3387             begin
    3388             OpenSound:='WARNING_LOWSUPPORT';
    3389             if Status and csResourceWeightsMask=0 then
    3390               MsgItem:='LOWSUPPORT'
    3391             else if (CityReport.Deployed<>0) and IsResourceUnused(cix,0,1) then
    3392               MsgItem:='LOWSUPPORT_UNREST'
    3393             else MsgItem:='LOWSUPPORT_TILES';
    3394             MessgText:=Format(Phrases.Lookup(MsgItem),[CityName(ID)]);
    3395             Kind:=mkYesNo;
    3396             IconKind:=mikImp;
    3397             IconIndex:=29;
    3398             ShowModal;
    3399             Zoom:= ModalResult<>mrOK;
    3400             end;
    3401         if Zoom then
    3402           begin // zoom to city
    3403           ZoomToCity(Loc);
    3404           exit
    3405           end
    3406         end;
    3407 
    3408   if (MyRO.Happened and phTech<>0) and (MyRO.ResearchTech<0)
    3409     and (MyData.FarTech<>adNexus) then
    3410     if not ChooseResearch then
    3411       exit;
    3412   end;
    3413 
    3414 RememberPeaceViolation;
    3415 
    3416 SetUnFocus(-1);
    3417 for uix:=0 to MyRO.nUn-1 do
    3418   MyUn[uix].Status:=MyUn[uix].Status and usPersistent;
    3419 
    3420 CityDlg.CloseAction:=None;
    3421 if IsMultiPlayerGame then
    3422   begin // close windows for next player
    3423   for i:=0 to Screen.FormCount-1 do
    3424     if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
    3425       Screen.Forms[i].Close;
    3426   end
    3427 else
    3428   begin
    3429   if CityDlg.Visible then CityDlg.Close;
    3430   if UnitStatDlg.Visible then UnitStatDlg.Close;
    3431   end;
    3432 for i:=0 to Screen.FormCount-1 do
    3433   if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
    3434     Screen.Forms[i].Enabled:=false;
    3435 
    3436 if Server(sTurn,pTurn,0,nil^)>=rExecuted then
    3437   begin
    3438   if Jump[pTurn]>0 then EOT.Hint:=Phrases.Lookup('BTN_STOP')
    3439   else EOT.Hint:=Phrases.Lookup('BTN_SKIP');
    3440   result:=true;
    3441   SetTroopLoc(-1);
    3442   pTurn:=-1;
    3443   pLogo:=-1;
    3444   UnitInfoBtn.Visible:=false;
    3445   UnitBtn.Visible:=false;
    3446   TerrainBtn.Visible:=false;
    3447   EOT.ButtonIndex:=eotCancel;
    3448   EOT.Visible:=true;
    3449   MapValid:=false;
    3450   PanelPaint;
    3451   Update;
    3452   ClientMode:=-1;
    3453   idle:=false;
    3454   skipped:=WasSkipped;
    3455   for p1:=1 to nPl-1 do
    3456     if G.RO[p1]<>nil then skipped:=true; // don't show enemy moves in hotseat mode
    3457   end
    3458 else PanelPaint
    3459 end; // EndTurn
    3460 
    3461 procedure TMainScreen.EndNego;
    3462 begin
    3463 if NegoDlg.Visible then NegoDlg.Close;
    3464 HaveStrategyAdvice:=false;
    3465   // AdvisorDlg.HaveStrategyAdvice;
    3466   // negotiation might have changed advices
    3467 EOT.ButtonIndex:=eotCancel;
    3468 EOT.Visible:=true;
    3469 PanelPaint;
    3470 Update;
    3471 ClientMode:=-1;
    3472 idle:=false;
    3473 end;
    3474 
    3475 procedure TMainScreen.ProcessRect(x0,y0,nx,ny,Options: integer);
    3476 var
    3477 xs,ys,xl,yl: integer;
    3478 begin
    3479 xl:=nx*xxt+xxt;
    3480 yl:=ny*yyt+yyt*2;
    3481 xs:=(x0-xw)*(xxt*2)+y0 and 1*xxt-G.lx*(xxt*2);
    3482 // |xs+xl/2-MapWidth/2| -> min
    3483 while abs(2*(xs+G.lx*(xxt*2))+xl-MapWidth)<abs(2*xs+xl-MapWidth) do
    3484   inc(xs,G.lx*(xxt*2));
    3485 ys:=(y0-yw)*yyt-yyt;
    3486 if xs+xl>MapWidth then xl:=MapWidth-xs;
    3487 if ys+yl>MapHeight then yl:=MapHeight-ys;
    3488 if (xl<=0) or (yl<=0) then exit;
    3489 if Options and prPaint<>0 then
    3490   begin
    3491   if Options and prAutoBounds<>0 then
    3492     MainMap.SetPaintBounds(xs,ys,xs+xl,ys+yl);
    3493   MainMap.Paint(xs,ys,x0+G.lx*y0,nx,ny,-1,-1);
    3494   end;
    3495 if Options and prInvalidate<>0 then
    3496   RectInvalidate(MapOffset+xs,TopBarHeight+ys,MapOffset+xs+xl,TopBarHeight+ys+yl)
    3497 end;
    3498 
    3499 procedure TMainScreen.PaintLoc(Loc: integer; Radius: integer = 0);
    3500 var
    3501 yLoc,x0: integer;
    3502 begin
    3503 if MapValid then
    3504   begin
    3505   yLoc:=(Loc+G.lx*1024) div G.lx -1024;
    3506   x0:=(Loc+(yLoc and 1-2*Radius+G.lx*1024) div 2) mod G.lx;
    3507   offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
    3508   ProcessRect(x0,yLoc-2*Radius,4*Radius+1,4*Radius+1,
    3509     prPaint or prAutoBounds or prInvalidate);
    3510   Update;
    3511   end
    3512 end;
    3513 
    3514 procedure TMainScreen.PaintLocTemp(Loc, Style: integer);
    3515 var
    3516 y0,x0,xMap,yMap: integer;
    3517 begin
    3518 if not MapValid then exit;
    3519 Buffer.Canvas.Font.Assign(UniFont[ftSmall]);
    3520 y0:=Loc div G.lx;
    3521 x0:=Loc mod G.lx;
    3522 xMap:=(x0-xw)*(xxt*2)+y0 and 1*xxt-G.lx*(xxt*2);
    3523 // |xMap+xxt-MapWidth/2| -> min
    3524 while abs(2*(xMap+G.lx*(xxt*2))+2*xxt-MapWidth)<abs(2*xMap+2*xxt-MapWidth) do
    3525   inc(xMap,G.lx*(xxt*2));
    3526 yMap:=(y0-yw)*yyt-yyt;
    3527 NoMap.SetOutput(Buffer);
    3528 NoMap.SetPaintBounds(0,0,2*xxt,3*yyt);
    3529 NoMap.Paint(0,0,Loc,1,1,-1,-1,Style=pltsBlink);
    3530 PaintBufferToScreen(xMap,yMap,2*xxt,3*yyt);
    3531 end;
    3532 
    3533 // paint content of buffer directly to screen instead of offscreen
    3534 // panel protusions are added
    3535 // NoMap must be set to buffer and bounds before
    3536 procedure TMainScreen.PaintBufferToScreen(xMap,yMap,width,height: integer);
    3537 begin
    3538 if xMap+width>MapWidth then
    3539   width:=MapWidth-xMap;
    3540 if yMap+height>MapHeight then
    3541   height:=MapHeight-yMap;
    3542 if (width<=0) or (height<=0) or (width+xMap<=0) or (height+yMap<=0) then
    3543   exit;
    3544 
    3545 NoMap.BitBlt(Panel,-xMap-MapOffset,-yMap+MapHeight-overlap,xMidPanel,overlap,
    3546   0,0,SRCCOPY);
    3547 NoMap.BitBlt(Panel,-xMap-MapOffset+xRightPanel,-yMap+MapHeight-overlap,
    3548   Panel.Width-xRightPanel,overlap,xRightPanel,0,SRCCOPY);
    3549 if yMap<0 then
    3550   begin
    3551   if xMap<0 then
    3552     BitBlt(Canvas.Handle,MapOffset,TopBarHeight,width+xMap,height+yMap,
    3553       Buffer.Canvas.Handle,-xMap,-yMap,SRCCOPY)
    3554   else BitBlt(Canvas.Handle,xMap+MapOffset,TopBarHeight,width,height+yMap,
    3555     Buffer.Canvas.Handle,0,-yMap,SRCCOPY)
    3556   end
    3557 else
    3558   begin
    3559   if xMap<0 then
    3560     BitBlt(Canvas.Handle,MapOffset,TopBarHeight+yMap,width+xMap,height,
    3561       Buffer.Canvas.Handle,-xMap,0,SRCCOPY)
    3562   else BitBlt(Canvas.Handle,xMap+MapOffset,TopBarHeight+yMap,width,height,
    3563     Buffer.Canvas.Handle,0,0,SRCCOPY);
    3564   end
    3565 end;
    3566 
    3567 procedure TMainScreen.PaintLoc_BeforeMove(FromLoc: integer);
    3568 var
    3569 yLoc,x0: integer;
    3570 begin
    3571 if MapValid then
    3572   begin
    3573   yLoc:=(FromLoc+G.lx*1024) div G.lx -1024;
    3574   x0:=(FromLoc+(yLoc and 1+G.lx*1024) div 2) mod G.lx;
    3575   offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
    3576   ProcessRect(x0,yLoc,1,1,prPaint or prAutoBounds);
    3577   end
    3578 end;
    3579 
    3580 procedure TMainScreen.PaintDestination;
    3581 var
    3582 Destination: integer;
    3583 begin
    3584 if (UnFocus>=0) and (MyUn[UnFocus].Status and usGoto<>0) then
    3585   begin
    3586   Destination:=MyUn[UnFocus].Status shr 16;
    3587   if (Destination<>$7FFF) and (Destination<>MyUn[UnFocus].Loc) then
    3588     PaintLocTemp(Destination,pltsBlink);
    3589   end;
    3590 end;
    3591 
    3592 procedure TMainScreen.MiniPaint;
    3593 type
    3594 TLine=array[0..99999999,0..2] of Byte;
    3595 var
    3596 uix,cix,x,y,Loc,i,hw,xm,cm,cmPolOcean,cmPolNone:integer;
    3597 PrevMiniLine,MiniLine:^TLine;
    3598 begin
    3599 cmPolOcean:=GrExt[HGrSystem].Data.Canvas.Pixels[101,67];
    3600 cmPolNone:=GrExt[HGrSystem].Data.Canvas.Pixels[102,67];
    3601 hw:=MapWidth div (xxt*2);
    3602 with Mini.Canvas do
    3603   begin
    3604   Brush.Color:=$000000;
    3605   FillRect(Rect(0,0,Mini.Width,Mini.Height));
    3606   end;
    3607 MiniLine:=nil;
    3608 for y:=0 to G.ly-1 do
    3609   begin
    3610   PrevMiniLine:=MiniLine;
    3611   MiniLine:=Mini.ScanLine[y];
    3612   for x:=0 to G.lx-1 do if MyMap[x+G.lx*y] and fTerrain<>fUNKNOWN then
    3613     begin
    3614     Loc:=x+G.lx*y;
    3615     for i:=0 to 1 do
    3616       begin
    3617       xm:=((x-xwMini)*2+i+y and 1-hw+G.lx*5) mod (G.lx*2);
    3618       cm:=MiniColors[MyMap[Loc] and fTerrain,i];
    3619       if ClientMode=cEditMap then
    3620         begin
    3621         if MyMap[Loc] and (fPrefStartPos or fStartPos)<>0 then
    3622           cm:=$FFFFFF;
    3623         end
    3624       else if MyMap[Loc] and fCity<>0 then
    3625         begin
    3626         cix:=MyRO.nCity-1;
    3627         while (cix>=0) and (MyCity[cix].Loc<>Loc) do dec(cix);
    3628         if cix>=0 then cm:=Tribe[me].Color
    3629         else
    3630           begin
    3631           cix:=MyRO.nEnemyCity-1;
    3632           while (cix>=0) and (MyRO.EnemyCity[cix].Loc<>Loc) do dec(cix);
    3633           if cix>=0 then cm:=Tribe[MyRO.EnemyCity[cix].Owner].Color
    3634           end;
    3635         cm:=$808080 or cm shr 1; {increase brightness}
    3636         if PrevMiniLine<>nil then
    3637           begin // 2x2 city dot covers two scanlines
    3638           PrevMiniLine[xm,0]:=cm shr 16;
    3639           PrevMiniLine[xm,1]:=cm shr 8 and $FF;
    3640           PrevMiniLine[xm,2]:=cm and $FF;
     7649              GamePopup.Popup(Left + 4, Top + GetSystemMetrics(SM_CYCAPTION) + 4
     7650                + TopBarHeight - 1);
    36417651          end
    36427652        end
    3643       else if (i=0) and (MyMap[Loc] and fUnit<>0) then
    3644         begin
    3645         uix:=MyRO.nUn-1;
    3646         while (uix>=0) and (MyUn[uix].Loc<>Loc) do dec(uix);
    3647         if uix>=0 then cm:=Tribe[me].Color
     7653        else if IsPanelPixel(x, y) then
     7654          PanelBoxMouseDown(Sender, Button, Shift, x,
     7655            y - (ClientHeight - PanelHeight))
     7656        else if (y >= TopBarHeight) and (x >= MapOffset) and
     7657          (x < MapOffset + MapWidth) then
     7658          MapBoxMouseDown(Sender, Button, Shift, x - MapOffset,
     7659            y - TopBarHeight)
     7660    end;
     7661
     7662    procedure TMainScreen.FormMouseMove(Sender: TObject; Shift: TShiftState;
     7663      x, y: integer);
     7664    begin
     7665      if idle then
     7666        if IsPanelPixel(x, y) then
     7667          PanelBoxMouseMove(Sender, Shift, x, y - (ClientHeight - PanelHeight))
     7668        else if (y >= TopBarHeight) and (x >= MapOffset) and
     7669          (x < MapOffset + MapWidth) then
     7670          MapBoxMouseMove(Sender, Shift, x - MapOffset, y - TopBarHeight);
     7671    end;
     7672
     7673    procedure TMainScreen.FormMouseUp(Sender: TObject; Button: TMouseButton;
     7674      Shift: TShiftState; x, y: integer);
     7675    begin
     7676      if idle then
     7677        PanelBoxMouseUp(Sender, Button, Shift, x,
     7678          y - (ClientHeight - PanelHeight));
     7679    end;
     7680
     7681    procedure TMainScreen.FormPaint(Sender: TObject);
     7682    begin
     7683      MainOffscreenPaint;
     7684      if (MapOffset > 0) or (MapOffset + MapWidth < ClientWidth) then
     7685        with Canvas do
     7686        begin // pillarbox, make left and right border black
     7687          if me < 0 then
     7688            Brush.Color := $000000
     7689          else
     7690            Brush.Color := EmptySpaceColor;
     7691          if xMidPanel > MapOffset then
     7692            FillRect(Rect(0, TopBarHeight, MapOffset, TopBarHeight + MapHeight
     7693              - overlap))
     7694          else
     7695          begin
     7696            FillRect(Rect(0, TopBarHeight, xMidPanel, TopBarHeight + MapHeight -
     7697              overlap));
     7698            FillRect(Rect(xMidPanel, TopBarHeight, MapOffset,
     7699              TopBarHeight + MapHeight));
     7700          end;
     7701          if xRightPanel < MapOffset + MapWidth then
     7702            FillRect(Rect(MapOffset + MapWidth, TopBarHeight, ClientWidth,
     7703              TopBarHeight + MapHeight - overlap))
     7704          else
     7705          begin
     7706            FillRect(Rect(MapOffset + MapWidth, TopBarHeight, xRightPanel,
     7707              TopBarHeight + MapHeight));
     7708            FillRect(Rect(xRightPanel, TopBarHeight, ClientWidth,
     7709              TopBarHeight + MapHeight - overlap));
     7710          end;
     7711          Brush.Style := bsClear;
     7712        end;
     7713      BitBlt(Canvas.Handle, MapOffset, TopBarHeight, MapWidth,
     7714        MapHeight - overlap, offscreen.Canvas.Handle, 0, 0, SRCCOPY);
     7715      BitBlt(Canvas.Handle, 0, 0, ClientWidth, TopBarHeight,
     7716        TopBar.Canvas.Handle, 0, 0, SRCCOPY);
     7717      if xMidPanel > MapOffset then
     7718        BitBlt(Canvas.Handle, xMidPanel, TopBarHeight + MapHeight - overlap,
     7719          ClientWidth div 2 - xMidPanel, overlap, offscreen.Canvas.Handle,
     7720          xMidPanel - MapOffset, MapHeight - overlap, SRCCOPY)
     7721      else
     7722        BitBlt(Canvas.Handle, MapOffset, TopBarHeight + MapHeight - overlap,
     7723          ClientWidth div 2 - MapOffset, overlap, offscreen.Canvas.Handle, 0,
     7724          MapHeight - overlap, SRCCOPY);
     7725      if xRightPanel < MapOffset + MapWidth then
     7726        BitBlt(Canvas.Handle, ClientWidth div 2, TopBarHeight + MapHeight -
     7727          overlap, xRightPanel - ClientWidth div 2, overlap,
     7728          offscreen.Canvas.Handle, ClientWidth div 2 - MapOffset,
     7729          MapHeight - overlap, SRCCOPY)
     7730      else
     7731        BitBlt(Canvas.Handle, ClientWidth div 2, TopBarHeight + MapHeight -
     7732          overlap, MapOffset + MapWidth - ClientWidth div 2, overlap,
     7733          offscreen.Canvas.Handle, ClientWidth div 2 - MapOffset,
     7734          MapHeight - overlap, SRCCOPY);
     7735      BitBlt(Canvas.Handle, 0, TopBarHeight + MapHeight - overlap, xMidPanel,
     7736        overlap, Panel.Canvas.Handle, 0, 0, SRCCOPY);
     7737      BitBlt(Canvas.Handle, xRightPanel, TopBarHeight + MapHeight - overlap,
     7738        Panel.width - xRightPanel, overlap, Panel.Canvas.Handle, xRightPanel,
     7739        0, SRCCOPY);
     7740      BitBlt(Canvas.Handle, 0, TopBarHeight + MapHeight, Panel.width,
     7741        PanelHeight - overlap, Panel.Canvas.Handle, 0, overlap, SRCCOPY);
     7742      if (pLogo >= 0) and (G.RO[pLogo] = nil) and (AILogo[pLogo] <> nil) then
     7743        BitBlt(Canvas.Handle, xRightPanel + 10 - (16 + 64),
     7744          ClientHeight - PanelHeight, 64, 64, AILogo[pLogo].Canvas.Handle, 0, 0,
     7745          SRCCOPY);
     7746    end;
     7747
     7748    procedure TMainScreen.RectInvalidate(Left, Top, Rigth, Bottom: integer);
     7749    var
     7750      r0: HRgn;
     7751    begin
     7752      r0 := CreateRectRgn(Left, Top, Rigth, Bottom);
     7753      InvalidateRgn(Handle, r0, false);
     7754      DeleteObject(r0);
     7755    end;
     7756
     7757    procedure TMainScreen.SmartRectInvalidate(Left, Top, Rigth,
     7758      Bottom: integer);
     7759    var
     7760      i: integer;
     7761      r0, r1: HRgn;
     7762    begin
     7763      r0 := CreateRectRgn(Left, Top, Rigth, Bottom);
     7764      for i := 0 to ControlCount - 1 do
     7765        if not(Controls[i] is TArea) and Controls[i].Visible then
     7766        begin
     7767          with Controls[i].BoundsRect do
     7768            r1 := CreateRectRgn(Left, Top, Right, Bottom);
     7769          CombineRgn(r0, r0, r1, RGN_DIFF);
     7770          DeleteObject(r1);
     7771        end;
     7772      InvalidateRgn(Handle, r0, false);
     7773      DeleteObject(r0);
     7774    end;
     7775
     7776    procedure TMainScreen.mRepClicked(Sender: TObject);
     7777    begin
     7778      with TMenuItem(Sender) do
     7779      begin
     7780        Checked := not Checked;
     7781        if Checked then
     7782          CityRepMask := CityRepMask or (1 shl (Tag shr 8))
    36487783        else
     7784          CityRepMask := CityRepMask and not(1 shl (Tag shr 8))
     7785      end
     7786    end;
     7787
     7788    procedure TMainScreen.mLogClick(Sender: TObject);
     7789    begin
     7790      LogDlg.Show
     7791    end;
     7792
     7793    procedure TMainScreen.FormShow(Sender: TObject);
     7794    begin
     7795      Timer1.Enabled := true
     7796    end;
     7797
     7798    procedure TMainScreen.FormClose(Sender: TObject; var Action: TCloseAction);
     7799    begin
     7800      Timer1.Enabled := false
     7801    end;
     7802
     7803    procedure TMainScreen.Radio(Sender: TObject);
     7804    begin
     7805      TMenuItem(Sender).Checked := true
     7806    end;
     7807
     7808    procedure TMainScreen.mManipClick(Sender: TObject);
     7809    var
     7810      Flag: integer;
     7811    begin
     7812      with TMenuItem(Sender) do
     7813      begin
     7814        Flag := 1 shl (Tag shr 8);
     7815        if Checked then
     7816          Server(sClearTestFlag, 0, Flag, nil^)
     7817        else
     7818        begin
     7819          Server(sSetTestFlag, 0, Flag, nil^);
     7820          Play('CHEAT');
     7821        end;
     7822        if not supervising then
     7823        begin
     7824          if Flag = tfUncover then
    36497825          begin
    3650           uix:=MyRO.nEnemyUn-1;
    3651           while (uix>=0) and (MyRO.EnemyUn[uix].Loc<>Loc) do dec(uix);
    3652           if uix>=0 then cm:=Tribe[MyRO.EnemyUn[uix].Owner].Color
    3653           end;
    3654         cm:=$808080 or cm shr 1; {increase brightness}
    3655         end
    3656       else if MapOptionChecked and (1 shl moPolitical)<>0 then
    3657         begin
    3658         if MyMap[Loc] and fTerrain<fGrass then cm:=cmPolOcean
    3659         else if MyRO.Territory[Loc]<0 then cm:=cmPolNone
    3660         else cm:=Tribe[MyRO.Territory[Loc]].Color;
    3661         end;
    3662       MiniLine[xm,0]:=cm shr 16;
    3663       MiniLine[xm,1]:=cm shr 8 and $FF;
    3664       MiniLine[xm,2]:=cm and $FF;
    3665       end;
    3666     end
    3667   end;
    3668 end;
    3669 
    3670 procedure TMainScreen.MainOffscreenPaint;
    3671 var
    3672 ProcessOptions: integer;
    3673 rec:TRect;
    3674 DoInvalidate: boolean;
    3675 begin
    3676 if me<0 then
    3677   with offscreen.Canvas do
    3678     begin
    3679     Brush.Color:=$000000;
    3680     FillRect(Rect(0,0,MapWidth,MapHeight));
    3681     Brush.Style:=bsClear;
    3682     OffscreenUser:=self;
    3683     exit
    3684     end;
    3685 
    3686 MainMap.SetPaintBounds(0,0,MapWidth,MapHeight);
    3687 if OffscreenUser<>self then
    3688   begin
    3689   if OffscreenUser<>nil then OffscreenUser.Update;
    3690     // complete working with old owner to prevent rebound
    3691   if MapValid and (xwd=xw) and (ywd=yw) then
    3692     MainMap.SetPaintBounds(0,0,UsedOffscreenWidth,UsedOffscreenHeight);
    3693   MapValid:=false;
    3694   OffscreenUser:=self;
    3695   end;
    3696 
    3697 if xw-xwd>G.lx div 2 then xwd:=xwd+G.lx
    3698 else if xwd-xw>G.lx div 2 then xwd:=xwd-G.lx;
    3699 if not MapValid or (xw-xwd>MapWidth div (xxt*2)) or (xwd-xw>MapWidth div (xxt*2))
    3700   or (yw-ywd>MapHeight div yyt) or (ywd-yw>MapHeight div yyt) then
    3701   begin
    3702   offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
    3703   ProcessRect(xw,yw,MapWidth div xxt,MapHeight div yyt,prPaint or prInvalidate)
    3704   end
    3705 else
    3706   begin
    3707   if (xwd=xw) and (ywd=yw) then exit; {map window not moved}
    3708   offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
    3709   rec:=Rect(0,0,MapWidth,MapHeight);
    3710   ScrollDC(offscreen.Canvas.Handle,(xwd-xw)*(xxt*2),(ywd-yw)*yyt,rec,rec,0,nil);
    3711   for DoInvalidate:=false to FastScrolling do
    3712     begin
    3713     if DoInvalidate then
    3714       begin
    3715       rec.bottom:=MapHeight-overlap;
    3716       ScrollDC(Canvas.Handle,(xwd-xw)*(xxt*2),(ywd-yw)*yyt,rec,rec,0,nil);
    3717       ProcessOptions:=prInvalidate;
    3718       end
    3719     else ProcessOptions:=prPaint or prAutoBounds;
    3720     if yw<ywd then
    3721       begin
    3722       ProcessRect(xw,yw,MapWidth div xxt,ywd-yw-1,ProcessOptions);
    3723       if xw<xwd then
    3724         ProcessRect(xw,ywd,(xwd-xw)*2-1,MapHeight div yyt-ywd+yw,ProcessOptions)
    3725       else if xw>xwd then
    3726         ProcessRect((xwd+MapWidth div (xxt*2)) mod G.lx,ywd,(xw-xwd)*2+1,
    3727           MapHeight div yyt-ywd+yw,ProcessOptions)
    3728       end
    3729     else if yw>ywd then
    3730       begin
    3731       if DoInvalidate then
    3732         RectInvalidate(MapOffset,TopBarHeight+MapHeight-overlap-(yw-ywd)*yyt,MapOffset+MapWidth,
    3733           TopBarHeight+MapHeight-overlap)
    3734       else ProcessRect(xw,(ywd+MapHeight div (yyt*2) *2),MapWidth div xxt,
    3735         yw-ywd+1,ProcessOptions);
    3736       if xw<xwd then
    3737         ProcessRect(xw,yw,(xwd-xw)*2-1,MapHeight div yyt-yw+ywd-2,
    3738           ProcessOptions)
    3739       else if xw>xwd then
    3740         ProcessRect((xwd+MapWidth div (xxt*2)) mod G.lx,yw,(xw-xwd)*2+1,
    3741           MapHeight div yyt-yw+ywd-2,ProcessOptions)
    3742       end
    3743     else
    3744       if xw<xwd then
    3745         ProcessRect(xw,yw,(xwd-xw)*2-1,MapHeight div yyt,ProcessOptions)
    3746       else if xw>xwd then
    3747         ProcessRect((xwd+MapWidth div (xxt*2)) mod G.lx,yw,(xw-xwd)*2+1,
    3748           MapHeight div yyt,ProcessOptions);
    3749     end;
    3750   if not FastScrolling then
    3751     RectInvalidate(MapOffset,TopBarHeight,MapOffset+MapWidth,TopBarHeight+MapHeight-overlap);
    3752   RectInvalidate(xMidPanel,TopBarHeight+MapHeight-overlap,xRightPanel,TopBarHeight+MapHeight)
    3753   end;
    3754 //if (xwd<>xw) or (ywd<>yw) then
    3755 //  Server(sChangeSuperView,me,yw*G.lx+xw,nil^); // for synchronizing client side viewer, not used currently
    3756 xwd:=xw;ywd:=yw;
    3757 MapValid:=true;
    3758 end;
    3759 
    3760 procedure TMainScreen.PaintAll;
    3761 begin
    3762 MainOffscreenPaint;
    3763 xwMini:=xw; ywMini:=yw;
    3764 MiniPaint;
    3765 PanelPaint;
    3766 end;
    3767 
    3768 procedure TMainScreen.PaintAllMaps;
    3769 begin
    3770 MainOffscreenPaint;
    3771 xwMini:=xw; ywMini:=yw;
    3772 MiniPaint;
    3773 CopyMiniToPanel;
    3774 RectInvalidate(xMini+2,TopBarHeight+MapHeight-overlap+yMini+2,xMini+2+G.lx*2,
    3775   TopBarHeight+MapHeight-overlap+yMini+2+G.ly);
    3776 end;
    3777 
    3778 procedure TMainScreen.CopyMiniToPanel;
    3779 begin
    3780 BitBlt(Panel.Canvas.Handle,xMini+2,yMini+2,G.lx*2,G.ly,Mini.Canvas.Handle,0,0,SRCCOPY);
    3781 if MarkCityLoc>=0 then
    3782   Sprite(Panel, HGrSystem, xMini-2+(4*G.lx+2*(MarkCityLoc mod G.lx)
    3783     +(G.lx-MapWidth div (xxt*2))-2*xwd) mod (2*G.lx) +MarkCityLoc div G.lx and 1,
    3784     yMini-3+MarkCityLoc div G.lx,10,10,77,47)
    3785 else if ywmax<=0 then
    3786   Frame(Panel.Canvas,xMini+2+G.lx-MapWidth div (xxt*2),yMini+2,
    3787     xMini+1+G.lx+MapWidth div (xxt*2),
    3788     yMini+2+G.ly-1,MainTexture.clMark,MainTexture.clMark)
    3789 else Frame(Panel.Canvas,xMini+2+G.lx-MapWidth div (xxt*2),yMini+2+yw,
    3790   xMini+1+G.lx+MapWidth div (xxt*2),
    3791   yMini+yw+MapHeight div yyt,MainTexture.clMark,MainTexture.clMark);
    3792 end;
    3793 
    3794 procedure TMainScreen.PanelPaint;
    3795 
    3796   function MovementToString(var Un: TUn): string;
    3797   begin
    3798   result:=ScreenTools.MovementToString(Un.Movement);
    3799   if Un.Master>=0 then
    3800     result:='('+result+')'
    3801   else if (MyModel[Un.mix].Domain=dAir)
    3802     and (MyModel[Un.mix].Kind<>mkSpecial_Glider) then
    3803     result:=Format('%s(%d)',[result,Un.Fuel]);
    3804   end;
    3805 
    3806 var
    3807 i,uix,uixDefender,x,xSrc,ySrc,xSrcBase,ySrcBase,CostFactor,Count,mixShow,
    3808   xTreasurySection,xResearchSection,JobFocus,TrueMoney,
    3809   TrueResearch: integer;
    3810 Tile: cardinal;
    3811 s: string;
    3812 unx:TUn;
    3813 UnitInfo: TUnitInfo;
    3814 JobProgressData: TJobProgressData;
    3815 Prio: boolean;
    3816 begin
    3817 with Panel.Canvas do
    3818   begin
    3819   Fill(Panel.Canvas,0,3,xMidPanel+7-10,PanelHeight-3,
    3820     wMainTexture-(xMidPanel+7-10),hMainTexture-PanelHeight);
    3821   Fill(Panel.Canvas,xRightPanel+10-7,3,Panel.Width-xRightPanel-10+7,PanelHeight-3,
    3822     -(xRightPanel+10-7),hMainTexture-PanelHeight);
    3823   FillLarge(Panel.Canvas,xMidPanel-2,PanelHeight-MidPanelHeight,xRightPanel+2,PanelHeight,
    3824     ClientWidth div 2);
    3825 
    3826   Brush.Style:=bsClear;
    3827   Pen.Color:=$000000;
    3828   MoveTo(0,0);LineTo(xMidPanel+7-8,0); LineTo(xMidPanel+7-8,PanelHeight-MidPanelHeight);
    3829   LineTo(xRightPanel,PanelHeight-MidPanelHeight); LineTo(xRightPanel,0);
    3830   LineTo(ClientWidth,0);
    3831   Pen.Color:=MainTexture.clBevelLight;
    3832   MoveTo(xMidPanel+7-9,PanelHeight-MidPanelHeight+2);
    3833   LineTo(xRightPanel+10-8,PanelHeight-MidPanelHeight+2);
    3834   Pen.Color:=MainTexture.clBevelLight;
    3835   MoveTo(0,1);LineTo(xMidPanel+7-9,1); Pen.Color:=MainTexture.clBevelShade;
    3836   LineTo(xMidPanel+7-9,PanelHeight-MidPanelHeight+1); Pen.Color:=MainTexture.clBevelLight;
    3837   LineTo(xRightPanel+10-9,PanelHeight-MidPanelHeight+1); Pen.Color:=MainTexture.clBevelLight;
    3838   LineTo(xRightPanel+10-9,1); LineTo(ClientWidth,1);
    3839   MoveTo(ClientWidth,2); LineTo(xRightPanel+10-8,2); LineTo(xRightPanel+10-8,PanelHeight);
    3840   MoveTo(0,2);LineTo(xMidPanel+7-10,2); Pen.Color:=MainTexture.clBevelShade;
    3841   LineTo(xMidPanel+7-10,PanelHeight);
    3842   Corner(Panel.Canvas,xMidPanel+7-16,1,1,MainTexture);
    3843   Corner(Panel.Canvas,xRightPanel+10-9,1,0,MainTexture);
    3844   if ClientMode<>cEditMap then
    3845     begin
    3846     if supervising then
    3847       begin
    3848       Frame(Panel.Canvas, ClientWidth-xPalace-1, yPalace-1,
    3849         ClientWidth-xPalace+xSizeBig, yPalace+ySizeBig, $B0B0B0, $FFFFFF);
    3850       RFrame(Panel.Canvas, ClientWidth-xPalace-2, yPalace-2,
    3851         ClientWidth-xPalace+xSizeBig+1, yPalace+ySizeBig+1, $FFFFFF, $B0B0B0);
    3852       BitBlt(Panel.Canvas.Handle, ClientWidth-xPalace, yPalace, xSizeBig,
    3853         ySizeBig, GrExt[HGrSystem2].Data.Canvas.Handle, 70, 123, SRCCOPY);
    3854       end
    3855     else if MyRO.NatBuilt[imPalace]>0 then
    3856       ImpImage(Panel.Canvas, ClientWidth-xPalace, yPalace, imPalace, -1, GameMode<>cMovie
    3857        {(GameMode<>cMovie) and (MyRO.Government<>gAnarchy)})
    3858     else ImpImage(Panel.Canvas, ClientWidth-xPalace, yPalace, 21, -1, GameMode<>cMovie
    3859       {(GameMode<>cMovie) and (MyRO.Government<>gAnarchy)});
    3860     end;
    3861 
    3862   if GameMode=cMovie then
    3863     Frame(Panel.Canvas,xMini+1,yMini+1,xMini+2+G.lx*2,yMini+2+G.ly,$000000,$000000)
    3864   else
    3865     begin
    3866     Frame(Panel.Canvas,xMini+1,yMini+1,xMini+2+G.lx*2,yMini+2+G.ly,$B0B0B0,$FFFFFF);
    3867     RFrame(Panel.Canvas,xMini,yMini,xMini+3+G.lx*2,yMini+3+G.ly,$FFFFFF,$B0B0B0);
    3868     end;
    3869   CopyMiniToPanel;
    3870   if ClientMode<>cEditMap then // MapBtn icons
    3871     for i:=0 to 5 do if i<>3 then
    3872       Dump(Panel,HGrSystem,xMini+G.lx-42+16*i,PanelHeight-26,8,8,121+i*9,61);
    3873 
    3874   if ClientMode=cEditMap then
    3875     begin
    3876     for i:=0 to TrRow-1 do trix[i]:=-1;
    3877     Count:=0;
    3878     for i:=0 to nBrushTypes-1 do
    3879       begin // display terrain types
    3880       if (Count>=TrRow*sb.si.npos) and (Count<TrRow*(sb.si.npos+1)) then
    3881         begin
    3882         trix[Count-TrRow*sb.si.npos]:=BrushTypes[i];
    3883         x:=(Count-TrRow*sb.si.npos)*TrPitch;
    3884         xSrcBase:=-1;
    3885         case BrushTypes[i] of
    3886           0..8: begin xSrc:=BrushTypes[i]; ySrc:=0 end;
    3887           9..30:
    3888             begin
    3889             xSrcBase:=2; ySrcBase:=2;
    3890             xSrc:=0; ySrc:=2*integer(BrushTypes[i])-15
    3891             end;
    3892           fRiver: begin xSrc:=7; ySrc:=14 end;
    3893           fRoad: begin xSrc:=0; ySrc:=9 end;
    3894           fRR: begin xSrc:=0; ySrc:=10 end;
    3895           fCanal: begin xSrc:=0; ySrc:=11 end;
    3896           fPoll: begin xSrc:=6; ySrc:=12 end;
    3897           fDeadLands,fDeadLands or fCobalt,fDeadLands or fUranium,
    3898             fDeadLands or fMercury:
    3899             begin
    3900             xSrcBase:=6; ySrcBase:=2;
    3901             xSrc:=8; ySrc:=12+BrushTypes[i] shr 25;
    3902             end;
    3903           tiIrrigation, tiFarm, tiMine, tiBase:
    3904             begin xSrc:=BrushTypes[i] shr 12-1; ySrc:=12 end;
    3905           tiFort:
    3906             begin xSrc:=3; ySrc:=12; xSrcBase:=7; ySrcBase:=12 end;
    3907           fPrefStartPos: begin xSrc:=0; ySrc:=1 end;
    3908           fStartPos: begin xSrc:=0; ySrc:=2 end;
    3909           end;
    3910         if xSrcBase>=0 then
    3911           Sprite(Panel,HGrTerrain,xTroop+2+x,yTroop+9-yyt,xxt*2,yyt*3,
    3912             1+xSrcBase*(xxt*2+1),1+ySrcBase*(yyt*3+1));
    3913         Sprite(Panel,HGrTerrain,xTroop+2+x,yTroop+9-yyt,xxt*2,yyt*3,
    3914           1+xSrc*(xxt*2+1),1+ySrc*(yyt*3+1));
    3915         if BrushTypes[i]=BrushType then
    3916           begin
    3917           Frame(Panel.Canvas,xTroop+2+x,yTroop+7-yyt div 2,xTroop+2*xxt+x,
    3918             yTroop+2*yyt+11,$000000,$000000);
    3919           Frame(Panel.Canvas,xTroop+1+x,yTroop+6-yyt div 2,xTroop+2*xxt-1+x,
    3920             yTroop+2*yyt+10,MainTexture.clMark,MainTexture.clMark);
     7826            MapValid := false;
     7827            PaintAllMaps;
    39217828          end
    3922         end;
    3923       inc(Count)
    3924       end;
    3925     case BrushType of
    3926       fDesert, fPrairie, fTundra, fArctic, fSwamp, fHills, fMountains:
    3927         s:=Phrases.Lookup('TERRAIN',BrushType);
    3928       fShore: s:=Format(Phrases.Lookup('TWOTERRAINS'),
    3929         [Phrases.Lookup('TERRAIN',fOcean),Phrases.Lookup('TERRAIN',fShore)]);
    3930       fGrass: s:=Format(Phrases.Lookup('TWOTERRAINS'),
    3931         [Phrases.Lookup('TERRAIN',fGrass),Phrases.Lookup('TERRAIN',fGrass+12)]);
    3932       fForest: s:=Format(Phrases.Lookup('TWOTERRAINS'),
    3933         [Phrases.Lookup('TERRAIN',fForest),Phrases.Lookup('TERRAIN',fJungle)]);
    3934       fRiver: s:=Phrases.Lookup('RIVER');
    3935       fDeadLands,fDeadLands or fCobalt,fDeadLands or fUranium,
    3936         fDeadLands or fMercury:
    3937         s:=Phrases.Lookup('TERRAIN',3*12+BrushType shr 25);
    3938       fPrefStartPos: s:=Phrases.Lookup('MAP_PREFSTART');
    3939       fStartPos: s:=Phrases.Lookup('MAP_START');
    3940       fPoll: s:=Phrases.Lookup('POLL');
    3941       else // terrain improvements
    3942         begin
    3943         case BrushType of
    3944           fRoad: i:=1;
    3945           fRR: i:=2;
    3946           tiIrrigation: i:=4;
    3947           tiFarm: i:=5;
    3948           tiMine: i:=7;
    3949           fCanal: i:=8;
    3950           tiFort: i:=10;
    3951           tiBase: i:=12;
    3952           end;
    3953         s:=Phrases.Lookup('JOBRESULT',i);
    3954         end
    3955       end;
    3956     LoweredTextOut(Panel.Canvas,-1,MainTexture,xTroop+1,PanelHeight-19,s);
    3957     end
    3958   else if TroopLoc>=0 then
    3959     begin
    3960     Brush.Style:=bsClear;
    3961     if UnFocus>=0 then with MyUn[UnFocus],MyModel[mix] do
    3962       begin {display info about selected unit}
    3963       if Job=jCity then
    3964         mixShow:=-1 // building site
    3965       else mixShow:=mix;
    3966       with Tribe[me].ModelPicture[mixShow] do
    3967         begin
    3968         Sprite(Panel,HGr,xMidPanel+7+12,yTroop+1,64,48,
    3969           pix mod 10 *65+1,pix div 10 *49+1);
    3970         if MyUn[UnFocus].Flags and unFortified<>0 then
    3971           Sprite(Panel,HGrStdUnits,xMidPanel+7+12,yTroop+1,xxu*2,yyu*2,1+6*(xxu*2+1),1);
    3972         end;
    3973 
    3974       MakeBlue(Panel,xMidPanel+7+12+10,yTroop-13,44,12);
    3975       s:=MovementToString(MyUn[UnFocus]);
    3976       RisedTextOut(Panel.Canvas,xMidPanel+7+12+32-BiColorTextWidth(Panel.Canvas,s) div 2,
    3977         yTroop-16,s);
    3978 
    3979       s:=IntToStr(Health)+'%';
    3980       LightGradient(Panel.Canvas,xMidPanel+7+12+7,PanelHeight-22,(Health+1) div 2,
    3981         (ColorOfHealth(Health) and $FEFEFE shr 2)*3);
    3982       if Health<100 then
    3983         LightGradient(Panel.Canvas,xMidPanel+7+12+7+(Health+1) div 2,
    3984           PanelHeight-22,50-(Health+1) div 2,$000000);
    3985       RisedTextOut(Panel.Canvas,xMidPanel+7+12+32-BiColorTextWidth(Panel.Canvas,s) div 2,
    3986         PanelHeight-23,s);
    3987 
    3988       FrameImage(Panel.Canvas,GrExt[HGrSystem].Data,xMidPanel+7+xUnitText,yTroop+15,12,14,
    3989         121+Exp div ExpCost *13,28);
    3990       if Job=jCity then s:=Tribe[me].ModelName[-1]
    3991       else s:=Tribe[me].ModelName[mix];
    3992       if Home>=0 then
    3993         begin
    3994         LoweredTextOut(Panel.Canvas,-1,MainTexture,xMidPanel+7+xUnitText+18,yTroop+5,s);
    3995         LoweredTextOut(Panel.Canvas,-1,MainTexture,xMidPanel+7+xUnitText+18,yTroop+21,
    3996           '('+CityName(MyCity[Home].ID)+')');
    3997         end
    3998       else LoweredTextOut(Panel.Canvas,-1,MainTexture,xMidPanel+7+xUnitText+18,yTroop+13,s);
    3999       end;
    4000 
    4001     if (UnFocus>=0) and (MyUn[UnFocus].Loc<>TroopLoc) then
    4002       begin // divide panel
    4003       if SmallScreen and not supervising then
    4004         x:=xTroop-8
    4005       else x:=xTroop-152;
    4006       Pen.Color:=MainTexture.clBevelShade;
    4007       MoveTo(x-1,PanelHeight-MidPanelHeight+2);
    4008       LineTo(x-1,PanelHeight);
    4009       Pen.Color:=MainTexture.clBevelLight;
    4010       MoveTo(x,PanelHeight-MidPanelHeight+2);
    4011       LineTo(x,PanelHeight);
    4012       end;
    4013 
    4014     for i:=0 to 23 do trix[i]:=-1;
    4015     if MyMap[TroopLoc] and fUnit<>0 then
    4016       begin
    4017       if MyMap[TroopLoc] and fOwned<>0 then
    4018         begin
    4019         if (TrCnt>1) or (UnFocus<0) or (MyUn[UnFocus].Loc<>TroopLoc) then
    4020           begin
    4021           LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop+10, PanelHeight-24,
    4022             Phrases.Lookup('PRESENT'));
    4023           Server(sGetDefender,me,TroopLoc,uixDefender);
    4024           Count:=0;
    4025           for Prio:=true downto false do
    4026             for uix:=0 to MyRO.nUn-1 do if (uix=uixDefender)=Prio then
    4027               begin // display own units
    4028               unx:=MyUn[uix];
    4029               if unx.Loc=TroopLoc then
    4030                 begin
    4031                 if (Count>=TrRow*sb.si.npos) and (Count<TrRow*(sb.si.npos+1)) then
    4032                   begin
    4033                   trix[Count-TrRow*sb.si.npos]:=uix;
    4034                   MakeUnitInfo(me,unx,UnitInfo);
    4035                   x:=(Count-TrRow*sb.si.npos)*TrPitch;
    4036                   if uix=UnFocus then
    4037                     begin
    4038                     Frame(Panel.Canvas,xTroop+4+x,yTroop+3,xTroop+64+x,
    4039                       yTroop+47,$000000,$000000);
    4040                     Frame(Panel.Canvas,xTroop+3+x,yTroop+2,xTroop+63+x,
    4041                       yTroop+46,MainTexture.clMark,MainTexture.clMark);
    4042                     end
    4043                   else if (unx.Master>=0) and (unx.Master=UnFocus) then
    4044                     begin
    4045                     CFrame(Panel.Canvas,xTroop+4+x,yTroop+3,xTroop+64+x,
    4046                       yTroop+47,8,$000000);
    4047                     CFrame(Panel.Canvas,xTroop+3+x,yTroop+2,xTroop+63+x,
    4048                       yTroop+46,8,MainTexture.clMark);
    4049                     end;
    4050                   NoMap.SetOutput(Panel);
    4051                   NoMap.PaintUnit(xTroop+2+x,yTroop+1,UnitInfo,unx.Status);
    4052                   if (ClientMode<scContact)
    4053                     and ((unx.Job>jNone)
    4054                       or (unx.Status and (usStay or usRecover or usGoto)<>0)) then
    4055                     Sprite(Panel, HGrSystem, xTroop+2+60-20+x, yTroop+35,
    4056                       20, 20, 81, 25);
    4057 
    4058                   if not supervising then
    4059                     begin
    4060                     MakeBlue(Panel,xTroop+2+10+x,yTroop-13,44,12);
    4061                     s:=MovementToString(unx);
    4062                     RisedTextOut(Panel.Canvas,xTroop+x+34-BiColorTextWidth(Panel.Canvas,s) div 2,
    4063                       yTroop-16,s);
    4064                     end
    4065                   end;
    4066                 inc(Count)
    4067                 end;
    4068               end; // for uix:=0 to MyRO.nUn-1
    4069           assert(Count=TrCnt);
    4070           end
    4071         end
    4072       else
    4073         begin
    4074         LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop+8, PanelHeight-24,
    4075           Phrases.Lookup('PRESENT'));
    4076         Server(sGetUnits,me,TroopLoc,Count);
    4077         for i:=0 to Count-1 do
    4078           if (i>=TrRow*sb.si.npos) and (i<TrRow*(sb.si.npos+1)) then
    4079             begin // display enemy units
    4080             trix[i-TrRow*sb.si.npos]:=i;
    4081             x:=(i-TrRow*sb.si.npos)*TrPitch;
    4082             NoMap.SetOutput(Panel);
    4083             NoMap.PaintUnit(xTroop+2+x,yTroop+1,MyRO.EnemyUn[MyRO.nEnemyUn+i],0);
    4084             end;
    4085         end;
    4086       end;
    4087     if not SmallScreen or supervising then
    4088       begin // show terrain and improvements
    4089       PaintZoomedTile(Panel, xTerrain-xxt*2, 110-yyt*3, TroopLoc);
    4090       if (UnFocus>=0) and (MyUn[UnFocus].Job<>jNone) then
    4091         begin
    4092         JobFocus:=MyUn[UnFocus].Job;
    4093         Server(sGetJobProgress, me, MyUn[UnFocus].Loc, JobProgressData);
    4094         MakeBlue(Panel,xTerrain-72,148-17,144,31);
    4095         PaintRelativeProgressBar(Panel.Canvas,3,xTerrain-68,148+3,63,
    4096           JobProgressData[JobFocus].Done,
    4097           JobProgressData[JobFocus].NextTurnPlus,
    4098           JobProgressData[JobFocus].Required,true,MainTexture);
    4099         s:=Format('%s/%s',[ScreenTools.MovementToString(JobProgressData[JobFocus].Done),
    4100           ScreenTools.MovementToString(JobProgressData[JobFocus].Required)]);
    4101         RisedTextOut(Panel.Canvas,xTerrain+6,148-3,s);
    4102         Tile:=MyMap[MyUn[UnFocus].Loc];
    4103         if (JobFocus=jRoad) and (Tile and fRiver<>0) then
    4104           JobFocus:=nJob+0
    4105         else if (JobFocus=jRR) and (Tile and fRiver<>0) then
    4106           JobFocus:=nJob+1
    4107         else if JobFocus=jClear then
    4108           begin
    4109           if Tile and fTerrain=fForest then
    4110             JobFocus:=nJob+2
    4111           else if Tile and fTerrain=fDesert then
    4112             JobFocus:=nJob+3
    4113           else JobFocus:=nJob+4
    4114           end;
    4115         s:=Phrases.Lookup('JOBRESULT', JobFocus);
    4116         RisedTextOut(Panel.Canvas,xTerrain-BiColorTextWidth(Panel.Canvas,s) div 2,
    4117           148-19,s);
    4118         end;
    4119       if MyMap[TroopLoc] and (fTerrain or fSpecial)=fGrass or fSpecial1 then
    4120         s:=Phrases.Lookup('TERRAIN',fGrass+12)
    4121       else if MyMap[TroopLoc] and fDeadlands<>0 then
    4122         s:=Phrases.Lookup('TERRAIN',3*12)
    4123       else if (MyMap[TroopLoc] and fTerrain=fForest)
    4124         and IsJungle(TroopLoc div G.lx) then
    4125         s:=Phrases.Lookup('TERRAIN',fJungle)
    4126       else s:=Phrases.Lookup('TERRAIN',MyMap[TroopLoc] and fTerrain);
    4127       RisedTextOut(Panel.Canvas,xTerrain-BiColorTextWidth(Panel.Canvas,s) div 2,
    4128         99,s);
    4129       end;
    4130 
    4131     if TerrainBtn.Visible then with TerrainBtn do
    4132       RFrame(Panel.Canvas,Left-1,Top-self.ClientHeight+(PanelHeight-1),
    4133         Left+Width,Top+Height-self.ClientHeight+PanelHeight,
    4134         MainTexture.clBevelShade,MainTexture.clBevelLight)
    4135     end {if TroopLoc>=0}
    4136   end;
    4137 
    4138 for i:=0 to ControlCount-1 do
    4139   if Controls[i] is TButtonB then with TButtonB(Controls[i]) do
    4140     begin
    4141     if Visible then
    4142       begin
    4143       Dump(Panel,HGrSystem,Left,Top-self.ClientHeight+PanelHeight,25,25,169,243);
    4144       Sprite(Panel,HGrSystem,Left,Top-self.ClientHeight+PanelHeight,25,25,
    4145         1+26*ButtonIndex,337);
    4146       RFrame(Panel.Canvas,Left-1,Top-self.ClientHeight+(PanelHeight-1),
    4147         Left+Width,Top+Height-self.ClientHeight+PanelHeight,
    4148         MainTexture.clBevelShade,MainTexture.clBevelLight);
    4149       end;
    4150     end;
    4151 
    4152 if ClientMode<>cEditMap then
    4153   begin
    4154   for i:=0 to ControlCount-1 do
    4155     if Controls[i] is TButtonC then with TButtonC(Controls[i]) do
    4156       begin
    4157       Dump(Panel,HGrSystem,Left,Top-self.ClientHeight+PanelHeight,12,12,
    4158         169,178+13*ButtonIndex);
    4159       RFrame(Panel.Canvas,Left-1,Top-self.ClientHeight+(PanelHeight-1),
    4160         Left+Width,Top+Height-self.ClientHeight+PanelHeight,
    4161         MainTexture.clBevelShade,MainTexture.clBevelLight);
    4162       end
    4163   end;
    4164 EOT.SetBack(Panel.Canvas,EOT.Left,EOT.Top-(ClientHeight-PanelHeight));
    4165 SmartRectInvalidate(0,ClientHeight-PanelHeight,ClientWidth,ClientHeight);
    4166 
    4167 // topbar
    4168 xTreasurySection:=ClientWidth div 2-172;
    4169 xResearchSection:=ClientWidth div 2; //ClientWidth div 2+68 = maximum to right
    4170 FillLarge(TopBar.Canvas,0,0,ClientWidth,TopBarHeight-3,ClientWidth div 2);
    4171 with TopBar.Canvas do
    4172   begin
    4173   Pen.Color:=$000000;
    4174   MoveTo(0,TopBarHeight-1); LineTo(ClientWidth, TopBarHeight-1);
    4175   Pen.Color:=MainTexture.clBevelShade;
    4176   MoveTo(0,TopBarHeight-2); LineTo(ClientWidth, TopBarHeight-2);
    4177   MoveTo(0,TopBarHeight-3); LineTo(ClientWidth, TopBarHeight-3);
    4178   Pen.Color:=MainTexture.clBevelLight;
    4179   frame(TopBar.Canvas,40,-1,xTreasurySection-1,TopBarHeight-7,
    4180     MainTexture.clBevelShade,MainTexture.clBevelLight);
    4181   frame(TopBar.Canvas,xResearchSection+332,-1,ClientWidth,TopBarHeight-7,
    4182     MainTexture.clBevelShade,MainTexture.clBevelLight);
    4183   end;
    4184 if GameMode<>cMovie then
    4185   ImageOp_BCC(TopBar,Templates,2,1,145,38,36,36,$BFBF20,$4040DF);
    4186 if MyRO.nCity>0 then
    4187   begin
    4188   TrueMoney:=MyRO.Money;
    4189   TrueResearch:=MyRO.Research;
    4190   if supervising then
    4191     begin // normalize values from after-turn state
    4192     dec(TrueMoney,TaxSum);
    4193     if TrueMoney<0 then
    4194       TrueMoney:=0; // shouldn't happen
    4195     dec(TrueResearch,ScienceSum);
    4196     if TrueResearch<0 then
    4197       TrueResearch:=0; // shouldn't happen
    4198     end;
    4199 
    4200   // treasury section
    4201   ImageOp_BCC(TopBar,Templates,xTreasurySection+8,1,145,1,36,36,$40A040,$4030C0);
    4202   s:=IntToStr(TrueMoney);
    4203   LoweredTextOut(TopBar.Canvas,-1,MainTexture,xTreasurySection+48,0,s+'%c');
    4204   if MyRO.Government<>gAnarchy then
    4205     begin
    4206     ImageOp_BCC(TopBar,Templates,xTreasurySection+48,22,124,1,14,14,$0000C0, $0080C0);
    4207     if TaxSum>=0 then
    4208       s:=Format(Phrases.Lookup('MONEYGAINPOS'),[TaxSum])
    4209     else s:=Format(Phrases.Lookup('MONEYGAINNEG'),[TaxSum]);
    4210     LoweredTextOut(TopBar.Canvas,-1,MainTexture,xTreasurySection+48+15,18,s);
    4211     end;
    4212 
    4213   // research section
    4214   ImageOp_BCC(TopBar,Templates,xResearchSection+8,1,145,75,36,36,$FF0000,$00FFE0);
    4215   if MyData.FarTech<>adNexus then
    4216     begin
    4217     if MyRO.ResearchTech<0 then
    4218       CostFactor:=2
    4219     else if (MyRO.ResearchTech=adMilitary) or (MyRO.Tech[MyRO.ResearchTech]=tsSeen) then
    4220       CostFactor:=1
    4221     else if MyRO.ResearchTech in FutureTech then
    4222       if MyRO.Government=gFuture then
    4223         CostFactor:=4
    4224       else CostFactor:=8
    4225     else CostFactor:=2;
    4226     Server(sGetTechCost,me,0,i);
    4227     CostFactor:=CostFactor*22; // length of progress bar
    4228     PaintRelativeProgressBar(TopBar.Canvas,2,xResearchSection+48+1,26,
    4229       CostFactor,TrueResearch,ScienceSum,i,true,MainTexture);
    4230 
    4231     if MyRO.ResearchTech<0 then
    4232       s:=Phrases.Lookup('SCIENCE')
    4233     else if MyRO.ResearchTech=adMilitary then
    4234       s:=Phrases.Lookup('INITUNIT')
    4235     else
    4236       begin
    4237       s:=Phrases.Lookup('ADVANCES', MyRO.ResearchTech);
    4238       if MyRO.ResearchTech in FutureTech then
    4239         if MyRO.Tech[MyRO.ResearchTech]>=1 then
    4240           s:=s+' '+IntToStr(MyRO.Tech[MyRO.ResearchTech]+1)
    4241         else s:=s+' 1';
    4242       end;
    4243     if ScienceSum>0 then
    4244       begin
    4245 {      j:=(i-MyRO.Research-1) div ScienceSum +1;
    4246       if j<1 then j:=1;
    4247       if j>1 then
    4248         s:=Format(Phrases.Lookup('TECHWAIT'),[s,j]);}
    4249       LoweredTextOut(TopBar.Canvas,-1,MainTexture,xResearchSection+48,0,s);
    4250       end
    4251     else LoweredTextOut(TopBar.Canvas,-1,MainTexture,xResearchSection+48,0,s);
    4252     end
    4253   else CostFactor:=0;
    4254   if (MyData.FarTech<>adNexus) and (ScienceSum>0) then
    4255     begin
    4256     ImageOp_BCC(TopBar,Templates,xResearchSection+48+CostFactor+11,22,124,1,14,14,$0000C0, $0080C0);
    4257     s:=Format(Phrases.Lookup('TECHGAIN'),[ScienceSum]);
    4258     LoweredTextOut(TopBar.Canvas,-1,MainTexture,xResearchSection+48+CostFactor+26,18,s);
    4259     end
    4260   end;
    4261 if ClientMode<>cEditMap then
    4262   begin
    4263   TopBar.Canvas.Font.Assign(UniFont[ftCaption]);
    4264   s:=TurnToString(MyRO.Turn);
    4265   RisedTextOut(TopBar.Canvas,40+(xTreasurySection-40-BiColorTextWidth(TopBar.Canvas,s)) div 2,6,s);
    4266   TopBar.Canvas.Font.Assign(UniFont[ftNormal]);
    4267   end;
    4268 RectInvalidate(0,0,ClientWidth,TopBarHeight);
    4269 end;{PanelPaint}
    4270 
    4271 procedure TMainScreen.FocusOnLoc(Loc:integer; Options: integer = 0);
    4272 var
    4273 dx: integer;
    4274 Outside, Changed: boolean;
    4275 begin
    4276 dx:=G.lx+1-(xw-Loc+G.lx*1024+1) mod G.lx;
    4277 Outside:=(dx>=(MapWidth+1) div (xxt*2)-2)
    4278   or (ywmax>0) and ((yw>0) and (Loc div G.lx<=yw+1)
    4279     or (yw<ywmax) and (Loc div G.lx>=yw+(MapHeight-1) div yyt-2));
    4280 Changed:=true;
    4281 if Outside then
    4282   begin Centre(Loc); PaintAllMaps end
    4283 else if not MapValid then
    4284   PaintAllMaps
    4285 else Changed:=false;
    4286 if Options and flRepaintPanel<>0 then
    4287   PanelPaint;
    4288 if Changed and (Options and flImmUpdate<>0) then Update;
    4289 end;
    4290 
    4291 procedure TMainScreen.NextUnit(NearLoc:integer;AutoTurn:boolean);
    4292 var
    4293 Dist,TestDist:single;
    4294 i,uix,NewFocus:integer;
    4295 GotoOnly: boolean;
    4296 begin
    4297 if ClientMode>=scContact then exit;
    4298 DestinationMarkON:=false;
    4299 PaintDestination;
    4300 for GotoOnly:=GoOnPhase downto false do
    4301   begin
    4302   NewFocus:=-1;
    4303   for i:=1 to MyRO.nUn do
    4304     begin
    4305     uix:=(UnFocus+i) mod MyRO.nUn;
    4306     if (MyUn[uix].Loc>=0) and (MyUn[uix].Job=jNone)
    4307       and (MyUn[uix].Status and (usStay or usRecover or usWaiting)=usWaiting)
    4308       and (not GotoOnly or (MyUn[uix].Status and usGoto<>0)) then
    4309       if NearLoc<0 then begin NewFocus:=uix; Break end
    4310       else
    4311         begin
    4312         TestDist:=Distance(NearLoc,MyUn[uix].Loc);
    4313         if (NewFocus<0) or (TestDist<Dist) then
    4314           begin NewFocus:=uix; Dist:=TestDist end
    4315         end
    4316     end;
    4317   if GotoOnly then
    4318     if NewFocus<0 then GoOnPhase:=false
    4319     else break;
    4320   end;
    4321 if NewFocus>=0 then
    4322   begin
    4323   SetUnFocus(NewFocus);
    4324   SetTroopLoc(MyUn[NewFocus].Loc);
    4325   FocusOnLoc(TroopLoc,flRepaintPanel)
    4326   end
    4327 else if AutoTurn and not mWaitTurn.Checked then
    4328   begin
    4329   TurnComplete:=true;
    4330   SetUnFocus(-1);
    4331   SetTroopLoc(-1);
    4332   PostMessage(Handle,WM_EOT,0,0)
    4333   end
    4334 else
    4335   begin
    4336   if {(UnFocus>=0) and} not TurnComplete and EOT.Visible then Play('TURNEND');
    4337   TurnComplete:=true;
    4338   SetUnFocus(-1);
    4339   SetTroopLoc(-1);
    4340   PanelPaint;
    4341   end;
    4342 end;{NextUnit}
    4343 
    4344 procedure TMainScreen.Scroll(dx,dy: integer);
    4345 begin
    4346 xw:=(xw+G.lx+dx) mod G.lx;
    4347 if ywmax>0 then
    4348   begin
    4349   yw:=yw+2*dy;
    4350   if yw<0 then yw:=0
    4351   else if yw>ywmax then yw:=ywmax;
    4352   end;
    4353 MainOffscreenPaint;
    4354 xwMini:=xw; ywMini:=yw;
    4355 MiniPaint;
    4356 CopyMiniToPanel;
    4357 RectInvalidate(xMini+2,TopBarHeight+MapHeight-overlap+yMini+2,xMini+2+G.lx*2,
    4358   TopBarHeight+MapHeight-overlap+yMini+2+G.ly);
    4359 Update;
    4360 end;
    4361 
    4362 procedure TMainScreen.Timer1Timer(Sender:TObject);
    4363 var
    4364 dx, dy, speed: integer;
    4365 begin
    4366 if idle and (me>=0) and (GameMode<>cMovie) then
    4367   if (fsModal in Screen.ActiveForm.FormState)
    4368     or (Screen.ActiveForm is TBufferedDrawDlg)
    4369     and (TBufferedDrawDlg(Screen.ActiveForm).WindowMode<>wmPersistent) then
    4370     begin
    4371     BlinkTime:=BlinkOnTime+BlinkOffTime-1;
    4372     if not BlinkON then
    4373       begin
    4374       BlinkON:=true;
    4375       if UnFocus>=0 then
    4376         PaintLocTemp(MyUn[UnFocus].Loc)
    4377       else if TurnComplete and not supervising then
    4378         EOT.SetButtonIndexFast(eotBlinkOn)
    4379       end
    4380     end
    4381   else
    4382     begin
    4383     if Application.Active and not mScrollOff.Checked then
    4384       begin
    4385       if mScrollFast.Checked then Speed:=2
    4386       else Speed:=1;
    4387       dx:=0;
    4388       dy:=0;
    4389       if Mouse.CursorPos.y<Screen.Height-PanelHeight then
    4390         if Mouse.CursorPos.x=0 then dx:=-Speed // scroll left
    4391         else if Mouse.CursorPos.x=Screen.Width-1 then dx:=Speed; // scroll right
    4392       if Mouse.CursorPos.y=0 then dy:=-Speed // scroll up
    4393       else if (Mouse.CursorPos.y=Screen.Height-1)
    4394         and (Mouse.CursorPos.x>=TerrainBtn.Left+TerrainBtn.Width)
    4395         and (Mouse.CursorPos.x<xRightPanel+10-8) then dy:=Speed; // scroll down
    4396       if (dx<>0) or (dy<>0) then
    4397         begin
    4398         if (Screen.ActiveForm<>MainScreen)
    4399           and (@Screen.ActiveForm.OnDeactivate<>nil) then
    4400           Screen.ActiveForm.OnDeactivate(nil);
    4401         Scroll(dx,dy);
    4402         end
    4403       end;
    4404 
    4405     BlinkTime:=(BlinkTime+1) mod (BlinkOnTime+BlinkOffTime);
    4406     BlinkON:= BlinkTime>=BlinkOffTime;
    4407     DestinationMarkON:=true;
    4408     if UnFocus>=0 then
    4409       begin
    4410       if (BlinkTime=0) or (BlinkTime=BlinkOffTime) then
    4411         begin
    4412         PaintLocTemp(MyUn[UnFocus].Loc,pltsBlink);
    4413         PaintDestination;
    4414   //      if MoveHintToLoc>=0 then
    4415   //        ShowMoveHint(MoveHintToLoc, true);
     7829          else if Flag = tfAllTechs then
     7830            TellNewModels
    44167831        end
    44177832      end
    4418     else if TurnComplete and not supervising then
    4419       begin
    4420       if BlinkTime=0 then EOT.SetButtonIndexFast(eotBlinkOff)
    4421       else if BlinkTime=BlinkOffTime then EOT.SetButtonIndexFast(eotBlinkOn)
     7833    end;
     7834
     7835    procedure TMainScreen.MapBtnClick(Sender: TObject);
     7836    begin
     7837      with TButtonC(Sender) do
     7838      begin
     7839        MapOptionChecked := MapOptionChecked xor (1 shl (Tag shr 8));
     7840        SetMapOptions;
     7841        ButtonIndex := MapOptionChecked shr (Tag shr 8) and 1 + 2
     7842      end;
     7843      if Sender = MapBtn0 then
     7844      begin
     7845        MiniPaint;
     7846        PanelPaint
     7847      end // update mini map only
     7848      else
     7849      begin
     7850        MapValid := false;
     7851        PaintAllMaps;
     7852      end; // update main map
     7853    end;
     7854
     7855    procedure TMainScreen.GrWallBtnDownChanged(Sender: TObject);
     7856    begin
     7857      if TButtonBase(Sender).Down then
     7858      begin
     7859        MapOptionChecked := MapOptionChecked or (1 shl moGreatWall);
     7860        TButtonBase(Sender).Hint := '';
    44227861      end
    4423     end
    4424 end;
    4425 
    4426 procedure TMainScreen.Centre(Loc:integer);
    4427 begin
    4428 if FastScrolling and MapValid then update;
    4429   // necessary because ScrollDC for form canvas is called after
    4430 xw:=(Loc mod G.lx-(MapWidth-xxt*2*((Loc div G.lx) and 1)) div (xxt*4)+G.lx) mod G.lx;
    4431 if ywmax<=0 then yw:=ywcenter
    4432 else
    4433   begin
    4434   yw:=(Loc div G.lx-MapHeight div (yyt*2)+1) and not 1;
    4435   if yw<0 then yw:=0
    4436   else if yw>ywmax then yw:=ywmax;
    4437   end
    4438 end;
    4439 
    4440 function TMainScreen.ZoomToCity(Loc: integer; NextUnitOnClose: boolean = false;
    4441   ShowEvent: integer = 0): boolean;
    4442 begin
    4443 result:= MyMap[Loc] and (fOwned or fSpiedOut)<>0;
    4444 if result then with CityDlg do
    4445   begin
    4446   if ClientMode>=scContact then
    4447     begin
    4448     CloseAction:=None;
    4449     RestoreUnFocus:=-1;
    4450     end
    4451   else if NextUnitOnClose then
    4452     begin
    4453     CloseAction:=StepFocus;
    4454     RestoreUnFocus:=-1;
    4455     end
    4456   else if not Visible then
    4457     begin
    4458     CloseAction:=RestoreFocus;
    4459     RestoreUnFocus:=UnFocus;
    4460     end;
    4461   SetUnFocus(-1);
    4462   SetTroopLoc(Loc);
    4463   MarkCityLoc:=Loc;
    4464   PanelPaint;
    4465   ShowNewContent(wmPersistent, Loc, ShowEvent);
    4466   end
    4467 end;
    4468 
    4469 function TMainScreen.LocationOfScreenPixel(x,y: integer): integer;
    4470 var
    4471 qx,qy: integer;
    4472 begin
    4473 qx:=(x*(yyt*2)+y*(xxt*2)+xxt*yyt*2) div (xxt*yyt*4)-1;
    4474 qy:=(y*(xxt*2)-x*(yyt*2)-xxt*yyt*2+4000*xxt*yyt) div (xxt*yyt*4)-999;
    4475 result:=(xw+(qx-qy+2048) div 2-1024+G.lx) mod G.lx+G.lx*(yw+qx+qy);
    4476 end;
    4477 
    4478 procedure TMainScreen.MapBoxMouseDown(Sender:TObject;
    4479   Button:TMouseButton;Shift:TShiftState;x,y:integer);
    4480 var
    4481 i,uix,emix,p1,dx,dy,MouseLoc:integer;
    4482 EditTileData: TEditTileData;
    4483 m,m2: TMenuItem;
    4484 MoveAdviceData: TMoveAdviceData;
    4485 DoCenter: boolean;
    4486 begin
    4487 if GameMode=cMovie then
    4488   exit;
    4489 
    4490 if CityDlg.Visible then CityDlg.Close;
    4491 if UnitStatDlg.Visible then UnitStatDlg.Close;
    4492 MouseLoc:=LocationOfScreenPixel(x,y);
    4493 if (MouseLoc<0) or (MouseLoc>=G.lx*G.ly) then exit;
    4494 if (Button=mbLeft) and not(ssShift in Shift) then
    4495   begin
    4496   DoCenter:=true;
    4497   if ClientMode=cEditMap then
    4498     begin
    4499     DoCenter:=false;
    4500     EditTileData.Loc:=MouseLoc;
    4501     if ssCtrl in Shift then // toggle special resource
    4502       case MyMap[MouseLoc] and fTerrain of
    4503         fOcean: EditTileData.NewTile:=MyMap[MouseLoc];
    4504         fGrass, fArctic: EditTileData.NewTile:=MyMap[MouseLoc] and not fSpecial
    4505           or ((MyMap[MouseLoc] shr 5 and 3+1) mod 2 shl 5);
    4506         else EditTileData.NewTile:=MyMap[MouseLoc] and not fSpecial
    4507           or ((MyMap[MouseLoc] shr 5 and 3+1) mod 3 shl 5)
    4508         end
    4509     else if BrushType<=fTerrain then
    4510       EditTileData.NewTile:=MyMap[MouseLoc] and not fTerrain or fSpecial or BrushType
    4511     else if BrushType and fDeadLands<>0 then
    4512       if MyMap[MouseLoc] and (fDeadLands or fModern)
    4513         =BrushType and (fDeadLands or fModern) then
    4514         EditTileData.NewTile:=MyMap[MouseLoc] and not (fDeadLands or fModern)
    4515       else EditTileData.NewTile:=MyMap[MouseLoc] and not (fDeadLands or fModern)
    4516         or BrushType
    4517     else if BrushType and fTerImp<>0 then
    4518       if MyMap[MouseLoc] and fTerImp=BrushType then
    4519         EditTileData.NewTile:=MyMap[MouseLoc] and not fTerImp
    4520       else EditTileData.NewTile:=MyMap[MouseLoc] and not fTerImp or BrushType
    4521     else if BrushType and (fPrefStartPos or fStartPos)<>0 then
    4522       if MyMap[MouseLoc] and (fPrefStartPos or fStartPos)
    4523         =BrushType and (fPrefStartPos or fStartPos) then
    4524         EditTileData.NewTile:=MyMap[MouseLoc] and not (fPrefStartPos or fStartPos)
    4525       else EditTileData.NewTile:=MyMap[MouseLoc]
    4526         and not (fPrefStartPos or fStartPos) or BrushType
    4527     else EditTileData.NewTile:=MyMap[MouseLoc] xor BrushType;
    4528     Server(sEditTile,me,0,EditTileData);
    4529     Edited:=true;
    4530     BrushLoc:=MouseLoc;
    4531     PaintLoc(MouseLoc,2);
    4532     MiniPaint;
    4533     BitBlt(Panel.Canvas.Handle,xMini+2,yMini+2,G.lx*2,G.ly,Mini.Canvas.Handle,
    4534       0,0,SRCCOPY);
    4535     if ywmax<=0 then
    4536       Frame(Panel.Canvas,xMini+2+G.lx-MapWidth div (2*xxt),yMini+2,
    4537         xMini+1+G.lx+MapWidth div (2*xxt),
    4538         yMini+2+G.ly-1,MainTexture.clMark,MainTexture.clMark)
    4539     else Frame(Panel.Canvas,xMini+2+G.lx-MapWidth div (2*xxt),yMini+2+yw,
    4540       xMini+2+G.lx+MapWidth div (2*xxt)-1,
    4541       yMini+2+yw+MapHeight div yyt-2,MainTexture.clMark,MainTexture.clMark);
    4542     RectInvalidate(xMini+2,TopBarHeight+MapHeight-overlap+yMini+2,xMini+2+G.lx*2,
    4543       TopBarHeight+MapHeight-overlap+yMini+2+G.ly)
    4544     end
    4545   else if MyMap[MouseLoc] and fCity<>0 then {city clicked}
    4546     begin
    4547     if MyMap[MouseLoc] and (fOwned or fSpiedOut)<>0 then
    4548       begin
    4549       ZoomToCity(MouseLoc);
    4550       DoCenter:=false;
     7862      else
     7863      begin
     7864        MapOptionChecked := MapOptionChecked and not(1 shl moGreatWall);
     7865        TButtonBase(Sender).Hint := Phrases.Lookup('CONTROLS',
     7866          -1 + TButtonBase(Sender).Tag and $FF);
     7867      end;
     7868      SetMapOptions;
     7869      MapValid := false;
     7870      PaintAllMaps;
     7871    end;
     7872
     7873    procedure TMainScreen.BareBtnDownChanged(Sender: TObject);
     7874    begin
     7875      if TButtonBase(Sender).Down then
     7876      begin
     7877        MapOptionChecked := MapOptionChecked or (1 shl moBareTerrain);
     7878        TButtonBase(Sender).Hint := '';
    45517879      end
    4552     else
    4553       begin
    4554       UnitStatDlg.ShowNewContent_EnemyCity(wmPersistent, MouseLoc);
    4555       DoCenter:=false;
    4556       end
    4557     end
    4558   else if MyMap[MouseLoc] and fUnit<>0 then {unit clicked}
    4559     if MyMap[MouseLoc] and fOwned<>0 then
    4560       begin
    4561       DoCenter:=false;
    4562       if not supervising and (ClientMode<scContact) then
    4563         begin // not in negotiation mode
    4564         if (UnFocus>=0) and (MyUn[UnFocus].Loc=MouseLoc) then
    4565           begin // rotate
    4566           uix:=(UnFocus+1) mod MyRO.nUn;
    4567           i:=MyRO.nUn-1;
    4568           while i>0 do
    4569             begin
    4570             if (MyUn[uix].Loc=MouseLoc) and (MyUn[uix].Job=jNone)
    4571               and (MyUn[uix].Status and (usStay or usRecover or usEnhance or usWaiting)=usWaiting) then
    4572               break;
    4573             dec(i);
    4574             uix:=(uix+1) mod MyRO.nUn;
    4575             end;
    4576           if i=0 then uix:=UnFocus
    4577           end
    4578         else Server(sGetDefender,me,MouseLoc,uix);
    4579         if uix<>UnFocus then
    4580           SetUnFocus(uix);
    4581         TurnComplete:=false;
    4582         EOT.ButtonIndex:=eotGray;
    4583         end;
    4584       SetTroopLoc(MouseLoc);
    4585       PanelPaint;
    4586       end // own unit
    4587     else if (MyMap[MouseLoc] and fSpiedOut<>0) and not(ssCtrl in Shift) then
    4588       begin
    4589       DoCenter:=false;
    4590       SetTroopLoc(MouseLoc);
    4591       PanelPaint;
    4592       end
    4593     else
    4594       begin
    4595       DoCenter:=false;
    4596       UnitStatDlg.ShowNewContent_EnemyLoc(wmPersistent, MouseLoc);
     7880      else
     7881      begin
     7882        MapOptionChecked := MapOptionChecked and not(1 shl moBareTerrain);
     7883        TButtonBase(Sender).Hint := Phrases.Lookup('CONTROLS',
     7884          -1 + TButtonBase(Sender).Tag and $FF);
    45977885      end;
    4598   if DoCenter then begin Centre(MouseLoc); PaintAllMaps end
    4599   end
    4600 else if (ClientMode<>cEditMap) and (Button=mbRight) and not(ssShift in Shift) then
    4601   begin
    4602   if supervising then
    4603     begin
    4604     EditLoc:=MouseLoc;
    4605     Server(sGetModels,me,0,nil^);
    4606     EmptyMenu(mCreateUnit);
    4607     for p1:=0 to nPl-1 do if 1 shl p1 and MyRO.Alive<>0 then
    4608       begin
    4609       m:=TMenuItem.Create(mCreateUnit);
    4610       m.Caption:=Tribe[p1].TPhrase('SHORTNAME');
    4611       for emix:=MyRO.nEnemyModel-1 downto 0 do
    4612         if (MyRO.EnemyModel[emix].Owner=p1) and
    4613           (Server(sCreateUnit-sExecute+p1 shl 4,me,MyRO.EnemyModel[emix].mix,MouseLoc)>=rExecuted) then
    4614           begin
    4615           if Tribe[p1].ModelPicture[MyRO.EnemyModel[emix].mix].HGr=0 then
    4616             InitEnemyModel(emix);
    4617           m2:=TMenuItem.Create(m);
    4618           m2.Caption:=Tribe[p1].ModelName[MyRO.EnemyModel[emix].mix];
    4619           m2.Tag:=p1 shl 16 + MyRO.EnemyModel[emix].mix;
    4620           m2.OnClick:=CreateUnitClick;
    4621           m.Add(m2);
    4622           end;
    4623       m.Visible:= m.Count>0;
    4624       mCreateUnit.Add(m);
    4625       end;
    4626     if FullScreen then EditPopup.Popup(Left+x, Top+y)
    4627     else EditPopup.Popup(Left+x+4, Top+y+GetSystemMetrics(SM_CYCAPTION)+4);
    4628     end
    4629   else if (UnFocus>=0) and (MyUn[UnFocus].Loc<>MouseLoc) then with MyUn[UnFocus] do
    4630     begin
    4631     dx:=((MouseLoc mod G.lx *2 +MouseLoc div G.lx and 1)
    4632       -(Loc mod G.lx *2 +Loc div G.lx and 1)+3*G.lx) mod (2*G.lx) -G.lx;
    4633     dy:=MouseLoc div G.lx-Loc div G.lx;
    4634     if abs(dx)+abs(dy)<3 then
     7886      SetMapOptions;
     7887      MapValid := false;
     7888      PaintAllMaps;
     7889    end;
     7890
     7891    procedure TMainScreen.FormKeyUp(Sender: TObject; var Key: word;
     7892      Shift: TShiftState);
     7893    begin
     7894      if idle and (Key = VK_APPS) then
     7895      begin
     7896        InitPopup(GamePopup);
     7897        if FullScreen then
     7898          GamePopup.Popup(Left, Top + TopBarHeight - 1)
     7899        else
     7900          GamePopup.Popup(Left + 4, Top + GetSystemMetrics(SM_CYCAPTION) + 4 +
     7901            TopBarHeight - 1);
     7902        exit
     7903      end // windows menu button calls game menu
     7904    end;
     7905
     7906    procedure TMainScreen.CreateUnitClick(Sender: TObject);
     7907    var
     7908      p1, mix: integer;
     7909    begin
     7910      p1 := TComponent(Sender).Tag shr 16;
     7911      mix := TComponent(Sender).Tag and $FFFF;
     7912      if Server(sCreateUnit + p1 shl 4, me, mix, EditLoc) >= rExecuted then
     7913        PaintLoc(EditLoc);
     7914    end;
     7915
     7916    procedure TMainScreen.mSoundOffClick(Sender: TObject);
     7917    begin
     7918      SoundMode := smOff;
     7919    end;
     7920
     7921    procedure TMainScreen.mSoundOnClick(Sender: TObject);
     7922    begin
     7923      SoundMode := smOn;
     7924    end;
     7925
     7926    procedure TMainScreen.mSoundOnAltClick(Sender: TObject);
     7927    begin
     7928      SoundMode := smOnAlt;
     7929    end;
     7930
     7931    { procedure TMainScreen.AdviceBtnClick;
     7932      var
     7933      OldAdviceLoc: integer;
    46357934      begin
    46367935      DestinationMarkON:=false;
    46377936      PaintDestination;
    4638       Status:=Status and ($FFFF-usStay-usRecover-usGoto-usEnhance) or usWaiting;
    4639       MoveUnit(dx,dy,muAutoNext) {simple move}
    4640       end
    4641     else if GetMoveAdvice(UnFocus,MouseLoc,MoveAdviceData)>=rExecuted then
    4642       begin
    4643       if MyMap[MouseLoc] and (fUnit or fOwned)=fUnit then
    4644         begin // check for suicide mission before movement
    4645         with MyUn[UnFocus],BattleDlg.Forecast do
    4646           begin
    4647           pAtt:=me;
    4648           mixAtt:=mix;
    4649           HealthAtt:=Health;
    4650           ExpAtt:=Exp;
    4651           FlagsAtt:=Flags;
    4652           end;
    4653         BattleDlg.Forecast.Movement:=MyUn[UnFocus].Movement;
    4654         if (Server(sGetBattleForecastEx,me,MouseLoc,BattleDlg.Forecast)>=rExecuted)
    4655           and (BattleDlg.Forecast.EndHealthAtt<=0) then
    4656           begin
    4657           BattleDlg.uix:=UnFocus;
    4658           BattleDlg.ToLoc:=MouseLoc;
    4659           BattleDlg.IsSuicideQuery:=true;
    4660           BattleDlg.ShowModal;
    4661           if BattleDlg.ModalResult<>mrOK then
    4662             exit;
    4663           end
    4664         end;
    4665       DestinationMarkON:=false;
    4666       PaintDestination;
    4667       Status:=Status and not (usStay or usRecover or usEnhance) or usWaiting;
    4668       MoveToLoc(MouseLoc,false); {goto}
    4669       end
    4670     end
    4671   end
    4672 else if (Button=mbMiddle) and (UnFocus>=0)
    4673   and (MyModel[MyUn[UnFocus].mix].Kind in [mkSettler,mkSlaves]) then
    4674   begin
    4675   DestinationMarkON:=false;
    4676   PaintDestination;
    4677   MyUn[UnFocus].Status:=MyUn[UnFocus].Status and ($FFFF-usStay-usRecover-usGoto) or usEnhance;
    4678   uix:=UnFocus;
    4679   if MouseLoc<>MyUn[uix].Loc then MoveToLoc(MouseLoc,true); {goto}
    4680   if (UnFocus=uix) and (MyUn[uix].Loc=MouseLoc) then MenuClick(mEnhance)
    4681   end
    4682 else if (Button=mbLeft) and (ssShift in Shift)
    4683   and (MyMap[MouseLoc] and fTerrain<>fUNKNOWN) then
    4684   HelpOnTerrain(MouseLoc, wmPersistent)
    4685 else if (ClientMode<=cContinue) and (Button=mbRight) and (ssShift in Shift)
    4686   and (UnFocus>=0) and (MyMap[MouseLoc] and (fUnit or fOwned)=fUnit) then
    4687   begin // battle forecast
    4688   with MyUn[UnFocus],BattleDlg.Forecast do
    4689     begin
    4690     pAtt:=me;
    4691     mixAtt:=mix;
    4692     HealthAtt:=Health;
    4693     ExpAtt:=Exp;
    4694     FlagsAtt:=Flags;
    4695     end;
    4696   BattleDlg.Forecast.Movement:=MyUn[UnFocus].Movement;
    4697   if Server(sGetBattleForecastEx,me,MouseLoc,BattleDlg.Forecast)>=rExecuted then
    4698     begin
    4699     BattleDlg.uix:=UnFocus;
    4700     BattleDlg.ToLoc:=MouseLoc;
    4701     BattleDlg.Left:=x-BattleDlg.Width div 2;
    4702     if BattleDlg.Left<0 then
    4703       BattleDlg.Left:=0
    4704     else if BattleDlg.Left+BattleDlg.Width>Screen.Width then
    4705       BattleDlg.Left:=Screen.Width-BattleDlg.Width;
    4706     BattleDlg.Top:=y-BattleDlg.Height div 2;
    4707     if BattleDlg.Top<0 then
    4708       BattleDlg.Top:=0
    4709     else if BattleDlg.Top+BattleDlg.Height>Screen.Height then
    4710       BattleDlg.Top:=Screen.Height-BattleDlg.Height;
    4711     BattleDlg.IsSuicideQuery:=false;
    4712     BattleDlg.Show;
    4713     end
    4714   end
    4715 end;
    4716 
    4717 function TMainScreen.MoveUnit(dx,dy:integer; Options: integer): integer;
    4718 // move focused unit to adjacent tile
    4719 var
    4720 i,cix,uix,euix,FromLoc,ToLoc,DirCode,UnFocus0,Defender,Mission,p1,
    4721   NewTiles,cixChanged: integer;
    4722 OldToTile: cardinal;
    4723 CityCaptured, IsAttack, OldUnrest, NewUnrest, NeedEcoUpdate, NeedRepaintPanel,
    4724   ToTransport, ToShip: boolean;
    4725 PlaneReturnData: TPlaneReturnData;
    4726 QueryItem: string;
    4727 begin
    4728 result:=eInvalid;
    4729 UnFocus0:=UnFocus;
    4730 FromLoc:=MyUn[UnFocus].Loc;
    4731 ToLoc:=dLoc(FromLoc,dx,dy);
    4732 if (ToLoc<0) or (ToLoc>=G.lx*G.ly) then begin result:=eInvalid; exit; end;
    4733 if MyMap[ToLoc] and fStealthUnit<>0 then
    4734   begin
    4735   SoundMessage(Phrases.LookUp('ATTACKSTEALTH'),'');
    4736   exit;
    4737   end;
    4738 if MyMap[ToLoc] and fHiddenUnit<>0 then
    4739   begin
    4740   SoundMessage(Phrases.LookUp('ATTACKSUB'),'');
    4741   exit;
    4742   end;
    4743 
    4744 if MyMap[ToLoc] and (fUnit or fOwned)=fUnit then
    4745   begin // attack -- search enemy unit
    4746   if (MyModel[MyUn[UnFocus].mix].Attack=0)
    4747     and not ((MyModel[MyUn[UnFocus].mix].Cap[mcBombs]>0)
    4748       and (MyUn[UnFocus].Flags and unBombsLoaded<>0)) then
    4749     begin
    4750     SoundMessage(Phrases.LookUp('NOATTACKER'),'');
    4751     exit;
    4752     end;
    4753   euix:=MyRO.nEnemyUn-1;
    4754   while (euix>=0) and (MyRO.EnemyUn[euix].Loc<>ToLoc) do dec(euix);
    4755   end;
    4756 
    4757 DirCode:=dx and 7 shl 4+dy and 7 shl 7;
    4758 result:=Server(sMoveUnit-sExecute+DirCode,me,UnFocus,nil^);
    4759 if (result<rExecuted) and (MyUn[UnFocus].Job>jNone) then
    4760   Server(sStartJob+jNone shl 4,me,UnFocus,nil^);
    4761 if (result<rExecuted) and (result<>eNoTime_Move) then
    4762   begin
    4763   case result of
    4764     eNoTime_Load:
    4765       if MyModel[MyUn[UnFocus].mix].Domain=dAir then
    4766         SoundMessage(Phrases.Lookup('NOTIMELOADAIR'),'NOMOVE_TIME')
    4767       else
    4768         SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
    4769           [MovementToString(MyModel[MyUn[UnFocus].mix].Speed)]),'NOMOVE_TIME');
    4770     eNoTime_Bombard: SoundMessage(Phrases.Lookup('NOTIMEBOMBARD'),'NOMOVE_TIME');
    4771     eNoTime_Expel: SoundMessage(Phrases.Lookup('NOTIMEEXPEL'),'NOMOVE_TIME');
    4772     eNoRoad: SoundMessage(Phrases.Lookup('NOROAD'),'NOMOVE_DEFAULT');
    4773     eNoNav: SoundMessage(Phrases.Lookup('NONAV'),'NOMOVE_DEFAULT');
    4774     eNoCapturer: SoundMessage(Phrases.Lookup('NOCAPTURER'),'NOMOVE_DEFAULT');
    4775     eNoBombarder: SoundMessage(Phrases.Lookup('NOBOMBARDER'),'NOMOVE_DEFAULT');
    4776     eZOC: ContextMessage(Phrases.Lookup('ZOC'), 'NOMOVE_ZOC', hkText, HelpDlg.TextIndex('MOVEMENT'));
    4777     eTreaty:
    4778       if MyMap[ToLoc] and (fUnit or fOwned)<>fUnit then {no enemy unit -- move}
    4779         SoundMessage(Tribe[MyRO.Territory[ToLoc]].TPhrase('PEACE_NOMOVE'),
    4780           'NOMOVE_TREATY')
    4781       else SoundMessage(Tribe[MyRO.EnemyUn[euix].Owner].TPhrase
    4782         ('PEACE_NOATTACK'),'NOMOVE_TREATY');
    4783     eDomainMismatch:
    4784       begin
    4785       if (MyModel[MyUn[UnFocus].mix].Domain<dSea)
    4786         and (MyMap[ToLoc] and (fUnit or fOwned)=fUnit or fOwned) then
    4787         begin // false load attempt
    4788         ToShip:=false;
    4789         ToTransport:=false;
    4790         for uix:=0 to MyRo.nUn-1 do
    4791           if (MyUn[uix].Loc=ToLoc) and (MyModel[MyUn[uix].mix].Domain=dSea) then
    4792             begin
    4793             ToShip:=true;
    4794             if MyModel[MyUn[uix].mix].Cap[mcSeaTrans]>0 then
    4795               ToTransport:=true;
    4796             end;
    4797         if ToTransport then
    4798           SoundMessage(Phrases.Lookup('FULLTRANSPORT'),'NOMOVE_DEFAULT')
    4799         else if ToShip then
    4800           SoundMessage(Phrases.Lookup('NOTRANSPORT'),'NOMOVE_DEFAULT')
    4801         else Play('NOMOVE_DOMAIN');
    4802         end
    4803       else Play('NOMOVE_DOMAIN');
    4804       end
    4805     else Play('NOMOVE_DEFAULT');
    4806     end;
    4807   exit;
    4808   end;
    4809 
    4810 if ((result=eWon) or (result=eLost) or (result=eBloody))
    4811   and (MyUn[UnFocus].Movement<100)
    4812   and (MyModel[MyUn[UnFocus].mix].Cap[mcWill]=0) then
    4813   begin
    4814   if SimpleQuery(mkYesNo,Format(Phrases.Lookup('FASTATTACK'),
    4815     [MyUn[UnFocus].Movement]),'NOMOVE_TIME')<>mrOk then
    4816     begin result:=eInvalid; exit; end;
    4817   Update; // remove message box from screen
    4818   end;
    4819 
    4820 OldUnrest:=false;
    4821 NewUnrest:=false;
    4822 if (result>=rExecuted) and (result and rUnitRemoved=0)
    4823   and (MyMap[ToLoc] and (fUnit or fOwned)<>fUnit) then
    4824   begin
    4825   OldUnrest:=UnrestAtLoc(UnFocus,FromLoc);
    4826   NewUnrest:=UnrestAtLoc(UnFocus,ToLoc);
    4827   if NewUnrest>OldUnrest then
    4828     begin
    4829     if MyRO.Government=gDemocracy then
    4830       begin
    4831       QueryItem:='UNREST_NOTOWN';
    4832       p1:=me;
    4833       end
    4834     else
    4835       begin
    4836       QueryItem:='UNREST_FOREIGN';
    4837       p1:=MyRO.Territory[ToLoc];
     7937      AdvisorDlg.GiveStrategyAdvice;
     7938      OldAdviceLoc:=MainMap.AdviceLoc;
     7939      MainMap.AdviceLoc:=-1;
     7940      PaintLoc(OldAdviceLoc);
     7941      end; }
     7942
     7943    { procedure TMainScreen.SetAdviceLoc(Loc: integer; AvoidRect: TRect);
     7944      var
     7945      OldAdviceLoc,x,y: integer;
     7946      begin
     7947      if Loc<>MainMap.AdviceLoc then
     7948      begin
     7949      if Loc>=0 then
     7950      begin // center
     7951      y:=Loc div G.lx;
     7952      x:=(Loc+G.lx - AvoidRect.Right div (2*66)) mod G.lx;
     7953      Centre(y*G.lx+x);
     7954      PaintAllMaps;
    48387955      end;
    4839     with MessgExDlg do
    4840       begin
    4841       MessgText:=Format(Tribe[p1].TPhrase(QueryItem),[Phrases.Lookup('GOVERNMENT',MyRO.Government)]);
    4842       Kind:=mkYesNo;
    4843       IconKind:=mikImp;
    4844       IconIndex:=imPalace;
    4845       ShowModal;
    4846       if ModalResult<>mrOk then
    4847         begin result:=eInvalid; exit; end;
     7956      OldAdviceLoc:=MainMap.AdviceLoc;
     7957      MainMap.AdviceLoc:=Loc;
     7958      PaintLoc(OldAdviceLoc);
     7959      PaintLoc(MainMap.AdviceLoc);
    48487960      end;
    4849     Update; // remove message box from screen
    4850     end
    4851   end;
    4852 
    4853 if (result>=rExecuted)
    4854   and (MyModel[MyUn[UnFocus].mix].Domain=dAir)
    4855   and (MyUn[UnFocus].Status and usToldNoReturn=0) then
    4856   begin // can plane return?
    4857   PlaneReturnData.Fuel:=MyUn[UnFocus].Fuel;
    4858   if (MyMap[ToLoc] and (fUnit or fOwned)=fUnit)
    4859     or (MyMap[ToLoc] and (fCity or fOwned)=fCity) then
    4860     begin // attack/expel/bombard -> 100MP
    4861     PlaneReturnData.Loc:=FromLoc;
    4862     PlaneReturnData.Movement:=MyUn[UnFocus].Movement-100;
    4863     if PlaneReturnData.Movement<0 then PlaneReturnData.Movement:=0;
    4864     end
    4865   else // move
    4866     begin
    4867     PlaneReturnData.Loc:=ToLoc;
    4868     if dx and 1<>0 then PlaneReturnData.Movement:=MyUn[UnFocus].Movement-100
    4869     else PlaneReturnData.Movement:=MyUn[UnFocus].Movement-150;
    4870     end;
    4871   if Server(sGetPlaneReturn, me, UnFocus, PlaneReturnData)=eNoWay then
    4872     begin
    4873     if MyModel[MyUn[UnFocus].mix].Kind=mkSpecial_Glider then
    4874       QueryItem:='LOWFUEL_GLIDER'
    4875     else QueryItem:='LOWFUEL';
    4876     if SimpleQuery(mkYesNo,Phrases.Lookup(QueryItem),'WARNING_LOWSUPPORT')<>mrOk then
    4877       begin result:=eInvalid; exit; end;
    4878     Update; // remove message box from screen
    4879     MyUn[UnFocus].Status:=MyUn[UnFocus].Status or usToldNoReturn;
    4880     end
    4881   end;
    4882 
    4883 if result=eMissionDone then
    4884   begin
    4885   ModalSelectDlg.ShowNewContent(wmModal,kMission);
    4886   Update; // dialog still on screen
    4887   Mission:=ModalSelectDlg.result;
    4888   if Mission<0 then exit;
    4889   Server(sSetSpyMission+Mission shl 4, me, 0, nil^);
    4890   end;
    4891 
    4892 CityCaptured:=false;
    4893 if result=eNoTime_Move then Play('NOMOVE_TIME')
    4894 else
    4895   begin
    4896   NeedEcoUpdate:=false;
    4897   DestinationMarkON:=false;
    4898   PaintDestination;
    4899   if result and rUnitRemoved<>0 then
    4900     CityOptimizer_BeforeRemoveUnit(UnFocus);
    4901   IsAttack:= (result=eBombarded)
    4902     or (result<>eMissionDone) and (MyMap[ToLoc] and (fUnit or fOwned)=fUnit);
    4903   if not IsAttack then
    4904     begin // move
    4905     cix:=MyRO.nCity-1; {look for own city at dest location}
    4906     while (cix>=0) and (MyCity[cix].Loc<>ToLoc) do dec(cix);
    4907     if (result<>eMissionDone) and (MyMap[ToLoc] and fCity<>0) and (cix<0) then
    4908       CityCaptured:=true;
    4909     result:=Server(sMoveUnit+DirCode,me,UnFocus,nil^);
    4910     case result of
    4911       eHiddenUnit:
    4912         begin Play('NOMOVE_SUBMARINE'); PaintLoc(ToLoc) end;
    4913       eStealthUnit:
    4914         begin Play('NOMOVE_STEALTH'); PaintLoc(ToLoc) end;
    4915       eZOC_EnemySpotted:
    4916         begin Play('NOMOVE_ZOC'); PaintLoc(ToLoc,1) end;
    4917       rExecuted..maxint:
    4918         begin
    4919         if result and rUnitRemoved<>0 then UnFocus:=-1 // unit died
    4920         else
    4921           begin
    4922           assert(UnFocus>=0);
    4923           MyUn[UnFocus].Status:=MyUn[UnFocus].Status and not (usStay or usRecover);
    4924           for uix:=0 to MyRO.nUn-1 do if MyUn[uix].Master=UnFocus then
    4925             MyUn[uix].Status:=MyUn[uix].Status and not usWaiting;
    4926           if CityCaptured
    4927             and (MyRO.Government in [gRepublic,gDemocracy,gFuture]) then
    4928             begin // borders have moved, unrest might have changed in any city
    4929             CityOptimizer_BeginOfTurn;
    4930             NeedEcoUpdate:=true;
    4931             end
    4932           else
    4933             begin
    4934             if OldUnrest<>NewUnrest then
    4935               begin
    4936               CityOptimizer_CityChange(MyUn[UnFocus].Home);
    4937               for uix:=0 to MyRO.nUn-1 do if MyUn[uix].Master=UnFocus then
    4938                 CityOptimizer_CityChange(MyUn[uix].Home);
    4939               NeedEcoUpdate:=true;
    4940               end;
    4941             if (MyRO.Government=gDespotism)
    4942               and (MyModel[MyUn[UnFocus].mix].Kind=mkSpecial_TownGuard) then
    4943               begin
    4944               if MyMap[FromLoc] and fCity<>0 then
    4945                 begin // town guard moved out of city in despotism -- reoptimize!
    4946                 cixChanged:=MyRO.nCity-1;
    4947                 while (cixChanged>=0) and (MyCity[cixChanged].Loc<>FromLoc) do
    4948                   dec(cixChanged);
    4949                 assert(cixChanged>=0);
    4950                 if cixChanged>=0 then
    4951                   begin
    4952                   CityOptimizer_CityChange(cixChanged);
    4953                   NeedEcoUpdate:=true;
    4954                   end;
    4955                 end;
    4956               if (MyMap[ToLoc] and fCity<>0) and not CityCaptured then
    4957                 begin // town guard moved into city in despotism -- reoptimize!
    4958                 cixChanged:=MyRO.nCity-1;
    4959                 while (cixChanged>=0) and (MyCity[cixChanged].Loc<>ToLoc) do
    4960                   dec(cixChanged);
    4961                 assert(cixChanged>=0);
    4962                 if cixChanged>=0 then
    4963                   begin
    4964                   CityOptimizer_CityChange(cixChanged);
    4965                   NeedEcoUpdate:=true;
    4966                   end
    4967                 end
    4968               end
    4969             end 
    4970           end;
    4971         end;
    4972       else
    4973         assert(false);
    4974       end;
    4975     SetTroopLoc(ToLoc);
    4976     end
    4977   else
    4978     begin {enemy unit -- attack}
    4979     if result=eBombarded then Defender:=MyRO.Territory[ToLoc]
    4980     else Defender:=MyRO.EnemyUn[euix].Owner;
    4981     {if MyRO.Treaty[Defender]=trCeaseFire then
    4982       if SimpleQuery(mkYesNo,Phrases.Lookup('FRCANCELQUERY_CEASEFIRE'),
    4983         'MSG_DEFAULT')<>mrOK then
    4984         exit;}
    4985     if (Options and muNoSuicideCheck=0)
    4986       and (result and rUnitRemoved<>0) and (result<>eMissionDone) then
    4987       begin // suicide query
    4988       with MyUn[UnFocus],BattleDlg.Forecast do
    4989         begin
    4990         pAtt:=me;
    4991         mixAtt:=mix;
    4992         HealthAtt:=Health;
    4993         ExpAtt:=Exp;
    4994         FlagsAtt:=Flags;
    4995         end;
    4996       BattleDlg.Forecast.Movement:=MyUn[UnFocus].Movement;
    4997       Server(sGetBattleForecastEx,me,ToLoc,BattleDlg.Forecast);
    4998       BattleDlg.uix:=UnFocus;
    4999       BattleDlg.ToLoc:=ToLoc;
    5000       BattleDlg.IsSuicideQuery:=true;
    5001       BattleDlg.ShowModal;
    5002       if BattleDlg.ModalResult<>mrOK then
    5003         exit;
    5004       end;
    5005 
    5006     cixChanged:=-1;
    5007     if (result and rUnitRemoved<>0) and (MyRO.Government=gDespotism)
    5008       and (MyModel[MyUn[UnFocus].mix].Kind=mkSpecial_TownGuard)
    5009       and (MyMap[FromLoc] and fCity<>0) then
    5010       begin // town guard died in city in despotism -- reoptimize!
    5011       cixChanged:=MyRO.nCity-1;
    5012       while (cixChanged>=0) and (MyCity[cixChanged].Loc<>FromLoc) do
    5013         dec(cixChanged);
    5014       assert(cixChanged>=0);
    5015       end;
    5016 
    5017     for i:=0 to MyRO.nEnemyModel-1 do
    5018       LostArmy[i]:=MyRO.EnemyModel[i].Lost;
    5019     OldToTile:=MyMap[ToLoc];
    5020     result:=Server(sMoveUnit+DirCode,me,UnFocus,nil^);
    5021     nLostArmy:=0;
    5022     for i:=0 to MyRO.nEnemyModel-1 do
    5023       begin
    5024       LostArmy[i]:=MyRO.EnemyModel[i].Lost-LostArmy[i];
    5025       inc(nLostArmy,LostArmy[i])
    5026       end;
    5027     if result and rUnitRemoved<>0 then
    5028       begin
    5029       UnFocus:=-1;
    5030       SetTroopLoc(FromLoc);
    5031       end;
    5032     if (OldToTile and not MyMap[ToLoc] and fCity<>0)
    5033       and (MyRO.Government in [gRepublic,gDemocracy,gFuture]) then
    5034       begin // city was destroyed, borders have moved, unrest might have changed in any city
    5035       CityOptimizer_BeginOfTurn;
    5036       NeedEcoUpdate:=true;
    5037       end
    5038     else
    5039       begin
    5040       if cixChanged>=0 then
    5041         begin
    5042         CityOptimizer_CityChange(cixChanged);
    5043         NeedEcoUpdate:=true;
    5044         end;
    5045       if (result=eWon) or (result=eBloody) or (result=eExpelled) then
    5046         begin
    5047         CityOptimizer_TileBecomesAvailable(ToLoc);
    5048         NeedEcoUpdate:=true;
    5049         end;
    5050       end;
    5051     if nLostArmy>1 then
    5052       begin
    5053       with MessgExDlg do
    5054         begin
    5055         Kind:=mkOk;
    5056         IconKind:=mikEnemyArmy;
    5057         MessgText:=Tribe[Defender].TString(Phrases.Lookup('ARMYLOST',
    5058           MyRO.EnemyModel[MyRO.EnemyUn[euix].emix].Domain));
    5059         ShowModal;
    5060         end
    5061       end
    5062     end;
    5063   if result and rUnitRemoved<>0 then
    5064     begin
    5065     CityOptimizer_AfterRemoveUnit;
    5066     ListDlg.RemoveUnit;
    5067     NeedEcoUpdate:=true;
    5068     end;
    5069   if NeedEcoUpdate then
    5070     begin
    5071     UpdateViews(true);
    5072     Update
    5073     end
    5074   end;
    5075 
    5076 if result=eMissionDone then
    5077   begin
    5078   p1:=MyRO.Territory[ToLoc];
    5079   case Mission of
    5080     smStealMap:
    5081       begin MapValid:=false; PaintAllMaps end;
    5082     smStealCivilReport:
    5083       TribeMessage(p1,Tribe[p1].TPhrase('DOSSIER_PREPARED'),'');
    5084     smStealMilReport:
    5085       ListDlg.ShowNewContent_MilReport(wmPersistent,p1);
    5086     end;
    5087   end;
    5088 
    5089 if UnFocus>=0 then
    5090   CheckToldNoReturn(UnFocus);
    5091 
    5092 NeedRepaintPanel:=false;
    5093 if result>=rExecuted then
    5094   begin
    5095   if CityCaptured and (MyMap[ToLoc] and fCity=0) then
    5096     begin // city destroyed
    5097     for i:=0 to 27 do {tell about destroyed wonders}
    5098       if (MyRO.Wonder[i].CityID=-2) and (MyData.ToldWonders[i].CityID<>-2) then
    5099         with MessgExDlg do
    5100           begin
    5101           if WondersDlg.Visible then
    5102             WondersDlg.SmartUpdateContent(false);
    5103           OpenSound:='WONDER_DESTROYED';
    5104           MessgText:=Format(Phrases.Lookup('WONDERDEST'),
    5105             [Phrases.Lookup('IMPROVEMENTS',i)]);
    5106           Kind:=mkOkHelp;
    5107           HelpKind:=hkImp;
    5108           HelpNo:=i;
    5109           IconKind:=mikImp;
    5110           IconIndex:=i;
    5111           ShowModal;
    5112           MyData.ToldWonders[i]:=MyRO.Wonder[i];
    5113           end
    5114     end;
    5115   if CityCaptured and (MyMap[ToLoc] and fCity<>0) then
    5116     begin // city captured
    5117     ListDlg.AddCity;
    5118     for i:=0 to 27 do {tell about capture of wonders}
    5119       if MyRO.City[MyRO.nCity-1].Built[i]>0 then with MessgExDlg do
    5120         begin
    5121         if WondersDlg.Visible then
    5122           WondersDlg.SmartUpdateContent(false);
    5123         OpenSound:='WONDER_CAPTURED';
    5124         MessgText:=Format(Tribe[me].TPhrase('WONDERCAPTOWN'),
    5125           [Phrases.Lookup('IMPROVEMENTS',i)]);
    5126         Kind:=mkOkHelp;
    5127         HelpKind:=hkImp;
    5128         HelpNo:=i;
    5129         IconKind:=mikImp;
    5130         IconIndex:=i;
    5131         ShowModal;
    5132         MyData.ToldWonders[i]:=MyRO.Wonder[i];
    5133         end;
    5134 
    5135     if MyRO.Happened and phStealTech<>0 then
    5136       begin {Temple of Zeus -- choose advance to steal}
    5137       ModalSelectDlg.ShowNewContent(wmModal,kStealTech);
    5138       Server(sStealTech,me,ModalSelectDlg.result,nil^);
    5139       end;
    5140     TellNewModels;
    5141 
    5142     cix:=MyRO.nCity-1;
    5143     while (cix>=0) and (MyCity[cix].Loc<>ToLoc) do
    5144       dec(cix);
    5145     assert(cix>=0);
    5146     MyCity[cix].Status:=MyCity[cix].Status
    5147       and not csResourceWeightsMask or (3 shl 4); // captured city, set to maximum growth
    5148     NewTiles:=1 shl 13; {exploit central tile only}
    5149     Server(sSetCityTiles,me,cix,NewTiles);
    5150     end
    5151   else NeedRepaintPanel:=true;
    5152   end;
    5153 TellNewContacts;
    5154 
    5155 if (UnFocus>=0) and (MyUn[UnFocus].Master>=0) then
    5156   with MyUn[MyUn[UnFocus].Master] do
    5157     if Status and usStay<>0 then
    5158       begin
    5159       Status:=Status and not usStay;
    5160       if (Movement>=100) and (Status and (usRecover or usGoto)=0) then
    5161         Status:=Status or usWaiting;
    5162       end;
    5163 if Options and (muAutoNoWait or muAutoNext)<>0 then
    5164   begin
    5165   if (UnFocus>=0) and ((result=eNoTime_Move) or UnitExhausted(UnFocus)
    5166     or (MyUn[UnFocus].Master>=0)
    5167     or (MyModel[MyUn[UnFocus].mix].Domain=dAir)
    5168       and ((MyMap[MyUn[UnFocus].Loc] and fCity<>0) {aircrafts stop in cities}
    5169         or (MyMap[MyUn[UnFocus].Loc] and fTerImp=tiBase))) then
    5170     begin
    5171     MyUn[UnFocus].Status:=MyUn[UnFocus].Status and not usWaiting;
    5172     if Options and muAutoNext<>0 then
    5173       if CityCaptured and (MyMap[ToLoc] and fCity<>0) then
    5174         begin
    5175         UnFocus:=-1;
    5176         PaintLoc(ToLoc); // don't show unit in city if not selected
    5177         end
    5178       else NextUnit(UnStartLoc,true)
    5179     end
    5180   else if (UnFocus<0) and (Options and muAutoNext<>0) then
    5181     NextUnit(UnStartLoc,result<>eMissionDone);
    5182   end;
    5183 
    5184 if NeedRepaintPanel and (UnFocus=UnFocus0) then
    5185   if IsAttack then PanelPaint
    5186   else
    5187     begin
    5188     assert(result<>eMissionDone);
    5189     CheckTerrainBtnVisible;
    5190     FocusOnLoc(ToLoc,flRepaintPanel or flImmUpdate)
    5191     end;
    5192 
    5193 if (result>=rExecuted) and CityCaptured and (MyMap[ToLoc] and fCity<>0) then
    5194   ZoomToCity(ToLoc,UnFocus<0,chCaptured); // show captured city
    5195 end; // moveunit
    5196 
    5197 procedure TMainScreen.MoveOnScreen(ShowMove: TShowMove; Step0,Step1,nStep: integer;
    5198   Restore: boolean = true);
    5199 var
    5200 ToLoc,xFromLoc,yFromLoc,xToLoc,yToLoc,xFrom,yFrom,xTo,yTo,xMin,yMin,xRange,yRange,
    5201   xw1,Step,xMoving,yMoving,yl,SliceCount:integer;
    5202 UnitInfo: TUnitInfo;
    5203 Ticks0,Ticks: int64;
    5204 begin
    5205 Timer1.Enabled:=false;
    5206 QueryPerformanceCounter(Ticks0);
    5207 with ShowMove do
    5208   begin
    5209   UnitInfo.Owner:=Owner;
    5210   UnitInfo.mix:=mix;
    5211   UnitInfo.Health:=Health;
    5212   UnitInfo.Job:=jNone;
    5213   UnitInfo.Flags:=Flags;
    5214   if Owner<>me then
    5215     UnitInfo.emix:=emix;
    5216 
    5217   ToLoc:=dLoc(FromLoc,dx,dy);
    5218   xToLoc:=ToLoc mod G.lx; yToLoc:=ToLoc div G.lx;
    5219   xFromLoc:=FromLoc mod G.lx; yFromLoc:=FromLoc div G.lx;
    5220   if xToLoc>xFromLoc+2 then xToLoc:=xToLoc-G.lx
    5221   else if xToLoc<xFromLoc-2 then xToLoc:=xToLoc+G.lx;
    5222 
    5223   xw1:=xw+G.lx;
    5224   // ((xFromLoc-xw1)*2+yFromLoc and 1+1)*xxt+dx*xxt/2-MapWidth/2 -> min
    5225   while abs(((xFromLoc-xw1+G.lx)*2+yFromLoc and 1+1)*xxt*2+dx*xxt-MapWidth)
    5226     <abs(((xFromLoc-xw1)*2+yFromLoc and 1+1)*xxt*2+dx*xxt-MapWidth) do
    5227     dec(xw1,G.lx);
    5228 
    5229   xTo:=(xToLoc-xw1)*(xxt*2) + yToLoc and 1 *xxt +(xxt-xxu);
    5230   yTo:=(yToLoc-yw)*yyt +(yyt-yyu_anchor);
    5231   xFrom:=(xFromLoc-xw1)*(xxt*2) + yFromLoc and 1 *xxt +(xxt-xxu);
    5232   yFrom:=(yFromLoc-yw)*yyt +(yyt-yyu_anchor);
    5233   if xFrom<xTo then begin xMin:=xFrom;xRange:=xTo-xFrom end
    5234   else begin xMin:=xTo;xRange:=xFrom-xTo end;
    5235   if yFrom<yTo then begin yMin:=yFrom;yRange:=yTo-yFrom end
    5236   else begin yMin:=yTo;yRange:=yFrom-yTo end;
    5237   inc(xRange,xxt*2);
    5238   inc(yRange,yyt*3);
    5239 
    5240   MainOffscreenPaint;
    5241   NoMap.SetOutput(Buffer);
    5242   NoMap.SetPaintBounds(0,0,xRange,yRange);
    5243   for Step:=0 to abs(Step1-Step0) do
    5244     begin
    5245     BitBlt(Buffer.Canvas.Handle,0,0,xRange,yRange,
    5246       offscreen.Canvas.Handle,xMin,yMin,SRCCOPY);
    5247     if Step1<>Step0 then
    5248       begin
    5249       xMoving:=xFrom+Round((Step0+Step*(Step1-Step0) div abs(Step1-Step0))
    5250         *(xTo-xFrom)/nStep);
    5251       yMoving:=yFrom+Round((Step0+Step*(Step1-Step0) div abs(Step1-Step0))
    5252         *(yTo-yFrom)/nStep);
    5253       end
    5254     else begin xMoving:=xFrom; yMoving:=yFrom; end;
    5255     NoMap.PaintUnit(xMoving-xMin,yMoving-yMin,UnitInfo,0);
    5256     PaintBufferToScreen(xMin,yMin,xRange,yRange);
    5257 
    5258     SliceCount:=0;
    5259     Ticks:=Ticks0;
    5260     repeat
    5261       if (SliceCount=0) or ((Ticks-Ticks0)*12000 *(SliceCount+1)
    5262         div SliceCount<MoveTime*PerfFreq)  then
    5263         begin
    5264         if not idle or (GameMode=cMovie) then
    5265           Application.ProcessMessages;
    5266         Sleep(1);
    5267         inc(SliceCount)
    5268         end;
    5269       QueryPerformanceCounter(Ticks);
    5270     until (Ticks-Ticks0)*12000>=MoveTime*PerfFreq;
    5271     Ticks0:=Ticks
    5272     end;
    5273   end;
    5274 if Restore then
    5275   begin
    5276   BitBlt(Buffer.Canvas.Handle,0,0,xRange,yRange,offscreen.Canvas.Handle,xMin,
    5277     yMin,SRCCOPY);
    5278   PaintBufferToScreen(xMin,yMin,xRange,yRange);
    5279   end;
    5280 BlinkTime:=-1;
    5281 Timer1.Enabled:=true;
    5282 end;
    5283 
    5284 procedure TMainScreen.MoveToLoc(Loc: integer; CheckSuicide: boolean);
    5285 // path finder: move focused unit to loc, start multi-turn goto if too far
    5286 var
    5287 uix,i,MoveOptions,NextLoc,MoveResult: integer;
    5288 MoveAdviceData: TMoveAdviceData;
    5289 StopReason: (None, Arrived, Dead, NoTime, EnemySpotted, MoveError);
    5290 begin
    5291 if MyUn[UnFocus].Job>jNone then
    5292   Server(sStartJob+jNone shl 4,me,UnFocus,nil^);
    5293 if GetMoveAdvice(UnFocus,Loc,MoveAdviceData)>=rExecuted then
    5294   begin
    5295   uix:=UnFocus;
    5296   StopReason:=None;
    5297   repeat
    5298     for i:=0 to MoveAdviceData.nStep-1 do
    5299       begin
    5300       if i=MoveAdviceData.nStep-1 then MoveOptions:=muAutoNext
    5301       else MoveOptions:=0;
    5302       NextLoc:=dLoc(MyUn[uix].Loc,MoveAdviceData.dx[i],MoveAdviceData.dy[i]);
    5303       if (NextLoc=Loc)
    5304         or (Loc=maNextCity) and (MyMap[NextLoc] and fCity<>0) then
    5305         StopReason:=Arrived;
    5306       if not CheckSuicide and (NextLoc=Loc) then
    5307         MoveOptions:=MoveOptions or muNoSuicideCheck;
    5308       MoveResult:=MoveUnit(MoveAdviceData.dx[i],MoveAdviceData.dy[i],MoveOptions);
    5309       if MoveResult<rExecuted then StopReason:=MoveError
    5310       else if MoveResult and rUnitRemoved<>0 then StopReason:=Dead
    5311       else if (StopReason=None) and (MoveResult and rEnemySpotted<>0) then
    5312         StopReason:=EnemySpotted;
    5313       if StopReason<>None then break;
    5314       end;
    5315     if (StopReason=None) and ((MoveAdviceData.nStep<25)
    5316       or (MyRO.Wonder[woShinkansen].EffectiveOwner<>me)) then
    5317       StopReason:=NoTime;
    5318     if StopReason<>None then break;
    5319     if GetMoveAdvice(UnFocus,Loc,MoveAdviceData)<rExecuted then
    5320       begin assert(false); break end
    5321   until false;
    5322 
    5323   case StopReason of
    5324     None: assert(false);
    5325     Arrived: MyUn[uix].Status:=MyUn[uix].Status and ($FFFF-usGoto);
    5326     Dead: if UnFocus<0 then NextUnit(UnStartLoc,false);
    5327     else
    5328       begin // multi-turn goto
    5329       if Loc=maNextCity then
    5330         MyUn[uix].Status:=MyUn[uix].Status and ($FFFF-usStay-usRecover) or usGoto +$7FFF shl 16
    5331       else MyUn[uix].Status:=MyUn[uix].Status and ($FFFF-usStay-usRecover) or usGoto +Loc shl 16;
    5332       PaintLoc(MyUn[uix].Loc);
    5333       if (StopReason=NoTime) and (UnFocus=uix) then
    5334         begin
    5335         MyUn[uix].Status:=MyUn[uix].Status and not usWaiting;
    5336         NextUnit(UnStartLoc,true)
    5337         end;
    5338       end
    5339     end
    5340   end
    5341 end;
    5342 
    5343 procedure TMainScreen.PanelBoxMouseDown(Sender:TObject;
    5344   Button:TMouseButton;Shift:TShiftState;x,y:integer);
    5345 var
    5346 i,xMouse,MouseLoc,p1: integer;
    5347 begin
    5348 if GameMode=cMovie then
    5349   exit;
    5350 
    5351 if Button=mbLeft then
    5352   begin
    5353   if (x>=xMini+2) and (y>=yMini+2) and (x<xMini+2+2*G.lx) and (y<yMini+2+G.ly) then
    5354     if ssShift in Shift then
    5355       begin
    5356       xMouse:=(xwMini+(x-(xMini+2)+MapWidth div (xxt*2)+G.lx) div 2) mod G.lx;
    5357       MouseLoc:=xMouse+G.lx*(y-(yMini+2));
    5358       if MyMap[MouseLoc] and fTerrain<>fUNKNOWN then
    5359         begin
    5360         p1:=MyRO.Territory[MouseLoc];
    5361         if (p1=me) or (p1>=0) and (MyRO.Treaty[p1]>=trNone) then
    5362         NatStatDlg.ShowNewContent(wmPersistent, p1);
    5363         end
    5364       end
    5365     else
    5366       begin
    5367       if CityDlg.Visible then CityDlg.Close;
    5368       if UnitStatDlg.Visible then UnitStatDlg.Close;
    5369       Tracking:=true;
    5370       PanelBoxMouseMove(Sender,Shift+[ssLeft],x,y);
    5371       end
    5372   else if (ClientMode<>cEditMap) and (x>=ClientWidth-xPalace) and (y>=yPalace)
    5373     and (x<ClientWidth-xPalace+xSizeBig) and (y<yPalace+ySizeBig) then
    5374     begin
    5375     InitPopup(StatPopup);       
    5376     if FullScreen then
    5377       StatPopup.Popup(Left+ClientWidth-xPalace+xSizeBig+2,
    5378         Top+ClientHeight-PanelHeight+yPalace-1)
    5379     else StatPopup.Popup(Left+ClientWidth-xPalace+6,
    5380       Top+ClientHeight-PanelHeight+yPalace+ySizeBig+GetSystemMetrics(SM_CYCAPTION)+3)
    5381     end
    5382 (*  else if (x>=xAdvisor-3) and (y>=yAdvisor-3)
    5383     and (x<xAdvisor+16+3) and (y<yAdvisor+16+3) and HaveStrategyAdvice then
    5384     AdviceBtnClick*)
    5385   else if (x>=xTroop+1) and (y>=yTroop+1)
    5386     and (x<xTroop+TrRow*TrPitch) and (y<=yTroop+55) then
    5387     begin
    5388     i:=(x-xTroop-1) div TrPitch;
    5389     if trix[i]>=0 then
    5390       if ClientMode=cEditMap then begin BrushType:=trix[i]; PanelPaint end
    5391       else if (TroopLoc>=0) then
    5392         if MyMap[TroopLoc] and fOwned<>0 then
    5393           begin
    5394           if ssShift in Shift then
    5395             UnitStatDlg.ShowNewContent_OwnModel(wmPersistent, MyUn[trix[i]].mix)
    5396           else if not supervising and (ClientMode<scContact)
    5397             and (x-xTroop-1-i*TrPitch>=60-20) and (y>=yTroop+35)
    5398             and ((MyUn[trix[i]].Job>jNone)
    5399               or (MyUn[trix[i]].Status and (usStay or usRecover or usGoto)<>0)) then
    5400             begin // wake up
    5401             MyUn[trix[i]].Status:=MyUn[trix[i]].Status
    5402               and ($FFFF-usStay-usRecover-usGoto-usEnhance) or usWaiting;
    5403             if MyUn[trix[i]].Job>jNone then
    5404               Server(sStartJob+jNone shl 4,me,trix[i],nil^);
    5405             if (UnFocus<0) and not CityDlg.Visible then
    5406               begin
    5407               SetUnFocus(trix[i]);
    5408               SetTroopLoc(MyUn[trix[i]].Loc);
    5409               FocusOnLoc(TroopLoc,flRepaintPanel)
    5410               end
    5411             else
    5412               begin
    5413               if CityDlg.Visible and (CityDlg.RestoreUnFocus<0) then
    5414                 CityDlg.RestoreUnFocus:=trix[i];
    5415               PanelPaint;
    5416               end
    5417             end
    5418           else if (ClientMode<scContact) then
    5419             begin
    5420             if supervising then
    5421               UnitStatDlg.ShowNewContent_OwnUnit(wmPersistent, trix[i])
    5422             else if CityDlg.Visible then
    5423               begin
    5424               CityDlg.CloseAction:=None;
    5425               CityDlg.Close;
    5426               SumCities(TaxSum,ScienceSum);
    5427               SetUnFocus(trix[i]);
    5428               end
    5429             else
    5430               begin
    5431               DestinationMarkON:=false;
    5432               PaintDestination;
    5433               UnFocus:=trix[i];
    5434               UnStartLoc:=TroopLoc;
    5435               BlinkTime:=0;
    5436               BlinkOn:=false;
    5437               PaintLoc(TroopLoc);
    5438               end;
    5439             if UnFocus>=0 then
    5440               begin
    5441               UnitInfoBtn.Visible:=true;
    5442               UnitBtn.Visible:=true;
    5443               TurnComplete:=false;
    5444               EOT.ButtonIndex:=eotGray;
    5445               end;
    5446             CheckTerrainBtnVisible;
    5447             PanelPaint;
    5448             end
    5449           end
    5450         else if Server(sGetUnits,me,TroopLoc,TrCnt)>=rExecuted then
    5451           if ssShift in Shift then
    5452             UnitStatDlg.ShowNewContent_EnemyModel(wmPersistent,
    5453               MyRO.EnemyUn[MyRO.nEnemyUn+trix[i]].emix) // model info
    5454           else UnitStatDlg.ShowNewContent_EnemyUnit(wmPersistent,
    5455             MyRO.nEnemyUn+trix[i]); // unit info
    5456     end
    5457   end
    5458 end;
    5459 
    5460 procedure TMainScreen.SetTroopLoc(Loc:integer);
    5461 var
    5462 trixFocus,uix,uixDefender: integer;
    5463 Prio: boolean;
    5464 begin
    5465 TroopLoc:=Loc;
    5466 TrRow:=(xRightPanel+10-xTroop-GetSystemMetrics(SM_CXVSCROLL)-19) div TrPitch;
    5467 TrCnt:=0;
    5468 trixFocus:=-1;
    5469 if ClientMode=cEditMap then TrCnt:=nBrushTypes
    5470 else if (Loc>=0) and (MyMap[Loc] and fUnit<>0) then
    5471   if MyMap[Loc] and fOwned<>0 then
    5472     begin // count own units here
    5473     Server(sGetDefender,me,TroopLoc,uixDefender);
    5474     for Prio:=true downto false do
    5475       for uix:=0 to MyRO.nUn-1 do
    5476         if ((uix=uixDefender)=Prio) and (MyUn[uix].Loc=Loc) then
    5477           begin
    5478           if uix=UnFocus then trixFocus:=TrCnt;
    5479           inc(TrCnt);
    5480           end
    5481     end
    5482   else // count enemy units here
    5483     Server(sGetUnits,me,Loc,TrCnt);
    5484 if TrCnt=0 then InitPVSB(sb,0,1)
    5485 else
    5486   begin
    5487   InitPVSB(sb,(TrCnt+TrRow-1) div TrRow-1,1);
    5488   with sb.si do if (nMax>=integer(nPage)) and (trixFocus>=0) then
    5489     begin
    5490     sb.si.npos:=trixFocus div TrRow;
    5491     sb.si.FMask:=SIF_POS;
    5492     SetScrollInfo(sb.h,SB_CTL,sb.si,true);
    5493     end
    5494   end
    5495 end;
    5496 
    5497 (*procedure TMainScreen.ShowMoveHint(ToLoc: integer; Force: boolean = false);
    5498 var
    5499 Step,Loc,x0,y0,xs,ys: integer;
    5500 Info: string;
    5501 InfoSize: TSize;
    5502 MoveAdvice: TMoveAdviceData;
    5503 begin
    5504 if (ToLoc<0) or (ToLoc>=G.lx*G.ly)
    5505   or (UnFocus<0) or (MyUn[UnFocus].Loc=ToLoc) then
    5506   ToLoc:=-1
    5507 else
    5508   begin
    5509   MoveAdvice.ToLoc:=ToLoc;
    5510   MoveAdvice.MoreTurns:=0;
    5511   MoveAdvice.MaxHostile_MovementLeft:=MyUn[UnFocus].Health-50;
    5512   if Server(sGetMoveAdvice,me,UnFocus,MoveAdvice)<rExecuted then
    5513     ToLoc:=-1
    5514   end;
    5515 if (ToLoc=MoveHintToLoc) and not Force then exit;
    5516 if (ToLoc<>MoveHintToLoc) and (MoveHintToLoc>=0) then
    5517   begin invalidate; update end; // clear old hint from screen
    5518 MoveHintToLoc:=ToLoc;
    5519 if ToLoc<0 then exit;
    5520 
    5521 with canvas do
    5522   begin
    5523   Pen.Color:=$80C0FF;
    5524   Pen.Width:=3;
    5525   Loc:=MyUn[UnFocus].Loc;
    5526   for Step:=0 to MoveAdvice.nStep do
    5527     begin
    5528     y0:=(Loc+G.lx*1024) div G.lx -1024;
    5529     x0:=(Loc+(y0 and 1+G.lx*1024) div 2) mod G.lx;
    5530     xs:=(x0-xw)*66+y0 and 1*33-G.lx*66;
    5531     while abs(2*(xs+G.lx*66)-MapWidth)<abs(2*xs-MapWidth) do
    5532       inc(xs,G.lx*66);
    5533     ys:=(y0-yw)*16;
    5534     if Step=0 then moveto(xs+33,ys+16)
    5535     else lineto(xs+33,ys+16);
    5536     if Step<MoveAdvice.nStep then
    5537       Loc:=dLoc(Loc,MoveAdvice.dx[Step],MoveAdvice.dy[Step]);
    5538     end;
    5539   Brush.Color:=$80C0FF;
    5540   Info:=' '+inttostr(88)+' ';
    5541   InfoSize:=TextExtent(Info);
    5542   TextOut(xs+33-InfoSize.cx div 2, ys+16-InfoSize.cy div 2, Info);
    5543   Brush.Style:=bsClear;
    5544   end
    5545 end;*)
    5546 
    5547 procedure TMainScreen.SetDebugMap(p: integer);
    5548 begin
    5549 IsoEngine.pDebugMap:=p;
    5550 IsoEngine.Options:=IsoEngine.Options and not (1 shl moLocCodes);
    5551 mLocCodes.Checked:=false;
    5552 MapValid:=false;
    5553 MainOffscreenPaint;
    5554 end;
    5555 
    5556 procedure TMainScreen.SetViewpoint(p: integer);
    5557 var
    5558 i: integer;
    5559 begin
    5560 if supervising and (G.RO[0].Turn>0)
    5561   and ((p=0) or (1 shl p and G.RO[0].Alive<>0)) then
    5562   begin
    5563   for i:=0 to Screen.FormCount-1 do
    5564     if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
    5565       Screen.Forms[i].Close; // close windows
    5566   ItsMeAgain(p);
    5567   SumCities(TaxSum,ScienceSum);
    5568   for i:=0 to MyRO.nModel-1 do
    5569     if Tribe[me].ModelPicture[i].HGr=0 then
    5570       InitMyModel(i,true);
    5571 
    5572   SetTroopLoc(-1);
    5573   PanelPaint;
    5574   MapValid:=false;
    5575   PaintAllMaps;
    5576   end
    5577 end;
    5578 
    5579 procedure TMainScreen.FormKeyDown(Sender:TObject;var Key:word;
    5580   Shift:TShiftState);
    5581 
    5582   procedure MenuClick_Check(Popup: TPopupMenu; Item: TMenuItem);
    5583   begin
    5584   InitPopup(Popup);
    5585   if Item.Visible and Item.Enabled then MenuClick(Item);
    5586   end;
    5587 
    5588 var
    5589 dx,dy: integer;
    5590 time0,time1: int64;
    5591 begin
    5592 if GameMode=cMovie then
    5593   begin
    5594   case Key of
    5595     VK_F4: MenuClick_Check(StatPopup,mScienceStat);
    5596     VK_F6: MenuClick_Check(StatPopup,mDiagram);
    5597     VK_F7: MenuClick_Check(StatPopup,mWonders);
    5598     VK_F8: MenuClick_Check(StatPopup,mShips);
    5599     end;
    5600   exit;
    5601   end;
    5602 
    5603 if not idle then exit;
    5604 
    5605 if ClientMode=cEditMap then
    5606   begin
    5607   if Shift=[ssCtrl] then
    5608     case char(Key) of
    5609 (*      'A':
    5610         begin // auto symmetry
    5611         Server($7F0,me,0,nil^);
    5612         MapValid:=false;
    5613         PaintAll;
    5614         end;
    5615       'B':
    5616         begin // land mass
    5617         dy:=0;
    5618         for dx:=G.lx to G.lx*(G.ly-1)-1 do
    5619           if MyMap[dx] and fTerrain>=fGrass then inc(dy);
    5620         dy:=dy
    5621         end;*)
    5622       'Q':MenuClick(mResign);
    5623       'R':MenuClick(mRandomMap);
    5624       end
    5625   else if Shift=[] then
    5626     case char(Key) of
    5627       char(VK_F1): MenuClick(mHelp);
    5628       end;
    5629   exit;
    5630   end;
    5631 
    5632 if Shift=[ssAlt] then
    5633   case char(Key) of
    5634     '0': SetDebugMap(-1);
    5635     '1'..'9': SetDebugMap(ord(Key)-48);
    5636     end
    5637 else if Shift=[ssCtrl] then
    5638   case char(Key) of
    5639     'J':MenuClick(mJump);
    5640     'K':mShowClick(mDebugMap);
    5641     'L':mShowClick(mLocCodes);
    5642     'M':if LogDlg.Visible then LogDlg.Close else LogDlg.Show;
    5643     'N':mNamesClick(mNames);
    5644     'Q':MenuClick_Check(GamePopup,mResign);
    5645     'R':MenuClick(mRun);
    5646     '0'..'9':
    5647        begin
    5648        if ord(Key)-48=me then
    5649          SetViewpoint(0)
    5650        else SetViewpoint(ord(Key)-48);
    5651        end;
    5652     ' ':
    5653       begin // test map repaint time
    5654       QueryPerformanceCounter(time0);
    5655       MapValid:=false;
    5656       MainOffscreenPaint;
    5657       QueryPerformanceCounter(time1);
    5658       SimpleMessage(Format('Map repaint time: %.3f ms',[{$IFDEF VER100}(time1.LowPart-time0.LowPart)
    5659         {$ELSE}(time1-time0){$ENDIF}*1000.0/PerfFreq]));
    5660       end
    5661     end
    5662 else if Shift=[] then
    5663   case char(Key) of
    5664     char(VK_F1): MenuClick(mHelp);
    5665     char(VK_F2):MenuClick_Check(StatPopup,mUnitStat);
    5666     char(VK_F3):MenuClick_Check(StatPopup,mCityStat);
    5667     char(VK_F4):MenuClick_Check(StatPopup,mScienceStat);
    5668     char(VK_F5):MenuClick_Check(StatPopup,mEUnitStat);
    5669     char(VK_F6):MenuClick_Check(StatPopup,mDiagram);
    5670     char(VK_F7):MenuClick_Check(StatPopup,mWonders);
    5671     char(VK_F8):MenuClick_Check(StatPopup,mShips);
    5672     char(VK_F9):MenuClick_Check(StatPopup,mNations);
    5673     char(VK_F10):MenuClick_Check(StatPopup,mEmpire);
    5674     char(VK_ADD): EndTurn;
    5675     '1':MapBtnClick(MapBtn0);
    5676     '2':MapBtnClick(MapBtn1);
    5677     '3':MapBtnClick(MapBtn4);
    5678     '4':MapBtnClick(MapBtn5);
    5679     '5':MapBtnClick(MapBtn6);
    5680     'T':MenuClick(mTechTree);
    5681     'W':MenuClick(mWait);
    5682     end;
    5683 
    5684 if UnFocus>=0 then
    5685   if Shift=[ssCtrl] then
    5686     case char(Key) of
    5687       'C':MenuClick_Check(UnitPopup,mCancel);
    5688       'D':MenuClick(mDisband);
    5689       'P':MenuClick_Check(UnitPopup,mPillage);
    5690       'T':MenuClick_Check(UnitPopup,mSelectTransport);
    5691       end
    5692   else if Shift=[] then
    5693     case char(Key) of
    5694       ' ':MenuClick(mNoOrders);
    5695       'A':MenuClick_Check(TerrainPopup,mAirBase);
    5696       'B':MenuClick_Check(UnitPopup,mCity);
    5697       'C':MenuClick(mCentre);
    5698       'E':
    5699         begin
    5700         InitPopup(TerrainPopup);
    5701         if mEnhance.Visible and mEnhance.Enabled then MenuClick(mEnhance)
    5702         else MenuClick(mEnhanceDef)
    5703         end;
    5704       'F':MenuClick_Check(TerrainPopup,mFort);
    5705       'G':MenuClick_Check(UnitPopup,mGoOn);
    5706       'H':MenuClick_Check(UnitPopup,mHome);
    5707       'I':
    5708         if JobTest(UnFocus,jFarm,[eTreaty]) then MenuClick(mFarm)
    5709         else if JobTest(UnFocus,jClear,[eTreaty]) then MenuClick(mClear)
    5710         else MenuClick_Check(TerrainPopup,mIrrigation);
    5711       'L':MenuClick_Check(UnitPopup,mLoad);
    5712       'M':
    5713         if JobTest(UnFocus,jAfforest,[eTreaty]) then MenuClick(mAfforest)
    5714         else MenuClick_Check(TerrainPopup,mMine);
    5715       'N':MenuClick_Check(TerrainPopup,mCanal);
    5716       'O':MenuClick_Check(TerrainPopup,mTrans);
    5717       'P':MenuClick_Check(TerrainPopup,mPollution);
    5718       'R':
    5719         if JobTest(UnFocus,jRR,[eTreaty]) then MenuClick(mRR)
    5720         else MenuClick_Check(TerrainPopup,mRoad);
    5721       'S':MenuClick(mStay);
    5722       'U':MenuClick_Check(UnitPopup,mUnload);
    5723       'V':MenuClick_Check(UnitPopup,mRecover);
    5724       'Z':MenuClick_Check(UnitPopup,mUtilize);
    5725       #33..#40,#97..#100,#102..#105:
    5726         begin {arrow keys}
    5727         DestinationMarkON:=false;
    5728         PaintDestination;
    5729         MyUn[UnFocus].Status:=MyUn[UnFocus].Status
    5730           and ($FFFF-usStay-usRecover-usGoto-usEnhance) or usWaiting;
    5731         case Key of
    5732           VK_NUMPAD1,VK_END: begin dx:=-1; dy:=1 end;
    5733           VK_NUMPAD2,VK_DOWN: begin dx:=0; dy:=2 end;
    5734           VK_NUMPAD3,VK_NEXT: begin dx:=1; dy:=1 end;
    5735           VK_NUMPAD4,VK_LEFT: begin dx:=-2; dy:=0 end;
    5736           VK_NUMPAD6,VK_RIGHT: begin dx:=2; dy:=0 end;
    5737           VK_NUMPAD7,VK_HOME: begin dx:=-1; dy:=-1 end;
    5738           VK_NUMPAD8,VK_UP: begin dx:=0; dy:=-2 end;
    5739           VK_NUMPAD9,VK_PRIOR: begin dx:=1; dy:=-1 end;
    5740           end;
    5741         MoveUnit(dx,dy,muAutoNext)
    5742         end;
    5743       end
    5744 end;
    5745 
    5746 procedure TMainScreen.MenuClick(Sender:TObject);
    5747 
    5748   function DoJob(j0:integer): integer;
    5749   var
    5750   Loc0, Movement0: integer;
    5751   begin
    5752   with MyUn[UnFocus] do
    5753     begin
    5754     DestinationMarkON:=false;
    5755     PaintDestination;
    5756     Loc0:=Loc;
    5757     Movement0:=Movement;
    5758     if j0<0 then result:=ProcessEnhancement(UnFocus,MyData.EnhancementJobs) // terrain enhancement
    5759     else result:=Server(sStartJob+j0 shl 4,me,UnFocus,nil^);
    5760     if result>=rExecuted then
    5761       begin
    5762       if result=eDied then UnFocus:=-1;
    5763       PaintLoc(Loc0);
    5764       if UnFocus>=0 then
    5765         begin
    5766         if (j0<0) and (result<>eJobDone) then // multi-turn terrain enhancement
    5767           Status:=Status and ($FFFF-usStay-usRecover-usGoto) or usEnhance
    5768         else Status:=Status and ($FFFF-usStay-usRecover-usGoto-usEnhance);
    5769         if (Job<>jNone) or (Movement0<100) then
    5770           begin
    5771           Status:=Status and not usWaiting;
    5772           NextUnit(UnStartLoc,true);
    5773           end
    5774         else PanelPaint
    5775         end
    5776       else NextUnit(UnStartLoc,true);
    5777       end
    5778     end;
    5779   case result of
    5780     eNoBridgeBuilding: SoundMessage(Phrases.Lookup('NOBB'),'INVALID');
    5781     eNoCityTerrain: SoundMessage(Phrases.Lookup('NOCITY'),'INVALID');
    5782     eTreaty: SoundMessage(Tribe[MyRO.Territory[Loc0]].TPhrase('PEACE_NOWORK'),'NOMOVE_TREATY');
    5783     else if result<rExecuted then Play('INVALID')
    5784     end
    5785   end;
    5786 
    5787 var
    5788 i,uix,NewFocus,Loc0,OldMaster,Destination,cix,cixOldHome,ServerResult: integer;
    5789 AltGovs,changed: boolean;
    5790 QueryText: string;
    5791 
    5792 begin
    5793 if Sender=mResign then
    5794   if ClientMode=cEditMap then
    5795     begin
    5796     if Edited then
    5797       begin
    5798       QueryText:=Phrases.Lookup('MAP_CLOSE');
    5799       case SimpleQuery(mkYesNoCancel,QueryText,'') of
    5800         mrIgnore:
    5801           Server(sAbandonMap,me,0,nil^);
    5802         mrOK:
    5803           Server(sSaveMap,me,0,nil^);
    5804         end
    5805       end
    5806     else Server(sAbandonMap,me,0,nil^)
    5807     end
    5808   else
    5809     begin
    5810     if Server(sGetGameChanged,0,0,nil^)=eOK then
    5811       begin
    5812       QueryText:=Phrases.Lookup('RESIGN');
    5813       case SimpleQuery(mkYesNoCancel,QueryText,'') of
    5814         mrIgnore:
    5815           Server(sResign,0,0,nil^);
    5816         mrOK:
    5817           Server(sBreak,0,0,nil^)
    5818         end
    5819       end
    5820     else Server(sResign,0,0,nil^)
    5821     end
    5822 else if Sender=mEmpire then
    5823   RatesDlg.ShowNewContent(wmPersistent)
    5824 else if Sender=mRevolution then
    5825   begin
    5826   AltGovs:=false;
    5827   for i:=2 to nGov-1 do
    5828     if (GovPreq[i]<>preNA) and ((GovPreq[i]=preNone)
    5829       or (MyRO.Tech[GovPreq[i]]>=tsApplicable)) then
    5830       AltGovs:=true;
    5831 
    5832   if not AltGovs then
    5833     SoundMessage(Phrases.Lookup('NOALTGOVS'),'MSG_DEFAULT')
    5834   else
    5835     begin
    5836     changed:=false;
    5837     if MyRO.Happened and phChangeGov<>0 then
    5838       begin
    5839       ModalSelectDlg.ShowNewContent(wmModal,kGov);
    5840       if ModalSelectDlg.result>=0 then
    5841         begin
    5842         Play('NEWGOV');
    5843         Server(sSetGovernment,me,ModalSelectDlg.result,nil^);
    5844         CityOptimizer_BeginOfTurn;
    5845         changed:=true;
    5846         end
    5847       end
    5848     else with MessgExDlg do
    5849       begin // revolution!
    5850       MessgText:=Tribe[me].TPhrase('REVOLUTION');
    5851       Kind:=mkYesNo;
    5852       IconKind:=mikPureIcon;
    5853       IconIndex:=72; // anarchy palace
    5854       ShowModal;
    5855       if ModalResult=mrOK then
    5856         begin
    5857         Play('REVOLUTION');
    5858         Server(sRevolution,me,0,nil^);
    5859         changed:=true;
    5860         if NatStatDlg.Visible then NatStatDlg.Close;
    5861         if CityDlg.Visible then CityDlg.Close;
    5862         end
    5863       end;
    5864     if changed then
    5865       UpdateViews(true);
    5866     end
    5867   end
    5868 else if Sender=mWebsite then
    5869   ShellExecute(Handle,'open','http://c-evo.org','','',SW_SHOWNORMAL)
    5870 else if Sender=mRandomMap then
    5871   begin
    5872   if not Edited or (SimpleQuery(mkYesNo,Phrases.Lookup('MAP_RANDOM'),'')=mrOK) then
    5873     begin
    5874     Server(sRandomMap,me,0,nil^);
    5875     Edited:=true;
    5876     MapValid:=false;
    5877     PaintAllMaps;
    5878     end
    5879   end
    5880 else if Sender=mJump then
    5881   begin
    5882   if supervising then
    5883     Jump[0]:=20
    5884   else Jump[me]:=20;
    5885   EndTurn(true);
    5886   end
    5887 else if Sender=mRun then
    5888   begin
    5889   if supervising then
    5890     Jump[0]:=999999
    5891   else Jump[me]:=999999;
    5892   EndTurn(true);
    5893   end
    5894 else if Sender=mEnhanceDef then
    5895   begin
    5896   if UnFocus>=0 then
    5897     EnhanceDlg.ShowNewContent(wmPersistent, MyMap[MyUn[UnFocus].Loc] and fTerrain)
    5898   else EnhanceDlg.ShowNewContent(wmPersistent)
    5899   end
    5900 else if Sender=mCityTypes then
    5901   CityTypeDlg.ShowNewContent(wmModal) // must be modal because types are not saved before closing
    5902 else if Sender=mUnitStat then
    5903   begin
    5904   if G.Difficulty[me]>0 then
    5905     ListDlg.ShowNewContent_MilReport(wmPersistent,me)
    5906   else
    5907     begin
    5908     i:=1;
    5909     while (i<nPl) and (1 shl i and MyRO.Alive=0) do inc(i);
    5910     if i<nPl then
    5911       ListDlg.ShowNewContent_MilReport(wmPersistent,i);
    5912     end;
    5913   end
    5914 else if Sender=mEUnitStat then
    5915   begin
    5916   if MyRO.nEnemyModel>0 then
    5917     ListDlg.ShowNewContent(wmPersistent,kAllEModels);
    5918   end
    5919 else if Sender=mCityStat then
    5920   ListDlg.ShowNewContent(wmPersistent,kCities)
    5921 else if Sender=mScienceStat then
    5922   ListDlg.ShowNewContent(wmPersistent,kScience)
    5923 else if Sender=mNations then
    5924   NatStatDlg.ShowNewContent(wmPersistent)
    5925 else if Sender=mHelp then
    5926   if ClientMode=cEditMap then
    5927     HelpDlg.ShowNewContent(wmPersistent, hkText, HelpDlg.TextIndex('MAPEDIT'))
    5928   else HelpDlg.ShowNewContent(wmPersistent, hkMisc, miscMain)
    5929 else if Sender=mTechTree then
    5930   TechTreeDlg.ShowModal
    5931 else if Sender=mWonders then
    5932   WondersDlg.ShowNewContent(wmPersistent)
    5933 else if Sender=mDiagram then
    5934   DiaDlg.ShowNewContent_Charts(wmPersistent)
    5935 else if Sender=mShips then
    5936   DiaDlg.ShowNewContent_Ship(wmPersistent)
    5937 else if Sender=mWait then
    5938   begin
    5939   if UnFocus>=0 then
    5940     begin
    5941     DestinationMarkON:=false;
    5942     PaintDestination;
    5943     MyUn[UnFocus].Status:=MyUn[UnFocus].Status and ($FFFF-usStay-usRecover-usGoto-usEnhance) or usWaiting;
    5944     end;
    5945   NextUnit(-1,false);
    5946   end
    5947 else if UnFocus>=0 then with MyUn[UnFocus] do
    5948   if Sender=mGoOn then
    5949     begin
    5950     if Status shr 16=$7FFF then Destination:=maNextCity
    5951     else Destination:=Status shr 16;
    5952     Status:=Status and not (usStay or usRecover) or usWaiting;
    5953     MoveToLoc(Destination,true);
    5954     end
    5955   else if Sender=mHome then
    5956     if MyMap[Loc] and fCity<>0 then
    5957       begin
    5958       cixOldHome:=Home;
    5959       if Server(sSetUnitHome,me,UnFocus,nil^)>=rExecuted then
    5960         begin
    5961         CityOptimizer_CityChange(cixOldHome);
    5962         CityOptimizer_CityChange(Home);
    5963         UpdateViews(true);
    5964         end
    5965       else Play('INVALID');
    5966       end
    5967     else
    5968       begin
    5969       Status:=Status and not (usStay or usRecover or usEnhance);
    5970       MoveToLoc(maNextCity,true)
    5971       end
    5972   else if Sender=mCentre then begin Centre(Loc); PaintAllMaps end
    5973   else if Sender=mCity then
    5974     begin
    5975     Loc0:=Loc;
    5976     if MyMap[Loc] and fCity=0 then
    5977       begin // build city
    5978       if DoJob(jCity)=eCity then
    5979         begin
    5980         MapValid:=false;
    5981         PaintAll;
    5982         ZoomToCity(Loc0,true,chFounded);
    5983         end
    5984       end
    5985     else
    5986       begin
    5987       CityOptimizer_BeforeRemoveUnit(UnFocus);
    5988       ServerResult:=Server(sAddToCity,me,UnFocus,nil^);
    5989       if ServerResult>=rExecuted then
    5990         begin
    5991         cix:=MyRO.nCity-1;
    5992         while (cix>=0) and (MyCity[cix].Loc<>Loc0) do
    5993           dec(cix);
    5994         assert(cix>=0);
    5995         CityOptimizer_CityChange(cix);
    5996         CityOptimizer_AfterRemoveUnit; // does nothing here
    5997         SetTroopLoc(Loc0);
    5998         UpdateViews(true);
    5999         DestinationMarkON:=false;
    6000         PaintDestination;
    6001         UnFocus:=-1;
    6002         PaintLoc(Loc0);
    6003         NextUnit(UnStartLoc,true);
    6004         end
    6005       else if ServerResult=eMaxSize then
    6006         SimpleMessage(Phrases.Lookup('ADDTOMAXSIZE'));
    6007       end
    6008     end
    6009   else if Sender=mRoad then DoJob(jRoad)
    6010   else if Sender=mRR then DoJob(jRR)
    6011   else if Sender=mClear then DoJob(jClear)
    6012   else if Sender=mIrrigation then DoJob(jIrr)
    6013   else if Sender=mFarm then DoJob(jFarm)
    6014   else if Sender=mAfforest then DoJob(jAfforest)
    6015   else if Sender=mMine then DoJob(jMine)
    6016   else if Sender=mCanal then DoJob(jCanal)
    6017   else if Sender=MTrans then DoJob(jTrans)
    6018   else if Sender=mFort then DoJob(jFort)
    6019   else if Sender=mAirBase then DoJob(jBase)
    6020   else if Sender=mPollution then DoJob(jPoll)
    6021   else if Sender=mPillage then DoJob(jPillage)
    6022   else if Sender=mEnhance then DoJob(-1)
    6023   else if Sender=mStay then
    6024     begin
    6025     DestinationMarkON:=false;
    6026     PaintDestination;
    6027     Status:=Status and ($FFFF-usRecover-usGoto-usEnhance) or usStay;
    6028     if Job>jNone then
    6029       Server(sStartJob+jNone shl 4,me,UnFocus,nil^);
    6030     NextUnit(UnStartLoc,true)
    6031     end
    6032   else if Sender=mRecover then
    6033     begin
    6034     DestinationMarkON:=false;
    6035     PaintDestination;
    6036     Status:=Status and ($FFFF-usStay-usGoto-usEnhance) or usRecover;
    6037     if Job>jNone then
    6038       Server(sStartJob+jNone shl 4,me,UnFocus,nil^);
    6039     NextUnit(UnStartLoc,true)
    6040     end
    6041   else if Sender=mNoOrders then
    6042     begin
    6043     Status:=Status and not usWaiting;
    6044     NextUnit(UnStartLoc,true)
    6045     end
    6046   else if Sender=mCancel then
    6047     begin
    6048     DestinationMarkON:=false;
    6049     PaintDestination;
    6050     Status:=Status and ($FFFF-usRecover-usGoto-usEnhance);
    6051     if Job>jNone then
    6052       Server(sStartJob+jNone shl 4,me,UnFocus,nil^);
    6053     end
    6054   else if (Sender=mDisband) or (Sender=mUtilize) then
    6055     begin
    6056     if (Sender=mUtilize)
    6057       and not (Server(sRemoveUnit-sExecute,me,UnFocus,nil^)=eUtilized) then
    6058       begin
    6059       SimpleMessage(Phrases2.Lookup('SHIP_UTILIZE'));
    6060         // freight for colony ship is the only case in which the command is
    6061         // available to player though not valid
    6062       exit
    6063       end;
    6064     if (Sender=mUtilize) and (Health<100) then
    6065       if SimpleQuery(mkYesNo,Phrases.Lookup('DAMAGED_UTILIZE'),'')<>mrOK then
    6066         exit;
    6067     Loc0:=Loc;
    6068     CityOptimizer_BeforeRemoveUnit(UnFocus);
    6069     if Server(sRemoveUnit,me,UnFocus,nil^)=eUtilized then Play('CITY_UTILIZE')
    6070     else Play('DISBAND');
    6071     CityOptimizer_AfterRemoveUnit;
    6072     SetTroopLoc(Loc0);
    6073     UpdateViews(true);
    6074     DestinationMarkON:=false;
    6075     PaintDestination;
    6076     UnFocus:=-1;
    6077     PaintLoc(Loc0);
    6078     NextUnit(UnStartLoc,true);
    6079     end
    6080   else if Sender=mLoad then
    6081     begin
    6082     i:=Server(sLoadUnit,me,UnFocus,nil^);
    6083     if i>=rExecuted then
    6084       begin
    6085       if MyModel[mix].Domain=dAir then Play('MOVE_PLANELANDING')
    6086       else Play('MOVE_LOAD');
    6087       DestinationMarkON:=false;
    6088       PaintDestination;
    6089       Status:=Status and ($FFFF-usWaiting-usStay-usRecover-usGoto-usEnhance);
    6090       NextUnit(UnStartLoc,true);
    6091       end
    6092     else if i=eNoTime_Load then
    6093       if MyModel[mix].Domain=dAir then
    6094         SoundMessage(Phrases.Lookup('NOTIMELOADAIR'),'NOMOVE_TIME')
    6095       else
    6096         SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
    6097           [MovementToString(MyModel[mix].Speed)]),'NOMOVE_TIME');
    6098     end
    6099   else if Sender=mUnload then
    6100     if Master>=0 then
    6101       begin
    6102       OldMaster:=Master;
    6103       i:=Server(sUnloadUnit,me,UnFocus,nil^);
    6104       if i>=rExecuted then
    6105         begin
    6106         if MyModel[mix].Domain=dAir then Play('MOVE_PLANESTART')
    6107         else if (MyModel[MyUn[OldMaster].mix].Domain=dAir)
    6108           and (MyMap[Loc] and fCity=0) and (MyMap[Loc] and fTerImp<>tiBase) then
    6109           Play('MOVE_PARACHUTE')
    6110         else Play('MOVE_UNLOAD');
    6111         Status:=Status and not usWaiting;
    6112         if MyModel[mix].Domain<>dAir then NextUnit(Loc,true)
    6113         else PanelPaint
    6114         end
    6115       else if i=eNoTime_Load then
    6116         if MyModel[mix].Domain=dAir then
    6117           SoundMessage(Phrases.Lookup('NOTIMELOADAIR'),'NOMOVE_TIME')
    6118         else
    6119           SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
    6120             [MovementToString(MyModel[mix].Speed)]),'NOMOVE_TIME');
    6121       end
    6122     else
    6123       begin
    6124       NewFocus:=-1;
    6125       uix:=UnFocus;
    6126       for i:=1 to MyRo.nUn-1 do
    6127         begin
    6128         uix:=(uix+MyRO.nUn-1) mod MyRO.nUn;
    6129         if (MyUn[uix].Master=UnFocus)
    6130           and (MyUn[uix].Movement=integer(MyModel[MyUn[uix].mix].Speed)) then
    6131           begin
    6132           MyUn[uix].Status:=MyUn[uix].Status or usWaiting;
    6133           NewFocus:=uix
    6134           end;
    6135         end;
    6136       if NewFocus>=0 then
    6137         begin
    6138         SetUnFocus(NewFocus);
    6139         SetTroopLoc(Loc);
    6140         PanelPaint
    6141         end
    6142       end
    6143   else if Sender=mSelectTransport then
    6144     Server(sSelectTransport,me,UnFocus,nil^)
    6145 end;
    6146 
    6147 procedure TMainScreen.InitPopup(Popup: TPopupMenu);
    6148 var
    6149 i,p1,Tile,Test: integer;
    6150 NoSuper,extended,Multi,NeedSep,HaveCities: boolean;
    6151 LastSep,m: TMenuItem;
    6152 mox: ^TModel;
    6153 begin
    6154 NoSuper:=not supervising and (1 shl me and MyRO.Alive<>0);
    6155 HaveCities:=false;
    6156 for i:=0 to MyRO.nCity-1 do if MyCity[i].Loc>=0 then
    6157   begin HaveCities:=true; Break end;
    6158 if Popup=GamePopup then
    6159   begin
    6160   mTechTree.Visible:= ClientMode<>cEditMap;
    6161   mResign.Enabled:= supervising or (me=0) and (ClientMode<scContact);
    6162   mRandomMap.Visible:= (ClientMode=cEditMap)
    6163     and (Server(sMapGeneratorRequest,me,0,nil^)=eOk);
    6164   mOptions.Visible:= ClientMode<>cEditMap;
    6165   mManip.Visible:= ClientMode<>cEditMap;
    6166   if ClientMode<>cEditMap then
    6167     begin
    6168     mWaitTurn.Visible:= NoSuper;
    6169     mRep.Visible:= NoSuper;
    6170     mRepList.Visible:= NoSuper;
    6171     mRepScreens.Visible:= NoSuper;
    6172     N10.Visible:= NoSuper;
    6173     mOwnMovement.Visible:= NoSuper;
    6174     mAllyMovement.Visible:= NoSuper;
    6175     case SoundMode of
    6176       smOff: mSoundOff.Checked:=true;
    6177       smOn: mSoundOn.Checked:=true;
    6178       smOnAlt: mSoundOnAlt.Checked:=true;
    6179       end;
    6180 
    6181     for i:=0 to nTestFlags-1 do
    6182       mManip[i].Checked:= MyRO.TestFlags and (1 shl i)<>0;
    6183     mManip.Enabled:= supervising or (me=0);
    6184 
    6185     Multi:=false;
    6186     for p1:=1 to nPl-1 do
    6187       if G.RO[p1]<>nil then Multi:=true;
    6188     mEnemyMovement.Visible:=not Multi;
    6189     end;
    6190   mMacro.Visible:= NoSuper and (ClientMode<scContact);
    6191   if NoSuper and (ClientMode<scContact) then
    6192     begin
    6193     mCityTypes.Enabled:=false;
    6194     // check if city types already usefull:
    6195     if MyRO.nCity>0 then
    6196       for i:=28 to nImp-1 do
    6197         if (i<>imTrGoods) and (Imp[i].Kind=ikCommon) and (Imp[i].Preq<>preNA)
    6198           and ((Imp[i].Preq=preNone) or (MyRO.Tech[Imp[i].Preq]>=tsApplicable)) then
    6199           begin mCityTypes.Enabled:=true; Break end;
    6200     end;
    6201   mViewpoint.visible:=(ClientMode<>cEditMap) and supervising;
    6202   mViewpoint.enabled:= G.RO[0].Turn>0;
    6203   if supervising then
    6204     begin
    6205     EmptyMenu(mViewpoint);
    6206     for p1:=0 to nPl-1 do
    6207       if (p1=0) or (1 shl p1 and G.RO[0].Alive<>0) then
    6208         begin
    6209         m:=TMenuItem.Create(mViewpoint);
    6210         if p1=0 then
    6211           m.Caption:=Phrases.Lookup('SUPER')
    6212         else m.Caption:=Tribe[p1].TString(Phrases2.Lookup('BELONG'));
    6213         m.Tag:=p1;
    6214         m.OnClick:=ViewPointClick;
    6215         if p1<10 then
    6216           m.ShortCut:=Shortcut(48+p1, [ssCtrl]);
    6217         m.RadioItem:=true;
    6218         if p1=me then
    6219           m.Checked:=true;
    6220         mViewPoint.Add(m);
    6221         end
    6222     end;
    6223   mDebugMap.visible:=(ClientMode<>cEditMap) and supervising;
    6224   if supervising then
    6225     begin
    6226     EmptyMenu(mDebugMap);
    6227     for p1:=0 to nPl-1 do
    6228       if (p1=0) or (1 shl p1 and G.RO[0].Alive<>0) then
    6229         begin
    6230         m:=TMenuItem.Create(mDebugMap);
    6231         if p1=0 then
    6232           m.Caption:=Phrases2.Lookup('MENU_DEBUGMAPOFF')
    6233         else m.Caption:=Tribe[p1].TString(Phrases2.Lookup('BELONG'));
    6234         if p1=0 then
    6235           m.Tag:=-1
    6236         else m.Tag:=p1;
    6237         m.OnClick:=DebugMapClick;
    6238         if p1<10 then
    6239           m.ShortCut:=Shortcut(48+p1, [ssAlt]);
    6240         m.RadioItem:=true;
    6241         if m.Tag=IsoEngine.pDebugMap then
    6242           m.Checked:=true;
    6243         mDebugMap.Add(m);
    6244         end
    6245     end;
    6246   mSmallTiles.Checked:= xxt=33;
    6247   mNormalTiles.Checked:= xxt=48;
    6248   end
    6249 else if Popup=StatPopup then
    6250   begin
    6251   mEmpire.Visible:= NoSuper;
    6252   mEmpire.Enabled:= MyRO.Government<>gAnarchy;
    6253   mRevolution.Visible:= NoSuper;
    6254   mRevolution.Enabled:= (MyRO.Government<>gAnarchy) and (ClientMode<scContact);
    6255   mUnitStat.Enabled:= NoSuper or (MyRO.Turn>0);
    6256   mCityStat.Visible:= 1 shl me and MyRO.Alive<>0;
    6257   mCityStat.Enabled:= HaveCities;
    6258   mScienceStat.Visible:= true;
    6259   mScienceStat.Enabled:= not NoSuper or (MyRO.ResearchTech>=0)
    6260     or (MyRO.Happened and phTech<>0)
    6261     or (MyRO.Happened and phGameEnd<>0) // no researchtech in case just completed
    6262     or (MyRO.TestFlags and (tfAllTechs or tfUncover or tfAllContact)<>0);
    6263   mEUnitStat.Enabled:= MyRO.nEnemyModel>0;
    6264 {  mWonders.Enabled:= false;
    6265   for i:=0 to 27 do if MyRO.Wonder[i].CityID<>-1 then
    6266     mWonders.Enabled:=true;}
    6267   mDiagram.Enabled:= MyRO.Turn>=2;
    6268   mShips.Enabled:=false;
    6269   for p1:=0 to nPl-1 do
    6270     if MyRO.Ship[p1].Parts[spComp]+MyRO.Ship[p1].Parts[spPow]
    6271       +MyRO.Ship[p1].Parts[spHab]>0 then
    6272       mShips.Enabled:=true;
    6273   end
    6274 else if Popup=UnitPopup then
    6275   begin
    6276   mox:=@MyModel[MyUn[UnFocus].mix];
    6277   Tile:=MyMap[MyUn[UnFocus].Loc];
    6278   extended:=Tile and fCity=0;
    6279   if extended then
    6280     begin
    6281     mCity.Caption:=Phrases.Lookup('BTN_FOUND');
    6282     mHome.Caption:=Phrases.Lookup('BTN_MOVEHOME')
    6283     end
    6284   else
    6285     begin
    6286     mCity.Caption:=Phrases.Lookup('BTN_ADD');
    6287     mHome.Caption:=Phrases.Lookup('BTN_SETHOME')
    6288     end;
    6289 
    6290   extended:=extended and ((mox.Kind=mkSettler) or (mox.Kind=mkSlaves)
    6291       and (MyRO.Wonder[woPyramids].EffectiveOwner>=0))
    6292     and (MyUn[UnFocus].Master<0) and (Tile and fDeadLands=0);
    6293   if (mox.Kind=mkFreight) and (Tile and fCity<>0) and not Phrases2FallenBackToEnglish
    6294     or (Server(sRemoveUnit-sExecute,me,UnFocus,nil^)=eUtilized) then
    6295     begin
    6296     mDisband.Visible:=false;
    6297     mUtilize.Visible:=true;
    6298     if mox.Kind=mkFreight then
    6299       mUtilize.Caption:=Phrases.Lookup('UTILIZE')
    6300     else mUtilize.Caption:=Phrases.Lookup('INTEGRATE')
    6301     end
    6302   else begin mDisband.Visible:=true; mUtilize.Visible:=false end;
    6303   mGoOn.Visible:= MyUn[UnFocus].Status and (usGoto or usWaiting)=usGoto or usWaiting;
    6304   mHome.Visible:=HaveCities;
    6305   mRecover.Visible:= (MyUn[UnFocus].Health<100) and (Tile and fTerrain>=fGrass)
    6306     and ((MyRO.Wonder[woGardens].EffectiveOwner=me)
    6307       or (Tile and fTerrain<>fArctic) and (Tile and fTerrain<>fDesert))
    6308     and not ((mox.Domain=dAir) and (Tile and fCity=0) and (Tile and fTerImp<>tiBase));
    6309   mStay.Visible:= not ((mox.Domain=dAir) and (Tile and fCity=0) and (Tile and fTerImp<>tiBase));
    6310   mCity.Visible:=extended and (mox.Kind=mkSettler) or (Tile and fCity<>0)
    6311     and ((mox.Kind in [mkSettler,mkSlaves]) or (MyUn[UnFocus].Flags and unConscripts<>0));
    6312   mPillage.Visible:=(Tile and (fRoad or fRR or fCanal or fTerImp)<>0)
    6313     and (MyUn[UnFocus].Master<0) and (mox.Domain=dGround);
    6314   mCancel.Visible:=(MyUn[UnFocus].Job>jNone) or (MyUn[UnFocus].Status and (usRecover or usGoto)<>0);
    6315 
    6316   Test:=Server(sLoadUnit-sExecute,me,UnFocus,nil^);
    6317   mLoad.Visible:= (Test>=rExecuted) or (Test=eNoTime_Load);
    6318   mUnload.Visible:= (MyUn[UnFocus].Master>=0)
    6319     or (MyUn[UnFocus].TroopLoad+MyUn[UnFocus].AirLoad>0);
    6320   mSelectTransport.Visible:=
    6321     Server(sSelectTransport-sExecute,me,UnFocus,nil^)>=rExecuted;
    6322   end
    6323 else {if Popup=TerrainPopup then}
    6324   begin
    6325   mox:=@MyModel[MyUn[UnFocus].mix];
    6326   Tile:=MyMap[MyUn[UnFocus].Loc];
    6327   extended:=Tile and fCity=0;
    6328 
    6329   if (Tile and fRiver<>0) and (MyRO.Tech[adBridgeBuilding]>=tsApplicable) then
    6330     begin
    6331     mRoad.Caption:=Phrases.Lookup('BTN_BUILDBRIDGE');
    6332     mRR.Caption:=Phrases.Lookup('BTN_BUILDRRBRIDGE');
    6333     end
    6334   else
    6335     begin
    6336     mRoad.Caption:=Phrases.Lookup('BTN_BUILDROAD');
    6337     mRR.Caption:=Phrases.Lookup('BTN_BUILDRR');
    6338     end;
    6339   if Tile and fTerrain=fForest then
    6340     mClear.Caption:=Phrases.Lookup('BTN_CLEAR')
    6341   else if Tile and fTerrain=fDesert then
    6342     mClear.Caption:=Phrases.Lookup('BTN_UNDESERT')
    6343   else mClear.Caption:=Phrases.Lookup('BTN_DRAIN');
    6344 
    6345   extended:=extended and ((mox.Kind=mkSettler) or (mox.Kind=mkSlaves)
    6346       and (MyRO.Wonder[woPyramids].EffectiveOwner>=0))
    6347     and (MyUn[UnFocus].Master<0);
    6348   if extended then
    6349     begin
    6350     mRoad.Visible:= JobTest(UnFocus,jRoad,[eNoBridgeBuilding,eTreaty]);
    6351     mRR.Visible:= JobTest(UnFocus,jRR,[eNoBridgeBuilding,eTreaty]);
    6352     mClear.Visible:= JobTest(UnFocus,jClear,[eTreaty]);
    6353     mIrrigation.Visible:= JobTest(UnFocus,jIrr,[eTreaty]);
    6354     mFarm.Visible:= JobTest(UnFocus,jFarm,[eTreaty]);
    6355     mAfforest.Visible:= JobTest(UnFocus,jAfforest,[eTreaty]);
    6356     mMine.Visible:= JobTest(UnFocus,jMine,[eTreaty]);
    6357     MTrans.Visible:= JobTest(UnFocus,jTrans,[eTreaty]);
    6358     mCanal.Visible:= JobTest(UnFocus,jCanal,[eTreaty]);
    6359     mFort.Visible:= JobTest(UnFocus,jFort,[eTreaty]);
    6360     mAirBase.Visible:= JobTest(UnFocus,jBase,[eTreaty]);
    6361     mPollution.Visible:=JobTest(UnFocus,jPoll,[eTreaty]);
    6362     mEnhance.Visible:= (Tile and fDeadLands=0)
    6363       and (MyData.EnhancementJobs[MyMap[MyUn[UnFocus].Loc] and fTerrain,0]<>jNone);
    6364     end
    6365   else
    6366     begin
    6367     for i:=0 to Popup.Items.Count-1 do Popup.Items[i].Visible:=false;
    6368     end;
    6369   end;
    6370 
    6371 // set menu seperators
    6372 LastSep:=nil;
    6373 needsep:=false;
    6374 for i:=0 to Popup.Items.Count-1 do
    6375   if Popup.Items[i].Caption='-' then
    6376     begin
    6377     Popup.Items[i].Visible:=needsep;
    6378     if needsep then LastSep:=Popup.Items[i];
    6379     needsep:=false
    6380     end
    6381   else if Popup.Items[i].Visible then needsep:=true;
    6382 if (LastSep<>nil) and not NeedSep then LastSep.Visible:=false   
    6383 end;
    6384 
    6385 procedure TMainScreen.PanelBtnClick(Sender: TObject);
    6386 var
    6387 Popup: TPopupMenu;
    6388 begin
    6389 if Sender=UnitBtn then Popup:=UnitPopup
    6390 else {if Sender=TerrainBtn then} Popup:=TerrainPopup;
    6391 InitPopup(Popup);
    6392 if FullScreen then
    6393   Popup.Popup(Left+TControl(Sender).Left,Top+TControl(Sender).Top)
    6394 else Popup.Popup(Left+TControl(Sender).Left+4,Top+TControl(Sender).Top
    6395   +GetSystemMetrics(SM_CYCAPTION)+4);
    6396 end;
    6397 
    6398 procedure TMainScreen.CityClosed(Activateuix: integer; StepFocus: boolean;
    6399   SelectFocus: boolean);
    6400 begin
    6401 if supervising then
    6402   begin
    6403   SetTroopLoc(-1);
    6404   PanelPaint
    6405   end
    6406 else
    6407   begin
    6408   if Activateuix>=0 then
    6409     begin
    6410     SetUnFocus(Activateuix);
    6411     SetTroopLoc(MyUn[Activateuix].Loc);
    6412     if SelectFocus then FocusOnLoc(TroopLoc,flRepaintPanel)
    6413     else PanelPaint
    6414     end
    6415   else if StepFocus then NextUnit(TroopLoc,true)
    6416   else
    6417     begin
    6418     SetTroopLoc(-1);
    6419     PanelPaint
    6420     end
    6421   end
    6422 end;
    6423 
    6424 procedure TMainScreen.Toggle(Sender: TObject);
    6425 begin
    6426 TMenuItem(Sender).Checked:=not TMenuItem(Sender).Checked
    6427 end;
    6428 
    6429 procedure TMainScreen.PanelBoxMouseMove(Sender: TObject;
    6430   Shift: TShiftState; x, y: integer);
    6431 var
    6432 xCentre,yCentre: integer;
    6433 begin
    6434 if Tracking and (ssLeft in Shift) then
    6435   begin
    6436   if (x>=xMini+2) and (y>=yMini+2) and (x<xMini+2+2*G.lx) and (y<yMini+2+G.ly) then
    6437     begin
    6438     xCentre:=(xwMini+(x-xMini-2) div 2+G.lx div 2+MapWidth div (xxt*4)) mod G.lx;
    6439     yCentre:=(y-yMini-2);
    6440     xw:=(xCentre-MapWidth div (xxt*4)+G.lx) mod G.lx;
    6441     if ywmax<=0 then yw:=ywcenter
    6442     else
    6443       begin
    6444       yw:=(yCentre-MapHeight div (yyt*2)+1) and not 1;
    6445       if yw<0 then yw:=0
    6446       else if yw>ywmax then yw:=ywmax;
    6447       end;
    6448     BitBlt(Buffer.Canvas.Handle,0,0,G.lx*2,G.ly,Mini.Canvas.Handle,0,0,SRCCOPY);
    6449     if ywmax<=0 then
    6450       Frame(Buffer.Canvas,x-xMini-2-MapWidth div (xxt*2),0,
    6451         x-xMini-2+MapWidth div (xxt*2)-1,
    6452         G.ly-1,MainTexture.clMark,MainTexture.clMark)
    6453     else Frame(Buffer.Canvas,x-xMini-2-MapWidth div (xxt*2),yw,
    6454       x-xMini-2+MapWidth div (xxt*2)-1,
    6455       yw+MapHeight div yyt-2,MainTexture.clMark,MainTexture.clMark);
    6456     BitBlt(Panel.Canvas.Handle,xMini+2,yMini+2,G.lx*2,G.ly,Buffer.Canvas.Handle,
    6457       0,0,SRCCOPY);
    6458     MainOffscreenPaint;
    6459     RectInvalidate(xMini+2,TopBarHeight+MapHeight-overlap+yMini+2,
    6460       xMini+2+G.lx*2,TopBarHeight+MapHeight-overlap+yMini+2+G.ly);
    6461     Update;
    6462     end
    6463   end
    6464 else Tracking:=false
    6465 end;
    6466 
    6467 procedure TMainScreen.PanelBoxMouseUp(Sender: TObject;
    6468   Button: TMouseButton; Shift: TShiftState; x, y: integer);
    6469 begin
    6470 if Tracking then
    6471   begin
    6472   Tracking:=false;
    6473   xwMini:=xw; ywMini:=yw;
    6474   MiniPaint;
    6475   PanelPaint;
    6476   end
    6477 end;
    6478 
    6479 procedure TMainScreen.MapBoxMouseMove(Sender: TObject; Shift: TShiftState; x,
    6480   y: integer);
    6481 var
    6482 MouseLoc: integer;
    6483 begin
    6484 xMouse:=x; yMouse:=y;
    6485 if (ClientMode=cEditMap) and (ssLeft in Shift) and not tracking then
    6486   begin
    6487   MouseLoc:=LocationOfScreenPixel(x,y);
    6488   if MouseLoc<>BrushLoc then
    6489     MapBoxMouseDown(nil, mbLeft, Shift, x, y);
    6490   end
    6491 (*else if idle and (UnFocus>=0) then
    6492   begin
    6493   qx:=(xMouse*32+yMouse*66+16*66) div(32*66)-1;
    6494   qy:=(yMouse*66-xMouse*32-16*66+2000*33*32) div(32*66)-999;
    6495   MouseLoc:=(xw+(qx-qy+2048) div 2-1024+G.lx) mod G.lx+G.lx*(yw+qx+qy);
    6496   ShowMoveHint(MouseLoc);
    6497   end*)
    6498 end;
    6499 
    6500 procedure TMainScreen.mShowClick(Sender: TObject);
    6501 begin
    6502 TMenuItem(Sender).Checked:=not TMenuItem(Sender).Checked;
    6503 SetMapOptions;
    6504 MapValid:=false;
    6505 PaintAllMaps;
    6506 end;
    6507 
    6508 procedure TMainScreen.mNamesClick(Sender: TObject);
    6509 var
    6510 p1: integer;
    6511 begin
    6512 mNames.Checked:=not mNames.Checked;
    6513 GenerateNames:=mNames.Checked;
    6514 for p1:=0 to nPl-1 do if Tribe[p1]<>nil then
    6515   if GenerateNames then Tribe[p1].NumberName:=-1
    6516   else Tribe[p1].NumberName:=p1;
    6517 MapValid:=false;
    6518 PaintAll;
    6519 end;
    6520 
    6521 function TMainScreen.IsPanelPixel(x,y: integer): boolean;
    6522 begin
    6523 result:= (y>=TopBarHeight+MapHeight)
    6524   or (y>=ClientHeight-PanelHeight) and ((x<xMidPanel) or (x>=xRightPanel))
    6525 end;
    6526 
    6527 procedure TMainScreen.FormMouseDown(Sender: TObject; Button: TMouseButton;
    6528   Shift: TShiftState; x, y: integer);
    6529 begin
    6530 if idle then
    6531   if (x<40) and (y<40) then
    6532     begin
    6533     if GameMode<>cMovie then
    6534       begin
    6535       InitPopup(GamePopup);
    6536       if FullScreen then
    6537         GamePopup.Popup(Left,Top+TopBarHeight-1)
    6538       else GamePopup.Popup(Left+4,Top+GetSystemMetrics(SM_CYCAPTION)+4+TopBarHeight-1);
    6539       end
    6540     end
    6541   else if IsPanelPixel(x,y) then
    6542     PanelBoxMouseDown(Sender,Button,Shift,x,y-(ClientHeight-PanelHeight))
    6543   else if (y>=TopBarHeight) and (x>=MapOffset) and (x<MapOffset+MapWidth) then
    6544     MapBoxMouseDown(Sender,Button,Shift,x-MapOffset,y-TopBarHeight)
    6545 end;
    6546 
    6547 procedure TMainScreen.FormMouseMove(Sender: TObject; Shift: TShiftState; x,
    6548   y: integer);
    6549 begin
    6550 if idle then
    6551   if IsPanelPixel(x,y) then
    6552     PanelBoxMouseMove(Sender,Shift,x,y-(ClientHeight-PanelHeight))
    6553   else if (y>=TopBarHeight) and (x>=MapOffset) and (x<MapOffset+MapWidth) then
    6554     MapBoxMouseMove(Sender,Shift,x-MapOffset,y-TopBarHeight);
    6555 end;
    6556 
    6557 procedure TMainScreen.FormMouseUp(Sender: TObject; Button: TMouseButton;
    6558   Shift: TShiftState; x, y: integer);
    6559 begin
    6560 if idle then
    6561   PanelBoxMouseUp(Sender,Button,Shift,x,y-(ClientHeight-PanelHeight));
    6562 end;
    6563 
    6564 procedure TMainScreen.FormPaint(Sender: TObject);
    6565 begin
    6566 MainOffscreenPaint;
    6567 if (MapOffset>0) or (MapOffset+MapWidth<ClientWidth) then with canvas do
    6568   begin // pillarbox, make left and right border black
    6569   if me<0 then
    6570     brush.color:=$000000
    6571   else brush.color:=EmptySpaceColor;
    6572   if xMidPanel>MapOffset then
    6573     FillRect(Rect(0,TopBarHeight,MapOffset,TopBarHeight+MapHeight-overlap))
    6574   else
    6575     begin
    6576     FillRect(Rect(0,TopBarHeight,xMidPanel,TopBarHeight+MapHeight-overlap));
    6577     FillRect(Rect(xMidPanel,TopBarHeight,MapOffset,TopBarHeight+MapHeight));
    6578     end;
    6579   if xRightPanel<MapOffset+MapWidth then
    6580     FillRect(Rect(MapOffset+MapWidth,TopBarHeight,ClientWidth,TopBarHeight+MapHeight-overlap))
    6581   else
    6582     begin
    6583     FillRect(Rect(MapOffset+MapWidth,TopBarHeight,xRightPanel,TopBarHeight+MapHeight));
    6584     FillRect(Rect(xRightPanel,TopBarHeight,ClientWidth,TopBarHeight+MapHeight-overlap));
    6585     end;
    6586   Brush.Style:=bsClear;
    6587   end;
    6588 BitBlt(Canvas.Handle,MapOffset,TopBarHeight,MapWidth,MapHeight-overlap,offscreen.Canvas.Handle,
    6589   0,0,SRCCOPY);
    6590 BitBlt(Canvas.Handle,0,0,ClientWidth,TopBarHeight,TopBar.Canvas.Handle,
    6591   0,0,SRCCOPY);
    6592 if xMidPanel>MapOffset then
    6593   BitBlt(Canvas.Handle,xMidPanel,TopBarHeight+MapHeight-overlap,
    6594     ClientWidth div 2-xMidPanel,overlap,
    6595     offscreen.Canvas.Handle,xMidPanel-MapOffset,MapHeight-overlap,SRCCOPY)
    6596 else BitBlt(Canvas.Handle,MapOffset,TopBarHeight+MapHeight-overlap,
    6597   ClientWidth div 2-MapOffset,overlap,
    6598   offscreen.Canvas.Handle,0,MapHeight-overlap,SRCCOPY);
    6599 if xRightPanel<MapOffset+MapWidth then
    6600   BitBlt(Canvas.Handle,ClientWidth div 2,TopBarHeight+MapHeight-overlap,
    6601     xRightPanel-ClientWidth div 2,overlap,
    6602     offscreen.Canvas.Handle,ClientWidth div 2-MapOffset,MapHeight-overlap,SRCCOPY)
    6603 else BitBlt(Canvas.Handle,ClientWidth div 2,TopBarHeight+MapHeight-overlap,
    6604   MapOffset+MapWidth-ClientWidth div 2,overlap,
    6605   offscreen.Canvas.Handle,ClientWidth div 2-MapOffset,MapHeight-overlap,SRCCOPY);
    6606 BitBlt(Canvas.Handle,0,TopBarHeight+MapHeight-overlap,xMidPanel,overlap,
    6607   Panel.Canvas.Handle,0,0,SRCCOPY);
    6608 BitBlt(Canvas.Handle,xRightPanel,TopBarHeight+MapHeight-overlap,Panel.Width-xRightPanel,
    6609   overlap,Panel.Canvas.Handle,xRightPanel,0,SRCCOPY);
    6610 BitBlt(Canvas.Handle,0,TopBarHeight+MapHeight,Panel.Width,PanelHeight-overlap,
    6611   Panel.Canvas.Handle,0,overlap,SRCCOPY);
    6612 if (pLogo>=0) and (G.RO[pLogo]=nil) and (AILogo[pLogo]<>nil) then
    6613   BitBlt(Canvas.Handle, xRightPanel+10-(16+64), ClientHeight-PanelHeight, 64,64,
    6614     AILogo[pLogo].Canvas.Handle,0,0,SRCCOPY);     
    6615 end;
    6616 
    6617 procedure TMainScreen.RectInvalidate(Left,Top,Rigth,Bottom: integer);
    6618 var
    6619 r0: HRgn;
    6620 begin
    6621 r0:=CreateRectRgn(Left,Top,Rigth,Bottom);
    6622 InvalidateRgn(Handle,r0,false);
    6623 DeleteObject(r0);
    6624 end;
    6625 
    6626 procedure TMainScreen.SmartRectInvalidate(Left,Top,Rigth,Bottom: integer);
    6627 var
    6628 i: integer;
    6629 r0,r1: HRgn;
    6630 begin
    6631 r0:=CreateRectRgn(Left,Top,Rigth,Bottom);
    6632 for i:=0 to ControlCount-1 do
    6633   if not (Controls[i] is TArea) and Controls[i].Visible then
    6634     begin
    6635     with Controls[i].BoundsRect do
    6636       r1:=CreateRectRgn(Left,Top,Right,Bottom);
    6637     CombineRgn(r0,r0,r1,RGN_DIFF);
    6638     DeleteObject(r1);
    6639     end;
    6640 InvalidateRgn(Handle,r0,false);
    6641 DeleteObject(r0);
    6642 end;
    6643 
    6644 procedure TMainScreen.mRepClicked(Sender: TObject);
    6645 begin
    6646 with TMenuItem(Sender) do
    6647   begin
    6648   Checked:=not Checked;
    6649   if Checked then CityRepMask:=CityRepMask or (1 shl (Tag shr 8))
    6650   else CityRepMask:=CityRepMask and not (1 shl (Tag shr 8))
    6651   end
    6652 end;
    6653 
    6654 procedure TMainScreen.mLogClick(Sender: TObject);
    6655 begin
    6656 LogDlg.Show
    6657 end;
    6658 
    6659 procedure TMainScreen.FormShow(Sender: TObject);
    6660 begin
    6661 Timer1.Enabled:=true
    6662 end;
    6663 
    6664 procedure TMainScreen.FormClose(Sender: TObject; var Action: TCloseAction);
    6665 begin
    6666 Timer1.Enabled:=false
    6667 end;
    6668 
    6669 procedure TMainScreen.Radio(Sender: TObject);
    6670 begin
    6671 TMenuItem(Sender).Checked:=true
    6672 end;
    6673 
    6674 procedure TMainScreen.mManipClick(Sender: TObject);
    6675 var
    6676 Flag: integer;
    6677 begin
    6678 with TMenuItem(Sender) do
    6679   begin
    6680   Flag:=1 shl (Tag shr 8);
    6681   if Checked then Server(sClearTestFlag,0,Flag,nil^)
    6682   else
    6683     begin
    6684     Server(sSetTestFlag,0,Flag,nil^);
    6685     Play('CHEAT');
    6686     end;
    6687   if not supervising then
    6688     begin
    6689     if Flag=tfUncover then
    6690       begin MapValid:=false; PaintAllMaps; end
    6691     else if Flag=tfAllTechs then
    6692       TellNewModels
    6693     end
    6694   end
    6695 end;
    6696 
    6697 procedure TMainScreen.MapBtnClick(Sender: TObject);
    6698 begin
    6699 with TButtonC(Sender) do
    6700   begin
    6701   MapOptionChecked:=MapOptionChecked xor (1 shl (Tag shr 8));
    6702   SetMapOptions;
    6703   ButtonIndex:=MapOptionChecked shr (Tag shr 8) and 1 +2
    6704   end;
    6705 if Sender=MapBtn0 then
    6706   begin MiniPaint; PanelPaint end // update mini map only
    6707 else begin MapValid:=false; PaintAllMaps; end; // update main map
    6708 end;
    6709 
    6710 procedure TMainScreen.GrWallBtnDownChanged(Sender: TObject);
    6711 begin
    6712 if TButtonBase(Sender).Down then
    6713   begin
    6714   MapOptionChecked:=MapOptionChecked or (1 shl moGreatWall);
    6715   TButtonBase(Sender).Hint:='';
    6716   end
    6717 else
    6718   begin
    6719   MapOptionChecked:=MapOptionChecked and not (1 shl moGreatWall);
    6720   TButtonBase(Sender).Hint:=Phrases.Lookup('CONTROLS',-1+TButtonBase(Sender).Tag and $FF);
    6721   end;
    6722 SetMapOptions;
    6723 MapValid:=false;
    6724 PaintAllMaps;
    6725 end;
    6726 
    6727 procedure TMainScreen.BareBtnDownChanged(Sender: TObject);
    6728 begin
    6729 if TButtonBase(Sender).Down then
    6730   begin
    6731   MapOptionChecked:=MapOptionChecked or (1 shl moBareTerrain);
    6732   TButtonBase(Sender).Hint:='';
    6733   end
    6734 else
    6735   begin
    6736   MapOptionChecked:=MapOptionChecked and not (1 shl moBareTerrain);
    6737   TButtonBase(Sender).Hint:=Phrases.Lookup('CONTROLS',-1+TButtonBase(Sender).Tag and $FF);
    6738   end;
    6739 SetMapOptions;
    6740 MapValid:=false;
    6741 PaintAllMaps;
    6742 end;
    6743 
    6744 procedure TMainScreen.FormKeyUp(Sender: TObject; var Key: Word;
    6745   Shift: TShiftState);
    6746 begin
    6747 if idle and (Key=VK_APPS) then
    6748   begin
    6749   InitPopup(GamePopup);
    6750   if FullScreen then
    6751     GamePopup.Popup(Left,Top+TopBarHeight-1)
    6752   else GamePopup.Popup(Left+4,Top+GetSystemMetrics(SM_CYCAPTION)+4+TopBarHeight-1);
    6753   exit
    6754   end // windows menu button calls game menu
    6755 end;
    6756 
    6757 procedure TMainScreen.CreateUnitClick(Sender: TObject);
    6758 var
    6759 p1,mix: integer;
    6760 begin
    6761 p1:=TComponent(Sender).Tag shr 16;
    6762 mix:=TComponent(Sender).Tag and $FFFF;
    6763 if Server(sCreateUnit+p1 shl 4,me,mix,EditLoc)>=rExecuted then
    6764   PaintLoc(EditLoc);
    6765 end;
    6766 
    6767 procedure TMainScreen.mSoundOffClick(Sender: TObject);
    6768 begin
    6769 SoundMode:=smOff;
    6770 end;
    6771 
    6772 procedure TMainScreen.mSoundOnClick(Sender: TObject);
    6773 begin
    6774 SoundMode:=smOn;
    6775 end;
    6776 
    6777 procedure TMainScreen.mSoundOnAltClick(Sender: TObject);
    6778 begin
    6779 SoundMode:=smOnAlt;
    6780 end;
    6781 
    6782 {procedure TMainScreen.AdviceBtnClick;
    6783 var
    6784 OldAdviceLoc: integer;
    6785 begin
    6786 DestinationMarkON:=false;
    6787 PaintDestination;
    6788 AdvisorDlg.GiveStrategyAdvice;
    6789 OldAdviceLoc:=MainMap.AdviceLoc;
    6790 MainMap.AdviceLoc:=-1;
    6791 PaintLoc(OldAdviceLoc);
    6792 end;}
    6793 
    6794 {procedure TMainScreen.SetAdviceLoc(Loc: integer; AvoidRect: TRect);
    6795 var
    6796 OldAdviceLoc,x,y: integer;
    6797 begin
    6798 if Loc<>MainMap.AdviceLoc then
    6799   begin
    6800   if Loc>=0 then
    6801     begin // center
    6802     y:=Loc div G.lx;
    6803     x:=(Loc+G.lx - AvoidRect.Right div (2*66)) mod G.lx;
    6804     Centre(y*G.lx+x);
    6805     PaintAllMaps;
    6806     end;
    6807   OldAdviceLoc:=MainMap.AdviceLoc;
    6808   MainMap.AdviceLoc:=Loc;
    6809   PaintLoc(OldAdviceLoc);
    6810   PaintLoc(MainMap.AdviceLoc);
    6811   end;
    6812 end;}
    6813 
    6814 procedure TMainScreen.UnitInfoBtnClick(Sender: TObject);
    6815 begin
    6816 if UnFocus>=0 then
    6817   UnitStatDlg.ShowNewContent_OwnModel(wmPersistent, MyUn[UnFocus].mix)
    6818 end;
    6819 
    6820 procedure TMainScreen.ViewpointClick(Sender: TObject);
    6821 begin
    6822 SetViewpoint(TMenuItem(Sender).Tag);
    6823 end;
    6824 
    6825 procedure TMainScreen.DebugMapClick(Sender: TObject);
    6826 begin
    6827 SetDebugMap(TMenuItem(Sender).Tag);
    6828 end;
    6829 
    6830 procedure TMainScreen.mSmallTilesClick(Sender: TObject);
    6831 begin
    6832 SetTileSize(33,16);
    6833 end;
    6834 
    6835 procedure TMainScreen.mNormalTilesClick(Sender: TObject);
    6836 begin
    6837 SetTileSize(48,24);
    6838 end;
    6839 
    6840 procedure TMainScreen.SetTileSize(x,y: integer);
    6841 var
    6842 i,CenterLoc: integer;
    6843 begin
    6844 CenterLoc:=(xw+MapWidth div (xxt*4)) mod G.lx+(yw+MapHeight div (yyt*2))*G.lx;
    6845 IsoEngine.ApplyTileSize(x,y);
    6846 FormResize(nil);
    6847 Centre(CenterLoc);
    6848 PaintAllMaps;
    6849 for i:=0 to Screen.FormCount-1 do
    6850   if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg) then
    6851     TBufferedDrawDlg(Screen.Forms[i]).SmartUpdateContent(false);
    6852 end;
    6853 
    6854 procedure TMainScreen.SaveSettings;
    6855 var
    6856 i,j: integer;
    6857 Reg: TRegistry;
    6858 begin
    6859 OptionChecked:=OptionChecked and soExtraMask;
    6860 for i:=0 to ComponentCount-1 do if Components[i] is TMenuItem then
    6861   for j:=0 to nSaveOption-1 do
    6862     if TMenuItem(Components[i]).Checked
    6863       and (TMenuItem(Components[i]).Tag=SaveOption[j]) then
    6864       inc(OptionChecked,1 shl j);
    6865 
    6866 Reg:=TRegistry.Create;
    6867 Reg.OpenKey('SOFTWARE\cevo\RegVer9',true);
    6868 Reg.WriteInteger('TileWidth',xxt*2);
    6869 Reg.WriteInteger('TileHeight',yyt*2);
    6870 Reg.WriteInteger('OptionChecked', OptionChecked);
    6871 Reg.WriteInteger('MapOptionChecked', MapOptionChecked);
    6872 Reg.WriteInteger('CityReport',integer(CityRepMask));
    6873 Reg.closekey;
    6874 Reg.Free;
    6875 end;
    6876 
    6877 procedure TMainScreen.MovieSpeedBtnClick(Sender: TObject);
    6878 begin
    6879 MovieSpeed:=TButtonB(Sender).Tag shr 8;
    6880 CheckMovieSpeedBtnState;
    6881 end;
     7961      end; }
     7962
     7963    procedure TMainScreen.UnitInfoBtnClick(Sender: TObject);
     7964    begin
     7965      if UnFocus >= 0 then
     7966        UnitStatDlg.ShowNewContent_OwnModel(wmPersistent, MyUn[UnFocus].mix)
     7967    end;
     7968
     7969    procedure TMainScreen.ViewpointClick(Sender: TObject);
     7970    begin
     7971      SetViewpoint(TMenuItem(Sender).Tag);
     7972    end;
     7973
     7974    procedure TMainScreen.DebugMapClick(Sender: TObject);
     7975    begin
     7976      SetDebugMap(TMenuItem(Sender).Tag);
     7977    end;
     7978
     7979    procedure TMainScreen.mSmallTilesClick(Sender: TObject);
     7980    begin
     7981      SetTileSize(33, 16);
     7982    end;
     7983
     7984    procedure TMainScreen.mNormalTilesClick(Sender: TObject);
     7985    begin
     7986      SetTileSize(48, 24);
     7987    end;
     7988
     7989    procedure TMainScreen.SetTileSize(x, y: integer);
     7990    var
     7991      i, CenterLoc: integer;
     7992    begin
     7993      CenterLoc := (xw + MapWidth div (xxt * 4)) mod G.lx +
     7994        (yw + MapHeight div (yyt * 2)) * G.lx;
     7995      IsoEngine.ApplyTileSize(x, y);
     7996      FormResize(nil);
     7997      Centre(CenterLoc);
     7998      PaintAllMaps;
     7999      for i := 0 to Screen.FormCount - 1 do
     8000        if Screen.Forms[i].Visible and (Screen.Forms[i] is TBufferedDrawDlg)
     8001        then
     8002          TBufferedDrawDlg(Screen.Forms[i]).SmartUpdateContent(false);
     8003    end;
     8004
     8005    procedure TMainScreen.SaveSettings;
     8006    var
     8007      i, j: integer;
     8008      Reg: TRegistry;
     8009    begin
     8010      OptionChecked := OptionChecked and soExtraMask;
     8011      for i := 0 to ComponentCount - 1 do
     8012        if Components[i] is TMenuItem then
     8013          for j := 0 to nSaveOption - 1 do
     8014            if TMenuItem(Components[i]).Checked and
     8015              (TMenuItem(Components[i]).Tag = SaveOption[j]) then
     8016              inc(OptionChecked, 1 shl j);
     8017
     8018      Reg := TRegistry.Create;
     8019      Reg.OpenKey('SOFTWARE\cevo\RegVer9', true);
     8020      Reg.WriteInteger('TileWidth', xxt * 2);
     8021      Reg.WriteInteger('TileHeight', yyt * 2);
     8022      Reg.WriteInteger('OptionChecked', OptionChecked);
     8023      Reg.WriteInteger('MapOptionChecked', MapOptionChecked);
     8024      Reg.WriteInteger('CityReport', integer(CityRepMask));
     8025      Reg.closekey;
     8026      Reg.free;
     8027    end;
     8028
     8029    procedure TMainScreen.MovieSpeedBtnClick(Sender: TObject);
     8030    begin
     8031      MovieSpeed := TButtonB(Sender).Tag shr 8;
     8032      CheckMovieSpeedBtnState;
     8033    end;
    68828034
    68838035initialization
     8036
    68848037QueryPerformanceFrequency(PerfFreq);
    68858038
    68868039end.
    6887 
Note: See TracChangeset for help on using the changeset viewer.