source: branches/AlphaChannel/LocalPlayer/Term.pas

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