source: tags/1.3.6/LocalPlayer/Term.pas

Last change on this file was 624, checked in by chronos, 2 months ago
  • Fixed: Do not process keyboard input during unit move on Linux.
File size: 279.2 KB
Line 
1{$INCLUDE Switches.inc}
2unit Term;
3
4interface
5
6uses
7{$IFDEF WINDOWS}
8 Windows,
9{$ENDIF}
10{$IFDEF UNIX}
11 LMessages, Messages,
12{$ENDIF}
13 Protocol, Tribes, PVSB, ClientTools, ScreenTools, BaseWin, Messg, ButtonBase,
14 LCLIntf, LCLType, SysUtils, Classes, DrawDlg, Types, Math,
15 DateUtils, Platform, ButtonB, ButtonC, EOTButton, Area, Help,
16 GraphicSet, MiniMap, IsoEngine, Wonders, TechTree, Enhance, Nego, CityType,
17 Diagram, CityScreen, Rates, Battle, NatStat, UnitStat, Draft, Select, MessgEx,
18 {$IFDEF DPI}Dpi.Graphics, Dpi.Controls, Dpi.Forms, Dpi.Menus, Dpi.ExtCtrls,
19 Dpi.PixelPointer, Dpi.Common, System.UITypes{$ELSE}
20 Graphics, Controls, Forms, Menus, ExtCtrls, PixelPointer{$ENDIF};
21
22const
23 WM_EOT = WM_USER;
24
25type
26 TPaintLocTempStyle = (pltsNormal, pltsBlink);
27
28 TSoundBlock = (sbStart, sbWonder, sbScience, sbContact, sbTurn);
29 TSoundBlocks = set of TSoundBlock;
30
31 { TMainScreen }
32
33 TMainScreen = class(TDrawDlg)
34 mBigTiles: TMenuItem;
35 mFillMap: TMenuItem;
36 mNextUnit: TMenuItem;
37 N13: TMenuItem;
38 mPrevUnit: TMenuItem;
39 Timer1: TTimer;
40 GamePopup: TPopupMenu;
41 UnitPopup: TPopupMenu;
42 mIrrigation: TMenuItem;
43 mCity: TMenuItem;
44 mRoad: TMenuItem;
45 mMine: TMenuItem;
46 mPollution: TMenuItem;
47 mHome: TMenuItem;
48 mStay: TMenuItem;
49 mDisband: TMenuItem;
50 mWait: TMenuItem;
51 mNoOrders: TMenuItem;
52 MTrans: TMenuItem;
53 UnitBtn: TButtonB;
54 mResign: TMenuItem;
55 mOptions: TMenuItem;
56 mEnMoves: TMenuItem;
57 mWaitTurn: TMenuItem;
58 mRep: TMenuItem;
59 mFort: TMenuItem;
60 mCentre: TMenuItem;
61 N1: TMenuItem;
62 mAirBase: TMenuItem;
63 N5: TMenuItem;
64 mCityTypes: TMenuItem;
65 mHelp: TMenuItem;
66 mCanal: TMenuItem;
67 mTest: TMenuItem;
68 mLocCodes: TMenuItem;
69 mLoad: TMenuItem;
70 StatPopup: TPopupMenu;
71 mCityStat: TMenuItem;
72 mUnitStat: TMenuItem;
73 mWonders: TMenuItem;
74 mScienceStat: TMenuItem;
75 mRailRoad: TMenuItem;
76 mClear: TMenuItem;
77 mFarm: TMenuItem;
78 mAfforest: TMenuItem;
79 mRep0: TMenuItem;
80 mRep1: TMenuItem;
81 mRep2: TMenuItem;
82 mRep3: TMenuItem;
83 mRep4: TMenuItem;
84 mRep5: TMenuItem;
85 mRep7: TMenuItem;
86 mRep8: TMenuItem;
87 mRep9: TMenuItem;
88 mRep15: TMenuItem;
89 mCancel: TMenuItem;
90 mLog: TMenuItem;
91 mEUnitStat: TMenuItem;
92 mRep10: TMenuItem;
93 mEnAttacks: TMenuItem;
94 mEnNoMoves: TMenuItem;
95 mDiagram: TMenuItem;
96 mJump: TMenuItem;
97 mNations: TMenuItem;
98 mManip: TMenuItem;
99 mManip0: TMenuItem;
100 mManip1: TMenuItem;
101 mManip2: TMenuItem;
102 mManip3: TMenuItem;
103 mManip4: TMenuItem;
104 mManip5: TMenuItem;
105 mEnhanceDef: TMenuItem;
106 mEnhance: TMenuItem;
107 mShips: TMenuItem;
108 mMacro: TMenuItem;
109 mRun: TMenuItem;
110 N10: TMenuItem;
111 mRepList: TMenuItem;
112 mRepScreens: TMenuItem;
113 mRep11: TMenuItem;
114 mNames: TMenuItem;
115 mManip6: TMenuItem;
116 mRep12: TMenuItem;
117 mRandomMap: TMenuItem;
118 mUnload: TMenuItem;
119 mRecover: TMenuItem;
120 MapBtn0: TButtonC;
121 MapBtn1: TButtonC;
122 MapBtn4: TButtonC;
123 MapBtn5: TButtonC;
124 EditPopup: TPopupMenu;
125 mCreateUnit: TMenuItem;
126 MapBtn6: TButtonC;
127 mDebugMap: TMenuItem;
128 mUtilize: TMenuItem;
129 mRep6: TMenuItem;
130 mEnemyMovement: TMenuItem;
131 mEnFastMoves: TMenuItem;
132 mOwnMovement: TMenuItem;
133 mSlowMoves: TMenuItem;
134 mFastMoves: TMenuItem;
135 mVeryFastMoves: TMenuItem;
136 mGoOn: TMenuItem;
137 mSound: TMenuItem;
138 mSoundOn: TMenuItem;
139 mSoundOnAlt: TMenuItem;
140 mSoundOff: TMenuItem;
141 N6: TMenuItem;
142 TerrainBtn: TButtonB;
143 TerrainPopup: TPopupMenu;
144 mScrolling: TMenuItem;
145 mScrollSlow: TMenuItem;
146 mScrollFast: TMenuItem;
147 mScrollOff: TMenuItem;
148 mPillage: TMenuItem;
149 mSelectTransport: TMenuItem;
150 mEmpire: TMenuItem;
151 N4: TMenuItem;
152 N2: TMenuItem;
153 mWebsite: TMenuItem;
154 N3: TMenuItem;
155 mRevolution: TMenuItem;
156 mRep13: TMenuItem;
157 UnitInfoBtn: TButtonB;
158 EOT: TEOTButton;
159 mAllyMovement: TMenuItem;
160 mAlSlowMoves: TMenuItem;
161 mAlFastMoves: TMenuItem;
162 N7: TMenuItem;
163 mEffectiveMovesOnly: TMenuItem;
164 N8: TMenuItem;
165 mAlEffectiveMovesOnly: TMenuItem;
166 mAlNoMoves: TMenuItem;
167 N9: TMenuItem;
168 mViewpoint: TMenuItem;
169 mTileSize: TMenuItem;
170 mNormalTiles: TMenuItem;
171 mSmallTiles: TMenuItem;
172 N11: TMenuItem;
173 MenuArea: TArea;
174 TreasuryArea: TArea;
175 ResearchArea: TArea;
176 ManagementArea: TArea;
177 mTechTree: TMenuItem;
178 MovieSpeed1Btn: TButtonB;
179 MovieSpeed2Btn: TButtonB;
180 MovieSpeed3Btn: TButtonB;
181 MovieSpeed4Btn: TButtonB;
182 N12: TMenuItem;
183 mRep14: TMenuItem;
184 procedure FormCreate(Sender: TObject);
185 procedure FormDestroy(Sender: TObject);
186 procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
187 WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
188 procedure mAfforestClick(Sender: TObject);
189 procedure mAirBaseClick(Sender: TObject);
190 procedure mCanalClick(Sender: TObject);
191 procedure mCancelClick(Sender: TObject);
192 procedure mCentreClick(Sender: TObject);
193 procedure mcityClick(Sender: TObject);
194 procedure mCityStatClick(Sender: TObject);
195 procedure mCityTypesClick(Sender: TObject);
196 procedure mClearClick(Sender: TObject);
197 procedure mDiagramClick(Sender: TObject);
198 procedure mEmpireClick(Sender: TObject);
199 procedure mFillMapClick(Sender: TObject);
200 procedure mEnhanceClick(Sender: TObject);
201 procedure mEnhanceDefClick(Sender: TObject);
202 procedure mEUnitStatClick(Sender: TObject);
203 procedure mFarmClick(Sender: TObject);
204 procedure mfortClick(Sender: TObject);
205 procedure mGoOnClick(Sender: TObject);
206 procedure mHelpClick(Sender: TObject);
207 procedure mhomeClick(Sender: TObject);
208 procedure mirrigationClick(Sender: TObject);
209 procedure mirrigationDrawItem(Sender: TObject; ACanvas: TCanvas;
210 ARect: TRect; AState: TOwnerDrawState);
211 procedure mJumpClick(Sender: TObject);
212 procedure mLoadClick(Sender: TObject);
213 procedure mmineClick(Sender: TObject);
214 procedure mNationsClick(Sender: TObject);
215 procedure mNextUnitClick(Sender: TObject);
216 procedure mnoordersClick(Sender: TObject);
217 procedure mPillageClick(Sender: TObject);
218 procedure mpollutionClick(Sender: TObject);
219 procedure mPrevUnitClick(Sender: TObject);
220 procedure mRandomMapClick(Sender: TObject);
221 procedure mRecoverClick(Sender: TObject);
222 procedure mResignClick(Sender: TObject);
223 procedure mRevolutionClick(Sender: TObject);
224 procedure mroadClick(Sender: TObject);
225 procedure mRailRoadClick(Sender: TObject);
226 procedure mRunClick(Sender: TObject);
227 procedure mScienceStatClick(Sender: TObject);
228 procedure mSelectTransportClick(Sender: TObject);
229 procedure mShipsClick(Sender: TObject);
230 procedure mstayClick(Sender: TObject);
231 procedure mTechTreeClick(Sender: TObject);
232 procedure mtransClick(Sender: TObject);
233 procedure mUnitStatClick(Sender: TObject);
234 procedure mUnloadClick(Sender: TObject);
235 procedure mwaitClick(Sender: TObject);
236 procedure mWebsiteClick(Sender: TObject);
237 procedure mWondersClick(Sender: TObject);
238 procedure Timer1Timer(Sender: TObject);
239 procedure MapBoxMouseDown(Sender: TObject; Button: TMouseButton;
240 Shift: TShiftState; X, Y: Integer);
241 procedure EOTClick(Sender: TObject);
242 procedure PanelBoxMouseDown(Sender: TObject; Button: TMouseButton;
243 Shift: TShiftState; X, Y: Integer);
244 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
245 procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
246 procedure mDisbandOrUtilizeClick(Sender: TObject);
247 procedure FormResize(Sender: TObject);
248 procedure PanelBtnClick(Sender: TObject);
249 procedure Toggle(Sender: TObject);
250 procedure PanelBoxMouseMove(Sender: TObject; Shift: TShiftState;
251 X, Y: Integer);
252 procedure PanelBoxMouseUp(Sender: TObject; Button: TMouseButton;
253 Shift: TShiftState; X, Y: Integer);
254 procedure MapBoxMouseMove(Sender: TObject; Shift: TShiftState;
255 X, Y: Integer);
256 procedure mShowClick(Sender: TObject);
257 procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
258 Shift: TShiftState; X, Y: Integer);
259 procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
260 procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
261 Shift: TShiftState; X, Y: Integer);
262 procedure FormPaint(Sender: TObject);
263 procedure FormClose(Sender: TObject; var Action: TCloseAction);
264 procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
265 procedure FormShow(Sender: TObject);
266 procedure mRepClicked(Sender: TObject);
267 procedure mLogClick(Sender: TObject);
268 procedure Radio(Sender: TObject);
269 procedure mManipClick(Sender: TObject);
270 procedure mNamesClick(Sender: TObject);
271 procedure MapBtnClick(Sender: TObject);
272 procedure CreateUnitClick(Sender: TObject);
273 procedure mSoundOffClick(Sender: TObject);
274 procedure mSoundOnClick(Sender: TObject);
275 procedure mSoundOnAltClick(Sender: TObject);
276 procedure UnitInfoBtnClick(Sender: TObject);
277 procedure ViewpointClick(Sender: TObject);
278 procedure DebugMapClick(Sender: TObject);
279 procedure mSmallTilesClick(Sender: TObject);
280 procedure mNormalTilesClick(Sender: TObject);
281 procedure mBigTilesClick(Sender: TObject);
282 procedure GrWallBtnDownChanged(Sender: TObject);
283 procedure BareBtnDownChanged(Sender: TObject);
284 procedure MovieSpeedBtnClick(Sender: TObject);
285 private
286 xw: Integer; // Base map x
287 yw: Integer; // Base map y
288 xwd: Integer;
289 ywd: Integer;
290 xwMini: Integer;
291 ywMini: Integer;
292 xMidPanel: Integer;
293 xRightPanel: Integer;
294 xTroop: Integer;
295 xTerrain: Integer;
296 xMini: Integer;
297 yMini: Integer;
298 ywmax: Integer;
299 ywcenter: Integer;
300 TroopLoc: Integer;
301 TrCnt: Integer;
302 TrRow: Integer;
303 TrPitch: Integer;
304 MapWidth: Integer;
305 MapOffset: Integer;
306 MapHeight: Integer;
307 BlinkTime: Integer;
308 BrushLoc: Integer;
309 EditLoc: Integer;
310 xMouse: Integer;
311 yMouse: Integer;
312 BrushType: Cardinal;
313 trix: array [0 .. 63] of Integer;
314 AILogo: array [0 .. nPl - 1] of TBitmap;
315 MiniMap: TMiniMap;
316 Panel: TBitmap;
317 TopBar: TBitmap;
318 VerticalScrollBar: TPVScrollBar;
319 Closable: Boolean;
320 RepaintOnResize: Boolean;
321 Tracking: Boolean;
322 TurnComplete: Boolean;
323 Edited: Boolean;
324 GoOnPhase: Boolean;
325 HaveStrategyAdvice: Boolean;
326 FirstMovieTurn: Boolean;
327 FormFullScreen: Boolean;
328 FormRestoredSize: TRect;
329 FormWindowState: TWindowState;
330 MainMap: TIsoMap;
331 NoMap: TIsoMap;
332 NoMapPanel: TIsoMap;
333 LastResizeWidth: Integer;
334 LastResizeHeight: Integer;
335 LastWindowState: TWindowState;
336 KeyboardDisabled: Boolean;
337 // Forms
338 FWondersDlg: TWondersDlg;
339 FTechTreeDlg: TTechTreeDlg;
340 FEnhanceDlg: TEnhanceDlg;
341 FNegoDlg: TNegoDlg;
342 FCityTypeDlg: TCityTypeDlg;
343 FDiaDlg: TDiaDlg;
344 FCityDlg: TCityDlg;
345 FRatesDlg: TRatesDlg;
346 FBattleDlg: TBattleDlg;
347 FNatStatDlg: TNatStatDlg;
348 FUnitStatDlg: TUnitStatDlg;
349 FDraftDlg: TDraftDlg;
350 FModalSelectDlg: TModalSelectDlg;
351 FListDlg: TListDlg;
352 FMessgExDlg: TMessgExDlg;
353 FHelpDlg: THelpDlg;
354 procedure ResizeControls;
355 procedure ArrangeDialogs;
356 procedure ArrangeDialog(Form: TBufferedDrawDlg);
357 function ChooseUnusedTribe: Integer;
358 function DoJob(j0: Integer): Integer;
359 function GetBattleDlg: TBattleDlg;
360 function GetCityDlg: TCityDlg;
361 function GetCityTypeDlg: TCityTypeDlg;
362 function GetDiaDlg: TDiaDlg;
363 function GetDraftDlg: TDraftDlg;
364 function GetEnhanceDlg: TEnhanceDlg;
365 function GetHelpDlg: THelpDlg;
366 function GetListDlg: TListDlg;
367 function GetMessgExDlg: TMessgExDlg;
368 function GetModalSelectDlg: TModalSelectDlg;
369 function GetNatStatDlg: TNatStatDlg;
370 function GetNegoDlg: TNegoDlg;
371 function GetRatesDlg: TRatesDlg;
372 function GetTechTreeDlg: TTechTreeDlg;
373 procedure GetTribeList;
374 function GetUnitStatDlg: TUnitStatDlg;
375 function GetWondersDlg: TWondersDlg;
376 procedure InitModule;
377 procedure DoneModule;
378 procedure InitTurn(NewPlayer: Integer);
379 procedure SaveMenuItemsState;
380 procedure ScrollBarUpdate(Sender: TObject);
381 procedure ArrangeMidPanel;
382 procedure MainOffscreenPaint;
383 procedure MiniMapPaint;
384 procedure PaintAll;
385 procedure PaintAllMaps;
386 procedure CopyMiniToPanel;
387 procedure PanelPaint;
388 procedure FocusNextUnit(Dir: Integer = 1);
389 procedure NextUnit(NearLoc: Integer; AutoTurn: Boolean);
390 procedure Scroll(dx, dy: Integer);
391 procedure SetMapPos(Loc: Integer; MapPos: TPoint);
392 procedure Centre(Loc: Integer);
393 procedure SetTroopLoc(Loc: Integer);
394 procedure ProcessRect(x0, y0, nx, ny, Options: Integer);
395 procedure PaintLoc(Loc: Integer; Radius: Integer = 0);
396 procedure PaintLoc_BeforeMove(FromLoc: Integer);
397 procedure PaintLocTemp(Loc: Integer; Style: TPaintLocTempStyle = pltsNormal);
398 procedure PaintBufferToScreen(xMap, yMap, Width, Height: Integer);
399 procedure PaintDestination;
400 procedure SetUnFocus(uix: Integer);
401 function MoveUnit(dx, dy: Integer; Options: Integer = 0): Integer;
402 procedure MoveToLoc(Loc: Integer; CheckSuicide: Boolean);
403 procedure MoveOnScreen(ShowMove: TShowMove; Step0, Step1, nStep: Integer;
404 Restore: Boolean = True);
405 procedure FocusOnLoc(Loc: Integer; Options: Integer = 0);
406 function EndTurn(WasSkipped: Boolean = False): Boolean;
407 procedure EndNego;
408 function IsPanelPixel(X, Y: Integer): Boolean;
409 procedure InitPopup(Popup: TPopupMenu);
410 procedure SetMapOptions;
411 procedure CheckMovieSpeedBtnState;
412 procedure CheckTerrainBtnVisible;
413 procedure RememberPeaceViolation;
414 procedure SetDebugMap(P: Integer);
415 procedure SetViewpoint(P: Integer);
416 function LocationOfScreenPixel(X, Y: Integer): Integer;
417 function GetCenterLoc: Integer;
418 procedure SetTileSizeCenter(TileSize: TTileSize);
419 procedure SetTileSize(TileSize: TTileSize; Loc: Integer; MapPos: TPoint);
420 procedure RectInvalidate(Left, Top, Rigth, Bottom: Integer);
421 procedure ShowEnemyShipChange(ShowShipChange: TShowShipChange);
422 procedure SmartRectInvalidate(Left, Top, Rigth, Bottom: Integer);
423 procedure LoadSettings;
424 procedure SaveSettings;
425 procedure OnScroll(var Msg: TMessage); message WM_VSCROLL;
426 procedure OnEOT(var Msg: TMessage); message WM_EOT;
427 procedure SoundPreload(Check: TSoundBlocks);
428 procedure UpdateKeyShortcuts;
429 procedure SetFullScreen(Active: Boolean);
430 procedure PaintZoomedTile(Dst: TBitmap; X, Y, Loc: Integer);
431 procedure UpdateInterface;
432 public
433 UsedOffscreenWidth: Integer;
434 UsedOffscreenHeight: Integer;
435 Offscreen: TBitmap;
436 OffscreenUser: TForm;
437 procedure Client(Command, NewPlayer: Integer; var Data);
438 procedure SetAIName(P: Integer; Name: string);
439 function ZoomToCity(Loc: Integer; NextUnitOnClose: Boolean = False;
440 ShowEvent: Integer = 0): Boolean;
441 procedure CityClosed(Activateuix: Integer; StepFocus: Boolean = False;
442 SelectFocus: Boolean = False);
443 function DipCall(Command: Integer): Integer;
444 function OfferCall(var Offer: TOffer): Integer;
445 procedure UpdateViews(UpdateCityScreen: Boolean = False);
446 function ContactRefused(P: Integer; Item: String): Boolean;
447 procedure RepaintAll;
448 // Forms
449 property WondersDlg: TWondersDlg read GetWondersDlg;
450 property TechTreeDlg: TTechTreeDlg read GetTechTreeDlg;
451 property EnhanceDlg: TEnhanceDlg read GetEnhanceDlg;
452 property NegoDlg: TNegoDlg read GetNegoDlg;
453 property CityTypeDlg: TCityTypeDlg read GetCityTypeDlg;
454 property DiaDlg: TDiaDlg read GetDiaDlg;
455 property CityDlg: TCityDlg read GetCityDlg;
456 property RatesDlg: TRatesDlg read GetRatesDlg;
457 property BattleDlg: TBattleDlg read GetBattleDlg;
458 property NatStatDlg: TNatStatDlg read GetNatStatDlg;
459 property UnitStatDlg: TUnitStatDlg read GetUnitStatDlg;
460 property DraftDlg: TDraftDlg read GetDraftDlg;
461 property ModalSelectDlg: TModalSelectDlg read GetModalSelectDlg;
462 property ListDlg: TListDlg read GetListDlg;
463 property MessgExDlg: TMessgExDlg read GetMessgExDlg;
464 property HelpDlg: THelpDlg read GetHelpDlg;
465 end;
466
467var
468 MainScreen: TMainScreen;
469
470type
471
472 { TTribeInfo }
473
474 TTribeInfo = record
475 trix: Integer;
476 FileName: ShortString;
477 function GetCommandDataSize: Byte;
478 end;
479
480 { TCityNameInfo }
481
482 TCityNameInfo = record
483 ID: Integer;
484 NewName: ShortString;
485 function GetCommandDataSize: Byte;
486 end;
487
488 { TModelNameInfo }
489
490 TModelNameInfo = record
491 mix: Integer;
492 NewName: ShortString;
493 function GetCommandDataSize: Byte;
494 end;
495
496 TFormAction = (faClose, faEnable, faDisable, faUpdate, faSmartUpdateContent);
497
498const
499 crImpDrag = 2;
500 crFlatHand = 3;
501
502 xxu = 32;
503 yyu = 24; // half of unit slot size x/y
504 yyu_anchor = 32;
505 xxc = 32;
506 yyc = 16; // 1/2 of city slot size in x, 1/2 of ground tile size in y (=1/3 of slot)
507
508 // layout
509 TopBarHeight = 41;
510 PanelHeight = 168;
511 MidPanelHeight = 120;
512 // TopBarHeight+MidPanelHeight should be same as BaseWin.yUnused
513 MapCenterUp = (MidPanelHeight - TopBarHeight) div 2;
514
515 nCityType = 4;
516
517 { client exclusive commands: }
518 cSetTribe = $9000;
519 cSetNewModelPicture = $9100;
520 cSetModelName = $9110;
521 cSetModelPicture = $9120;
522 cSetSlaveIndex = $9131;
523 cSetCityName = $9200;
524
525 // city status flags
526 csTypeMask = $0007;
527 csToldDelay = $0008;
528 csResourceWeightsMask = $00F0;
529 csToldBombard = $0100;
530
531 { unit status flags }
532 usStay = $01;
533 usWaiting = $02;
534 usGoto = $04;
535 usEnhance = $08;
536 usRecover = $10;
537 usToldNoReturn = $100;
538 usPersistent = usStay or usGoto or usEnhance or usRecover or
539 Integer($FFFF0000);
540
541 { model status flags }
542 msObsolete = $1;
543 msAllowConscripts = $2;
544
545 { additional city happened flags }
546 chTypeDel = $8000;
547 chAllImpsMade = $4000;
548
549 adNone = $801;
550 adFar = $802;
551 adNexus = $803;
552
553 SpecialModelPictureCode: array [0 .. nSpecialModel - 1] of Integer = (10,
554 11, 40, 41, 21, 30, { 50,51, } 64, 74, { 71, } 73);
555
556 pixSlaves = 0;
557 pixNoSlaves = 1; // index of slaves in StdUnits
558
559 // icons.bmp properties
560 xSizeSmall = 36;
561 ySizeSmall = 20;
562 SystemIconLines = 2;
563 // lines of system icons in icons.bmp before improvements
564
565 nCityEventPriority = 16;
566 CityEventPriority: array [0 .. nCityEventPriority - 1] of Integer =
567 (chDisorder, chImprovementLost, chUnitLost, chAllImpsMade, chProduction,
568 chOldWonder, chNoSettlerProd, chPopDecrease, chProductionSabotaged,
569 chNoGrowthWarning, chPollution, chTypeDel, chFounded, chSiege,
570 chAfterCapture, chPopIncrease);
571
572 CityEventSoundItem: array [0 .. 15] of string = ('CITY_DISORDER', '',
573 'CITY_POPPLUS', 'CITY_POPMINUS', 'CITY_UNITLOST', 'CITY_IMPLOST',
574 'CITY_SABOTAGE', 'CITY_GROWTHNEEDSIMP', 'CITY_POLLUTION', 'CITY_SIEGE',
575 'CITY_WONDEREX', 'CITY_EMDELAY', 'CITY_FOUNDED', 'CITY_FOUNDED', '',
576 'CITY_INVALIDTYPE');
577
578type
579 TPersistentData = record
580 FarTech: Integer;
581 ToldAge: Integer;
582 ToldModels: Integer;
583 ToldAlive: Integer;
584 ToldContact: Integer;
585 ToldOwnCredibility: Integer;
586 ColdWarStart: Integer;
587 PeaceEvaHappened: Integer;
588 EnhancementJobs: TEnhancementJobs;
589 ImpOrder: array [0 .. nCityType - 1] of TImpOrder;
590 ToldWonders: array [0 .. nWonder - 1] of TWonderInfo;
591 ToldTech: array [0 .. nAdv - 1] of ShortInt;
592 end;
593
594 TDipMem = record
595 pContact: Integer;
596 SentCommand: Integer;
597 FormerTreaty: Integer;
598 SentOffer: TOffer;
599 DeliveredPrices: TPriceSet;
600 ReceivedPrices: TPriceSet;
601 end;
602
603 TCurrentMoveInfo = record
604 AfterMovePaintRadius: Integer;
605 AfterAttackExpeller: Integer;
606 DoShow: Boolean;
607 IsAlly: Boolean;
608 end;
609
610var
611 MyData: ^TPersistentData;
612 AdvIcon: array [0 .. nAdv - 1] of Integer;
613 { icons displayed with the technologies }
614 GameMode: Integer;
615 ClientMode: Integer;
616 Age: Integer;
617 UnFocus: Integer;
618 OptionChecked: TSaveOptions;
619 MapOptionChecked: TMapOptions;
620 nLostArmy: Integer;
621 ScienceSum: Integer;
622 TaxSum: Integer;
623 SoundPreloadDone: TSoundBlocks;
624 MarkCityLoc: Integer;
625 MovieSpeed: Integer;
626 CityRepMask: Cardinal;
627 ReceivedOffer: TOffer;
628 Buffer: TBitmap;
629 SmallImp: TBitmap;
630 BlinkON: Boolean;
631 DestinationMarkON: Boolean;
632 StartRunning: Boolean;
633 Supervising: Boolean;
634 UnusedTribeFiles: TStringList;
635 TribeNames: TStringList;
636 TribeOriginal: array [0 .. nPl - 1] of Boolean;
637 LostArmy: array [0 .. nPl * nMmax - 1] of Integer;
638 DipMem: array [0 .. nPl - 1] of TDipMem;
639
640function CityEventName(I: Integer): string;
641function RoughCredibility(Credibility: Integer): Integer;
642
643function InitEnemyModel(emix: Integer): Boolean;
644procedure InitAllEnemyModels;
645procedure InitMyModel(Mix: Integer; Final: Boolean);
646
647procedure ImpImage(ca: TCanvas; X, Y, iix: Integer; Government: Integer = -1;
648 IsControl: Boolean = False);
649procedure HelpOnTerrain(Loc: Integer; NewMode: TWindowMode);
650function AlignUp(Value, Alignment: Integer): Integer;
651
652
653implementation
654
655uses
656 Directories, Log, Sound, Registry, Global, KeyBindings, CmdList;
657
658{$R *.lfm}
659
660const
661 lxmax_xxx = 130;
662 LeftPanelWidth = 70;
663 Overlap = PanelHeight - MidPanelHeight;
664 yTroop = PanelHeight - 83;
665 xPalace = 66;
666 yPalace = 24; // 120;
667{ xAdvisor = 108;
668 yAdvisor = 48;}
669 xUnitText = 80;
670 BlinkOnTime = 12;
671 BlinkOffTime = 6;
672 MoveTime = 300; // {time for moving a unit in ms}
673 WaitAfterShowMove = 32;
674 FastScrolling = False; // causes problems with overlapping windows
675
676 BrushTypes: array[0..25] of Cardinal = (fPrefStartPos,
677 fStartPos, fShore, fGrass, fTundra, fPrairie, fDesert, fSwamp, fForest,
678 fHills, fMountains, fArctic, fDeadLands, fDeadLands or fCobalt,
679 fDeadLands or fUranium, fDeadLands or fMercury, fRiver, fRoad, fRR, fCanal,
680 tiIrrigation, tiFarm, tiMine, fPoll, tiFort, tiBase);
681
682 // MoveUnit options:
683 muAutoNoWait = $0001;
684 muAutoNext = $0002;
685 muNoSuicideCheck = $0004;
686
687 // ProcessRect options:
688 prPaint = $0001;
689 prAutoBounds = $0002;
690 prInvalidate = $0004;
691
692 // FocusOnLoc options:
693 flRepaintPanel = $0001;
694 flImmUpdate = $0002;
695
696var
697 Jump: array [0 .. nPl - 1] of Integer;
698 pTurn: Integer;
699 pLogo: Integer;
700 UnStartLoc: Integer;
701 ToldSlavery: Integer;
702 SmallScreen: Boolean;
703 GameOK: Boolean;
704 MapValid: Boolean;
705 Skipped: Boolean;
706 Idle: Boolean;
707
708 SaveOption: array of Integer;
709 CurrentMoveInfo: TCurrentMoveInfo;
710
711function CityEventName(I: Integer): string;
712begin
713 if I = 14 then // chAllImpsMade
714 if not Phrases2FallenBackToEnglish then
715 Result := Phrases2.Lookup('CITYEVENT_ALLIMPSMADE')
716 else
717 Result := Phrases.Lookup('CITYEVENTS', 1)
718 else
719 Result := Phrases.Lookup('CITYEVENTS', I);
720end;
721
722procedure InitSmallImp;
723begin
724 SmallImp.SetSize(BigImp.Width * xSizeSmall div xSizeBig,
725 BigImp.Height * ySizeSmall div ySizeBig);
726 UnshareBitmap(SmallImp);
727 SmallImp.Canvas.StretchDraw(Rect(0, 0, SmallImp.Width, SmallImp.Height), BigImp);
728end;
729
730procedure ImpImage(ca: TCanvas; X, Y, iix: Integer; Government: Integer;
731 IsControl: Boolean);
732begin
733 if Government < 0 then
734 Government := MyRO.Government;
735 if (iix = imPalace) and (Government <> gAnarchy) then
736 iix := Government - 8;
737 FrameImage(ca, BigImp, X, Y, xSizeBig, ySizeBig, (iix + SystemIconLines * 7)
738 mod 7 * xSizeBig, (iix + SystemIconLines * 7) div 7 * ySizeBig, IsControl);
739end;
740
741procedure HelpOnTerrain(Loc: Integer; NewMode: TWindowMode);
742begin
743 if MyMap[Loc] and fDeadLands <> 0 then
744 MainScreen.HelpDlg.ShowNewContent(NewMode, hkTer, 3 * 12)
745 else if (MyMap[Loc] and fTerrain = fForest) and IsJungle(Loc div G.lx) then
746 MainScreen.HelpDlg.ShowNewContent(NewMode, hkTer,
747 fJungle + (MyMap[Loc] shr 5 and 3) * 12)
748 else
749 MainScreen.HelpDlg.ShowNewContent(NewMode, hkTer, MyMap[Loc] and fTerrain +
750 (MyMap[Loc] shr 5 and 3) * 12);
751end;
752
753function AlignUp(Value, Alignment: Integer): Integer;
754begin
755 Result := Value or (Alignment - 1);
756end;
757
758{ *** tribe management procedures *** }
759
760function RoughCredibility(Credibility: Integer): Integer;
761begin
762 case Credibility of
763 0 .. 69:
764 Result := 0;
765 70 .. 89:
766 Result := 1;
767 90 .. 99:
768 Result := 2;
769 100:
770 Result := 3;
771 end;
772end;
773
774procedure ChooseModelPicture(P, mix, Code, Hash, Turn: Integer;
775 ForceNew, Final: Boolean);
776var
777 I: Integer;
778 Picture: TModelPictureInfo;
779 IsNew: Boolean;
780begin
781 Picture.trix := P;
782 Picture.mix := mix;
783 if Code = 74 then
784 begin // use correct pictures for slaves
785 if Tribe[P].mixSlaves < 0 then
786 if not TribeOriginal[P] then
787 Tribe[P].mixSlaves := mix
788 else
789 begin
790 I := mix + P shl 16;
791 Server(cSetSlaveIndex, 0, 0, I);
792 end;
793 if ToldSlavery = 1 then
794 Picture.pix := pixSlaves
795 else
796 Picture.pix := pixNoSlaves;
797 Picture.Hash := 0;
798 Picture.GrName := 'StdUnits.png';
799 IsNew := True;
800 end
801 else
802 begin
803 Picture.Hash := Hash;
804 IsNew := Tribe[P].ChooseModelPicture(Picture, Code, Turn, ForceNew);
805 end;
806 if Final then
807 if not TribeOriginal[P] then
808 Tribe[P].SetModelPicture(Picture, IsNew)
809 else if IsNew then
810 Server(CommandWithData(cSetNewModelPicture, Picture.GetCommandDataSize),
811 0, 0, Picture)
812 else
813 Server(CommandWithData(cSetModelPicture, Picture.GetCommandDataSize),
814 0, 0, Picture)
815 else
816 with Tribe[P].ModelPicture[mix] do
817 begin
818 HGr := LoadGraphicSet(Picture.GrName);
819 pix := Picture.pix;
820 end;
821end;
822
823function InitEnemyModel(emix: Integer): Boolean;
824begin
825 if GameMode = cMovie then
826 begin
827 Result := False;
828 Exit;
829 end;
830 with MyRO.EnemyModel[emix] do
831 ChooseModelPicture(Owner, mix, ModelCode(MyRO.EnemyModel[emix]),
832 ModelHash(MyRO.EnemyModel[emix]), MyRO.Turn, False, True);
833 Result := True;
834end;
835
836procedure InitAllEnemyModels;
837var
838 emix: Integer;
839begin
840 for emix := 0 to MyRO.nEnemyModel - 1 do
841 with MyRO.EnemyModel[emix] do
842 if not Assigned(Tribe[Owner].ModelPicture[mix].HGr) then
843 InitEnemyModel(emix);
844end;
845
846procedure InitMyModel(Mix: Integer; Final: Boolean);
847var
848 mi: TModelInfo;
849begin
850 if (GameMode = cMovie) and (MyModel[mix].Kind < $08) then
851 Exit;
852 // don't exit for special units because cSetModelPicture comes after TellNewModels
853 MakeModelInfo(Me, Mix, MyModel[mix], mi);
854 ChooseModelPicture(Me, Mix, ModelCode(mi), ModelHash(mi), MyRO.Turn,
855 False, Final);
856end;
857
858function AttackSound(Code: Integer): string;
859begin
860 Result := 'ATTACK_' + Char(48 + Code div 100 mod 10) +
861 Char(48 + Code div 10 mod 10) + Char(48 + Code mod 10);
862end;
863
864procedure CheckToldNoReturn(uix: Integer);
865// check whether aircraft survived low-fuel warning
866begin
867 Assert(not Supervising);
868 with MyUn[uix] do
869 if (Status and usToldNoReturn <> 0) and
870 ((MyMap[Loc] and fCity <> 0) or (MyMap[Loc] and fTerImp = tiBase) or
871 (Master >= 0)) then
872 Status := Status and not usToldNoReturn;
873end;
874
875function CreateTribe(P: Integer; FileName: string; Original: Boolean): Boolean;
876begin
877 FileName := LocalizedFilePath('Tribes' + DirectorySeparator + FileName +
878 CevoTribeExt);
879 if not FileExists(FileName) then
880 begin
881 Result := False;
882 Exit;
883 end;
884
885 TribeOriginal[P] := Original;
886 Tribe[P] := TTribe.Create(FileName);
887 with Tribe[P] do
888 begin
889 if (GameMode = cNewGame) or not Original then
890 begin
891 Term.ChooseModelPicture(P, 0, 010, 1, 0, True, True);
892 Term.ChooseModelPicture(P, 1, 040, 1, 0, True, True);
893 Term.ChooseModelPicture(P, 2, 041, 1, 0, True, True);
894 Term.ChooseModelPicture(P, -1, 017, 1, 0, True, True);
895 end;
896 DipMem[P].pContact := -1;
897 end;
898 Result := True;
899end;
900
901procedure TellNewContacts;
902var
903 p1: Integer;
904begin
905 if not Supervising then
906 for p1 := 0 to nPl - 1 do
907 if (p1 <> Me) and (1 shl p1 and MyData.ToldContact = 0) and
908 (1 shl p1 and MyRO.Alive <> 0) and (MyRO.Treaty[p1] > trNoContact) then
909 begin
910 TribeMessage(p1, Tribe[p1].TPhrase('FRNEWNATION'), '');
911 MyData.ToldContact := MyData.ToldContact or (1 shl p1);
912 end;
913end;
914
915procedure TellNewModels;
916var
917 mix: Integer;
918 ModelNameInfo: TModelNameInfo;
919begin
920 if Supervising then
921 Exit;
922 with Tribe[Me] do
923 while MyData.ToldModels < MyRO.nModel do
924 begin { new Unit class available }
925 if Assigned(ModelPicture[MyData.ToldModels].HGr) and
926 (MyModel[MyData.ToldModels].Kind <> mkSelfDeveloped) then
927 begin // save picture of DevModel
928 ModelPicture[MyData.ToldModels + 1] := ModelPicture[MyData.ToldModels];
929 ModelName[MyData.ToldModels + 1] := ModelName[MyData.ToldModels];
930 ModelPicture[MyData.ToldModels].HGr := nil;
931 end;
932 if not Assigned(ModelPicture[MyData.ToldModels].HGr) then
933 InitMyModel(MyData.ToldModels, True);
934 { only run if no researched model }
935 with MainScreen.MessgExDlg do
936 begin
937 { MakeModelInfo(me,MyData.ToldModels,MyModel[MyData.ToldModels],mi);
938 if mi.Attack=0 then OpenSound:='MSG_DEFAULT'
939 else OpenSound:=AttackSound(ModelCode(mi)); }
940 if MyModel[MyData.ToldModels].Kind = mkSelfDeveloped then
941 OpenSound := 'NEWMODEL_' + Char(48 + Age);
942 MessgText := Phrases.Lookup('MODELAVAILABLE');
943 if GameMode = cMovie then
944 begin
945 Kind := mkOkHelp; // doesn't matter
946 MessgText := MessgText + '\' + ModelName[MyData.ToldModels];
947 end
948 else
949 begin
950 Kind := mkModel;
951 EInput.Text := ModelName[MyData.ToldModels];
952 end;
953 IconKind := mikModel;
954 IconIndex := MyData.ToldModels;
955 ShowModal;
956 if (EInput.Text <> '') and (EInput.Text <> ModelName[MyData.ToldModels])
957 then
958 begin // user renamed model
959 ModelNameInfo.mix := MyData.ToldModels;
960 ModelNameInfo.NewName := EInput.Text;
961 if ModelNameInfo.GetCommandDataSize > CommandDataMaxSize then
962 Delete(ModelNameInfo.NewName, Length(ModelNameInfo.NewName) -
963 (ModelNameInfo.GetCommandDataSize - 1 - CommandDataMaxSize), MaxInt);
964 Server(CommandWithData(cSetModelName, ModelNameInfo.GetCommandDataSize),
965 Me, 0, ModelNameInfo);
966 end;
967 end;
968 if MyModel[MyData.ToldModels].Kind = mkSettler then
969 begin // engineers make settlers obsolete
970 for mix := 0 to MyData.ToldModels - 1 do
971 if MyModel[mix].Kind = mkSettler then
972 MyModel[mix].Status := MyModel[mix].Status or msObsolete;
973 end;
974 Inc(MyData.ToldModels);
975 end;
976end;
977
978{ TTribeInfo }
979
980function TTribeInfo.GetCommandDataSize: Byte;
981begin
982 Result := SizeOf(trix) + 1 + Length(FileName)
983end;
984
985{ TModelNameInfo }
986
987function TModelNameInfo.GetCommandDataSize: Byte;
988begin
989 Result := SizeOf(mix) + 1 + Length(NewName);
990end;
991
992{ TCityNameInfo }
993
994function TCityNameInfo.GetCommandDataSize: Byte;
995begin
996 Result := SizeOf(ID) + 1 + Length(NewName);
997end;
998
999procedure TMainScreen.PaintZoomedTile(Dst: TBitmap; X, Y, Loc: Integer);
1000
1001 procedure TerrainSprite(xDst, yDst, xSrc, ySrc: Integer);
1002 begin
1003 with NoMapPanel do
1004 Sprite(Dst, HGrTerrain, X + xDst, Y + yDst, xxt * 2, yyt * 3,
1005 1 + xSrc * (xxt * 2 + 1), 1 + ySrc * (yyt * 3 + 1));
1006 end;
1007
1008 procedure TerrainSprite4(xSrc, ySrc: Integer);
1009 begin
1010 with NoMapPanel do begin
1011 Sprite(Dst, HGrTerrain, X + xxt, Y + yyt + 2, xxt * 2, yyt * 2 - 2,
1012 1 + xSrc * (xxt * 2 + 1), 3 + yyt + ySrc * (yyt * 3 + 1));
1013 Sprite(Dst, HGrTerrain, X + 4, Y + 2 * yyt, xxt * 2 - 4, yyt * 2,
1014 5 + xSrc * (xxt * 2 + 1), 1 + yyt + ySrc * (yyt * 3 + 1));
1015 Sprite(Dst, HGrTerrain, X + xxt * 2, Y + 2 * yyt, xxt * 2 - 4, yyt * 2,
1016 1 + xSrc * (xxt * 2 + 1), 1 + yyt + ySrc * (yyt * 3 + 1));
1017 Sprite(Dst, HGrTerrain, X + xxt, Y + yyt * 3, xxt * 2, yyt * 2 - 2,
1018 1 + xSrc * (xxt * 2 + 1), 1 + yyt + ySrc * (yyt * 3 + 1));
1019 end;
1020 end;
1021
1022var
1023 cix, ySrc, Tile: Integer;
1024begin
1025 with NoMapPanel do begin
1026 Tile := MyMap[Loc];
1027 if Tile and fCity <> 0 then
1028 begin
1029 if MyRO.Tech[adRailroad] >= tsApplicable then
1030 Tile := Tile or fRR
1031 else
1032 Tile := Tile or fRoad;
1033 if Tile and fOwned <> 0 then
1034 begin
1035 cix := MyRO.nCity - 1;
1036 while (cix >= 0) and (MyCity[cix].Loc <> Loc) do
1037 Dec(cix);
1038 Assert(cix >= 0);
1039 if MyCity[cix].Built[imSupermarket] > 0 then
1040 Tile := Tile or tiFarm
1041 else
1042 Tile := Tile or tiIrrigation;
1043 end
1044 else Tile := Tile or tiIrrigation;
1045 end;
1046
1047 if Tile and fTerrain >= fForest then
1048 TerrainSprite4(2, 2)
1049 else
1050 TerrainSprite4(Tile and fTerrain, 0);
1051 if Tile and fTerrain >= fForest then
1052 begin
1053 if (Tile and fTerrain = fForest) and IsJungle(Loc div G.lx) then
1054 ySrc := 18
1055 else
1056 ySrc := 3 + 2 * (Tile and fTerrain - fForest);
1057 TerrainSprite(xxt, 0, 6, ySrc);
1058 TerrainSprite(0, yyt, 3, ySrc);
1059 TerrainSprite((xxt * 2), yyt, 4, ySrc + 1);
1060 TerrainSprite(xxt, (yyt * 2), 1, ySrc + 1);
1061 end;
1062
1063 // irrigation
1064 case Tile and fTerImp of
1065 tiIrrigation: begin
1066 TerrainSprite(xxt, 0, 0, 12);
1067 TerrainSprite(xxt * 2, yyt, 0, 12);
1068 end;
1069 tiFarm: begin
1070 TerrainSprite(xxt, 0, 1, 12);
1071 TerrainSprite(xxt * 2, yyt, 1, 12);
1072 end;
1073 end;
1074
1075 // river/canal/road/railroad
1076 if Tile and fRiver <> 0 then begin
1077 TerrainSprite(0, yyt, 2, 14);
1078 TerrainSprite(xxt, (yyt * 2), 2, 14);
1079 end;
1080 if Tile and fCanal <> 0 then begin
1081 TerrainSprite(xxt, 0, 7, 11);
1082 TerrainSprite(xxt, 0, 3, 11);
1083 TerrainSprite(xxt * 2, yyt, 7, 11);
1084 TerrainSprite(xxt * 2, yyt, 3, 11);
1085 end;
1086 if Tile and fRR <> 0 then begin
1087 TerrainSprite((xxt * 2), yyt, 1, 10);
1088 TerrainSprite((xxt * 2), yyt, 5, 10);
1089 TerrainSprite(xxt, (yyt * 2), 1, 10);
1090 TerrainSprite(xxt, (yyt * 2), 5, 10);
1091 end
1092 else if Tile and fRoad <> 0 then begin
1093 TerrainSprite((xxt * 2), yyt, 8, 9);
1094 TerrainSprite((xxt * 2), yyt, 5, 9);
1095 TerrainSprite(xxt, (yyt * 2), 1, 9);
1096 TerrainSprite(xxt, (yyt * 2), 5, 9);
1097 end;
1098
1099 if Tile and fPoll <> 0 then
1100 TerrainSprite(xxt, (yyt * 2), 6, 12);
1101
1102 // special
1103 if Tile and (fTerrain or fSpecial) = fGrass or fSpecial1 then TerrainSprite4(2, 1)
1104 else if Tile and fSpecial <> 0 then
1105 if Tile and fTerrain < fForest then
1106 TerrainSprite(0, yyt, Tile and fTerrain, Tile and fSpecial shr 5)
1107 else if (Tile and fTerrain = fForest) and IsJungle(Loc div G.lx) then
1108 TerrainSprite(0, yyt, 8, 17 + Tile and fSpecial shr 5)
1109 else
1110 TerrainSprite(0, yyt, 8, 2 + (Tile and fTerrain - fForest) * 2 + Tile and
1111 fSpecial shr 5)
1112 else if Tile and fDeadLands <> 0 then begin
1113 TerrainSprite4(6, 2);
1114 TerrainSprite(xxt, yyt, 8, 12 + Tile shr 25 and 3);
1115 end;
1116
1117 // other improvements
1118 case Tile and fTerImp of
1119 tiMine: TerrainSprite(xxt, 0, 2, 12);
1120 tiFort: begin
1121 TerrainSprite(xxt, 0, 7, 12);
1122 TerrainSprite(xxt, 0, 3, 12);
1123 end;
1124 tiBase: TerrainSprite(xxt, 0, 4, 12);
1125 end;
1126 end;
1127end;
1128
1129procedure TMainScreen.UpdateInterface;
1130begin
1131 mFillMap.Enabled := BrushType in [fShore, fGrass, fTundra, fPrairie, fDesert, fSwamp, fForest,
1132 fHills, fMountains, fArctic];
1133end;
1134
1135function ChooseResearch: Boolean;
1136var
1137 ChosenResearch: Integer;
1138begin
1139 if (MyData.FarTech <> adNone) and (MyRO.Tech[MyData.FarTech] >= tsApplicable)
1140 then
1141 MyData.FarTech := adNone;
1142 repeat
1143 { research complete -- select new }
1144 repeat
1145 MainScreen.ModalSelectDlg.ShowNewContent(wmModal, kAdvance);
1146 if MainScreen.ModalSelectDlg.Result < 0 then
1147 begin
1148 Result := False;
1149 Exit;
1150 end;
1151 ChosenResearch := MainScreen.ModalSelectDlg.Result;
1152 if ChosenResearch = adMilitary then
1153 begin
1154 MainScreen.DraftDlg.ShowNewContent(wmModal);
1155 if MainScreen.DraftDlg.ModalResult <> mrOK then
1156 Tribe[Me].ModelPicture[MyRO.nModel].HGr := nil;
1157 end;
1158 until (ChosenResearch <> adMilitary) or (MainScreen.DraftDlg.ModalResult = mrOK);
1159
1160 if ChosenResearch = adMilitary then
1161 InitMyModel(MyRO.nModel, True)
1162 else if ChosenResearch = adFar then
1163 begin
1164 MainScreen.ModalSelectDlg.ShowNewContent(wmModal, kFarAdvance);
1165 if MainScreen.ModalSelectDlg.Result >= 0 then
1166 if (MainScreen.ModalSelectDlg.Result = adNone) or
1167 (Server(sSetResearch - sExecute, Me, MainScreen.ModalSelectDlg.Result, nil^) <
1168 rExecuted) then
1169 MyData.FarTech := MainScreen.ModalSelectDlg.Result
1170 else
1171 begin
1172 ChosenResearch := MainScreen.ModalSelectDlg.Result;
1173 // can be researched immediately
1174 MyData.FarTech := adNone;
1175 end;
1176 end;
1177 until ChosenResearch <> adFar;
1178 if ChosenResearch = adNexus then
1179 MyData.FarTech := adNexus
1180 else
1181 Server(sSetResearch, Me, ChosenResearch, nil^);
1182 MainScreen.ListDlg.TechChange;
1183 Result := True;
1184end;
1185
1186procedure ApplyToVisibleForms(FormAction: TFormAction);
1187var
1188 I: Integer;
1189 Form: TForm;
1190begin
1191 for I := 0 to Screen.FormCount - 1 do begin
1192 Form := Screen.Forms[I];
1193 if Form.Visible and (Form is TBufferedDrawDlg) then begin
1194 case FormAction of
1195 faClose: Form.Close;
1196 faEnable: Form.Enabled := True;
1197 faDisable: Form.Enabled := False;
1198 faUpdate: begin
1199 if @Form.OnShow <> nil then Form.OnShow(nil);
1200 Form.Invalidate;
1201 Form.Update;
1202 end;
1203 faSmartUpdateContent: TBufferedDrawDlg(Form).SmartUpdateContent(False);
1204 end;
1205 end;
1206 end;
1207end;
1208
1209(* ** client function handling ** *)
1210
1211function TMainScreen.DipCall(Command: Integer): Integer;
1212var
1213 I: Integer;
1214 IsTreatyDeal: Boolean;
1215begin
1216 Result := Server(Command, Me, 0, nil^);
1217 if Result >= rExecuted then
1218 begin
1219 if Command and $FF0F = scContact then
1220 begin
1221 DipMem[Me].pContact := Command shr 4 and $F;
1222 NegoDlg.Initiate;
1223 DipMem[Me].DeliveredPrices := [];
1224 DipMem[Me].ReceivedPrices := [];
1225 end;
1226
1227 DipMem[Me].SentCommand := Command;
1228 DipMem[Me].FormerTreaty := MyRO.Treaty[DipMem[Me].pContact];
1229 if Command = scDipCancelTreaty then
1230 Play('CANCELTREATY')
1231 else if Command = scDipAccept then
1232 begin // remember delivered and received prices
1233 for I := 0 to ReceivedOffer.nDeliver - 1 do
1234 Include(DipMem[Me].ReceivedPrices, ReceivedOffer.Price[I] shr 24);
1235 for I := 0 to ReceivedOffer.nCost - 1 do
1236 Include(DipMem[Me].DeliveredPrices,
1237 ReceivedOffer.Price[ReceivedOffer.nDeliver + I] shr 24);
1238 IsTreatyDeal := False;
1239 for I := 0 to ReceivedOffer.nDeliver + ReceivedOffer.nCost - 1 do
1240 if ReceivedOffer.Price[I] and opMask = opTreaty then begin
1241 IsTreatyDeal := True;
1242 Break;
1243 end;
1244 if IsTreatyDeal then
1245 Play('NEWTREATY')
1246 else
1247 Play('ACCEPTOFFER');
1248 end;
1249 CityDlg.CloseAction := None;
1250 if G.RO[DipMem[Me].pContact] <> nil then
1251 begin // close windows for next player
1252 ApplyToVisibleForms(faClose);
1253 end
1254 else
1255 begin
1256 if CityDlg.Visible then
1257 CityDlg.Close;
1258 if UnitStatDlg.Visible then
1259 UnitStatDlg.Close;
1260 end;
1261 end;
1262end;
1263
1264function TMainScreen.OfferCall(var Offer: TOffer): Integer;
1265begin
1266 Result := Server(scDipOffer, Me, 0, Offer);
1267 if Result >= rExecuted then
1268 begin
1269 DipMem[Me].SentCommand := scDipOffer;
1270 DipMem[Me].FormerTreaty := MyRO.Treaty[DipMem[Me].pContact];
1271 DipMem[Me].SentOffer := Offer;
1272 CityDlg.CloseAction := None;
1273 if G.RO[DipMem[Me].pContact] <> nil then
1274 begin // close windows for next player
1275 ApplyToVisibleForms(faClose);
1276 end
1277 else
1278 begin
1279 if CityDlg.Visible then
1280 CityDlg.Close;
1281 if UnitStatDlg.Visible then
1282 UnitStatDlg.Close;
1283 end;
1284 end;
1285end;
1286
1287procedure TMainScreen.SetUnFocus(uix: Integer);
1288var
1289 Loc0: Integer;
1290begin
1291 Assert(not ((uix >= 0) and Supervising));
1292 if uix <> UnFocus then
1293 begin
1294 DestinationMarkON := False;
1295 PaintDestination;
1296 if uix >= 0 then
1297 UnStartLoc := MyUn[uix].Loc;
1298 BlinkON := False;
1299 BlinkTime := -1;
1300 if UnFocus >= 0 then
1301 begin
1302 Loc0 := MyUn[UnFocus].Loc;
1303 if (uix < 0) or (Loc0 <> MyUn[uix].Loc) then
1304 begin
1305 UnFocus := -1;
1306 PaintLoc(Loc0);
1307 end;
1308 end;
1309 UnFocus := uix;
1310 end;
1311 UnitInfoBtn.Visible := UnFocus >= 0;
1312 UnitBtn.Visible := UnFocus >= 0;
1313 CheckTerrainBtnVisible;
1314end;
1315
1316procedure TMainScreen.CheckTerrainBtnVisible;
1317var
1318 Tile: Integer;
1319 mox: ^TModel;
1320begin
1321 if UnFocus >= 0 then
1322 begin
1323 mox := @MyModel[MyUn[UnFocus].mix];
1324 Tile := MyMap[MyUn[UnFocus].Loc];
1325 TerrainBtn.Visible := (Tile and fCity = 0) and (MyUn[UnFocus].Master < 0)
1326 and ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves) and
1327 (MyRO.Wonder[woPyramids].EffectiveOwner >= 0));
1328 end
1329 else
1330 TerrainBtn.Visible := False;
1331end;
1332
1333procedure TMainScreen.CheckMovieSpeedBtnState;
1334begin
1335 if GameMode = cMovie then
1336 begin
1337 MovieSpeed1Btn.Down := MovieSpeed = 1;
1338 MovieSpeed1Btn.Visible := True;
1339 MovieSpeed2Btn.Down := MovieSpeed = 2;
1340 MovieSpeed2Btn.Visible := True;
1341 MovieSpeed3Btn.Down := MovieSpeed = 3;
1342 MovieSpeed3Btn.Visible := True;
1343 MovieSpeed4Btn.Down := MovieSpeed = 4;
1344 MovieSpeed4Btn.Visible := True;
1345 end
1346 else
1347 begin
1348 MovieSpeed1Btn.Visible := False;
1349 MovieSpeed2Btn.Visible := False;
1350 MovieSpeed3Btn.Visible := False;
1351 MovieSpeed4Btn.Visible := False;
1352 end;
1353end;
1354
1355procedure TMainScreen.SetMapOptions;
1356begin
1357 MiniMap.MapOptions := MapOptionChecked;
1358 MapOptions := MapOptionChecked;
1359 if ClientMode = cEditMap then
1360 MapOptions := MapOptions + [moEditMode];
1361 if mLocCodes.Checked then
1362 MapOptions := MapOptions + [moLocCodes];
1363end;
1364
1365procedure TMainScreen.UpdateViews(UpdateCityScreen: Boolean);
1366begin
1367 SumCities(TaxSum, ScienceSum);
1368 PanelPaint; // TopBar was enough!!!
1369 ListDlg.EcoChange;
1370 NatStatDlg.EcoChange;
1371 if UpdateCityScreen then
1372 CityDlg.SmartUpdateContent;
1373end;
1374
1375procedure TMainScreen.SetAIName(P: Integer; Name: string);
1376begin
1377 if Name = '' then
1378 begin
1379 if AILogo[P] <> nil then
1380 begin
1381 FreeAndNil(AILogo[P]);
1382 end;
1383 end
1384 else
1385 begin
1386 if AILogo[P] = nil then
1387 AILogo[P] := TBitmap.Create;
1388 if not LoadGraphicFile(AILogo[P], HomeDir + Name + '.png', [gfNoError]) then
1389 begin
1390 FreeAndNil(AILogo[P]);
1391 end;
1392 end;
1393end;
1394
1395function TMainScreen.ContactRefused(P: Integer; Item: String): Boolean;
1396// return whether treaty was cancelled
1397var
1398 S: string;
1399begin
1400 Assert(MyRO.Treaty[P] >= trPeace);
1401 S := Tribe[P].TPhrase(Item);
1402 if MyRO.Turn < MyRO.LastCancelTreaty[P] + CancelTreatyTurns then
1403 begin
1404 SimpleMessage(S);
1405 Result := False;
1406 end
1407 else
1408 begin
1409 case MyRO.Treaty[P] of
1410 trPeace:
1411 S := S + ' ' + Phrases.Lookup('FRCANCELQUERY_PEACE');
1412 trFriendlyContact:
1413 S := S + ' ' + Phrases.Lookup('FRCANCELQUERY_FRIENDLY');
1414 trAlliance:
1415 S := S + ' ' + Phrases.Lookup('FRCANCELQUERY_ALLIANCE');
1416 end;
1417 Result := SimpleQuery(mkYesNo, S, 'NEGO_REJECTED') = mrOK;
1418 if Result then
1419 begin
1420 Play('CANCELTREATY');
1421 Server(sCancelTreaty, Me, 0, nil^);
1422 if MyRO.Treaty[P] = trNone then
1423 CityOptimizer_BeginOfTurn;
1424 // peace treaty was cancelled -- use formerly forbidden tiles
1425 MapValid := False;
1426 PaintAllMaps;
1427 end;
1428 end;
1429end;
1430
1431procedure TMainScreen.RememberPeaceViolation;
1432var
1433 uix, p1: Integer;
1434begin
1435 MyData.PeaceEvaHappened := 0;
1436 for uix := 0 to MyRO.nUn - 1 do
1437 with MyUn[uix] do
1438 if Loc >= 0 then
1439 begin
1440 p1 := MyRO.Territory[Loc];
1441 if (p1 <> Me) and (p1 >= 0) and
1442 (MyRO.Turn = MyRO.EvaStart[p1] + (PeaceEvaTurns - 1)) then
1443 MyData.PeaceEvaHappened := MyData.PeaceEvaHappened or (1 shl p1);
1444 end;
1445end;
1446
1447procedure TMainScreen.SoundPreload(Check: TSoundBlocks);
1448const
1449 nStartBlock = 27;
1450 StartBlock: array [0 .. nStartBlock - 1] of string = ('INVALID', 'TURNEND',
1451 'DISBAND', 'CHEAT', 'MSG_DEFAULT', 'WARNING_DISORDER', 'WARNING_FAMINE',
1452 'WARNING_LOWSUPPORT', 'WARNING_LOWFUNDS', 'MOVE_MOUNTAIN', 'MOVE_LOAD',
1453 'MOVE_UNLOAD', 'MOVE_DIE', 'NOMOVE_TIME', 'NOMOVE_DOMAIN',
1454 'NOMOVE_DEFAULT', 'CITY_SELLIMP', 'CITY_REBUILDIMP', 'CITY_BUYPROJECT',
1455 'CITY_UTILIZE', 'NEWMODEL_0', 'NEWADVANCE_0', 'AGE_0', 'REVOLUTION',
1456 'NEWGOV', 'CITY_INVALIDTYPE', 'MSG_GAMEOVER');
1457
1458 nWonderBlock = 6;
1459 WonderBlock: array [0 .. nWonderBlock - 1] of string = ('WONDER_BUILT',
1460 'WONDER_CAPTURED', 'WONDER_EXPIRED', 'WONDER_DESTROYED', 'MSG_COLDWAR',
1461 'NEWADVANCE_GRLIB');
1462
1463 nScienceBlock = 17;
1464 ScienceBlock: array [0 .. nScienceBlock - 1] of string = ('MOVE_PARACHUTE',
1465 'MOVE_PLANESTART', 'MOVE_PLANELANDING', 'MOVE_COVERT', 'NEWMODEL_1',
1466 'NEWMODEL_2', 'NEWMODEL_3', 'NEWADVANCE_1', 'NEWADVANCE_2',
1467 'NEWADVANCE_3', 'AGE_1', 'AGE_2', 'AGE_3', 'SHIP_BUILT', 'SHIP_TRADED',
1468 'SHIP_CAPTURED', 'SHIP_DESTROYED');
1469
1470 nContactBlock = 20;
1471 ContactBlock: array [0 .. nContactBlock - 1] of string = ('NEWTREATY',
1472 'CANCELTREATY', 'ACCEPTOFFER', 'MSG_WITHDRAW', 'MSG_BANKRUPT',
1473 'CONTACT_0', 'CONTACT_1', 'CONTACT_2', 'CONTACT_3', 'CONTACT_4',
1474 'CONTACT_5', 'CONTACT_5', 'CONTACT_6', 'NEGO_REJECTED', 'MOVE_CAPTURE',
1475 'MOVE_EXPEL', 'NOMOVE_TREATY', 'NOMOVE_ZOC', 'NOMOVE_SUBMARINE',
1476 'NOMOVE_STEALTH');
1477
1478var
1479 I, cix, mix: Integer;
1480 Need: Boolean;
1481 mi: TModelInfo;
1482begin
1483 if (sbStart in Check) and not (sbStart in SoundPreloadDone) then begin
1484 for I := 0 to nStartBlock - 1 do
1485 PreparePlay(StartBlock[I]);
1486 SoundPreloadDone := SoundPreloadDone + [sbStart];
1487 end;
1488 if (sbWonder in Check) and not (sbWonder in SoundPreloadDone) then begin
1489 Need := False;
1490 for I := 0 to nWonder - 1 do
1491 if MyRO.Wonder[I].CityID <> WonderNotBuiltYet then begin
1492 Need := True;
1493 Break;
1494 end;
1495 if Need then begin
1496 for I := 0 to nWonderBlock - 1 do
1497 PreparePlay(WonderBlock[I]);
1498 SoundPreloadDone := SoundPreloadDone + [sbWonder];
1499 end;
1500 end;
1501 if ((sbScience in Check) and not (sbScience in SoundPreloadDone)) and
1502 (MyRO.Tech[adScience] >= tsApplicable) then begin
1503 for I := 0 to nScienceBlock - 1 do
1504 PreparePlay(ScienceBlock[I]);
1505 SoundPreloadDone := SoundPreloadDone + [sbScience];
1506 end;
1507 if ((sbContact in Check) and not (sbContact in SoundPreloadDone)) and
1508 (MyRO.nEnemyModel + MyRO.nEnemyCity > 0) then begin
1509 for I := 0 to nContactBlock - 1 do
1510 PreparePlay(ContactBlock[I]);
1511 SoundPreloadDone := SoundPreloadDone + [sbContact];
1512 end;
1513 if sbTurn in Check then begin
1514 if MyRO.Happened and phShipComplete <> 0 then
1515 PreparePlay('MSG_YOUWIN');
1516 if MyData.ToldAlive <> MyRO.Alive then
1517 PreparePlay('MSG_EXTINCT');
1518 for cix := 0 to MyRO.nCity - 1 do
1519 with MyCity[cix] do
1520 if (Loc >= 0) and (Flags and CityRepMask <> 0) then
1521 for I := 0 to 12 do
1522 if 1 shl I and Flags and CityRepMask <> 0 then
1523 PreparePlay(CityEventSoundItem[I]);
1524 for mix := 0 to MyRO.nModel - 1 do
1525 with MyModel[mix] do
1526 if Attack > 0 then
1527 begin
1528 MakeModelInfo(Me, mix, MyModel[mix], mi);
1529 PreparePlay(AttackSound(ModelCode(mi)));
1530 end;
1531 end;
1532end;
1533
1534procedure TMainScreen.GetTribeList;
1535var
1536 SearchRec: TSearchRec;
1537 Color: TColor;
1538 Name: string;
1539 Ok: Boolean;
1540begin
1541 UnusedTribeFiles.Clear;
1542 Ok := FindFirst(LocalizedFilePath('Tribes') + DirectorySeparator + '*' + CevoTribeExt,
1543 faArchive + faReadOnly, SearchRec) = 0;
1544 if not Ok then
1545 begin
1546 FindClose(SearchRec);
1547 Ok := FindFirst(LocalizedFilePath('Tribes' + DirectorySeparator + '*' + CevoTribeExt),
1548 faArchive + faReadOnly, SearchRec) = 0;
1549 end;
1550 if Ok then
1551 repeat
1552 SearchRec.Name := Copy(SearchRec.Name, 1, Length(SearchRec.Name) - Length(CevoTribeExt));
1553 if GetTribeInfo(SearchRec.Name, Name, Color) then
1554 UnusedTribeFiles.AddObject(SearchRec.Name, TObject(Color));
1555 until FindNext(SearchRec) <> 0;
1556 FindClose(SearchRec);
1557end;
1558
1559function TMainScreen.GetUnitStatDlg: TUnitStatDlg;
1560begin
1561 if not Assigned(FUnitStatDlg) then begin
1562 FUnitStatDlg := TUnitStatDlg.Create(nil);
1563 ArrangeDialog(FUnitStatDlg);
1564 FUnitStatDlg.CheckAge;
1565 end;
1566 Result := FUnitStatDlg;
1567end;
1568
1569function TMainScreen.GetWondersDlg: TWondersDlg;
1570begin
1571 if not Assigned(FWondersDlg) then FWondersDlg := TWondersDlg.Create(nil);
1572 Result := FWondersDlg;
1573end;
1574
1575function TMainScreen.ChooseUnusedTribe: Integer;
1576var
1577 I: Integer;
1578 J: Integer;
1579 ColorDistance: Integer;
1580 BestColorDistance: Integer;
1581 TestColorDistance: Integer;
1582 CountBest: Integer;
1583begin
1584 Assert(UnusedTribeFiles.Count > 0);
1585 Result := -1;
1586 BestColorDistance := -1;
1587 for J := 0 to UnusedTribeFiles.Count - 1 do
1588 begin
1589 ColorDistance := 250; // consider differences more than this infinite
1590 for I := 0 to nPl - 1 do
1591 if Tribe[I] <> nil then
1592 begin
1593 TestColorDistance := Abs(Integer(UnusedTribeFiles.Objects[J])
1594 shr 16 and $FF - Tribe[I].Color shr 16 and $FF) +
1595 Abs(Integer(UnusedTribeFiles.Objects[J]) shr 8 and
1596 $FF - Tribe[I].Color shr 8 and $FF) * 3 +
1597 Abs(Integer(UnusedTribeFiles.Objects[J]) and
1598 $FF - Tribe[I].Color and $FF) * 2;
1599 if TestColorDistance < ColorDistance then
1600 ColorDistance := TestColorDistance;
1601 end;
1602 if ColorDistance > BestColorDistance then
1603 begin
1604 CountBest := 0;
1605 BestColorDistance := ColorDistance;
1606 end;
1607 if ColorDistance = BestColorDistance then
1608 begin
1609 Inc(CountBest);
1610 if DelphiRandom(CountBest) = 0 then
1611 Result := J;
1612 end;
1613 end;
1614end;
1615
1616procedure TMainScreen.ShowEnemyShipChange(ShowShipChange: TShowShipChange);
1617var
1618 I, TestCost, MostCost: Integer;
1619 Ship1Plus, Ship2Plus: Boolean;
1620begin
1621 with ShowShipChange, MessgExDlg do
1622 begin
1623 case Reason of
1624 scrProduction:
1625 begin
1626 OpenSound := 'SHIP_BUILT';
1627 MessgText := Tribe[Ship1Owner].TPhrase('SHIPBUILT');
1628 IconKind := mikShip;
1629 IconIndex := Ship1Owner;
1630 end;
1631
1632 scrDestruction:
1633 begin
1634 OpenSound := 'SHIP_DESTROYED';
1635 MessgText := Tribe[Ship1Owner].TPhrase('SHIPDESTROYED');
1636 IconKind := mikImp;
1637 end;
1638
1639 scrTrade:
1640 begin
1641 OpenSound := 'SHIP_TRADED';
1642 Ship1Plus := False;
1643 Ship2Plus := False;
1644 for I := 0 to nShipPart - 1 do
1645 begin
1646 if Ship1Change[I] > 0 then Ship1Plus := True;
1647 if Ship2Change[I] > 0 then Ship2Plus := True;
1648 end;
1649 if Ship1Plus and Ship2Plus then
1650 MessgText := Tribe[Ship1Owner].TPhrase('SHIPBITRADE1') + ' ' +
1651 Tribe[Ship2Owner].TPhrase('SHIPBITRADE2')
1652 else if Ship1Plus then
1653 MessgText := Tribe[Ship1Owner].TPhrase('SHIPUNITRADE1') + ' ' +
1654 Tribe[Ship2Owner].TPhrase('SHIPUNITRADE2')
1655 else // if Ship2Plus then
1656 MessgText := Tribe[Ship2Owner].TPhrase('SHIPUNITRADE1') + ' ' +
1657 Tribe[Ship1Owner].TPhrase('SHIPUNITRADE2');
1658 IconKind := mikImp;
1659 end;
1660
1661 scrCapture:
1662 begin
1663 OpenSound := 'SHIP_CAPTURED';
1664 MessgText := Tribe[Ship2Owner].TPhrase('SHIPCAPTURE1') + ' ' +
1665 Tribe[Ship1Owner].TPhrase('SHIPCAPTURE2');
1666 IconKind := mikShip;
1667 IconIndex := Ship2Owner;
1668 end;
1669 end;
1670
1671 if IconKind = mikImp then
1672 begin
1673 MostCost := 0;
1674 for I := 0 to nShipPart - 1 do
1675 begin
1676 TestCost := Abs(Ship1Change[I]) * Imp[imShipComp + I].Cost;
1677 if TestCost > MostCost then
1678 begin
1679 MostCost := TestCost;
1680 IconIndex := imShipComp + I;
1681 end;
1682 end;
1683 end;
1684
1685 Kind := mkOk;
1686 ShowModal;
1687 end;
1688end;
1689
1690procedure TMainScreen.InitModule;
1691var
1692 I, J, Domain: Integer;
1693begin
1694 { search icons for advances: }
1695 for I := 0 to nAdv - 1 do
1696 if I in FutureTech then
1697 AdvIcon[I] := 96 + I - futResearchTechnology
1698 else
1699 begin
1700 AdvIcon[I] := -1;
1701 for Domain := 0 to nDomains - 1 do
1702 for J := 0 to nUpgrade - 1 do
1703 if upgrade[Domain, J].Preq = I then
1704 if AdvIcon[I] >= 0 then
1705 AdvIcon[I] := 85
1706 else
1707 AdvIcon[I] := 86 + Domain;
1708 for J := 0 to nFeature - 1 do
1709 if Feature[J].Preq = I then
1710 for Domain := 0 to nDomains - 1 do
1711 if 1 shl Domain and Feature[J].Domains <> 0 then
1712 if (AdvIcon[I] >= 0) and (AdvIcon[I] <> 86 + Domain) then
1713 AdvIcon[I] := 85
1714 else
1715 AdvIcon[I] := 86 + Domain;
1716 for J := nWonder to nImp - 1 do
1717 if Imp[J].Preq = I then
1718 AdvIcon[I] := J;
1719 for J := nWonder to nImp - 1 do
1720 if (Imp[J].Preq = I) and (Imp[J].Kind <> ikCommon) then
1721 AdvIcon[I] := J;
1722 for J := 0 to nJob - 1 do
1723 if I = JobPreq[J] then
1724 AdvIcon[I] := 84;
1725 for J := 0 to nWonder - 1 do
1726 if Imp[J].Preq = I then
1727 AdvIcon[I] := J;
1728 if AdvIcon[I] < 0 then
1729 if AdvValue[I] < 1000 then
1730 AdvIcon[I] := -7
1731 else
1732 AdvIcon[I] := 24 + AdvValue[I] div 1000;
1733 for J := 2 to nGov - 1 do
1734 if GovPreq[J] = I then
1735 AdvIcon[I] := J - 8;
1736 end;
1737 AdvIcon[adConscription] := 86 + dGround;
1738
1739 UnusedTribeFiles := TStringList.Create;
1740 UnusedTribeFiles.Sorted := True;
1741 TribeNames := TStringList.Create;
1742
1743 IsoEngine.Init(InitEnemyModel);
1744 // non-default tile size is missing a file, switch to default
1745 MainMap.SetOutput(Offscreen);
1746
1747 HGrStdUnits := LoadGraphicSet('StdUnits.png');
1748 SmallImp := TBitmap.Create;
1749 SmallImp.PixelFormat := TPixelFormat.pf24bit;
1750 InitSmallImp;
1751 SoundPreloadDone := [];
1752 StartRunning := False;
1753
1754 VerticalScrollBar := TPVScrollbar.Create(Self);
1755 VerticalScrollBar.WheelSteps := 1;
1756 VerticalScrollBar.OnUpdate := ScrollBarUpdate;
1757end;
1758
1759procedure TMainScreen.DoneModule;
1760begin
1761 FreeAndNil(SmallImp);
1762 FreeAndNil(UnusedTribeFiles);
1763 FreeAndNil(TribeNames);
1764end;
1765
1766procedure TMainScreen.InitTurn(NewPlayer: Integer);
1767const
1768 nAdvBookIcon = 16;
1769 AdvBookIcon: array [0 .. nAdvBookIcon - 1] of record Adv,
1770 Icon: Integer end = ((Adv: adPolyTheism; Icon: woZeus),
1771 (Adv: adBronzeWorking; Icon: woColossus), (Adv: adMapMaking;
1772 Icon: woLighthouse), (Adv: adPoetry; Icon: imTheater), (Adv: adMonotheism;
1773 Icon: woMich), (Adv: adPhilosophy; Icon: woLeo), (Adv: adTheoryOfGravity;
1774 Icon: woNewton), (Adv: adSteel; Icon: woEiffel), (Adv: adDemocracy;
1775 Icon: woLiberty), (Adv: adAutomobile; Icon: imHighways),
1776 (Adv: adSanitation; Icon: imSewer), (Adv: adElectronics; Icon: woHoover),
1777 (Adv: adNuclearFission; Icon: woManhattan), (Adv: adRecycling;
1778 Icon: imRecycling), (Adv: adComputers; Icon: imResLab),
1779 (Adv: adSpaceFlight; Icon: woMIR));
1780 sbAll = [sbStart, sbWonder, sbScience, sbContact, sbTurn];
1781var
1782 p1, I, ad, uix, cix, MoveOptions, MoveResult, Loc1,
1783 NewAgeCenterTo, Winners, NewGovAvailable, dx,
1784 dy: Integer;
1785 MoveAdviceData: TMoveAdviceData;
1786 Picture: TModelPictureInfo;
1787 S, Item, Item2: string;
1788 UpdatePanel, OwnWonder, ok, Stop, ShowCityList, WondersOnly,
1789 AllowCityScreen: Boolean;
1790begin
1791 if IsMultiPlayerGame and (NewPlayer <> Me) then
1792 begin
1793 UnitInfoBtn.Visible := False;
1794 UnitBtn.Visible := False;
1795 TerrainBtn.Visible := False;
1796 EOT.Visible := False;
1797 end;
1798 if IsMultiPlayerGame and (NewPlayer <> Me) and
1799 (G.RO[0].Happened and phShipComplete = 0) then
1800 begin // inter player screen
1801 for I := 0 to ControlCount - 1 do
1802 if Controls[I] is TButtonC then
1803 Controls[I].Visible := False;
1804 Me := -1;
1805 MainTexture.Age := -1;
1806 with Panel.Canvas do
1807 begin
1808 Brush.Color := $000000;
1809 FillRect(Rect(0, 0, Panel.Width, Panel.Height));
1810 Brush.Style := TBrushStyle.bsClear;
1811 end;
1812 with TopBar.Canvas do
1813 begin
1814 Brush.Color := $000000;
1815 FillRect(Rect(0, 0, TopBar.Width, TopBar.Height));
1816 Brush.Style := TBrushStyle.bsClear;
1817 end;
1818 Invalidate;
1819
1820 S := TurnToString(G.RO[0].Turn);
1821 if Supervising then
1822 SimpleMessage(Format(Phrases.Lookup('SUPERTURN'), [S]))
1823 else
1824 SimpleMessage(Format(Tribe[NewPlayer].TPhrase('TURN'), [S]));
1825 end;
1826 for I := 0 to ControlCount - 1 do
1827 if Controls[I] is TButtonC then
1828 Controls[I].Visible := True;
1829
1830 ItsMeAgain(NewPlayer);
1831 MyData := G.RO[NewPlayer].Data;
1832 if not Supervising then
1833 SoundPreload(sbAll);
1834 if (Me = 0) and ((MyRO.Turn = 0) or (ClientMode = cResume)) then
1835 Invalidate; // colorize empty space
1836
1837 if not Supervising then
1838 begin
1839
1840 { if MyRO.Happened and phGameEnd<>0 then
1841 begin
1842 Age := 3;
1843 MainTexture.Age := -1;
1844 end
1845 else }
1846 begin
1847 Age := GetAge(Me);
1848 if MainTexture.Age <> Age then begin
1849 MainTexture.Age := Age;
1850 EOT.Invalidate; // has visible background parts in its bounds
1851 end;
1852 end;
1853 // age:=MyRO.Turn mod 4; //!!!
1854 if ClientMode = cMovieTurn then
1855 EOT.ButtonIndex := eotCancel
1856 else if ClientMode < scContact then
1857 EOT.ButtonIndex := eotGray
1858 else
1859 EOT.ButtonIndex := eotBackToNego;
1860 end
1861 else
1862 begin
1863 Age := 0;
1864 MainTexture.Age := -1;
1865 if ClientMode = cMovieTurn then
1866 EOT.ButtonIndex := eotCancel
1867 else
1868 EOT.ButtonIndex := eotBlinkOn;
1869 end;
1870 InitCityMark(MainTexture);
1871 if Assigned(FCityDlg) then FCityDlg.CheckAge;
1872 if Assigned(FNatStatDlg) then FNatStatDlg.CheckAge;
1873 if Assigned(FUnitStatDlg) then FUnitStatDlg.CheckAge;
1874 if Assigned(FHelpDlg) then FHelpDlg.Difficulty := G.Difficulty[Me];
1875
1876 UnFocus := -1;
1877 MarkCityLoc := -1;
1878 BlinkON := False;
1879 BlinkTime := -1;
1880 Tracking := False;
1881 TurnComplete := False;
1882
1883 if (ToldSlavery < 0) or
1884 ((ToldSlavery = 1) <> (MyRO.Wonder[woPyramids].EffectiveOwner >= 0)) then
1885 begin
1886 if MyRO.Wonder[woPyramids].EffectiveOwner >= 0 then
1887 ToldSlavery := 1
1888 else
1889 ToldSlavery := 0;
1890 for p1 := 0 to nPl - 1 do
1891 if (Tribe[p1] <> nil) and (Tribe[p1].mixSlaves >= 0) then
1892 with Picture do
1893 begin // replace unit picture
1894 mix := Tribe[p1].mixSlaves;
1895 if ToldSlavery = 1 then
1896 pix := pixSlaves
1897 else
1898 pix := pixNoSlaves;
1899 Hash := 0;
1900 GrName := 'StdUnits.png';
1901 Tribe[p1].SetModelPicture(Picture, True);
1902 end;
1903 end;
1904
1905 if not Supervising and (ClientMode = cTurn) then
1906 begin
1907 for cix := 0 to MyRO.nCity - 1 do
1908 if (MyCity[cix].Loc >= 0) and
1909 ((MyRO.Turn = 0) or (MyCity[cix].Flags and chFounded <> 0)) then
1910 MyCity[cix].Status := MyCity[cix].Status and
1911 not csResourceWeightsMask or (3 shl 4);
1912 // new city, set to maximum growth
1913 end;
1914 if (ClientMode = cTurn) or (ClientMode = cContinue) then
1915 CityOptimizer_BeginOfTurn; // maybe peace was made or has ended
1916 SumCities(TaxSum, ScienceSum);
1917
1918 if ClientMode = cMovieTurn then
1919 begin
1920 UnitInfoBtn.Visible := False;
1921 UnitBtn.Visible := False;
1922 TerrainBtn.Visible := False;
1923 EOT.Hint := Phrases.Lookup('BTN_STOP');
1924 EOT.Visible := True;
1925 end
1926 else if ClientMode < scContact then
1927 begin
1928 UnitInfoBtn.Visible := UnFocus >= 0;
1929 UnitBtn.Visible := UnFocus >= 0;
1930 CheckTerrainBtnVisible;
1931 TurnComplete := Supervising;
1932 EOT.Hint := Phrases.Lookup('BTN_ENDTURN');
1933 EOT.Visible := Server(sTurn - sExecute, Me, 0, nil^) >= rExecuted;
1934 end
1935 else
1936 begin
1937 UnitInfoBtn.Visible := False;
1938 UnitBtn.Visible := False;
1939 TerrainBtn.Visible := False;
1940 EOT.Hint := Phrases.Lookup('BTN_NEGO');
1941 EOT.Visible := True;
1942 end;
1943 SetTroopLoc(-1);
1944 MapValid := False;
1945 NewAgeCenterTo := 0;
1946 if ((MyRO.Turn = 0) and not Supervising or IsMultiPlayerGame or
1947 (ClientMode = cResume)) and (MyRO.nCity > 0) then
1948 begin
1949 Loc1 := MyCity[0].Loc;
1950 if (ClientMode = cTurn) and (MyRO.Turn = 0) then
1951 with MainMap do begin // move city out of center to not be covered by welcome screen
1952 dx := MapWidth div (xxt * 5);
1953 if dx > 5 then
1954 dx := 5;
1955 dy := MapHeight div (yyt * 5);
1956 if dy > 5 then
1957 dy := 5;
1958 if Loc1 >= G.lx * G.ly div 2 then
1959 begin
1960 NewAgeCenterTo := -1;
1961 Loc1 := dLoc(Loc1, -dx, -dy);
1962 end
1963 else
1964 begin
1965 NewAgeCenterTo := 1;
1966 Loc1 := dLoc(Loc1, -dx, dy);
1967 end
1968 end;
1969 Centre(Loc1);
1970 end;
1971
1972 ApplyToVisibleForms(faEnable);
1973
1974 if ClientMode <> cResume then
1975 begin
1976 PaintAll;
1977 if (MyRO.Happened and phChangeGov <> 0) and (MyRO.NatBuilt[imPalace] > 0)
1978 then
1979 ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, imPalace,
1980 gAnarchy { , GameMode<>cMovie } );
1981 // first turn after anarchy -- don't show despotism palace!
1982 Update;
1983 ApplyToVisibleForms(faUpdate);
1984
1985 if MyRO.Happened and phGameEnd <> 0 then
1986 with MessgExDlg do
1987 begin // game ended
1988 if MyRO.Happened and phExtinct <> 0 then
1989 begin
1990 OpenSound := 'MSG_GAMEOVER';
1991 MessgText := Tribe[Me].TPhrase('GAMEOVER');
1992 IconKind := mikBigIcon;
1993 IconIndex := 8;
1994 end
1995 else if MyRO.Happened and phShipComplete <> 0 then
1996 begin
1997 Winners := 0;
1998 for p1 := 0 to nPl - 1 do
1999 if 1 shl p1 and MyRO.Alive <> 0 then
2000 begin
2001 Winners := Winners or 1 shl p1;
2002 for I := 0 to nShipPart - 1 do
2003 if MyRO.Ship[p1].Parts[I] < ShipNeed[I] then
2004 Winners := Winners and not (1 shl p1);
2005 end;
2006 Assert(Winners <> 0);
2007 if Winners and (1 shl Me) <> 0 then
2008 begin
2009 S := '';
2010 for p1 := 0 to nPl - 1 do
2011 if (p1 <> Me) and (1 shl p1 and Winners <> 0) then
2012 if S = '' then
2013 S := Tribe[p1].TPhrase('SHORTNAME')
2014 else
2015 S := Format(Phrases.Lookup('SHAREDWIN_CONCAT'),
2016 [S, Tribe[p1].TPhrase('SHORTNAME')]);
2017
2018 OpenSound := 'MSG_YOUWIN';
2019 MessgText := Tribe[Me].TPhrase('MYSPACESHIP');
2020 if S <> '' then
2021 MessgText := MessgText + '\' +
2022 Format(Phrases.Lookup('SHAREDWIN'), [S]);
2023 IconKind := mikBigIcon;
2024 IconIndex := 9;
2025 end
2026 else
2027 begin
2028 Assert(Me = 0);
2029 OpenSound := 'MSG_GAMEOVER';
2030 MessgText := '';
2031 for p1 := 0 to nPl - 1 do
2032 if Winners and (1 shl p1) <> 0 then
2033 MessgText := MessgText + Tribe[p1].TPhrase('SPACESHIP1');
2034 MessgText := MessgText + '\' + Phrases.Lookup('SPACESHIP2');
2035 IconKind := mikEnemyShipComplete;
2036 end
2037 end
2038 else { if MyRO.Happened and fTimeUp<>0 then }
2039 begin
2040 Assert(Me = 0);
2041 OpenSound := 'MSG_GAMEOVER';
2042 if not Supervising then
2043 MessgText := Tribe[Me].TPhrase('TIMEUP')
2044 else
2045 MessgText := Phrases.Lookup('TIMEUPSUPER');
2046 IconKind := mikImp;
2047 IconIndex := 22;
2048 end;
2049 Kind := mkOk;
2050 ShowModal;
2051 if MyRO.Happened and phExtinct = 0 then
2052 begin
2053 p1 := 0;
2054 while (p1 < nPl - 1) and (Winners and (1 shl p1) = 0) do
2055 Inc(p1);
2056 if MyRO.Happened and phShipComplete = 0 then
2057 DiaDlg.ShowNewContent_Charts(wmModal);
2058 end;
2059 TurnComplete := True;
2060 Exit;
2061 end;
2062 if not Supervising and (1 shl Me and MyRO.Alive = 0) then
2063 begin
2064 TurnComplete := True;
2065 Exit;
2066 end;
2067
2068 if (ClientMode = cContinue) and
2069 (DipMem[Me].SentCommand and $FF0F = scContact) then
2070 // contact was refused
2071 if MyRO.Treaty[DipMem[Me].pContact] >= trPeace then
2072 ContactRefused(DipMem[Me].pContact, 'FRREJECTED')
2073 else
2074 SoundMessage(Tribe[DipMem[Me].pContact].TPhrase('FRREJECTED'),
2075 'NEGO_REJECTED');
2076
2077 if not Supervising and (Age > MyData.ToldAge) and
2078 ((Age > 0) or (ClientMode <> cMovieTurn)) then
2079 with MessgExDlg do
2080 begin
2081 if Age = 0 then
2082 begin
2083 if Phrases2FallenBackToEnglish then
2084 begin
2085 S := Tribe[Me].TPhrase('AGE0');
2086 MessgText :=
2087 Format(S, [TurnToString(MyRO.Turn), CityName(MyCity[0].ID)]);
2088 end
2089 else
2090 begin
2091 S := Tribe[Me].TString(Phrases2.Lookup('AGE0'));
2092 MessgText := Format(S, [TurnToString(MyRO.Turn)]);
2093 end;
2094 end
2095 else
2096 begin
2097 S := Tribe[Me].TPhrase('AGE' + Char(48 + Age));
2098 MessgText := Format(S, [TurnToString(MyRO.Turn)]);
2099 end;
2100 IconKind := mikAge;
2101 IconIndex := Age;
2102 { if age = 0 then } Kind := mkOk
2103 { else begin Kind := mkOkHelp; HelpKind := hkAdv; HelpNo := AgePreq[age]; end; };
2104 CenterTo := NewAgeCenterTo;
2105 OpenSound := 'AGE_' + Char(48 + Age);
2106 Application.ProcessMessages;
2107 ShowModal;
2108 MyData.ToldAge := Age;
2109 if Age > 0 then
2110 MyData.ToldTech[AgePreq[Age]] := MyRO.Tech[AgePreq[Age]];
2111 end;
2112
2113 if MyData.ToldAlive <> MyRO.Alive then
2114 begin
2115 for p1 := 0 to nPl - 1 do
2116 if (MyData.ToldAlive - MyRO.Alive) and (1 shl p1) <> 0 then
2117 with MessgExDlg do
2118 begin
2119 OpenSound := 'MSG_EXTINCT';
2120 S := Tribe[p1].TPhrase('EXTINCT');
2121 MessgText := Format(S, [TurnToString(MyRO.Turn)]);
2122 if MyRO.Alive = 1 shl Me then
2123 MessgText := MessgText + Phrases.Lookup('EXTINCTALL');
2124 Kind := mkOk;
2125 IconKind := mikImp;
2126 IconIndex := 21;
2127 ShowModal;
2128 end;
2129 if (ClientMode <> cMovieTurn) and not Supervising then
2130 DiaDlg.ShowNewContent_Charts(wmModal);
2131 end;
2132
2133 // tell changes of own credibility
2134 if not Supervising then
2135 begin
2136 if RoughCredibility(MyRO.Credibility) <>
2137 RoughCredibility(MyData.ToldOwnCredibility) then
2138 begin
2139 if RoughCredibility(MyRO.Credibility) >
2140 RoughCredibility(MyData.ToldOwnCredibility) then
2141 S := Phrases.Lookup('CREDUP')
2142 else
2143 S := Phrases.Lookup('CREDDOWN');
2144 TribeMessage(Me, Format(S, [Phrases.Lookup('CREDIBILITY',
2145 RoughCredibility(MyRO.Credibility))]), '');
2146 end;
2147 MyData.ToldOwnCredibility := MyRO.Credibility;
2148 end;
2149
2150 for I := 0 to nWonder - 1 do
2151 begin
2152 OwnWonder := False;
2153 for cix := 0 to MyRO.nCity - 1 do
2154 if (MyCity[cix].Loc >= 0) and (MyCity[cix].ID = MyRO.Wonder[I].CityID)
2155 then begin
2156 OwnWonder := True;
2157 Break;
2158 end;
2159 if MyRO.Wonder[I].CityID <> MyData.ToldWonders[I].CityID then
2160 begin
2161 if MyRO.Wonder[I].CityID = WonderDestroyed then
2162 with MessgExDlg do
2163 begin { tell about destroyed wonders }
2164 OpenSound := 'WONDER_DESTROYED';
2165 MessgText := Format(Phrases.Lookup('WONDERDEST'),
2166 [Phrases.Lookup('IMPROVEMENTS', I)]);
2167 Kind := mkOkHelp;
2168 HelpKind := hkImp;
2169 HelpNo := I;
2170 IconKind := mikImp;
2171 IconIndex := I;
2172 ShowModal;
2173 end
2174 else
2175 begin
2176 if I = woManhattan then
2177 if MyRO.Wonder[I].EffectiveOwner > Me then
2178 MyData.ColdWarStart := MyRO.Turn - 1
2179 else
2180 MyData.ColdWarStart := MyRO.Turn;
2181 if not OwnWonder then
2182 with MessgExDlg do
2183 begin { tell about newly built wonders }
2184 if I = woManhattan then
2185 begin
2186 OpenSound := 'MSG_COLDWAR';
2187 S := Tribe[MyRO.Wonder[I].EffectiveOwner].TPhrase('COLDWAR');
2188 end
2189 else if MyRO.Wonder[I].EffectiveOwner >= 0 then
2190 begin
2191 OpenSound := 'WONDER_BUILT';
2192 S := Tribe[MyRO.Wonder[I].EffectiveOwner]
2193 .TPhrase('WONDERBUILT');
2194 end
2195 else
2196 begin
2197 OpenSound := 'MSG_DEFAULT';
2198 S := Phrases.Lookup('WONDERBUILTEXP');
2199 // already expired when built
2200 end;
2201 MessgText := Format(S, [Phrases.Lookup('IMPROVEMENTS', I),
2202 CityName(MyRO.Wonder[I].CityID)]);
2203 Kind := mkOkHelp;
2204 HelpKind := hkImp;
2205 HelpNo := I;
2206 IconKind := mikImp;
2207 IconIndex := I;
2208 ShowModal;
2209 end;
2210 end;
2211 end
2212 else if (MyRO.Wonder[I].EffectiveOwner <> MyData.ToldWonders[I]
2213 .EffectiveOwner) and (MyRO.Wonder[I].CityID > WonderDestroyed) then
2214 if MyRO.Wonder[I].EffectiveOwner < 0 then
2215 begin
2216 if I <> woMIR then
2217 with MessgExDlg do
2218 begin { tell about expired wonders }
2219 OpenSound := 'WONDER_EXPIRED';
2220 MessgText := Format(Phrases.Lookup('WONDEREXP'),
2221 [Phrases.Lookup('IMPROVEMENTS', I),
2222 CityName(MyRO.Wonder[I].CityID)]);
2223 Kind := mkOkHelp;
2224 HelpKind := hkImp;
2225 HelpNo := I;
2226 IconKind := mikImp;
2227 IconIndex := I;
2228 ShowModal;
2229 end;
2230 end
2231 else if (MyData.ToldWonders[I].EffectiveOwner >= 0) and not OwnWonder
2232 then
2233 with MessgExDlg do
2234 begin { tell about capture of wonders }
2235 OpenSound := 'WONDER_CAPTURED';
2236 S := Tribe[MyRO.Wonder[I].EffectiveOwner].TPhrase('WONDERCAPT');
2237 MessgText := Format(S, [Phrases.Lookup('IMPROVEMENTS', I),
2238 CityName(MyRO.Wonder[I].CityID)]);
2239 Kind := mkOkHelp;
2240 HelpKind := hkImp;
2241 HelpNo := I;
2242 IconKind := mikImp;
2243 IconIndex := I;
2244 ShowModal;
2245 end;
2246 end;
2247
2248 if MyRO.Turn = MyData.ColdWarStart + ColdWarTurns then
2249 begin
2250 SoundMessageEx(Phrases.Lookup('COLDWAREND'), 'MSG_DEFAULT');
2251 MyData.ColdWarStart := -ColdWarTurns - 1;
2252 end;
2253
2254 TellNewModels;
2255 end; // ClientMode<>cResume
2256 MyData.ToldAlive := MyRO.Alive;
2257 Move(MyRO.Wonder, MyData.ToldWonders, SizeOf(MyData.ToldWonders));
2258
2259 NewGovAvailable := -1;
2260 if ClientMode <> cResume then
2261 begin // tell about new techs
2262 for ad := 0 to nAdv - 1 do
2263 if (MyRO.TestFlags and tfAllTechs = 0) and
2264 ((MyRO.Tech[ad] >= tsApplicable) <> (MyData.ToldTech[ad] >=
2265 tsApplicable)) or (ad in FutureTech) and
2266 (MyRO.Tech[ad] <> MyData.ToldTech[ad]) then
2267 with MessgExDlg do
2268 begin
2269 Item := 'RESEARCH_GENERAL';
2270 if GameMode <> cMovie then
2271 OpenSound := 'NEWADVANCE_' + Char(48 + Age);
2272 Item2 := Phrases.Lookup('ADVANCES', ad);
2273 if ad in FutureTech then
2274 Item2 := Item2 + ' ' + IntToStr(MyRO.Tech[ad]);
2275 MessgText := Format(Phrases.Lookup(Item), [Item2]);
2276 Kind := mkOkHelp;
2277 HelpKind := hkAdv;
2278 HelpNo := ad;
2279 IconKind := mikBook;
2280 IconIndex := -1;
2281 for I := 0 to nAdvBookIcon - 1 do
2282 if AdvBookIcon[I].Adv = ad then
2283 IconIndex := AdvBookIcon[I].Icon;
2284 ShowModal;
2285 MyData.ToldTech[ad] := MyRO.Tech[ad];
2286 for I := gMonarchy to nGov - 1 do
2287 if GovPreq[I] = ad then
2288 NewGovAvailable := I;
2289 end;
2290 end;
2291
2292 ShowCityList := False;
2293 if ClientMode = cTurn then
2294 begin
2295 if (MyRO.Happened and phTech <> 0) and (MyData.FarTech <> adNexus) then
2296 ChooseResearch;
2297
2298 UpdatePanel := False;
2299 if MyRO.Happened and phChangeGov <> 0 then
2300 begin
2301 ModalSelectDlg.ShowNewContent(wmModal, kGov);
2302 Play('NEWGOV');
2303 Server(sSetGovernment, Me, ModalSelectDlg.Result, nil^);
2304 CityOptimizer_BeginOfTurn;
2305 UpdatePanel := True;
2306 end;
2307 end; // ClientMode=cTurn
2308
2309 if not Supervising and ((ClientMode = cTurn) or (ClientMode = cMovieTurn))
2310 then
2311 for cix := 0 to MyRO.nCity - 1 do
2312 with MyCity[cix] do
2313 Status := Status and not csToldBombard;
2314
2315 if ((ClientMode = cTurn) or (ClientMode = cMovieTurn)) and
2316 (MyRO.Government <> gAnarchy) then
2317 begin
2318 // tell what happened in cities
2319 for WondersOnly := True downto False do
2320 for cix := 0 to MyRO.nCity - 1 do
2321 with MyCity[cix] do
2322 if (MyRO.Turn > 0) and (Loc >= 0) and (Flags and chCaptured = 0) and
2323 (WondersOnly = (Flags and chProduction <> 0) and
2324 (Project0 and cpImp <> 0) and (Project0 and cpIndex < nWonder)) then
2325 begin
2326 if WondersOnly then
2327 with MessgExDlg do
2328 begin { tell about newly built wonder }
2329 OpenSound := 'WONDER_BUILT';
2330 S := Tribe[Me].TPhrase('WONDERBUILTOWN');
2331 MessgText :=
2332 Format(S, [Phrases.Lookup('IMPROVEMENTS',
2333 Project0 and cpIndex), CityName(ID)]);
2334 Kind := mkOkHelp;
2335 HelpKind := hkImp;
2336 HelpNo := Project0 and cpIndex;
2337 IconKind := mikImp;
2338 IconIndex := Project0 and cpIndex;
2339 ShowModal;
2340 end;
2341 if not Supervising and (ClientMode = cTurn) then
2342 begin
2343 AllowCityScreen := True;
2344 if (Status and 7 <> 0) and
2345 (Project and (cpImp + cpIndex) = cpImp + imTrGoods) then
2346 if (MyData.ImpOrder[Status and 7 - 1, 0] >= 0) then
2347 begin
2348 if AutoBuild(cix, MyData.ImpOrder[Status and 7 - 1]) then
2349 AllowCityScreen := False
2350 else if Flags and chProduction <> 0 then
2351 Flags := (Flags and not chProduction) or chAllImpsMade
2352 end
2353 else
2354 Flags := Flags or chTypeDel;
2355 if (Size >= NeedAqueductSize) and
2356 (MyRO.Tech[Imp[imAqueduct].Preq] < tsApplicable) or
2357 (Size >= NeedSewerSize) and
2358 (MyRO.Tech[Imp[imSewer].Preq] < tsApplicable) then
2359 Flags := Flags and not chNoGrowthWarning;
2360 // don't remind of unknown building
2361 if Flags and chNoSettlerProd = 0 then
2362 Status := Status and not csToldDelay
2363 else if Status and csToldDelay = 0 then
2364 Status := Status or csToldDelay
2365 else
2366 Flags := Flags and not chNoSettlerProd;
2367 if mRepScreens.Checked then
2368 begin
2369 if (Flags and CityRepMask <> 0) and AllowCityScreen then
2370 begin { show what happened in cities }
2371 SetTroopLoc(MyCity[cix].Loc);
2372 MarkCityLoc := MyCity[cix].Loc;
2373 PanelPaint;
2374 CityDlg.CloseAction := None;
2375 CityDlg.ShowNewContent(wmModal, MyCity[cix].Loc,
2376 Flags and CityRepMask);
2377 UpdatePanel := True;
2378 end;
2379 end
2380 else { if mRepList.Checked then }
2381 begin
2382 if Flags and CityRepMask <> 0 then
2383 ShowCityList := True;
2384 end;
2385 end;
2386 end; { city loop }
2387 end; // ClientMode=cTurn
2388
2389 if ClientMode = cTurn then
2390 begin
2391 if NewGovAvailable >= 0 then
2392 with MessgExDlg do
2393 begin
2394 MessgText := Format(Phrases.Lookup('AUTOREVOLUTION'),
2395 [Phrases.Lookup('GOVERNMENT', NewGovAvailable)]);
2396 Kind := mkYesNo;
2397 IconKind := mikPureIcon;
2398 IconIndex := 6 + NewGovAvailable;
2399 ShowModal;
2400 if ModalResult = mrOK then
2401 begin
2402 Play('REVOLUTION');
2403 Server(sRevolution, Me, 0, nil^);
2404 end;
2405 end;
2406 end; // ClientMode=cTurn
2407
2408 if (ClientMode = cTurn) or (ClientMode = cMovieTurn) then
2409 begin
2410 if MyRO.Happened and phGliderLost <> 0 then
2411 ContextMessage(Phrases.Lookup('GLIDERLOST'), 'MSG_DEFAULT',
2412 hkModel, 200);
2413 if MyRO.Happened and phPlaneLost <> 0 then
2414 ContextMessage(Phrases.Lookup('PLANELOST'), 'MSG_DEFAULT',
2415 hkFeature, mcFuel);
2416 if MyRO.Happened and phPeaceEvacuation <> 0 then
2417 for p1 := 0 to nPl - 1 do
2418 if 1 shl p1 and MyData.PeaceEvaHappened <> 0 then
2419 SoundMessageEx(Tribe[p1].TPhrase('WITHDRAW'), 'MSG_DEFAULT');
2420 if MyRO.Happened and phPeaceViolation <> 0 then
2421 for p1 := 0 to nPl - 1 do
2422 if (1 shl p1 and MyRO.Alive <> 0) and (MyRO.EvaStart[p1] = MyRO.Turn)
2423 then
2424 SoundMessageEx(Format(Tribe[p1].TPhrase('VIOLATION'),
2425 [TurnToString(MyRO.Turn + PeaceEvaTurns - 1)]), 'MSG_WITHDRAW');
2426 TellNewContacts;
2427 end;
2428
2429 if ClientMode = cMovieTurn then
2430 Update
2431 else if ClientMode = cTurn then
2432 begin
2433 if UpdatePanel then
2434 UpdateViews;
2435 Application.ProcessMessages;
2436
2437 if not Supervising then
2438 for uix := 0 to MyRO.nUn - 1 do
2439 with MyUn[uix] do
2440 if Loc >= 0 then
2441 begin
2442 if Flags and unWithdrawn <> 0 then
2443 Status := 0;
2444 if Health = 100 then
2445 Status := Status and not usRecover;
2446 if (Master >= 0) or UnitExhausted(uix) then
2447 Status := Status and not usWaiting
2448 else
2449 Status := Status or usWaiting;
2450 CheckToldNoReturn(uix);
2451 if Status and usGoto <> 0 then
2452 begin { continue multi-turn goto }
2453 SetUnFocus(uix);
2454 SetTroopLoc(Loc);
2455 FocusOnLoc(TroopLoc, flRepaintPanel or flImmUpdate);
2456 if Status shr 16 = $7FFF then
2457 MoveResult := GetMoveAdvice(UnFocus, maNextCity,
2458 MoveAdviceData)
2459 else
2460 MoveResult := GetMoveAdvice(UnFocus, Status shr 16,
2461 MoveAdviceData);
2462 if MoveResult >= rExecuted then
2463 begin // !!! Shinkansen
2464 MoveResult := eOK;
2465 Ok := True;
2466 for I := 0 to MoveAdviceData.nStep - 1 do
2467 begin
2468 Loc1 := dLoc(Loc, MoveAdviceData.dx[I],
2469 MoveAdviceData.dy[I]);
2470 if (MyMap[Loc1] and (fCity or fOwned) = fCity)
2471 // don't capture cities during auto move
2472 or (MyMap[Loc1] and (fUnit or fOwned) = fUnit) then
2473 // don't attack during auto move
2474 begin
2475 Ok := False;
2476 Break;
2477 end
2478 else
2479 begin
2480 if (Loc1 = MoveAdviceData.ToLoc) or
2481 (MoveAdviceData.ToLoc = maNextCity) and
2482 (MyMap[dLoc(Loc, MoveAdviceData.dx[I],
2483 MoveAdviceData.dy[I])] and fCity <> 0) then
2484 MoveOptions := muAutoNoWait
2485 else
2486 MoveOptions := 0;
2487 MoveResult := MoveUnit(MoveAdviceData.dx[I],
2488 MoveAdviceData.dy[I], MoveOptions);
2489 if (MoveResult < rExecuted) or (MoveResult = eEnemySpotted)
2490 then
2491 begin
2492 Ok := False;
2493 Break;
2494 end;
2495 end
2496 end;
2497 Stop := not ok or (Loc = MoveAdviceData.ToLoc) or
2498 (MoveAdviceData.ToLoc = maNextCity) and
2499 (MyMap[Loc] and fCity <> 0);
2500 end
2501 else
2502 begin
2503 MoveResult := eOK;
2504 Stop := True;
2505 end;
2506
2507 if MoveResult <> eDied then
2508 if Stop then
2509 Status := Status and ($FFFF - usGoto)
2510 else
2511 Status := Status and not usWaiting;
2512 end;
2513
2514 if Status and (usEnhance or usGoto) = usEnhance then
2515 // continue terrain enhancement
2516 begin
2517 MoveResult := ProcessEnhancement(uix, MyData.EnhancementJobs);
2518 if MoveResult <> eDied then
2519 if MoveResult = eJobDone then
2520 Status := Status and not usEnhance
2521 else
2522 Status := Status and not usWaiting;
2523 end;
2524 end;
2525 end; // ClientMode=cTurn
2526
2527 HaveStrategyAdvice := False;
2528 GoOnPhase := True;
2529 if Supervising or (GameMode = cMovie) then
2530 begin
2531 SetTroopLoc(-1);
2532 PaintAll;
2533 end { supervisor }
2534 { else if (ClientMode=cTurn) and (MyRO.Turn=0) then
2535 begin
2536 SetUnFocus(0);
2537 ZoomToCity(MyCity[0].Loc)
2538 end }
2539 else
2540 begin
2541 if ClientMode >= scContact then
2542 SetUnFocus(-1)
2543 else
2544 NextUnit(-1, False);
2545 if UnFocus < 0 then
2546 begin
2547 UnStartLoc := -1;
2548 if IsMultiPlayerGame or (ClientMode = cResume) then
2549 if MyRO.nCity > 0 then
2550 FocusOnLoc(MyCity[0].Loc)
2551 else
2552 FocusOnLoc(G.lx * G.ly div 2);
2553 SetTroopLoc(-1);
2554 PanelPaint;
2555 end;
2556 if ShowCityList then
2557 ListDlg.ShowNewContent(wmPersistent, kCityEvents);
2558 end;
2559end;
2560
2561procedure TMainScreen.Client(Command, NewPlayer: Integer; var Data);
2562var
2563 I, J, p1, mix, ToLoc, AnimationSpeed, ShowMoveDomain, cix, ecix: Integer;
2564 Color: TColor;
2565 Name, S: string;
2566 TribeInfo: TTribeInfo;
2567 mi: TModelInfo;
2568 SkipTurn, IsAlpine, IsTreatyDeal: Boolean;
2569begin
2570 case Command of
2571 cTurn, cResume, cContinue, cMovieTurn, scContact, scDipStart .. scDipBreak:
2572 begin
2573 Supervising := G.Difficulty[NewPlayer] = 0;
2574 ArrangeMidPanel;
2575 end
2576 end;
2577 case Command of
2578 cDebugMessage:
2579 LogDlg.Add(NewPlayer, G.RO[0].Turn, PChar(@Data));
2580
2581 cShowNego:
2582 with TShowNegoData(Data) do
2583 begin
2584 S := Format('P%d to P%d: ', [pSender, pTarget]);
2585 if (Action = scDipOffer) and (Offer.nDeliver + Offer.nCost > 0) then
2586 begin
2587 S := S + 'Offer ';
2588 for I := 0 to Offer.nDeliver + Offer.nCost - 1 do
2589 begin
2590 if I = Offer.nDeliver then
2591 S := S + ' for '
2592 else if I > 0 then
2593 S := S + '+';
2594 case Offer.Price[I] and opMask of
2595 opChoose:
2596 S := S + 'Price of choice';
2597 opCivilReport:
2598 S := S + 'State report';
2599 opMilReport:
2600 S := S + 'Military report';
2601 opMap:
2602 S := S + 'Map';
2603 opTreaty:
2604 S := S + 'Treaty';
2605 opShipParts:
2606 S := S + 'Ship part';
2607 opMoney:
2608 S := S + IntToStr(Offer.Price[I] and $FFFFFF) + 'o';
2609 opTribute:
2610 S := S + IntToStr(Offer.Price[I] and $FFFFFF) + 'o tribute';
2611 opTech:
2612 S := S + Phrases.Lookup('ADVANCES', Offer.Price[I] and $FFFFFF);
2613 opAllTech:
2614 S := S + 'All advances';
2615 opModel:
2616 S := S + Tribe[pSender].ModelName[Offer.Price[I] and $FFFFFF];
2617 opAllModel:
2618 S := S + 'All models';
2619 end;
2620 end;
2621 LogDlg.Add(NewPlayer, G.RO[0].Turn, PChar(S));
2622 end
2623 else if Action = scDipAccept then
2624 begin
2625 S := S + '--- ACCEPTED! ---';
2626 LogDlg.Add(NewPlayer, G.RO[0].Turn, PChar(S));
2627 end;
2628 end;
2629
2630 cInitModule:
2631 begin
2632 Server := TInitModuleData(Data).Server;
2633 InitModule;
2634 TInitModuleData(Data).DataSize := SizeOf(TPersistentData);
2635 TInitModuleData(Data).Flags := aiThreaded;
2636 end;
2637
2638 cReleaseModule: DoneModule;
2639
2640 cHelpOnly, cStartHelp, cStartCredits:
2641 begin
2642 Age := 0;
2643 if Command = cHelpOnly then
2644 MainTexture.Age := -1;
2645 Tribes.Init;
2646 HelpDlg.UserLeft := Screen.PrimaryMonitor.Left + (Screen.PrimaryMonitor.Width - HelpDlg.Width) div 2;
2647 HelpDlg.UserTop := Screen.PrimaryMonitor.Top + (Screen.PrimaryMonitor.Height - HelpDlg.Height) div 2;
2648 HelpDlg.Difficulty := 0;
2649 if Command = cStartCredits then
2650 HelpDlg.ShowNewContent(wmModal, hkMisc, Integer(miscCredits))
2651 else
2652 HelpDlg.ShowNewContent(wmModal, hkMisc, Integer(miscMain));
2653 Tribes.Done;
2654 end;
2655
2656 cNewGame, cLoadGame, cMovie, cNewMap:
2657 begin
2658 GenerateNames := mNames.Checked;
2659 GameOK := True;
2660 G := TNewGameData(Data);
2661 Me := -1;
2662 pLogo := -1;
2663 ClientMode := -1;
2664 SetMapOptions;
2665 MainMap.pDebugMap := -1;
2666 Idle := False;
2667 FillChar(Jump, SizeOf(Jump), 0);
2668 if StartRunning then
2669 Jump[0] := 999999;
2670 GameMode := Command;
2671 GrExt.ResetPixUsed;
2672 MainMap.Reset;
2673 NoMap.Reset;
2674 Tribes.Init;
2675 GetTribeList;
2676 for p1 := 0 to nPl - 1 do
2677 if (G.RO[p1] <> nil) and (G.RO[p1].Data <> nil) then
2678 with TPersistentData(G.RO[p1].Data^) do
2679 begin
2680 FarTech := adNone;
2681 FillChar(EnhancementJobs, SizeOf(EnhancementJobs), jNone);
2682 FillChar(ImpOrder, SizeOf(ImpOrder), Byte(-1));
2683 ColdWarStart := -ColdWarTurns - 1;
2684 ToldAge := -1;
2685 ToldModels := 3;
2686 ToldAlive := 0;
2687 ToldContact := 0;
2688 ToldOwnCredibility := InitialCredibility;
2689 for I := 0 to nPl - 1 do
2690 if G.Difficulty[I] > 0 then
2691 Inc(ToldAlive, 1 shl I);
2692 PeaceEvaHappened := 0;
2693 for I := 0 to nWonder - 1 do
2694 with ToldWonders[I] do
2695 begin
2696 CityID := -1;
2697 EffectiveOwner := -1;
2698 end;
2699 FillChar(ToldTech, SizeOf(ToldTech), Byte(tsNA));
2700 if G.Difficulty[p1] > 0 then
2701 SoundPreload([sbStart]);
2702 end;
2703
2704 ArrangeDialogs;
2705
2706 Age := 0;
2707 MovieSpeed := 1;
2708 LogDlg.mSlot.Visible := True;
2709 LogDlg.Host := Self;
2710 if Assigned(FHelpDlg) then FHelpDlg.ClearHistory;
2711 if Assigned(FCityDlg) then FCityDlg.Reset;
2712
2713 MiniMap.Size := Point(G.lx, G.ly);
2714 MiniMap.Bitmap.SetSize(MiniMap.Size.X * 2, MiniMap.Size.Y);
2715
2716 for I := 0 to nPl - 1 do begin
2717 Tribe[I] := nil;
2718 TribeOriginal[I] := False;
2719 end;
2720 ToldSlavery := -1;
2721 RepaintOnResize := False;
2722 Closable := False;
2723 FirstMovieTurn := True;
2724
2725 MenuArea.Visible := GameMode <> cMovie;
2726 TreasuryArea.Visible := GameMode < cMovie;
2727 ResearchArea.Visible := GameMode < cMovie;
2728 ManagementArea.Visible := GameMode < cMovie;
2729 end;
2730
2731 cGetReady, cReplay:
2732 if NewPlayer = 0 then
2733 begin
2734 I := 0;
2735 for p1 := 0 to nPl - 1 do
2736 if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) then
2737 Inc(I);
2738 if I > UnusedTribeFiles.Count then
2739 begin
2740 GameOK := False;
2741 SimpleMessage(Phrases.Lookup('TOOFEWTRIBES'));
2742 end
2743 else
2744 begin
2745 for p1 := 0 to nPl - 1 do
2746 if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) and (G.RO[p1] <> nil)
2747 then
2748 begin // let player select own tribes
2749 TribeInfo.trix := p1;
2750 TribeNames.Clear;
2751 for J := 0 to UnusedTribeFiles.Count - 1 do
2752 begin
2753 GetTribeInfo(UnusedTribeFiles[J], Name, Color);
2754 TribeNames.AddObject(Name, TObject(Color));
2755 end;
2756 Assert(TribeNames.Count > 0);
2757 ModalSelectDlg.ShowNewContent(wmModal, kTribe);
2758 Application.ProcessMessages;
2759 TribeInfo.FileName := UnusedTribeFiles[ModalSelectDlg.Result];
2760 UnusedTribeFiles.Delete(ModalSelectDlg.Result);
2761
2762 if GameMode = cLoadGame then
2763 CreateTribe(TribeInfo.trix, TribeInfo.FileName, False)
2764 else
2765 Server(CommandWithData(cSetTribe, TribeInfo.GetCommandDataSize),
2766 0, 0, TribeInfo);
2767 end;
2768
2769 for p1 := 0 to nPl - 1 do
2770 if (G.Difficulty[p1] > 0) and (Tribe[p1] = nil) and (G.RO[p1] = nil)
2771 then
2772 begin // autoselect enemy tribes
2773 J := ChooseUnusedTribe;
2774 TribeInfo.FileName := UnusedTribeFiles[J];
2775 UnusedTribeFiles.Delete(J);
2776 TribeInfo.trix := p1;
2777 if GameMode = cLoadGame then
2778 CreateTribe(TribeInfo.trix, TribeInfo.FileName, False)
2779 else
2780 Server(CommandWithData(cSetTribe, TribeInfo.GetCommandDataSize),
2781 0, 0, TribeInfo);
2782 end;
2783 end;
2784 if not mNames.Checked then
2785 for p1 := 0 to nPl - 1 do
2786 if Tribe[p1] <> nil then
2787 Tribe[p1].NumberName := p1;
2788 end;
2789
2790 cBreakGame:
2791 begin
2792 SaveSettings;
2793 if Assigned(FCityDlg) then CityDlg.CloseAction := None;
2794 ApplyToVisibleForms(faClose);
2795 if LogDlg.Visible then
2796 LogDlg.Close;
2797 LogDlg.List.Clear;
2798 StartRunning := not Idle and (Jump[0] > 0); // AI called Reload
2799 Me := -1;
2800 Idle := False;
2801 ClientMode := -1;
2802 UnitInfoBtn.Visible := False;
2803 UnitBtn.Visible := False;
2804 TerrainBtn.Visible := False;
2805 MovieSpeed1Btn.Visible := False;
2806 MovieSpeed2Btn.Visible := False;
2807 MovieSpeed3Btn.Visible := False;
2808 MovieSpeed4Btn.Visible := False;
2809 EOT.Visible := False;
2810 for I := 0 to ControlCount - 1 do
2811 if Controls[I] is TButtonC then
2812 Controls[I].Visible := False;
2813 VerticalScrollBar.Init(0, 1);
2814 for p1 := 0 to nPl - 1 do
2815 if Tribe[p1] <> nil then
2816 FreeAndNil(Tribe[p1]);
2817 Tribes.Done;
2818 RepaintOnResize := False;
2819 Closable := True;
2820 Close;
2821 end;
2822
2823 cShowGame:
2824 begin
2825 with Panel.Canvas do
2826 begin
2827 Brush.Color := $000000;
2828 FillRect(Rect(0, 0, Panel.Width, Panel.Height));
2829 Brush.Style := TBrushStyle.bsClear;
2830 end;
2831 with TopBar.Canvas do
2832 begin
2833 Brush.Color := $000000;
2834 FillRect(Rect(0, 0, TopBar.Width, TopBar.Height));
2835 Brush.Style := TBrushStyle.bsClear;
2836 end;
2837 Show;
2838 Update;
2839 ResizeControls;
2840 RepaintOnResize := True;
2841 xw := 0;
2842 yw := ywcenter;
2843 end;
2844
2845 cShowTurnChange:
2846 begin
2847 if Integer(Data) >= 0 then
2848 begin
2849 pLogo := Integer(Data);
2850 if G.RO[pLogo] = nil then
2851 begin
2852 if AILogo[pLogo] <> nil then
2853 BitBltCanvas(Canvas, (xRightPanel + 10) - (16 + 64),
2854 ClientHeight - PanelHeight, 64, 64, AILogo[pLogo].Canvas,
2855 0, 0);
2856 end;
2857 end;
2858 end;
2859
2860 cTurn, cResume, cContinue:
2861 if not GameOK then
2862 Server(sResign, NewPlayer, 0, nil^)
2863 else
2864 begin
2865 ClientMode := Command;
2866 pTurn := NewPlayer;
2867 pLogo := NewPlayer;
2868
2869 if Command = cResume then
2870 begin // init non-original model pictures (maybe tribes not found)
2871 for p1 := 0 to nPl - 1 do
2872 if G.RO[p1] <> nil then
2873 begin
2874 ItsMeAgain(p1);
2875 for mix := 0 to MyRO.nModel - 1 do
2876 if not Assigned(Tribe[Me].ModelPicture[mix].HGr) then
2877 InitMyModel(mix, True);
2878 end;
2879 Me := -1;
2880 end;
2881
2882 if Jump[pTurn] > 0 then
2883 Application.ProcessMessages;
2884 if Jump[pTurn] > 0 then
2885 if G.RO[NewPlayer].Happened and phGameEnd <> 0 then
2886 Jump[pTurn] := 0
2887 else
2888 Dec(Jump[pTurn]);
2889 SkipTurn := Jump[pTurn] > 0;
2890 if SkipTurn then
2891 begin
2892 ItsMeAgain(NewPlayer);
2893 MyData := G.RO[NewPlayer].Data;
2894 SetTroopLoc(-1);
2895 MiniMapPaint;
2896 InitAllEnemyModels; // necessary for correct replay
2897 if not EndTurn(True) then
2898 SkipTurn := False;
2899 end;
2900 if not SkipTurn then
2901 begin
2902 if ((ClientMode < scDipStart) or (ClientMode > scDipBreak)) and
2903 Assigned(FNegoDlg) and NegoDlg.Visible then
2904 NegoDlg.Close;
2905 Skipped := False; // always show my moves during my turn
2906 Idle := True;
2907 InitTurn(NewPlayer);
2908 DipMem[Me].pContact := -1;
2909 (* if (Me=0) and (MyRO.Alive and (1 shl Me)=0)} then
2910 begin
2911 if SimpleQuery(Phrases.Lookup('RESIGN'))=mrIgnore then
2912 Server(sResign,Me,0,nil^)
2913 else Server(sBreak,Me,0,nil^)
2914 end
2915 else Play('TURNSTART'); *)
2916 end;
2917 end;
2918
2919 cMovieTurn:
2920 begin
2921 ClientMode := Command;
2922 pTurn := NewPlayer;
2923 pLogo := -1;
2924 Skipped := False; // always show my moves during my turn
2925 Idle := True;
2926 if FirstMovieTurn then
2927 begin
2928 CheckMovieSpeedBtnState;
2929 FirstMovieTurn := False;
2930 end;
2931 InitTurn(NewPlayer);
2932 Application.ProcessMessages;
2933 if MovieSpeed = 4 then
2934 begin
2935 Sleep(75);
2936 // this break will ensure speed of fast forward does not depend on cpu speed
2937 Application.ProcessMessages;
2938 end;
2939 end;
2940
2941 cMovieEndTurn:
2942 begin
2943 RememberPeaceViolation;
2944 pTurn := -1;
2945 pLogo := -1;
2946 MapValid := False;
2947 ClientMode := -1;
2948 Idle := False;
2949 Skipped := False;
2950 end;
2951
2952 cEditMap:
2953 begin
2954 ClientMode := cEditMap;
2955 SetMapOptions;
2956 MainMap.pDebugMap := -1;
2957 ItsMeAgain(0);
2958 MyData := nil;
2959 UnitInfoBtn.Visible := False;
2960 UnitBtn.Visible := False;
2961 TerrainBtn.Visible := False;
2962 MovieSpeed1Btn.Visible := False;
2963 MovieSpeed2Btn.Visible := False;
2964 MovieSpeed3Btn.Visible := False;
2965 MovieSpeed4Btn.Visible := False;
2966 EOT.Visible := False;
2967 HelpDlg.Difficulty := 0;
2968 BrushType := fGrass;
2969 UpdateInterface;
2970 BrushLoc := -1;
2971 Edited := False;
2972 UnFocus := -1;
2973 MarkCityLoc := -1;
2974 Tracking := False;
2975 TurnComplete := False;
2976 MapValid := False;
2977 ResizeControls;
2978 SetTroopLoc(-1);
2979 Idle := True;
2980 end;
2981
2982 (* cNewContact:
2983 begin
2984 end;
2985 *)
2986
2987 scContact:
2988 begin
2989 DipMem[NewPlayer].pContact := Integer(Data);
2990 if Jump[NewPlayer] > 0 then
2991 DipCall(scReject)
2992 else
2993 begin
2994 ClientMode := Command;
2995 InitTurn(NewPlayer);
2996 MyData.ToldContact := MyData.ToldContact or (1 shl Integer(Data));
2997 // don't tell about new nation when already contacted by them
2998 with MessgExDlg do
2999 begin
3000 OpenSound := 'CONTACT_' + Char(48 + MyRO.EnemyReport[Integer(Data)
3001 ].Attitude);
3002 MessgText := Tribe[Integer(Data)].TPhrase('FRCONTACT');
3003 Kind := mkYesNo;
3004 IconKind := mikTribe;
3005 IconIndex := Integer(Data);
3006 ShowModal;
3007 if ModalResult = mrOK then
3008 begin
3009 NegoDlg.Respond;
3010 DipMem[Me].DeliveredPrices := [];
3011 DipMem[Me].ReceivedPrices := [];
3012 DipCall(scDipStart);
3013 end
3014 else
3015 begin
3016 DipCall(scReject);
3017 EndNego;
3018 end;
3019 end;
3020 end;
3021 end;
3022
3023 scDipStart .. scDipBreak:
3024 begin
3025 ClientMode := Command;
3026 InitTurn(NewPlayer);
3027 if Command = scDipStart then
3028 Play('CONTACT_' + Char(48 + MyRO.Attitude[DipMem[NewPlayer]
3029 .pContact]))
3030 else if Command = scDipCancelTreaty then
3031 Play('CANCELTREATY')
3032 else if Command = scDipOffer then
3033 begin
3034 ReceivedOffer := TOffer(Data);
3035 InitAllEnemyModels;
3036 end
3037 else if Command = scDipAccept then
3038 begin // remember delivered and received prices
3039 for I := 0 to DipMem[Me].SentOffer.nDeliver - 1 do
3040 Include(DipMem[Me].DeliveredPrices,
3041 DipMem[Me].SentOffer.Price[I] shr 24);
3042 for I := 0 to DipMem[Me].SentOffer.nCost - 1 do
3043 Include(DipMem[Me].ReceivedPrices,
3044 DipMem[Me].SentOffer.Price[DipMem[Me].SentOffer.nDeliver +
3045 I] shr 24);
3046 IsTreatyDeal := False;
3047 for I := 0 to ReceivedOffer.nDeliver + ReceivedOffer.nCost - 1 do
3048 if DipMem[Me].SentOffer.Price[I] and opMask = opTreaty then begin
3049 IsTreatyDeal := True;
3050 Break;
3051 end;
3052 if IsTreatyDeal then
3053 Play('NEWTREATY')
3054 else
3055 Play('ACCEPTOFFER');
3056 end;
3057 NegoDlg.Start;
3058 Idle := True;
3059 end;
3060
3061 cShowCancelTreaty:
3062 if not IsMultiPlayerGame then
3063 begin
3064 case G.RO[NewPlayer].Treaty[Integer(Data)] of
3065 trPeace:
3066 S := Tribe[Integer(Data)].TPhrase('FRCANCELBYREJECT_PEACE');
3067 trFriendlyContact:
3068 S := Tribe[Integer(Data)].TPhrase('FRCANCELBYREJECT_FRIENDLY');
3069 trAlliance:
3070 S := Tribe[Integer(Data)].TPhrase('FRCANCELBYREJECT_ALLIANCE');
3071 end;
3072 TribeMessage(Integer(Data), S, 'CANCELTREATY');
3073 end;
3074
3075 cShowCancelTreatyByAlliance:
3076 if Idle and (NewPlayer = Me) then
3077 TribeMessage(Integer(Data), Tribe[Integer(Data)
3078 ].TPhrase('FRENEMYALLIANCE'), 'CANCELTREATY');
3079
3080 cShowSupportAllianceAgainst:
3081 if not IsMultiPlayerGame and (Jump[0] = 0) then
3082 TribeMessage(Integer(Data) and $F, Tribe[Integer(Data) and $F]
3083 .TPhrase('FRMYALLIANCE1') + ' ' + Tribe[Integer(Data) shr 4]
3084 .TPhrase('FRMYALLIANCE2'), 'CANCELTREATY');
3085
3086 cShowPeaceViolation:
3087 if not IsMultiPlayerGame and (Jump[0] = 0) then
3088 TribeMessage(Integer(Data),
3089 Format(Tribe[Integer(Data)].TPhrase('EVIOLATION'),
3090 [TurnToString(MyRO.Turn + PeaceEvaTurns - 1)]), 'MSG_WITHDRAW');
3091
3092 cShowEndContact:
3093 EndNego;
3094
3095 cShowUnitChanged, cShowCityChanged, cShowAfterMove, cShowAfterAttack:
3096 if (Idle and (NewPlayer = Me) or not Idle and not skipped) and
3097 not ((GameMode = cMovie) and (MovieSpeed = 4)) then
3098 begin
3099 Assert(NewPlayer = Me);
3100 if not Idle or (GameMode = cMovie) then
3101 Application.ProcessMessages;
3102 if Command = cShowCityChanged then
3103 begin
3104 CurrentMoveInfo.DoShow := False;
3105 if Idle then
3106 CurrentMoveInfo.DoShow := True
3107 else if CurrentMoveInfo.IsAlly then
3108 CurrentMoveInfo.DoShow := not mAlNoMoves.Checked
3109 else
3110 CurrentMoveInfo.DoShow := not mEnNoMoves.Checked;
3111 end
3112 else if Command = cShowUnitChanged then
3113 begin
3114 CurrentMoveInfo.DoShow := False;
3115 if Idle then
3116 CurrentMoveInfo.DoShow := not mEffectiveMovesOnly.Checked
3117 else if CurrentMoveInfo.IsAlly then
3118 CurrentMoveInfo.DoShow :=
3119 not (mAlNoMoves.Checked or mAlEffectiveMovesOnly.Checked)
3120 else
3121 CurrentMoveInfo.DoShow :=
3122 not (mEnNoMoves.Checked or mEnAttacks.Checked);
3123 end;
3124 // else keep DoShow from cShowMove/cShowAttack
3125
3126 if CurrentMoveInfo.DoShow then
3127 begin
3128 if Command = cShowCityChanged then
3129 MapValid := False;
3130 FocusOnLoc(Integer(Data), flImmUpdate);
3131 // OldUnFocus:=UnFocus;
3132 // UnFocus:=-1;
3133 if Command = cShowAfterMove then
3134 PaintLoc(Integer(Data), CurrentMoveInfo.AfterMovePaintRadius)
3135 // show discovered areas
3136 else
3137 PaintLoc(Integer(Data), 1);
3138 // UnFocus:=OldUnFocus;
3139 if (Command = cShowAfterAttack) and
3140 (CurrentMoveInfo.AfterAttackExpeller >= 0) then
3141 begin
3142 SoundMessageEx(Tribe[CurrentMoveInfo.AfterAttackExpeller]
3143 .TPhrase('EXPEL'), '');
3144 CurrentMoveInfo.AfterAttackExpeller := -1;
3145 Update; // remove message box from screen
3146 end
3147 else if not Idle then
3148 if Command = cShowCityChanged then
3149 Sleep(MoveTime * WaitAfterShowMove div 16)
3150 else if (Command = cShowUnitChanged) and
3151 (MyMap[Integer(Data)] and fUnit <> 0) then
3152 Sleep(MoveTime * WaitAfterShowMove div 32)
3153 end // if CurrentMoveInfo.DoShow
3154 else
3155 MapValid := False;
3156 end;
3157
3158 cShowMoving, cShowCapturing:
3159 if (Idle and (NewPlayer = Me) or not Idle and not skipped and
3160 (TShowMove(Data).emix <> $FFFF)) and
3161 not ((GameMode = cMovie) and (MovieSpeed = 4)) then
3162 begin
3163 Assert(NewPlayer = Me);
3164 if not Idle or (GameMode = cMovie) then
3165 Application.ProcessMessages;
3166 with TShowMove(Data) do
3167 begin
3168 CurrentMoveInfo.DoShow := False;
3169 if not Idle and (not Assigned(Tribe[Owner].ModelPicture[mix].HGr)) then
3170 InitEnemyModel(emix);
3171
3172 ToLoc := dLoc(FromLoc, dx, dy);
3173 if Idle then
3174 begin // own unit -- make discovered land visible
3175 Assert(Owner = Me); // no foreign moves during my turn!
3176 CurrentMoveInfo.DoShow := not mEffectiveMovesOnly.Checked or
3177 (Command = cShowCapturing);
3178 if CurrentMoveInfo.DoShow then
3179 begin
3180 if GameMode = cMovie then
3181 begin
3182 if MovieSpeed = 3 then
3183 AnimationSpeed := 4
3184 else if MovieSpeed = 2 then
3185 AnimationSpeed := 8
3186 else
3187 AnimationSpeed := 16;
3188 end
3189 else
3190 begin
3191 if mVeryFastMoves.Checked then
3192 AnimationSpeed := 4
3193 else if mFastMoves.Checked then
3194 AnimationSpeed := 8
3195 else
3196 AnimationSpeed := 16;
3197 end;
3198 with MyModel[mix] do
3199 begin
3200 if (Kind = mkDiplomat) or (Domain = dAir) or
3201 (Cap[mcRadar] + Cap[mcCarrier] + Cap[mcAcademy] > 0) or
3202 (MyMap[ToLoc] and fTerrain = fMountains) or
3203 (MyMap[ToLoc] and fTerImp = tiFort) or
3204 (MyMap[ToLoc] and fTerImp = tiBase) then
3205 CurrentMoveInfo.AfterMovePaintRadius := 2
3206 else
3207 CurrentMoveInfo.AfterMovePaintRadius := 1;
3208 if (MyRO.Wonder[woShinkansen].EffectiveOwner = Me) and
3209 (Domain = dGround) and
3210 (MyMap[FromLoc] and (fRR or fCity) <> 0) and
3211 (MyMap[ToLoc] and (fRR or fCity) <> 0) and
3212 (Flags and umPlaneUnloading = 0) then
3213 AnimationSpeed := 4;
3214 ShowMoveDomain := Domain;
3215 IsAlpine := Cap[mcAlpine] > 0;
3216 end;
3217 end;
3218 end
3219 else
3220 begin
3221 CurrentMoveInfo.IsAlly := MyRO.Treaty[Owner] = trAlliance;
3222 if GameMode = cMovie then
3223 CurrentMoveInfo.DoShow := True
3224 else if CurrentMoveInfo.IsAlly then
3225 CurrentMoveInfo.DoShow := not mAlNoMoves.Checked and
3226 not (mAlEffectiveMovesOnly.Checked and
3227 (Command <> cShowCapturing))
3228 else
3229 CurrentMoveInfo.DoShow := not mEnNoMoves.Checked and
3230 not (mEnAttacks.Checked and (Command <> cShowCapturing));
3231 if CurrentMoveInfo.DoShow then
3232 begin
3233 if Command = cShowCapturing then
3234 begin // show capture message
3235 if MyMap[ToLoc] and fOwned <> 0 then
3236 begin // own city, search
3237 cix := MyRO.nCity - 1;
3238 while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
3239 Dec(cix);
3240 S := CityName(MyCity[cix].ID);
3241 end
3242 else
3243 begin // foreign city, search
3244 ecix := MyRO.nEnemyCity - 1;
3245 while (ecix >= 0) and (MyRO.EnemyCity[ecix].Loc <> ToLoc) do
3246 Dec(ecix);
3247 S := CityName(MyRO.EnemyCity[ecix].ID);
3248 end;
3249 TribeMessage(Owner, Format(Tribe[Owner].TPhrase('CAPTURE'),
3250 [S]), '');
3251 Update; // remove message box from screen
3252 end;
3253
3254 if CurrentMoveInfo.IsAlly then
3255 begin // allied unit -- make discovered land visible
3256 if mAlFastMoves.Checked then
3257 AnimationSpeed := 8
3258 else
3259 AnimationSpeed := 16;
3260 with MyRO.EnemyModel[emix] do
3261 if (Kind = mkDiplomat) or (Domain = dAir) or (ATrans_Fuel > 0)
3262 or (Cap and (1 shl (mcRadar - mcFirstNonCap) or
3263 1 shl (mcAcademy - mcFirstNonCap)) <> 0) or
3264 (MyMap[ToLoc] and fTerrain = fMountains) or
3265 (MyMap[ToLoc] and fTerImp = tiFort) or
3266 (MyMap[ToLoc] and fTerImp = tiBase) then
3267 CurrentMoveInfo.AfterMovePaintRadius := 2
3268 else
3269 CurrentMoveInfo.AfterMovePaintRadius := 1;
3270 end
3271 else
3272 begin
3273 if mEnFastMoves.Checked then
3274 AnimationSpeed := 8
3275 else
3276 AnimationSpeed := 16;
3277 CurrentMoveInfo.AfterMovePaintRadius := 0;
3278 // enemy unit, nothing discovered
3279 end;
3280 if GameMode = cMovie then
3281 begin
3282 if MovieSpeed = 3 then
3283 AnimationSpeed := 4
3284 else if MovieSpeed = 2 then
3285 AnimationSpeed := 8
3286 else
3287 AnimationSpeed := 16;
3288 end;
3289 ShowMoveDomain := MyRO.EnemyModel[emix].Domain;
3290 IsAlpine := MyRO.EnemyModel[emix].Cap and
3291 (1 shl (mcAlpine - mcFirstNonCap)) <> 0;
3292 end
3293 end;
3294
3295 if CurrentMoveInfo.DoShow then
3296 begin
3297 if Command = cShowCapturing then
3298 Play('MOVE_CAPTURE')
3299 else if EndHealth <= 0 then
3300 Play('MOVE_DIE')
3301 else if Flags and umSpyMission <> 0 then
3302 Play('MOVE_COVERT')
3303 else if Flags and umShipLoading <> 0 then
3304 if ShowMoveDomain = dAir then
3305 Play('MOVE_PLANELANDING')
3306 else
3307 Play('MOVE_LOAD')
3308 else if Flags and umPlaneLoading <> 0 then
3309 Play('MOVE_LOAD')
3310 else if Flags and umShipUnloading <> 0 then
3311 if ShowMoveDomain = dAir then
3312 Play('MOVE_PLANESTART')
3313 else
3314 Play('MOVE_UNLOAD')
3315 else if Flags and umPlaneUnloading <> 0 then
3316 if (MyMap[FromLoc] and fCity = 0) and
3317 (MyMap[FromLoc] and fTerImp <> tiBase) then
3318 Play('MOVE_PARACHUTE')
3319 else
3320 Play('MOVE_UNLOAD')
3321 else if (ShowMoveDomain = dGround) and not IsAlpine and
3322 (MyMap[ToLoc] and fTerrain = fMountains) and
3323 ((MyMap[FromLoc] and (fRoad or fRR or fCity) = 0) or
3324 (MyMap[ToLoc] and (fRoad or fRR or fCity) = 0)) then
3325 Play('MOVE_MOUNTAIN');
3326
3327 FocusOnLoc(FromLoc, flImmUpdate);
3328 PaintLoc_BeforeMove(FromLoc);
3329 if Command = cShowCapturing then
3330 MoveOnScreen(TShowMove(Data), 1, 32, 32)
3331 else
3332 MoveOnScreen(TShowMove(Data), 1, AnimationSpeed, AnimationSpeed)
3333 end // if CurrentMoveInfo.DoShow
3334 else
3335 MapValid := False;
3336 end;
3337 end;
3338
3339 cShowAttacking:
3340 if (Idle and (NewPlayer = Me) or not Idle and not skipped and
3341 (TShowMove(Data).emix <> $FFFF)) and
3342 not ((GameMode = cMovie) and (MovieSpeed = 4)) then
3343 begin
3344 Assert(NewPlayer = Me);
3345 if not Idle or (GameMode = cMovie) then
3346 Application.ProcessMessages;
3347 with TShowMove(Data) do
3348 begin
3349 CurrentMoveInfo.AfterAttackExpeller := -1;
3350 CurrentMoveInfo.DoShow := False;
3351 if Idle then
3352 CurrentMoveInfo.DoShow := True // own unit -- always show attacks
3353 else
3354 begin
3355 CurrentMoveInfo.IsAlly := MyRO.Treaty[Owner] = trAlliance;
3356 if CurrentMoveInfo.IsAlly then
3357 CurrentMoveInfo.DoShow := not mAlNoMoves.Checked
3358 else
3359 CurrentMoveInfo.DoShow := not mEnNoMoves.Checked;
3360 end;
3361 if CurrentMoveInfo.DoShow then
3362 begin
3363 ToLoc := dLoc(FromLoc, dx, dy);
3364 if not Assigned(Tribe[Owner].ModelPicture[mix].HGr) then
3365 InitEnemyModel(emix);
3366
3367 if (MyMap[ToLoc] and (fCity or fUnit or fOwned) = fCity or fOwned)
3368 then
3369 begin // tell about bombardment
3370 cix := MyRO.nCity - 1;
3371 while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
3372 Dec(cix);
3373 if MyCity[cix].Status and csToldBombard = 0 then
3374 begin
3375 if not Supervising then
3376 MyCity[cix].Status := MyCity[cix].Status or csToldBombard;
3377 S := CityName(MyCity[cix].ID);
3378 SoundMessageEx(Format(Tribe[Owner].TPhrase('BOMBARD'),
3379 [S]), '');
3380 Update; // remove message box from screen
3381 end;
3382 end
3383 else if Flags and umExpelling <> 0 then
3384 CurrentMoveInfo.AfterAttackExpeller := Owner;
3385
3386 if Flags and umExpelling <> 0 then
3387 Play('MOVE_EXPEL')
3388 else if Owner = Me then
3389 begin
3390 MakeModelInfo(Me, mix, MyModel[mix], mi);
3391 Play(AttackSound(ModelCode(mi)));
3392 end
3393 else
3394 Play(AttackSound(ModelCode(MyRO.EnemyModel[emix])));
3395
3396 FocusOnLoc(FromLoc, flImmUpdate);
3397
3398 // before combat
3399 MainMap.AttackBegin(TShowMove(Data));
3400 if MyMap[ToLoc] and fCity <> 0 then
3401 PaintLoc(ToLoc);
3402 PaintLoc(FromLoc);
3403 MoveOnScreen(TShowMove(Data), 1, 9, 16);
3404 MoveOnScreen(TShowMove(Data), 17, 12, 32);
3405 MoveOnScreen(TShowMove(Data), 7, 11, 16);
3406
3407 // after combat
3408 MainMap.AttackEffect(TShowMove(Data));
3409 PaintLoc(ToLoc);
3410 if EndHealth > 0 then
3411 begin
3412 Health := EndHealth;
3413 MoveOnScreen(TShowMove(Data), 10, 0, 16);
3414 end
3415 else if not Idle then
3416 Sleep(MoveTime div 2);
3417 MainMap.AttackEnd;
3418 end // if CurrentMoveInfo.DoShow
3419 else
3420 MapValid := False;
3421 end;
3422 end;
3423
3424 cShowMissionResult:
3425 if Cardinal(Data) = 0 then
3426 SoundMessageEx(Phrases.Lookup('NOFOREIGNINFO'), '')
3427 else
3428 begin
3429 S := Phrases.Lookup('FOREIGNINFO');
3430 for p1 := 0 to nPl - 1 do
3431 if 3 shl (p1 * 2) and Cardinal(Data) <> 0 then
3432 S := S + '\' + Tribe[p1].TPhrase('SHORTNAME');
3433 SoundMessageEx(S, '');
3434 end;
3435
3436 cShowShipChange:
3437 if not IsMultiPlayerGame and (Jump[0] = 0) then
3438 ShowEnemyShipChange(TShowShipChange(Data));
3439
3440 cShowGreatLibTech:
3441 if not IsMultiPlayerGame and (Jump[0] = 0) then
3442 with MessgExDlg do
3443 begin
3444 MessgText := Format(Phrases.Lookup('GRLIB_GENERAL'),
3445 [Phrases.Lookup('ADVANCES', Integer(Data))]);
3446 OpenSound := 'NEWADVANCE_GRLIB';
3447 Kind := mkOk;
3448 IconKind := mikImp;
3449 IconIndex := woGrLibrary;
3450 ShowModal;
3451 end;
3452
3453 cRefreshDebugMap:
3454 begin
3455 if Integer(Data) = MainMap.pDebugMap then
3456 begin
3457 MapValid := False;
3458 MainOffscreenPaint;
3459 Update;
3460 end;
3461 end;
3462
3463 else
3464 if Command >= cClientEx then
3465 case Command and (not Integer(CommandDataElementCountMask)) of
3466 cSetTribe:
3467 with TTribeInfo(Data) do begin
3468 I := UnusedTribeFiles.Count - 1;
3469 while (I >= 0) and
3470 (AnsiCompareFileName(UnusedTribeFiles[I], FileName) <> 0) do
3471 Dec(I);
3472 if I >= 0 then
3473 UnusedTribeFiles.Delete(I);
3474 CreateTribe(trix, FileName, True);
3475 end;
3476 cSetNewModelPicture:
3477 if TribeOriginal[TModelPictureInfo(Data).trix] then
3478 Tribe[TModelPictureInfo(Data).trix].SetModelPicture
3479 (TModelPictureInfo(Data), True);
3480 cSetModelPicture:
3481 if TribeOriginal[TModelPictureInfo(Data).trix] then
3482 Tribe[TModelPictureInfo(Data).trix].SetModelPicture
3483 (TModelPictureInfo(Data), False);
3484 cSetSlaveIndex:
3485 Tribe[Integer(Data) shr 16].mixSlaves := Integer(Data) and $FFFF;
3486 cSetCityName:
3487 with TCityNameInfo(Data) do
3488 if TribeOriginal[ID shr 12] then
3489 Tribe[ID shr 12].SetCityName(ID and $FFF, NewName);
3490 cSetModelName:
3491 with TModelNameInfo(Data) do
3492 if TribeOriginal[NewPlayer] then
3493 Tribe[NewPlayer].ModelName[mix] := NewName;
3494 end;
3495 end;
3496end;
3497
3498{ *** main part *** }
3499
3500procedure TMainScreen.FormCreate(Sender: TObject);
3501var
3502 I, J: Integer;
3503begin
3504 NoMap := TIsoMap.Create;
3505 MainMap := TIsoMap.Create;
3506 NoMapPanel := TIsoMap.Create;
3507
3508 UpdateKeyShortcuts;
3509
3510 MainFormKeyDown := FormKeyDown;
3511 BaseWin.CreateOffscreen(Offscreen, Width, Height);
3512
3513 // define which menu settings to save
3514 SetLength(SaveOption, 22);
3515 SaveOption[0] := mAlEffectiveMovesOnly.Tag;
3516 SaveOption[1] := mEnMoves.Tag;
3517 SaveOption[2] := mEnAttacks.Tag;
3518 SaveOption[3] := mEnNoMoves.Tag;
3519 SaveOption[4] := mWaitTurn.Tag;
3520 SaveOption[5] := mEffectiveMovesOnly.Tag;
3521 SaveOption[6] := mEnFastMoves.Tag;
3522 SaveOption[7] := mSlowMoves.Tag;
3523 SaveOption[8] := mFastMoves.Tag;
3524 SaveOption[9] := mVeryFastMoves.Tag;
3525 SaveOption[10] := mNames.Tag;
3526 SaveOption[11] := mRepList.Tag;
3527 SaveOption[12] := mRepScreens.Tag;
3528 SaveOption[13] := mSoundOff.Tag;
3529 SaveOption[14] := mSoundOn.Tag;
3530 SaveOption[15] := mSoundOnAlt.Tag;
3531 SaveOption[16] := mScrollSlow.Tag;
3532 SaveOption[17] := mScrollFast.Tag;
3533 SaveOption[18] := mScrollOff.Tag;
3534 SaveOption[19] := mAlSlowMoves.Tag;
3535 SaveOption[20] := mAlFastMoves.Tag;
3536 SaveOption[21] := mAlNoMoves.Tag;
3537
3538 LoadSettings;
3539
3540 Screen.Cursors[crImpDrag] := LoadCursor(HInstance, 'DRAG');
3541 Screen.Cursors[crFlatHand] := LoadCursor(HInstance, 'FLATHAND');
3542
3543 // tag-controlled language
3544 for I := 0 to ComponentCount - 1 do
3545 if Components[I].Tag and $FF <> 0 then
3546 if Components[I] is TMenuItem then begin
3547 TMenuItem(Components[I]).Caption := Phrases.Lookup('CONTROLS',
3548 -1 + Components[I].Tag and $FF);
3549 for J := 0 to Length(SaveOption) - 1 do
3550 if Components[I].Tag and $FF = SaveOption[J] then
3551 TMenuItem(Components[I]).Checked := TSaveOption(J) in OptionChecked;
3552 end else
3553 if Components[I] is TButtonBase then begin
3554 TButtonBase(Components[I]).Hint := Phrases.Lookup('CONTROLS',
3555 -1 + Components[I].Tag and $FF);
3556 if (Components[I] is TButtonC) and
3557 (TButtonC(Components[I]).ButtonIndex <> 1) then
3558 TButtonC(Components[I]).ButtonIndex :=
3559 Integer(MapOptionChecked) shr (Components[I].Tag shr 8) and 1 + 2;
3560 end;
3561
3562 // non-tag-controlled language
3563 mTechTree.Caption := Phrases2.Lookup('MENU_ADVTREE');
3564 mViewpoint.Caption := Phrases2.Lookup('MENU_VIEWPOINT');
3565 if not Phrases2FallenBackToEnglish then
3566 begin
3567 MenuArea.Hint := Phrases2.Lookup('BTN_MENU');
3568 TreasuryArea.Hint := Phrases2.Lookup('TIP_TREASURY');
3569 ResearchArea.Hint := Phrases.Lookup('SCIENCE');
3570 ManagementArea.Hint := Phrases2.Lookup('BTN_MANAGE');
3571 end;
3572 for I := 0 to mRep.Count - 1 do
3573 begin
3574 J := mRep[I].Tag shr 8;
3575 mRep[I].Caption := CityEventName(J);
3576 mRep[I].Checked := CityRepMask and (1 shl J) <> 0;
3577 end;
3578
3579 MiniMap := TMiniMap.Create;
3580 Panel := TBitmap.Create;
3581 Panel.PixelFormat := TPixelFormat.pf24bit;
3582 Panel.Canvas.Font.Assign(UniFont[ftSmall]);
3583 Panel.Canvas.Brush.Style := TBrushStyle.bsClear;
3584 TopBar := TBitmap.Create;
3585 TopBar.PixelFormat := TPixelFormat.pf24bit;
3586 TopBar.Canvas.Font.Assign(UniFont[ftNormal]);
3587 TopBar.Canvas.Brush.Style := TBrushStyle.bsClear;
3588 Buffer := TBitmap.Create;
3589 Buffer.PixelFormat := TPixelFormat.pf24bit;
3590 if 2 * lxmax > 3 * xSizeBig then Buffer.Width := 2 * lxmax
3591 else Buffer.Width := 3 * xSizeBig;
3592 if lymax > 3 * ySizeBig then Buffer.Height := lymax
3593 else Buffer.Height := 3 * ySizeBig;
3594 Buffer.Canvas.Font.Assign(UniFont[ftSmall]);
3595 for I := 0 to nPl - 1 do
3596 AILogo[I] := nil;
3597 Canvas.Font.Assign(UniFont[ftSmall]);
3598 InitButtons;
3599 EOT.Template := Templates.Data;
3600end;
3601
3602procedure TMainScreen.FormDestroy(Sender: TObject);
3603var
3604 I: Integer;
3605begin
3606 if Assigned(FWondersDlg) then FreeAndNil(FWondersDlg);
3607 if Assigned(FTechTreeDlg) then FreeAndNil(FTechTreeDlg);
3608 if Assigned(FEnhanceDlg) then FreeAndNil(FEnhanceDlg);
3609 if Assigned(FNegoDlg) then FreeAndNil(FNegoDlg);
3610 if Assigned(FCityTypeDlg) then FreeAndNil(FCityTypeDlg);
3611 if Assigned(FDiaDlg) then FreeAndNil(FDiaDlg);
3612 if Assigned(FCityDlg) then FreeAndNil(FCityDlg);
3613 if Assigned(FRatesDlg) then FreeAndNil(FRatesDlg);
3614 if Assigned(FBattleDlg) then FreeAndNil(FBattleDlg);
3615 if Assigned(FNatStatDlg) then FreeAndNil(FNatStatDlg);
3616 if Assigned(FUnitStatDlg) then FreeAndNil(FUnitStatDlg);
3617 if Assigned(FDraftDlg) then FreeAndNil(FDraftDlg);
3618 if Assigned(FModalSelectDlg) then FreeAndNil(FModalSelectDlg);
3619 if Assigned(FListDlg) then FreeAndNil(FListDlg);
3620 if Assigned(FMessgExDlg) then FreeAndNil(FMessgExDlg);
3621 if Assigned(FHelpDlg) then FreeAndNil(FHelpDlg);
3622
3623 MainFormKeyDown := nil;
3624 FreeAndNil(VerticalScrollBar);
3625 FreeAndNil(TopBar);
3626 FreeAndNil(MiniMap);
3627 FreeAndNil(Buffer);
3628 FreeAndNil(Panel);
3629 for I := 0 to nPl - 1 do
3630 if AILogo[I] <> nil then
3631 FreeAndNil(AILogo[I]);
3632 FreeAndNil(Offscreen);
3633 FreeAndNil(MainMap);
3634 FreeAndNil(NoMap);
3635 FreeAndNil(NoMapPanel);
3636end;
3637
3638procedure TMainScreen.FormMouseWheel(Sender: TObject; Shift: TShiftState;
3639 WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
3640var
3641 MouseLoc: Integer;
3642begin
3643 if (MousePos.Y > ClientHeight - MidPanelHeight) and
3644 (MousePos.Y < ClientHeight) then begin
3645 if VerticalScrollBar.ProcessMouseWheel(WheelDelta) then begin
3646 PanelPaint;
3647 Update;
3648 end;
3649 end else begin
3650 if (WheelDelta > 0) and (MainMap.TileSize < High(TTileSize)) then begin
3651 MouseLoc := LocationOfScreenPixel(MousePos.X, MousePos.Y);
3652 SetTileSize(Succ(MainMap.TileSize), MouseLoc, Point(MousePos.X, MousePos.Y));
3653 end
3654 else if (WheelDelta < 0) and (MainMap.TileSize > Low(TTileSize)) then begin
3655 MouseLoc := LocationOfScreenPixel(MousePos.X, MousePos.Y);
3656 SetTileSize(Pred(MainMap.TileSize), MouseLoc, Point(MousePos.X, MousePos.Y));
3657 end;
3658 end;
3659end;
3660
3661procedure TMainScreen.mAfforestClick(Sender: TObject);
3662begin
3663 if UnFocus >= 0 then
3664 with TUn(MyUn[UnFocus]) do
3665 DoJob(jAfforest);
3666end;
3667
3668procedure TMainScreen.mAirBaseClick(Sender: TObject);
3669begin
3670 if UnFocus >= 0 then
3671 with TUn(MyUn[UnFocus]) do
3672 DoJob(jBase);
3673end;
3674
3675procedure TMainScreen.mCanalClick(Sender: TObject);
3676begin
3677 if UnFocus >= 0 then
3678 with TUn(MyUn[UnFocus]) do
3679 DoJob(jCanal);
3680end;
3681
3682procedure TMainScreen.mCancelClick(Sender: TObject);
3683begin
3684 if UnFocus >= 0 then
3685 with MyUn[UnFocus] do begin
3686 DestinationMarkON := False;
3687 PaintDestination;
3688 Status := Status and ($FFFF - usRecover - usGoto - usEnhance);
3689 if Job > jNone then
3690 Server(sStartJob + jNone shl 4, Me, UnFocus, nil^);
3691 end;
3692end;
3693
3694procedure TMainScreen.mCentreClick(Sender: TObject);
3695begin
3696 if UnFocus >= 0 then
3697 with TUn(MyUn[UnFocus]) do begin
3698 Centre(Loc);
3699 PaintAllMaps;
3700 end;
3701end;
3702
3703procedure TMainScreen.mcityClick(Sender: TObject);
3704var
3705 Loc0: Integer;
3706 cix: Integer;
3707 ServerResult: Integer;
3708begin
3709 if UnFocus >= 0 then
3710 with TUn(MyUn[UnFocus]) do begin
3711 Loc0 := Loc;
3712 if MyMap[Loc] and fCity = 0 then
3713 begin // build city
3714 if DoJob(jCity) = eCity then
3715 begin
3716 MapValid := False;
3717 PaintAll;
3718 ZoomToCity(Loc0, True, chFounded);
3719 end;
3720 end else begin
3721 CityOptimizer_BeforeRemoveUnit(UnFocus);
3722 ServerResult := Server(sAddToCity, Me, UnFocus, nil^);
3723 if ServerResult >= rExecuted then
3724 begin
3725 cix := MyRO.nCity - 1;
3726 while (cix >= 0) and (MyCity[cix].Loc <> Loc0) do
3727 Dec(cix);
3728 Assert(cix >= 0);
3729 CityOptimizer_CityChange(cix);
3730 CityOptimizer_AfterRemoveUnit; // does nothing here
3731 SetTroopLoc(Loc0);
3732 UpdateViews(True);
3733 DestinationMarkON := False;
3734 PaintDestination;
3735 UnFocus := -1;
3736 PaintLoc(Loc0);
3737 NextUnit(UnStartLoc, True);
3738 end
3739 else if ServerResult = eMaxSize then
3740 SimpleMessage(Phrases.Lookup('ADDTOMAXSIZE'));
3741 end;
3742 end;
3743end;
3744
3745procedure TMainScreen.mCityStatClick(Sender: TObject);
3746begin
3747 ListDlg.ShowNewContent(wmPersistent, kCities);
3748end;
3749
3750procedure TMainScreen.mCityTypesClick(Sender: TObject);
3751begin
3752 CityTypeDlg.ShowNewContent(wmModal);
3753 // must be modal because types are not saved before closing
3754end;
3755
3756procedure TMainScreen.mClearClick(Sender: TObject);
3757begin
3758 if UnFocus >= 0 then
3759 with TUn(MyUn[UnFocus]) do
3760 DoJob(jClear);
3761end;
3762
3763procedure TMainScreen.mDiagramClick(Sender: TObject);
3764begin
3765 DiaDlg.ShowNewContent_Charts(wmPersistent);
3766end;
3767
3768procedure TMainScreen.mEmpireClick(Sender: TObject);
3769begin
3770 RatesDlg.ShowNewContent(wmPersistent);
3771end;
3772
3773procedure TMainScreen.mFillMapClick(Sender: TObject);
3774var
3775 FillMapData: TFillMapData;
3776begin
3777 if not Edited or (SimpleQuery(mkYesNo, Phrases.Lookup('MAP_FILL'), '')
3778 = mrOK) then begin
3779 FillMapData.Tile := BrushType;
3780 Server(sFillMap, Me, 0, FillMapData);
3781 Edited := True;
3782 MapValid := False;
3783 PaintAllMaps;
3784 end;
3785end;
3786
3787procedure TMainScreen.mEnhanceClick(Sender: TObject);
3788begin
3789 if UnFocus >= 0 then
3790 with TUn(MyUn[UnFocus]) do
3791 DoJob(-1);
3792end;
3793
3794procedure TMainScreen.mEnhanceDefClick(Sender: TObject);
3795begin
3796 if UnFocus >= 0 then
3797 EnhanceDlg.ShowNewContent(wmPersistent,
3798 MyMap[MyUn[UnFocus].Loc] and fTerrain)
3799 else
3800 EnhanceDlg.ShowNewContent(wmPersistent);
3801end;
3802
3803procedure TMainScreen.mEUnitStatClick(Sender: TObject);
3804begin
3805 if MyRO.nEnemyModel > 0 then
3806 ListDlg.ShowNewContent(wmPersistent, kAllEModels);
3807end;
3808
3809procedure TMainScreen.mFarmClick(Sender: TObject);
3810begin
3811 if UnFocus >= 0 then
3812 with TUn(MyUn[UnFocus]) do
3813 DoJob(jFarm);
3814end;
3815
3816procedure TMainScreen.mfortClick(Sender: TObject);
3817begin
3818 if UnFocus >= 0 then
3819 with TUn(MyUn[UnFocus]) do
3820 DoJob(jFort);
3821end;
3822
3823procedure TMainScreen.mGoOnClick(Sender: TObject);
3824var
3825 Destination: Integer;
3826begin
3827 if UnFocus >= 0 then
3828 with TUn(MyUn[UnFocus]) do begin
3829 if Status shr 16 = $7FFF then
3830 Destination := maNextCity
3831 else
3832 Destination := Status shr 16;
3833 Status := Status and not (usStay or usRecover) or usWaiting;
3834 MoveToLoc(Destination, True);
3835 end;
3836end;
3837
3838procedure TMainScreen.mHelpClick(Sender: TObject);
3839begin
3840 if ClientMode = cEditMap then
3841 HelpDlg.ShowNewContent(wmPersistent, hkText, HelpDlg.TextIndex('MAPEDIT'))
3842 else
3843 HelpDlg.ShowNewContent(wmPersistent, hkMisc, Integer(miscMain));
3844end;
3845
3846procedure TMainScreen.mhomeClick(Sender: TObject);
3847var
3848 cixOldHome: Integer;
3849begin
3850 if UnFocus >= 0 then
3851 with TUn(MyUn[UnFocus]) do begin
3852 if MyMap[Loc] and fCity <> 0 then
3853 begin
3854 cixOldHome := Home;
3855 if Server(sSetUnitHome, Me, UnFocus, nil^) >= rExecuted then
3856 begin
3857 CityOptimizer_CityChange(cixOldHome);
3858 CityOptimizer_CityChange(Home);
3859 UpdateViews(True);
3860 end
3861 else
3862 Play('INVALID');
3863 end
3864 else
3865 begin
3866 Status := Status and not (usStay or usRecover or usEnhance);
3867 MoveToLoc(maNextCity, True);
3868 end;
3869 end;
3870end;
3871
3872procedure TMainScreen.mirrigationClick(Sender: TObject);
3873begin
3874 if UnFocus >= 0 then
3875 with TUn(MyUn[UnFocus]) do
3876 DoJob(jIrr);
3877end;
3878
3879procedure TMainScreen.mirrigationDrawItem(Sender: TObject; ACanvas: TCanvas;
3880 ARect: TRect; AState: TOwnerDrawState);
3881begin
3882
3883end;
3884
3885procedure TMainScreen.mJumpClick(Sender: TObject);
3886begin
3887 if Supervising then
3888 Jump[0] := 20
3889 else
3890 Jump[Me] := 20;
3891 EndTurn(True);
3892end;
3893
3894procedure TMainScreen.mLoadClick(Sender: TObject);
3895var
3896 I: Integer;
3897begin
3898 if UnFocus >= 0 then
3899 with MyUn[UnFocus] do begin
3900 I := Server(sLoadUnit, Me, UnFocus, nil^);
3901 if I >= rExecuted then
3902 begin
3903 if MyModel[mix].Domain = dAir then
3904 Play('MOVE_PLANELANDING')
3905 else
3906 Play('MOVE_LOAD');
3907 DestinationMarkON := False;
3908 PaintDestination;
3909 Status := Status and ($FFFF - usWaiting - usStay - usRecover - usGoto - usEnhance);
3910 NextUnit(UnStartLoc, True);
3911 end
3912 else if I = eNoTime_Load then
3913 if MyModel[mix].Domain = dAir then
3914 SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
3915 else
3916 SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
3917 [MovementToString(MyModel[mix].speed)]), 'NOMOVE_TIME');
3918 end;
3919end;
3920
3921procedure TMainScreen.mmineClick(Sender: TObject);
3922begin
3923 if UnFocus >= 0 then
3924 with TUn(MyUn[UnFocus]) do
3925 DoJob(jMine);
3926end;
3927
3928procedure TMainScreen.mNationsClick(Sender: TObject);
3929begin
3930 NatStatDlg.ShowNewContent(wmPersistent);
3931end;
3932
3933procedure TMainScreen.mNextUnitClick(Sender: TObject);
3934begin
3935 if UnFocus >= 0 then
3936 with MyUn[UnFocus] do begin
3937 Status := Status and not usWaiting;
3938 FocusNextUnit(1);
3939 end;
3940end;
3941
3942procedure TMainScreen.mnoordersClick(Sender: TObject);
3943begin
3944 if UnFocus >= 0 then
3945 with MyUn[UnFocus] do begin
3946 Status := Status and not usWaiting;
3947 NextUnit(UnStartLoc, True);
3948 end;
3949end;
3950
3951procedure TMainScreen.mPillageClick(Sender: TObject);
3952begin
3953 DoJob(jPillage);
3954end;
3955
3956procedure TMainScreen.mpollutionClick(Sender: TObject);
3957begin
3958 if UnFocus >= 0 then
3959 with TUn(MyUn[UnFocus]) do
3960 DoJob(jPoll);
3961end;
3962
3963procedure TMainScreen.mPrevUnitClick(Sender: TObject);
3964begin
3965 if UnFocus >= 0 then
3966 with MyUn[UnFocus] do begin
3967 Status := Status and not usWaiting;
3968 FocusNextUnit(-1);
3969 end;
3970end;
3971
3972procedure TMainScreen.mRandomMapClick(Sender: TObject);
3973begin
3974 if not Edited or (SimpleQuery(mkYesNo, Phrases.Lookup('MAP_RANDOM'), '')
3975 = mrOK) then begin
3976 Server(sRandomMap, Me, 0, nil^);
3977 Edited := True;
3978 MapValid := False;
3979 PaintAllMaps;
3980 end;
3981end;
3982
3983procedure TMainScreen.mRecoverClick(Sender: TObject);
3984begin
3985 if UnFocus >= 0 then
3986 with MyUn[UnFocus] do begin
3987 DestinationMarkON := False;
3988 PaintDestination;
3989 Status := Status and ($FFFF - usStay - usGoto - usEnhance) or usRecover;
3990 if Job > jNone then
3991 Server(sStartJob + jNone shl 4, Me, UnFocus, nil^);
3992 NextUnit(UnStartLoc, True);
3993 end;
3994end;
3995
3996procedure TMainScreen.mResignClick(Sender: TObject);
3997var
3998 QueryText: string;
3999begin
4000 if ClientMode = cEditMap then begin
4001 if Edited then begin
4002 QueryText := Phrases.Lookup('MAP_CLOSE');
4003 case SimpleQuery(mkYesNoCancel, QueryText, '') of
4004 mrIgnore: Server(sAbandonMap, Me, 0, nil^);
4005 mrOK: Server(sSaveMap, Me, 0, nil^);
4006 end;
4007 end else
4008 Server(sAbandonMap, Me, 0, nil^);
4009 end else begin
4010 if Server(sGetGameChanged, 0, 0, nil^) = eOK then begin
4011 QueryText := Phrases.Lookup('RESIGN');
4012 case SimpleQuery(mkYesNoCancel, QueryText, '') of
4013 mrIgnore: Server(sResign, 0, 0, nil^);
4014 mrOK: Server(sBreak, 0, 0, nil^);
4015 end;
4016 end else
4017 Server(sResign, 0, 0, nil^);
4018 end;
4019end;
4020
4021procedure TMainScreen.mRevolutionClick(Sender: TObject);
4022var
4023 AltGovs: Boolean;
4024 RevolutionChanged: Boolean;
4025 I: Integer;
4026begin
4027 AltGovs := False;
4028 for I := 2 to nGov - 1 do
4029 if (GovPreq[I] <> preNA) and
4030 ((GovPreq[I] = preNone) or (MyRO.Tech[GovPreq[I]] >= tsApplicable)) then begin
4031 AltGovs := True;
4032 Break;
4033 end;
4034
4035 if not AltGovs then
4036 SoundMessage(Phrases.Lookup('NOALTGOVS'), 'MSG_DEFAULT')
4037 else
4038 begin
4039 RevolutionChanged := False;
4040 if MyRO.Happened and phChangeGov <> 0 then
4041 begin
4042 ModalSelectDlg.ShowNewContent(wmModal, kGov);
4043 if ModalSelectDlg.Result >= 0 then
4044 begin
4045 Play('NEWGOV');
4046 Server(sSetGovernment, Me, ModalSelectDlg.Result, nil^);
4047 CityOptimizer_BeginOfTurn;
4048 RevolutionChanged := True;
4049 end;
4050 end
4051 else
4052 with MessgExDlg do
4053 begin // revolution!
4054 MessgExDlg.MessgText := Tribe[Me].TPhrase('REVOLUTION');
4055 MessgExDlg.Kind := mkYesNo;
4056 MessgExDlg.IconKind := mikPureIcon;
4057 MessgExDlg.IconIndex := 72; // anarchy palace
4058 MessgExDlg.ShowModal;
4059 if ModalResult = mrOK then
4060 begin
4061 Play('REVOLUTION');
4062 Server(sRevolution, Me, 0, nil^);
4063 RevolutionChanged := True;
4064 if NatStatDlg.Visible then
4065 NatStatDlg.Close;
4066 if CityDlg.Visible then
4067 CityDlg.Close;
4068 end
4069 end;
4070 if RevolutionChanged then
4071 UpdateViews(True);
4072 end;
4073end;
4074
4075procedure TMainScreen.mroadClick(Sender: TObject);
4076begin
4077 if UnFocus >= 0 then
4078 with TUn(MyUn[UnFocus]) do
4079 DoJob(jRoad);
4080end;
4081
4082procedure TMainScreen.mRailRoadClick(Sender: TObject);
4083begin
4084 if UnFocus >= 0 then
4085 with TUn(MyUn[UnFocus]) do
4086 DoJob(jRR);
4087end;
4088
4089procedure TMainScreen.mRunClick(Sender: TObject);
4090begin
4091 if Supervising then
4092 Jump[0] := 999999
4093 else
4094 Jump[Me] := 999999;
4095 EndTurn(True);
4096end;
4097
4098procedure TMainScreen.mScienceStatClick(Sender: TObject);
4099begin
4100 ListDlg.ShowNewContent(wmPersistent, kScience);
4101end;
4102
4103procedure TMainScreen.mSelectTransportClick(Sender: TObject);
4104begin
4105 if UnFocus >= 0 then
4106 with TUn(MyUn[UnFocus]) do
4107 Server(sSelectTransport, Me, UnFocus, nil^);
4108end;
4109
4110procedure TMainScreen.mShipsClick(Sender: TObject);
4111begin
4112 DiaDlg.ShowNewContent_Ship(wmPersistent);
4113end;
4114
4115procedure TMainScreen.mstayClick(Sender: TObject);
4116begin
4117 if UnFocus >= 0 then
4118 with TUn(MyUn[UnFocus]) do begin
4119 DestinationMarkON := False;
4120 PaintDestination;
4121 Status := Status and ($FFFF - usRecover - usGoto - usEnhance) or usStay;
4122 if Job > jNone then
4123 Server(sStartJob + jNone shl 4, Me, UnFocus, nil^);
4124 NextUnit(UnStartLoc, True);
4125 end;
4126end;
4127
4128procedure TMainScreen.mTechTreeClick(Sender: TObject);
4129begin
4130 TechTreeDlg.ShowModal;
4131end;
4132
4133procedure TMainScreen.mtransClick(Sender: TObject);
4134begin
4135 if UnFocus >= 0 then
4136 with TUn(MyUn[UnFocus]) do
4137 DoJob(jTrans);
4138end;
4139
4140procedure TMainScreen.mUnitStatClick(Sender: TObject);
4141var
4142 I: Integer;
4143begin
4144 if G.Difficulty[Me] > 0 then
4145 ListDlg.ShowNewContent_MilReport(wmPersistent, Me)
4146 else
4147 begin
4148 I := 1;
4149 while (I < nPl) and (1 shl I and MyRO.Alive = 0) do
4150 Inc(I);
4151 if I < nPl then
4152 ListDlg.ShowNewContent_MilReport(wmPersistent, I);
4153 end;
4154end;
4155
4156procedure TMainScreen.mUnloadClick(Sender: TObject);
4157var
4158 I: Integer;
4159 OldMaster: Integer;
4160 NewFocus: Integer;
4161 uix: Integer;
4162begin
4163 if UnFocus >= 0 then
4164 with MyUn[UnFocus] do begin
4165 if Master >= 0 then begin
4166 OldMaster := Master;
4167 I := Server(sUnloadUnit, Me, UnFocus, nil^);
4168 if I >= rExecuted then
4169 begin
4170 if MyModel[mix].Domain = dAir then
4171 Play('MOVE_PLANESTART')
4172 else if (MyModel[MyUn[OldMaster].mix].Domain = dAir) and
4173 (MyMap[Loc] and fCity = 0) and (MyMap[Loc] and fTerImp <> tiBase)
4174 then
4175 Play('MOVE_PARACHUTE')
4176 else
4177 Play('MOVE_UNLOAD');
4178 Status := Status and not usWaiting;
4179 if MyModel[mix].Domain <> dAir then
4180 NextUnit(Loc, True)
4181 else
4182 PanelPaint;
4183 end
4184 else if I = eNoTime_Load then
4185 if MyModel[mix].Domain = dAir then
4186 SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
4187 else
4188 SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
4189 [MovementToString(MyModel[mix].speed)]), 'NOMOVE_TIME');
4190 end else begin
4191 NewFocus := -1;
4192 uix := UnFocus;
4193 for I := 1 to MyRO.nUn - 1 do
4194 begin
4195 uix := (uix + MyRO.nUn - 1) mod MyRO.nUn;
4196 if (MyUn[uix].Master = UnFocus) and
4197 (MyUn[uix].Movement = Integer(MyModel[MyUn[uix].mix].speed)) then
4198 begin
4199 MyUn[uix].Status := MyUn[uix].Status or usWaiting;
4200 NewFocus := uix;
4201 end;
4202 end;
4203 if NewFocus >= 0 then
4204 begin
4205 SetUnFocus(NewFocus);
4206 SetTroopLoc(Loc);
4207 PanelPaint;
4208 end;
4209 end;
4210 end;
4211end;
4212
4213procedure TMainScreen.mwaitClick(Sender: TObject);
4214begin
4215 if UnFocus >= 0 then
4216 with MyUn[UnFocus] do begin
4217 DestinationMarkON := False;
4218 PaintDestination;
4219 Status := Status and ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
4220 end;
4221 NextUnit(-1, False);
4222end;
4223
4224procedure TMainScreen.mWebsiteClick(Sender: TObject);
4225begin
4226 OpenURL(CevoHomepage);
4227end;
4228
4229procedure TMainScreen.mWondersClick(Sender: TObject);
4230begin
4231 WondersDlg.ShowNewContent(wmPersistent);
4232end;
4233
4234procedure TMainScreen.FormResize(Sender: TObject);
4235begin
4236 if (LastResizeWidth = Width) and (LastResizeHeight = Height) and
4237 (LastWindowState = WindowState) then Exit
4238 else begin
4239 LastResizeWidth := Width;
4240 LastResizeHeight := Height;
4241 LastWindowState := WindowState;
4242 end;
4243
4244 ResizeControls;
4245end;
4246
4247procedure TMainScreen.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
4248begin
4249 CanClose := Closable;
4250 if not Closable and Idle and (Me = 0) and (ClientMode < scContact) then
4251 mResign.Click;
4252end;
4253
4254procedure TMainScreen.OnScroll(var Msg: TMessage);
4255begin
4256 if VerticalScrollBar.Process(Msg) then begin
4257 PanelPaint;
4258 Update;
4259 end;
4260end;
4261
4262procedure TMainScreen.OnEOT(var Msg: TMessage);
4263begin
4264 EndTurn;
4265end;
4266
4267procedure TMainScreen.EOTClick(Sender: TObject);
4268begin
4269 if GameMode = cMovie then
4270 begin
4271 MessgExDlg.CancelMovie;
4272 Server(sBreak, Me, 0, nil^);
4273 end
4274 else if ClientMode < 0 then
4275 Skipped := True
4276 else if ClientMode >= scContact then
4277 NegoDlg.ShowNewContent(wmPersistent)
4278 else if Jump[pTurn] > 0 then
4279 begin
4280 Jump[pTurn] := 0;
4281 StartRunning := False;
4282 end
4283 else
4284 EndTurn;
4285end;
4286
4287// set xTerrain, xTroop, and TrRow
4288procedure TMainScreen.ArrangeMidPanel;
4289begin
4290 if ClientMode = cEditMap then
4291 xTroop := xMidPanel + 15
4292 else
4293 with MainMap do begin
4294 if Supervising then
4295 xTerrain := xMidPanel + 2 * xxt + 14
4296 else if ClientWidth < 1280 then
4297 xTerrain := ClientWidth div 2 + (1280 - ClientWidth) div 3
4298 else
4299 xTerrain := ClientWidth div 2;
4300 xTroop := xTerrain + 2 * xxt + 12;
4301 if SmallScreen and not Supervising then
4302 xTroop := xRightPanel + 10 - 3 * 66 -
4303 GetSystemMetrics(SM_CXVSCROLL) - 19 - 4;
4304 // not perfect but we assume almost no one is still playing on a 800x600 screen
4305 end;
4306 TrRow := (xRightPanel + 10 - xTroop - GetSystemMetrics(SM_CXVSCROLL) - 19)
4307 div TrPitch;
4308end;
4309
4310function TMainScreen.EndTurn(WasSkipped: Boolean): Boolean;
4311
4312 function IsResourceUnused(cix, NeedFood, NeedProd: Integer): Boolean;
4313 var
4314 dx, dy, fix: Integer;
4315 CityAreaInfo: TCityAreaInfo;
4316 TileInfo: TTileInfo;
4317 begin
4318 Server(sGetCityAreaInfo, Me, cix, CityAreaInfo);
4319 for dy := -3 to 3 do
4320 for dx := -3 to 3 do
4321 if ((dx + dy) and 1 = 0) and (dx * dx * dy * dy < 81) then
4322 begin
4323 fix := (dy + 3) shl 2 + (dx + 3) shr 1;
4324 if (MyCity[cix].Tiles and (1 shl fix) = 0) // not used yet
4325 and (CityAreaInfo.Available[fix] = faAvailable) then // usable
4326 begin
4327 TileInfo.ExplCity := cix;
4328 Server(sGetHypoCityTileInfo, Me, dLoc(MyCity[cix].Loc, dx, dy),
4329 TileInfo);
4330 if (TileInfo.Food >= NeedFood) and (TileInfo.Prod >= NeedProd) then
4331 begin
4332 Result := True;
4333 Exit;
4334 end;
4335 end
4336 end;
4337 Result := False;
4338 end;
4339
4340var
4341 p1, uix, cix, CenterLoc: Integer;
4342 MsgItem: string;
4343 CityReport: TCityReport;
4344 PlaneReturnData: TPlaneReturnData;
4345 Zoom: Boolean;
4346begin
4347 Result := False;
4348 if ClientMode >= scDipOffer then
4349 Exit;
4350
4351 if Supervising and (Me <> 0) then begin
4352 ApplyToVisibleForms(faClose);
4353 ItsMeAgain(0);
4354 end;
4355
4356 CityOptimizer_EndOfTurn;
4357
4358 if not WasSkipped then // check warnings
4359 begin
4360 // need to move planes home?
4361 for uix := 0 to MyRO.nUn - 1 do
4362 with MyUn[uix] do
4363 if (Loc >= 0) and (MyModel[mix].Domain = dAir) and
4364 (Status and usToldNoReturn = 0) and (Master < 0) and
4365 (MyMap[Loc] and fCity = 0) and (MyMap[Loc] and fTerImp <> tiBase) then
4366 begin
4367 PlaneReturnData.Fuel := Fuel;
4368 PlaneReturnData.Loc := Loc;
4369 PlaneReturnData.Movement := 0; // end turn without further movement?
4370 if Server(sGetPlaneReturn, Me, uix, PlaneReturnData) = eNoWay then
4371 begin
4372 CenterLoc := Loc + G.lx * 6;
4373 // centering the unit itself would make it covered by the query dialog
4374 while CenterLoc >= G.lx * G.ly do
4375 Dec(CenterLoc, G.lx * 2);
4376 Centre(CenterLoc);
4377 SetTroopLoc(-1);
4378 PaintAll;
4379
4380 if MyModel[mix].Kind = mkSpecial_Glider then
4381 MsgItem := 'LOWFUEL_GLIDER'
4382 else
4383 MsgItem := 'LOWFUEL';
4384 if SimpleQuery(mkYesNo, Phrases.Lookup(MsgItem),
4385 'WARNING_LOWSUPPORT') <> mrOK then
4386 begin
4387 SetUnFocus(uix);
4388 SetTroopLoc(Loc);
4389 PanelPaint;
4390 Exit;
4391 end;
4392 MyUn[uix].Status := MyUn[uix].Status or usToldNoReturn;
4393 end;
4394 end;
4395
4396 if not Supervising and (MyRO.TestFlags and tfImmImprove = 0) and
4397 (MyRO.Government <> gAnarchy) and (MyRO.Money + TaxSum < 0) and
4398 (MyRO.TaxRate < 100) then // low funds!
4399 with MessgExDlg do
4400 begin
4401 OpenSound := 'WARNING_LOWFUNDS';
4402 MessgText := Phrases.Lookup('LOWFUNDS');
4403 Kind := mkYesNo;
4404 IconKind := mikImp;
4405 IconIndex := imTrGoods;
4406 ShowModal;
4407 if ModalResult <> mrOK then
4408 Exit;
4409 end;
4410
4411 if MyRO.Government <> gAnarchy then
4412 for cix := 0 to MyRO.nCity - 1 do
4413 with MyCity[cix] do
4414 if (Loc >= 0) and (Flags and chCaptured = 0) then
4415 begin
4416 Zoom := False;
4417 CityReport.HypoTiles := -1;
4418 CityReport.HypoTax := -1;
4419 CityReport.HypoLux := -1;
4420 Server(sGetCityReport, Me, cix, CityReport);
4421
4422 if (CityReport.Working - CityReport.Happy > Size shr 1) and
4423 (Flags and chCaptured <= $10000) then
4424 with MessgExDlg do
4425 begin
4426 OpenSound := 'WARNING_DISORDER';
4427 if Status and csResourceWeightsMask = 0 then
4428 MsgItem := 'DISORDER'
4429 else
4430 MsgItem := 'DISORDER_UNREST';
4431 MessgText := Format(Phrases.Lookup(MsgItem), [CityName(ID)]);
4432 Kind := mkYesNo;
4433 // BigIcon := 29;
4434 ShowModal;
4435 Zoom := ModalResult <> mrOK;
4436 end;
4437 if not Zoom and (Food + CityReport.FoodRep - CityReport.Eaten < 0)
4438 then
4439 with MessgExDlg do
4440 begin
4441 OpenSound := 'WARNING_FAMINE';
4442 if Status and csResourceWeightsMask = 0 then
4443 MsgItem := 'FAMINE'
4444 else if (CityReport.Deployed <> 0) and
4445 IsResourceUnused(cix, 1, 0) then
4446 MsgItem := 'FAMINE_UNREST'
4447 else
4448 MsgItem := 'FAMINE_TILES';
4449 MessgText := Format(Phrases.Lookup(MsgItem), [CityName(ID)]);
4450 Kind := mkYesNo;
4451 IconKind := mikImp;
4452 IconIndex := 22;
4453 ShowModal;
4454 Zoom := ModalResult <> mrOK;
4455 end;
4456 if not Zoom and (CityReport.ProdRep < CityReport.Support) then
4457 with MessgExDlg do
4458 begin
4459 OpenSound := 'WARNING_LOWSUPPORT';
4460 if Status and csResourceWeightsMask = 0 then
4461 MsgItem := 'LOWSUPPORT'
4462 else if (CityReport.Deployed <> 0) and
4463 IsResourceUnused(cix, 0, 1) then
4464 MsgItem := 'LOWSUPPORT_UNREST'
4465 else
4466 MsgItem := 'LOWSUPPORT_TILES';
4467 MessgText := Format(Phrases.Lookup(MsgItem), [CityName(ID)]);
4468 Kind := mkYesNo;
4469 IconKind := mikImp;
4470 IconIndex := 29;
4471 ShowModal;
4472 Zoom := ModalResult <> mrOK;
4473 end;
4474 if Zoom then
4475 begin // zoom to city
4476 ZoomToCity(Loc);
4477 Exit;
4478 end;
4479 end;
4480
4481 if (MyRO.Happened and phTech <> 0) and (MyRO.ResearchTech < 0) and
4482 (MyData.FarTech <> adNexus) then
4483 if not ChooseResearch then
4484 Exit;
4485 end;
4486
4487 RememberPeaceViolation;
4488
4489 SetUnFocus(-1);
4490 for uix := 0 to MyRO.nUn - 1 do
4491 MyUn[uix].Status := MyUn[uix].Status and usPersistent;
4492
4493 CityDlg.CloseAction := None;
4494 if IsMultiPlayerGame then begin
4495 // Close windows for next player
4496 ApplyToVisibleForms(faClose);
4497 end else begin
4498 if CityDlg.Visible then
4499 CityDlg.Close;
4500 if UnitStatDlg.Visible then
4501 UnitStatDlg.Close;
4502 end;
4503 ApplyToVisibleForms(faDisable);
4504
4505 if Server(sTurn, pTurn, 0, nil^) >= rExecuted then
4506 begin
4507 if Jump[pTurn] > 0 then
4508 EOT.Hint := Phrases.Lookup('BTN_STOP')
4509 else
4510 EOT.Hint := Phrases.Lookup('BTN_SKIP');
4511 Result := True;
4512 SetTroopLoc(-1);
4513 pTurn := -1;
4514 pLogo := -1;
4515 UnitInfoBtn.Visible := False;
4516 UnitBtn.Visible := False;
4517 TerrainBtn.Visible := False;
4518 EOT.ButtonIndex := eotCancel;
4519 EOT.Visible := True;
4520 MapValid := False;
4521 PanelPaint;
4522 Update;
4523 ClientMode := -1;
4524 Idle := False;
4525 Skipped := WasSkipped;
4526 for p1 := 1 to nPl - 1 do
4527 if G.RO[p1] <> nil then begin
4528 Skipped := True; // don't show enemy moves in hotseat mode
4529 Break;
4530 end;
4531 end
4532 else
4533 PanelPaint;
4534end;
4535
4536procedure TMainScreen.EndNego;
4537begin
4538 if NegoDlg.Visible then
4539 NegoDlg.Close;
4540 HaveStrategyAdvice := False;
4541 EOT.ButtonIndex := eotCancel;
4542 EOT.Visible := True;
4543 PanelPaint;
4544 Update;
4545 ClientMode := -1;
4546 Idle := False;
4547end;
4548
4549procedure TMainScreen.ProcessRect(x0, y0, nx, ny, Options: Integer);
4550var
4551 xs, ys, xl, yl: Integer;
4552begin
4553 with MainMap do begin
4554 xl := nx * xxt + xxt;
4555 yl := ny * yyt + yyt * 2;
4556 xs := (x0 - xw) * (xxt * 2) + y0 and 1 * xxt - G.lx * (xxt * 2);
4557 // |xs+xl/2-MapWidth/2| -> min
4558 while Abs(2 * (xs + G.lx * (xxt * 2)) + xl - MapWidth) <
4559 Abs(2 * xs + xl - MapWidth) do
4560 Inc(xs, G.lx * (xxt * 2));
4561 ys := (y0 - yw) * yyt - yyt;
4562 if xs + xl > MapWidth then
4563 xl := MapWidth - xs;
4564 if ys + yl > MapHeight then
4565 yl := MapHeight - ys;
4566 if (xl <= 0) or (yl <= 0) then
4567 Exit;
4568 if Options and prPaint <> 0 then begin
4569 if Options and prAutoBounds <> 0 then
4570 MainMap.SetPaintBounds(xs, ys, xs + xl, ys + yl);
4571 MainMap.Paint(xs, ys, x0 + G.lx * y0, nx, ny, -1, -1);
4572 end;
4573 if Options and prInvalidate <> 0 then
4574 RectInvalidate(MapOffset + xs, TopBarHeight + ys, MapOffset + xs + xl,
4575 TopBarHeight + ys + yl)
4576 end;
4577end;
4578
4579procedure TMainScreen.PaintLoc(Loc: Integer; Radius: Integer = 0);
4580var
4581 yLoc, x0: Integer;
4582begin
4583 if MapValid then begin
4584 yLoc := (Loc + G.lx * 1024) div G.lx - 1024;
4585 x0 := (Loc + (yLoc and 1 - 2 * Radius + G.lx * 1024) div 2) mod G.lx;
4586 Offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
4587 ProcessRect(x0, yLoc - 2 * Radius, 4 * Radius + 1, 4 * Radius + 1,
4588 prPaint or prAutoBounds or prInvalidate);
4589 Update;
4590 end;
4591end;
4592
4593procedure TMainScreen.PaintLocTemp(Loc: Integer; Style: TPaintLocTempStyle);
4594var
4595 y0, x0, xMap, yMap: Integer;
4596begin
4597 with NoMap do begin
4598 if not MapValid then
4599 Exit;
4600 Buffer.Canvas.Font.Assign(UniFont[ftSmall]);
4601 y0 := Loc div G.lx;
4602 x0 := Loc mod G.lx;
4603 xMap := (x0 - xw) * (xxt * 2) + y0 and 1 * xxt - G.lx * (xxt * 2);
4604 // |xMap+xxt-MapWidth/2| -> min
4605 while Abs(2 * (xMap + G.lx * (xxt * 2)) + 2 * xxt - MapWidth) <
4606 Abs(2 * xMap + 2 * xxt - MapWidth) do
4607 Inc(xMap, G.lx * (xxt * 2));
4608 yMap := (y0 - yw) * yyt - yyt;
4609 NoMap.SetOutput(Buffer);
4610 NoMap.SetPaintBounds(0, 0, 2 * xxt, 3 * yyt);
4611 NoMap.Paint(0, 0, Loc, 1, 1, -1, -1, Style = pltsBlink);
4612 PaintBufferToScreen(xMap, yMap, 2 * xxt, 3 * yyt);
4613 end;
4614end;
4615
4616// paint content of buffer directly to screen instead of offscreen
4617// panel protusions are added
4618// NoMap must be set to buffer and bounds before
4619procedure TMainScreen.PaintBufferToScreen(xMap, yMap, Width, Height: Integer);
4620begin
4621 if xMap + Width > MapWidth then
4622 Width := MapWidth - xMap;
4623 if yMap + Height > MapHeight then
4624 Height := MapHeight - yMap;
4625 if (Width <= 0) or (Height <= 0) or (Width + xMap <= 0) or (Height + yMap <= 0)
4626 then
4627 Exit;
4628
4629 NoMap.BitBltBitmapOutput(Panel, -xMap - MapOffset, -yMap + MapHeight - Overlap, xMidPanel,
4630 Overlap, 0, 0);
4631 NoMap.BitBltBitmapOutput(Panel, -xMap - MapOffset + xRightPanel,
4632 -yMap + MapHeight - Overlap, Panel.Width - xRightPanel, Overlap,
4633 xRightPanel, 0);
4634 if yMap < 0 then
4635 begin
4636 if xMap < 0 then
4637 BitBltCanvas(Canvas, MapOffset, TopBarHeight, Width + xMap,
4638 Height + yMap, Buffer.Canvas, -xMap, -yMap)
4639 else
4640 BitBltCanvas(Canvas, xMap + MapOffset, TopBarHeight, Width,
4641 Height + yMap, Buffer.Canvas, 0, -yMap);
4642 end
4643 else
4644 begin
4645 if xMap < 0 then
4646 BitBltCanvas(Canvas, MapOffset, TopBarHeight + yMap, Width + xMap,
4647 Height, Buffer.Canvas, -xMap, 0)
4648 else
4649 BitBltCanvas(Canvas, xMap + MapOffset, TopBarHeight + yMap, Width,
4650 Height, Buffer.Canvas, 0, 0);
4651 end;
4652end;
4653
4654procedure TMainScreen.PaintLoc_BeforeMove(FromLoc: Integer);
4655var
4656 yLoc, x0: Integer;
4657begin
4658 if MapValid then
4659 begin
4660 yLoc := (FromLoc + G.lx * 1024) div G.lx - 1024;
4661 x0 := (FromLoc + (yLoc and 1 + G.lx * 1024) div 2) mod G.lx;
4662 Offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
4663 ProcessRect(x0, yLoc, 1, 1, prPaint or prAutoBounds);
4664 end
4665end;
4666
4667procedure TMainScreen.PaintDestination;
4668var
4669 Destination: Integer;
4670begin
4671 if (UnFocus >= 0) and (MyUn[UnFocus].Status and usGoto <> 0) then
4672 begin
4673 Destination := MyUn[UnFocus].Status shr 16;
4674 if (Destination <> $7FFF) and (Destination <> MyUn[UnFocus].Loc) then
4675 PaintLocTemp(Destination, pltsBlink);
4676 end;
4677end;
4678
4679{$IFDEF UNIX}
4680// Can't do scrolling of DC under Linux, then fallback into BitBlt.
4681function ScrollDC(Canvas: TCanvas; dx: longint; dy: longint; const lprcScroll:TRect; const lprcClip:TRect; hrgnUpdate:HRGN; lprcUpdate: PRect):Boolean;
4682begin
4683 Result := BitBltCanvas(Canvas, lprcScroll.Left + dx, lprcScroll.Top + dy, lprcScroll.Right - lprcScroll.Left, lprcScroll.Bottom - lprcScroll.Top,
4684 Canvas, lprcScroll.Left, lprcScroll.Top);
4685end;
4686{$ENDIF}
4687
4688procedure TMainScreen.MainOffscreenPaint;
4689var
4690 ProcessOptions: Integer;
4691 Rec: TRect;
4692 DoInvalidate: Boolean;
4693begin
4694 if Me < 0 then
4695 with Offscreen.Canvas do
4696 begin
4697 Brush.Color := $000000;
4698 FillRect(Rect(0, 0, MapWidth, MapHeight));
4699 Brush.Style := TBrushStyle.bsClear;
4700 OffscreenUser := Self;
4701 Exit;
4702 end;
4703
4704 MainMap.SetPaintBounds(0, 0, MapWidth, MapHeight);
4705 if OffscreenUser <> Self then
4706 begin
4707 if OffscreenUser <> nil then
4708 OffscreenUser.Update;
4709 // complete working with old owner to prevent rebound
4710 if MapValid and (xwd = xw) and (ywd = yw) then
4711 MainMap.SetPaintBounds(0, 0, UsedOffscreenWidth, UsedOffscreenHeight);
4712 MapValid := False;
4713 OffscreenUser := Self;
4714 end;
4715
4716 with MainMap do begin
4717 if xw - xwd > G.lx div 2 then
4718 xwd := xwd + G.lx
4719 else if xwd - xw > G.lx div 2 then
4720 xwd := xwd - G.lx;
4721 if not MapValid or (xw - xwd > MapWidth div (xxt * 2)) or
4722 (xwd - xw > MapWidth div (xxt * 2)) or (yw - ywd > MapHeight div yyt) or
4723 (ywd - yw > MapHeight div yyt) then
4724 begin
4725 Offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
4726 ProcessRect(xw, yw, MapWidth div xxt, MapHeight div yyt,
4727 prPaint or prInvalidate);
4728 end else begin
4729 if (xwd = xw) and (ywd = yw) then
4730 Exit; { map window not moved }
4731 Offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
4732 Rec := Rect(0, 0, MapWidth, MapHeight);
4733{$IFDEF WINDOWS}
4734 ScrollDC(Offscreen.Canvas.Handle, (xwd - xw) * (xxt * 2), (ywd - yw) * yyt,
4735 rec, rec, 0, nil);
4736{$ENDIF}
4737{$IFDEF UNIX}
4738 ScrollDC(Offscreen.Canvas, (xwd - xw) * (xxt * 2), (ywd - yw) * yyt,
4739 Rec, Rec, 0, nil);
4740{$ENDIF}
4741 for DoInvalidate := False to FastScrolling do begin
4742 if DoInvalidate then begin
4743 Rec.Bottom := MapHeight - Overlap;
4744{$IFDEF WINDOWS}
4745 ScrollDC(Canvas.Handle, (xwd - xw) * (xxt * 2), (ywd - yw) * yyt, rec,
4746 rec, 0, nil);
4747{$ENDIF}
4748{$IFDEF UNIX}
4749 ScrollDC(Canvas, (xwd - xw) * (xxt * 2), (ywd - yw) * yyt,
4750 Rec, Rec, 0, nil);
4751{$ENDIF}
4752 ProcessOptions := prInvalidate;
4753 end
4754 else ProcessOptions := prPaint or prAutoBounds;
4755 if yw < ywd then begin
4756 ProcessRect(xw, yw, MapWidth div xxt, ywd - yw - 1, ProcessOptions);
4757 if xw < xwd then
4758 ProcessRect(xw, ywd, (xwd - xw) * 2 - 1, MapHeight div yyt - ywd + yw,
4759 ProcessOptions)
4760 else if xw > xwd then
4761 ProcessRect((xwd + MapWidth div (xxt * 2)) mod G.lx, ywd,
4762 (xw - xwd) * 2 + 1, MapHeight div yyt - ywd + yw, ProcessOptions);
4763 end
4764 else if yw > ywd then begin
4765 if DoInvalidate then
4766 RectInvalidate(MapOffset, TopBarHeight + MapHeight - Overlap -
4767 (yw - ywd) * yyt, MapOffset + MapWidth, TopBarHeight + MapHeight
4768 - Overlap)
4769 else
4770 ProcessRect(xw, (ywd + MapHeight div (yyt * 2) * 2), MapWidth div xxt,
4771 yw - ywd + 1, ProcessOptions);
4772 if xw < xwd then
4773 ProcessRect(xw, yw, (xwd - xw) * 2 - 1, MapHeight div yyt - yw + ywd -
4774 2, ProcessOptions)
4775 else if xw > xwd then
4776 ProcessRect((xwd + MapWidth div (xxt * 2)) mod G.lx, yw,
4777 (xw - xwd) * 2 + 1, MapHeight div yyt - yw + ywd - 2,
4778 ProcessOptions);
4779 end
4780 else if xw < xwd then
4781 ProcessRect(xw, yw, (xwd - xw) * 2 - 1, MapHeight div yyt,
4782 ProcessOptions)
4783 else if xw > xwd then
4784 ProcessRect((xwd + MapWidth div (xxt * 2)) mod G.lx, yw,
4785 (xw - xwd) * 2 + 1, MapHeight div yyt, ProcessOptions);
4786 end;
4787 if not FastScrolling then
4788 RectInvalidate(MapOffset, TopBarHeight, MapOffset + MapWidth,
4789 TopBarHeight + MapHeight - Overlap);
4790 RectInvalidate(xMidPanel, TopBarHeight + MapHeight - Overlap, xRightPanel,
4791 TopBarHeight + MapHeight);
4792 end;
4793 end;
4794 // if (xwd<>xw) or (ywd<>yw) then
4795 // Server(sChangeSuperView,me,yw*G.lx+xw,nil^); // for synchronizing client side viewer, not used currently
4796 xwd := xw;
4797 ywd := yw;
4798 MapValid := True;
4799end;
4800
4801procedure TMainScreen.MiniMapPaint;
4802begin
4803 with MainMap do
4804 MiniMap.Paint(MyMap, MapWidth, ClientMode, xxt, xwMini);
4805end;
4806
4807procedure TMainScreen.PaintAll;
4808begin
4809 MainOffscreenPaint;
4810 xwMini := xw;
4811 ywMini := yw;
4812 MiniMapPaint;
4813 PanelPaint;
4814end;
4815
4816procedure TMainScreen.RepaintAll;
4817begin
4818 RectInvalidate(0, TopBarHeight, Width, TopBarHeight + MapHeight);
4819 MapValid := False;
4820 PaintAll;
4821end;
4822
4823procedure TMainScreen.PaintAllMaps;
4824begin
4825 MainOffscreenPaint;
4826 xwMini := xw;
4827 ywMini := yw;
4828 MiniMapPaint;
4829 CopyMiniToPanel;
4830 RectInvalidate(xMini + 2, TopBarHeight + MapHeight - Overlap + yMini + 2,
4831 xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - Overlap + yMini +
4832 2 + G.ly);
4833end;
4834
4835procedure TMainScreen.CopyMiniToPanel;
4836begin
4837 with MainMap do begin
4838 BitBltBitmap(Panel, xMini + 2, yMini + 2, G.lx * 2, G.ly,
4839 MiniMap.Bitmap, 0, 0);
4840 if MarkCityLoc >= 0 then
4841 Sprite(Panel, HGrSystem, xMini - 2 + (4 * G.lx + 2 * (MarkCityLoc mod G.lx)
4842 + (G.lx - MapWidth div (xxt * 2)) - 2 * xwd) mod (2 * G.lx) +
4843 MarkCityLoc div G.lx and 1, yMini - 3 + MarkCityLoc div G.lx, CityMark2.Width,
4844 CityMark2.Height, CityMark2.Left, CityMark2.Top)
4845 else if ywmax <= 0 then
4846 Frame(Panel.Canvas,
4847 xMini + 2 + G.lx - MapWidth div (xxt * 2), yMini + 2,
4848 xMini + 1 + G.lx + MapWidth div (xxt * 2), yMini + 2 + G.ly - 1,
4849 MainTexture.ColorMark, MainTexture.ColorMark)
4850 else
4851 Frame(Panel.Canvas,
4852 xMini + 2 + G.lx - MapWidth div (xxt * 2), yMini + 2 + yw,
4853 xMini + 1 + G.lx + MapWidth div (xxt * 2), yMini + yw + MapHeight div yyt,
4854 MainTexture.ColorMark, MainTexture.ColorMark);
4855 end;
4856end;
4857
4858procedure TMainScreen.PanelPaint;
4859
4860 function MovementToString(var Un: TUn): string;
4861 begin
4862 Result := ScreenTools.MovementToString(Un.Movement);
4863 if Un.Master >= 0 then
4864 Result := '(' + Result + ')'
4865 else if (MyModel[Un.mix].Domain = dAir) and
4866 (MyModel[Un.mix].Kind <> mkSpecial_Glider) then
4867 Result := Format('%s(%d)', [Result, Un.Fuel]);
4868 end;
4869
4870var
4871 I, uix, uixDefender, X, CostFactor, Count,
4872 mixShow, xTreasurySection, xResearchSection, JobFocus, TrueMoney,
4873 TrueResearch: Integer;
4874 Src, SrcBase: TPoint;
4875 Tile: Cardinal;
4876 S: string;
4877 unx: TUn;
4878 UnitInfo: TUnitInfo;
4879 JobProgressData: TJobProgressData;
4880 Prio: Boolean;
4881begin
4882 if not Assigned(MyRO) then Exit;
4883 with Panel.Canvas do
4884 begin
4885 Fill(Panel.Canvas, 0, 3, xMidPanel + 7 - 10, PanelHeight - 3,
4886 MainTexture.Width - (xMidPanel + 7 - 10), MainTexture.Height - PanelHeight);
4887 Fill(Panel.Canvas, xRightPanel + 10 - 7, 3, Panel.Width - xRightPanel - 10 +
4888 7, PanelHeight - 3, -(xRightPanel + 10 - 7), MainTexture.Height - PanelHeight);
4889 FillLarge(Panel.Canvas, xMidPanel - 2, PanelHeight - MidPanelHeight,
4890 xRightPanel + 2, PanelHeight, ClientWidth div 2);
4891
4892 Brush.Style := TBrushStyle.bsClear;
4893 Pen.Color := $000000;
4894 MoveTo(0, 0);
4895 LineTo(xMidPanel + 7 - 8, 0);
4896 LineTo(xMidPanel + 7 - 8, PanelHeight - MidPanelHeight);
4897 LineTo(xRightPanel, PanelHeight - MidPanelHeight);
4898 LineTo(xRightPanel, 0);
4899 LineTo(ClientWidth, 0);
4900 Pen.Color := MainTexture.ColorBevelLight;
4901 MoveTo(xMidPanel + 7 - 9, PanelHeight - MidPanelHeight + 2);
4902 LineTo(xRightPanel + 10 - 8, PanelHeight - MidPanelHeight + 2);
4903 Pen.Color := MainTexture.ColorBevelLight;
4904 MoveTo(0, 1);
4905 LineTo(xMidPanel + 7 - 9, 1);
4906 Pen.Color := MainTexture.ColorBevelShade;
4907 LineTo(xMidPanel + 7 - 9, PanelHeight - MidPanelHeight + 1);
4908 Pen.Color := MainTexture.ColorBevelLight;
4909 LineTo(xRightPanel + 10 - 9, PanelHeight - MidPanelHeight + 1);
4910 Pen.Color := MainTexture.ColorBevelLight;
4911 LineTo(xRightPanel + 10 - 9, 1);
4912 LineTo(ClientWidth, 1);
4913 MoveTo(ClientWidth, 2);
4914 LineTo(xRightPanel + 10 - 8, 2);
4915 LineTo(xRightPanel + 10 - 8, PanelHeight);
4916 MoveTo(0, 2);
4917 LineTo(xMidPanel + 7 - 10, 2);
4918 Pen.Color := MainTexture.ColorBevelShade;
4919 LineTo(xMidPanel + 7 - 10, PanelHeight);
4920 Corner(Panel.Canvas, xMidPanel + 7 - 16, 1, 1, MainTexture);
4921 Corner(Panel.Canvas, xRightPanel + 10 - 9, 1, 0, MainTexture);
4922 if ClientMode <> cEditMap then
4923 begin
4924 if Supervising then
4925 begin
4926 ScreenTools.Frame(Panel.Canvas, ClientWidth - xPalace - 1, yPalace - 1,
4927 ClientWidth - xPalace + xSizeBig, yPalace + ySizeBig,
4928 $B0B0B0, $FFFFFF);
4929 RFrame(Panel.Canvas, ClientWidth - xPalace - 2, yPalace - 2,
4930 ClientWidth - xPalace + xSizeBig + 1, yPalace + ySizeBig + 1,
4931 $FFFFFF, $B0B0B0);
4932 BitBltBitmap(Panel, ClientWidth - xPalace, yPalace, xSizeBig,
4933 ySizeBig, HGrSystem2.Data, 70, 123);
4934 end
4935 else if MyRO.NatBuilt[imPalace] > 0 then
4936 ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, imPalace, -1,
4937 GameMode <> cMovie
4938 { (GameMode <> cMovie) and (MyRO.Government <> gAnarchy) } )
4939 else
4940 ImpImage(Panel.Canvas, ClientWidth - xPalace, yPalace, 21, -1,
4941 GameMode <> cMovie
4942 { (GameMode <> cMovie) and (MyRO.Government <> gAnarchy) } );
4943 end;
4944
4945 if GameMode = cMovie then
4946 ScreenTools.Frame(Panel.Canvas, xMini + 1, yMini + 1,
4947 xMini + 2 + G.lx * 2, yMini + 2 + G.ly, $000000, $000000)
4948 else
4949 begin
4950 ScreenTools.Frame(Panel.Canvas, xMini + 1, yMini + 1,
4951 xMini + 2 + G.lx * 2, yMini + 2 + G.ly, $B0B0B0, $FFFFFF);
4952 RFrame(Panel.Canvas, xMini, yMini, xMini + 3 + G.lx * 2, yMini + 3 + G.ly,
4953 $FFFFFF, $B0B0B0);
4954 end;
4955 CopyMiniToPanel;
4956 if ClientMode <> cEditMap then // MapBtn icons
4957 for I := 0 to 5 do
4958 if I <> 3 then
4959 Dump(Panel, HGrSystem, xMini + G.lx - 42 + 16 * I, PanelHeight - 26,
4960 8, 8, 121 + I * 9, 61);
4961
4962 if ClientMode = cEditMap then begin
4963 for I := 0 to TrRow - 1 do
4964 trix[I] := -1;
4965 Count := 0;
4966 for I := 0 to Length(BrushTypes) - 1 do
4967 begin // display terrain types
4968 if (Count >= TrRow * VerticalScrollBar.Position) and (Count < TrRow * (VerticalScrollBar.Position + 1))
4969 then begin
4970 trix[Count - TrRow * VerticalScrollBar.Position] := BrushTypes[I];
4971 X := (Count - TrRow * VerticalScrollBar.Position) * TrPitch;
4972 SrcBase.X := -1;
4973 case BrushTypes[I] of
4974 0..8: Src := Point(BrushTypes[I], 0);
4975 9..30: begin
4976 SrcBase := Point(2, 2);
4977 Src := Point(0, 2 * Integer(BrushTypes[I]) - 15);
4978 end;
4979 fRiver: Src := Point(7, 14);
4980 fRoad: Src := Point(0, 9);
4981 fRR: Src := Point(0, 10);
4982 fCanal: Src := Point(0, 11);
4983 fPoll: Src := Point(6, 12);
4984 fDeadLands, fDeadLands or fCobalt, fDeadLands or fUranium,
4985 fDeadLands or fMercury:
4986 begin
4987 SrcBase := Point(6, 2);
4988 Src := Point(8, 12 + BrushTypes[I] shr 25);
4989 end;
4990 tiIrrigation, tiFarm, tiMine, tiBase:
4991 Src := Point(BrushTypes[I] shr 12 - 1, 12);
4992 tiFort: begin
4993 Src := Point(3, 12);
4994 SrcBase := Point(7, 12);
4995 end;
4996 fPrefStartPos: Src := Point(0, 1);
4997 fStartPos: Src := Point(0, 2);
4998 end;
4999 with MainMap do begin
5000 if SrcBase.X >= 0 then
5001 Sprite(Panel, HGrTerrain, xTroop + 2 + X, yTroop + 9 - yyt, xxt * 2,
5002 yyt * 3, 1 + SrcBase.X * (xxt * 2 + 1),
5003 1 + SrcBase.Y * (yyt * 3 + 1));
5004 Sprite(Panel, HGrTerrain, xTroop + 2 + X, yTroop + 9 - yyt, xxt * 2,
5005 yyt * 3, 1 + Src.X * (xxt * 2 + 1), 1 + Src.Y * (yyt * 3 + 1));
5006 if BrushTypes[I] = BrushType then begin
5007 ScreenTools.Frame(Panel.Canvas, xTroop + 2 + X,
5008 yTroop + 7 - yyt div 2, xTroop + 2 * xxt + X,
5009 yTroop + 2 * yyt + 11, $000000, $000000);
5010 ScreenTools.Frame(Panel.Canvas, xTroop + 1 + X,
5011 yTroop + 6 - yyt div 2, xTroop + 2 * xxt - 1 + X,
5012 yTroop + 2 * yyt + 10, MainTexture.ColorMark, MainTexture.ColorMark);
5013 end;
5014 end;
5015 end;
5016 Inc(Count);
5017 end;
5018 case BrushType of
5019 fDesert, fPrairie, fTundra, fArctic, fSwamp, fHills, fMountains:
5020 S := Phrases.Lookup('TERRAIN', BrushType);
5021 fShore:
5022 S := Format(Phrases.Lookup('TWOTERRAINS'),
5023 [Phrases.Lookup('TERRAIN', fOcean), Phrases.Lookup('TERRAIN',
5024 fShore)]);
5025 fGrass:
5026 S := Format(Phrases.Lookup('TWOTERRAINS'),
5027 [Phrases.Lookup('TERRAIN', fGrass), Phrases.Lookup('TERRAIN',
5028 fGrass + 12)]);
5029 fForest:
5030 S := Format(Phrases.Lookup('TWOTERRAINS'),
5031 [Phrases.Lookup('TERRAIN', fForest), Phrases.Lookup('TERRAIN',
5032 fJungle)]);
5033 fRiver:
5034 S := Phrases.Lookup('RIVER');
5035 fDeadLands, fDeadLands or fCobalt, fDeadLands or fUranium,
5036 fDeadLands or fMercury:
5037 S := Phrases.Lookup('TERRAIN', 3 * 12 + BrushType shr 25);
5038 fPrefStartPos:
5039 S := Phrases.Lookup('MAP_PREFSTART');
5040 fStartPos:
5041 S := Phrases.Lookup('MAP_START');
5042 fPoll:
5043 S := Phrases.Lookup('POLL');
5044 else // terrain improvements
5045 begin
5046 case BrushType of
5047 fRoad: I := 1;
5048 fRR: I := 2;
5049 tiIrrigation: I := 4;
5050 tiFarm: I := 5;
5051 tiMine: I := 7;
5052 fCanal: I := 8;
5053 tiFort: I := 10;
5054 tiBase: I := 12;
5055 end;
5056 S := Phrases.Lookup('JOBRESULT', I);
5057 end;
5058 end;
5059 LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 1,
5060 PanelHeight - 19, S);
5061 end
5062 else if TroopLoc >= 0 then
5063 begin
5064 Brush.Style := TBrushStyle.bsClear;
5065 if UnFocus >= 0 then
5066 with MyUn^[UnFocus] do
5067 with MyModel^[mix] do
5068 if (Me >= 0) and (Me < nPl) then
5069 begin { display info about selected unit }
5070 if Job = jCity then
5071 mixShow := -1 // building site
5072 else
5073 mixShow := mix;
5074 with Tribe[Me].ModelPicture[mixShow] do
5075 begin
5076 Sprite(Panel, HGr, xMidPanel + 7 + 12, yTroop + 1, 64, 48,
5077 pix mod 10 * 65 + 1, pix div 10 * 49 + 1);
5078 if MyUn[UnFocus].Flags and unFortified <> 0 then
5079 Sprite(Panel, HGrStdUnits, xMidPanel + 7 + 12, yTroop + 1,
5080 xxu * 2, yyu * 2, 1 + 6 * (xxu * 2 + 1), 1);
5081 end;
5082
5083 MakeBlue(Panel, xMidPanel + 7 + 12 + 10, yTroop - 13, 44, 12);
5084 S := MovementToString(MyUn[UnFocus]);
5085 RisedTextOut(Panel.Canvas, xMidPanel + 7 + 12 + 32 -
5086 BiColorTextWidth(Panel.Canvas, S) div 2, yTroop - 16, S);
5087
5088 S := IntToStr(Health) + '%';
5089 LightGradient(Panel.Canvas, xMidPanel + 7 + 12 + 7, PanelHeight - 22,
5090 (Health + 1) div 2, (ColorOfHealth(Health) and $FEFEFE shr 2) * 3);
5091 if Health < 100 then
5092 LightGradient(Panel.Canvas, xMidPanel + 7 + 12 + 7 + (Health + 1)
5093 div 2, PanelHeight - 22, 50 - (Health + 1) div 2, $000000);
5094 RisedTextOut(Panel.Canvas, xMidPanel + 7 + 12 + 32 -
5095 BiColorTextWidth(Panel.Canvas, S) div 2, PanelHeight - 23, S);
5096
5097 FrameImage(Panel.Canvas, HGrSystem.Data,
5098 xMidPanel + 7 + xUnitText, yTroop + 15, 12, 14,
5099 121 + Exp div ExpCost * 13, 28);
5100 if Job = jCity then
5101 S := Tribe[Me].ModelName[-1]
5102 else
5103 S := Tribe[Me].ModelName[mix];
5104 if Home >= 0 then
5105 begin
5106 LoweredTextOut(Panel.Canvas, -1, MainTexture,
5107 xMidPanel + 7 + xUnitText + 18, yTroop + 5, S);
5108 LoweredTextOut(Panel.Canvas, -1, MainTexture,
5109 xMidPanel + 7 + xUnitText + 18, yTroop + 21,
5110 '(' + CityName(MyCity[Home].ID) + ')');
5111 end
5112 else
5113 LoweredTextOut(Panel.Canvas, -1, MainTexture,
5114 xMidPanel + 7 + xUnitText + 18, yTroop + 13, S);
5115 end;
5116
5117 if (UnFocus >= 0) and (MyUn[UnFocus].Loc <> TroopLoc) then
5118 begin // divide panel
5119 if SmallScreen and not Supervising then
5120 X := xTroop - 8
5121 else
5122 X := xTroop - 152;
5123 Pen.Color := MainTexture.ColorBevelShade;
5124 MoveTo(X - 1, PanelHeight - MidPanelHeight + 2);
5125 LineTo(X - 1, PanelHeight);
5126 Pen.Color := MainTexture.ColorBevelLight;
5127 MoveTo(X, PanelHeight - MidPanelHeight + 2);
5128 LineTo(X, PanelHeight);
5129 end;
5130
5131 for I := 0 to 23 do
5132 trix[I] := -1;
5133 if MyMap[TroopLoc] and fUnit <> 0 then
5134 begin
5135 if MyMap[TroopLoc] and fOwned <> 0 then
5136 begin
5137 if (TrCnt > 1) or (UnFocus < 0) or (MyUn[UnFocus].Loc <> TroopLoc)
5138 then
5139 begin
5140 LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 10,
5141 PanelHeight - 24, Phrases.Lookup('PRESENT'));
5142 Server(sGetDefender, Me, TroopLoc, uixDefender);
5143 Count := 0;
5144 for Prio := True downto False do
5145 for uix := 0 to MyRO.nUn - 1 do
5146 if (uix = uixDefender) = Prio then
5147 begin // display own units
5148 unx := MyUn[uix];
5149 if unx.Loc = TroopLoc then
5150 begin
5151 if (Count >= TrRow * VerticalScrollBar.Position) and
5152 (Count < TrRow * (VerticalScrollBar.Position + 1)) and
5153 (Me >= 0) and (Me < nPl) then
5154 begin
5155 trix[Count - TrRow * VerticalScrollBar.Position] := uix;
5156 MakeUnitInfo(Me, unx, UnitInfo);
5157 X := (Count - TrRow * VerticalScrollBar.Position) * TrPitch;
5158 if uix = UnFocus then
5159 begin
5160 ScreenTools.Frame(Panel.Canvas, xTroop + 4 + X,
5161 yTroop + 3, xTroop + 64 + X, yTroop + 47,
5162 $000000, $000000);
5163 ScreenTools.Frame(Panel.Canvas, xTroop + 3 + X,
5164 yTroop + 2, xTroop + 63 + X, yTroop + 46,
5165 MainTexture.ColorMark, MainTexture.ColorMark);
5166 end
5167 else if (unx.Master >= 0) and (unx.Master = UnFocus) then
5168 begin
5169 CFrame(Panel.Canvas, xTroop + 4 + X, yTroop + 3,
5170 xTroop + 64 + X, yTroop + 47, 8, $000000);
5171 CFrame(Panel.Canvas, xTroop + 3 + X, yTroop + 2,
5172 xTroop + 63 + X, yTroop + 46, 8, MainTexture.ColorMark);
5173 end;
5174 NoMapPanel.SetOutput(Panel);
5175 NoMapPanel.PaintUnit(xTroop + 2 + X, yTroop + 1, UnitInfo,
5176 unx.Status);
5177 if (ClientMode < scContact) and
5178 ((unx.Job > jNone) or
5179 (unx.Status and (usStay or usRecover or usGoto) <> 0))
5180 then
5181 Sprite(Panel, HGrSystem, xTroop + 2 + 60 - 20 + X,
5182 yTroop + 35, 20, 20, 81, 25);
5183
5184 if not Supervising then
5185 begin
5186 MakeBlue(Panel, xTroop + 2 + 10 + X,
5187 yTroop - 13, 44, 12);
5188 S := MovementToString(unx);
5189 RisedTextOut(Panel.Canvas,
5190 xTroop + X + 34 - BiColorTextWidth(Panel.Canvas, S)
5191 div 2, yTroop - 16, S);
5192 end;
5193 end;
5194 Inc(Count);
5195 end;
5196 end; // for uix:=0 to MyRO.nUn-1
5197 Assert(Count = TrCnt);
5198 end;
5199 end
5200 else
5201 begin
5202 LoweredTextOut(Panel.Canvas, -1, MainTexture, xTroop + 8,
5203 PanelHeight - 24, Phrases.Lookup('PRESENT'));
5204 Server(sGetUnits, Me, TroopLoc, Count);
5205 for I := 0 to Count - 1 do
5206 if (I >= TrRow * VerticalScrollBar.Position) and (I < TrRow * (VerticalScrollBar.Position + 1)) then
5207 begin // display enemy units
5208 trix[I - TrRow * VerticalScrollBar.Position] := I;
5209 X := (I - TrRow * VerticalScrollBar.Position) * TrPitch;
5210 NoMapPanel.SetOutput(Panel);
5211 NoMapPanel.PaintUnit(xTroop + 2 + X, yTroop + 1,
5212 MyRO.EnemyUn[MyRO.nEnemyUn + I], 0);
5213 end;
5214 end;
5215 end;
5216 if not SmallScreen or Supervising then
5217 begin // show terrain and improvements
5218 with NoMapPanel do
5219 PaintZoomedTile(Panel, xTerrain - xxt * 2, 110 - yyt * 3, TroopLoc);
5220 if (UnFocus >= 0) and (MyUn[UnFocus].Job <> jNone) then begin
5221 JobFocus := MyUn[UnFocus].Job;
5222 Server(sGetJobProgress, Me, MyUn[UnFocus].Loc, JobProgressData);
5223 MakeBlue(Panel, xTerrain - 72, 148 - 17, 144, 31);
5224 PaintRelativeProgressBar(Panel.Canvas, 3, xTerrain - 68, 148 + 3, 63,
5225 JobProgressData[JobFocus].Done,
5226 JobProgressData[JobFocus].NextTurnPlus,
5227 JobProgressData[JobFocus].Required, True, MainTexture);
5228 S := Format('%s/%s',
5229 [ScreenTools.MovementToString(JobProgressData[JobFocus].Done),
5230 ScreenTools.MovementToString(JobProgressData[JobFocus].Required)]);
5231 RisedTextOut(Panel.Canvas, xTerrain + 6, 148 - 3, S);
5232 Tile := MyMap[MyUn[UnFocus].Loc];
5233 if (JobFocus = jRoad) and (Tile and fRiver <> 0) then
5234 JobFocus := nJob + 0
5235 else if (JobFocus = jRR) and (Tile and fRiver <> 0) then
5236 JobFocus := nJob + 1
5237 else if JobFocus = jClear then
5238 begin
5239 if Tile and fTerrain = fForest then
5240 JobFocus := nJob + 2
5241 else if Tile and fTerrain = fDesert then
5242 JobFocus := nJob + 3
5243 else
5244 JobFocus := nJob + 4;
5245 end;
5246 S := Phrases.Lookup('JOBRESULT', JobFocus);
5247 RisedTextOut(Panel.Canvas, xTerrain - BiColorTextWidth(Panel.Canvas,
5248 S) div 2, 148 - 19, S);
5249 end;
5250 if MyMap[TroopLoc] and (fTerrain or fSpecial) = fGrass or fSpecial1 then
5251 S := Phrases.Lookup('TERRAIN', fGrass + 12)
5252 else if MyMap[TroopLoc] and fDeadLands <> 0 then
5253 S := Phrases.Lookup('TERRAIN', 3 * 12)
5254 else if (MyMap[TroopLoc] and fTerrain = fForest) and
5255 IsJungle(TroopLoc div G.lx) then
5256 S := Phrases.Lookup('TERRAIN', fJungle)
5257 else
5258 S := Phrases.Lookup('TERRAIN', MyMap[TroopLoc] and fTerrain);
5259 RisedTextOut(Panel.Canvas, xTerrain - BiColorTextWidth(Panel.Canvas, S)
5260 div 2, 99, S);
5261 end;
5262
5263 if TerrainBtn.Visible then
5264 with TerrainBtn do
5265 RFrame(Panel.Canvas, Left - 1, Top - Self.ClientHeight +
5266 (PanelHeight - 1), Left + Width, Top + Height - Self.ClientHeight +
5267 PanelHeight, MainTexture.ColorBevelShade, MainTexture.ColorBevelLight)
5268 end; { if TroopLoc >= 0 }
5269 end;
5270
5271 for I := 0 to ControlCount - 1 do
5272 if Controls[I] is TButtonB then
5273 with TButtonB(Controls[I]) do
5274 begin
5275 if Visible then
5276 begin
5277 Dump(Panel, HGrSystem, Left, Top - Self.ClientHeight + PanelHeight,
5278 25, 25, 169, 243);
5279 Sprite(Panel, HGrSystem, Left, Top - Self.ClientHeight + PanelHeight,
5280 25, 25, 1 + 26 * ButtonIndex, 337);
5281 RFrame(Panel.Canvas, Left - 1, Top - Self.ClientHeight +
5282 (PanelHeight - 1), Left + Width, Top + Height - Self.ClientHeight +
5283 PanelHeight, MainTexture.ColorBevelShade, MainTexture.ColorBevelLight);
5284 end;
5285 end;
5286
5287 if ClientMode <> cEditMap then
5288 begin
5289 for I := 0 to ControlCount - 1 do
5290 if Controls[I] is TButtonC then
5291 with TButtonC(Controls[I]) do
5292 begin
5293 Dump(Panel, HGrSystem, Left, Top - Self.ClientHeight + PanelHeight,
5294 12, 12, 169, 178 + 13 * ButtonIndex);
5295 RFrame(Panel.Canvas, Left - 1, Top - Self.ClientHeight +
5296 (PanelHeight - 1), Left + Width, Top + Height - Self.ClientHeight +
5297 PanelHeight, MainTexture.ColorBevelShade, MainTexture.ColorBevelLight);
5298 end;
5299 end;
5300 EOT.SetBack(Panel.Canvas, EOT.Left, EOT.Top - (ClientHeight - PanelHeight));
5301 SmartRectInvalidate(0, ClientHeight - PanelHeight, ClientWidth, ClientHeight);
5302
5303 // topbar
5304 xTreasurySection := ClientWidth div 2 - 172;
5305 xResearchSection := ClientWidth div 2;
5306 // ClientWidth div 2 + 68 = maximum to right
5307 FillLarge(TopBar.Canvas, 0, 0, ClientWidth, TopBarHeight - 3,
5308 ClientWidth div 2);
5309 with TopBar.Canvas do
5310 begin
5311 Pen.Color := $000000;
5312 MoveTo(0, TopBarHeight - 1);
5313 LineTo(ClientWidth, TopBarHeight - 1);
5314 Pen.Color := MainTexture.ColorBevelShade;
5315 MoveTo(0, TopBarHeight - 2);
5316 LineTo(ClientWidth, TopBarHeight - 2);
5317 MoveTo(0, TopBarHeight - 3);
5318 LineTo(ClientWidth, TopBarHeight - 3);
5319 Pen.Color := MainTexture.ColorBevelLight;
5320 ScreenTools.Frame(TopBar.Canvas, 40, -1, xTreasurySection - 1,
5321 TopBarHeight - 7, MainTexture.ColorBevelShade, MainTexture.ColorBevelLight);
5322 ScreenTools.Frame(TopBar.Canvas, xResearchSection + 332, -1, ClientWidth,
5323 TopBarHeight - 7, MainTexture.ColorBevelShade, MainTexture.ColorBevelLight);
5324 end;
5325 if GameMode <> cMovie then
5326 ImageOp_BCC(TopBar, Templates.Data, Point(2, 1), MenuLogo.BoundsRect, $BFBF20, $4040DF);
5327 if MyRO.nCity > 0 then
5328 begin
5329 TrueMoney := MyRO.Money;
5330 TrueResearch := MyRO.Research;
5331 if Supervising then
5332 begin // normalize values from after-turn state
5333 Dec(TrueMoney, TaxSum);
5334 if TrueMoney < 0 then
5335 TrueMoney := 0; // shouldn't happen
5336 Dec(TrueResearch, ScienceSum);
5337 if TrueResearch < 0 then
5338 TrueResearch := 0; // shouldn't happen
5339 end;
5340
5341 // treasury section
5342 ImageOp_BCC(TopBar, Templates.Data, Point(xTreasurySection + 8, 1), TreasuryIcon.BoundsRect,
5343 $40A040, $4030C0);
5344 S := IntToStr(TrueMoney);
5345 LoweredTextOut(TopBar.Canvas, -1, MainTexture, xTreasurySection + 48, 0,
5346 S + '%c');
5347 if MyRO.Government <> gAnarchy then
5348 begin
5349 ImageOp_BCC(TopBar, Templates.Data, Point(xTreasurySection + 48, 22), ChangeIcon.BoundsRect,
5350 $0000C0, $0080C0);
5351 if TaxSum >= 0 then
5352 S := Format(Phrases.Lookup('MONEYGAINPOS'), [TaxSum])
5353 else
5354 S := Format(Phrases.Lookup('MONEYGAINNEG'), [TaxSum]);
5355 LoweredTextOut(TopBar.Canvas, -1, MainTexture, xTreasurySection + 48 +
5356 15, 18, S);
5357 end;
5358
5359 // research section
5360 ImageOp_BCC(TopBar, Templates.Data, Point(xResearchSection + 8, 1), ResearchIcon.BoundsRect,
5361 $FF0000, $00FFE0);
5362 if MyData.FarTech <> adNexus then
5363 begin
5364 if MyRO.ResearchTech < 0 then
5365 CostFactor := 2
5366 else if (MyRO.ResearchTech = adMilitary) or
5367 (MyRO.Tech[MyRO.ResearchTech] = tsSeen) then
5368 CostFactor := 1
5369 else if MyRO.ResearchTech in FutureTech then
5370 if MyRO.Government = gFuture then
5371 CostFactor := 4
5372 else
5373 CostFactor := 8
5374 else
5375 CostFactor := 2;
5376 Server(sGetTechCost, Me, 0, I);
5377 CostFactor := CostFactor * 22; // length of progress bar
5378 PaintRelativeProgressBar(TopBar.Canvas, 2, xResearchSection + 48 + 1, 26,
5379 CostFactor, TrueResearch, ScienceSum, I, True, MainTexture);
5380
5381 if MyRO.ResearchTech < 0 then
5382 S := Phrases.Lookup('SCIENCE')
5383 else if MyRO.ResearchTech = adMilitary then
5384 S := Phrases.Lookup('INITUNIT')
5385 else
5386 begin
5387 S := Phrases.Lookup('ADVANCES', MyRO.ResearchTech);
5388 if MyRO.ResearchTech in FutureTech then
5389 if MyRO.Tech[MyRO.ResearchTech] >= 1 then
5390 S := S + ' ' + IntToStr(MyRO.Tech[MyRO.ResearchTech] + 1)
5391 else
5392 S := S + ' 1';
5393 end;
5394 if ScienceSum > 0 then
5395 begin
5396 { j := (i - MyRO.Research - 1) div ScienceSum + 1;
5397 if J < 1 then J := 1;
5398 if J > 1 then
5399 S := Format(Phrases.Lookup('TECHWAIT'), [S, J]); }
5400 LoweredTextOut(TopBar.Canvas, -1, MainTexture,
5401 xResearchSection + 48, 0, S);
5402 end
5403 else
5404 LoweredTextOut(TopBar.Canvas, -1, MainTexture,
5405 xResearchSection + 48, 0, S);
5406 end
5407 else
5408 CostFactor := 0;
5409 if (MyData.FarTech <> adNexus) and (ScienceSum > 0) then
5410 begin
5411 ImageOp_BCC(TopBar, Templates.Data, Point(xResearchSection + 48 + CostFactor + 11,
5412 22), ChangeIcon.BoundsRect, $0000C0, $0080C0);
5413 S := Format(Phrases.Lookup('TECHGAIN'), [ScienceSum]);
5414 LoweredTextOut(TopBar.Canvas, -1, MainTexture, xResearchSection + 48 +
5415 CostFactor + 26, 18, S);
5416 end;
5417 end;
5418 if ClientMode <> cEditMap then
5419 begin
5420 TopBar.Canvas.Font.Assign(UniFont[ftCaption]);
5421 S := TurnToString(MyRO.Turn);
5422 RisedTextOut(TopBar.Canvas,
5423 40 + (xTreasurySection - 40 - BiColorTextWidth(TopBar.Canvas, S))
5424 div 2, 6, S);
5425 TopBar.Canvas.Font.Assign(UniFont[ftNormal]);
5426 end;
5427 RectInvalidate(0, 0, ClientWidth, TopBarHeight);
5428end;
5429
5430procedure TMainScreen.FocusNextUnit(Dir: Integer);
5431var
5432 I, uix, NewFocus: Integer;
5433begin
5434 if ClientMode >= scContact then
5435 Exit;
5436 DestinationMarkON := False;
5437 PaintDestination;
5438 NewFocus := -1;
5439 for I := 1 to MyRO.nUn do begin
5440 uix := (UnFocus + I * Dir + MyRO.nUn) mod MyRO.nUn;
5441 if (MyUn[uix].Loc >= 0) and (MyUn[uix].Status and usStay = 0) then begin
5442 NewFocus := uix;
5443 Break;
5444 end;
5445 end;
5446 if NewFocus >= 0 then begin
5447 SetUnFocus(NewFocus);
5448 SetTroopLoc(MyUn[NewFocus].Loc);
5449 FocusOnLoc(TroopLoc, flRepaintPanel);
5450 end;
5451end;
5452
5453procedure TMainScreen.FocusOnLoc(Loc: Integer; Options: Integer = 0);
5454var
5455 dx: Integer;
5456 Outside, Changed: Boolean;
5457begin
5458 with MainMap do begin
5459 dx := G.lx + 1 - (xw - Loc + G.lx * 1024 + 1) mod G.lx;
5460 Outside := (dx >= (MapWidth + 1) div (xxt * 2) - 2) or (ywmax > 0) and
5461 ((yw > 0) and (Loc div G.lx <= yw + 1) or (yw < ywmax) and
5462 (Loc div G.lx >= yw + (MapHeight - 1) div yyt - 2));
5463 end;
5464 Changed := True;
5465 if Outside then begin
5466 Centre(Loc);
5467 PaintAllMaps;
5468 end
5469 else if not MapValid then
5470 PaintAllMaps
5471 else
5472 Changed := False;
5473 if Options and flRepaintPanel <> 0 then
5474 PanelPaint;
5475 if Changed and (Options and flImmUpdate <> 0) then
5476 Update;
5477end;
5478
5479procedure TMainScreen.NextUnit(NearLoc: Integer; AutoTurn: Boolean);
5480var
5481 Dist, TestDist: Single;
5482 I, uix, NewFocus: Integer;
5483 GotoOnly: Boolean;
5484begin
5485 Dist := 0;
5486 if ClientMode >= scContact then
5487 Exit;
5488 DestinationMarkON := False;
5489 PaintDestination;
5490 for GotoOnly := GoOnPhase downto False do begin
5491 NewFocus := -1;
5492 for I := 1 to MyRO.nUn do begin
5493 uix := (UnFocus + I) mod MyRO.nUn;
5494 if (MyUn[uix].Loc >= 0) and (MyUn[uix].Job = jNone) and
5495 (MyUn[uix].Status and (usStay or usRecover or usWaiting) = usWaiting)
5496 and (not GotoOnly or (MyUn[uix].Status and usGoto <> 0)) then
5497 if NearLoc < 0 then begin
5498 NewFocus := uix;
5499 Break;
5500 end else begin
5501 TestDist := Distance(NearLoc, MyUn[uix].Loc);
5502 if (NewFocus < 0) or (TestDist < Dist) then begin
5503 NewFocus := uix;
5504 Dist := TestDist;
5505 end;
5506 end;
5507 end;
5508 if GotoOnly then
5509 if NewFocus < 0 then GoOnPhase := False
5510 else Break;
5511 end;
5512 if NewFocus >= 0 then begin
5513 SetUnFocus(NewFocus);
5514 SetTroopLoc(MyUn[NewFocus].Loc);
5515 FocusOnLoc(TroopLoc, flRepaintPanel);
5516 end else
5517 if AutoTurn and not mWaitTurn.Checked then begin
5518 TurnComplete := True;
5519 SetUnFocus(-1);
5520 SetTroopLoc(-1);
5521 PostMessage(Handle, WM_EOT, 0, 0);
5522 end else begin
5523 if { (UnFocus>=0) and } not TurnComplete and EOT.Visible then
5524 Play('TURNEND');
5525 TurnComplete := True;
5526 SetUnFocus(-1);
5527 SetTroopLoc(-1);
5528 PanelPaint;
5529 end;
5530end;
5531
5532procedure TMainScreen.Scroll(dx, dy: Integer);
5533begin
5534 xw := (xw + G.lx + dx) mod G.lx;
5535 if ywmax > 0 then
5536 begin
5537 yw := yw + 2 * dy;
5538 if yw < 0 then
5539 yw := 0
5540 else if yw > ywmax then
5541 yw := ywmax;
5542 end;
5543 MainOffscreenPaint;
5544 xwMini := xw;
5545 ywMini := yw;
5546 MiniMapPaint;
5547 CopyMiniToPanel;
5548 RectInvalidate(xMini + 2, TopBarHeight + MapHeight - Overlap + yMini + 2,
5549 xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - Overlap + yMini +
5550 2 + G.ly);
5551 Update;
5552end;
5553
5554procedure TMainScreen.Timer1Timer(Sender: TObject);
5555var
5556 dx, dy, ScrollSpeed: Integer;
5557 MousePos: TPoint;
5558const
5559 ScrollWidth = 5;
5560begin
5561 if Idle and (Me >= 0) and (GameMode <> cMovie) then
5562 if Assigned(Screen.ActiveForm) and
5563 (TFormStateType.fsModal in Screen.ActiveForm.FormState) or
5564 (Screen.ActiveForm is TBufferedDrawDlg) and
5565 (TBufferedDrawDlg(Screen.ActiveForm).WindowMode <> wmPersistent) then
5566 begin
5567 BlinkTime := BlinkOnTime + BlinkOffTime - 1;
5568 if not BlinkON then
5569 begin
5570 BlinkON := True;
5571 if UnFocus >= 0 then
5572 PaintLocTemp(MyUn[UnFocus].Loc)
5573 else if TurnComplete and not Supervising then
5574 EOT.SetButtonIndexFast(eotBlinkOn);
5575 end;
5576 end else begin
5577 if Application.Active and not mScrollOff.Checked then
5578 begin
5579 if mScrollFast.Checked then ScrollSpeed := 2
5580 else ScrollSpeed := 1;
5581 dx := 0;
5582 dy := 0;
5583 MousePos := ScreenToClient(Mouse.CursorPos);
5584 if MousePos.Y < Height - PanelHeight then
5585 if MousePos.X <= ScrollWidth then
5586 dx := -ScrollSpeed // scroll left
5587 else if MousePos.X >= Width - ScrollWidth - 1 then
5588 dx := ScrollSpeed; // scroll right
5589 if MousePos.Y <= ScrollWidth then
5590 dy := -ScrollSpeed // scroll up
5591 else if (MousePos.Y >= Height - ScrollWidth - 1) and
5592 (MousePos.X >= TerrainBtn.Left + TerrainBtn.Width) and
5593 (MousePos.X < xRightPanel + 10 - 8) then
5594 dy := ScrollSpeed; // scroll down
5595 if (dx <> 0) or (dy <> 0) then
5596 begin
5597 if Assigned(Screen.ActiveForm) and
5598 (Screen.ActiveForm <> MainScreen) and
5599 (@Screen.ActiveForm.OnDeactivate <> nil) then
5600 Screen.ActiveForm.OnDeactivate(nil);
5601 Scroll(dx, dy);
5602 end;
5603 end;
5604
5605 BlinkTime := (BlinkTime + 1) mod (BlinkOnTime + BlinkOffTime);
5606 BlinkON := BlinkTime >= BlinkOffTime;
5607 DestinationMarkON := True;
5608 if UnFocus >= 0 then
5609 begin
5610 if (BlinkTime = 0) or (BlinkTime = BlinkOffTime) then
5611 begin
5612 PaintLocTemp(MyUn[UnFocus].Loc, pltsBlink);
5613 PaintDestination;
5614 // if MoveHintToLoc >= 0 then
5615 // ShowMoveHint(MoveHintToLoc, True);
5616 end;
5617 end
5618 else if TurnComplete and not Supervising then
5619 begin
5620 if BlinkTime = 0 then
5621 EOT.SetButtonIndexFast(eotBlinkOff)
5622 else if BlinkTime = BlinkOffTime then
5623 EOT.SetButtonIndexFast(eotBlinkOn);
5624 end;
5625 end;
5626end;
5627
5628procedure TMainScreen.SetMapPos(Loc: Integer; MapPos: TPoint);
5629begin
5630 with MainMap do begin
5631 if FastScrolling and MapValid then
5632 Update;
5633 // necessary because ScrollDC for form canvas is called after
5634 xw := (Loc mod G.lx) - (MapPos.X - ((xxt * 2) * ((Loc div G.lx) and 1)) div 2)
5635 div (xxt * 2);
5636 xw := (xw + G.lx) mod G.lx;
5637 if ywmax <= 0 then yw := ywcenter
5638 else begin
5639 yw := (Loc div G.lx - (MapPos.Y * 2) div (yyt * 2) + 1) and not 1;
5640 if yw < 0 then yw := 0
5641 else if yw > ywmax then yw := ywmax;
5642 end;
5643 end;
5644end;
5645
5646procedure TMainScreen.Centre(Loc: Integer);
5647begin
5648 SetMapPos(Loc, Point(MapWidth div 2, MapHeight div 2));
5649end;
5650
5651function TMainScreen.ZoomToCity(Loc: Integer; NextUnitOnClose: Boolean = False;
5652 ShowEvent: Integer = 0): Boolean;
5653begin
5654 Result := MyMap[Loc] and (fOwned or fSpiedOut) <> 0;
5655 if Result then
5656 with CityDlg do
5657 begin
5658 if ClientMode >= scContact then
5659 begin
5660 CloseAction := None;
5661 RestoreUnFocus := -1;
5662 end
5663 else if NextUnitOnClose then
5664 begin
5665 CloseAction := StepFocus;
5666 RestoreUnFocus := -1;
5667 end
5668 else if not Visible then
5669 begin
5670 CloseAction := RestoreFocus;
5671 RestoreUnFocus := UnFocus;
5672 end;
5673 SetUnFocus(-1);
5674 SetTroopLoc(Loc);
5675 MarkCityLoc := Loc;
5676 PanelPaint;
5677 ShowNewContent(wmPersistent, Loc, ShowEvent);
5678 end;
5679end;
5680
5681function TMainScreen.LocationOfScreenPixel(X, Y: Integer): Integer;
5682var
5683 qx, qy: Integer;
5684begin
5685 with MainMap do begin
5686 qx := (X * (yyt * 2) + Y * (xxt * 2) + xxt * yyt * 2) div (xxt * yyt * 4) - 1;
5687 qy := (Y * (xxt * 2) - X * (yyt * 2) - xxt * yyt * 2 + 4000 * xxt * yyt)
5688 div (xxt * yyt * 4) - 999;
5689 Result := (xw + (qx - qy + 2048) div 2 - 1024 + G.lx) mod G.lx + G.lx *
5690 (yw + qx + qy);
5691 end;
5692end;
5693
5694function TMainScreen.GetCenterLoc: Integer;
5695begin
5696 Result := (xw + MapWidth div (MainMap.xxt * 4)) mod G.lx +
5697 (yw + MapHeight div (MainMap.yyt * 2)) * G.lx;
5698end;
5699
5700procedure TMainScreen.MapBoxMouseDown(Sender: TObject; Button: TMouseButton;
5701 Shift: TShiftState; X, Y: Integer);
5702var
5703 I, uix, emix, p1, dx, dy, MouseLoc: Integer;
5704 EditTileData: TEditTileData;
5705 M, m2: TMenuItem;
5706 MoveAdviceData: TMoveAdviceData;
5707 DoCenter: Boolean;
5708begin
5709 if GameMode = cMovie then
5710 Exit;
5711
5712 if Assigned(FCityDlg) and CityDlg.Visible then
5713 CityDlg.Close;
5714 if Assigned(FUnitStatDlg) and UnitStatDlg.Visible then
5715 UnitStatDlg.Close;
5716 MouseLoc := LocationOfScreenPixel(X, Y);
5717 if (MouseLoc < 0) or (MouseLoc >= G.lx * G.ly) then
5718 Exit;
5719 if (Button = TMouseButton.mbLeft) and not (ssShift in Shift) then
5720 begin
5721 DoCenter := True;
5722 if ClientMode = cEditMap then
5723 begin
5724 DoCenter := False;
5725 EditTileData.Loc := MouseLoc;
5726 if ssCtrl in Shift then // toggle special resource
5727 case MyMap[MouseLoc] and fTerrain of
5728 fOcean:
5729 EditTileData.NewTile := MyMap[MouseLoc];
5730 fGrass, fArctic:
5731 EditTileData.NewTile := MyMap[MouseLoc] and not fSpecial or
5732 ((MyMap[MouseLoc] shr 5 and 3 + 1) mod 2 shl 5);
5733 else
5734 EditTileData.NewTile := MyMap[MouseLoc] and not fSpecial or
5735 ((MyMap[MouseLoc] shr 5 and 3 + 1) mod 3 shl 5)
5736 end
5737 else if BrushType <= fTerrain then
5738 EditTileData.NewTile := MyMap[MouseLoc] and not fTerrain or fSpecial or
5739 BrushType
5740 else if BrushType and fDeadLands <> 0 then
5741 if MyMap[MouseLoc] and (fDeadLands or fModern) = BrushType and
5742 (fDeadLands or fModern) then
5743 EditTileData.NewTile := MyMap[MouseLoc] and not (fDeadLands or fModern)
5744 else
5745 EditTileData.NewTile := MyMap[MouseLoc] and not (fDeadLands or fModern)
5746 or BrushType
5747 else if BrushType and fTerImp <> 0 then
5748 if MyMap[MouseLoc] and fTerImp = BrushType then
5749 EditTileData.NewTile := MyMap[MouseLoc] and not fTerImp
5750 else
5751 EditTileData.NewTile := MyMap[MouseLoc] and not fTerImp or BrushType
5752 else if BrushType and (fPrefStartPos or fStartPos) <> 0 then
5753 if MyMap[MouseLoc] and (fPrefStartPos or fStartPos) = BrushType and
5754 (fPrefStartPos or fStartPos) then
5755 EditTileData.NewTile := MyMap[MouseLoc] and
5756 not (fPrefStartPos or fStartPos)
5757 else
5758 EditTileData.NewTile := MyMap[MouseLoc] and
5759 not (fPrefStartPos or fStartPos) or BrushType
5760 else
5761 EditTileData.NewTile := MyMap[MouseLoc] xor BrushType;
5762 Server(sEditTile, Me, 0, EditTileData);
5763 Edited := True;
5764 BrushLoc := MouseLoc;
5765 PaintLoc(MouseLoc, 2);
5766 MiniMapPaint;
5767 BitBltBitmap(Panel, xMini + 2, yMini + 2, G.lx * 2, G.ly,
5768 MiniMap.Bitmap, 0, 0);
5769 with MainMap do begin
5770 if ywmax <= 0 then
5771 Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (2 * xxt),
5772 yMini + 2, xMini + 1 + G.lx + MapWidth div (2 * xxt),
5773 yMini + 2 + G.ly - 1, MainTexture.ColorMark, MainTexture.ColorMark)
5774 else
5775 Frame(Panel.Canvas, xMini + 2 + G.lx - MapWidth div (2 * xxt),
5776 yMini + 2 + yw, xMini + 2 + G.lx + MapWidth div (2 * xxt) - 1,
5777 yMini + 2 + yw + MapHeight div yyt - 2, MainTexture.ColorMark,
5778 MainTexture.ColorMark);
5779 end;
5780 RectInvalidate(xMini + 2, TopBarHeight + MapHeight - Overlap + yMini + 2,
5781 xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - Overlap + yMini
5782 + 2 + G.ly);
5783 end
5784 else if MyMap[MouseLoc] and fCity <> 0 then { city clicked }
5785 begin
5786 if MyMap[MouseLoc] and (fOwned or fSpiedOut) <> 0 then
5787 begin
5788 ZoomToCity(MouseLoc);
5789 DoCenter := False;
5790 end
5791 else
5792 begin
5793 UnitStatDlg.ShowNewContent_EnemyCity(wmPersistent, MouseLoc);
5794 DoCenter := False;
5795 end;
5796 end
5797 else if MyMap[MouseLoc] and fUnit <> 0 then { unit clicked }
5798 if MyMap[MouseLoc] and fOwned <> 0 then
5799 begin
5800 DoCenter := False;
5801 if not Supervising and (ClientMode < scContact) then
5802 begin // not in negotiation mode
5803 if (UnFocus >= 0) and (MyUn[UnFocus].Loc = MouseLoc) then
5804 begin // rotate
5805 uix := (UnFocus + 1) mod MyRO.nUn;
5806 I := MyRO.nUn - 1;
5807 while I > 0 do
5808 begin
5809 if (MyUn[uix].Loc = MouseLoc) and (MyUn[uix].Job = jNone) and
5810 (MyUn[uix].Status and (usStay or usRecover or usEnhance or
5811 usWaiting) = usWaiting) then
5812 Break;
5813 Dec(I);
5814 uix := (uix + 1) mod MyRO.nUn;
5815 end;
5816 if I = 0 then
5817 uix := UnFocus;
5818 end
5819 else
5820 Server(sGetDefender, Me, MouseLoc, uix);
5821 if uix <> UnFocus then
5822 SetUnFocus(uix);
5823 TurnComplete := False;
5824 EOT.ButtonIndex := eotGray;
5825 end;
5826 SetTroopLoc(MouseLoc);
5827 PanelPaint;
5828 end // own unit
5829 else if (MyMap[MouseLoc] and fSpiedOut <> 0) and not (ssCtrl in Shift) then
5830 begin
5831 DoCenter := False;
5832 SetTroopLoc(MouseLoc);
5833 PanelPaint;
5834 end
5835 else
5836 begin
5837 DoCenter := False;
5838 UnitStatDlg.ShowNewContent_EnemyLoc(wmPersistent, MouseLoc);
5839 end;
5840 if DoCenter then
5841 begin
5842 Centre(MouseLoc);
5843 PaintAllMaps;
5844 end;
5845 end
5846 else if (ClientMode <> cEditMap) and (Button = TMouseButton.mbRight) and
5847 not (ssShift in Shift) then
5848 begin
5849 if Supervising then
5850 begin
5851 EditLoc := MouseLoc;
5852 Server(sGetModels, Me, 0, nil^);
5853 EmptyMenu(mCreateUnit);
5854 for p1 := 0 to nPl - 1 do
5855 if 1 shl p1 and MyRO.Alive <> 0 then
5856 begin
5857 M := TMenuItem.Create(mCreateUnit);
5858 M.Caption := Tribe[p1].TPhrase('SHORTNAME');
5859 for emix := MyRO.nEnemyModel - 1 downto 0 do
5860 if (MyRO.EnemyModel[emix].Owner = p1) and
5861 (Server(sCreateUnit - sExecute + p1 shl 4, Me,
5862 MyRO.EnemyModel[emix].mix, MouseLoc) >= rExecuted) then
5863 begin
5864 if not Assigned(Tribe[p1].ModelPicture[MyRO.EnemyModel[emix].mix].HGr) then
5865 InitEnemyModel(emix);
5866 m2 := TMenuItem.Create(M);
5867 m2.Caption := Tribe[p1].ModelName[MyRO.EnemyModel[emix].mix];
5868 m2.Tag := p1 shl 16 + MyRO.EnemyModel[emix].mix;
5869 m2.OnClick := CreateUnitClick;
5870 M.Add(m2);
5871 end;
5872 M.Visible := M.Count > 0;
5873 mCreateUnit.Add(M);
5874 end;
5875 if FullScreen then
5876 EditPopup.Popup(Left + X, Top + Y)
5877 else
5878 EditPopup.Popup(Left + X + 4,
5879 Top + Y + GetSystemMetrics(SM_CYCAPTION) + 4);
5880 end
5881 else if (UnFocus >= 0) and (MyUn[UnFocus].Loc <> MouseLoc) then
5882 with MyUn[UnFocus] do
5883 begin
5884 dx := ((MouseLoc mod G.lx * 2 + MouseLoc div G.lx and 1) -
5885 (Loc mod G.lx * 2 + Loc div G.lx and 1) + 3 * G.lx)
5886 mod (2 * G.lx) - G.lx;
5887 dy := MouseLoc div G.lx - Loc div G.lx;
5888 if Abs(dx) + Abs(dy) < 3 then
5889 begin
5890 DestinationMarkON := False;
5891 PaintDestination;
5892 Status := Status and ($FFFF - usStay - usRecover - usGoto - usEnhance)
5893 or usWaiting;
5894 MoveUnit(dx, dy, muAutoNext); { simple move }
5895 end
5896 else if GetMoveAdvice(UnFocus, MouseLoc, MoveAdviceData) >= rExecuted
5897 then
5898 begin
5899 if MyMap[MouseLoc] and (fUnit or fOwned) = fUnit then
5900 begin // check for suicide mission before movement
5901 with MyUn[UnFocus], BattleDlg.Forecast do
5902 begin
5903 pAtt := Me;
5904 mixAtt := mix;
5905 HealthAtt := Health;
5906 ExpAtt := Exp;
5907 FlagsAtt := Flags;
5908 end;
5909 BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
5910 if (Server(sGetBattleForecastEx, Me, MouseLoc, BattleDlg.Forecast)
5911 >= rExecuted) and (BattleDlg.Forecast.EndHealthAtt <= 0) then
5912 begin
5913 BattleDlg.uix := UnFocus;
5914 BattleDlg.ToLoc := MouseLoc;
5915 BattleDlg.IsSuicideQuery := True;
5916 BattleDlg.ShowModal;
5917 if BattleDlg.ModalResult <> mrOK then
5918 Exit;
5919 end;
5920 end;
5921 DestinationMarkON := False;
5922 PaintDestination;
5923 Status := Status and not (usStay or usRecover or usEnhance) or
5924 usWaiting;
5925 MoveToLoc(MouseLoc, False); { goto }
5926 end;
5927 end;
5928 end
5929 else if (Button = TMouseButton.mbMiddle) and (UnFocus >= 0) and
5930 (MyModel[MyUn[UnFocus].mix].Kind in [mkSettler, mkSlaves]) then
5931 begin
5932 DestinationMarkON := False;
5933 PaintDestination;
5934 MyUn[UnFocus].Status := MyUn[UnFocus].Status and
5935 ($FFFF - usStay - usRecover - usGoto) or usEnhance;
5936 uix := UnFocus;
5937 if MouseLoc <> MyUn[uix].Loc then
5938 MoveToLoc(MouseLoc, True); { goto }
5939 if (UnFocus = uix) and (MyUn[uix].Loc = MouseLoc) then
5940 mEnhance.Click;
5941 end
5942 else if (Button = TMouseButton.mbLeft) and (ssShift in Shift) and
5943 (MyMap[MouseLoc] and fTerrain <> fUNKNOWN) then
5944 HelpOnTerrain(MouseLoc, wmPersistent)
5945 else if (ClientMode <= cContinue) and (Button = TMouseButton.mbRight) and
5946 (ssShift in Shift) and (UnFocus >= 0) and
5947 (MyMap[MouseLoc] and (fUnit or fOwned) = fUnit) then
5948 begin // battle forecast
5949 with MyUn[UnFocus], BattleDlg.Forecast do
5950 begin
5951 pAtt := Me;
5952 mixAtt := mix;
5953 HealthAtt := Health;
5954 ExpAtt := Exp;
5955 FlagsAtt := Flags;
5956 end;
5957 BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
5958 if Server(sGetBattleForecastEx, Me, MouseLoc, BattleDlg.Forecast) >= rExecuted
5959 then
5960 begin
5961 BattleDlg.uix := UnFocus;
5962 BattleDlg.ToLoc := MouseLoc;
5963 BattleDlg.Left := X - BattleDlg.Width div 2;
5964 if BattleDlg.Left < 0 then
5965 BattleDlg.Left := 0
5966 else if BattleDlg.Left + BattleDlg.Width > Screen.DesktopWidth then
5967 BattleDlg.Left := Screen.DesktopWidth - BattleDlg.Width;
5968 BattleDlg.Top := Y - BattleDlg.Height div 2;
5969 if BattleDlg.Top < 0 then
5970 BattleDlg.Top := 0
5971 else if BattleDlg.Top + BattleDlg.Height > Screen.DesktopHeight then
5972 BattleDlg.Top := Screen.DesktopHeight - BattleDlg.Height;
5973 BattleDlg.IsSuicideQuery := False;
5974 BattleDlg.Show;
5975 end;
5976 end;
5977end;
5978
5979function TMainScreen.MoveUnit(dx, dy: Integer; Options: Integer): Integer;
5980// move focused unit to adjacent tile
5981var
5982 I, cix, uix, euix, FromLoc, ToLoc, DirCode, UnFocus0, Defender, Mission, p1,
5983 NewTiles, cixChanged: Integer;
5984 OldToTile: Cardinal;
5985 CityCaptured, IsAttack, OldUnrest, NewUnrest, NeedEcoUpdate, NeedRepaintPanel,
5986 ToTransport, ToShip: Boolean;
5987 PlaneReturnData: TPlaneReturnData;
5988 QueryItem: string;
5989begin
5990 Result := eInvalid;
5991 UnFocus0 := UnFocus;
5992 FromLoc := MyUn[UnFocus].Loc;
5993 ToLoc := dLoc(FromLoc, dx, dy);
5994 if (ToLoc < 0) or (ToLoc >= G.lx * G.ly) then
5995 begin
5996 Result := eInvalid;
5997 Exit;
5998 end;
5999 if MyMap[ToLoc] and fStealthUnit <> 0 then
6000 begin
6001 SoundMessage(Phrases.Lookup('ATTACKSTEALTH'), '');
6002 Exit;
6003 end;
6004 if MyMap[ToLoc] and fHiddenUnit <> 0 then
6005 begin
6006 SoundMessage(Phrases.Lookup('ATTACKSUB'), '');
6007 Exit;
6008 end;
6009
6010 if MyMap[ToLoc] and (fUnit or fOwned) = fUnit then
6011 begin // attack -- search enemy unit
6012 if (MyModel[MyUn[UnFocus].mix].Attack = 0) and
6013 not ((MyModel[MyUn[UnFocus].mix].Cap[mcBombs] > 0) and
6014 (MyUn[UnFocus].Flags and unBombsLoaded <> 0)) then
6015 begin
6016 SoundMessage(Phrases.Lookup('NOATTACKER'), '');
6017 Exit;
6018 end;
6019 euix := MyRO.nEnemyUn - 1;
6020 while (euix >= 0) and (MyRO.EnemyUn[euix].Loc <> ToLoc) do
6021 Dec(euix);
6022 end;
6023
6024 DirCode := dx and 7 shl 4 + dy and 7 shl 7;
6025 Result := Server(sMoveUnit - sExecute + DirCode, Me, UnFocus, nil^);
6026 if (Result < rExecuted) and (MyUn[UnFocus].Job > jNone) then
6027 Server(sStartJob + jNone shl 4, Me, UnFocus, nil^);
6028 if (Result < rExecuted) and (Result <> eNoTime_Move) then
6029 begin
6030 case Result of
6031 eNoTime_Load:
6032 if MyModel[MyUn[UnFocus].mix].Domain = dAir then
6033 SoundMessage(Phrases.Lookup('NOTIMELOADAIR'), 'NOMOVE_TIME')
6034 else
6035 SoundMessage(Format(Phrases.Lookup('NOTIMELOADGROUND'),
6036 [MovementToString(MyModel[MyUn[UnFocus].mix].speed)]),
6037 'NOMOVE_TIME');
6038 eNoTime_Bombard:
6039 SoundMessage(Phrases.Lookup('NOTIMEBOMBARD'), 'NOMOVE_TIME');
6040 eNoTime_Expel:
6041 SoundMessage(Phrases.Lookup('NOTIMEEXPEL'), 'NOMOVE_TIME');
6042 eNoRoad:
6043 SoundMessage(Phrases.Lookup('NOROAD'), 'NOMOVE_DEFAULT');
6044 eNoNav:
6045 SoundMessage(Phrases.Lookup('NONAV'), 'NOMOVE_DEFAULT');
6046 eNoCapturer:
6047 SoundMessage(Phrases.Lookup('NOCAPTURER'), 'NOMOVE_DEFAULT');
6048 eNoBombarder:
6049 SoundMessage(Phrases.Lookup('NOBOMBARDER'), 'NOMOVE_DEFAULT');
6050 eZOC:
6051 ContextMessage(Phrases.Lookup('ZOC'), 'NOMOVE_ZOC', hkText,
6052 HelpDlg.TextIndex('MOVEMENT'));
6053 eTreaty:
6054 if MyMap[ToLoc] and (fUnit or fOwned) <> fUnit
6055 then { no enemy unit -- move }
6056 SoundMessage(Tribe[MyRO.Territory[ToLoc]].TPhrase('PEACE_NOMOVE'),
6057 'NOMOVE_TREATY')
6058 else
6059 SoundMessage(Tribe[MyRO.EnemyUn[euix].Owner]
6060 .TPhrase('PEACE_NOATTACK'), 'NOMOVE_TREATY');
6061 eDomainMismatch:
6062 begin
6063 if (MyModel[MyUn[UnFocus].mix].Domain < dSea) and
6064 (MyMap[ToLoc] and (fUnit or fOwned) = fUnit or fOwned) then
6065 begin // false load attempt
6066 ToShip := False;
6067 ToTransport := False;
6068 for uix := 0 to MyRO.nUn - 1 do
6069 if (MyUn[uix].Loc = ToLoc) and
6070 (MyModel[MyUn[uix].mix].Domain = dSea) then
6071 begin
6072 ToShip := True;
6073 if MyModel[MyUn[uix].mix].Cap[mcSeaTrans] > 0 then
6074 ToTransport := True;
6075 end;
6076 if ToTransport then
6077 SoundMessage(Phrases.Lookup('FULLTRANSPORT'), 'NOMOVE_DEFAULT')
6078 else if ToShip then
6079 SoundMessage(Phrases.Lookup('NOTRANSPORT'), 'NOMOVE_DEFAULT')
6080 else
6081 Play('NOMOVE_DOMAIN');
6082 end
6083 else
6084 Play('NOMOVE_DOMAIN');
6085 end
6086 else
6087 Play('NOMOVE_DEFAULT');
6088 end;
6089 Exit;
6090 end;
6091
6092 if ((Result = eWon) or (Result = eLost) or (Result = eBloody)) and
6093 (MyUn[UnFocus].Movement < 100) and
6094 (MyModel[MyUn[UnFocus].mix].Cap[mcWill] = 0) then
6095 begin
6096 if SimpleQuery(mkYesNo, Format(Phrases.Lookup('FASTATTACK'),
6097 [MyUn[UnFocus].Movement]), 'NOMOVE_TIME') <> mrOK then
6098 begin
6099 Result := eInvalid;
6100 Exit;
6101 end;
6102 Update; // remove message box from screen
6103 end;
6104
6105 OldUnrest := False;
6106 NewUnrest := False;
6107 if (Result >= rExecuted) and (Result and rUnitRemoved = 0) and
6108 (MyMap[ToLoc] and (fUnit or fOwned) <> fUnit) then
6109 begin
6110 OldUnrest := UnrestAtLoc(UnFocus, FromLoc);
6111 NewUnrest := UnrestAtLoc(UnFocus, ToLoc);
6112 if NewUnrest > OldUnrest then
6113 begin
6114 if MyRO.Government = gDemocracy then
6115 begin
6116 QueryItem := 'UNREST_NOTOWN';
6117 p1 := Me;
6118 end
6119 else
6120 begin
6121 QueryItem := 'UNREST_FOREIGN';
6122 p1 := MyRO.Territory[ToLoc];
6123 end;
6124 with MessgExDlg do
6125 begin
6126 MessgText := Format(Tribe[p1].TPhrase(QueryItem),
6127 [Phrases.Lookup('GOVERNMENT', MyRO.Government)]);
6128 Kind := mkYesNo;
6129 IconKind := mikImp;
6130 IconIndex := imPalace;
6131 ShowModal;
6132 if ModalResult <> mrOK then
6133 begin
6134 Result := eInvalid;
6135 Exit;
6136 end;
6137 end;
6138 Update; // remove message box from screen
6139 end;
6140 end;
6141
6142 if (Result >= rExecuted) and (MyModel[MyUn[UnFocus].mix].Domain = dAir) and
6143 (MyUn[UnFocus].Status and usToldNoReturn = 0) then
6144 begin // can plane return?
6145 PlaneReturnData.Fuel := MyUn[UnFocus].Fuel;
6146 if (MyMap[ToLoc] and (fUnit or fOwned) = fUnit) or
6147 (MyMap[ToLoc] and (fCity or fOwned) = fCity) then
6148 begin // attack/expel/bombard -> 100MP
6149 PlaneReturnData.Loc := FromLoc;
6150 PlaneReturnData.Movement := MyUn[UnFocus].Movement - 100;
6151 if PlaneReturnData.Movement < 0 then
6152 PlaneReturnData.Movement := 0;
6153 end
6154 else // move
6155 begin
6156 PlaneReturnData.Loc := ToLoc;
6157 if dx and 1 <> 0 then
6158 PlaneReturnData.Movement := MyUn[UnFocus].Movement - 100
6159 else
6160 PlaneReturnData.Movement := MyUn[UnFocus].Movement - 150;
6161 end;
6162 if Server(sGetPlaneReturn, Me, UnFocus, PlaneReturnData) = eNoWay then
6163 begin
6164 if MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_Glider then
6165 QueryItem := 'LOWFUEL_GLIDER'
6166 else
6167 QueryItem := 'LOWFUEL';
6168 if SimpleQuery(mkYesNo, Phrases.Lookup(QueryItem), 'WARNING_LOWSUPPORT')
6169 <> mrOK then
6170 begin
6171 Result := eInvalid;
6172 Exit;
6173 end;
6174 Update; // remove message box from screen
6175 MyUn[UnFocus].Status := MyUn[UnFocus].Status or usToldNoReturn;
6176 end;
6177 end;
6178
6179 if Result = eMissionDone then
6180 begin
6181 ModalSelectDlg.ShowNewContent(wmModal, kMission);
6182 Update; // dialog still on screen
6183 Mission := ModalSelectDlg.Result;
6184 if Mission < 0 then
6185 Exit;
6186 Server(sSetSpyMission + Mission shl 4, Me, 0, nil^);
6187 end;
6188
6189 CityCaptured := False;
6190 if Result = eNoTime_Move then
6191 Play('NOMOVE_TIME')
6192 else
6193 begin
6194 NeedEcoUpdate := False;
6195 DestinationMarkON := False;
6196 PaintDestination;
6197 if Result and rUnitRemoved <> 0 then
6198 CityOptimizer_BeforeRemoveUnit(UnFocus);
6199 IsAttack := (Result = eBombarded) or (Result <> eMissionDone) and
6200 (MyMap[ToLoc] and (fUnit or fOwned) = fUnit);
6201 if not IsAttack then
6202 begin // move
6203 cix := MyRO.nCity - 1; { look for own city at dest location }
6204 while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
6205 Dec(cix);
6206 if (Result <> eMissionDone) and (MyMap[ToLoc] and fCity <> 0) and (cix < 0)
6207 then
6208 CityCaptured := True;
6209 Result := Server(sMoveUnit + DirCode, Me, UnFocus, nil^);
6210 case Result of
6211 eHiddenUnit:
6212 begin
6213 Play('NOMOVE_SUBMARINE');
6214 PaintLoc(ToLoc);
6215 end;
6216 eStealthUnit:
6217 begin
6218 Play('NOMOVE_STEALTH');
6219 PaintLoc(ToLoc);
6220 end;
6221 eZOC_EnemySpotted:
6222 begin
6223 Play('NOMOVE_ZOC');
6224 PaintLoc(ToLoc, 1);
6225 end;
6226 rExecuted..MaxInt:
6227 begin
6228 if Result and rUnitRemoved <> 0 then
6229 UnFocus := -1 // unit died
6230 else
6231 begin
6232 Assert(UnFocus >= 0);
6233 MyUn[UnFocus].Status := MyUn[UnFocus].Status and
6234 not (usStay or usRecover);
6235 for uix := 0 to MyRO.nUn - 1 do
6236 if MyUn[uix].Master = UnFocus then
6237 MyUn[uix].Status := MyUn[uix].Status and not usWaiting;
6238 if CityCaptured and
6239 (MyRO.Government in [gRepublic, gDemocracy, gFuture]) then
6240 begin // borders have moved, unrest might have changed in any city
6241 CityOptimizer_BeginOfTurn;
6242 NeedEcoUpdate := True;
6243 end
6244 else
6245 begin
6246 if OldUnrest <> NewUnrest then
6247 begin
6248 CityOptimizer_CityChange(MyUn[UnFocus].Home);
6249 for uix := 0 to MyRO.nUn - 1 do
6250 if MyUn[uix].Master = UnFocus then
6251 CityOptimizer_CityChange(MyUn[uix].Home);
6252 NeedEcoUpdate := True;
6253 end;
6254 if (MyRO.Government = gDespotism) and
6255 (MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_TownGuard) then
6256 begin
6257 if MyMap[FromLoc] and fCity <> 0 then
6258 begin // town guard moved out of city in despotism -- reoptimize!
6259 cixChanged := MyRO.nCity - 1;
6260 while (cixChanged >= 0) and
6261 (MyCity[cixChanged].Loc <> FromLoc) do
6262 Dec(cixChanged);
6263 Assert(cixChanged >= 0);
6264 if cixChanged >= 0 then
6265 begin
6266 CityOptimizer_CityChange(cixChanged);
6267 NeedEcoUpdate := True;
6268 end;
6269 end;
6270 if (MyMap[ToLoc] and fCity <> 0) and not CityCaptured then
6271 begin // town guard moved into city in despotism -- reoptimize!
6272 cixChanged := MyRO.nCity - 1;
6273 while (cixChanged >= 0) and
6274 (MyCity[cixChanged].Loc <> ToLoc) do
6275 Dec(cixChanged);
6276 Assert(cixChanged >= 0);
6277 if cixChanged >= 0 then
6278 begin
6279 CityOptimizer_CityChange(cixChanged);
6280 NeedEcoUpdate := True;
6281 end;
6282 end;
6283 end;
6284 end;
6285 end;
6286 end;
6287 else
6288 Assert(False);
6289 end;
6290 SetTroopLoc(ToLoc);
6291 end
6292 else
6293 begin { enemy unit -- attack }
6294 if Result = eBombarded then
6295 Defender := MyRO.Territory[ToLoc]
6296 else
6297 Defender := MyRO.EnemyUn[euix].Owner;
6298 { if MyRO.Treaty[Defender]=trCeaseFire then
6299 if SimpleQuery(mkYesNo,Phrases.Lookup('FRCANCELQUERY_CEASEFIRE'),
6300 'MSG_DEFAULT')<>mrOK then
6301 Exit; }
6302 if (Options and muNoSuicideCheck = 0) and (Result and rUnitRemoved <> 0)
6303 and (Result <> eMissionDone) then
6304 begin // suicide query
6305 with MyUn[UnFocus], BattleDlg.Forecast do
6306 begin
6307 pAtt := Me;
6308 mixAtt := mix;
6309 HealthAtt := Health;
6310 ExpAtt := Exp;
6311 FlagsAtt := Flags;
6312 end;
6313 BattleDlg.Forecast.Movement := MyUn[UnFocus].Movement;
6314 Server(sGetBattleForecastEx, Me, ToLoc, BattleDlg.Forecast);
6315 BattleDlg.uix := UnFocus;
6316 BattleDlg.ToLoc := ToLoc;
6317 BattleDlg.IsSuicideQuery := True;
6318 BattleDlg.ShowModal;
6319 if BattleDlg.ModalResult <> mrOK then
6320 Exit;
6321 end;
6322
6323 cixChanged := -1;
6324 if (Result and rUnitRemoved <> 0) and (MyRO.Government = gDespotism) and
6325 (MyModel[MyUn[UnFocus].mix].Kind = mkSpecial_TownGuard) and
6326 (MyMap[FromLoc] and fCity <> 0) then
6327 begin // town guard died in city in despotism -- reoptimize!
6328 cixChanged := MyRO.nCity - 1;
6329 while (cixChanged >= 0) and (MyCity[cixChanged].Loc <> FromLoc) do
6330 Dec(cixChanged);
6331 Assert(cixChanged >= 0);
6332 end;
6333
6334 for I := 0 to MyRO.nEnemyModel - 1 do
6335 LostArmy[I] := MyRO.EnemyModel[I].Lost;
6336 OldToTile := MyMap[ToLoc];
6337 Result := Server(sMoveUnit + DirCode, Me, UnFocus, nil^);
6338 nLostArmy := 0;
6339 for I := 0 to MyRO.nEnemyModel - 1 do
6340 begin
6341 LostArmy[I] := MyRO.EnemyModel[I].Lost - LostArmy[I];
6342 Inc(nLostArmy, LostArmy[I]);
6343 end;
6344 if Result and rUnitRemoved <> 0 then
6345 begin
6346 UnFocus := -1;
6347 SetTroopLoc(FromLoc);
6348 end;
6349 if (OldToTile and not MyMap[ToLoc] and fCity <> 0) and
6350 (MyRO.Government in [gRepublic, gDemocracy, gFuture]) then
6351 begin // city was destroyed, borders have moved, unrest might have changed in any city
6352 CityOptimizer_BeginOfTurn;
6353 NeedEcoUpdate := True;
6354 end else begin
6355 if cixChanged >= 0 then
6356 begin
6357 CityOptimizer_CityChange(cixChanged);
6358 NeedEcoUpdate := True;
6359 end;
6360 if (Result = eWon) or (Result = eBloody) or (Result = eExpelled) then
6361 begin
6362 CityOptimizer_TileBecomesAvailable(ToLoc);
6363 NeedEcoUpdate := True;
6364 end;
6365 end;
6366 if nLostArmy > 1 then
6367 begin
6368 with MessgExDlg do
6369 begin
6370 Kind := mkOk;
6371 IconKind := mikEnemyArmy;
6372 MessgText := Tribe[Defender].TString(Phrases.Lookup('ARMYLOST',
6373 MyRO.EnemyModel[MyRO.EnemyUn[euix].emix].Domain));
6374 ShowModal;
6375 end;
6376 end;
6377 end;
6378 if Result and rUnitRemoved <> 0 then
6379 begin
6380 CityOptimizer_AfterRemoveUnit;
6381 ListDlg.RemoveUnit;
6382 NeedEcoUpdate := True;
6383 end;
6384 if NeedEcoUpdate then
6385 begin
6386 UpdateViews(True);
6387 Update;
6388 end;
6389 end;
6390
6391 if Result = eMissionDone then
6392 begin
6393 p1 := MyRO.Territory[ToLoc];
6394 case Mission of
6395 smStealMap:
6396 begin
6397 MapValid := False;
6398 PaintAllMaps
6399 end;
6400 smStealCivilReport:
6401 TribeMessage(p1, Tribe[p1].TPhrase('DOSSIER_PREPARED'), '');
6402 smStealMilReport:
6403 ListDlg.ShowNewContent_MilReport(wmPersistent, p1);
6404 end;
6405 end;
6406
6407 if UnFocus >= 0 then
6408 CheckToldNoReturn(UnFocus);
6409
6410 NeedRepaintPanel := False;
6411 if Result >= rExecuted then
6412 begin
6413 if CityCaptured and (MyMap[ToLoc] and fCity = 0) then
6414 begin // city destroyed
6415 for I := 0 to nWonder - 1 do { tell about destroyed wonders }
6416 if (MyRO.Wonder[I].CityID = WonderDestroyed) and (MyData.ToldWonders[I].CityID <> WonderDestroyed)
6417 then
6418 with MessgExDlg do
6419 begin
6420 if WondersDlg.Visible then
6421 WondersDlg.SmartUpdateContent(False);
6422 OpenSound := 'WONDER_DESTROYED';
6423 MessgText := Format(Phrases.Lookup('WONDERDEST'),
6424 [Phrases.Lookup('IMPROVEMENTS', I)]);
6425 Kind := mkOkHelp;
6426 HelpKind := hkImp;
6427 HelpNo := I;
6428 IconKind := mikImp;
6429 IconIndex := I;
6430 ShowModal;
6431 MyData.ToldWonders[I] := MyRO.Wonder[I];
6432 end;
6433 end;
6434 if CityCaptured and (MyMap[ToLoc] and fCity <> 0) then
6435 begin // city captured
6436 ListDlg.AddCity;
6437 for I := 0 to nWonder - 1 do { tell about capture of wonders }
6438 if MyRO.City[MyRO.nCity - 1].Built[I] > 0 then
6439 with MessgExDlg do
6440 begin
6441 if WondersDlg.Visible then
6442 WondersDlg.SmartUpdateContent(False);
6443 OpenSound := 'WONDER_CAPTURED';
6444 MessgText := Format(Tribe[Me].TPhrase('WONDERCAPTOWN'),
6445 [Phrases.Lookup('IMPROVEMENTS', I)]);
6446 Kind := mkOkHelp;
6447 HelpKind := hkImp;
6448 HelpNo := I;
6449 IconKind := mikImp;
6450 IconIndex := I;
6451 ShowModal;
6452 MyData.ToldWonders[I] := MyRO.Wonder[I];
6453 end;
6454
6455 if MyRO.Happened and phStealTech <> 0 then
6456 begin { Temple of Zeus -- choose advance to steal }
6457 ModalSelectDlg.ShowNewContent(wmModal, kStealTech);
6458 Server(sStealTech, Me, ModalSelectDlg.Result, nil^);
6459 end;
6460 TellNewModels;
6461
6462 cix := MyRO.nCity - 1;
6463 while (cix >= 0) and (MyCity[cix].Loc <> ToLoc) do
6464 Dec(cix);
6465 Assert(cix >= 0);
6466 MyCity[cix].Status := MyCity[cix].Status and not csResourceWeightsMask or
6467 (3 shl 4);
6468 // captured city, set to maximum growth
6469 NewTiles := 1 shl 13; { exploit central tile only }
6470 Server(sSetCityTiles, Me, cix, NewTiles);
6471 end
6472 else
6473 NeedRepaintPanel := True;
6474 end;
6475 TellNewContacts;
6476
6477 if (UnFocus >= 0) and (MyUn[UnFocus].Master >= 0) then
6478 with MyUn[MyUn[UnFocus].Master] do
6479 if Status and usStay <> 0 then
6480 begin
6481 Status := Status and not usStay;
6482 if (Movement >= 100) and (Status and (usRecover or usGoto) = 0) then
6483 Status := Status or usWaiting;
6484 end;
6485 if Options and (muAutoNoWait or muAutoNext) <> 0 then
6486 begin
6487 if (UnFocus >= 0) and ((Result = eNoTime_Move) or UnitExhausted(UnFocus) or
6488 (MyUn[UnFocus].Master >= 0) or (MyModel[MyUn[UnFocus].mix].Domain = dAir)
6489 and ((MyMap[MyUn[UnFocus].Loc] and fCity <> 0)
6490 { aircrafts stop in cities }
6491 or (MyMap[MyUn[UnFocus].Loc] and fTerImp = tiBase))) then
6492 begin
6493 MyUn[UnFocus].Status := MyUn[UnFocus].Status and not usWaiting;
6494 if Options and muAutoNext <> 0 then
6495 if CityCaptured and (MyMap[ToLoc] and fCity <> 0) then
6496 begin
6497 UnFocus := -1;
6498 PaintLoc(ToLoc); // don't show unit in city if not selected
6499 end
6500 else
6501 NextUnit(UnStartLoc, True);
6502 end
6503 else if (UnFocus < 0) and (Options and muAutoNext <> 0) then
6504 NextUnit(UnStartLoc, Result <> eMissionDone);
6505 end;
6506
6507 if NeedRepaintPanel and (UnFocus = UnFocus0) then
6508 if IsAttack then
6509 PanelPaint
6510 else
6511 begin
6512 Assert(Result <> eMissionDone);
6513 CheckTerrainBtnVisible;
6514 FocusOnLoc(ToLoc, flRepaintPanel or flImmUpdate);
6515 end;
6516
6517 if (Result >= rExecuted) and CityCaptured and (MyMap[ToLoc] and fCity <> 0)
6518 then
6519 ZoomToCity(ToLoc, UnFocus < 0, chCaptured); // show captured city
6520end;
6521
6522procedure TMainScreen.MoveOnScreen(ShowMove: TShowMove;
6523 Step0, Step1, nStep: Integer; Restore: Boolean = True);
6524var
6525 ToLoc, xFromLoc, yFromLoc, xToLoc, yToLoc, xFrom, yFrom, xTo, yTo, xMin, yMin,
6526 xRange, yRange, xw1, Step, xMoving, yMoving, SliceCount: Integer;
6527 UnitInfo: TUnitInfo;
6528 Ticks0, Ticks: TDateTime;
6529begin
6530 Timer1.Enabled := False;
6531 Ticks0 := NowPrecise;
6532 with ShowMove do
6533 begin
6534 UnitInfo.Owner := Owner;
6535 UnitInfo.mix := mix;
6536 UnitInfo.Health := Health;
6537 UnitInfo.Job := jNone;
6538 UnitInfo.Flags := Flags;
6539 if Owner <> Me then
6540 UnitInfo.emix := emix;
6541
6542 ToLoc := dLoc(FromLoc, dx, dy);
6543 xToLoc := ToLoc mod G.lx;
6544 yToLoc := ToLoc div G.lx;
6545 xFromLoc := FromLoc mod G.lx;
6546 yFromLoc := FromLoc div G.lx;
6547 if xToLoc > xFromLoc + 2 then
6548 xToLoc := xToLoc - G.lx
6549 else if xToLoc < xFromLoc - 2 then
6550 xToLoc := xToLoc + G.lx;
6551
6552 xw1 := xw + G.lx;
6553 // ((xFromLoc-xw1)*2+yFromLoc and 1+1)*xxt+dx*xxt/2-MapWidth/2 -> min
6554 with MainMap do begin
6555 while Abs(((xFromLoc - xw1 + G.lx) * 2 + yFromLoc and 1 + 1) * xxt * 2 + dx
6556 * xxt - MapWidth) < Abs(((xFromLoc - xw1) * 2 + yFromLoc and 1 + 1) * xxt
6557 * 2 + dx * xxt - MapWidth) do
6558 Dec(xw1, G.lx);
6559
6560 xTo := (xToLoc - xw1) * (xxt * 2) + yToLoc and 1 * xxt + (xxt - xxu);
6561 yTo := (yToLoc - yw) * yyt + (yyt - yyu_anchor);
6562 xFrom := (xFromLoc - xw1) * (xxt * 2) + yFromLoc and 1 * xxt + (xxt - xxu);
6563 yFrom := (yFromLoc - yw) * yyt + (yyt - yyu_anchor);
6564 if xFrom < xTo then begin
6565 xMin := xFrom;
6566 xRange := xTo - xFrom;
6567 end else begin
6568 xMin := xTo;
6569 xRange := xFrom - xTo;
6570 end;
6571 if yFrom < yTo then begin
6572 yMin := yFrom;
6573 yRange := yTo - yFrom;
6574 end else begin
6575 yMin := yTo;
6576 yRange := yFrom - yTo;
6577 end;
6578 Inc(xRange, xxt * 2);
6579 Inc(yRange, yyt * 3);
6580 end;
6581
6582 MainOffscreenPaint;
6583 NoMap.SetOutput(Buffer);
6584 NoMap.SetPaintBounds(0, 0, xRange, yRange);
6585 for Step := 0 to Abs(Step1 - Step0) do
6586 begin
6587 BitBltBitmap(Buffer, 0, 0, xRange, yRange, Offscreen, xMin, yMin);
6588 if Step1 <> Step0 then
6589 begin
6590 xMoving := xFrom +
6591 Round((Step0 + Step * (Step1 - Step0) div Abs(Step1 - Step0)) *
6592 (xTo - xFrom) / nStep);
6593 yMoving := yFrom +
6594 Round((Step0 + Step * (Step1 - Step0) div Abs(Step1 - Step0)) *
6595 (yTo - yFrom) / nStep);
6596 end
6597 else
6598 begin
6599 xMoving := xFrom;
6600 yMoving := yFrom;
6601 end;
6602 NoMap.PaintUnit(xMoving - xMin, yMoving - yMin, UnitInfo, 0);
6603 PaintBufferToScreen(xMin, yMin, xRange, yRange);
6604 {$IFDEF UNIX}
6605 // TODO: Force animation under UNIX. Causes also to process keyboard events
6606 // which can lead to unexpected errors.
6607 KeyboardDisabled := True;
6608 try
6609 Application.ProcessMessages;
6610 finally
6611 KeyboardDisabled := False;
6612 end;
6613 {$ENDIF}
6614
6615 SliceCount := 0;
6616 Ticks := Ticks0;
6617 repeat
6618 if (SliceCount = 0) or
6619 (Round(((Ticks - Ticks0) * 12) / OneMillisecond) * (SliceCount + 1) div SliceCount
6620 < MoveTime) then
6621 begin
6622 if not Idle or (GameMode = cMovie) then
6623 Application.ProcessMessages;
6624 Sleep(1);
6625 Inc(SliceCount);
6626 end;
6627 Ticks := NowPrecise;
6628 until (((Ticks - Ticks0) * 12) / OneMillisecond) >= MoveTime;
6629 Ticks0 := Ticks;
6630 end;
6631 end;
6632 if Restore then
6633 begin
6634 BitBltBitmap(Buffer, 0, 0, xRange, yRange, Offscreen, xMin, yMin);
6635 PaintBufferToScreen(xMin, yMin, xRange, yRange);
6636 end;
6637 BlinkTime := -1;
6638 Timer1.Enabled := True;
6639end;
6640
6641procedure TMainScreen.MoveToLoc(Loc: Integer; CheckSuicide: Boolean);
6642// path finder: move focused unit to loc, start multi-turn goto if too far
6643var
6644 uix, I, MoveOptions, NextLoc, MoveResult: Integer;
6645 MoveAdviceData: TMoveAdviceData;
6646 StopReason: (None, Arrived, Dead, NoTime, EnemySpotted, MoveError);
6647begin
6648 if MyUn[UnFocus].Job > jNone then
6649 Server(sStartJob + jNone shl 4, Me, UnFocus, nil^);
6650 if GetMoveAdvice(UnFocus, Loc, MoveAdviceData) >= rExecuted then
6651 begin
6652 uix := UnFocus;
6653 StopReason := None;
6654 repeat
6655 for I := 0 to MoveAdviceData.nStep - 1 do
6656 begin
6657 if I = MoveAdviceData.nStep - 1 then
6658 MoveOptions := muAutoNext
6659 else
6660 MoveOptions := 0;
6661 NextLoc := dLoc(MyUn[uix].Loc, MoveAdviceData.dx[I],
6662 MoveAdviceData.dy[I]);
6663 if (NextLoc = Loc) or (Loc = maNextCity) and
6664 (MyMap[NextLoc] and fCity <> 0) then
6665 StopReason := Arrived;
6666 if not CheckSuicide and (NextLoc = Loc) then
6667 MoveOptions := MoveOptions or muNoSuicideCheck;
6668 MoveResult := MoveUnit(MoveAdviceData.dx[I], MoveAdviceData.dy[I],
6669 MoveOptions);
6670 if MoveResult < rExecuted then
6671 StopReason := MoveError
6672 else if MoveResult and rUnitRemoved <> 0 then
6673 StopReason := Dead
6674 else if (StopReason = None) and (MoveResult and rEnemySpotted <> 0) then
6675 StopReason := EnemySpotted;
6676 if StopReason <> None then
6677 Break;
6678 end;
6679 if (StopReason = None) and ((MoveAdviceData.nStep < 25) or
6680 (MyRO.Wonder[woShinkansen].EffectiveOwner <> Me)) then
6681 StopReason := NoTime;
6682 if StopReason <> None then
6683 Break;
6684 if GetMoveAdvice(UnFocus, Loc, MoveAdviceData) < rExecuted then
6685 begin
6686 Assert(False);
6687 Break;
6688 end;
6689 until False;
6690
6691 case StopReason of
6692 None:
6693 Assert(False);
6694 Arrived:
6695 MyUn[uix].Status := MyUn[uix].Status and ($FFFF - usGoto);
6696 Dead:
6697 if UnFocus < 0 then
6698 NextUnit(UnStartLoc, False);
6699 else
6700 begin // multi-turn goto
6701 if Loc = maNextCity then
6702 MyUn[uix].Status := MyUn[uix].Status and ($FFFF - usStay - usRecover)
6703 or usGoto + $7FFF shl 16
6704 else
6705 MyUn[uix].Status := MyUn[uix].Status and ($FFFF - usStay - usRecover)
6706 or usGoto + Loc shl 16;
6707 PaintLoc(MyUn[uix].Loc);
6708 if (StopReason = NoTime) and (UnFocus = uix) then
6709 begin
6710 MyUn[uix].Status := MyUn[uix].Status and not usWaiting;
6711 NextUnit(UnStartLoc, True);
6712 end;
6713 end;
6714 end;
6715 end;
6716end;
6717
6718procedure TMainScreen.PanelBoxMouseDown(Sender: TObject; Button: TMouseButton;
6719 Shift: TShiftState; X, Y: Integer);
6720var
6721 I, xMouse, MouseLoc, p1: Integer;
6722begin
6723 if GameMode = cMovie then
6724 Exit;
6725
6726 if Button = TMouseButton.mbLeft then
6727 begin
6728 if (X >= xMini + 2) and (Y >= yMini + 2) and (X < xMini + 2 + 2 * G.lx) and
6729 (Y < yMini + 2 + G.ly) then
6730 if ssShift in Shift then
6731 begin
6732 with MainMap do
6733 xMouse := (xwMini + (X - (xMini + 2) + MapWidth div (xxt * 2) + G.lx)
6734 div 2) mod G.lx;
6735 MouseLoc := xMouse + G.lx * (Y - (yMini + 2));
6736 if MyMap[MouseLoc] and fTerrain <> fUNKNOWN then
6737 begin
6738 p1 := MyRO.Territory[MouseLoc];
6739 if (p1 = Me) or (p1 >= 0) and (MyRO.Treaty[p1] >= trNone) then
6740 NatStatDlg.ShowNewContent(wmPersistent, p1);
6741 end;
6742 end
6743 else
6744 begin
6745 if CityDlg.Visible then
6746 CityDlg.Close;
6747 if UnitStatDlg.Visible then
6748 UnitStatDlg.Close;
6749 Tracking := True;
6750 PanelBoxMouseMove(Sender, Shift + [ssLeft], X, Y);
6751 end
6752 else if (ClientMode <> cEditMap) and (X >= ClientWidth - xPalace) and
6753 (Y >= yPalace) and (X < ClientWidth - xPalace + xSizeBig) and
6754 (Y < yPalace + ySizeBig) then
6755 begin
6756 InitPopup(StatPopup);
6757 if FullScreen then
6758 StatPopup.Popup(Left + ClientWidth - xPalace + xSizeBig + 2,
6759 Top + ClientHeight - PanelHeight + yPalace - 1)
6760 else
6761 StatPopup.Popup(Left + ClientWidth - xPalace + 6,
6762 Top + ClientHeight - PanelHeight + yPalace + ySizeBig +
6763 GetSystemMetrics(SM_CYCAPTION) + 3);
6764 end
6765 (* else if (X >= xAdvisor - 3) and (Y >= yAdvisor - 3)
6766 and (X < xAdvisor + 16 + 3) and (Y < yAdvisor + 16 + 3) and HaveStrategyAdvice then
6767 AdviceBtnClick *)
6768 else if (X >= xTroop + 1) and (Y >= yTroop + 1) and
6769 (X < xTroop + TrRow * TrPitch) and (Y <= yTroop + 55) then
6770 begin
6771 I := (X - xTroop - 1) div TrPitch;
6772 if trix[I] >= 0 then
6773 if ClientMode = cEditMap then
6774 begin
6775 BrushType := trix[I];
6776 UpdateInterface;
6777 PanelPaint;
6778 end
6779 else if (TroopLoc >= 0) then
6780 if MyMap[TroopLoc] and fOwned <> 0 then
6781 begin
6782 if ssShift in Shift then
6783 UnitStatDlg.ShowNewContent_OwnModel(wmPersistent,
6784 MyUn[trix[I]].mix)
6785 else if not Supervising and (ClientMode < scContact) and
6786 (X - xTroop - 1 - I * TrPitch >= 60 - 20) and (Y >= yTroop + 35)
6787 and ((MyUn[trix[I]].Job > jNone) or (MyUn[trix[I]].Status and
6788 (usStay or usRecover or usGoto) <> 0)) then
6789 begin // wake up
6790 MyUn[trix[I]].Status := MyUn[trix[I]].Status and
6791 ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
6792 if MyUn[trix[I]].Job > jNone then
6793 Server(sStartJob + jNone shl 4, Me, trix[I], nil^);
6794 if (UnFocus < 0) and not CityDlg.Visible then
6795 begin
6796 SetUnFocus(trix[I]);
6797 SetTroopLoc(MyUn[trix[I]].Loc);
6798 FocusOnLoc(TroopLoc, flRepaintPanel);
6799 end
6800 else
6801 begin
6802 if CityDlg.Visible and (CityDlg.RestoreUnFocus < 0) then
6803 CityDlg.RestoreUnFocus := trix[I];
6804 PanelPaint;
6805 end;
6806 end
6807 else if (ClientMode < scContact) then
6808 begin
6809 if Supervising then
6810 UnitStatDlg.ShowNewContent_OwnUnit(wmPersistent, trix[I])
6811 else if CityDlg.Visible then
6812 begin
6813 CityDlg.CloseAction := None;
6814 CityDlg.Close;
6815 SumCities(TaxSum, ScienceSum);
6816 SetUnFocus(trix[I]);
6817 end
6818 else
6819 begin
6820 DestinationMarkON := False;
6821 PaintDestination;
6822 UnFocus := trix[I];
6823 UnStartLoc := TroopLoc;
6824 BlinkTime := 0;
6825 BlinkON := False;
6826 PaintLoc(TroopLoc);
6827 end;
6828 if UnFocus >= 0 then
6829 begin
6830 UnitInfoBtn.Visible := True;
6831 UnitBtn.Visible := True;
6832 TurnComplete := False;
6833 EOT.ButtonIndex := eotGray;
6834 end;
6835 CheckTerrainBtnVisible;
6836 PanelPaint;
6837 end;
6838 end
6839 else if Server(sGetUnits, Me, TroopLoc, TrCnt) >= rExecuted then
6840 if ssShift in Shift then
6841 UnitStatDlg.ShowNewContent_EnemyModel(wmPersistent,
6842 MyRO.EnemyUn[MyRO.nEnemyUn + trix[I]].emix) // model info
6843 else
6844 UnitStatDlg.ShowNewContent_EnemyUnit(wmPersistent,
6845 MyRO.nEnemyUn + trix[I]); // unit info
6846 end;
6847 end;
6848end;
6849
6850procedure TMainScreen.SetTroopLoc(Loc: Integer);
6851var
6852 trixFocus, uix, uixDefender: Integer;
6853 Prio: Boolean;
6854 RowsCount: Integer;
6855begin
6856 TroopLoc := Loc;
6857 TrRow := (xRightPanel + 10 - xTroop - GetSystemMetrics(SM_CXVSCROLL) - 19)
6858 div TrPitch;
6859 TrCnt := 0;
6860 trixFocus := -1;
6861 if ClientMode = cEditMap then
6862 TrCnt := Length(BrushTypes)
6863 else if (Loc >= 0) and (MyMap[Loc] and fUnit <> 0) then
6864 if MyMap[Loc] and fOwned <> 0 then
6865 begin // count own units here
6866 Server(sGetDefender, Me, TroopLoc, uixDefender);
6867 for Prio := True downto False do
6868 for uix := 0 to MyRO.nUn - 1 do
6869 if ((uix = uixDefender) = Prio) and (MyUn[uix].Loc = Loc) then
6870 begin
6871 if uix = UnFocus then
6872 trixFocus := TrCnt;
6873 Inc(TrCnt);
6874 end;
6875 end
6876 else // count enemy units here
6877 Server(sGetUnits, Me, Loc, TrCnt);
6878 if TrCnt = 0 then
6879 VerticalScrollBar.Init(0, 1)
6880 else
6881 begin
6882 {$IFDEF UNIX}
6883 RowsCount := Ceil(TrCnt / TrRow);
6884 {$ELSE}
6885 RowsCount := (TrCnt + TrRow - 1) div TrRow - 1;
6886 {$ENDIF}
6887 VerticalScrollBar.Init(RowsCount, 1);
6888 if (VerticalScrollBar.Max >= VerticalScrollBar.PageSize) and (trixFocus >= 0) then
6889 VerticalScrollBar.Position := trixFocus div TrRow;
6890 end;
6891end;
6892
6893(* procedure TMainScreen.ShowMoveHint(ToLoc: Integer; Force: Boolean = False);
6894 var
6895 Step,Loc,x0,y0,xs,ys: Integer;
6896 Info: string;
6897 InfoSize: TSize;
6898 MoveAdvice: TMoveAdviceData;
6899 begin
6900 if (ToLoc<0) or (ToLoc>=G.lx*G.ly)
6901 or (UnFocus<0) or (MyUn[UnFocus].Loc=ToLoc) then
6902 ToLoc:=-1
6903 else
6904 begin
6905 MoveAdvice.ToLoc:=ToLoc;
6906 MoveAdvice.MoreTurns:=0;
6907 MoveAdvice.MaxHostile_MovementLeft:=MyUn[UnFocus].Health-50;
6908 if Server(sGetMoveAdvice,Me,UnFocus,MoveAdvice)<rExecuted then
6909 ToLoc:=-1
6910 end;
6911 if (ToLoc=MoveHintToLoc) and not Force then Exit;
6912 if (ToLoc<>MoveHintToLoc) and (MoveHintToLoc>=0) then
6913 begin invalidate; update end; // clear old hint from screen
6914 MoveHintToLoc:=ToLoc;
6915 if ToLoc<0 then Exit;
6916
6917 with Canvas do
6918 begin
6919 Pen.Color:=$80C0FF;
6920 Pen.Width:=3;
6921 Loc:=MyUn[UnFocus].Loc;
6922 for Step:=0 to MoveAdvice.nStep do
6923 begin
6924 y0:=(Loc+G.lx*1024) div G.lx -1024;
6925 x0:=(Loc+(y0 and 1+G.lx*1024) div 2) mod G.lx;
6926 xs:=(x0-xw)*66+y0 and 1*33-G.lx*66;
6927 while Abs(2*(xs+G.lx*66)-MapWidth)<Abs(2*xs-MapWidth) do
6928 Inc(xs,G.lx*66);
6929 ys:=(y0-yw)*16;
6930 if Step=0 then moveto(xs+33,ys+16)
6931 else lineto(xs+33,ys+16);
6932 if Step<MoveAdvice.nStep then
6933 Loc:=dLoc(Loc,MoveAdvice.dx[Step],MoveAdvice.dy[Step]);
6934 end;
6935 Brush.Color:=$80C0FF;
6936 Info:=' '+IntToStr(88)+' ';
6937 InfoSize:=TextExtent(Info);
6938 TextOut(xs+33-InfoSize.cx div 2, ys+16-InfoSize.cy div 2, Info);
6939 Brush.Style:=bsClear;
6940 end
6941 end; *)
6942
6943procedure TMainScreen.SetDebugMap(P: Integer);
6944begin
6945 MainMap.pDebugMap := P;
6946 MapOptions := MapOptions - [moLocCodes];
6947 mLocCodes.Checked := False;
6948 MapValid := False;
6949 MainOffscreenPaint;
6950end;
6951
6952procedure TMainScreen.SetViewpoint(P: Integer);
6953var
6954 I: Integer;
6955begin
6956 if Supervising and (G.RO[0].Turn > 0) and
6957 ((P = 0) or (1 shl P and G.RO[0].Alive <> 0)) then
6958 begin
6959 ApplyToVisibleForms(faClose);
6960 ItsMeAgain(P);
6961 SumCities(TaxSum, ScienceSum);
6962 for I := 0 to MyRO.nModel - 1 do
6963 if not Assigned(Tribe[Me].ModelPicture[I].HGr) then
6964 InitMyModel(I, True);
6965
6966 SetTroopLoc(-1);
6967 PanelPaint;
6968 MapValid := False;
6969 PaintAllMaps;
6970 end;
6971end;
6972
6973procedure TMainScreen.UpdateKeyShortcuts;
6974begin
6975 mHelp.ShortCut := BHelp.ShortCut;
6976 mUnitStat.ShortCut := BUnitStat.ShortCut;
6977 mCityStat.ShortCut := BCityStat.ShortCut;
6978 mScienceStat.ShortCut := BScienceStat.ShortCut;
6979 mEUnitStat.ShortCut := BEUnitStat.ShortCut;;
6980 mDiagram.ShortCut := BDiagram.ShortCut;
6981 mWonders.ShortCut := BWonders.ShortCut;
6982 mShips.ShortCut := BShips.ShortCut;
6983 mNations.ShortCut := BNations.ShortCut;
6984 mEmpire.ShortCut := BEmpire.ShortCut;
6985 mResign.ShortCut := BResign.ShortCut;
6986 mRandomMap.ShortCut := BRandomMap.ShortCut;
6987 mFillMap.ShortCut := BFillMap.ShortCut;
6988 mDisband.ShortCut := BDisbandUnit.ShortCut;
6989 mFort.ShortCut := BFortify.ShortCut;
6990 mCentre.ShortCut := BCenterUnit.ShortCut;
6991 mStay.ShortCut := BStay.ShortCut;
6992 mNoOrders.ShortCut := BNoOrders.ShortCut;
6993 mPrevUnit.ShortCut := BPrevUnit.ShortCut;
6994 mNextUnit.ShortCut := BNextUnit.ShortCut;
6995 mCancel.ShortCut := BCancel.ShortCut;
6996 mPillage.ShortCut := BPillage.ShortCut;
6997 mTechTree.ShortCut := BTechTree.ShortCut;
6998 mWait.ShortCut := BWait.ShortCut;
6999 mJump.ShortCut := BJump.ShortCut;;
7000 mDebugMap.ShortCut := BDebugMap.ShortCut;
7001 mLocCodes.ShortCut := BLocCodes.ShortCut;
7002 mNames.ShortCut := BNames.ShortCut;
7003 mRun.ShortCut := BRun.ShortCut;
7004 mAirBase.ShortCut := BAirBase.ShortCut;
7005 mCity.ShortCut := BBuildCity.ShortCut;
7006 mEnhance.ShortCut := BEnhance.ShortCut;
7007 mGoOn.ShortCut := BGoOn.ShortCut;
7008 mHome.ShortCut := BHome.ShortCut;
7009 mFarm.ShortCut := BFarmClearIrrigation.ShortCut;
7010 mClear.ShortCut := BFarmClearIrrigation.ShortCut;
7011 mIrrigation.ShortCut := BFarmClearIrrigation.ShortCut;
7012 mLoad.ShortCut := BLoad.ShortCut;
7013 mAfforest.ShortCut := BAfforestMine.ShortCut;
7014 mMine.ShortCut := BAfforestMine.ShortCut;
7015 mCanal.ShortCut := BCanal.ShortCut;
7016 MTrans.ShortCut := BTrans.ShortCut;
7017 mPollution.ShortCut := BPollution.ShortCut;
7018 mRailRoad.ShortCut := BRailRoad.ShortCut;
7019 mRoad.ShortCut := BRailRoad.ShortCut;
7020 mUnload.ShortCut := BUnload.ShortCut;
7021 mRecover.ShortCut := BRecover.ShortCut;
7022 mUtilize.ShortCut := BUtilize.ShortCut;
7023end;
7024
7025procedure TMainScreen.SetFullScreen(Active: Boolean);
7026var
7027 Form: TForm;
7028begin
7029 Form := Self;
7030 if Active then begin
7031 FormFullScreen := True;
7032 if Form.WindowState = TWindowState.wsMaximized then begin
7033 FormRestoredSize := Bounds(Form.RestoredLeft, Form.RestoredTop, Form.RestoredWidth,
7034 Form.RestoredHeight);
7035 end else
7036 if Form.WindowState = TWindowState.wsNormal then begin
7037 FormRestoredSize := Bounds(Form.Left, Form.Top, Form.Width, Form.Height);
7038 end;
7039 FormWindowState := Form.WindowState;
7040 Form.WindowState := TWindowState.wsMaximized;
7041 Form.WindowState := TWindowState.wsNormal;
7042 ShowWindow(Form.Handle, SW_SHOWFULLSCREEN);
7043 {$IFDEF WINDOWS}
7044 Form.BorderStyle := TBorderStyle.bsNone;
7045 {$ENDIF}
7046 end else begin
7047 FormFullScreen := False;
7048 {$IFDEF WINDOWS}
7049 Form.BorderStyle := TBorderStyle.bsSizeable;
7050 {$ENDIF}
7051 ShowWindow(Form.Handle, SW_SHOWNORMAL);
7052 if FormWindowState = TWindowState.wsNormal then begin
7053 Form.WindowState := TWindowState.wsNormal;
7054 Form.BoundsRect := FormRestoredSize;
7055 end else
7056 if FormWindowState = TWindowState.wsMaximized then begin
7057 Form.BoundsRect := FormRestoredSize;
7058 Form.WindowState := TWindowState.wsMaximized;
7059 end;
7060 end;
7061end;
7062
7063procedure TMainScreen.FormKeyDown(Sender: TObject; var Key: Word;
7064 Shift: TShiftState);
7065
7066 procedure MenuClick_Check(Popup: TPopupMenu; Item: TMenuItem);
7067 begin
7068 InitPopup(Popup);
7069 if Item.Visible and Item.Enabled then
7070 Item.Click;
7071 end;
7072
7073 procedure SetViewpointMe(P: Integer);
7074 begin
7075 if P = Me then SetViewpoint(P)
7076 else SetViewpoint(P);
7077 end;
7078
7079 procedure DoMoveUnit(X, Y: Integer);
7080 begin
7081 DestinationMarkON := False;
7082 PaintDestination;
7083 MyUn[UnFocus].Status := MyUn[UnFocus].Status and
7084 ($FFFF - usStay - usRecover - usGoto - usEnhance) or usWaiting;
7085 MoveUnit(X, Y, muAutoNext);
7086 end;
7087
7088 procedure DoMoveMap(X, Y: Integer);
7089 var
7090 ScrollSpeed: Integer;
7091 begin
7092 if mScrollFast.Checked then ScrollSpeed := 2
7093 else ScrollSpeed := 1;
7094 if (X <> 0) or (Y <> 0) then begin
7095 Scroll(X * ScrollSpeed, Y * ScrollSpeed);
7096 end;
7097 end;
7098
7099var
7100 Time0, Time1: TDateTime;
7101 ShortCut: TShortCut;
7102begin
7103 if KeyboardDisabled then Exit;
7104
7105 ShortCut := KeyToShortCut(Key, Shift);
7106
7107 if BFullScreen.Test(ShortCut) then begin
7108 FullScreen := not FullScreen;
7109 SetFullScreen(FullScreen);
7110 end;
7111
7112 if GameMode = cMovie then begin
7113 if BScienceStat.Test(ShortCut) then MenuClick_Check(StatPopup, mScienceStat)
7114 else if BDiagram.Test(ShortCut) then MenuClick_Check(StatPopup, mDiagram)
7115 else if BWonders.Test(ShortCut) then MenuClick_Check(StatPopup, mWonders)
7116 else if BShips.Test(ShortCut) then MenuClick_Check(StatPopup, mShips);
7117 Exit;
7118 end;
7119
7120 if not Idle then Exit;
7121
7122 if ClientMode = cEditMap then begin
7123 if BResign.Test(ShortCut) then mResign.Click
7124 else if BRandomMap.Test(ShortCut) then mRandomMap.Click
7125 else if BFillMap.Test(ShortCut) then mFillMap.Click
7126 else if BHelp.Test(ShortCut) then mHelp.Click;
7127 Exit;
7128 end;
7129
7130 if BEndTurn.Test(ShortCut) then EndTurn
7131 else if BHelp.Test(ShortCut) then mHelp.Click
7132 else if BUnitStat.Test(ShortCut) then MenuClick_Check(StatPopup, mUnitStat)
7133 else if BCityStat.Test(ShortCut) then MenuClick_Check(StatPopup, mCityStat)
7134 else if BScienceStat.Test(ShortCut) then MenuClick_Check(StatPopup, mScienceStat)
7135 else if BEUnitStat.Test(ShortCut) then MenuClick_Check(StatPopup, mEUnitStat)
7136 else if BDiagram.Test(ShortCut) then MenuClick_Check(StatPopup, mDiagram)
7137 else if BWonders.Test(ShortCut) then MenuClick_Check(StatPopup, mWonders)
7138 else if BShips.Test(ShortCut) then MenuClick_Check(StatPopup, mShips)
7139 else if BNations.Test(ShortCut) then MenuClick_Check(StatPopup, mNations)
7140 else if BEmpire.Test(ShortCut) then MenuClick_Check(StatPopup, mEmpire)
7141
7142 else if BSetDebugMap0.Test(ShortCut) then SetDebugMap(-1)
7143 else if BSetDebugMap1.Test(ShortCut) then SetDebugMap(1)
7144 else if BSetDebugMap2.Test(ShortCut) then SetDebugMap(2)
7145 else if BSetDebugMap3.Test(ShortCut) then SetDebugMap(3)
7146 else if BSetDebugMap4.Test(ShortCut) then SetDebugMap(4)
7147 else if BSetDebugMap5.Test(ShortCut) then SetDebugMap(5)
7148 else if BSetDebugMap6.Test(ShortCut) then SetDebugMap(6)
7149 else if BSetDebugMap7.Test(ShortCut) then SetDebugMap(7)
7150 else if BSetDebugMap8.Test(ShortCut) then SetDebugMap(8)
7151 else if BSetDebugMap9.Test(ShortCut) then SetDebugMap(9)
7152
7153 else if BJump.Test(ShortCut) then mJump.Click
7154 else if BDebugMap.Test(ShortCut) then mShowClick(mDebugMap)
7155 else if BLocCodes.Test(ShortCut) then mShowClick(mLocCodes)
7156 else if BLogDlg.Test(ShortCut) then begin
7157 if LogDlg.Visible then LogDlg.Close
7158 else LogDlg.Show;
7159 end
7160 else if BNames.Test(ShortCut) then mNamesClick(mNames)
7161 else if BResign.Test(ShortCut) then MenuClick_Check(GamePopup, mResign)
7162 else if BRun.Test(ShortCut) then mRun.Click
7163 else if BTestMapRepaint.Test(ShortCut) then begin // test map repaint time
7164 Time0 := NowPrecise;
7165 MapValid := False;
7166 MainOffscreenPaint;
7167 Time1 := NowPrecise;
7168 SimpleMessage(Format('Map repaint time: %.3f ms',
7169 [(Time1 - Time0) / OneMillisecond]));
7170 end
7171 else if BSetViewpoint0.Test(ShortCut) then SetViewpointMe(0)
7172 else if BSetViewpoint1.Test(ShortCut) then SetViewpointMe(1)
7173 else if BSetViewpoint2.Test(ShortCut) then SetViewpointMe(2)
7174 else if BSetViewpoint3.Test(ShortCut) then SetViewpointMe(3)
7175 else if BSetViewpoint4.Test(ShortCut) then SetViewpointMe(4)
7176 else if BSetViewpoint5.Test(ShortCut) then SetViewpointMe(5)
7177 else if BSetViewpoint6.Test(ShortCut) then SetViewpointMe(6)
7178 else if BSetViewpoint7.Test(ShortCut) then SetViewpointMe(7)
7179 else if BSetViewpoint8.Test(ShortCut) then SetViewpointMe(8)
7180 else if BSetViewpoint9.Test(ShortCut) then SetViewpointMe(9)
7181
7182 else if BMapBtn0.Test(ShortCut) then MapBtnClick(MapBtn0)
7183 else if BMapBtn1.Test(ShortCut) then MapBtnClick(MapBtn1)
7184 else if BMapBtn4.Test(ShortCut) then MapBtnClick(MapBtn4)
7185 else if BMapBtn5.Test(ShortCut) then MapBtnClick(MapBtn5)
7186 else if BMapBtn6.Test(ShortCut) then MapBtnClick(MapBtn6)
7187 else if BTechTree.Test(ShortCut) then mTechTree.Click
7188 else if BWait.Test(ShortCut) then mWait.Click;
7189
7190 if UnFocus >= 0 then begin
7191 if BDisbandUnit.Test(ShortCut) then mDisband.Click
7192 else if BFortify.Test(ShortCut) then MenuClick_Check(TerrainPopup, mFort)
7193 else if BCenterUnit.Test(ShortCut) then mCentre.Click
7194 else if BStay.Test(ShortCut) then mStay.Click
7195 else if BNoOrders.Test(ShortCut) then mNoOrders.Click
7196 else if BPrevUnit.Test(ShortCut) then mPrevUnit.Click
7197 else if BNextUnit.Test(ShortCut) then mNextUnit.Click
7198 else if BCancel.Test(ShortCut) then MenuClick_Check(UnitPopup, mCancel)
7199 else if BPillage.Test(ShortCut) then MenuClick_Check(UnitPopup, mPillage)
7200 else if BSelectTransport.Test(ShortCut) then MenuClick_Check(UnitPopup, mSelectTransport)
7201 else if BAirBase.Test(ShortCut) then MenuClick_Check(TerrainPopup, mAirBase)
7202 else if BBuildCity.Test(ShortCut) then MenuClick_Check(UnitPopup, mCity)
7203 else if BEnhance.Test(ShortCut) then begin
7204 InitPopup(TerrainPopup);
7205 if mEnhance.Visible and mEnhance.Enabled then mEnhance.Click
7206 else mEnhanceDef.Click;
7207 end
7208 else if BGoOn.Test(ShortCut) then MenuClick_Check(UnitPopup, mGoOn)
7209 else if BHome.Test(ShortCut) then MenuClick_Check(UnitPopup, mHome)
7210 else if BFarmClearIrrigation.Test(ShortCut) then begin
7211 if JobTest(UnFocus, jFarm, [eTreaty]) then
7212 mFarm.Click
7213 else if JobTest(UnFocus, jClear, [eTreaty]) then
7214 mClear.Click
7215 else MenuClick_Check(TerrainPopup, mIrrigation);
7216 end
7217 else if BLoad.Test(ShortCut) then MenuClick_Check(UnitPopup, mLoad)
7218 else if BAfforestMine.Test(ShortCut) then begin
7219 if JobTest(UnFocus, jAfforest, [eTreaty]) then mAfforest.Click
7220 else MenuClick_Check(TerrainPopup, mMine);
7221 end
7222 else if BCanal.Test(ShortCut) then MenuClick_Check(TerrainPopup, mCanal)
7223 else if BTrans.Test(ShortCut) then MenuClick_Check(TerrainPopup, MTrans)
7224 else if BPollution.Test(ShortCut) then MenuClick_Check(TerrainPopup, mPollution)
7225 else if BRailRoad.Test(ShortCut) then begin
7226 if JobTest(UnFocus, jRR, [eTreaty]) then mRailRoad.Click
7227 else MenuClick_Check(TerrainPopup, mRoad);
7228 end
7229 else if BUnload.Test(ShortCut) then MenuClick_Check(UnitPopup, mUnload)
7230 else if BRecover.Test(ShortCut) then MenuClick_Check(UnitPopup, mRecover)
7231 else if BUtilize.Test(ShortCut) then MenuClick_Check(UnitPopup, mUtilize)
7232 // Unit move
7233 else if BUnitMoveLeftDown.Test(ShortCut) then DoMoveUnit(-1, 1)
7234 else if BUnitMoveDown.Test(ShortCut) then DoMoveUnit(0, 2)
7235 else if BUnitMoveRightDown.Test(ShortCut) then DoMoveUnit(1, 1)
7236 else if BUnitMoveLeft.Test(ShortCut) then DoMoveUnit(-2, 0)
7237 else if BUnitMoveRight.Test(ShortCut) then DoMoveUnit(2, 0)
7238 else if BUnitMoveLeftUp.Test(ShortCut) then DoMoveUnit(-1, -1)
7239 else if BUnitMoveUp.Test(ShortCut) then DoMoveUnit(0, -2)
7240 else if BUnitMoveRightUp.Test(ShortCut) then DoMoveUnit(1, -1)
7241 // Map move
7242 else if BMapMoveLeftDown.Test(ShortCut) then DoMoveMap(-1, 1)
7243 else if BMapMoveDown.Test(ShortCut) then DoMoveMap(0, 2)
7244 else if BMapMoveRightDown.Test(ShortCut) then DoMoveMap(1, 1)
7245 else if BMapMoveLeft.Test(ShortCut) then DoMoveMap(-2, 0)
7246 else if BMapMoveRight.Test(ShortCut) then DoMoveMap(2, 0)
7247 else if BMapMoveLeftUp.Test(ShortCut) then DoMoveMap(-1, -1)
7248 else if BMapMoveUp.Test(ShortCut) then DoMoveMap(0, -2)
7249 else if BMapMoveRightUp.Test(ShortCut) then DoMoveMap(1, -1);
7250 end;
7251end;
7252
7253function TMainScreen.DoJob(j0: Integer): Integer;
7254var
7255 Loc0, Movement0: Integer;
7256begin
7257 with MyUn[UnFocus] do
7258 begin
7259 DestinationMarkON := False;
7260 PaintDestination;
7261 Loc0 := Loc;
7262 Movement0 := Movement;
7263 if j0 < 0 then
7264 Result := ProcessEnhancement(UnFocus, MyData.EnhancementJobs)
7265 // terrain enhancement
7266 else
7267 Result := Server(sStartJob + j0 shl 4, Me, UnFocus, nil^);
7268 if Result >= rExecuted then
7269 begin
7270 if Result = eDied then
7271 UnFocus := -1;
7272 PaintLoc(Loc0);
7273 if UnFocus >= 0 then
7274 begin
7275 if (j0 < 0) and (Result <> eJobDone) then
7276 // multi-turn terrain enhancement
7277 Status := Status and ($FFFF - usStay - usRecover - usGoto) or
7278 usEnhance
7279 else
7280 Status := Status and
7281 ($FFFF - usStay - usRecover - usGoto - usEnhance);
7282 if (Job <> jNone) or (Movement0 < 100) then
7283 begin
7284 Status := Status and not usWaiting;
7285 NextUnit(UnStartLoc, True);
7286 end
7287 else
7288 PanelPaint;
7289 end
7290 else
7291 NextUnit(UnStartLoc, True);
7292 end;
7293 end;
7294 case Result of
7295 eNoBridgeBuilding:
7296 SoundMessage(Phrases.Lookup('NOBB'), 'INVALID');
7297 eNoCityTerrain:
7298 SoundMessage(Phrases.Lookup('NOCITY'), 'INVALID');
7299 eTreaty:
7300 SoundMessage(Tribe[MyRO.Territory[Loc0]].TPhrase('PEACE_NOWORK'),
7301 'NOMOVE_TREATY');
7302 else
7303 if Result < rExecuted then
7304 Play('INVALID');
7305 end;
7306end;
7307
7308function TMainScreen.GetBattleDlg: TBattleDlg;
7309begin
7310 if not Assigned(FBattleDlg) then FBattleDlg := TBattleDlg.Create(nil);
7311 Result := FBattleDlg;
7312end;
7313
7314function TMainScreen.GetCityDlg: TCityDlg;
7315begin
7316 if not Assigned(FCityDlg) then begin
7317 FCityDlg := TCityDlg.Create(nil);
7318 FCityDlg.CheckAge;
7319 end;
7320 Result := FCityDlg;
7321end;
7322
7323function TMainScreen.GetCityTypeDlg: TCityTypeDlg;
7324begin
7325 if not Assigned(FCityTypeDlg) then FCityTypeDlg := TCityTypeDlg.Create(nil);
7326 Result := FCityTypeDlg;
7327end;
7328
7329function TMainScreen.GetDiaDlg: TDiaDlg;
7330begin
7331 if not Assigned(FDiaDlg) then begin
7332 FDiaDlg := TDiaDlg.Create(nil);
7333 ArrangeDialog(FDiaDlg);
7334 end;
7335 Result := FDiaDlg;
7336end;
7337
7338function TMainScreen.GetDraftDlg: TDraftDlg;
7339begin
7340 if not Assigned(FDraftDlg) then FDraftDlg := TDraftDlg.Create(nil);
7341 Result := FDraftDlg;
7342end;
7343
7344function TMainScreen.GetEnhanceDlg: TEnhanceDlg;
7345begin
7346 if not Assigned(FEnhanceDlg) then FEnhanceDlg := TEnhanceDlg.Create(nil);
7347 Result := FEnhanceDlg;
7348end;
7349
7350function TMainScreen.GetHelpDlg: THelpDlg;
7351begin
7352 if not Assigned(FHelpDlg) then begin
7353 FHelpDlg := THelpDlg.Create(nil);
7354 ArrangeDialog(FHelpDlg);
7355 if Me <> -1 then
7356 FHelpDlg.Difficulty := G.Difficulty[Me]
7357 else FHelpDlg.Difficulty := 0;
7358 end;
7359 Result := FHelpDlg;
7360end;
7361
7362function TMainScreen.GetListDlg: TListDlg;
7363begin
7364 if not Assigned(FListDlg) then begin
7365 FListDlg := TListDlg.Create(nil);
7366 ArrangeDialog(FListDlg);
7367 end;
7368 Result := FListDlg;
7369end;
7370
7371function TMainScreen.GetMessgExDlg: TMessgExDlg;
7372begin
7373 if not Assigned(FMessgExDlg) then FMessgExDlg := TMessgExDlg.Create(nil);
7374 Result := FMessgExDlg;
7375end;
7376
7377function TMainScreen.GetModalSelectDlg: TModalSelectDlg;
7378begin
7379 if not Assigned(FModalSelectDlg) then FModalSelectDlg := TModalSelectDlg.Create(nil);
7380 Result := FModalSelectDlg;
7381end;
7382
7383function TMainScreen.GetNatStatDlg: TNatStatDlg;
7384begin
7385 if not Assigned(FNatStatDlg) then begin
7386 FNatStatDlg := TNatStatDlg.Create(nil);
7387 ArrangeDialog(FNatStatDlg);
7388 FNatStatDlg.CheckAge;
7389 end;
7390 Result := FNatStatDlg;
7391end;
7392
7393function TMainScreen.GetNegoDlg: TNegoDlg;
7394begin
7395 if not Assigned(FNegoDlg) then FNegoDlg := TNegoDlg.Create(nil);
7396 Result := FNegoDlg;
7397end;
7398
7399function TMainScreen.GetRatesDlg: TRatesDlg;
7400begin
7401 if not Assigned(FRatesDlg) then FRatesDlg := TRatesDlg.Create(nil);
7402 Result := FRatesDlg;
7403end;
7404
7405function TMainScreen.GetTechTreeDlg: TTechTreeDlg;
7406begin
7407 if not Assigned(FTechTreeDlg) then FTechTreeDlg := TTechTreeDlg.Create(nil);
7408 Result := FTechTreeDlg;
7409end;
7410
7411procedure TMainScreen.mDisbandOrUtilizeClick(Sender: TObject);
7412var
7413 Loc0: Integer;
7414begin
7415 if UnFocus >= 0 then
7416 with TUn(MyUn[UnFocus]) do begin
7417 if (Sender = mUtilize) and
7418 not (Server(sRemoveUnit - sExecute, Me, UnFocus, nil^) = eUtilized) then
7419 begin
7420 SimpleMessage(Phrases2.Lookup('SHIP_UTILIZE'));
7421 // freight for colony ship is the only case in which the command is
7422 // available to player though not valid
7423 Exit;
7424 end;
7425 if (Sender = mUtilize) and (Health < 100) then
7426 if SimpleQuery(mkYesNo, Phrases.Lookup('DAMAGED_UTILIZE'), '') <> mrOK
7427 then
7428 Exit;
7429 Loc0 := Loc;
7430 CityOptimizer_BeforeRemoveUnit(UnFocus);
7431 if Server(sRemoveUnit, Me, UnFocus, nil^) = eUtilized then
7432 Play('CITY_UTILIZE')
7433 else
7434 Play('DISBAND');
7435 CityOptimizer_AfterRemoveUnit;
7436 SetTroopLoc(Loc0);
7437 UpdateViews(True);
7438 DestinationMarkON := False;
7439 PaintDestination;
7440 UnFocus := -1;
7441 PaintLoc(Loc0);
7442 NextUnit(UnStartLoc, True);
7443 end;
7444end;
7445
7446procedure TMainScreen.InitPopup(Popup: TPopupMenu);
7447var
7448 I, p1, Tile, Test: Integer;
7449 NoSuper, Extended, Multi, NeedSep, HaveCities: Boolean;
7450 LastSep, M: TMenuItem;
7451 mox: ^TModel;
7452begin
7453 NoSuper := not Supervising and (1 shl Me and MyRO.Alive <> 0);
7454 HaveCities := False;
7455 for I := 0 to MyRO.nCity - 1 do
7456 if MyCity[I].Loc >= 0 then
7457 begin
7458 HaveCities := True;
7459 Break;
7460 end;
7461 if Popup = GamePopup then
7462 begin
7463 mTechTree.Visible := ClientMode <> cEditMap;
7464 mResign.Enabled := Supervising or (Me = 0) and (ClientMode < scContact);
7465 mRandomMap.Visible := (ClientMode = cEditMap) and
7466 (Server(sMapGeneratorRequest, Me, 0, nil^) = eOK);
7467 mFillMap.Visible := mRandomMap.Visible;
7468 mOptions.Visible := ClientMode <> cEditMap;
7469 mManip.Visible := ClientMode <> cEditMap;
7470 if ClientMode <> cEditMap then
7471 begin
7472 mWaitTurn.Visible := NoSuper;
7473 mRep.Visible := NoSuper;
7474 mRepList.Visible := NoSuper;
7475 mRepScreens.Visible := NoSuper;
7476 N10.Visible := NoSuper;
7477 mOwnMovement.Visible := NoSuper;
7478 mAllyMovement.Visible := NoSuper;
7479 case SoundMode of
7480 smOff:
7481 mSoundOff.Checked := True;
7482 smOn:
7483 mSoundOn.Checked := True;
7484 smOnAlt:
7485 mSoundOnAlt.Checked := True;
7486 end;
7487
7488 for I := 0 to nTestFlags - 1 do
7489 mManip[I].Checked := MyRO.TestFlags and (1 shl I) <> 0;
7490 mManip.Enabled := Supervising or (Me = 0);
7491
7492 Multi := False;
7493 for p1 := 1 to nPl - 1 do
7494 if G.RO[p1] <> nil then begin
7495 Multi := True;
7496 Break;
7497 end;
7498 mEnemyMovement.Visible := not Multi;
7499 end;
7500 mMacro.Visible := NoSuper and (ClientMode < scContact);
7501 if NoSuper and (ClientMode < scContact) then
7502 begin
7503 mCityTypes.Enabled := False;
7504 // check if city types already usefull:
7505 if MyRO.nCity > 0 then
7506 for I := nWonder to nImp - 1 do
7507 if (I <> imTrGoods) and (Imp[I].Kind = ikCommon) and
7508 (Imp[I].Preq <> preNA) and
7509 ((Imp[I].Preq = preNone) or (MyRO.Tech[Imp[I].Preq] >= tsApplicable))
7510 then
7511 begin
7512 mCityTypes.Enabled := True;
7513 Break
7514 end;
7515 end;
7516 mViewpoint.Visible := (ClientMode <> cEditMap) and Supervising;
7517 mViewpoint.Enabled := G.RO[0].Turn > 0;
7518 if Supervising then
7519 begin
7520 EmptyMenu(mViewpoint);
7521 for p1 := 0 to nPl - 1 do
7522 if (p1 = 0) or (1 shl p1 and G.RO[0].Alive <> 0) then
7523 begin
7524 M := TMenuItem.Create(mViewpoint);
7525 if p1 = 0 then
7526 M.Caption := Phrases.Lookup('SUPER')
7527 else
7528 M.Caption := Tribe[p1].TString(Phrases2.Lookup('BELONG'));
7529 M.Tag := p1;
7530 M.OnClick := ViewpointClick;
7531 if p1 < 10 then
7532 M.ShortCut := ShortCut(48 + p1, [ssCtrl]);
7533 M.RadioItem := True;
7534 if p1 = Me then
7535 M.Checked := True;
7536 mViewpoint.Add(M);
7537 end
7538 end;
7539 mDebugMap.Visible := (ClientMode <> cEditMap) and Supervising;
7540 if Supervising then
7541 begin
7542 EmptyMenu(mDebugMap);
7543 for p1 := 0 to nPl - 1 do
7544 if (p1 = 0) or (1 shl p1 and G.RO[0].Alive <> 0) then
7545 begin
7546 M := TMenuItem.Create(mDebugMap);
7547 if p1 = 0 then
7548 M.Caption := Phrases2.Lookup('MENU_DEBUGMAPOFF')
7549 else
7550 M.Caption := Tribe[p1].TString(Phrases2.Lookup('BELONG'));
7551 if p1 = 0 then
7552 M.Tag := -1
7553 else
7554 M.Tag := p1;
7555 M.OnClick := DebugMapClick;
7556 if p1 < 10 then
7557 M.ShortCut := ShortCut(48 + p1, [ssAlt]);
7558 M.RadioItem := True;
7559 if M.Tag = MainMap.pDebugMap then
7560 M.Checked := True;
7561 mDebugMap.Add(M);
7562 end;
7563 end;
7564 mSmallTiles.Checked := MainMap.TileSize = tsSmall;
7565 mNormalTiles.Checked := MainMap.TileSize = tsMedium;
7566 mBigTiles.Checked := MainMap.TileSize = tsBig;
7567 end
7568 else if Popup = StatPopup then
7569 begin
7570 mEmpire.Visible := NoSuper;
7571 mEmpire.Enabled := MyRO.Government <> gAnarchy;
7572 mRevolution.Visible := NoSuper;
7573 mRevolution.Enabled := (MyRO.Government <> gAnarchy) and
7574 (ClientMode < scContact);
7575 mUnitStat.Enabled := NoSuper or (MyRO.Turn > 0);
7576 mCityStat.Visible := 1 shl Me and MyRO.Alive <> 0;
7577 mCityStat.Enabled := HaveCities;
7578 mScienceStat.Visible := True;
7579 mScienceStat.Enabled := not NoSuper or (MyRO.ResearchTech >= 0) or
7580 (MyRO.Happened and phTech <> 0) or (MyRO.Happened and phGameEnd <> 0)
7581 // no researchtech in case just completed
7582 or (MyRO.TestFlags and (tfAllTechs or tfUncover or tfAllContact) <> 0);
7583 mEUnitStat.Enabled := MyRO.nEnemyModel > 0;
7584 { mWonders.Enabled:= False;
7585 for I := 0 to nWonder - 1 do if MyRO.Wonder[I].CityID <> WonderNotBuiltYet then
7586 mWonders.Enabled := True; }
7587 mDiagram.Enabled := MyRO.Turn >= 2;
7588 mShips.Enabled := False;
7589 for p1 := 0 to nPl - 1 do
7590 if MyRO.Ship[p1].Parts[spComp] + MyRO.Ship[p1].Parts[spPow] +
7591 MyRO.Ship[p1].Parts[spHab] > 0 then begin
7592 mShips.Enabled := True;
7593 Break;
7594 end;
7595 end
7596 else if Popup = UnitPopup then
7597 begin
7598 mox := @MyModel[MyUn[UnFocus].mix];
7599 Tile := MyMap[MyUn[UnFocus].Loc];
7600 Extended := Tile and fCity = 0;
7601 if Extended then
7602 begin
7603 mCity.Caption := Phrases.Lookup('BTN_FOUND');
7604 mHome.Caption := Phrases.Lookup('BTN_MOVEHOME')
7605 end
7606 else
7607 begin
7608 mCity.Caption := Phrases.Lookup('BTN_ADD');
7609 mHome.Caption := Phrases.Lookup('BTN_SETHOME')
7610 end;
7611
7612 Extended := Extended and ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves)
7613 and (MyRO.Wonder[woPyramids].EffectiveOwner >= 0)) and
7614 (MyUn[UnFocus].Master < 0) and (Tile and fDeadLands = 0);
7615 if (mox.Kind = mkFreight) and (Tile and fCity <> 0) and
7616 not Phrases2FallenBackToEnglish or
7617 (Server(sRemoveUnit - sExecute, Me, UnFocus, nil^) = eUtilized) then
7618 begin
7619 mDisband.Visible := False;
7620 mUtilize.Visible := True;
7621 if mox.Kind = mkFreight then
7622 mUtilize.Caption := Phrases.Lookup('UTILIZE')
7623 else
7624 mUtilize.Caption := Phrases.Lookup('INTEGRATE')
7625 end
7626 else
7627 begin
7628 mDisband.Visible := True;
7629 mUtilize.Visible := False
7630 end;
7631 mGoOn.Visible := MyUn[UnFocus].Status and (usGoto or usWaiting) = usGoto or
7632 usWaiting;
7633 mHome.Visible := HaveCities;
7634 mRecover.Visible := (MyUn[UnFocus].Health < 100) and
7635 (Tile and fTerrain >= fGrass) and
7636 ((MyRO.Wonder[woGardens].EffectiveOwner = Me) or
7637 (Tile and fTerrain <> fArctic) and (Tile and fTerrain <> fDesert)) and
7638 not ((mox.Domain = dAir) and (Tile and fCity = 0) and
7639 (Tile and fTerImp <> tiBase));
7640 mStay.Visible := not ((mox.Domain = dAir) and (Tile and fCity = 0) and
7641 (Tile and fTerImp <> tiBase));
7642 mCity.Visible := Extended and (mox.Kind = mkSettler) or
7643 (Tile and fCity <> 0) and ((mox.Kind in [mkSettler, mkSlaves]) or
7644 (MyUn[UnFocus].Flags and unConscripts <> 0));
7645 mPillage.Visible := (Tile and (fRoad or fRR or fCanal or fTerImp) <> 0) and
7646 (MyUn[UnFocus].Master < 0) and (mox.Domain = dGround);
7647 mCancel.Visible := (MyUn[UnFocus].Job > jNone) or
7648 (MyUn[UnFocus].Status and (usRecover or usGoto) <> 0);
7649
7650 Test := Server(sLoadUnit - sExecute, Me, UnFocus, nil^);
7651 mLoad.Visible := (Test >= rExecuted) or (Test = eNoTime_Load);
7652 mUnload.Visible := (MyUn[UnFocus].Master >= 0) or
7653 (MyUn[UnFocus].TroopLoad + MyUn[UnFocus].AirLoad > 0);
7654 mSelectTransport.Visible := Server(sSelectTransport - sExecute, Me, UnFocus,
7655 nil^) >= rExecuted;
7656 end
7657 else { if Popup=TerrainPopup then }
7658 begin
7659 mox := @MyModel[MyUn[UnFocus].mix];
7660 Tile := MyMap[MyUn[UnFocus].Loc];
7661 Extended := Tile and fCity = 0;
7662
7663 if (Tile and fRiver <> 0) and (MyRO.Tech[adBridgeBuilding] >= tsApplicable)
7664 then
7665 begin
7666 mRoad.Caption := Phrases.Lookup('BTN_BUILDBRIDGE');
7667 mRailRoad.Caption := Phrases.Lookup('BTN_BUILDRRBRIDGE');
7668 end
7669 else
7670 begin
7671 mRoad.Caption := Phrases.Lookup('BTN_BUILDROAD');
7672 mRailRoad.Caption := Phrases.Lookup('BTN_BUILDRR');
7673 end;
7674 if Tile and fTerrain = fForest then
7675 mClear.Caption := Phrases.Lookup('BTN_CLEAR')
7676 else if Tile and fTerrain = fDesert then
7677 mClear.Caption := Phrases.Lookup('BTN_UNDESERT')
7678 else
7679 mClear.Caption := Phrases.Lookup('BTN_DRAIN');
7680
7681 Extended := Extended and ((mox.Kind = mkSettler) or (mox.Kind = mkSlaves)
7682 and (MyRO.Wonder[woPyramids].EffectiveOwner >= 0)) and
7683 (MyUn[UnFocus].Master < 0);
7684 if Extended then
7685 begin
7686 mRoad.Visible := JobTest(UnFocus, jRoad, [eNoBridgeBuilding, eTreaty]);
7687 mRailRoad.Visible := JobTest(UnFocus, jRR, [eNoBridgeBuilding, eTreaty]);
7688 mClear.Visible := JobTest(UnFocus, jClear, [eTreaty]);
7689 mIrrigation.Visible := JobTest(UnFocus, jIrr, [eTreaty]);
7690 mFarm.Visible := JobTest(UnFocus, jFarm, [eTreaty]);
7691 mAfforest.Visible := JobTest(UnFocus, jAfforest, [eTreaty]);
7692 mMine.Visible := JobTest(UnFocus, jMine, [eTreaty]);
7693 MTrans.Visible := JobTest(UnFocus, jTrans, [eTreaty]);
7694 mCanal.Visible := JobTest(UnFocus, jCanal, [eTreaty]);
7695 mFort.Visible := JobTest(UnFocus, jFort, [eTreaty]);
7696 mAirBase.Visible := JobTest(UnFocus, jBase, [eTreaty]);
7697 mPollution.Visible := JobTest(UnFocus, jPoll, [eTreaty]);
7698 mEnhance.Visible := (Tile and fDeadLands = 0) and
7699 (MyData.EnhancementJobs[MyMap[MyUn[UnFocus].Loc] and fTerrain, 0]
7700 <> jNone);
7701 end
7702 else
7703 begin
7704 for I := 0 to Popup.Items.Count - 1 do
7705 Popup.Items[I].Visible := False;
7706 end;
7707 end;
7708
7709 // set menu seperators
7710 LastSep := nil;
7711 NeedSep := False;
7712 for I := 0 to Popup.Items.Count - 1 do
7713 if Popup.Items[I].Caption = '-' then
7714 begin
7715 Popup.Items[I].Visible := NeedSep;
7716 if NeedSep then
7717 LastSep := Popup.Items[I];
7718 NeedSep := False;
7719 end
7720 else if Popup.Items[I].Visible then
7721 NeedSep := True;
7722 if (LastSep <> nil) and not NeedSep then
7723 LastSep.Visible := False;
7724end;
7725
7726procedure TMainScreen.PanelBtnClick(Sender: TObject);
7727var
7728 Popup: TPopupMenu;
7729begin
7730 if Sender = UnitBtn then
7731 Popup := UnitPopup
7732 else { if Sender=TerrainBtn then }
7733 Popup := TerrainPopup;
7734 InitPopup(Popup);
7735 if FullScreen then
7736 Popup.Popup(Left + TControl(Sender).Left, Top + TControl(Sender).Top)
7737 else
7738 Popup.Popup(Left + TControl(Sender).Left + 4, Top + TControl(Sender).Top +
7739 GetSystemMetrics(SM_CYCAPTION) + 4);
7740end;
7741
7742procedure TMainScreen.CityClosed(Activateuix: Integer; StepFocus: Boolean;
7743 SelectFocus: Boolean);
7744begin
7745 if Supervising then
7746 begin
7747 SetTroopLoc(-1);
7748 PanelPaint;
7749 end
7750 else
7751 begin
7752 if Activateuix >= 0 then
7753 begin
7754 SetUnFocus(Activateuix);
7755 SetTroopLoc(MyUn[Activateuix].Loc);
7756 if SelectFocus then
7757 FocusOnLoc(TroopLoc, flRepaintPanel)
7758 else
7759 PanelPaint;
7760 end
7761 else if StepFocus then
7762 NextUnit(TroopLoc, True)
7763 else
7764 begin
7765 SetTroopLoc(-1);
7766 PanelPaint;
7767 end;
7768 end;
7769end;
7770
7771procedure TMainScreen.Toggle(Sender: TObject);
7772begin
7773 TMenuItem(Sender).Checked := not TMenuItem(Sender).Checked;
7774end;
7775
7776procedure TMainScreen.PanelBoxMouseMove(Sender: TObject; Shift: TShiftState;
7777 X, Y: Integer);
7778var
7779 xCentre, yCentre: Integer;
7780begin
7781 if Tracking and (ssLeft in Shift) then
7782 with MainMap do begin
7783 if (X >= xMini + 2) and (Y >= yMini + 2) and (X < xMini + 2 + 2 * G.lx) and
7784 (Y < yMini + 2 + G.ly) then
7785 begin
7786 xCentre := (xwMini + (X - xMini - 2) div 2 + G.lx div 2 +
7787 MapWidth div (xxt * 4)) mod G.lx;
7788 yCentre := (Y - yMini - 2);
7789 xw := (xCentre - MapWidth div (xxt * 4) + G.lx) mod G.lx;
7790 if ywmax <= 0 then
7791 yw := ywcenter
7792 else
7793 begin
7794 yw := (yCentre - MapHeight div (yyt * 2) + 1) and not 1;
7795 if yw < 0 then
7796 yw := 0
7797 else if yw > ywmax then
7798 yw := ywmax;
7799 end;
7800 BitBltBitmap(Buffer, 0, 0, G.lx * 2, G.ly, MiniMap.Bitmap, 0, 0);
7801 if ywmax <= 0 then
7802 Frame(Buffer.Canvas, X - xMini - 2 - MapWidth div (xxt * 2), 0,
7803 X - xMini - 2 + MapWidth div (xxt * 2) - 1, G.ly - 1,
7804 MainTexture.ColorMark, MainTexture.ColorMark)
7805 else
7806 Frame(Buffer.Canvas, X - xMini - 2 - MapWidth div (xxt * 2), yw,
7807 X - xMini - 2 + MapWidth div (xxt * 2) - 1, yw + MapHeight div yyt -
7808 2, MainTexture.ColorMark, MainTexture.ColorMark);
7809 BitBltBitmap(Panel, xMini + 2, yMini + 2, G.lx * 2, G.ly,
7810 Buffer, 0, 0);
7811 MainOffscreenPaint;
7812 RectInvalidate(xMini + 2, TopBarHeight + MapHeight - Overlap + yMini + 2,
7813 xMini + 2 + G.lx * 2, TopBarHeight + MapHeight - Overlap + yMini +
7814 2 + G.ly);
7815 Update;
7816 end;
7817 end
7818 else
7819 Tracking := False;
7820end;
7821
7822procedure TMainScreen.PanelBoxMouseUp(Sender: TObject; Button: TMouseButton;
7823 Shift: TShiftState; X, Y: Integer);
7824begin
7825 if Tracking then
7826 begin
7827 Tracking := False;
7828 xwMini := xw;
7829 ywMini := yw;
7830 MiniMapPaint;
7831 PanelPaint;
7832 end;
7833end;
7834
7835procedure TMainScreen.MapBoxMouseMove(Sender: TObject; Shift: TShiftState;
7836 X, Y: Integer);
7837var
7838 MouseLoc: Integer;
7839begin
7840 xMouse := X;
7841 yMouse := Y;
7842 if (ClientMode = cEditMap) and (ssLeft in Shift) and not Tracking then
7843 begin
7844 MouseLoc := LocationOfScreenPixel(X, Y);
7845 if MouseLoc <> BrushLoc then
7846 MapBoxMouseDown(nil, TMouseButton.mbLeft, Shift, X, Y);
7847 end
7848 (* else if Idle and (UnFocus >= 0) then
7849 begin
7850 qx := (xMouse * 32 + yMouse * 66 + 16 * 66) div(32 * 66) - 1;
7851 qy := (yMouse * 66 - xMouse * 32 - 16 * 66 + 2000 * 33 * 32) div(32 * 66) - 999;
7852 MouseLoc := (xw + (qx - qy + 2048) div 2 - 1024 + G.lx) mod G.lx + G.lx * (yw + qx + qy);
7853 ShowMoveHint(MouseLoc);
7854 end *)
7855end;
7856
7857procedure TMainScreen.mShowClick(Sender: TObject);
7858begin
7859 TMenuItem(Sender).Checked := not TMenuItem(Sender).Checked;
7860 SetMapOptions;
7861 MapValid := False;
7862 PaintAllMaps;
7863end;
7864
7865procedure TMainScreen.mNamesClick(Sender: TObject);
7866var
7867 p1: Integer;
7868begin
7869 mNames.Checked := not mNames.Checked;
7870 GenerateNames := mNames.Checked;
7871 for p1 := 0 to nPl - 1 do
7872 if Tribe[p1] <> nil then
7873 if GenerateNames then
7874 Tribe[p1].NumberName := -1
7875 else
7876 Tribe[p1].NumberName := p1;
7877 MapValid := False;
7878 PaintAll;
7879end;
7880
7881function TMainScreen.IsPanelPixel(X, Y: Integer): Boolean;
7882begin
7883 Result := (Y >= TopBarHeight + MapHeight) or (Y >= ClientHeight - PanelHeight)
7884 and ((X < xMidPanel) or (X >= xRightPanel));
7885end;
7886
7887procedure TMainScreen.FormMouseDown(Sender: TObject; Button: TMouseButton;
7888 Shift: TShiftState; X, Y: Integer);
7889begin
7890 if Idle then
7891 if (X < 40) and (Y < 40) then
7892 begin
7893 if GameMode <> cMovie then
7894 begin
7895 InitPopup(GamePopup);
7896 if FullScreen then
7897 GamePopup.Popup(Left, Top + TopBarHeight - 1)
7898 else
7899 GamePopup.Popup(Left + 4, Top + GetSystemMetrics(SM_CYCAPTION) + 4 +
7900 TopBarHeight - 1);
7901 end;
7902 end
7903 else if IsPanelPixel(X, Y) then
7904 PanelBoxMouseDown(Sender, Button, Shift, X,
7905 Y - (ClientHeight - PanelHeight))
7906 else if (Y >= TopBarHeight) and (X >= MapOffset) and
7907 (X < MapOffset + MapWidth) then
7908 MapBoxMouseDown(Sender, Button, Shift, X - MapOffset, Y - TopBarHeight);
7909end;
7910
7911procedure TMainScreen.FormMouseMove(Sender: TObject; Shift: TShiftState;
7912 X, Y: Integer);
7913begin
7914 if Idle then
7915 if IsPanelPixel(X, Y) then
7916 PanelBoxMouseMove(Sender, Shift, X, Y - (ClientHeight - PanelHeight))
7917 else if (Y >= TopBarHeight) and (X >= MapOffset) and
7918 (X < MapOffset + MapWidth) then
7919 MapBoxMouseMove(Sender, Shift, X - MapOffset, Y - TopBarHeight);
7920end;
7921
7922procedure TMainScreen.FormMouseUp(Sender: TObject; Button: TMouseButton;
7923 Shift: TShiftState; X, Y: Integer);
7924begin
7925 if Idle then
7926 PanelBoxMouseUp(Sender, Button, Shift, X, Y - (ClientHeight - PanelHeight));
7927end;
7928
7929procedure TMainScreen.FormPaint(Sender: TObject);
7930begin
7931 MainOffscreenPaint;
7932 if (MapOffset > 0) or (MapOffset + MapWidth < ClientWidth) then
7933 with Canvas do
7934 begin // pillarbox, make left and right border black
7935 if Me < 0 then
7936 Brush.Color := $000000
7937 else
7938 Brush.Color := EmptySpaceColor;
7939 if xMidPanel > MapOffset then
7940 FillRect(Rect(0, TopBarHeight, MapOffset, TopBarHeight + MapHeight
7941 - Overlap))
7942 else
7943 begin
7944 FillRect(Rect(0, TopBarHeight, xMidPanel, TopBarHeight + MapHeight -
7945 Overlap));
7946 FillRect(Rect(xMidPanel, TopBarHeight, MapOffset,
7947 TopBarHeight + MapHeight));
7948 end;
7949 if xRightPanel < MapOffset + MapWidth then
7950 FillRect(Rect(MapOffset + MapWidth, TopBarHeight, ClientWidth,
7951 TopBarHeight + MapHeight - Overlap))
7952 else
7953 begin
7954 FillRect(Rect(MapOffset + MapWidth, TopBarHeight, xRightPanel,
7955 TopBarHeight + MapHeight));
7956 FillRect(Rect(xRightPanel, TopBarHeight, ClientWidth,
7957 TopBarHeight + MapHeight - Overlap));
7958 end;
7959 Brush.Style := TBrushStyle.bsClear;
7960 end;
7961 BitBltCanvas(Canvas, MapOffset, TopBarHeight, MapWidth, MapHeight - Overlap,
7962 Offscreen.Canvas, 0, 0);
7963 BitBltCanvas(Canvas, 0, 0, ClientWidth, TopBarHeight, TopBar.Canvas,
7964 0, 0);
7965 if xMidPanel > MapOffset then
7966 BitBltCanvas(Canvas, xMidPanel, TopBarHeight + MapHeight - Overlap,
7967 ClientWidth div 2 - xMidPanel, Overlap, Offscreen.Canvas,
7968 xMidPanel - MapOffset, MapHeight - Overlap)
7969 else
7970 BitBltCanvas(Canvas, MapOffset, TopBarHeight + MapHeight - Overlap,
7971 ClientWidth div 2 - MapOffset, Overlap, Offscreen.Canvas, 0,
7972 MapHeight - Overlap);
7973 if xRightPanel < MapOffset + MapWidth then
7974 BitBltCanvas(Canvas, ClientWidth div 2, TopBarHeight + MapHeight - Overlap,
7975 xRightPanel - ClientWidth div 2, Overlap, Offscreen.Canvas,
7976 ClientWidth div 2 - MapOffset, MapHeight - Overlap)
7977 else
7978 BitBltCanvas(Canvas, ClientWidth div 2, TopBarHeight + MapHeight - Overlap,
7979 MapOffset + MapWidth - ClientWidth div 2, Overlap,
7980 Offscreen.Canvas, ClientWidth div 2 - MapOffset,
7981 MapHeight - Overlap);
7982 BitBltCanvas(Canvas, 0, TopBarHeight + MapHeight - Overlap, xMidPanel,
7983 Overlap, Panel.Canvas, 0, 0);
7984 BitBltCanvas(Canvas, xRightPanel, TopBarHeight + MapHeight - Overlap,
7985 Panel.Width - xRightPanel, Overlap, Panel.Canvas, xRightPanel, 0);
7986 BitBltCanvas(Canvas, 0, TopBarHeight + MapHeight, Panel.Width,
7987 PanelHeight - Overlap, Panel.Canvas, 0, Overlap);
7988 if (pLogo >= 0) and (G.RO[pLogo] = nil) and (AILogo[pLogo] <> nil) then
7989 BitBltCanvas(Canvas, xRightPanel + 10 - (16 + 64),
7990 ClientHeight - PanelHeight, 64, 64, AILogo[pLogo].Canvas, 0, 0);
7991end;
7992
7993procedure TMainScreen.RectInvalidate(Left, Top, Rigth, Bottom: Integer);
7994var
7995 r0: HRgn;
7996begin
7997 r0 := CreateRectRgn(Left, Top, Rigth, Bottom);
7998 InvalidateRgn(Handle, r0, False);
7999 DeleteObject(r0);
8000end;
8001
8002procedure TMainScreen.SmartRectInvalidate(Left, Top, Rigth, Bottom: Integer);
8003var
8004 I: Integer;
8005 r0, r1: HRgn;
8006begin
8007 r0 := CreateRectRgn(Left, Top, Rigth, Bottom);
8008 for I := 0 to ControlCount - 1 do
8009 if not (Controls[I] is TArea) and Controls[I].Visible then
8010 begin
8011 with Controls[I].BoundsRect do
8012 r1 := CreateRectRgn(Left, Top, Right, Bottom);
8013 CombineRgn(r0, r0, r1, RGN_DIFF);
8014 DeleteObject(r1);
8015 end;
8016 InvalidateRgn(Handle, r0, False);
8017 DeleteObject(r0);
8018end;
8019
8020procedure TMainScreen.LoadSettings;
8021var
8022 Reg: TRegistry;
8023 DefaultOptionChecked: TSaveOptions;
8024begin
8025 DefaultOptionChecked := [soEnMoves, soSlowMoves, soNames, soRepScreens,
8026 soSoundOn, soScrollSlow, soAlSlowMoves];
8027 Reg := TRegistry.Create;
8028 with Reg do try
8029 OpenKey(AppRegistryKey, False);
8030 if ValueExists('TileSize') then MainMap.TileSize := TTileSize(ReadInteger('TileSize'))
8031 else MainMap.TileSize := tsMedium;
8032 NoMap.TileSize := MainMap.TileSize;
8033 if ValueExists('OptionChecked') then OptionChecked := TSaveOptions(ReadInteger('OptionChecked'))
8034 else OptionChecked := DefaultOptionChecked;
8035 if ValueExists('MapOptionChecked') then MapOptionChecked := TMapOptions(ReadInteger('MapOptionChecked'))
8036 else MapOptionChecked := [moCityNames];
8037 if ValueExists('CityReport') then CityRepMask := Cardinal(ReadInteger('CityReport'))
8038 else CityRepMask := Cardinal(not chPopIncrease and not chNoGrowthWarning and
8039 not chCaptured);
8040 if (not (soScrollFast in OptionChecked)) and (not (soScrollSlow in OptionChecked)) and
8041 (not (soScrollOff in OptionChecked)) then
8042 OptionChecked := OptionChecked + [soScrollSlow];
8043 // old regver with no scrolling
8044 finally
8045 Free;
8046 end;
8047
8048 if soSoundOff in OptionChecked then
8049 SoundMode := smOff
8050 else if soSoundOnAlt in OptionChecked then
8051 SoundMode := smOnAlt
8052 else
8053 SoundMode := smOn;
8054end;
8055
8056procedure TMainScreen.mRepClicked(Sender: TObject);
8057begin
8058 with TMenuItem(Sender) do
8059 begin
8060 Checked := not Checked;
8061 if Checked then
8062 CityRepMask := CityRepMask or (1 shl (Tag shr 8))
8063 else
8064 CityRepMask := CityRepMask and not (1 shl (Tag shr 8));
8065 end;
8066end;
8067
8068procedure TMainScreen.mLogClick(Sender: TObject);
8069begin
8070 LogDlg.Show;
8071end;
8072
8073procedure TMainScreen.FormShow(Sender: TObject);
8074begin
8075 if FullScreen then BoundsRect := Screen.PrimaryMonitor.BoundsRect
8076 else BoundsRect := TermBounds;
8077 FormRestoredSize := TermBounds;
8078 SetFullScreen(FullScreen);
8079 FormResize(nil); // place mini map correctly according to its size
8080 Timer1.Enabled := True;
8081end;
8082
8083procedure TMainScreen.FormClose(Sender: TObject; var Action: TCloseAction);
8084begin
8085 if FullScreen then TermBounds := FormRestoredSize
8086 else TermBounds := BoundsRect;
8087 Timer1.Enabled := False;
8088end;
8089
8090procedure TMainScreen.Radio(Sender: TObject);
8091begin
8092 TMenuItem(Sender).Checked := True;
8093end;
8094
8095procedure TMainScreen.mManipClick(Sender: TObject);
8096var
8097 Flag: Integer;
8098begin
8099 with TMenuItem(Sender) do
8100 begin
8101 Flag := 1 shl (Tag shr 8);
8102 if Checked then
8103 Server(sClearTestFlag, 0, Flag, nil^)
8104 else
8105 begin
8106 Server(sSetTestFlag, 0, Flag, nil^);
8107 Play('CHEAT');
8108 end;
8109 if not Supervising then
8110 begin
8111 if Flag = tfUncover then
8112 begin
8113 MapValid := False;
8114 PaintAllMaps;
8115 end
8116 else if Flag = tfAllTechs then
8117 TellNewModels;
8118 end;
8119 end;
8120end;
8121
8122procedure TMainScreen.MapBtnClick(Sender: TObject);
8123begin
8124 with TButtonC(Sender) do
8125 begin
8126 MapOptionChecked := TMapOptions(Integer(MapOptionChecked) xor (1 shl (Tag shr 8)));
8127 SetMapOptions;
8128 ButtonIndex := Integer(MapOptionChecked) shr (Tag shr 8) and 1 + 2;
8129 end;
8130 if Sender = MapBtn0 then
8131 begin
8132 MiniMapPaint;
8133 PanelPaint;
8134 end // update mini map only
8135 else
8136 begin
8137 MapValid := False;
8138 PaintAllMaps;
8139 end; // update main map
8140end;
8141
8142procedure TMainScreen.GrWallBtnDownChanged(Sender: TObject);
8143begin
8144 if TButtonBase(Sender).Down then
8145 begin
8146 MapOptionChecked := MapOptionChecked + [moGreatWall];
8147 TButtonBase(Sender).Hint := '';
8148 end
8149 else
8150 begin
8151 MapOptionChecked := MapOptionChecked - [moGreatWall];
8152 TButtonBase(Sender).Hint := Phrases.Lookup('CONTROLS',
8153 -1 + TButtonBase(Sender).Tag and $FF);
8154 end;
8155 SetMapOptions;
8156 MapValid := False;
8157 PaintAllMaps;
8158end;
8159
8160procedure TMainScreen.BareBtnDownChanged(Sender: TObject);
8161begin
8162 if TButtonBase(Sender).Down then
8163 begin
8164 MapOptionChecked := MapOptionChecked + [moBareTerrain];
8165 TButtonBase(Sender).Hint := '';
8166 end
8167 else
8168 begin
8169 MapOptionChecked := MapOptionChecked - [moBareTerrain];
8170 TButtonBase(Sender).Hint := Phrases.Lookup('CONTROLS',
8171 -1 + TButtonBase(Sender).Tag and $FF);
8172 end;
8173 SetMapOptions;
8174 MapValid := False;
8175 PaintAllMaps;
8176end;
8177
8178procedure TMainScreen.FormKeyUp(Sender: TObject; var Key: Word;
8179 Shift: TShiftState);
8180begin
8181 if KeyboardDisabled then Exit;
8182
8183 if Idle and (Key = VK_APPS) then
8184 begin
8185 InitPopup(GamePopup);
8186 if FullScreen then
8187 GamePopup.Popup(Left, Top + TopBarHeight - 1)
8188 else
8189 GamePopup.Popup(Left + 4, Top + GetSystemMetrics(SM_CYCAPTION) + 4 +
8190 TopBarHeight - 1);
8191 Exit;
8192 end; // windows menu button calls game menu
8193end;
8194
8195procedure TMainScreen.CreateUnitClick(Sender: TObject);
8196var
8197 p1, mix: Integer;
8198begin
8199 p1 := TComponent(Sender).Tag shr 16;
8200 mix := TComponent(Sender).Tag and $FFFF;
8201 if Server(sCreateUnit + p1 shl 4, Me, mix, EditLoc) >= rExecuted then
8202 PaintLoc(EditLoc);
8203end;
8204
8205procedure TMainScreen.mSoundOffClick(Sender: TObject);
8206begin
8207 SoundMode := smOff;
8208end;
8209
8210procedure TMainScreen.mSoundOnClick(Sender: TObject);
8211begin
8212 SoundMode := smOn;
8213end;
8214
8215procedure TMainScreen.mSoundOnAltClick(Sender: TObject);
8216begin
8217 SoundMode := smOnAlt;
8218end;
8219
8220procedure TMainScreen.UnitInfoBtnClick(Sender: TObject);
8221begin
8222 if UnFocus >= 0 then
8223 UnitStatDlg.ShowNewContent_OwnModel(wmPersistent, MyUn[UnFocus].mix)
8224end;
8225
8226procedure TMainScreen.ViewpointClick(Sender: TObject);
8227begin
8228 SetViewpoint(TMenuItem(Sender).Tag);
8229end;
8230
8231procedure TMainScreen.DebugMapClick(Sender: TObject);
8232begin
8233 SetDebugMap(TMenuItem(Sender).Tag);
8234end;
8235
8236procedure TMainScreen.mSmallTilesClick(Sender: TObject);
8237begin
8238 SetTileSizeCenter(tsSmall);
8239end;
8240
8241procedure TMainScreen.mNormalTilesClick(Sender: TObject);
8242begin
8243 SetTileSizeCenter(tsMedium);
8244end;
8245
8246procedure TMainScreen.mBigTilesClick(Sender: TObject);
8247begin
8248 SetTileSizeCenter(tsBig);
8249end;
8250
8251procedure TMainScreen.SetTileSizeCenter(TileSize: TTileSize);
8252begin
8253 SetTileSize(TileSize, GetCenterLoc, Point(MapWidth div 2, MapHeight div 2));
8254end;
8255
8256procedure TMainScreen.SetTileSize(TileSize: TTileSize; Loc: Integer; MapPos: TPoint);
8257begin
8258 MainMap.TileSize := TileSize;
8259 NoMap.TileSize := TileSize;
8260 LastResizeWidth := -1; // Force repaint on
8261 ResizeControls;
8262 SetMapPos(Loc, MapPos);
8263 PaintAllMaps;
8264 ApplyToVisibleForms(faSmartUpdateContent);
8265end;
8266
8267procedure TMainScreen.SaveMenuItemsState;
8268var
8269 I, J: Integer;
8270begin
8271 if soTellAI in OptionChecked then OptionChecked := [soTellAI]
8272 else OptionChecked := [];
8273 for I := 0 to ComponentCount - 1 do
8274 if Components[I] is TMenuItem then
8275 for J := 0 to Length(SaveOption) - 1 do
8276 if TMenuItem(Components[I]).Checked and
8277 (TMenuItem(Components[I]).Tag = SaveOption[J]) then
8278 OptionChecked := OptionChecked + [TSaveOption(J)];
8279end;
8280
8281procedure TMainScreen.SaveSettings;
8282var
8283 Reg: TRegistry;
8284begin
8285 SaveMenuItemsState;
8286
8287 Reg := TRegistry.Create;
8288 with Reg do
8289 try
8290 OpenKey(AppRegistryKey, True);
8291 WriteInteger('TileSize', Integer(MainMap.TileSize));
8292 WriteInteger('OptionChecked', Integer(OptionChecked));
8293 WriteInteger('MapOptionChecked', Integer(MapOptionChecked));
8294 WriteInteger('CityReport', Integer(CityRepMask));
8295 finally
8296 Free;
8297 end;
8298end;
8299
8300procedure TMainScreen.MovieSpeedBtnClick(Sender: TObject);
8301begin
8302 MovieSpeed := TButtonB(Sender).Tag shr 8;
8303 CheckMovieSpeedBtnState;
8304end;
8305
8306procedure TMainScreen.ResizeControls;
8307var
8308 MiniFrame, MaxMapWidth: Integer;
8309begin
8310 BaseWin.CreateOffscreen(Offscreen, Width, Height);
8311 SmallScreen := Width < 1024;
8312 with MainMap do begin
8313 MaxMapWidth := (G.lx * 2 - 3) * xxt;
8314 // Avoid the same tile being visible left and right
8315 if Width <= MaxMapWidth then begin
8316 MapWidth := Width;
8317 MapOffset := 0;
8318 end else begin
8319 MapWidth := MaxMapWidth;
8320 MapOffset := (Width - MapWidth) div 2;
8321 end;
8322 MapHeight := Height - TopBarHeight - PanelHeight + Overlap;
8323 Panel.SetSize(Width, PanelHeight);
8324 TopBar.SetSize(Width, TopBarHeight);
8325 MiniFrame := (lxmax_xxx - G.ly) div 2;
8326 xMidPanel := (G.lx + MiniFrame) * 2 + 1;
8327 xRightPanel := Width - LeftPanelWidth - 10;
8328 if ClientMode = cEditMap then
8329 TrPitch := 2 * xxt
8330 else
8331 TrPitch := 66;
8332 xMini := MiniFrame - 5;
8333 yMini := (PanelHeight - 26 - lxmax_xxx) div 2 + MiniFrame;
8334 ywmax := (G.ly - MapHeight div yyt + 1) and not 1;
8335 ywcenter := -((MapHeight - yyt * (G.ly - 1)) div (4 * yyt)) * 2;
8336 end;
8337 // only for ywmax <= 0
8338 if ywmax <= 0 then
8339 yw := ywcenter
8340 else if yw < 0 then
8341 yw := 0
8342 else if yw > ywmax then
8343 yw := ywmax;
8344 UnitInfoBtn.Top := Height - 29;
8345 UnitInfoBtn.Left := xMidPanel + 7 + 99;
8346 UnitBtn.Top := Height - 29;
8347 UnitBtn.Left := xMidPanel + 7 + 99 + 31;
8348 TerrainBtn.Top := Height - 29;
8349 TerrainBtn.Left := xMidPanel + 7 + 99 + 62;
8350 MovieSpeed1Btn.Top := Height - 91;
8351 MovieSpeed1Btn.Left := Width div 2 - 62;
8352 MovieSpeed2Btn.Top := Height - 91;
8353 MovieSpeed2Btn.Left := Width div 2 - 62 + 29;
8354 MovieSpeed3Btn.Top := Height - 91;
8355 MovieSpeed3Btn.Left := Width div 2 - 62 + 2 * 29;
8356 MovieSpeed4Btn.Top := Height - 91;
8357 MovieSpeed4Btn.Left := Width div 2 - 62 + 3 * 29 + 12;
8358 EOT.Top := Height - 64;
8359 EOT.Left := Width - 62;
8360 VerticalScrollBar.SetBorderSpacing(Height - yTroop - 24, Width - xRightPanel + 8, 8);
8361 SetWindowPos(VerticalScrollBar.ScrollBar.Handle, 0, xRightPanel + 10 - 14 - GetSystemMetrics(SM_CXVSCROLL),
8362 Height - MidPanelHeight + 8, 0, 0, SWP_NOSIZE or SWP_NOZORDER);
8363 MapBtn0.Left := xMini + G.lx - 44;
8364 MapBtn0.Top := Height - 15;
8365 MapBtn1.Left := xMini + G.lx - 28;
8366 MapBtn1.Top := Height - 15;
8367 { MapBtn2.Left := xMini + G.lx - 20;
8368 MapBtn2.Top := Height - 15;
8369 MapBtn3.Left := xMini + G.lx - 4;
8370 MapBtn3.Top := Height - 15; }
8371 MapBtn5.Left := xMini + G.lx - 12;
8372 MapBtn5.Top := Height - 15;
8373 MapBtn4.Left := xMini + G.lx + 20;
8374 MapBtn4.Top := Height - 15;
8375 MapBtn6.Left := xMini + G.lx + 36;
8376 MapBtn6.Top := Height - 15;
8377 TreasuryArea.Left := Width div 2 - 172;
8378 ResearchArea.Left := Width div 2;
8379 ManagementArea.Left := Width - xPalace;
8380 ManagementArea.Top := TopBarHeight + MapHeight - Overlap + yPalace;
8381 ArrangeMidPanel;
8382 if RepaintOnResize then RepaintAll;
8383end;
8384
8385procedure TMainScreen.ArrangeDialogs;
8386begin
8387 ArrangeDialog(FListDlg);
8388 ArrangeDialog(FHelpDlg);
8389 ArrangeDialog(FUnitStatDlg);
8390 ArrangeDialog(FDiaDlg);
8391 ArrangeDialog(FNatStatDlg);
8392end;
8393
8394procedure TMainScreen.ArrangeDialog(Form: TBufferedDrawDlg);
8395begin
8396 if not Assigned(Form) then Exit;
8397
8398 if Form is TListDlg then begin;
8399 ListDlg.UserLeft := Screen.PrimaryMonitor.Left + 8;
8400 ListDlg.UserTop := Screen.PrimaryMonitor.Top + TopBarHeight + 8;
8401 end;
8402 if Form is THelpDlg then begin
8403 HelpDlg.UserLeft := Screen.PrimaryMonitor.Left + Screen.PrimaryMonitor.Width - HelpDlg.Width - 8;
8404 HelpDlg.UserTop := Screen.PrimaryMonitor.Top + TopBarHeight + 8;
8405 end;
8406 if Form is TUnitStatDlg then begin
8407 UnitStatDlg.UserLeft := Screen.PrimaryMonitor.Left + 397;
8408 UnitStatDlg.UserTop := Screen.PrimaryMonitor.Top + TopBarHeight + 64;
8409 end;
8410 if Form is TDiaDlg then begin
8411 DiaDlg.UserLeft := Screen.PrimaryMonitor.Left + (Screen.PrimaryMonitor.Width - DiaDlg.Width) div 2;
8412 DiaDlg.UserTop := Screen.PrimaryMonitor.Top + (Screen.PrimaryMonitor.Height - DiaDlg.Height) div 2;
8413 end;
8414 if Form is TNatStatDlg then begin
8415 NatStatDlg.UserLeft := Screen.PrimaryMonitor.Left + Screen.PrimaryMonitor.Width - NatStatDlg.Width - 8;
8416 NatStatDlg.UserTop := Screen.PrimaryMonitor.Top + Screen.PrimaryMonitor.Height - PanelHeight - NatStatDlg.Height - 8;
8417 if NatStatDlg.UserTop < 8 then
8418 NatStatDlg.UserTop := 8;
8419 end;
8420end;
8421
8422procedure TMainScreen.ScrollBarUpdate(Sender: TObject);
8423begin
8424 {$IFDEF UNIX}
8425 // Do not scroll with mouse wheel to and above max value
8426 if VerticalScrollBar.Position > VerticalScrollBar.Max - 1 then
8427 VerticalScrollBar.Position := VerticalScrollBar.Max - 1;
8428 {$ENDIF}
8429 PanelPaint;
8430 Update;
8431end;
8432
8433end.
8434
Note: See TracBrowser for help on using the repository browser.