source: trunk/LocalPlayer/CityScreen.pas@ 167

Last change on this file since 167 was 150, checked in by chronos, 7 years ago
  • Fixed: Problem with offscreen bitmap handle causing to not show extra map objects on city map.
  • Modified: Added named constants for positions of terrain images.
File size: 58.7 KB
Line 
1{$INCLUDE Switches.inc}
2unit CityScreen;
3
4interface
5
6uses
7 {$IFDEF LINUX}
8 LMessages,
9 {$ENDIF}
10 Protocol, ClientTools, Term, ScreenTools, IsoEngine, BaseWin,
11 LCLIntf, LCLType, Messages, SysUtils, Classes, Graphics, Controls, Forms, ExtCtrls,
12 ButtonA, ButtonC, Area, GraphType;
13
14const
15 WM_PLAYSOUND = WM_USER;
16
17type
18 TCityCloseAction = (None, RestoreFocus, StepFocus);
19
20 TCityDlg = class(TBufferedDrawDlg)
21 Timer1: TTimer;
22 CloseBtn: TButtonA;
23 PrevCityBtn: TButtonC;
24 NextCityBtn: TButtonC;
25 PageUpBtn: TButtonC;
26 PageDownBtn: TButtonC;
27 BuyBtn: TButtonC;
28 ProjectArea: TArea;
29 PrimacyArea: TArea;
30 Imp2Area: TArea;
31 Imp4Area: TArea;
32 Imp0Area: TArea;
33 Imp3Area: TArea;
34 Imp5Area: TArea;
35 Imp1Area: TArea;
36 Pop0Area: TArea;
37 Pop1Area: TArea;
38 SupportArea: TArea;
39 procedure FormCreate(Sender: TObject);
40 procedure FormDestroy(Sender: TObject);
41 procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
42 Shift: TShiftState; x, y: integer);
43 procedure BuyClick(Sender: TObject);
44 procedure CloseBtnClick(Sender: TObject);
45 procedure FormShow(Sender: TObject);
46 procedure FormClose(Sender: TObject; var Action: TCloseAction);
47 procedure Timer1Timer(Sender: TObject);
48 procedure FormPaint(Sender: TObject);
49 procedure NextCityBtnClick(Sender: TObject);
50 procedure PrevCityBtnClick(Sender: TObject);
51 procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
52 // procedure AdviceBtnClick(Sender: TObject);
53 procedure PageUpBtnClick(Sender: TObject);
54 procedure PageDownBtnClick(Sender: TObject);
55
56 public
57 RestoreUnFocus: integer;
58 CloseAction: TCityCloseAction;
59 procedure OffscreenPaint; override;
60 procedure ShowNewContent(NewMode, Loc: integer; ShowEvent: cardinal);
61 procedure Reset;
62 procedure CheckAge;
63
64 private
65 c: TCity;
66 Report: TCityReportNew;
67 cOwner, cGov, emix { enemy model index of produced unit } , cix, cLoc, Mode,
68 ZoomArea, Page, PageCount, BlinkTime, OpenSoundEvent, SizeClass,
69 AgePrepared: integer;
70 Optimize_cixTileChange, Optimize_TilesBeforeChange: integer;
71 Happened: cardinal;
72 imix: array [0 .. 15] of integer;
73 CityAreaInfo: TCityAreaInfo;
74 AreaMap: TIsoMap;
75 CityMapTemplate, SmallCityMapTemplate, Back, SmallCityMap, ZoomCityMap,
76 Template: TBitmap;
77 IsPort, ProdHint, AllowChange: boolean;
78 procedure InitSmallCityMap;
79 procedure InitZoomCityMap;
80 procedure ChooseProject;
81 procedure ChangeCity(d: integer);
82 procedure ChangeResourceWeights(iResourceWeights: integer);
83 procedure OnPlaySound(var Msg: TMessage); message WM_PLAYSOUND;
84 end;
85
86var
87 CityDlg: TCityDlg;
88
89implementation
90
91uses
92 Select, Messg, MessgEx, Help, Tribes, Directories, Math;
93
94{$R *.lfm}
95
96const
97 { modes }
98 mSupp = 1;
99 mImp = 2;
100
101 wBar = 106;
102 xDiv = 400;
103 xService = 296;
104 xmArea = 197;
105 ymArea = 170;
106 xView = 326;
107 yView = 275;
108 dxBar = wBar + 12;
109 dyBar = 39;
110 xHapp = 404;
111 yHapp = 9;
112 xFood = 404;
113 yFood = yHapp + 3 * dyBar + 6;
114 xProd = 404;
115 yProd = yFood + 3 * dyBar + 6;
116 xTrade = 404;
117 yTrade = yProd + 2 * dyBar + 22;
118 xPoll = xmArea - 186;
119 yPoll = ymArea + 64;
120 xmOpt = 40;
121 ymOpt = ymArea + 96 + 34;
122 xSmallMap = 271;
123 ySmallMap = 339;
124 wSmallMap = 98;
125 hSmallMap = 74;
126 xSupport = xSmallMap;
127 ySupport = ySmallMap + hSmallMap + 2;
128 wSupport = 64;
129 hSupport = 18;
130 xZoomMap = 34;
131 yZoomMap = 338;
132 wZoomMap = 228;
133 hZoomMap = 124;
134 wZoomEnvironment = 68;
135
136 ImpPosition: array [28 .. nImp - 1] of integer = (-1, // imTrGoods
137 21, // imBarracks
138 6, // imGranary
139 1, // imTemple
140 7, // imMarket
141 14, // imLibrary
142 8, // imCourt
143 18, // imWalls
144 10, // imAqueduct
145 11, // imBank
146 5, // imCathedral
147 13, // imUniversity
148 29, // imHarbor
149 2, // imTheater
150 24, // imFactory
151 25, // imMfgPlant
152 28, // imRecycling
153 27, // imPower
154 27, // imHydro
155 27, // imNuclear
156 26, // imPlatform
157 8, // imTownHall
158 10, // imSewer
159 3, // imSupermarket
160 17, // imHighways
161 15, // imResLab
162 19, // imMissileBat
163 23, // imCoastalFort
164 22, // imAirport
165 20, // imDockyard
166 8, // imPalace
167 -1, // imGrWall
168 4, // imColosseum
169 16, // imObservatory
170 21, // imMilAcademy
171 -1, // imBunker
172 -1, // imAlgae
173 9, // imStockEx
174 -1, // imSpacePort
175 -1, // imShipComp
176 -1, // imShipPow
177 -1); // imShipHab
178
179var
180 ImpSorted: array [0 .. nImp - 1] of integer;
181
182procedure TCityDlg.FormCreate(Sender: TObject);
183begin
184 inherited;
185 AreaMap := TIsoMap.Create;
186 AreaMap.SetOutput(offscreen);
187 AreaMap.SetPaintBounds(xmArea - 192, ymArea - 96 - 32, xmArea + 192,
188 ymArea + 96);
189 Mode := mImp;
190 ZoomArea := 1;
191 ProdHint := false;
192 RestoreUnFocus := -1;
193 OpenSoundEvent := -1;
194 AgePrepared := -2;
195 Optimize_cixTileChange := -1;
196 InitButtons();
197 // InitWindowRegion;
198 CloseBtn.Caption := Phrases.Lookup('BTN_OK');
199 BuyBtn.Hint := Phrases.Lookup('BTN_BUY');
200 if not Phrases2FallenBackToEnglish then
201 SupportArea.Hint := Phrases2.Lookup('TIP_SUPUNITS')
202 else
203 SupportArea.Hint := Phrases.Lookup('SUPUNITS');
204 if not Phrases2FallenBackToEnglish then
205 begin
206 Pop0Area.Hint := Phrases2.Lookup('TIP_WORKING');
207 Pop1Area.Hint := Phrases2.Lookup('TIP_CIVIL');
208 PrimacyArea.Hint := Phrases2.Lookup('TIP_PRIMACY');
209 ProjectArea.Hint := Phrases2.Lookup('TIP_PROJECT');
210 end;
211
212 Back := TBitmap.Create;
213 Back.PixelFormat := pf24bit;
214 Back.SetSize(Width, Height);
215 Back.Canvas.FillRect(0, 0, Back.Width, Back.Height);
216 Template := TBitmap.Create;
217 Template.PixelFormat := pf24bit;
218 LoadGraphicFile(Template, HomeDir + 'Graphics' + DirectorySeparator + 'City.png', gfNoGamma);
219 CityMapTemplate := TBitmap.Create;
220 CityMapTemplate.PixelFormat := pf24bit;
221 LoadGraphicFile(CityMapTemplate, HomeDir + 'Graphics' + DirectorySeparator + 'BigCityMap.png', gfNoGamma);
222 SmallCityMapTemplate := TBitmap.Create;
223 SmallCityMapTemplate.PixelFormat := pf24bit;
224 LoadGraphicFile(SmallCityMapTemplate, HomeDir + 'Graphics' + DirectorySeparator + 'SmallCityMap.png',
225 gfNoGamma);
226 SmallCityMap := TBitmap.Create;
227 SmallCityMap.PixelFormat := pf24bit;
228 SmallCityMap.SetSize(98, 74);
229 SmallCityMap.Canvas.FillRect(0, 0, SmallCityMap.Width, SmallCityMap.Height);
230 ZoomCityMap := TBitmap.Create;
231 ZoomCityMap.PixelFormat := pf24bit;
232 ZoomCityMap.SetSize(228, 124);
233 ZoomCityMap.Canvas.FillRect(0, 0, ZoomCityMap.Width, ZoomCityMap.Height);
234end;
235
236procedure TCityDlg.FormDestroy(Sender: TObject);
237begin
238 FreeAndNil(AreaMap);
239 FreeAndNil(SmallCityMap);
240 FreeAndNil(ZoomCityMap);
241 FreeAndNil(SmallCityMapTemplate);
242 FreeAndNil(CityMapTemplate);
243 FreeAndNil(Template);
244 FreeAndNil(Back);
245end;
246
247procedure TCityDlg.Reset;
248begin
249 Mode := mImp;
250 ZoomArea := 1;
251end;
252
253procedure TCityDlg.CheckAge;
254begin
255 if MainTextureAge <> AgePrepared then
256 begin
257 AgePrepared := MainTextureAge;
258
259 // TODO: FillRect should not be needed as BitBlt is with SRCCOPY
260 Back.Canvas.FillRect(0, 0, ClientWidth, ClientHeight);
261
262 bitblt(Back.Canvas.Handle, 0, 0, ClientWidth, ClientHeight,
263 MainTexture.Image.Canvas.Handle, 0, 0, SRCCOPY);
264 ImageOp_B(Back, Template, 0, 0, 0, 0, ClientWidth, ClientHeight);
265 end;
266end;
267
268procedure TCityDlg.CloseBtnClick(Sender: TObject);
269begin
270 Close;
271end;
272
273procedure TCityDlg.InitSmallCityMap;
274var
275 i, iix, cli1, Color0, Color1, Color2: integer;
276begin
277 if cix >= 0 then
278 c := MyCity[cix];
279 case MyMap[cLoc] and fTerrain of
280 fPrairie:
281 cli1 := cliPrairie;
282 fHills:
283 cli1 := cliHills;
284 fTundra:
285 cli1 := cliTundra;
286 else
287 cli1 := cliPlains;
288 end;
289 Color0 := Colors.Canvas.Pixels[clkAge0 + Age, cliRoad];
290 Color1 := Colors.Canvas.Pixels[clkCity, cli1];
291 Color2 := Colors.Canvas.Pixels[clkAge0 + Age, cliHouse];
292 SmallCityMap.Canvas.FillRect(0, 0, SmallCityMap.Width, SmallCityMap.Height);
293 bitblt(SmallCityMap.Canvas.Handle, 0, 0, 83, hSmallMap,
294 SmallCityMapTemplate.Canvas.Handle, 83 * SizeClass, 0, SRCCOPY);
295 if IsPort then
296 begin
297 bitblt(SmallCityMap.Canvas.Handle, 83, 0, 15, hSmallMap,
298 SmallCityMapTemplate.Canvas.Handle, 332 + 15, 0, SRCCOPY);
299 ImageOp_CCC(SmallCityMap, 0, 0, 83, hSmallMap, Color0, Color1, Color2);
300 Color2 := Colors.Canvas.Pixels[clkCity, cliWater];
301 ImageOp_CCC(SmallCityMap, 83, 0, 15, hSmallMap, Color0, Color1, Color2);
302 end
303 else
304 begin
305 bitblt(SmallCityMap.Canvas.Handle, 83, 0, 15, hSmallMap,
306 SmallCityMapTemplate.Canvas.Handle, 332, 0, SRCCOPY);
307 ImageOp_CCC(SmallCityMap, 0, 0, wSmallMap, hSmallMap, Color0,
308 Color1, Color2);
309 end;
310
311 with SmallCityMap.Canvas do
312 begin
313 brush.Color := ScreenTools.Colors.Canvas.Pixels[clkAge0 + Age, cliImp];
314 for i := 0 to 29 do
315 begin
316 for iix := 28 to nImp - 1 do
317 if (ImpPosition[iix] = i) and (c.Built[iix] > 0) then
318 begin
319 FillRect(Rect(5 + 16 * (i mod 3) + 48 * (i div 18),
320 3 + 12 * (i mod 18 div 3), 13 + 16 * (i mod 3) + 48 * (i div 18),
321 11 + 12 * (i mod 18 div 3)));
322 break;
323 end;
324 end;
325 i := 30;
326 for iix := 0 to nImp do
327 if (c.Built[iix] > 0) and ((iix < 28) or (ImpPosition[iix] < 0)) then
328 begin
329 FillRect(Rect(5 + 16 * (i mod 3) + 48 * (i div 18),
330 3 + 12 * (i mod 18 div 3), 13 + 16 * (i mod 3) + 48 * (i div 18),
331 11 + 12 * (i mod 18 div 3)));
332 inc(i);
333 if i = 36 then
334 break; // area is full
335 end;
336 if c.Project and cpImp <> 0 then
337 begin
338 iix := c.Project and cpIndex;
339 if iix <> imTrGoods then
340 begin
341 if (iix >= 28) and (ImpPosition[iix] >= 0) then
342 i := ImpPosition[iix];
343 if i < 36 then
344 begin
345 brush.Color := ScreenTools.Colors.Canvas.Pixels[clkAge0 + Age, cliImpProject];
346 FillRect(Rect(5 + 16 * (i mod 3) + 48 * (i div 18),
347 3 + 12 * (i mod 18 div 3), 13 + 16 * (i mod 3) + 48 * (i div 18),
348 11 + 12 * (i mod 18 div 3)));
349 end;
350 end;
351 end;
352 brush.style := bsClear;
353 end;
354end;
355
356procedure TCityDlg.InitZoomCityMap;
357begin
358 // TODO: FillRect should not be needed as BitBlt is with SRCCOPY
359 ZoomCityMap.Canvas.FillRect(0, 0, ZoomCityMap.Width, ZoomCityMap.Height);
360
361 bitblt(ZoomCityMap.Canvas.Handle, 0, 0, wZoomMap, hZoomMap,
362 Back.Canvas.Handle, xZoomMap, yZoomMap, SRCCOPY);
363 if Mode = mImp then begin
364 if ZoomArea < 3 then begin
365 ImageOp_B(ZoomCityMap, CityMapTemplate, 0, 0, 376 * SizeClass,
366 112 * ZoomArea, wZoomMap, hZoomMap);
367 end else begin
368 ImageOp_B(ZoomCityMap, CityMapTemplate, 0, 0, 376 * SizeClass + 216,
369 112 * (ZoomArea - 3), wZoomMap - wZoomEnvironment, hZoomMap);
370 ImageOp_B(ZoomCityMap, CityMapTemplate, wZoomMap - wZoomEnvironment, 0,
371 1504 + wZoomEnvironment * byte(IsPort), 112 * (ZoomArea - 3),
372 wZoomEnvironment, hZoomMap);
373 end;
374 end;
375end;
376
377procedure TCityDlg.OffscreenPaint;
378
379 procedure FillBar(x, y, pos, Growth, max, Kind: integer;
380 IndicateComplete: boolean);
381 var
382 Tex: TTexture;
383 begin
384 Tex := MainTexture;
385 if Kind = 3 then
386 begin
387 Tex.clBevelLight := GrExt[HGrSystem].Data.Canvas.Pixels[104, 36];
388 Tex.clBevelShade := Tex.clBevelLight;
389 end;
390 PaintRelativeProgressBar(offscreen.Canvas, Kind, x - 3, y, wBar - 4, pos,
391 Growth, max, IndicateComplete, Tex);
392 end;
393
394 procedure PaintResources(x, y, Loc: integer; Add4Happy: boolean);
395 var
396 d, i, Total, xGr, yGr: integer;
397 TileInfo: TTileInfo;
398 rare: boolean;
399 begin
400 if Server(sGetCityTileInfo, me, Loc, TileInfo) <> eOk then
401 begin
402 assert(cix < 0);
403 exit
404 end;
405 Total := TileInfo.Food + TileInfo.Prod + TileInfo.Trade;
406 rare := MyMap[Loc] and $06000000 > 0;
407 if rare then
408 inc(Total);
409 if Add4Happy then
410 inc(Total, 4);
411 if Total > 1 then
412 d := (xxt - 11) div (Total - 1);
413 if d < 1 then
414 d := 1;
415 if d > 4 then
416 d := 4;
417 for i := 0 to Total - 1 do
418 begin
419 yGr := 115;
420 if Add4Happy and (i >= Total - 4) then
421 begin
422 xGr := 132;
423 yGr := 126
424 end
425 else if rare and (i = Total - 1) then
426 xGr := 66 + 110
427 else if i >= TileInfo.Food + TileInfo.Prod then
428 xGr := 66 + 44
429 else if i >= TileInfo.Prod then
430 xGr := 66
431 else
432 xGr := 66 + 22;
433 Sprite(offscreen, HGrSystem, x + xxt - 5 + d * (2 * i + 1 - Total),
434 y + yyt - 5, 10, 10, xGr, yGr);
435 end;
436 end;
437
438 procedure MakeRed(X, Y, W, H: Integer);
439 var
440 XX, YY: Integer;
441 Gray: Integer;
442 PixelPtr: TPixelPointer;
443 begin
444 Offscreen.BeginUpdate;
445 PixelPtr.Init(Offscreen, X, Y);
446 for YY := 0 to H - 1 do begin
447 for XX := 0 to W - 1 do begin
448 Gray := (Integer(PixelPtr.Pixel^.B) + Integer(PixelPtr.Pixel^.G) +
449 Integer(PixelPtr.Pixel^.R)) * 85 shr 8;
450 PixelPtr.Pixel^.B := 0;
451 PixelPtr.Pixel^.G := 0;
452 PixelPtr.Pixel^.R := Gray; // 255-(255-gray) div 2;
453 PixelPtr.NextPixel;
454 end;
455 PixelPtr.NextLine;
456 end;
457 Offscreen.EndUpdate;
458 end;
459
460var
461 line, MessageCount: integer;
462
463 procedure CheckMessage(Flag: integer);
464 var
465 i, test: integer;
466 s: string;
467 begin
468 if Happened and Flag <> 0 then
469 begin
470 i := 0;
471 test := 1;
472 while test < Flag do
473 begin
474 inc(i);
475 inc(test, test)
476 end;
477
478 if AllowChange and (Sounds <> nil) and (OpenSoundEvent = -1) then
479 begin
480 s := CityEventSoundItem[i];
481 if s <> '' then
482 s := Sounds.Lookup(s);
483 if (Flag = chProduction) or (s <> '') and (s[1] <> '*') and (s[1] <> '[')
484 then
485 OpenSoundEvent := i
486 end;
487
488 s := CityEventName(i);
489 { if Flag=chNoGrowthWarning then
490 if c.Built[imAqueduct]=0 then
491 s:=Format(s,[Phrases.Lookup('IMPROVEMENTS',imAqueduct)])
492 else s:=Format(s,[Phrases.Lookup('IMPROVEMENTS',imSewer)]); }
493 RisedTextOut(offscreen.Canvas, xmOpt + 40, ymOpt - 1 - 8 * MessageCount +
494 16 * line, s);
495 inc(line)
496 end;
497 end;
498
499var
500 x, y, xGr, i, i1, j, iix, d, dx, dy, PrCost, Cnt, Loc1, FreeSupp, Paintiix,
501 HappyGain, OptiType, rx, ry, TrueFood, TrueProd, TruePoll: integer;
502 av: integer;
503 PrName, s: string;
504 UnitInfo: TUnitInfo;
505 UnitReport: TUnitReport;
506 RedTex: TTexture;
507 IsCityAlive, CanGrow: boolean;
508begin
509 inherited;
510 if cix >= 0 then
511 c := MyCity[cix];
512 Report.HypoTiles := -1;
513 Report.HypoTaxRate := -1;
514 Report.HypoLuxuryRate := -1;
515 if cix >= 0 then
516 Server(sGetCityReportNew, me, cix, Report) // own city
517 else
518 Server(sGetEnemyCityReportNew, me, cLoc, Report); // enemy city
519 TrueFood := c.Food;
520 TrueProd := c.Prod;
521 TruePoll := c.Pollution;
522 if supervising or (cix < 0) then
523 begin // normalize city from after-turn state
524 dec(TrueFood, Report.FoodSurplus);
525 if TrueFood < 0 then
526 TrueFood := 0; // shouldn't happen
527 dec(TrueProd, Report.Production);
528 if TrueProd < 0 then
529 TrueProd := 0; // shouldn't happen
530 dec(TruePoll, Report.AddPollution);
531 if TruePoll < 0 then
532 TruePoll := 0; // shouldn't happen
533 end;
534 IsCityAlive := (cGov <> gAnarchy) and (c.Flags and chCaptured = 0);
535 if not IsCityAlive then
536 Report.Working := c.Size;
537
538 RedTex := MainTexture;
539 RedTex.clBevelLight := $0000FF;
540 RedTex.clBevelShade := $000000;
541 RedTex.clTextLight := $000000;
542 RedTex.clTextShade := $0000FF;
543
544 bitblt(offscreen.Canvas.Handle, 0, 0, 640, 480, Back.Canvas.Handle, 0,
545 0, SRCCOPY);
546
547 offscreen.Canvas.Font.Assign(UniFont[ftCaption]);
548 RisedTextOut(offscreen.Canvas, 42, 7, Caption);
549 with offscreen.Canvas do
550 begin // city size
551 brush.Color := $000000;
552 FillRect(Rect(8 + 1, 7 + 1, 36 + 1, 32 + 1));
553 brush.Color := $FFFFFF;
554 FillRect(Rect(8, 7, 36, 32));
555 brush.style := bsClear;
556 Font.Color := $000000;
557 s := inttostr(c.Size);
558 TextOut(8 + 14 - textwidth(s) div 2, 7, s);
559 end;
560 offscreen.Canvas.Font.Assign(UniFont[ftSmall]);
561
562 if not IsCityAlive then
563 begin
564 MakeRed(18, 280, 298, 40);
565 if cGov = gAnarchy then
566 s := Phrases.Lookup('GOVERNMENT', gAnarchy)
567 else { if c.Flags and chCaptured<>0 then }
568 s := Phrases.Lookup('CITYEVENTS', 14);
569 RisedTextOut(offscreen.Canvas, 167 - BiColorTextWidth(offscreen.Canvas, s)
570 div 2, ymOpt - 9, s);
571 end
572 else if AllowChange then
573 begin
574 OptiType := c.Status shr 4 and $0F;
575 Sprite(offscreen, HGrSystem2, xmOpt - 32, ymOpt - 32, 64, 64,
576 1 + OptiType mod 3 * 64, 217 + OptiType div 3 * 64);
577
578 { display messages now }
579 MessageCount := 0;
580 for i := 0 to 31 do
581 if Happened and ($FFFFFFFF - chCaptured) and (1 shl i) <> 0 then
582 inc(MessageCount);
583 if MessageCount > 3 then
584 MessageCount := 3;
585 if MessageCount > 0 then
586 begin
587 MakeBlue(offscreen, 74, 280, 242, 40);
588 line := 0;
589 for i := 0 to nCityEventPriority - 1 do
590 if line < MessageCount then
591 CheckMessage(CityEventPriority[i]);
592 end
593 else
594 begin
595 s := Phrases.Lookup('CITYMANAGETYPE', OptiType);
596 j := pos('\', s);
597 if j = 0 then
598 LoweredTextout(offscreen.Canvas, -1, MainTexture, xmOpt + 40,
599 ymOpt - 9, s)
600 else
601 begin
602 LoweredTextout(offscreen.Canvas, -1, MainTexture, xmOpt + 40,
603 ymOpt - 17, copy(s, 1, j - 1));
604 LoweredTextout(offscreen.Canvas, -1, MainTexture, xmOpt + 40, ymOpt - 1,
605 copy(s, j + 1, 255));
606 end;
607 end;
608 end;
609
610 rx := (192 + xxt * 2 - 1) div (xxt * 2);
611 ry := (96 + yyt * 2 - 1) div (yyt * 2);
612 AreaMap.Paint(xmArea - xxt * 2 * rx, ymArea - yyt * 2 * ry - 3 * yyt,
613 dLoc(cLoc, -2 * rx + 1, -2 * ry - 1), 4 * rx - 1, 4 * ry + 1, cLoc, cOwner,
614 false, AllowChange and IsCityAlive and
615 (c.Status and csResourceWeightsMask = 0));
616 bitblt(offscreen.Canvas.Handle, xmArea + 102, 42, 90, 33, Back.Canvas.Handle,
617 xmArea + 102, 42, SRCCOPY);
618
619 if IsCityAlive then
620 for dy := -3 to 3 do
621 for dx := -3 to 3 do
622 if ((dx + dy) and 1 = 0) and (dx * dx * dy * dy < 81) then
623 begin
624 Loc1 := dLoc(cLoc, dx, dy);
625 av := CityAreaInfo.Available[(dy + 3) shl 2 + (dx + 3) shr 1];
626 if ((av = faNotAvailable) or (av = faTreaty) or (av = faInvalid)) and
627 ((Loc1 < 0) or (Loc1 >= G.lx * G.ly) or (MyMap[Loc1] and fCity = 0))
628 then
629 Sprite(offscreen, HGrTerrain, xmArea - xxt + xxt * dx,
630 ymArea - yyt + yyt * dy, xxt * 2, yyt * 2, 1 + 5 * (xxt * 2 + 1),
631 1 + yyt + 15 * (yyt * 3 + 1));
632 if (1 shl ((dy + 3) shl 2 + (dx + 3) shr 1) and c.Tiles <> 0) then
633 PaintResources(xmArea - xxt + xxt * dx, ymArea - yyt + yyt * dy,
634 Loc1, (dx = 0) and (dy = 0));
635 end;
636
637 if Report.Working > 1 then
638 d := (xService - (xmArea - 192) - 8 - 32) div (Report.Working - 1);
639 if d > 28 then
640 d := 28;
641 for i := Report.Working - 1 downto 0 do
642 begin
643 if IsCityAlive then
644 xGr := 29
645 else
646 xGr := 141;
647 bitblt(offscreen.Canvas.Handle, xmArea - 192 + 5 + i * d, ymArea - 96 - 29,
648 27, 30, GrExt[HGrSystem].Mask.Canvas.Handle, xGr, 171, SRCAND); { shadow }
649 Sprite(offscreen, HGrSystem, xmArea - 192 + 4 + i * d, ymArea - 96 - 30, 27,
650 30, xGr, 171);
651 end;
652 if c.Size - Report.Working > 1 then
653 d := (xmArea + 192 - xService - 32) div (c.Size - Report.Working - 1);
654 if d > 28 then
655 d := 28;
656 for i := 0 to c.Size - Report.Working - 1 do
657 begin
658 xGr := 1 + 112;
659 bitblt(offscreen.Canvas.Handle, xmArea + 192 - 27 + 1 - i * d, 29 + 1, 27,
660 30, GrExt[HGrSystem].Mask.Canvas.Handle, xGr, 171, SRCAND); { shadow }
661 Sprite(offscreen, HGrSystem, xmArea + 192 - 27 - i * d, 29, 27, 30,
662 xGr, 171);
663 Sprite(offscreen, HGrSystem, xmArea + 192 - 27 + 4 - i * d, 29 + 32, 10,
664 10, 121, 126);
665 Sprite(offscreen, HGrSystem, xmArea + 192 - 27 + 13 - i * d, 29 + 32, 10,
666 10, 121, 126);
667 // Sprite(offscreen,HGrSystem,xmArea+192-31+18-i*d,ymArea-96-80+32,10,10,88,115);
668 end;
669
670 if c.Project and cpImp = 0 then
671 PrName := Tribe[cOwner].ModelName[c.Project and cpIndex]
672 else
673 PrName := Phrases.Lookup('IMPROVEMENTS', c.Project and cpIndex);
674 PrCost := Report.ProjectCost;
675
676 // happiness section
677 if IsCityAlive then
678 begin
679 if cGov = gFundamentalism then
680 CountBar(offscreen, xHapp, yHapp + dyBar, wBar, 17,
681 Phrases.Lookup('FAITH'), Report.CollectedControl, MainTexture)
682 else
683 begin
684 CountBar(offscreen, xHapp, yHapp + dyBar, wBar, 17,
685 Phrases.Lookup('HAPPINESS'), Report.Morale, MainTexture);
686 CountBar(offscreen, xHapp, yHapp + 2 * dyBar, wBar, 16,
687 Phrases.Lookup('CONTROL'), Report.CollectedControl, MainTexture);
688 end;
689 CountBar(offscreen, xHapp, yHapp, wBar, 8, Phrases.Lookup('LUX'),
690 Report.Luxury, MainTexture);
691 CountBar(offscreen, xHapp + dxBar, yHapp, wBar, 19,
692 Phrases.Lookup('UNREST'), 2 * Report.Deployed, MainTexture);
693 CountBar(offscreen, xHapp + dxBar, yHapp + dyBar, wBar, 17,
694 Phrases.Lookup('HAPPINESSDEMAND'), c.Size, MainTexture);
695 if Report.HappinessBalance >= 0 then
696 CountBar(offscreen, xHapp + dxBar, yHapp + 2 * dyBar, wBar, 17,
697 Phrases.Lookup('HAPPINESSPLUS'), Report.HappinessBalance, MainTexture)
698 else
699 begin
700 MakeRed(xHapp + dxBar - 6, yHapp + 2 * dyBar, wBar + 10, 38);
701 CountBar(offscreen, xHapp + dxBar, yHapp + 2 * dyBar, wBar, 18,
702 Phrases.Lookup('LACK'), -Report.HappinessBalance, RedTex);
703 end;
704 end;
705
706 // food section
707 if IsCityAlive then
708 begin
709 CountBar(offscreen, xFood, yFood + dyBar div 2, wBar, 0,
710 Phrases.Lookup('FOOD'), Report.CollectedFood, MainTexture);
711 CountBar(offscreen, xFood + dxBar, yFood + dyBar, wBar, 0,
712 Phrases.Lookup('DEMAND'), 2 * c.Size, MainTexture);
713 CountBar(offscreen, xFood + dxBar, yFood, wBar, 0,
714 Phrases.Lookup('SUPPORT'), Report.FoodSupport, MainTexture);
715 if Report.FoodSurplus >= 0 then
716 if (cGov = gFuture) or (c.Size >= NeedAqueductSize) and
717 (Report.FoodSurplus < 2) then
718 CountBar(offscreen, xFood + dxBar, yFood + 2 * dyBar, wBar, 6,
719 Phrases.Lookup('PROFIT'), Report.FoodSurplus, MainTexture)
720 else
721 CountBar(offscreen, xFood + dxBar, yFood + 2 * dyBar, wBar, 0,
722 Phrases.Lookup('SURPLUS'), Report.FoodSurplus, MainTexture)
723 else
724 begin
725 MakeRed(xFood + dxBar - 6, yFood + 2 * dyBar, wBar + 10, 38);
726 CountBar(offscreen, xFood + dxBar, yFood + 2 * dyBar, wBar, 1,
727 Phrases.Lookup('LACK'), -Report.FoodSurplus, RedTex);
728 end;
729 end;
730 CanGrow := (c.Size < MaxCitySize) and (cGov <> gFuture) and
731 (Report.FoodSurplus > 0) and ((c.Size < NeedAqueductSize) or
732 (c.Built[imAqueduct] = 1) and (c.Size < NeedSewerSize) or
733 (c.Built[imSewer] = 1));
734 FillBar(xFood + 3, yFood + 102, TrueFood,
735 CutCityFoodSurplus(Report.FoodSurplus, IsCityAlive, cGov, c.Size),
736 Report.Storage, 1, CanGrow);
737 LoweredTextout(offscreen.Canvas, -1, MainTexture, xFood + 3 - 5,
738 yFood + 102 - 20, Format('%d/%d', [TrueFood, Report.Storage]));
739 LoweredTextout(offscreen.Canvas, -1, MainTexture, xFood - 2, yFood + 66,
740 Phrases.Lookup('STORAGE'));
741
742 // production section
743 if IsCityAlive then
744 begin
745 CountBar(offscreen, xProd, yProd, wBar, 2, Phrases.Lookup('MATERIAL'),
746 Report.CollectedMaterial, MainTexture);
747 CountBar(offscreen, xProd + dxBar, yProd, wBar, 2,
748 Phrases.Lookup('SUPPORT'), Report.MaterialSupport, MainTexture);
749 if Report.Production >= 0 then
750 if c.Project and (cpImp + cpIndex) = cpImp + imTrGoods then
751 CountBar(offscreen, xProd + dxBar, yProd + dyBar + 16, wBar, 6,
752 Phrases.Lookup('PROFIT'), Report.Production, MainTexture)
753 else
754 CountBar(offscreen, xProd + dxBar, yProd + dyBar + 16, wBar, 2,
755 Phrases.Lookup('PROD'), Report.Production, MainTexture)
756 else
757 begin
758 MakeRed(xProd + dxBar - 6, yProd + dyBar + 17, wBar + 10, 38);
759 CountBar(offscreen, xProd + dxBar, yProd + dyBar + 16, wBar, 3,
760 Phrases.Lookup('LACK'), -Report.Production, RedTex);
761 end;
762 end;
763 if c.Project and (cpImp + cpIndex) <> cpImp + imTrGoods then
764 with offscreen.Canvas do
765 begin
766 i := Report.Production;
767 if (i < 0) or not IsCityAlive then
768 i := 0;
769 FillBar(xProd + 3, yProd + 16 + 63, TrueProd, i, PrCost, 4, true);
770 LoweredTextout(offscreen.Canvas, -1, MainTexture, xProd + 3 - 5,
771 yProd + 16 + 43, Format('%d/%d', [TrueProd, PrCost]));
772 if BiColorTextWidth(offscreen.Canvas, PrName) > wBar + dxBar then
773 begin
774 repeat
775 Delete(PrName, length(PrName), 1)
776 until BiColorTextWidth(offscreen.Canvas, PrName) <= wBar + dxBar;
777 PrName := PrName + '.'
778 end;
779 end;
780 RisedTextOut(offscreen.Canvas, xProd - 2, yProd + 36, PrName);
781
782 // pollution section
783 if IsCityAlive and (Report.AddPollution > 0) then
784 begin
785 FillBar(xPoll + 3, yPoll + 20, TruePoll, Report.AddPollution,
786 MaxPollution, 3, true);
787 RisedTextOut(offscreen.Canvas, xPoll + 3 - 5, yPoll + 20 - 20,
788 Phrases.Lookup('POLL'));
789 end;
790
791 // trade section
792 if IsCityAlive and (Report.CollectedTrade > 0) then
793 begin
794 CountBar(offscreen, xTrade, yTrade + dyBar div 2, wBar, 4,
795 Phrases.Lookup('TRADE'), Report.CollectedTrade, MainTexture);
796 CountBar(offscreen, xTrade + dxBar, yTrade + 2 * dyBar, wBar, 5,
797 Phrases.Lookup('CORR'), Report.Corruption, MainTexture);
798 CountBar(offscreen, xTrade + dxBar, yTrade, wBar, 6, Phrases.Lookup('TAX'),
799 Report.Tax, MainTexture);
800 CountBar(offscreen, xTrade + dxBar, yTrade + dyBar, wBar, 12,
801 Phrases.Lookup('SCIENCE'), Report.Science, MainTexture);
802 end;
803
804 // small map
805 bitblt(offscreen.Canvas.Handle, xSmallMap, ySmallMap, wSmallMap, hSmallMap,
806 SmallCityMap.Canvas.Handle, 0, 0, SRCCOPY);
807 if Mode = mImp then
808 Frame(offscreen.Canvas, xSmallMap + 48 * (ZoomArea div 3),
809 ySmallMap + 24 * (ZoomArea mod 3), xSmallMap + 48 * (ZoomArea div 3) + 49,
810 ySmallMap + 24 * (ZoomArea mod 3) + 25, MainTexture.clMark,
811 MainTexture.clMark);
812 Frame(offscreen.Canvas, xSmallMap - 1, ySmallMap - 1, xSmallMap + wSmallMap,
813 ySmallMap + hSmallMap, $B0B0B0, $FFFFFF);
814 RFrame(offscreen.Canvas, xSmallMap - 2, ySmallMap - 2, xSmallMap + wSmallMap +
815 1, ySmallMap + hSmallMap + 1, $FFFFFF, $B0B0B0);
816
817 Frame(offscreen.Canvas, xSupport - 1, ySupport - 1, xSupport + wSupport,
818 ySupport + hSupport, $B0B0B0, $FFFFFF);
819 RFrame(offscreen.Canvas, xSupport - 2, ySupport - 2, xSupport + wSupport + 1,
820 ySupport + hSupport + 1, $FFFFFF, $B0B0B0);
821 x := xSupport + wSupport div 2;
822 y := ySupport + hSupport div 2;
823 if Mode = mSupp then
824 begin
825 offscreen.Canvas.brush.Color := MainTexture.clMark;
826 offscreen.Canvas.FillRect(Rect(x - 27, y - 6, x + 27, y + 6));
827 offscreen.Canvas.brush.style := bsClear;
828 end;
829 Sprite(offscreen, HGrSystem, x - 16, y - 5, 10, 10, 88, 115);
830 Sprite(offscreen, HGrSystem, x - 5, y - 5, 10, 10, 66, 115);
831 Sprite(offscreen, HGrSystem, x + 6, y - 5, 10, 10, 154, 126);
832
833 bitblt(offscreen.Canvas.Handle, xZoomMap, yZoomMap, wZoomMap, hZoomMap,
834 ZoomCityMap.Canvas.Handle, 0, 0, SRCCOPY);
835
836 for i := 0 to 5 do
837 imix[i] := -1;
838 if Mode = mImp then
839 begin
840 if ZoomArea = 5 then
841 begin
842 Cnt := 0;
843 for iix := 0 to nImp - 1 do
844 if ((iix < 28) or (ImpPosition[iix] < 0)) and (c.Built[iix] > 0) then
845 begin
846 i := Cnt - Page * 6;
847 if (i >= 0) and (i < 6) then
848 imix[i] := iix;
849 inc(Cnt);
850 end;
851 PageCount := (Cnt + 5) div 6;
852 end
853 else
854 begin
855 for iix := 28 to nImp - 1 do
856 begin
857 i := ImpPosition[iix] - 6 * ZoomArea;
858 if (i >= 0) and (i < 6) and (c.Built[iix] > 0) then
859 imix[i] := iix;
860 end;
861 PageCount := 0;
862 end;
863 for i := 0 to 5 do
864 if imix[i] >= 0 then
865 begin
866 iix := imix[i];
867 x := xZoomMap + 14 + 72 * (i mod 3);
868 y := yZoomMap + 14 + 56 * (i div 3);
869 ImpImage(offscreen.Canvas, x, y, iix, cGov, AllowChange and
870 (ClientMode < scContact));
871 if IsCityAlive then
872 begin
873 if iix = imColosseum then
874 begin
875 Sprite(offscreen, HGrSystem, x + 46, y, 14, 14, 82, 100);
876 end
877 else
878 begin
879 HappyGain := 0;
880 case iix of
881 0 .. 27, imTemple:
882 HappyGain := 2;
883 imTheater:
884 HappyGain := 4;
885 imCathedral:
886 if MyRO.Wonder[woBach].EffectiveOwner = cOwner then
887 HappyGain := 6
888 else
889 HappyGain := 4;
890 end;
891 if HappyGain > 1 then
892 begin
893 d := 30 div (HappyGain - 1);
894 if d > 10 then
895 d := 10
896 end;
897 for j := 0 to HappyGain - 1 do
898 Sprite(offscreen, HGrSystem, x + 50, y + d * j, 10, 10, 132, 126);
899 end;
900 for j := 0 to Imp[iix].Maint - 1 do
901 Sprite(offscreen, HGrSystem, x - 4, y + 29 - 3 * j, 10, 10,
902 132, 115);
903 end
904 end;
905 if imix[0] >= 0 then
906 Imp0Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[0])
907 else
908 Imp0Area.Hint := '';
909 if imix[1] >= 0 then
910 Imp1Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[1])
911 else
912 Imp1Area.Hint := '';
913 if imix[2] >= 0 then
914 Imp2Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[2])
915 else
916 Imp2Area.Hint := '';
917 if imix[3] >= 0 then
918 Imp3Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[3])
919 else
920 Imp3Area.Hint := '';
921 if imix[4] >= 0 then
922 Imp4Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[4])
923 else
924 Imp4Area.Hint := '';
925 if imix[5] >= 0 then
926 Imp5Area.Hint := Phrases.Lookup('IMPROVEMENTS', imix[5])
927 else
928 Imp5Area.Hint := '';
929 end
930 else { if mode=mSupp then }
931 begin
932 LoweredTextout(offscreen.Canvas, -1, MainTexture, xZoomMap + 6,
933 yZoomMap + 2, Phrases.Lookup('SUPUNITS'));
934 FreeSupp := c.Size * SupportFree[cGov] shr 1;
935 Cnt := 0;
936 for i := 0 to MyRO.nUn - 1 do
937 if (MyUn[i].Loc >= 0) and (MyUn[i].Home = cix) then
938 with MyModel[MyUn[i].mix] do
939 begin
940 Server(sGetUnitReport, me, i, UnitReport);
941 if (Cnt >= 6 * Page) and (Cnt < 6 * (Page + 1)) then
942 begin // unit visible in display
943 imix[Cnt - 6 * Page] := i;
944 x := ((Cnt - 6 * Page) mod 3) * 64 + xZoomMap;
945 y := ((Cnt - 6 * Page) div 3) * 52 + yZoomMap + 20;
946 MakeUnitInfo(me, MyUn[i], UnitInfo);
947 NoMap.SetOutput(offscreen);
948 NoMap.PaintUnit(x, y, UnitInfo, MyUn[i].Status);
949
950 for j := 0 to UnitReport.FoodSupport - 1 do
951 Sprite(offscreen, HGrSystem, x + 38 + 11 * j, y + 40, 10,
952 10, 66, 115);
953 for j := 0 to UnitReport.ProdSupport - 1 do
954 begin
955 if (FreeSupp > 0) and
956 (UnitReport.ReportFlags and urfAlwaysSupport = 0) then
957 begin
958 Sprite(offscreen, HGrSystem, x + 16 - 11 * j, y + 40, 10,
959 10, 143, 115);
960 dec(FreeSupp);
961 end
962 else
963 Sprite(offscreen, HGrSystem, x + 16 - 11 * j, y + 40, 10,
964 10, 88, 115);
965 end;
966 if UnitReport.ReportFlags and urfDeployed <> 0 then
967 for j := 0 to 1 do
968 Sprite(offscreen, HGrSystem, x + 27 + 11 * j, y + 40, 10,
969 10, 154, 126)
970 end // unit visible in display
971 else
972 dec(FreeSupp, UnitReport.ProdSupport);
973 inc(Cnt);
974 end;
975 PageCount := (Cnt + 5) div 6;
976 Imp0Area.Hint := '';
977 Imp1Area.Hint := '';
978 Imp2Area.Hint := '';
979 Imp3Area.Hint := '';
980 Imp4Area.Hint := '';
981 Imp5Area.Hint := '';
982 end;
983 PageUpBtn.Visible := PageCount > 1;
984 PageDownBtn.Visible := PageCount > 1;
985
986 with offscreen.Canvas do
987 begin
988 { display project now }
989 DLine(offscreen.Canvas, xView + 9 + xSizeBig, xProd + 2 * wBar + 10,
990 yProd + dyBar + 16, $FFFFFF, $B0B0B0);
991 if ProdHint then
992 begin
993 ScreenTools.Frame(offscreen.Canvas, xView + 9 - 1, yView + 5 - 1,
994 xView + 9 + xSizeBig, yView + 5 + ySizeBig, $B0B0B0, $FFFFFF);
995 RFrame(offscreen.Canvas, xView + 9 - 2, yView + 5 - 2,
996 xView + 9 + xSizeBig + 1, yView + 5 + ySizeBig + 1, $FFFFFF, $B0B0B0);
997 with offscreen.Canvas do
998 begin
999 brush.Color := $000000;
1000 FillRect(Rect(xView + 9, yView + 5, xView + 1 + 72 - 8,
1001 yView + 5 + 40));
1002 brush.style := bsClear;
1003 end;
1004 end
1005 else if AllowChange and (c.Status and 7 <> 0) then
1006 begin // city type autobuild
1007 FrameImage(offscreen.Canvas, bigimp, xView + 9, yView + 5, xSizeBig,
1008 ySizeBig, (c.Status and 7 - 1 + 3) * xSizeBig, 0, (cix >= 0) and
1009 (ClientMode < scContact));
1010 end
1011 else if c.Project and cpImp = 0 then
1012 begin // project is unit
1013 FrameImage(offscreen.Canvas, bigimp, xView + 9, yView + 5, xSizeBig,
1014 ySizeBig, 0, 0, AllowChange and (ClientMode < scContact));
1015 with Tribe[cOwner].ModelPicture[c.Project and cpIndex] do
1016 Sprite(offscreen, HGr, xView + 5, yView + 1, 64, 44,
1017 pix mod 10 * 65 + 1, pix div 10 * 49 + 1);
1018 end
1019 else
1020 begin // project is building
1021 if ProdHint then
1022 Paintiix := c.Project0 and cpIndex
1023 else
1024 Paintiix := c.Project and cpIndex;
1025 ImpImage(offscreen.Canvas, xView + 9, yView + 5, Paintiix, cGov,
1026 AllowChange and (ClientMode < scContact));
1027 end;
1028 end;
1029
1030 if AllowChange and (ClientMode < scContact) then
1031 begin
1032 i := Server(sBuyCityProject - sExecute, me, cix, nil^);
1033 BuyBtn.Visible := (i = eOk) or (i = eViolation);
1034 end
1035 else
1036 BuyBtn.Visible := false;
1037
1038 MarkUsedOffscreen(ClientWidth, ClientHeight);
1039end; { OffscreenPaint }
1040
1041procedure TCityDlg.FormShow(Sender: TObject);
1042var
1043 dx, dy, Loc1: integer;
1044 GetCityData: TGetCityData;
1045begin
1046 BlinkTime := 5;
1047 if cix >= 0 then
1048 begin { own city }
1049 c := MyCity[cix];
1050 cOwner := me;
1051 cGov := MyRO.Government;
1052 ProdHint := (cGov <> gAnarchy) and
1053 (Happened and (chProduction or chFounded or chCaptured or
1054 chAllImpsMade) <> 0);
1055 Server(sGetCityAreaInfo, me, cix, CityAreaInfo);
1056 NextCityBtn.Visible := WindowMode = wmPersistent;
1057 PrevCityBtn.Visible := WindowMode = wmPersistent;
1058 end
1059 else { enemy city }
1060 begin
1061 Mode := mImp;
1062 Server(sGetCity, me, cLoc, GetCityData);
1063 c := GetCityData.c;
1064 cOwner := GetCityData.Owner;
1065 cGov := MyRO.EnemyReport[cOwner].Government;
1066 Happened := c.Flags and $7FFFFFFF;
1067 ProdHint := false;
1068 Server(sGetEnemyCityAreaInfo, me, cLoc, CityAreaInfo);
1069
1070 if c.Project and cpImp = 0 then
1071 begin
1072 emix := MyRO.nEnemyModel - 1;
1073 while (emix > 0) and ((MyRO.EnemyModel[emix].Owner <> cOwner) or
1074 (integer(MyRO.EnemyModel[emix].mix) <> c.Project and cpIndex)) do
1075 dec(emix);
1076 if Tribe[cOwner].ModelPicture[c.Project and cpIndex].HGr = 0 then
1077 InitEnemyModel(emix);
1078 end;
1079
1080 NextCityBtn.Visible := false;
1081 PrevCityBtn.Visible := false;
1082 end;
1083 Page := 0;
1084
1085 if c.Size < 5 then
1086 SizeClass := 0
1087 else if c.Size < 9 then
1088 SizeClass := 1
1089 else if c.Size < 13 then
1090 SizeClass := 2
1091 else
1092 SizeClass := 3;
1093
1094 // check if port
1095 IsPort := false;
1096 for dx := -2 to 2 do
1097 for dy := -2 to 2 do
1098 if abs(dx) + abs(dy) = 2 then
1099 begin
1100 Loc1 := dLoc(cLoc, dx, dy);
1101 if (Loc1 >= 0) and (Loc1 < G.lx * G.ly) and
1102 (MyMap[Loc1] and fTerrain < fGrass) then
1103 IsPort := true;
1104 end;
1105
1106 if WindowMode = wmModal then
1107 begin { center on screen }
1108 Left := (Screen.Width - Width) div 2;
1109 Top := (Screen.Height - Height) div 2;
1110 end;
1111
1112 Caption := CityName(c.ID);
1113
1114 InitSmallCityMap;
1115 InitZoomCityMap;
1116 OpenSoundEvent := -1;
1117 OffscreenPaint;
1118 Timer1.Enabled := true;
1119end;
1120
1121procedure TCityDlg.ShowNewContent(NewMode, Loc: integer; ShowEvent: cardinal);
1122begin
1123 if MyMap[Loc] and fOwned <> 0 then
1124 begin // own city
1125 cix := MyRO.nCity - 1;
1126 while (cix >= 0) and (MyCity[cix].Loc <> Loc) do
1127 dec(cix);
1128 assert(cix >= 0);
1129 if (Optimize_cixTileChange >= 0) and
1130 (Optimize_TilesBeforeChange and not MyCity[Optimize_cixTileChange].Tiles
1131 <> 0) then
1132 begin
1133 CityOptimizer_ReleaseCityTiles(Optimize_cixTileChange,
1134 Optimize_TilesBeforeChange and
1135 not MyCity[Optimize_cixTileChange].Tiles);
1136 if WindowMode <> wmModal then
1137 MainScreen.UpdateViews;
1138 end;
1139 Optimize_cixTileChange := cix;
1140 Optimize_TilesBeforeChange := MyCity[cix].Tiles;
1141 end
1142 else
1143 cix := -1;
1144 AllowChange := not supervising and (cix >= 0);
1145 cLoc := Loc;
1146 Happened := ShowEvent;
1147 inherited ShowNewContent(NewMode);
1148end;
1149
1150procedure TCityDlg.FormMouseDown(Sender: TObject; Button: TMouseButton;
1151 Shift: TShiftState; x, y: integer);
1152var
1153 i, qx, qy, dx, dy, fix, NewTiles, Loc1, iix, SellResult: integer;
1154 Rebuild: boolean;
1155begin
1156 if (ssLeft in Shift) and (x >= xSmallMap) and (x < xSmallMap + wSmallMap) and
1157 (y >= ySmallMap) and (y < ySmallMap + hSmallMap) then
1158 begin
1159 Mode := mImp;
1160 ZoomArea := (y - ySmallMap) * 3 div hSmallMap + 3 *
1161 ((x - xSmallMap) * 2 div wSmallMap);
1162 Page := 0;
1163 InitZoomCityMap;
1164 SmartUpdateContent;
1165 exit;
1166 end;
1167 if (ssLeft in Shift) and (x >= xSupport) and (x < xSupport + wSupport) and
1168 (y >= ySupport) and (y < ySupport + hSupport) then
1169 begin
1170 Mode := mSupp;
1171 Page := 0;
1172 InitZoomCityMap;
1173 SmartUpdateContent;
1174 exit;
1175 end;
1176 if not AllowChange then
1177 exit; // not an own city
1178
1179 if (ssLeft in Shift) then
1180 if (ClientMode < scContact) and (x >= xView) and (y >= yView) and
1181 (x < xView + 73) and (y < yView + 50) then
1182 if cGov = gAnarchy then
1183 with MessgExDlg do
1184 begin
1185 { MessgText:=Phrases.Lookup('OUTOFCONTROL');
1186 if c.Project and cpImp=0 then
1187 MessgText:=Format(MessgText,[Tribe[cOwner].ModelName[c.Project and cpIndex]])
1188 else MessgText:=Format(MessgText,[Phrases.Lookup('IMPROVEMENTS',c.Project and cpIndex)]); }
1189 MessgText := Phrases.Lookup('NOCHANGEINANARCHY');
1190 Kind := mkOk;
1191 ShowModal;
1192 end
1193 else
1194 begin
1195 if ProdHint then
1196 begin
1197 ProdHint := false;
1198 SmartUpdateContent
1199 end;
1200 ChooseProject;
1201 end
1202 else if (Mode = mImp) and (x >= xZoomMap) and (x < xZoomMap + wZoomMap) and
1203 (y >= yZoomMap) and (y < yZoomMap + hZoomMap) then
1204 begin
1205 i := 5;
1206 while (i >= 0) and not((x >= xZoomMap + 14 + 72 * (i mod 3)) and
1207 (x < xZoomMap + 14 + 56 + 72 * (i mod 3)) and
1208 (y >= yZoomMap + 14 + 56 * (i div 3)) and
1209 (y < yZoomMap + 14 + 40 + 56 * (i div 3))) do
1210 dec(i);
1211 if i >= 0 then
1212 begin
1213 iix := imix[i];
1214 if iix >= 0 then
1215 if ssShift in Shift then
1216 HelpDlg.ShowNewContent(Mode or wmPersistent, hkImp, iix)
1217 else if (ClientMode < scContact) then
1218 with MessgExDlg do
1219 begin
1220 IconKind := mikImp;
1221 IconIndex := iix;
1222 if (iix = imPalace) or (Imp[iix].Kind = ikWonder) then
1223 begin
1224 MessgText := Phrases.Lookup('IMPROVEMENTS', iix);
1225 if iix = woOracle then
1226 MessgText := MessgText + '\' +
1227 Format(Phrases.Lookup('ORACLEINCOME'), [MyRO.OracleIncome]);
1228 Kind := mkOk;
1229 ShowModal;
1230 end
1231 else
1232 begin
1233 SellResult := Server(sSellCityImprovement - sExecute, me,
1234 cix, iix);
1235 if SellResult < rExecuted then
1236 begin
1237 if SellResult = eOnlyOnce then
1238 MessgText := Phrases.Lookup('NOSELLAGAIN')
1239 else
1240 MessgText := Phrases.Lookup('OUTOFCONTROL');
1241 MessgText := Format(MessgText,
1242 [Phrases.Lookup('IMPROVEMENTS', iix)]);
1243 Kind := mkOk;
1244 ShowModal;
1245 end
1246 else
1247 begin
1248 if Server(sRebuildCityImprovement - sExecute, me, cix, iix) < rExecuted
1249 then
1250 begin // no rebuild possible, ask for sell only
1251 Rebuild := false;
1252 MessgText := Phrases.Lookup('IMPROVEMENTS', iix);
1253 if not Phrases2FallenBackToEnglish then
1254 MessgText := Format(Phrases2.Lookup('SELL2'),
1255 [MessgText, Imp[iix].Cost * BuildCostMod
1256 [G.Difficulty[me]] div 12])
1257 else
1258 MessgText := Format(Phrases.Lookup('SELL'), [MessgText]);
1259 if iix = imSpacePort then
1260 with MyRO.Ship[me] do
1261 if Parts[0] + Parts[1] + Parts[2] > 0 then
1262 MessgText := MessgText + ' ' +
1263 Phrases.Lookup('SPDESTRUCTQUERY');
1264 Kind := mkYesNo;
1265 ShowModal;
1266 if ModalResult <> mrOK then
1267 iix := -1
1268 end
1269 else
1270 begin
1271 Rebuild := true;
1272 MessgText := Phrases.Lookup('IMPROVEMENTS', iix);
1273 if not Phrases2FallenBackToEnglish then
1274 MessgText := Format(Phrases2.Lookup('DISPOSE2'),
1275 [MessgText, Imp[iix].Cost * BuildCostMod
1276 [G.Difficulty[me]] div 12 * 2 div 3])
1277 else
1278 MessgText := Format(Phrases.Lookup('DISPOSE'),
1279 [MessgText]);
1280 if iix = imSpacePort then
1281 with MyRO.Ship[me] do
1282 if Parts[0] + Parts[1] + Parts[2] > 0 then
1283 MessgText := MessgText + ' ' +
1284 Phrases.Lookup('SPDESTRUCTQUERY');
1285 Kind := mkYesNo;
1286 ShowModal;
1287 if ModalResult <> mrOK then
1288 iix := -1
1289 end;
1290 if iix >= 0 then
1291 begin
1292 if Rebuild then
1293 begin
1294 Play('CITY_REBUILDIMP');
1295 Server(sRebuildCityImprovement, me, cix, iix);
1296 end
1297 else
1298 begin
1299 Play('CITY_SELLIMP');
1300 Server(sSellCityImprovement, me, cix, iix);
1301 end;
1302 CityOptimizer_CityChange(cix);
1303 InitSmallCityMap;
1304 SmartUpdateContent;
1305 if WindowMode <> wmModal then
1306 MainScreen.UpdateViews;
1307 end;
1308 end;
1309 end;
1310 end;
1311 end;
1312 end
1313 else if (Mode = mSupp) and (x >= xZoomMap) and (x < xZoomMap + wZoomMap) and
1314 (y >= yZoomMap) and (y < yZoomMap + hZoomMap) then
1315 begin
1316 i := 5;
1317 while (i >= 0) and not((x >= xZoomMap + 64 * (i mod 3)) and
1318 (x < xZoomMap + 64 + 64 * (i mod 3)) and
1319 (y >= yZoomMap + 20 + 48 * (i div 3)) and
1320 (y < yZoomMap + 20 + 52 + 48 * (i div 3))) do
1321 dec(i);
1322 if (i >= 0) and (imix[i] >= 0) then
1323 if ssShift in Shift then
1324 else if (cix >= 0) and (ClientMode < scContact) and
1325 (WindowMode <> wmModal) then
1326 begin
1327 CloseAction := None;
1328 Close;
1329 MainScreen.CityClosed(imix[i], false, true);
1330 end;
1331 end
1332 else if (x >= xmArea - 192) and (x < xmArea + 192) and (y >= ymArea - 96)
1333 and (y < ymArea + 96) then
1334 begin
1335 qx := ((4000 * xxt * yyt) + (x - xmArea) * (yyt * 2) + (y - ymArea + yyt)
1336 * (xxt * 2)) div (xxt * yyt * 4) - 1000;
1337 qy := ((4000 * xxt * yyt) + (y - ymArea + yyt) * (xxt * 2) - (x - xmArea)
1338 * (yyt * 2)) div (xxt * yyt * 4) - 1000;
1339 dx := qx - qy;
1340 dy := qx + qy;
1341 if (dx >= -3) and (dx <= 3) and (dy >= -3) and (dy <= 3) and
1342 (dx * dx * dy * dy < 81) and ((dx <> 0) or (dy <> 0)) then
1343 if ssShift in Shift then
1344 begin // terrain help
1345 Loc1 := dLoc(cLoc, dx, dy);
1346 if (Loc1 >= 0) and (Loc1 < G.lx * G.ly) then
1347 HelpOnTerrain(Loc1, Mode or wmPersistent)
1348 end
1349 else if (ClientMode < scContact) and (cGov <> gAnarchy) and
1350 (c.Flags and chCaptured = 0) then
1351 begin // toggle exploitation
1352 assert(not supervising);
1353 if c.Status and csResourceWeightsMask <> 0 then
1354 begin
1355 with MessgExDlg do
1356 begin
1357 MessgText := Phrases.Lookup('CITYMANAGEOFF');
1358 OpenSound := 'MSG_DEFAULT';
1359 Kind := mkOkCancel;
1360 IconKind := mikFullControl;
1361 ShowModal;
1362 end;
1363 if MessgExDlg.ModalResult = mrOK then
1364 begin
1365 MyCity[cix].Status := MyCity[cix].Status and
1366 not csResourceWeightsMask; // off
1367 c.Status := MyCity[cix].Status;
1368 SmartUpdateContent
1369 end;
1370 exit;
1371 end;
1372 fix := (dy + 3) shl 2 + (dx + 3) shr 1;
1373 NewTiles := MyCity[cix].Tiles xor (1 shl fix);
1374 if Server(sSetCityTiles, me, cix, NewTiles) >= rExecuted then
1375 begin
1376 SmartUpdateContent;
1377 if WindowMode <> wmModal then
1378 MainScreen.UpdateViews;
1379 end;
1380 end;
1381 end
1382 else if (ClientMode < scContact) and (cGov <> gAnarchy) and
1383 (c.Flags and chCaptured = 0) and (x >= xmOpt - 32) and (x < xmOpt + 32)
1384 and (y >= ymOpt - 32) and (y < ymOpt + 32) then
1385 begin
1386 i := sqr(x - xmOpt) + sqr(y - ymOpt); // click radius
1387 if i <= 32 * 32 then
1388 begin
1389 if i < 16 * 16 then // inner area clicked
1390 if c.Status and csResourceWeightsMask <> 0 then
1391 i := (c.Status shr 4 and $0F) mod 5 + 1 // rotate except off
1392 else
1393 i := 3 // rwGrowth
1394 else
1395 case trunc(arctan2(x - xmOpt, ymOpt - y) * 180 / pi) of
1396 - 25 - 52 * 2 .. -26 - 52:
1397 i := 1;
1398 -25 - 52 .. -26:
1399 i := 2;
1400 -25 .. 25:
1401 i := 3;
1402 26 .. 25 + 52:
1403 i := 4;
1404 26 + 52 .. 25 + 52 * 2:
1405 i := 5;
1406 180 - 26 .. 180, -180 .. -180 + 26:
1407 i := 0;
1408 else
1409 i := -1;
1410 end;
1411 if i >= 0 then
1412 begin
1413 ChangeResourceWeights(i);
1414 SmartUpdateContent;
1415 if WindowMode <> wmModal then
1416 MainScreen.UpdateViews;
1417 end;
1418 end;
1419 end;
1420end; { FormMouseDown }
1421
1422procedure TCityDlg.ChooseProject;
1423const
1424 ptSelect = 0;
1425 ptTrGoods = 1;
1426 ptUn = 2;
1427 ptCaravan = 3;
1428 ptImp = 4;
1429 ptWonder = 6;
1430 ptShip = 7;
1431 ptInvalid = 8;
1432
1433 function ProjectType(Project: integer): integer;
1434 begin
1435 if Project and cpCompleted <> 0 then
1436 result := ptSelect
1437 else if Project and (cpImp + cpIndex) = cpImp + imTrGoods then
1438 result := ptTrGoods
1439 else if Project and cpImp = 0 then
1440 if MyModel[Project and cpIndex].Kind = mkCaravan then
1441 result := ptCaravan
1442 else
1443 result := ptUn
1444 else if Project and cpIndex >= nImp then
1445 result := ptInvalid
1446 else if Imp[Project and cpIndex].Kind = ikWonder then
1447 result := ptWonder
1448 else if Imp[Project and cpIndex].Kind = ikShipPart then
1449 result := ptShip
1450 else
1451 result := ptImp
1452 end;
1453
1454var
1455 NewProject, OldMoney, pt0, pt1, cix1: integer;
1456 QueryOk: boolean;
1457begin
1458 assert(not supervising);
1459 ModalSelectDlg.ShowNewContent_CityProject(wmModal, cix);
1460 if ModalSelectDlg.result <> -1 then
1461 begin
1462 if ModalSelectDlg.result and cpType <> 0 then
1463 begin
1464 MyCity[cix].Status := MyCity[cix].Status and not 7 or
1465 (1 + ModalSelectDlg.result and cpIndex);
1466 AutoBuild(cix, MyData.ImpOrder[ModalSelectDlg.result and cpIndex]);
1467 end
1468 else
1469 begin
1470 NewProject := ModalSelectDlg.result;
1471 QueryOk := true;
1472 if (NewProject and cpImp <> 0) and (NewProject and cpIndex >= 28) and
1473 (MyRO.NatBuilt[NewProject and cpIndex] > 0) then
1474 with MessgExDlg do
1475 begin
1476 cix1 := MyRO.nCity - 1;
1477 while (cix1 >= 0) and
1478 (MyCity[cix1].Built[NewProject and cpIndex] = 0) do
1479 dec(cix1);
1480 MessgText := Format(Phrases.Lookup('DOUBLESTATEIMP'),
1481 [Phrases.Lookup('IMPROVEMENTS', NewProject and cpIndex),
1482 CityName(MyCity[cix1].ID)]);
1483 OpenSound := 'MSG_DEFAULT';
1484 Kind := mkOkCancel;
1485 IconKind := mikImp;
1486 IconIndex := NewProject and cpIndex;
1487 ShowModal;
1488 QueryOk := ModalResult = mrOK;
1489 end;
1490 if not QueryOk then
1491 exit;
1492
1493 if (MyCity[cix].Prod > 0) then
1494 begin
1495 pt0 := ProjectType(MyCity[cix].Project0);
1496 pt1 := ProjectType(NewProject);
1497 if (pt0 <> ptSelect) and (pt1 <> ptTrGoods) then
1498 begin
1499 if NewProject and (cpImp or cpIndex) <> MyCity[cix].Project0 and
1500 (cpImp or cpIndex) then
1501 begin // loss of material -- do query
1502 if (pt1 = ptTrGoods) or (pt1 = ptShip) or (pt1 <> pt0) and
1503 (pt0 <> ptCaravan) then
1504 QueryOk := SimpleQuery(mkOkCancel,
1505 Format(Phrases.Lookup('LOSEMAT'), [MyCity[cix].Prod0,
1506 MyCity[cix].Prod0]), 'MSG_DEFAULT') = mrOK
1507 else if MyCity[cix].Project and (cpImp or cpIndex) = MyCity[cix]
1508 .Project0 and (cpImp or cpIndex) then
1509 QueryOk := SimpleQuery(mkOkCancel, Phrases.Lookup('LOSEMAT3'),
1510 'MSG_DEFAULT') = mrOK
1511 end;
1512 end;
1513 end;
1514 if not QueryOk then
1515 exit;
1516
1517 OldMoney := MyRO.Money;
1518 MyCity[cix].Status := MyCity[cix].Status and not 7;
1519 if (NewProject and cpImp = 0) and
1520 ((MyCity[cix].Size < 4) and
1521 (MyModel[NewProject and cpIndex].Kind = mkSettler) or
1522 (MyCity[cix].Size < 3) and
1523 ((MyModel[NewProject and cpIndex].Kind = mkSlaves) or
1524 (NewProject and cpConscripts <> 0))) then
1525 if SimpleQuery(mkYesNo, Phrases.Lookup('EMIGRATE'), 'MSG_DEFAULT') <> mrOK
1526 then
1527 NewProject := NewProject or cpDisbandCity;
1528 Server(sSetCityProject, me, cix, NewProject);
1529 c.Project := MyCity[cix].Project;
1530 if MyRO.Money > OldMoney then
1531 Play('CITY_SELLIMP');
1532 end;
1533 CityOptimizer_CityChange(cix);
1534
1535 if WindowMode <> wmModal then
1536 MainScreen.UpdateViews;
1537 InitSmallCityMap;
1538 SmartUpdateContent;
1539 end;
1540end;
1541
1542procedure TCityDlg.BuyClick(Sender: TObject);
1543var
1544 NextProd, Cost: integer;
1545begin
1546 if (cix < 0) or (ClientMode >= scContact) then
1547 exit;
1548 with MyCity[cix], MessgExDlg do
1549 begin
1550 Cost := Report.ProjectCost;
1551 NextProd := Report.Production;
1552 if NextProd < 0 then
1553 NextProd := 0;
1554 Cost := Cost - Prod - NextProd;
1555 if (MyRO.Wonder[woMich].EffectiveOwner = me) and (Project and cpImp <> 0)
1556 then
1557 Cost := Cost * 2
1558 else
1559 Cost := Cost * 4;
1560 if (Cost <= 0) and (Report.HappinessBalance >= 0) { no disorder } then
1561 begin
1562 MessgText := Phrases.Lookup('READY');
1563 Kind := mkOk;
1564 end
1565 else if Cost > MyRO.Money then
1566 begin
1567 OpenSound := 'MSG_DEFAULT';
1568 MessgText := Format(Phrases.Lookup('NOMONEY'), [Cost, MyRO.Money]);
1569 Kind := mkOk;
1570 end
1571 else
1572 begin
1573 MessgText := Format(Phrases.Lookup('BUY'), [Cost]);
1574 Kind := mkYesNo;
1575 end;
1576 ShowModal;
1577 if (Kind = mkYesNo) and (ModalResult = mrOK) then
1578 begin
1579 if Server(sBuyCityProject, me, cix, nil^) >= rExecuted then
1580 begin
1581 Play('CITY_BUYPROJECT');
1582 SmartUpdateContent;
1583 if WindowMode <> wmModal then
1584 MainScreen.UpdateViews;
1585 end;
1586 end;
1587 end;
1588end;
1589
1590procedure TCityDlg.FormClose(Sender: TObject; var Action: TCloseAction);
1591begin
1592 Timer1.Enabled := false;
1593 ProdHint := false;
1594 MarkCityLoc := -1;
1595 if Optimize_cixTileChange >= 0 then
1596 begin
1597 if Optimize_TilesBeforeChange and not MyCity[Optimize_cixTileChange]
1598 .Tiles <> 0 then
1599 begin
1600 CityOptimizer_ReleaseCityTiles(Optimize_cixTileChange,
1601 Optimize_TilesBeforeChange and
1602 not MyCity[Optimize_cixTileChange].Tiles);
1603 if WindowMode <> wmModal then
1604 MainScreen.UpdateViews;
1605 end;
1606 Optimize_cixTileChange := -1;
1607 end;
1608 if CloseAction > None then
1609 MainScreen.CityClosed(RestoreUnFocus, CloseAction = StepFocus);
1610 RestoreUnFocus := -1;
1611 inherited;
1612end;
1613
1614procedure TCityDlg.Timer1Timer(Sender: TObject);
1615begin
1616 if ProdHint then
1617 begin
1618 BlinkTime := (BlinkTime + 1) mod 12;
1619 if BlinkTime = 0 then
1620 with Canvas do
1621 begin
1622 bitblt(Canvas.Handle, xView + 5, yView + 1, 64, 2, Back.Canvas.Handle,
1623 xView + 5, yView + 1, SRCCOPY);
1624 bitblt(Canvas.Handle, xView + 5, yView + 3, 2, 42, Back.Canvas.Handle,
1625 xView + 5, yView + 3, SRCCOPY);
1626 bitblt(Canvas.Handle, xView + 5 + 62, yView + 3, 2, 42,
1627 Back.Canvas.Handle, xView + 5 + 62, yView + 3, SRCCOPY);
1628 ScreenTools.Frame(Canvas, xView + 9 - 1, yView + 5 - 1, xView + 9 + xSizeBig,
1629 yView + 5 + ySizeBig, $B0B0B0, $FFFFFF);
1630 RFrame(Canvas, xView + 9 - 2, yView + 5 - 2, xView + 9 + xSizeBig + 1,
1631 yView + 5 + ySizeBig + 1, $FFFFFF, $B0B0B0);
1632 brush.Color := $000000;
1633 FillRect(Rect(xView + 9, yView + 5, xView + 1 + 72 - 8,
1634 yView + 5 + 40));
1635 brush.style := bsClear;
1636 end
1637 else if BlinkTime = 6 then
1638 begin
1639 if AllowChange and (c.Status and 7 <> 0) then
1640 begin // city type autobuild
1641 FrameImage(Canvas, bigimp, xView + 9, yView + 5, xSizeBig, ySizeBig,
1642 (c.Status and 7 - 1 + 3) * xSizeBig, 0, true);
1643 end
1644 else if c.Project and cpImp = 0 then
1645 begin // project is unit
1646 bitblt(Canvas.Handle, xView + 9, yView + 5, xSizeBig, ySizeBig,
1647 bigimp.Canvas.Handle, 0, 0, SRCCOPY);
1648 with Tribe[cOwner].ModelPicture[c.Project and cpIndex] do
1649 Sprite(Canvas, HGr, xView + 5, yView + 1, 64, 44, pix mod 10 * 65 + 1,
1650 pix div 10 * 49 + 1);
1651 end
1652 else
1653 ImpImage(Canvas, xView + 9, yView + 5, c.Project0 and cpIndex,
1654 cGov, true);
1655 end;
1656 end;
1657end;
1658
1659procedure TCityDlg.FormPaint(Sender: TObject);
1660begin
1661 inherited;
1662 if OpenSoundEvent >= 0 then
1663 PostMessage(Handle, WM_PLAYSOUND, 0, 0);
1664end;
1665
1666procedure TCityDlg.OnPlaySound(var Msg: TMessage);
1667begin
1668 if 1 shl OpenSoundEvent = chProduction then
1669 begin
1670 if c.Project0 and cpImp <> 0 then
1671 begin
1672 if c.Project0 and cpIndex >= 28 then
1673 // wonders have already extra message with sound
1674 if Imp[c.Project0 and cpIndex].Kind = ikShipPart then
1675 Play('SHIP_BUILT')
1676 else
1677 Play('CITY_IMPCOMPLETE')
1678 end
1679 else
1680 Play('CITY_UNITCOMPLETE');
1681 end
1682 else
1683 Play(CityEventSoundItem[OpenSoundEvent]);
1684 OpenSoundEvent := -2;
1685end;
1686
1687function Prio(iix: integer): integer;
1688begin
1689 case Imp[iix].Kind of
1690 ikWonder:
1691 result := iix + 10000;
1692 ikNatLocal, ikNatGlobal:
1693 case iix of
1694 imPalace:
1695 result := 0;
1696 else
1697 result := iix + 20000;
1698 end;
1699 else
1700 case iix of
1701 imTownHall, imCourt:
1702 result := iix + 30000;
1703 imAqueduct, imSewer:
1704 result := iix + 40000;
1705 imTemple, imTheater, imCathedral:
1706 result := iix + 50000;
1707 else
1708 result := iix + 90000;
1709 end;
1710 end;
1711end;
1712
1713procedure TCityDlg.NextCityBtnClick(Sender: TObject);
1714begin
1715 ChangeCity(+1);
1716end;
1717
1718procedure TCityDlg.PrevCityBtnClick(Sender: TObject);
1719begin
1720 ChangeCity(-1);
1721end;
1722
1723procedure TCityDlg.ChangeCity(d: integer);
1724var
1725 cixNew: integer;
1726begin
1727 cixNew := cix;
1728 repeat
1729 cixNew := (cixNew + MyRO.nCity + d) mod MyRO.nCity;
1730 until (MyCity[cixNew].Loc >= 0) or (cixNew = cix);
1731 if cixNew <> cix then
1732 MainScreen.ZoomToCity(MyCity[cixNew].Loc);
1733end;
1734
1735procedure TCityDlg.FormKeyDown(Sender: TObject; var Key: Word;
1736 Shift: TShiftState);
1737begin
1738 if ((Key = VK_UP) or (Key = VK_NUMPAD8)) and (cix >= 0) and
1739 (WindowMode = wmPersistent) then
1740 ChangeCity(-1)
1741 else if ((Key = VK_DOWN) or (Key = VK_NUMPAD2)) and (cix >= 0) and
1742 (WindowMode = wmPersistent) then
1743 ChangeCity(+1)
1744 else
1745 inherited;
1746end;
1747
1748{ procedure TCityDlg.AdviceBtnClick(Sender: TObject);
1749 begin
1750 AdvisorDlg.GiveCityAdvice(cix);
1751 end; }
1752
1753var
1754 i, j, k: integer;
1755
1756procedure TCityDlg.PageUpBtnClick(Sender: TObject);
1757begin
1758 if Page > 0 then
1759 begin
1760 dec(Page);
1761 SmartUpdateContent
1762 end;
1763end;
1764
1765procedure TCityDlg.PageDownBtnClick(Sender: TObject);
1766begin
1767 if Page < PageCount - 1 then
1768 begin
1769 inc(Page);
1770 SmartUpdateContent
1771 end;
1772end;
1773
1774procedure TCityDlg.ChangeResourceWeights(iResourceWeights: integer);
1775var
1776 Advice: TCityTileAdviceData;
1777begin
1778 assert(not supervising);
1779 assert(cix >= 0);
1780 MyCity[cix].Status := MyCity[cix].Status and not csResourceWeightsMask or
1781 (iResourceWeights shl 4);
1782 c.Status := MyCity[cix].Status;
1783 if iResourceWeights > 0 then
1784 begin
1785 Advice.ResourceWeights := OfferedResourceWeights[iResourceWeights];
1786 Server(sGetCityTileAdvice, me, cix, Advice);
1787 if Advice.Tiles <> MyCity[cix].Tiles then
1788 Server(sSetCityTiles, me, cix, Advice.Tiles);
1789 end;
1790end;
1791
1792initialization
1793
1794for i := 0 to nImp - 1 do
1795 ImpSorted[i] := i;
1796for i := 0 to nImp - 2 do
1797 for j := i + 1 to nImp - 1 do
1798 if Prio(ImpSorted[i]) > Prio(ImpSorted[j]) then
1799 begin
1800 k := ImpSorted[i];
1801 ImpSorted[i] := ImpSorted[j];
1802 ImpSorted[j] := k;
1803 end;
1804
1805end.
Note: See TracBrowser for help on using the repository browser.