source: tags/1.3.1/LocalPlayer/Term.pas

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