Home › Dev CE (experimental) › City

Experimental: needs Dev CE (fork of the Community Extension, release zip and source). A GameCore that adds these Lua methods by calling engine functions directly. Not part of the upstream Community Extension, single-player testing only. Descriptions on these pages were written by an AI assistant from decompiled code and are marked inferred unless a test result confirms them.

City

123 methods (Dev CE test build). this is found with the game's own ICity instance resolver (virtual).

Method Signature Purpose (AI-written, inferred) Tested Engine function Current
AddCityAllowedImprovement City:AddCityAllowedImprovement(eImprovement: integer) Appends an improvement type to the city's allowed-improvement list (variable at this+0x1550), growing the vector as needed. plumbing ✓ — 0x12f2b0
AddCityHappinessModifier City:AddCityHappinessModifier(eHappiness: integer, eYield: integer, eGreatPersonClass: integer, iYieldChange: integer, iGreatPersonChange: integer) Appends a happiness modifier record (happiness type, yield, great person class, yield change, great person change) to the city's modifier list. plumbing ✓ City::Instance::AddCityHappinessModifier 0x12f320
AddCityTerrainModifier City:AddCityTerrainModifier(eTerrain: integer, eAdjacentImprovement: integer, eYield: integer, iYieldChange: integer) Appends a (terrain, adjacent improvement, yield, change) record to the city terrain modifier list (this+0x740) if the change is positive and the improvement is not -1. plumbing ✓ — 0x12f3a0
AddCityValidTerrainImprovement City:AddCityValidTerrainImprovement(eImprovement: integer, eTerrain: integer) Appends an (improvement, terrain) pair to the city valid-terrain-improvement list (this+0x770), making the improvement valid on that terrain in this city. plumbing ✓ — 0x12f410
AddYieldPerTerrainClassCitiesImprovement City:AddYieldPerTerrainClassCitiesImprovement(eYield: integer, eImprovement: integer, iDelta: integer) Appends an (improvement, yield, delta) record to the city list at this+0x7a0 (yield per terrain class cities improvement); skipped if improvement or yield is -1. plumbing ✓ — 0x12fd30
AddYieldPerTerrainType City:AddYieldPerTerrainType(eTerrain: integer, eYield: integer, xValue: number (fixed point, 1/256 steps)) Appends a (terrain, yield, fixed-point value) record to the city list at this+0x830 that drives CalculateYieldPerTerrainType. plumbing ✓ — 0x12fda0
ApplyOuterDefenseHealing City:ApplyOuterDefenseHealing(iHPHealed: number (fixed point, 1/256 steps)) → boolean Heals the outer defense damage of all flagged defensible districts in the city by the given amount; returns whether none still has damage. plumbing ✓ — 0x111730
CalculateIdentityPerTurn City:CalculateIdentityPerTurn(eIdentityPlayer: integer) → number Sums identity per turn the city generates for the given player from many sources (martial law, occupation, starvation, trade routes, governor, happiness, religion, influence tokens, free-city bonuses). Decompilation truncated near the end, so the final handling is unseen. plumbing ✓ — 0x114630
CalculateLoyaltyPerTurn City:CalculateLoyaltyPerTurn() → number Sums identity per turn over all players (added for the owner, subtracted for others) plus the loyalty-from-pressure-ratio term. plumbing ✓ — 0x114c80
CalculateYieldFromOwnedBuilding City:CalculateYieldFromOwnedBuilding(eBuildingType: integer, eYield: integer) → number Computes the yield a given building produces for the city: zero if absent or pillaged, otherwise base building yield (power-aware) plus per-era yield bonuses, then yield modifiers, plus district extra regional yield when applicable. Result returned via a hidden out pointer. plumbing ✓ — 0x131670
CalculateYieldPerTerrainType City:CalculateYieldPerTerrainType(eYield: integer) → number For each stored per-terrain yield record matching the yield, counts city-radius plots worked by this city that have the record's terrain and multiplies by the record's value; sums the results. plumbing ✓ — 0x1318d0
CanBuildUnitsOfDomain City:CanBuildUnitsOfDomain(domain: integer) → boolean True if the city has a district of that military domain, or (for domain 0) the city plot passes a coastal check and domain 1 is valid there; domain 2 is always true. plumbing ✓ — 0x131a10
CanPlaceUnit City:CanPlaceUnit(eUnit: integer) → boolean Checks whether the city can place a newly bought or built unit: unit flags may allow it outright; otherwise looks for a valid placement plot in suitable districts (matching military domain, not pillaged or enemy-occupied) and finally the city center via CanPlaceAtLocation. plumbing ✓ — 0x120a80
ChangeAccumulatedIdentity City:ChangeAccumulatedIdentity(ePlayer: integer, xIdentityChange: number (fixed point, 1/256 steps)) For a Free Cities city, adds identity points for a major player (creating a new presence entry if none exists), with the value clamped at zero when decreasing. plumbing ✓ City::CulturalIdentity::ChangeAccumulatedIdentity 0x114fa0
ChangeAllowIncomingRegionalStackingCount City:ChangeAllowIncomingRegionalStackingCount(eYield: integer, iDelta: integer) Adds a delta to a per-yield counter controlling whether the city allows incoming regional stacking for that yield. plumbing ✓
ran ±1, reversible ✓, no visible effect
City::Instance::ChangeAllowIncomingRegionalStackingCount 0x131a90
ChangeCountAlwaysLoyalFlags City:ChangeCountAlwaysLoyalFlags(iDelta: integer) Adds a delta to the counter of always-loyal flags on the city and recalculates the city's conversion trends. plumbing ✓
ran ±1, reversible ✓, no visible effect
City::CulturalIdentity::ChangeCountAlwaysLoyalFlags 0x1150c0
ChangeExtraIdentityPerTurnPerCitizen City:ChangeExtraIdentityPerTurnPerCitizen(xDelta: number (fixed point, 1/256 steps)) Adds a fixed-point delta to the city's extra identity gained per turn per citizen. plumbing ✓
ran ±1, reversible ✓, no visible effect
City::CulturalIdentity::ChangeExtraIdentityPerTurnPerCitizen 0x115100
ChangeFlatYieldBonusForDomestic City:ChangeFlatYieldBonusForDomestic(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a fixed-point delta to the per-yield array entry for flat yield bonus for domestic routes. plumbing ✓ — 0x14da30
ChangeFlatYieldBonusForInternational ✓ City:ChangeFlatYieldBonusForInternational(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a delta to the city's flat yield bonus for international trade routes for one yield type. plumbing ✓
effect ✓ (GetFoodSurplus, GetTurnsUntilGrowth)
City::Trade::ChangeFlatYieldBonusForInternational 0x14da50
ChangeFlatYieldBonusFromOthers City:ChangeFlatYieldBonusFromOthers(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a fixed-point delta to the per-yield array entry for flat yield bonus from other routes. plumbing ✓ — 0x14da80
ChangeFlatYieldBonusToOthers City:ChangeFlatYieldBonusToOthers(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a fixed-point delta to the per-yield array entry for flat yield bonus given to others. plumbing ✓ — 0x14daa0
ChangeFlatYieldBonusToOthersForDomestic City:ChangeFlatYieldBonusToOthersForDomestic(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a fixed-point delta to the per-yield array entry for flat yield bonus to others for domestic routes. plumbing ✓ — 0x14dac0
ChangeFollowerYieldModifier ✓ City:ChangeFollowerYieldModifier(eYield: integer, iDelta: integer) Adds a delta to the city's follower (religion) yield modifier for one yield type and sends an event. plumbing ✓
effect ✓ (GetFoodSurplus)
City::Instance::ChangeFollowerYieldModifier 0x131af0
ChangeGreatWorkYieldModifier City:ChangeGreatWorkYieldModifier(eObjectType: integer, eYield: integer, iYieldChange: integer, iScalingFactor: integer) Adds or removes a great-work yield modifier entry (object type, yield type, flat change, scaling factor) in the city's culture modifier list; a negative change removes the matching entry. plumbing ✓ City::Culture::ChangeGreatWorkYieldModifier 0x11b800
ChangeIdentityPerTurnFromModifiers City:ChangeIdentityPerTurnFromModifiers(xDelta: number (fixed point, 1/256 steps)) Adds a delta to the modifier-based identity per turn and sends a reporting event. plumbing ✓ — 0x115130
ChangeIdentityPressureFromAges City:ChangeIdentityPressureFromAges(xChange: number (fixed point, 1/256 steps)) Adds a fixed-point delta to the identity pressure the city gets from ages. plumbing ✓
ran ±1, reversible ✓, no visible effect
City::CulturalIdentity::ChangeIdentityPressureFromAges 0x1151b0
ChangeIdentityPressureFromModifiers City:ChangeIdentityPressureFromModifiers(xChange: number (fixed point, 1/256 steps)) Adds a fixed-point delta to the identity pressure the city gets from modifiers. plumbing ✓
ran ±1, reversible ✓, no visible effect
City::CulturalIdentity::ChangeIdentityPressureFromModifiers 0x1151e0
ChangeNumForeignRoutesPassingThrough City:ChangeNumForeignRoutesPassingThrough(iChange: integer) Adds a delta to the count of foreign trade routes passing through the city, clamped to at least 0. plumbing ✓ — 0x14dae0
ChangeRequiredPower City:ChangeRequiredPower(xRequiredPower: number (fixed point, 1/256 steps), eBuilding: integer, eProject: integer) Adds a power requirement amount to the city's total required power (floored at 0) and tracks it per building/project in a list. Only acts when building or project is -1 and the amount is non-zero. plumbing ✓ — 0x1471e0
ChangeRequiredPowerFromModifiers City:ChangeRequiredPowerFromModifiers(xRequiredPower: number (fixed point, 1/256 steps)) Adds an amount to the modifier-derived required power (floored at 0) and recalculates the city's power. plumbing ✓ — 0x1472b0
ChangeTourism City:ChangeTourism(eImprovement: integer, eObjectType: integer, bAffectsWonders: boolean, bAffectsReligiousTourism: boolean, iScalingFactor: integer, iModifierID: integer) Adds or removes a tourism modifier entry in the city's culture list (improvement, great work type, wonders/religious flags, scaling factor, modifier id); a negative scaling factor removes matching entries. plumbing ✓ City::Culture::ChangeTourism 0x11b960
ChangeYieldChange ✓ City:ChangeYieldChange(eYield: integer, iDelta: integer) Adds a delta to the city's flat yield bonus for one yield type and sends an event. plumbing ✓
effect ✓ (GetFoodSurplus, GetTurnsUntilGrowth)
City::Instance::ChangeYieldChange 0x131c60
ChangeYieldFromForeignRoutesPassingThrough ✓ City:ChangeYieldFromForeignRoutesPassingThrough(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a delta to the yield the city gets from foreign trade routes passing through it, for one yield type. plumbing ✓
effect ✓ (GetFoodSurplus, GetTurnsUntilGrowth)
City::Trade::ChangeYieldFromForeignRoutesPassingThrough 0x14db00
ChangeYieldModifier ✓ City:ChangeYieldModifier(eYield: integer, iDelta: integer) Adds a delta to the city's percentage yield modifier for one yield type and sends an event. plumbing ✓
effect ✓ (GetFoodSurplus)
City::Instance::ChangeYieldModifier 0x131cf0
ChangeYieldModifierPerGovernorTitle City:ChangeYieldModifierPerGovernorTitle(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a fixed-point delta to a city's per-governor-title yield modifier for one yield and sends an event. plumbing ✓
ran ±1, reversible ✓, no visible effect
City::Instance::ChangeYieldModifierPerGovernorTitle 0x131d80
ChangeYieldPerDestinationLuxuryResourceForInternational ✓ City:ChangeYieldPerDestinationLuxuryResourceForInternational(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a delta to the per-destination-luxury-resource yield modifier for international routes, for one yield type. plumbing ✓
effect ✓ (GetFoodSurplus, GetTurnsUntilGrowth)
City::Trade::ChangeYieldPerDestinationLuxuryResourceForInternational 0x14db30
ChangeYieldPerDestinationStrategicResourceForDomestic ✓ City:ChangeYieldPerDestinationStrategicResourceForDomestic(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a delta to the per-destination-strategic-resource yield modifier for domestic routes, for one yield type. plumbing ✓
effect ✓ (GetFoodSurplus)
City::Trade::ChangeYieldPerDestinationStrategicResourceForDomestic 0x14db60
ChangeYieldPerDestinationStrategicResourceForInternational ✓ City:ChangeYieldPerDestinationStrategicResourceForInternational(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a delta to the per-destination-strategic-resource yield modifier for international routes, for one yield type. plumbing ✓
effect ✓ (GetFoodSurplus)
City::Trade::ChangeYieldPerDestinationStrategicResourceForInternational 0x14db90
ChangeYieldPerLocalBonusResourceForDomestic ✓ City:ChangeYieldPerLocalBonusResourceForDomestic(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a delta to the per-local-bonus-resource yield modifier for domestic routes, for one yield type. plumbing ✓
effect ✓ (GetFoodSurplus, GetTurnsUntilGrowth)
City::Trade::ChangeYieldPerLocalBonusResourceForDomestic 0x14dbc0
ChangeYieldPerLocalBonusResourceForInternational ✓ City:ChangeYieldPerLocalBonusResourceForInternational(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a delta to the per-local-bonus-resource yield modifier for international routes, for one yield type. plumbing ✓
effect ✓ (GetFoodSurplus, GetTurnsUntilGrowth)
City::Trade::ChangeYieldPerLocalBonusResourceForInternational 0x14dbf0
ChangeYieldPerLocalLuxuryResourceForInternational ✓ City:ChangeYieldPerLocalLuxuryResourceForInternational(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a delta to the per-local-luxury-resource yield modifier for international routes, for one yield type. plumbing ✓
effect ✓ (GetFoodSurplus, GetTurnsUntilGrowth)
City::Trade::ChangeYieldPerLocalLuxuryResourceForInternational 0x14dc20
ChangeYieldPerLocalStrategicResourceForInternational ✓ City:ChangeYieldPerLocalStrategicResourceForInternational(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a delta to the per-local-strategic-resource yield modifier for international routes, for one yield type. plumbing ✓
effect ✓ (GetFoodSurplus, GetTurnsUntilGrowth)
City::Trade::ChangeYieldPerLocalStrategicResourceForInternational 0x14dc50
ChangeYieldPerMajorTradePartner City:ChangeYieldPerMajorTradePartner(eYield: integer, xDelta: number (fixed point, 1/256 steps)) Adds a delta to the per-major-trade-partner yield modifier for one yield type. plumbing ✓
ran ±1, reversible ✓, no visible effect
City::Trade::ChangeYieldPerMajorTradePartner 0x14dc80
CheckNotifications City:CheckNotifications() Checks whether required power exceeds available power; if the city is not fully powered by an active project and 10+ turns passed since the last warning, sends a power-shortage notification to the owner. plumbing ✓ — 0x1474f0
CountIncomingRoutes City:CountIncomingRoutes() → number Counts trade routes whose destination is this city via the trade manager. plumbing ✓ — 0x14dcb0
CountOutgoingRoutes City:CountOutgoingRoutes() → number Counts trade routes originating from this city via the trade manager. plumbing ✓ — 0x14dd00
DoBorderExpansion City:DoBorderExpansion() Per-turn culture border growth: if the capability is present and the city is not blocked, adds the city culture yield (scaled by a percent modifier) to the stored culture; when it reaches the next plot cost it annexes the queued or next buyable plot and bumps the plots-acquired counter. Then re-queues the next buyable plot. plumbing ✓ — 0x11bcb0
DoFoundCity City:DoFoundCity() Called when a city is founded: acquires the starting plots (count from GetNumStartingPlots, min 0) and replays influence tokens the owner already received from each player via OnPlayerGaveInfluenceToken. plumbing ✓ — 0x11be40
DoRejectedByPlayer City:DoRejectedByPlayer(ePlayer: integer) Marks a player as having rejected the city: updates or inserts that player's identity presence entry with zero amount and rejected flag, then recalculates conversion trends. plumbing ✓ — 0x115b10
DoTurnActivate City:DoTurnActivate() Per-turn loyalty and identity update; for free cities computes identity pressure changes per player through lambdas and applies them with ChangeAccumulatedIdentity. Decompilation truncated, so the remaining steps are unseen. plumbing ✓ — 0x115be0
GetAccumulatedIdentityPercent City:GetAccumulatedIdentityPercent(ePlayer: integer) → number Returns the share in percent of accumulated identity held by the given player out of the total of all entries. plumbing ✓ — 0x116340
GetBuildingPurchaseCost City:GetBuildingPurchaseCost(ePurchaseYield: integer, eBuilding: integer) → number Purchase cost of a building in the given yield: production cost converted to purchase cost, game-speed scaled, reduced by city, player and religion purchase-discount bonuses, minimum 1, rounded down to a global step. plumbing ✓ — 0x120ed0
GetCityHappinessYieldModifier City:GetCityHappinessYieldModifier(eHappiness: integer, eYield: integer) → number Sums (percent value * 256) over city happiness-yield entries (list at this+0x720) matching the happiness type and yield type. Result is returned via a hidden out pointer, so the decompiled parameter list is register-shifted. plumbing ✓ — 0x132ad0
GetCityTerrainAdjacentImprovementModifier City:GetCityTerrainAdjacentImprovementModifier(eTerrain: integer, eAdjacentImprovement: integer, eYield: integer) → number Sums the stored values (times 256) of city terrain-modifier records (list at this+0x750) matching terrain, adjacent improvement and yield. Result is returned via a hidden out pointer, so the decompiled parameter list is register-shifted. plumbing ✓ — 0x132b10
GetCultureCostNextPlot City:GetCultureCostNextPlot() → number Culture cost of the city's next border plot: (coefficient * plotsAcquired) ^ exponent plus a base value from global parameters, scaled for game speed. plumbing ✓ — 0x11c570
GetCultureYield City:GetCultureYield() → number Returns the owning city's culture yield by forwarding to City::Instance::GetYield. The yield-type argument is not visible in this decompilation (passed in a register). plumbing ✓ — 0x11c5d0
GetDistrictPurchaseCost City:GetDistrictPurchaseCost(ePurchaseYield: integer, eDistrict: integer) → number Purchase cost of a district: player district cost converted to purchase cost, reduced by the city and player purchase-discount bonuses, minimum 1, rounded down to a global step. plumbing ✓ — 0x121030
GetFreePower City:GetFreePower() → number Returns the city's free power, scaled by a percentage bonus (100 + percent) when the percent field is positive. plumbing ✓ — 0x147c50
GetGoldFromCitizens City:GetGoldFromCitizens() → number Returns gold from citizens: the city value at +0x268 times the citizen counter at this+0xa4 in 8-bit fixed point, 0 if the counter is not positive. Result goes through a hidden out pointer. plumbing ✓ — 0x121140
GetGreatWorkTourismModifier City:GetGreatWorkTourismModifier(eObject: integer) → number Starts at 100 and, for every tourism modifier entry whose great-work object type matches, adds (entry value - 100); returns the combined percent. plumbing ✓ — 0x11c600
GetGreatWorkYieldChange City:GetGreatWorkYieldChange(eObject: integer, eYield: integer) → number Scans the city's great-work yield list for the first entry matching object type and yield with a positive flat change, and returns that change; 0 if none. plumbing ✓ — 0x11c630
GetGreatWorkYieldModifier City:GetGreatWorkYieldModifier(eObject: integer, eYield: integer) → number Starts at 100 and multiplies by each matching (object type, yield) entry with a positive percent value / 100; returns the compounded percent. plumbing ✓ — 0x11c660
GetHighestOuterDefenseDamage City:GetHighestOuterDefenseDamage() → number Returns the highest outer defense damage among the city's flagged districts. plumbing ✓ — 0x111800
GetIdentityPerTurnFromGovernor City:GetIdentityPerTurnFromGovernor() → number Returns the identity pressure of the governor assigned to this city, in fixed point; 0 if none. plumbing ✓ — 0x116570
GetIdentityPerTurnFromHappiness City:GetIdentityPerTurnFromHappiness() → number Returns identity per turn change tied to the city's happiness level, 0 for free cities. plumbing ✓ — 0x1165e0
GetIdentityPerTurnFromInfluenceTokens City:GetIdentityPerTurnFromInfluenceTokens() → number For city states, returns the most tokens received times a global parameter; otherwise 0. plumbing ✓ — 0x116660
GetIdentityPerTurnFromMartialLaw City:GetIdentityPerTurnFromMartialLaw() → number If the city is occupied and a defensible district has a garrisoned unit, returns a global parameter plus a player value; otherwise 0. plumbing ✓ — 0x1166f0
GetIdentityPerTurnFromOccupation City:GetIdentityPerTurnFromOccupation() → number Returns the negative of the scaled grievances of the original owner toward this city's owner, clamped between global limits; 0 if the owner is the original or not alive. plumbing ✓ — 0x116b40
GetIdentityPerTurnFromOriginalOwnership City:GetIdentityPerTurnFromOriginalOwnership() → number For free cities returns a global parameter; otherwise 0. plumbing ✓ — 0x116c50
GetIdentityPerTurnFromOwnershipBeforeOccupation City:GetIdentityPerTurnFromOwnershipBeforeOccupation() → number For free cities returns a global parameter; otherwise 0. plumbing ✓ — 0x116d30
GetIdentityPerTurnFromReligion City:GetIdentityPerTurnFromReligion() → number Returns one of two global parameters depending on whether the owner's created religion matches the city's majority religion; 0 if either is none. plumbing ✓ — 0x116d90
GetIdentityPerTurnFromStarvation City:GetIdentityPerTurnFromStarvation() → number Returns a global parameter if the city is starving (turns until starvation not -1), else 0; free cities give 0. plumbing ✓ — 0x116e20
GetIdentityPerTurnFromTradeRoutes City:GetIdentityPerTurnFromTradeRoutes() → number Accumulates identity per turn from outgoing trade routes using the owner's domestic-route origin value, written through an out pointer. plumbing ✓ — 0x116ea0
GetIdentityPerTurnPerCitizen City:GetIdentityPerTurnPerCitizen() → number Computes a per-citizen identity value from civ-wide loyalty per civilian, the capital's value, a global adjustment and the current production project's value, written through an out pointer. plumbing ✓ — 0x116f80
GetIdentityPressureFromOwnership City:GetIdentityPressureFromOwnership(eToPlayer: integer) → number Returns a non-negative global parameter chosen by whether the player is the owner and by a city flag (offset 0x280); 0 for NO_PLAYER. plumbing ✓ — 0x1170c0
GetImprovementTourismModifier City:GetImprovementTourismModifier(eImprovement: integer) → number Starts at 100 and adds (entry value - 100) for each tourism modifier entry that targets the given improvement type. plumbing ✓ — 0x11c6b0
GetLastTurnAnyDistrictDamaged City:GetLastTurnAnyDistrictDamaged() → number Returns the latest turn on which any flagged district was damaged, -100 if none. plumbing ✓ — 0x111890
GetLoyaltyLevel City:GetLoyaltyLevel() → number Maps the city's loyalty value to the loyalty level definition whose range contains it; -1 if none. plumbing ✓ — 0x117410
GetNonreligiousTourism City:GetNonreligiousTourism() → number Sums tourism from great works (non-religious), wonders, improvements, features, districts, a free-power bonus and national park tourism, then applies the owner's tourism modifier percent. plumbing ✓ — 0x11c770
GetNumStartingPlots City:GetNumStartingPlots() → number Number of plots a city starts with: the civilization-level definition's value plus a player offset, plus the game-configured tile count for major players. Returns 0 for a null city or player index -1. plumbing ✓ — 0x11c890
GetReligiousTourism City:GetReligiousTourism() → number Tourism from religion: if the city is its owner's religion holy city, 100 plus religious-tourism modifier entries scaled by a global parameter, plus religious great-work tourism, then the owner's tourism modifier percent. plumbing ✓ — 0x11c940
GetReligiousTourismModifier City:GetReligiousTourismModifier() → number Starts at 100 and adds (entry value - 100) for tourism modifier entries flagged religious (byte at entry+9). plumbing ✓ — 0x11ca40
GetTourism City:GetTourism() → number Total city tourism: GetNonreligiousTourism plus GetReligiousTourism. plumbing ✓ — 0x11ca70
GetTourismFromDistricts City:GetTourismFromDistricts() → number Sums tourism from the city's districts: a per-district value (offset 600) plus tourism adjacency yield modifiers across all yield types. Private method exposed to Lua. plumbing ✓ — 0x11caa0
GetTourismFromFeatures City:GetTourismFromFeatures() → number Counts city-radius plots owned by the same player and worked by this city that have a feature, adding the per-feature tourism value (this+0x20, min 0) for each. Private method exposed to Lua. plumbing ✓ — 0x11cb80
GetTourismFromImprovements City:GetTourismFromImprovements() → number Walks the city-radius plots and, for owned plots with an improvement whose tourism definition passes civic and tech prerequisites, adds tourism from GetTourismFromImprovementOnPlot scaled by the improvement tourism modifier percent. plumbing ✓ — 0x11cd40
GetTurnsLeft City:GetTurnsLeft() → number Estimates turns until the next border plot: computes the plot culture cost (same formula as GetCultureCostNextPlot), the city culture yield and the stored culture, then calls ComputeTurnsLeft. plumbing ✓ — 0x11cef0
GetUnitPurchaseCost City:GetUnitPurchaseCost(ePurchaseYield: integer, eUnit: integer, eFormation: integer) → number Purchase cost of a unit in the given yield and formation: unit production cost converted to purchase cost, reduced by purchase-discount bonuses, adjusted by the owner's unit-cost modifier for non-civilian formation classes, rounded to a global step. plumbing ✓ — 0x1216a0
GetWonderTourismModifier City:GetWonderTourismModifier() → number Starts at 100 and adds (entry value - 100) for tourism modifier entries flagged as wonder (byte at entry+8). plumbing ✓ — 0x11cf80
GetYieldFromBuildings City:GetYieldFromBuildings(eYield: integer) → number Calls CalculateYieldFromBuildings and clamps the result by the optional min and max values it returns, giving the building yield for the yield type. Result is returned via a hidden out pointer, so the decompiled parameter list is register-shifted. plumbing ✓ — 0x133510
GetYieldFromForeignRoutesPassingThrough City:GetYieldFromForeignRoutesPassingThrough(eYield: integer) → number Returns the per-route yield value for a yield type multiplied by the number of foreign routes passing through the city. plumbing ✓ — 0x14de50
GetYieldFromMajorTradePartners City:GetYieldFromMajorTradePartners(eYield: integer) → number If the per-partner yield for the yield type is positive, multiplies it by the number of outgoing major trade partners of this city; otherwise 0. Result is returned via a hidden out pointer, so the decompiled parameter list is register-shifted. plumbing ✓ — 0x133570
GetYieldFromOutgoingTradeRoutes City:GetYieldFromOutgoingTradeRoutes(eYield: integer) → number Asks the trade manager to compute the yield this city gets from its outgoing trade routes for the yield type. Result is returned via a hidden out pointer, so the decompiled parameter list is register-shifted. plumbing ✓ — 0x133600
GetYieldFromPopulation City:GetYieldFromPopulation(eYield: integer) → number Yield from population: per-citizen amounts for science, culture or gold (gold only with a positive counter) from global parameters, plus a per-yield-type per-citizen bonus array times population. Result is returned via a hidden out pointer, so the decompiled parameter list is register-shifted. plumbing ✓ — 0x133660
GetYieldFromTiles City:GetYieldFromTiles(eYield: integer) → number Sums yield of worked plots in city radius (plot yield times workers), plus yield of improved plots outside territory matching improvement-outside-territory definitions when a city flag is set. Result is returned via a hidden out pointer, so the decompiled parameter list is register-shifted. plumbing ✓ — 0x133780
GetYieldPerMajorTradePartner City:GetYieldPerMajorTradePartner(eYield: integer) → number Returns the per-yield value granted for each major trade partner. plumbing ✓ — 0x14e060
GetYieldPerTerrainClassCitiesImprovement City:GetYieldPerTerrainClassCitiesImprovement(eYield: integer, eImprovement: integer) → number Sums the delta of stored records (list at this+0x7b0) matching the yield and improvement. plumbing ✓ — 0x133920
HasActiveTradingPost City:HasActiveTradingPost(ePlayer: integer) → boolean Returns true if the city has a trading post flag for the player and the city owner is not at war with that player. plumbing ✓ — 0x14e0a0
HasBeenRejectedByPlayer City:HasBeenRejectedByPlayer(ePlayer: integer) → boolean Returns whether the player's identity presence entry has the rejected flag. plumbing ✓ — 0x1180e0
HasCityTerrainAdjacentImprovementModifier City:HasCityTerrainAdjacentImprovementModifier(eTerrain: integer, eYield: integer) → boolean True if any city terrain-modifier record matches the terrain and yield. plumbing ✓ — 0x133950
HasDistrict City:HasDistrict() → boolean Returns true if a district exists at the city's own plot (the city center district). plumbing ✓ — 0x1339b0
HasInactiveTradingPost City:HasInactiveTradingPost(ePlayer: integer) → boolean Returns true if a trading post flag is set for the player but is not active, such as when the owner is at war with that player. plumbing ✓ — 0x14e100
IsAllowIncomingRegionalStacking City:IsAllowIncomingRegionalStacking(eYield: integer) → boolean Checks whether incoming regional yield stacking is allowed for a yield, using a per-yield array with a fallback default value. plumbing ✓ — 0x134620
IsAlwaysFullyLoyal City:IsAlwaysFullyLoyal() → boolean True if a stored always-loyal counter is positive or the location check says so. plumbing ✓ — 0x118320
IsCityState City:IsCityState() → boolean Returns true if the city's owner player has the city-state civilization level. plumbing ✓ — 0x134670
IsFullyPoweredByActiveProject City:IsFullyPoweredByActiveProject() → boolean Returns true if the city's current production project exists and its definition links to a government record with two flags set, meaning the project fully powers the city. plumbing ✓ — 0x147e10
IsOccupied City:IsOccupied(ignoreNoPenalty: boolean) → boolean Returns the city's occupied flag, unless the owner has a no-penalty flag set and the caller does not ask to ignore it. plumbing ✓ — 0x1346b0
RecalculatePower City:RecalculatePower() Recomputes how much power a city needs: zeroes the required total, re-adds power requirements of non-pillaged buildings, the current production project and extra amounts, then signals whether the city is powered and sends an event when power balance sign changes. plumbing ✓ City::Power::RecalculatePower 0x147e80
RemoveCityAllowedImprovement City:RemoveCityAllowedImprovement(eImprovement: integer) Removes the first occurrence of an improvement type from the city's allowed-improvement list by rebuilding the vector without it. plumbing ✓ — 0x134790
RemoveCityHappinessModifier City:RemoveCityHappinessModifier(eHappiness: integer, eYield: integer, eGreatPersonClass: integer, iYieldChange: integer, iGreatPersonChange: integer) Rebuilds the city's happiness modifier list, intended to drop a matching modifier record. plumbing ✓ City::Instance::RemoveCityHappinessModifier 0x1349b0
RemoveCityTerrainModifier City:RemoveCityTerrainModifier(eTerrain: integer, eAdjacentImprovement: integer, eYield: integer, iYieldChange: integer) Removes the first matching entry from the city's terrain-modifier list. Does nothing unless iYieldChange > 0 and eAdjacentImprovement is valid. plumbing ✓ — 0x134b10
RemoveCityValidTerrainImprovement City:RemoveCityValidTerrainImprovement(eImprovement: integer, eTerrain: integer) Removes the first entry matching the improvement or terrain from the city's valid terrain-improvement list. plumbing ✓ — 0x134c90
RemoveDynamicAdjacencyBonus City:RemoveDynamicAdjacencyBonus(eDistrict: integer, eTerrain: integer, eFeature: integer, bIsRiver: boolean, iAppeal: integer, bAdjacentDistrict: boolean, eYield: integer) Removes matching dynamic adjacency bonus entries from the city's list. plumbing ✓ City::Instance::RemoveDynamicAdjacencyBonus 0x134d90
RemoveImprovementAdjacencyBonus City:RemoveImprovementAdjacencyBonus(eDistrict: integer, eImprovement: integer, eYield: integer) Erases all dynamic adjacency bonus entries in the city that match the given district, improvement and yield. plumbing ✓ — 0x134e50
RemoveYieldPerTerrainClassCitiesImprovement City:RemoveYieldPerTerrainClassCitiesImprovement(eYield: integer, eImprovement: integer, iDelta: integer) Removes the first matching entry from the city's yield-per-terrain-class improvement list. plumbing ✓ — 0x134ee0
RemoveYieldPerTerrainType City:RemoveYieldPerTerrainType(eTerrain: integer, eYield: integer, xValue: number (fixed point, 1/256 steps)) Erases all entries matching terrain, yield and value from the city's yield-per-terrain-type list. plumbing ✓ — 0x135010
ResetAccumulatedIdentity City:ResetAccumulatedIdentity() Clears the accumulated identity list by resetting its end pointer to the start. plumbing ✓ — 0x118590
ResetCache City:ResetCache() Resizes and clears the city's per-yield cached values so they will be recomputed. plumbing ✓ City::Instance::ResetCache 0x135370
ResetTemporaryPower City:ResetTemporaryPower() Zeroes the temporary power value and clears the entries in two per-item lists. plumbing ✓ — 0x1481a0
SetBuildingFaithPurchaseByDistrict City:SetBuildingFaithPurchaseByDistrict(eDistrict: integer, bNewValue: boolean) Enables or disables faith purchasing for every building that belongs to a given district type by adjusting a per-building counter. plumbing ✓ City::Gold::SetBuildingFaithPurchaseByDistrict 0x121c20
SetComponentID City:SetComponentID(eOwner: integer, id: integer) Assigns the city's owner and id fields and updates the object's archive ID. plumbing ✓ — 0x1357f0
SetOccupied City:SetOccupied(bNewValue: boolean) Sets the city's occupied flag and sends an event if the stored value actually changed. plumbing ✓ City::Instance::SetOccupied 0x135a30
SetSiegeProtection City:SetSiegeProtection(bProtected: boolean) Sets the city's siege-protection flag, then re-applies the district's current besieged status so the siege state refreshes. plumbing ✓ City::Combat::SetSiegeProtection 0x111b10

Details

AddCityAllowedImprovement

Arguments: eImprovement — improvement type to allow in this city

Writes - city allowed-improvement list (this+0x1550)

Input checks: No validation (no -1 check, no duplicate check).

Multiplayer: may-desync, writes synchronised city state. Risk: medium (modifies replicated city data; appends without de-duplication). Confidence of the reading: medium.

AddCityHappinessModifier

Arguments: eHappiness — happiness state the modifier applies to; eYield — yield affected; eGreatPersonClass — great person class affected; iYieldChange — yield change; must be >0 unless iGreatPersonChange >0; iGreatPersonChange — great person point change

Writes - 20-byte modifier record appended to the vector held in the city's auto variable at this+0x710

Side effects - may reallocate the vector

Input checks: Silently does nothing unless iYieldChange > 0 or iGreatPersonChange > 0. Enum values are stored unchecked and not deduplicated.

Preconditions - game thread - gameplay state

Multiplayer: safe-deterministic. Risk: low (Append to a synchronised auto variable; no validation of enums.). Confidence of the reading: high.

Verified from the code - Returns without effect when both change values are not positive - Writes through FAutoVariable<VariantMap>::edit at this+0x710 and appends five 4-byte fields - Record type is typed as BeliefYield in symbols but the field is City happiness modifiers

Inferred - Record semantic is 'when city is in this happiness state, add yield/GP'

Open questions - How RemoveCityHappinessModifier matches records (see that function)

AddCityTerrainModifier

Arguments: eTerrain — terrain type the modifier applies to; eAdjacentImprovement — adjacent improvement required; eYield — yield type changed; iYieldChange — yield amount, must be > 0

Writes - city terrain modifier list (this+0x740)

Input checks: Silently ignores non-positive change and improvement -1; terrain and yield unchecked.

Multiplayer: may-desync, writes synchronised city state. Risk: medium (modifies replicated city data; appends without de-duplication). Confidence of the reading: medium.

AddCityValidTerrainImprovement

Arguments: eImprovement — improvement type; eTerrain — terrain type where it becomes valid

Writes - city valid terrain-improvement list (this+0x770)

Input checks: Silently ignores either argument being -1; no duplicate check.

Multiplayer: may-desync, writes synchronised city state. Risk: medium (modifies replicated city data; appends without de-duplication). Confidence of the reading: medium.

AddYieldPerTerrainClassCitiesImprovement

Arguments: eYield — yield type; eImprovement — improvement type; iDelta — yield amount added (inferred)

Writes - city yield-per-terrain-class list (this+0x7a0)

Input checks: Silently ignores -1 improvement or yield; delta unchecked.

Multiplayer: may-desync, writes synchronised city state. Risk: medium (modifies replicated city data; appends without de-duplication). Confidence of the reading: medium.

AddYieldPerTerrainType

Arguments: eTerrain — terrain type; eYield — yield type; xValue — fixed-point yield per matching plot (passed by pointer)

Writes - city yield-per-terrain-type list (this+0x830)

Input checks: No validation at all (no -1 or range check).

Multiplayer: may-desync, writes synchronised city state. Risk: medium (modifies replicated city data; appends without de-duplication). Confidence of the reading: medium.

ApplyOuterDefenseHealing

Arguments: iHPHealed — Fixed-point amount of HP to heal

Writes - Outer defense damage of each flagged district (ChangeDamage by negative amount)

Input checks: Skips null districts and those not flagged at offset 0x3f8; amount not validated.

Multiplayer: may-desync, modifies district damage. Risk: medium (Writes district damage). Confidence of the reading: high.

CalculateIdentityPerTurn

Arguments: eIdentityPlayer — Player whose identity per turn is calculated

Input checks: Returns 0 for NO_PLAYER; rest truncated.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: medium.

CalculateLoyaltyPerTurn

Input checks: No inputs.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

CalculateYieldFromOwnedBuilding

Arguments: eBuildingType — building type to evaluate (inferred); eYield — yield type to compute (inferred)

Input checks: Checks HasBuilding, pillaged state and null definition; argument mapping in the decompilation is register-shifted, so which argument is which is uncertain.

Multiplayer: read-only, computation (flagged writes are local temporaries). Risk: low (pure getter). Confidence of the reading: low.

CalculateYieldPerTerrainType

Arguments: eYield — yield type to compute

Input checks: Skips null plots and plots worked by another city.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

CanBuildUnitsOfDomain

Arguments: domain — domain type (numeric)

Input checks: No range check on domain; domain 2 short-circuits to true.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: medium.

CanPlaceUnit

Arguments: eUnit — unit type to place

Input checks: Null city returns false; an out-of-range unit index gives a null definition that is dereferenced unchecked; plot coordinates below -9999 treated as invalid.

Multiplayer: read-only, placement query. Risk: low (pure getter). Confidence of the reading: medium.

ChangeAccumulatedIdentity

Arguments: ePlayer — major player whose identity changes; xIdentityChange — identity delta (raw/256)

Writes - per-player identity presence list at this+0xc8 (new entry appended or existing amount changed)

Side effects - may grow the presence vector

Input checks: Does nothing unless the city's owner is Free Cities and ePlayer is major. New entries only created for positive deltas; existing entries below 0 clamp to 0; entries with the flag byte set are not changed.

Preconditions - city owned by Free Cities - valid player id - game thread

Multiplayer: may-desync: direct state edit; run on all clients. Risk: medium (EditPlayer on unchecked player id). Confidence of the reading: medium.

Verified from the code - gates on owner IsFreeCities and param IsMajor - entries are 12 bytes (player, amount, flag byte) - negative result clamped to 0; positive new entry appended

Inferred - flag byte probably marks a locked/loyal entry

Open questions - flag byte meaning - behaviour when entry search runs to end pointer is partially garbled in decompile

ChangeAllowIncomingRegionalStackingCount

Arguments: eYield — yield type; iDelta — amount added to the counter

Writes - per-yield int at array in auto variable this+0x6b0 (added to), or a fallback int at +0x18 of the container if index beyond its size

Input checks: Silent no-op if eYield is -1 or >= number of yield types. If the index is within the type range but beyond the container length, the delta goes into a fallback field instead.

Preconditions - game thread

Multiplayer: safe-deterministic. Risk: low (Bounds checked counter change.). Confidence of the reading: medium.

Verified from the code - Range check against NUM_YIELD_TYPES - Edits the auto variable at this+0x6b0 and adds iDelta to int[eYield] - Fallback add to container+0x18 when index >= container length at +0x10

Inferred - It is a reference-counted flag for regional (per-region) stacking of yields

Open questions - Purpose of the fallback field at container+0x18

ChangeCountAlwaysLoyalFlags

Arguments: iDelta — change in the number of always-loyal flags

Writes - always-loyal flag count at this+0x1a0 (value at +0x1b0)

Side effects - calls RecalculateConversionTrends

Input checks: None; count can go negative.

Preconditions - valid city - game thread

Multiplayer: may-desync: edits synchronized state. Risk: low (simple counter). Confidence of the reading: medium.

Verified from the code - new value = old + delta stored via the variable's move assignment - then RecalculateConversionTrends

Inferred - flag count above zero means city is always loyal

Open questions - how the count is consumed

ChangeExtraIdentityPerTurnPerCitizen

Arguments: xDelta — amount to add (raw/256)

Writes - extra identity per turn per citizen at this+0x1e8 (value at +0x1f8)

Side effects - none

Input checks: None; unclamped.

Preconditions - valid city - game thread

Multiplayer: may-desync: edits synchronized state. Risk: low (simple value add). Confidence of the reading: high.

Verified from the code - reads old value, adds delta from reference, stores via the variable's move assignment

Inferred - does not recompute trends here

ChangeFlatYieldBonusForDomestic

Arguments: eYield — yield type used as array index; xDelta — fixed-point amount to add

Writes - flat yield bonus for domestic routes (offset 0x68)

Input checks: ignores out-of-range yield index; no other checks

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: high.

ChangeFlatYieldBonusForInternational

Arguments: eYield — yield index; xDelta — amount to add (raw/256)

Writes - per-yield FixedPoint array at this+0x88 (flat bonus, international routes)

Input checks: Bounds checked: index >= array size is silently ignored.

Preconditions - valid city Trade object - yield index within yield count

Multiplayer: may-desync: direct state change without events; must run on all clients. Risk: low (bounds-checked simple add; no recalculation of displayed yields triggered). Confidence of the reading: high.

Verified from the code - unsigned bounds check against vector length - adds raw delta to element

Inferred - array is the international flat bonus table by name

Open questions - whether city yields are refreshed elsewhere

ChangeFlatYieldBonusFromOthers

Arguments: eYield — yield type used as array index; xDelta — fixed-point amount to add

Writes - flat yield bonus from other routes (offset 0x48)

Input checks: ignores out-of-range yield index; no other checks

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: high.

ChangeFlatYieldBonusToOthers

Arguments: eYield — yield type used as array index; xDelta — fixed-point amount to add

Writes - flat yield bonus given to others (offset 0x28)

Input checks: ignores out-of-range yield index; no other checks

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: high.

ChangeFlatYieldBonusToOthersForDomestic

Arguments: eYield — yield type used as array index; xDelta — fixed-point amount to add

Writes - flat yield bonus to others for domestic routes (offset 0x8)

Input checks: ignores out-of-range yield index; no other checks

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: high.

ChangeFollowerYieldModifier

Arguments: eYield — yield type; iDelta — amount to add

Writes - per-yield array at this+0x4d0 (element += iDelta); out-of-range yield writes to a dummy slot

Side effects - sends Reporting::Event 0xef1e2348 with city id and yield

Input checks: Out-of-range yield hits a dummy slot rather than crashing.

Preconditions - gameplay state

Multiplayer: safe-deterministic. Risk: low (Bounds handled additive change). Confidence of the reading: high.

Verified from the code - bounds checked with dummy slot - edit() before write - same event as ChangeYieldChange

Inferred - 'Follower' semantics come from the function name

Open questions - unit of the modifier (percent assumed)

ChangeGreatWorkYieldModifier

Arguments: eObjectType — great work object type; eYield — yield type affected; iYieldChange — flat yield change; iScalingFactor — scaling factor

Writes - modifier vector at this+0x68 (entry of 16 bytes appended or removed)

Side effects - may reallocate the vector

Input checks: If both values are positive an entry is appended; if either is negative, all entries matching type, yield and the negated values are removed (copying the vector); if both are zero nothing happens. No check on type/yield validity.

Preconditions - valid city - game thread

Multiplayer: may-desync: edits synchronized state; run on all clients. Risk: low (contained list edit). Confidence of the reading: medium.

Verified from the code - zero/both-nonpositive-with-a-negative triggers a rebuild of the vector without the entry equal to (type,yield,-change,-scaling) - positive case appends the 4-field entry - mixed positive and negative: positive branch tested first only if both >0

Inferred - note a mixed-sign call (one positive, one negative) is appended, not removed - removal rebuilds by copy and drops all matches

Open questions - whether the mixed-sign case is intended - consumer of the list

ChangeIdentityPerTurnFromModifiers

Arguments: xDelta — Fixed-point amount added to the modifier identity value

Writes - Identity-per-turn-from-modifiers value (this+0x1b8/0x1c8)

Side effects - Reporting::Event::Send for the city and player

Input checks: No validation of the delta.

Multiplayer: may-desync, changes synchronised city state. Risk: medium (Alters loyalty modifier). Confidence of the reading: high.

ChangeIdentityPressureFromAges

Arguments: xChange — amount to add (raw/256)

Writes - identity pressure from ages at this+0xf8 (value at +0x108)

Side effects - none

Input checks: None; unclamped.

Preconditions - valid city - game thread

Multiplayer: may-desync: edits synchronized state. Risk: low (simple value add). Confidence of the reading: high.

Verified from the code - reads old value, adds delta from reference, stores via the variable's move assignment

ChangeIdentityPressureFromModifiers

Arguments: xChange — amount to add (raw/256)

Writes - identity pressure from modifiers at this+0x140 (value at +0x150)

Side effects - none

Input checks: None; unclamped.

Preconditions - valid city - game thread

Multiplayer: may-desync: edits synchronized state. Risk: low (simple value add). Confidence of the reading: high.

Verified from the code - reads old value, adds delta from reference, stores via the variable's move assignment

ChangeNumForeignRoutesPassingThrough

Arguments: iChange — signed change to the count

Writes - foreign routes passing through count (0x230)

Input checks: clamps at 0

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: high.

ChangeRequiredPower

Arguments: xRequiredPower — fixed-point change in required power; eBuilding — building type the requirement belongs to; eProject — project type the requirement belongs to

Writes - total required power (0x58) - per building/project requirement list (0x60..0x70)

Input checks: does nothing unless (eBuilding == -1 or eProject == -1) and amount non-zero; clamps results at 0

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: medium.

ChangeRequiredPowerFromModifiers

Arguments: xRequiredPower — fixed-point change in required power from modifiers

Writes - required power from modifiers (0x5c) - fields updated by RecalculatePower

Side effects - calls RecalculatePower

Input checks: does nothing for zero; clamps at 0

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: high.

ChangeTourism

Arguments: eImprovement — improvement type; eObjectType — great work object type; bAffectsWonders — whether it applies to wonders; bAffectsReligiousTourism — whether it applies to religious tourism; iScalingFactor — scaling factor (positive adds, negative removes); iModifierID — modifier id the entry belongs to

Writes - tourism modifier vector at this+0x30 (20-byte entries appended or removed)

Side effects - may reallocate the vector

Input checks: Positive factor appends; negative removes all entries with the same improvement, object type, both flags and modifier id (the stored factor is not compared); zero does nothing.

Preconditions - valid city - game thread

Multiplayer: may-desync: edits synchronized state. Risk: low (contained list edit). Confidence of the reading: medium.

Verified from the code - removal path copies the vector and skips entries matching improvement, type, both flags and modifier id - append path stores the 20-byte entry

Inferred - vector element type shown as BeliefYield is probably a mislabel

Open questions - the consumer of this list

ChangeYieldChange

Arguments: eYield — yield type; iDelta — amount to add

Writes - per-yield array at this+0x530 (element += iDelta); out-of-range yield writes to a fallback slot

Side effects - sends Reporting::Event 0xef1e2348 with city id and yield (shared event with the modifier setters)

Input checks: Out-of-range or negative yield does not crash: it writes to a dummy slot at offset 0x18 of the map object.

Preconditions - gameplay state

Multiplayer: safe-deterministic. Risk: low (Bounds handled, additive change). Confidence of the reading: high.

Verified from the code - bounds check with dummy slot fallback - event always sent - edit() on the variant map

Inferred - offset +0x530 is a flat yield bonus vs +0x4a0 multiplier

Open questions - which yield calculation reads this array

ChangeYieldFromForeignRoutesPassingThrough

Arguments: eYield — yield index; xDelta — amount to add (raw/256)

Writes - per-yield FixedPoint array at this+0x148

Input checks: Bounds checked: out-of-range yield silently ignored.

Preconditions - valid city Trade object

Multiplayer: may-desync: direct state change; must run on all clients. Risk: low (bounds-checked simple add). Confidence of the reading: high.

Verified from the code - bounds check then raw add to array element

Inferred - meaning taken from the function name

ChangeYieldModifier

Arguments: eYield — yield type; iDelta — amount to add

Writes - per-yield array at this+0x4a0 (element += iDelta); out-of-range yield writes to a dummy slot

Side effects - sends Reporting::Event 0xef1e2348 with city id and yield

Input checks: Out-of-range yield hits a dummy slot rather than crashing.

Preconditions - gameplay state

Multiplayer: safe-deterministic. Risk: low (Bounds handled additive change). Confidence of the reading: high.

Verified from the code - bounds checked with dummy slot - edit() before write - event identical to the other two yield setters

Inferred - modifier is likely a percentage

Open questions - whether yields are recalculated automatically afterwards

ChangeYieldModifierPerGovernorTitle

Arguments: eYield — yield; xDelta — amount to add (raw/256)

Writes - array at this+0x500 element for yield

Side effects - Reporting::Event 0xef1e2348

Input checks: Out-of-range yield index writes to a fallback slot instead of crashing.

Preconditions - gameplay state

Multiplayer: may-desync: must be applied everywhere. Risk: low (bounded fallback). Confidence of the reading: high.

Verified from the code - bounds check with fallback slot - event includes yield

ChangeYieldPerDestinationLuxuryResourceForInternational

Arguments: eYield — yield index; xDelta — amount to add (raw/256)

Writes - per-yield FixedPoint array at this+0xe8

Input checks: Bounds checked: out-of-range yield silently ignored.

Preconditions - valid city Trade object

Multiplayer: may-desync: direct state change; must run on all clients. Risk: low (bounds-checked simple add). Confidence of the reading: high.

Verified from the code - bounds check then raw add to array element

Inferred - meaning taken from the function name

ChangeYieldPerDestinationStrategicResourceForDomestic

Arguments: eYield — yield index; xDelta — amount to add (raw/256)

Writes - per-yield FixedPoint array at this+0x108

Input checks: Bounds checked: out-of-range yield silently ignored.

Preconditions - valid city Trade object

Multiplayer: may-desync: direct state change; must run on all clients. Risk: low (bounds-checked simple add). Confidence of the reading: high.

Verified from the code - bounds check then raw add to array element

Inferred - meaning taken from the function name

ChangeYieldPerDestinationStrategicResourceForInternational

Arguments: eYield — yield index; xDelta — amount to add (raw/256)

Writes - per-yield FixedPoint array at this+0x128

Input checks: Bounds checked: out-of-range yield silently ignored.

Preconditions - valid city Trade object

Multiplayer: may-desync: direct state change; must run on all clients. Risk: low (bounds-checked simple add). Confidence of the reading: high.

Verified from the code - bounds check then raw add to array element

Inferred - meaning taken from the function name

ChangeYieldPerLocalBonusResourceForDomestic

Arguments: eYield — yield index; xDelta — amount to add (raw/256)

Writes - per-yield FixedPoint array at this+0xa8

Input checks: Bounds checked: out-of-range yield silently ignored.

Preconditions - valid city Trade object

Multiplayer: may-desync: direct state change; must run on all clients. Risk: low (bounds-checked simple add). Confidence of the reading: high.

Verified from the code - bounds check then raw add to array element

Inferred - meaning taken from the function name

ChangeYieldPerLocalBonusResourceForInternational

Arguments: eYield — yield index; xDelta — amount to add (raw/256)

Writes - per-yield FixedPoint array at this+0xc8

Input checks: Bounds checked: out-of-range yield silently ignored.

Preconditions - valid city Trade object

Multiplayer: may-desync: direct state change; must run on all clients. Risk: low (bounds-checked simple add). Confidence of the reading: high.

Verified from the code - bounds check then raw add to array element

Inferred - meaning taken from the function name

ChangeYieldPerLocalLuxuryResourceForInternational

Arguments: eYield — yield index; xDelta — amount to add (raw/256)

Writes - per-yield FixedPoint array at this+0x168

Input checks: Bounds checked: out-of-range yield silently ignored.

Preconditions - valid city Trade object

Multiplayer: may-desync: direct state change; must run on all clients. Risk: low (bounds-checked simple add). Confidence of the reading: high.

Verified from the code - bounds check then raw add to array element

Inferred - meaning taken from the function name

ChangeYieldPerLocalStrategicResourceForInternational

Arguments: eYield — yield index; xDelta — amount to add (raw/256)

Writes - per-yield FixedPoint array at this+0x188

Input checks: Bounds checked: out-of-range yield silently ignored.

Preconditions - valid city Trade object

Multiplayer: may-desync: direct state change; must run on all clients. Risk: low (bounds-checked simple add). Confidence of the reading: high.

Verified from the code - bounds check then raw add to array element

Inferred - meaning taken from the function name

ChangeYieldPerMajorTradePartner

Arguments: eYield — yield index; xDelta — amount to add (raw/256)

Writes - per-yield FixedPoint array at this+0x1a8

Input checks: Bounds checked: out-of-range yield silently ignored.

Preconditions - valid city Trade object

Multiplayer: may-desync: direct state change; must run on all clients. Risk: low (bounds-checked simple add). Confidence of the reading: high.

Verified from the code - bounds check then raw add to array element

Inferred - meaning taken from the function name

CheckNotifications

Writes - last notification turn (0xa4)

Side effects - sends a notification with localized text (power required vs available) - reads current game turn

Input checks: checks game pointer non-null; no input

Multiplayer: may-desync, sends notification and writes last-notified turn. Risk: medium (sends notification and writes city state; uses turn). Confidence of the reading: medium.

CountIncomingRoutes

Input checks: returns 0 if no current game

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: high.

CountOutgoingRoutes

Input checks: returns 0 if no current game

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: high.

DoBorderExpansion

Writes - stored culture accumulator (this+0x8) - plots-acquired count (this+0x10) - queued next-plot index (this+0x1c) - plot ownership via AnnexPlot

Side effects - annexes a plot to the city (AnnexPlot)

Input checks: Checks capability hash 0xc7331068, a block flag at this+0x28, null city and null civilization-level definition; does not otherwise validate the queued plot.

Multiplayer: may-desync, changes plot ownership and culture state. Risk: high (writes city culture and plot ownership). Confidence of the reading: medium.

DoFoundCity

Writes - city plot ownership (via AcquirePlots) - culture-side influence-token bookkeeping (via OnPlayerGaveInfluenceToken)

Side effects - acquires plots for the city

Input checks: Clamps a negative starting-plot count to 0; dereferences the owning city without a null check.

Multiplayer: may-desync, acquires plots and changes city state. Risk: high (assigns plot ownership; calling on an established city re-runs founding logic). Confidence of the reading: medium.

DoRejectedByPlayer

Arguments: ePlayer — Player that rejected the city

Writes - Identity presence list entry for ePlayer (amount zeroed, rejected flag set)

Side effects - RecalculateConversionTrends

Input checks: No check of the ePlayer value.

Multiplayer: may-desync, changes city identity state. Risk: medium (Writes presence list). Confidence of the reading: high.

DoTurnActivate

Writes - Accumulated identity per player - Other city identity fields (truncated)

Side effects - Notification (per facts) - Several internal lambdas run

Input checks: Checks free-cities status and player validity; rest truncated.

Multiplayer: may-desync, per-turn city state change. Risk: high (Changes accumulated identity). Confidence of the reading: low.

GetAccumulatedIdentityPercent

Arguments: ePlayer — Player whose share is returned

Input checks: Handles empty or zero total; ePlayer not validated.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetBuildingPurchaseCost

Arguments: ePurchaseYield — yield used to pay (gold branch vs other, e.g. faith); eBuilding — building type to price

Input checks: Null building definition returns 0; no range check on the yield type.

Multiplayer: read-only, cost computation. Risk: low (pure getter). Confidence of the reading: high.

GetCityHappinessYieldModifier

Arguments: eHappiness — happiness type to match (inferred); eYield — yield type to match (inferred)

Input checks: No range checks.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: medium.

GetCityTerrainAdjacentImprovementModifier

Arguments: eTerrain — terrain type to match (inferred); eAdjacentImprovement — adjacent improvement to match (inferred); eYield — yield type to match (inferred)

Input checks: No range checks.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: low.

GetCultureCostNextPlot

Input checks: None; no parameters.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetCultureYield

Input checks: Relies on the owning city pointer being non-null; no checks.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: medium.

GetDistrictPurchaseCost

Arguments: ePurchaseYield — yield used to pay (gold vs other); eDistrict — district type to price

Input checks: Null district definition returns 0; no range check on the yield type.

Multiplayer: read-only, cost computation. Risk: low (pure getter). Confidence of the reading: high.

GetFreePower

Input checks: none

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: high.

GetGoldFromCitizens

Input checks: Counter must be positive; the city pointer is not null-checked.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: medium.

GetGreatWorkTourismModifier

Arguments: eObject — great work object type to match

Input checks: No range check; unmatched type returns 100.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetGreatWorkYieldChange

Arguments: eObject — great work object type to match; eYield — yield type to match

Input checks: No range check; only positive entries count and only the first match is returned.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetGreatWorkYieldModifier

Arguments: eObject — great work object type to match; eYield — yield type to match

Input checks: No range check; non-positive entries are skipped.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetHighestOuterDefenseDamage

Input checks: Skips null or unflagged districts.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetIdentityPerTurnFromGovernor

Input checks: Null-checks governor.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetIdentityPerTurnFromHappiness

Input checks: Free-city check only.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetIdentityPerTurnFromInfluenceTokens

Input checks: Only for city states and a non-zero parameter.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetIdentityPerTurnFromMartialLaw

Input checks: Checks occupied state and garrison.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetIdentityPerTurnFromOccupation

Input checks: Checks the original owner is alive and different.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetIdentityPerTurnFromOriginalOwnership

Input checks: Free-city check only.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetIdentityPerTurnFromOwnershipBeforeOccupation

Input checks: Free-city check only.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetIdentityPerTurnFromReligion

Input checks: Checks both religion values for none.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetIdentityPerTurnFromStarvation

Input checks: Free-city check only.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetIdentityPerTurnFromTradeRoutes

Input checks: Only iterates routes when the per-route value is non-zero.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: medium.

GetIdentityPerTurnPerCitizen

Input checks: Null-checks capital and project definitions.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: medium.

GetIdentityPressureFromOwnership

Arguments: eToPlayer — Player the pressure applies to

Input checks: Returns 0 for NO_PLAYER; clamps to non-negative.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetImprovementTourismModifier

Arguments: eImprovement — improvement type to match

Input checks: No range check; unmatched type returns 100.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetLastTurnAnyDistrictDamaged

Input checks: Skips null or unflagged districts.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetLoyaltyLevel

Input checks: Iterates definitions, skips null.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

GetNonreligiousTourism

Input checks: Reads the owner via the player manager without checking the player index.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetNumStartingPlots

Input checks: Checks null city and player index -1; a null definition falls back to 0.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetReligiousTourism

Input checks: Handles a missing holy city (base 0); does not null-check the owner.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetReligiousTourismModifier

Input checks: None; no parameters.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetTourism

Input checks: None; no parameters.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetTourismFromDistricts

Input checks: Skips null district lookups.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetTourismFromFeatures

Input checks: Skips null plots and plots owned by another player or worked by another city.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetTourismFromImprovements

Input checks: Checks plot ownership, null improvement, null tourism definition, civic and tech requirements.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetTurnsLeft

Input checks: None; no parameters. The flagged writes are only local temporaries.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetUnitPurchaseCost

Arguments: ePurchaseYield — yield used to pay; eUnit — unit type to price; eFormation — formation (normal, corps, army) used for the production cost

Input checks: Checks unit index range and null definition (returns 0); no range check on yield or formation.

Multiplayer: read-only, cost computation. Risk: low (pure getter). Confidence of the reading: high.

GetWonderTourismModifier

Input checks: None; no parameters.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

GetYieldFromBuildings

Arguments: eYield — yield type

Input checks: None visible; cleans up a temporary breakdown vector.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: medium.

GetYieldFromForeignRoutesPassingThrough

Arguments: eYield — yield type used as array index

Input checks: out-of-range index returns 0

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: medium.

GetYieldFromMajorTradePartners

Arguments: eYield — yield type

Input checks: Returns 0 when the per-partner yield is not positive.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: medium.

GetYieldFromOutgoingTradeRoutes

Arguments: eYield — yield type

Input checks: None; delegates entirely to Trade::Manager.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: medium.

GetYieldFromPopulation

Arguments: eYield — yield type

Input checks: Bounds-checks the yield index against the array, otherwise uses a default slot.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: medium.

GetYieldFromTiles

Arguments: eYield — yield type

Input checks: Skips null plots and plots without workers.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: medium.

GetYieldPerMajorTradePartner

Arguments: eYield — yield type used as array index

Input checks: out-of-range index returns 0

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: medium.

GetYieldPerTerrainClassCitiesImprovement

Arguments: eYield — yield type to match; eImprovement — improvement type to match

Input checks: No range checks.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

HasActiveTradingPost

Arguments: ePlayer — player whose trading post is checked

Input checks: returns false for ePlayer out of range or missing owner

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: high.

HasBeenRejectedByPlayer

Arguments: ePlayer — Player to check

Input checks: Not-found returns false.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

HasCityTerrainAdjacentImprovementModifier

Arguments: eTerrain — terrain to match; eYield — yield to match

Input checks: No range checks.

Multiplayer: read-only, pure computation. Risk: low (pure getter). Confidence of the reading: high.

HasDistrict

Input checks: none needed; no inputs

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: high.

HasInactiveTradingPost

Arguments: ePlayer — player whose trading post is checked

Input checks: returns false for ePlayer out of range; flag lookup after war check is unguarded when owner missing

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: medium.

IsAllowIncomingRegionalStacking

Arguments: eYield — yield type index

Input checks: returns false for -1 or index >= NUM_YIELD_TYPES; indices beyond the array use the default field

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: medium.

IsAlwaysFullyLoyal

Input checks: Delegates to IsAlwaysFullyLoyalAtLocation.

Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.

IsCityState

Input checks: none; assumes owner id is valid

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: high.

IsFullyPoweredByActiveProject

Input checks: returns false when no project is in production or definitions are missing

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: low.

IsOccupied

Arguments: ignoreNoPenalty — if true skip the owner's no-penalty check

Input checks: none; owner lookup unchecked

Multiplayer: read-only, pure getter. Risk: low (pure getter). Confidence of the reading: high.

RecalculatePower

Writes - required power total at this+0x58 (zeroed then rebuilt) - this+0x68 reset from this+0x60 - powered flag at this+0xa0 (set to true when newly powered)

Side effects - city-powered signal dispatch (city, bool) - Reporting::Event 0xd210fbfb when surplus/deficit sign changes - calls ChangeRequiredPower per building/project

Input checks: No inputs. Skips signal if there is no current game. Requirement lookups are null-checked.

Preconditions - gameplay state - city must have an owner

Multiplayer: safe-deterministic. Risk: low (pure recalculation of derived state). Confidence of the reading: medium.

Verified from the code - only major players get building/project requirements added - only buildings that exist and are not pillaged contribute - signal sent with the city and a bool - event sent only when sign of (produced minus required) changes between before and after

Inferred - this+0x30 is power produced, +0x8 is a base amount scaled by a percent modifier - fixed-point 8 fractional bits used for requirements

Open questions - exact semantics of fields 0x5c, 0x60, 0x68 - type confusion in Find template names

RemoveCityAllowedImprovement

Arguments: eImprovement — improvement type to remove

Writes - city allowed-improvements list (offset 0x1550)

Input checks: no range check on eImprovement; if absent the list is rebuilt unchanged

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: medium.

RemoveCityHappinessModifier

Arguments: eHappiness — happiness type to match; eYield — yield to match; eGreatPersonClass — great person class to match; iYieldChange — yield change (checked for <0 as the trigger); iGreatPersonChange — great person change

Writes - clears and refills the modifier vector in auto variable at this+0x710

Side effects - allocates a temporary copy of the vector and frees it

Input checks: Does nothing unless iYieldChange < 0 or iGreatPersonChange < 0. Unmatched id combinations leave the list rebuilt as copied.

Preconditions - game thread

Multiplayer: safe-deterministic. Risk: medium (Matching logic looks odd (any one field equal counts as a match; after the first match later records are not re-added), so it may drop more than expected.). Confidence of the reading: low.

Verified from the code - Runs only if either amount is negative - Copies the vector, sets the live vector's end to its begin, then re-adds records - A record is considered matching if happiness OR yield OR great person class equals the argument; once matched, a flag stops all later records being re-added - Non-matching records are re-added only when both amounts differ from the arguments

Inferred - Decompilation may have merged conditions; the intended behaviour is probably removing one exact record - Caller likely passes negated amounts

Open questions - Whether the OR/AND logic is a decompiler artefact or a real game quirk - Why the first matching record and everything after is lost

RemoveCityTerrainModifier

Arguments: eTerrain — terrain type of entry; eAdjacentImprovement — adjacent improvement of entry; eYield — yield type (not used in the match shown) (inferred); iYieldChange — yield amount; must be > 0

Writes - city terrain-modifier list (offset 0x740)

Input checks: requires iYieldChange > 0 and improvement != -1; the match uses OR over terrain/improvement/amount so a loosely matching entry may be removed

Multiplayer: may-desync, modifies synchronised city state; loose match may remove wrong entry. Risk: medium (modifies synchronised city state; loose match may remove wrong entry). Confidence of the reading: medium.

RemoveCityValidTerrainImprovement

Arguments: eImprovement — improvement type; eTerrain — terrain type

Writes - city valid terrain-improvement list (offset 0x770)

Input checks: returns early if either type is -1; match uses OR so one equal field removes an entry

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: medium.

RemoveDynamicAdjacencyBonus

Arguments: eDistrict — district type of the bonus; eTerrain — terrain filter; eFeature — feature filter; bIsRiver — river adjacency; iAppeal — appeal value; bAdjacentDistrict — adjacent district flag; eYield — yield type

Writes - dynamic adjacency bonus vector at this+0x800 (matching elements erased)

Input checks: No validation; non-matches leave list unchanged.

Preconditions - game thread

Multiplayer: may-desync: synced city state. Risk: low (list filter). Confidence of the reading: medium.

Verified from the code - remove-if then erase on vector - match criteria are packed from all 7 parameters

Inferred - matching compares all fields (lambda not shown) - no cache refresh is triggered here

Open questions - exact lambda comparison, whether adjacency yields recalculated elsewhere

RemoveImprovementAdjacencyBonus

Arguments: eDistrict — district type of bonus; eImprovement — improvement type of bonus; eYield — yield type of bonus

Writes - city dynamic adjacency bonus list (offset 0x800)

Input checks: no validation; non-matching input erases nothing

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: high.

RemoveYieldPerTerrainClassCitiesImprovement

Arguments: eYield — yield type; eImprovement — improvement type; iDelta — amount of the entry

Writes - city yield-per-terrain-class improvement list (offset 0x7a0)

Input checks: returns early if yield or improvement is -1; match uses OR over the three fields

Multiplayer: may-desync, modifies synchronised city state; loose OR match. Risk: medium (modifies synchronised city state; loose OR match). Confidence of the reading: medium.

RemoveYieldPerTerrainType

Arguments: eTerrain — terrain type; eYield — yield type; xValue — fixed-point yield value to match

Writes - city yield-per-terrain-type list (offset 0x830)

Input checks: no validation; unmatched input erases nothing

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: high.

ResetAccumulatedIdentity

Writes - Accumulated identity per-player list emptied

Input checks: None.

Multiplayer: may-desync, clears synchronised city state. Risk: medium (Wipes city identity data). Confidence of the reading: high.

ResetCache

Writes - per-yield cached value array at this+0x1950 (capacity at +0x1958, count at +0x1960): all entries marked invalid, count set to number of yields

Side effects - may allocate a bigger block

Input checks: None needed. Protected method.

Preconditions - definitions loaded

Multiplayer: safe-deterministic. Risk: low (Only invalidates a cache.). Confidence of the reading: medium.

Verified from the code - Count comes from yield definitions list size - Grows the vector when capacity is smaller - Sets the validity byte of every 8-byte entry (value+flag) to 0 - Updates the stored count

Inferred - Each entry is a CachedValue of fixed-point with a valid flag

Open questions - The value field is written from an uninitialised local so its content is irrelevant

ResetTemporaryPower

Writes - temporary power (0x30) - list at 0x38..0x40 - list at 0x80..0x88 entries

Input checks: none

Multiplayer: may-desync, modifies synchronised city state. Risk: medium (modifies synchronised city state). Confidence of the reading: medium.

SetBuildingFaithPurchaseByDistrict

Arguments: eDistrict — district type whose buildings are affected; bNewValue — true adds one to each counter, false subtracts one

Writes - per-building int counter array at this+0x50 (+1 or -1 per matching building)

Input checks: No validation. Counters are reference counts, so unbalanced false calls go negative. Building index used unchecked into the array.

Preconditions - definitions loaded - counter array sized for all buildings

Multiplayer: safe-deterministic. Risk: low (Simple counter change; the name says Set but it increments/decrements.). Confidence of the reading: high.

Verified from the code - Iterates all building definitions - Matches when the building's district entry equals eDistrict - Adds or subtracts 1 in an int array at this+0x50 indexed by the building type

Inferred - The array is a faith-purchase enable refcount; nonzero likely means purchasable

Open questions - How the counter is later interpreted (>0?)

SetComponentID

Arguments: eOwner — owner player id; id — city id number

Writes - city id field (0xa8) - city owner field (0xd8) - FAutoArchive id (offset 0x8)

Side effects - calls FAutoArchive::SetID

Input checks: no validation

Multiplayer: may-desync, changes city identity used by archive/networking. Risk: high (changes city identity used by archive/networking). Confidence of the reading: medium.

SetOccupied

Arguments: bNewValue — new occupied flag

Writes - bool at this+0x328 (auto-variable at this+0x318)

Side effects - sends Reporting::Event 0xde2d2813 with city id when value changed

Input checks: No input checks; the event compares old and new stored value.

Preconditions - gameplay state

Multiplayer: safe-deterministic. Risk: low (Single flag write). Confidence of the reading: medium.

Verified from the code - writes through an auto-variable - event only when flag changed

Inferred - occupied means city is under foreign/captured occupation

Open questions - effects of the flag are elsewhere (e.g. yields or loyalty)

SetSiegeProtection

Arguments: bProtected — whether the city is protected from siege

Writes - siege-protection byte at this+0x18 - district siege status (via SetSiegeStatus)

Side effects - district SetSiegeStatus may update visuals/combat state

Input checks: None; assumes a valid city pointer at this+0.

Preconditions - valid city - game thread

Multiplayer: may-desync: edits gameplay state; apply on all clients. Risk: low (single flag plus status refresh). Confidence of the reading: medium.

Verified from the code - stores the bool at this+0x18 - reads district IsBesieged then calls SetSiegeStatus on the editable district with the result

Inferred - IsBesieged now takes the new protection flag into account so the status may flip

Open questions - whether SetSiegeStatus triggers notifications