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