Home › Dev CE (experimental) › CityBuildings

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.

CityBuildings

27 methods (Dev CE test build). this is found with the game's own ICityBuildings instance resolver (plain).

Method Signature Purpose (AI-written, inferred) Tested Engine function Current
AddGreatWork CityBuildings:AddGreatWork(iIndex: integer) Places a great work into the first empty compatible slot in the city's buildings, and signals if the building is correctly themed. plumbing ✓
this ✓ (oracle)
City::Buildings::AddGreatWork 0x109290
AddGreatWorkToSlot CityBuildings:AddGreatWorkToSlot(iIndex: integer, eBuilding: integer, iSlot: integer) Places a great work into a slot of a building in the city, using the first empty slot if slot is negative, then checks themed-building bonus. plumbing ✓
this ✓ (oracle)
City::Buildings::AddGreatWorkToSlot 0x1099b0
ChangeWonderYieldChange ✓ CityBuildings:ChangeWonderYieldChange(eYield: integer, iChange: integer) Adds a flat yield delta that applies to wonders in the city, per yield type, keeping a small list of (yield, value) pairs. plumbing ✓
effect ✓ (GetFoodSurplus, GetTurnsUntilGrowth)
this ✓ (oracle)
City::Buildings::ChangeWonderYieldChange 0x109d30
ChangeYieldChange ✓ CityBuildings:ChangeYieldChange(eBuilding: integer, eYield: integer, iChange: integer) Adds a flat yield delta for a specific building in a city, creating or removing the entry as needed. plumbing ✓
effect ✓ (GetFoodSurplus)
this ✓ (oracle)
City::Buildings::ChangeYieldChange 0x109dc0
ChangeYieldChangeCityStates ✓ CityBuildings:ChangeYieldChangeCityStates(eBuilding: integer, eYield: integer, iChange: integer) Same as ChangeYieldChange but for the separate list of per-building flat yield changes tied to city states. plumbing ✓
effect ✓ (GetFoodSurplus)
this ✓ (oracle)
City::Buildings::ChangeYieldChangeCityStates 0x109f10
ChangeYieldChangeFromFeature CityBuildings:ChangeYieldChangeFromFeature(eFeature: integer, eYield: integer, iChange: integer) Adds or removes a flat yield change entry keyed by feature and yield. Positive deltas append a new entry; negative deltas rebuild the list without the matching entry. plumbing ✓
this ✓ (oracle)
City::Buildings::ChangeYieldChangeFromFeature 0x10a060
ChangeYieldModifier CityBuildings:ChangeYieldModifier(eBuilding: integer, eYield: integer, iChange: integer) Adds a delta to a per-building percentage yield modifier entry in a city. Creates the entry if missing and removes it when the sum becomes zero. plumbing ✓
ran ±1, reversible ✓, no visible effect
this ✓ (oracle)
City::Buildings::ChangeYieldModifier 0x10a1d0
CheckForThemedBuilding CityBuildings:CheckForThemedBuilding(eBuilding: integer) If the building is themed correctly, dispatches a game signal with the city instance and the building type (signal on current game at +0x240; Ghidra shows a Unit-based signature, likely a mismatched type). plumbing ✓
this ✓ (oracle)
— 0x10a2c0
GetFreeSlot CityBuildings:GetFreeSlot(eBuilding: integer) → number Finds the first empty great-work slot index in the given building's slot list. plumbing ✓
this ✓ (oracle)
— 0x10b7a0
GetFreeSlotOfType CityBuildings:GetFreeSlotOfType(eBuilding: integer, slotType: integer) → number Finds the first empty slot of a specific great-work slot type in the given building. plumbing ✓
this ✓ (oracle)
— 0x10b800
GetNumBuildings CityBuildings:GetNumBuildings() → number Counts non-wonder buildings (flag 0x40 clear) that exist in the city, using the location array. plumbing ✓
this ✓ (oracle)
— 0x10bab0
GetNumBuildingsAtLocation CityBuildings:GetNumBuildingsAtLocation(iPlotIndex: integer) → number Counts buildings whose recorded plot index equals the given plot index. plumbing ✓
this ✓ (oracle)
— 0x10bb40
GetNumFreeSlots CityBuildings:GetNumFreeSlots(slotType: integer) → number Counts empty great-work slots of a given slot type across all buildings. plumbing ✓
this ✓ (oracle)
— 0x10bbb0
GetNumGreatWorks CityBuildings:GetNumGreatWorks(eGreatWorkObjectTypeFilter: integer) → number Counts great works held in slots, optionally filtered by great work object type (all if filter is -1). plumbing ✓
this ✓ (oracle)
— 0x10bc50
GetNumWonders CityBuildings:GetNumWonders() → number Counts wonders (building flag 0x40 set) that exist in the city. plumbing ✓
this ✓ (oracle)
— 0x10bd40
GetTourismFromGreatWorks CityBuildings:GetTourismFromGreatWorks(bReligious: boolean) → number Sums tourism from great works across all buildings with great-work slots via GetBuildingTourismFromGreatWorks. plumbing ✓
this ✓ (oracle)
— 0x10bdd0
GetTourismFromOneWonder CityBuildings:GetTourismFromOneWonder(eBuilding: integer) → number Computes tourism of a single wonder: global base parameter plus era difference between player's era and wonder's era, scaled by city wonder tourism modifier; returns the base if the global flag is off. plumbing ✓
this ✓ (oracle)
— 0x10be50
GetTourismFromWonders CityBuildings:GetTourismFromWonders() → number Sums tourism over all wonders present in the city that are not flagged in the exclusion array, via GetTourismFromOneWonder. plumbing ✓
this ✓ (oracle)
— 0x10bf80
GetYieldChange CityBuildings:GetYieldChange(eBuilding: integer, eYield: integer) → number Returns total flat yield change of a building for a yield: district-derived yield (if a yield-conversion applies), plus a wonder-specific entry, plus a stored per-building yield modifier. plumbing ✓
this ✓ (oracle)
— 0x10c0e0
GetYieldChangeCityStates CityBuildings:GetYieldChangeCityStates(eBuilding: integer, eYield: integer) → number Returns the stored city-state yield change for a building and yield, or 0 if none. plumbing ✓
this ✓ (oracle)
— 0x10c250
GetYieldChangeFromFeature CityBuildings:GetYieldChangeFromFeature(eFeature: integer, eYield: integer) → number Sums yield change entries matching a feature and yield from the stored list. plumbing ✓
this ✓ (oracle)
— 0x10c290
GetYieldFromGreatWorks CityBuildings:GetYieldFromGreatWorks(eYield: integer) → number Sums yield from great works for a yield type across all buildings with slots via GetBuildingYieldFromGreatWorks. plumbing ✓
this ✓ (oracle)
— 0x10c2d0
GetYieldModifier CityBuildings:GetYieldModifier(eBuilding: integer, eYield: integer) → number Looks up the stored yield modifier percent for a building (mapped to its generic equivalent) and yield; 0 if none. plumbing ✓
this ✓ (oracle)
— 0x10c350
IsInCity CityBuildings:IsInCity(iIndex: integer) → boolean Checks whether the great work with the given list index is held in any building slot of this city. plumbing ✓
this ✓ (oracle)
City::Buildings::IsInCity 0x10cc60
RemoveAllBuildings CityBuildings:RemoveAllBuildings() Removes every building from a city: for each building slot it clears the plot link and wonder status, removes great-work slots, and sends removal events. plumbing ✓
this ✓ (oracle)
City::Buildings::RemoveAllBuildings 0x10cf80
RemoveYieldModifier CityBuildings:RemoveYieldModifier(eBuilding: integer, eYield: integer) Removes the first (building, yield) modifier entry from the city's building yield-modifier list by swapping in the last element. plumbing ✓
this ✓ (oracle)
— 0x10d5c0
SetEraCreatedToGameEra CityBuildings:SetEraCreatedToGameEra(eBuilding: integer) Records the current game era as the era in which a given building was created in this city. plumbing ✓
this ✓ (oracle)
City::Buildings::SetEraCreatedToGameEra 0x10e880

Details

AddGreatWork

Arguments: iIndex — great work list index

Writes - slot entry in building's great-work slot array

Side effects - signal dispatch (city, building) when themed correctly

Input checks: If no valid slot, does nothing. Index not bounds-checked in game culture list.

Preconditions - gameplay state

Multiplayer: may-desync: must be applied everywhere. Risk: medium (unchecked index). Confidence of the reading: medium.

Verified from the code - first empty slot that accepts object type - signal only if themed correctly

Open questions - slot kind 0xffffffff meaning empty

AddGreatWorkToSlot

Arguments: iIndex — great work index; eBuilding — building to hold it; iSlot — slot index, negative = first empty slot

Writes - great work id stored in the building's slot array

Side effects - calls CheckForThemedBuilding(building)

Input checks: Silent return if the building is not in the city, slot out of range, or no empty slot.

Preconditions - building exists in city - game thread

Multiplayer: safe-deterministic. Risk: low (bounds checked). Confidence of the reading: high.

Verified from the code - finds building by type - negative slot picks first slot whose value is -1 - bounds checks slot - assigns and runs theming check

Inferred - does not remove the great work from elsewhere

Open questions - does not check slot type compatibility

ChangeWonderYieldChange

Arguments: eYield — yield type; iChange — delta to add

Writes - list of (yield, value) 8-byte pairs at this+0xb0 (capacity +0xb8, count +0xc0)

Side effects - may grow the vector

Input checks: no check on eYield (a -1 yield is appended); entries are never removed when sum is zero

Preconditions - valid city Buildings

Multiplayer: safe-deterministic. Risk: low (simple list update). Confidence of the reading: medium.

Verified from the code - linear search for matching yield; adds delta if found, else appends

Inferred - entry meaning is yield change for each wonder (from the name)

Open questions - where the list is consumed

ChangeYieldChange

Arguments: eBuilding — building type; eYield — yield type; iChange — delta to add

Writes - list of (building, yield, value) 12-byte entries at this+0x80 (capacity +0x88, count +0x90)

Side effects - entry removed (swap with last) when the sum becomes zero - may grow the vector

Input checks: new entries created only if both ids != -1; otherwise silent no-op

Preconditions - valid city Buildings

Multiplayer: safe-deterministic. Risk: low (id-guarded list edit). Confidence of the reading: high.

Verified from the code - FindYieldChange used to locate entry - append when absent, remove via swap-with-last when value equals -iChange, else add

Inferred - yields are not recomputed here

Open questions - who triggers yield recompute

ChangeYieldChangeCityStates

Arguments: eBuilding — building type; eYield — yield type; iChange — delta to add

Writes - list of (building, yield, value) entries at this+0x98 (capacity +0xa0, count +0xa8)

Side effects - entry removed (swap with last) when the sum becomes zero - may grow the vector

Input checks: new entries only if both ids != -1; otherwise silent no-op

Preconditions - valid city Buildings

Multiplayer: safe-deterministic. Risk: low (id-guarded list edit). Confidence of the reading: medium.

Verified from the code - identical algorithm to ChangeYieldChange on a separate vector at +0x98

Inferred - list name suggests city-state based yield (e.g. per suzerain/envoy)

Open questions - consumer of the list and exact condition

ChangeYieldChangeFromFeature

Arguments: eFeature — feature type; eYield — yield type; iChange — delta (positive adds an entry, negative removes a matching one)

Writes - list of (feature, yield, value) 12-byte entries at this+0xf8 (capacity +0x100, count +0x108)

Side effects - allocates and frees a temporary vector on negative deltas

Input checks: for positive deltas, appends only when feature and yield are not -1 (silent no-op otherwise); entries are not merged, duplicates allowed

Preconditions - valid city Buildings

Multiplayer: safe-deterministic. Risk: medium (negative path appears to only copy to a temp and free it; stored list is not updated in the visible code, possible decompile artifact). Confidence of the reading: low.

Verified from the code - iChange < 0 branch builds a filtered copy skipping the first entry equal to the negated value, then calls operator_delete and returns - iChange >= 0 branch appends a new entry without merging

Inferred - intent is add/remove symmetric entries; negative branch seems not to write the filtered list back (decompile may be incomplete)

Open questions - whether the filtered list is written back in the real code (decompile shows only delete) - whether iChange of 0 appends an empty entry

ChangeYieldModifier

Arguments: eBuilding — building type index; eYield — yield type index; iChange — delta to add to the modifier

Writes - vector of (building, yield, value) 12-byte entries at this+0x68 (capacity at +0x70, count at +0x78)

Side effects - calls RemoveYieldModifier when an existing entry would become zero - may grow the vector

Input checks: new entries are only created if building and yield are not -1; if the entry exists it is updated regardless; if not found and ids invalid, silent no-op

Preconditions - valid city Buildings object - gameplay thread

Multiplayer: safe-deterministic. Risk: low (simple bookkeeping with id guard). Confidence of the reading: high.

Verified from the code - linear search over 12-byte entries comparing first two ints - appends when none found and both ids != -1 - removes via RemoveYieldModifier when existing value == -iChange - else adds iChange

Inferred - value is percent yield modifier from the name - this change is not immediately propagated to city yields (no recompute call seen)

Open questions - whether the caller triggers a yield recompute

CheckForThemedBuilding

Arguments: eBuilding — building type to check

Side effects - Dispatches a game-level signal (themed-building event) when theme is correct

Input checks: No range check; relies on IsBuildingThemedCorrectly.

Multiplayer: may-desync: fires signal handlers that may change state. Risk: medium (signal listeners may alter synchronised state). Confidence of the reading: medium.

GetFreeSlot

Arguments: eBuilding — building type

Input checks: None; returns -1 if building not found.

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

GetFreeSlotOfType

Arguments: eBuilding — building type; slotType — great work slot type required

Input checks: None; returns -1 if not found.

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

GetNumBuildings

Input checks: Bounds-checks index against array size.

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

GetNumBuildingsAtLocation

Arguments: iPlotIndex — plot index to match

Input checks: Bounds-checks against array size; negative entries skipped.

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

GetNumFreeSlots

Arguments: slotType — great work slot type

Input checks: None.

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

GetNumGreatWorks

Arguments: eGreatWorkObjectTypeFilter — object type filter or -1 for all

Input checks: Checks definition index and null; -1 means no filter.

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

GetNumWonders

Input checks: Bounds-checks against array size.

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

GetTourismFromGreatWorks

Arguments: bReligious — whether to count religious great works (inferred)

Input checks: None.

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

GetTourismFromOneWonder

Arguments: eBuilding — wonder building type

Input checks: Range-checks building but does not null-check the definition or era before dereference.

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

GetTourismFromWonders

Input checks: Bounds-checked against array sizes.

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

GetYieldChange

Arguments: eBuilding — building type; eYield — yield type

Input checks: Range-checks building; no null check on the definition before field reads.

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

GetYieldChangeCityStates

Arguments: eBuilding — building type; eYield — yield type

Input checks: None.

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

GetYieldChangeFromFeature

Arguments: eFeature — feature type; eYield — yield type

Input checks: None.

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

GetYieldFromGreatWorks

Arguments: eYield — yield type

Input checks: None.

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

GetYieldModifier

Arguments: eBuilding — building type; eYield — yield type

Input checks: None.

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

IsInCity

Arguments: iIndex — great work list index

Input checks: None.

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

RemoveAllBuildings

Writes - building plot-location array at this+0x8 set to -1 - building flag array at this+0x20 cleared to 0 - array at this+0x38 set to -1 - wonder type on the wonder plot via the improvement builder

Side effects - dispatches a game signal (+0x210) per removed building - calls RemoveGreatWorkSlots - if the building is a nuclear reactor type, calls Fallout::Manager::RemoveNuclearReactor - calls a virtual on Rules::Cities (slot 0xa8) with the building index and plot - sends Reporting::Event 0xe074eef4 per building with plot coordinates

Input checks: No arguments. Index bounds are checked for the definition arrays; null definition pointers are handled in places but one lookup dereferences without a null check.

Preconditions - gameplay state - city must be fully initialised

Multiplayer: may-desync: mass state mutation including map and wonder state. Risk: high (Wipes all buildings, wonders and side data in one call). Confidence of the reading: medium.

Verified from the code - iterates all slots of the building array - skips slots whose value is -1 - sets slot value to -1 after processing - sends one event per removed building

Inferred - the array at +0x8 maps building type to plot id - flag 0x10 at definition+0x159 means wonder - government lookup with bit 8 means nuclear reactor (odd naming)

Open questions - what the Rules::Cities virtual at 0xa8 does - exact role of the government-collection lookup

RemoveYieldModifier

Arguments: eBuilding — building type of the entry to remove; eYield — yield type of the entry to remove

Writes - City::Buildings yield-modifier array (data ptr 0x68, count 0x78): one 12-byte entry removed

Input checks: No range check on types; silently does nothing if no matching entry.

Multiplayer: may-desync, changes city yield modifier data. Risk: medium (alters city yield modifiers without any recalculation call). Confidence of the reading: medium.

SetEraCreatedToGameEra

Arguments: eBuilding — building type index

Writes - per-building era-created 16-bit entry in the array at this+0x38, indexed by building type

Input checks: None. The building index is used unchecked to index the array, so an invalid or negative index writes out of bounds (crash or memory corruption risk).

Preconditions - valid building type index - game running (Eras singleton exists) - game thread

Multiplayer: safe-deterministic. Risk: medium (Unchecked array index; otherwise a trivial deterministic write.). Confidence of the reading: high.

Verified from the code - Calls Game::Eras::Edit and copies a 16-bit value from Eras+0xb8 - Stores it at (this+0x38)[eBuilding] as 2 bytes - No bounds check on the index

Inferred - Eras+0xb8 is the current game era; the array is the per-building created-era table

Open questions - Exact meaning/name of the field at Eras+0xb8