<?xml version="1.0"?>
<rss version="2.0"><channel><title/><link>https://tesall.club/blogs/blog/21-dnevnik-razrabotki/</link><description>&#x417;&#x430;&#x43C;&#x435;&#x442;&#x43A;&#x438; &#x43F;&#x43E; &#x445;&#x43E;&#x434;&#x443; &#x43C;&#x43E;&#x434;&#x43E;&#x441;&#x442;&#x440;&#x43E;&#x439;&#x441;&#x442;&#x432;&#x430;</description><language>ru</language><item><title>&#x414;&#x432;&#x435; &#x43A;&#x43E;&#x43F;&#x438;&#x438; &#x421;&#x43A;&#x430;&#x439;&#x440;&#x438;&#x43C; &#x43F;&#x43E;&#x434; &#x43E;&#x434;&#x43D;&#x438;&#x43C; &#x421;&#x442;&#x438;&#x43C;&#x43E;&#x43C;.</title><link>https://tesall.club/blogs/entry/608-dve-kopii-skajrim-pod-odnim-stimom/</link><description><![CDATA[Статья предназначена для тех, кто не только активно делает моды, но и активно играет.<br>
<br>
Решил поделиться опытом как удобнее "обустроиться" при модостроительстве. Ведь создание модов, их тестирование, зачастую требуют специфических условий к используемым плагинам, и в конце концов "мешает" игровой сборке, то есть мешает играть! О том как разделить эти конфликтующие функции и пойдет речь.<br>
Довольно быстро пришло понимание, что играть и делать моды, а особенно тестировать сторонние "творения", в итоге приводят к нарастающим проблемам в совместимости модов и замусориванию папки игры "остатками" ресурсов. Необходимо было разделить эти функции.<br>
Пораскинув мозгами и собрав в кучу то, что после них осталось, я разработал схему использования лицензированной версии игры как для модостроения, так и для игры, под одним аккаунтом Стим, но двумя пользователями ПК.<br>
<br>
Итак, "принцип действия" следующий:<br>
<br>
Используется два пользователя компьютера, назовем их Test и Game, один для моддинга, второй только для игры. У каждого из них собственные независимые папки для документов, и соответственно, собственные настройки игры и сохранения.<br>
Используются две копии Wrye Bash, у каждого пользователя собственные настройки bash.ini для создания уникальных папок для хранения архивов с модами, назовем их Skyrim Mods Test и Skyrim Mods Game.<br>
<br>
Используются две копии папки с игрой, имеющие уникальные названия, привязанные к пользователям, например, Skyrim Test и Skyrim Game.<br>
<br>
Последний штрих, чтобы все это работало, при входе под именем пользователя Test или Game, переименовать соответствующую папку с игрой в стандартное название Skyrim, понимаемое Стимом. Переименовывать можно вручную, но эффективнее автоматизировать этот процесс, например, создав задачу в Планировщике задач ОС Виндовс.<br>
<br>
<a href="https://tesall.club/uploads/monthly_2014_01/ashampoo-snap-2013-12-11-17h25m40s-002.png.mxj2reqn9dc78guwpz5041ab3ytovhsl.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Ashampoo_Snap_2013.12.11_17h25m40s_002_.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145461" data-ratio="0.86" style="height:auto;" width="604" data-src="https://tesall.club/uploads/monthly_2014_01/ashampoo-snap-2013-12-11-17h25m40s-002.png.8ol703uht4qg1yzfxj9nsvmrd6baiepk.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a> <a href="https://tesall.club/uploads/monthly_2014_01/ashampoo-snap-2013-12-11-17h37m03s-003.png.bf79n260ige1rdlma5spcw38yq4xutvh.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Ashampoo_Snap_2013.12.11_17h37m03s_003_.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145463" data-ratio="0.86" style="height:auto;" width="604" data-src="https://tesall.club/uploads/monthly_2014_01/ashampoo-snap-2013-12-11-17h37m03s-003.png.kyb0vmnqli1p748gzherwosd2a5jcf3t.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a>]]></description><guid isPermaLink="false">608</guid><pubDate>Wed, 19 Feb 2014 16:23:59 +0000</pubDate></item><item><title>&#x420;&#x435;&#x43F;&#x43E;&#x437;&#x438;&#x442;&#x43E;&#x440;&#x438;&#x438; II: &#x440;&#x430;&#x437;&#x440;&#x430;&#x431;&#x43E;&#x442;&#x43A;&#x430;, &#x447;&#x430;&#x441;&#x442;&#x44C; 6</title><link>https://tesall.club/blogs/entry/298-repozitorii-ii-razrabotka-chast-6/</link><description><![CDATA[<a href="/blog/21/entry-294-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D1%87%D0%B0%D1%81%D1%82%D1%8C-5/">Начало здесь</a><br>
<br>
<br>
Здесь было полтора часа текста! :dash2:<br>
<br>
Желание писать повторно - :suicide:]]></description><guid isPermaLink="false">298</guid><pubDate>Sun, 16 Jun 2013 15:23:00 +0000</pubDate></item><item><title>&#x420;&#x435;&#x43F;&#x43E;&#x437;&#x438;&#x442;&#x43E;&#x440;&#x438;&#x438; II: &#x440;&#x430;&#x437;&#x440;&#x430;&#x431;&#x43E;&#x442;&#x43A;&#x430;, &#x447;&#x430;&#x441;&#x442;&#x44C; 5</title><link>https://tesall.club/blogs/entry/294-repozitorii-ii-razrabotka-chast-5/</link><description><![CDATA[<a href="/blog/21/entry-288-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D1%87%D0%B0%D1%81%D1%82%D1%8C-4/">Начало здесь</a><br>
<br>
Что ни говори, а когда не пишешь блог, работа над модом проходит гораздо быстрее! С другой стороны, ведение блога разработки дисциплинирует "творческие порывы" , заставляя использовать более оптимальный код и меньше "мусорить"...<br>
<br>
Понадобились сутки, чтобы в корне переделать систему вызова хранилищ. Теперь она основывается не на системе меню, а на ... говорящем активаторе! Да, да, это такой активатор который позволяет использовать диалоги с "не НПС"! Я приспособил его для отображения и запуска списка репозиториев. <span style="font-size: large;">В результате, я получил быстрый и простой доступ к любому репозиторию. Да, и визуально, это более элегантное решение!</span><br>
<br>
<p style="text-align: center;"><a href="https://tesall.club/uploads/monthly_2013_06/screenshot6.png.a2vw34tedx9zoljkbq1ry0c7pg65nuhs.png" class="ipsAttachLink ipsAttachLink_image"><img alt="ScreenShot6.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145388" data-ratio="1.60" style="height:auto;" width="1000" data-src="https://tesall.club/uploads/monthly_2013_06/screenshot6.thumb.png.qirv8tuc0y9h3m7wsj61en5xpofg4b2d.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a></p><br>
<br>
Полагаю, такое решение будет полезно при необходимости отображения большого количества опций, поэтому покажу как его сделать.<br>
<br>
<div class="message success">В окне <strong>Object Window,</strong> в разделе <strong>Actors</strong>, найдите категорию <strong>Talking Activator</strong>. В таблице справа, создайте новый объект, или используйте уже имеющийся как шаблон. Для наших целей не важно какой вид и какую модель будет использовать этот активатор, мы будет активировать его удаленно. Внесите уникальное имя, это обязательно и название активатора, оно будет отображаться на экране.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.06.12 19.35.52_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145389" data-ratio="2.11" style="height:auto;" width="523" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-12-19-35-52-001.png.n0acu3j214odzgse9k7lfw8qmtryxbv6.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
Перетащите этот объект в ячейку, в моем случае это <strong>CB_Cell</strong>. Если вы не используете собственных ячеек и не желаете "затрагивать" ванильные, можно обращаться к активатору напрямую, в скрипте, создавая его <strong>object reference</strong>, с помощью функции <strong>PlaceAtMe</strong>(). Но я рекомендую, все же, разместить объект в ячейке, это более эффективно с точки зрения производительности, и оптимально с точки зрения более короткого кода! На этом, говорящий активатор готов к использованию.<br>
<br>
Создайте квест стартующий с игрой, флажок <strong>Start Game Enabled</strong>, остальные флажки снимите, установите высокий приоритет (более 80) и сохраните его, закрыв. Заново откройте, теперь появились дополнительные вкладки, переключитесь на <strong>Player Dialoge</strong> и заполните таблицы, как показано на рисунке:<br>
 <br>
<p style="text-align: center;"><a href="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-12-20-27-20-002.png.gow36er8inls21ybu45jkqf0cv7zdt9a.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Snap_2013.06.12 20.27.20_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145390" data-ratio="2.02" style="height:auto;" width="1000" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-12-20-27-20-002.thumb.png.vz57gwa8mjerxpq4bk3i6cf9h1sltodn.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a></p><br>
<br>
В нижней части вкладки, в окне <strong>End </strong>впишите команду активации нужного контейнера. Чтобы присвоить этому фрагменту свойство (Property), первоначально скомпилируйте скрипт с любым комментом и закройте окно. Вновь откройте, будет доступен ввод свойств для скрипта. Введите и заполните свойство для контейнера, раскомментируйте и отредактируйте код. Скомпилируйте и закройте окно.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.06.12 20.38.25_004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145391" data-ratio="2.52" style="height:auto;" width="609" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-12-20-38-25-004.png.8qfb74hiu5v2ygpasr6c1xzmw9jknd3o.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
<br>
Если вам, как и мне, потребуется создать определенный порядок пунктов меню, то используйте значение приоритета топика, в правом верхнем углу окна вкладки. Чем выше приоритет тем выше будет расположен пункт в меню.<br>
<br>
Чтобы сработал этот диалог и отобразился список нашего меню, удаленно активируем Talking Activator. Эту функцию я "повесил" на нажатие кнопки в скрипте квеста.<pre class="ipsCode prettyprint prettyprinted">
CB_TalkingActivator.Activate(GetPlayer())</pre><br>
Вот и все, меню в виде диалога готово, остался последний штрих.<br>
</div><br>
<br>
<p class="message error">Чтобы наш диалог сразу отображался в игре, необходимо создать <strong>SEQ-файл</strong>!<br>
Самый простой способ его создания, не требующий ручного ввода, использовать <strong>TES5Edit</strong>. Загрузите в эту программу мод, найдите его и выделите название, важно стоять именно на названии мода, тогда в контекстном меню, в пункте Разное, появится пункт Создать SEQ-файл. Само создание происходит мгновенно и в нужную папку (Data\SEQ), с правильным названием (в моем случае, Collector bags II.seq).</p><br>
<br>
<a href="/blog/21/entry-298-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D1%87%D0%B0%D1%81%D1%82%D1%8C-6/">Продолжение здесь</a>]]></description><guid isPermaLink="false">294</guid><pubDate>Wed, 12 Jun 2013 18:04:00 +0000</pubDate></item><item><title>&#x420;&#x435;&#x43F;&#x43E;&#x437;&#x438;&#x442;&#x43E;&#x440;&#x438;&#x438; II: &#x440;&#x430;&#x437;&#x440;&#x430;&#x431;&#x43E;&#x442;&#x43A;&#x430;, &#x447;&#x430;&#x441;&#x442;&#x44C; 4</title><link>https://tesall.club/blogs/entry/288-repozitorii-ii-razrabotka-chast-4/</link><description><![CDATA[<a href="/blog/21/entry-283-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D1%87%D0%B0%D1%81%D1%82%D1%8C-3/">Начало здесь</a><br>
<br>
Сначала хотел отредактировать предыдущий дневник, но потом подумал, какого черта, это же дневник, а не инструкция прямого действия! А поводом к такому решению послужило событие, заставившее меня отказаться от использования метода добавления в хранилище, разработанное на предыдущем шаге.<br>
<br>
Я нашел решение - прямой доступ к текущей записи инвентаря! То, что вчера казалось невозможным, сегодня реализуется парой строчек кода!<br>
<br>
Скрипт <strong>CB_PlayerAlias_Script </strong>я откатил до предыдущего состояния, проще говоря, отредактировал, убрав обработку по нажатию клавиш. И создал новый скрипт.<br>
<br>
<div class="message success"><br>
Для решения текущей задачи, я создал скрипт <strong>CB_PlayerQuest_Script</strong> в нашем квесте <strong>CB_Player</strong>.<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<p style="text-align: center;"><img alt="Snap_2013.06.08 16.26.05_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145382" data-ratio="5.81" style="height:auto;" width="971" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-08-16-26-05-001.png.xpn5rcb61aj4fe3iym8dzou92t0lv7hg.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
Звучит скрипт так. Определиться когда открыто меню инвентаря. Если нужное меню открыто, ожидать нажатия клавиши (в данном случае Back Space). И если такая клавиша нажата, получить FormID текущей записи, по которой определить объект и отправить его в соответствующее хранилище.<br>
<br>
<div class="ipsSpoiler" data-ipsspoiler=""><div class="ipsSpoiler_header"><span>Новый скрипт</span></div><div class="ipsSpoiler_contents"><pre class="ipsCode prettyprint prettyprinted">
Scriptname CB_PlayerQuest_Script extends Quest  ObjectReference Property BoxWeapon AutoObjectReference Property BoxArmor AutoObjectReference Property BoxPotion AutoObjectReference Property BoxScroll AutoObjectReference Property BoxFood AutoObjectReference Property BoxIngr AutoObjectReference Property BoxBook AutoObjectReference Property BoxMisc AutoEvent OnInit()	RegisterForMenu("InventoryMenu")	EndEventEvent OnMenuOpen(String MenuName)	If MenuName == "InventoryMenu"		RegisterForKey(14)	EndIfEndEventEvent OnMenuClose(String MenuName)	If MenuName == "InventoryMenu"		UnregisterForKey(14)	EndIfEndEventEvent OnKeyDown(Int KeyCode)		If KeyCode == 14			int formid			formid = UI.Getint("InventoryMenu", "_root.Menu_mc.inventoryLists.itemList.selectedEntry.formId")			form selectedForm = Game.GetForm(formid)						If selectedForm as Weapon				Game.GetPlayer().RemoveItem(selectedForm, 1, True, BoxWeapon)			ElseIf selectedForm as Armor				Game.GetPlayer().RemoveItem(selectedForm, 1, True, BoxArmor)			ElseIf selectedForm as Potion				If (selectedForm as Potion).isFood()					Game.GetPlayer().RemoveItem(selectedForm, 1, True, BoxFood)				Else					Game.GetPlayer().RemoveItem(selectedForm, 1, True, BoxPotion)				EndIf							ElseIf selectedForm as Scroll				Game.GetPlayer().RemoveItem(selectedForm, 1, True, BoxScroll)			ElseIf selectedForm as Ingredient				Game.GetPlayer().RemoveItem(selectedForm, 1, True, BoxIngr)			ElseIf selectedForm as Book				Game.GetPlayer().RemoveItem(selectedForm, 1, True, BoxBook)			ElseIf selectedForm as MiscObject				Game.GetPlayer().RemoveItem(selectedForm, 1, True, BoxMisc)			EndIf					EndIf	EndEvent</pre><br>
</div></div><br>
<br>
Не забываем заполнить свойства скрипта.<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.06.08 16.38.34_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145383" data-ratio="1.36" style="height:auto;" width="527" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-08-16-38-34-002.png.u4cgs1vwdf86ab7z03n2ijeyxoql9tpk.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
</div><br>
Сохраняем результат работы.<br>
Тестирование в игре показало отличную скорость реакции на нажатие клавиши и стабильную работу.<br>
<br>
А теперь вернемся и закончим предыдущий шаг - фильтрование объектов в категории Разное. Мы повесили скрипт на хранилище "<strong>-Все разное</strong>", он работает - сортирует объекты по нужным хранилищам, но у нас нет доступа к этим хранилищам. Вот его и сделаем сейчас!<br>
<br>
<div class="message success"><br>
Меня устраивал метод доступа к хранилищам через меню, и хотя я стараюсь избегать частого его использования, все же воспользуюсь им и сейчас.<br>
В окне <strong>Object Window</strong> выбираем категорию <strong>Message</strong>, и в таблице справа, жмем ПКМ и выбираем пункт <strong>New</strong>.<br>
<br>
<br>
<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.06.09 15.22.55_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145384" data-ratio="0.96" style="height:auto;" width="661" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-09-15-22-55-002.png.anyuigtl7xzqj4h9cdbf0wo6kps82mer.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
Я создал три объекта <strong>Message</strong>, для отображения трех групп кнопок, иначе они не поместятся на экране.<br>
<br>
<br>
<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.06.11 14.30.19_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145385" data-ratio="0.96" style="height:auto;" width="661" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-11-14-30-19-001.png.hwaeko39m087yrbfs5pv16ut4gxziq2n.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
<p style="text-align: center;"><img alt="Snap_2013.06.11 14.30.47_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145386" data-ratio="0.96" style="height:auto;" width="661" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-11-14-30-47-002.png.9n13rf527mwdzpvctskhjgbi6axylu0q.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
<p style="text-align: center;"><img alt="Snap_2013.06.11 14.31.17_003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145387" data-ratio="0.96" style="height:auto;" width="661" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-11-14-31-17-003.png.0qt27okyjricdsgzupnwl865fahxvme9.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
</div><br>
<br>
Наверное, проводятся какие-то работы на сайте, потому что блог лишен всех кнопок управления форматированием, а открытие и закрытие черновика "ломает" уже готовый (форматированный текст). Но я все же продолжу - не хочу терять время...<br>
<br>
<div class="message success">Меню будет вызываться из двух "режимов". Первый, когда инвентарь закрыт, нажатие кнопки Back Space откроет начальное меню, из которого, по цепочке, можно получить доступ ко всем кнопкам, и вызвать любое хранилище. Второй, когда инвентарь открыт, нажатие на репозиторий "-Все разное" откроет третью часть меню, для доступа к разному.<br>
Для оптимизации, чтобы не использовать одинаковый вызов меню в двух скриптах одного квеста, я вызываю функцию из скрипта квеста.<br>
<br>
Ниже представлены измененные скрипты псевдонима и квеста.<br>
<br>
<div class="ipsSpoiler" data-ipsspoiler=""><div class="ipsSpoiler_header"><span>Скрипт псевдонима</span></div><div class="ipsSpoiler_contents">Scriptname CB_PlayerAlias_Script extends ReferenceAlias<br>
{Следим за игроком}<br>
Import Game<br>
<br>
ObjectReference Property BoxWeapon Auto ; хранилище в ячейке CB_Cell<br>
ObjectReference Property BoxArmor Auto<br>
ObjectReference Property BoxPotion Auto<br>
ObjectReference Property BoxScroll Auto<br>
ObjectReference Property BoxFood Auto<br>
ObjectReference Property BoxIngr Auto<br>
ObjectReference Property BoxBook Auto<br>
ObjectReference Property BoxMisc Auto<br>
<br>
Ammo Property CB_Weapon Auto ; репозиторий<br>
Armor Property CB_Armor Auto<br>
Potion Property CB_Potion Auto<br>
Scroll Property CB_Scroll Auto<br>
Potion Property CB_Food Auto<br>
Ingredient Property CB_Ingredient Auto<br>
Book Property CB_Book Auto<br>
MiscObject Property CB_Misc Auto<br>
<br>
;Message Property CB_Message Auto<br>
<br>
Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference)<br>
<br>
If akBaseObject == CB_Weapon<br>
GetPlayer().UnEquipItem(CB_Weapon, False, True)<br>
<br>
DisablePlayerControls(abMenu = True)<br>
EnablePlayerControls(abMenu = True)<br>
<br>
BoxWeapon.Activate(GetPlayer())<br>
<br>
ElseIf akBaseObject == CB_Armor<br>
GetPlayer().UnEquipItem(CB_Armor, False, True)<br>
<br>
DisablePlayerControls(abMenu = True)<br>
EnablePlayerControls(abMenu = True)<br>
<br>
BoxArmor.Activate(GetPlayer())<br>
<br>
ElseIf akBaseObject == CB_Potion<br>
; GetPlayer().AddItem(CB_Potion, 1, True)<br>
<br>
DisablePlayerControls(abMenu = True)<br>
EnablePlayerControls(abMenu = True)<br>
<br>
BoxPotion.Activate(GetPlayer())<br>
<br>
ElseIf akBaseObject == CB_Scroll<br>
GetPlayer().UnEquipItem(CB_Scroll, False, True)<br>
<br>
DisablePlayerControls(abMenu = True)<br>
EnablePlayerControls(abMenu = True)<br>
<br>
BoxScroll.Activate(GetPlayer())<br>
<br>
ElseIf akBaseObject == CB_Food<br>
; GetPlayer().AddItem(CB_Food, 1, True)<br>
<br>
DisablePlayerControls(abMenu = True)<br>
EnablePlayerControls(abMenu = True)<br>
<br>
BoxFood.Activate(GetPlayer())<br>
<br>
ElseIf akBaseObject == CB_Ingredient<br>
; GetPlayer().AddItem(CB_Ingredient, 1, True)<br>
<br>
DisablePlayerControls(abMenu = True)<br>
EnablePlayerControls(abMenu = True)<br>
<br>
BoxIngr.Activate(GetPlayer())<br>
<br>
ElseIf akBaseObject == CB_Book<br>
GetPlayer().UnEquipItem(CB_Book, False, True)<br>
<br>
DisablePlayerControls(abMenu = True)<br>
EnablePlayerControls(abMenu = True)<br>
<br>
BoxBook.Activate(GetPlayer())<br>
<br>
ElseIf akBaseObject == CB_Misc<br>
GetPlayer().UnEquipItem(CB_Misc, False, True)<br>
<br>
DisablePlayerControls(abMenu = True)<br>
EnablePlayerControls(abMenu = True)<br>
<br>
; BoxMisc.Activate(GetPlayer())<br>
(GetOwningQuest() as CB_PlayerQuest_Script).ShowMenu03()<br>
EndIf<br>
EndEvent<br>
<br>
Event OnItemRemoved(Form akBaseObject, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer)<br>
If akBaseObject == CB_Weapon<br>
ReturnItem(akBaseObject, akDestContainer)<br>
ElseIf akBaseObject == CB_Armor<br>
ReturnItem(akBaseObject, akDestContainer)<br>
ElseIf akBaseObject == CB_Potion<br>
ReturnItem(akBaseObject, akDestContainer)<br>
ElseIf akBaseObject == CB_Scroll<br>
ReturnItem(akBaseObject, akDestContainer)<br>
ElseIf akBaseObject == CB_Food<br>
ReturnItem(akBaseObject, akDestContainer)<br>
ElseIf akBaseObject == CB_Ingredient<br>
ReturnItem(akBaseObject, akDestContainer)<br>
ElseIf akBaseObject == CB_Book<br>
ReturnItem(akBaseObject, akDestContainer)<br>
ElseIf akBaseObject == CB_Misc<br>
ReturnItem(akBaseObject, akDestContainer)<br>
EndIf<br>
EndEvent<br>
<br>
Function ReturnItem(Form _BaseItem, ObjectReference _DestContainer)<br>
If !_DestContainer<br>
If GetPlayer().GetItemCount(_BaseItem) == 0<br>
GetPlayer().AddItem(_BaseItem, 1, True)<br>
EndIf<br>
Else<br>
If GetPlayer().GetItemCount(_BaseItem) == 0<br>
_DestContainer.RemoveItem(_BaseItem, 1, True, GetPlayer())<br>
EndIf<br>
EndIf<br>
EndFunction<br>
</div></div><br>
<br>
<div class="ipsSpoiler" data-ipsspoiler=""><div class="ipsSpoiler_header"><span>Скрипт квеста</span></div><div class="ipsSpoiler_contents">Scriptname CB_PlayerQuest_Script extends Quest<br>
<br>
Import Game<br>
<br>
ObjectReference Property BoxWeapon Auto<br>
ObjectReference Property BoxArmor Auto<br>
ObjectReference Property BoxPotion Auto<br>
ObjectReference Property BoxScroll Auto<br>
ObjectReference Property BoxFood Auto<br>
ObjectReference Property BoxIngr Auto<br>
ObjectReference Property BoxBook Auto<br>
ObjectReference Property BoxMisc Auto<br>
<br>
ObjectReference Property BoxOre Auto<br>
ObjectReference Property BoxAnim Auto<br>
ObjectReference Property BoxGem Auto<br>
ObjectReference Property BoxSoul Auto<br>
<br>
Message Property CB_Message01 Auto<br>
Message Property CB_Message02 Auto<br>
Message Property CB_Message03 Auto<br>
<br>
Bool isMenuOpen = False<br>
<br>
Event OnInit()<br>
RegisterForMenu("InventoryMenu")<br>
RegisterForKey(14)<br>
EndEvent<br>
<br>
Event OnMenuOpen(String MenuName)<br>
If MenuName == "InventoryMenu"<br>
<br>
isMenuOpen = True<br>
EndIf<br>
EndEvent<br>
<br>
Event OnMenuClose(String MenuName)<br>
If MenuName == "InventoryMenu"<br>
<br>
isMenuOpen = False<br>
EndIf<br>
EndEvent<br>
<br>
Event OnKeyDown(Int KeyCode)<br>
If KeyCode == 14<br>
If isMenuOpen<br>
Int countID = 0<br>
Int iNumKeysPressed = Input.GetNumKeysPressed()<br>
<br>
<br>
Int formID = UI.Getint("InventoryMenu", "_root.Menu_mc.inventoryLists.itemList.selectedEntry.formId")<br>
<br>
If formid<br>
form selectedForm = Game.GetForm(formID)<br>
<br>
If iNumKeysPressed == 2<br>
countID = UI.Getint("InventoryMenu", "_root.Menu_mc.inventoryLists.itemList.selectedEntry.count")<br>
Else<br>
countID = 1<br>
EndIf<br>
<br>
If selectedForm as Weapon<br>
GetPlayer().RemoveItem(selectedForm, countID, True, BoxWeapon)<br>
ElseIf selectedForm as Ammo<br>
GetPlayer().RemoveItem(selectedForm, countID, True, BoxWeapon)<br>
ElseIf selectedForm as Armor<br>
GetPlayer().RemoveItem(selectedForm, countID, True, BoxArmor)<br>
ElseIf selectedForm as Potion<br>
If (selectedForm as Potion).isFood()<br>
GetPlayer().RemoveItem(selectedForm, countID, True, BoxFood)<br>
Else<br>
GetPlayer().RemoveItem(selectedForm, countID, True, BoxPotion)<br>
EndIf<br>
<br>
ElseIf selectedForm as Scroll<br>
GetPlayer().RemoveItem(selectedForm, countID, True, BoxScroll)<br>
ElseIf selectedForm as Ingredient<br>
GetPlayer().RemoveItem(selectedForm, countID, True, BoxIngr)<br>
ElseIf selectedForm as Book<br>
GetPlayer().RemoveItem(selectedForm, countID, True, BoxBook)<br>
ElseIf selectedForm as MiscObject<br>
GetPlayer().RemoveItem(selectedForm, countID, True, BoxMisc)<br>
EndIf<br>
EndIf<br>
Else<br>
ShowMenu01()<br>
EndIf<br>
EndIf<br>
EndEvent<br>
<br>
Function ShowMenu01()<br>
Int Button = CB_Message01.Show()<br>
If Button == 0 ; Далее<br>
ShowMenu02()<br>
ElseIf Button == 1<br>
BoxWeapon.Activate(GetPlayer())<br>
ElseIf Button == 2<br>
BoxArmor.Activate(GetPlayer())<br>
ElseIf Button == 3<br>
BoxPotion.Activate(GetPlayer())<br>
ElseIf Button == 4<br>
BoxScroll.Activate(GetPlayer())<br>
ElseIf Button == 5 ; Отмена<br>
Return<br>
EndIf<br>
EndFunction<br>
<br>
Function ShowMenu02()<br>
Int Button = CB_Message02.Show()<br>
If Button == 0 ; Далее<br>
ShowMenu03()<br>
ElseIf Button == 1<br>
BoxFood.Activate(GetPlayer())<br>
ElseIf Button == 2<br>
BoxIngr.Activate(GetPlayer())<br>
ElseIf Button == 3<br>
BoxBook.Activate(GetPlayer())<br>
ElseIf Button == 5 ; Отмена<br>
Return<br>
EndIf<br>
EndFunction<br>
<br>
Function ShowMenu03()<br>
Int Button = CB_Message03.Show()<br>
If Button == 0 ; Отмена<br>
Return<br>
ElseIf Button == 1<br>
BoxMisc.Activate(GetPlayer())<br>
ElseIf Button == 2<br>
BoxOre.Activate(GetPlayer())<br>
ElseIf Button == 3<br>
BoxAnim.Activate(GetPlayer())<br>
ElseIf Button == 4<br>
BoxGem.Activate(GetPlayer())<br>
ElseIf Button == 5<br>
BoxSoul.Activate(GetPlayer())<br>
EndIf<br>
EndFunction<br>
</div></div><br>
</div><br>
<br>
В результате, мы имеем полноценный мод, предоставляющий бездонные хранилища для всех категорий объектов, с простым и удобным доступом. И хотя еще не реализована автосортировка, но простота и скорость добавления объектов "напрямую", по нажатию кнопки, без открытия хранилища, компенсирует ее отсутствие!<br>
<br>
На этом этот шаг заканчиваю - сложно писать блог, используя теги по-памяти и без гарантии сохранения форматирования...<br>
<br>
<a href="/blog/21/entry-294-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D1%87%D0%B0%D1%81%D1%82%D1%8C-5/">Продолжение здесь</a>]]></description><guid isPermaLink="false">288</guid><pubDate>Tue, 11 Jun 2013 12:09:00 +0000</pubDate></item><item><title>&#x420;&#x435;&#x43F;&#x43E;&#x437;&#x438;&#x442;&#x43E;&#x440;&#x438;&#x438; II: &#x440;&#x430;&#x437;&#x440;&#x430;&#x431;&#x43E;&#x442;&#x43A;&#x430;, &#x447;&#x430;&#x441;&#x442;&#x44C; 2</title><link>https://tesall.club/blogs/entry/282-repozitorii-ii-razrabotka-chast-2/</link><description><![CDATA[<p><a href="/blog/21/entry-278-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D1%87%D0%B0%D1%81%D1%82%D1%8C-1/">Начало здесь</a>.<br><br><span style="font-size:14px;">Приступим к "прикручиванию" скриптов к репозиториям для придания им функциональности. Иначе говоря, заставим их делать то, для чего они предназначены - открывать хранилища!</span><br>
Из предыдущего опыта я знаю, что скрипты можно повесить прямиком на репозитории и они будут замечательно работать, но... Поскольку это объекты инвентаря, которые мы "одеваем", возникнет необходимость "снять", и эта процедура из самого объекта не работает и придется прикручивать ее к "игроку". А раз так, то логичнее все сразу "расписать" в одном скрипте, а не "распылять" по множеству объектов!<br><br>
</p><div class="message success"><br>
В окне <strong>Object Window</strong> выбираем пункт <strong>Quest</strong>, в таблице справа находим наш квест <strong>CB_Player</strong> и открываем его для редактирования. Переключаемся на закладку <strong>Quest Aliases</strong>, где у нас уже есть один псевдоним - <strong>Player</strong>.
<br><br><p style="text-align:center;"><span><img alt="Snap_2013.06.01 16.57.54_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145376" data-ratio="4.85" style="height:auto;" width="747" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-01-16-57-54-002.png.x1yjcikbq3f85wl2se6n0zhma47v9tdg.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></p>
<br><p>Открываем его редактирования и в секторе <strong>Scripts</strong> жмем кнопку <strong>Add</strong>, чтобы добавить новый скрипт. В следующем окне выбираем пункт <strong>New script</strong>, а дальше заполняем название и жмем <strong>ОК</strong>.<br>
&nbsp;</p>
<p style="text-align:center;"><span><img alt="Snap_2013.06.01 16.31.36_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145377" data-ratio="1.01" style="height:auto;" width="303" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-01-16-31-36-001.png.49pt7lnokz6bjm0h8xifuaev2dwcq53r.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></p>
<br><p>Открываем этот новый скрипт для редактирования и начинаем творить (пока для одного репозитория). "Звучит" скрипт так - если одетый объект это репозиторий, то снять его, закрыть меню и открыть хранилище.</p>
<p></p><div class="ipsSpoiler" data-ipsspoiler=""><div class="ipsSpoiler_header"><span>Скрипт</span></div><div class="ipsSpoiler_contents">
<pre class="_prettyXprint _lang-auto _linenums:0">
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

</pre>
<p></p></div></div><br>
&nbsp;
<p><span style="font-size:14px;">После сохранения и компиляции скрипта, открываем и заполняем его свойства. Для хранилища вручную указываем нашу ячейку и хранилище. А для репозитория можно воспользоваться авто-заполнением - жмем кнопку </span><strong>Auto-Fill</strong><span style="font-size:14px;">.</span></p>
<br><br><p style="text-align:center;"><span style="font-size:14px;"><span><img alt="Snap_2013.06.01 17.16.03_003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145378" data-ratio="2.42" style="height:auto;" width="719" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-01-17-16-03-003.png.ghljckntmq567arpdsifo24e93x108zb.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></span></p>
<br><br><p>Жмем <strong>ОК</strong> чтобы закрыть свойства, потом закрываем окно псевдонима и окно квеста. Везде используем кнопку <strong>ОК</strong>, чтобы сохранить изменения.<br>
</p></div><br><br>
Сохраняем результаты работы, нажав пиктограмму <strong>Сохранить</strong>, и пойдем в игру проверить работоспособность репозитория "- Все оружие".<br><br>
... Все работает как планировалось! А значит можно расширить этот скрипт, включив в него все репозитории и хранилища.<br><br>
Поскольку я задавал легко запоминающиеся описательные названия объектов, мне легче и быстрее добавлять свойства (Property) прямо в теле скрипта, а после компиляции их заполнять. В некоторых случаях, может быть проще сначала задать и заполнить свойства через редактор, а потом править скрипт.<br><br>
<div class="message success"><br>
Вот полностью готовый скрипт. Как видите он однообразен, проверяет что одето и снимает этот объект, потом закрывает меню и открывает соответствующее хранилище. Исключение составляют репозитории, при "одевании" расходующиеся, такие как еда, зелье или ингредиенты. В этих случаях следует "пополнить" инвентарь, использовав функцию добавления.
<p></p><div class="ipsSpoiler" data-ipsspoiler=""><div class="ipsSpoiler_header"><span>Скрипт</span></div><div class="ipsSpoiler_contents">
<pre class="_prettyXprint _lang-auto _linenums:0">
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
</pre>
<p></p></div></div>
<p>Заполненные свойства скрипта.<br>
&nbsp;</p>
<p style="text-align:center;"><span><img alt="Snap_2013.06.01 21.00.03_004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145379" data-ratio="1.76" style="height:auto;" width="719" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-01-21-00-03-004.png.3ksb8oa5pg1r7yfnduxm26w9velq4jhc.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></p>
<p></p></div><br><br>
Зайдя в игру, убеждаемся что все работает - хранилища открываются, принимают только определенные для них типы объектов и вообще все замечательно, кроме одного. Репозитории перемещаются и "принимаются" хранилищами, а мы этого не хотим! В наших планах чтобы репозитории невозможно было переместить из инвентаря или выбросить в мир!<br>
Помните, при создании фильтров для хранилищ, мы упоминали спец. объекты, которые не должны попадать в хранилище. Тогда эти свойства остались не заполнены, пора их заполнить, ведь спец. объекты (репозитории) уже созданы.<br><br>
&lt;...здесь пауза длиной в сутки...&gt;<br><br>
Как я выяснил, использование скриптов на каждом отдельном хранилище, для возврата попавшего туда репозитория, не эффективно! Наилучший способ - обработать эту ситуацию в уже имеющемся скрипте псевдонима Player.<br>
Значит, скрипты на хранилищах надо "почистить" от неиспользуемых свойств. И изменить скрипт CB_PlayerAlias_Script так чтобы репозитории всегда "возвращались" в инвентарь.<br><br>
<div class="message success"><br>
Сначала чистим. Это не сложно, ведь основной скрипт у нас на "родительском" объекте <strong>CB_Container</strong>.<br>
Отправляемся редактировать скрипт висящий на контейнере. Выбираем в окне <strong>Object Window</strong> раздел <strong>Container</strong>, находим наш объект <strong>CB_Container</strong> и открываем для редактирования. Чтобы удалить ненужное свойство (<strong>Property</strong>), нужно отредактировать сам скрипт. Открываем его, находим строку и удаляем ее.
<pre class="_prettyXprint _lang-auto _linenums:0">
Form Property CB_Object Auto
{специальный объект для активации этого контейнера}
</pre>
<pre class="_prettyXprint">
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

</pre>
<p>&nbsp;</p>
<p></p><p class="message error">Компилируем и сохраняем скрипт, и обязательно заходим в окно свойств скрипта, во-первых, убедиться что свойство удалилось, во-вторых, чтобы редактор "запомнил" эти изменения. Если этого не сделать останется ссылка на несуществующее свойство, и хотя на работу мода это не повлияет, зато будет постоянно генерироваться предупреждение в лог-файле.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p style="text-align:center;"><img alt="Snap_2013.06.03 15.16.16_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145380" data-ratio="1.84" style="height:auto;" width="489" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-03-15-16-16-001.png.v4dm91irsuqo2a8h3cpt6f7b5nkzyejw.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p>
<p>&nbsp;</p>
<p><br>
</p></div>
<p>&nbsp;</p>
<p></p><div class="message success">
<p>Тоже самое делаем для хранилища&nbsp;CB_Box_Food, редактируем его скрипт&nbsp;CB_Box_FilterFood_Script, избавляясь от свойства&nbsp;CB_FOOD. Вот измененный скрипт.</p>
<p></p><div class="ipsSpoiler" data-ipsspoiler=""><div class="ipsSpoiler_header"><span>Измененный скрипт</span></div><div class="ipsSpoiler_contents">
<pre class="_prettyXprint">
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

</pre>
<p></p></div></div>
<p></p></div>
<p>&nbsp;</p>
<p><span style="font-size:14px;">Сохраняем промежуточные результаты работы и переходим к скрипту&nbsp;</span><span style="font-size:14px;"><strong>CB_PlayerAlias_Script</strong>.</span></p>
<p>&nbsp;</p>
<p></p><div class="message success">
<p>Выделяем в окне <strong>Object Window</strong> категорию <strong>Quest</strong>, и в таблице справа, находим наш квест <strong>CB_Player</strong>. Открываем и переключаемся на закладку <strong>Quest Aliases</strong>. Открываем псевдоним <strong>Player</strong> и редактируем его скрипт.</p>
<p>Я добавил обработку события&nbsp;<strong>OnItemRemoved()</strong>, чтобы когда удаляется один из репозиториев, восстанавливать его количество в инвентаре. Дабы не "раздувать" скрипт однотипными командами, добавил функцию - она нужна только для компактности кода.</p>
<p>&nbsp;</p>
<p></p><div class="ipsSpoiler" data-ipsspoiler=""><div class="ipsSpoiler_header"><span>Измененный скрипт</span></div><div class="ipsSpoiler_contents">
<pre class="_prettyXprint">
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

Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer)
	
	If akBaseItem == CB_Weapon
		ReturnItem(akBaseItem, akDestContainer)
	ElseIf akBaseItem == CB_Armor
		ReturnItem(akBaseItem, akDestContainer)
	ElseIf akBaseItem == CB_Potion
		ReturnItem(akBaseItem, akDestContainer)
	ElseIf akBaseItem == CB_Scroll
		ReturnItem(akBaseItem, akDestContainer)
	ElseIf akBaseItem == CB_Food
		ReturnItem(akBaseItem, akDestContainer)
	ElseIf akBaseItem == CB_Ingredient
		ReturnItem(akBaseItem, akDestContainer)
	ElseIf akBaseItem == CB_Book
		ReturnItem(akBaseItem, akDestContainer)
	ElseIf akBaseItem == CB_Misc
		ReturnItem(akBaseItem, akDestContainer)
	EndIf
EndEvent

Function ReturnItem(Form _BaseItem, ObjectReference _DestContainer)
	If !_DestContainer
		If GetPlayer().GetItemCount(_BaseItem) == 0
			GetPlayer().AddItem(_BaseItem, 1, True)
		EndIf
	Else
		If GetPlayer().GetItemCount(_BaseItem) == 0
			_DestContainer.RemoveItem(_BaseItem, 1, True, GetPlayer())
		EndIf
	EndIf
EndFunction
&nbsp;</pre>
<p>&nbsp;</p>
<p></p></div></div>
<p>&nbsp;</p>
<p></p></div>
<p>На этом этапе мы получили полноценный рабочий мод! Бездонные хранилища для каждой категории отдельно! И хотя на этом останавливаться я не собираюсь, но уже можно гордиться результатом...</p>
<p>&nbsp;</p>
<p><a href="/blog/21/entry-283-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D1%87%D0%B0%D1%81%D1%82%D1%8C-3/">Продолжение здесь</a>.</p>]]></description><guid isPermaLink="false">282</guid><pubDate>Mon, 03 Jun 2013 13:05:00 +0000</pubDate></item><item><title>&#x420;&#x435;&#x43F;&#x43E;&#x437;&#x438;&#x442;&#x43E;&#x440;&#x438;&#x438; II: &#x440;&#x430;&#x437;&#x440;&#x430;&#x431;&#x43E;&#x442;&#x43A;&#x430;, &#x447;&#x430;&#x441;&#x442;&#x44C; 3</title><link>https://tesall.club/blogs/entry/283-repozitorii-ii-razrabotka-chast-3/</link><description><![CDATA[<a href="/blog/21/entry-282-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D1%87%D0%B0%D1%81%D1%82%D1%8C-2/">Начало здесь</a>.<br>
<br>
Пару дней ушло на "творческие метания"! Пытался совместить свои желания с возможностями игровой механики. Я совершенно точно знаю, что хочу видеть в моде - перемещение объекта из инвентаря в нужное хранилище без открытия последнего! И хотя SKSE существенно расширяет наши возможности, но определить скриптами текущий объект в инвентаре, пока не возможно, а значит невозможно и произвести над ним желаемые действия!<br>
<br>
Но решение найдено! И хотя оно малопроизводительно (прямое управление объектом было бы на порядок быстрее), но оно элегантное и главное - работает!<br>
<br>
<div class="message success"><br>
Чтобы реализовать такое действие, внесем коррективы в существующий скрипт <strong>CB_PlayerAlias_Script</strong>, прикрепленный к псевдониму <strong>Player</strong>, нашего квеста <strong>CB_Player</strong>.<br>
В событии при удалении объекта OnItemRemoved() мы предотвращали "потерю" репозиториев из инвентаря. Туда же я добавил код, анализирующий нажатие клавиш. Теперь, если при удалении объекта была нажата не одна, а две клавиши, то удаленный объект добавляется в соответствующее хранилище, а его ссылка в мире удаляется. Для игрока эта операция будет выглядеть как перемещение объекта из инвентаря в хранилище!<br>
Благодаря использованию функции SKSE <strong>GetNumKeysPressed()</strong>, определяющей количество нажатых клавиш, мы избегаем конфликта с любыми модами, управляющими кнопками клавиатуры. При этом сами можем использовать любые комбинации клавиш в сочетании с клавишей, назначенной для выбрасывания объектов из инвентаря! Например, (удобнее для пальцев) "<strong>L-Shift + R</strong>" или "<strong>L-Ctrl + R</strong>" или "<strong>R-Alt + R</strong>" (неудобно, но работает!)...<br>
<br>
<div class="ipsSpoiler" data-ipsspoiler=""><div class="ipsSpoiler_header"><span>Измененный скрипт</span></div><div class="ipsSpoiler_contents"><pre class="ipsCode prettyprint prettyprinted">
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

Ammo 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
Int iNumKeysPressed = 0

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

Event OnItemRemoved(Form akBaseObject, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer)
		
	iNumKeysPressed = Input.GetNumKeysPressed()
	
	If iNumKeysPressed == 2
		ObjectReference itemREF = FindClosestReferenceOfTypeFromRef(akBaseObject, GetPlayer(), 256)
			If akBaseObject as Weapon
				BoxWeapon.AddItem(itemREF, aiItemCount, True)
			ElseIf akBaseObject as Ammo
				BoxWeapon.AddItem(itemREF, aiItemCount, True)
			ElseIf akBaseObject as Armor
				BoxArmor.AddItem(itemREF, aiItemCount, True)
			ElseIf akBaseObject as Potion
				If (akBaseObject as Potion).isFood()
					BoxFood.AddItem(itemREF, aiItemCount, True)
				Else
					BoxPotion.AddItem(itemREF, aiItemCount, True)
				EndIf
			ElseIf akBaseObject as Scroll
				BoxScroll.AddItem(itemREF, aiItemCount, True)
			ElseIf akBaseObject as Ingredient
				BoxIngr.AddItem(itemREF, aiItemCount, True)
			ElseIf akBaseObject as Book
				BoxBook.AddItem(itemREF, aiItemCount, True)
			ElseIf akBaseObject as MiscObject
				BoxMisc.AddItem(itemREF, aiItemCount, True)
			EndIf
		itemREF.Disable()
		itemREF.Delete()
	EndIf
		
	If akBaseObject == CB_Weapon
		ReturnItem(akBaseObject, akDestContainer)
	ElseIf akBaseObject == CB_Armor
		ReturnItem(akBaseObject, akDestContainer)
	ElseIf akBaseObject == CB_Potion
		ReturnItem(akBaseObject, akDestContainer)
	ElseIf akBaseObject == CB_Scroll
		ReturnItem(akBaseObject, akDestContainer)
	ElseIf akBaseObject == CB_Food
		ReturnItem(akBaseObject, akDestContainer)
	ElseIf akBaseObject == CB_Ingredient
		ReturnItem(akBaseObject, akDestContainer)
	ElseIf akBaseObject == CB_Book
		ReturnItem(akBaseObject, akDestContainer)
	ElseIf akBaseObject == CB_Misc
		ReturnItem(akBaseObject, akDestContainer)
	EndIf
EndEvent

Function ReturnItem(Form _BaseItem, ObjectReference _DestContainer)
	If !_DestContainer
		If GetPlayer().GetItemCount(_BaseItem) == 0
			GetPlayer().AddItem(_BaseItem, 1, True)
		EndIf
	Else
		If GetPlayer().GetItemCount(_BaseItem) == 0
			_DestContainer.RemoveItem(_BaseItem, 1, True, GetPlayer())
		EndIf
	EndIf
EndFunction
</pre><br>
<br>
</div></div><br>
<br>
Я уже протестировал этот код в игре, и мне понравилось! Я могу очень "гибко" выкладывать объекты в хранилища, и если надо переместить большое количество объектов, то комбинацию клавиш нажимать при подтверждении удаления!<br>
</div><br>
<br>
Теперь обратим внимание на хранилище "-Все разное". Сейчас там складируются те категории объектов, доступ к которым мы хотели бы иметь отдельно. Мне представляется, что сортировки по категориям, внутри этого хранилища, будет достаточно. Вот этой задачей и займемся.<br>
<br>
<div class="message success"><br>
В окне <strong>Cell View</strong> находим нашу ячейку <strong>CB_Cell</strong>, а в ней хранилище <strong>CB_Misc</strong>. Открываем его для редактирования, переключаемся на вкладку скриптов. Поскольку функциональности имеющегося скрипта нам недостаточно, отключаем его, кнопка <strong>Remove</strong>, и добавляем новый скрипт, кнопка <strong>Add</strong>.<br>
<br>
<div class="ipsSpoiler" data-ipsspoiler=""><div class="ipsSpoiler_header"><span>Новый скрипт</span></div><div class="ipsSpoiler_contents"><pre class="ipsCode prettyprint prettyprinted">
Scriptname CB_Box_MiscSwitch_Script extends ObjectReference  

Keyword Property VendorItemOreIngot Auto
Keyword Property VendorItemGem Auto
Keyword Property VendorItemAnimalHide Auto
Keyword Property VendorItemAnimalPart Auto
Keyword Property VendorItemSoulGem Auto

ObjectReference Property BoxOre Auto
ObjectReference Property BoxGem Auto
ObjectReference Property BoxSoul Auto
ObjectReference Property BoxAnim Auto

Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)
	If akBaseItem as MiscObject
		If akBaseItem.HasKeyword(VendorItemOreIngot)
			Self.RemoveItem(akBaseItem, aiItemCount, True, BoxOre)
		ElseIf akBaseItem.HasKeyword(VendorItemGem)
			Self.RemoveItem(akBaseItem, aiItemCount, True, BoxGem)
		ElseIf akBaseItem.HasKeyword(VendorItemAnimalHide) || akBaseItem.HasKeyword(VendorItemAnimalPart)
			Self.RemoveItem(akBaseItem, aiItemCount, True, BoxAnim)
		ElseIf akBaseItem.HasKeyword(VendorItemSoulGem)
			Self.RemoveItem(akBaseItem, aiItemCount, True, BoxSoul)	
		EndIf
	Else
		Self.RemoveItem(akBaseItem, aiItemCount, True, akSourceContainer)
	EndIf
EndEvent
</pre><br>
</div></div><br>
Заполняем все его свойства.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.06.07 16.33.16_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145381" data-ratio="0.75" style="height:auto;" width="491" data-src="https://tesall.club/uploads/monthly_2013_06/snap-2013-06-07-16-33-16-001.png.dwgehmf2l7r149pv3kcx8zyji056unso.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
<span style="font-size: large;"></span></div>[/size]<br>
<br>
<a href="/blog/21/entry-288-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D1%87%D0%B0%D1%81%D1%82%D1%8C-4/">Продолжение здесь</a>]]></description><guid isPermaLink="false">283</guid><pubDate>Mon, 03 Jun 2013 13:01:00 +0000</pubDate></item><item><title>&#x420;&#x435;&#x43F;&#x43E;&#x437;&#x438;&#x442;&#x43E;&#x440;&#x438;&#x438; II: &#x440;&#x430;&#x437;&#x440;&#x430;&#x431;&#x43E;&#x442;&#x43A;&#x430;, &#x447;&#x430;&#x441;&#x442;&#x44C; 1</title><link>https://tesall.club/blogs/entry/278-repozitorii-ii-razrabotka-chast-1/</link><description><![CDATA[<a href="/blog/21/entry-274-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D0%BE/">Начало здесь</a>.<br>
<br>
Вчера мы закончили создавать хранилища, а ночью, пока все спали, я зашел в игру, "телепортировался" в ячейку <strong>CB_Cell</strong> и проверил работоспособность фильтров на хранилищах. Все работает правильно, как и ожидалось!<br>
<br>
Сегодня создаем специальные объекты. Я буду называть их репозиториями, ведь для игрока они представляются бездонными контейнерами, хотя на деле являются лишь активаторами, спусковыми крючками для открытия соответствующих хранилищ.<br>
<br>
Как я и планировал, использую принцип репозиториев из первой версии мода - в каждой категории объектов будет специальный объект при активации которого открывается соответствующее хранилище.<br>
<br>
Приступим к созданию репозиториев в том же порядке, каком расположены категории в инвентаре.<br>
<br>
<div class="message success"><br>
Начнем с категории "Оружие". В окне <strong>Object Window</strong> выделяем пункт <strong>Weapon</strong>. В таблице справа, кликаем ПКМ и выбираем пункт <strong>New</strong>. Откроется пустой бланк объекта <strong>Weapon</strong>. Нам потребуется заполнить лишь названия и тип одевания (<strong>Equip Type</strong>), чтобы при использовании не заменять в руках оружие, остальные поля оставляем пустые. Даже модель объекта нас пока не тревожит, оставим ее "на потом". Жмем <strong>ОК</strong> - объект готов.<br>
<br>
<br>
<br>
<br>
<br>
<br>
<p style="text-align: center;"><img alt="Snap_2013.05.30 15.05.32_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145361" data-ratio="4.10" style="height:auto;" width="988" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-15-05-32-001.png.lkf7zu9g2t5ja016oesycbhxd8mvnwpq.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
</div><br>
<br>
<div class="message success"><br>
Следующая категория "Броня". <span style="font-size: large;">В окне </span><strong>Object Window</strong><span style="font-size: large;"> выделяем пункт <strong>Armor</strong>. </span><span style="font-size: large;">В таблице справа, кликаем ПКМ и выбираем пункт </span><strong>New</strong><span style="font-size: large;">. Откроется пустой бланк объекта </span><strong>Armor</strong><span style="font-size: large;">. </span><span style="font-size: large;">Нам потребуется заполнить лишь названия и установить <strong>Equip Type</strong> равным <strong>Potion</strong>, </span><span style="font-size: large;">остальные поля оставляем пустые. </span><span style="font-size: large;">Жмем </span><strong>ОК</strong><span style="font-size: large;"> - объект готов.</span><br>
 <br>
<p style="text-align: center;"><span style="font-size: large;"><img alt="Snap_2013.05.30 15.26.35_003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145362" data-ratio="4.68" style="height:auto;" width="983" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-15-26-35-003.png.po7m06ucz2wbtr5n4ahxfisl8kdqvj93.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></p><br>
<br>
</div><br>
<br>
<div class="message success"><br>
Категория "Зелья". <span style="font-size: large;">В окне </span><strong>Object Window</strong><span style="font-size: large;"> выделяем пункт <strong>Potion</strong>. </span><span style="font-size: large;">В таблице справа, кликаем ПКМ и выбираем пункт </span><strong>New</strong><span style="font-size: large;">. Откроется пустой бланк объекта </span><strong>Potion</strong><span style="font-size: large;">. </span><span style="font-size: large;">Нам потребуется заполнить названия и выбрать магический эффект в табличке <strong>Results</strong>. Без указания </span>магического<span style="font-size: large;"> эффекта игру будет "выбивать", поэтому, на данном этапе, выбираем любой эффект.</span><br>
 <br>
<p style="text-align: center;"><span style="font-size: large;"><img alt="Snap_2013.05.30 15.58.45_004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145363" data-ratio="3.96" style="height:auto;" width="649" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-15-58-45-004.png.1pydwgsvnmxuo8ce7zrhl5qk6j20a3t4.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></p><br>
<br>
<span style="font-size: large;"></span></div>[/size]<br>
<br>
<div class="message success"><br>
Категория "Свитки". <span style="font-size: large;">В окне </span><strong>Object Window</strong><span style="font-size: large;"> выделяем пункт <strong>Scroll</strong>. </span><span style="font-size: large;">В таблице справа, кликаем ПКМ и выбираем пункт </span><strong>New</strong><span style="font-size: large;">. Откроется пустой бланк объекта </span><strong>Scroll</strong><span style="font-size: large;">. </span><span style="font-size: large;">Нам потребуется заполнить названия и опять же выбрать любой магический эффект.</span><br>
<br>
<br>
<br>
<br>
<br>
<p style="text-align: center;"><span style="font-size: large;"><img alt="Snap_2013.05.30 16.10.04_005.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145364" data-ratio="1.27" style="height:auto;" width="508" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-16-10-04-005.png.1hngtp8vy9ab27uldq6sr5cow3mf0ixe.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></p><br>
<br>
</div><br>
<br>
<div class="message success"><br>
Категория "Еда и напитки". <span style="font-size: large;">Чтобы создать объект в этой категории, в</span><span style="font-size: large;"> окне </span><strong>Object Window</strong><span style="font-size: large;"> выделяем пункт <strong>Potion</strong>. </span><span style="font-size: large;">В таблице справа, кликаем ПКМ и выбираем пункт </span><strong>New</strong><span style="font-size: large;">. Откроется пустой бланк объекта </span><strong>Potion</strong><span style="font-size: large;">. </span><span style="font-size: large;">Нам потребуется заполнить названия и эффект, так же, как при создании репозитория для зелий, и вдобавок установить флажок <strong>Food Item</strong>.</span><br>
 <br>
<p style="text-align: center;"><span style="font-size: large;"><img alt="Snap_2013.05.30 16.19.57_006.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145365" data-ratio="1.51" style="height:auto;" width="697" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-16-19-57-006.png.ldtw5248q6g7frecn0ham3jospuv1kzi.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></p><br>
<br>
</div><br>
<br>
<div class="message success"><br>
Категория "Ингредиенты". <span style="font-size: large;">В окне </span><strong>Object Window</strong><span style="font-size: large;"> выделяем пункт <strong>Ingredient</strong>. </span><span style="font-size: large;">В таблице справа, кликаем ПКМ и выбираем пункт </span><strong>New</strong><span style="font-size: large;">. Откроется пустой бланк объекта </span><strong>Ingredient</strong><span style="font-size: large;">. </span><span style="font-size: large;">Нам потребуется заполнить названия, эффект и Equip Type (необязательно).</span><br>
 <br>
<p style="text-align: center;"><span style="font-size: large;"><img alt="Snap_2013.05.30 16.30.02_007.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145366" data-ratio="2.89" style="height:auto;" width="538" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-16-30-02-007.png.2hzyc14rm50gpsxk8id6ofbnwjleq9tu.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></p><br>
<br>
</div><br>
<br>
<div class="message success"><br>
Категория "Книги". <span style="font-size: large;">В окне </span><strong>Object Window</strong><span style="font-size: large;"> выделяем пункт <strong>Book</strong>. </span><span style="font-size: large;">В таблице справа, кликаем ПКМ и выбираем пункт </span><strong>New</strong><span style="font-size: large;">. Откроется пустой бланк объекта </span><strong>Book</strong><span style="font-size: large;">. </span><span style="font-size: large;">Нам потребуется заполнить названия и вид в инвентаре <strong>Inventory Art</strong> (произвольным значением для книг).</span><br>
 <br>
<p style="text-align: center;"><span style="font-size: large;"><img alt="Snap_2013.05.30 16.39.46_008.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145367" data-ratio="0.71" style="height:auto;" width="301" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-16-39-46-008.png.esymgxj2hlqwzkrobf7654inc13v80at.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></p><br>
<br>
</div><br>
<br>
<div class="message success"><br>
Категория "Разное". <span style="font-size: large;">В окне </span><strong>Object Window</strong><span style="font-size: large;"> выделяем пункт <strong>MiscItem</strong>. </span><span style="font-size: large;">В таблице справа, кликаем ПКМ и выбираем пункт </span><strong>New</strong><span style="font-size: large;">. Откроется пустой бланк объекта </span><strong>MiscItem</strong><span style="font-size: large;">. </span><span style="font-size: large;">Нам потребуется только заполнить названия.</span><br>
 <br>
<p style="text-align: center;"><span style="font-size: large;"><img alt="Snap_2013.05.30 16.48.03_009.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145368" data-ratio="1.23" style="height:auto;" width="259" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-16-48-03-009.png.kc2vj4d3rg5ef8sat9p0xni6qzolbmyw.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></p><br>
<br>
</div><br>
<br>
Созданных репозиториев достаточно, чтобы обслужить все наши хранилища. Репозиторий "Все разное" будет открывать меню для доступа к хранилищам, у которых нет собственных репозиториев.<br>
<br>
А сейчас, чтобы закончить этот этап на мажорной ноте, "положим" все эти репозитории в инвентарь ГГ.<br>
<br>
<div class="message success"><br>
В окне <strong>Object Window</strong><span style="font-size: large;"> в разделе <strong>Character</strong> выделяем пункт <strong>Quest. </strong></span><span style="font-size: large;">В таблице справа, кликаем ПКМ и выбираем пункт </span><strong>New</strong><span style="font-size: large;">. Откроется пустой бланк объекта <strong>Quest</strong>. Указываем название и снимаем флажок <strong>Run Once</strong> (запустить один раз). Жмем <strong>ОК</strong> чтобы сохранить квест и открываем его снова.</span><br>
 <br>
<p style="text-align: center;"><span style="font-size: large;"><img alt="Snap_2013.05.30 17.02.16_010.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145369" data-ratio="2.72" style="height:auto;" width="653" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-17-02-16-010.png.yrw2dmtzk6ub8ljqoag04ih9x1pc5s7n.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></span></p><br>
<br>
<br>
Переключаемся на закладку <strong>Quest Aliases</strong>, в табличке ниже кликаем ПКМ и выбираем первый пункт<strong> New Reference Alias</strong>.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.30 17.08.24_011.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145370" data-ratio="1.42" style="height:auto;" width="377" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-17-08-24-011.png.h468bj20ky7zdlgauevci3o1pw9msrq5.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
Задаем имя псевдонима - <strong>Player</strong> (произвольное). И в разделе <strong>Unique Actor</strong> выбираем пункт <strong>Player</strong>.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.30 17.13.11_012.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145371" data-ratio="2.50" style="height:auto;" width="563" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-17-13-11-012.png.012lg6tjiq7u93v85pzoefdmsckhaywb.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
В нижней части окна, в табличке <strong>Alias Inventory</strong>, кликаем ПКМ и выбираем пункт <strong>New</strong>.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.30 17.18.29_013.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145372" data-ratio="4.59" style="height:auto;" width="592" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-17-18-29-013.png.8e7mxtco5jdkyifwsghv2lu3a0qr9nzb.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
Появится запись, которую надо изменить на желаемую нам.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.30 17.21.40_014.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145373" data-ratio="4.13" style="height:auto;" width="607" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-17-21-40-014.png.q4dw1f6jrt5ubvmkn2zcolph8xy0is9a.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
Вот так, добавляя новую запись и заменяя ее на желаемую, вводим полный список репозиториев.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.30 17.25.34_016.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145374" data-ratio="1.96" style="height:auto;" width="413" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-30-17-25-34-016.png.86ckqzjwhe39opt5ny2uv74rxm10ibda.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
Теперь жмем <strong>ОК</strong> для сохранения этого псевдонима, и еще раз <strong>ОК</strong>, чтобы сохранить квест.<br>
Сохраняем нашу работу - жмем пиктограмму <strong>Сохранить</strong>.<br>
</div><br>
<br>
На сегодня это все, но хотелось бы увидеть результат, поэтому захожу в игру, и с удовлетворением вижу репозитории:<br>
 <br>
<p style="text-align: center;"><img alt="ScreenShot4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145375" data-ratio="0.96" style="height:auto;" width="386" data-src="https://tesall.club/uploads/monthly_2013_05/screenshot4.png.zpw8t175udfirg2y3mkn6a04xleqjov9.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
<a href="/blog/21/entry-282-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D1%87%D0%B0%D1%81%D1%82%D1%8C-2/">Продолжение здесь</a>.]]></description><guid isPermaLink="false">278</guid><pubDate>Thu, 30 May 2013 15:47:00 +0000</pubDate></item><item><title>&#x420;&#x435;&#x43F;&#x43E;&#x437;&#x438;&#x442;&#x43E;&#x440;&#x438;&#x438; II: &#x43D;&#x43E;&#x432;&#x430;&#x44F; &#x432;&#x435;&#x440;&#x441;&#x438;&#x44F;</title><link>https://tesall.club/blogs/entry/272-repozitorii-ii-novaya-versiya/</link><description><![CDATA[Достаточно поигравшись с модом Репозитории (Collector bags v1.0) и столкнувшись с рядом проблем в совместимости, я понял, что надо менять концепцию мода. И менять кардинально. Поэтому, начинаю новый проект с "чистого листа". А поскольку задачи, которые я буду решать, могут заинтересовать начинающих мододелов, постараюсь как можно детальнее проиллюстрировать весь процесс создания мода.<br>
<br>
Первым делом попробую сформулировать новый алгоритм.<br>
Но прежде, напомню о назначении или "призвании" мода Репозитории - хранилища по категориям, этакие "бездонные сумки", автоматически сортирующие все попадающие в инвентарь объекты, что избавляет игрока от необходимости постоянно их выкладывать и в то же время, легко доступны.<br>
<br>
Главной проблемой первой версии мода стали объекты не подлежащие немедленной сортировке. И если задачу, например, с медвежьими шкурами, которые надо насобирать определенное количество, или Алыми корнями Нирна и тому подобное, можно решить путем создания "стоп-листа", то специальные объекты из DLC HearthFire вообще не видны игроку и не должны перемещаться из инвентаря! Таким образом, правильное решение - это отсутствие действия автосортировки по-умолчанию!<br>
<br>
Итак! Цели обозначены, проблемы определены. Попробую представить порядок действий мода, пока в общих чертах.<br>
<br>
<div class="message success">Объекты попадающие в инвентарь остаются в нем. Игрок создает и редактирует список объектов для автосортировки. В результате, объекты из этого списка, попадая в инвентарь, автоматически сортируются по категориям в хранилища.<br>
Такой подход позволит "штатную" работу квестовым и "невидимым служебным" предметам. Это удобно для изучения новых ингредиентов, которые желательно "съесть", а потом уже собирать, а также для продуктов питания, например, порционные бурдюки с водой желательно оставлять в инвентаре.<br>
Доступ к хранилищам - через удаленную активацию контейнера.</div><br>
<br>
Необходимые шаги по созданию мода:<br>
<br>
* Создаю контейнеры для каждой категории, к которой хочу иметь отдельный доступ и размещаю в "мире". <em>Необходимо продумать размещение для облегчения доступа игрока к ним.</em><br>
<br>
* На каждый контейнер вешаю скрипт, проверяющий поступающий объект на наличие "keyword" характеризующего данную категорию. <em>Это исключит попадание "сторонних" объектов в это хранилище.</em><br>
<br>
* Если в первой версии, любой объект попавший в инвентарь подвергался сортировке, то теперь этого не будет. При попадании объекта в инвентарь ничего не происходит! <em>Это позволит работать игровым скриптам в "штатном" режиме.</em><br>
<br>
* Автосортировка будет производится на основе списка объектов, выбранных игроком. <em>Нужно придумать механизм создания такого списка. В первой версии это был динамически создаваемый FormList.</em><br>
<br>
* Имея список для сортировки, можно использовать функцию AddInventoryEventFilter() для реагирования на событие добавления объекта. <em>Объекты из списка будут автоматически рассортированы по хранилищам.</em><br>
<br>
* Добавление в хранилище объектов "не из списка", т.е. одноразовое, сделать без открытия соответствующего хранилища. <em>Просто выбрав в инвентаре объект и нажав "горячую клавишу" , отправляю его в нужное хранилище. Это значительно сэкономит время обработки и решит проблему с зависанием открытия сундука, время от времени появлявшуюся в первой версии мода. </em><br>
<br>
* Доступ к хранилищам для изъятия объектов. Если организовать доступ через меню, это получится слишком громоздко и не вместится в одно окно, что усложнит скрипт. Вероятно, использую метод из первой версии - создание специальных объектов инвентаря в каждой категории.<br>
<br>
* Автовыгрузка перед использованием станков крафтинга. Вероятно, использую метод из первой версии - создание специального объекта инвентаря в категории Разное.<br>
<br>
Ну вот, в общих чертах, алгоритм готов и можно приступать к созданию!<br>
<div class="message success"><br>
Открываем Creation Kit, выбираем пиктограмму <strong>Открыть</strong>.<br>
В появившемся окошке выделяем флажком файл <strong>Skyrim.esm</strong> и жмем <strong>ОК</strong>.<br>
Некоторые модмейкеры выделяют и файл <strong>Update.esm</strong>, но делать это не нужно!<br>
Это не испортит ваш мод, но может добавить проблем в случае создания патчей на его основе.<br>
<p style="text-align: center;"><br>
<a href="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-23-15-23-54-001.png.p6albj2o7x1zrdtheiug98ys3km5f04v.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Snap_2013.05.23 15.23.54_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145323" data-ratio="2.01" style="height:auto;" width="642" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-23-15-23-54-001.png.9uk02o3wthe7yjia5xv4pczdng6qlbfm.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a></p><br>
</div><br>
<div class="message success"><br>
Первым шагом будет создание контейнеров. В окне <strong>Object Window</strong> выбираю категорию <strong>Container</strong>.<br>
Мне важно, как будут выглядеть контейнеры, ведь игроку, при обновлении мода, потребуется с ними взаимодействовать. Поэтому выбираю модель ларцов, они небольшие по размеру и это важно, ведь категорий, а значит и хранилищ, будет много.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.24 15.40.19_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145325" data-ratio="0.67" style="height:auto;" width="165" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-24-15-40-19-002.png.25b7x1ctjedy9kn8ipo3rmazwhl6sgvf.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
</div><br>
<div class="message success"><br>
Для простоты создания, нахожу готовый контейнер, использующий модель <strong>StrongBox01</strong> и очищаю его содержимое. Даю ему свое название и имя и при закрытии указываю - создать новую форму.<br>
 <br>
<p style="text-align: center;"><a href="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-24-16-48-47-003.png.m26g9i0cbdoflv758psaeyzkr4u3nwtj.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Snap_2013.05.24 16.48.47_003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145326" data-ratio="2.16" style="height:auto;" width="1000" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-24-16-48-47-003.thumb.png.kbz47u0vehc6foxmy2iadrl935jw8nqg.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a></p><br>
<br>
Немного о названиях объектов внутри мода.<br>
Рекомендуется, хотя совсем не обязательно, использовать префиксы в названиях создаваемых объектов. Это значительно облегчает их поиск, выделяет среди встроенных игровых объектов! Префиксы - это произвольные сокращения или легко набираемые аббревиатуры, размещаемые в начале названия объекта и одинаковые в пределах одного мода. Например, <em>xxxNewBox</em> или <em>aaaaNewBox</em>.<br>
Для своих модов я применяю сокращения от английского названия файла плагина, в данном случае <em>CB_</em>, поскольку файл называется <em>Collector bags</em>.<br>
</div><br>
<br>
<div class="message success"><br>
Создав этот объект, можно сохранить мод.<br>
Жмем на пиктограмму <strong>Сохранить</strong> и, в появившемся окне, вписываем название для своего плагина.<br>
Название должно быть на английском языке, точнее, использовать символы английского алфавита, и очень желательно, информативным - чтобы по названию можно было бы понять о чем он.<br>
 <br>
<p style="text-align: center;"><a href="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-24-17-06-17-004.png.eoi8qvpuamg2w0b51t7k9cfd6synrl4h.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Snap_2013.05.24 17.06.17_004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145328" data-ratio="1.60" style="height:auto;" width="840" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-24-17-06-17-004.png.6ksw0h1i92onter4b3lpjqa5xmyzdc8u.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a></p><br>
</div><br>
Сохранив свою работу, закрываем Creation Kit. Продолжим завтра...<br>
<a href="/blog/21/entry-274-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D0%BE/">Продолжение здесь</a>.]]></description><guid isPermaLink="false">272</guid><pubDate>Wed, 29 May 2013 17:38:11 +0000</pubDate></item><item><title>&#x420;&#x435;&#x43F;&#x43E;&#x437;&#x438;&#x442;&#x43E;&#x440;&#x438;&#x438; II: &#x43D;&#x430;&#x447;&#x430;&#x43B;&#x43E;</title><link>https://tesall.club/blogs/entry/274-repozitorii-ii-nachalo/</link><description><![CDATA[<a href="/blog/21/entry-272-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D0%BD%D0%BE%D0%B2%D0%B0%D1%8F-%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F/">Начало здесь</a>.<br>
Продолжаю дневник о разработке мода, создаем хранилища.<br>
<br>
<div class="message success"><br>
Загружаем Creation Kit, жмем пиктограмму <strong>Открыть,</strong> находим и выделяем в списке файл, который сохранили вчера.<br>
Дважды кликнув по нему, ставим флажок и обязательно кликаем по кнопке внизу <strong>Set as Active File</strong>, статус файла меняется на активный. Только активный плагин можно редактировать, иначе он будет выступать в роли мастер-файла!<br>
<br>
При открытии удобно заполнить "шапку" нашего мода, которая будет отображаться в различных менеджерах загрузки модов.<br>
Указываю автора - себя, и в окошке ниже - краткое описание мода и, при желании, номер версии мода (номер придумал сам).<br>
<br>
<br>
<a href="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-25-16-25-34-002.png.e8jmxrk1g0blcf3vha5i4wnysz7d2p9q.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Snap_2013.05.25 16.25.34_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145330" data-ratio="2.01" style="height:auto;" width="642" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-25-16-25-34-002.png.qy9781wfg5mxvc3s0dpr6tan4uhkobjz.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a> <a href="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-25-16-26-50-003.png.snzxc6478mdokhgt1p5ifqjvy0e2awb9.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Snap_2013.05.25 16.26.50_003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145332" data-ratio="2.01" style="height:auto;" width="642" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-25-16-26-50-003.png.ai7w2pmco1u3v469fbetzd50lxnsgk8q.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a><br>
<br>
<br>
</div><br>
Вчера мы создали контейнер с названием <strong>CB_Container</strong>, он послужит нам образцом, шаблоном для создания хранилищ-репозиториев. Но есть важная задача, которую необходимо решить прежде, чем двигаться дальше - где размещать хранилища?<br>
<p class="message error"><br>
<strong>Пояснение.</strong> При желании удалить мод или в экстренных случаях игрок должен иметь возможность забрать "<em>нажитое непосильным трудом</em>" напрямую из хранилищ. Для этого он должен иметь возможность прибыть к месту размещения этих хранилищ и активировать контейнеры "вручную".<br>
</p><br>
В первой версии мода я использовал для этих целей служебную ячейку QASmoke, но это не самый удобный вариант. Хотя бы потому что заставляет рядового игрока использовать консоль и запоминать "необязательную" информацию.<br>
<br>
В этот раз я собираюсь рассмотреть два варианта - размещение в известном, доступном игроку месте и создание собственной ячейки исключительно для размещения хранилищ.<br>
Итак, первый вариант, размещение контейнеров в уже известном мире. Плюсы - легкодоступность для игрока и простая реализация. Минусы - несомненная конфликтность с модами, изменяющими эту ячейку. Чем популярнее ячейка, тем больше вероятность ее "улучшения", а значит и конфликт с хранилищами.<br>
Вариант второй, собственная ячейка. Плюсы - полная "неконфликтность". Минусы - относительная сложность реализации, ведь доступ в ячейку возможен только через телепортацию (дверь, заклинание).<br>
И все-таки, прикинув свои возможности, я выбираю второй, сложный вариант, для обеспечения неконфликтности с любым модом, включая даже экзотический "Тропический Скайрим"! И пусть это потребует больше работы, но я постараюсь обойтись даже без телепортации.<br>
Механизм будет следующий - создание хранилищ в собственной ячейке и их динамическое размещение в доступном игроку месте.<br>
<br>
Теперь понятно что и где делать и я приступаю...<br>
<div class="message success"><br>
Создаем ячейку. Поскольку ячейка будет служебной, без доступа игрока и без телепортации в нее ГГ, то нет необходимости в каких-либо "излишествах", она будет абсолютно пустой! Чтобы сделать такую "пустую" ячейку, выбираем меню <strong>World </strong>-- <strong>Cells</strong>... и в открывшемся окне, в списке кликаем ПКМ и выбираем пункт <strong>New</strong>.<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<p style="text-align: center;"><br>
<a href="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-15-25-25-001.png.637qsofnr89hjd5kiapuctb201gxmew4.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Snap_2013.05.28 15.25.25_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145334" data-ratio="3.39" style="height:auto;" width="762" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-15-25-25-001.png.z4cw9jqvi2aket1d3p0l8mx6rony5sfg.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a></p><br>
Вносим название ячейки, не забывая применять префикс.<br>
<p style="text-align: center;"><br>
<a href="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-15-26-36-002.png.8e2jwgotdr7zipmla453n6hfybvqkc0s.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Snap_2013.05.28 15.26.36_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145336" data-ratio="2.50" style="height:auto;" width="295" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-15-26-36-002.png.inw70buyzoj8vxp5gdc6tf94r1em3akl.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a></p><br>
И убеждаемся, в окне <strong>Cell View</strong>, есть наша ячейка и она абсолютно пуста.<br>
<p style="text-align: center;"><br>
<a href="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-15-28-44-003.png.mcvruxilqf9y62h81z57epn3gsadbjwo.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Snap_2013.05.28 15.28.44_003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145338" data-ratio="2.26" style="height:auto;" width="457" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-15-28-44-003.png.31g7xnz6hjroi80ecsvqfukdla9mwpby.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a></p><br>
</div><br>
<div class="message success"><br>
Вызываем ячейку <strong>CB_Cell</strong> в окне <strong>Render Window</strong>, просто дважды кликнув по ней в окне <strong>Cell View</strong>. Для создания наших хранилищ перетягиваем в окно <strong>Render Window</strong>, созданный ранее контейнер <strong>CB_Container</strong> из окна <strong>Object Window</strong>. Перетягиваем контейнер столько раз сколько хранилищ нам необходимо!<br>
<br>
 <br>
<p style="text-align: center;"><a href="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-15-47-31-004.png.ybutgo0am6fr49dq7v8n5hjiz3selcxk.png" class="ipsAttachLink ipsAttachLink_image"><img alt="Snap_2013.05.28 15.47.31_004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145340" data-ratio="2.59" style="height:auto;" width="816" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-15-47-31-004.png.1k2d9vwncfgb5us7qp4rjl3eyhx0t6zo.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></a></p><br>
Чтобы различать наши хранилища присваиваем им имя. Для этого или дважды кликнуть по объекту в окне <strong>Render Window</strong>, или в окне <strong>Cell View</strong> выбрать пункт <strong>Edit</strong>.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.28 15.53.12_005.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145342" data-ratio="2.20" style="height:auto;" width="413" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-15-53-12-005.png.zvbepil9qyrwatfnud8s175o6j40c3hx.png" src="https://tesall.club/applications/core/interface/js/spacer.png"><img alt="Snap_2013.05.28 15.54.21_006.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145343" data-ratio="2.23" style="height:auto;" width="411" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-15-54-21-006.png.ycfhz6gxq3pivm854dublowj1srtae0k.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
</div><br>
<br>
<div class="message success"><br>
После добавления и переименования вот что получилось у меня - 12 хранилищ для всех категорий на которые я хочу делить попадаемые в инвентарь объекты.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.28 16.39.21_009.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145344" data-ratio="1.00" style="height:auto;" width="413" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-16-39-21-009.png.nar6vlqtoghbcis3y1fmpjdku25z4x79.png" src="https://tesall.club/applications/core/interface/js/spacer.png"><img alt="Snap_2013.05.28 16.40.13_010.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145345" data-ratio="1.00" style="height:auto;" width="414" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-16-40-13-010.png.3jfn4y0m1dp89z5vwo6ebilcqk72rtuh.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
</div><br>
<br>
Жмем пиктограмму <strong>Сохранить</strong>, чтобы не потерять нашу работу.<br>
Осталось прицепить фильтр на каждый контейнер, чтобы туда попадали объекты только определенной категории. Сделаем это с помощью скриптов и так как событие это однообразное для большинства хранилищ, то сделаем его на основе шаблона скрипта.<br>
<br>
<div class="message success"><br>
Переходим в окно <strong>Object Window</strong><span style="font-size: large;"> и находим наш контейнер </span><strong>CB_Container.</strong><span style="font-size: large;"> Открываем его для редактирования, жмем кнопку <strong>Add</strong>.</span><br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.28 19.01.34_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145346" data-ratio="1.77" style="height:auto;" width="297" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-19-01-34-001.png.cbzuk07dy2wtmoe9l458x6jga3nrihqp.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
В открывшемся окне-списке выбираем первый пункт<strong> [New Script]</strong> и жмем кнопку <strong>ОК</strong>.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.28 19.08.37_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145347" data-ratio="1.43" style="height:auto;" width="490" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-19-08-37-002.png.2qixc1kabpje68vsh945r3mf0y7gtulo.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
Нам предложат назвать новый скрипт. Я использую составное название, чтобы понимать к чему относится этот скрипт. Вы можете называть скрипты произвольно, но рекомендуется придерживаться хотя бы простейших правил, чтобы избежать беспорядка. Плюс, в данном случае, я заполнил поле документации - краткое описание назначения этого скрипта.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.28 19.13.56_003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145348" data-ratio="1.01" style="height:auto;" width="303" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-19-13-56-003.png.jape4hofw31z5k6muiy7cg0nsqlb98rd.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
После нажатия кнопки <strong>ОК</strong>, в свойствах контейнера, в окошке Скрипты появится добавленный скрипт. Взаимодействуют с ним с помощью ПКМ. Я использую Notepad++ как редактор скриптов Папирус, поэтому выбираю пункт <strong>Open in External Editor</strong>, вы можете использовать встроенный редактор, тогда для вас пункт <span style="font-size: large;"><strong>Edit Source</strong>.</span><br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.28 19.28.41_004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145349" data-ratio="1.08" style="height:auto;" width="378" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-19-28-41-004.png.qlwd2a16hx4cf98b3tyskjruezi5on07.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
</div><br>
<br>
В данном случае я собираюсь писать "универсальный" скрипт, который выступит шаблоном-образцом для всех моих хранилищ, поэтому методы его создания будут отличаться от создания "стандартного", обычного скрипта. Я не буду использовать возможности автоматического заполнения свойств скрипта, используемые мной названия свойств носят описательный характер. И да, мне придется использовать функцию SKSE.<br>
<br>
<div class="message success"><br>
В "переводе" на человеческий язык, скрипт звучит так:<br>
Если в контейнер попал объект не соответствующий указанному типу, то вернуть его "отправителю". Если объект соответствует указанному типу, но является специальным объектом для активации данного контейнера, то вернуть его в инвентарь ГГ. Как вы заметили, хотя мы еще не создали эти "специальные объекты", но уже можем на них ссылаться. Это потому, что скрипты в Скайриме изолированы от игры. Именно поэтому применяются свойства (<strong>Property</strong>), как механизм передачи данных между скриптом и игрой.<br>
[spoiler="Сначала хотел листинг выкладывать тоже картинками, для "визуальности", но потом передумал"].<br>
<img alt="Snap_2013.05.28 20.42.31_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145350" data-ratio="1.36" style="height:auto;" width="766" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-20-42-31-001.png.l084qybxsk6ad7hpwenjvr9omi1tg32z.png" src="https://tesall.club/applications/core/interface/js/spacer.png"><br>
[/spoiler]<pre class="ipsCode prettyprint prettyprinted">
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
</pre><br>
</div><br>
<div class="message success"><br>
А теперь обратите внимание, хотя скрипт мы прицепили к контейнеру (базовому объекту), каждое из 12 наших хранилищ тоже "обзавелось" копией этого скрипта. Нам осталось только заполнить свойства подходящими для них значениями. Открываем хранилище для редактирования, переключаемся на закладку <strong>Script</strong>, и пользуясь подсказкой в описании к свойствам, присваиваем нужное значение типа объекта.<br>
Например, для хранилища оружия под названием <strong>CB_Box_Weapon</strong> указываем тип объекта <strong>41</strong>, для брони - 26 и так далее.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.28 21.18.50_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145351" data-ratio="1.08" style="height:auto;" width="624" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-28-21-18-50-002.png.5ed0kbpxqzicnwvsr893julamfty7146.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
</div><br>
<br>
Вы, наверное, уже заметили что не все типы объектов можно так определить. Например, еду (Food) или драгоценные камни (Gem) с помощью этой функции не обнаружить. Не страшно - применим для их определения другую функцию, а значит напишем и прицепим новый скрипт!<br>
<br>
<div class="message success"><br>
В этот раз скрипт нужно цеплять непосредственно на хранилище. Переходим в окно <strong>Cell View</strong>, находим нашу ячейку <strong>CB_Cell</strong>, выбираем хранилище еды <strong>CB_Box_Food</strong>, открываем для редактирования, переходим на вкладку <strong>Script</strong>, выделяем имеющийся там скрипт и жмем кнопку <strong>Remove</strong>. Скрипт отмечается как удаленный - красным минусом.<br>
Добавляем новый скрипт - жмем кнопку <strong>Add</strong>, выбираем пункт <strong>New Script</strong>, вписываем новое название для скрипта и <strong>ОК</strong>. Новый скрипт добавится в список со знаком "плюс".<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.29 16.07.03_004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145352" data-ratio="1.80" style="height:auto;" width="374" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-29-16-07-03-004.png.wvrmzy4nlcq1560opj9x7dg2afbti3k8.png" src="https://tesall.club/applications/core/interface/js/spacer.png"> <img alt="Snap_2013.05.29 16.08.14_005.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145353" data-ratio="1.80" style="height:auto;" width="374" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-29-16-08-14-005.png.6boesla2dpch3qwf9gtj5m8v1zrnu07y.png" src="https://tesall.club/applications/core/interface/js/spacer.png"> <img alt="Snap_2013.05.29 16.10.22_006.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145354" data-ratio="1.80" style="height:auto;" width="374" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-29-16-10-22-006.png.y6pwlomsi2xuz3c1n9qgehdvfa5b0748.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
Открываем скрипт для редактирования - ПКМ, пункт <strong>Edit Source</strong> или <strong>Open in External Editor</strong><strong>.</strong><br>
</div><br>
<br>
<div class="message success"><br>
Скрипт для контейнера с едой "переводится" так - если объект не имеет ключевого слова или не является едой (функция SKSE), то вернуть его "отправителю". А если имеет ключевое слово или является едой, но при этом является и специальным объектом, то вернуть его в инвентарь ГГ.<pre class="ipsCode prettyprint prettyprinted">
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</pre><br>
После компиляции и сохранения скрипта, заходим в его свойства и, кликнув на кнопку <strong>Auto Fill</strong>, заполняем его значение. Это возможно потому, что название свойства (<strong>Property</strong>) и название ключевого слова (<strong>Keyword</strong>) совпадают!<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.29 16.55.19_008.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145355" data-ratio="1.57" style="height:auto;" width="664" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-29-16-55-19-008.png.e78b3jfcgt2onk4uprzmhlv9a6s0iwyq.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
</div><br>
<br>
<div class="message success"><br>
Для двух хранилищ, драгоценных камней <strong>CB_Box_Gem</strong> и руды и слитков <strong>CB_Box_Ore</strong>, скрипт одинаков, поэтому используем один на двоих!<br>
Открываем хранилище <strong>CB_Box_Gem</strong>, удаляем имеющийся скрипт и создаем новый.<pre class="ipsCode prettyprint prettyprinted">
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
</pre><br>
<br>
Открываем хранилище <strong>CB_Box_Ore</strong>, удаляем имеющийся скрипт и добавляем скрипт сделанный выше. Для этого жмем кнопку <strong>Add</strong>, и в списке по названию находим скрипт.<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.29 17.10.46_009.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145356" data-ratio="1.66" style="height:auto;" width="411" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-29-17-10-46-009.png.hwi06l8j7pnze2k9aovxb5yrtf1gcd4u.png" src="https://tesall.club/applications/core/interface/js/spacer.png"> <img alt="Snap_2013.05.29 17.11.31_010.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145357" data-ratio="1.67" style="height:auto;" width="411" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-29-17-11-31-010.png.ke64rybdisqxlno1jfuc750g983zvhpt.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<br>
А вот когда заполняем их свойства, то используем разные значения!<br>
 <br>
<p style="text-align: center;"><img alt="Snap_2013.05.29 17.15.26_011.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145358" data-ratio="1.12" style="height:auto;" width="413" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-29-17-15-26-011.png.oh2fuxvabj1gps480y9t6clkz7wierd3.png" src="https://tesall.club/applications/core/interface/js/spacer.png"> <img alt="Snap_2013.05.29 17.17.38_012.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145359" data-ratio="1.12" style="height:auto;" width="415" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-29-17-17-38-012.png.2l6hqvd5b7841umiycfkg3ewnopzrt9s.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
</div><br>
<br>
Осталось "обработать" последнее хранилище <strong>CB_Box_Anim</strong>, предназначенное для хранения шкур, кожи и прочих частей животных.<br>
<br>
[<span style="font-size: large;">success]</span><br>
В этом случае скрипт ничем не отличается от предыдущих, но использует два ключевых слова (<strong>Keyword</strong>). Когда есть возможность, я всегда использую названия объектов из Creation Kit, это позволяет автоматически заполнять свойства.<pre class="ipsCode prettyprint prettyprinted">
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
</pre><br>
<br>
<p style="text-align: center;"><img alt="Snap_2013.05.29 19.10.07_013.png" class="ipsImage ipsImage_thumbnailed" data-fileid="145360" data-ratio="0.75" style="height:auto;" width="412" data-src="https://tesall.club/uploads/monthly_2013_05/snap-2013-05-29-19-10-07-013.png.c5vi6rt39kdfqjoe2zywhg01n8uap74x.png" src="https://tesall.club/applications/core/interface/js/spacer.png"></p><br>
<span style="font-size: large;">[/success]</span><br>
<br>
<span style="font-size: large;">Жмем пиктограмму <strong>Сохранить</strong>. </span><br>
<span style="font-size: large;">На этом этап создания хранилищ закончен. Половина мода сделана, ведь хранилища - основной компонент всего проекта! Остались мелочи - реализовать механизм по обслуживанию этих хранилищ, но это сделаем чуть позже...</span><br>
<br>
<span style="font-size: large;"><a href="/blog/21/entry-278-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8-ii-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D1%87%D0%B0%D1%81%D1%82%D1%8C-1/">Продолжение здесь</a>.</span>]]></description><guid isPermaLink="false">274</guid><pubDate>Wed, 29 May 2013 17:38:00 +0000</pubDate></item><item><title>&#x41A;&#x443;&#x437;&#x43D;&#x435;&#x447;&#x43D;&#x43E;&#x435; &#x434;&#x435;&#x43B;&#x43E;: &#x440;&#x430;&#x441;&#x448;&#x438;&#x440;&#x435;&#x43D;&#x43D;&#x43E;&#x435; (&#x420;&#x430;&#x437;&#x43D;&#x43E;&#x435;)</title><link>https://tesall.club/blogs/entry/132-kuznechnoe-delo-rasshirennoe-raznoe/</link><description><![CDATA[Сбылась мечта-идея, вынашиваемая около года!<br>
<br>
Очень хотелось сделать не просто улучшения колуна и кирки, а чтобы эти улучшения были логически обоснованы. В настоящий момент, разные моды, в том числе и мой, с подачи пользователя <strong>fr0d016,</strong> улучшают на точильном камне колун и кирку. Но, сами по себе эти улучшения ничего полезного не несут - незначительное увеличение урона, вот и вся польза!<br>
<br>
А теперь, встречайте!<br>
<br>
<a href="http://savepic.org/2787263.htm" rel="nofollow external noopener noreferrer" target="_blank"><img alt="2787263m.jpg" class="ipsImage" style="height:auto;" data-src="http://savepic.org/2787263m.jpg" src="https://tesall.club/applications/core/interface/js/spacer.png"></a> <a href="http://savepic.org/2810814.htm" rel="nofollow external noopener noreferrer" target="_blank"><img alt="2810814m.jpg" class="ipsImage" style="height:auto;" data-src="http://savepic.org/2810814m.jpg" src="https://tesall.club/applications/core/interface/js/spacer.png"></a><br>
<br>
Теперь каждое улучшение инструмента приводит к изменениям не только его характеристик, но и внешнего вида, а также, увеличению производительности труда! <br>
Теперь у игрока есть стимул для улучшения инструментов! Ведь чем лучше инструмент, тем больше материала получаешь за один подход!<br>
Это ощутимое подспорье для заработка на дровах у персонажей начального уровня.<br>
<br>
Еще более привлекательно, смотрятся в этом свете, улучшенные кирки. Они совместимы с DLC, и значительно облегчат жизнь строителям собственного жилья!<br>
Имея при себе разные виды инструмента, вы можете "регулировать" количество добываемого материала. Например, вам не надо столько железной руды - используйте простейший инструмент, попалась жила с редкой рудой - грех не извлечь максимальное количество.<br>
<br>
Идеалом, пиком совершенства, при улучшении кирок, является Кирка геолога! Уже не нужно носится по всему краю в поисках конкретной, но такой редкой, руды! Кирка геолога позволит вам самим выбрать какую руду добывать из этой жилы! <br>
<br>
И это не все!<br>
Все улучшенные инструменты в процессе использования изнашиваются и превращаются в более простую модель! Вам придется заново использовать точильный станок, чтобы вернуть улучшенный вариант. И чем лучше инструмент, тем быстрее он изнашивается!<br>
<br>
А воспоминания о Нериме! Славный звук ломающихся инструментов...<br>
Да-да, все улучшенные инструменты не вечны и когда-нибудь сломаются совсем! И чем "дороже" инструмент, тем короче у него "срок жизни". И тогда вы услышите звук падающего из рук инструмента...<br>
<br>
Теперь о том, как эти инструменты сделать и как ими пользоваться.<br>
Для моей реализации, стандартная функция точильного камня не годилась. Но и добавлять еще один точильный камень не было смысла. Поэтому, был придуман вариант использования точильного камня в двух режимах! Чтобы включить такой режим нужно экипировать любой инструмент (колун, кирку).  При этом название активации станка изменится на: "Точильный камень: Режим заточки". В этом режиме возможно улучшать инструменты. Параллельно доступен стандартный режим - для улучшения оружия.  Вы можете выбирать между режимами, перед активацией, перемещая курсор с абразивного круга на место для сиденья.<br>
<br>
Перед колкой дров или добычей руды, теперь необходимо выбрать и экипировать нужный инструмент. Для индикации готовности, надпись на рубочной колоде или выходе руды изменится, например на "Колун (Хорош.) готов"<br>
<br>
Вот, собственно, и все! Я доволен как паровоз.<br>
Осталось только "обкатать" пару дней, чтобы убедиться что инструменты изнашиваются и ломаются правильно и не слишком часто/редко.]]></description><guid isPermaLink="false">132</guid><pubDate>Mon, 11 Feb 2013 17:41:00 +0000</pubDate></item><item><title>&#x41A;&#x443;&#x437;&#x43D;&#x435;&#x447;&#x43D;&#x43E;&#x435; &#x434;&#x435;&#x43B;&#x43E;: &#x440;&#x430;&#x441;&#x448;&#x438;&#x440;&#x435;&#x43D;&#x43D;&#x43E;&#x435; (&#x410;&#x43B;&#x445;&#x438;&#x43C;&#x438;&#x447;&#x435;&#x441;&#x43A;&#x438;&#x439; &#x43A;&#x43E;&#x442;&#x435;&#x43B;)</title><link>https://tesall.club/blogs/entry/116-kuznechnoe-delo-rasshirennoe-alhimicheskiy-kote/</link><description><![CDATA[По моим ощущениям - я на финишной прямой! <br>
<br>
Конечно, времени потрачено много, но и сделано немало. Тройка дней потрачена на создание коллизий для новых объектов, потом столько же на попытки их использовать! Мог ли я подумать, что объекты типа Misc не годятся для "призыва на себя" статиков! После выбрасывания в мир объекта типа Misc его координаты положения сохраняются в точке появления, обычно это на высоте роста ГГ. И потом независимо куда я его потащил и где активировал,  его координаты продолжают ссылаться на ту точку и, естественно, новый объект проявляется там, а не в месте активации. Поэтому пришлось прибегнуть к другим типам объектов, в частности, экстрактор и куб, до своей установки, будут иметь тип BOOK. Но результат достигнут - где активировал, там и получил новый объект!<br>
<br>
Итак, что мы имеем. По сюжету, вся аппаратура и необходимая литература, сосредоточена в Хижине Алхимика. В дневник Алхимика сделана приписка о спрятанных вещах. Сами предметы "замаскированы" в самой хижине и рядом с ней. Точный указаний давать не буду, но найти придется следующее:<br>
1. крышка алх. котла (рис.1)<br>
2. алх. куб (рис. 2)<br>
3. алх. экстрактор( рис. 3)<br>
4. Молчащая книга (книга рецептов создания вышеперечисленного) (рис. 4)<br>
5, Чертеж топки <br>
<br>
<a href="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-60373700-1359059169.jpg.yxb6iajdqh80epturmvgzcsfn42lk31o.jpg" class="ipsAttachLink ipsAttachLink_image"><img data-fileid="2244" src="https://tesall.club/applications/core/interface/js/spacer.png" data-src="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-60373700-1359059169.thumb.jpg.lv6irnh1fa9oempug43tbks2zqxy85w7.jpg" data-ratio="63.00" width="100" class="ipsImage ipsImage_thumbnailed" alt="Крышка.jpg"></a> <a href="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-75664500-1359059197.jpg.k8jdr2apneu109fmvboh4lgytxsw657z.jpg" class="ipsAttachLink ipsAttachLink_image"><img data-fileid="2245" src="https://tesall.club/applications/core/interface/js/spacer.png" data-src="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-75664500-1359059197.thumb.jpg.2zwjeail1hp9b4tr5c0xyqs36gokdm8v.jpg" data-ratio="63.00" width="100" class="ipsImage ipsImage_thumbnailed" alt="Куб.jpg"></a> <a href="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-46614900-1359059231.jpg.8yhopkwuvjabq1c6dg9e4ix3lznmf70t.jpg" class="ipsAttachLink ipsAttachLink_image"><img data-fileid="2246" src="https://tesall.club/applications/core/interface/js/spacer.png" data-src="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-46614900-1359059231.thumb.jpg.ymi38ware19l6u4pnoks7vzjd0qf5tgh.jpg" data-ratio="63.00" width="100" class="ipsImage ipsImage_thumbnailed" alt="Давилка.jpg"></a> <a href="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-97069500-1359059258.jpg.gsjcxd9nutzb4pha76vfey1r0wlkoim3.jpg" class="ipsAttachLink ipsAttachLink_image"><img data-fileid="2247" src="https://tesall.club/applications/core/interface/js/spacer.png" data-src="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-97069500-1359059258.thumb.jpg.eu5v4clnsk607zjhbp39dtg2am1qxr8o.jpg" data-ratio="63.00" width="100" class="ipsImage ipsImage_thumbnailed" alt="Книга.jpg"></a><br>
<br>
Работать с аппаратурой, на мой взгляд, просто.<br>
<br>
Алхимический котел собирается из трех частей (топка, обычный казан и крышка на него). Раскладываете чертеж топки в нужном месте, активируете и получаете топку. При наличии в инвентаре казана, активация топки установит его, аналогичные действия и для крышки. Чтобы котел заработал нужно в топку загрузить уголь. Одного бруска угля хватает на определенное время, по истечении которого огонь тухнет и котел перестает работать. Уголь можно добавлять/закладывать/забирать в любых количествах. Котел принимает только ванильные зелья в двух экземплярах и выдает один пузырек с усиленным эффектом.<br>
<br>
Куб принимает ванильные продукты питания естественного происхождения (сырые овощи, фрукты, мясо) и ванильные вино-водочные напитки и возвращает их же, но уже в качестве ингредиентов (операция действует в обоих направлениях). В таком виде их можно использовать на обычном алхимическом столе.<br>
<br>
В экстрактор можно загрузить ванильные продукты питания не подвергавшиеся термической обработке и получить соответствующую вытяжку. Количество и ассортимент одновременной закладки не ограничен! Агрегат выдаст правильное количество каждого типа. <br>
<br>
Молчащая книга необходима при крафтинге вышеперечисленных изделий. Только при ее наличии в инвентаре будут "видны" рецепты. Рецепты не сложные, двух-трех составные.<br>
<br>
Единственный предмет существующий в одном экземпляре - чертеж топки, но его можно (и нужно) забирать после создания самой топки.<br>
Таким образом, можно обеспечить себя любым количеством алхимической аппаратуры и установить ее в любом удобном для вас месте.<br>
<br>
Обращаю ваше внимание, что магические чернила на данной аппаратуре создаваться не будут. Для них я планирую создать собственный оригинальный агрегат в рамках модуля Scrolls.<br>
<br>
Что осталось сделать:<br>
Планирую разместить статическую (нерабочую) модель котла где-нибудь в районе Университета Волшебства, просто чтобы при случае она "сообщала", где искать все эти предметы. К сожалению, на то что должно уходить ровно минуту, я потрачу пару часов. Мой старый компьютер "не тянет" рендер в редакторе, поэтому размещаю все объекты "по старинке" - в таблицах с помощью TESVSnip, что требует многократного зайти/выйти в игру.<br>
Плюс, меняю структуру папок и файлов в архиве мода, для поддержки Мастера-Установщика.<br>
<br>
После этого, скорее всего выложу то что получится, и сразу займусь следующими модулями, в первую очередь - дробилками.]]></description><guid isPermaLink="false">116</guid><pubDate>Thu, 24 Jan 2013 20:06:00 +0000</pubDate></item><item><title>&#x41A;&#x443;&#x437;&#x43D;&#x435;&#x447;&#x43D;&#x43E;&#x435; &#x434;&#x435;&#x43B;&#x43E;: &#x440;&#x430;&#x441;&#x448;&#x438;&#x440;&#x435;&#x43D;&#x43D;&#x43E;&#x435; (&#x410;&#x43B;&#x445;&#x438;&#x43C;&#x438;&#x447;&#x435;&#x441;&#x43A;&#x438;&#x439; &#x43A;&#x43E;&#x442;&#x435;&#x43B;)</title><link>https://tesall.club/blogs/entry/100-kuznechnoe-delo-rasshirennoe-alhimicheskiy-kote/</link><description><![CDATA[Итак, главный котел закончен - звуки и эффекты "прикручены", меню крафтинга прицеплено. Все работает, все нравится, но...<br>
Мне показалось это слишком просто! Захотелось большего!<br>
<br>
Почему бы не задействовать готовые зелья при создании новых на стандартном алхимическом столе? Почему бы не применять вина/бренди в алхимических опытах? Для этого нужно лишь "превратить" группу ALCH в группу INGR!<br>
<br>
Идея показалась интересной и вот этим я и занимался эти дни.<br>
<br>
Как оказалось, группы INGR(ингредиенты) и ALCH(Potion) по своей структуре практически идентичны! Отличие только в размере одного поля Data - остальное все совпадает! Даже окошки свойств для этих объектов содержат одинаковые поля, хотя я точно помню, что в первых версиях конструктора для объектов Potion невозможно было прицепить скрипт. Значит, Беседка развивает формат, стремясь к какой-то своей цели! Может быть даже планирует объединить эти группы? <br>
<br>
Для меня же, задача упростилась и свелась к дублированию записей Potion и смене принадлежности на группу INGR. Для этого, я открыл skyrim.esm в TES5Edit, выделил все записи из группы зелий и скопировал их в новый плагин. TES5Edit, в случае групповых операций, предлагает переименовывать объекты используя префиксы и суффиксы, что очень удобно! Таким образом я получил список с новыми объектами, но идентичные по свойствам группе зелий.<br>
<br>
Далее, имея новый плагин с новым списком зелий, я воспользовался программой TESVSnip. Она предоставляет низкоуровневый доступ к структуре мода, так что можно отредактировать служебные поля, недоступные изменению в других программах. Таким образом, я заменил для каждой записи заголовок ALCH на INGR, и получил список новых ингредиентов по свойствам идентичными своим "образцам"! Исключение составило поле Data, содержимое которого, скорее всего "испортилось", но я надеялся его восстановить в последствии.<br>
<br>
Следующим шагом стала загрузка этого списка в конструктор. КК при загрузке нормально обработал эти новые записи и я получил "новые ингредиенты". Единственной информацией, потерянной из-за несовпадение поля Data, стали вес и цена! Но их легко я внес прямо в конструкторе.<br>
<br>
Итак, я получил зелья, напитки и "сырые" продукты питания как ингредиенты и мог их использовать на обычном алхимическом столе! Но, предстояло решить задачу внедрения этих новых объектов в "жизнь" (в игру).<br>
<br>
Я пошел по пути "наименьшего сопротивления" и ввел в игру "алхимический куб", который при активации "конвертирует" добавляемые в него объекты ALCH в INGR и наоборот! Это значит, что если вы захотите использовать корзину яблок или готовые яды в своих алхимических опытах, вам придется конвертировать их в ингредиенты. Остатки можно конвертировать обратно в исходные объекты, а можно носить и пользоваться ими и в таком виде - эффект идентичен!<br>
<br>
Не буду описывать подробно весь процесс создания скрипта для такого "куба", это та еще песня! Ведь пришлось работать с большим количеством объектов, а это значит, с большим количеством Property и еще большим количеством однообразных блоков кода скрипта. Но упомяну основные этапы этой работы.<br>
<br>
Использовать КК для ввода большого количества Property нецелесообразно! Это займет несколько дней! Поэтому, я использовал SkyEdit для экспорта нужных записей в файл csv(таблица). Открыл этот файл редактором электронных таблиц и операциями замены текста и применением формул, сформатировал список Property и целые блоки кода с нужными Property. А потом вставил их в файл скрипта и применил Autofill. Таким образом, скрипт размером более чем в 3200 строк я изготовил чуть более за час!<br>
<br>
На данный момент, алхимический куб готов и работает. Несмотря на "тяжелый" скрипт, скоростью его работы я доволен.<br>
<br>
Из запланированного осталось сделать аппарат для получения эссенций. Да-да! Я решил сделать эту функцию отдельным агрегатом и несколько другим способом нежели котел. <br>
<br>
Так что работы продолжаются!]]></description><guid isPermaLink="false">100</guid><pubDate>Wed, 09 Jan 2013 19:59:00 +0000</pubDate></item><item><title>&#x41A;&#x443;&#x437;&#x43D;&#x435;&#x447;&#x43D;&#x43E;&#x435; &#x434;&#x435;&#x43B;&#x43E;: &#x440;&#x430;&#x441;&#x448;&#x438;&#x440;&#x435;&#x43D;&#x43D;&#x43E;&#x435; (&#x410;&#x43B;&#x445;&#x438;&#x43C;&#x438;&#x447;&#x435;&#x441;&#x43A;&#x438;&#x439; &#x43A;&#x43E;&#x442;&#x435;&#x43B;)</title><link>https://tesall.club/blogs/entry/88-kuznechnoe-delo-rasshirennoe-alhimicheskiy-kote/</link><description><![CDATA[Вот что получилось из этих запчастей... видео темновато, но так виднее световые эффекты:<br>
<br>
<a href="http://youtu.be/YEh-5fvg8v8" rel="nofollow external noopener noreferrer" target="_blank">http://youtu.be/YEh-5fvg8v8</a><br>
<br>
Решил добавить скрин...<br>
<br>
<a href="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-17490700-1356802193.jpg.914wqg3ilj5emxbrthzop76uaf2d0sky.jpg" class="ipsAttachLink ipsAttachLink_image"><img data-fileid="2201" src="https://tesall.club/applications/core/interface/js/spacer.png" data-src="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-17490700-1356802193.thumb.jpg.wpq3vuk260x9ln5yjfor4de8a7sczbgm.jpg" data-ratio="94.00" width="100" class="ipsImage ipsImage_thumbnailed" alt="ScreenShot3.jpg"></a>]]></description><guid isPermaLink="false">88</guid><pubDate>Sat, 29 Dec 2012 13:08:00 +0000</pubDate></item><item><title>&#x41A;&#x443;&#x437;&#x43D;&#x435;&#x447;&#x43D;&#x43E;&#x435; &#x434;&#x435;&#x43B;&#x43E;: &#x440;&#x430;&#x441;&#x448;&#x438;&#x440;&#x435;&#x43D;&#x43D;&#x43E;&#x435; (&#x410;&#x43B;&#x445;&#x438;&#x43C;&#x438;&#x447;&#x435;&#x441;&#x43A;&#x438;&#x439; &#x43A;&#x43E;&#x442;&#x435;&#x43B;)</title><link>https://tesall.club/blogs/entry/77-kuznechnoe-delo-rasshirennoe-alhimicheskiy-kote/</link><description><![CDATA[Наконец-то я "добрался" до своего главного мода и могу поправить некоторые "шероховатости".<br>
В данный момент, уже готовы модели для нового алхимического котла, который будет собираться из топки, казана и специальной крышки:<br>
<img alt="Snap_2012.12.18 16.39.11_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="2177" style="height:auto;" data-src="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-07644800-1356291023.png.g310k9pt4u7szije52lvoxa8w6mdrhby.png" src="https://tesall.club/applications/core/interface/js/spacer.png"> <img alt="Snap_2012.12.18 16.41.09_003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="2178" style="height:auto;" data-src="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-28982700-1356291042.png.f20u18bojvm4rgix5nqy6tkpdz9a7scl.png" src="https://tesall.club/applications/core/interface/js/spacer.png"> <img alt="Snap_2012.12.18 16.40.28_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="2179" style="height:auto;" data-src="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-94113100-1356291065.png.talr0qkj5om2ds48h1fwc9e6pyubzgn3.png" src="https://tesall.club/applications/core/interface/js/spacer.png"><br>
<br>
Квестов, как таковых, на их получение не планирую. Полагаю, будет документ описывающий возможность создать/собрать такой котел и этого достаточно. Размещение котла - произвольное, но без возможности разобрать/передвинуть.<br>
<br>
В результате должен получится вот такой агрегат:<br>
<img alt="Snap_2012.12.18 16.42.31_004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="2180" style="height:auto;" data-src="https://tesall.club/uploads/monthly_2020_04/blogentry-1669-0-35937800-1356291104.png.gd7yxehts6zjwq1k0f4a9m58p3n2clvu.png" src="https://tesall.club/applications/core/interface/js/spacer.png"><br>
<br>
Топится будет углем, соответствующие модели костров в топке будут.<br>
Планирую изменить алгоритм создания зелий и вернуться к стандартному меню крафтинга - это быстрее в реализации и привычнее пользователю, хотя теряется эффект визуализации...<br>
<br>
P.S. Блоги для меня дело новое непривычное, возможны некие "накладки" пока осваиваюсь...]]></description><guid isPermaLink="false">77</guid><pubDate>Sun, 23 Dec 2012 19:28:00 +0000</pubDate></item></channel></rss>
