source: tags/1.3.5/LocalPlayer/Term.pas

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