Загрузка данных
Ниже — где это задано в OpenMW 0.47.0, как устроено соответствие «тип записи → слот», и что пришлось бы менять для **новых слотов** и **новых типов** экипировки.
---
## 1. Слоты персонажа (инвентарные слоты экипировки)
Все именованные слоты и их количество заданы в `MWWorld::InventoryStore` в `apps/openmw/mwworld/inventorystore.hpp`:
```45:67:C:\Users\user\Desktop\openmw-openmw-0.47.0\apps\openmw\mwworld\inventorystore.hpp
static constexpr int Slot_Helmet = 0;
static constexpr int Slot_Cuirass = 1;
static constexpr int Slot_Greaves = 2;
static constexpr int Slot_LeftPauldron = 3;
static constexpr int Slot_RightPauldron = 4;
static constexpr int Slot_LeftGauntlet = 5;
static constexpr int Slot_RightGauntlet = 6;
static constexpr int Slot_Boots = 7;
static constexpr int Slot_Shirt = 8;
static constexpr int Slot_Pants = 9;
static constexpr int Slot_Skirt = 10;
static constexpr int Slot_Robe = 11;
static constexpr int Slot_LeftRing = 12;
static constexpr int Slot_RightRing = 13;
static constexpr int Slot_Amulet = 14;
static constexpr int Slot_Belt = 15;
static constexpr int Slot_CarriedRight = 16;
static constexpr int Slot_CarriedLeft = 17;
static constexpr int Slot_Ammunition = 18;
static constexpr int Slots = 19;
static constexpr int Slot_NoSlot = -1;
```
Внутренне массив слотов инициализируется по `Slots` в `initSlots()` в `inventorystore.cpp` (по одному `end()` на каждый индекс).
В сохранениях слот хранится как целое число в `ESM::InventoryState::mEquipmentSlots` (`components/esm/inventorystate.hpp`).
---
## 2. «Типы экипировки» в смысле данных Morrowind (ESM)
Это не отдельная общая таблица «типов», а поля в записях плагина плюс перечисления в загрузчиках ESM.
**Броня** — `ESM::Armor::Type` в `components/esm/loadarmo.hpp` (значения 0–10, как в оригинальном формате):
```72:85:C:\Users\user\Desktop\openmw-openmw-0.47.0\components\esm\loadarmo.hpp
enum Type
{
Helmet = 0,
Cuirass = 1,
LPauldron = 2,
RPauldron = 3,
Greaves = 4,
Boots = 5,
LGauntlet = 6,
RGauntlet = 7,
Shield = 8,
LBracer = 9,
RBracer = 10
};
```
**Одежда** — `ESM::Clothing::Type` в `components/esm/loadclot.hpp`:
```24:36:C:\Users\user\Desktop\openmw-openmw-0.47.0\components\esm\loadclot.hpp
enum Type
{
Pants = 0,
Shoes = 1,
Shirt = 2,
Belt = 3,
Robe = 4,
RGlove = 5,
LGlove = 6,
Skirt = 7,
Ring = 8,
Amulet = 9
};
```
**Части тела для привязки мешей** (BIPED / `Part` в ARMO/CLOT) — `ESM::PartReferenceType` в том же `loadarmo.hpp` (`PRT_Head` … `PRT_Tail`, `PRT_Count`).
**Оружие** — не «слот типа брони», а тип оружия в записи `WEAP`; класс (ручное / боеприпасы / метательное) берётся через `MWMechanics::getWeaponType()` и `ESM::WeaponType` (см. `weapon.cpp`).
**Факел** — слот только если у записи флаг `Carry`; тогда `Slot_CarriedLeft` (`light.cpp`).
**Отмычка / щуп** — `Slot_CarriedRight` (`lockpick.cpp` и аналогично `probe.cpp`).
---
## 3. Где тип предмета сопоставляется со слотом
Общий интерфейс — `MWWorld::Class::getEquipmentSlots()`; для каждого класса предмета своя реализация.
Примеры:
- **Броня** — таблица `ESM::Armor::Type` → `InventoryStore::Slot_*` в `apps/openmw/mwclass/armor.cpp` (`getEquipmentSlots`).
- **Одежда** — кольца получают два допустимых слота (левое/правое), остальное через таблицу в `apps/openmw/mwclass/clothing.cpp`.
- **Оружие** — `apps/openmw/mwclass/weapon.cpp`: боеприпасы → `Slot_Ammunition`, метательное и прочее оружие → в основном `Slot_CarriedRight`, плюс флаг «можно ли экипировать стаком» (`stack`).
Любой новый тип предмета, который должен экипироваться, обычно потребует своего класса в `mwclass/` с корректным `getEquipmentSlots`, либо расширения существующего.
---
## 4. Где слоты используются кроме «надеть/снять»
Имеет смысл просмотреть все вхождения `InventoryStore::Slot_` и циклы `for (slot = 0; slot < Slots; ++slot)`:
- **Отрисовка NPC** — `apps/openmw/mwrender/npcanimation.cpp`: массив `slotlist` задаёт, в каком порядке и с каким приоритетом обрабатываются слоты одежды/брони для навешивания `PartReference`; щит/факел на левой руке, оружие на правой и т.д.
- **Скрипты MW** — например `GetArmorType` в `apps/openmw/mwscript/containerextensions.cpp` жёстко мапит «индекс брони» MW на конкретный `Slot_*`.
- **Механика** — броня для NPC, эффекты, снаряжение: `mwclass/npc.cpp`, `mwmechanics/tickableeffects.cpp`, и т.д.
То есть новый слот — это не только константа в `inventorystore.hpp`, но и все места, где слот имеет смысл (анимация, скрипты, UI-поведение, если появится отдельная логика).
---
## 5. Как модифицировать код, чтобы добавить новые типы и слоты
Идея разбивается на два уровня сложности.
### А) Новый слот под уже существующий тип данных MW (редко нужно менять ESM enum)
Пример: вы хотите **второй** слот под кольцо или разделить «левую руку» на два логических слота — тогда:
1. В `inventorystore.hpp` добавить `Slot_...`, увеличить `Slots` (новые индексы **должны добавляться в конец**, иначе сломаются сохранения: в сейвах лежат старые номера слотов).
2. В соответствующем `getEquipmentSlots` (например `Clothing.cpp` для колец) возвращать новый индекс в векторе разрешённых слотов.
3. Если предмет должен **отображаться на теле** — в `npcanimation.cpp` добавить слот в `slotlist` (и при необходимости логику `reserveIndividualPart` как у робы/юбки).
4. Если затрагивается броня/рейтинг — проверить `npc.cpp` (массивы рейтингов по слотам) и любые перечисления слотов в механике/скриптах.
5. Для **OpenMW-CS** и экспорта плагинов — если там захардкожены списки типов/слотов, их тоже расширить (в этой копии дерева можно поискать по именам слотов/типов).
### Б) Новый **тип** в смысле нового значения `mType` у ARMO/CLOT (расширение формата относительно vanilla)
Файлы `.esp` хранят целое число типа. Ванильный редактор и старые плагины знают только диапазоны 0–10 (ARMO) и 0–9 (CLOT). Чтобы это было устойчиво:
1. В `components/esm/loadarmo.hpp` / `loadclot.hpp` (или только в логике, если не хотите трогать имена enum) завести новые константы **с новыми числовыми значениями** (11, 12, …), не пересекающимися с ванильными.
2. В `armor.cpp` / `clothing.cpp` в таблицах `getEquipmentSlots` (и везде, где есть `switch` по `mType`: звуки, навыки, вес по GMST в `armor.cpp` и т.д.) добавить ветки для новых типов.
3. Задать новый **слот** по схеме из пункта А.
4. В данных предмета в `PartReferenceList` указать нужные `PRT_*`, чтобы модель встала на скелет (новая «анатомия» без новых `PRT_*` обычно не нужна).
Если нужна **новая зона тела** (новый кусок скелета, не покрываемый текущими `PRT_*`), это уже тяжёлый слой: расширение `ESM::PartReferenceType` и `PRT_Count`, все массивы `mObjectParts`, карты костей в `npcanimation`, записи `BodyPart` в плагинах — по сути новый подформат контента.
### В) Новый класс предмета (новый record type)
Тогда: новый `ESM::...`, регистрация в `esmstore`, новый `MWClass::...` с `getEquipmentSlots`, плюс всё, что должно с предметом происходить (активация, чин, зачарование, отображение в инвентаре).
---
## 6. Практические ограничения
- **Совместимость сейвов**: смена числовых значений уже существующих `Slot_*` ломает загрузку старых сохранений; безопаснее только добавлять новые индексы в конец и при необходимости мигрировать старые сейвы.
- **Плагины Morrowind**: новые значения `mType` в ARMO/CLOT создаются только если редактор/конвертер их пишет; OpenMW-CS в вашей ветке нужно проверить отдельно.
- **Скрипты MW**: опкоды вроде `GetArmorType` завязаны на фиксированный набор «локаций брони» — для новых слотов может понадобиться новый API или расширение существующего.
Если опишете конкретную цель (например: «второе кольцо», «плащ в отдельном слоте», «новый record ARMO с типом 11»), можно точечно перечислить минимальный набор файлов под этот сценарий; в Ask-режиме я могу только направлять, без правок в репозитории. Для автоматических правок в коде удобнее переключиться в Agent mode.