Приступим к "прикручиванию" скриптов к репозиториям для придания им функциональности. Иначе говоря, заставим их делать то, для чего они предназначены - открывать хранилища!
Из предыдущего опыта я знаю, что скрипты можно повесить прямиком на репозитории и они будут замечательно работать, но... Поскольку это объекты инвентаря, которые мы "одеваем", возникнет необходимость "снять", и эта процедура из самого объекта не работает и придется прикручивать ее к "игроку". А раз так, то логичнее все сразу "расписать" в одном скрипте, а не "распылять" по множеству объектов!
В окне Object Window выбираем пункт Quest, в таблице справа находим наш квест CB_Player и открываем его для редактирования. Переключаемся на закладку Quest Aliases, где у нас уже есть один псевдоним - Player.
Открываем его редактирования и в секторе Scripts жмем кнопку Add, чтобы добавить новый скрипт. В следующем окне выбираем пункт New script, а дальше заполняем название и жмем ОК.
Открываем этот новый скрипт для редактирования и начинаем творить (пока для одного репозитория). "Звучит" скрипт так - если одетый объект это репозиторий, то снять его, закрыть меню и открыть хранилище.
Скрипт
Scriptname CB_PlayerAlias_Script extends ReferenceAlias
{Следим за игроком}
Import Game
ObjectReference Property BoxWeapon Auto ; хранилище в ячейке CB_Cell
Weapon Property CB_Weapon Auto ; репозиторий
Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference)
If akBaseObject == CB_Weapon
GetPlayer().UnEquipItem(CB_Weapon, False, True) ; снять одетый репозиторий
DisablePlayerControls(abMenu = True) ; запретить и скрыть меню
EnablePlayerControls(abMenu = True) ; разрешить меню
BoxWeapon.Activate(GetPlayer()) ; открыть хранилище
EndIf
EndEvent
После сохранения и компиляции скрипта, открываем и заполняем его свойства. Для хранилища вручную указываем нашу ячейку и хранилище. А для репозитория можно воспользоваться авто-заполнением - жмем кнопку Auto-Fill.
Жмем ОК чтобы закрыть свойства, потом закрываем окно псевдонима и окно квеста. Везде используем кнопку ОК, чтобы сохранить изменения.
Сохраняем результаты работы, нажав пиктограмму Сохранить, и пойдем в игру проверить работоспособность репозитория "- Все оружие".
... Все работает как планировалось! А значит можно расширить этот скрипт, включив в него все репозитории и хранилища.
Поскольку я задавал легко запоминающиеся описательные названия объектов, мне легче и быстрее добавлять свойства (Property) прямо в теле скрипта, а после компиляции их заполнять. В некоторых случаях, может быть проще сначала задать и заполнить свойства через редактор, а потом править скрипт.
Вот полностью готовый скрипт. Как видите он однообразен, проверяет что одето и снимает этот объект, потом закрывает меню и открывает соответствующее хранилище. Исключение составляют репозитории, при "одевании" расходующиеся, такие как еда, зелье или ингредиенты. В этих случаях следует "пополнить" инвентарь, использовав функцию добавления.
Скрипт
Scriptname CB_PlayerAlias_Script extends ReferenceAlias
{Следим за игроком}
Import Game
ObjectReference Property BoxWeapon Auto ; хранилище в ячейке CB_Cell
ObjectReference Property BoxArmor Auto
ObjectReference Property BoxPotion Auto
ObjectReference Property BoxScroll Auto
ObjectReference Property BoxFood Auto
ObjectReference Property BoxIngr Auto
ObjectReference Property BoxBook Auto
ObjectReference Property BoxMisc Auto
Weapon Property CB_Weapon Auto ; репозиторий
Armor Property CB_Armor Auto
Potion Property CB_Potion Auto
Scroll Property CB_Scroll Auto
Potion Property CB_Food Auto
Ingredient Property CB_Ingredient Auto
Book Property CB_Book Auto
MiscObject Property CB_Misc Auto
Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference)
If akBaseObject == CB_Weapon
GetPlayer().UnEquipItem(CB_Weapon, False, True) ; снять одетый репозиторий
DisablePlayerControls(abMenu = True) ; запретить и скрыть меню
EnablePlayerControls(abMenu = True) ; разрешить меню
BoxWeapon.Activate(GetPlayer()) ; открыть хранилище
ElseIf akBaseObject == CB_Armor
GetPlayer().UnEquipItem(CB_Armor, False, True)
DisablePlayerControls(abMenu = True)
EnablePlayerControls(abMenu = True)
BoxArmor.Activate(GetPlayer())
ElseIf akBaseObject == CB_Potion
; мы съели репозиторий, вместо снятия надо добавить новый репозиторий
GetPlayer().AddItem(CB_Potion, 1, True)
DisablePlayerControls(abMenu = True)
EnablePlayerControls(abMenu = True)
BoxPotion.Activate(GetPlayer())
ElseIf akBaseObject == CB_Scroll
GetPlayer().UnEquipItem(CB_Scroll, False, True)
DisablePlayerControls(abMenu = True)
EnablePlayerControls(abMenu = True)
BoxScroll.Activate(GetPlayer())
ElseIf akBaseObject == CB_Food
; мы съели репозиторий, вместо снятия надо добавить новый репозиторий
GetPlayer().AddItem(CB_Food, 1, True)
DisablePlayerControls(abMenu = True)
EnablePlayerControls(abMenu = True)
BoxFood.Activate(GetPlayer())
ElseIf akBaseObject == CB_Ingredient
; мы съели репозиторий, вместо снятия надо добавить новый репозиторий
GetPlayer().AddItem(CB_Ingredient, 1, True)
DisablePlayerControls(abMenu = True)
EnablePlayerControls(abMenu = True)
BoxIngr.Activate(GetPlayer())
ElseIf akBaseObject == CB_Book
GetPlayer().UnEquipItem(CB_Book, False, True)
DisablePlayerControls(abMenu = True)
EnablePlayerControls(abMenu = True)
BoxBook.Activate(GetPlayer())
ElseIf akBaseObject == CB_Misc
GetPlayer().UnEquipItem(CB_Misc, False, True)
DisablePlayerControls(abMenu = True)
EnablePlayerControls(abMenu = True)
BoxMisc.Activate(GetPlayer())
EndIf
EndEvent
Заполненные свойства скрипта.
Зайдя в игру, убеждаемся что все работает - хранилища открываются, принимают только определенные для них типы объектов и вообще все замечательно, кроме одного. Репозитории перемещаются и "принимаются" хранилищами, а мы этого не хотим! В наших планах чтобы репозитории невозможно было переместить из инвентаря или выбросить в мир!
Помните, при создании фильтров для хранилищ, мы упоминали спец. объекты, которые не должны попадать в хранилище. Тогда эти свойства остались не заполнены, пора их заполнить, ведь спец. объекты (репозитории) уже созданы.
<...здесь пауза длиной в сутки...>
Как я выяснил, использование скриптов на каждом отдельном хранилище, для возврата попавшего туда репозитория, не эффективно! Наилучший способ - обработать эту ситуацию в уже имеющемся скрипте псевдонима Player.
Значит, скрипты на хранилищах надо "почистить" от неиспользуемых свойств. И изменить скрипт CB_PlayerAlias_Script так чтобы репозитории всегда "возвращались" в инвентарь.
Сначала чистим. Это не сложно, ведь основной скрипт у нас на "родительском" объекте CB_Container.
Отправляемся редактировать скрипт висящий на контейнере. Выбираем в окне Object Window раздел Container, находим наш объект CB_Container и открываем для редактирования. Чтобы удалить ненужное свойство (Property), нужно отредактировать сам скрипт. Открываем его, находим строку и удаляем ее.
Form Property CB_Object Auto
{специальный объект для активации этого контейнера}
Scriptname CB_Box_FilterType_Script extends ObjectReference
{Фильтр по типу объекта для контейнера}
Int Property TypeObject Auto
{тип объекта по списку SKSE
41 - Weapon
26 - Armor
46 - Potion
23 - Scroll
- Food
30 - Ingredient
27 - Book
32 - Misc
- Gem
52 - Soul
- Ore
- Anim}
Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)
If akBaseItem.GetType() == TypeObject
Else
Self.RemoveItem(akBaseItem, aiItemCount, True, akSourceContainer)
EndIf
EndEvent
Компилируем и сохраняем скрипт, и обязательно заходим в окно свойств скрипта, во-первых, убедиться что свойство удалилось, во-вторых, чтобы редактор "запомнил" эти изменения. Если этого не сделать останется ссылка на несуществующее свойство, и хотя на работу мода это не повлияет, зато будет постоянно генерироваться предупреждение в лог-файле.
Тоже самое делаем для хранилища CB_Box_Food, редактируем его скрипт CB_Box_FilterFood_Script, избавляясь от свойства CB_FOOD. Вот измененный скрипт.
Измененный скрипт
Scriptname CB_Box_FilterFood_Script extends ObjectReference
{Фильтр по ключевым словам для контейнера}
Keyword Property VendorItemFood Auto
{ключевое слово}
Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)
If akBaseItem.HasKeyword(VendorItemFood) || (akBaseItem as Potion).IsFood()
Else
Self.RemoveItem(akBaseItem, aiItemCount, True, akSourceContainer)
EndIf
EndEvent
Сохраняем промежуточные результаты работы и переходим к скрипту CB_PlayerAlias_Script.
Выделяем в окне Object Window категорию Quest, и в таблице справа, находим наш квест CB_Player. Открываем и переключаемся на закладку Quest Aliases. Открываем псевдоним Player и редактируем его скрипт.
Я добавил обработку события OnItemRemoved(), чтобы когда удаляется один из репозиториев, восстанавливать его количество в инвентаре. Дабы не "раздувать" скрипт однотипными командами, добавил функцию - она нужна только для компактности кода.
На этом этапе мы получили полноценный рабочий мод! Бездонные хранилища для каждой категории отдельно! И хотя на этом останавливаться я не собираюсь, но уже можно гордиться результатом...