You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
autohero/docs/specification-content-catal...

307 lines
19 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# AutoHero Content Catalog (MVP Companion)
Aligned with `specification.md` sections 2.32.4, 4, **5.3**, **6.36.4**, 8, 11, and 12. Section **0a**: `gear.form.*`; section **0d**: `gear.ammo.*` и слот `quiver`. **Item scaling** (`ilvl`, `M(rarity)`, `L(ilvl)`) — канон в `specification.md` §6.4.
Goal: provide engineering-ready IDs and mappings for models, sounds, and VFX intent.
## 0) Equipment Slot Catalog (gear)
Naming convention:
- `gear.slot.<slug>` — canonical slot keys (see `specification.md` §6.3)
- Item instances reference exactly one slot; item family IDs may use `item.<category>.<slug>.v1` when introduced in implementation
| slotId | displayName (EN) | notes |
|---|---|---|
| `gear.slot.main_hand` | Main hand | weapons |
| `gear.slot.off_hand` | Off hand | shield or off-hand weapon |
| `gear.slot.head` | Head | helmet, hood, hat |
| `gear.slot.chest` | Chest | body armor |
| `gear.slot.legs` | Legs | leggings, greaves |
| `gear.slot.feet` | Feet | boots |
| `gear.slot.cloak` | Cloak | cloak, cape, mantle |
| `gear.slot.neck` | Neck | amulet, medallion |
| `gear.slot.finger` | Finger | rings (implementation may use `finger_1` / `finger_2`) |
| `gear.slot.wrist` | Wrist | bracers, bracelets |
| `gear.slot.quiver` | Quiver | arrows/bolts; active only with bow or crossbow in `main_hand` (see §5.3) |
### 0a) Equipment form catalog (виды / подтипы по слотам)
Назначение: стабильные ключи **формы предмета** (визуальный и дизайн-архетип), привязанные к **ровно одному** `gear.slot.*`.
Используются в данных лута, UI-иконках, генерации имён и связке с `modelId` одежды.
Naming convention:
- `gear.form.<slotKey>.<formSlug>` — канонический ID вида; `<slotKey>` совпадает с суффиксом `gear.slot.<slotKey>`
- Предмет в инвентаре ссылается на `slotId` + опционально `formId` = `gear.form.*`
- Новые виды добавляются только сюда; произвольные строки в коде не вводить
| formId | slotId | displayName (EN) | displayName (RU) | notes |
|---|---|---|---|---|
| `gear.form.main_hand.sword` | `gear.slot.main_hand` | Sword | Меч | baseline blade |
| `gear.form.main_hand.axe` | `gear.slot.main_hand` | Axe | Топор | heavy swing |
| `gear.form.main_hand.dagger` | `gear.slot.main_hand` | Dagger | Кинжал | fast, low base |
| `gear.form.main_hand.mace` | `gear.slot.main_hand` | Mace | Булава | blunt |
| `gear.form.main_hand.staff` | `gear.slot.main_hand` | Staff | Посох | two-handed caster vibe |
| `gear.form.main_hand.spear` | `gear.slot.main_hand` | Spear | Копьё | reach |
| `gear.form.main_hand.bow` | `gear.slot.main_hand` | Bow | Лук | ranged; pairs with `gear.slot.quiver` |
| `gear.form.main_hand.crossbow` | `gear.slot.main_hand` | Crossbow | Арбалет | ranged; pairs with `gear.slot.quiver` |
| `gear.form.off_hand.shield` | `gear.slot.off_hand` | Shield | Щит | block / defense |
| `gear.form.off_hand.buckler` | `gear.slot.off_hand` | Buckler | Баклер | small shield |
| `gear.form.off_hand.orb` | `gear.slot.off_hand` | Orb | Сфера | off-hand caster |
| `gear.form.head.helmet` | `gear.slot.head` | Helmet | Шлем | full head metal |
| `gear.form.head.hood` | `gear.slot.head` | Hood | Капюшон | cloth/leather |
| `gear.form.head.hat` | `gear.slot.head` | Hat | Шляпа | wide brim / travel |
| `gear.form.head.circlet` | `gear.slot.head` | Circlet | Диадема | light headband |
| `gear.form.head.mask` | `gear.slot.head` | Mask | Маска | face cover |
| `gear.form.head.coif` | `gear.slot.head` | Coif | Койф | mail under-helmet |
| `gear.form.chest.plate` | `gear.slot.chest` | Plate cuirass | Латы / кираса | heavy plate |
| `gear.form.chest.mail` | `gear.slot.chest` | Mail hauberk | Кольчуга | ring mail |
| `gear.form.chest.leather` | `gear.slot.chest` | Leather jack | Кожаный доспех | light |
| `gear.form.chest.robe` | `gear.slot.chest` | Robe | Роба | cloth / caster |
| `gear.form.chest.brigandine` | `gear.slot.chest` | Brigandine | Брига | riveted plates on cloth |
| `gear.form.legs.greaves` | `gear.slot.legs` | Greaves | Наколенники / латы ног | plate legs |
| `gear.form.legs.chausses` | `gear.slot.legs` | Chausses | Поножи (кольч.) | mail legs |
| `gear.form.legs.pants` | `gear.slot.legs` | Pants | Штаны | cloth/leather legs |
| `gear.form.legs.tassets` | `gear.slot.legs` | Tassets | Тассы | hanging plates |
| `gear.form.feet.boots` | `gear.slot.feet` | Boots | Сапоги | default footwear |
| `gear.form.feet.sabatons` | `gear.slot.feet` | Sabatons | Сабатоны | plate boots |
| `gear.form.feet.shoes` | `gear.slot.feet` | Shoes | Ботинки / туфли | light |
| `gear.form.feet.sandals` | `gear.slot.feet` | Sandals | Сандалии | open |
| `gear.form.cloak.cloak` | `gear.slot.cloak` | Cloak | Плащ | back slot mantle |
| `gear.form.cloak.cape` | `gear.slot.cloak` | Cape | Накидка | short back |
| `gear.form.cloak.mantle` | `gear.slot.cloak` | Mantle | Мантия | heavy drape |
| `gear.form.neck.amulet` | `gear.slot.neck` | Amulet | Амулет | default neck |
| `gear.form.neck.medallion` | `gear.slot.neck` | Medallion | Медальон | disk |
| `gear.form.neck.pendant` | `gear.slot.neck` | Pendant | Кулон | gem drop |
| `gear.form.neck.talisman` | `gear.slot.neck` | Talisman | Талисман | charm |
| `gear.form.finger.ring` | `gear.slot.finger` | Ring | Кольцо | default ring |
| `gear.form.finger.signet` | `gear.slot.finger` | Signet | Перстень | heavy ring |
| `gear.form.finger.band` | `gear.slot.finger` | Band | Обручь | slim band |
| `gear.form.wrist.bracers` | `gear.slot.wrist` | Bracers | Наручи | armor wrist |
| `gear.form.wrist.bracelet` | `gear.slot.wrist` | Bracelet | Браслет | jewelry |
| `gear.form.wrist.vambraces` | `gear.slot.wrist` | Vambraces | Рукава (латные) | plate forearm |
### 0d) Ammunition catalog (боеприпасы, слот `gear.slot.quiver`)
Naming convention:
- `gear.ammo.<slug>.v1` — каноническое семейство боеприпасов
- Экземпляр несёт `ilvl`, `rarity`; **первичный** бонус к атаке: `primaryOut = round(basePrimary × L(ilvl) × M(rarity))` (§6.4.3)
- **Вторичные** поля (`baseCritBps`, `baseArmorPenBps`): `secondaryOut = round(base × M(rarity))` (§6.4.4). Базисные пункты (bps): `100 = 1.00%`.
- `deltaSpeed` — целое, добавляется к стату **Speed** героя с предмета **без** масштабирования по `ilvl` (только знак и величина из каталога; при необходимости позже — отдельный баланс-пас)
| ammoId | basePrimary | baseCritBps | baseArmorPenBps | deltaSpeed | displayName (EN) | displayName (RU) | notes |
|---|---:|---:|---:|---:|---|---|---|
| `gear.ammo.crude_wood.v1` | 2 | 0 | 0 | 0 | Crude Wood Arrows | Грубые деревянные стрелы | стартовый/дешёвый дроп |
| `gear.ammo.hunting_standard.v1` | 3 | 15 | 0 | 0 | Standard Hunting Arrows | Охотничьи стрелы | лёгкий крит |
| `gear.ammo.flint_tipped.v1` | 4 | 35 | 0 | 0 | Flint-Tipped Arrows | Стрелы с кремнёвым наконечником | универсал |
| `gear.ammo.iron_bodkin.v1` | 5 | 0 | 80 | 0 | Iron Bodkin | Железные бодкины | упор в пробитие, без крита |
| `gear.ammo.steel_broadhead.v1` | 7 | 55 | 40 | -1 | Steel Broadheads | Стальные широкие наконечники | тяжелее, 1 Speed |
| `gear.ammo.silver_anointed.v1` | 6 | 25 | 100 | 0 | Silver-Anointed Bolts | Освящённые серебряные болты | тег `holy` для будущих модификаторов против нежити |
| `gear.ammo.glass_razor.v1` | 6 | 140 | 0 | -1 | Glass-Razor Quills | Стеклянные бритвенные оперения | высокий крит, хрупкий стиль |
| `gear.ammo.rune_fletched.v1` | 8 | 70 | 50 | 0 | Rune-Fletched Arrows | Стрелы с руническим оперением | маг. среда |
| `gear.ammo.manticore_barb.v1` | 10 | 90 | 70 | 0 | Manticore Barb Shafts | Шипы мантикоры | сильный mid/high family |
| `gear.ammo.starfall_sabot.v1` | 12 | 110 | 90 | 0 | Starfall Sabots | Сабо падающей звезды | top family base для лейт-дропа |
**Баланс-якорь:** при `ilvl ≈ 25`, `Common`, семейство `steel_broadhead`: `primaryOut ≈ round(7 × 1.72 × 1.00) = 12` к Attack; при `Rare`, `ilvl ≈ 14`: `round(7 × 1.39 × 1.30) ≈ 13` — редкость компенсирует более низкий ilvl (см. §6.4.3).
## 0b) World encounter & social content (map)
Naming convention:
- `encounter.player_meet.v1` — abstract meeting of two heroes (payload names players, positions)
- `event.duel.offer.v1` — optional duel prompt UI contract
- `event.social.pass.v1` — talk/walk / emote-only resolution
- `event.quest.alms.v1` — NPC mini-quest: pay gold → random garment
| contentKey | type | summary |
|---|---|---|
| `encounter.player_meet.v1` | encounter | Two heroes in proximity; server rolls outcome bucket (social vs duel prompt vs silent) |
| `event.social.pass.v1` | event | Emote / short line; no combat |
| `event.duel.offer.v1` | event | Show duel accept/decline; both must accept |
| `event.quest.alms.v1` | event | NPC asks for coins; success grants random `gear.slot.*` item |
## 0c) Non-hostile NPC catalog (minimal)
Naming convention:
- `npc.<role>.<slug>.v1`
- `modelId` follows `monster.*` style but for neutral: `npc.model.<slug>.v1` (neutral rigs)
| npcId | displayName | role | modelId | defaultInteraction |
|---|---|---|---|---|
| `npc.traveler.worn_merchant.v1` | Worn Merchant | quest_giver | `npc.model.worn_merchant.v1` | `event.quest.alms.v1` |
| `npc.hermit.ash_sage.v1` | Ash Sage | flavor_talk | `npc.model.ash_sage.v1` | `event.social.pass.v1` |
| `npc.child.lost_acorn.v1` | Lost Acorn Kid | flavor_talk | `npc.model.lost_acorn.v1` | `event.social.pass.v1` |
### 0c.1) Town building façades (`town_buildings.building_type`)
Stable keys for server-driven settlement props (non-interactive shell; NPC role is on `npcs.type`).
| buildingType | notes |
|---|---|
| `house.merchant` | Soft-goods / travel vendor stall |
| `house.armorer` | Armor pieces (legs, wrist, chest, head slots) |
| `house.weapon_smith` | Weapons (`main_hand`) |
| `house.jeweler` | Rings, amulets (`finger`, `neck`) |
| `house.bounty_hunter` | Contracts: kill / collect quests |
| `house.elder` | Civic / travel: visit / collect quests |
| `house.healer` | Healing services |
| `house.quest_giver` | Legacy façade (pre-migration rows may retain until reauthored) |
## 1) Monster Model Catalog
Naming convention:
- **Enemy content ID:** `enemy.<type>` where `<type>` is the **unique** DB column `enemies.type` (slug). There are **220** such IDs (one row per archetype × level band × biome template).
- **Archetype** (column `enemies.archetype`, snake_case): **22** families —
`wolf`, `boar`, `zombie`, `spider`, `orc`, `skeleton`, `battle_lizard`, `element`, `demon`, `skeleton_king`, `forest_warden`, `titan`, `golem`, `wraith`, `bandit`, `cultist`, `treant`, `basilisk`, `wyvern`, `harpy`, `manticore`, `shade`.
- **Biome** (column `enemies.biome`): canonical world bands — `meadow`, `forest`, `ruins`, `canyon`, `swamp`, `volcanic`, `astral`.
- **Model asset ID:** `monster.<tier>.<slug>.v1` — optional; for MVP procedural/client visuals may key off `enemy.<type>` alone.
- **Authoritative list of all `enemy.<type>` IDs** — the generated `INSERT` block in `backend/migrations/000006b_enemy_data.sql` (220 rows). Example slugs: `wolf_l1_1_meadow`, `element_l12_14_forest`, `titan_l34_35_astral`.
Slug pattern (informative): `<archetype>_l<low>_<high>_<biome>` where `low/high` are the five contiguous bands for that archetype (from `000006b_enemy_data.sql`), and each band has two biome variants drawn from the canonical list above.
**Legacy reference table (13 named anchors from early design — not exhaustive):**
| enemyId (legacy name) | notes |
|---|---|
| `enemy.wolf_forest` | superseded by many `wolf_*` slugs |
| `enemy.boar_wild` | superseded by `boar_*` |
| … | see SQL migration for full set |
## 2) Object Model Catalog (Map Objects)
Naming convention:
- `obj.<category>.<variant>.v1`
- Keep collision simple in MVP: `road` non-blocking, all others blocking unless flagged
| objectType | variantId | modelId | gameplayTag | notes |
|---|---|---|---|---|
| `road` | `dirt_straight` | `obj.road.dirt_straight.v1` | `path` | default biome path |
| `road` | `dirt_curve` | `obj.road.dirt_curve.v1` | `path` | curve segment |
| `road` | `stone_straight` | `obj.road.stone_straight.v1` | `path` | higher tier area visual |
| `road` | `stone_intersection` | `obj.road.stone_intersection.v1` | `path` | junction tile |
| `tree` | `pine_small` | `obj.tree.pine_small.v1` | `nature_blocker` | forest filler |
| `tree` | `pine_tall` | `obj.tree.pine_tall.v1` | `nature_blocker` | silhouette depth |
| `tree` | `dead_tree` | `obj.tree.dead_tree.v1` | `nature_blocker` | corrupted zone accent |
| `bush` | `bush_round` | `obj.bush.round.v1` | `nature_soft` | low silhouette |
| `bush` | `bush_berries` | `obj.bush.berries.v1` | `nature_soft` | color variation |
| `rock` | `rock_small` | `obj.rock.small.v1` | `stone_blocker` | edge clutter |
| `rock` | `rock_large` | `obj.rock.large.v1` | `stone_blocker` | hard blocker |
| `rock` | `rock_crystal` | `obj.rock.crystal.v1` | `stone_accent` | elite-zone hint |
| `prop` | `campfire_off` | `obj.prop.campfire_off.v1` | `poi` | non-interactive MVP |
| `prop` | `cart_broken` | `obj.prop.cart_broken.v1` | `poi` | roadside storytelling |
| `prop` | `sign_wood` | `obj.prop.sign_wood.v1` | `poi` | route marker |
| `prop` | `totem_bone` | `obj.prop.totem_bone.v1` | `poi_dark` | undead area marker |
## 3) Sound Cue Catalog (Gameplay + UI)
Naming convention:
- `sfx.<domain>.<intent>.v1`
- `ambient.*` loops; all others one-shots
| soundCueId | category | trigger | defaultMixNotes |
|---|---|---|---|
| `sfx.combat.hit.v1` | combat | normal successful hit | short, dry, high frequency |
| `sfx.combat.crit.v1` | combat | critical hit | layered transient + brighter tail |
| `sfx.combat.death_enemy.v1` | combat | enemy dies | medium tail, low-mid body |
| `sfx.loot.pickup.v1` | reward | loot granted/picked | fast sparkle, non-intrusive |
| `sfx.status.buff_activate.v1` | status | any buff applied | uplifting whoosh/chime |
| `sfx.status.debuff_apply.v1` | status | any debuff applied | dark stinger, short |
| `sfx.ambient.forest_loop.v1` | ambient | forest biome active | birds/wind, low distraction |
| `sfx.ui.click.v1` | ui | button tap/click | soft click, no low-end |
| `sfx.progress.level_up.v1` | progression | player level increases | celebratory stinger |
| `sfx.social.emote.v1` | social | player meet / NPC short interaction | light chirp, non-combat |
| `sfx.ui.duel_prompt.v1` | ui | duel offer shown | subtle tension, not alarm |
## 4) Enemy/Object -> Sound + VFX Intent Mapping
MVP guidance:
- Default: **shared** hit/death cues for all `enemy.*` (`sfx.combat.hit.v1` / `sfx.combat.death_enemy.v1`); **elite** templates (`is_elite` in DB) may use `sfx.combat.crit.v1` on hit where appropriate.
- Status-linked VFX follow **abilities** on the template (poison/burn/slow/stun/etc.), not the 13 legacy names — map by `archetype` + abilities when adding audio.
- VFX rarity colors for loot follow `specification.md` section 11.
| sourceType | sourceId pattern | onHitSoundCueId | onDeathSoundCueId | notes |
|---|---|---|---|---|
| `enemy` | `enemy.<type>` (220 slugs) | `sfx.combat.hit.v1` | `sfx.combat.death_enemy.v1` | per-template elite overrides possible |
| `object` | `road:*` | *(none)* | *(none)* | *(none)* | `subtle dust under movement` |
| `object` | `tree:*` | *(none)* | *(none)* | *(none)* | `sway only; no combat VFX` |
| `object` | `bush:*` | *(none)* | *(none)* | *(none)* | `minor rustle if traversed nearby` |
| `object` | `rock:*` | *(none)* | *(none)* | *(none)* | `static; optional tiny pebbles` |
| `object` | `prop:campfire_off` | *(none)* | *(none)* | *(none)* | `optional smoke wisps` |
## 5) JSON-Ready Schema Examples (Map Payload)
### 5.1 Minimal Entity Schemas
```json
{
"enemy": {
"id": "spawn-000123",
"enemyId": "enemy.demon_l10_12_meadow",
"level": 14,
"modelId": "monster.elite.demon_l10_12_meadow.v1",
"soundCueId": "sfx.combat.hit.v1"
},
"object": {
"id": "obj-00421",
"objectType": "tree",
"variantId": "pine_tall",
"modelId": "obj.tree.pine_tall.v1",
"soundCueId": null
}
}
```
### 5.2 Map Chunk Payload Example
```json
{
"chunkId": "forest_01_03",
"ambientSoundCueId": "sfx.ambient.forest_loop.v1",
"enemies": [
{
"id": "e-1001",
"enemyId": "enemy.wolf_l1_1_meadow",
"level": 3,
"modelId": "monster.base.wolf_l1_1_meadow.v1",
"soundCueId": "sfx.combat.hit.v1"
},
{
"id": "e-1002",
"enemyId": "enemy.demon_l10_12_meadow",
"level": 12,
"modelId": "monster.elite.demon_l10_12_meadow.v1",
"soundCueId": "sfx.combat.hit.v1"
}
],
"objects": [
{
"id": "o-2201",
"objectType": "road",
"variantId": "dirt_curve",
"modelId": "obj.road.dirt_curve.v1",
"soundCueId": null
},
{
"id": "o-2202",
"objectType": "tree",
"variantId": "pine_small",
"modelId": "obj.tree.pine_small.v1",
"soundCueId": null
},
{
"id": "o-2203",
"objectType": "prop",
"variantId": "totem_bone",
"modelId": "obj.prop.totem_bone.v1",
"soundCueId": null
}
]
}
```
## MVP Defaults (Recommended)
1. Use one shared hit/death sound for all base enemies; add unique status sounds for elites only.
2. Keep `soundCueId` optional per entity; use `ambientSoundCueId` at chunk/biome level.
3. Start with one model per enemy archetype (`.v1`), then skin variants later (`.v2`, `.v3`).
4. Map objects may remain non-interactive in early MVP; **NPCs and player-meet events** use `npc.*` / `event.*` keys from §0b0c when wired.
5. Preserve stable IDs (`enemyId`, `modelId`, `soundCueId`, `gear.slot.*`, `gear.form.*`, `gear.ammo.*`, `npc.*`, `event.*`) as content-contract keys across backend/client.
6. Optional duel/social flow: prefer one generic UI sound for accept/decline (e.g. extend catalog with `sfx.ui.duel_prompt.v1` when implemented).