source: branches/highdpi/LocalPlayer/Term.pas@ 210

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