Template:EntryDef

From Heroes of Might and Magic: Olden Era Official Wiki

A generic, hand-curated reference table for named terms with no extra structure — the catch-all for any reference data that fits the "name + description + i18n" shape and nothing else. As soon as an entity needs additional columns (rank, pattern_token, cost, prerequisites, …) it belongs in its own dedicated table.

Entry is a thin structural stub. It carries only the identity and traceability of each term; all display text — names, descriptions, and their translations, English included — lives in the shared Translation table, whose (type, subtype, variant) key tiers match this row's (type, subtype, variant).

Each row carries:

  • a type + subtype + variant primary key
  • an optional icon filename
  • the canonical L10n name_sid + desc_sid + optional narrative_description_sid the row was sourced from — traceability only, not part of the lookup path
  • a source_path pointer to the L10n file (or source JSON for per-patch extracts) the row came from

Entry rows come from two sources:

  1. Hand-curated seeds — small enums the wiki ships pre-populated (attack archetypes, movement types, creature types). These live in the ENTRY_SEEDS dict in src/obelisk/emit/unit.py.
  2. Per-patch extracted data — name+i18n-only data harvested from the source JSON each patch (currently: faction city names from DB/fractions/*.json). The extractor module (extract/faction.py, etc.) hands the SID directly to emit_entry_page; no seed-dict detour.

In both cases the bot resolves each row's translations from the L10n corpus on every extract and emits them as Translation rows, so per-patch text changes flow through.

Schema

This template defines the table "Entry". View table.

{{EntryDef
| type = String (allowed values=attack_archetype,movement,creature_type,FactionCityName,resource,hero_stat,unit_stat,ui)
| subtype = String
| variant = String                            <!-- optional third key component for sub-row variants (level/rank); sparse -->
| icon = String
| name_sid = String
| desc_sid = String
| narrative_description_sid = String
| source_path = String
}}

Field notes

  • Primary key is (type, subtype, variant) as a tuple. variant is the optional third key tier — sparse, and not used by any Entry type that currently ships (it's kept on the stub for uniformity with the shared key pyramid). Joins from per-unit columns include the type discriminator: e.g. UnitDef.attack_type joins to EntryDef.subtype WHERE EntryDef.type='attack_archetype'.
  • variant is String-typed so it can hold either integer indices or freeform variant codes should a future Entry type need a third key tier. Per-(entity, level) data — law levels, skill levels, spell ranks — does not fold into Entry; those are per-level rows of real parent entities and live in their own structural tables (LawLevel, SkillLevel, SpellRank) with translations keyed by target_id + variant in the Translation table.
  • All display text is in Translation, not here. To get the English label for an Entry term: Translation.name WHERE type='<type>' AND subtype='<subtype>' AND variant='<variant>' AND language='en'. Other languages swap the language filter.
  • icon is optional. Sparse-emit: if a seed has no icon configured, the field is omitted from the row.
  • name_sid / desc_sid / narrative_description_sid are surfaced for traceability — they point at the L10n entries the row was sourced from. Useful for "find which game string drives this label" queries, but they are not the join path to translations.

Page layout

Each Entry type gets its own top-level wiki namespace and on-disk directory — the EntryDef Cargo table name only surfaces in the table schema and the {{EntryDef | … }} template invocations inside each page. The EntryDef abstraction is internal; user-facing wiki paths use the per-domain names that already exist as game concepts.

  • On wiki: Data:<PascalType>/<subtype> (e.g. Data:Movement/fly).
  • On disk: data/<type>/<subtype>.wiki.txt (e.g. data/movement/fly.wiki.txt).

Each Entry page emits the {{EntryDef}} stub row followed by one {{TranslationDef}} row per language.

Examples:

Type On disk On wiki
attack_archetype data/attack_archetype/melee.wiki.txt Data:AttackArchetype/melee
movement data/movement/fly.wiki.txt Data:Movement/fly
creature_type data/creature_type/demon.wiki.txt Data:CreatureType/demon (Hive Spawn)
FactionCityName (inline on data/factions/<id>.wiki.txt) (inline on Data:Faction/<id>)

The directory→wiki-namespace mapping lives in _DIR_TO_WIKI_TABLE (src/obelisk/diff/wiki_diff.py) — extend it when adding a new Entry type.

Initial canonical content

These three types ship in the initial Entry rollout. Each row's name and description come from the L10n corpus via name_sid / desc_sid on every extract and land in the Translation table; the tables below summarize.

type=attack_archetype (3 rows)

subtype display name (en) name_sid
melee Melee Attack base_passive_melee_attack_name
ranged Ranged Attack base_passive_ranged_attack_name
reach Long Reach base_passive_remote_attack_name

JSON enum mapping (in extract/unit.py): melee → melee, shoot → ranged, range → reach. Naming flip on range→reach.

type=movement (2 rows)

subtype display name (en) name_sid
fly Flying base_passive_flyer_name
teleport Blink base_passive_blink_name

Naming flip on teleport enum → "Blink" display. Walkers are encoded as the absence of Unit.move_type — no Entry row.

type=creature_type (7 rows)

subtype display name (en) name_sid
living Living base_class_living
undead Undead base_class_undead
demon Hive Spawn base_class_demon
magic_creature Magic Creature base_class_magic_creature
embodiment Embodiment base_class_embodiment
dragon Dragon base_class_dragon
construct Construct base_class_construct

Naming flip on demon enum → "Hive Spawn" display. Description text contains placeholders that are pre-substituted at extract time via Lang/args/unitsAbility.json + units.script (class-wide morale and luck range bounds).

type=FactionCityName (120 rows; per-patch extracted)

Six factions × 20 names each. Subtype is <faction>_<index> (e.g. dungeon_1 … dungeon_20). Source: cityNames array on each faction record in DB/fractions/*.json. Display names are genuinely translated (8-16 distinct strings per name across the 16 languages — CJK languages get full character-set translations; Latin scripts mix preservation, idiomatic translation, and phonetic transliteration). No desc_sid exists for city names — description translation rows are simply not emitted.

Unlike the rows above, these are not hand-curated seeds — they're extracted per-patch from the source JSON. They also do not live on individual wiki pages: the 20 city Entry stubs for a given faction (plus their Translation rows) are appended to that faction's Data:Faction/<id> page, in numeric source order. The faction emitter calls render_entry_block(...) to inline each row.

What does NOT belong here

Anything with structure beyond name/description/i18n keeps its own table. For example, AttackPassiveDef carries pattern_token and rank columns and stays separate. The rule: if you'd add a column for a single use case, it goes in its own dedicated table. Entry is for the "identical shape, different domain" cases only.

Related

  • Translation — every Entry term's display text (all languages) lives there, keyed by matching (type, subtype, variant).
  • [[../Unit|UnitDef]] — references multiple Entry types via attack_type, move_type, creature_type columns.
  • AttackPassive — separate table; has columns beyond the Entry shape.