Home › Dev CE (experimental) › PlayerCulture
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.
PlayerCulture
49 methods (Dev CE test build). this is found with the game's own IPlayerCulture instance resolver (virtual).
| Method |
Signature |
Purpose (AI-written, inferred) |
Tested |
Engine function |
Current |
| AddTourismAtPlot |
PlayerCulture:AddTourismAtPlot(iPlotIndex: integer, iTourism: integer) |
Adds tourism to a plot's entry in the player's tourism location list, scaled by a percentage modifier (floor -100%). |
plumbing ✓ this ✓ (oracle) |
Player::Culture::AddTourismAtPlot |
0x279f60 |
| AddTourismIntoFavor |
PlayerCulture:AddTourismIntoFavor(iTourism: integer, iFavor: integer) |
Appends an (iTourism, iFavor) pair to a per-player list at offset 0x6a8 that defines a tourism-into-favor conversion entry. |
plumbing ✓ this ✓ (oracle) |
— |
0x27a090 |
| ApplyTourism |
PlayerCulture:ApplyTourism() |
For every player in the manager's list that this player has met, computes tourism towards them and adds it to the accumulated per-player tourism array, then recomputes. |
plumbing ✓ this ✓ (oracle) |
— |
0x27a0e0 |
| CanFillAllPolicySlots |
PlayerCulture:CanFillAllPolicySlots() → boolean |
Checks whether the player has enough unlocked policies to fill every government slot, matching slot types and wildcard slots. Decompilation is truncated before the final result. |
plumbing ✓ this ✓ (oracle) |
— |
0x27b790 |
| CanTriggerBoost |
PlayerCulture:CanTriggerBoost(eCivic: integer) → boolean |
Returns false if the civic is already known, otherwise finds the boost whose civic type matches and asks Boost::Manager::CanTriggerThisBoost whether the Eureka can fire. |
plumbing ✓ this ✓ (oracle) |
— |
0x27be50 |
| ChangeGreatWorkObjectTourismModifier |
PlayerCulture:ChangeGreatWorkObjectTourismModifier(eGreatWorkObjectType: integer, iModDelta: integer) |
Adds a delta to the tourism modifier for a specific great work object type, if that type already has a record. |
plumbing ✓ ran ±1, reversible ✓, no visible effect this ✓ (oracle) |
Player::Culture::ChangeGreatWorkObjectTourismModifier |
0x27c0b0 |
| ChangeTourismModifier |
PlayerCulture:ChangeTourismModifier(iDelta: integer) |
Adds a delta to the tourism modifier stored at Culture+0x508. |
plumbing ✓ this ✓ (oracle) |
— |
0x27c110 |
| ChangeTourismOn |
PlayerCulture:ChangeTourismOn(ePlayer: integer, xValue: number (fixed point, 1/256 steps)) |
Adds a delta to this player's accumulated tourism toward another player. |
plumbing ✓ this ✓ (oracle) |
Player::Culture::ChangeTourismOn |
0x27c140 |
| CheckForDominance |
PlayerCulture:CheckForDominance() |
For each other player, compares this player's tourist count with that player's culture-based threshold to set/clear a dominance flag and turns-until-dominant, sending notifications to both players when dominance is first reached. Decompilation is truncated near the end. |
plumbing ✓ this ✓ (oracle) |
— |
0x27c190 |
| ComputeTourismOn |
PlayerCulture:ComputeTourismOn(ePlayer: integer) → number |
Computes fixed-point tourism this player generates towards the given player from city religious and non-religious tourism, era differences, trade routes, open borders, government modifiers and monopolies. Decompilation truncated at the end. |
plumbing ✓ this ✓ (oracle) |
— |
0x27ca80 |
| ComputeTurnsUntilDominant |
PlayerCulture:ComputeTurnsUntilDominant(ePlayer: integer) → number |
Estimates turns until this player becomes culturally dominant over ePlayer from the tourist totals and the other player's culture values; -1 if not progressing. |
plumbing ✓ this ✓ (oracle) |
— |
0x27cf40 |
| DoCulture |
PlayerCulture:DoCulture() |
Per-turn culture processing: records last culture rate, handles pending government change, computes culture yield, advances civic progress, and for major players runs tourism recording/application/distribution and dominance checks, then era flags, obsolete policies and notifications. Decompilation truncated. |
plumbing ✓ this ✓ (oracle) |
— |
0x27d3c0 |
| DoEndTurn |
PlayerCulture:DoEndTurn() |
Clears the boolean flag at Culture+0x450 at end of turn. |
plumbing ✓ this ✓ (oracle) |
— |
0x27d770 |
| GetFavorPerTurnFromBuilding |
PlayerCulture:GetFavorPerTurnFromBuilding(eBuilding: integer) → number |
Looks up a building in a list of (building, favor) pairs at Culture+0x7a8 and returns its favor per turn. |
plumbing ✓ this ✓ (oracle) |
— |
0x27e1e0 |
| GetFavorPerTurnFromPolicy |
PlayerCulture:GetFavorPerTurnFromPolicy(ePolicy: integer) → number |
Looks up a policy in a list of (policy, favor) pairs at Culture+0x778 and returns its favor per turn. |
plumbing ✓ this ✓ (oracle) |
— |
0x27e210 |
| GetGreatWorkObjectNoTourism |
PlayerCulture:GetGreatWorkObjectNoTourism(eGreatWorkObjectType: integer) → boolean |
Looks up a great work object type in the 12-byte entry list at Culture+0x748 and returns its no-tourism flag. |
plumbing ✓ this ✓ (oracle) |
— |
0x27e240 |
| GetGreatWorkObjectTourismModifier |
PlayerCulture:GetGreatWorkObjectTourismModifier(eGreatWorkObjectType: integer) → number |
Looks up a great work object type in the 12-byte entry list at Culture+0x748 and returns its tourism modifier. |
plumbing ✓ this ✓ (oracle) |
— |
0x27e270 |
| GetNumCivicsCompleted |
PlayerCulture:GetNumCivicsCompleted(bIncludeRepeatedCivics: boolean) → number |
Counts civics that are completed for the player; optionally adds the repeated-civics counter at Culture+0x850. |
plumbing ✓ this ✓ (oracle) |
— |
0x27e2e0 |
| GetNumPoliciesEnactedSpecificType |
PlayerCulture:GetNumPoliciesEnactedSpecificType(eGovernmentSlot: integer) → number |
Counts currently slotted policies whose definition's slot type equals eGovernmentSlot. |
plumbing ✓ this ✓ (oracle) |
— |
0x27e390 |
| GetNumPoliciesUnlocked |
PlayerCulture:GetNumPoliciesUnlocked() → number |
Counts policies for which IsPolicyUnlocked is true. |
plumbing ✓ this ✓ (oracle) |
— |
0x27e4e0 |
| GetNumPolicySlotsOpen |
PlayerCulture:GetNumPolicySlotsOpen() → number |
Counts empty policy slots (entries with policy -1) in the slot array at Culture+0x1a0; 0 if no government. |
plumbing ✓ this ✓ (oracle) |
— |
0x27e590 |
| GetOtherGovernmentIntoleranceModifier |
PlayerCulture:GetOtherGovernmentIntoleranceModifier(GovA: integer, GovB: integer) → number |
Returns the intolerance modifier at Culture+0x838 when two different governments have equal-sized lists (vector at definition+0x90), else 0. |
plumbing ✓ this ✓ (oracle) |
— |
0x27e640 |
| GetSlotType |
PlayerCulture:GetSlotType(iSlotIndex: integer) → number |
Returns the government slot type of the slot at the given index. |
plumbing ✓ this ✓ (oracle) |
— |
0x27e940 |
| GetTourismNationalParksModifier |
PlayerCulture:GetTourismNationalParksModifier() → number |
Returns a fixed-point multiplier 1.0 + (Culture+0x730)/100 for national parks tourism; 1.0 if the value is not positive. |
plumbing ✓ this ✓ (oracle) |
— |
0x27fe90 |
| GetTouristsTo |
PlayerCulture:GetTouristsTo() → number |
Sums per-player tourist counts (array at Culture+0x5f8) over all other players this player has met. |
plumbing ✓ this ✓ (oracle) |
— |
0x2805b0 |
| GrantRandomBoostGoodyHut |
PlayerCulture:GrantRandomBoostGoodyHut(iNumFreeBoosts: integer, eSource: integer) |
Grants a number of random civic boosts (from the era of the cheapest not-yet-owned civic) to a player, used by goody huts. |
plumbing ✓ this ✓ (oracle) |
Player::Culture::GrantRandomBoostGoodyHut |
0x280860 |
| GrantRandomBoostsByEra |
PlayerCulture:GrantRandomBoostsByEra(iNumFreeBoosts: integer, eStartEra: integer, eEndEra: integer) |
Randomly triggers a number of civic boosts for a player, picking among boostable civics whose era is between a start and end era that are not yet researched or boosted. |
plumbing ✓ this ✓ (oracle) |
Player::Culture::GrantRandomBoostsByEra |
0x280c80 |
| GrantRandomCivics |
PlayerCulture:GrantRandomCivics(iNumCivics: integer) |
Builds a list of civics that can be progressed and are not yet completed, then randomly picks up to iNumCivics of them and grants them via cultural progress at full civic cost. Decompilation truncated. |
plumbing ✓ this ✓ (oracle) |
— |
0x280fb0 |
| HasFeaturesModifiedUnlock |
PlayerCulture:HasFeaturesModifiedUnlock(eFeature: integer) → boolean |
Searches the (feature, civic) pair list at Culture+0x700 and returns true if a matching feature has its civic completed. |
plumbing ✓ this ✓ (oracle) |
— |
0x2815e0 |
| IsCivicRevealed |
PlayerCulture:IsCivicRevealed(eCivic: integer) → boolean |
Returns true if the civic is visible to the player: owned, boost triggered, or a prerequisite owned (for flagged civics); true for unflagged civics; false if no definition. |
plumbing ✓ this ✓ (oracle) |
— |
0x281c80 |
| IsProgressingCivic |
PlayerCulture:IsProgressingCivic(eCivic: integer) → boolean |
Returns true if the civic currently being progressed (first entry of list at Culture+0x408) equals eCivic. |
plumbing ✓ this ✓ (oracle) |
— |
0x282210 |
| RecomputeTourismOn |
PlayerCulture:RecomputeTourismOn(ePlayer: integer) |
Recomputes how many tourists this player receives from another player's culture and updates the stored value and the other player's tourism-related total by the difference. |
plumbing ✓ this ✓ (oracle) |
Player::Culture::RecomputeTourismOn |
0x282cb0 |
| RemoveCultureBombTrigger |
PlayerCulture:RemoveCultureBombTrigger(eBuilding: integer, bCapturesOwnedTiles: boolean) |
Finds the first entry in the list at Culture+0x678 matching the given type and capture flag, and erases it. (DWARF lists both eBuilding and eDistrict variants; decompile uses DistrictTypes.) |
plumbing ✓ this ✓ (oracle) |
— |
0x282e80 |
| RemoveGovernmentTypeSlotModifier |
PlayerCulture:RemoveGovernmentTypeSlotModifier(eGovernmentType: integer, eSlotType: integer, bAddSlot: boolean) |
Finds the (government, slot type) modifier entry and adjusts its count by 1 (opposite of Set); if the player's current government matches, clears policies, rebuilds slots and resets flags. |
plumbing ✓ this ✓ (oracle) |
— |
0x282f30 |
| RemoveModifiedPolicySlot |
PlayerCulture:RemoveModifiedPolicySlot(eGovSlot: integer, bAddSlot: boolean) |
Removes one entry for the slot type from the added (0x1e0) or removed (0x208) modified slot list depending on bAddSlot, then clears policies of that slot type and refreshes the government. |
plumbing ✓ this ✓ (oracle) |
— |
0x283060 |
| RemoveReplacedPolicySlot |
PlayerCulture:RemoveReplacedPolicySlot(eReplacedSlot: integer, eAddedSlot: integer) |
Clears all policies, erases entries matching (replaced slot, added slot) from the replaced-slot list at Culture+0x230, and re-applies the current government. |
plumbing ✓ this ✓ (oracle) |
— |
0x2831a0 |
| RemoveTourismIntoFavor |
PlayerCulture:RemoveTourismIntoFavor(iTourism: integer, iFavor: integer) |
Rebuilds the tourism-into-favor pair list at Culture+0x6a8 from a copy, omitting entries matching (iTourism, iFavor). |
plumbing ✓ this ✓ (oracle) |
— |
0x283300 |
| SetAllCivicsByPreviousEra |
PlayerCulture:SetAllCivicsByPreviousEra(eEraType: integer) |
Marks as completed every civic whose era is earlier than the given era (era index >1), notifying listeners for each and once overall. |
plumbing ✓ this ✓ (oracle) |
Player::Culture::SetAllCivicsByPreviousEra |
0x284060 |
| SetCultureRateChange |
PlayerCulture:SetCultureRateChange(xNewValue: number (fixed point, 1/256 steps)) |
If the value differs from Culture+0x448, assigns it (via auto-variable at 0x438) and sends a culture-rate-changed event. |
plumbing ✓ this ✓ (oracle) |
— |
0x284990 |
| SetFavorPerTurnFromBuilding |
PlayerCulture:SetFavorPerTurnFromBuilding(eBuilding: integer, iFavor: integer) |
Sets the per-turn Favor yield contributed by a building, replacing the existing value or adding a new record. |
plumbing ✓ this ✓ (oracle) |
Player::Culture::SetFavorPerTurnFromBuilding |
0x284ca0 |
| SetFavorPerTurnFromPolicy |
PlayerCulture:SetFavorPerTurnFromPolicy(ePolicy: integer, iFavor: integer) |
Sets the per-turn Favor yield contributed by a policy, replacing the existing value or adding a new record. |
plumbing ✓ this ✓ (oracle) |
Player::Culture::SetFavorPerTurnFromPolicy |
0x284d60 |
| SetFeatureModifiedUnlock |
PlayerCulture:SetFeatureModifiedUnlock(eFeature: integer, eCivic: integer) |
Appends a (feature, civic) pair to the list at Culture+0x6f0 so the feature is unlocked once the civic is completed. |
plumbing ✓ this ✓ (oracle) |
— |
0x284e20 |
| SetGovernmentTypeSlotModifier |
PlayerCulture:SetGovernmentTypeSlotModifier(eGovernmentType: integer, eSlotType: integer, bAddSlot: boolean) |
Finds or creates the (government, slot type) modifier entry and increments or decrements its count; if the current government matches, clears policies, rebuilds slots and resets flags. |
plumbing ✓ this ✓ (oracle) |
— |
0x284e90 |
| SetGreatWorkObjectNoTourism |
PlayerCulture:SetGreatWorkObjectNoTourism(eGreatWorkObjectType: integer, bNoTourism: boolean) |
Sets a flag that makes a great work object type produce no tourism, if the type has a record. |
plumbing ✓ this ✓ (oracle) |
Player::Culture::SetGreatWorkObjectNoTourism |
0x285030 |
| SetModifiedPolicySlot |
PlayerCulture:SetModifiedPolicySlot(eGovSlot: integer, bAddSlot: boolean) |
Appends the slot type to the added (0x1e0) or removed (0x208) slot list depending on bAddSlot, then stores previous policies, clears them, rebuilds slots and resets flags. |
plumbing ✓ this ✓ (oracle) |
— |
0x285090 |
| SetNumFreeCivicBoostOnNewEra |
PlayerCulture:SetNumFreeCivicBoostOnNewEra(numBoosts: integer, applyImmediately: boolean) |
Adds to the number of free civic boosts granted when a new era begins, optionally granting boosts immediately. |
plumbing ✓ this ✓ (oracle) |
Player::Culture::SetNumFreeCivicBoostOnNewEra |
0x285190 |
| SetPolicyBanned |
PlayerCulture:SetPolicyBanned(ePolicy: integer, bBanned: boolean) |
Marks a policy as banned or unbanned for the player; when banning an active policy it removes it from its slot. |
plumbing ✓ this ✓ (oracle) |
Player::Culture::SetPolicyBanned |
0x285230 |
| SetPolicyChangeMade |
PlayerCulture:SetPolicyChangeMade(bNewValue: boolean) |
If true stores the current turn in Culture+0x7c8, otherwise stores -1 (marks whether a policy change was made this turn). |
plumbing ✓ this ✓ (oracle) |
— |
0x285300 |
| SetReplacedPolicySlot |
PlayerCulture:SetReplacedPolicySlot(eReplacedSlot: integer, eAddedSlot: integer, bReplacesAll: boolean) |
Appends a (replaced slot, added slot, replacesAll) entry to the list at Culture+0x230, clears policies and re-applies the current government if any. |
plumbing ✓ this ✓ (oracle) |
— |
0x285920 |
Details
AddTourismAtPlot
Arguments: iPlotIndex — plot index; iTourism — base tourism before modifier
Writes
- tourism location vector at this+0x648 (existing entry amount increased or new entry appended)
Input checks: No plot validation; modifier clamped at -100.
Preconditions
- game thread
Multiplayer: may-desync: synced vector. Risk: low (append/add only). Confidence of the reading: medium.
Verified from the code
- amount = (max(mod,-100)+100)*tourism/100 using integer division
- finds entry by plot index with find_if
- adds or appends
Inferred
- modifier pointer chain is the player's tourism modifier
Open questions
- what source is at +0x6f0 -> +0x508
AddTourismIntoFavor
Arguments: iTourism — tourism amount of the entry (inferred); iFavor — favor amount of the entry (inferred)
Writes
- vector at Culture+0x6a8 (tourism/favor pair list) gets one 8-byte entry appended
Input checks: No validation; duplicates allowed.
Multiplayer: may-desync, edits synchronised player data. Risk: medium (writes synchronised list used by tourism-to-favor logic). Confidence of the reading: medium.
ApplyTourism
Writes
- Culture+0x480 per-player accumulated tourism array (adds ComputeTourismOn result for player ids <22)
- Culture+0x510 value set from Diplomacy::GetTourismFromAlliances
Side effects
- calls RecomputeTourismOn for each met player
Input checks: Only touches players already met; index guarded to < 22.
Multiplayer: may-desync, accumulates tourism into game state. Risk: medium (changes tourism totals every call). Confidence of the reading: medium.
CanFillAllPolicySlots
Input checks: No input; iterates government slot and policy definitions.
Multiplayer: read-only, only computes from definitions. Risk: low (pure check (truncated decompile)). Confidence of the reading: low.
CanTriggerBoost
Arguments: eCivic — civic type whose boost is tested
Input checks: No range check on eCivic beyond Types::GetIndex.
Multiplayer: read-only, queries boost and civic state. Risk: low (pure getter). Confidence of the reading: medium.
ChangeGreatWorkObjectTourismModifier
Arguments: eGreatWorkObjectType — great work object type; iModDelta — amount added to the modifier
Writes
- second field of the matching 12-byte record in the vector at this+0x738
Side effects
- none
Input checks: Type -1 returns silently. If no record exists for the type, nothing happens (no insertion).
Preconditions
- records for object types pre-populated
Multiplayer: may-desync: player state mutation; must run identically on all clients. Risk: low (bounded linear search, silent miss). Confidence of the reading: high.
Verified from the code
- searches vector of 12-byte entries by first field
- adds to second field on match, no insert on miss
Inferred
- third field is the no-tourism flag set by SetGreatWorkObjectNoTourism
Open questions
- where the vector is populated
ChangeTourismModifier
Arguments: iDelta — amount added to the modifier
Writes
- Culture+0x508 tourism modifier += iDelta
Input checks: None.
Multiplayer: may-desync, changes synchronised tourism modifier. Risk: medium (modifies tourism output). Confidence of the reading: high.
ChangeTourismOn
Arguments: ePlayer — player the tourism is directed at; xValue — amount to add (raw/256)
Writes
- tourism-on-player array entry at this+0x480 (index ePlayer)
Side effects
- none beyond marking the game variable edited
Input checks: Silently ignores ePlayer >= 0x16 (22); the check is unsigned so negatives are ignored too.
Preconditions
- valid player id < 22
- game thread
Multiplayer: may-desync: edits synchronized state directly. Risk: low (bounds-checked simple add). Confidence of the reading: high.
Verified from the code
- bound check param < 0x16
- reads old value, calls edit, writes old+delta
- delta is read through a pointer (FixedPoint passed by reference)
Inferred
- value is FixedPoint raw int; no clamping
Open questions
- why the limit is 22 rather than 64 (likely only majors)
CheckForDominance
Writes
- per-player dominance flag array (Culture+0x4a8)
- per-player turns-until-dominant array (Culture+0x4d0)
Side effects
- sends Reporting::Notification to this player and the dominated player
Input checks: Skips same team and unmet players (clearing their state).
Multiplayer: may-desync, writes dominance state and sends notifications. Risk: medium (drives cultural victory progress). Confidence of the reading: medium.
ComputeTourismOn
Arguments: ePlayer — target player of the tourism
Input checks: No range check on ePlayer; EditPlayer assumed valid.
Multiplayer: read-only, computes from synchronised state. Risk: low (pure getter). Confidence of the reading: medium.
ComputeTurnsUntilDominant
Arguments: ePlayer — player whose culture is compared
Input checks: Does not check ePlayer range; returns -1 if rates are non-positive.
Multiplayer: read-only, no state written. Risk: low (pure getter). Confidence of the reading: high.
DoCulture
Writes
- many Culture fields (0x420-0x468, 0xf8, 0x5b0, 0x5b8, 0x5d0)
- civic progress via ChangeCulturalProgress
- current government via SetCurrentGovernment
Side effects
- Reporting::Event::Send and several Notification::Send calls
Input checks: Guards on IsMajor and civic progress state.
Multiplayer: may-desync, runs the turn culture update. Risk: high (executes full per-turn culture logic). Confidence of the reading: medium.
DoEndTurn
Writes
- Culture+0x450 flag set to false
Input checks: None.
Multiplayer: may-desync, writes synchronised flag. Risk: low (single flag write). Confidence of the reading: medium.
GetFavorPerTurnFromBuilding
Arguments: eBuilding — building type to look up
Input checks: Returns 0 for -1 or not found.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: high.
GetFavorPerTurnFromPolicy
Arguments: ePolicy — policy type to look up
Input checks: Returns 0 for -1 or not found.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: high.
GetGreatWorkObjectNoTourism
Arguments: eGreatWorkObjectType — great work object type
Input checks: Returns false for -1 or not found.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: high.
GetGreatWorkObjectTourismModifier
Arguments: eGreatWorkObjectType — great work object type
Input checks: Returns 0 for -1 or not found.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: high.
GetNumCivicsCompleted
Arguments: bIncludeRepeatedCivics — if true adds the repeated civic count
Input checks: Checks index bounds against Culture+0x368 and civic existence.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: medium.
GetNumPoliciesEnactedSpecificType
Arguments: eGovernmentSlot — slot type to count
Input checks: Skips empty slots (-1); policy lookup handles missing definitions.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: high.
GetNumPoliciesUnlocked
Input checks: None needed.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: high.
GetNumPolicySlotsOpen
Input checks: Returns 0 when government is -1 or no slots.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: high.
GetOtherGovernmentIntoleranceModifier
Arguments: GovA — first government type; GovB — second government type
Input checks: Bounds-checks the index but dereferences definitions unchecked.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: medium.
GetSlotType
Arguments: iSlotIndex — slot index
Input checks: Upper bound checked; negative index not checked.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: high.
GetTourismNationalParksModifier
Input checks: None.
Multiplayer: read-only, writes only the return slot. Risk: low (pure getter). Confidence of the reading: medium.
GetTouristsTo
Input checks: Excludes self and unmet players.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: high.
GrantRandomBoostGoodyHut
Arguments: iNumFreeBoosts — how many boosts to grant; eSource — source of the boost, passed to TriggerBoost
Writes
- triggers civic boosts through TriggerBoost
- consumes random numbers
Side effects
- calls Culture::TriggerBoost for each chosen civic
- advances the game random number generator (label: Choosing random civic boost to grant based on era)
- heap-allocates a candidate list when it overflows inline storage
Input checks: Does nothing if count <= 0 or no candidate boosts. Civic ids of -1 or out of range skip the already-boosted checks.
Preconditions
- valid player
- game thread
Multiplayer: safe-deterministic. Risk: low (uses the game RNG with a fixed label, normal gameplay path). Confidence of the reading: medium.
Verified from the code
- picks a lowest-era civic not yet owned/boosted then collects its era's boosts that exist and whose civic is not already owned
- draws with Game::Instance::GetRandNum using the label 'Choosing random civic boost to grant based on era'
- removes each chosen entry from the candidate list so no repeats
- calls TriggerBoost for each selection not already boosted
Inferred
- target era is the lowest era among unowned civics
- decompiled types are misleading (government/tech names reused for civics)
Open questions
- exact era-selection logic is partly garbled by decompiler type confusion
- whether the HasBoost check refers to the era's boost objects
GrantRandomBoostsByEra
Arguments: iNumFreeBoosts — how many boosts to grant; eStartEra — lower era bound (inclusive); eEndEra — upper era bound (inclusive)
Writes
- calls TriggerBoost on this player (source code 2) for each chosen civic
Side effects
- draws random numbers from the game random stream (labelled with a log string including the player id)
- triggers civic boosts
Input checks: if either era is not found in definitions the candidate list stays empty and nothing is granted; loop stops when candidates run out
Preconditions
- valid owning player
- game thread; deterministic RNG state
Multiplayer: safe-deterministic. Risk: medium (consumes game RNG and triggers boosts; fine if run on all clients). Confidence of the reading: medium.
Verified from the code
- builds a weighted candidate list of civics with weight 1
- random index chosen via Game::Instance::GetRandNum with a log text including the player id
- chosen entry removed from list then TriggerBoost(civic, 2) called
- stops at iNumFreeBoosts or when list is empty
Inferred
- candidate items are civics (names TechTypes in decompile are reused types)
- era filter compares an era index field at +0x1c
Open questions
- meaning of TriggerBoost source value 2
- decompile mixes tech/civic type names so list element type is unsure
GrantRandomCivics
Arguments: iNumCivics — how many civics to grant
Writes
- cultural progress per granted civic via SetCulturalProgress
Side effects
- consumes game random numbers (GetRandNum)
Input checks: Stops when no candidates left; iNumCivics <= 0 does nothing.
Multiplayer: may-desync, uses RNG and grants civics. Risk: high (changes civic progress and RNG state). Confidence of the reading: medium.
HasFeaturesModifiedUnlock
Arguments: eFeature — feature type to test
Input checks: Bounds-checks civic index; no check on eFeature.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: high.
IsCivicRevealed
Arguments: eCivic — civic type to test
Input checks: Returns false when civic definition not found.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: medium.
IsProgressingCivic
Arguments: eCivic — civic type to compare
Input checks: Returns false if the progress list is empty.
Multiplayer: read-only, only reads synchronised state. Risk: low (pure getter). Confidence of the reading: high.
RecomputeTourismOn
Arguments: ePlayer — the other player id
Writes
- per-player tourist count array at this+0x5e8 (entry ePlayer)
- an AI control/priority-style int on the other player's object (+0x6f0 -> +0x5a0) adjusted by the delta
Side effects
- calls ComputeTouristsFrom(ePlayer)
Input checks: no bounds check on ePlayer; EditPlayer result not null-checked
Preconditions
- valid player id
- gameplay thread
Multiplayer: safe-deterministic. Risk: medium (unchecked index and cross-player write). Confidence of the reading: medium.
Verified from the code
- indexes player arrays by ePlayer*4 without bounds check
- other player's field at +0x6f0 pointer then +0x5b0 minus the delta is stored back through a MoveAssignment on +0x5a0
Inferred
- the +0x6f0 object is the other player's Culture and the field is a running total tied to tourists received (probably lifetime/visiting tourists)
- the +0x5a0 type name AI::Control::ControlPriority is likely a mis-resolved template
Open questions
- exact meaning of the field updated on the other player
RemoveCultureBombTrigger
Arguments: eBuilding — type matched against the list entry field (district/building) (inferred); bCapturesOwnedTiles — captures-owned-tiles flag that must match
Writes
- entry removed from culture bomb trigger list at Culture+0x678
Input checks: Silently does nothing if no entry matches.
Multiplayer: may-desync, edits synchronised list. Risk: medium (removes culture bomb triggers). Confidence of the reading: medium.
RemoveGovernmentTypeSlotModifier
Arguments: eGovernmentType — government whose modifier is changed; eSlotType — slot type being modified; bAddSlot — true if the original modifier added a slot
Writes
- modifier entry count in list at Culture+0x258
- Culture+0x7c8 reset to -1, Culture+0x450 set true, policies cleared
Side effects
- Reporting::Event::Send(0xa981150) when current government matches
Input checks: If no entry found nothing changes in the list; current government still rebuilt.
Multiplayer: may-desync, rebuilds policy slots. Risk: high (clears all enacted policies on current government). Confidence of the reading: medium.
RemoveModifiedPolicySlot
Arguments: eGovSlot — slot type whose modifier is removed; bAddSlot — selects list: true=added-slots list, false=removed-slots list
Writes
- entry erased from slot modifier list (0x1e0 or 0x208)
- policies of that slot type cleared
Side effects
- SetCurrentGovernment re-applies current government
Input checks: Returns early for slot -1.
Multiplayer: may-desync, edits slots and policies. Risk: high (clears policies). Confidence of the reading: medium.
RemoveReplacedPolicySlot
Arguments: eReplacedSlot — slot type that was replaced; eAddedSlot — slot type that replaced it
Writes
- entries removed from list at Culture+0x230
- all policies cleared
Side effects
- SetCurrentGovernment re-applies current government if one is set
Input checks: Returns early if either slot is -1.
Multiplayer: may-desync, edits slots and policies. Risk: high (clears all policies). Confidence of the reading: medium.
RemoveTourismIntoFavor
Arguments: iTourism — tourism value of the entry to remove (inferred); iFavor — favor value of the entry to remove (inferred)
Writes
- list at Culture+0x6a8 rebuilt without matching entries
Input checks: None; non-matching list stays unchanged.
Multiplayer: may-desync, edits synchronised list. Risk: medium (list rewrite). Confidence of the reading: medium.
SetAllCivicsByPreviousEra
Arguments: eEraType — era; civics from earlier eras are granted
Writes
- civic-completed byte array at this+0x348
Side effects
- signal (Unit*,uint) per civic granted (game signal +0x498) with the player and civic id
- signal (uint) on player object +0x798 with last granted civic
Input checks: Era index looked up with bounds check but result used unchecked when out of range (null deref risk); does nothing if era's index <=1.
Preconditions
- game thread
- valid era type
Multiplayer: may-desync: grants civics. Risk: medium (bulk grant and unchecked era pointer). Confidence of the reading: medium.
Verified from the code
- skips when era value <=1
- only civics whose era value is below target era
- dispatches per-civic signal and one final signal if any granted
Inferred
- does not trigger boosts or other civic side effects
Open questions
- whether already-owned civics also re-trigger the signal (no check seen)
SetCultureRateChange
Arguments: xNewValue — new fixed-point culture rate change
Writes
- culture rate change value at Culture+0x438/0x448
Side effects
- Reporting::Event::Send(0x8aba2360, player)
Input checks: Skips when unchanged.
Multiplayer: may-desync, writes culture rate. Risk: medium (changes applied culture rate). Confidence of the reading: medium.
SetFavorPerTurnFromBuilding
Arguments: eBuilding — building type; iFavor — favor per turn value (assigned, not added)
Writes
- (building, favor) pair vector at this+0x798
Side effects
- vector may reallocate
Input checks: Type -1 returns silently. No range check on value.
Preconditions
- valid Culture object
Multiplayer: may-desync: player state mutation; must run identically on all clients. Risk: low (simple keyed assignment). Confidence of the reading: high.
Verified from the code
- linear search by building; overwrite second int if found, else append 8-byte pair
Inferred
- total favor per turn aggregates these entries (Gathering Storm)
Open questions
- aggregation point
SetFavorPerTurnFromPolicy
Arguments: ePolicy — policy type; iFavor — favor per turn value (assigned, not added)
Writes
- (policy, favor) pair vector at this+0x768
Side effects
- vector may reallocate
Input checks: Type -1 returns silently. No range check.
Preconditions
- valid Culture object
Multiplayer: may-desync: player state mutation; must run identically on all clients. Risk: low (simple keyed assignment). Confidence of the reading: high.
Verified from the code
- linear search by policy; overwrite or append 8-byte pair
Inferred
- sums into player's favor income
Open questions
- aggregation point
SetFeatureModifiedUnlock
Arguments: eFeature — feature type to unlock; eCivic — civic that unlocks it
Writes
- entry appended to list at Culture+0x6f0
Input checks: No validation or duplicate check.
Multiplayer: may-desync, edits synchronised list. Risk: medium (adds unlock condition). Confidence of the reading: medium.
SetGovernmentTypeSlotModifier
Arguments: eGovernmentType — government whose slots are modified; eSlotType — slot type being modified; bAddSlot — true adds a slot (+1), false removes (-1)
Writes
- modifier list at Culture+0x258
- Culture+0x7c8 reset to -1, Culture+0x450 set true, policies cleared
Side effects
- Reporting::Event::Send(0xa981150) when current government matches
Input checks: No range checks on enums.
Multiplayer: may-desync, rebuilds slots and clears policies. Risk: high (clears all enacted policies on current government). Confidence of the reading: medium.
SetGreatWorkObjectNoTourism
Arguments: eGreatWorkObjectType — great work object type; bNoTourism — true to suppress tourism
Writes
- bool flag in the third field of the matching record in the vector at this+0x738
Side effects
- none
Input checks: Type -1 returns silently. Missing record: silent no-op.
Preconditions
- records for object types pre-populated
Multiplayer: may-desync: player state mutation; must run identically on all clients. Risk: low (flag write with silent miss). Confidence of the reading: high.
Verified from the code
- same record vector as ChangeGreatWorkObjectTourismModifier
- writes a bool at offset 8 of the 12-byte record
Inferred
- flag consulted in tourism calculation
SetModifiedPolicySlot
Arguments: eGovSlot — slot type to add or remove; bAddSlot — true uses the added-slots list, false the removed list
Writes
- slot modifier list (0x1e0 or 0x208)
- Culture+0x7c8 reset to -1, Culture+0x450 set true, policies cleared
Side effects
- Reporting::Event::Send(0xa981150, player)
Input checks: No validation of slot type.
Multiplayer: may-desync, rebuilds slots and clears policies. Risk: high (clears all enacted policies). Confidence of the reading: medium.
SetNumFreeCivicBoostOnNewEra
Arguments: numBoosts — amount added to the stored counter (despite 'Set' name it is additive); applyImmediately — if true and boosts positive, grant random boosts now
Writes
- free civic boost counter at this+0x7f0 (via wrapper at this+0x7e0)
- random civic boosts granted through GrantRandomBoostsByEra
Side effects
- may call GrantRandomBoostsByEra, which uses game randomness and awards boosts
Input checks: No zero check. Immediate grant requires a valid era (not -1) and a positive amount; otherwise only the counter changes.
Preconditions
- owning player valid with an era set
Multiplayer: may-desync: random boost granting must be run identically on all clients (uses synchronized RNG presumably). Risk: medium (counter can go negative; immediate grant uses random selection). Confidence of the reading: medium.
Verified from the code
- counter = old + param
- immediate grant only if bool set, era != -1, param > 0
- calls GrantRandomBoostsByEra with the current era twice
Inferred
- boosts are civic (culture) boosts per the name
- RNG used inside GrantRandomBoostsByEra
Open questions
- meaning of two era arguments
- whether counter is consumed or persistent
SetPolicyBanned
Arguments: ePolicy — policy type; bBanned — true to ban
Writes
- banned flag array entry at this+0x320
- policy slot cleared via ClearPolicySlot
- another tracked value at this+0x7c8 set to -1 after a slot clear
Side effects
- removes the active policy from its slot if found; resets a tracked field at this+0x7c8 to -1
Input checks: Policy id is range checked against array size (unsigned compare, so -1 is rejected silently). Out of range does nothing.
Preconditions
- valid policy index
- player culture initialised
Multiplayer: may-desync: removes active policies; must run identically on all clients. Risk: medium (can evict an active policy and change slots). Confidence of the reading: medium.
Verified from the code
- bounds check on policy id
- writes banned flag
- clears the slot only when banning and the policy is flagged active
- scan for slot entry holding that policy
Inferred
- flag at +0x308 means 'currently active'
- value at +0x7c8 is something like a last-removed-policy marker
Open questions
- what +0x7c8 means
- if slot not found, +0x7c8 stays unchanged (return before)
SetPolicyChangeMade
Arguments: bNewValue — true marks a change made this turn, false clears it
Writes
- Culture+0x7c8 = current turn or -1
Input checks: None.
Multiplayer: may-desync, writes synchronised turn marker. Risk: low (single value write). Confidence of the reading: high.
SetReplacedPolicySlot
Arguments: eReplacedSlot — slot type being replaced; eAddedSlot — slot type taking its place; bReplacesAll — stored flag, whether it replaces all such slots (inferred)
Writes
- entry appended to list at Culture+0x230
- all policies cleared
Side effects
- SetCurrentGovernment re-applies current government
Input checks: No validation or duplicate check.
Multiplayer: may-desync, edits slots and clears policies. Risk: high (clears all policies). Confidence of the reading: medium.