| 1 | {$INCLUDE switches}
|
|---|
| 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 | {$IFOPT O-}assert(1 shl p and InvalidTreatyMap = 0); {$ENDIF}
|
|---|
| 633 | Best := 0;
|
|---|
| 634 | result := -1;
|
|---|
| 635 | with RW[p].City[cix] do
|
|---|
| 636 | begin
|
|---|
| 637 | V21_to_Loc(Loc, Radius);
|
|---|
| 638 | for V21 := 1 to 26 do
|
|---|
| 639 | if V21 <> CityOwnTile then
|
|---|
| 640 | begin
|
|---|
| 641 | Loc1 := Radius[V21];
|
|---|
| 642 | if (Loc1 >= 0) and (Loc1 < MapSize) and
|
|---|
| 643 | (RealMap[Loc1] and fTerrain >= fGrass) and
|
|---|
| 644 | (RealMap[Loc1] and (fPoll or fDeadLands or fCity) = 0) then
|
|---|
| 645 | begin
|
|---|
| 646 | pTerr := RealMap[Loc1] shr 27;
|
|---|
| 647 | if (pTerr = nPl) or (pTerr = p) or (RW[p].Treaty[pTerr] < trPeace)
|
|---|
| 648 | then
|
|---|
| 649 | begin
|
|---|
| 650 | GetTileInfo(p, cix, Loc1, TileInfo);
|
|---|
| 651 | Resources := TileInfo.Prod shl 16 + TileInfo.Trade shl 8 +
|
|---|
| 652 | TileInfo.Food;
|
|---|
| 653 | { priority: 1.prod - 2.trade - 3.food }
|
|---|
| 654 | dy := V21 shr 2 - 3;
|
|---|
| 655 | dx := V21 and 3 shl 1 - 3 + (dy + 3) and 1;
|
|---|
| 656 | Dist := abs(dx) + abs(dy) + abs(abs(dx) - abs(dy)) shr 1;
|
|---|
| 657 | if (Resources > Best) or (Resources = Best) and (Dist < BestDist)
|
|---|
| 658 | then
|
|---|
| 659 | begin
|
|---|
| 660 | result := Loc1;
|
|---|
| 661 | Best := Resources;
|
|---|
| 662 | BestDist := Dist
|
|---|
| 663 | end
|
|---|
| 664 | end
|
|---|
| 665 | end
|
|---|
| 666 | end;
|
|---|
| 667 | end
|
|---|
| 668 | end;
|
|---|
| 669 |
|
|---|
| 670 | function AddBestCityTile(p, cix: integer): boolean;
|
|---|
| 671 | var
|
|---|
| 672 | TileLoc, V21: integer;
|
|---|
| 673 | begin
|
|---|
| 674 | NextBest(p, cix, TileLoc, V21);
|
|---|
| 675 | result := TileLoc >= 0;
|
|---|
| 676 | if result then
|
|---|
| 677 | with RW[p].City[cix] do
|
|---|
| 678 | begin
|
|---|
| 679 | assert(1 shl V21 and Tiles = 0);
|
|---|
| 680 | Tiles := Tiles or (1 shl V21);
|
|---|
| 681 | UsedByCity[TileLoc] := Loc
|
|---|
| 682 | end
|
|---|
| 683 | end;
|
|---|
| 684 |
|
|---|
| 685 | procedure CityGrowth(p, cix: integer);
|
|---|
| 686 | var
|
|---|
| 687 | TileLoc, V21: integer;
|
|---|
| 688 | AltCityReport: TCityReport;
|
|---|
| 689 | begin
|
|---|
| 690 | with RW[p].City[cix] do
|
|---|
| 691 | begin
|
|---|
| 692 | inc(Size);
|
|---|
| 693 | NextBest(p, cix, TileLoc, V21);
|
|---|
| 694 | if TileLoc >= 0 then
|
|---|
| 695 | begin { test whether exploitation of tile would lead to disorder }
|
|---|
| 696 | AltCityReport.HypoTiles := Tiles + 1 shl V21;
|
|---|
| 697 | AltCityReport.HypoTax := -1;
|
|---|
| 698 | AltCityReport.HypoLux := -1;
|
|---|
| 699 | GetSmallCityReport(p, cix, AltCityReport);
|
|---|
| 700 | if AltCityReport.Working - AltCityReport.Happy <= Size shr 1 then
|
|---|
| 701 | // !!! change to new style disorder
|
|---|
| 702 | begin { no disorder -- exploit tile }
|
|---|
| 703 | assert(1 shl V21 and Tiles = 0);
|
|---|
| 704 | Tiles := Tiles or (1 shl V21);
|
|---|
| 705 | UsedByCity[TileLoc] := Loc
|
|---|
| 706 | end
|
|---|
| 707 | end;
|
|---|
| 708 | end
|
|---|
| 709 | end;
|
|---|
| 710 |
|
|---|
| 711 | procedure CityShrink(p, cix: integer);
|
|---|
| 712 | var
|
|---|
| 713 | TileLoc, V21, Working: integer;
|
|---|
| 714 | AltCityReport: TCityReport;
|
|---|
| 715 | begin
|
|---|
| 716 | with RW[p].City[cix] do
|
|---|
| 717 | begin
|
|---|
| 718 | Working := 0;
|
|---|
| 719 | for V21 := 1 to 26 do
|
|---|
| 720 | if Tiles and (1 shl V21) <> 0 then
|
|---|
| 721 | inc(Working);
|
|---|
| 722 | dec(Size);
|
|---|
| 723 | if Food > StorageSize[Difficulty[p]] then
|
|---|
| 724 | Food := StorageSize[Difficulty[p]];
|
|---|
| 725 | NextWorst(p, cix, TileLoc, V21);
|
|---|
| 726 | if Working > Size then
|
|---|
| 727 | begin { all citizens were working -- worst tile no longer exploited }
|
|---|
| 728 | assert(1 shl V21 and Tiles <> 0);
|
|---|
| 729 | Tiles := Tiles and not(1 shl V21);
|
|---|
| 730 | UsedByCity[TileLoc] := -1
|
|---|
| 731 | end
|
|---|
| 732 | else { test whether exploitation of tile would lead to disorder }
|
|---|
| 733 | begin
|
|---|
| 734 | AltCityReport.HypoTiles := -1;
|
|---|
| 735 | AltCityReport.HypoTax := -1;
|
|---|
| 736 | AltCityReport.HypoLux := -1;
|
|---|
| 737 | GetSmallCityReport(p, cix, AltCityReport);
|
|---|
| 738 | if AltCityReport.Working - AltCityReport.Happy > Size shr 1 then
|
|---|
| 739 | // !!! change to new style disorder
|
|---|
| 740 | begin { disorder -- don't exploit tile }
|
|---|
| 741 | assert(1 shl V21 and Tiles <> 0);
|
|---|
| 742 | Tiles := Tiles and not(1 shl V21);
|
|---|
| 743 | UsedByCity[TileLoc] := -1
|
|---|
| 744 | end
|
|---|
| 745 | end;
|
|---|
| 746 | end
|
|---|
| 747 | end;
|
|---|
| 748 |
|
|---|
| 749 | procedure Pollute(p, cix: integer);
|
|---|
| 750 | var
|
|---|
| 751 | PollutionLoc: integer;
|
|---|
| 752 | begin
|
|---|
| 753 | with RW[p].City[cix] do
|
|---|
| 754 | begin
|
|---|
| 755 | Pollution := Pollution - MaxPollution;
|
|---|
| 756 | PollutionLoc := NextPoll(p, cix);
|
|---|
| 757 | if PollutionLoc >= 0 then
|
|---|
| 758 | begin
|
|---|
| 759 | inc(Flags, chPollution);
|
|---|
| 760 | RealMap[PollutionLoc] := RealMap[PollutionLoc] or fPoll;
|
|---|
| 761 | end
|
|---|
| 762 | end;
|
|---|
| 763 | end;
|
|---|
| 764 |
|
|---|
| 765 | {
|
|---|
| 766 | Turn Processing
|
|---|
| 767 | ____________________________________________________________________
|
|---|
| 768 | }
|
|---|
| 769 | procedure PayCityMaintenance(p, cix: integer);
|
|---|
| 770 | var
|
|---|
| 771 | i: integer;
|
|---|
| 772 | begin
|
|---|
| 773 | with RW[p], City[cix] do
|
|---|
| 774 | for i := 28 to nImp - 1 do
|
|---|
| 775 | if (Built[i] > 0) and (Project0 and (cpImp or cpIndex) <> (cpImp or i))
|
|---|
| 776 | then // don't pay maintenance when just completed
|
|---|
| 777 | begin
|
|---|
| 778 | dec(Money, Imp[i].Maint);
|
|---|
| 779 | if Money < 0 then
|
|---|
| 780 | begin { out of money - sell improvement }
|
|---|
| 781 | inc(Money, Imp[i].Cost * BuildCostMod[Difficulty[p]] div 12);
|
|---|
| 782 | Built[i] := 0;
|
|---|
| 783 | if Imp[i].Kind <> ikCommon then
|
|---|
| 784 | begin
|
|---|
| 785 | assert(i <> imSpacePort);
|
|---|
| 786 | // never sell automatically! (solution: no maintenance)
|
|---|
| 787 | NatBuilt[i] := 0;
|
|---|
| 788 | if i = imGrWall then
|
|---|
| 789 | GrWallContinent[p] := -1;
|
|---|
| 790 | end;
|
|---|
| 791 | inc(Flags, chImprovementLost)
|
|---|
| 792 | end
|
|---|
| 793 | end;
|
|---|
| 794 | end;
|
|---|
| 795 |
|
|---|
| 796 | procedure CollectCityResources(p, cix: integer);
|
|---|
| 797 | var
|
|---|
| 798 | CityStorage, CityProjectCost: integer;
|
|---|
| 799 | CityReport: TCityReportNew;
|
|---|
| 800 | Disorder: boolean;
|
|---|
| 801 | begin
|
|---|
| 802 | with RW[p], City[cix], CityReport do
|
|---|
| 803 | if Flags and chCaptured <> 0 then
|
|---|
| 804 | begin
|
|---|
| 805 | Flags := Flags and not chDisorder;
|
|---|
| 806 | dec(Flags, $10000);
|
|---|
| 807 | if Flags and chCaptured = 0 then
|
|---|
| 808 | Flags := Flags or chAfterCapture;
|
|---|
| 809 | end
|
|---|
| 810 | else if Government = gAnarchy then
|
|---|
| 811 | Flags := Flags and not chDisorder
|
|---|
| 812 | else
|
|---|
| 813 | begin
|
|---|
| 814 | HypoTiles := -1;
|
|---|
| 815 | HypoTaxRate := -1;
|
|---|
| 816 | HypoLuxuryRate := -1;
|
|---|
| 817 | GetCityReportNew(p, cix, CityReport);
|
|---|
| 818 | CityStorage := StorageSize[Difficulty[p]];
|
|---|
| 819 | CityProjectCost := GetProjectCost(p, cix);
|
|---|
| 820 |
|
|---|
| 821 | Disorder := (HappinessBalance < 0);
|
|---|
| 822 | if Disorder and (Flags and chDisorder <> 0) then
|
|---|
| 823 | CollectedMaterial := 0; // second turn disorder
|
|---|
| 824 | if Disorder then
|
|---|
| 825 | Flags := Flags or chDisorder
|
|---|
| 826 | else
|
|---|
| 827 | Flags := Flags and not chDisorder;
|
|---|
| 828 |
|
|---|
| 829 | if not Disorder and ((Government = gFuture) or (Size >= NeedAqueductSize)
|
|---|
| 830 | and (FoodSurplus < 2)) and (FoodSurplus > 0) then
|
|---|
| 831 | inc(Money, FoodSurplus)
|
|---|
| 832 | else if not(Disorder and (FoodSurplus > 0)) then
|
|---|
| 833 | begin { calculate new food storage }
|
|---|
| 834 | Food := Food + FoodSurplus;
|
|---|
| 835 | if ((GTestFlags and tfImmGrow <> 0) or (Food >= CityStorage) and
|
|---|
| 836 | (Food - FoodSurplus < CityStorage)) // only warn once
|
|---|
| 837 | and (Size < MaxCitySize) and
|
|---|
| 838 | (Project and (cpImp + cpIndex) <> cpImp + imAqueduct) and
|
|---|
| 839 | (Project and (cpImp + cpIndex) <> cpImp + imSewer) and
|
|---|
| 840 | not CanCityGrow(p, cix) then
|
|---|
| 841 | inc(Flags, chNoGrowthWarning);
|
|---|
| 842 | end;
|
|---|
| 843 |
|
|---|
| 844 | if Prod > CityProjectCost then
|
|---|
| 845 | begin
|
|---|
| 846 | inc(Money, Prod - CityProjectCost);
|
|---|
| 847 | Prod := CityProjectCost
|
|---|
| 848 | end;
|
|---|
| 849 | if Production < 0 then
|
|---|
| 850 | Flags := Flags or chUnitLost
|
|---|
| 851 | else if not Disorder and (Flags and chProductionSabotaged = 0) then
|
|---|
| 852 | if Project and (cpImp + cpIndex) = cpImp + imTrGoods then
|
|---|
| 853 | inc(Money, Production)
|
|---|
| 854 | else
|
|---|
| 855 | inc(Prod, Production);
|
|---|
| 856 |
|
|---|
| 857 | if not Disorder then
|
|---|
| 858 | begin
|
|---|
| 859 | { sum research points and taxes }
|
|---|
| 860 | inc(Research, Science);
|
|---|
| 861 | inc(Money, Tax);
|
|---|
| 862 | Pollution := Pollution + AddPollution;
|
|---|
| 863 | end;
|
|---|
| 864 | end;
|
|---|
| 865 | end;
|
|---|
| 866 |
|
|---|
| 867 | function CityTurn(p, cix: integer): boolean;
|
|---|
| 868 | // return value: whether city keeps existing
|
|---|
| 869 | var
|
|---|
| 870 | i, uix, cix2, p1, SizeMod, CityStorage, CityProjectCost, NewImp, Det,
|
|---|
| 871 | TestDet: integer;
|
|---|
| 872 | LackOfMaterial, CheckGrow, DoProd, IsActive: boolean;
|
|---|
| 873 | begin
|
|---|
| 874 | with RW[p], City[cix] do
|
|---|
| 875 | begin
|
|---|
| 876 | SizeMod := 0;
|
|---|
| 877 | CityStorage := StorageSize[Difficulty[p]];
|
|---|
| 878 | CityProjectCost := GetProjectCost(p, cix);
|
|---|
| 879 |
|
|---|
| 880 | LackOfMaterial := Flags and chUnitLost <> 0;
|
|---|
| 881 | Flags := Flags and not chUnitLost;
|
|---|
| 882 |
|
|---|
| 883 | IsActive := (Government <> gAnarchy) and (Flags and chCaptured = 0);
|
|---|
| 884 | CheckGrow := (Flags and chDisorder = 0) and IsActive and
|
|---|
| 885 | (Government <> gFuture);
|
|---|
| 886 | if CheckGrow and (GTestFlags and tfImmGrow <> 0) then { fast growth }
|
|---|
| 887 | begin
|
|---|
| 888 | if CanCityGrow(p, cix) then
|
|---|
| 889 | inc(SizeMod)
|
|---|
| 890 | end
|
|---|
| 891 | else if CheckGrow and (Food >= CityStorage) then { normal growth }
|
|---|
| 892 | begin
|
|---|
| 893 | if CanCityGrow(p, cix) then
|
|---|
| 894 | begin
|
|---|
| 895 | if Built[imGranary] = 1 then
|
|---|
| 896 | dec(Food, CityStorage shr 1)
|
|---|
| 897 | else
|
|---|
| 898 | dec(Food, CityStorage);
|
|---|
| 899 | inc(SizeMod)
|
|---|
| 900 | end
|
|---|
| 901 | end
|
|---|
| 902 | else if Food < 0 then { famine }
|
|---|
| 903 | begin
|
|---|
| 904 | Food := 0;
|
|---|
| 905 | // check if settlers or conscripts there to disband
|
|---|
| 906 | uix := -1;
|
|---|
| 907 | for i := 0 to nUn - 1 do
|
|---|
| 908 | if (Un[i].Loc >= 0) and (Un[i].Home = cix) and
|
|---|
| 909 | ((Model[Un[i].mix].Kind = mkSettler)
|
|---|
| 910 | { and (GWonder[woFreeSettlers].EffectiveOwner<>p) }
|
|---|
| 911 | or (Un[i].Flags and unConscripts <> 0)) and
|
|---|
| 912 | ((uix = -1) or (Model[Un[i].mix].Cost < Model[Un[uix].mix].Cost) or
|
|---|
| 913 | (Model[Un[i].mix].Cost = Model[Un[uix].mix].Cost) and
|
|---|
| 914 | (Un[i].Exp < Un[uix].Exp)) then
|
|---|
| 915 | uix := i;
|
|---|
| 916 |
|
|---|
| 917 | if uix >= 0 then
|
|---|
| 918 | begin
|
|---|
| 919 | RemoveUnit_UpdateMap(p, uix);
|
|---|
| 920 | inc(Flags, chUnitLost);
|
|---|
| 921 | end
|
|---|
| 922 | else
|
|---|
| 923 | begin
|
|---|
| 924 | dec(SizeMod);
|
|---|
| 925 | inc(Flags, chPopDecrease)
|
|---|
| 926 | end
|
|---|
| 927 | end;
|
|---|
| 928 | if Food > CityStorage then
|
|---|
| 929 | Food := CityStorage;
|
|---|
| 930 |
|
|---|
| 931 | if LackOfMaterial then
|
|---|
| 932 | begin
|
|---|
| 933 | if Flags and chUnitLost = 0 then
|
|---|
| 934 | begin { one unit lost }
|
|---|
| 935 | uix := -1;
|
|---|
| 936 | Det := MaxInt;
|
|---|
| 937 | for i := 0 to nUn - 1 do
|
|---|
| 938 | if (Un[i].Loc >= 0) and (Un[i].Home = cix) then
|
|---|
| 939 | with Model[Un[i].mix] do
|
|---|
| 940 | begin
|
|---|
| 941 | if Kind = mkSpecial_TownGuard then
|
|---|
| 942 | TestDet := Un[i].Health + Un[i].Exp shl 8
|
|---|
| 943 | // disband townguards first
|
|---|
| 944 | else
|
|---|
| 945 | begin
|
|---|
| 946 | TestDet := Un[i].Health + Un[i].Exp shl 8 + Cost shl 16;
|
|---|
| 947 | // value of unit
|
|---|
| 948 | if Flags and mdDoubleSupport <> 0 then
|
|---|
| 949 | TestDet := TestDet shr 1;
|
|---|
| 950 | // double support, tend to disband first
|
|---|
| 951 | end;
|
|---|
| 952 | if TestDet < Det then
|
|---|
| 953 | begin
|
|---|
| 954 | uix := i;
|
|---|
| 955 | Det := TestDet
|
|---|
| 956 | end;
|
|---|
| 957 | end;
|
|---|
| 958 | if uix >= 0 then
|
|---|
| 959 | begin
|
|---|
| 960 | RemoveUnit_UpdateMap(p, uix);
|
|---|
| 961 | inc(Flags, chUnitLost);
|
|---|
| 962 | end
|
|---|
| 963 | end
|
|---|
| 964 | end;
|
|---|
| 965 |
|
|---|
| 966 | if GTestFlags and tfImmImprove <> 0 then
|
|---|
| 967 | Prod := CityProjectCost;
|
|---|
| 968 | DoProd := (Project and (cpImp + cpIndex) <> cpImp + imTrGoods) and
|
|---|
| 969 | (Prod >= CityProjectCost);
|
|---|
| 970 |
|
|---|
| 971 | // check if wonder already built
|
|---|
| 972 | if (Project and cpImp <> 0) and (Project and cpIndex < 28) and
|
|---|
| 973 | (GWonder[Project and cpIndex].CityID <> -1) then
|
|---|
| 974 | begin
|
|---|
| 975 | inc(Flags, chOldWonder);
|
|---|
| 976 | DoProd := false;
|
|---|
| 977 | end;
|
|---|
| 978 |
|
|---|
| 979 | // check if producing settlers would disband city
|
|---|
| 980 | if DoProd and (Project and (cpImp or cpDisbandCity) = 0) and
|
|---|
| 981 | ((Size + SizeMod - 2 < 2) and
|
|---|
| 982 | (Model[Project and cpIndex].Kind = mkSettler) or (Size + SizeMod - 1 < 2)
|
|---|
| 983 | and ((Model[Project and cpIndex].Kind = mkSlaves) or
|
|---|
| 984 | (Project and cpConscripts <> 0))) then
|
|---|
| 985 | begin
|
|---|
| 986 | inc(Flags, chNoSettlerProd);
|
|---|
| 987 | DoProd := false;
|
|---|
| 988 | end;
|
|---|
| 989 |
|
|---|
| 990 | if DoProd then
|
|---|
| 991 | begin { project complete }
|
|---|
| 992 | dec(Prod, CityProjectCost);
|
|---|
| 993 | if Project and cpImp = 0 then { produce unit }
|
|---|
| 994 | begin
|
|---|
| 995 | if nUn < numax then
|
|---|
| 996 | begin
|
|---|
| 997 | CreateUnit(p, Project and cpIndex);
|
|---|
| 998 | Un[nUn - 1].Loc := Loc;
|
|---|
| 999 | with Un[nUn - 1] do
|
|---|
| 1000 | begin
|
|---|
| 1001 | Home := cix;
|
|---|
| 1002 | if (Model[mix].Domain < dSea) and (Built[imElite] = 1) then
|
|---|
| 1003 | Exp := ExpCost * (nExp - 1) { elite }
|
|---|
| 1004 | else if (Model[mix].Domain < dSea) and (Built[imBarracks] = 1) or
|
|---|
| 1005 | (Model[mix].Domain = dSea) and (Built[imDockyard] = 1) or
|
|---|
| 1006 | (Model[mix].Domain = dAir) and (Built[imAirport] = 1) then
|
|---|
| 1007 | Exp := ExpCost * 2; { vet }
|
|---|
| 1008 | if Project and cpConscripts <> 0 then
|
|---|
| 1009 | Flags := Flags or unConscripts
|
|---|
| 1010 | end;
|
|---|
| 1011 | PlaceUnit(p, nUn - 1);
|
|---|
| 1012 | UpdateUnitMap(Loc);
|
|---|
| 1013 | if Model[Project and cpIndex].Kind = mkSettler then
|
|---|
| 1014 | dec(SizeMod, 2) { settler produced - city shrink }
|
|---|
| 1015 | else if (Model[Project and cpIndex].Kind = mkSlaves) or
|
|---|
| 1016 | (Project and cpConscripts <> 0) then
|
|---|
| 1017 | dec(SizeMod); { slaves/conscripts produced - city shrink }
|
|---|
| 1018 | end;
|
|---|
| 1019 | Project0 := Project or cpRepeat or cpCompleted;
|
|---|
| 1020 | end
|
|---|
| 1021 | else if Imp[Project and cpIndex].Kind = ikShipPart then
|
|---|
| 1022 | begin { produce ship parts }
|
|---|
| 1023 | inc(GShip[p].Parts[Project and cpIndex - imShipComp]);
|
|---|
| 1024 | Project0 := Project or cpCompleted;
|
|---|
| 1025 | end
|
|---|
| 1026 | else { produce improvement }
|
|---|
| 1027 | begin
|
|---|
| 1028 | NewImp := Project and cpIndex;
|
|---|
| 1029 | inc(Money, Prod); { change rest to money }
|
|---|
| 1030 | Project0 := Project or cpCompleted;
|
|---|
| 1031 | Project := cpImp + imTrGoods;
|
|---|
| 1032 | Prod := 0;
|
|---|
| 1033 |
|
|---|
| 1034 | if Imp[NewImp].Kind in [ikNatLocal, ikNatGlobal] then
|
|---|
| 1035 | begin // nat. project
|
|---|
| 1036 | for i := 0 to nCity - 1 do
|
|---|
| 1037 | if (City[i].Loc >= 0) and (City[i].Built[NewImp] = 1) then
|
|---|
| 1038 | begin { allowed only once }
|
|---|
| 1039 | inc(Money, Imp[NewImp].Cost * BuildCostMod[Difficulty[p]] div 12);
|
|---|
| 1040 | City[i].Built[NewImp] := 0;
|
|---|
| 1041 | end;
|
|---|
| 1042 | NatBuilt[NewImp] := 1;
|
|---|
| 1043 |
|
|---|
| 1044 | // immediate nat. project effects
|
|---|
| 1045 | case NewImp of
|
|---|
| 1046 | imGrWall:
|
|---|
| 1047 | GrWallContinent[p] := Continent[Loc];
|
|---|
| 1048 | end;
|
|---|
| 1049 | end;
|
|---|
| 1050 |
|
|---|
| 1051 | if NewImp < 28 then
|
|---|
| 1052 | begin // wonder
|
|---|
| 1053 | GWonder[NewImp].CityID := ID;
|
|---|
| 1054 | GWonder[NewImp].EffectiveOwner := p;
|
|---|
| 1055 | CheckExpiration(NewImp);
|
|---|
| 1056 |
|
|---|
| 1057 | // immediate wonder effects
|
|---|
| 1058 | case NewImp of
|
|---|
| 1059 | woEiffel:
|
|---|
| 1060 | begin // reactivate wonders
|
|---|
| 1061 | for i := 0 to 27 do
|
|---|
| 1062 | if Imp[i].Expiration >= 0 then
|
|---|
| 1063 | for cix2 := 0 to nCity - 1 do
|
|---|
| 1064 | if (City[cix2].Loc >= 0) and (City[cix2].Built[i] = 1)
|
|---|
| 1065 | then
|
|---|
| 1066 | GWonder[i].EffectiveOwner := p
|
|---|
| 1067 | end;
|
|---|
| 1068 | woLighthouse:
|
|---|
| 1069 | CheckSpecialModels(p, preLighthouse);
|
|---|
| 1070 | woLeo:
|
|---|
| 1071 | begin
|
|---|
| 1072 | inc(Research, TechBaseCost(nTech[p], Difficulty[p]) +
|
|---|
| 1073 | TechBaseCost(nTech[p] + 2, Difficulty[p]));
|
|---|
| 1074 | CheckSpecialModels(p, preLeo);
|
|---|
| 1075 | end;
|
|---|
| 1076 | woPyramids:
|
|---|
| 1077 | CheckSpecialModels(p, preBuilder);
|
|---|
| 1078 | woMir:
|
|---|
| 1079 | begin
|
|---|
| 1080 | for p1 := 0 to nPl - 1 do
|
|---|
| 1081 | if (p1 <> p) and (1 shl p1 and GAlive <> 0) then
|
|---|
| 1082 | begin
|
|---|
| 1083 | if RW[p].Treaty[p1] = trNoContact then
|
|---|
| 1084 | IntroduceEnemy(p, p1);
|
|---|
| 1085 | GiveCivilReport(p, p1);
|
|---|
| 1086 | GiveMilReport(p, p1)
|
|---|
| 1087 | end;
|
|---|
| 1088 | end
|
|---|
| 1089 | end;
|
|---|
| 1090 | end;
|
|---|
| 1091 |
|
|---|
| 1092 | for i := 0 to nImpReplacement - 1 do // sell obsolete buildings
|
|---|
| 1093 | if (ImpReplacement[i].NewImp = NewImp) and
|
|---|
| 1094 | (Built[ImpReplacement[i].OldImp] > 0) then
|
|---|
| 1095 | begin
|
|---|
| 1096 | inc(RW[p].Money, Imp[ImpReplacement[i].OldImp].Cost * BuildCostMod
|
|---|
| 1097 | [Difficulty[p]] div 12);
|
|---|
| 1098 | Built[ImpReplacement[i].OldImp] := 0;
|
|---|
| 1099 | end;
|
|---|
| 1100 |
|
|---|
| 1101 | if NewImp in [imPower, imHydro, imNuclear] then
|
|---|
| 1102 | for i := 0 to nImp - 1 do
|
|---|
| 1103 | if (i <> NewImp) and (i in [imPower, imHydro, imNuclear]) and
|
|---|
| 1104 | (Built[i] > 0) then
|
|---|
| 1105 | begin // sell obsolete power plant
|
|---|
| 1106 | inc(RW[p].Money, Imp[i].Cost * BuildCostMod[Difficulty[p]
|
|---|
| 1107 | ] div 12);
|
|---|
| 1108 | Built[i] := 0;
|
|---|
| 1109 | end;
|
|---|
| 1110 |
|
|---|
| 1111 | Built[NewImp] := 1;
|
|---|
| 1112 | end;
|
|---|
| 1113 | Prod0 := Prod;
|
|---|
| 1114 | inc(Flags, chProduction)
|
|---|
| 1115 | end
|
|---|
| 1116 | else
|
|---|
| 1117 | begin
|
|---|
| 1118 | Project0 := Project0 and not cpCompleted;
|
|---|
| 1119 | if Project0 and not cpAuto <> Project and not cpAuto then
|
|---|
| 1120 | Project0 := Project;
|
|---|
| 1121 | Prod0 := Prod;
|
|---|
| 1122 | end;
|
|---|
| 1123 |
|
|---|
| 1124 | if SizeMod > 0 then
|
|---|
| 1125 | begin
|
|---|
| 1126 | CityGrowth(p, cix);
|
|---|
| 1127 | inc(Flags, chPopIncrease);
|
|---|
| 1128 | end;
|
|---|
| 1129 | result := Size + SizeMod >= 2;
|
|---|
| 1130 | if result then
|
|---|
| 1131 | while SizeMod < 0 do
|
|---|
| 1132 | begin
|
|---|
| 1133 | CityShrink(p, cix);
|
|---|
| 1134 | inc(SizeMod)
|
|---|
| 1135 | end;
|
|---|
| 1136 | end
|
|---|
| 1137 | end; // CityTurn
|
|---|
| 1138 |
|
|---|
| 1139 | {
|
|---|
| 1140 | Tile Access
|
|---|
| 1141 | ____________________________________________________________________
|
|---|
| 1142 | }
|
|---|
| 1143 | function SetCityTiles(p, cix, NewTiles: integer;
|
|---|
| 1144 | TestOnly: boolean = false): integer;
|
|---|
| 1145 | var
|
|---|
| 1146 | V21, Working, ChangeTiles, AddTiles, Loc1: integer;
|
|---|
| 1147 | CityAreaInfo: TCityAreaInfo;
|
|---|
| 1148 | Radius: TVicinity21Loc;
|
|---|
| 1149 | begin
|
|---|
| 1150 | with RW[p].City[cix] do
|
|---|
| 1151 | begin
|
|---|
| 1152 | ChangeTiles := NewTiles xor integer(Tiles);
|
|---|
| 1153 | AddTiles := NewTiles and not Tiles;
|
|---|
| 1154 | if Mode = moPlaying then
|
|---|
| 1155 | begin // do all checks
|
|---|
| 1156 | if NewTiles and not $67F7F76 <> 0 then
|
|---|
| 1157 | begin
|
|---|
| 1158 | result := eInvalid;
|
|---|
| 1159 | exit
|
|---|
| 1160 | end; // invalid tile index included
|
|---|
| 1161 | if NewTiles and (1 shl 13) = 0 then
|
|---|
| 1162 | begin
|
|---|
| 1163 | result := eViolation;
|
|---|
| 1164 | exit
|
|---|
| 1165 | end; // city tile must be exploited
|
|---|
| 1166 | if ChangeTiles = 0 then
|
|---|
| 1167 | begin
|
|---|
| 1168 | result := eNotChanged;
|
|---|
| 1169 | exit
|
|---|
| 1170 | end;
|
|---|
| 1171 | if AddTiles <> 0 then
|
|---|
| 1172 | begin
|
|---|
| 1173 | // check if new tiles possible
|
|---|
| 1174 | GetCityAreaInfo(p, Loc, CityAreaInfo);
|
|---|
| 1175 | for V21 := 1 to 26 do
|
|---|
| 1176 | if AddTiles and (1 shl V21) <> 0 then
|
|---|
| 1177 | if CityAreaInfo.Available[V21] <> faAvailable then
|
|---|
| 1178 | begin
|
|---|
| 1179 | result := eTileNotAvailable;
|
|---|
| 1180 | exit
|
|---|
| 1181 | end;
|
|---|
| 1182 | // not more tiles than inhabitants
|
|---|
| 1183 | Working := 0;
|
|---|
| 1184 | for V21 := 1 to 26 do
|
|---|
| 1185 | if NewTiles and (1 shl V21) <> 0 then
|
|---|
| 1186 | inc(Working);
|
|---|
| 1187 | if Working > Size then
|
|---|
| 1188 | begin
|
|---|
| 1189 | result := eNoWorkerAvailable;
|
|---|
| 1190 | exit
|
|---|
| 1191 | end;
|
|---|
| 1192 | end;
|
|---|
| 1193 | end;
|
|---|
| 1194 | result := eOk;
|
|---|
| 1195 | if not TestOnly then
|
|---|
| 1196 | begin
|
|---|
| 1197 | V21_to_Loc(Loc, Radius);
|
|---|
| 1198 | for V21 := 1 to 26 do
|
|---|
| 1199 | if ChangeTiles and (1 shl V21) <> 0 then
|
|---|
| 1200 | begin
|
|---|
| 1201 | Loc1 := Radius[V21];
|
|---|
| 1202 | assert((Loc1 >= 0) and (Loc1 < MapSize));
|
|---|
| 1203 | if NewTiles and (1 shl V21) <> 0 then
|
|---|
| 1204 | UsedByCity[Loc1] := Loc // employ tile
|
|---|
| 1205 | else if UsedByCity[Loc1] <> Loc then
|
|---|
| 1206 | assert(Mode < moPlaying)
|
|---|
| 1207 | // should only happen during loading, because of wrong sSetCityTiles command order
|
|---|
| 1208 | else
|
|---|
| 1209 | UsedByCity[Loc1] := -1 // unemploy tile
|
|---|
| 1210 | end;
|
|---|
| 1211 | Tiles := NewTiles
|
|---|
| 1212 | end
|
|---|
| 1213 | end;
|
|---|
| 1214 | end;
|
|---|
| 1215 |
|
|---|
| 1216 | procedure GetCityTileAdvice(p, cix: integer; var Advice: TCityTileAdviceData);
|
|---|
| 1217 | const
|
|---|
| 1218 | oFood = 0;
|
|---|
| 1219 | oProd = 1;
|
|---|
| 1220 | oTax = 2;
|
|---|
| 1221 | oScience = 3;
|
|---|
| 1222 | type
|
|---|
| 1223 | TTileData = record
|
|---|
| 1224 | Food, Prod, Trade, SubValue, V21: integer;
|
|---|
| 1225 | end;
|
|---|
| 1226 | var
|
|---|
| 1227 | i, V21, Loc1, nHierarchy, iH, iT, iH_Switch, MinWorking, MaxWorking,
|
|---|
| 1228 | WantedProd, MinFood, MinProd, count, Take, MaxTake, AreaSize, FormulaCode,
|
|---|
| 1229 | NeedRare, RareTiles, cix1, dx, dy, BestTiles, ProdBeforeBoost, TestTiles,
|
|---|
| 1230 | SubPlus, SuperPlus: integer;
|
|---|
| 1231 | SuperValue, BestSuperValue, SubValue, BestSubValue: integer;
|
|---|
| 1232 | Value, BestValue, ValuePlus: extended;
|
|---|
| 1233 | ValueFormula_Weight: array [oFood .. oScience] of extended;
|
|---|
| 1234 | ValueFormula_Multiply: array [oFood .. oScience] of boolean;
|
|---|
| 1235 | Output: array [oFood .. oScience] of integer;
|
|---|
| 1236 | TileInfo, BaseTileInfo: TTileInfo;
|
|---|
| 1237 | Radius, Radius1: TVicinity21Loc;
|
|---|
| 1238 | TestReport: TCityReport;
|
|---|
| 1239 | CityReportEx: TCityReportEx;
|
|---|
| 1240 | CityAreaInfo: TCityAreaInfo;
|
|---|
| 1241 | Hierarchy: array [0 .. 20, 0 .. 31] of TTileData;
|
|---|
| 1242 | nTile, nSelection: array [0 .. 20] of integer;
|
|---|
| 1243 | SubCriterion: array [0 .. 27] of integer;
|
|---|
| 1244 | FoodWasted, FoodToTax, ProdToTax, RareOK, NeedStep2, IsBest: boolean;
|
|---|
| 1245 | begin
|
|---|
| 1246 | if (RW[p].Government = gAnarchy) or (RW[p].City[cix].Flags and chCaptured <> 0)
|
|---|
| 1247 | then
|
|---|
| 1248 | begin
|
|---|
| 1249 | FillChar(Advice.CityReport, SizeOf(Advice.CityReport), 0);
|
|---|
| 1250 | Advice.Tiles := 1 shl CityOwnTile;
|
|---|
| 1251 | Advice.CityReport.HypoTiles := 1 shl CityOwnTile;
|
|---|
| 1252 | exit;
|
|---|
| 1253 | end;
|
|---|
| 1254 |
|
|---|
| 1255 | for i := oFood to oScience do
|
|---|
| 1256 | begin // decode evaluation formula from weights parameter
|
|---|
| 1257 | FormulaCode := Advice.ResourceWeights shr (24 - 8 * i) and $FF;
|
|---|
| 1258 | ValueFormula_Multiply[i] := FormulaCode and $80 <> 0;
|
|---|
| 1259 | if FormulaCode and $40 <> 0 then
|
|---|
| 1260 | ValueFormula_Weight[i] := (FormulaCode and $0F) *
|
|---|
| 1261 | (1 shl (FormulaCode and $30 shr 4)) / 16
|
|---|
| 1262 | else
|
|---|
| 1263 | ValueFormula_Weight[i] := (FormulaCode and $0F) *
|
|---|
| 1264 | (1 shl (FormulaCode and $30 shr 4));
|
|---|
| 1265 | end;
|
|---|
| 1266 |
|
|---|
| 1267 | TestReport.HypoTiles := 1 shl CityOwnTile;
|
|---|
| 1268 | TestReport.HypoTax := -1;
|
|---|
| 1269 | TestReport.HypoLux := -1;
|
|---|
| 1270 | GetSmallCityReport(p, cix, TestReport, @CityReportEx);
|
|---|
| 1271 | with RW[p].City[cix] do
|
|---|
| 1272 | begin
|
|---|
| 1273 | V21_to_Loc(Loc, Radius);
|
|---|
| 1274 | FoodToTax := RW[p].Government = gFuture;
|
|---|
| 1275 | ProdToTax := Project and (cpImp + cpIndex) = cpImp + imTrGoods;
|
|---|
| 1276 | FoodWasted := not FoodToTax and (Food = StorageSize[Difficulty[p]]) and
|
|---|
| 1277 | not CanCityGrow(p, cix);
|
|---|
| 1278 |
|
|---|
| 1279 | // sub criteria
|
|---|
| 1280 | for V21 := 1 to 26 do
|
|---|
| 1281 | begin
|
|---|
| 1282 | Loc1 := Radius[V21];
|
|---|
| 1283 | if Loc1 >= 0 then
|
|---|
| 1284 | SubCriterion[V21] := 3360 - (Distance(Loc, Loc1) - 1) * 32 -
|
|---|
| 1285 | V21 xor $15;
|
|---|
| 1286 | end;
|
|---|
| 1287 | for cix1 := 0 to RW[p].nCity - 1 do
|
|---|
| 1288 | if cix1 <> cix then
|
|---|
| 1289 | begin
|
|---|
| 1290 | Loc1 := RW[p].City[cix1].Loc;
|
|---|
| 1291 | if Loc1 >= 0 then
|
|---|
| 1292 | begin
|
|---|
| 1293 | if Distance(Loc, Loc1) <= 10 then
|
|---|
| 1294 | begin // cities overlap -- prefer tiles outside common range
|
|---|
| 1295 | V21_to_Loc(Loc1, Radius1);
|
|---|
| 1296 | for V21 := 1 to 26 do
|
|---|
| 1297 | begin
|
|---|
| 1298 | Loc1 := Radius1[V21];
|
|---|
| 1299 | if (Loc1 >= 0) and (Loc1 < MapSize) and (Distance(Loc, Loc1) <= 5)
|
|---|
| 1300 | then
|
|---|
| 1301 | begin
|
|---|
| 1302 | dxdy(Loc, Loc1, dx, dy);
|
|---|
| 1303 | dec(SubCriterion[(dy + 3) shl 2 + (dx + 3) shr 1], 160);
|
|---|
| 1304 | end
|
|---|
| 1305 | end
|
|---|
| 1306 | end
|
|---|
| 1307 | end
|
|---|
| 1308 | end;
|
|---|
| 1309 |
|
|---|
| 1310 | GetCityAreaInfo(p, Loc, CityAreaInfo);
|
|---|
| 1311 | AreaSize := 0;
|
|---|
| 1312 | for V21 := 1 to 26 do
|
|---|
| 1313 | if CityAreaInfo.Available[V21] = faAvailable then
|
|---|
| 1314 | inc(AreaSize);
|
|---|
| 1315 |
|
|---|
| 1316 | if RW[p].Government = gFundamentalism then
|
|---|
| 1317 | begin
|
|---|
| 1318 | MinWorking := Size;
|
|---|
| 1319 | MaxWorking := Size;
|
|---|
| 1320 | end
|
|---|
| 1321 | else
|
|---|
| 1322 | begin
|
|---|
| 1323 | MinWorking := CityReportEx.TradeProcessing.HappyBase shr 1;
|
|---|
| 1324 | if MinWorking > Size then
|
|---|
| 1325 | MinWorking := Size;
|
|---|
| 1326 | if (RW[p].LuxRate = 0) and not CityReportEx.TradeProcessing.FlexibleLuxury
|
|---|
| 1327 | then
|
|---|
| 1328 | MaxWorking := MinWorking
|
|---|
| 1329 | else
|
|---|
| 1330 | MaxWorking := Size;
|
|---|
| 1331 | end;
|
|---|
| 1332 | if MaxWorking > AreaSize then
|
|---|
| 1333 | begin
|
|---|
| 1334 | MaxWorking := AreaSize;
|
|---|
| 1335 | if MinWorking > AreaSize then
|
|---|
| 1336 | MinWorking := AreaSize;
|
|---|
| 1337 | end;
|
|---|
| 1338 | if TestReport.Support = 0 then
|
|---|
| 1339 | WantedProd := 0
|
|---|
| 1340 | else
|
|---|
| 1341 | WantedProd := 1 + (TestReport.Support * 100 - 1)
|
|---|
| 1342 | div (100 + CityReportEx.ProdProcessing.ProdBonus * 50 +
|
|---|
| 1343 | CityReportEx.ProdProcessing.FutProdBonus);
|
|---|
| 1344 |
|
|---|
| 1345 | // consider resources for ship parts
|
|---|
| 1346 | NeedRare := 0;
|
|---|
| 1347 | if (GTestFlags and tfNoRareNeed = 0) and (Project and cpImp <> 0) then
|
|---|
| 1348 | case Project and cpIndex of
|
|---|
| 1349 | imShipComp:
|
|---|
| 1350 | NeedRare := fCobalt;
|
|---|
| 1351 | imShipPow:
|
|---|
| 1352 | NeedRare := fUranium;
|
|---|
| 1353 | imShipHab:
|
|---|
| 1354 | NeedRare := fMercury;
|
|---|
| 1355 | end;
|
|---|
| 1356 | if NeedRare > 0 then
|
|---|
| 1357 | begin
|
|---|
| 1358 | RareTiles := 0;
|
|---|
| 1359 | for V21 := 1 to 26 do
|
|---|
| 1360 | begin
|
|---|
| 1361 | Loc1 := Radius[V21];
|
|---|
| 1362 | if (Loc1 >= 0) and (Loc1 < MapSize) and
|
|---|
| 1363 | (RealMap[Loc1] and fModern = cardinal(NeedRare)) then
|
|---|
| 1364 | RareTiles := RareTiles or (1 shl V21);
|
|---|
| 1365 | end
|
|---|
| 1366 | end;
|
|---|
| 1367 |
|
|---|
| 1368 | // step 1: sort tiles to hierarchies
|
|---|
| 1369 | nHierarchy := 0;
|
|---|
| 1370 | for V21 := 1 to 26 do // non-rare tiles
|
|---|
| 1371 | if (CityAreaInfo.Available[V21] = faAvailable) and
|
|---|
| 1372 | ((NeedRare = 0) or (1 shl V21 and RareTiles = 0)) then
|
|---|
| 1373 | begin
|
|---|
| 1374 | Loc1 := Radius[V21];
|
|---|
| 1375 | assert((Loc1 >= 0) and (Loc1 < MapSize));
|
|---|
| 1376 | GetTileInfo(p, cix, Loc1, TileInfo);
|
|---|
| 1377 | if V21 = CityOwnTile then
|
|---|
| 1378 | BaseTileInfo := TileInfo
|
|---|
| 1379 | else
|
|---|
| 1380 | begin
|
|---|
| 1381 | iH := 0;
|
|---|
| 1382 | while iH < nHierarchy do
|
|---|
| 1383 | begin
|
|---|
| 1384 | iT := 0;
|
|---|
| 1385 | while (iT < nTile[iH]) and (TileInfo.Food <= Hierarchy[iH, iT].Food)
|
|---|
| 1386 | and (TileInfo.Prod <= Hierarchy[iH, iT].Prod) and
|
|---|
| 1387 | (TileInfo.Trade <= Hierarchy[iH, iT].Trade) and
|
|---|
| 1388 | not((TileInfo.Food = Hierarchy[iH, iT].Food) and
|
|---|
| 1389 | (TileInfo.Prod = Hierarchy[iH, iT].Prod) and
|
|---|
| 1390 | (TileInfo.Trade = Hierarchy[iH, iT].Trade) and
|
|---|
| 1391 | (SubCriterion[V21] >= SubCriterion[Hierarchy[iH, iT].V21])) do
|
|---|
| 1392 | inc(iT);
|
|---|
| 1393 | if (iT = nTile[iH]) // new worst tile in this hierarchy
|
|---|
| 1394 | or ((TileInfo.Food >= Hierarchy[iH, iT].Food)
|
|---|
| 1395 | // new middle tile in this hierarchy
|
|---|
| 1396 | and (TileInfo.Prod >= Hierarchy[iH, iT].Prod) and
|
|---|
| 1397 | (TileInfo.Trade >= Hierarchy[iH, iT].Trade)) then
|
|---|
| 1398 | break; // insert position found!
|
|---|
| 1399 | inc(iH);
|
|---|
| 1400 | end;
|
|---|
| 1401 | if iH = nHierarchy then
|
|---|
| 1402 | begin // need to start new hierarchy
|
|---|
| 1403 | nTile[iH] := 0;
|
|---|
| 1404 | inc(nHierarchy);
|
|---|
| 1405 | iT := 0;
|
|---|
| 1406 | end;
|
|---|
| 1407 | move(Hierarchy[iH, iT], Hierarchy[iH, iT + 1],
|
|---|
| 1408 | (nTile[iH] - iT) * SizeOf(TTileData));
|
|---|
| 1409 | inc(nTile[iH]);
|
|---|
| 1410 | Hierarchy[iH, iT].V21 := V21;
|
|---|
| 1411 | Hierarchy[iH, iT].Food := TileInfo.Food;
|
|---|
| 1412 | Hierarchy[iH, iT].Prod := TileInfo.Prod;
|
|---|
| 1413 | Hierarchy[iH, iT].Trade := TileInfo.Trade;
|
|---|
| 1414 | Hierarchy[iH, iT].SubValue := SubCriterion[V21];
|
|---|
| 1415 | end
|
|---|
| 1416 | end;
|
|---|
| 1417 | if NeedRare <> 0 then
|
|---|
| 1418 | begin // rare tiles need own hierarchy
|
|---|
| 1419 | iH := nHierarchy;
|
|---|
| 1420 | for V21 := 1 to 26 do
|
|---|
| 1421 | if (CityAreaInfo.Available[V21] = faAvailable) and
|
|---|
| 1422 | (1 shl V21 and RareTiles <> 0) then
|
|---|
| 1423 | begin
|
|---|
| 1424 | Loc1 := Radius[V21];
|
|---|
| 1425 | assert((V21 <> CityOwnTile) and (Loc1 >= 0) and (Loc1 < MapSize));
|
|---|
| 1426 | GetTileInfo(p, cix, Loc1, TileInfo);
|
|---|
| 1427 | if iH = nHierarchy then
|
|---|
| 1428 | begin // need to start new hierarchy
|
|---|
| 1429 | nTile[iH] := 0;
|
|---|
| 1430 | inc(nHierarchy);
|
|---|
| 1431 | iT := 0;
|
|---|
| 1432 | end
|
|---|
| 1433 | else
|
|---|
| 1434 | iT := nTile[iH];
|
|---|
| 1435 | inc(nTile[iH]);
|
|---|
| 1436 | Hierarchy[iH, iT].V21 := V21;
|
|---|
| 1437 | Hierarchy[iH, iT].Food := TileInfo.Food; // = 0
|
|---|
| 1438 | Hierarchy[iH, iT].Prod := TileInfo.Prod; // = 1
|
|---|
| 1439 | Hierarchy[iH, iT].Trade := TileInfo.Trade; // = 0
|
|---|
| 1440 | Hierarchy[iH, iT].SubValue := SubCriterion[V21];
|
|---|
| 1441 | end;
|
|---|
| 1442 | end;
|
|---|
| 1443 | if Built[imAlgae] > 0 then
|
|---|
| 1444 | inc(BaseTileInfo.Food, 12);
|
|---|
| 1445 |
|
|---|
| 1446 | // step 2: summarize resources
|
|---|
| 1447 | for iH := 0 to nHierarchy - 1 do
|
|---|
| 1448 | begin
|
|---|
| 1449 | move(Hierarchy[iH, 0], Hierarchy[iH, 1], nTile[iH] * SizeOf(TTileData));
|
|---|
| 1450 | Hierarchy[iH, 0].Food := 0;
|
|---|
| 1451 | Hierarchy[iH, 0].Prod := 0;
|
|---|
| 1452 | Hierarchy[iH, 0].Trade := 0;
|
|---|
| 1453 | Hierarchy[iH, 0].SubValue := 0;
|
|---|
| 1454 | Hierarchy[iH, 0].V21 := 0;
|
|---|
| 1455 | for iT := 1 to nTile[iH] do
|
|---|
| 1456 | begin
|
|---|
| 1457 | inc(Hierarchy[iH, iT].Food, Hierarchy[iH, iT - 1].Food);
|
|---|
| 1458 | inc(Hierarchy[iH, iT].Prod, Hierarchy[iH, iT - 1].Prod);
|
|---|
| 1459 | inc(Hierarchy[iH, iT].Trade, Hierarchy[iH, iT - 1].Trade);
|
|---|
| 1460 | inc(Hierarchy[iH, iT].SubValue, Hierarchy[iH, iT - 1].SubValue);
|
|---|
| 1461 | Hierarchy[iH, iT].V21 := 1 shl Hierarchy[iH, iT].V21 +
|
|---|
| 1462 | Hierarchy[iH, iT - 1].V21;
|
|---|
| 1463 | end;
|
|---|
| 1464 | end;
|
|---|
| 1465 |
|
|---|
| 1466 | // step 3: try all combinations
|
|---|
| 1467 | BestValue := 0.0;
|
|---|
| 1468 | BestSuperValue := 0;
|
|---|
| 1469 | BestSubValue := 0;
|
|---|
| 1470 | BestTiles := 0;
|
|---|
| 1471 | FillChar(nSelection, SizeOf(nSelection), 0);
|
|---|
| 1472 | TestReport.FoodRep := BaseTileInfo.Food;
|
|---|
| 1473 | ProdBeforeBoost := BaseTileInfo.Prod;
|
|---|
| 1474 | TestReport.Trade := BaseTileInfo.Trade;
|
|---|
| 1475 | TestReport.Working := 1;
|
|---|
| 1476 | MinFood := 0;
|
|---|
| 1477 | MinProd := 0;
|
|---|
| 1478 | iH_Switch := nHierarchy;
|
|---|
| 1479 | count := 0;
|
|---|
| 1480 | repeat
|
|---|
| 1481 | // ensure minima
|
|---|
| 1482 | iH := 0;
|
|---|
| 1483 | while (TestReport.Working < MaxWorking) and (iH < iH_Switch) and
|
|---|
| 1484 | ((TestReport.Working < MinWorking) or
|
|---|
| 1485 | (TestReport.FoodRep < TestReport.Eaten) or
|
|---|
| 1486 | (ProdBeforeBoost < WantedProd)) do
|
|---|
| 1487 | begin
|
|---|
| 1488 | assert(nSelection[iH] = 0);
|
|---|
| 1489 | Take := MinWorking - TestReport.Working;
|
|---|
| 1490 | if Take > nTile[iH] then
|
|---|
| 1491 | Take := nTile[iH]
|
|---|
| 1492 | else
|
|---|
| 1493 | begin
|
|---|
| 1494 | if Take < 0 then
|
|---|
| 1495 | Take := 0;
|
|---|
| 1496 | MaxTake := nTile[iH];
|
|---|
| 1497 | if TestReport.Working + MaxTake > MaxWorking then
|
|---|
| 1498 | MaxTake := MaxWorking - TestReport.Working;
|
|---|
| 1499 | while (Take < MaxTake) and
|
|---|
| 1500 | (TestReport.FoodRep + Hierarchy[iH, Take].Food < MinFood) do
|
|---|
| 1501 | inc(Take);
|
|---|
| 1502 | while (Take < MaxTake) and
|
|---|
| 1503 | (ProdBeforeBoost + Hierarchy[iH, Take].Prod < MinProd) do
|
|---|
| 1504 | inc(Take);
|
|---|
| 1505 | end;
|
|---|
| 1506 | nSelection[iH] := Take;
|
|---|
| 1507 | inc(TestReport.Working, Take);
|
|---|
| 1508 | with Hierarchy[iH, Take] do
|
|---|
| 1509 | begin
|
|---|
| 1510 | inc(TestReport.FoodRep, Food);
|
|---|
| 1511 | inc(ProdBeforeBoost, Prod);
|
|---|
| 1512 | inc(TestReport.Trade, Trade);
|
|---|
| 1513 | end;
|
|---|
| 1514 | inc(iH);
|
|---|
| 1515 | end;
|
|---|
| 1516 |
|
|---|
| 1517 | assert((TestReport.Working >= MinWorking) and
|
|---|
| 1518 | (TestReport.Working <= MaxWorking));
|
|---|
| 1519 | if (TestReport.FoodRep >= MinFood) and (ProdBeforeBoost >= MinProd) then
|
|---|
| 1520 | begin
|
|---|
| 1521 | SplitTrade(TestReport.Trade, RW[p].TaxRate, RW[p].LuxRate,
|
|---|
| 1522 | TestReport.Working, CityReportEx.TradeProcessing,
|
|---|
| 1523 | TestReport.Corruption, TestReport.Tax, TestReport.Lux,
|
|---|
| 1524 | TestReport.Science);
|
|---|
| 1525 |
|
|---|
| 1526 | if CityReportEx.BaseHappiness + CityReportEx.BaseControl +
|
|---|
| 1527 | TestReport.Lux + 2 * (Size - TestReport.Working) - 2 *
|
|---|
| 1528 | TestReport.Deployed >= Size then
|
|---|
| 1529 | begin // city is not in disorder -- evaluate combination
|
|---|
| 1530 | inc(count);
|
|---|
| 1531 | if (MinProd < WantedProd) and (ProdBeforeBoost > MinProd) then
|
|---|
| 1532 | begin // no combination reached wanted prod yet
|
|---|
| 1533 | MinProd := ProdBeforeBoost;
|
|---|
| 1534 | if MinProd > WantedProd then
|
|---|
| 1535 | MinProd := WantedProd
|
|---|
| 1536 | end;
|
|---|
| 1537 | if MinProd = WantedProd then
|
|---|
| 1538 | // do not care for food before prod is ensured
|
|---|
| 1539 | if (MinFood < TestReport.Eaten) and (TestReport.FoodRep > MinFood)
|
|---|
| 1540 | then
|
|---|
| 1541 | begin // no combination reached wanted food yet
|
|---|
| 1542 | MinFood := TestReport.FoodRep;
|
|---|
| 1543 | if MinFood > TestReport.Eaten then
|
|---|
| 1544 | MinFood := TestReport.Eaten
|
|---|
| 1545 | end;
|
|---|
| 1546 | BoostProd(ProdBeforeBoost, CityReportEx.ProdProcessing,
|
|---|
| 1547 | TestReport.ProdRep, TestReport.PollRep);
|
|---|
| 1548 | SuperValue := 0;
|
|---|
| 1549 |
|
|---|
| 1550 | // super-criterion A: unit support granted?
|
|---|
| 1551 | if TestReport.ProdRep >= TestReport.Support then
|
|---|
| 1552 | SuperValue := SuperValue or 1 shl 30;
|
|---|
| 1553 |
|
|---|
| 1554 | // super-criterion B: food demand granted?
|
|---|
| 1555 | if TestReport.FoodRep >= TestReport.Eaten then
|
|---|
| 1556 | SuperValue := SuperValue or 63 shl 24
|
|---|
| 1557 | else if TestReport.FoodRep > TestReport.Eaten - 63 then
|
|---|
| 1558 | SuperValue := SuperValue or
|
|---|
| 1559 | (63 - (TestReport.Eaten - TestReport.FoodRep)) shl 24;
|
|---|
| 1560 |
|
|---|
| 1561 | SuperPlus := SuperValue - BestSuperValue;
|
|---|
| 1562 | if SuperPlus >= 0 then
|
|---|
| 1563 | begin
|
|---|
| 1564 | Output[oTax] := TestReport.Tax;
|
|---|
| 1565 | Output[oScience] := TestReport.Science;
|
|---|
| 1566 |
|
|---|
| 1567 | if TestReport.FoodRep < TestReport.Eaten then
|
|---|
| 1568 | Output[oFood] := TestReport.FoodRep
|
|---|
| 1569 | // appreciate what we have, combination will have bad supervalue anyway
|
|---|
| 1570 | else if FoodWasted then
|
|---|
| 1571 | Output[oFood] := 0
|
|---|
| 1572 | else
|
|---|
| 1573 | begin
|
|---|
| 1574 | Output[oFood] := TestReport.FoodRep - TestReport.Eaten;
|
|---|
| 1575 | if FoodToTax or (Size >= NeedAqueductSize) and (Output[oFood] = 1)
|
|---|
| 1576 | then
|
|---|
| 1577 | begin
|
|---|
| 1578 | inc(Output[oTax], Output[oFood]);
|
|---|
| 1579 | Output[oFood] := 0;
|
|---|
| 1580 | end;
|
|---|
| 1581 | end;
|
|---|
| 1582 |
|
|---|
| 1583 | if TestReport.ProdRep < TestReport.Support then
|
|---|
| 1584 | Output[oProd] := TestReport.ProdRep
|
|---|
| 1585 | // appreciate what we have, combination will have bad supervalue anyway
|
|---|
| 1586 | else
|
|---|
| 1587 | begin
|
|---|
| 1588 | if NeedRare > 0 then
|
|---|
| 1589 | begin
|
|---|
| 1590 | RareOK := false;
|
|---|
| 1591 | for iH := 0 to nHierarchy - 1 do
|
|---|
| 1592 | if Hierarchy[iH, nSelection[iH]].V21 and RareTiles <> 0 then
|
|---|
| 1593 | RareOK := true;
|
|---|
| 1594 | if not RareOK then
|
|---|
| 1595 | TestReport.ProdRep := TestReport.Support;
|
|---|
| 1596 | end;
|
|---|
| 1597 | Output[oProd] := TestReport.ProdRep - TestReport.Support;
|
|---|
| 1598 | if ProdToTax then
|
|---|
| 1599 | begin
|
|---|
| 1600 | inc(Output[oTax], Output[oProd]);
|
|---|
| 1601 | Output[oProd] := 0;
|
|---|
| 1602 | end;
|
|---|
| 1603 | end;
|
|---|
| 1604 |
|
|---|
| 1605 | NeedStep2 := false;
|
|---|
| 1606 | Value := 0;
|
|---|
| 1607 | for i := oFood to oScience do
|
|---|
| 1608 | if ValueFormula_Multiply[i] then
|
|---|
| 1609 | NeedStep2 := true
|
|---|
| 1610 | else
|
|---|
| 1611 | Value := Value + ValueFormula_Weight[i] * Output[i];
|
|---|
| 1612 | if NeedStep2 then
|
|---|
| 1613 | begin
|
|---|
| 1614 | if Value > 0 then
|
|---|
| 1615 | Value := ln(Value) + 123;
|
|---|
| 1616 | for i := oFood to oScience do
|
|---|
| 1617 | if ValueFormula_Multiply[i] and (Output[i] > 0) then
|
|---|
| 1618 | Value := Value + ValueFormula_Weight[i] *
|
|---|
| 1619 | (ln(Output[i]) + 123);
|
|---|
| 1620 | end;
|
|---|
| 1621 |
|
|---|
| 1622 | ValuePlus := Value - BestValue;
|
|---|
| 1623 | if (SuperPlus > 0) or (ValuePlus >= 0.0) then
|
|---|
| 1624 | begin
|
|---|
| 1625 | SubValue := (TestReport.FoodRep + ProdBeforeBoost +
|
|---|
| 1626 | TestReport.Trade) shl 18;
|
|---|
| 1627 | TestTiles := 1 shl CityOwnTile;
|
|---|
| 1628 | for iH := 0 to nHierarchy - 1 do
|
|---|
| 1629 | begin
|
|---|
| 1630 | inc(TestTiles, Hierarchy[iH, nSelection[iH]].V21);
|
|---|
| 1631 | inc(SubValue, Hierarchy[iH, nSelection[iH]].SubValue);
|
|---|
| 1632 | end;
|
|---|
| 1633 | IsBest := true;
|
|---|
| 1634 | if (SuperPlus = 0) and (ValuePlus = 0.0) then
|
|---|
| 1635 | begin
|
|---|
| 1636 | SubPlus := SubValue - BestSubValue;
|
|---|
| 1637 | if SubPlus < 0 then
|
|---|
| 1638 | IsBest := false
|
|---|
| 1639 | else if SubPlus = 0 then
|
|---|
| 1640 | begin
|
|---|
| 1641 | assert(TestTiles <> BestTiles);
|
|---|
| 1642 | IsBest := TestTiles > BestTiles
|
|---|
| 1643 | end
|
|---|
| 1644 | end;
|
|---|
| 1645 | if IsBest then
|
|---|
| 1646 | begin
|
|---|
| 1647 | BestSuperValue := SuperValue;
|
|---|
| 1648 | BestValue := Value;
|
|---|
| 1649 | BestSubValue := SubValue;
|
|---|
| 1650 | BestTiles := TestTiles;
|
|---|
| 1651 | TestReport.Happy :=
|
|---|
| 1652 | (CityReportEx.TradeProcessing.HappyBase - Size) div 2 +
|
|---|
| 1653 | TestReport.Lux shr 1;
|
|---|
| 1654 | Advice.CityReport := TestReport;
|
|---|
| 1655 | end
|
|---|
| 1656 | end // if (SuperPlus>0) or (ValuePlus>=0.0)
|
|---|
| 1657 | end // if SuperPlus>=0
|
|---|
| 1658 | end
|
|---|
| 1659 | end;
|
|---|
| 1660 |
|
|---|
| 1661 | // calculate next combination
|
|---|
| 1662 | iH_Switch := 0;
|
|---|
| 1663 | repeat
|
|---|
| 1664 | with Hierarchy[iH_Switch, nSelection[iH_Switch]] do
|
|---|
| 1665 | begin
|
|---|
| 1666 | dec(TestReport.FoodRep, Food);
|
|---|
| 1667 | dec(ProdBeforeBoost, Prod);
|
|---|
| 1668 | dec(TestReport.Trade, Trade);
|
|---|
| 1669 | end;
|
|---|
| 1670 | inc(nSelection[iH_Switch]);
|
|---|
| 1671 | inc(TestReport.Working);
|
|---|
| 1672 | if (nSelection[iH_Switch] <= nTile[iH_Switch]) and
|
|---|
| 1673 | (TestReport.Working <= MaxWorking) then
|
|---|
| 1674 | begin
|
|---|
| 1675 | with Hierarchy[iH_Switch, nSelection[iH_Switch]] do
|
|---|
| 1676 | begin
|
|---|
| 1677 | inc(TestReport.FoodRep, Food);
|
|---|
| 1678 | inc(ProdBeforeBoost, Prod);
|
|---|
| 1679 | inc(TestReport.Trade, Trade);
|
|---|
| 1680 | end;
|
|---|
| 1681 | break;
|
|---|
| 1682 | end;
|
|---|
| 1683 | dec(TestReport.Working, nSelection[iH_Switch]);
|
|---|
| 1684 | nSelection[iH_Switch] := 0;
|
|---|
| 1685 | inc(iH_Switch);
|
|---|
| 1686 | until iH_Switch = nHierarchy;
|
|---|
| 1687 | until iH_Switch = nHierarchy; // everything tested -- done
|
|---|
| 1688 | end;
|
|---|
| 1689 | assert(BestSuperValue > 0); // advice should always be possible
|
|---|
| 1690 | Advice.Tiles := BestTiles;
|
|---|
| 1691 | Advice.CityReport.HypoTiles := BestTiles;
|
|---|
| 1692 | end; // GetCityTileAdvice
|
|---|
| 1693 |
|
|---|
| 1694 | {
|
|---|
| 1695 | Start/End Game
|
|---|
| 1696 | ____________________________________________________________________
|
|---|
| 1697 | }
|
|---|
| 1698 | procedure InitGame;
|
|---|
| 1699 | var
|
|---|
| 1700 | p, i, mixTownGuard: integer;
|
|---|
| 1701 | begin
|
|---|
| 1702 | MaxDist := Distance(0, MapSize - lx shr 1);
|
|---|
| 1703 | for p := 0 to nPl - 1 do
|
|---|
| 1704 | if (1 shl p and GAlive <> 0) then
|
|---|
| 1705 | with RW[p] do
|
|---|
| 1706 | begin // initialize capital
|
|---|
| 1707 | mixTownGuard := 0;
|
|---|
| 1708 | while Model[mixTownGuard].Kind <> mkSpecial_TownGuard do
|
|---|
| 1709 | inc(mixTownGuard);
|
|---|
| 1710 | with City[0] do
|
|---|
| 1711 | begin
|
|---|
| 1712 | Built[imPalace] := 1;
|
|---|
| 1713 | Size := 4;
|
|---|
| 1714 | for i := 2 to Size do
|
|---|
| 1715 | AddBestCityTile(p, 0);
|
|---|
| 1716 | Project := mixTownGuard;
|
|---|
| 1717 | end;
|
|---|
| 1718 | NatBuilt[imPalace] := 1;
|
|---|
| 1719 | end;
|
|---|
| 1720 | end;
|
|---|
| 1721 |
|
|---|
| 1722 | procedure ReleaseGame;
|
|---|
| 1723 | begin
|
|---|
| 1724 | end;
|
|---|
| 1725 |
|
|---|
| 1726 | end.
|
|---|