Перейти к содержимому






- - - - -

Репозитории II: начало

Написано Umbakano Jr, 29 мая 2013 · 675 просмотры

Начало здесь.
Продолжаю дневник о разработке мода, создаем хранилища.


Загружаем Creation Kit, жмем пиктограмму Открыть, находим и выделяем в списке файл, который сохранили вчера.
Дважды кликнув по нему, ставим флажок и обязательно кликаем по кнопке внизу Set as Active File, статус файла меняется на активный. Только активный плагин можно редактировать, иначе он будет выступать в роли мастер-файла!

При открытии удобно заполнить "шапку" нашего мода, которая будет отображаться в различных менеджерах загрузки модов.
Указываю автора - себя, и в окошке ниже - краткое описание мода и, при желании, номер версии мода (номер придумал сам).


Изображение Изображение



Вчера мы создали контейнер с названием CB_Container, он послужит нам образцом, шаблоном для создания хранилищ-репозиториев. Но есть важная задача, которую необходимо решить прежде, чем двигаться дальше - где размещать хранилища?


Пояснение. При желании удалить мод или в экстренных случаях игрок должен иметь возможность забрать "нажитое непосильным трудом" напрямую из хранилищ. Для этого он должен иметь возможность прибыть к месту размещения этих хранилищ и активировать контейнеры "вручную".


В первой версии мода я использовал для этих целей служебную ячейку QASmoke, но это не самый удобный вариант. Хотя бы потому что заставляет рядового игрока использовать консоль и запоминать "необязательную" информацию.

В этот раз я собираюсь рассмотреть два варианта - размещение в известном, доступном игроку месте и создание собственной ячейки исключительно для размещения хранилищ.
Итак, первый вариант, размещение контейнеров в уже известном мире. Плюсы - легкодоступность для игрока и простая реализация. Минусы - несомненная конфликтность с модами, изменяющими эту ячейку. Чем популярнее ячейка, тем больше вероятность ее "улучшения", а значит и конфликт с хранилищами.
Вариант второй, собственная ячейка. Плюсы - полная "неконфликтность". Минусы - относительная сложность реализации, ведь доступ в ячейку возможен только через телепортацию (дверь, заклинание).
И все-таки, прикинув свои возможности, я выбираю второй, сложный вариант, для обеспечения неконфликтности с любым модом, включая даже экзотический "Тропический Скайрим"! И пусть это потребует больше работы, но я постараюсь обойтись даже без телепортации.
Механизм будет следующий - создание хранилищ в собственной ячейке и их динамическое размещение в доступном игроку месте.

Теперь понятно что и где делать и я приступаю...

Создаем ячейку. Поскольку ячейка будет служебной, без доступа игрока и без телепортации в нее ГГ, то нет необходимости в каких-либо "излишествах", она будет абсолютно пустой! Чтобы сделать такую "пустую" ячейку, выбираем меню World -- Cells... и в открывшемся окне, в списке кликаем ПКМ и выбираем пункт New.












Изображение
Вносим название ячейки, не забывая применять префикс.

Изображение
И убеждаемся, в окне Cell View, есть наша ячейка и она абсолютно пуста.

Изображение


Вызываем ячейку CB_Cell в окне Render Window, просто дважды кликнув по ней в окне Cell View. Для создания наших хранилищ перетягиваем в окно Render Window, созданный ранее контейнер CB_Container из окна Object Window. Перетягиваем контейнер столько раз сколько хранилищ нам необходимо!


Изображение
Чтобы различать наши хранилища присваиваем им имя. Для этого или дважды кликнуть по объекту в окне Render Window, или в окне Cell View выбрать пункт Edit.

ИзображениеИзображение



После добавления и переименования вот что получилось у меня - 12 хранилищ для всех категорий на которые я хочу делить попадаемые в инвентарь объекты.

ИзображениеИзображение


Жмем пиктограмму Сохранить, чтобы не потерять нашу работу.
Осталось прицепить фильтр на каждый контейнер, чтобы туда попадали объекты только определенной категории. Сделаем это с помощью скриптов и так как событие это однообразное для большинства хранилищ, то сделаем его на основе шаблона скрипта.


Переходим в окно Object Window и находим наш контейнер CB_Container. Открываем его для редактирования, жмем кнопку Add.

Изображение
В открывшемся окне-списке выбираем первый пункт [New Script] и жмем кнопку ОК.

Изображение
Нам предложат назвать новый скрипт. Я использую составное название, чтобы понимать к чему относится этот скрипт. Вы можете называть скрипты произвольно, но рекомендуется придерживаться хотя бы простейших правил, чтобы избежать беспорядка. Плюс, в данном случае, я заполнил поле документации - краткое описание назначения этого скрипта.

Изображение

После нажатия кнопки ОК, в свойствах контейнера, в окошке Скрипты появится добавленный скрипт. Взаимодействуют с ним с помощью ПКМ. Я использую Notepad++ как редактор скриптов Папирус, поэтому выбираю пункт Open in External Editor, вы можете использовать встроенный редактор, тогда для вас пункт Edit Source.

Изображение



В данном случае я собираюсь писать "универсальный" скрипт, который выступит шаблоном-образцом для всех моих хранилищ, поэтому методы его создания будут отличаться от создания "стандартного", обычного скрипта. Я не буду использовать возможности автоматического заполнения свойств скрипта, используемые мной названия свойств носят описательный характер. И да, мне придется использовать функцию SKSE.


В "переводе" на человеческий язык, скрипт звучит так:
Если в контейнер попал объект не соответствующий указанному типу, то вернуть его "отправителю". Если объект соответствует указанному типу, но является специальным объектом для активации данного контейнера, то вернуть его в инвентарь ГГ. Как вы заметили, хотя мы еще не создали эти "специальные объекты", но уже можем на них ссылаться. Это потому, что скрипты в Скайриме изолированы от игры. Именно поэтому применяются свойства (Property), как механизм передачи данных между скриптом и игрой.
Сначала хотел листинг выкладывать тоже картинками, для "визуальности", но потом передумал
Scriptname CB_Box_Weapon_Script extends ObjectReference  
{Фильтр для контейнера}

Form Property CB_Object Auto
{специальный объект для активации этого контейнера}
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
		If akBaseItem == CB_Object
			Self.RemoveItem(akBaseItem, aiItemCount, True, Game.GetPlayer())
		EndIf
	Else
		Self.RemoveItem(akBaseItem, aiItemCount, True, akSourceContainer)
	EndIf
EndEvent


А теперь обратите внимание, хотя скрипт мы прицепили к контейнеру (базовому объекту), каждое из 12 наших хранилищ тоже "обзавелось" копией этого скрипта. Нам осталось только заполнить свойства подходящими для них значениями. Открываем хранилище для редактирования, переключаемся на закладку Script, и пользуясь подсказкой в описании к свойствам, присваиваем нужное значение типа объекта.
Например, для хранилища оружия под названием CB_Box_Weapon указываем тип объекта 41, для брони - 26 и так далее.

Изображение


Вы, наверное, уже заметили что не все типы объектов можно так определить. Например, еду (Food) или драгоценные камни (Gem) с помощью этой функции не обнаружить. Не страшно - применим для их определения другую функцию, а значит напишем и прицепим новый скрипт!


В этот раз скрипт нужно цеплять непосредственно на хранилище. Переходим в окно Cell View, находим нашу ячейку CB_Cell, выбираем хранилище еды CB_Box_Food, открываем для редактирования, переходим на вкладку Script, выделяем имеющийся там скрипт и жмем кнопку Remove. Скрипт отмечается как удаленный - красным минусом.
Добавляем новый скрипт - жмем кнопку Add, выбираем пункт New Script, вписываем новое название для скрипта и ОК. Новый скрипт добавится в список со знаком "плюс".

Изображение Изображение Изображение

Открываем скрипт для редактирования - ПКМ, пункт Edit Source или Open in External Editor.



Скрипт для контейнера с едой "переводится" так - если объект не имеет ключевого слова или не является едой (функция SKSE), то вернуть его "отправителю". А если имеет ключевое слово или является едой, но при этом является и специальным объектом, то вернуть его в инвентарь ГГ.
Scriptname CB_Box_FilterFood_Script extends ObjectReference  
{Фильтр по ключевым словам для контейнера}

Potion Property CB_FOOD Auto
{специальный объект для активации этого контейнера}
Keyword Property VendorItemFood Auto
{ключевое слово}

Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)
	If akBaseItem.HasKeyword(VendorItemFood) || (akBaseItem as Potion).IsFood()
		If akBaseItem == CB_FOOD
			Self.RemoveItem(akBaseItem, aiItemCount, True, Game.GetPlayer())
		EndIf
	Else
		Self.RemoveItem(akBaseItem, aiItemCount, True, akSourceContainer)
	EndIf
EndEvent
После компиляции и сохранения скрипта, заходим в его свойства и, кликнув на кнопку Auto Fill, заполняем его значение. Это возможно потому, что название свойства (Property) и название ключевого слова (Keyword) совпадают!

Изображение



Для двух хранилищ, драгоценных камней CB_Box_Gem и руды и слитков CB_Box_Ore, скрипт одинаков, поэтому используем один на двоих!
Открываем хранилище CB_Box_Gem, удаляем имеющийся скрипт и создаем новый.
Scriptname CB_Box_FilterGemOre_Script extends ObjectReference  
{Фильтр по ключевым словам для контейнера}

Keyword Property VendorItemGem Auto
{ключевое слово}

Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)
	If akBaseItem.HasKeyword(VendorItemGem)
	Else	
		Self.RemoveItem(akBaseItem, aiItemCount, True, akSourceContainer)
	EndIf
EndEvent

Открываем хранилище CB_Box_Ore, удаляем имеющийся скрипт и добавляем скрипт сделанный выше. Для этого жмем кнопку Add, и в списке по названию находим скрипт.

Изображение Изображение

А вот когда заполняем их свойства, то используем разные значения!

Изображение Изображение


Осталось "обработать" последнее хранилище CB_Box_Anim, предназначенное для хранения шкур, кожи и прочих частей животных.

[success]
В этом случае скрипт ничем не отличается от предыдущих, но использует два ключевых слова (Keyword). Когда есть возможность, я всегда использую названия объектов из Creation Kit, это позволяет автоматически заполнять свойства.
Scriptname CB_Box_FilterAnim_Script extends ObjectReference  
{Фильтр по ключевым словам для контейнера}

Keyword Property VendorItemAnimalHide Auto
Keyword Property VendorItemAnimalPart Auto

Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)
	If akBaseItem.HasKeyword(VendorItemAnimalHide) || akBaseItem.HasKeyword(VendorItemAnimalPart)
	Else	
		Self.RemoveItem(akBaseItem, aiItemCount, True, akSourceContainer)
	EndIf	
EndEvent

Изображение
[/success]

Жмем пиктограмму Сохранить.
На этом этап создания хранилищ закончен. Половина мода сделана, ведь хранилища - основной компонент всего проекта! Остались мелочи - реализовать механизм по обслуживанию этих хранилищ, но это сделаем чуть позже...

Продолжение здесь.




Хмммм. Мдя. Ну будем надеяться это исправят. Придется тебе составлять текст в Статьях и там держать копию и там же править.

Ага, только в блогах такой мульки функции нет!

Профессор, править что-либо, включающее дополнительные тэги, можно ТОЛЬКО через ПОЛНУЮ форму!!! иначе каждый раз придется все восстанавливать))

Постоянно слетает форматирование! За это время я бы уже закончил мод... вот это круто!

 

P.S. Вот опять... пока одно исправлял, другое слетело!

Круто!