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