Home › Dev CE (experimental) › PlayerUnits

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.

PlayerUnits

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

Method Signature Purpose (AI-written, inferred) Tested Engine function Current
AddEmbarkUnitPass PlayerUnits:AddEmbarkUnitPass(eUnit: integer) Appends a unit type to the player's embark-pass list (units allowed to embark) stored in the variant vector at +0x2a0. plumbing ✓ — 0x34c410
AddRandomBasePromotion PlayerUnits:AddRandomBasePromotion(eUnit: integer) → boolean Picks a random promotion of the unit's promotion class that the player does not already have as a base promotion for this unit type, adds it via ChangeBasePromotionCount, and assigns it to existing units. plumbing ✓ — 0x34c480
AddUnlimitedPromotionChoiceUnitType PlayerUnits:AddUnlimitedPromotionChoiceUnitType(eUnit: integer) Adds a unit type to the list (+0xe8) of types that receive unlimited promotion choices, unless already present. plumbing ✓ — 0x34c670
AssignBasePromotionsToUnits PlayerUnits:AssignBasePromotionsToUnits() For each unit the player owns, grants every base promotion (matching unit type with positive count) the unit does not yet have. plumbing ✓ — 0x34c800
CanEmbark PlayerUnits:CanEmbark(eUnit: integer) → boolean Returns whether the player can embark the given unit type: false for barbarians, true if a global parameter allows it, if the unit is in the embark-pass list, or if an owned tech/civic grants embarkation for that unit. plumbing ✓ — 0x34c950
ChangeAddOnDistrictFounding PlayerUnits:ChangeAddOnDistrictFounding(districtHash: integer, unitHash: integer, iDelta: integer) Adds a delta to a counter keyed by district hash and unit hash, recording that a unit can found or add on to a district. plumbing ✓ Player::Units::ChangeAddOnDistrictFounding 0x34cb20
ChangeBasePromotionCount PlayerUnits:ChangeBasePromotionCount(eUnit: integer, ePromotion: integer, iDelta: integer) → boolean Adds iDelta to the count for the (unit type, promotion) base promotion entry, removing the entry when the count drops to 0 or below, or appends a new entry when none exists and iDelta is positive. plumbing ✓ — 0x34cbd0
ChangeExtraBuildCharges PlayerUnits:ChangeExtraBuildCharges(eUnit: integer, iChange: integer) Adds a delta to the extra build charges a player grants to a unit type, clamped at zero. plumbing ✓
ran ±1, reversible ✓, no visible effect
Player::Units::ChangeExtraBuildCharges 0x34cd90
ChangeFreePass PlayerUnits:ChangeFreePass(eBuildUnit: integer) Appends a unit type to the free-pass list (+0x278), then recalculates which unit types the player can ever train. plumbing ✓ — 0x949640
ChangeProductionModifier PlayerUnits:ChangeProductionModifier(eUnit: integer, iDelta: integer) Adds a delta to a per-unit-type production modifier stored for the player. The delta is scaled by a constant and stored as a fixed-point value. plumbing ✓
ran ±1, reversible ✓, no visible effect
Player::Units::ChangeProductionModifier 0x9497a0
DoEndTurn PlayerUnits:DoEndTurn() End-of-turn processing for the player's units: for non-barbarian players iterates units and applies fallout damage on plots with fallout turns remaining (scaled by a per-unit reduction), sending reporting events. Decompilation is truncated so the rest is unknown. plumbing ✓ — 0x34d690
DoTurnActivate PlayerUnits:DoTurnActivate() At turn start resets and recomputes per-resource hero-related unit counts (vector +0x5c8) from units' definitions, then iterates required resources for a major player; decompilation is truncated. plumbing ✓ — 0x34e9d0
GetCost PlayerUnits:GetCost(eUnit: integer) → number Returns the per-unit-type cost from the player's cost array (+0x1c0), or 0 when the type index is beyond the array. plumbing ✓ — 0x34f550
GetNumUnitsFromCity PlayerUnits:GetNumUnitsFromCity(eUnitType: integer, cityID: integer) → number Counts the player's units of a given type whose origin city ID matches. plumbing ✓ — 0x34f5d0
GetNumUnitsOfType PlayerUnits:GetNumUnitsOfType(eUnit: integer) → number Counts the player's units of the given type. plumbing ✓ — 0x34f6b0
GetResourceCost PlayerUnits:GetResourceCost(eUnit: integer, eMilitaryFormation: integer) → number Returns the resource cost of a unit type from array +0x1e8, doubled for formation 1 (corps) and tripled for formation 2 (army); 0 if out of range. plumbing ✓ — 0x34f6e0
IsProposedPromotion PlayerUnits:IsProposedPromotion(iUnitID: integer, ePromotion: integer) → boolean Checks whether the (unit ID, promotion) pair is in the list of proposed promotions at +0x3c8. plumbing ✓ — 0x34f8e0
RemoveEmbarkUnitPass PlayerUnits:RemoveEmbarkUnitPass(eUnit: integer) Rebuilds the embark-pass list without the first occurrence of the given unit type and writes it back to +0x2a0. plumbing ✓ — 0x34fbf0
RemoveFreePass PlayerUnits:RemoveFreePass(eUnit: integer) Rebuilds the free-pass list without all occurrences of the unit type, writes it to +0x278 and recalculates can-ever-train. plumbing ✓ — 0x34fe20
RemoveUnlimitedPromotionChoiceUnitType PlayerUnits:RemoveUnlimitedPromotionChoiceUnitType(eUnit: integer) Removes the unit type from the unlimited-promotion-choice list (+0xe8) if present. plumbing ✓ — 0x350040
SetBannedProductionYield PlayerUnits:SetBannedProductionYield(eNewYield: integer) Sets which yield type may not be used to produce units and, when a restriction is active, removes non-formation-class-2 units currently at the head of every city's build queue. plumbing ✓ Player::Units::SetBannedProductionYield 0x350cf0
SetCanEverTrain PlayerUnits:SetCanEverTrain() Rebuilds the player's table of unit types that can ever be trained, taking into account unlocked units, civ/leader/level traits, unit properties, and replacement relationships. plumbing ✓ Player::Units::SetCanEverTrain 0x350dc0
SetCorpsArmyUnlockCivic PlayerUnits:SetCorpsArmyUnlockCivic(bLand: boolean, bCorps: boolean, eCivic: integer) Stores the civic that unlocks corps or army for land or naval units: land+corps +0x418, land+army +0x430, naval+corps +0x448, naval+army +0x460. plumbing ✓ — 0x3511f0
SetCorpsArmyUnlockTech PlayerUnits:SetCorpsArmyUnlockTech(bLand: boolean, bCorps: boolean, eTech: integer) Stores the tech that unlocks corps or army: land+corps +0x478, land+army +0x490, naval+corps +0x4a8, naval+army +0x4c0. plumbing ✓ — 0x351260
SetModifiedArmyCorpsStrength PlayerUnits:SetModifiedArmyCorpsStrength(bLand: boolean, bCorps: boolean, iAmount: integer) Adjusts one of four stored strength modifiers by an amount, chosen by whether the unit is land/sea and corps/army. plumbing ✓ Player::Units::SetModifiedArmyCorpsStrength 0x3512d0
SetPromotionSelected PlayerUnits:SetPromotionSelected(iUnitID: integer, ePromotion: integer, bClearProposals: boolean) Records that a promotion has been selected by incrementing its counter in a promotion list, and optionally rebuilds a pending proposals list excluding entries for the given unit id. plumbing ✓ Player::Units::SetPromotionSelected 0x351330

Details

AddEmbarkUnitPass

Arguments: eUnit — Unit type to grant the embark pass for

Writes - Embark unit pass vector at Units+0x2a0 (append)

Input checks: Ignores -1 (NO_UNIT); does not check for duplicates or that the type is valid.

Multiplayer: may-desync, edits synchronised player list. Risk: medium (Allows duplicates and writes player state.). Confidence of the reading: high.

AddRandomBasePromotion

Arguments: eUnit — Unit type to receive a random base promotion

Writes - Base promotion list (+0x3f8..0x400) via ChangeBasePromotionCount - Existing units' promotions via AssignBasePromotionsToUnits

Side effects - Consumes a game random roll labelled 'Random Base Promotion'

Input checks: Returns false for -1 or unit type without a definition; if no candidate remains passes -1 promotion (which fails).

Multiplayer: may-desync, uses game RNG and edits player units. Risk: high (Consumes RNG and promotes units.). Confidence of the reading: medium.

AddUnlimitedPromotionChoiceUnitType

Arguments: eUnit — Unit type to add

Writes - Unlimited-promotion-choice unit type vector at Units+0xe8

Input checks: Checks for duplicates only; no validity or -1 check.

Multiplayer: may-desync, edits synchronised player list. Risk: medium (Writes player state without range check.). Confidence of the reading: high.

AssignBasePromotionsToUnits

Writes - Each owned unit's experience/promotion data (+0x960 via SetPromotion)

Input checks: Skips when the player has no units; no other checks.

Multiplayer: may-desync, changes unit promotions. Risk: medium (Changes promotions of many units.). Confidence of the reading: high.

CanEmbark

Arguments: eUnit — Unit type to test

Input checks: Unit type bounds-checked against definitions; no null handling for owner beyond use.

Multiplayer: read-only, pure check of definitions and player state. Risk: low (Pure check.). Confidence of the reading: medium.

ChangeAddOnDistrictFounding

Arguments: districtHash — hash of the district type; unitHash — hash of the unit type; iDelta — amount added to the counter

Writes - nested hash map (district hash to unit hash to count) in the variant map at this+0x2c8; creates entries on demand

Side effects - allocates new map entries when keys are missing

Input checks: No validation of the hashes; any value creates an entry. Counts can go negative or stay at zero without removal.

Preconditions - gameplay Lua state only - must run on the game thread

Multiplayer: may-desync: direct replicated state write; hash maps must stay identical on all clients. Risk: low (hash-keyed counter with auto-create). Confidence of the reading: medium.

Verified from the code - outer map lookup/insert by district hash, inner lookup/insert by unit hash with initial 0, then adds iDelta

Inferred - nonzero count enables the unit to found that district; semantic taken from the name

Open questions - where the counters are read and how zero or negative values are treated

ChangeBasePromotionCount

Arguments: eUnit — Unit type of the base promotion; ePromotion — Promotion type; iDelta — Amount to add to the count (negative to remove)

Writes - Base promotion vector at Units+0x3e8 (entries of 12 bytes: unit, promotion, count)

Input checks: Returns false for -1 unit or promotion; no delta range check; no definition validity check.

Multiplayer: may-desync, edits synchronised player list. Risk: medium (Does not itself apply promotions to units.). Confidence of the reading: high.

ChangeExtraBuildCharges

Arguments: eUnit — unit type; iChange — delta to add

Writes - per-unit extra build charges array at this+0x318

Side effects - none

Input checks: silently ignores out-of-range or negative unit ids; result clamped to 0

Preconditions - gameplay thread

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

Verified from the code - bounds check 0 <= unit < count at +0x338 - clamps negative sum to 0

Inferred - applies to newly created units of that type (not confirmed)

Open questions - whether existing units are updated

ChangeFreePass

Arguments: eBuildUnit — Unit type to add to the free pass list

Writes - Free pass unit vector at Units+0x278 (append) - Can-ever-train data via SetCanEverTrain

Input checks: No -1 or range check; appends even if present.

Multiplayer: may-desync, edits player list and buildability. Risk: medium (Unchecked append.). Confidence of the reading: medium.

ChangeProductionModifier

Arguments: eUnit — unit type index to modify; iDelta — amount to add (scaled by a small constant, then converted to a fixed-point int)

Writes - per-unit-type int array in a game variable at this+0x200 (production modifier, fixed point)

Side effects - marks the game variable as edited (FAutoVariable edit)

Input checks: Silently does nothing if the unit type is not below the array size; the unsigned compare also rejects negative ids.

Preconditions - gameplay state only - game thread

Multiplayer: may-desync: direct state change, must be applied identically on all clients. Risk: low (bounds-checked simple array add). Confidence of the reading: medium.

Verified from the code - bounds check against this+0x220 - multiplies delta by a float constant then splits into integer and fractional parts packed as integer part shifted by 8 plus 8-bit fraction - adds the packed value into the array slot

Inferred - value is a percentage-like modifier in 8.8 style fixed point - constant is likely 0.01

Open questions - exact constant value and the modifier semantics

DoEndTurn

Writes - Unit damage via Unit manager (fallout damage)

Side effects - Reporting events - Unit manager virtual calls

Input checks: Skips when the player has no units; decompilation is truncated so remaining logic is unknown.

Multiplayer: may-desync, damages units at turn end. Risk: high (Turn-processing function; output truncated.). Confidence of the reading: low.

DoTurnActivate

Writes - Per-resource vector at Units+0x5c8 - Unit Religion-related bool at unit +0x708

Side effects - Reporting event block 0x1153df52

Input checks: No argument; remaining logic is truncated.

Multiplayer: may-desync, turn-start processing of player state. Risk: high (Truncated; changes turn state.). Confidence of the reading: low.

GetCost

Arguments: eUnit — Unit type index

Input checks: Upper bound only (unsigned compare, so -1 returns 0).

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

GetNumUnitsFromCity

Arguments: eUnitType — Unit type to count; cityID — Origin city ID (compared with unit field +0x8a0)

Input checks: None.

Multiplayer: read-only, counts owned units. Risk: low (Pure getter.). Confidence of the reading: high.

GetNumUnitsOfType

Arguments: eUnit — Unit type to count

Input checks: None.

Multiplayer: read-only, counts owned units. Risk: low (Pure getter.). Confidence of the reading: high.

GetResourceCost

Arguments: eUnit — Unit type; eMilitaryFormation — Formation: 1 corps (x2), 2 army (x3), else standard

Input checks: Bounds check on unit type; formation value not validated.

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

IsProposedPromotion

Arguments: iUnitID — Unit ID; ePromotion — Promotion type

Input checks: None.

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

RemoveEmbarkUnitPass

Arguments: eUnit — Unit type to remove one pass for

Writes - Embark unit pass vector at Units+0x2a0 (rebuilt)

Input checks: Ignores -1; silently does nothing if the type is absent.

Multiplayer: may-desync, edits synchronised player list. Risk: medium (Removes only the first copy.). Confidence of the reading: high.

RemoveFreePass

Arguments: eUnit — Unit type to remove

Writes - Free pass vector at Units+0x278 (rebuilt) - Can-ever-train data

Input checks: No -1 check; absent type is a no-op rewrite.

Multiplayer: may-desync, edits player list and buildability. Risk: medium (Rewrites list.). Confidence of the reading: high.

RemoveUnlimitedPromotionChoiceUnitType

Arguments: eUnit — Unit type to remove

Writes - Unlimited-promotion-choice vector at Units+0xe8

Input checks: No-op if absent; no -1 check.

Multiplayer: may-desync, edits synchronised player list. Risk: medium (Writes player state.). Confidence of the reading: high.

SetBannedProductionYield

Arguments: eNewYield — yield type that is banned for unit production

Writes - banned yield value in a tracked variable at this+0x568 - city build queues (PopFront) in each city of the player

Side effects - pops the front item of the build queue of cities whose current production is a unit whose formation class is not 2

Input checks: Unit index is bounds checked against definition list (null definition otherwise, which would then be dereferenced - crash risk). No validation of the yield value.

Preconditions - gameplay state - player with a city list

Multiplayer: may-desync: edits city queues, must run identically everywhere. Risk: medium (mutates build queues; possible null deref on bad definition). Confidence of the reading: medium.

Verified from the code - assigns new yield into this+0x568 via CopyAssignmentDo - only loops when int at this+0x578 equals 1 - loops over cities of player and pops queue front when current unit formation class != 2

Inferred - formation class 2 is probably a civilian or special class - this+0x578 is probably a flag that the ban is active

Open questions - meaning of the 0x578 field and formation class 2 - helper template name suggests different type but writes a YieldTypes

SetCanEverTrain

Writes - per-unit can-ever-train array at this+0x118 (reset to -1, then set to unit index when allowed)

Side effects - resizes and refills the table

Input checks: null definitions handled; per-unit pointers in the definition list assumed non-null

Preconditions - owning player set at this+0x90 - definitions loaded

Multiplayer: safe-deterministic. Risk: medium (bulk rebuild of cached table). Confidence of the reading: medium.

Verified from the code - array at +0x118 set to definition count entries of -1 - units in list at +0x288 are marked allowed immediately - entries with +0x128 value -1 get checked further against level hash cases and properties - unit removed (set to -1) by flag bits at +0x1b8/+0x1b9 or when definition field +0x2d0 not in civ/leader lists - also marks replaced units from list at +0x2b0

Inferred - level hash constants select property hashes for civilization levels (e.g. city-state/free city) - list at +0x2b0 is unit replacement or upgrade targets

Open questions - meaning of the hash constants and flag bits - the function exits through the definition loop end; any additional state set is not seen

SetCorpsArmyUnlockCivic

Arguments: bLand — True for land units, false for naval; bCorps — True for corps slot, false for army slot; eCivic — Civic type that unlocks the formation

Writes - One of four unlock-civic fields in Player::Units

Input checks: No range checks on civic.

Multiplayer: may-desync, writes player field. Risk: low (Single field write.). Confidence of the reading: high.

SetCorpsArmyUnlockTech

Arguments: bLand — True for land units, false for naval; bCorps — True for corps slot, false for army slot; eTech — Tech type that unlocks the formation

Writes - One of four unlock-tech fields in Player::Units

Input checks: No range checks on tech.

Multiplayer: may-desync, writes player field. Risk: low (Single field write.). Confidence of the reading: high.

SetModifiedArmyCorpsStrength

Arguments: bLand — true selects land slots, false naval slots (inferred); bCorps — true selects corps, false army (inferred); iAmount — amount added to the current value

Writes - one of four tracked ints at this+0x4d8, 0x4f0, 0x508, 0x520 (value at +0x10 of each)

Side effects - tracked variable assignment, may notify variable system

Input checks: No validation; any int accepted.

Preconditions - gameplay state

Multiplayer: may-desync: direct state change. Risk: low (simple add to fixed slot). Confidence of the reading: medium.

Verified from the code - four-way selection by two bools - new value is old value plus iAmount (despite the Set name it adds)

Inferred - bool meanings (land vs sea, corps vs army) are deduced from the name

Open questions - which bool order maps to which slot is deduced only from the name

SetPromotionSelected

Arguments: iUnitID — unit id whose pending proposals are dropped; ePromotion — promotion type to mark; bClearProposals — also remove proposals for this unit

Writes - promotion/count pair list at this+0x388 (count of matching entry incremented) - proposal vector at this+0x3b8 (cleared and refilled)

Side effects - allocates a temporary vector copy

Input checks: If promotion not found in the list nothing is incremented (silent). No unit validation.

Preconditions - gameplay state

Multiplayer: may-desync: direct state change. Risk: low (simple list updates). Confidence of the reading: medium.

Verified from the code - linear search of 8-byte pairs for promotion - increments second element of found pair - if bClearProposals copies vector at +0x3c8, clears +0x3b8 and re-adds entries whose id field differs from iUnitID

Inferred - list is promotion with selection count - vector types in the symbol names look mismatched (symbol folding)

Open questions - real meaning of the vectors at 0x3b8 and 0x3c8