Загрузка данных


Ниже — где это задано в 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.