source: tags/1.2.0/LocalPlayer/Term.pas

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