Home › Dev CE (experimental) › PlayerCities
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.
PlayerCities
19 methods (Dev CE test build). this is found with the game's own IPlayerCities instance resolver (plain).
| Method |
Signature |
Purpose (AI-written, inferred) |
Tested |
Engine function |
Current |
| AddBuildingReplacementOverride |
PlayerCities:AddBuildingReplacementOverride(eBuildingToReplace: integer, eBuildingOverride: integer) |
Registers a building replacement (one building replaced by another) on the player, then swaps existing buildings in every city and moves their great works. The decompilation is truncated near the end. |
plumbing ✓ |
— |
0x264110 |
| ChangeExtraStartingPopulationOffHomeContinent |
PlayerCities:ChangeExtraStartingPopulationOffHomeContinent(iChange: integer) |
Adds a delta to a player's bonus starting population for cities founded off their home continent. |
plumbing ✓ ran ±1, reversible ✓, no visible effect |
Player::Cities::ChangeExtraStartingPopulationOffHomeContinent |
0x2644d0 |
| CheckUnhandledCityDecisions |
PlayerCities:CheckUnhandledCityDecisions() |
Collects the player's cities that have pending decisions (fields 0x2e0/0x2f8 set). For human players it issues a Destroy command request per city; for AI it resets two request fields to -1. The decompilation is truncated. |
plumbing ✓ |
— |
0x264500 |
| DoEndTurn |
PlayerCities:DoEndTurn() |
If the player has any cities, calls City::Manager::Heal on each city. |
plumbing ✓ |
— |
0x265330 |
| DoSetTurnComplete |
PlayerCities:DoSetTurnComplete(eRequestType: integer) |
For two specific turn request subtypes and a human player, clears unassigned production overflow in all cities. |
plumbing ✓ |
— |
0x2653d0 |
| DoTurnActivate |
PlayerCities:DoTurnActivate() |
Gets the improvements rules object and calls a lambda invoker; the decompilation shows only these two calls, so the real behaviour is unclear. |
plumbing ✓ |
— |
0x265410 |
| GetAICitiesCaptured |
PlayerCities:GetAICitiesCaptured(neverHuman: boolean) → number |
Counts this player's cities originally owned by another AI major player; if neverHuman is true, owners with a nonempty nickname are skipped. |
plumbing ✓ |
— |
0x265600 |
| GetNumBuildings |
PlayerCities:GetNumBuildings(eBuilding: integer) → number |
Counts the player's cities that have the given building. |
plumbing ✓ |
— |
0x2658c0 |
| GetNumCapturedCityStates |
PlayerCities:GetNumCapturedCityStates() → number |
Counts cities whose original owner differs from the current owner and is neither a major player nor barbarian. |
plumbing ✓ |
— |
0x265920 |
| GetNumOriginalCapitalsCaptured |
PlayerCities:GetNumOriginalCapitalsCaptured() → number |
Counts cities whose original owner differs from the current owner, are flagged as original capital (0x298) and whose original owner is a major player. |
plumbing ✓ |
— |
0x2659a0 |
| HasCityOnContinent |
PlayerCities:HasCityOnContinent(continent: integer) → boolean |
Returns true if the continent is in the player's list of continents with cities. |
plumbing ✓ |
— |
0x265aa0 |
| HasSlotForGreatWork |
PlayerCities:HasSlotForGreatWork(iIndex: integer) → boolean |
Returns true if any city of the player can accept the great work index into a slot. |
plumbing ✓ |
— |
0x265ae0 |
| IsDistrictBuildingBanned |
PlayerCities:IsDistrictBuildingBanned(eDistrict: integer) → boolean |
Returns true if the district type is in the player's banned-district list. |
plumbing ✓ |
— |
0x265d10 |
| RemoveBuildingReplacementOverride |
PlayerCities:RemoveBuildingReplacementOverride(eBuildingToReplace: integer, eBuildingOverride: integer) |
Removes one matching pair from the building replacement list, then reverts existing buildings in the player's cities and relocates great works. The decompilation is truncated near the end. |
plumbing ✓ |
— |
0x265e80 |
| RemoveUnassignedProductionOverflow |
PlayerCities:RemoveUnassignedProductionOverflow() |
For each city of the player with no active build item (field 0x12b0 zero or pointer 0x12a0 null), clears the build queue production overflow. |
plumbing ✓ |
— |
0x266120 |
| SetCanEverConstruct |
PlayerCities:SetCanEverConstruct() |
Rebuilds a player's table of buildings that can ever be constructed, based on civ/leader/government traits, obsolete wonders and building conditions, then marks related buildings. |
plumbing ✓ |
Player::Cities::SetCanEverConstruct |
0x266570 |
| SetCityUrbanDefenses |
PlayerCities:SetCityUrbanDefenses(iDefenseValue: integer) |
Sets the player city urban-defense value and fires an event with the owner id and value. |
plumbing ✓ |
Player::Cities::SetCityUrbanDefenses |
0x266f50 |
| SetDistrictBuildingBanned |
PlayerCities:SetDistrictBuildingBanned(eDistrict: integer, bBan: boolean) |
Adds or removes a district type in the list of districts whose buildings are banned for this player. |
plumbing ✓ |
Player::Cities::SetDistrictBuildingBanned |
0x266f90 |
| SetPopulationAfterConquest |
PlayerCities:SetPopulationAfterConquest(iPercent: integer) |
Stores a percentage setting for the population kept in cities after conquest. |
plumbing ✓ |
Player::Cities::SetPopulationAfterConquest |
0x2670b0 |
Details
AddBuildingReplacementOverride
Arguments: eBuildingToReplace — building type that is to be replaced; eBuildingOverride — building type that replaces it
Writes
- building replacement override list at 0x168
- cities' buildings (ReplaceBuilding)
- can-ever-construct state
Side effects
- notifies Rules::Cities OnCityBuildingOverrideAdded and relocates great works in each affected city
Input checks: Ignores -1 for either argument and skips duplicate pairs; does not check the buildings exist.
Multiplayer: may-desync, changes cities' buildings. Risk: high (rewrites buildings in all cities of the player). Confidence of the reading: medium.
ChangeExtraStartingPopulationOffHomeContinent
Arguments: iChange — amount added to the stored bonus
Writes
- extra starting population off home continent counter at this+0x1a8 (assigned through an auto-variable wrapper at this+0x198)
Side effects
- none visible beyond the tracked variable assignment
Input checks: Zero change returns immediately. No range clamp on result.
Preconditions
- valid Cities object for a player
Multiplayer: may-desync: player state mutation; must be applied identically on all clients. Risk: low (simple integer accumulator, no clamping needed). Confidence of the reading: high.
Verified from the code
- no-op if param is 0
- new value = old value + change, stored at this+0x1a8
Inferred
- counter is applied when new cities are founded off home continent (from the name)
Open questions
- where the counter is consumed
CheckUnhandledCityDecisions
Writes
- city decision fields reset to -1 for AI cities
- city command requests queued for humans
Side effects
- queues City::Commands::Destroy request through the command manager for human players
Input checks: Skips cities without a valid index; no other checks.
Multiplayer: may-desync, resets city decisions and queues commands. Risk: high (can issue destroy commands and clear AI decisions). Confidence of the reading: low.
DoEndTurn
Writes
- city health through Heal (delegated)
Side effects
- each city is healed by City::Manager::Heal
Input checks: Skips when there are no cities; an invalid city index passes null to Heal.
Multiplayer: may-desync, heals cities. Risk: medium (changes city health state). Confidence of the reading: medium.
DoSetTurnComplete
Arguments: eRequestType — turn request subtype; only two hashed values (0x720b6468, 0x4601eac9) trigger the work
Writes
- city build queue overflow (via RemoveUnassignedProductionOverflow)
Input checks: Only acts for the two request subtypes and human players.
Multiplayer: may-desync, clears city production overflow. Risk: medium (indirectly clears build queue overflow). Confidence of the reading: medium.
DoTurnActivate
Writes
- unknown, delegated to a lambda
Input checks: None visible.
Multiplayer: unknown, behaviour hidden in a lambda. Risk: medium (body only calls a lambda, effect unknown). Confidence of the reading: low.
GetAICitiesCaptured
Arguments: neverHuman — if true, exclude owners whose configuration has a nonempty nickname (inferred)
Input checks: Skips cities with flag at 0x208 set, invalid original owners and the player itself.
Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: medium.
GetNumBuildings
Arguments: eBuilding — building type to count
Input checks: None; passes the building type to HasBuilding for each city.
Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.
GetNumCapturedCityStates
Input checks: None.
Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.
GetNumOriginalCapitalsCaptured
Input checks: None.
Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.
HasCityOnContinent
Arguments: continent — continent type to look for in the list at 0x128
Input checks: None; linear search.
Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.
HasSlotForGreatWork
Arguments: iIndex — great work list index to place
Input checks: None; each city is queried with no building filter.
Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.
IsDistrictBuildingBanned
Arguments: eDistrict — district type to look for in the ban list at 0x228
Input checks: None; linear search.
Multiplayer: read-only, pure query. Risk: low (pure getter). Confidence of the reading: high.
RemoveBuildingReplacementOverride
Arguments: eBuildingToReplace — building type that had been replaced; eBuildingOverride — building type that replaced it
Writes
- building replacement override list at 0x168 (rebuilt without the pair)
- cities' buildings (ReplaceBuilding)
- can-ever-construct state
Side effects
- relocates great works in each affected city via Rules::Cities
Input checks: No -1 or existence check; rebuilds the list even if the pair is absent.
Multiplayer: may-desync, changes cities' buildings. Risk: high (rewrites buildings in all cities of the player). Confidence of the reading: medium.
RemoveUnassignedProductionOverflow
Writes
- city build queue overflow cleared
Input checks: Invalid city indices pass a null city; no other checks.
Multiplayer: may-desync, clears city overflow production. Risk: medium (loses leftover production). Confidence of the reading: medium.
SetCanEverConstruct
Writes
- per-building can-ever-construct int array at this+0x140 (cleared to -1, then set to the building's own index when allowed)
- local fixed_vector scratch of unlocked building ids
Side effects
- resizes and refills the can-ever-construct vector
- calls Initializer::ObsoleteWonders per building
Input checks: null definition pointers skipped; recomputation only in the branch where civ or leader definition exists
Preconditions
- owning player set (this+0x90)
- definitions loaded
Multiplayer: safe-deterministic. Risk: medium (bulk rebuild of a cached table; output C is truncated so details unconfirmed). Confidence of the reading: low.
Verified from the code
- array at +0x140 is reset to size of building definition count filled with -1
- civilization and leader types read from player configuration of owner
- checks BuildingCondition entries and ObsoleteWonders
- entries set to the building index mean allowed
Inferred
- conditions with flag bit 1 and matching type block the building
- unique building replacement handling occurs in the truncated tail
Open questions
- input C is truncated mid-function so the tail (unique-building replacement and final writes) was not read
- semantics of fixed_vector scratch use
SetCityUrbanDefenses
Arguments: iDefenseValue — new urban defense value
Writes
- int at this+0xec (urban defenses)
Side effects
- sends reporting event 0x93556d2d with player id and new value
Input checks: No validation; value stored as-is.
Preconditions
- gameplay Lua state
- valid Cities object
Multiplayer: may-desync: direct state write. Risk: medium (Unvalidated state write.). Confidence of the reading: medium.
Verified from the code
- Stores param at this+0xec
- Sends event 0x93556d2d with owner id and value
Inferred
- It is a replacement, not additive
- Field is player-wide (stored on Cities, not on a city)
Open questions
- How the value is consumed in combat
SetDistrictBuildingBanned
Arguments: eDistrict — district whose buildings are banned/unbanned; bBan — true to add the ban, false to remove it
Writes
- banned-district-buildings list at this+0x218
Side effects
- none visible; unlike SetCityProductionBanned it does not touch build queues
Input checks: Type -1 returns silently. Duplicates not checked. Unban of absent entry silent.
Preconditions
- valid player Cities object
Multiplayer: may-desync: player state mutation; must run identically on all clients. Risk: low (list edit only, no queue changes). Confidence of the reading: high.
Verified from the code
- appends on ban, erase-by-shift on unban
- no queue manipulation in this function
Inferred
- checked by building eligibility logic
Open questions
- whether existing queued buildings are purged elsewhere
SetPopulationAfterConquest
Arguments: iPercent — percentage value stored
Writes
- population-after-conquest percent at this+0x1b0 (via auto-variable assignment)
Side effects
- none visible
Input checks: A value of 0 is ignored (returns without writing), so it cannot be set to 0 through this function. No clamping.
Preconditions
- valid player Cities object
Multiplayer: may-desync: player state mutation; must run identically on all clients. Risk: low (single integer assignment). Confidence of the reading: medium.
Verified from the code
- param 0 is a no-op
- otherwise assigns the value (not additive) at this+0x1b0
Inferred
- value is a percentage as named in the Linux parameter
- consumer is city capture logic
Open questions
- default value and where it is consumed
- whether the 0 guard is deliberate