source: trunk/LocalPlayer/Term.pas

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