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