source: trunk/LocalPlayer/Term.pas

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