source: tags/1.3.1/LocalPlayer/ClientTools.pas

Last change on this file was 442, checked in by chronos, 2 years ago
  • Modified: Code cleanup.
File size: 21.9 KB
Line 
1{$INCLUDE Switches.inc}
2unit ClientTools;
3
4interface
5
6uses
7 Protocol;
8
9const
10 nOfferedResourceWeights = 6;
11 OfferedResourceWeights: array [0 .. nOfferedResourceWeights - 1] of cardinal =
12 (rwOff, rwMaxScience, rwForceScience, rwMaxGrowth, rwForceProd, rwMaxProd);
13
14type
15 TImpOrder = array [0 .. (nImp + 4) div 4 * 4 - 1] of shortint;
16 TEnhancementJobs = array [0 .. 11, 0 .. 7] of byte;
17 JobResultSet = set of 0 .. 39;
18
19 TMapOption = (
20 // options switched by buttons
21 moPolitical = 0, moCityNames = 1, moGreatWall = 4, moGrid = 5, moBareTerrain = 6,
22 // other options
23 moEditMode = 16, moLocCodes = 17
24 );
25 TMapOptions = set of TMapOption;
26
27 TSaveOption = (soAlEffectiveMovesOnly = 0, soEnMoves = 1, soEnAttacks = 2,
28 soEnNoMoves = 3, soWaitTurn = 4, soEffectiveMovesOnly = 5, soEnFastMoves = 6,
29 soSlowMoves = 7, soFastMoves = 8, soVeryFastMoves = 9, soNames = 10,
30 soRepList = 11, soRepScreens = 12, soSoundOff = 13, soSoundOn = 14,
31 soSoundOnAlt = 15, soScrollSlow = 16, soScrollFast = 17, soScrollOff = 18,
32 soAlSlowMoves = 19, soAlFastMoves = 20, somAlNoMoves = 21, soTellAI = 30);
33 TSaveOptions = set of TSaveOption;
34
35var
36 Server: TServerCall;
37 G: TNewGameData;
38 me: integer;
39 MyRO: ^TPlayerContext;
40 MyMap: ^TTileList;
41 MyUn: ^TUnList;
42 MyCity: ^TCityList;
43 MyModel: ^TModelList;
44
45 AdvValue: array [0 .. nAdv - 1] of integer;
46
47function dLoc(Loc, dx, dy: integer): integer;
48function Distance(Loc0, Loc1: integer): integer;
49function UnrestAtLoc(uix, Loc: integer): boolean;
50function GetMoveAdvice(uix, ToLoc: integer;
51 var MoveAdviceData: TMoveAdviceData): integer;
52function ColorOfHealth(Health: integer): integer;
53function IsMultiPlayerGame: boolean;
54procedure ItsMeAgain(p: integer);
55function GetAge(p: integer): integer;
56function IsCivilReportNew(Enemy: integer): boolean;
57function IsMilReportNew(Enemy: integer): boolean;
58function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean;
59 gov, size: integer): integer;
60function CityTaxBalance(cix: integer; const CityReport: TCityReportNew): integer;
61procedure SumCities(var TaxSum, ScienceSum: integer);
62function JobTest(uix, Job: integer; IgnoreResults: JobResultSet = []): boolean;
63procedure GetUnitInfo(Loc: integer; var uix: integer; var UnitInfo: TUnitInfo);
64procedure GetCityInfo(Loc: integer; var cix: integer; var CityInfo: TCityInfo);
65function UnitExhausted(uix: integer): boolean;
66function ModelHash(const ModelInfo: TModelInfo): integer;
67function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs): integer;
68function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean;
69procedure DebugMessage(Level: integer; Text: string);
70procedure CityOptimizer_BeginOfTurn;
71procedure CityOptimizer_CityChange(cix: integer);
72procedure CityOptimizer_TileBecomesAvailable(Loc: integer);
73procedure CityOptimizer_ReleaseCityTiles(cix, ReleasedTiles: integer);
74procedure CityOptimizer_BeforeRemoveUnit(uix: integer);
75procedure CityOptimizer_AfterRemoveUnit;
76procedure CityOptimizer_EndOfTurn;
77function GetMyCityByLoc(Loc: Integer): PCity;
78function GetEnemyCityByLoc(Loc: Integer): PCityInfo;
79function GetMyUnitByLoc(Loc: Integer): PUn;
80function GetEnemyUnitByLoc(Loc: Integer): PUnitInfo;
81
82
83implementation
84
85var
86 CityNeedsOptimize: array [0 .. ncmax - 1] of boolean;
87
88function dLoc(Loc, dx, dy: integer): integer;
89var
90 y0: integer;
91begin
92 y0 := (Loc + G.lx * 1024) div G.lx - 1024;
93 Result := (Loc + (dx + y0 and 1 + G.lx * 1024) shr 1) mod G.lx + G.lx * (y0 + dy);
94end;
95
96function Distance(Loc0, Loc1: integer): integer;
97var
98 dx, dy: integer;
99begin
100 Inc(Loc0, G.lx * 1024);
101 Inc(Loc1, G.lx * 1024);
102 dx := abs(((Loc1 mod G.lx * 2 + Loc1 div G.lx and 1) -
103 (Loc0 mod G.lx * 2 + Loc0 div G.lx and 1) + 3 * G.lx) mod (2 * G.lx) - G.lx);
104 dy := abs(Loc1 div G.lx - Loc0 div G.lx);
105 Result := dx + dy + abs(dx - dy) shr 1;
106end;
107
108function UnrestAtLoc(uix, Loc: integer): boolean;
109var
110 uix1: integer;
111begin
112 Result := False;
113 if MyModel[MyUn[uix].mix].Flags and mdCivil = 0 then
114 case MyRO.Government of
115 gRepublic, gFuture:
116 Result := (MyRO.Territory[Loc] >= 0) and (MyRO.Territory[Loc] <> me) and
117 (MyRO.Treaty[MyRO.Territory[Loc]] < trAlliance);
118 gDemocracy:
119 Result := (MyRO.Territory[Loc] < 0) or (MyRO.Territory[Loc] <> me) and
120 (MyRO.Treaty[MyRO.Territory[Loc]] < trAlliance);
121 end;
122 with MyModel[MyUn[uix].mix] do
123 if Cap[mcSeaTrans] + Cap[mcAirTrans] + Cap[mcCarrier] > 0 then
124 for uix1 := 0 to MyRO.nUn - 1 do // check transported units too
125 if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) then
126 Result := Result or UnrestAtLoc(uix1, Loc);
127end;
128
129function GetMoveAdvice(uix, ToLoc: integer;
130 var MoveAdviceData: TMoveAdviceData): integer;
131var
132 MinEndHealth: integer;
133begin
134 if MyModel[MyUn[uix].mix].Domain = dGround then
135 MinEndHealth := 100
136 else
137 MinEndHealth := 1; // resistent to hostile terrain -- don't consider
138 repeat
139 if MyUn[uix].Health >= MinEndHealth then
140 begin
141 MoveAdviceData.ToLoc := ToLoc;
142 MoveAdviceData.MoreTurns := 999;
143 MoveAdviceData.MaxHostile_MovementLeft := MyUn[uix].Health - MinEndHealth;
144 Result := Server(sGetMoveAdvice, me, uix, MoveAdviceData);
145 if (MinEndHealth <= 1) or (Result <> eNoWay) then
146 exit;
147 end;
148 case MinEndHealth of
149 100:
150 MinEndHealth := 50;
151 50:
152 MinEndHealth := 25;
153 25:
154 MinEndHealth := 12;
155 else
156 MinEndHealth := 1
157 end;
158 until False;
159end;
160
161function ColorOfHealth(Health: integer): integer;
162var
163 red, green: integer;
164begin
165 green := 400 * Health div 100;
166 if green > 200 then
167 green := 200;
168 red := 510 * (100 - Health) div 100;
169 if red > 255 then
170 red := 255;
171 Result := green shl 8 + red;
172end;
173
174function IsMultiPlayerGame: boolean;
175var
176 p1: integer;
177begin
178 Result := False;
179 for p1 := 1 to nPl - 1 do
180 if G.RO[p1] <> nil then
181 Result := True;
182end;
183
184procedure ItsMeAgain(p: integer);
185begin
186 if G.RO[p] <> nil then
187 MyRO := pointer(G.RO[p])
188 else if G.SuperVisorRO[p] <> nil then
189 MyRO := pointer(G.SuperVisorRO[p])
190 else
191 exit;
192 me := p;
193 MyMap := pointer(MyRO.Map);
194 MyUn := pointer(MyRO.Un);
195 MyCity := pointer(MyRO.City);
196 MyModel := pointer(MyRO.Model);
197end;
198
199function GetAge(p: integer): integer;
200var
201 i: integer;
202begin
203 if p = me then begin
204 Result := 0;
205 for i := 1 to 3 do
206 if MyRO.Tech[AgePreq[i]] >= tsApplicable then
207 Result := i;
208 end else begin
209 Result := 0;
210 for i := 1 to 3 do
211 if MyRO.EnemyReport[p].Tech[AgePreq[i]] >= tsApplicable then
212 Result := i;
213 end;
214end;
215
216function IsCivilReportNew(Enemy: integer): boolean;
217var
218 i: integer;
219begin
220 assert(Enemy <> me);
221 i := MyRO.EnemyReport[Enemy].TurnOfCivilReport;
222 Result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me);
223end;
224
225function IsMilReportNew(Enemy: integer): boolean;
226var
227 i: integer;
228begin
229 assert(Enemy <> me);
230 i := MyRO.EnemyReport[Enemy].TurnOfMilReport;
231 Result := (i = MyRO.Turn) or (i = MyRO.Turn - 1) and (Enemy > me);
232end;
233
234function CutCityFoodSurplus(FoodSurplus: integer; IsCityAlive: boolean;
235 gov, size: integer): integer;
236begin
237 Result := FoodSurplus;
238 if not IsCityAlive or (Result > 0) and ((gov = gFuture) or
239 (size >= NeedAqueductSize) and (Result < 2)) then
240 Result := 0; { no growth }
241end;
242
243function CityTaxBalance(cix: integer; const CityReport: TCityReportNew): integer;
244var
245 i: integer;
246begin
247 Result := 0;
248 if (CityReport.HappinessBalance >= 0) { no disorder } and
249 (MyCity[cix].Flags and chCaptured = 0) then // not captured
250 begin
251 Inc(Result, CityReport.Tax);
252 if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) and
253 (CityReport.Production > 0) then
254 Inc(Result, CityReport.Production);
255 if ((MyRO.Government = gFuture) or (MyCity[cix].size >=
256 NeedAqueductSize) and (CityReport.FoodSurplus < 2)) and
257 (CityReport.FoodSurplus > 0) then
258 Inc(Result, CityReport.FoodSurplus);
259 end;
260 for i := nWonder to nImp - 1 do
261 if MyCity[cix].Built[i] > 0 then
262 Dec(Result, Imp[i].Maint);
263end;
264
265procedure SumCities(var TaxSum, ScienceSum: integer);
266var
267 cix: integer;
268 CityReport: TCityReportNew;
269begin
270 TaxSum := MyRO.OracleIncome;
271 ScienceSum := 0;
272 if MyRO.Government = gAnarchy then
273 exit;
274 for cix := 0 to MyRO.nCity - 1 do
275 if MyCity[cix].Loc >= 0 then
276 begin
277 CityReport.HypoTiles := -1;
278 CityReport.HypoTaxRate := -1;
279 CityReport.HypoLuxuryRate := -1;
280 Server(sGetCityReportNew, me, cix, CityReport);
281 if (CityReport.HappinessBalance >= 0) { no disorder } and
282 (MyCity[cix].Flags and chCaptured = 0) then // not captured
283 ScienceSum := ScienceSum + CityReport.Science;
284 TaxSum := TaxSum + CityTaxBalance(cix, CityReport);
285 end;
286end;
287
288function JobTest(uix, Job: integer; IgnoreResults: JobResultSet): boolean;
289var
290 Test: integer;
291begin
292 Test := Server(sStartJob + Job shl 4 - sExecute, me, uix, nil^);
293 Result := (Test >= rExecuted) or (Test in IgnoreResults);
294end;
295
296procedure GetUnitInfo(Loc: integer; var uix: integer; var UnitInfo: TUnitInfo);
297var
298 i, Cnt: integer;
299begin
300 if MyMap[Loc] and fOwned <> 0 then
301 begin
302 Server(sGetDefender, me, Loc, uix);
303 Cnt := 0;
304 for i := 0 to MyRO.nUn - 1 do
305 if MyUn[i].Loc = Loc then
306 Inc(Cnt);
307 MakeUnitInfo(me, MyUn[uix], UnitInfo);
308 if Cnt > 1 then
309 UnitInfo.Flags := UnitInfo.Flags or unMulti;
310 end
311 else
312 begin
313 uix := MyRO.nEnemyUn - 1;
314 while (uix >= 0) and (MyRO.EnemyUn[uix].Loc <> Loc) do
315 Dec(uix);
316 UnitInfo := MyRO.EnemyUn[uix];
317 end;
318end;
319
320procedure GetCityInfo(Loc: integer; var cix: integer; var CityInfo: TCityInfo);
321begin
322 if MyMap[Loc] and fOwned <> 0 then
323 begin
324 CityInfo.Loc := Loc;
325 cix := MyRO.nCity - 1;
326 while (cix >= 0) and (MyCity[cix].Loc <> Loc) do
327 Dec(cix);
328 with CityInfo do
329 begin
330 Owner := me;
331 ID := MyCity[cix].ID;
332 size := MyCity[cix].size;
333 Flags := 0;
334 if MyCity[cix].Built[imPalace] > 0 then
335 Inc(Flags, ciCapital);
336 if (MyCity[cix].Built[imWalls] > 0) or
337 (MyMap[MyCity[cix].Loc] and fGrWall <> 0) then
338 Inc(Flags, ciWalled);
339 if MyCity[cix].Built[imCoastalFort] > 0 then
340 Inc(Flags, ciCoastalFort);
341 if MyCity[cix].Built[imMissileBat] > 0 then
342 Inc(Flags, ciMissileBat);
343 if MyCity[cix].Built[imBunker] > 0 then
344 Inc(Flags, ciBunker);
345 if MyCity[cix].Built[imSpacePort] > 0 then
346 Inc(Flags, ciSpacePort);
347 end;
348 end
349 else
350 begin
351 cix := MyRO.nEnemyCity - 1;
352 while (cix >= 0) and (MyRO.EnemyCity[cix].Loc <> Loc) do
353 Dec(cix);
354 CityInfo := MyRO.EnemyCity[cix];
355 end;
356end;
357
358function UnitExhausted(uix: integer): boolean;
359 // check if another move of this unit is still possible
360var
361 dx, dy: integer;
362begin
363 Result := True;
364 if (MyUn[uix].Movement > 0) or
365 (MyRO.Wonder[woShinkansen].EffectiveOwner = me) then
366 if (MyUn[uix].Movement >= 100) or
367 ((MyModel[MyUn[uix].mix].Kind = mkCaravan) and
368 (MyMap[MyUn[uix].Loc] and fCity <> 0)) then
369 Result := False
370 else
371 for dx := -2 to 2 do
372 for dy := -2 to 2 do
373 if abs(dx) + abs(dy) = 2 then
374 if Server(sMoveUnit - sExecute + dx and 7 shl 4 + dy and
375 7 shl 7, me, uix, nil^) >= rExecuted then
376 Result := False;
377end;
378
379function ModelHash(const ModelInfo: TModelInfo): integer;
380var
381 i, FeatureCode, Hash1, Hash2, Hash2r, d: cardinal;
382begin
383 with ModelInfo do
384 if Kind > mkEnemyDeveloped then
385 Result := integer($C0000000 + Speed div 50 + Kind shl 8)
386 else
387 begin
388 FeatureCode := 0;
389 for i := mcFirstNonCap to nFeature - 1 do
390 if 1 shl Domain and Feature[i].Domains <> 0 then
391 begin
392 FeatureCode := FeatureCode * 2;
393 if 1 shl (i - mcFirstNonCap) <> 0 then
394 Inc(FeatureCode);
395 end;
396 case Domain of
397 dGround:
398 begin
399 assert(FeatureCode < 1 shl 8);
400 assert(Attack < 5113);
401 assert(Defense < 2273);
402 assert(Cost < 1611);
403 Hash1 := (Attack * 2273 + Defense) * 9 + (Speed - 150) div 50;
404 Hash2 := FeatureCode * 1611 + Cost;
405 end;
406 dSea:
407 begin
408 assert(FeatureCode < 1 shl 9);
409 assert(Attack < 12193);
410 assert(Defense < 6097);
411 assert(Cost < 4381);
412 Hash1 := ((Attack * 6097 + Defense) * 5 +
413 (Speed - 350) div 100) * 2;
414 if Weight >= 6 then
415 Inc(Hash1);
416 Hash2 := ((TTrans * 17 + ATrans_Fuel) shl 9 + FeatureCode) *
417 4381 + Cost;
418 end;
419 dAir:
420 begin
421 assert(FeatureCode < 1 shl 5);
422 assert(Attack < 2407);
423 assert(Defense < 1605);
424 assert(Bombs < 4813);
425 assert(Cost < 2089);
426 Hash1 := (Attack * 1605 + Defense) shl 5 + FeatureCode;
427 Hash2 := ((Bombs * 7 + ATrans_Fuel) * 4 + TTrans) * 2089 + Cost;
428 end;
429 end;
430 Hash2r := 0;
431 for i := 0 to 7 do
432 begin
433 Hash2r := Hash2r * 13;
434 d := Hash2 div 13;
435 Inc(Hash2r, Hash2 - d * 13);
436 Hash2 := d;
437 end;
438 Result := integer(Domain shl 30 + Hash1 xor Hash2r);
439 end;
440end;
441
442function ProcessEnhancement(uix: integer; const Jobs: TEnhancementJobs): integer;
443 { return values:
444 eJobDone - all applicable jobs done
445 eOK - enhancement not complete
446 eDied - job done and died (thurst) }
447var
448 stage, NextJob, Tile: integer;
449 Done: set of jNone .. jPoll;
450begin
451 Done := [];
452 Tile := MyMap[MyUn[uix].Loc];
453 if Tile and fRoad <> 0 then
454 include(Done, jRoad);
455 if Tile and fRR <> 0 then
456 include(Done, jRR);
457 if (Tile and fTerImp = tiIrrigation) or (Tile and fTerImp = tiFarm) then
458 include(Done, jIrr);
459 if Tile and fTerImp = tiFarm then
460 include(Done, jFarm);
461 if Tile and fTerImp = tiMine then
462 include(Done, jMine);
463 if Tile and fPoll = 0 then
464 include(Done, jPoll);
465
466 if MyUn[uix].Job = jNone then
467 Result := eJobDone
468 else
469 Result := eOK;
470 while (Result <> eOK) and (Result <> eDied) do
471 begin
472 stage := -1;
473 repeat
474 if stage = -1 then
475 NextJob := jPoll
476 else
477 NextJob := Jobs[Tile and fTerrain, stage];
478 if (NextJob = jNone) or not (NextJob in Done) then
479 Break;
480 Inc(stage);
481 until stage = 5;
482 if (stage = 5) or (NextJob = jNone) then
483 begin
484 Result := eJobDone;
485 Break;
486 end; // tile enhancement complete
487 Result := Server(sStartJob + NextJob shl 4, me, uix, nil^);
488 include(Done, NextJob);
489 end;
490end;
491
492function AutoBuild(cix: integer; const ImpOrder: TImpOrder): boolean;
493var
494 i, NewProject: integer;
495begin
496 Result := False;
497 if (MyCity[cix].Project and (cpImp + cpIndex) = cpImp + imTrGoods) or
498 (MyCity[cix].Flags and chProduction <> 0) then
499 begin
500 i := 0;
501 repeat
502 while (ImpOrder[i] >= 0) and (MyCity[cix].Built[ImpOrder[i]] > 0) do
503 Inc(i);
504 if ImpOrder[i] < 0 then
505 Break;
506 assert(i < nImp);
507 NewProject := cpImp + ImpOrder[i];
508 if Server(sSetCityProject, me, cix, NewProject) >= rExecuted then
509 begin
510 Result := True;
511 CityOptimizer_CityChange(cix);
512 Break;
513 end;
514 Inc(i);
515 until False;
516 end;
517end;
518
519procedure CalculateAdvValues;
520var
521 i, j: integer;
522 known: array [0 .. nAdv - 1] of integer;
523
524 procedure MarkPreqs(i: integer);
525 begin
526 if known[i] = 0 then
527 begin
528 known[i] := 1;
529 if (i <> adScience) and (i <> adMassProduction) then
530 begin
531 if (AdvPreq[i, 0] >= 0) then
532 MarkPreqs(AdvPreq[i, 0]);
533 if (AdvPreq[i, 1] >= 0) then
534 MarkPreqs(AdvPreq[i, 1]);
535 end;
536 end;
537 end;
538
539begin
540 FillChar(AdvValue, SizeOf(AdvValue), 0);
541 for i := 0 to nAdv - 1 do
542 begin
543 FillChar(known, SizeOf(known), 0);
544 MarkPreqs(i);
545 for j := 0 to nAdv - 1 do
546 if known[j] > 0 then
547 Inc(AdvValue[i]);
548 if i in FutureTech then
549 Inc(AdvValue[i], 3000)
550 else if known[adMassProduction] > 0 then
551 Inc(AdvValue[i], 2000)
552 else if known[adScience] > 0 then
553 Inc(AdvValue[i], 1000);
554 end;
555end;
556
557procedure DebugMessage(Level: integer; Text: string);
558begin
559 Server(sMessage, me, Level, PChar(Text)^);
560end;
561
562function MarkCitiesAround(Loc, cixExcept: integer): boolean;
563 // return whether a city was marked
564var
565 cix: integer;
566begin
567 Result := False;
568 for cix := 0 to MyRO.nCity - 1 do
569 if (cix <> cixExcept) and (MyCity[cix].Loc >= 0) and
570 (MyCity[cix].Flags and chCaptured = 0) and
571 (Distance(MyCity[cix].Loc, Loc) <= 5) then
572 begin
573 CityNeedsOptimize[cix] := True;
574 Result := True;
575 end;
576end;
577
578procedure OptimizeCities(CheckOnly: boolean);
579var
580 cix, fix, dx, dy, Loc1, OptiType: integer;
581 Done: boolean;
582 Advice: TCityTileAdviceData;
583begin
584 repeat
585 Done := True;
586 for cix := 0 to MyRO.nCity - 1 do
587 if CityNeedsOptimize[cix] then
588 begin
589 OptiType := (MyCity[cix].Status shr 4) and $0F;
590 if OptiType <> 0 then
591 begin
592 Advice.ResourceWeights := OfferedResourceWeights[OptiType];
593 Server(sGetCityTileAdvice, me, cix, Advice);
594 if Advice.Tiles <> MyCity[cix].Tiles then
595 if CheckOnly then
596 begin
597 // TODO: What is this assert for?
598 // Need to optimize city tiles but CheckOnly true?
599 //assert(false)
600 end
601 else
602 begin
603 for fix := 1 to 26 do
604 if MyCity[cix].Tiles and not Advice.Tiles and
605 (1 shl fix) <> 0 then
606 begin // tile no longer used by this city -- check using it by another
607 dy := fix shr 2 - 3;
608 dx := fix and 3 shl 1 - 3 + (dy + 3) and 1;
609 Loc1 := dLoc(MyCity[cix].Loc, dx, dy);
610 if MarkCitiesAround(Loc1, cix) then
611 Done := False;
612 end;
613 Server(sSetCityTiles, me, cix, Advice.Tiles);
614 end;
615 end;
616 CityNeedsOptimize[cix] := False;
617 end;
618 until Done;
619end;
620
621procedure CityOptimizer_BeginOfTurn;
622var
623 cix: integer;
624begin
625 FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false
626 if MyRO.Government <> gAnarchy then
627 begin
628 for cix := 0 to MyRO.nCity - 1 do
629 if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0)
630 then
631 CityNeedsOptimize[cix] := True;
632 OptimizeCities(False); // optimize all cities
633 end;
634end;
635
636procedure CityOptimizer_CityChange(cix: integer);
637begin
638 if (MyRO.Government <> gAnarchy) and (cix <> -1) and (MyCity[cix].Flags and
639 chCaptured = 0) then
640 begin
641 CityNeedsOptimize[cix] := True;
642 OptimizeCities(False);
643 end;
644end;
645
646procedure CityOptimizer_TileBecomesAvailable(Loc: integer);
647begin
648 if (MyRO.Government <> gAnarchy) and MarkCitiesAround(Loc, -1) then
649 OptimizeCities(False);
650end;
651
652procedure CityOptimizer_ReleaseCityTiles(cix, ReleasedTiles: integer);
653var
654 fix, dx, dy, Loc1: integer;
655 Done: boolean;
656begin
657 if (MyRO.Government <> gAnarchy) and (ReleasedTiles <> 0) then
658 begin
659 Done := True;
660 for fix := 1 to 26 do
661 if ReleasedTiles and (1 shl fix) <> 0 then
662 begin
663 dy := fix shr 2 - 3;
664 dx := fix and 3 shl 1 - 3 + (dy + 3) and 1;
665 Loc1 := dLoc(MyCity[cix].Loc, dx, dy);
666 if MarkCitiesAround(Loc1, cix) then
667 Done := False;
668 end;
669 if not Done then
670 OptimizeCities(False);
671 end;
672end;
673
674procedure CityOptimizer_BeforeRemoveUnit(uix: integer);
675var
676 uix1: integer;
677begin
678 if MyRO.Government <> gAnarchy then
679 begin
680 if MyUn[uix].Home >= 0 then
681 CityNeedsOptimize[MyUn[uix].Home] := True;
682
683 // transported units are also removed
684 for uix1 := 0 to MyRO.nUn - 1 do
685 if (MyUn[uix1].Loc >= 0) and (MyUn[uix1].Master = uix) and
686 (MyUn[uix1].Home >= 0) then
687 CityNeedsOptimize[MyUn[uix1].Home] := True;
688 end;
689end;
690
691procedure CityOptimizer_AfterRemoveUnit;
692begin
693 if MyRO.Government <> gAnarchy then
694 OptimizeCities(False);
695end;
696
697procedure CityOptimizer_EndOfTurn;
698// all cities should already be optimized here -- only check this
699var
700 cix: integer;
701begin
702{$IFOPT O-}
703 if MyRO.Government <> gAnarchy then
704 begin
705 FillChar(CityNeedsOptimize, MyRO.nCity - 1, 0); // false
706 for cix := 0 to MyRO.nCity - 1 do
707 if (MyCity[cix].Loc >= 0) and (MyCity[cix].Flags and chCaptured = 0)
708 then
709 CityNeedsOptimize[cix] := True;
710 OptimizeCities(True); // check all cities
711 end;
712{$ENDIF}
713end;
714
715function GetMyCityByLoc(Loc: Integer): PCity;
716var
717 I: Integer;
718begin
719 I := MyRO.nCity - 1;
720 while (I >= 0) and (MyCity[I].Loc <> Loc) do Dec(I);
721 if I >= 0 then Result := @MyCity[I]
722 else Result := nil;
723end;
724
725function GetEnemyCityByLoc(Loc: Integer): PCityInfo;
726var
727 I: Integer;
728begin
729 I := MyRO.nEnemyCity - 1;
730 while (I >= 0) and (MyRo.EnemyCity[I].Loc <> Loc) do Dec(I);
731 if I >= 0 then Result := @MyRo.EnemyCity[I]
732 else Result := nil;
733end;
734
735function GetMyUnitByLoc(Loc: Integer): PUn;
736var
737 I: Integer;
738begin
739 I := MyRO.nUn - 1;
740 while (I >= 0) and (MyUn[I].Loc <> Loc) do Dec(I);
741 if I >= 0 then Result := @MyUn[I]
742 else Result := nil;
743end;
744
745function GetEnemyUnitByLoc(Loc: Integer): PUnitInfo;
746var
747 I: Integer;
748begin
749 I := MyRO.nEnemyUn - 1;
750 while (I >= 0) and (MyRO.EnemyUn[I].Loc <> Loc) do Dec(I);
751 if I >= 0 then Result := @MyRO.EnemyUn[I]
752 else Result := nil;
753end;
754
755
756initialization
757
758Assert(nImp < 128);
759CalculateAdvValues;
760
761end.
Note: See TracBrowser for help on using the repository browser.