Template:HeroDef: Difference between revisions
obelisk-bot: uploading initial Cargo templates |
obelisk-bot: Pushing translation table rework |
||
| (One intermediate revision by the same user not shown) | |||
| Line 5: | Line 5: | ||
The bot emits these per-hero blocks at <code>Data:Hero/<id></code>: | The bot emits these per-hero blocks at <code>Data:Hero/<id></code>: | ||
# <code><nowiki>{{HeroDef | id | # <code><nowiki>{{HeroDef | id=… | start_skills=… | start_magics=… | …}}</nowiki></code> — main row. <code>start_skills</code> and <code>start_magics</code> are comma-joined SID lists inline on this row (no side tables for them). | ||
# <code><nowiki>{{TranslationDef | type=hero | target_id=<id> | …}}</nowiki></code> — name/ | # <code><nowiki>{{TranslationDef | type=hero | target_id=<id> | language=… | name=… | description=… }}</nowiki></code> × N — name/description, one row per language. | ||
# <code><nowiki>{{TranslationDef | type=hero_motto | target_id=<id> | …}}</nowiki></code> — motto translation ( | # <code><nowiki>{{TranslationDef | type=hero_motto | target_id=<id> | language=… | description=… }}</nowiki></code> × N — motto, a separate translation key, one row per language (motto text goes in the <code>description</code> column since it may carry markup). | ||
# <code><nowiki>{{HeroStartSquadDef | …}}</nowiki></code> × N — one per starting squad slot (primary + alt collapsed via <code>variant</code> discriminator). | # <code><nowiki>{{HeroStartSquadDef | …}}</nowiki></code> × N — one per starting squad slot (primary + alt collapsed via <code>variant</code> discriminator). | ||
| Line 13: | Line 13: | ||
{{#cargo_declare:_table=Hero | {{#cargo_declare:_table=Hero | ||
| id = String | | id = String | ||
| name_sid = String | | name_sid = String | ||
| motto_sid = String | | motto_sid = String | ||
| Line 60: | Line 57: | ||
{{HeroDef | {{HeroDef | ||
| id = String | | id = String | ||
<!-- Localization references — display text lives in the Translation table: | |||
type='hero' carries name+description, type='hero_motto' carries the motto --> | |||
| name_sid = String | | name_sid = String | ||
| motto_sid = String | | motto_sid = String | ||
| Line 85: | Line 82: | ||
<!-- Note: spell level / isLearned are dropped (constant in the | <!-- Note: spell level / isLearned are dropped (constant in the | ||
2026-05-03 corpus | 2026-05-03 corpus). Skill level is preserved because 8/208 | ||
entries diverge from the default of 1. --> | |||
| Line 143: | Line 140: | ||
== Field notes == | == Field notes == | ||
* '''<code>id</code>''' is the hero's source JSON id (e.g. <code>human_hero_1</code>, <code>campaign_M10_hero_demon_1</code>). | * '''<code>id</code>''' is the hero's source JSON id (e.g. <code>human_hero_1</code>, <code>campaign_M10_hero_demon_1</code>). | ||
* '''<code>name_sid</code>/<code>motto_sid</code>/<code>desc_sid</code>''' carry the source SID for traceability | * '''<code>name_sid</code>/<code>motto_sid</code>/<code>desc_sid</code>''' carry the source SID for traceability only. Faction heroes use implicit conventions (<code><id></code> / <code><id>_motto</code> / <code><id>_description</code>); campaign heroes set them explicitly in source JSON. | ||
* ''' | * '''Display name / motto / description''' for every language (English included) live in the [[Template:TranslationDef|Translation]] table — <code>type='hero'</code> rows carry name + description, <code>type='hero_motto'</code> rows carry the motto. Both keyed on <code>target_id = Hero.id</code>. | ||
* '''<code>class_id</code>''' is <code><class_type>_<faction></code> — matches <code>HeroClass.id</code>. | * '''<code>class_id</code>''' is <code><class_type>_<faction></code> — matches <code>HeroClass.id</code>. | ||
* '''<code>faction</code>/<code>class_type</code>''' are denormalized from the class so that "all human heroes" / "all might heroes" filters don't need a join. | * '''<code>faction</code>/<code>class_type</code>''' are denormalized from the class so that "all human heroes" / "all might heroes" filters don't need a join. | ||
| Line 154: | Line 151: | ||
* <code>SkillDef</code> (future) — joined on <code>start_skills</code> LIKE <code>%<sid>%</code> or via Cargo's <code>HOLDS</code> operator on the List column. | * <code>SkillDef</code> (future) — joined on <code>start_skills</code> LIKE <code>%<sid>%</code> or via Cargo's <code>HOLDS</code> operator on the List column. | ||
* <code>SpellDef</code> (future) — same join pattern via <code>start_magics</code>. | * <code>SpellDef</code> (future) — same join pattern via <code>start_magics</code>. | ||
* [[Template:HeroSpecializationDef|HeroSpecialization]] — joined on <code>specialization_id = id</code> (N:1). The hero's unique passive. | |||
* [[Template:TranslationDef|<code> | * [[Template:TranslationDef|Translation]] — display text in every language (English included), joined on <code>id = Translation.target_id</code> with <code>Translation.type IN ('hero', 'hero_motto')</code> and the desired <code>language</code> filter (1:N, two keys × one row per language). | ||
== Notes == | == Notes == | ||
| Line 162: | Line 159: | ||
</noinclude><includeonly>{{#cargo_store:_table=Hero | </noinclude><includeonly>{{#cargo_store:_table=Hero | ||
| id = {{{id|}}} | | id = {{{id|}}} | ||
| name_sid = {{{name_sid|}}} | | name_sid = {{{name_sid|}}} | ||
| motto_sid = {{{motto_sid|}}} | | motto_sid = {{{motto_sid|}}} | ||
| Line 204: | Line 198: | ||
| roll_lvl24_power = {{{roll_lvl24_power|}}} | | roll_lvl24_power = {{{roll_lvl24_power|}}} | ||
| roll_lvl24_knowledge = {{{roll_lvl24_knowledge|}}} | | roll_lvl24_knowledge = {{{roll_lvl24_knowledge|}}} | ||
}}</includeonly> | }} | ||
Created <code>Hero</code> entry: <code>{{{id|}}}</code></includeonly> | |||
Latest revision as of 20:48, 14 May 2026
One row per hero (~177 in the 2026-05-03 corpus: 108 faction + 46 campaign + 21 tutorial + 2 custom-map). Carries the per-hero identity (name/motto/desc), the link to the parent HeroClass, and any class-default fields the hero diverges on. Faction heroes match their class template exactly, so their override fields are sparse-emitted (absent); campaign and tutorial heroes routinely override stats, start_level, and
attacks_times_before.
The bot emits these per-hero blocks at Data:Hero/<id>:
{{HeroDef | id=… | start_skills=… | start_magics=… | …}}— main row.start_skillsandstart_magicsare comma-joined SID lists inline on this row (no side tables for them).{{TranslationDef | type=hero | target_id=<id> | language=… | name=… | description=… }}× N — name/description, one row per language.{{TranslationDef | type=hero_motto | target_id=<id> | language=… | description=… }}× N — motto, a separate translation key, one row per language (motto text goes in thedescriptioncolumn since it may carry markup).{{HeroStartSquadDef | …}}× N — one per starting squad slot (primary + alt collapsed viavariantdiscriminator).
Schema
This template defines the table "Hero". View table.
{{HeroDef
| id = String
<!-- Localization references — display text lives in the Translation table:
type='hero' carries name+description, type='hero_motto' carries the motto -->
| name_sid = String
| motto_sid = String
| desc_sid = String
| class_id = String <!-- joins HeroClass.id (e.g. magic_demon) -->
| faction = String <!-- denormalized from class -->
| class_type = String (allowed values=might,magic)
| icon = String
| specialization_id = String <!-- joins HeroSpecialization.id -->
| source_path = String
<!-- Inline list-of-SID columns (always present; empty when none).
start_skills and start_skill_levels are positionally aligned —
the Nth element of start_skill_levels is the level for the Nth
skill SID in start_skills. -->
| start_skills = List (,) of String <!-- joins future Skill.id -->
| start_skill_levels = List (,) of Integer <!-- positionally aligned with start_skills -->
| start_magics = List (,) of String <!-- joins future Spell.id -->
<!-- Note: spell level / isLearned are dropped (constant in the
2026-05-03 corpus). Skill level is preserved because 8/208
entries diverge from the default of 1. -->
<!-- Class-default override fields. Sparse: absent means inherit from
HeroClass. Faction heroes always inherit (no overrides).
Campaign/tutorial heroes routinely override stats + a few others. -->
| cost_gold = Integer
| start_level = Integer
| attacks_times_before = String <!-- comma-joined floats -->
| mesh = String
| mount = String
| native_biome = String
| skills_roll_variant = String
<!-- Stat block overrides -->
| view_radius = Integer
| stats_num = Integer
| magic_casts_per_round = Integer
| enable_tactics = Boolean
| tactics_placement_size = Integer
| enable_hero_native_biome = Boolean
| offence = Integer
| defence = Integer
| spell_power = Integer
| intelligence = Integer
| luck = Integer
| morale = Integer
<!-- statsRolls overrides (named after the four primary stats; see
HeroClass.md for the v=0..3 → attack/defense/power/knowledge
mapping). -->
| roll_lvl1_attack = Integer
| roll_lvl1_defense = Integer
| roll_lvl1_power = Integer
| roll_lvl1_knowledge = Integer
| roll_lvl24_attack = Integer
| roll_lvl24_defense = Integer
| roll_lvl24_power = Integer
| roll_lvl24_knowledge = Integer
}}
Override semantics
Every Cargo query that wants the effective value of a class-shared field on a hero should use:
<syntaxhighlight lang="sql"> COALESCE(Hero.<col>, HeroClass.<col>) AS effective_<col> </syntaxhighlight>
Joining on Hero.class_id = HeroClass.id. Hero wins if present; HeroClass fills in otherwise.
For faction heroes (108): all 11 class-shared columns are absent on the Hero row — every query falls through to HeroClass.
For campaign/tutorial heroes: ~3-5 columns are typically present (empirically: stats_*, start_level, attacks_times_before). Other class-shared columns still inherit from HeroClass.
Field notes
idis the hero's source JSON id (e.g.human_hero_1,campaign_M10_hero_demon_1).name_sid/motto_sid/desc_sidcarry the source SID for traceability only. Faction heroes use implicit conventions (<id>/<id>_motto/<id>_description); campaign heroes set them explicitly in source JSON.- Display name / motto / description for every language (English included) live in the Translation table —
type='hero'rows carry name + description,type='hero_motto'rows carry the motto. Both keyed ontarget_id = Hero.id. class_idis<class_type>_<faction>— matchesHeroClass.id.faction/class_typeare denormalized from the class so that "all human heroes" / "all might heroes" filters don't need a join.specialization_idpoints at a row inHeroSpecializationDef(one specialization per hero, 1:1 ratio). Schema for that table comes in a follow-up.
Related tables
- HeroClass — joined on
class_id = id(N:1). Carries the class defaults the Hero row may override. - HeroStartSquad — joined on
hero_id = id(1:N). Each row is one slot in primary or alt starting army. SkillDef(future) — joined onstart_skillsLIKE%<sid>%or via Cargo'sHOLDSoperator on the List column.SpellDef(future) — same join pattern viastart_magics.- HeroSpecialization — joined on
specialization_id = id(N:1). The hero's unique passive. - Translation — display text in every language (English included), joined on
id = Translation.target_idwithTranslation.type IN ('hero', 'hero_motto')and the desiredlanguagefilter (1:N, two keys × one row per language).


