source: branches/delphi/LocalPlayer/Term.pas

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