source: tags/1.3.8/LocalPlayer/Term.pas

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