source: tags/1.3.2/LocalPlayer/Term.pas

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