1 | {$INCLUDE Switches.inc}
|
---|
2 | unit CityProcessing;
|
---|
3 |
|
---|
4 | interface
|
---|
5 |
|
---|
6 | uses
|
---|
7 | Protocol, Database;
|
---|
8 |
|
---|
9 | // Reporting
|
---|
10 | procedure GetCityAreaInfo(P, Loc: Integer; var CityAreaInfo: TCityAreaInfo);
|
---|
11 | function CanCityGrow(P, cix: Integer): Boolean;
|
---|
12 | function GetCityReport(P, cix: Integer; var CityReport: TCityReport): Integer;
|
---|
13 | function GetCityReportNew(P, cix: Integer;
|
---|
14 | var CityReportNew: TCityReportNew): Integer;
|
---|
15 |
|
---|
16 | // Internal Tile Picking
|
---|
17 | function AddBestCityTile(P, cix: Integer): Boolean;
|
---|
18 | procedure CityGrowth(P, cix: Integer);
|
---|
19 | procedure CityShrink(P, cix: Integer);
|
---|
20 | procedure Pollute(P, cix: Integer);
|
---|
21 |
|
---|
22 | // Turn Processing
|
---|
23 | procedure PayCityMaintenance(P, cix: Integer);
|
---|
24 | procedure CollectCityResources(P, cix: Integer);
|
---|
25 | function CityTurn(P, cix: Integer): Boolean;
|
---|
26 |
|
---|
27 | // Tile Access
|
---|
28 | function SetCityTiles(P, cix, NewTiles: Integer;
|
---|
29 | TestOnly: Boolean = False): Integer;
|
---|
30 | procedure GetCityTileAdvice(P, cix: Integer; var Advice: TCityTileAdviceData);
|
---|
31 |
|
---|
32 | // Start/End Game
|
---|
33 | procedure InitGame;
|
---|
34 | procedure ReleaseGame;
|
---|
35 |
|
---|
36 |
|
---|
37 | implementation
|
---|
38 |
|
---|
39 | type
|
---|
40 | TTradeProcessing = record
|
---|
41 | TaxBonus: Integer;
|
---|
42 | LuxBonus: Integer;
|
---|
43 | ScienceBonus: Integer;
|
---|
44 | FutResBonus: Integer;
|
---|
45 | ScienceDoubling: Integer;
|
---|
46 | HappyBase: Integer;
|
---|
47 | RelCorr: Single;
|
---|
48 | FlexibleLuxury: Boolean;
|
---|
49 | end;
|
---|
50 |
|
---|
51 | TProdProcessing = record
|
---|
52 | ProdBonus: Integer;
|
---|
53 | PollBonus: Integer;
|
---|
54 | FutProdBonus: Integer;
|
---|
55 | PollThreshold: Integer;
|
---|
56 | end;
|
---|
57 |
|
---|
58 | PCityReportEx = ^TCityReportEx;
|
---|
59 |
|
---|
60 | TCityReportEx = record
|
---|
61 | BaseHappiness: Integer;
|
---|
62 | BaseControl: Integer;
|
---|
63 | Material: Integer;
|
---|
64 | ProdProcessing: TProdProcessing;
|
---|
65 | TradeProcessing: TTradeProcessing;
|
---|
66 | end;
|
---|
67 |
|
---|
68 | var
|
---|
69 | MaxDist: Integer;
|
---|
70 |
|
---|
71 | {
|
---|
72 | Reporting
|
---|
73 | ____________________________________________________________________
|
---|
74 | }
|
---|
75 | procedure GetCityAreaInfo(P, Loc: Integer; var CityAreaInfo: TCityAreaInfo);
|
---|
76 | var
|
---|
77 | V21, Loc1, p1: Integer;
|
---|
78 | Radius: TVicinity21Loc;
|
---|
79 | begin
|
---|
80 | {$IFOPT O-}Assert(1 shl P and InvalidTreatyMap = 0); {$ENDIF}
|
---|
81 | with CityAreaInfo do
|
---|
82 | begin
|
---|
83 | V21_to_Loc(Loc, Radius);
|
---|
84 | for V21 := 0 to 26 do
|
---|
85 | begin
|
---|
86 | Loc1 := Radius[V21];
|
---|
87 | if (Loc1 < 0) or (Loc1 >= MapSize) then
|
---|
88 | Available[V21] := faInvalid
|
---|
89 | else
|
---|
90 | begin
|
---|
91 | p1 := RealMap[Loc1] shr 27;
|
---|
92 | if (p1 < nPl) and (p1 <> P) and (RW[P].Treaty[p1] >= trPeace) then
|
---|
93 | Available[V21] := faTreaty
|
---|
94 | else if (ZoCMap[Loc1] > 0) and (Occupant[Loc1] <> P) and
|
---|
95 | (RW[P].Treaty[Occupant[Loc1]] < trAlliance) then
|
---|
96 | Available[V21] := faSiege
|
---|
97 | else if (UsedByCity[Loc1] <> -1) and (UsedByCity[Loc1] <> Loc) then
|
---|
98 | Available[V21] := faNotAvailable
|
---|
99 | else
|
---|
100 | Available[V21] := faAvailable;
|
---|
101 | end;
|
---|
102 | end;
|
---|
103 | end;
|
---|
104 | end;
|
---|
105 |
|
---|
106 | function CanCityGrow(P, cix: Integer): Boolean;
|
---|
107 | begin
|
---|
108 | with RW[P].City[cix] do
|
---|
109 | Result := (Size < MaxCitySize) and
|
---|
110 | ((Size < NeedAqueductSize) or (Built[imAqueduct] = 1) and
|
---|
111 | (Size < NeedSewerSize) or (Built[imSewer] = 1));
|
---|
112 | end;
|
---|
113 |
|
---|
114 | procedure DetermineCityProdProcessing(P, cix: Integer;
|
---|
115 | var ProdProcessing: TProdProcessing);
|
---|
116 | begin
|
---|
117 | with RW[P].City[cix], ProdProcessing do
|
---|
118 | begin
|
---|
119 | ProdBonus := 0;
|
---|
120 | PollBonus := 0;
|
---|
121 | if Built[imFactory] = 1 then
|
---|
122 | Inc(ProdBonus);
|
---|
123 | if Built[imMfgPlant] = 1 then
|
---|
124 | Inc(ProdBonus);
|
---|
125 | if (Built[imPower] = 1) or (Built[imHydro] = 1) or (Built[imNuclear] = 1) or
|
---|
126 | (GWonder[woHoover].EffectiveOwner = P) then
|
---|
127 | ProdBonus := ProdBonus * 2;
|
---|
128 | if Built[imFactory] = 1 then
|
---|
129 | Inc(PollBonus);
|
---|
130 | if Built[imMfgPlant] = 1 then
|
---|
131 | Inc(PollBonus);
|
---|
132 | if (Built[imFactory] + Built[imMfgPlant] > 0) then
|
---|
133 | if (Built[imHydro] > 0) or (GWonder[woHoover].EffectiveOwner = P) then
|
---|
134 | Dec(PollBonus)
|
---|
135 | else if (Built[imNuclear] = 0) and (Built[imPower] = 1) then
|
---|
136 | Inc(PollBonus);
|
---|
137 | if (RW[P].Government <= gDespotism) or (Built[imRecycling] = 1) then
|
---|
138 | PollBonus := -2; // no pollution
|
---|
139 | PollThreshold := Size;
|
---|
140 | FutProdBonus := 0;
|
---|
141 | if RW[P].Tech[futProductionTechnology] > 0 then
|
---|
142 | begin // future tech benefits
|
---|
143 | if Built[imFactory] = 1 then
|
---|
144 | Inc(FutProdBonus, FactoryFutureBonus * RW[P].Tech
|
---|
145 | [futProductionTechnology]);
|
---|
146 | if Built[imMfgPlant] = 1 then
|
---|
147 | Inc(FutProdBonus, MfgPlantFutureBonus * RW[P].Tech
|
---|
148 | [futProductionTechnology]);
|
---|
149 | end;
|
---|
150 | end;
|
---|
151 | end;
|
---|
152 |
|
---|
153 | procedure BoostProd(BaseProd: Integer; ProdProcessing: TProdProcessing;
|
---|
154 | var Prod, Poll: Integer);
|
---|
155 | begin
|
---|
156 | Poll := BaseProd * (2 + ProdProcessing.PollBonus) shr 1;
|
---|
157 | if Poll <= ProdProcessing.PollThreshold then
|
---|
158 | Poll := 0
|
---|
159 | else
|
---|
160 | Dec(Poll, ProdProcessing.PollThreshold);
|
---|
161 | if ProdProcessing.FutProdBonus > 0 then
|
---|
162 | Prod := BaseProd * (100 + ProdProcessing.ProdBonus * 50 +
|
---|
163 | ProdProcessing.FutProdBonus) div 100
|
---|
164 | else
|
---|
165 | Prod := BaseProd * (2 + ProdProcessing.ProdBonus) shr 1;
|
---|
166 | end;
|
---|
167 |
|
---|
168 | procedure DetermineCityTradeProcessing(P, cix, HappinessBeforeLux: Integer;
|
---|
169 | var TradeProcessing: TTradeProcessing);
|
---|
170 | var
|
---|
171 | I, Dist: Integer;
|
---|
172 | begin
|
---|
173 | with RW[P].City[cix], TradeProcessing do
|
---|
174 | begin
|
---|
175 | TaxBonus := 0;
|
---|
176 | ScienceBonus := 0;
|
---|
177 | if Built[imMarket] = 1 then
|
---|
178 | Inc(TaxBonus, 2);
|
---|
179 | if Built[imBank] = 1 then
|
---|
180 | begin
|
---|
181 | Inc(TaxBonus, 3);
|
---|
182 | if RW[P].NatBuilt[imStockEx] = 1 then
|
---|
183 | Inc(TaxBonus, 3);
|
---|
184 | end;
|
---|
185 | LuxBonus := TaxBonus;
|
---|
186 | if Built[imLibrary] = 1 then
|
---|
187 | Inc(ScienceBonus, 2);
|
---|
188 | if Built[imUniversity] = 1 then
|
---|
189 | Inc(ScienceBonus, 3);
|
---|
190 | if Built[imResLab] = 1 then
|
---|
191 | Inc(ScienceBonus, 3);
|
---|
192 | ScienceDoubling := 0;
|
---|
193 | if Built[imNatObs] > 0 then
|
---|
194 | Inc(ScienceDoubling);
|
---|
195 | if RW[P].Government = gFundamentalism then
|
---|
196 | Dec(ScienceDoubling)
|
---|
197 | else if (GWonder[woNewton].EffectiveOwner = P) and
|
---|
198 | (RW[P].Government = gMonarchy) then
|
---|
199 | Inc(ScienceDoubling);
|
---|
200 | FlexibleLuxury := ((ServerVersion[P] >= $0100F1) and
|
---|
201 | (GWonder[woLiberty].EffectiveOwner = P) or (ServerVersion[P] < $0100F1)
|
---|
202 | and (GWonder[woMich].EffectiveOwner = P)) and
|
---|
203 | (RW[P].Government <> gAnarchy);
|
---|
204 | FutResBonus := 0;
|
---|
205 | if RW[P].Tech[futResearchTechnology] > 0 then
|
---|
206 | begin // future tech benefits
|
---|
207 | if Built[imUniversity] = 1 then
|
---|
208 | Inc(FutResBonus, UniversityFutureBonus * RW[P].Tech
|
---|
209 | [futResearchTechnology]);
|
---|
210 | if Built[imResLab] = 1 then
|
---|
211 | Inc(FutResBonus, ResLabFutureBonus * RW[P].Tech[futResearchTechnology]);
|
---|
212 | end;
|
---|
213 | if (RW[P].NatBuilt[imPalace] > 0) or (ServerVersion[P] < $010000) then
|
---|
214 | begin // calculate corruption
|
---|
215 | Dist := MaxDist;
|
---|
216 | for I := 0 to RW[P].nCity - 1 do
|
---|
217 | if (RW[P].City[I].Loc >= 0) and (RW[P].City[I].Built[imPalace] = 1) then
|
---|
218 | Dist := Distance(Loc, RW[P].City[I].Loc);
|
---|
219 | if (Dist = 0) or (CorrLevel[RW[P].Government] = 0) then
|
---|
220 | RelCorr := 0.0
|
---|
221 | else
|
---|
222 | begin
|
---|
223 | RelCorr := Dist / MaxDist;
|
---|
224 | if CorrLevel[RW[P].Government] > 1 then
|
---|
225 | RelCorr := Exp(ln(RelCorr) / CorrLevel[RW[P].Government]);
|
---|
226 | if Built[imCourt] = 1 then
|
---|
227 | RelCorr := RelCorr / 2;
|
---|
228 | // !!! floating point calculation always deterministic???
|
---|
229 | end
|
---|
230 | end
|
---|
231 | else if Built[imCourt] = 1 then
|
---|
232 | RelCorr := 0.5
|
---|
233 | else
|
---|
234 | RelCorr := 1.0;
|
---|
235 | HappyBase := Size + HappinessBeforeLux;
|
---|
236 | end;
|
---|
237 | end;
|
---|
238 |
|
---|
239 | procedure SplitTrade(Trade, TaxRate, LuxRate, Working: Integer;
|
---|
240 | TradeProcessing: TTradeProcessing; var Corruption, Tax, Lux,
|
---|
241 | Science: Integer);
|
---|
242 | var
|
---|
243 | plus: Integer;
|
---|
244 | begin
|
---|
245 | Corruption := Trunc(Trade * TradeProcessing.RelCorr);
|
---|
246 | Tax := (TaxRate * (Trade - Corruption) + 50) div 100;
|
---|
247 | if TradeProcessing.FlexibleLuxury then
|
---|
248 | begin
|
---|
249 | plus := Working * 2 - TradeProcessing.HappyBase;
|
---|
250 | // required additional luxury
|
---|
251 | if plus > 0 then
|
---|
252 | begin
|
---|
253 | Lux := (4 * plus + 3 + TradeProcessing.LuxBonus)
|
---|
254 | div (4 + TradeProcessing.LuxBonus);
|
---|
255 | if Lux > Trade - Corruption then
|
---|
256 | Lux := Trade - Corruption;
|
---|
257 | if Tax > Trade - Corruption - Lux then
|
---|
258 | Tax := Trade - Corruption - Lux;
|
---|
259 | end
|
---|
260 | else
|
---|
261 | Lux := 0;
|
---|
262 | end
|
---|
263 | else if (LuxRate = 0) or (TaxRate = 100) then
|
---|
264 | Lux := 0
|
---|
265 | else
|
---|
266 | Lux := (LuxRate * (Trade - Corruption) + 49) div 100;
|
---|
267 | Science := Trade - Corruption - Lux - Tax;
|
---|
268 | Tax := Tax * (4 + TradeProcessing.TaxBonus) shr 2;
|
---|
269 | Lux := Lux * (4 + TradeProcessing.LuxBonus) shr 2;
|
---|
270 | if TradeProcessing.FutResBonus > 0 then
|
---|
271 | Science := Science * (100 + TradeProcessing.ScienceBonus * 25 +
|
---|
272 | TradeProcessing.FutResBonus) div 100
|
---|
273 | else
|
---|
274 | Science := Science * (4 + TradeProcessing.ScienceBonus) shr 2;
|
---|
275 | Science := Science shl 2 shr (2 - TradeProcessing.ScienceDoubling);
|
---|
276 | end;
|
---|
277 |
|
---|
278 | function GetProjectCost(P, cix: Integer): Integer;
|
---|
279 | var
|
---|
280 | I: Integer;
|
---|
281 | begin
|
---|
282 | with RW[P].City[cix] do
|
---|
283 | begin
|
---|
284 | if Project and cpImp = 0 then
|
---|
285 | begin
|
---|
286 | Result := RW[P].Model[Project and cpIndex].Cost; { unit project }
|
---|
287 | if Project and cpConscripts <> 0 then
|
---|
288 | begin
|
---|
289 | I := RW[P].Model[Project and cpIndex].MCost;
|
---|
290 | Result := Result - 3 * I;
|
---|
291 | if Result <= 0 then
|
---|
292 | Result := I;
|
---|
293 | end
|
---|
294 | else if RW[P].Model[Project and cpIndex].Cap[mcLine] > 0 then
|
---|
295 | if Project0 and (not cpAuto or cpRepeat) = Project and not cpAuto or cpRepeat
|
---|
296 | then
|
---|
297 | Result := Result shr 1
|
---|
298 | else
|
---|
299 | Result := Result * 2;
|
---|
300 | end
|
---|
301 | else
|
---|
302 | begin { improvement project }
|
---|
303 | Result := Imp[Project and cpIndex].Cost;
|
---|
304 | if (Project and cpIndex < nWonder) and (GWonder[woColossus].EffectiveOwner = P)
|
---|
305 | then
|
---|
306 | Result := Result * ColossusEffect div 100;
|
---|
307 | end;
|
---|
308 | Result := Result * BuildCostMod[Difficulty[P]] div 12;
|
---|
309 | end;
|
---|
310 | end;
|
---|
311 |
|
---|
312 | function GetSmallCityReport(P, cix: Integer; var CityReport: TCityReport;
|
---|
313 | PCityReportEx: PCityReportEx = nil): Integer;
|
---|
314 | var
|
---|
315 | I, uix, V21, Loc1, ForcedSupport, BaseHappiness, Control: Integer;
|
---|
316 | ProdProcessing: TProdProcessing;
|
---|
317 | TradeProcessing: TTradeProcessing;
|
---|
318 | Radius: TVicinity21Loc;
|
---|
319 | UnitReport: TUnitReport;
|
---|
320 | RareOK: array [0 .. 3] of Integer;
|
---|
321 | TileInfo: TTileInfo;
|
---|
322 | begin
|
---|
323 | with RW[P].City[cix], CityReport do
|
---|
324 | begin
|
---|
325 | if HypoTiles <= 0 then
|
---|
326 | HypoTiles := Tiles;
|
---|
327 | if HypoTax < 0 then
|
---|
328 | HypoTax := RW[P].TaxRate;
|
---|
329 | if HypoLux < 0 then
|
---|
330 | HypoLux := RW[P].LuxRate;
|
---|
331 |
|
---|
332 | if (Flags and chCaptured <> 0) or (RW[P].Government = gAnarchy) then
|
---|
333 | begin
|
---|
334 | Working := 0;
|
---|
335 | for V21 := 1 to 26 do
|
---|
336 | if HypoTiles and (1 shl V21) <> 0 then
|
---|
337 | Inc(Working); // for backward compatibility
|
---|
338 |
|
---|
339 | if RW[P].Government = gFundamentalism then
|
---|
340 | begin
|
---|
341 | Happy := Size;
|
---|
342 | Control := Size;
|
---|
343 | end // !!! old bug, kept for compatibility
|
---|
344 | else
|
---|
345 | begin
|
---|
346 | Happy := 0;
|
---|
347 | Control := 0;
|
---|
348 | end;
|
---|
349 |
|
---|
350 | BaseHappiness := BasicHappy * 2;
|
---|
351 | Support := 0;
|
---|
352 | Deployed := 0;
|
---|
353 | Eaten := Size * 2;
|
---|
354 | FoodRep := Size * 2;
|
---|
355 | ProdRep := 0;
|
---|
356 | Trade := 0;
|
---|
357 | PollRep := 0;
|
---|
358 | Corruption := 0;
|
---|
359 | Tax := 0;
|
---|
360 | Lux := 0;
|
---|
361 | Science := 0;
|
---|
362 |
|
---|
363 | if PCityReportEx <> nil then
|
---|
364 | begin
|
---|
365 | PCityReportEx.Material := ProdRep;
|
---|
366 | PCityReportEx.BaseHappiness := BaseHappiness;
|
---|
367 | PCityReportEx.BaseControl := Control;
|
---|
368 | end;
|
---|
369 | end
|
---|
370 | else // not captured, no anarchy
|
---|
371 | begin
|
---|
372 | Control := 0;
|
---|
373 | BaseHappiness := BasicHappy * 2;
|
---|
374 | Happy := BasicHappy;
|
---|
375 | if (Built[imColosseum] > 0) then
|
---|
376 | begin
|
---|
377 | if (Happy < (Size + 1) shr 1) then
|
---|
378 | Happy := (Size + 1) shr 1;
|
---|
379 | if Size > 4 then
|
---|
380 | BaseHappiness := Size;
|
---|
381 | end;
|
---|
382 | for I := 0 to nWonder - 1 do
|
---|
383 | if Built[I] = 1 then
|
---|
384 | begin
|
---|
385 | Inc(Happy);
|
---|
386 | Inc(BaseHappiness, 2);
|
---|
387 | end;
|
---|
388 | if Built[imTemple] = 1 then
|
---|
389 | begin
|
---|
390 | Inc(Happy);
|
---|
391 | Inc(BaseHappiness, 2);
|
---|
392 | end;
|
---|
393 | if Built[imCathedral] = 1 then
|
---|
394 | begin
|
---|
395 | Inc(Happy, 2);
|
---|
396 | Inc(BaseHappiness, 4);
|
---|
397 | if GWonder[woBach].EffectiveOwner = P then
|
---|
398 | begin
|
---|
399 | Inc(Happy);
|
---|
400 | Inc(BaseHappiness, 2);
|
---|
401 | end;
|
---|
402 | end;
|
---|
403 | if Built[imTheater] > 0 then
|
---|
404 | begin
|
---|
405 | Inc(Happy, 2);
|
---|
406 | Inc(BaseHappiness, 4);
|
---|
407 | end;
|
---|
408 |
|
---|
409 | // calculate unit support
|
---|
410 | {$IFOPT O-}Assert(InvalidTreatyMap = 0); {$ENDIF}
|
---|
411 | Support := 0;
|
---|
412 | ForcedSupport := 0;
|
---|
413 | Eaten := Size * 2;
|
---|
414 | Deployed := 0;
|
---|
415 | for uix := 0 to RW[P].nUn - 1 do
|
---|
416 | with RW[P].Un[uix] do
|
---|
417 | if (Loc >= 0) and (Home = cix) then
|
---|
418 | begin
|
---|
419 | GetUnitReport(P, uix, UnitReport);
|
---|
420 | Inc(Eaten, UnitReport.FoodSupport);
|
---|
421 | if UnitReport.ReportFlags and urfAlwaysSupport <> 0 then
|
---|
422 | Inc(ForcedSupport, UnitReport.ProdSupport)
|
---|
423 | else
|
---|
424 | Inc(Support, UnitReport.ProdSupport);
|
---|
425 | if UnitReport.ReportFlags and urfDeployed <> 0 then
|
---|
426 | Inc(Deployed);
|
---|
427 | end;
|
---|
428 | if Deployed >= Happy then
|
---|
429 | Happy := 0
|
---|
430 | else
|
---|
431 | Dec(Happy, Deployed);
|
---|
432 | Dec(Support, Size * SupportFree[RW[P].Government] shr 1);
|
---|
433 | if Support < 0 then
|
---|
434 | Support := 0;
|
---|
435 | Inc(Support, ForcedSupport);
|
---|
436 |
|
---|
437 | { control }
|
---|
438 | case RW[P].Government of
|
---|
439 | gDespotism:
|
---|
440 | for uix := 0 to RW[P].nUn - 1 do
|
---|
441 | if (RW[P].Un[uix].Loc = Loc) and
|
---|
442 | (RW[P].Model[RW[P].Un[uix].mix].Kind = mkSpecial_TownGuard) then
|
---|
443 | begin
|
---|
444 | Inc(Happy);
|
---|
445 | Inc(Control, 2);
|
---|
446 | end;
|
---|
447 | gFundamentalism:
|
---|
448 | begin
|
---|
449 | BaseHappiness := 0; // done by control
|
---|
450 | Happy := Size;
|
---|
451 | Control := Size;
|
---|
452 | end;
|
---|
453 | end;
|
---|
454 |
|
---|
455 | // collect processing parameters
|
---|
456 | DetermineCityProdProcessing(P, cix, ProdProcessing);
|
---|
457 | DetermineCityTradeProcessing(P, cix, BaseHappiness + Control - 2 *
|
---|
458 | Deployed, TradeProcessing);
|
---|
459 |
|
---|
460 | // collect resources
|
---|
461 | Working := 0;
|
---|
462 | FoodRep := 0;
|
---|
463 | ProdRep := 0;
|
---|
464 | Trade := 0;
|
---|
465 | FillChar(RareOK, SizeOf(RareOK), 0);
|
---|
466 | V21_to_Loc(Loc, Radius);
|
---|
467 | for V21 := 1 to 26 do
|
---|
468 | if HypoTiles and (1 shl V21) <> 0 then
|
---|
469 | begin { sum resources of exploited tiles }
|
---|
470 | Loc1 := Radius[V21];
|
---|
471 | if (Loc1 < 0) or (Loc1 >= MapSize) then
|
---|
472 | // HypoTiles go beyond map border!
|
---|
473 | begin
|
---|
474 | Result := eInvalid;
|
---|
475 | Exit;
|
---|
476 | end;
|
---|
477 | GetTileInfo(P, cix, Loc1, TileInfo);
|
---|
478 | Inc(FoodRep, TileInfo.Food);
|
---|
479 | Inc(ProdRep, TileInfo.Prod);
|
---|
480 | Inc(Trade, TileInfo.Trade);
|
---|
481 | if (RealMap[Loc1] and fModern <> 0) and
|
---|
482 | (RW[P].Tech[adMassProduction] >= tsApplicable) then
|
---|
483 | Inc(RareOK[RealMap[Loc1] shr 25 and 3]);
|
---|
484 | Inc(Working);
|
---|
485 | end;
|
---|
486 | if Built[imAlgae] = 1 then
|
---|
487 | Inc(FoodRep, 12);
|
---|
488 |
|
---|
489 | if PCityReportEx <> nil then
|
---|
490 | begin
|
---|
491 | PCityReportEx.Material := ProdRep;
|
---|
492 | PCityReportEx.BaseHappiness := BaseHappiness;
|
---|
493 | PCityReportEx.BaseControl := Control;
|
---|
494 | PCityReportEx.ProdProcessing := ProdProcessing;
|
---|
495 | PCityReportEx.TradeProcessing := TradeProcessing;
|
---|
496 | end;
|
---|
497 |
|
---|
498 | BoostProd(ProdRep, ProdProcessing, ProdRep, PollRep);
|
---|
499 | SplitTrade(Trade, HypoTax, HypoLux, Working, TradeProcessing, Corruption,
|
---|
500 | Tax, Lux, Science);
|
---|
501 | Happy := Happy + (Lux + Size and 1) shr 1;
|
---|
502 | // new style disorder requires 1 lux less for cities with odd size
|
---|
503 |
|
---|
504 | // check if rare resource available
|
---|
505 | if (GTestFlags and tfNoRareNeed = 0) and (ProdRep > Support) and
|
---|
506 | (Project and cpImp <> 0) and ((Project and cpIndex = imShipComp) and
|
---|
507 | (RareOK[1] = 0) or (Project and cpIndex = imShipPow) and (RareOK[2] = 0)
|
---|
508 | or (Project and cpIndex = imShipHab) and (RareOK[3] = 0)) then
|
---|
509 | ProdRep := Support;
|
---|
510 | end;
|
---|
511 | end;
|
---|
512 | Result := eOk;
|
---|
513 | end;
|
---|
514 |
|
---|
515 | function GetCityReport(P, cix: Integer; var CityReport: TCityReport): Integer;
|
---|
516 | begin
|
---|
517 | Result := GetSmallCityReport(P, cix, CityReport);
|
---|
518 | CityReport.Storage := StorageSize[Difficulty[P]];
|
---|
519 | CityReport.ProdCost := GetProjectCost(P, cix);
|
---|
520 | end;
|
---|
521 |
|
---|
522 | function GetCityReportNew(P, cix: Integer;
|
---|
523 | var CityReportNew: TCityReportNew): Integer;
|
---|
524 | var
|
---|
525 | CityReport: TCityReport;
|
---|
526 | CityReportEx: TCityReportEx;
|
---|
527 | begin
|
---|
528 | with CityReportNew do
|
---|
529 | begin
|
---|
530 | CityReport.HypoTiles := HypoTiles;
|
---|
531 | CityReport.HypoTax := HypoTaxRate;
|
---|
532 | CityReport.HypoLux := HypoLuxuryRate;
|
---|
533 | Result := GetSmallCityReport(P, cix, CityReport, @CityReportEx);
|
---|
534 | FoodSupport := CityReport.Eaten - 2 * RW[P].City[cix].Size;
|
---|
535 | MaterialSupport := CityReport.Support;
|
---|
536 | ProjectCost := GetProjectCost(P, cix);
|
---|
537 | Storage := StorageSize[Difficulty[P]];
|
---|
538 | Deployed := CityReport.Deployed;
|
---|
539 | Morale := CityReportEx.BaseHappiness;
|
---|
540 | CollectedControl := CityReportEx.BaseControl +
|
---|
541 | (RW[P].City[cix].Size - CityReport.Working) * 2;
|
---|
542 | CollectedFood := CityReport.FoodRep;
|
---|
543 | CollectedMaterial := CityReportEx.Material;
|
---|
544 | CollectedTrade := CityReport.Trade;
|
---|
545 | Working := CityReport.Working;
|
---|
546 | Production := CityReport.ProdRep - CityReport.Support;
|
---|
547 | AddPollution := CityReport.PollRep;
|
---|
548 | Corruption := CityReport.Corruption;
|
---|
549 | Tax := CityReport.Tax;
|
---|
550 | Science := CityReport.Science;
|
---|
551 | Luxury := CityReport.Lux;
|
---|
552 | FoodSurplus := CityReport.FoodRep - CityReport.Eaten;
|
---|
553 | HappinessBalance := Morale + Luxury + CollectedControl - RW[P].City[cix]
|
---|
554 | .Size - 2 * Deployed;
|
---|
555 | end;
|
---|
556 | end;
|
---|
557 |
|
---|
558 | {
|
---|
559 | Internal Tile Picking
|
---|
560 | ____________________________________________________________________
|
---|
561 | }
|
---|
562 | procedure NextBest(P, cix: Integer; var SelectedLoc, SelectedV21: Integer);
|
---|
563 | { best tile unused but available by city cix }
|
---|
564 | var
|
---|
565 | Resources, Most, Loc1, p1, V21: Integer;
|
---|
566 | TileInfo: TTileInfo;
|
---|
567 | Radius: TVicinity21Loc;
|
---|
568 | begin
|
---|
569 | {$IFOPT O-}Assert(1 shl P and InvalidTreatyMap = 0); {$ENDIF}
|
---|
570 | Most := 0;
|
---|
571 | SelectedLoc := -1;
|
---|
572 | SelectedV21 := -1;
|
---|
573 | with RW[P].City[cix] do
|
---|
574 | begin
|
---|
575 | V21_to_Loc(Loc, Radius);
|
---|
576 | for V21 := 1 to 26 do
|
---|
577 | begin
|
---|
578 | Loc1 := Radius[V21];
|
---|
579 | if (Loc1 >= 0) and (Loc1 < MapSize) and (UsedByCity[Loc1] = -1) then
|
---|
580 | begin
|
---|
581 | p1 := RealMap[Loc1] shr 27;
|
---|
582 | if ((p1 = nPl) or (p1 = P) or (RW[P].Treaty[p1] < trPeace)) and
|
---|
583 | ((ZoCMap[Loc1] = 0) or (Occupant[Loc1] = P) or
|
---|
584 | (RW[P].Treaty[Occupant[Loc1]] = trAlliance)) then
|
---|
585 | begin
|
---|
586 | GetTileInfo(P, cix, Loc1, TileInfo);
|
---|
587 | Resources := TileInfo.Food shl 16 + TileInfo.Prod shl 8 +
|
---|
588 | TileInfo.Trade;
|
---|
589 | { priority: 1.food - 2.prod - 3.trade }
|
---|
590 | if Resources > Most then
|
---|
591 | begin
|
---|
592 | SelectedLoc := Loc1;
|
---|
593 | SelectedV21 := V21;
|
---|
594 | Most := Resources;
|
---|
595 | end;
|
---|
596 | end;
|
---|
597 | end;
|
---|
598 | end;
|
---|
599 | end;
|
---|
600 | end;
|
---|
601 |
|
---|
602 | procedure NextWorst(P, cix: Integer; var SelectedLoc, SelectedV21: Integer);
|
---|
603 | { worst tile used by city cix }
|
---|
604 | var
|
---|
605 | Resources, Least, Loc1, V21: Integer;
|
---|
606 | Radius: TVicinity21Loc;
|
---|
607 | TileInfo: TTileInfo;
|
---|
608 | begin
|
---|
609 | Least := MaxInt;
|
---|
610 | SelectedLoc := -1;
|
---|
611 | SelectedV21 := -1;
|
---|
612 | with RW[P].City[cix] do
|
---|
613 | begin
|
---|
614 | V21_to_Loc(Loc, Radius);
|
---|
615 | for V21 := 1 to 26 do
|
---|
616 | if V21 <> CityOwnTile then
|
---|
617 | begin
|
---|
618 | Loc1 := Radius[V21];
|
---|
619 | if (Loc1 >= 0) and (Loc1 < MapSize) and (1 shl V21 and Tiles <> 0) then
|
---|
620 | begin
|
---|
621 | GetTileInfo(P, cix, Loc1, TileInfo);
|
---|
622 | Resources := TileInfo.Food shl 16 + TileInfo.Prod shl 8 +
|
---|
623 | TileInfo.Trade;
|
---|
624 | { priority: 1.food - 2.prod - 3.trade }
|
---|
625 | if Resources < Least then
|
---|
626 | begin
|
---|
627 | SelectedLoc := Loc1;
|
---|
628 | SelectedV21 := V21;
|
---|
629 | Least := Resources;
|
---|
630 | end;
|
---|
631 | end;
|
---|
632 | end;
|
---|
633 | end;
|
---|
634 | end;
|
---|
635 |
|
---|
636 | function NextPoll(P, cix: Integer): Integer;
|
---|
637 | var
|
---|
638 | Resources, Best, dx, dy, Loc1, Dist, BestDist, V21, pTerr: Integer;
|
---|
639 | Radius: TVicinity21Loc;
|
---|
640 | TileInfo: TTileInfo;
|
---|
641 | begin
|
---|
642 | BestDist := MaxInt;
|
---|
643 | {$IFOPT O-}Assert(1 shl P and InvalidTreatyMap = 0); {$ENDIF}
|
---|
644 | Best := 0;
|
---|
645 | Result := -1;
|
---|
646 | with RW[P].City[cix] do
|
---|
647 | begin
|
---|
648 | V21_to_Loc(Loc, Radius);
|
---|
649 | for V21 := 1 to 26 do
|
---|
650 | if V21 <> CityOwnTile then
|
---|
651 | begin
|
---|
652 | Loc1 := Radius[V21];
|
---|
653 | if (Loc1 >= 0) and (Loc1 < MapSize) and
|
---|
654 | (RealMap[Loc1] and fTerrain >= fGrass) and
|
---|
655 | (RealMap[Loc1] and (fPoll or fDeadLands or fCity) = 0) then
|
---|
656 | begin
|
---|
657 | pTerr := RealMap[Loc1] shr 27;
|
---|
658 | if (pTerr = nPl) or (pTerr = P) or (RW[P].Treaty[pTerr] < trPeace)
|
---|
659 | then
|
---|
660 | begin
|
---|
661 | GetTileInfo(P, cix, Loc1, TileInfo);
|
---|
662 | Resources := TileInfo.Prod shl 16 + TileInfo.Trade shl 8 +
|
---|
663 | TileInfo.Food;
|
---|
664 | { priority: 1.prod - 2.trade - 3.food }
|
---|
665 | dy := V21 shr 2 - 3;
|
---|
666 | dx := V21 and 3 shl 1 - 3 + (dy + 3) and 1;
|
---|
667 | Dist := abs(dx) + abs(dy) + abs(abs(dx) - abs(dy)) shr 1;
|
---|
668 | if (Resources > Best) or (Resources = Best) and (Dist < BestDist)
|
---|
669 | then
|
---|
670 | begin
|
---|
671 | Result := Loc1;
|
---|
672 | Best := Resources;
|
---|
673 | BestDist := Dist;
|
---|
674 | end;
|
---|
675 | end;
|
---|
676 | end;
|
---|
677 | end;
|
---|
678 | end;
|
---|
679 | end;
|
---|
680 |
|
---|
681 | function AddBestCityTile(P, cix: Integer): Boolean;
|
---|
682 | var
|
---|
683 | TileLoc, V21: Integer;
|
---|
684 | begin
|
---|
685 | NextBest(P, cix, TileLoc, V21);
|
---|
686 | Result := TileLoc >= 0;
|
---|
687 | if Result then
|
---|
688 | with RW[P].City[cix] do
|
---|
689 | begin
|
---|
690 | Assert(1 shl V21 and Tiles = 0);
|
---|
691 | Tiles := Tiles or (1 shl V21);
|
---|
692 | UsedByCity[TileLoc] := Loc;
|
---|
693 | end;
|
---|
694 | end;
|
---|
695 |
|
---|
696 | procedure CityGrowth(P, cix: Integer);
|
---|
697 | var
|
---|
698 | TileLoc, V21: Integer;
|
---|
699 | AltCityReport: TCityReport;
|
---|
700 | begin
|
---|
701 | with RW[P].City[cix] do
|
---|
702 | begin
|
---|
703 | Inc(Size);
|
---|
704 | NextBest(P, cix, TileLoc, V21);
|
---|
705 | if TileLoc >= 0 then
|
---|
706 | begin { test whether exploitation of tile would lead to disorder }
|
---|
707 | AltCityReport.HypoTiles := Tiles + 1 shl V21;
|
---|
708 | AltCityReport.HypoTax := -1;
|
---|
709 | AltCityReport.HypoLux := -1;
|
---|
710 | GetSmallCityReport(P, cix, AltCityReport);
|
---|
711 | if AltCityReport.Working - AltCityReport.Happy <= Size shr 1 then
|
---|
712 | // !!! change to new style disorder
|
---|
713 | begin { no disorder -- exploit tile }
|
---|
714 | Assert(1 shl V21 and Tiles = 0);
|
---|
715 | Tiles := Tiles or (1 shl V21);
|
---|
716 | UsedByCity[TileLoc] := Loc;
|
---|
717 | end;
|
---|
718 | end;
|
---|
719 | end;
|
---|
720 | end;
|
---|
721 |
|
---|
722 | procedure CityShrink(P, cix: Integer);
|
---|
723 | var
|
---|
724 | TileLoc, V21, Working: Integer;
|
---|
725 | AltCityReport: TCityReport;
|
---|
726 | begin
|
---|
727 | with RW[P].City[cix] do
|
---|
728 | begin
|
---|
729 | Working := 0;
|
---|
730 | for V21 := 1 to 26 do
|
---|
731 | if Tiles and (1 shl V21) <> 0 then
|
---|
732 | Inc(Working);
|
---|
733 | Dec(Size);
|
---|
734 | if Food > StorageSize[Difficulty[P]] then
|
---|
735 | Food := StorageSize[Difficulty[P]];
|
---|
736 | NextWorst(P, cix, TileLoc, V21);
|
---|
737 | if Working > Size then
|
---|
738 | begin { all citizens were working -- worst tile no longer exploited }
|
---|
739 | Assert(1 shl V21 and Tiles <> 0);
|
---|
740 | Tiles := Tiles and not(1 shl V21);
|
---|
741 | UsedByCity[TileLoc] := -1;
|
---|
742 | end
|
---|
743 | else { test whether exploitation of tile would lead to disorder }
|
---|
744 | begin
|
---|
745 | AltCityReport.HypoTiles := -1;
|
---|
746 | AltCityReport.HypoTax := -1;
|
---|
747 | AltCityReport.HypoLux := -1;
|
---|
748 | GetSmallCityReport(P, cix, AltCityReport);
|
---|
749 | if AltCityReport.Working - AltCityReport.Happy > Size shr 1 then
|
---|
750 | // !!! change to new style disorder
|
---|
751 | begin { disorder -- don't exploit tile }
|
---|
752 | Assert(1 shl V21 and Tiles <> 0);
|
---|
753 | Tiles := Tiles and not(1 shl V21);
|
---|
754 | UsedByCity[TileLoc] := -1;
|
---|
755 | end;
|
---|
756 | end;
|
---|
757 | end;
|
---|
758 | end;
|
---|
759 |
|
---|
760 | procedure Pollute(P, cix: Integer);
|
---|
761 | var
|
---|
762 | PollutionLoc: Integer;
|
---|
763 | begin
|
---|
764 | with RW[P].City[cix] do
|
---|
765 | begin
|
---|
766 | Pollution := Pollution - MaxPollution;
|
---|
767 | PollutionLoc := NextPoll(P, cix);
|
---|
768 | if PollutionLoc >= 0 then
|
---|
769 | begin
|
---|
770 | Inc(Flags, chPollution);
|
---|
771 | RealMap[PollutionLoc] := RealMap[PollutionLoc] or fPoll;
|
---|
772 | end;
|
---|
773 | end;
|
---|
774 | end;
|
---|
775 |
|
---|
776 | {
|
---|
777 | Turn Processing
|
---|
778 | ____________________________________________________________________
|
---|
779 | }
|
---|
780 | procedure PayCityMaintenance(P, cix: Integer);
|
---|
781 | var
|
---|
782 | I: Integer;
|
---|
783 | begin
|
---|
784 | with RW[P], City[cix] do
|
---|
785 | for I := nWonder to nImp - 1 do
|
---|
786 | if (Built[I] > 0) and (Project0 and (cpImp or cpIndex) <> (cpImp or I))
|
---|
787 | then // don't pay maintenance when just completed
|
---|
788 | begin
|
---|
789 | Dec(Money, Imp[I].Maint);
|
---|
790 | if Money < 0 then
|
---|
791 | begin { out of money - sell improvement }
|
---|
792 | Inc(Money, Imp[I].Cost * BuildCostMod[Difficulty[P]] div 12);
|
---|
793 | Built[I] := 0;
|
---|
794 | if Imp[I].Kind <> ikCommon then
|
---|
795 | begin
|
---|
796 | Assert(I <> imSpacePort);
|
---|
797 | // never sell automatically! (solution: no maintenance)
|
---|
798 | NatBuilt[I] := 0;
|
---|
799 | if I = imGrWall then
|
---|
800 | GrWallContinent[P] := -1;
|
---|
801 | end;
|
---|
802 | Inc(Flags, chImprovementLost);
|
---|
803 | end;
|
---|
804 | end;
|
---|
805 | end;
|
---|
806 |
|
---|
807 | procedure CollectCityResources(P, cix: Integer);
|
---|
808 | var
|
---|
809 | CityStorage, CityProjectCost: Integer;
|
---|
810 | CityReport: TCityReportNew;
|
---|
811 | Disorder: Boolean;
|
---|
812 | begin
|
---|
813 | with RW[P], City[cix], CityReport do
|
---|
814 | if Flags and chCaptured <> 0 then
|
---|
815 | begin
|
---|
816 | Flags := Flags and not chDisorder;
|
---|
817 | Dec(Flags, $10000);
|
---|
818 | if Flags and chCaptured = 0 then
|
---|
819 | Flags := Flags or chAfterCapture;
|
---|
820 | end
|
---|
821 | else if Government = gAnarchy then
|
---|
822 | Flags := Flags and not chDisorder
|
---|
823 | else
|
---|
824 | begin
|
---|
825 | HypoTiles := -1;
|
---|
826 | HypoTaxRate := -1;
|
---|
827 | HypoLuxuryRate := -1;
|
---|
828 | GetCityReportNew(P, cix, CityReport);
|
---|
829 | CityStorage := StorageSize[Difficulty[P]];
|
---|
830 | CityProjectCost := GetProjectCost(P, cix);
|
---|
831 |
|
---|
832 | Disorder := (HappinessBalance < 0);
|
---|
833 | if Disorder and (Flags and chDisorder <> 0) then
|
---|
834 | CollectedMaterial := 0; // second turn disorder
|
---|
835 | if Disorder then
|
---|
836 | Flags := Flags or chDisorder
|
---|
837 | else
|
---|
838 | Flags := Flags and not chDisorder;
|
---|
839 |
|
---|
840 | if not Disorder and ((Government = gFuture) or (Size >= NeedAqueductSize)
|
---|
841 | and (FoodSurplus < 2)) and (FoodSurplus > 0) then
|
---|
842 | Inc(Money, FoodSurplus)
|
---|
843 | else if not(Disorder and (FoodSurplus > 0)) then
|
---|
844 | begin { calculate new food storage }
|
---|
845 | Food := Food + FoodSurplus;
|
---|
846 | if ((GTestFlags and tfImmGrow <> 0) or (Food >= CityStorage) and
|
---|
847 | (Food - FoodSurplus < CityStorage)) // only warn once
|
---|
848 | and (Size < MaxCitySize) and
|
---|
849 | (Project and (cpImp + cpIndex) <> cpImp + imAqueduct) and
|
---|
850 | (Project and (cpImp + cpIndex) <> cpImp + imSewer) and
|
---|
851 | not CanCityGrow(P, cix) then
|
---|
852 | Inc(Flags, chNoGrowthWarning);
|
---|
853 | end;
|
---|
854 |
|
---|
855 | if Prod > CityProjectCost then
|
---|
856 | begin
|
---|
857 | Inc(Money, Prod - CityProjectCost);
|
---|
858 | Prod := CityProjectCost;
|
---|
859 | end;
|
---|
860 | if Production < 0 then
|
---|
861 | Flags := Flags or chUnitLost
|
---|
862 | else if not Disorder and (Flags and chProductionSabotaged = 0) then
|
---|
863 | if Project and (cpImp + cpIndex) = cpImp + imTrGoods then
|
---|
864 | Inc(Money, Production)
|
---|
865 | else
|
---|
866 | Inc(Prod, Production);
|
---|
867 |
|
---|
868 | if not Disorder then
|
---|
869 | begin
|
---|
870 | { sum research points and taxes }
|
---|
871 | Inc(Research, Science);
|
---|
872 | Inc(Money, Tax);
|
---|
873 | Pollution := Pollution + AddPollution;
|
---|
874 | end;
|
---|
875 | end;
|
---|
876 | end;
|
---|
877 |
|
---|
878 | function CityTurn(P, cix: Integer): Boolean;
|
---|
879 | // return value: whether city keeps existing
|
---|
880 | var
|
---|
881 | I, uix, cix2, p1, SizeMod, CityStorage, CityProjectCost, NewImp, Det,
|
---|
882 | TestDet: Integer;
|
---|
883 | LackOfMaterial, CheckGrow, DoProd, IsActive: Boolean;
|
---|
884 | begin
|
---|
885 | with RW[P], City[cix] do
|
---|
886 | begin
|
---|
887 | SizeMod := 0;
|
---|
888 | CityStorage := StorageSize[Difficulty[P]];
|
---|
889 | CityProjectCost := GetProjectCost(P, cix);
|
---|
890 |
|
---|
891 | LackOfMaterial := Flags and chUnitLost <> 0;
|
---|
892 | Flags := Flags and not chUnitLost;
|
---|
893 |
|
---|
894 | IsActive := (Government <> gAnarchy) and (Flags and chCaptured = 0);
|
---|
895 | CheckGrow := (Flags and chDisorder = 0) and IsActive and
|
---|
896 | (Government <> gFuture);
|
---|
897 | if CheckGrow and (GTestFlags and tfImmGrow <> 0) then { fast growth }
|
---|
898 | begin
|
---|
899 | if CanCityGrow(P, cix) then
|
---|
900 | Inc(SizeMod);
|
---|
901 | end
|
---|
902 | else if CheckGrow and (Food >= CityStorage) then { normal growth }
|
---|
903 | begin
|
---|
904 | if CanCityGrow(P, cix) then
|
---|
905 | begin
|
---|
906 | if Built[imGranary] = 1 then
|
---|
907 | Dec(Food, CityStorage shr 1)
|
---|
908 | else
|
---|
909 | Dec(Food, CityStorage);
|
---|
910 | Inc(SizeMod);
|
---|
911 | end;
|
---|
912 | end
|
---|
913 | else if Food < 0 then { famine }
|
---|
914 | begin
|
---|
915 | Food := 0;
|
---|
916 | // check if settlers or conscripts there to disband
|
---|
917 | uix := -1;
|
---|
918 | for I := 0 to nUn - 1 do
|
---|
919 | if (Un[I].Loc >= 0) and (Un[I].Home = cix) and
|
---|
920 | ((Model[Un[I].mix].Kind = mkSettler)
|
---|
921 | { and (GWonder[woFreeSettlers].EffectiveOwner<>p) }
|
---|
922 | or (Un[I].Flags and unConscripts <> 0)) and
|
---|
923 | ((uix = -1) or (Model[Un[I].mix].Cost < Model[Un[uix].mix].Cost) or
|
---|
924 | (Model[Un[I].mix].Cost = Model[Un[uix].mix].Cost) and
|
---|
925 | (Un[I].Exp < Un[uix].Exp)) then
|
---|
926 | uix := I;
|
---|
927 |
|
---|
928 | if uix >= 0 then
|
---|
929 | begin
|
---|
930 | RemoveUnit_UpdateMap(P, uix);
|
---|
931 | Inc(Flags, chUnitLost);
|
---|
932 | end
|
---|
933 | else
|
---|
934 | begin
|
---|
935 | Dec(SizeMod);
|
---|
936 | Inc(Flags, chPopDecrease);
|
---|
937 | end
|
---|
938 | end;
|
---|
939 | if Food > CityStorage then
|
---|
940 | Food := CityStorage;
|
---|
941 |
|
---|
942 | if LackOfMaterial then
|
---|
943 | begin
|
---|
944 | if Flags and chUnitLost = 0 then
|
---|
945 | begin { one unit lost }
|
---|
946 | uix := -1;
|
---|
947 | Det := MaxInt;
|
---|
948 | for I := 0 to nUn - 1 do
|
---|
949 | if (Un[I].Loc >= 0) and (Un[I].Home = cix) then
|
---|
950 | with Model[Un[I].mix] do
|
---|
951 | begin
|
---|
952 | if Kind = mkSpecial_TownGuard then
|
---|
953 | TestDet := Un[I].Health + Un[I].Exp shl 8
|
---|
954 | // disband townguards first
|
---|
955 | else
|
---|
956 | begin
|
---|
957 | TestDet := Un[I].Health + Un[I].Exp shl 8 + Cost shl 16;
|
---|
958 | // value of unit
|
---|
959 | if Flags and mdDoubleSupport <> 0 then
|
---|
960 | TestDet := TestDet shr 1;
|
---|
961 | // double support, tend to disband first
|
---|
962 | end;
|
---|
963 | if TestDet < Det then
|
---|
964 | begin
|
---|
965 | uix := I;
|
---|
966 | Det := TestDet;
|
---|
967 | end;
|
---|
968 | end;
|
---|
969 | if uix >= 0 then
|
---|
970 | begin
|
---|
971 | RemoveUnit_UpdateMap(P, uix);
|
---|
972 | Inc(Flags, chUnitLost);
|
---|
973 | end;
|
---|
974 | end;
|
---|
975 | end;
|
---|
976 |
|
---|
977 | if GTestFlags and tfImmImprove <> 0 then
|
---|
978 | Prod := CityProjectCost;
|
---|
979 | DoProd := (Project and (cpImp + cpIndex) <> cpImp + imTrGoods) and
|
---|
980 | (Prod >= CityProjectCost);
|
---|
981 |
|
---|
982 | // check if wonder already built
|
---|
983 | if (Project and cpImp <> 0) and (Project and cpIndex < nWonder) and
|
---|
984 | (GWonder[Project and cpIndex].CityID <> WonderNotBuiltYet) then
|
---|
985 | begin
|
---|
986 | Inc(Flags, chOldWonder);
|
---|
987 | DoProd := False;
|
---|
988 | end;
|
---|
989 |
|
---|
990 | // check if producing settlers would disband city
|
---|
991 | if DoProd and (Project and (cpImp or cpDisbandCity) = 0) and
|
---|
992 | ((Size + SizeMod - 2 < 2) and
|
---|
993 | (Model[Project and cpIndex].Kind = mkSettler) or (Size + SizeMod - 1 < 2)
|
---|
994 | and ((Model[Project and cpIndex].Kind = mkSlaves) or
|
---|
995 | (Project and cpConscripts <> 0))) then
|
---|
996 | begin
|
---|
997 | Inc(Flags, chNoSettlerProd);
|
---|
998 | DoProd := False;
|
---|
999 | end;
|
---|
1000 |
|
---|
1001 | if DoProd then
|
---|
1002 | begin { project complete }
|
---|
1003 | Dec(Prod, CityProjectCost);
|
---|
1004 | if Project and cpImp = 0 then { produce unit }
|
---|
1005 | begin
|
---|
1006 | if nUn < numax then
|
---|
1007 | begin
|
---|
1008 | CreateUnit(P, Project and cpIndex);
|
---|
1009 | Un[nUn - 1].Loc := Loc;
|
---|
1010 | with Un[nUn - 1] do
|
---|
1011 | begin
|
---|
1012 | Home := cix;
|
---|
1013 | if (Model[mix].Domain < dSea) and (Built[imElite] = 1) then
|
---|
1014 | Exp := ExpCost * (nExp - 1) { elite }
|
---|
1015 | else if (Model[mix].Domain < dSea) and (Built[imBarracks] = 1) or
|
---|
1016 | (Model[mix].Domain = dSea) and (Built[imDockyard] = 1) or
|
---|
1017 | (Model[mix].Domain = dAir) and (Built[imAirport] = 1) then
|
---|
1018 | Exp := ExpCost * 2; { vet }
|
---|
1019 | if Project and cpConscripts <> 0 then
|
---|
1020 | Flags := Flags or unConscripts;
|
---|
1021 | end;
|
---|
1022 | PlaceUnit(P, nUn - 1);
|
---|
1023 | UpdateUnitMap(Loc);
|
---|
1024 | if Model[Project and cpIndex].Kind = mkSettler then
|
---|
1025 | Dec(SizeMod, 2) { settler produced - city shrink }
|
---|
1026 | else if (Model[Project and cpIndex].Kind = mkSlaves) or
|
---|
1027 | (Project and cpConscripts <> 0) then
|
---|
1028 | Dec(SizeMod); { slaves/conscripts produced - city shrink }
|
---|
1029 | end;
|
---|
1030 | Project0 := Project or cpRepeat or cpCompleted;
|
---|
1031 | end
|
---|
1032 | else if Imp[Project and cpIndex].Kind = ikShipPart then
|
---|
1033 | begin { produce ship parts }
|
---|
1034 | Inc(GShip[P].Parts[Project and cpIndex - imShipComp]);
|
---|
1035 | Project0 := Project or cpCompleted;
|
---|
1036 | end
|
---|
1037 | else { produce improvement }
|
---|
1038 | begin
|
---|
1039 | NewImp := Project and cpIndex;
|
---|
1040 | Inc(Money, Prod); { change rest to money }
|
---|
1041 | Project0 := Project or cpCompleted;
|
---|
1042 | Project := cpImp + imTrGoods;
|
---|
1043 | Prod := 0;
|
---|
1044 |
|
---|
1045 | if Imp[NewImp].Kind in [ikNatLocal, ikNatGlobal] then
|
---|
1046 | begin // nat. project
|
---|
1047 | for I := 0 to nCity - 1 do
|
---|
1048 | if (City[I].Loc >= 0) and (City[I].Built[NewImp] = 1) then
|
---|
1049 | begin { allowed only once }
|
---|
1050 | Inc(Money, Imp[NewImp].Cost * BuildCostMod[Difficulty[P]] div 12);
|
---|
1051 | City[I].Built[NewImp] := 0;
|
---|
1052 | end;
|
---|
1053 | NatBuilt[NewImp] := 1;
|
---|
1054 |
|
---|
1055 | // immediate nat. project effects
|
---|
1056 | case NewImp of
|
---|
1057 | imGrWall:
|
---|
1058 | GrWallContinent[P] := Continent[Loc];
|
---|
1059 | end;
|
---|
1060 | end;
|
---|
1061 |
|
---|
1062 | if NewImp < nWonder then
|
---|
1063 | begin // wonder
|
---|
1064 | GWonder[NewImp].CityID := ID;
|
---|
1065 | GWonder[NewImp].EffectiveOwner := P;
|
---|
1066 | CheckExpiration(NewImp);
|
---|
1067 |
|
---|
1068 | // immediate wonder effects
|
---|
1069 | case NewImp of
|
---|
1070 | woEiffel:
|
---|
1071 | begin // reactivate wonders
|
---|
1072 | for I := 0 to nWonder - 1 do
|
---|
1073 | if Imp[I].Expiration >= 0 then
|
---|
1074 | for cix2 := 0 to nCity - 1 do
|
---|
1075 | if (City[cix2].Loc >= 0) and (City[cix2].Built[I] = 1)
|
---|
1076 | then
|
---|
1077 | GWonder[I].EffectiveOwner := P;
|
---|
1078 | end;
|
---|
1079 | woLighthouse:
|
---|
1080 | CheckSpecialModels(P, preLighthouse);
|
---|
1081 | woLeo:
|
---|
1082 | begin
|
---|
1083 | Inc(Research, TechBaseCost(nTech[P], Difficulty[P]) +
|
---|
1084 | TechBaseCost(nTech[P] + 2, Difficulty[P]));
|
---|
1085 | CheckSpecialModels(P, preLeo);
|
---|
1086 | end;
|
---|
1087 | woPyramids:
|
---|
1088 | CheckSpecialModels(P, preBuilder);
|
---|
1089 | woMir:
|
---|
1090 | begin
|
---|
1091 | for p1 := 0 to nPl - 1 do
|
---|
1092 | if (p1 <> P) and (1 shl p1 and GAlive <> 0) then
|
---|
1093 | begin
|
---|
1094 | if RW[P].Treaty[p1] = trNoContact then
|
---|
1095 | IntroduceEnemy(P, p1);
|
---|
1096 | GiveCivilReport(P, p1);
|
---|
1097 | GiveMilReport(P, p1);
|
---|
1098 | end;
|
---|
1099 | end;
|
---|
1100 | end;
|
---|
1101 | end;
|
---|
1102 |
|
---|
1103 | for I := 0 to nImpReplacement - 1 do // sell obsolete buildings
|
---|
1104 | if (ImpReplacement[I].NewImp = NewImp) and
|
---|
1105 | (Built[ImpReplacement[I].OldImp] > 0) then
|
---|
1106 | begin
|
---|
1107 | Inc(RW[P].Money, Imp[ImpReplacement[I].OldImp].Cost * BuildCostMod
|
---|
1108 | [Difficulty[P]] div 12);
|
---|
1109 | Built[ImpReplacement[I].OldImp] := 0;
|
---|
1110 | end;
|
---|
1111 |
|
---|
1112 | if NewImp in [imPower, imHydro, imNuclear] then
|
---|
1113 | for I := 0 to nImp - 1 do
|
---|
1114 | if (I <> NewImp) and (I in [imPower, imHydro, imNuclear]) and
|
---|
1115 | (Built[I] > 0) then
|
---|
1116 | begin // sell obsolete power plant
|
---|
1117 | Inc(RW[P].Money, Imp[I].Cost * BuildCostMod[Difficulty[P]
|
---|
1118 | ] div 12);
|
---|
1119 | Built[I] := 0;
|
---|
1120 | end;
|
---|
1121 |
|
---|
1122 | Built[NewImp] := 1;
|
---|
1123 | end;
|
---|
1124 | Prod0 := Prod;
|
---|
1125 | Inc(Flags, chProduction);
|
---|
1126 | end
|
---|
1127 | else
|
---|
1128 | begin
|
---|
1129 | Project0 := Project0 and not cpCompleted;
|
---|
1130 | if Project0 and not cpAuto <> Project and not cpAuto then
|
---|
1131 | Project0 := Project;
|
---|
1132 | Prod0 := Prod;
|
---|
1133 | end;
|
---|
1134 |
|
---|
1135 | if SizeMod > 0 then
|
---|
1136 | begin
|
---|
1137 | CityGrowth(P, cix);
|
---|
1138 | Inc(Flags, chPopIncrease);
|
---|
1139 | end;
|
---|
1140 | Result := Size + SizeMod >= 2;
|
---|
1141 | if Result then
|
---|
1142 | while SizeMod < 0 do
|
---|
1143 | begin
|
---|
1144 | CityShrink(P, cix);
|
---|
1145 | Inc(SizeMod);
|
---|
1146 | end;
|
---|
1147 | end;
|
---|
1148 | end;
|
---|
1149 |
|
---|
1150 | {
|
---|
1151 | Tile Access
|
---|
1152 | ____________________________________________________________________
|
---|
1153 | }
|
---|
1154 | function SetCityTiles(P, cix, NewTiles: Integer;
|
---|
1155 | TestOnly: Boolean = False): Integer;
|
---|
1156 | var
|
---|
1157 | V21, Working, ChangeTiles, AddTiles, Loc1: Integer;
|
---|
1158 | CityAreaInfo: TCityAreaInfo;
|
---|
1159 | Radius: TVicinity21Loc;
|
---|
1160 | begin
|
---|
1161 | with RW[P].City[cix] do
|
---|
1162 | begin
|
---|
1163 | ChangeTiles := NewTiles xor Integer(Tiles);
|
---|
1164 | AddTiles := NewTiles and not Tiles;
|
---|
1165 | if Mode = moPlaying then
|
---|
1166 | begin // do all checks
|
---|
1167 | if NewTiles and not $67F7F76 <> 0 then
|
---|
1168 | begin
|
---|
1169 | Result := eInvalid;
|
---|
1170 | Exit
|
---|
1171 | end; // invalid tile index included
|
---|
1172 | if NewTiles and (1 shl 13) = 0 then
|
---|
1173 | begin
|
---|
1174 | Result := eViolation;
|
---|
1175 | Exit
|
---|
1176 | end; // city tile must be exploited
|
---|
1177 | if ChangeTiles = 0 then
|
---|
1178 | begin
|
---|
1179 | Result := eNotChanged;
|
---|
1180 | Exit
|
---|
1181 | end;
|
---|
1182 | if AddTiles <> 0 then
|
---|
1183 | begin
|
---|
1184 | // check if new tiles possible
|
---|
1185 | GetCityAreaInfo(P, Loc, CityAreaInfo);
|
---|
1186 | for V21 := 1 to 26 do
|
---|
1187 | if AddTiles and (1 shl V21) <> 0 then
|
---|
1188 | if CityAreaInfo.Available[V21] <> faAvailable then
|
---|
1189 | begin
|
---|
1190 | Result := eTileNotAvailable;
|
---|
1191 | Exit;
|
---|
1192 | end;
|
---|
1193 | // not more tiles than inhabitants
|
---|
1194 | Working := 0;
|
---|
1195 | for V21 := 1 to 26 do
|
---|
1196 | if NewTiles and (1 shl V21) <> 0 then
|
---|
1197 | Inc(Working);
|
---|
1198 | if Working > Size then
|
---|
1199 | begin
|
---|
1200 | Result := eNoWorkerAvailable;
|
---|
1201 | Exit;
|
---|
1202 | end;
|
---|
1203 | end;
|
---|
1204 | end;
|
---|
1205 | Result := eOk;
|
---|
1206 | if not TestOnly then
|
---|
1207 | begin
|
---|
1208 | V21_to_Loc(Loc, Radius);
|
---|
1209 | for V21 := 1 to 26 do
|
---|
1210 | if ChangeTiles and (1 shl V21) <> 0 then
|
---|
1211 | begin
|
---|
1212 | Loc1 := Radius[V21];
|
---|
1213 | Assert((Loc1 >= 0) and (Loc1 < MapSize));
|
---|
1214 | if NewTiles and (1 shl V21) <> 0 then
|
---|
1215 | UsedByCity[Loc1] := Loc // employ tile
|
---|
1216 | else if UsedByCity[Loc1] <> Loc then
|
---|
1217 | Assert(Mode < moPlaying)
|
---|
1218 | // should only happen during loading, because of wrong sSetCityTiles command order
|
---|
1219 | else
|
---|
1220 | UsedByCity[Loc1] := -1; // unemploy tile
|
---|
1221 | end;
|
---|
1222 | Tiles := NewTiles;
|
---|
1223 | end;
|
---|
1224 | end;
|
---|
1225 | end;
|
---|
1226 |
|
---|
1227 | procedure GetCityTileAdvice(P, cix: Integer; var Advice: TCityTileAdviceData);
|
---|
1228 | const
|
---|
1229 | oFood = 0;
|
---|
1230 | oProd = 1;
|
---|
1231 | oTax = 2;
|
---|
1232 | oScience = 3;
|
---|
1233 | type
|
---|
1234 | TTileData = record
|
---|
1235 | Food: Integer;
|
---|
1236 | Prod: Integer;
|
---|
1237 | Trade: Integer;
|
---|
1238 | SubValue: Integer;
|
---|
1239 | V21: Integer;
|
---|
1240 | end;
|
---|
1241 | var
|
---|
1242 | I, V21, Loc1, nHierarchy, iH, iT, iH_Switch, MinWorking, MaxWorking,
|
---|
1243 | WantedProd, MinFood, MinProd, count, Take, MaxTake, AreaSize, FormulaCode,
|
---|
1244 | NeedRare, RareTiles, cix1, dx, dy, BestTiles, ProdBeforeBoost, TestTiles,
|
---|
1245 | SubPlus, SuperPlus: Integer;
|
---|
1246 | SuperValue, BestSuperValue, SubValue, BestSubValue: Integer;
|
---|
1247 | Value, BestValue, ValuePlus: Extended;
|
---|
1248 | ValueFormula_Weight: array [oFood .. oScience] of Extended;
|
---|
1249 | ValueFormula_Multiply: array [oFood .. oScience] of Boolean;
|
---|
1250 | Output: array [oFood .. oScience] of Integer;
|
---|
1251 | TileInfo, BaseTileInfo: TTileInfo;
|
---|
1252 | Radius, Radius1: TVicinity21Loc;
|
---|
1253 | TestReport: TCityReport;
|
---|
1254 | CityReportEx: TCityReportEx;
|
---|
1255 | CityAreaInfo: TCityAreaInfo;
|
---|
1256 | Hierarchy: array [0 .. 20, 0 .. 31] of TTileData;
|
---|
1257 | nTile, nSelection: array [0 .. 20] of Integer;
|
---|
1258 | SubCriterion: array [0 .. 27] of Integer;
|
---|
1259 | FoodWasted, FoodToTax, ProdToTax, RareOK, NeedStep2, IsBest: Boolean;
|
---|
1260 | begin
|
---|
1261 | if (RW[P].Government = gAnarchy) or (RW[P].City[cix].Flags and chCaptured <> 0)
|
---|
1262 | then
|
---|
1263 | begin
|
---|
1264 | FillChar(Advice.CityReport, SizeOf(Advice.CityReport), 0);
|
---|
1265 | Advice.Tiles := 1 shl CityOwnTile;
|
---|
1266 | Advice.CityReport.HypoTiles := 1 shl CityOwnTile;
|
---|
1267 | Exit;
|
---|
1268 | end;
|
---|
1269 |
|
---|
1270 | for I := oFood to oScience do
|
---|
1271 | begin // decode evaluation formula from weights parameter
|
---|
1272 | FormulaCode := Advice.ResourceWeights shr (24 - 8 * I) and $FF;
|
---|
1273 | ValueFormula_Multiply[I] := FormulaCode and $80 <> 0;
|
---|
1274 | if FormulaCode and $40 <> 0 then
|
---|
1275 | ValueFormula_Weight[I] := (FormulaCode and $0F) *
|
---|
1276 | (1 shl (FormulaCode and $30 shr 4)) / 16
|
---|
1277 | else
|
---|
1278 | ValueFormula_Weight[I] := (FormulaCode and $0F) *
|
---|
1279 | (1 shl (FormulaCode and $30 shr 4));
|
---|
1280 | end;
|
---|
1281 |
|
---|
1282 | TestReport.HypoTiles := 1 shl CityOwnTile;
|
---|
1283 | TestReport.HypoTax := -1;
|
---|
1284 | TestReport.HypoLux := -1;
|
---|
1285 | GetSmallCityReport(P, cix, TestReport, @CityReportEx);
|
---|
1286 | with RW[P].City[cix] do
|
---|
1287 | begin
|
---|
1288 | V21_to_Loc(Loc, Radius);
|
---|
1289 | FoodToTax := RW[P].Government = gFuture;
|
---|
1290 | ProdToTax := Project and (cpImp + cpIndex) = cpImp + imTrGoods;
|
---|
1291 | FoodWasted := not FoodToTax and (Food = StorageSize[Difficulty[P]]) and
|
---|
1292 | not CanCityGrow(P, cix);
|
---|
1293 |
|
---|
1294 | // sub criteria
|
---|
1295 | for V21 := 1 to 26 do
|
---|
1296 | begin
|
---|
1297 | Loc1 := Radius[V21];
|
---|
1298 | if Loc1 >= 0 then
|
---|
1299 | SubCriterion[V21] := 3360 - (Distance(Loc, Loc1) - 1) * 32 -
|
---|
1300 | V21 xor $15;
|
---|
1301 | end;
|
---|
1302 | for cix1 := 0 to RW[P].nCity - 1 do
|
---|
1303 | if cix1 <> cix then
|
---|
1304 | begin
|
---|
1305 | Loc1 := RW[P].City[cix1].Loc;
|
---|
1306 | if Loc1 >= 0 then
|
---|
1307 | begin
|
---|
1308 | if Distance(Loc, Loc1) <= 10 then
|
---|
1309 | begin // cities overlap -- prefer tiles outside common range
|
---|
1310 | V21_to_Loc(Loc1, Radius1);
|
---|
1311 | for V21 := 1 to 26 do
|
---|
1312 | begin
|
---|
1313 | Loc1 := Radius1[V21];
|
---|
1314 | if (Loc1 >= 0) and (Loc1 < MapSize) and (Distance(Loc, Loc1) <= 5)
|
---|
1315 | then
|
---|
1316 | begin
|
---|
1317 | dxdy(Loc, Loc1, dx, dy);
|
---|
1318 | Dec(SubCriterion[(dy + 3) shl 2 + (dx + 3) shr 1], 160);
|
---|
1319 | end;
|
---|
1320 | end;
|
---|
1321 | end;
|
---|
1322 | end;
|
---|
1323 | end;
|
---|
1324 |
|
---|
1325 | GetCityAreaInfo(P, Loc, CityAreaInfo);
|
---|
1326 | AreaSize := 0;
|
---|
1327 | for V21 := 1 to 26 do
|
---|
1328 | if CityAreaInfo.Available[V21] = faAvailable then
|
---|
1329 | Inc(AreaSize);
|
---|
1330 |
|
---|
1331 | if RW[P].Government = gFundamentalism then
|
---|
1332 | begin
|
---|
1333 | MinWorking := Size;
|
---|
1334 | MaxWorking := Size;
|
---|
1335 | end
|
---|
1336 | else
|
---|
1337 | begin
|
---|
1338 | MinWorking := CityReportEx.TradeProcessing.HappyBase shr 1;
|
---|
1339 | if MinWorking > Size then
|
---|
1340 | MinWorking := Size;
|
---|
1341 | if (RW[P].LuxRate = 0) and not CityReportEx.TradeProcessing.FlexibleLuxury
|
---|
1342 | then
|
---|
1343 | MaxWorking := MinWorking
|
---|
1344 | else
|
---|
1345 | MaxWorking := Size;
|
---|
1346 | end;
|
---|
1347 | if MaxWorking > AreaSize then
|
---|
1348 | begin
|
---|
1349 | MaxWorking := AreaSize;
|
---|
1350 | if MinWorking > AreaSize then
|
---|
1351 | MinWorking := AreaSize;
|
---|
1352 | end;
|
---|
1353 | if TestReport.Support = 0 then
|
---|
1354 | WantedProd := 0
|
---|
1355 | else
|
---|
1356 | WantedProd := 1 + (TestReport.Support * 100 - 1)
|
---|
1357 | div (100 + CityReportEx.ProdProcessing.ProdBonus * 50 +
|
---|
1358 | CityReportEx.ProdProcessing.FutProdBonus);
|
---|
1359 |
|
---|
1360 | // consider resources for ship parts
|
---|
1361 | NeedRare := 0;
|
---|
1362 | if (GTestFlags and tfNoRareNeed = 0) and (Project and cpImp <> 0) then
|
---|
1363 | case Project and cpIndex of
|
---|
1364 | imShipComp:
|
---|
1365 | NeedRare := fCobalt;
|
---|
1366 | imShipPow:
|
---|
1367 | NeedRare := fUranium;
|
---|
1368 | imShipHab:
|
---|
1369 | NeedRare := fMercury;
|
---|
1370 | end;
|
---|
1371 | if NeedRare > 0 then
|
---|
1372 | begin
|
---|
1373 | RareTiles := 0;
|
---|
1374 | for V21 := 1 to 26 do
|
---|
1375 | begin
|
---|
1376 | Loc1 := Radius[V21];
|
---|
1377 | if (Loc1 >= 0) and (Loc1 < MapSize) and
|
---|
1378 | (RealMap[Loc1] and fModern = Cardinal(NeedRare)) then
|
---|
1379 | RareTiles := RareTiles or (1 shl V21);
|
---|
1380 | end;
|
---|
1381 | end;
|
---|
1382 |
|
---|
1383 | // step 1: sort tiles to hierarchies
|
---|
1384 | nHierarchy := 0;
|
---|
1385 | for V21 := 1 to 26 do // non-rare tiles
|
---|
1386 | if (CityAreaInfo.Available[V21] = faAvailable) and
|
---|
1387 | ((NeedRare = 0) or (1 shl V21 and RareTiles = 0)) then
|
---|
1388 | begin
|
---|
1389 | Loc1 := Radius[V21];
|
---|
1390 | Assert((Loc1 >= 0) and (Loc1 < MapSize));
|
---|
1391 | GetTileInfo(P, cix, Loc1, TileInfo);
|
---|
1392 | if V21 = CityOwnTile then
|
---|
1393 | BaseTileInfo := TileInfo
|
---|
1394 | else
|
---|
1395 | begin
|
---|
1396 | iH := 0;
|
---|
1397 | while iH < nHierarchy do
|
---|
1398 | begin
|
---|
1399 | iT := 0;
|
---|
1400 | while (iT < nTile[iH]) and (TileInfo.Food <= Hierarchy[iH, iT].Food)
|
---|
1401 | and (TileInfo.Prod <= Hierarchy[iH, iT].Prod) and
|
---|
1402 | (TileInfo.Trade <= Hierarchy[iH, iT].Trade) and
|
---|
1403 | not((TileInfo.Food = Hierarchy[iH, iT].Food) and
|
---|
1404 | (TileInfo.Prod = Hierarchy[iH, iT].Prod) and
|
---|
1405 | (TileInfo.Trade = Hierarchy[iH, iT].Trade) and
|
---|
1406 | (SubCriterion[V21] >= SubCriterion[Hierarchy[iH, iT].V21])) do
|
---|
1407 | Inc(iT);
|
---|
1408 | if (iT = nTile[iH]) // new worst tile in this hierarchy
|
---|
1409 | or ((TileInfo.Food >= Hierarchy[iH, iT].Food)
|
---|
1410 | // new middle tile in this hierarchy
|
---|
1411 | and (TileInfo.Prod >= Hierarchy[iH, iT].Prod) and
|
---|
1412 | (TileInfo.Trade >= Hierarchy[iH, iT].Trade)) then
|
---|
1413 | Break; // insert position found!
|
---|
1414 | Inc(iH);
|
---|
1415 | end;
|
---|
1416 | if iH = nHierarchy then
|
---|
1417 | begin // need to start new hierarchy
|
---|
1418 | nTile[iH] := 0;
|
---|
1419 | Inc(nHierarchy);
|
---|
1420 | iT := 0;
|
---|
1421 | end;
|
---|
1422 | Move(Hierarchy[iH, iT], Hierarchy[iH, iT + 1],
|
---|
1423 | (nTile[iH] - iT) * SizeOf(TTileData));
|
---|
1424 | Inc(nTile[iH]);
|
---|
1425 | Hierarchy[iH, iT].V21 := V21;
|
---|
1426 | Hierarchy[iH, iT].Food := TileInfo.Food;
|
---|
1427 | Hierarchy[iH, iT].Prod := TileInfo.Prod;
|
---|
1428 | Hierarchy[iH, iT].Trade := TileInfo.Trade;
|
---|
1429 | Hierarchy[iH, iT].SubValue := SubCriterion[V21];
|
---|
1430 | end;
|
---|
1431 | end;
|
---|
1432 | if NeedRare <> 0 then
|
---|
1433 | begin // rare tiles need own hierarchy
|
---|
1434 | iH := nHierarchy;
|
---|
1435 | for V21 := 1 to 26 do
|
---|
1436 | if (CityAreaInfo.Available[V21] = faAvailable) and
|
---|
1437 | (1 shl V21 and RareTiles <> 0) then
|
---|
1438 | begin
|
---|
1439 | Loc1 := Radius[V21];
|
---|
1440 | Assert((V21 <> CityOwnTile) and (Loc1 >= 0) and (Loc1 < MapSize));
|
---|
1441 | GetTileInfo(P, cix, Loc1, TileInfo);
|
---|
1442 | if iH = nHierarchy then
|
---|
1443 | begin // need to start new hierarchy
|
---|
1444 | nTile[iH] := 0;
|
---|
1445 | Inc(nHierarchy);
|
---|
1446 | iT := 0;
|
---|
1447 | end
|
---|
1448 | else
|
---|
1449 | iT := nTile[iH];
|
---|
1450 | Inc(nTile[iH]);
|
---|
1451 | Hierarchy[iH, iT].V21 := V21;
|
---|
1452 | Hierarchy[iH, iT].Food := TileInfo.Food; // = 0
|
---|
1453 | Hierarchy[iH, iT].Prod := TileInfo.Prod; // = 1
|
---|
1454 | Hierarchy[iH, iT].Trade := TileInfo.Trade; // = 0
|
---|
1455 | Hierarchy[iH, iT].SubValue := SubCriterion[V21];
|
---|
1456 | end;
|
---|
1457 | end;
|
---|
1458 | if Built[imAlgae] > 0 then
|
---|
1459 | Inc(BaseTileInfo.Food, 12);
|
---|
1460 |
|
---|
1461 | // step 2: summarize resources
|
---|
1462 | for iH := 0 to nHierarchy - 1 do
|
---|
1463 | begin
|
---|
1464 | Move(Hierarchy[iH, 0], Hierarchy[iH, 1], nTile[iH] * SizeOf(TTileData));
|
---|
1465 | Hierarchy[iH, 0].Food := 0;
|
---|
1466 | Hierarchy[iH, 0].Prod := 0;
|
---|
1467 | Hierarchy[iH, 0].Trade := 0;
|
---|
1468 | Hierarchy[iH, 0].SubValue := 0;
|
---|
1469 | Hierarchy[iH, 0].V21 := 0;
|
---|
1470 | for iT := 1 to nTile[iH] do
|
---|
1471 | begin
|
---|
1472 | Inc(Hierarchy[iH, iT].Food, Hierarchy[iH, iT - 1].Food);
|
---|
1473 | Inc(Hierarchy[iH, iT].Prod, Hierarchy[iH, iT - 1].Prod);
|
---|
1474 | Inc(Hierarchy[iH, iT].Trade, Hierarchy[iH, iT - 1].Trade);
|
---|
1475 | Inc(Hierarchy[iH, iT].SubValue, Hierarchy[iH, iT - 1].SubValue);
|
---|
1476 | Hierarchy[iH, iT].V21 := 1 shl Hierarchy[iH, iT].V21 +
|
---|
1477 | Hierarchy[iH, iT - 1].V21;
|
---|
1478 | end;
|
---|
1479 | end;
|
---|
1480 |
|
---|
1481 | // step 3: try all combinations
|
---|
1482 | BestValue := 0.0;
|
---|
1483 | BestSuperValue := 0;
|
---|
1484 | BestSubValue := 0;
|
---|
1485 | BestTiles := 0;
|
---|
1486 | FillChar(nSelection, SizeOf(nSelection), 0);
|
---|
1487 | TestReport.FoodRep := BaseTileInfo.Food;
|
---|
1488 | ProdBeforeBoost := BaseTileInfo.Prod;
|
---|
1489 | TestReport.Trade := BaseTileInfo.Trade;
|
---|
1490 | TestReport.Working := 1;
|
---|
1491 | MinFood := 0;
|
---|
1492 | MinProd := 0;
|
---|
1493 | iH_Switch := nHierarchy;
|
---|
1494 | count := 0;
|
---|
1495 | repeat
|
---|
1496 | // ensure minima
|
---|
1497 | iH := 0;
|
---|
1498 | while (TestReport.Working < MaxWorking) and (iH < iH_Switch) and
|
---|
1499 | ((TestReport.Working < MinWorking) or
|
---|
1500 | (TestReport.FoodRep < TestReport.Eaten) or
|
---|
1501 | (ProdBeforeBoost < WantedProd)) do
|
---|
1502 | begin
|
---|
1503 | Assert(nSelection[iH] = 0);
|
---|
1504 | Take := MinWorking - TestReport.Working;
|
---|
1505 | if Take > nTile[iH] then
|
---|
1506 | Take := nTile[iH]
|
---|
1507 | else
|
---|
1508 | begin
|
---|
1509 | if Take < 0 then
|
---|
1510 | Take := 0;
|
---|
1511 | MaxTake := nTile[iH];
|
---|
1512 | if TestReport.Working + MaxTake > MaxWorking then
|
---|
1513 | MaxTake := MaxWorking - TestReport.Working;
|
---|
1514 | while (Take < MaxTake) and
|
---|
1515 | (TestReport.FoodRep + Hierarchy[iH, Take].Food < MinFood) do
|
---|
1516 | Inc(Take);
|
---|
1517 | while (Take < MaxTake) and
|
---|
1518 | (ProdBeforeBoost + Hierarchy[iH, Take].Prod < MinProd) do
|
---|
1519 | Inc(Take);
|
---|
1520 | end;
|
---|
1521 | nSelection[iH] := Take;
|
---|
1522 | Inc(TestReport.Working, Take);
|
---|
1523 | with Hierarchy[iH, Take] do
|
---|
1524 | begin
|
---|
1525 | Inc(TestReport.FoodRep, Food);
|
---|
1526 | Inc(ProdBeforeBoost, Prod);
|
---|
1527 | Inc(TestReport.Trade, Trade);
|
---|
1528 | end;
|
---|
1529 | Inc(iH);
|
---|
1530 | end;
|
---|
1531 |
|
---|
1532 | Assert((TestReport.Working >= MinWorking) and
|
---|
1533 | (TestReport.Working <= MaxWorking));
|
---|
1534 | if (TestReport.FoodRep >= MinFood) and (ProdBeforeBoost >= MinProd) then
|
---|
1535 | begin
|
---|
1536 | SplitTrade(TestReport.Trade, RW[P].TaxRate, RW[P].LuxRate,
|
---|
1537 | TestReport.Working, CityReportEx.TradeProcessing,
|
---|
1538 | TestReport.Corruption, TestReport.Tax, TestReport.Lux,
|
---|
1539 | TestReport.Science);
|
---|
1540 |
|
---|
1541 | if CityReportEx.BaseHappiness + CityReportEx.BaseControl +
|
---|
1542 | TestReport.Lux + 2 * (Size - TestReport.Working) - 2 *
|
---|
1543 | TestReport.Deployed >= Size then
|
---|
1544 | begin // city is not in disorder -- evaluate combination
|
---|
1545 | Inc(count);
|
---|
1546 | if (MinProd < WantedProd) and (ProdBeforeBoost > MinProd) then
|
---|
1547 | begin // no combination reached wanted prod yet
|
---|
1548 | MinProd := ProdBeforeBoost;
|
---|
1549 | if MinProd > WantedProd then
|
---|
1550 | MinProd := WantedProd
|
---|
1551 | end;
|
---|
1552 | if MinProd = WantedProd then
|
---|
1553 | // do not care for food before prod is ensured
|
---|
1554 | if (MinFood < TestReport.Eaten) and (TestReport.FoodRep > MinFood)
|
---|
1555 | then
|
---|
1556 | begin // no combination reached wanted food yet
|
---|
1557 | MinFood := TestReport.FoodRep;
|
---|
1558 | if MinFood > TestReport.Eaten then
|
---|
1559 | MinFood := TestReport.Eaten
|
---|
1560 | end;
|
---|
1561 | BoostProd(ProdBeforeBoost, CityReportEx.ProdProcessing,
|
---|
1562 | TestReport.ProdRep, TestReport.PollRep);
|
---|
1563 | SuperValue := 0;
|
---|
1564 |
|
---|
1565 | // super-criterion A: unit support granted?
|
---|
1566 | if TestReport.ProdRep >= TestReport.Support then
|
---|
1567 | SuperValue := SuperValue or 1 shl 30;
|
---|
1568 |
|
---|
1569 | // super-criterion B: food demand granted?
|
---|
1570 | if TestReport.FoodRep >= TestReport.Eaten then
|
---|
1571 | SuperValue := SuperValue or 63 shl 24
|
---|
1572 | else if TestReport.FoodRep > TestReport.Eaten - 63 then
|
---|
1573 | SuperValue := SuperValue or
|
---|
1574 | (63 - (TestReport.Eaten - TestReport.FoodRep)) shl 24;
|
---|
1575 |
|
---|
1576 | SuperPlus := SuperValue - BestSuperValue;
|
---|
1577 | if SuperPlus >= 0 then
|
---|
1578 | begin
|
---|
1579 | Output[oTax] := TestReport.Tax;
|
---|
1580 | Output[oScience] := TestReport.Science;
|
---|
1581 |
|
---|
1582 | if TestReport.FoodRep < TestReport.Eaten then
|
---|
1583 | Output[oFood] := TestReport.FoodRep
|
---|
1584 | // appreciate what we have, combination will have bad supervalue anyway
|
---|
1585 | else if FoodWasted then
|
---|
1586 | Output[oFood] := 0
|
---|
1587 | else
|
---|
1588 | begin
|
---|
1589 | Output[oFood] := TestReport.FoodRep - TestReport.Eaten;
|
---|
1590 | if FoodToTax or (Size >= NeedAqueductSize) and (Output[oFood] = 1)
|
---|
1591 | then
|
---|
1592 | begin
|
---|
1593 | Inc(Output[oTax], Output[oFood]);
|
---|
1594 | Output[oFood] := 0;
|
---|
1595 | end;
|
---|
1596 | end;
|
---|
1597 |
|
---|
1598 | if TestReport.ProdRep < TestReport.Support then
|
---|
1599 | Output[oProd] := TestReport.ProdRep
|
---|
1600 | // appreciate what we have, combination will have bad supervalue anyway
|
---|
1601 | else
|
---|
1602 | begin
|
---|
1603 | if NeedRare > 0 then
|
---|
1604 | begin
|
---|
1605 | RareOK := False;
|
---|
1606 | for iH := 0 to nHierarchy - 1 do
|
---|
1607 | if Hierarchy[iH, nSelection[iH]].V21 and RareTiles <> 0 then
|
---|
1608 | RareOK := True;
|
---|
1609 | if not RareOK then
|
---|
1610 | TestReport.ProdRep := TestReport.Support;
|
---|
1611 | end;
|
---|
1612 | Output[oProd] := TestReport.ProdRep - TestReport.Support;
|
---|
1613 | if ProdToTax then
|
---|
1614 | begin
|
---|
1615 | Inc(Output[oTax], Output[oProd]);
|
---|
1616 | Output[oProd] := 0;
|
---|
1617 | end;
|
---|
1618 | end;
|
---|
1619 |
|
---|
1620 | NeedStep2 := False;
|
---|
1621 | Value := 0;
|
---|
1622 | for I := oFood to oScience do
|
---|
1623 | if ValueFormula_Multiply[I] then
|
---|
1624 | NeedStep2 := True
|
---|
1625 | else
|
---|
1626 | Value := Value + ValueFormula_Weight[I] * Output[I];
|
---|
1627 | if NeedStep2 then
|
---|
1628 | begin
|
---|
1629 | if Value > 0 then
|
---|
1630 | Value := ln(Value) + 123;
|
---|
1631 | for I := oFood to oScience do
|
---|
1632 | if ValueFormula_Multiply[I] and (Output[I] > 0) then
|
---|
1633 | Value := Value + ValueFormula_Weight[I] *
|
---|
1634 | (ln(Output[I]) + 123);
|
---|
1635 | end;
|
---|
1636 |
|
---|
1637 | ValuePlus := Value - BestValue;
|
---|
1638 | if (SuperPlus > 0) or (ValuePlus >= 0.0) then
|
---|
1639 | begin
|
---|
1640 | SubValue := (TestReport.FoodRep + ProdBeforeBoost +
|
---|
1641 | TestReport.Trade) shl 18;
|
---|
1642 | TestTiles := 1 shl CityOwnTile;
|
---|
1643 | for iH := 0 to nHierarchy - 1 do
|
---|
1644 | begin
|
---|
1645 | Inc(TestTiles, Hierarchy[iH, nSelection[iH]].V21);
|
---|
1646 | Inc(SubValue, Hierarchy[iH, nSelection[iH]].SubValue);
|
---|
1647 | end;
|
---|
1648 | IsBest := True;
|
---|
1649 | if (SuperPlus = 0) and (ValuePlus = 0.0) then
|
---|
1650 | begin
|
---|
1651 | SubPlus := SubValue - BestSubValue;
|
---|
1652 | if SubPlus < 0 then
|
---|
1653 | IsBest := False
|
---|
1654 | else if SubPlus = 0 then
|
---|
1655 | begin
|
---|
1656 | Assert(TestTiles <> BestTiles);
|
---|
1657 | IsBest := TestTiles > BestTiles
|
---|
1658 | end
|
---|
1659 | end;
|
---|
1660 | if IsBest then
|
---|
1661 | begin
|
---|
1662 | BestSuperValue := SuperValue;
|
---|
1663 | BestValue := Value;
|
---|
1664 | BestSubValue := SubValue;
|
---|
1665 | BestTiles := TestTiles;
|
---|
1666 | TestReport.Happy :=
|
---|
1667 | (CityReportEx.TradeProcessing.HappyBase - Size) div 2 +
|
---|
1668 | TestReport.Lux shr 1;
|
---|
1669 | Advice.CityReport := TestReport;
|
---|
1670 | end;
|
---|
1671 | end; // if (SuperPlus>0) or (ValuePlus>=0.0)
|
---|
1672 | end; // if SuperPlus>=0
|
---|
1673 | end;
|
---|
1674 | end;
|
---|
1675 |
|
---|
1676 | // calculate next combination
|
---|
1677 | iH_Switch := 0;
|
---|
1678 | repeat
|
---|
1679 | with Hierarchy[iH_Switch, nSelection[iH_Switch]] do
|
---|
1680 | begin
|
---|
1681 | Dec(TestReport.FoodRep, Food);
|
---|
1682 | Dec(ProdBeforeBoost, Prod);
|
---|
1683 | Dec(TestReport.Trade, Trade);
|
---|
1684 | end;
|
---|
1685 | Inc(nSelection[iH_Switch]);
|
---|
1686 | Inc(TestReport.Working);
|
---|
1687 | if (nSelection[iH_Switch] <= nTile[iH_Switch]) and
|
---|
1688 | (TestReport.Working <= MaxWorking) then
|
---|
1689 | begin
|
---|
1690 | with Hierarchy[iH_Switch, nSelection[iH_Switch]] do
|
---|
1691 | begin
|
---|
1692 | Inc(TestReport.FoodRep, Food);
|
---|
1693 | Inc(ProdBeforeBoost, Prod);
|
---|
1694 | Inc(TestReport.Trade, Trade);
|
---|
1695 | end;
|
---|
1696 | Break;
|
---|
1697 | end;
|
---|
1698 | Dec(TestReport.Working, nSelection[iH_Switch]);
|
---|
1699 | nSelection[iH_Switch] := 0;
|
---|
1700 | Inc(iH_Switch);
|
---|
1701 | until iH_Switch = nHierarchy;
|
---|
1702 | until iH_Switch = nHierarchy; // everything tested -- done
|
---|
1703 | end;
|
---|
1704 | Assert(BestSuperValue > 0); // advice should always be possible
|
---|
1705 | Advice.Tiles := BestTiles;
|
---|
1706 | Advice.CityReport.HypoTiles := BestTiles;
|
---|
1707 | end;
|
---|
1708 |
|
---|
1709 | {
|
---|
1710 | Start/End Game
|
---|
1711 | ____________________________________________________________________
|
---|
1712 | }
|
---|
1713 | procedure InitGame;
|
---|
1714 | var
|
---|
1715 | P, I, mixTownGuard: Integer;
|
---|
1716 | begin
|
---|
1717 | MaxDist := Distance(0, MapSize - lx shr 1);
|
---|
1718 | for P := 0 to nPl - 1 do
|
---|
1719 | if (1 shl P and GAlive <> 0) then
|
---|
1720 | with RW[P] do
|
---|
1721 | begin // initialize capital
|
---|
1722 | mixTownGuard := 0;
|
---|
1723 | while Model[mixTownGuard].Kind <> mkSpecial_TownGuard do
|
---|
1724 | Inc(mixTownGuard);
|
---|
1725 | with City[0] do
|
---|
1726 | begin
|
---|
1727 | Built[imPalace] := 1;
|
---|
1728 | Size := 4;
|
---|
1729 | for I := 2 to Size do
|
---|
1730 | AddBestCityTile(P, 0);
|
---|
1731 | Project := mixTownGuard;
|
---|
1732 | end;
|
---|
1733 | NatBuilt[imPalace] := 1;
|
---|
1734 | end;
|
---|
1735 | end;
|
---|
1736 |
|
---|
1737 | procedure ReleaseGame;
|
---|
1738 | begin
|
---|
1739 | end;
|
---|
1740 |
|
---|
1741 | end.
|
---|