Skip to content

Game data

The items data: typed tables, lookups by name, and the generated id enums.

gamedata.data

Static game data from the GGE items payload.

The client builds its combat maths from items_v{version}.json on the GGE CDN. That file is ~20 MB: GameData.require loads it on the first use of an API that needs it, and GameData.load (or EmpireClient.load_game_data) loads it up front. What is parsed is trimmed to the combat-relevant tables, the tables the id enums name and the rewards, and cached on disk per version, so the download happens once per game patch.

GameData.load is the only loader: troop counts and the id generator read the same process-wide copy, so one process downloads the items once.

Classes:

Name Description
GameData

The combat-relevant tables for one items version.

Functions:

Name Description
default_cache_dir

Where trimmed game data is cached (honours XDG_CACHE_HOME).

logger module-attribute

logger = logging.getLogger(__name__)

CACHE_FILENAME_TEMPLATE module-attribute

CACHE_FILENAME_TEMPLATE = 'items_v{version}.trimmed.json'

CAMP_TABLES module-attribute

CAMP_TABLES = ('nomadCamps', 'samuraiCamps', 'factioninvasioncamps', 'allianceInvasionCamps')

EVENT_CAMP_TABLES module-attribute

EVENT_CAMP_TABLES = ('daimyoCastles', 'daimyoTownships')

RAW_TABLES module-attribute

RAW_TABLES = ('bossdungeons', 'specialcamps', 'eventAutoScalingUnitPairings', 'eventAutoScalingToolPairings', 'mainquests')

Tables kept verbatim. The client parses no bossdungeons, pairing or mainquests rows, so their meaning is the server's; it reads specialcamps into two value objects by row type (FactionEventVO.parseAdditionalXmlFromRoot, bundle line 7400), which are not modeled yet.

R module-attribute

R = TypeVar('R', bound=EmpireModel)

GameData pydantic-model

Bases: EmpireModel

The combat-relevant tables for one items version.

Load it explicitly:

data = GameData.load()
data.units[Unit.MEAD_RANGER_L6].range_attack
data.buildings[Building.KEEP_L1].might_value
data.general("Toril").general_id

The tables the id enums name are keyed by their enum: a row whose id the enum lacks (items newer than the enums) is keyed by its plain int, and as the enums are IntEnums, a plain id from a packet indexes every table.

The tables keyed by id enums, titles, construction_item_recipes, scaling_camps, rewards and the two daimyo contract tables are read-only Table mappings that validate a row the first time it is read, so loading costs no validation for them.

Fields:

model_config class-attribute

model_config: ConfigDict = ConfigDict(extra='ignore')

version pydantic-field

version: str

schema_fingerprint pydantic-field

schema_fingerprint: str = ''

Hash of the table fields, so a cache from older tables is not reused.

effect_caps pydantic-field

effect_caps: dict[int, EffectCapDef]

equipment_effects pydantic-field

equipment_effects: dict[int, EquipmentEffectDef]

relic_effects pydantic-field

relic_effects: dict[int, RelicEffectDef]

equipment_sets pydantic-field

equipment_sets: dict[int, list[EquipmentSetDef]]

Each equipment set's threshold rows by set id, in the order listed.

fortifications pydantic-field

fortifications: dict[GameDataId['Building'], FortificationDef]

alliance_buffs pydantic-field

alliance_buffs: dict[int, AllianceBuffDef]

attack_slots pydantic-field

attack_slots: dict[int, AttackSlotDef]

tool_categories pydantic-field

tool_categories: dict[int, ToolCategoryDef]

default_lords pydantic-field

default_lords: dict[int, DefaultLordDef]

vip_levels pydantic-field

vip_levels: dict[int, VipLevelDef]

dungeons pydantic-field

dungeons: list[DungeonDefence]

camps pydantic-field

event_camps pydantic-field

event_camps: dict[str, dict[int, EventCampDef]]

league_brackets pydantic-field

league_brackets: list[LeagueBracketDef]

raw_tables pydantic-field

raw_tables: dict[str, list[Any]]

units cached property

units: Table[GameDataId['Unit'], UnitStats]

Combat units by Unit: the units rows without slotTypes.

tools cached property

tools: Table[GameDataId['Tool'], ToolStats]

Siege and defence tools by Tool: the units rows with slotTypes.

effects cached property

effects: Table[GameDataId['Effect'], EffectDef]

Effects by Effect.

effect_types cached property

effect_types: Table[GameDataId['EffectType'], EffectTypeDef]

Effect types by EffectType.

construction_items cached property

construction_items: Table[GameDataId['ConstructionItem'], ConstructionItemDef]

Construction items by ConstructionItem.

global_effects cached property

global_effects: Table[GameDataId['GlobalEffect'], GlobalEffectDef]

Global effects by GlobalEffect.

general_skills cached property

general_skills: Table[GameDataId['GeneralSkill'], GeneralSkillDef]

General skill levels by GeneralSkill.

legend_skills cached property

legend_skills: Table[GameDataId['LegendSkill'], LegendSkillDef]

Legend skill levels by LegendSkill.

generals cached property

generals: Table[GameDataId['General'], GeneralDef]

Generals by General.

general_abilities cached property

general_abilities: Table[GameDataId['GeneralAbility'], GeneralAbilityDef]

General ability levels by GeneralAbility.

currencies cached property

currencies: Table[GameDataId['CurrencyId'], CurrencyDef]

Currencies by CurrencyId; coins and rubies are not in it.

raid_bosses cached property

raid_bosses: Table[GameDataId['RaidBoss'], RaidBossDef]

Alliance raid bosses by RaidBoss.

buildings cached property

buildings: Table[GameDataId['Building'], BuildingDef]

Buildings, towers, gates, moats and decorations by Building.

researches cached property

researches: Table[GameDataId['Research'], ResearchDef]

Research levels by Research, each with what it costs.

events cached property

events: Table[GameDataId['Event'], EventDef]

Events by Event.

loot_boxes cached property

loot_boxes: Table[GameDataId['LootBox'], LootBoxDef]

Loot boxes by LootBox.

loot_box_types cached property

loot_box_types: Table[GameDataId['LootBoxType'], LootBoxTypeDef]

Loot box types by LootBoxType.

equipment_groups cached property

equipment_groups: Table[GameDataId['EquipmentGroup'], EquipmentGroupDef]

Equipment item groups by EquipmentGroup.

difficulty_types cached property

difficulty_types: Table[GameDataId['DifficultyType'], DifficultyTypeDef]

Event difficulty types by DifficultyType.

quests cached property

quests: Table[GameDataId['QuestId'], QuestDef]

Quests by QuestId.

daily_quests cached property

daily_quests: Table[GameDataId['DailyQuestId'], DailyQuestDef]

Daily quests by DailyQuestId.

titles cached property

titles: Table[GameDataId['Title'], TitleDef]

Titles by Title.

gems cached property

gems: Table[GameDataId['Gem'], GemDef]

Gems by Gem.

sceat_skills cached property

sceat_skills: Table[GameDataId['SceatSkill'], SceatSkillDef]

Sceat skill levels by SceatSkill.

horses cached property

horses: Table[GameDataId['Horse'], HorseStats]

Travel boosters by Horse, the value movements send as HBW.

achievements cached property

achievements: Table[GameDataId['Achievement'], AchievementDef]

Achievement series steps by Achievement.

alliance_crest_colors cached property

alliance_crest_colors: Table[GameDataId['AllianceCrestColor'], AllianceCrestColorDef]

Alliance crest colours by AllianceCrestColor.

alliance_crest_layouts cached property

alliance_crest_layouts: Table[GameDataId['AllianceCrestLayout'], AllianceCrestLayoutDef]

Alliance crest layouts by AllianceCrestLayout.

construction_item_recipes cached property

construction_item_recipes: Table[int, ConstructionItemRecipeDef]

The constructionItemRecipes rows, by the recipe id a blueprint research unlocks.

scaling_camps cached property

scaling_camps: Table[int, ScalingCampDef]

The eventAutoScalingCamps rows, by the scaling camp id a map row names.

daimyo_castle_contracts cached property

daimyo_castle_contracts: Table[int, DaimyoContractDef]

The daimyo castles' alliance contracts by id, in the items' order.

Client: SamuraiDaimyoDataXml.daimyoCastleAllianceContracts (bundle line 13914)

daimyo_township_contracts cached property

daimyo_township_contracts: Table[int, DaimyoContractDef]

The daimyo townships' alliance contracts by id, in the items' order.

Client: SamuraiDaimyoDataXml.daimyoTownshipAllianceContracts (bundle line 13914)

rewards cached property

The rewards by id, each with the collectables it gives.

Client: CastleRewardData.parseXml (bundle line 142323)

reward_list

reward_list(reward_ids: Iterable[int], *, combine: bool = False) -> tuple[Collectable, ...]

What the rewards give, one after the other: a campaign's reward_ids, a title's reward_id.

An id with no reward (-1, or one the items lack) gives nothing.

Parameters:

Name Type Description Default
reward_ids Iterable[int]

The rewards, in order

required
combine bool

Add up the duplicates the client adds up, as some of its dialogs ask for

False

Client: CastleRewardData.getListByIdArray (bundle line 142344)

get_unit

get_unit(wod_id: int) -> UnitStats | None

get_tool

get_tool(wod_id: int) -> ToolStats | None

is_unit

is_unit(wod_id: int) -> bool

Whether the ID is a combat unit rather than a tool or boost item.

is_tool

is_tool(wod_id: int) -> bool

units_by_role

units_by_role(role: UnitRole) -> list[UnitStats]

Every unit of one role (SoldierUnitVO.role, bundle line 12590).

get_horse

get_horse(wod_id: int) -> HorseStats | None

A travel booster by its HBW value.

get_default_lord

get_default_lord(lord_id: int) -> DefaultLordDef | None

A default lord, i.e. one of the negative LID sentinels.

vip_level

vip_level(points: int) -> VipLevelDef | None

The VIP level points VIP points reach: the one whose range holds them, else the top one when points are above 0, else None.

Client: CastleVIPData.getVIPLevelInfoVOByPoints (bundle line 47531)

get_event_camp

get_event_camp(table: str, camp_id: int) -> EventCampDef | None

One rank of a daimyo castle (daimyoCastles) or township (daimyoTownships).

scaling_camp_level

scaling_camp_level(scaling_camp_id: int) -> int | None

The level an event's difficulty scaling gives a camp.

A map row that names a scaling camp overrides every other level source, which is how a chosen difficulty raises a camp for one player only.

event_base_camp_level

event_base_camp_level(event_id: int, player_level: int, *, sub_type: int = 0) -> int | None

Where an invasion event's camps start for a player of this level.

Each event sorts players into level bands and gives every band its own victory range; a camp's base level is the bottom of that range, which is why the same camp is harder for a higher-level player.

league_type

league_type(league_type_id: int, event_id: int = -1, *, sub_type: int = 0) -> LeagueBracketDef | None

A league by the LID a highscore reply names, within its event.

The same id is a different level band in every event, and within an event in every sub type, so both are part of the key; event_id=-1 finds the rows of no event.

Client: AScoreEventVO.generateLeagueLevelsList (bundle line 14971)

resolve_relic_effect

resolve_relic_effect(relic_effect_id: int) -> EffectDef | None

The plain effect a relic bonus id points at.

Relic bonuses index the relic effect table, which then names a normal effect; the two id spaces overlap and disagree.

effect_type_name

effect_type_name(effect_id: int) -> str

Resolve an effect ID to its effect type's name.

dungeon_defense

dungeon_defense(victories: int, kingdom_id: Kingdom = GREEN) -> DungeonDefence | None

The camp defense for a victory count in a kingdom.

raw

raw(table: str) -> list[Any]

An unmodeled table, exactly as the payload had it.

general

general(name: str) -> GeneralDef | None

A general by its generalName, e.g. "Toril".

general_ability

general_ability(name: str, level: int) -> GeneralAbilityDef | None

A general's ability at one level, e.g. ("PowerSurge", 1).

general_skill

general_skill(general_id: int, name: str, level: int) -> GeneralSkillDef | None

One level of a general's skill; the general's id comes from general.

Skill names repeat across generals, so the general is part of the key.

legend_skill

legend_skill(tree_id: int, group_id: int, level: int) -> LegendSkillDef | None

A legend skill by its tree, group and level.

Its effectType is no key: the same effect sits in more than one tree.

currency

currency(json_key: str) -> CurrencyDef | None

A currency by its JSONKey, e.g. "KT" for khan tablets.

C1 and C2 (coins and rubies) are not in this table.

Client: CurrencyData.getXmlCurrencyByKey (bundle line 141194)

effect_type

effect_type(name: str) -> EffectTypeDef | None

An effect type by name, e.g. "fameDefenseBonus".

raid_boss

raid_boss(name: str) -> RaidBossDef | None

An alliance raid boss by name, e.g. "Necromancer".

global_effect

global_effect(name: str) -> GlobalEffectDef | None

A global effect by name.

Names are not quite unique: "SpeedBoost" is two effects of different strength, and asking for it raises with both ids.

unit

unit(unit_type: str, level: int | None = None) -> UnitStats | None

A unit by its type and, optionally, level.

Units have no unique name. A type repeats across levels, and event variants of one unit share its type, often with no level to tell them apart (Ogermace is both 68 and 7), so a lookup that still matches several units raises rather than picking one. A row without a level has level -1, as the client reads it, so level=-1 finds those and level=0 only a row whose level is 0.

tool

tool(tool_type: str, level: int | None = None) -> ToolStats | None

A tool by its type and, optionally, level; see unit for why it can be ambiguous.

Event copies of a tool share its type (EliteComboRam is both 113 and 564).

parse classmethod

parse(version: str, items_data: dict[str, Any]) -> 'GameData'

Trim a full items payload down to the combat-relevant tables.

load classmethod

load(*, refresh: bool = False, cache_dir: str | Path | None = None) -> 'GameData'

The game data for the current items version, downloaded at most once per version.

The version file is checked on every call, so a game patch invalidates the cache on its own. The data is kept for the process and every caller gets the same instance while the version holds: it is shared, so treat it as read-only and never change its tables or rows. Without a kept copy for the version, the disk cache is tried, and only a miss downloads the full payload. Concurrent loads, in threads or processes sharing cache_dir, make one download between them.

When the CDN cannot be reached, the data already kept is returned (with a warning), even if a newer version could not be fetched. Only a load with nothing kept, or with refresh=True, raises. After a failed fetch the CDN is not asked again for five minutes.

Parameters:

Name Type Description Default
refresh bool

Ignore the kept and cached copies and any failure backoff, and re-download

False
cache_dir str | Path | None

Where to keep trimmed data (default: XDG cache dir). It is read and written only when the kept copy is not current, so a call that finds it current returns it whatever cache_dir it was loaded with.

None

Raises:

Type Description
NetworkError

Nothing is kept (or refresh is set) and the CDN could not be reached, now or less than five minutes ago

loaded classmethod

loaded() -> 'GameData | None'

The data the last load in this process gave, or None; never touches the network.

It is the instance load hands every caller, so treat it as read-only.

require classmethod

require() -> 'GameData'

The data loaded in this process, loading it on first use: what the APIs that need game data read.

loaded when there is data, without touching the network; otherwise load, which reads the disk cache when present and downloads only on a miss. Threads that call it at once share one download. After a failed load it raises without another request for five minutes, as load does.

Raises:

Type Description
GameDataNotLoadedError

Nothing is loaded and the game data cannot be loaded

default_cache_dir

default_cache_dir() -> Path

Where trimmed game data is cached (honours XDG_CACHE_HOME).

gamedata.models

Typed rows from the GGE items payload.

Values arrive as strings, so every numeric field relies on pydantic coercion. Tables whose meaning is not yet established are kept raw by GameData instead of being modeled here on a guess.

Classes:

Name Description
UnitStats

A combat unit.

ToolStats

A siege or defense tool.

EffectDef

An effect, e.g. relicOffensiveMeleeBonus.

EffectTypeDef

An effect type, e.g. fameDefenseBonus.

EffectCapDef

The ceiling a group of effects stacks up to.

EffectValue

One bonus of an items row: an effect and its value, an effectID&value entry of the effects column.

EquipmentEffectValue

One bonus of an equipment set or default commander: an equipment effect id and its value.

EffectSpecRow

Base for tables whose bonuses are an effects column of effectID&value entries, comma separated.

EquipmentEffectSpecRow

Base for tables whose effects column names equipment effect ids: equipment sets and default commanders.

ConstructionItemDef

A construction item - the decorations placed on castle buildings.

AllianceBuffDef

One level of an alliance buff.

GlobalEffectDef

A global (event) effect, active for everyone while its event runs.

SceatSkillDef

One level of a sceat skill, from the Hall of Legends trees.

GeneralSkillDef

One level of a general's skill.

FortificationDef

A wall, gate or moat building and the protection it gives.

RelicEffectDef

A relic effect, which is a different id space from a plain effect.

EquipmentEffectDef

A bonus an equipment item can roll.

GemDef

A gem that can be slotted into an equipment item.

EquipmentSetDef

One threshold of an equipment set: the bonuses worn items of the set grant from needed_items on.

LegendSkillDef

One level of a legend skill, e.g. gateReduction.

AttackSlotDef

An attack-screen slot and what unlocking it costs.

ToolCategoryDef

A tool category, e.g. basic.

HorseStats

A travel booster - the value behind the HBW field on movements.

DefaultLordDef

A default commander, one of the negative commander ids.

GeneralAbilityDef

One level of a general's ability, the value set_abilities sends per slot.

CurrencyDef

A currency; json_key is the key the server uses for it in currency lists.

RaidBossDef

An alliance raid boss.

GeneralDef

A general, the hero assigned to a commander.

DungeonDefence

What defends an NPC camp at a given victory count.

NpcCampDefence

An event camp's defense, shared shape across the camp tables.

EventCampDef

One rank of a daimyo castle or township.

LeagueBracketDef

A league: the level band an event sorts a player into, a row of leaguetypes.

Functions:

Name Description
parse_stacks

Parse the wodID+count#wodID+count encoding used for camp defenses.

parse_ids

Parse a comma-separated ID list.

Attributes:

Name Type Description
FIGHT_TYPE_OFFENSIVE
FIGHT_TYPE_DEFENSIVE
ECONOMY_SORT_CATEGORY

FIGHT_TYPE_OFFENSIVE module-attribute

FIGHT_TYPE_OFFENSIVE = 0

FIGHT_TYPE_DEFENSIVE module-attribute

FIGHT_TYPE_DEFENSIVE = 1

ECONOMY_SORT_CATEGORY module-attribute

ECONOMY_SORT_CATEGORY = 7

READING_CACHE module-attribute

READING_CACHE: ContextVar[bool] = ContextVar('reading_game_data_cache', default=False)

True while GameData reads its own cache, whose ints are already parsed values.

UnitStats pydantic-model

Bases: _UnitRow

A combat unit.

GameData.parse takes the units rows without slotTypes as units. The client picks a row's class from name and group instead (CastleWodData.getClassName, bundle line 2057): Barracks, Eventunit, Keep, Kingdomunit and QuickAttack rows are SoldierUnitVOs, while an Unknown row is a bare BasicUnitVO that reads no soldier columns.

Client: SoldierUnitVO.parseXmlNode (bundle line 12531), after BasicUnitVO.parseXmlNode (bundle line 19211)

Fields:

Validators:

wod_id pydantic-field

wod_id: GameDataId['Unit']

Wire key wodID

The unit; required

unit_type pydantic-field

unit_type: str = ''

Wire key type

Unit type, e.g. MeadRanger; shared across levels

role pydantic-field

role: GameDataKey[UnitRole] = ''

Melee or ranged; empty for none

melee_attack pydantic-field

melee_attack: int = 0

Wire key meleeAttack

Base melee attack

range_attack pydantic-field

range_attack: int = 0

Wire key rangeAttack

Base ranged attack

melee_defense pydantic-field

melee_defense: int = 0

Wire key meleeDefence

Base defence against melee

range_defense pydantic-field

range_defense: int = 0

Wire key rangeDefence

Base defence against ranged

loot_value pydantic-field

loot_value: int = 0

Wire key lootValue

Loot one unit carries

mead_supply pydantic-field

mead_supply: int = 0

Wire key meadSupply

Mead upkeep

beef_supply pydantic-field

beef_supply: int = 0

Wire key beefSupply

Beef upkeep

food_supply pydantic-field

food_supply: int = 0

Wire key foodSupply

Food upkeep, before the global food-consumption effect

healing_cost_coins pydantic-field

healing_cost_coins: int = 0

Wire key healingCostC1

Coin cost to heal one, before cost effects

healing_cost_rubies pydantic-field

healing_cost_rubies: int = 0

Wire key healingCostC2

Ruby cost to heal one

hybrid pydantic-field

hybrid: bool = False

Fits either flank

name_text_id property

name_text_id: str

The text id of its name, <type>_name in lower case: BasicUnitVO.getNameString (bundle line 19219).

is_melee property

is_melee: bool

is_ranged property

is_ranged: bool

is_allround property

is_allround: bool

A hybrid unit, which fits either flank (BasicUnitVO.isAllround, bundle line 19318).

attack_value property

attack_value: int

Raw offence, before any commander or equipment effects.

The client adds a global-event bonus on top of this (EFFECT_TYPE_ATTACK_BONUS_UNIT), which is not modeled yet.

is_offensive property

is_offensive: bool

Whether the game treats this unit as an attacker (BasicUnitVO.isOffensive, bundle line 19316).

This is the fightType column, not "has an attack value": a defensive unit such as a halberdier carries a small attack value but is never an auto-fill candidate.

ToolStats pydantic-model

Bases: _UnitRow

A siege or defense tool.

GameData.parse takes the units rows with slotTypes as tools; the client's ToolUnitVO rows are those named Workshop, Dworkshop, Elitetool and Eventtool. effects name plain effect ids; resolve them through effects.

The raw_*_bonus columns are percentages. The client scales them by 0.01 as it parses, so the fractions are the properties of the same name without raw_: scaling in a validator would scale again on every cache round trip.

Client: ToolUnitVO.parseXmlNode (bundle line 6538), after BasicUnitVO.parseXmlNode (bundle line 19211); ToolUnitVO.parseEffects (bundle line 6644)

Fields:

Validators:

wod_id pydantic-field

wod_id: GameDataId['Tool']

Wire key wodID

The tool; required

tool_type pydantic-field

tool_type: str = ''

Wire key type

Tool type, e.g. Ladder; shared across levels, keys the per-wave limit

category pydantic-field

category: GameDataKey[ToolSide] = '0'

Wire key typ

Attack or defence; "0" when the row has none

slot_types pydantic-field

slot_types: tuple[int, ...] = ()

Wire key slotTypes

Attack-screen slot types it fits

raw_allowed_to_attack pydantic-field

raw_allowed_to_attack: str = ''

Wire key allowedToAttack

space+areaType pairs joined by #; see allowed_targets

tool_category pydantic-field

tool_category: GameDataKey[ToolCategory] = ''

Wire key toolCategory

Tool category, e.g. basic; empty for none

amount_per_wave pydantic-field

amount_per_wave: int = -1

Wire key amountPerWave

The row's per-wave limit; -1 when absent. per_wave_limit is the limit that applies

can_attack_npc pydantic-field

can_attack_npc: bool = True

Wire key canBeUsedToAttackNPC

Usable against an NPC target

effects pydantic-field

effects: tuple[EffectValue, ...] = ()

The tool's own effects

raw_wall_bonus pydantic-field

raw_wall_bonus: int = 0

Wire key wallBonus

Wall protection cancelled, in percent

raw_gate_bonus pydantic-field

raw_gate_bonus: int = 0

Wire key gateBonus

Gate protection cancelled, in percent

raw_moat_bonus pydantic-field

raw_moat_bonus: int = 0

Wire key moatBonus

Moat protection cancelled, in percent

raw_def_range_bonus pydantic-field

raw_def_range_bonus: int = 0

Wire key defRangeBonus

Defender ranged strength cancelled, in percent

raw_def_melee_bonus pydantic-field

raw_def_melee_bonus: int = 0

Wire key defMeleeBonus

Defender melee strength cancelled, in percent

raw_off_range_bonus pydantic-field

raw_off_range_bonus: int = 0

Wire key offRangeBonus

Ranged attack added, in percent

raw_off_melee_bonus pydantic-field

raw_off_melee_bonus: int = 0

Wire key offMeleeBonus

Melee attack added, in percent

name_text_id property

name_text_id: str

The text id of its name, <type>_name in lower case: BasicUnitVO.getNameString (bundle line 19219).

wall_bonus property

wall_bonus: float

Wall protection this tool cancels, as a fraction.

gate_bonus property

gate_bonus: float

Gate protection this tool cancels, as a fraction.

moat_bonus property

moat_bonus: float

Moat protection this tool cancels, as a fraction.

def_range_bonus property

def_range_bonus: float

Defender ranged strength this tool cancels, as a fraction.

def_melee_bonus property

def_melee_bonus: float

Defender melee strength this tool cancels, as a fraction.

off_range_bonus property

off_range_bonus: float

Ranged attack this tool adds, as a fraction.

off_melee_bonus property

off_melee_bonus: float

Melee attack this tool adds, as a fraction.

allowed_targets property

allowed_targets: tuple[tuple[int | None, int | None], ...]

(space_id, area_type) pairs this tool may attack.

An empty list means no restriction, and -1 in either position means "any". A position with no leading integer is None, the client's NaN: that pair matches no target but still makes the list a restriction.

Client: BasicUnitVO.parseSpaceIdAreaTypeValues (bundle line 19214)

per_wave_limit property

per_wave_limit: int

How many of this tool one wave may carry; 0 or less means no limit.

An offence support tool - one that fits slot type 10 - is always limited to one, whatever the column says.

Client: ToolUnitVO.amountPerWave (bundle line 6658)

is_attack_tool property

is_attack_tool: bool

typ is ClientConstCastle.ATTACK_TOOL.

is_defense_tool property

is_defense_tool: bool

typ is ClientConstCastle.DEFENSE_TOOL.

is_allowed_by_attack_target

is_allowed_by_attack_target(space_id: int | None, area_type: int | None) -> bool

Whether the tool may attack this target; no list means allowed anywhere.

None for the space or area type means it is unknown and matches any pair; a pair holding the client's NaN matches nothing.

Client: BasicUnitVO.checkIfTargetIsInArray (bundle line 19324)

fits_slot

fits_slot(slot_type: int) -> bool

Whether this tool may go in the given slot type (ToolUnitVO.isToolForSlotType, bundle line 6541).

EffectDef pydantic-model

Bases: _Row

An effect, e.g. relicOffensiveMeleeBonus.

An effect names which bonus an item grants; the effect type says what it modifies, and the cap says what it stacks with.

Fields:

Validators:

effect_id pydantic-field

effect_id: GameDataId['Effect']

Wire key effectID

The effect

name pydantic-field

name: str = ''

effect_type_id pydantic-field

effect_type_id: GameDataId['EffectType'] = 0

Wire key effectTypeID

The effect type it modifies

cap_id pydantic-field

cap_id: int | None = None

Wire key capID

area_type_ids pydantic-field

area_type_ids: tuple[GameDataId[MapItemType], ...] = ()

Wire key areaTypeID

Area types it applies to; empty for every area

is_pvp_fight pydantic-field

is_pvp_fight: bool = False

Wire key isPvPFight

is_pve_fight pydantic-field

is_pve_fight: bool = False

Wire key isPvEFight

space_ids pydantic-field

space_ids: tuple[GameDataId[Kingdom], ...] = ()

Wire key spaceIDs

Kingdoms it applies in, as the client compares them with the area's spaceId; empty for every one

player_relation pydantic-field

player_relation: GameDataKey[PlayerRelation] = ''

Wire key playerRelation

The relationship to the target it needs; empty for any

raid_boss_ids pydantic-field

raid_boss_ids: tuple[GameDataId['RaidBoss'], ...] = ()

Wire key raidBossID

Raid bosses it is tied to; empty for none in particular

applies_to_area

applies_to_area(area_type: int | None) -> bool

Whether the effect counts against a target of this area type; None or below 0 is every area.

Client: BonusVO.matchesConditions (bundle line 5708) checks the area type only above -1

applies_to_space

applies_to_space(space_id: int | None) -> bool

Whether the effect counts in this castle space; None or below 0 is every space.

Client: BonusVO.matchesConditions (bundle line 5708) checks the space only above -1

applies_to_relation

applies_to_relation(relation: PlayerRelation | str | None) -> bool

Whether the effect counts given the relationship to the target.

An unconditioned effect always counts; passing None leaves conditioned ones in, since the relationship is unknown rather than absent.

is_for_raid_boss

is_for_raid_boss(raid_boss_id: int) -> bool

Whether the effect counts against this raid boss.

Client: EffectVO.isForRaidBoss (bundle line 41705).

applies_to_raid_boss

applies_to_raid_boss(raid_boss_id: int | None) -> bool

Whether the effect counts against this raid boss; None keeps every effect.

Client: EffectVO.isForRaidBoss (bundle line 41705) once a boss is known.

applies_to_fight

applies_to_fight(*, player_target: bool | None) -> bool

Whether the effect counts in this kind of fight.

Some effects are flagged for player fights only and some for NPC fights only; an unflagged effect counts in both.

EffectTypeDef pydantic-model

Bases: _Row

An effect type, e.g. fameDefenseBonus.

Fields:

effect_type_id pydantic-field

effect_type_id: GameDataId['EffectType']

Wire key effectTypeID

The effect type

name pydantic-field

name: str = ''

sort_category pydantic-field

sort_category: int | None = None

Wire key sortCategory

combat_type pydantic-field

combat_type: int | None = None

Wire key combatType

is_economy property

is_economy: bool

Economy effects, which every combat filter strategy drops.

Category 7 in the client's own grouping.

EffectCapDef pydantic-model

Bases: _Row

The ceiling a group of effects stacks up to.

A row without maxTotalBonus - cap 99 among them - is uncapped, which is why the field is optional rather than defaulting to zero.

Fields:

cap_id pydantic-field

cap_id: int

Wire key capID

max_total_bonus pydantic-field

max_total_bonus: float | None = None

Wire key maxTotalBonus

is_uncapped property

is_uncapped: bool

EffectValue pydantic-model

Bases: _EffectEntry

One bonus of an items row: an effect and its value, an effectID&value entry of the effects column.

The client reads the value with the class its effect's type names (BonusVO.parseFromValueString, bundle line 5706): one number (EffectValueSimple, bundle line 17751), wodID+value pairs joined by # (EffectValueWodID and EffectValueMap, bundle lines 17699 and 31617) or ids joined by # (EffectValueIdList, bundle line 62242). Which one applies needs the effect types table, so values keeps the numbers in that structure: 10 is ((10,),), 686+30#687+30 is ((686, 30), (687, 30)) and 1#2 is ((1,), (2,)).

The numbers stay plain even where they are ids: the key of a wodID+value pair is a wod id (EffectValueWodID reads Number of it), and an id list names whatever its effect type unlocks, so which table they index depends on the effect type, not on the column.

Fields:

id_field class-attribute

id_field: str = 'effect_id'

effect_id pydantic-field

effect_id: GameDataId['Effect']

The effect

EquipmentEffectValue pydantic-model

Bases: _EffectEntry

One bonus of an equipment set or default commander: an equipment effect id and its value.

The id indexes GameData.equipment_effects, not the effects table; equipment effects have no enum.

Client: EquipmentBonusVO.parseEquipmentFromValueString (bundle line 20940)

Fields:

id_field class-attribute

id_field: str = 'equipment_effect_id'

equipment_effect_id pydantic-field

equipment_effect_id: int

The equipment effect, a GameData.equipment_effects key

EffectSpecRow pydantic-model

Bases: _Row

Base for tables whose bonuses are an effects column of effectID&value entries, comma separated.

Construction items, alliance buffs, global effects, sceat skills, general skills and gems name plain effect ids this way, each parsed with BonusVO.parseFromValueString (bundle line 5706): construction items in ConstructionItemVO.parseBoni (bundle line 47721), alliance buffs in AllianceBuffVO.fillFromParamXml (bundle line 70575), global effects in GlobalEffectVO.parseXml (bundle line 143698), sceat skills in CastleSceatSkillVO.parseBoni (bundle line 23075), general skills in GeneralSkillVO.parseXML (bundle line 113368) and gems in CastleGemVO.parseXML (bundle line 28295).

Fields:

effects pydantic-field

effects: tuple[EffectValue, ...] = ()

The bonuses it grants

EquipmentEffectSpecRow pydantic-model

Bases: _Row

Base for tables whose effects column names equipment effect ids: equipment sets and default commanders.

Client: XmlEquipmentSetVO.addEffect (bundle line 144229), DefaultLordVO.parseFromXml (bundle line 102001)

Fields:

Validators:

effects pydantic-field

effects: tuple[EquipmentEffectValue, ...] = ()

The bonuses it grants

CastleEffectValue pydantic-model

Bases: _Row

One fixed bonus of a construction item: a column named after the bonus, and its value.

Client: CastleEffectVO.createFromXML (bundle line 79059)

Fields:

effect pydantic-field

effect: CastleEffect

The bonus, the column's name

value pydantic-field

value: float

Number of the column; NaN when it is no number

from_row classmethod

from_row(row: Mapping[str, object]) -> list[CastleEffectValue]

Each bonus column with text in it, in the client's order of the bonuses.

ConstructionItemDef pydantic-model

Bases: EffectSpecRow

A construction item - the decorations placed on castle buildings.

Their bonuses are real combat bonuses: the flank unit limit item grants +2% per level, so a level 15 one is the +30% a player sees on the flanks. Besides effects, many rows grant fixed bonuses in columns of their own (castle_effects), which the game lists first.

Client: ConstructionItemVO.fillFromParamXML (bundle line 47718)

Fields:

Validators:

construction_item_id pydantic-field

construction_item_id: GameDataId['ConstructionItem']

Wire key constructionItemID

The construction item

name pydantic-field

name: str = ''

group_id pydantic-field

group_id: int = 0

Wire key constructionItemGroupID

level pydantic-field

level: int = 0

rareness_id pydantic-field

rareness_id: int = 0

Wire key rarenessID

slot_type_id pydantic-field

slot_type_id: int = 0

Wire key slotTypeID

effect_group_id pydantic-field

effect_group_id: int = 0

Wire key constructionItemEffectGroupID

is_premium pydantic-field

is_premium: bool = False

Wire key isPremium

A premium item; any text in the column counts

castle_effects pydantic-field

castle_effects: tuple[CastleEffectValue, ...] = ()

The fixed bonuses, one per bonus column with text in it

AllianceBuffDef pydantic-model

Bases: EffectSpecRow

One level of an alliance buff.

Fields:

alliance_buff_id pydantic-field

alliance_buff_id: int

Wire key allianceBuffID

series_id pydantic-field

series_id: GameDataId[AllianceBuffType] = 0

Wire key allianceBuffSeriesID

The upgrade or boost the level belongs to

level pydantic-field

level: int = 0

max_level pydantic-field

max_level: int = 0

Wire key maxLevel

GlobalEffectDef pydantic-model

Bases: EffectSpecRow

A global (event) effect, active for everyone while its event runs.

Fields:

global_effect_id pydantic-field

global_effect_id: GameDataId['GlobalEffect']

Wire key globalEffectID

The global effect

name pydantic-field

name: str = ''

boost_value pydantic-field

boost_value: float = 0

Wire key boostValue

min_level pydantic-field

min_level: int = 0

Wire key minLevel

max_level pydantic-field

max_level: int = 0

Wire key maxLevel

SceatSkillDef pydantic-model

Bases: EffectSpecRow

One level of a sceat skill, from the Hall of Legends trees.

Fields:

skill_id pydantic-field

skill_id: GameDataId['SceatSkill']

Wire key skillID

The sceat skill

skill_group_id pydantic-field

skill_group_id: int = 0

Wire key skillGroupID

level pydantic-field

level: int = 0

skill_tree_id pydantic-field

skill_tree_id: int = 0

Wire key skillTreeID

tier pydantic-field

tier: int = 0

GeneralSkillDef pydantic-model

Bases: EffectSpecRow

One level of a general's skill.

Fields:

skill_id pydantic-field

skill_id: GameDataId['GeneralSkill']

Wire key skillID

The general skill

general_id pydantic-field

general_id: GameDataId['General'] = 0

Wire key generalID

The general it belongs to

name pydantic-field

name: str = ''

skill_group_id pydantic-field

skill_group_id: int = 0

Wire key skillGroupID

level pydantic-field

level: int = 0

tier pydantic-field

tier: int = 0

FortificationDef pydantic-model

Bases: _Row

A wall, gate or moat building and the protection it gives.

The bonuses are the items columns, i.e. percentages: a level 3 castle wall reads 70 and protects by 0.70 once scaled.

Fields:

wod_id pydantic-field

wod_id: GameDataId['Building']

Wire key wodID

The wall, gate or moat

label pydantic-field

label: str = ''

Wire key comment2

level pydantic-field

level: int = 0

wall_bonus pydantic-field

wall_bonus: float = 0

Wire key wallBonus

gate_bonus pydantic-field

gate_bonus: float = 0

Wire key gateBonus

moat_bonus pydantic-field

moat_bonus: float = 0

Wire key moatBonus

RelicEffectDef pydantic-model

Bases: _Row

A relic effect, which is a different id space from a plain effect.

A relic item's bonus ids index this table, not effects: id 4 is perceptionBonus as a plain effect but gateReduction as a relic effect. Resolving in the wrong space yields a plausible, wrong answer.

Fields:

relic_effect_id pydantic-field

relic_effect_id: int

Wire key id

effect_id pydantic-field

effect_id: GameDataId['Effect'] = 0

Wire key effectID

The effect it resolves to

minimum_value pydantic-field

minimum_value: float = 0

Wire key minimumValue

maximum_value pydantic-field

maximum_value: float = 0

Wire key maximumValue

relic_effect_type pydantic-field

relic_effect_type: GameDataKey[RelicEffectType] = ''

Wire key relicEffectType

Its kind; empty for none

EquipmentEffectDef pydantic-model

Bases: _Row

A bonus an equipment item can roll.

Client: XmlEquipmentEffectVO.parseXml (bundle line 144158)

Fields:

Validators:

equipment_effect_id pydantic-field

equipment_effect_id: int

Wire key equipmentEffectID

The id an item's bonus row names

effect_id pydantic-field

effect_id: GameDataId['Effect'] = -1

Wire key effectID

The effect it resolves to; -1 when unset

bonus pydantic-field

bonus: int = 0

Bonus value

wearer_id pydantic-field

wearer_id: GameDataId[WearerType] = -1

Wire key wearerID

Who can roll it

item_group_ids pydantic-field

item_group_ids: tuple[GameDataId['EquipmentGroup'], ...] = ()

Wire key itemGroupID

The item groups that can roll it

ignore_cap pydantic-field

ignore_cap: bool = False

Wire key ignoreCap

The bonus escapes its effect's cap

GemDef pydantic-model

Bases: EffectSpecRow

A gem that can be slotted into an equipment item.

Its effects name plain effect ids.

Client: CastleGemVO.parseXML (bundle lines 28287-28291)

Fields:

gem_id pydantic-field

gem_id: GameDataId['Gem']

Wire key gemID

The gem, as in Equipment.gem_id

level pydantic-field

level: int = 0

Wire key gemLevelID

Gem level; 0 for a unique gem

reuse_asset_of_gem_id pydantic-field

reuse_asset_of_gem_id: GameDataId['Gem'] = -1

Wire key reuseAssetOfGemID

The gem whose look and name it shares; -1 for its own

set_id pydantic-field

set_id: int = -1

Wire key setID

Equipment set the gem counts toward; -1 for none

trigger_chance pydantic-field

trigger_chance: int = 100

Wire key triggerChance

Trigger chance; the effect totals do not apply it

EquipmentSetDef pydantic-model

Bases: EquipmentEffectSpecRow

One threshold of an equipment set: the bonuses worn items of the set grant from needed_items on.

Its effects name equipment effect ids.

Client: EquipmentXml.parseEquipmentSets (bundle line 144122) groups the rows by setID; XmlEquipmentSetVO.addEffect (bundle line 144227) parses each effect with EquipmentBonusVO.parseEquipmentFromValueString (bundle line 20940).

Fields:

Validators:

row_id pydantic-field

row_id: int = -1

Wire key ID

Row id

set_id pydantic-field

set_id: int

Wire key setID

Equipment set id, as in Equipment.set_id and GemDef.set_id

needed_items pydantic-field

needed_items: int = 0

Wire key neededItems

Set items and gems worn from which the bonuses apply

LegendSkillDef pydantic-model

Bases: _Row

One level of a legend skill, e.g. gateReduction.

Fields:

skill_id pydantic-field

skill_id: GameDataId['LegendSkill']

Wire key skillID

The legend skill

level pydantic-field

level: int = 0

tier pydantic-field

tier: int = 0

skill_tree_id pydantic-field

skill_tree_id: int = 0

Wire key skillTreeID

skill_group_id pydantic-field

skill_group_id: int = 0

Wire key skillGroupID

effect_type pydantic-field

effect_type: str = ''

Wire key effectType

total_effect_value pydantic-field

total_effect_value: float = 0

Wire key totalEffectValue

total_cost_skill_points pydantic-field

total_cost_skill_points: int = 0

Wire key totalCostSkillPoints

AttackSlotDef pydantic-model

Bases: _Row

An attack-screen slot and what unlocking it costs.

Fields:

slot_id pydantic-field

slot_id: int

Wire key slotID

Attack slot id

cost_rubies pydantic-field

cost_rubies: int = 0

Wire key costC2

Rubies to unlock the slot

ToolCategoryDef pydantic-model

Bases: _Row

A tool category, e.g. basic.

Fields:

tool_category_id pydantic-field

tool_category_id: int

Wire key toolCategoryID

name pydantic-field

name: str = ''

HorseStats pydantic-model

Bases: _Row

A travel booster - the value behind the HBW field on movements.

The game names a horse only by its button's place in the travel dialog, the tooltip text horse<n> (ACastlePostActionDialog.calculateTooltip, bundle line 27269), not by its row, so the Horse enum is named from the two designer labels.

Client: HorseTravelboosterVO.parseXmlNode (bundle line 118814) after AVisualVO.parseXmlNode (bundle line 17800), read from the horses table

Fields:

Validators:

wod_id pydantic-field

wod_id: GameDataId['Horse']

Wire key wodID

The horse, the value sent as HBW

source pydantic-field

source: str = ''

Wire key name

The row's name, Horse for every row

group pydantic-field

group: str = ''

The row's group, Travelbooster for every row

label pydantic-field

label: str = ''

Wire key comment2

Designer label the game does not read, e.g. Warhorse or Fast Ship

building_label pydantic-field

building_label: str = ''

Wire key comment1

Designer label the game does not read, e.g. Stable1 or Harbor3

horse_type pydantic-field

horse_type: str = ''

Wire key type

The horse's type within its building

unit_boost pydantic-field

unit_boost: int = 0

Wire key unitBoost

Travel speed bonus percent for troops

market_boost pydantic-field

market_boost: int = 0

Wire key marketBoost

Travel speed bonus percent for traders

spy_boost pydantic-field

spy_boost: int = 0

Wire key spyBoost

Travel speed bonus percent for spies

cost_factor_c1 pydantic-field

cost_factor_c1: float = 0

Wire key costFactorC1

Coin cost multiplier; 0 when not paid in coins

cost_factor_c2 pydantic-field

cost_factor_c2: float = 0

Wire key costFactorC2

Ruby cost multiplier; 0 when not paid in rubies

is_instant_spy_horse pydantic-field

is_instant_spy_horse: bool = False

Wire key isInstantSpyHorse

Can be paid with feathers as well as rubies

DefaultLordDef pydantic-model

Bases: EquipmentEffectSpecRow

A default commander, one of the negative commander ids.

-14 is the bought premium commander, -15 the commander of a robber baron attack, -21 the NPC that holds a camp, and so on. Its effects name equipment effect ids.

Client: DefaultLordVO.parseFromXml (bundle line 101999) parses each effect with EquipmentBonusVO.parseEquipmentFromValueString.

Fields:

Validators:

lord_id pydantic-field

lord_id: int

Wire key lordID

lord_type pydantic-field

lord_type: str = ''

Wire key type

wearer_id pydantic-field

wearer_id: GameDataId[WearerType] = 0

Wire key wearerID

Who wears it

GeneralAbilityDef pydantic-model

Bases: _Row

One level of a general's ability, the value set_abilities sends per slot.

Client: GeneralAbilityXmlVO.fillFromParamXml (bundle line 113203), keyed by abilityID in GeneralsData (bundle line 113021)

Fields:

Validators:

ability_id pydantic-field

ability_id: GameDataId['GeneralAbility'] = 0

Wire key abilityID

The ability, the value set_abilities sends

name pydantic-field

name: str = ''

Ability name, unique per level

ability_group_id pydantic-field

ability_group_id: int = 0

Wire key abilityGroupID

The group the levels share

level pydantic-field

level: int = 0

Ability level

ability_trigger_id pydantic-field

ability_trigger_id: int = 0

Wire key abilityTriggerID

What triggers the ability

trigger_per_wave pydantic-field

trigger_per_wave: int = 0

Wire key triggerPerWave

Triggers per wave

ability_attack_effect_id pydantic-field

ability_attack_effect_id: int = 0

Wire key abilityAttackEffectID

Effect while attacking

ability_defense_effect_id pydantic-field

ability_defense_effect_id: int = 0

Wire key abilityDefenseEffectID

Effect while defending

CurrencyDef pydantic-model

Bases: _Row

A currency; json_key is the key the server uses for it in currency lists.

The caps, rareness and hidden flags the client reads from other tables are not parsed.

Client: XmlCurrencyVO.parseXml (bundle line 141282), read from the currencies table by CurrencyData.parseXml (bundle line 141151)

Fields:

Validators:

currency_id pydantic-field

currency_id: GameDataId['CurrencyId'] = -1

Wire key currencyID

The currency; -1 when unset

name pydantic-field

name: str = ''

Wire key Name

Internal name

json_key pydantic-field

json_key: str = ''

Wire key JSONKey

The key the server uses for it, e.g. GXP1

asset_name pydantic-field

asset_name: str = ''

Wire key assetName

Icon asset name

name_text_id property

name_text_id: str

The text id of its name, currency_name_<assetName or Name>.

Client: CollectableItemGenericCurrencyVO.getNameTextId and getNameOrAssetName (bundle lines 5267 and 5273)

VipLevelDef pydantic-model

Bases: _Row

A VIP level: the VIP points it spans and the premium commanders it gives free each day.

The other bonuses the client reads from the row are not parsed.

Client: VIPLevelInfoVO.parseConfigXML and inPointRange (bundle lines 77271, 77287), read from the viplevels table by CastleVIPData.parseVIPLevels (bundle line 47518)

Fields:

Validators:

vip_level_id pydantic-field

vip_level_id: int = -1

Wire key vipLevelID

VIP level, 1 and up

min_points pydantic-field

min_points: int = 0

Wire key thresholdMin

The fewest VIP points at this level

max_points pydantic-field

max_points: int = 0

Wire key thresholdMax

The most VIP points at this level

free_premium_commanders_per_day pydantic-field

free_premium_commanders_per_day: int = 0

Wire key freePremiumGeneralsPerDay

Premium commanders a day that cost no rubies while VIP time runs

in_point_range

in_point_range(points: int) -> bool

Whether points VIP points fall in this level, both ends included.

RaidBossDef pydantic-model

Bases: _Row

An alliance raid boss.

Client: AllianceRaidbossVO.parseXML (bundle line 113835), read from the raidBosses table by RaidBossData (bundle line 113671)

Fields:

Validators:

raid_boss_id pydantic-field

raid_boss_id: GameDataId['RaidBoss'] = 0

Wire key raidBossID

The raid boss

name pydantic-field

name: str = ''

Internal name, unique

rarity pydantic-field

rarity: int = 0

Rarity

GeneralDef pydantic-model

Bases: _Row

A general, the hero assigned to a commander.

Client: GeneralXmlVO.fillFromParamXml (bundle line 33102)

Fields:

general_id pydantic-field

general_id: GameDataId['General']

Wire key generalID

The general

name pydantic-field

name: str = ''

Wire key generalName

Internal name, unique per general

raw_attack_slots pydantic-field

raw_attack_slots: str = ''

Wire key attackSlots

raw_defense_slots pydantic-field

raw_defense_slots: str = ''

Wire key defenseSlots

rarity_id pydantic-field

rarity_id: int = 0

Wire key generalRarityID

max_level pydantic-field

max_level: int = 0

Wire key maxLevel

max_star_level pydantic-field

max_star_level: int = 0

Wire key maxStarLevel

attack_slots property

attack_slots: tuple[int, ...]

defense_slots property

defense_slots: tuple[int, ...]

DungeonDefence pydantic-model

Bases: _Row

What defends an NPC camp at a given victory count.

The per-flank fields use the wodID+count#wodID+count encoding; read them through the parsed properties.

Fields:

count_victories pydantic-field

count_victories: int = 0

Wire key countVictories

kingdom_id pydantic-field

kingdom_id: GameDataId[Kingdom] = 0

Wire key kID

The kingdom

lord_id pydantic-field

lord_id: int = 0

Wire key lordID

skip_costs pydantic-field

skip_costs: int = 0

Wire key skipCosts

raw_units_left pydantic-field

raw_units_left: str = ''

Wire key unitsL

raw_units_middle pydantic-field

raw_units_middle: str = ''

Wire key unitsM

raw_units_right pydantic-field

raw_units_right: str = ''

Wire key unitsR

raw_units_keep pydantic-field

raw_units_keep: str = ''

Wire key unitsK

raw_tools_left pydantic-field

raw_tools_left: str = ''

Wire key toolL

raw_tools_middle pydantic-field

raw_tools_middle: str = ''

Wire key toolM

raw_tools_right pydantic-field

raw_tools_right: str = ''

Wire key toolR

units_left property

units_left: list[tuple[int, int]]

units_middle property

units_middle: list[tuple[int, int]]

units_right property

units_right: list[tuple[int, int]]

units_keep property

units_keep: list[tuple[int, int]]

tools_left property

tools_left: list[tuple[int, int]]

tools_middle property

tools_middle: list[tuple[int, int]]

tools_right property

tools_right: list[tuple[int, int]]

total_units

total_units() -> int

Defending units across every flank and the keep.

NpcCampDefence pydantic-model

Bases: _Row

An event camp's defense, shared shape across the camp tables.

Covers the nomad, samurai, faction invasion and alliance invasion camps.

Fields:

count_victory pydantic-field

count_victory: int = 0

Wire key countVictory

def_strength pydantic-field

def_strength: int = 0

Wire key defStrength

raw_defense_units pydantic-field

raw_defense_units: str = ''

Wire key defenceUnits

raw_defense_tools pydantic-field

raw_defense_tools: str = ''

Wire key defenceTools

wall_bonus pydantic-field

wall_bonus: float = 0

Wire key wallBonus

gate_bonus pydantic-field

gate_bonus: float = 0

Wire key gateBonus

lord_id pydantic-field

lord_id: int = 0

Wire key lordID

guards pydantic-field

guards: int = 0

unit_wall_count pydantic-field

unit_wall_count: int = 0

Wire key unitWallCount

cool_down pydantic-field

cool_down: int = 0

Wire key coolDown

dungeon_level pydantic-field

dungeon_level: int = 0

Wire key dungeonlevel

defense_unit_ids property

defense_unit_ids: tuple[int, ...]

defense_tool_ids property

defense_tool_ids: tuple[int, ...]

EventCampDef pydantic-model

Bases: _Row

One rank of a daimyo castle or township.

A map row names the rank rather than the level, so the level, and the fortification that comes with it, are looked up here.

Fields:

camp_id pydantic-field

camp_id: int = 0

Wire key id

rank pydantic-field

rank: int = 0

level pydantic-field

level: int = 0

wall_bonus pydantic-field

wall_bonus: float = 0

Wire key wallBonus

gate_bonus pydantic-field

gate_bonus: float = 0

Wire key gateBonus

moat_bonus pydantic-field

moat_bonus: float = 0

Wire key moatBonus

guards pydantic-field

guards: int = 0

unit_wall_count pydantic-field

unit_wall_count: int = 0

Wire key unitWallCount

LeagueBracketDef pydantic-model

Bases: _Row

A league: the level band an event sorts a player into, a row of leaguetypes.

Its league_type_id is the LID of the highscore commands. Ids repeat across events, and within an event across sub types. An invasion camp's base level is the band's lower victory count, so this is also what says how hard the samurai camps are for a player of a given level.

Client: AScoreEventVO.generateLeagueLevelsList (bundle line 14971), LeagueTypeVO.parseXML (bundle line 91460)

Fields:

Validators:

league_type_id pydantic-field

league_type_id: int | None = None

Wire key leaguetypeID

League type id; None when the row has none

event_id pydantic-field

event_id: GameDataId['Event'] | None = None

Wire key eventID

The event it belongs to; -1 for none, None when the row has none

sub_type pydantic-field

sub_type: int = 0

Wire key subType

The event's sub type, e.g. a Berimond faction

min_level pydantic-field

min_level: int = 0

Wire key minLevel

Lowest player level in the league

max_level pydantic-field

max_level: int = 0

Wire key maxLevel

Highest player level in the league

victory_min pydantic-field

victory_min: int = 0

Wire key countVictoryMin

Lower victory count

victory_max pydantic-field

victory_max: int = 0

Wire key countVictoryMax

Upper victory count

parse_stacks

parse_stacks(value: str | None) -> list[tuple[int, int]]

Parse the wodID+count#wodID+count encoding used for camp defenses.

Unparseable segments are skipped rather than failing the row.

parse_ids

parse_ids(value: str | None) -> tuple[int, ...]

Parse a comma-separated ID list.

is_castle_effect_column

is_castle_effect_column(column: str) -> bool

Whether a constructionItems column is a fixed bonus (CastleEffectValue).

gamedata.tables

Typed rows of the items tables the generated id enums name: buildings, researches, events, loot boxes, equipment groups, difficulty types, quests, daily quests, titles, achievements and alliance crest layouts and colours, plus difficulty scaling camps and the rewards.

Each model reads the columns its client value object reads, with the same defaults. The rewards rows are read into collectables (CollectableParserX2CRewards, bundle line 62897); the costs and other collectable columns the client reads with CollectableParserX2CList (bundle line 62874) from other tables are not read yet.

Classes:

Name Description
BuildingDef

A building: what every building, tower, gate, moat and decoration row has in common.

ResearchDef

One level of a research.

EventDef

An event: who sees it and where.

LootBoxDef

A loot box.

LootBoxTypeDef

A loot box type, whose keys count toward a free box.

EquipmentGroupDef

An equipment item group, as equipment effects name them.

DifficultyTypeDef

An event difficulty type, e.g. easyPlus.

QuestCondition

One thing a quest counts: a type+amount+data part of its conditions.

QuestDef

A quest: where it shows, what unlocks it and what it counts.

DailyQuestDef

A daily quest.

TitleDef

A title of the glory, Berimond or Storm Islands title systems.

AchievementCondition

One thing an achievement counts: a type+amount+params part of its conditions.

AchievementDef

One step of an achievement series.

AllianceCrestColorDef

A colour an alliance crest can use.

AllianceCrestLayoutDef

A layout an alliance crest can use, and the bonuses it grants.

ConstructionItemRecipeDef

A recipe that crafts a construction item, one of a blueprint's.

ScalingCampDef

A camp of an event's difficulty scaling: the level and costs a chosen difficulty gives it.

DaimyoContractDef

An alliance contract of the daimyo event: one level of a contract rank.

RewardDef

One reward of the items: what it gives, and to whom.

Functions:

Name Description
row_id

The row's own id, parseInt of it; a row without one is skipped, as nothing can look it up.

Attributes:

Name Type Description
RewardId

The id of a rewards row, whose collectables GameData.reward_list gives.

RewardId module-attribute

RewardId = NewType('RewardId', int)

The id of a rewards row, whose collectables GameData.reward_list gives.

The rows have no name, so no generated enum names them; this type marks the id space instead.

BuildingDef pydantic-model

Bases: EffectSpecRow

A building: what every building, tower, gate, moat and decoration row has in common.

The per-building columns the client's building subclasses read on top (storage, production, hospital capacity, ...) are not read; fortifications has the walls, gates and moats. Nor are the collectable lists AShopVO.parseXmlNode reads with its items parsers: the cost* columns (costs) other than costC2, the sell* columns other than sellC1 (the sell list) and tempServerCostWood and tempServerCostStone (temporary server repair costs).

Client: AVisualVO.parseXmlNode (bundle line 17800), AShopVO.parseXmlNode (bundle lines 31713-31715), ABasicBuildingVO.parseXmlNode, parseEffects and parseAreaSpecificEffects (bundle lines 17842-17864)

Fields:

Validators:

building_id pydantic-field

building_id: GameDataId['Building']

Wire key wodID

The building

name pydantic-field

name: str = ''

Building name, shared across levels, e.g. Keep

group pydantic-field

Building group, e.g. Building or Tower

building_type pydantic-field

building_type: str = ''

Wire key type

Building type, e.g. Level1; empty for none

level pydantic-field

level: int = -1

Upgrade level; -1 when the row has none

required_level pydantic-field

required_level: int = 0

Wire key requiredLevel

Player level needed to build it

required_legend_level pydantic-field

required_legend_level: int = 0

Wire key requiredLegendLevel

Legend level needed to build it

early_unlock_required_level pydantic-field

early_unlock_required_level: int = 0

Wire key earlyUnlockRequiredLevel

Player level from which it can be unlocked early

upgrade_building_id pydantic-field

upgrade_building_id: GameDataId['Building'] = 0

Wire key upgradeWodID

The building it upgrades to; 0 for none

downgrade_building_id pydantic-field

downgrade_building_id: GameDataId['Building'] = 0

Wire key downgradeWodID

The building it downgrades to; 0 for none

shop_category pydantic-field

shop_category: str = 'NOT_IN_SHOP'

Wire key shopCategory

Build menu category; NOT_IN_SHOP for none

xp pydantic-field

xp: int = 0

Experience for building it

might_value pydantic-field

might_value: int = 0

Wire key mightValue

Might points it gives

storeable pydantic-field

storeable: bool = False

It can be put into storage

maximum_count pydantic-field

maximum_count: int = 1000000

Wire key maximumCount

How many a castle may have

destructable pydantic-field

destructable: bool = True

It can be torn down

temp_server_destructable pydantic-field

temp_server_destructable: bool = True

Wire key tempServerDestructable

It can be torn down on a temporary server

is_battle_ground pydantic-field

is_battle_ground: bool = False

Wire key isBattleGround

Built on a battle ground only

is_not_battle_ground pydantic-field

is_not_battle_ground: bool = False

Wire key isNotBattleGround

Never built on a battle ground

slum_level_needed pydantic-field

slum_level_needed: int = 0

Wire key slumLevelNeeded

Slum level needed to build it

needs_construction_expert pydantic-field

needs_construction_expert: bool = False

Wire key constructionExpert

Building it needs the construction expert

sell_coins pydantic-field

sell_coins: int = 0

Wire key sellC1

Coins for selling it

cost_rubies pydantic-field

cost_rubies: int = 0

Wire key costC2

Rubies it costs to build or upgrade to

sort_order pydantic-field

sort_order: float = 1000000

Wire key sortOrder

Order in the build menu; a value that is no number sorts last

only_in_area_types pydantic-field

only_in_area_types: tuple[GameDataId[MapItemType], ...] = ()

Wire key onlyInAreaTypes

The castle types it may be built in; empty for any

only_in_kingdoms pydantic-field

only_in_kingdoms: tuple[GameDataId[Kingdom], ...] = ()

Wire key kIDs

The kingdoms it may be built in; empty for every kingdom

only_in_event_ids pydantic-field

only_in_event_ids: tuple[GameDataId['Event'], ...] = ()

Wire key eventIDs

The events it may be built in; empty for none in particular

available_in_map_ids pydantic-field

available_in_map_ids: tuple[int, ...] = ()

Wire key mapIDs

The maps it may be built on; empty for any

sceat_skill_id pydantic-field

sceat_skill_id: GameDataId['SceatSkill'] = 0

Wire key sceatSkillLocked

The sceat skill that unlocks it; 0 for none

construction_item_group_ids pydantic-field

construction_item_group_ids: tuple[int, ...] = ()

Wire key constructionItemGroupIDs

The construction item groups it takes

low_level_build_durations pydantic-field

low_level_build_durations: tuple[int, ...] = ()

Wire key lowLevelBuildDuration

Build times in seconds at the lowest player levels

low_level_main_castle_cost_rubies pydantic-field

low_level_main_castle_cost_rubies: tuple[int, ...] = ()

Wire key lowLevelMainCastleCostC2

Ruby costs in the main castle at the lowest player levels

effect_locked pydantic-field

effect_locked: bool = False

Wire key effectLocked

Its effects need unlocking

wall_bonus pydantic-field

wall_bonus: int = 0

Wire key wallBonus

Wall protection, in percent

moat_bonus pydantic-field

moat_bonus: int = 0

Wire key moatBonus

Moat protection, in percent

build_duration pydantic-field

build_duration: int = 0

Wire key buildDuration

Build time in seconds

building_ground_type pydantic-field

building_ground_type: GameDataKey[BuildingGroundType] = BuildingGroundType.NONE

Wire key buildingGroundType

The ground it stands on

district_type_id pydantic-field

district_type_id: int = 0

Wire key districtTypeID

The district type it belongs to

is_district pydantic-field

is_district: bool = False

Wire key isDistrict

It is a district

is_relic_building pydantic-field

is_relic_building: bool = False

Wire key isRelicBuilding

It is a relic building

area_specific_effects pydantic-field

area_specific_effects: tuple[EffectValue, ...] = ()

Wire key areaSpecificEffects

Bonuses that count only where their effect's conditions hold

rubies_to_build

rubies_to_build(player_level: int | None) -> int

The rubies it costs to build, before cost effects: low_level_main_castle_cost_rubies for the player's level when it names one, else cost_rubies, and 0 at level 0. With the level unknown, the most either could be.

Client: ABasicBuildingVO.costC2 (bundle lines 17950-17953)

seconds_to_build

seconds_to_build(player_level: int) -> int

Its build time in seconds before boosts: low_level_build_durations for the player's level when that is above 0, else build_duration.

Client: ABasicBuildingVO.basicBuildDuration (bundle lines 17888-17890)

ResearchDef pydantic-model

Bases: EffectSpecRow

One level of a research.

costs and temp_server_costs read every cost column of the row (see Collectable.from_columns), a currency named by its Name (costLegendaryToken) by the currency names GameData passes in as validation context (currency_ids).

Client: AResearchVO.fillFromParamXML (bundle lines 61502-61516); getBaseCosts (bundle line 61530) picks temp_server_costs on a temporary server, and getFinalCosts (bundle line 61531) applies discounts to them

Fields:

Validators:

research_id pydantic-field

research_id: GameDataId['Research']

Wire key researchID

The research

label pydantic-field

label: str = ''

Wire key comment2

Designer label the game does not read, e.g. recruitment speed

group_id pydantic-field

group_id: int = -1

Wire key groupID

The group the research's levels share

level pydantic-field

level: int = -1

Research level

prerequisite_ids pydantic-field

prerequisite_ids: tuple[GameDataId['Research'], ...] = ()

Wire key prerequisiteIDs

Researches it needs first

min_research_tower_level pydantic-field

min_research_tower_level: int = 1

Wire key minResearchTowerLevel

Research tower level it needs

required_level pydantic-field

required_level: int = 0

Wire key requiredLevel

Player level it needs

required_legend_level pydantic-field

required_legend_level: int = 0

Wire key requiredLegendLevel

Legend level it needs

research_duration pydantic-field

research_duration: int = 0

Wire key researchDuration

Research time in seconds

temp_server_research_duration pydantic-field

temp_server_research_duration: int = 0

Wire key globalServerResearchDuration

Research time on a temporary server

only_with_research_expert pydantic-field

only_with_research_expert: bool = False

Wire key onlyWithResearchExpert

It needs the research expert

cost_rubies pydantic-field

cost_rubies: int = 0

Wire key costC2

Rubies it costs

costs pydantic-field

costs: tuple[Collectable, ...] = ()

What it costs, in the items' order: resources, coins, rubies, tokens, ...

temp_server_costs pydantic-field

temp_server_costs: tuple[Collectable, ...] = ()

What it costs on a temporary server

EventDef pydantic-model

Bases: _Row

An event: who sees it and where.

Client: ASpecialEventVO.parseBasicsFromXmlNode (bundle lines 2959-2974)

Fields:

Validators:

event_id pydantic-field

event_id: GameDataId['Event']

Wire key eventID

The event

event_type pydantic-field

event_type: str = ''

Wire key eventType

Event type, e.g. NomadInvasion

min_level pydantic-field

min_level: int = 0

Wire key minLevel

Lowest player level that sees it

max_level pydantic-field

max_level: int = 99

Wire key maxLevel

Highest player level that sees it

open_with_login pydantic-field

open_with_login: bool = False

Wire key openWithLogin

Its dialog opens on login

sort_order pydantic-field

sort_order: int = 0

Wire key sortOrder

Order among the events

crossplay_min_level pydantic-field

crossplay_min_level: int = -1

Wire key crossplayMinLevel

Lowest level on a crossplay server; -1 for none

extension_unlock pydantic-field

extension_unlock: int = 0

Wire key eventExtensionUnlock

Its extension unlock

kingdoms pydantic-field

kingdoms: tuple[GameDataId[Kingdom], ...] = (Kingdom.GREEN,)

Wire key kIDs

The kingdoms it runs in

area_types pydantic-field

area_types: tuple[GameDataId[MapItemType], ...] = (MapItemType.CASTLE,)

Wire key areaTypes

The castle types it counts in

LootBoxDef pydantic-model

Bases: _Row

A loot box.

Client: LootBoxVO.parseXML (bundle line 112502)

Fields:

Validators:

loot_box_id pydantic-field

loot_box_id: GameDataId['LootBox']

Wire key lootBoxID

The loot box

name pydantic-field

name: str = ''

Internal name, e.g. MysteryBoxBronze

loot_box_type_id pydantic-field

loot_box_type_id: GameDataId['LootBoxType'] = 0

Wire key lootBoxTypeID

Its type

tombola_id pydantic-field

tombola_id: int = 0

Wire key lootBoxTombolaID

The tombola it draws from

key_tombola_id pydantic-field

key_tombola_id: int = 0

Wire key lootBoxKeyTombolaID

The tombola its keys draw from

rarity pydantic-field

rarity: int = 0

Rarity

draws pydantic-field

draws: int = 0

Draws per opening

sort_order pydantic-field

sort_order: int = 0

Wire key sortOrder

Order among the loot boxes

LootBoxTypeDef pydantic-model

Bases: _Row

A loot box type, whose keys count toward a free box.

Client: LootBoxTypeVO.parseXML (bundle line 58900)

Fields:

Validators:

loot_box_type_id pydantic-field

loot_box_type_id: GameDataId['LootBoxType']

Wire key lootBoxTypeID

The loot box type

theme pydantic-field

theme: str = ''

Wire key lootBoxTheme

Its theme, e.g. MysteryBox

key_payout_threshold pydantic-field

key_payout_threshold: int = 0

Wire key lootBoxKeyPayoutThreshold

Keys that pay out a box

EquipmentGroupDef pydantic-model

Bases: _Row

An equipment item group, as equipment effects name them.

Client: XmlEquipmentGroupVO.parseXml (bundle line 144187)

Fields:

Validators:

group_id pydantic-field

group_id: GameDataId['EquipmentGroup']

Wire key itemGroupID

The item group

name pydantic-field

name: str = ''

Internal name, e.g. AttackPVP

wearer_id pydantic-field

wearer_id: GameDataId[WearerType] = -1

Wire key wearerID

Who wears it; -1 for any

slot_id pydantic-field

slot_id: GameDataId[EquipmentSlot] = -1

Wire key slotID

The slot it goes in

pic_id pydantic-field

pic_id: int = -1

Wire key picID

Its picture

drop_rate pydantic-field

drop_rate: int = -1

Wire key dropRate

Its drop rate

DifficultyTypeDef pydantic-model

Bases: _Row

An event difficulty type, e.g. easyPlus.

Client: EventAutoScalingDifficultyTypeVO.parseXML (bundle line 38258)

Fields:

Validators:

difficulty_type_id pydantic-field

difficulty_type_id: GameDataId['DifficultyType']

Wire key difficultyTypeID

The type

name pydantic-field

name: str = ''

Internal name, e.g. easyPlus

sort_order pydantic-field

sort_order: int = 0

Wire key sortOrder

Order among the types

QuestCondition pydantic-model

Bases: _Row

One thing a quest counts: a type+amount+data part of its conditions.

Client: ABasicQuestConditionVO.loadFromParamArray (bundle line 52833)

Fields:

condition_type pydantic-field

What it counts, e.g. buyRubies

amount pydantic-field

amount: int = 0

How many it needs

raw_data pydantic-field

raw_data: str = ''

Its |-separated parameters, which mean something different for each type

parse_list classmethod

parse_list(value: object) -> list[QuestCondition] | object

Each #-separated condition of a conditions column; an empty part is left out.

Client: CastleQuestVO.parseConditions (bundle line 52467), DailyQuestVO.fillFromParamXML (bundle line 134125)

QuestDef pydantic-model

Bases: _Row

A quest: where it shows, what unlocks it and what it counts.

Client: CastleQuestVO.fillFromParamXML (bundle lines 52452-52454)

Fields:

Validators:

quest_id pydantic-field

quest_id: GameDataId['QuestId']

Wire key questID

The quest

series_id pydantic-field

series_id: int = -1

Wire key questSeriesID

The quest series; -1 for none

series_number pydantic-field

series_number: int = 1

Wire key questSeriesNumber

Its place in the series

quests_in_series pydantic-field

quests_in_series: int = 0

Wire key numberOfQuestsInSeries

Quests in the series

shown_kingdom pydantic-field

shown_kingdom: GameDataId[Kingdom] = Kingdom.GREEN

Wire key shownKingdomID

The kingdom it is shown in

trigger_kingdom pydantic-field

trigger_kingdom: GameDataId[Kingdom] = Kingdom.GREEN

Wire key triggerKingdomID

The kingdom it counts in, as the row has it

hidden pydantic-field

hidden: bool = False

It is not shown

map_id pydantic-field

map_id: int = -1

Wire key mapID

The map it belongs to; -1 for none

required_level pydantic-field

required_level: int = 0

Wire key requiredLevel

Player level it needs

required_legend_level pydantic-field

required_legend_level: int = 0

Wire key requiredLegendLevel

Legend level it needs

required_quest_id pydantic-field

required_quest_id: GameDataId['QuestId'] = -1

Wire key requiredQuestID

The quest it needs first; -1 for none

quest_giver_id pydantic-field

quest_giver_id: int = 0

Wire key questGiverID

The character who gives it

event_id pydantic-field

event_id: GameDataId['Event'] = 0

Wire key eventID

The event it belongs to; 0 for none

duration pydantic-field

duration: int = -1

Seconds it runs; -1 for no limit

objective_type pydantic-field

objective_type: int = 0

Wire key objectiveType

Its objective type

auto_show pydantic-field

auto_show: bool = False

Wire key autoShow

It opens on its own

sort_priority pydantic-field

sort_priority: int | None = None

Wire key sortPriority

Order in the quest book; None sorts last

cost_rubies pydantic-field

cost_rubies: int = 0

Wire key c2Cost

Rubies to finish it at once

questbook_tab_id pydantic-field

questbook_tab_id: int = -1

Wire key questbookTabID

Its quest book tab; -1 for none

conditions pydantic-field

conditions: tuple[QuestCondition, ...] = ()

What it counts

DailyQuestDef pydantic-model

Bases: _Row

A daily quest.

Client: DailyQuestVO.fillFromParamXML (bundle lines 134124-134131)

Fields:

Validators:

quest_id pydantic-field

quest_id: GameDataId['DailyQuestId']

Wire key dailyQuestID

The daily quest

trigger_kingdom pydantic-field

trigger_kingdom: GameDataId[Kingdom] = Kingdom.GREEN

Wire key triggerKingdomID

The kingdom it counts in; -1 for any

is_temp_server_quest pydantic-field

is_temp_server_quest: bool = False

Wire key isTempServerQuest

It runs on temporary servers

daily_task_points pydantic-field

daily_task_points: int = 0

Wire key addDailyDutyPoints

Daily task points it gives

level_calculated pydantic-field

level_calculated: bool = False

Wire key levelCalculated

Its amounts scale with the player's level

conditions pydantic-field

conditions: tuple[QuestCondition, ...] = ()

What it counts

TitleDef pydantic-model

Bases: EffectSpecRow

A title of the glory, Berimond or Storm Islands title systems.

Client: TitleVO.parseXml (bundle lines 62705-62713)

Fields:

Validators:

title_id pydantic-field

title_id: GameDataId['Title']

Wire key titleID

The title

title_system pydantic-field

title_system: GameDataKey[TitleSystem] = '-1'

Wire key type

Its title system

threshold pydantic-field

threshold: int = -1

Points from which it is held; -1 for a top-X title

display_type pydantic-field

display_type: GameDataKey[TitleDisplayType] = '-1'

Wire key displayType

Whether it goes before or after the name

forced pydantic-field

forced: bool = False

It is a forced title

decay pydantic-field

decay: int = -1

Its point decay

is_positive pydantic-field

is_positive: bool = False

Wire key isPositive

It is a positive title

top_x pydantic-field

top_x: int = -1

Wire key topX

The top ranks that hold it; -1 or 0 for a points title

previous_title_id pydantic-field

previous_title_id: GameDataId['Title'] = -1

Wire key previousTitleID

The title below it in its system; -1 for the first

reward_id pydantic-field

reward_id: RewardId = RewardId(-1)

Wire key rewardID

Its reward, whose collectables GameData.reward_list gives; -1 for none

might_value pydantic-field

might_value: int = -1

Wire key mightValue

Might points it gives

rewards

rewards(data: GameData) -> tuple[Collectable, ...]

What holding the title gives; nothing when it has no reward.

Client: CastleTitleSystemHelper.getTitleRewardText reads getListById(rewardID) when it is above -1 (bundle line 4444)

AchievementCondition pydantic-model

Bases: _Row

One thing an achievement counts: a type+amount+params part of its conditions.

Client: AchievementConditionVO (bundle line 92956)

Fields:

condition_type pydantic-field

condition_type: str

What it counts, e.g. achievementPoints

amount pydantic-field

amount: int = 0

How many it needs

params pydantic-field

params: tuple[str, ...] = ()

Its further parameters, which differ for each type

parse_list classmethod

parse_list(value: object) -> list[AchievementCondition] | object

Each #-separated condition of a conditions column; an empty part is left out.

Client: AchievementVO.fillFromParamXML (bundle lines 92883-92887)

AchievementDef pydantic-model

Bases: _Row

One step of an achievement series.

Client: AchievementVO.fillFromParamXML (bundle lines 92882-92887) and AchievementSerieVO.fillFromParamXML (bundle line 92817), grouped by series in CastleAchievementData (bundle lines 29820-29827)

Fields:

Validators:

achievement_id pydantic-field

achievement_id: GameDataId['Achievement']

Wire key achievementID

The achievement

series_id pydantic-field

series_id: int = 0

Wire key achievementSeriesID

The series it is a step of

series_number pydantic-field

series_number: int = 0

Wire key achievementSeriesNumber

Its step in the series

achievements_in_series pydantic-field

achievements_in_series: int = 0

Wire key numberOfAchievementsInSeries

Steps in the series

required_achievement_id pydantic-field

required_achievement_id: GameDataId['Achievement'] = 0

Wire key requiredAchievementID

The step before it; -1 or 0 for none

achievement_points pydantic-field

achievement_points: int = 0

Wire key achievementPoints

Achievement points it gives

category pydantic-field

category: str = ''

The series' category, e.g. achievement or event

conditions pydantic-field

conditions: tuple[AchievementCondition, ...] = ()

What it counts

AllianceCrestColorDef pydantic-model

Bases: _Row

A colour an alliance crest can use.

Client: AllianceCrestColorVO.parseXML (bundle line 111012), keyed by id in CastleAllianceCrestData.parseXML (bundle lines 110965-110970)

Fields:

Validators:

color_id pydantic-field

color_id: GameDataId['AllianceCrestColor']

Wire key allianceCoatColorID

The colour

color pydantic-field

color: str = ''

The colour as hex text, e.g. 0xDBDACA

AllianceCrestLayoutDef pydantic-model

Bases: EffectSpecRow

A layout an alliance crest can use, and the bonuses it grants.

Client: AllianceCrestLayoutVO.parseXML and parseEffects (bundle lines 111024-111032), keyed by id in CastleAllianceCrestData.parseXML (bundle lines 110958-110963)

Fields:

Validators:

layout_id pydantic-field

layout_id: GameDataId['AllianceCrestLayout']

Wire key allianceCoatLayoutID

The layout

color_count pydantic-field

color_count: int = 0

Wire key noofColors

Colours it takes

event_id pydantic-field

event_id: GameDataId['Event'] = 0

Wire key eventID

The event that awards it; 0 for none

max_duration pydantic-field

max_duration: int = 0

Wire key maxDuration

Seconds it is held once won; 0 for a layout that does not expire

effect_icon_id pydantic-field

effect_icon_id: int = 0

Wire key effectIconID

The icon its bonus shows

label pydantic-field

label: str = ''

Wire key comment1

Designer label the game does not read, e.g. nomad

ConstructionItemRecipeDef pydantic-model

Bases: _Row

A recipe that crafts a construction item, one of a blueprint's.

Client: ConstructionItemRecipeVO.parseFromXml (bundle line 141060), grouped into blueprints by ConstructionItemBlueprintData.parseFromXml (bundle line 141026)

Fields:

Validators:

recipe_id pydantic-field

recipe_id: int

Wire key constructionItemRecipeID

The recipe, as a research unlocks it

blueprint_id pydantic-field

blueprint_id: int = 0

Wire key blueprintID

The blueprint it belongs to

construction_item_id pydantic-field

construction_item_id: GameDataId['ConstructionItem'] = 0

Wire key constructionItemID

The construction item it crafts

ScalingCampDef pydantic-model

Bases: _Row

A camp of an event's difficulty scaling: the level and costs a chosen difficulty gives it.

Client: DifficultyScalingCampXmlVO.parseXML (bundle line 145227), keyed by id in CastleEventDifficultyScalingData (bundle line 145211)

Fields:

Validators:

scaling_camp_id pydantic-field

scaling_camp_id: int

Wire key eventAutoScalingCampID

The scaling camp, as map rows name it

rank pydantic-field

rank: int = 0

Its rank

level pydantic-field

level: int = 0

Wire key camplevel

The camp level it gives

cool_down pydantic-field

cool_down: int = 0

Wire key coolDown

Cooldown in seconds after an attack

event_id pydantic-field

event_id: GameDataId['Event'] = 0

Wire key eventID

The event it belongs to

cooldown_increase pydantic-field

cooldown_increase: int = 0

Wire key cooldownIncrease

Cooldown added per attack

cooldown_increase_cap pydantic-field

cooldown_increase_cap: int = 0

Wire key cooldownIncreaseCap

Most cooldown added

skip_cost pydantic-field

skip_cost: int = 0

Wire key skipCosts

Cost to skip the cooldown

skip_cost_increase pydantic-field

skip_cost_increase: int = 0

Wire key skipCostIncrease

Skip cost added per attack

skip_cost_increase_cap pydantic-field

skip_cost_increase_cap: int = 0

Wire key skipCostIncreaseCap

Most skip cost added

wall_bonus pydantic-field

wall_bonus: int = 0

Wire key wallBonus

Wall protection, in percent

gate_bonus pydantic-field

gate_bonus: int = 0

Wire key gateBonus

Gate protection, in percent

moat_bonus pydantic-field

moat_bonus: int = 0

Wire key moatBonus

Moat protection, in percent

unit_capacity pydantic-field

unit_capacity: int = 0

Wire key unitCapacity

Units it holds

shogun_points_needed_for_level_up pydantic-field

shogun_points_needed_for_level_up: int = -1

Wire key shogunPointsNeededForLevelUp

Shogun points to the next level; -1 for none

player_rage_cap pydantic-field

player_rage_cap: int = -1

Wire key playerRageCap

Most rage a player builds; -1 for none

rage_needed_for_level_up pydantic-field

rage_needed_for_level_up: int = -1

Wire key rageNeededForLevelUp

Rage to the next level; -1 for none

normal_def_strength_boost_min pydantic-field

normal_def_strength_boost_min: int = 0

Wire key normalDiffDefStrengthBoostMinDefense

Least defence boost, normal difficulty

normal_def_strength_boost_max pydantic-field

normal_def_strength_boost_max: int = 0

Wire key normalDiffDefStrengthBoostMaxDefense

Most defence boost, normal difficulty

premium_def_strength_boost_min pydantic-field

premium_def_strength_boost_min: int = 0

Wire key premiumDiffDefStrengthBoostMinDefense

Least defence boost, premium difficulty

premium_def_strength_boost_max pydantic-field

premium_def_strength_boost_max: int = 0

Wire key premiumDiffDefStrengthBoostMaxDefense

Most defence boost, premium difficulty

DaimyoContractDef pydantic-model

Bases: _Row

An alliance contract of the daimyo event: one level of a contract rank.

The contracts of one rank, in the table's order, are that rank's levels.

Client: XmlSamuraiDaimyoContractVO.parseXml (bundle line 66377), keyed by id in SamuraiDaimyoDataXml.parseXml (bundle line 13914)

Fields:

Validators:

contract_id pydantic-field

contract_id: int

Wire key id

The contract

rank pydantic-field

rank: int = -1

The contract rank it is a level of

enable_on_start pydantic-field

enable_on_start: bool = False

Wire key enableOnStart

Open from the event's start, not after another contract

next_contract_id pydantic-field

next_contract_id: int = -1

Wire key nextContract

The contract after it; -1 for none

shogun_points pydantic-field

shogun_points: int = -1

Wire key shogunPoints

Shogun points it takes

war_effort_points pydantic-field

war_effort_points: int = -1

Wire key warEffortPoints

War effort points it gives

RewardDef pydantic-model

Bases: _Row

One reward of the items: what it gives, and to whom.

collectables reads every collectable column of the row (see Collectable.from_reward_row), each add<currency name> column by the currency names GameData passes in as validation context (currency_ids); read without them, such a column is kept as OTHER.

Client: RewardVO.fillFromParamXml (bundle line 142368), read from the rewards table by CastleRewardData.parseXml (bundle line 142323)

Fields:

Validators:

reward_id pydantic-field

reward_id: RewardId

Wire key rewardID

The reward

grant_type pydantic-field

Wire key grantType

Who it goes to

collectables pydantic-field

collectables: tuple[Collectable, ...] = ()

What it gives, in the client's order

row_id

row_id(value: object) -> int

The row's own id, parseInt of it; a row without one is skipped, as nothing can look it up.

is_research_cost_column

is_research_cost_column(column: str) -> bool

Whether a researches column is a cost: cost<name> or globalServerCost<name>.

gamedata.table

A game-data table: rows keyed by id, each validated the first time it is read.

Loading the game data then costs no row validation at all: a table holds the items rows as the file has them, trimmed to the columns its model reads, and validates a row when it is asked for.

Classes:

Name Description
Table

One items table by id, read-only.

logger module-attribute

logger = logging.getLogger(__name__)

K module-attribute

K = TypeVar('K')

R module-attribute

R = TypeVar('R', bound=BaseModel)

Table

Table(model: type[R], id_field: str, rows: Mapping[int, dict[str, Any]], *, name: str = '', context: dict[str, Any] | None = None)

Bases: Mapping[K, R], Generic[K, R]

One items table by id, read-only.

Reading a row by id (table[Building.KEEP_L1], table.get(171), 171 in table) validates that row alone. Iterating, len() or comparing validates every row once, and keys come back as the rows' ids: the enum member, or the plain int of an id the enum lacks. A row that does not fit its model is left out, as if the table did not have it, with a warning the first time it is read. A table is shared by every thread that reads the game data: each row is validated once, so table[k] is table[k] holds across threads. context is passed to each row's validation, for a model that reads a row by another table.

gamedata.collectables

Collectables: one reward, cost or lot of goods, typed by kind, as the client's single parser reads them.

The server sends collectables in two layouts, which the client reads with one key table:

  • rows, [[key, entry, amount?], ...] (a mission's rewards, goods on their way): CollectableRows
  • an object, {key: [entry, ...], "SO": sort order} (the login bonus): CollectableObject

Each entry's layout depends on its kind ([unit_id, amount] under U, an amount under C1, {"ID": booster id, "D": seconds} under B, ...); Collectable reads it into item, amount and duration_seconds. An entry under a key the client has no type for is kept as CollectableKind.OTHER with its key and value, where the client drops it.

Classes:

Name Description
Collectable

One collectable: a reward, a cost or a lot of goods, typed by its kind.

Attributes:

Name Type Description
CollectableItem
MINUTE_SKIP_FIRST_ID

The start of the minute skips' currency id range: items currencyTypes row MinuteSkip ("1000-1999").

CollectableRows

A model field read from collectable rows, [[key, entry, amount?], ...] (see Collectable.from_rows).

CollectableObject

A model field read from a reward object, {key: [entry, ...]} (see Collectable.from_object).

CurrencyIdRows

A model field read from [[currency_id, amount], ...] rows, one currency collectable per row, as sent.

CurrencyAmounts

Currencies by id and amount, sent as [[currency_id, amount], ...] in insertion order.

CollectableItem module-attribute

MINUTE_SKIP_KEY module-attribute

MINUTE_SKIP_KEY = 'MS'

A minute skip sent as ["MS<n>", amount]: the currency MINUTE_SKIP_FIRST_ID + n.

MINUTE_SKIP_FIRST_ID module-attribute

MINUTE_SKIP_FIRST_ID = 1000

The start of the minute skips' currency id range: items currencyTypes row MinuteSkip ("1000-1999").

Client: CollectableHelper.getTypeByServerKey (bundle lines 1604-1605), XmlCurrencyRangeVO.parseXml (bundle line 141268)

CollectableRows module-attribute

CollectableRows = Annotated[tuple[Collectable, ...], BeforeValidator(_collectables(Collectable.from_rows))]

A model field read from collectable rows, [[key, entry, amount?], ...] (see Collectable.from_rows).

CollectableObject module-attribute

CollectableObject = Annotated[tuple[Collectable, ...], BeforeValidator(_collectables(Collectable.from_object))]

A model field read from a reward object, {key: [entry, ...]} (see Collectable.from_object).

CurrencyIdRows module-attribute

CurrencyIdRows = Annotated[tuple[Collectable, ...], BeforeValidator(_currency_id_rows)]

A model field read from [[currency_id, amount], ...] rows, one currency collectable per row, as sent.

Unlike CurrencyAmounts, rows are not added up and an amount keeps its sign.

Client: CollectableItemGenericCurrencyVO(e[0], e[1]) per row (bundle line 138308)

CurrencyAmounts module-attribute

CurrencyAmounts = Annotated[dict[EnumOrInt['CurrencyId'], int], BeforeValidator(_currency_rows), PlainSerializer(_rows_of)]

Currencies by id and amount, sent as [[currency_id, amount], ...] in insertion order.

Unlike CollectableRows, the rows name the currency by its currencyID, not a server key.

Client: CastleFightScreenVO.addCollectorBooster (bundle line 30584) pushes [currency_id, amount]

Collectable pydantic-model

Bases: EmpireModel

One collectable: a reward, a cost or a lot of goods, typed by its kind.

item is what the entry names, for the kinds that name one: the unit or tool for UNITS, the Currency for CURRENCY, the BoosterId for a booster, the loot box, building, construction item, gem or crest layout, the rareness of a random equipment, or the id of an equipment, crest symbol, gift package or material bag, which no enum names. amount is how many; an entry that names an item without a count is 1.

Client: CollectableHelper.getTypeByServerKey and createVO (bundle lines 1603-1629), then the item class's parseServerObject

Fields:

model_config class-attribute

model_config: ConfigDict = ConfigDict(frozen=True)

kind pydantic-field

What it is

key pydantic-field

key: str

The server key it came under, as sent (for a game-data reward, its kind's or currency's); the only name an OTHER entry has

amount pydantic-field

amount: int | float = 1

How many

item pydantic-field

item: CollectableItem | None = None

What the entry names; None for a kind that names nothing

duration_seconds pydantic-field

duration_seconds: int | float | None = None

How long it lasts, for a booster, VIP time or crest layout; None otherwise

value pydantic-field

value: Any = None

The entry as sent, for an OTHER entry and a kind whose layout is not read here (relics, equipment sent whole, alliance gifts); None otherwise

send_key property

send_key: str

The key the client sends for this collectable, as when the login bonus reward is picked.

A currency goes as its own key, anything else as its kind's key: a booster with a kind of its own as that kind's (PG, XPB, ...), a hero random equipment as RE.

Raises:

Type Description
ValueError

An OTHER entry, which the client never offers, or a currency whose key is unknown

Client: CollectableHelper.getServerKeyByCollectable (bundle line 1646)

from_entry classmethod

from_entry(key: str, entry: Any, amount: Any = None) -> Collectable

One entry under its server key; amount is the third place of a row, where it has one.

Client: CollectableParserS2CParamList.createByParamListMethod (bundle line 40569), LostAndFoundListItemVO.parseData (bundle line 144545)

from_object classmethod

from_object(value: Any) -> tuple[Collectable, ...]

A reward object {key: [entry, ...], "SO": sort order} as its collectables, in the order sent.

A key whose value is no list is skipped, as the client skips a null one; SO only sorts the display.

Client: CollectableParserS2CParamObject.createList and parseSortOrder (bundle lines 62810-62818)

from_rows classmethod

from_rows(value: Any) -> tuple[Collectable, ...]

Collectable rows [[key, entry, amount?], ...], a list of such lists, or an old-style goods list.

An old-style list holds amounts in a fixed order of goods and currencies, a 0 for none.

Client: CollectableParserS2CParamList.createList and createByParamListMethod (bundle lines 40560-40573), CollectableParserS2COldGoods.createByParamListOldGoods (bundle line 62797)

of_currency classmethod

of_currency(currency_id: int, amount: int | float = 1) -> Collectable

A currency named by its currencyID, under its server key (the id itself where the key is unknown).

Client: CollectableItemGenericCurrencyVO (bundle line 5258) takes the id and amount

from_reward_row classmethod

from_reward_row(row: Mapping[str, Any], currency_ids: Mapping[str, int]) -> tuple[Collectable, ...]

What one rewards row of the items gives, in the client's order.

Each column of a kind holds #-separated parts, read as the kind's item class reads them; then each add<name> column adds one more, of the kind name names or else the currency whose Name it is (currency_ids, by name); duplicates the client adds up are added up. An add column naming neither is kept as OTHER, where the client drops it. A random equipment of a hero rareness reads as HERO_RANDOM, as a packet's does. The columns no parser reads (comment1, hiddenFood, ignore* and the like) give nothing.

Client: CollectableParserX2CRewards.createList (bundle line 62897) and CollectableParserX2CList.createList (bundle line 62874) with CurrencyData.getXmlCurrencyByName (bundle line 141193)

from_columns classmethod

from_columns(row: Mapping[str, Any], prefix: str, currency_ids: Mapping[str, int]) -> tuple[Collectable, ...]

One collectable per <prefix><name> column of an items row, in the row's order: a research's cost columns, a reward's add columns.

name is a kind's items key (C2, Wood) or else the Name of a currency (LegendaryToken, by currency_ids). A column naming neither is kept as OTHER, where the client drops it.

Client: CollectableParserX2CList.createList (bundle lines 62874-62881) with CurrencyData.getXmlCurrencyByName (bundle line 141193)

merged staticmethod

merged(collectables: Iterable[Collectable]) -> tuple[Collectable, ...]

The collectables with the duplicates the client adds up added up, each into the first it adds up with.

Most kinds add up by kind; currencies, units, buildings, construction items, material bags and crest layouts only for the same item; boosters, equipment, gems, relics and the other one-off kinds never. VIP time, dungeon protection and crest layouts add their durations, the others their amounts. Two different loot boxes add up into the first one's box, as in the client. The client also requires the same grant type, which a collectable does not carry: the collectables of one reward share theirs, so merge only collectables of one grant type.

Client: CollectableList.combineDuplicatedItems (bundle line 1887), isCombineAbleWith and combineWith of ACollectableItemVO (bundle lines 3569, 3558) and its overrides

is_reward_column

is_reward_column(column: str) -> bool

Whether a rewards row column holds a collectable: a kind's items column or an add column.

gamedata.lenient

Lenient id fields: the enum member for an id the enum knows, the plain value for one it does not.

A client release can send an id the generated enums do not have yet. A field typed EnumOrInt[Kingdom] keeps such an id as its int instead of failing the packet, and logs a warning once per id. EnumOrInt[Unit, Tool] takes a member of either, for an id from a table two enums share. Name a generated enum by its name in quotes (EnumOrInt["QuestId"], the enum imported under TYPE_CHECKING) so its module loads only when a value arrives; the largest of them hold thousands of members.

Inside the items tables GameDataId[E] and GameDataKey[E] do the same without the warning: loading items newer than the enums already warns once for the whole version.

Classes:

Name Description
LenientEnum

The validator behind the lenient types: reads the id, then looks its member up.

EnumOrInt

EnumOrInt[E]: a member of the IntEnum E, or the plain int of an id E lacks.

EnumOrStr

EnumOrStr[E]: a member of the str Enum E, or the plain str of a key E lacks.

GameDataId

GameDataId[E]: EnumOrInt[E] for an id inside the items tables, kept without a warning.

GameDataKey

GameDataKey[E]: EnumOrStr[E] for a fixed text column of the items tables, kept without a warning.

Functions:

Name Description
known

The member of the first of enums that has value, else value itself.

logger module-attribute

logger = logging.getLogger(__name__)

LenientEnum

LenientEnum(enum: type[Enum] | str | tuple[type[Enum] | str, ...], base: type[int] | type[str], *, warn: bool = True)

The validator behind the lenient types: reads the id, then looks its member up.

Attributes:

Name Type Description
base
warn
enums tuple[type[Enum], ...]

The enums, in lookup order; one named by a string is looked up among the game-data id enums on first use.

base instance-attribute

base = base

warn instance-attribute

warn = warn

enums property

enums: tuple[type[Enum], ...]

The enums, in lookup order; one named by a string is looked up among the game-data id enums on first use.

EnumOrInt

EnumOrInt[E]: a member of the IntEnum E, or the plain int of an id E lacks.

EnumOrInt[E, F] looks the id up in E, then in F.

EnumOrStr

EnumOrStr[E]: a member of the str Enum E, or the plain str of a key E lacks.

GameDataId

GameDataId[E]: EnumOrInt[E] for an id inside the items tables, kept without a warning.

GameDataKey

GameDataKey[E]: EnumOrStr[E] for a fixed text column of the items tables, kept without a warning.

known

known(enums: type[_E] | Iterable[type[_E]], value: Any, *, warn: bool = True) -> _E | Any

The member of the first of enums that has value, else value itself.

A value none of them has is logged once per enum name and value, unless warn is False.

gamedata.effect_texts

An effect with its value, described the way the game's tooltips describe it.

Usage
from empire_core.gamedata import EffectTemplate, describe_construction_item, describe_effect

item = game_data.construction_items[ConstructionItem.BARRACKS_COST_G1_L1]
describe_construction_item(item, game_data)        # "-2% recruitment costs"
describe_effect(gem.effects[0], game_data, EffectTemplate.EQUIPMENT, trigger_chance=gem.trigger_chance)

The text comes from the language file (empire_core.texts), fetched on first use and cached; the game data names the effect and how its value reads.

Functions:

Name Description
describe_effect

One bonus as the game describes it in lang: "-5% recruitment costs".

describe_effects

Each bonus as describe_effect describes it; an effect game_data lacks is left out.

describe_construction_item

A construction item's bonuses as its tooltip lists them, one per line: the fixed bonuses of its own

describe_building

A decoration's effects as its info lists them, its effects then its area_specific_effects, each with

Number module-attribute

Number = int | float | None

Replacements module-attribute

Replacements = Callable[[EffectValue, 'GameData', str], list[object]]

describe_effect

describe_effect(effect: EffectValue | EquipmentEffectValue, game_data: GameData, template: EffectTemplate = CONSTRUCTION_ITEM, *, trigger_chance: int = 100, lang: str = 'en') -> str | None

One bonus as the game describes it in lang: "-5% recruitment costs".

The text is the template's for the effect, filled with the value as the effect's type reads it (one number, the value of the first unit it names, the ids it unlocks, ...). An equipment effect resolves to its effect and always reads as equipment. A gem that does not always trigger (GemDef.trigger_chance below 100) reads gem_effect_description_<gem type> with the chance first. Fetches the language file on first use (empire_core.texts.text).

Returns:

Type Description
str | None

The description; None when game_data does not have the effect

Client: EffectTypeEnum registrations (bundle line 1322) choose the value class, whose textReplacements fill the text

describe_effects

describe_effects(effects: Iterable[EffectValue], game_data: GameData, template: EffectTemplate = CONSTRUCTION_ITEM, *, lang: str = 'en') -> list[str]

Each bonus as describe_effect describes it; an effect game_data lacks is left out.

describe_construction_item

describe_construction_item(item: ConstructionItemDef, game_data: GameData, *, lang: str = 'en') -> str

A construction item's bonuses as its tooltip lists them, one per line: the fixed bonuses of its own columns (ci_effect_<column>, the value as it is), then its effects; ci_effect_NA for none.

Client: ConstructionItemVO.effectText (bundle line 47766), the fixed bonuses' text from CastleEffectVO.constructionItemTextId (bundle line 79073)

describe_building

describe_building(building: BuildingDef, game_data: GameData, *, lang: str = 'en') -> list[str]

A decoration's effects as its info lists them, its effects then its area_specific_effects, each with its cap.

Client: ABasicBuildingVO.allBuildingEffects (bundle line 18113) and ADecoBuildingVO.createAdditionalEffectItems (bundle line 11897)

gamedata.troops

Telling troops from equipment in a unit dict, by the loaded game data.

Troops are the units rows without slotTypes, which GameData keeps as its units; the rows with them are tools. The ids come from GameData.load, so they share its one download, cache and failure backoff.

With no game data loaded, a CDN outage makes get_troop_ids raise NetworkError rather than return an empty set, so callers can tell "metadata unavailable" apart from "no troop IDs". count_troops still degrades to counting every unit in that case, which inflates the count; see its docstring.

Functions:

Name Description
troop_data_available

Whether game data is loaded in this process, i.e. whether troop counts are exact.

get_troop_ids

The wodID of every troop: the ids of the loaded game data's units.

count_troops

Count only actual troops in a unit dict, excluding equipment.

logger module-attribute

logger = logging.getLogger(__name__)

troop_data_available

troop_data_available() -> bool

Whether game data is loaded in this process, i.e. whether troop counts are exact.

Returns:

Type Description
bool

True once a GameData.load has succeeded here, so

bool

count_troops filters equipment out. False means

bool

count_troops would load the game data first, or fall back to counting

bool

every unit. This does not touch the network.

get_troop_ids

get_troop_ids(force_refresh: bool = False) -> set[int]

The wodID of every troop: the ids of the loaded game data's units.

Uses the game data already loaded in the process (GameData.loaded, which client.game_data reads too), and loads it through GameData.load when there is none.

Parameters:

Name Type Description Default
force_refresh bool

Load the game data again, past its cache and failure backoff

False

Returns:

Type Description
set[int]

Set of wodID values for valid troops. An empty set means the CDN data

set[int]

genuinely listed no troops - a fetch failure raises instead.

Raises:

Type Description
NetworkError

The game data is not loaded and could not be. Within five minutes of a failed fetch this is raised without another request.

count_troops

count_troops(units: dict[int, int], troop_ids: set[int] | None = None) -> int

Count only actual troops in a unit dict, excluding equipment.

Parameters:

Name Type Description Default
units dict[int, int]

Dict of {unit_id: count}

required
troop_ids set[int] | None

Explicit set of valid troop IDs. Taken from the game data (loading it if needed) when omitted. An explicitly empty set counts nothing, since it means "no unit ID is a troop".

None

Returns:

Type Description
int

Total count of actual troops.

int

Degraded fallback: when troop_ids is omitted and the game data

int

cannot be loaded, every unit is counted - including equipment - so the

int

result can be inflated. The fallback warns (throttled to once per

int

retry interval); callers that need to know whether a count is exact

int

should check troop_data_available, or call

int

get_troop_ids themselves and handle NetworkError.

gamedata.cdn

The items payload on the GGE CDN, fetched without any caching.

GameData.load is the one place that calls these, caches the result and backs off after a failure; everything else reads the game data through it.

Functions:

Name Description
get_items_version

The current items version, from ItemsVersion.properties.

fetch_items_data

The full items_v{version}.json payload.

get_items_version

get_items_version() -> str

The current items version, from ItemsVersion.properties.

Client: BasicFrameOne.loadItemVersionXML loads {baseURL}/ItemsVersion.properties (ggs.dll lines 3928 and 32238) and onVersionPropertiesLoaded keeps the text after the first =, trimmed (ggs.dll line 32240).

Raises:

Type Description
ValueError

The text is not dotted digits (786.03), so it is never put in a URL or file name

fetch_items_data

fetch_items_data(version: str) -> dict[str, Any]

The full items_v{version}.json payload.

Generated ids

One enum per items table, generated for one items version (ITEMS_VERSION). Only the classes are shown here; their members are in the source and in your editor's autocomplete.

Game-data ids as enums, so they autocomplete.

One enum per items table, each member named from the row in UPPER_SNAKE; where two rows would share a name, both carry their id (SPEED_BOOST_2). Currencies and researches are named from the game's English text (Currency.SKIP_5_MINUTES is "MS2"), where the row has its own. Members are plain ints (Currency members plain strs), so they go on the wire and into models as their value.

Most members also carry their row's fixed id and number columns, e.g. Unit.MEAD_RANGER_L6.role and .level or Tool.X.category, so [t for t in Tool if t.category == "Defence"] works without game data. Anything a balance patch can change is not baked in: for the full row, load a GameData (nothing here downloads it) and index its table with the member, e.g. game_data.units[Unit.MEAD_RANGER_L6].

Enums whose rows the game names by a text (units, tools, currencies, researches, generals, legend and sceat skills, events, gems, achievements, titles, crest layouts, main quests) have display_name(lang="en"), the name the game shows: Unit.MEAD_RANGER_L6.display_name("de"). It reads the language file, fetched on first use and cached (empire_core.texts).

ITEMS_VERSION is the items version they were generated from, and is_current says whether a loaded GameData is that version. For anything newer, use the named lookups on GameData.

Equipment, relic effects and alliance buffs have no enum, as the game names none of their rows; look them up by id on GameData (equipment_effects, relic_effects, alliance_buffs). Nor do the 27,000 rewards: the game shows no text for one, and the notes some rows carry name where it is given, not the reward.

Regenerate with uv run python scripts/generate_gamedata_ids.py.

Modules:

Name Description
achievements
alliance_crests
buildings
construction_items
currencies
daily_quests
difficulty_types
effect_types
effects
equipment_groups
events
gems
general_abilities
general_skills
generals
global_effects
horses
legend_skills
loot_box_types
loot_boxes
main_quests
quests
raid_bosses
researches
sceat_skills
titles
tools
units

Classes:

Name Description
Achievement

Achievement ids from the achievements table, named from the series' English name and the step as its level; the

AllianceCrestColor

Alliance crest colour ids from the allianceCoatColors table. The game names no colour, so each is named by its

AllianceCrestLayout

Alliance crest layout ids from the allianceCoatLayouts table, named from the game's English name, else the

Building

Building wodID values from the buildings table, named name, type (for decorations) and level.

ConstructionItem

Construction item ids from the constructionItems table, named name, group and level.

Currency

Currency keys from the currencies table, the key the server uses, named from the game's English name; coins and

CurrencyId

Currency ids from the currencies table, as other tables reference them; names match Currency.

DailyQuestId

Daily quest ids from the dailyactivities table, named from what the first condition counts. Named DailyQuestId,

DifficultyType

Event difficulty type ids from the eventAutoScalingDifficultyTypes table.

EffectType

Effect type ids from the effecttypes table.

Effect

Effect ids from the effects table.

EquipmentGroup

Equipment item group ids from the equipment_groups table, as equipment effects name them.

Event

Event ids from the events table, named from eventType.

Gem

Gem ids from the gems table, named from the game's English name and, unless unique, level.

GeneralAbility

General ability ids from the generalAbilities table, one per level.

GeneralSkill

General skill ids from the generalSkills table, named general, skill and level.

General

General ids from the generals table.

GlobalEffect

Global effect ids from the globalEffects table.

Horse

Travel booster wodID values from the horses table, the HBW movements send, named from the comment2

LegendSkill

Legend skill ids from the legendskills table, named effect type, tree, group and level.

LootBoxType

Loot box type ids from the lootBoxTypes table, named from lootBoxTheme; keys count per type.

LootBox

Loot box ids from the lootBoxes table, named name and rarity.

MainQuest

Main quest ids from the mainquests table, the quest book's chapters, named from the game's English title.

QuestId

Quest ids from the quests table, named from what the first condition counts; most names carry their id, as many

RaidBoss

Alliance raid boss ids from the raidBosses table.

Research

Research ids from the researches table, named from the game's English title and level; a blueprint or recipe

SceatSkill

Sceat skill ids from the sceatSkills table, named from the game's English name and level.

Title

Title ids from the titles table, named from the game's English title.

Tool

Tool wodID values from the units table (rows with slotTypes).

Unit

Unit wodID values from the units table (rows without slotTypes).

Functions:

Name Description
is_current

Whether game_data is the items version these enums were generated from.

Achievement

Bases: IntEnum

Achievement ids from the achievements table, named from the series' English name and the step as its level; the main series from what it counts.

Client: AchievementVO.fillFromParamXML (bundle line 92882); names from AchievementSerieVO.nameString (bundle line 92822)

Methods:

Name Description
display_name

The game's name for it in lang, the text achievementName_<series_id>.

Attributes:

Name Type Description
series_id int

The series it is a step of.

series_number int

Its step in the series.

text_id str

The text id of its name, achievementName_<series_id>.

series_id instance-attribute

series_id: int

The series it is a step of.

series_number instance-attribute

series_number: int

Its step in the series.

text_id property

text_id: str

The text id of its name, achievementName_<series_id>.

display_name

display_name(lang: str = 'en') -> str

The game's name for it in lang, the text achievementName_<series_id>.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: AchievementSerieVO.nameString (bundle line 92822)

AllianceCrestColor

Bases: IntEnum

Alliance crest colour ids from the allianceCoatColors table. The game names no colour, so each is named by its id and carries its hex colour.

Client: AllianceCrestColorVO.parseXML (bundle line 111012)

Attributes:

Name Type Description
color str

The colour as hex text, e.g. 0xDBDACA.

color instance-attribute

color: str

The colour as hex text, e.g. 0xDBDACA.

AllianceCrestLayout

Bases: IntEnum

Alliance crest layout ids from the allianceCoatLayouts table, named from the game's English name, else the comment1 note.

Client: AllianceCrestLayoutVO.parseXML (bundle line 111024); names from CollectableItemAllianceCrestLayoutVO.getNameTextId (bundle line 89359)

Methods:

Name Description
display_name

The game's name for it in lang, the text allianceCoat_Layout_name_<value>.

Attributes:

Name Type Description
color_count int

Colours it takes.

text_id str

The text id of its name, allianceCoat_Layout_name_<value>.

color_count instance-attribute

color_count: int

Colours it takes.

text_id property

text_id: str

The text id of its name, allianceCoat_Layout_name_<value>.

display_name

display_name(lang: str = 'en') -> str

The game's name for it in lang, the text allianceCoat_Layout_name_<value>.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: CollectableItemAllianceCrestLayoutVO.getNameTextId (bundle line 89359)

Building

Bases: IntEnum

Building wodID values from the buildings table, named name, type (for decorations) and level.

Client: AVisualVO.parseXmlNode (bundle line 17800) reads name, group and type, AShopVO.parseXmlNode (bundle line 31713) the level

Attributes:

Name Type Description
group str

The group column, e.g. Building or Tower.

level int

Upgrade level; -1 when the row has none.

group instance-attribute

group: str

The group column, e.g. Building or Tower.

level instance-attribute

level: int

Upgrade level; -1 when the row has none.

ConstructionItem

Bases: IntEnum

Construction item ids from the constructionItems table, named name, group and level.

Client: ConstructionItemVO.parseBasicValues (bundle line 47719)

Attributes:

Name Type Description
group_id int

The constructionItemGroupID column.

level int

Upgrade level; -1 when the row has none.

rareness_id int

The rarenessID column.

group_id instance-attribute

group_id: int

The constructionItemGroupID column.

level instance-attribute

level: int

Upgrade level; -1 when the row has none.

rareness_id instance-attribute

rareness_id: int

The rarenessID column.

Currency

Bases: str, Enum

Currency keys from the currencies table, the key the server uses, named from the game's English name; coins and rubies are not in it.

Client: CurrencyData.getXmlCurrencyByKey (bundle line 141194); names from currency_name_<assetName or Name> (CollectableItemGenericCurrencyVO.getNameTextId, bundle line 5267)

Methods:

Name Description
display_name

The game's name for it in lang, the text currency_name_<assetName or Name>.

Attributes:

Name Type Description
currency_id int

The currency's id, as other tables reference it.

text_id str

The text id the game names it by, which display_name reads.

currency_id instance-attribute

currency_id: int

The currency's id, as other tables reference it.

text_id instance-attribute

text_id: str

The text id the game names it by, which display_name reads.

display_name

display_name(lang: str = 'en') -> str

The game's name for it in lang, the text currency_name_<assetName or Name>.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: CollectableItemGenericCurrencyVO.getNameTextId (bundle line 5267)

CurrencyId

Bases: IntEnum

Currency ids from the currencies table, as other tables reference them; names match Currency.

Client: XmlCurrencyVO.parseXml (bundle line 141282)

Methods:

Name Description
display_name

The game's name for it in lang, the text currency_name_<assetName or Name>.

Attributes:

Name Type Description
json_key str

The key the server uses for it, a Currency value.

text_id str

The text id the game names it by, which display_name reads.

json_key instance-attribute

json_key: str

The key the server uses for it, a Currency value.

text_id instance-attribute

text_id: str

The text id the game names it by, which display_name reads.

display_name

display_name(lang: str = 'en') -> str

The game's name for it in lang, the text currency_name_<assetName or Name>.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: CollectableItemGenericCurrencyVO.getNameTextId (bundle line 5267)

DailyQuestId

Bases: IntEnum

Daily quest ids from the dailyactivities table, named from what the first condition counts. Named DailyQuestId, as empire_core.quests.DailyQuest is today's quest.

Client: CastleDailyQuestData.createXmlQuestDic (bundle line 134082), DailyQuestVO.fillFromParamXML (bundle line 134124)

Attributes:

Name Type Description
trigger_kingdom_id int

The kingdom the quest counts in, a Kingdom value; -1 for any.

trigger_kingdom_id instance-attribute

trigger_kingdom_id: int

The kingdom the quest counts in, a Kingdom value; -1 for any.

DifficultyType

Bases: IntEnum

Event difficulty type ids from the eventAutoScalingDifficultyTypes table.

Client: EventAutoScalingDifficultyTypeVO.parseXML (bundle line 38258)

EffectType

Bases: IntEnum

Effect type ids from the effecttypes table.

Client: CastleEffectTypeVO (bundle line 111835)

Effect

Bases: IntEnum

Effect ids from the effects table.

Client: EffectVO.parseXML (bundle line 41702)

Attributes:

Name Type Description
effect_type_id int

The effect type it modifies, an EffectType value.

effect_type_id instance-attribute

effect_type_id: int

The effect type it modifies, an EffectType value.

EquipmentGroup

Bases: IntEnum

Equipment item group ids from the equipment_groups table, as equipment effects name them.

Client: XmlEquipmentGroupVO.parseXml (bundle line 144187)

Attributes:

Name Type Description
wearer_id int

Who wears it, a WearerType value.

slot_id int

The slot it goes in, an EquipmentSlot value.

wearer_id instance-attribute

wearer_id: int

Who wears it, a WearerType value.

slot_id instance-attribute

slot_id: int

The slot it goes in, an EquipmentSlot value.

Event

Bases: IntEnum

Event ids from the events table, named from eventType.

Client: CastleSpecialEventData.storeXmlEvents (bundle line 139777) keys rows by eventID, ASpecialEventVO.parseBasicsFromXmlNode (bundle line 2959) reads eventType

Methods:

Name Description
display_name

The game's name for it in lang, the text event_title_<value>; None when the language file has no such

Attributes:

Name Type Description
text_id str

The text id of its name, event_title_<value>.

text_id property

text_id: str

The text id of its name, event_title_<value>.

display_name

display_name(lang: str = 'en') -> str | None

The game's name for it in lang, the text event_title_<value>; None when the language file has no such text.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: "event_title_" + eventID, as the reward hub, alliance quests and season events name an event (bundle lines 54451, 111097 and 31389)

Gem

Bases: IntEnum

Gem ids from the gems table, named from the game's English name and, unless unique, level.

Client: CastleGemVO.parseXML (bundle line 28287); names from CastleGemVO.nameString (bundle line 28321)

Methods:

Name Description
display_name

The game's name for it in lang, the text gem_unique_<reuseAssetOfGemID> or gem_effect_name_<gem type>,

Attributes:

Name Type Description
level int

Gem level; 0 for a unique gem.

set_id int

Its set; -1 for none.

text_id str

The text id the game names it by, which display_name reads.

level instance-attribute

level: int

Gem level; 0 for a unique gem.

set_id instance-attribute

set_id: int

Its set; -1 for none.

text_id instance-attribute

text_id: str

The text id the game names it by, which display_name reads.

display_name

display_name(lang: str = 'en') -> str

The game's name for it in lang, the text gem_unique_<reuseAssetOfGemID> or gem_effect_name_<gem type>, its {0} filled with the level.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: CastleGemVO.nameString (bundle line 28321)

GeneralAbility

Bases: IntEnum

General ability ids from the generalAbilities table, one per level.

Client: GeneralAbilityXmlVO.fillFromParamXml (bundle line 113203)

Attributes:

Name Type Description
ability_group_id int

The group the ability's levels share.

level int

Upgrade level; -1 when the row has none.

ability_group_id instance-attribute

ability_group_id: int

The group the ability's levels share.

level instance-attribute

level: int

Upgrade level; -1 when the row has none.

GeneralSkill

Bases: IntEnum

General skill ids from the generalSkills table, named general, skill and level.

Client: GeneralSkillVO.parseXML (bundle line 113363)

Attributes:

Name Type Description
general_id int

The general it belongs to, a General value.

level int

Upgrade level; -1 when the row has none.

general_id instance-attribute

general_id: int

The general it belongs to, a General value.

level instance-attribute

level: int

Upgrade level; -1 when the row has none.

General

Bases: IntEnum

General ids from the generals table.

Client: GeneralXmlVO.fillFromParamXml (bundle line 33102)

Methods:

Name Description
display_name

The game's name for it in lang, the text generals_characters_<value>_name; None when the language file

Attributes:

Name Type Description
rarity_id int

The generalRarityID column.

text_id str

The text id of its name, generals_characters_<value>_name.

rarity_id instance-attribute

rarity_id: int

The generalRarityID column.

text_id property

text_id: str

The text id of its name, generals_characters_<value>_name.

display_name

display_name(lang: str = 'en') -> str | None

The game's name for it in lang, the text generals_characters_<value>_name; None when the language file has no such text.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: GeneralXmlVO.nameTextID (bundle line 33105)

GlobalEffect

Bases: IntEnum

Global effect ids from the globalEffects table.

Client: GlobalEffectVO.parseXml (bundle line 143690)

Horse

Bases: IntEnum

Travel booster wodID values from the horses table, the HBW movements send, named from the comment2 and comment1 notes: the game names a horse only by its button's place in the travel dialog, the tooltip text horse<n>.

Client: HorseTravelboosterVO.parseXmlNode (bundle line 118814); ACastlePostActionDialog.calculateTooltip (bundle line 27269)

LegendSkill

Bases: IntEnum

Legend skill ids from the legendskills table, named effect type, tree, group and level.

Client: CastleLegendSkillVO.parseXML (bundle line 48652)

Methods:

Name Description
display_name

The game's name for it in lang, the text dialog_legendTemple_<skill_group_id>_name.

Attributes:

Name Type Description
skill_tree_id int

The tree it sits in.

skill_group_id int

The group its levels share.

level int

Upgrade level; -1 when the row has none.

text_id str

The text id of its name, dialog_legendTemple_<skill_group_id>_name.

skill_tree_id instance-attribute

skill_tree_id: int

The tree it sits in.

skill_group_id instance-attribute

skill_group_id: int

The group its levels share.

level instance-attribute

level: int

Upgrade level; -1 when the row has none.

text_id property

text_id: str

The text id of its name, dialog_legendTemple_<skill_group_id>_name.

display_name

display_name(lang: str = 'en') -> str

The game's name for it in lang, the text dialog_legendTemple_<skill_group_id>_name.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: CastleLegendSkillVO.nameTextID (bundle line 48669)

LootBoxType

Bases: IntEnum

Loot box type ids from the lootBoxTypes table, named from lootBoxTheme; keys count per type.

Client: LootBoxTypeVO.parseXML (bundle line 58900)

LootBox

Bases: IntEnum

Loot box ids from the lootBoxes table, named name and rarity.

Client: LootBoxVO.parseXML (bundle line 112502)

Attributes:

Name Type Description
rarity int

The rarity column.

rarity instance-attribute

rarity: int

The rarity column.

MainQuest

Bases: IntEnum

Main quest ids from the mainquests table, the quest book's chapters, named from the game's English title.

Client: CastleQuestBookMainQuestListVO.parseListsFromParamObject (bundle line 52419); names from mainquest_<id>_title (bundle line 93386)

Methods:

Name Description
display_name

The game's name for it in lang, the text mainquest_<value>_title.

Attributes:

Name Type Description
text_id str

The text id of its name, mainquest_<value>_title.

text_id property

text_id: str

The text id of its name, mainquest_<value>_title.

display_name

display_name(lang: str = 'en') -> str

The game's name for it in lang, the text mainquest_<value>_title.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: the quest book's chapter dialog (bundle line 93386)

QuestId

Bases: IntEnum

Quest ids from the quests table, named from what the first condition counts; most names carry their id, as many quests count the same thing. Named QuestId, as empire_core.quests.Quest is your running quest.

Client: CastleQuestData.generateQuestXMLList (bundle line 20192), CastleQuestVO.fillFromParamXML (bundle line 52452)

Attributes:

Name Type Description
series_id int

The quest series it belongs to; -1 for none.

event_id int

The event it belongs to, an Event value; 0 for none.

series_id instance-attribute

series_id: int

The quest series it belongs to; -1 for none.

event_id instance-attribute

event_id: int

The event it belongs to, an Event value; 0 for none.

RaidBoss

Bases: IntEnum

Alliance raid boss ids from the raidBosses table.

Client: AllianceRaidbossVO.parseXML (bundle line 113835)

Research

Bases: IntEnum

Research ids from the researches table, named from the game's English title and level; a blueprint or recipe research from the comment2 note, group and level.

Client: AResearchVO.fillFromParamXML (bundle line 61502), which does not read comment2; titles from ResearchVO.nameTextId (bundle line 61480)

Methods:

Name Description
display_name

The game's name for it in lang, the text research_<groupID>_title or ci_blueprint_<item name>; None for

Attributes:

Name Type Description
group_id int

The group the research's levels share.

level int

Upgrade level; -1 when the row has none.

text_id str

The text id the game names it by, which display_name reads.

group_id instance-attribute

group_id: int

The group the research's levels share.

level instance-attribute

level: int

Upgrade level; -1 when the row has none.

text_id instance-attribute

text_id: str

The text id the game names it by, which display_name reads.

display_name

display_name(lang: str = 'en') -> str | None

The game's name for it in lang, the text research_<groupID>_title or ci_blueprint_<item name>; None for a row without one.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: ResearchVO.nameTextId (bundle line 61480), BlueprintResearchVO.nameTextId (bundle line 139596); a crafting recipe research has none here, as its name holds its recipe's output (CraftingRecipeResearchVO.fullNameText, bundle line 139405)

SceatSkill

Bases: IntEnum

Sceat skill ids from the sceatSkills table, named from the game's English name and level.

Client: CastleSceatSkillVO.parseXML (bundle line 23074); names from nameTextID (bundle line 23110)

Methods:

Name Description
display_name

The game's name for it in lang, the text dialog_legendTemple_sceat_<skill_group_id>_name.

Attributes:

Name Type Description
skill_group_id int

The group its levels share.

skill_tree_id int

The tree it sits in.

level int

Upgrade level; -1 when the row has none.

text_id str

The text id of its name, dialog_legendTemple_sceat_<skill_group_id>_name.

skill_group_id instance-attribute

skill_group_id: int

The group its levels share.

skill_tree_id instance-attribute

skill_tree_id: int

The tree it sits in.

level instance-attribute

level: int

Upgrade level; -1 when the row has none.

text_id property

text_id: str

The text id of its name, dialog_legendTemple_sceat_<skill_group_id>_name.

display_name

display_name(lang: str = 'en') -> str

The game's name for it in lang, the text dialog_legendTemple_sceat_<skill_group_id>_name.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: CastleSceatSkillVO.nameTextID (bundle line 23110)

Title

Bases: IntEnum

Title ids from the titles table, named from the game's English title.

Client: TitleVO.parseXml (bundle line 62705); names from TitleVO.textID (bundle line 62756)

Methods:

Name Description
display_name

The game's name for it in lang, the text playerTitle_<value>.

Attributes:

Name Type Description
title_system str

Its title system, a TitleSystem value.

text_id str

The text id of its name, playerTitle_<value>.

title_system instance-attribute

title_system: str

Its title system, a TitleSystem value.

text_id property

text_id: str

The text id of its name, playerTitle_<value>.

display_name

display_name(lang: str = 'en') -> str

The game's name for it in lang, the text playerTitle_<value>.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: TitleVO.textID (bundle line 62756)

Tool

Bases: IntEnum

Tool wodID values from the units table (rows with slotTypes).

Client: ToolUnitVO.parseXmlNode (bundle line 6538)

Methods:

Name Description
display_name

The game's name for it in lang, the text <type>_name.

Attributes:

Name Type Description
level int

Upgrade level; -1 when the row has none.

category str

Attack or Defence; "0" when the row has none.

text_id str

The text id the game names it by, which display_name reads.

level instance-attribute

level: int

Upgrade level; -1 when the row has none.

category instance-attribute

category: str

Attack or Defence; "0" when the row has none.

text_id instance-attribute

text_id: str

The text id the game names it by, which display_name reads.

display_name

display_name(lang: str = 'en') -> str

The game's name for it in lang, the text <type>_name.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: BasicUnitVO.getNameString (bundle line 19219)

Unit

Bases: IntEnum

Unit wodID values from the units table (rows without slotTypes).

Client: SoldierUnitVO.parseXmlNode (bundle line 12531)

Methods:

Name Description
display_name

The game's name for it in lang, the text <type>_name.

Attributes:

Name Type Description
level int

Upgrade level; -1 when the row has none.

role str

melee or ranged.

text_id str

The text id the game names it by, which display_name reads.

level instance-attribute

level: int

Upgrade level; -1 when the row has none.

role instance-attribute

role: str

melee or ranged.

text_id instance-attribute

text_id: str

The text id the game names it by, which display_name reads.

display_name

display_name(lang: str = 'en') -> str

The game's name for it in lang, the text <type>_name.

Fetches the language file on first use and caches it (empire_core.texts.text); a text the file lacks, or a failed fetch, gives the text id.

Client: BasicUnitVO.getNameString (bundle line 19219)

is_current

is_current(game_data: GameData) -> bool

Whether game_data is the items version these enums were generated from.