Content packs — портабельный D&D

Долгосрочная цель: D&D 5e — один из контент-паков, не часть движка. Pack содержит монстров, спеллы, предметы, классы, расы, условия — в портабельном JSON-формате с версиями. Сейчас в проде — item/monster/spell таблицы встроены в схему; никакой изоляции от движка нет.


Зачем паки

Движок ничего не должен знать о Wizards of the Coast. Текущее состояние — обратное: таблицы items, monsters, spells созданы под D&D 5e; миграции 018, 043, 044/049–054 — сиды конкретных книг (dnd.su). Цель — сделать D&D одним из подключаемых паков, а движок — способным работать с любой системой.

Полная концептуальная картина → concepts/engine-vs-content.md.


Машинерия: эпик RPG-движка (045–051)

Контент-паки — верхний слой. Нижний слой — движок (спека 045 Engine Core): единообразный механизм «модуль = нода». Модуль декларирует, что он делает (эффекты, ресурсы), а не то, к какой D&D-категории принадлежит.

СпекаЧто
045 Engine Coreмодули, эффекты, ресурсы; слой-0 (формулы); реалтайм
046база спеллов — машинерия баз dnd.su; поглощает roadmap-слот 039
047форк нод: forked_from, апстрим не тянется
048база фитов + бэкграундов (+расы?)
049пирамида прогрессии (level-up)
050база классов / мана-максимум (DMG Spell Points)
051конструктор хоумбрю (UI-редактор effect-блоков)

До завершения 045 контент-паки как таковые не существуют — есть только embedded D&D-контент в схеме.


Состав content_pack

{
  "id": "dnd5e-srd-v2.5",
  "name": "D&D 5e SRD",
  "version": "2.5.0",
  "system": "dnd5e",
  "schema_version": 1,
  "contents": {
    "monsters":    [...],
    "spells":      [...],
    "items":       [...],
    "classes":     [...],
    "races":       [...],
    "conditions":  [...],
    "backgrounds": [...]
  }
}

Каждый объект внутри содержит поле id (стабильный slug), version, и тип-специфичные поля. Формат валидируется против JSON Schema при импорте.


Что в паке, что в движке

В content_packВ движке (tables/events)
Статблоки монстровnodes, events, npc_groups
Параметры спелловnodes (module-node), events (casting event)
Предметы с атрибутамиnodes (module-node), attachment на PC
Классовые таблицы прогрессиипирамида прогрессии (спека 049)
Расовые трейтыgrants-рёбра (R5 эпика)
Условия и эффектыevents (event_type='condition_applied')
Конфиг маны (DMG Spell Points)конфигурируемые данные кампании (R12)

Движок хранит факты (событие произошло, модуль прикреплён к PC). Пак описывает правила (что делает этот модуль, какой у него эффект).


Версионирование пака

Формат версии: major.minor.patch (SemVer).

  • patch — исправление опечатки в тексте; обратно совместимо.
  • minor — добавление новых сущностей; обратно совместимо.
  • major — изменение механики (другой эффект, другой stat); требует явного подтверждения DM при обновлении.

Кампания привязана к конкретной версии пака. Обновление пака — явная операция DM, не автоматическая.


Импорт и экспорт

Импорт: JSON-файл (или ZIP с несколькими пак-файлами) валидируется против JSON Schema; все id проверяются на конфликты с уже установленными паками кампании; DM видит diff — что добавится / изменится / конфликтует.

Экспорт: кампания может экспортировать свои форкнутые (хоумбрю) сущности как отдельный пак. Это позволяет переиспользовать хоумбрю в другой кампании.


Перенос персонажа между паками

Если персонаж переносится из кампании с паком dnd5e-srd-v2.5 в кампанию с паком dnd5e-homerules-v1.0:

  1. Движок сверяет каждый attached module по id с пак-манифестом новой кампании.
  2. Совместимые модули (совпадает id) переносятся as-is.
  3. Несовместимые (нет в новом паке, или major-конфликт) — помечаются как unresolved, PC остаётся с текстовым placeholder'ом.
  4. DM нового пака решает, как резолвить: привязать к другому модулю, оставить как текст, или форкнуть.

Это долгосрочный сценарий — за горизонтом ближайших спек, но архитектура (модуль = нода, forked_from, версии) готовится под него с самого начала.


Машинерия движка: спека 045 Engine Core. Принцип изоляции: concepts/engine-vs-content.md. Текущий инвентарь/предметы: features/inventory-and-items/README.md.