source: trunk/LocalPlayer/Term.pas

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