Урок 37 Задача: Создание квеста с добавлением дополнительных внутриэтапных заданий. Особенности- отсутствие диалогов, использование рестрикторов. Реализация на X-Ray 1.6.01
Поставленная задача в данном уроке будет заключаться в обучении основным принципам создания среднего по сложности квеста в игре Сталкер Зов Припяти без использования каких-либо диалогов. Выдача задания будет осуществляться автоматически, в данном случае зададим ее при старте игры. Также будет показан прием добавления во внутреннею структуру основного задания нескольких дополнительных подквестов и объяснение применение рестриторов на всех поставленных этапах.
Само задание следующее: При старте ГГ на ПДА придет сообщение о необходимости установки схронов. Осущесвляется выдача квеста. Необходимо забрать утерянные рюкзаки и заложить их в трех указанных точках. После этого задание автоматически завершается. Выдача награды не предусмотрена.
Необходимые для редактирования файлы:
1. конфигурационные в (gamedata\configs\gameplay\) -character_desc_jupiter.xml -info_zaton.xml 2. конфигурационные в (gamedata\configs\misc\) - tm_jupiter.ltx - quest_items.ltx - devices.ltx - death_generic.ltx 3. конфигурационные в (gamedata\configs\text\rus\) - st_quests_zaton.xml - st_items_quest.xml - ui_st_screen.xml 4. конфигурационные в (gamedata\configs\misc\trade\) - trade_generic.ltx 5. конфигурационные в (gamedata\configs\ui\) - game_tutorials.xml 6. конфигурационные в (gamedata\configs\scripts\zaton\) - файлы логик рестрикторов 7. скриптовый в (gamedata\scripts\) - ui_si.script - bind_stalker.script - new_tasks.script - xr_effects.script 8. all.spawn. (gamedata\spawns\) - alife_zaton.ltx
На первоначальном этапе определимся с квестовыми предметами. Всего их шесть. Три будут отвечать за айтем рюкзака до его закладки. Они будут являться потомками основного родительского класса device_pda.Другие три будут определены другим классом, им будет соответствовать установленная логикаи они отвечают за рюкзаки после установки схрона. Пропишем секции их конфигов в файле quest_items.ltx (Здесь и далее буду приводить конфиг только одной секции, остальные задаются аналогично только с изменением числовых значений в имени).
Первый конфиг не содержит в себе прикрепленного файла в дополнительной секции и определяется как простой квестовый предмет, второй же содержит прикрепленный конфиг с логикой его zat_example_taynik_1.ltx Для определении секции zat_example_taynik_1 необходимо определить родительский класс default_inventory_box в файле devices.ltx
В этой секции указываются основные параметры такие как основной класс, форма, визуал. Кроме того определим его основную логику в конфигурационном файле zat_example_taynik_1.ltx
Здесь указывается активная секция это ph_idle@nothing, а также ее содержание. Тайник после установки можно использовать, т.е. возможно его наполнение различными предметами, также при наведении на него будет активна надпись из секции st_taynik_check_descr
Зарегистрируем конфиги первой секции предмета тайник zat_example_taynik_..._item. В файле death_generic.ltx пропишем код
Отметим особенности: Активная секция sr_idle@start переход на вторую происходит по достижению трех условий - наличие инфопоршня активности второго этапа основного задания (zat_test_quest_rest_main_come) - актор находиться в зоне действия рестриктора - наличие в его инвентаре zat_example_taynik_1_item При выполнении всех этих условий выполняется работа рестриктора определяемая в туториале zat_test_quest_1_tutor При получении инфопоршня zat_test_quest_restr_1 происходит переход в третью нулевую секцию логики рестриктора sr_idle@nil При выхода актора из зоны рестриктора его работа прекращается и логика переключается во второе состояние sr_idle@tutorial из которого она может снова перейти в первое или в третье.
Объявим в файле game_tutorials.xml туторы выполняемые в работе рестрикторов
Основные параметры это функция скрипта обработчика действия xr_effects.zat_test_quest_1 и активная надпись из секции zat_test_quest_tips В файле xr_effects.scripts определим функции
Код
function zat_test_quest_1(actor, npc) if xr_conditions.actor_in_zone(actor, npc, {"zat_test_quest_restrictor_1"}) then remove_item(actor, npc, {"zat_example_taynik_1_item"}) alife():create("zat_example_taynik_1",vector():set(210.996811,15.980440,480.381104),1323235,6) db.actor:give_info_portion("zat_test_quest_restr_1") end end
Опишем ее: - если выполнено условие нахождение актора в зоне рестриктора zat_test_quest_restrictor_1 то происходит удаление из инвентаря ГГ айтема первого конфига тайника zat_example_taynik_1_item, создается по заданным координатам второй zat_example_taynik_1 и выдается инфопоршень zat_test_quest_restr_1
Выдача задания будет происходит при старте ГГ одновременно с квестами основного сюжета. Для этого добавим инфопоршень выдачи и сам квест в секцию логики [sr_idle] оригинального рестриктор zat_b101_logic.ltx
Выдача подквестов будет осуществлять в логике другого рестриктора zat_restr_logic_main.ltx Его секция прописывается в all.spawn по аналогии с предыдущими. Сама логика имеет следующий вид:
Особенности: - При старте задания необходимо посетить зону основного рестриктора, устанавливается тагет на zat_restr_main_id. В момент посещения активируются подквесты, выдается инфопоршень zat_test_quest_rest_main_come, задание обновляется, его тагет уходит в nill. после взятия всех квестовых айтемов- необходимо завершение всех трех подквестов для получения инфопоршня zat_test_quest_complete
Скриптовая функция которая отвечает за создание трех основных квестовых предметов и выдачу завершающего основное задание инфопоршня прописывается в файл new_tasks.script, и объявляется в апдейте актора файла bind_stalker.script
Код
new_tasks.task_spec()
сама функция
Код
--/Квест Example function task_spec() local level_name=level.name() if level_name=="zaton" then if has_alife_info("zat_test_quest_begin") and not has_alife_info("zat_test_quest_spawn_items") then alife():create("zat_example_taynik_1_item",vector():set(248.498016,14.915686,484.567932),1391296,6) alife():create("zat_example_taynik_2_item",vector():set(247.778076,14.872326,484.085999),1390040,6) alife():create("zat_example_taynik_3_item",vector():set(247.055069,14.796996,483.116058),1388814,6) news_manager.send_tip(db.actor, "Чтобы выполнить тестовое задание необходимо установить все тайники. Подбери рюкзаки оставленные сталкерами", nil, nil, 14000) db.actor:give_info_portion("zat_test_quest_spawn_items") end if has_alife_info("zat_test_quest_restr_1") and has_alife_info("zat_test_quest_restr_2") and has_alife_info("zat_test_quest_restr_3") and not has_alife_info("zat_test_quest_complete") then db.actor:give_info_portion("zat_test_quest_complete") end end end
Описание: При нахождении ГГ на локации Затон и наличии инфопоршня zat_test_quest_begin создаются квестовые айтемы и отправляется мессадж на пда ГГ. При завершении всех трех подквестов выдается инфопоршень zat_test_quest_complete завершения основного.
Все инфопоршни необходимые нам пропишем в файле info_zaton.xml
Урок 38 Задача: Создание примитивного квеста на поиск двух различных предметов, с выдачей ачивмента. Особенности- пысовский способ его написания, добавление по завершении простого достижения (ачивмента). Реализация на X-Ray 1.6.01
Поставленная в данном уроке задача схожа с той что была в уроке 33 данной темы. Основным отличием от него будет являться способ реализации заданий такого типа. Если ранее основным обработчиком на обновление этапов квеста служило использование функций actor_has_item(...), то сейчас последовательное обновление будет осуществляться через выдачу соответствующих инфопорций. Будет подробно рассмотрена структура диалога в котором будет происходить их выдача. Также среди особенностей отметим добавление по завершении задания специального достижения.
Необходимые для редактирования файлы:
1. конфигурационные в (gamedata\configs\gameplay\) -character_desc_zaton.xml -dialogs_zaton.xml -info_zaton.xml -character_desc_general.xml (необязательно) 2. конфигурационные в (gamedata\configs\misc\) - tm_zaton.ltx - achievements.ltx 3. конфигурационные в (gamedata\configs\text\rus\) - st_dialogs_zaton.xml - st_quests_zaton.xml - st_achievement.xml - ui_st_screen.xml 4. скриптовые в (gamedata\scripts\) - dialogs_zaton.script - xr_statistic.script
В файле achievements.ltx в самом низу добавим следующую секцию:
Код
[sich_helper] icon = ui_inGame2_Iskatel hint = st_sp_achievement_22_hint name = st_sp_achievement_22_name desc = st_sp_achievement_22_descr functor = xr_statistic.sich_helper_functor
-[sich_helper]- уникальное имя секции ачивмента. его же необходимо зарегистрировать в начале файла в списке всех достижений. -icon- имя секции иконки достижения. берется из файла ui_actor_achivments.xml (\configs\ui\textures_descr\) в свою очередь сама иконка прописывается в ui_actor_achivments.dds (\textures\ui\) В данном случае возьмем стандартную иконку из другого достижения. - hint- описание в ПДА при наведении на ачивку. - name- название (имя) достижения. - desc- описание самого достижения. - functor- имя функции из xr_statistic.script отвечающей за срабатывания условий на получение достижения и собственно его выдача.
Описание русской транскрипции добавим в файл st_achievement.xml
Код
<string id="st_sp_achievement_22_name"> <text>Помошник торговца</text> </string> <string id="st_sp_achievement_22_hint"> <text>Бандиты стали лучше к Вам относится.</text> </string> <string id="st_sp_achievement_22_descr"> <text>Вы нашли и принесли артефакты скряге Сычу. Тем самым Вы заслужили уважение бандитов.</text> </string>
В xr_statistic.script добавляем исполняемую функцию:
Код
function sich_helper_functor() if not has_alife_info("sich_helper_achievement_gained") then if has_alife_info("zat_geonezis_example_quest_complete") then news_manager.send_tip(db.actor, "st_ach_sich_helper", nil, "seeker", nil, nil) xr_effects.inc_faction_goodwill_to_actor(db.actor, nil, {"bandit", 100}) db.actor:give_info_portion("sich_helper_achievement_gained") end end return has_alife_info("sich_helper_achievement_gained") end
более подробно разберем работу данной функции: - происходит проверка, а не было ли уже получено данное достижение (отсутствие инфопоршня sich_helper_achievement_gained) - срабатывание условия выдачи достижения в данном случае условие только одно- это получение инфопоршня zat_geonezis_example_quest_complete (который будет выдаваться по завершению квеста) - далее происходит отправка на пда ГГ сообщения с текстом что достижение было получено. - вызывается обработчик функций на выполнение "бонуса" или "антибонуса" достижения. (в данном случае это только увеличение репутации у сталкеров) - выдается инфопоршень получения достижения (в рассматриваемом примере это sich_helper_achievement_gained)
Так, теперь приступим к процессу формирования задания.
Опишем подробно только второй диалог, который будет активен после взятия задания. Первый, на получения квеста можно будет посмотреть в файле dialogs_zaton.xml имя диалога- jup_azot_sborkiquest_init_dialog Соответственно русскую транскрипцию диалогов и квестов также не будем приводить. Ее можно будет увидеть в файлах st_quests_zaton.xml и st_dialogs_zaton.xml
начнем по-порядку разбирать особенности этого диалога:
- обязательными условиями его активации будет наличие инфопоршня выдачи задания jup_azot_quest_sborki_give, а также функции прекондишина actor_has_first_or_second_grenader_item - будет происходить выбор четырех последующих фраз для генерации в зависимости от наличия у ГГ квестовых предметов. - четвертая, имеющая нулевое значение отрицания- будет активна при любых условиях. - первая и вторая- когда у ГГ есть один из двух необходимых предметов активны при наличии выполнения соответствующих прекондишинов if_actor_has_zat_grenader_stalker_flash и if_actor_has_zat_grenader_stalker_gran_instrument. при этом проиходит передача этого предмета НПС функции (transfer_....),получении от НПС награды на каждом этапе и выдача инфопорции на обновление задания. первый и второй этапы- взаимоисключающие. одновременно они не могут быть активны. - третья- когда у ГГ есть оба необходимых предмета. происходит их передача и завершение квеста.
добавим все скриптовые функции в файл dialogs_zaton.script
Код
function jup_azot_quest_sborki_give() task_manager.get_task_manager():give_task("geonezis_azot_quest_sborki_give") end
function zat_b33_relocate_money_to_azot(first_speaker, second_speaker) dialogs.relocate_money_from_actor(first_speaker, second_speaker, 500) end
function actor_has_first_or_second_grenader_item(first_speaker, second_speaker) return first_speaker:object("af_baloon") ~= nil or first_speaker:object("af_gold_fish") ~= nil end
function actor_has_first_and_second_grenader_item(first_speaker, second_speaker) return first_speaker:object("af_baloon") ~= nil and first_speaker:object("af_gold_fish") ~= nil end
function if_actor_has_zat_grenader_stalker_flash(first_speaker, second_speaker) return first_speaker:object("af_baloon") ~= nil and first_speaker:object("af_gold_fish") == nil end
function if_actor_has_zat_grenader_stalker_gran_instrument(first_speaker, second_speaker) return first_speaker:object("af_gold_fish") ~= nil and first_speaker:object("af_baloon") == nil end
function transfer_zat_grenader_stalker_flash(first_speaker, second_speaker) dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, "af_baloon") end
function transfer_zat_grenader_stalker_gran_instrument(first_speaker, second_speaker) dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, "af_gold_fish") end
Тайтлы и дескрипшины задания будут обновляться после второго разговора с НПС, при получении соответствующих инфопоршней. То есть основное отличие от задания из урока № 33 это его обновление после передачи предметов, а не при их получении и наличии в инвентаре ГГ. По завершении задания будет выдаваться инфопоршень zat_geonezis_example_quest_complete необходимый для выдачи ачивмента, который в свою очередь будет теперь необходим для разблокировки следующего смыслового диалога zat_b30_owl_stalker_trader_buy_info
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Урок 39 Задача: Создание квеста с добавлением дополнительных внутриэтапных заданий. Особенности- отсутствие диалогов, использование физических объектов класса physic_destroyable_object в качестве квестовых предметов. Реализация на X-Ray 1.6.01
В данном уроке речь пойдет о реализации задания подобного тому что было рассмотрено в уроке. В отличие от него теперь добавление внутриэтапных заданий будет завязано не на применение рестрикторов, а на использование физических объектов специального класса. Задание этих объектов будет осуществлено как в моде SGM (автор GeJorge) Также особенностью будет добавление класса метки объекта (также по аналогии с SGM) что позволит отказаться от применения рестрикторов в определенных моментах. Выдача задания осуществляется при старте игры. Диалогов нет.
Само задание: ГГ на ПДА приходит сообщение о необходимости обыска трех точек с установленными там объектами. Необходимо выяснить что это за объекты и вернуться в стартовую точку. После этого задание автоматически завершается. Выдача награды не предусмотрена.
Необходимые для редактирования файлы:
1. конфигурационные в (gamedata\configs\gameplay\) -info_zaton.xml 2. конфигурационные в (gamedata\configs\misc\) - tm_zaton.ltx - quest_items.ltx 3. конфигурационные в (gamedata\configs\text\rus\) - st_quests_zaton.xml - ui_st_screen.xml 4. конфигурационные в (gamedata\configs\models\) - dynamic_objects.ltx 5. конфигурационные в (gamedata\configs\scripts\zaton\) - файлы логик рестрикторов и объектов 6. скриптовый в (gamedata\scripts\) - bind_stalker.script - new_tasks.script 7. all.spawn. (gamedata\spawns\) - alife_zaton.ltx 8. физическая модель в (gamedata\meshes\dynamics\box\) - konteyner.ogf
Некоторые этапы добавления изменений будут приведены с сокращением, ввиду их схожести с аналогичными в других уроках. Акцент будет сделан на впервые вносимые изменения и аспекты.
Изначально создадим новые классы квестовых предметов.
Класс родительского предмета метка будет соответствовать стандартному квестовому device_pda, но будет иметь визуал нулевого значения. поэтому при написания квестов и установки тагета в них можно будет воспользоваться именно этим приемом, а не добавлением цели на айдишнике отдельного рестриктора. пропишем в quest_items.ltx секцию
сами добавленные метки имеют следующие секции. как видим они являются потомками родительского класса quest_spot. также указывается айди метки по которому будет прописываться таргет story_id.
Новый физический объект используемый нами в квесте объявим в файле dynamic_objects.ltx . Он будет иметь свой уникальный класс наследуемый от основного physic_destroyable_object Секции конфигов будут следующими:
- активная секция логики ph_idle@retranslator_take - первоначальная активная надпись считывается из секции st_take_the_quest_item - при юзании предмета произойдет выдача инфопорции zat_test_quest_item_1_used и переход во вторую секцию логики ph_idle@retranslator_heavy - при этом изменяется активная надпись на st_quest_item_is_used - при получении инфопорции zat_test_quest_complete логика обнуляется.
Теперь необходимо создать основной рестриктор на обход которого будет завязана основа квеста. Сам рестриктор создаем в all.spawn по аналоги с предыдущими уроками. Логика рестриктора из файла zat_restr_logic_main.ltx имеет следующий вид:
- имеет три секции первая активная, во вторую переходит по совокупности полученных условий при обновлении квеста. - при этом происходит выдача трех подзаданий. - для перехода в нулевую секцию необходимо завершение задания.
Выдача задания будет происходит при старте ГГ одновременно с квестами основного сюжета. Для этого добавим инфопоршень выдачи и сам квест в секцию логики [sr_idle] оригинального рестриктор zat_b101_logic.ltx
Особенности: - При старте задания необходимо посетить зону основного рестриктора, устанавливается тагет на zat_restr_main_id. В момент посещения активируются подквесты, выдается инфопоршень zat_test_quest_rest_main_come, задание обновляется, его тагет уходит в nil. после юзания всех квестовых айтемов созданных в начале объектов проиходит завершение всех трех подквестов, основной квест обновляется снова. чтобы завершить его необходимо снова посетить точку основного рестриктора.
Скриптовая функция которая отвечает за создание трех основных квестовых предметов и выдачу завершающего основное задание инфопоршня прописывается в файл new_tasks.script, и объявляется в апдейте актора файла bind_stalker.script
Код
new_tasks.task_spec()
сама функция
Код
--/Квест Example function task_spec() local level_name=level.name() if level_name=="zaton" then if has_alife_info("zat_test_quest_begin") and not has_alife_info("zat_test_quest_spawn_items") then alife():create("zat_test_stalker_container_1_spot",vector():set(210.996811,15.980440,480.381104),1323235,6) alife():create("zat_test_stalker_container_2_spot",vector():set(267.914307,17.374102,483.001709),1424536,6) alife():create("zat_test_stalker_container_3_spot",vector():set(305.260254,18.979174,532.515625),1484018,287) news_manager.send_tip(db.actor, "Для начала займи указанную точку", nil, nil, 14000) db.actor:give_info_portion("zat_test_quest_spawn_items") end if has_alife_info("zat_test_quest_rest_main_come") and not has_alife_info("zat_test_quest_spawn_items_2") then alife():create("zat_test_stalker_container_1",vector():set(210.996811,15.980440,480.381104),1323235,6) alife():create("zat_test_stalker_container_2",vector():set(267.914307,17.374102,483.001709),1424536,6) alife():create("zat_test_stalker_container_3",vector():set(305.260254,18.979174,532.515625),1484018,287) news_manager.send_tip(db.actor, "Чтобы выполнить тестовое задание необходимо исследовать все контейнеры.", nil, nil, 14000) db.actor:give_info_portion("zat_test_quest_spawn_items_2") end if has_alife_info("zat_test_quest_item_1_used") and has_alife_info("zat_test_quest_item_2_used") and has_alife_info("zat_test_quest_item_3_used") and not has_alife_info("zat_test_quest_all_item_used") then db.actor:give_info_portion("zat_test_quest_all_item_used") end end end
описание: - первоначально по выдаче задания происходит создания меток дополнительных подквестов. - при выдачи самих подквестов происходит создание самих предметов необходимых для их выполнения. - при наличии трех инфопорций полученных от юзания всех предметов выдается общий инфопоршень на обновление основного задания.
Все инфопоршни необходимые нам пропишем в файле info_zaton.xml Всю текстовую транскрипцию определим в xml-файлах. На этом урок завершен.
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Урок 40 Задача: Создание квеста с добавлением дополнительных внутриэтапных заданий. Особенности- отсутствие диалогов, добавление тайников в качестве квестовых предметов. Реализация на X-Ray 1.6.01
Данный урок практически полностью аналогичен тому что был изложен ранее. Его основной отличительной особенностью от предыдущего является только то что выполнение внутренних подквестов будет завязано на исследовании тайников (взятие квестовых предметов из них). Будет показан принцип добавление в игру тайников определенных отдельным классом и их заполнение различными предметами. Поэтому урок будет приведен по максимуму сокращенно, с указанием только основных особенностей и списком всех используемых файлов. Полностью просмотреть вносимые изменения вы сможете скачав пример с отработанным заданием или же изучив материал из урока 44.
1. конфигурационные в (gamedata\configs\gameplay\) -info_zaton.xml 2. конфигурационные в (gamedata\configs\misc\) - tm_zaton.ltx - quest_items.ltx 3. конфигурационные в (gamedata\configs\text\rus\) - st_quests_zaton.xml
4. конфигурационные в (gamedata\configs\scripts\zaton\) - файлы логик рестрикторов и объектов 6. скриптовый в (gamedata\scripts\) - bind_stalker.script - new_tasks.script 7. all.spawn. (gamedata\spawns\) - alife_zaton.ltx
Определим в файле quest_items.ltx две родительские секции для создания предмета нового класса "квестовый рюкзак".
В дальнейшем нами будет использоваться переопределенный класс quest_rukzak с определенным визуалом dynamics\devices\dev_rukzak\dev_rukzak.ogf. В классе default_inventory_box определяются другие основные параметры.
Вся остальная структура добавляемых изменений аналогично указанным ранее. По другом задается только основной квестовый скрипт в файле new_tasks.script
Код
--/Квест Example function task_spec() local level_name=level.name() if level_name=="zaton" then if has_alife_info("zat_test_quest_begin") and not has_alife_info("zat_test_quest_spawn_items") then alife():create("zat_test_stalker_container_1_spot",vector():set(210.996811,15.980440,480.381104),1323235,6) alife():create("zat_test_stalker_container_2_spot",vector():set(267.914307,17.374102,483.001709),1424536,6) alife():create("zat_test_stalker_container_3_spot",vector():set(305.260254,18.979174,532.515625),1484018,287) news_manager.send_tip(db.actor, "Для начала займи указанную точку", nil, nil, 14000) db.actor:give_info_portion("zat_test_quest_spawn_items") end if has_alife_info("zat_test_quest_rest_main_come") and not has_alife_info("zat_test_quest_spawn_items_2") then local x1_cell=alife():create("quest_rukzak",vector():set(210.996811,15.980440,480.381104),1323235,6) parse_table=utils.parse_spawns("zat_test_quest_item_info_1,af_medusa,wpn_ak74,stalker_outfit,wpn_pm") for k,v in pairs(parse_table) do for i=1,v.prob do alife():create(v.section,vector(),0,0,x1_cell.id) end end local x2_cell=alife():create("quest_rukzak",vector():set(267.914307,17.374102,483.001709),1424536,6) parse_table=utils.parse_spawns("zat_test_quest_item_info_2,af_ice,wpn_abakan,dolg_outfit,wpn_pm") for k,v in pairs(parse_table) do for i=1,v.prob do alife():create(v.section,vector(),0,0,x2_cell.id) end end local x3_cell=alife():create("quest_rukzak",vector():set(305.260254,18.979174,532.515625),1484018,287) parse_table=utils.parse_spawns("zat_test_quest_item_info_3,af_fire,wpn_lr300,svoboda_light_outfit,wpn_pm") for k,v in pairs(parse_table) do for i=1,v.prob do alife():create(v.section,vector(),0,0,x3_cell.id) end end news_manager.send_tip(db.actor, "Чтобы выполнить тестовое задание необходимо исследовать все тайники.", nil, nil, 14000) db.actor:give_info_portion("zat_test_quest_spawn_items_2") end if (not has_alife_info("zat_test_quest_item_1_used")) and has_alife_info("zat_test_quest_spawn_items_2") and db.actor:object("zat_test_quest_item_info_1") then db.actor:give_info_portion("zat_test_quest_item_1_used") end if (not has_alife_info("zat_test_quest_item_2_used")) and has_alife_info("zat_test_quest_spawn_items_2") and db.actor:object("zat_test_quest_item_info_2") then db.actor:give_info_portion("zat_test_quest_item_2_used") end if (not has_alife_info("zat_test_quest_item_3_used")) and has_alife_info("zat_test_quest_spawn_items_2") and db.actor:object("zat_test_quest_item_info_3") then db.actor:give_info_portion("zat_test_quest_item_3_used") end if has_alife_info("zat_test_quest_item_1_used") and has_alife_info("zat_test_quest_item_2_used") and has_alife_info("zat_test_quest_item_3_used") and not has_alife_info("zat_test_quest_all_item_used") then db.actor:give_info_portion("zat_test_quest_all_item_used") end end end
Особенности: - при старте задания создаются квестовые метки - при достижении позиции актора внутри основного рестриктора происходит создание трех квестовых тайников quest_rukzak по заданным координатам и их заполнение различными предметами. - при обыски тайника и взятии ГГ квестового предмета из него происходит выдача инфопоршеней на завершение внутренних подзаданий. - после обыска всех трех тайников выдается основной инфопоршень на обновление основного задания.
Справочный материал Тема: Функции некоторых скриптов и их применение.
ФУНКЦИИ, КОТОРЫЕ РАЗРЕШЕНО ВЫЗЫВАТЬ ИЗ ДРУГИХ СКРИПТОВ Активация схем производится с помощью функций:
function gulag_activate(npc, ini, section, gulag_name, death, combat, actor_dialogs, trade, hit) Предназначение: активирует заданную схему, используется схемой гулаг. Тип скрипта определяется автоматически по имени секции. Здесь: npc - персонаж, для которого будет активирована схема ini - его customdata section - имя секции, которая должна быть активирована gulag_name - имя гулага, которое будет добавлено спереди к именам путей death, combat, actor_dialogs, trade, hit - имена секций, задающих поведение при смерти и в бою
function assign_storage_and_bind(npc, ini, scheme, section) Предназначение: Вызывает функцию add_to_binder схемы, а также создает (если его еще нет) и возвращает ссылку на storage для схемы. Примечание: в storage при этом могут оставаться старые данные, схема должна очистить его самостоятельно.
function subscribe_action_for_events(npc, storage, new_action) Предназначение: Регистрирует класс для получения нотификаций о таких событиях как сброс схемы, сохранение и т.д. Класс реализует соответствующие функции (reset_scheme() и т.д.), которые будут вызываться из xr_logic в нужные моменты.
function pick_section_from_condlist(actor, npc, condlist) Предназначение: Проверяет условия condlist, и если они успешны - ставит указанные infoportions и возвращает текст. Если условия не выполняются - возвращает nil.
function try_switch_to_another_section(npc, st, actor) Предназчанение: Используя настройки xr_logic из storage персонажа, пытается переключить его на другую схему, если хоть одно из условий переключения сработало. Обычно вызывается из метода update класса персонажа.
function is_active(npc, st) Предназначение: Вызывается из evaluator-а (или в самом начале update у предметов и монстров) для проверки, что данная схема сейчас активна (схема определяется по данным в storage).
function cfg_get_switch_conditions(ini, section, npc) Предназначение: Считывает все возможные условия переключения схем.
function parse_condlist(npc, section, field, src) Предназначение: Распарсивает условия вида: {+infop1} section1 %-infop2%, {+infop3 -infop4} section2 ... в таблицу. Параметры section и field используются только в сообщениях об ошибках. Если строка src считана не из файла, а передается в эту функцию гулагом, то нужно задать следующие параметры: --]] -- section = "[[[gulag_tasks.script]]]" -- field = "[[[gulag_name=имя_гулага]]]" --[[
-- ПРИВАТНЫЕ ФУНКЦИИ ----------------------------------------------------------------------------------------------------
function activate_by_section(npc, ini, section, loading) Предназначение: Активирует указанную секцию. Если в данный момент какая-либо секция уже активирована, сообщает об ошибке.
function switch_to_section(npc, st, section) Предназначение: Выполняет переключение с одной секции на другую, если новая секция не nil. Если же она nil, остается активной старая секция.
function abort_syntax_error_in_cond(npc, section, field) Предназначение: Сообщает о синтаксической ошибке в условиях переключения схем секции section и поля field, и останавливает игру.
function parse_infop(rslt, str) Предназначение: Распарсивает условия вида " +infop1 =func -infop2 " и т.д. (все не перечислены) в таблицу.
function cfg_get_number_and_condlist(ini, section, field, npc) function cfg_get_string_and_condlist(ini, section, field, npc) function cfg_get_condlist(ini, section, field, npc) Предназначение: Считывает из customdata различные условия переключения схем.
function add_condition(lst, at, cond) Предназначение: Добавляет условие в список условий переключения схем.
function cfg_get_overrides(ini, section, npc) Предназначение: Считывает настройки для схем общего поведения.
function generic_scheme_overrides(npc) Предназначение: Возвращает ссылку на настройки схем общего поведения, актуальные для работающей в данный момент схемы, либо nil, если ни одна из секций не активна, либо настройки не заданы.
--]]
--[[ -- Предназначение: -- вызывается при включении набора скриптов через секцию logic у персонажа. Если в секции logic присутствует только -- поле cfg, использует конфигурационный файл, заданный в этом поле, и возвращает новый ini file. -- Здесь: -- npc - персонаж, для которого будет активирована схема -- ini - его customdata -- stype - тип скрипта. Поскольку имя секции все еще неизвестно, его нужно задавать явно. Допустимые значения -- перечислены в файле modules.script. -- section - имя секции logic -- gulag_name - имя гулага, если скрипт включается гулагом, а не биндером --]]
Справочный материал Тема: Описание анимаций используемых в сталкере.
wait - стоит ни чего не делает wait_na - то же самое что и wait, стоит ни чего не делает guard - стоит, держит ствол в руках, медленно смотрит по сторонам.Короче анимка охраника guard_chasovoy - анимка часового, делает много чего.разминается, чешит задницу,ствол на плечо руку ко лбу и смотрит по сторонам и еще что то было. guard_na - тоже самое что и guard guard_fire - прикольная анимка, стоит ствол на плече, но время от времени отстрелевает всех подрят. Я эту анимку сталкеру на скадовске поставил. Пока дошел до скадовска этот ублюдок на базе уже троих положил. threat - стоит прицелевшись threat_danger - немного пригнувшись быстро смотрит по сторонам, потом прицеливается и анимка проигровается сначала. give_orders - стоит прицелевшись, но после того как к нему подойдет ГГ начинает проигрывать анимку wait threat_heli - тоже самое что и threat hide - на одном колене прицеливается, смотрит по сторонам, опускет оружие, опять смотрит по сторонам и потом все сначала. press - стоит и по направлению своего взгляда показывает пальцем ward - Стоит, руки за спину, медленно смотрит по сторонам fold_arms - стоит сложа руки search - присел что-то посмотрел, привстал чуть нагнулся и что-то высматривает stoop_no_weap - чуть наклонившись, руки ставит на ноги чуть выше коленок что то высматривает в низу salut - стоит по стоике смирно, потом отдает честь и опять в стоику salut_free - просто расслабившись стоит, отдает честь и опять стоит prisoner - анимка заложника. hide_no_wpn - присел на одно колено, облокотился на руки, и что-то высматривает типо следопыта(наверное это анимка глухоря) hello - стоит мохает рукой hello_wpn - ствол на плече, мохает рукой refuse - стоит пожимает плечами,мохает головой claim - стоит прицелевшись, потом мохает рукой, типо иди сюда backoff - стоит и показует что бы гг убрал ствол punch - анимка удара кулаком в голову binocular - стоит смотрит в биноколь
Очень полезная информация для создателей модов: Предоставляю вам список анимаций, которые использовались ПЫСами в анимпоинтах: zat_b14_give_artefact_idle - стоя рулим( Я так понял что этот анимпоинт связан с баржей на затоне) zat_b14_give_artefact_act - стоя поворачиваем руль zat_b38_stalker_break_lock - чиним замок zat_b38_stalker_turn_on_lift - открываем лифт и спускаемся вниз по лестнице zat_b38_stalker_jump_tonnel - прыгаем в люк zat_b38_stalker_alert - идет как бандит, а потом оглядывается и вскидывает оружие zat_b20_noah_jump - отходим и прыгаем с разбега pri_a17_ice_climb - вверх по лестнице pri_a17_fall_down - попали в человека и он упал pri_a17_pray_in - идет на тебя и по моему посылает pri_a17_pray- идет на тебя и по моему посылает (много раз) zat_b22_medic_turn_idle - чистит стол. Хотя не особо понятно что он делает (видимо эту анимацию исполняет медик на Скадовске) zat_b22_medic_turn_out - отворачиваемся от стола zat_b22_medic_suicide - суицид zat_b3_tech_drunk - спит (Кардан) zat_b3_tech_drink - выпиваем водочки (Кардан) zat_b3_tech_idle - сидим на стуле (Кардан) zat_b3_tech_surprise - заснул сидя (Кардан) give_orders - тоже самое что и анимка give_orders - оглядываемся по сторонам и посылаем на два стороны чуваков bloodsucker_search - оглядываемся по сторонам bloodsucker_panic - от бедра стреляем jup_b10_drunk_ravings - спим сидя pas_b400_vano_probe - тыкаем в детекторе что то pri_a28_kirillov_sit_high_radio - сидим высоко и ковыряемся в радио pri_a18_inspert_monolit_actor - идем и оглядываем все вокруг pri_a20_colonel_radio - стоим оперевшись об стол и смотря в комп/радио pri_a21_sentry_madness - стоим и отстреливаемся по кругу pri_a21_sentry_madness_suicide - отстреливаемся и потом суицид pri_a28_army_trance_out - Совсем не понятно zat_b106_wounded_idle - лежит на кровати (Краб) zat_b38_cop_dead - Прикидываемся трупом jup_b15_zulus_sit_drink - сидим в позе Зулуса и пьем водку jup_b15_zulus_sit_idle - сидим в позе Зулуса jup_b15_zulus_sit_out - слазим со стола jup_b219_actor_one - оружие на плечо и смотрим jup_b219_azot_all - стоим бьем кулаком по столу, указываем в стол zat_b100_heli_2_serch - сидим и тыкаем в ПДА пальцем jup_b217_guide_stand - оглядываемся потихоньку и идем к точке jup_b217_nitro_stand - стоим у стены боком jup_b41_novikov_stand - руки в кармане и стоим pri_b305_actor - идем прямо потом крадемся вправо наставляем ногу на ящик и пушкой смотрим туда jup_a9_cam2_actor - чуть чуть наклонились и рассматриваем что то pri_a25_psy_medic_idle - пси раненый pri_a25_psy_medic_out - выход из пси ранения
Для того чтобы НПС занял анимпоинт и принялся проигрывать нужную анимацию, ему нужно задать логику: [logic@bar_stalker_sleep] active = animpoint@animpoint_stalker_sleep
Трехмерная графика и анимация, открывающие двери в захватывающий мир виртуальной реальности, занимают особое место среди компьютерных технологий, а пакет Maya справедливо считается одним из лучших (и, увы, одним из самых сложных в изучении) в области трехмерного моделирования, анимации и рендеринга. Он обладает всеми необходимыми средствами для создания игровых миров и анимационных роликов и потому используется рядом разработчиков компьютерных игр и незаменим в компьютерной мультипликации и художественной анимации. Более того, Maya позволяет внедрять фотореалистичные элементы в обычные фильмы, открывая дорогу применению разнообразных спецэффектов, которые невозможно, слишком дорого или чересчур опасно воспроизвести в действительности. Созданная в среде Maya трехмерная анимация часто используется при разработке демонстрируемых по телевидению рекламных роликов, телевизионных заставок и клипов. Дизайнерам данный пакет предоставляет средства фотореалистической визуализации для анализа разрабатываемого проекта, проведения презентаций и создания маркетинговых материалов. Maya также может использоваться в судебной медицине, когда возникает необходимость продемонстрировать воссозданную последовательность происходивших событий, что актуально, например, в отношении автомобильных аварий. Также Maya находит применение в архитектуре и промышленности для визуального представления самых разных моделей, начиная от обычных флаконов и заканчивая автомобилями и самолетами. Пакет Maya достаточно сложен в освоении и имеет огромное число настроек, инструментов и меню — их значительно больше, чем в любом из конкурирующих пакетов, например в 3D Studio MAX. Даже простое перечисление инструментария займет немало времени и вместе с тем не даст ни малейшего представления о нюансах работы. Поэтому знакомиться с возможностями пакета мы будем последовательно и на конкретных примерах, а на первом уроке просто попытаемся немного освоиться с интерфейсом программы, экспериментируя с простыми геометрическими объектами. Теоретические аспекты работы
Для работы в программе предназначена стандартное для Windows-программ главное командное меню и целая серия панелей инструментов, которые располагаются со всех четырех сторон рабочего окна и занимающие большую часть рабочего пространства (рис. 1). С помощью панелей инструментов обеспечивается быстрый доступ к любому элементу интерфейса, к инструментам панелей, а также к любым командам главного меню.
Рис. 1. Фрагмент окна Maya при первом запуске
Командное меню расположено в верхней части окна программы и является динамическим, так как часть входящих в него команд изменяются при смене режима работы — первые 6 пунктов меню: File (Файл), Edit (Редактирование), Modify (Изменение), Create (Создание), Display (Отображение) и Window (Окно) одинаковы для всех режимов. Всего предусмотрено 4 режима работы: Animation (Анимация), Modeling (Моделирование), Dynamics (Динамика) и Rendering (Рендеринг). Нужный режим выбирается из раскрывающегося списка, расположенного в левой верхней части окна программы (рис. 2) — сегодня все эксперименты мы будем проводить в режиме Rendering. Переключать режимы можно и с помощью функциональных клавиш F2, F3, F4 и F5. При необходимости некоторые из пунктов меню могут быть превращены в плавающие панели, что позволяет иметь под рукой наиболее часто используемые наборы инструментов. Пункты меню, для которых данное преобразование возможно, отмечены в верхней части двойной линией — для превращения пункта меню в панель достаточно щелкнуть на этой двойной линии (рис. 3).
Рис. 2. Установка режима работы
Рис. 3. Пример пункта меню, которое может быть превращено в плавающую панель (слева), и соответствующая ему панель (справа)
Наиболее часто используемые панели и палитры загружаются при начальном запуске программы — они отмечены на рис. 4. Прямо под командным меню находится строка состояния (Status Line), в самом начале которой как раз и располагается выше рассмотренный список смены режима. В ней размещаются большинство переключателей и кнопок, необходимых для управления объектами и запуска часто применяемых функций. Ниже расположена панель Shelf (Полка) с самыми разнообразными вкладками — на ней находятся инструменты для создания объектов и их деформации, команды управления анимацией и рендерингом и т.д. Слева расположена панель Tool Box, где преимущественно объединены команды для выполнения операций перемещения, вращения и масштабирования объектов, а также кнопки вариантов отображения окон проекций. В нижней части программного окна расположены палитры Time Slider и Range Slider, позволяющие управлять анимацией. А существенная по размерам область экрана в правой части окна содержит редактор атрибутов Attribute Editor, предназначенный для редактирования объектов. Любую из панелей можно скрыть, щелкнув на треугольнике в ее левом верхнем углу. За открытие/скрытие названных панелей (их называют универсальными) отвечает строка меню UI Elements (Универсальные элементы) из меню Display (Отображение — рис. 5). Кроме того, в правом верхнем углу программного окна имеются кнопки для быстрого открытия/закрытия панелей Attribute Editor, Tool Settings и Channel Box/Layer Editor (рис. 6).
Рис. 4. Загружаемый по умолчанию набор панелей
Рис. 5. Открытие/скрытие универсальных панелей
Рис. 6. Кнопки быстрого открытия/закрытия панелей
Вызывать любые команды можно, не прибегая к командному меню, панели Shelf и пр., а через так называемое меню оперативного доступа, что зачастую оказывается быстрее. Вызов сокращенного варианта данного меню осуществляется при нажатии и удерживании в течение некоторого промежутка времени клавиши Пробел, а вызов полного варианта — в результате последующего щелчка на кнопке Hotbox Controls (Элементы управления меню оперативного доступа) (рис. 7).
Рис. 7. Сокращенный вариант меню быстрого доступа
Все создаваемые в программе элементы называют объектами, и к объектам относятся не только любые геометрические тела, но и формы, камеры и источники света и др. Объектами можно управлять, модифицируя их произвольным образом, объединяя в группы, связывая друг с другом и пр., и добиваясь в конечном счете создания нужной сцены. Процесс создания объектов называется моделированием. Моделирование осуществляется в окнах просмотра проекций, которые и занимают основную часть экрана и позволяют рассмотреть объекты с разных позиций и в различных проекциях. По умолчанию на экране отображается одно прямоугольное окно, соответствующее проекции Perspective (Перспектива). Для одновременного появления четырех окон проекции — Тор (Сверху), Side (Сбоку), Front (Спереди) и Perspective (Перспектива) можно нажать клавишу Пробел или щелкнуть на кнопке Four View палитры Tool Box. Повторное нажатие клавиши Пробел (при предварительной активизации нужного окна проекции) позволяет развернуть на весь экран любую другую проекцию. В Maya существует достаточно большее число вариантов компоновок проекций, для выбора которых предназначена команда Panels=>Layouts (Панели=>Компоновка) из меню окна проекций (рис. 8). По умолчанию при открытии программы устанавливается режим работы с одним окном проекции Perspective. При желании можно изменить режим загрузки режима по умолчанию, выбрав нужный вариант компоновки из списка команды Panels=>Saved Layouts (Панели=>Сохранение компоновки) — рис. 9.
Рис. 8. Выбор варианта компоновки проекций
Рис. 9. Сохранение варианта компоновки проекций в качестве варианта, загружаемого по умолчанию
Любое окно проекции может быть сохранено, что в ряде случаев поможет сэкономить время — например гораздо быстрее по окончании настройки положения объектов (но перед редактированием других характеристик, что может потребовать, в частности, изменения угла обзора) сохранить нужные проекции, чтобы затем иметь возможность их быстро . Для сохранения конкретной проекции активизируйте окно данной проекции и выберите из меню окна проекции команду View=>Bookmarks=>Edit Bookmarks (Вид=>Закладки=>Редактирование закладок — рис. 10) и введите имя закладки. Объекты отображаются в окнах проекций либо в виде каркасов, либо с раскрашенной поверхностью (рис. 11) — изменение режима отображения объектов осуществляется через меню Shading (Затенение) окна конкретной проекции. За установку режима каркасного отображения отвечает команда Wireframe (Каркас) — ей соответствует горячая клавиша 4, а режима тонированной раскраски — Smooth Shade All (Сглаживать все, горячая клавиша 5). Кроме того, предусмотрена возможность изменения размеров окон проекции, реализуемая обычным для окон образом.
Рис. 10. Сохранение проекции
Все объекты делятся на категории, выбор которых осуществляется из панели Shelf (Полка) с помощью соответствующих кнопок или через командное меню Create (Создание — рис. 12), в котором находится список всех базовых визуализируемых объектов. К числу таких объектов можно отнести сплайны, полигоны, источники света, камеры, кривые и пр. В каждой категории существует целый список разнообразных объектов, например в категории NURBS Primitives (NURBS-примитивы) и Polygon Primitives (Полигональные примитивы) входят Sphere (Сфера), Cube (Куб), Cylinder (Цилиндр), Cone (Конус), Plane (Плоскость) и Torus (Topус).
Рис. 12. Выбор объекта из группы через командное меню.
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Урок 42 Задача: Редактируем текстуры оружия (делаем зимний камуфляж для Абакана) Что нам потребуется (найти ранее):Adobe Photoshop + DDS Plugins, файл текстур Абакана, файл текстур камуфляжа
Приступим. 1. Запускаем Photoshop, открываем wpn_abakan.dds и камуфляж. 2. Переходим на вкладку с камуфляжем. Там выбираем: Выделение---->Все. Дальше: Редактирование---->Определить узор.
3.Теперь переходим на текстуру Абакана. Выбираем:Инструменты---->Узорный штамп. Сверху в параметрах выбираем нужный нам размер штампа и в параметре "Непрозрачность" ставим, примерно, на 26%. 4.Закрашиваем текстуру.
5.Заходим в игру и смотрим наше творение.
Урок 43 Задача: Создаем текстуру детектора "Серафим" Пояснение: Сегодня будем редактировать файлы textures/item/item_detector_2 и item_detector_2_segment. "Серафим" использует текстуру детектора "Медведь", получается, если мы изменим item_detector_2, то изменится визуал обоих. Вообще, лучше создать отдельную модель для "Серафима", но сегодня нам это не принципиально
Лично меня чуток раздражает несоответствие цвета иконки и текстуры самого детектора "Серафим". Ну, и сам ржавый цвет "Медведя" поднадоел. Так-что, будем опираться на иконку.
1.Открываем item_detector_2 и item_detector_2_segment каким-нибудь .dds редактором (сегодня я использую Paint.net). 2. Редактируем item_detector_2. Выбираем в параметрах "Коррекция"---->"Оттенок и насыщенность". Если мы опираемся на иконку, то делаем цвет синего или голубого оттенка. Табло смотрится не очень. Обводим его с помощью "лассо" и меняем его оттенок на бирюзовый. У меня получилось так:
3.Приступим к item_detector_2_segment. Проделываем тоже самое, только меняем цвета на розово-красные. Пример:
4.Сохраняем все это и смотрим результат:
Урок 44 Задача: Простейшая настройка модели нпс из Сталкера ЗП/ЧН в SDK Actor Editor Потребуется: SDK Actor Editor с плагинами для ЗП, модель нпс в формате .object, файл настроек костей для моделей ЗП/ЧН (обязательно скачать, ссылка ниже)
Итак, мы что-то делали с моделью сталкера, например, в Milshape 3d, и теперь нам надо ее настроить. Сегодня осваиваем самый легкий стандартный способ. 1. Для начала, копируем текстуры модели в аналогичную папку в gamedata СДК. 2. Открываем модель. Должно выглядеть как-то так
3. Открываем вкладку Bones и нажимаем Load. Далее указываем путь к ранее скачанным настройкам костей. 4. В Motions нажимаем на Motion Reference. Выбираем параметры stalker_animation, stalker_scenario_animation, stalker_scripts_animation и stalker_smart_cover_animation
5. В Object внизу есть поле User Data. Там указываем путь к файлу модели в configs/models. В моем случае, это выглядит так #include "models\capture\stalker_freedom_2.ltx" 6. Все! Экспортируем в OGF.
1. Файл настроек костей для моделей, на самом деле содержит настройки предельных углов поворота костей, шейпы (физические поверхности) костей и их положение, а также группировку костей в скелете и развесовку костей (физическую массу частей скелета). Все эти настройки конечно можно сделать вручную, но проще подгрузить из готового файла *.bones, который можно получить из уже готовой 3D модели в формате *.ogf, при помощи конвертора от бардака:
Код
[Преобразование скелета из .ogf в .bones] Команда: converter [-ogf] -bones <оригинал> [-out <результат>]
2. Параметр User Data обычно содержит дополнительные настройки модели, которые могут быть как прямым текстом, так и ссылкой на файл с данными настройками. В моделях НПС эти настройки показывают степень урона при попадании по различным областям модели, общий имунитет к воздействиям и т.д. и т.п. Аналогично в моделях монстров, разрушаемых объектов и техники. Например настройки модели вертолета включают в себя: назначение специфических костей вертолета (где пушки, ракеты, пропеллеры); распределение урона по областям (бонешейпам); путь к файлам моделей осколков вертолета при взрыве; фактор времени уборки частей вертолета после взрыва; параметры взрыва вертолета и некоторые физические параметры модели.
Урок 45 Задача: Пришиваем голову персонажа к модели экзоскелета (самый простой способ) Потребуется:Milkshape 1.8.4 с плагинами, модель зомбака в экзоскелете (или любая другая модель с уже готовым лицом),модель нужного нам персонажа
Для начала хотел бы сказать, что это далеко не единственный способ, но он является самым легким. В нашем случае - это то, что надо. Хорошо. 1. Открываем милку и загружаем модель нужного нам перса (у меня это Лебедев) 2. Видим, что у него две группы - лицо и тело. Удаляем группу тела и ее материал. Голову и скелет оставляем)
3. Экспортируем это в Half-life SMD. Выбираем верхнее и нежнее значение.
4. Теперь открываем модель зомби в экзе. Удаляем группу и материал головы. 5. Импортируем ранее сохраненный SMD (выбираем все три значения). И смотрим, как оно стало. Если что-то не так стало, правим (например, иногда не в ту сторону голова развернута) 6. Теперь мы можем настроить текстуры: Выделяем материал--->Внизу кнопка Emissive--->Выбираем белый цвет--->Дальше справа есть название текстуры, нажимаем и выбираем то, что мы хотим У меня вышло так
7. Все! Экспорт и настройка в СДК!
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Урок 46 Задача: Создание инвентарного комплекса в чистом ЗП
Перед тем, как начать урок, я хочу сказать, что скриптовой частью я обязан товарищу Ховану и Николаю Болтову. Именно благодаря их скриптам я нашел способ сделать подобную вещь! Огромное им спасибо! А теперь перейдем к уроку.
Файлы, которые нам потребуются: - configs/misc/items.ltx - configs/text/rus/st_items_equipment.ltx - scripts/_g.script - scripts/bind_stalker.script - scripts/my_callbacks.script
Возможно, вы когда-нибудь задумывались над вопросом создания предмета, из при использовании которого в инвентарь будут выпадать сразу несколько других, как, например, универсальный медкомплект. Долго думая, я понял, что такого эффекта можно достичь используя коллбеки на использовании предметов. Что такое "коллбек"? Если коротко, - это что-то в роде скрипта инфопорции. Однако, коллбек может работать как единожды, так и постоянно: при подборе предметов, при их использовании, при выстреле, при попадению по нпс и так далее. Нас интересует коллбек использования предмета, который будет работать постоянно.
1. Откроем items.ltx и скопируем секцию какого-нибудь бустера. Вставим новую секцию где-нибудь в это-же файле. 2. Настроим его так, как нам этого захочется.
Долго здесь зацикливаться не будем. Все элементарно. Могу только сказать, что при использовании будет проигрываться звук аптечки, а модель взяли армейской аптечки. 3. В st_items_equipment.ltx создаем описание и название предмета
Код
<string id="st_medkit_complex"> <text>Универсальный медкомплект</text> </string> <string id="st_medkit_complex_desc"> <text>Специальный медкомплект, разработанный для спецслужб в Зоне. Включает в себя все основные медикаменты.</text> </string>
На этом с конфигами все. 4. Руководствуясь материалом, взятым из сборника модостроения от Хована, мы создаем файл my_callbacks.script в папке scripts. 5. Наполняем его следующим образом
Код
function on_use_item(sect) --Переменные local actor=db.actor local item_name=sect:section() local actor_pos=db.actor:position() local active_slot=db.actor:active_slot() local active_item=db.actor:active_item() local pistol_in_slot=db.actor:item_in_slot(2) local rifle_in_slot=db.actor:item_in_slot(3) local outfit_in_slot=db.actor:item_in_slot(7) local helm_in_slot=db.actor:item_in_slot(12) --Коллбеки if item_name=="medkit_complex" then give_object_to_actor("drug_anabiotic") give_object_to_actor("antirad") give_object_to_actor("bandage") give_object_to_actor("drug_radioprotector") give_object_to_actor("drug_antidot") give_object_to_actor("drug_psy_blockade") give_object_to_actor("drug_coagulant") give_object_to_actor("drug_booster") end end
give_object_to_actor - как-раз и есть скрипт выдачи ГГ предмета, опираясь на коллбек. В скобках название предмета. Вообщем, продолжаем так-же, и добавляем, что хотим. Надеюсь, принцип ясен. 6. Зарегистрируем наш файл в bind_stalker.script. Там находим функцию function actor_binder:use_inventory_item(obj) и под вторым end прописываем
Код
if obj~=nil then my_callbacks.on_use_item(obj) end
В целом выглядит так:
Код
function actor_binder:use_inventory_item(obj) if(obj) then local s_obj = alife():object(obj:id()) if(s_obj) and (s_obj:section_name()=="drug_anabiotic") then xr_effects.disable_ui_only(db.actor, nil) level.add_cam_effector("camera_effects\\surge_02.anm", 10, false, "bind_stalker.anabiotic_callback") level.add_pp_effector("surge_fade.ppe", 11, false) give_info("anabiotic_in_process") _G.mus_vol = get_console():get_float("snd_volume_music") _G.amb_vol = get_console():get_float("snd_volume_eff") get_console():execute("snd_volume_music 0") get_console():execute("snd_volume_eff 0") end end if obj~=nil then my_callbacks.on_use_item(obj) end end
7. Осталось добавить глобальную функцию give_object_to_actor в _g.script. Внизу пишем:
Код
-- 'Создание предмета в рюкзаке ГГ. function give_object_to_actor(obj,count) if count==nil then count=1 end for i=1, count do alife():create(obj,db.actor:position(),db.actor:level_vertex_id(),db.actor:game_vertex_id(),db.actor:id()) end end
На этом урок заканчивается. Осталось только прописать пак ГГ и протестировать!
Урок 47 Задача: Регистрация новых звуков эксклюзивно для новой локации
Допустим, мы подключили к нашему моду локацию Болота из ЧН и мы хотим провести заселение. Наверняка, мы захотим добавить некоторые звуки новым квестовым НПС. А квестовым НПС у нас на сей урок станет восстановленный нами бармен "Чистого Неба", Холод. В первую очередь ему нужны фразы приветствия и прощания, а остальные пока подождут.
1. Нам надо зарегистрировать нашу локацию в configs/misc/script_sound.ltx. Открываем, и прописываем сверху
Код
#include "script_sound_marsh.ltx"
Ниже в секции
Код
[list]
добавим в конце list_script_sound_marsh 2. Далее в configs/misc создаем файл script_sound_marsh.ltx. 3. Начинаем его заполнять. Создаем список всех звуков, то есть секцию [list_script_sound_marsh]. В ней прописываем все секции звуковых файлов локации. В этот раз мы возьмем фразы Холода. Секция тогда будет выглядеть так:
Обратите внимание, что в параметре path название звука оборвано. А в параметре shuffle стоит рандом. Выходит звук приветствия/прощания не один, и будет рандомный выбор. Название у звуков отличается только после нижнего подчеркивания. 5. Добавим нужный звуковые файлы. Можно скопировать в ЗП полностью всю ЧНовскую папку sounds/character_voice/scenario/marsh, или выбрать оттуда только нужные звуки: mar_csky_barman_meet_bye_1 mar_csky_barman_meet_bye_2 mar_csky_barman_meet_bye_3 mar_csky_barman_meet_greet_1 mar_csky_barman_meet_greet_2 mar_csky_barman_meet_greet_3 6. Теперь можем прописать Холоду в логику:
Урок 48 Задача: Создание аномалии нового типа, на примере хроноаномалии.
Сразу определимся, что аномалия - это некий участок игрового пространства при попадании в который ГГ начинают проявляться внешние воздействия: 1. Визуальный эффект аномалии, как на экране у игрока (постпроцесс), так и на локации (партиклы) 2. Звук сработавшей аномалии (может быть а может отсутствовать если аномалия безшумная) 3. Воздействие на параметры ГГ и на окружающее пространство, тут выбор воздействия достаточно широк от не смертельных воздействий до прямой угрозе жизни все на ваш выбор. Создаем спейс-рестриктор в all.spawn:
Код
[20000] ; cse_abstract properties section_name = space_restrictor name = zat_time_anomaly_test position = 245.037811,16.290030,504.355347 direction = 0,0,0
Все стандартно, тип рестриктора 3, координаты, рестриктор сферической формы радиусом, например, пять метров. Создаем точку пути (в ней будем проигрывать партиклы для визуальных эффектов аномалии):
В логике первая активная секция [sr_idle@wait] - ожидание попадания ГГ внутрь рестриктора, как только он попался переключаемся на одну из секций воздействия sr_idle@inside_0 и перед этим запускаем эффекты: 1. run_postprocess(_actor_death_effector:9999:true) - это постпроцесс _actor_death_effector (раскачивание камеры и эффект зернения на экране), можно использовать существующие или создавать свои. 2. play_particle_on_path(anomaly2\a_test:zat_time_anomaly_test_way) - это проигрывание партикла anomaly2\a_test в точке at_time_anomaly_test_way, визуализация аномалии, партиклы можно использовать существующие в particles.xr или сделать свои. В секциях воздействия [sr_idle@inside_0] и [sr_idle@inside_1] есть прежде всего строка ожидающая выхода ГГ из зоны действия аномалии on_actor_outside, при этом аномалия возвращается в исходное состояние. Также в этих секциях обозначено воздействие аномалии on_timer = 1000. Тоесть каждые 1000 мс происходит перемотка игрового времени на 5 минут forward_game_time(0:5) и проигрвание звука play_sound(pda_alarm), звук pda_alarm взят для примера, нужно добавить свой. Секции [sr_idle@inside_0] и [sr_idle@inside_1] образуют некий автогенератор с двумя состояниями, рестриктор попеременно переключается то в оду секцию то в другую - это сделано для того чтобы точнее дозировать воздействие аномалии.
Урок 49 Задача: Создание работающего лифта.
В данном уроке я рассмотрю возможность создания работающего лифта на локации. Он работает только для ГГ и не будет работать для НПС по причине ограничений самого движка. Прежде всего хочу сказать, что реализация лифта основана на динамическом объекте door_lab_x8. Итак начинаем с создания объекта лифт. I. Создаем в 3D редакторе обект. Я сделал тестовый объект в виде прямоугольной платформы, назначил материал, текстуру, создал скелет из двух суставов link и platform. Импортировал в object. II. Создаем анимацю движения. Я сделал простую, короткую анимацию в 30 кадров (ее можно растянуть в SDK поэтому делать ее полноценной длительности смысла нет). III. Настройка объекта лифт в SDK. В SDK нужно настроить шейдеры и материал объекта если необходимо (по умолчанию все и так работает), затем подгрузить созданную анимацию lift_up.skl, затем настроить сустав platform, а именно создать бонешейп, выбрать тип сустава Joint и самое главное настроить Game Material = objects\metal_box. В подключенной анимации уменьшил скорость воспроизведения Speed = 0.1 и поставил флаг Stop at end. Полученный объект импортируем в ogf. IV. Вставляем анимационные и интерактивные объекты на локацию. В all.spawn создаются секции подвижной анимированной платформы:
Код
[20000] ; cse_abstract properties section_name = door_lab_x8 name = zat_lift_test position = 245.037811,16.290030,504.355347 direction = 0,0,0
Тут все понятно: start_snd - звук в начале анимации, stop_snd - звук после окончания анимации. Если анимация достаточно длинная то может понадобиться повторяющийся звук проигрываемый между начальным и конечным idle_snd = device\airtight_gates_idle и idle_delay = 6500 Нижняя кнопка:
При "нажатии" на кнопку лифт проигрывает анимацию в обратном направлении (едет вниз) anim_obj_backward(zat_lift_test) VI. Некое допиливание скрипта bind_door_labx8.script, для того чтобы отключать звук после окончания отыгрывания анимации в обратном порядке. В функции function door_binder_labx8:animation_end_callback(is_end) закоментировать условие if is_end then, таким образом:
Код
function door_binder_labx8:animation_end_callback(is_end) --if is_end then if self.stop_snd then self.stop_snd:play_at_pos(self.object, self.object:position(), 0, sound_object.s3d) end self.is_idle = true self.anim_time = self.object:get_physics_object():anim_time_get() xr_logic.pick_section_from_condlist(get_story_object("actor"), obj, self.on_stop) --end end
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Урок 50 Задача: Текстурирование.Создание золотистой текстуры оружия Требуемая утилита:Paint.Net
Перед началом я хотел бы сказать, что способ этот далеко не единственный в своем роде. Но для людей, начинающих разбирать текстурирование, самое то. Paint.Net, я считаю, будет самой удобной утилитой в данном случае.
Начнем. 1. Открываем любую текстуру оружия. Я выбрал Форт-12, то есть текстура textures/wpn/wpn_fort.dds
2. Выделяем нужный нам участок, или всю текстуру, это уже по Вашему усмотрению. 3. Сверху в инструментах выбираем Эффекты --> Для фотографий --> Портретный. У нас есть три параметра: Смягчение, Освещенность, Теплота. В нашем случае нам важна как раз Теплота. Хотя остальные два параметра тоже можно использовать, они очень даже полезны во многих случаях. Я взял Теплоту на максимум.
4. Не снимая выделения, переходим к Коррекция --> Оттенок и насыщенность и редактируем Оттенок, Осветленность, Насыщенность так, как пожелаем. В нашем случае главная цель использование этого инструмента - сделать оттенок более желтым. Насыщенность я тоже немного увеличил для презентабельности.
5. По окончанию работы экспортим в DDS. По хорошему можно было бы сделать новый бамп и бамп#, но на статике роли не играет. И не факт, что будет играть на динамике.
Урок 51 Задача: Создание артефакта в Сталкер Зов Припяти (полный разбор) Ссылка на урок Урок 52 Задача: Исправление скрипта отвечающего за спавн сквадов на стартовых позициях в начале новой игры
Если вы добавляли локации при помощи программы от АМК для склейки геймграфа или при помощи SDK, то может возникнуть проблема с спавном сквадов на стартовых позициях (через конфиг-файл simulation.ltx). Для устранения этой проблемы нужно исправить скрипт sim_board.script функция sim_board:fill_start_position() на такой:
Код
--' Заполнение стартового расположения function sim_board:fill_start_position() if self.start_position_filled == true then return end self.start_position_filled = true for level in game_graph():levels() do local section_name = "start_position_" .. alife():level_name(level.id) if setting_ini:section_exist(section_name) then local n = setting_ini:line_count(section_name) if n~=0 then for i=0,n-1 do local result, id, value = setting_ini:r_line(section_name,i,"","") local smrt_names = utils.parse_names(value) for k,v in pairs(smrt_names) do local smart = self.smarts_by_names[v] if smart == nil then abort("Wrong smart name [%s] in start position", tostring(v)) end local squad = self:create_squad(smart, id) self:enter_smart(squad, smart.id) end end end end end end
1. Скопировать мод-источник в отдельную папку (чтобы не запароть исходный)
2. Распаковть в папку spawns архив с universal acdc.
3. Первое что нужно сделать, настроить программу на распознание неизвестных ей секций, для этого декомпилируем all.spawn коммандой:
Код
universal_acdc.pl -d all.spawn -out all
и внимательно смотрим лог, там будут сообщения типа "unknown class for section stalker_outfit_anom", что значит что программа не знает к какому классу объектов отнести объект с именем секции stalker_outfit_anom. Из редми к программе мне стало известно, что нужно в файл clsids.ini добавить секции путем добавления строк, одна беда как я ни пытался программа не видела внесенные изменения в этот файл (если у кого получиться - сообщите как удалось). Поэтому я пошел другим путем - прямое редактирование скрипта stkutils\scan.pm, там после строки:
Код
'zone_mine_steam_weak' => 'ZS_MBALD',
я добавил:
Код
'stalker_outfit_anom' => 'E_STLK',
Почему E_STLK? Потому что объект с именем секции stalker_outfit_anom вероятнее всего бронежилет, а он имеет идентификатор clsid равный E_STLK, что соответствует классу cse_alife_item_custom_outfit. Если после добавления строки декомпиляция не проходит до конца и вылет отличается от unknown class for section, то вероятнее всего класс определен не верно и нужно пытаться выбрать другой. Итак определяя классы недостающих секций добираемся до момента когда all.spawn будет полностью декомпилирован.
4. Итак секции настроены пора приступить к разбивке all.spawn на группу файлов level.spawn (спавн объекты) и level.game (точки путей), это делается командой:
Тут вероятна ситуация как у меня, файлы появились при этом level.game сформированы нормально (еще бы формат точек путей не менялся со времен древних билдов), а вот при формировании level.spawn программа вылетела с ошибкой. Что делать? Вероятно формат all.spawn не совсем подходит universal acdc, но он же его декомпилировал! Вот и выход: в третьем шаге файл all.spawn был полностью декомпилирован, вот теперь мы его скомпилируем снова командой:
На этот раз разбивка на файлы прошла без ошибок и можно заменить файлы в папке gamedata\levels\<имя уровня> на полученные файлы level.spawn и level.game.
5. Декомпилируем локацию программой converter.exe (тут подробно не останавливаюсь благо есть много инструкций), но возможна опять "назадача" и программа при декомпиляции уровня споткнется как раз на файле level.spawn! Что-же остается? Лечить!
6. Если level.spawn не подошел декомпилятору converter.exe, то попробуем получить его другим путем, благо universal acdc предоставляет последнюю возможность. Переименуем файл alife_<имя локации>.ltx в level_spawn.ltx и запустим компиляцию файла level.spawn из файла level_spawn.ltx командой:
Код
universal_acdc.pl -compile all -l
Полученный файл level.spawn поместим в папку уровня и снова пробуем декомпиляцию уровня в формат SDK, на этот раз все проходит успешно (по крайней мере у меня).
7. Открываем нашу локацию в SDK (надеюсь без вылетов) и видим все спавн-элементы и пути теперь доступны для редактирования в более удобной форме.
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Урок 54 Задача: Создание квеста на поиск перехода на другую локацию. Переход будет доступен после активации по сюжету. Установка меток на квестовую область и место перехода. Использование окна подтверждения (GUI) для подтверждения перехода или возврата на текущую локацию (как это было в ТЧ и ЧН).
Создание нового перехода с локации на локацию является архиважной задачей для сюжетного модостроителя. К сожалению, в "ЗП" процесс перехода осуществлялся путём использованием гидов, и у Актора не было возможности самому дотопать до перехода и нажать заветную кнопку "Перейти на другую локацию? Да!", как это было в предыдущих частях. Давайте исправим этот досадный пробел. P.S. В SGM это всё сделано, однако мне оказалось проще написать самому, чем пробовать вытащить оттуда.
Пункт первый. (К поставленной задаче слабо относящийся, но тем не менее, очень важный).
Цитата
Давайте заспаним Актора на Юпитере. Распаковываем all.spawn, в файле alife_zaton.ltx меняем координаты в секции [982] (section_name = actor) в ДВУХ (!) местах на те, которые нам нужны. Кстати, любые изменения в all.spawn (создание рестрикторов, левел-чейнджеров, точек путей и др.) требуют новой игры!!! Пусть ГГ у нас стартует около моста близ цементного завода. Для того, чтобы он появился действительно там, а не на Янове, есть несколько методов. Лично я ковырял файлы configs\scripts\jupiter\ jup_b47_logic.ltx и zat_b215_logic_jupiter.ltx. Что именно там изменено, можно посмотреть, сравнив файлы из моего архива с оригинальными. Кстати, для Припяти надо ковырять файлы configs\scripts\pripyat\ pri_a15_sr_cutscene.ltx и pri_a15_sr_exit.ltx. Итак, новая игра, и ГГ у нас появляется на Юпитере.
Пункт второй. Выдача квеста. Пусть ГГ получит задачу: "Найти переход на Затон. Переход искать в районе разрушенного моста". Задачу можно выдать из диалога, из логики рестриктора, либо из любой функции, как вам будет удобно. Открываем configs\misc\tm_jupiter.ltx и пишем туда описание квеста:
Код
[jup_find_level_changer_to_zaton_quest] ;уникальное имя квеста icon = ui_inGame2_Put_v_pripyat ;иконка квеста. Описание в configs\ui\textures_descr\ui_actor_newsmanager_icons.xml. Сама текстура - в textures\ui\ui_actor_newsmanager_icons.dds prior = 1 ; приоритет? storyline = true ;тип метки для задания, но без использования поля target метка не ставится (а его у нас здесь нет) title = jup_find_level_changer_to_zaton_quest_name ;заголовок квеста - пишем в configs\text\rus\st_quests_niv_jupiter.xml descr = jup_find_level_changer_to_zaton_quest_text ;описание квеста там же condlist_0 = {+jup_level_changer_to_zaton_finded} complete ;условия для выполнения: засчитается при выдаче инфопоршня jup_level_changer_to_zaton_finded
Сам квест в данном примере выдадим из логики рестриктора, но об это чуть по-позже. Вернёмся к метке на задание. В "ЗП" метки ставились конкретно на объект (target = obg_sid) в виде маленьких кружков, цвет которых зависел от параметра storyline = true / false. В то же время, если у нас задача "Поискать в какой-то зоне", то надо ставить большую серую круглую метку, как это было в "ТЧ". Поэтому придётся сделать, как было там. А именно, восстановим колл-бэк на инфопоршни в файле scripts\ bind_stalker.script. В пустую функцию actor_binder:info_callback дописываем:
Код
mapspots.process_info_portion(info_id)
Эта функция будет ставить и удалять метки по выданным инфопоршням. Создаём файл scripts\mapspots.script, в нём пишем функцию process_info_portion(info_id), которой в качестве параметра будут передаваться все инфопоршни, а она уже будет думать, что с ними делать. Сама функция состоит из двух других (потом можно добавить функции для других локаций):
Код
function process_info_portion(info_id) if db.actor == nil then return end -- перечислим функции, которые обрабатываем add_niv_level_changer_spot() -- на переходы jupiter_process_info_portion(info_id) -- на события на Юпитере end
Из событий на Юпитере у нас пока только поставить метку на область поисков при выдаче задания и снять её при выполнении задания.
Код
-- функция для обработки инфопоршней на метки на Юпитере function jupiter_process_info_portion(info_id)
local jup_d8_bridge_id_id = get_story_object_id("jup_d8_bridge_id") --определяем id объекта по story_id
if info_id == "jup_strelok_hiring_end" then level.map_add_object_spot_ser(jup_d8_bridge_id_id, "crlc_small", "jup_d8_bridge_map_spot_text") --ставим метку на мост на d8, параметры: id, тип метки (кружок), текст метки. elseif info_id == "jup_level_changer_to_zaton_finded" then --удаляем метку с моста на d8 level.map_remove_object_spot(jup_d8_bridge_id_id, "crlc_small") return false end end
ВАЖНО: поставить метку можно только на объект, обладающий story_id!
Пункт третий. (Создадим объект (спейс-рестриктор), на который мы будем ставить метку. Найдём в распакованном спауне файл alife_jupiter.ltx, а в нем - любую секцию рестриктора (section_name = space_restrictor). Скопируем её в конец файла и присвоим номер [6122] (для чистого ЗП only!). Выйдем на мост, получим координаты и впишем их в эту секцию (position, game_vertex_id, level_vertex_id), придумаем уникальное имя (name = jup_d8_bridge_sr) и, самое главное, пропишем кастом_дату:
Код
custom_data = <<END [story_object] story_id = jup_d8_bridge_id ; вот где story_id пишется! [logic] cfg = scripts\jupiter\jup_d8_bridge_sr.ltx ; путь к логике относительно папки configs END
Осталось еще указать форму и размер рестриктора, например сферу с радиусом 4 м.
Т.е. для обнаружения перехода на другую локацию Актор должен зайти внутрь рестриктора.
Пункт четвертый. Логика рестриктора. Просто зайти в рестриктор - это тривиально. Пусть ГГ ищет переход... глядя в бинокль, благо с моста смотреть удобно! И тогда через 30 игровых секунд переход сам найдётся! Для этого пишем логику в файле configs\scripts\jupiter\jup_d8_bridge_sr.ltx
Код
[logic] active = sr_idle@control
[sr_idle@control] on_info = {-jup_strelok_hiring_end} %+jup_strelok_hiring_end =give_task(jup_find_level_changer_to_zaton_quest)% ;проверяем, есть ли инфо jup_strelok_hiring_end. Если нет - то выдаем его и задачу jup_find_level_changer_to_zaton_quest. ;обращаем внимание, что из логики функции вызываются немного по другому. Так, из обычной функции выдача квеста происходила бы так: task_manager.get_task_manager():give_task("jup_find_level_changer_to_zaton_quest ")
on_actor_inside = {+jup_strelok_hiring_end =look_binocular} sr_idle@message ;помним, что функции для проверки условий {=функция} должны находиться в файле scripts\xr_conditions.script ; в условии {} сначала проверяем наличие инфопоршня - вдруг по сюжету его еще не давали. Тогда сколько ни гляди в бинокль - ничего не найдёшь. Если вы считаете по-другому - уберите этот инфопоршень отсюда.
[sr_idle@message] on_game_timer = 30|sr_idle@nil %+jup_level_changer_to_zaton_finded =new_way_finded_message +jup_level_changer_to_zaton_activated =give_task(jup_go_to_zaton_quest)% ;помним, что функции, выполняемые из логики, должны находиться в файле scripts\xr_effects.script. ; В этой секции через 30 игровых секунд выдаём инфо jup_level_changer_to_zaton_finded по которому задание засчитывается и метка с рестриктора снимается. ; только в качестве примера сразу же выдадим разрешение на активацию телепорта jup_level_changer_to_zaton_activated и квест "Попасть на Затон" (jup_go_to_zaton_quest). По сюжету это инфо и задание у меня даются намного позднее. А без инфо переход не сработает.
[sr_idle@nil] ;выключаем рестриктор
Ищем переход в бинокль smile (на самом деле проверяем, что активное оружие - бинокль):
Код
function look_binocular () local active_item = db.actor:active_item()
if active_item ~= nil then local section_name = active_item:section() if section_name == "wpn_binoc" then return true end end return false
end
Говорим сами с собой (или по радио) про обнаруженный переход (у меня ГГ любит поговорить с умным и уважаемым человеком!):
Код
function new_way_finded_message () local news_caption = game.translate_string("st_tip") local news_text = "new_way_finded_message_text" local texture = "ui_iconsTotal_yan_scientist_job" db.actor:give_game_news(news_caption, news_text, texture, 0, 15*1000) end
Пункт пятый. Рестриктор, управляющий переходом. Итак, переход найден. И это опять спейс-рестриктор! Пусть его секция будет [6123], name = jup_d9_lev_ch_zaton_sr, story_id = jup_d9_lev_ch_zaton_sr_id, cfg = scripts\jupiter\jup_d9_lev_ch_zaton_sr.ltx Сперва поставим на него метку. Помните, в mapspots.process_info_portion(info_id) была функция add_niv_level_changer_spot()? Напишем так:
Код
-- список инфопоршней для открытия переходов и имена левел-чейнджеров
--ставим метку на левел-чейнджер при обнаружении его
function add_niv_level_changer_spot() local i for i = 1,#niv_level_changer_table do if db.actor:has_info(niv_level_changer_table[i][1]) then if db.actor:dont_has_info(niv_level_changer_table[i][2]) then
local obj_id = get_story_object_id(niv_level_changer_table[i][3]) level.map_add_object_spot_ser(obj_id, niv_level_changer_table[i][4], niv_level_changer_table[i][5])
db.actor:give_info_portion(niv_level_changer_table[i][2]) end end end
end
ИНТЕРЕСНО: знак # в #niv_level_changer_table возвращает число строк в массиве, т.о., дописывая потом данные в массив, мы можем не менять ничего в тексте функции!
Метки на переход (level_changer_up_right, level_changer_down_left и др.) находятся в файлах configs\ui\map_spots.xml и map_spots_16.xml Для того, чтобы на мини-карте отображалась метка перехода, необходимо слегка отредактировать все метки: дописать внутрь тег mini_map и указать для него такой же spot, как и для level_map.
Итак, место перехода отмечено - идём туда. Как работает рестриктор? Пусть в нём появляется окно "Перейти на другую локацию?" Если "ДА" - то идет телепорт в ЛевелЧейнджер (точка actor_go_to_zaton_walk:actor_go_to_zaton_look), расположенный в недоступном месте (за границей локации, например). Если "НЕТ" - то Актора телепортирует немного назад и разворачивает на 180 градусов (точка actor_doesnt_go_to_zaton_walk:actor_doesnt_go_to_zaton_look). Эта же точка будет точкой выхода при обратном переходе Затон - Юпитер. А может рано ещё уходить с этой локации? Нет проблем - пишем такую логику в configs\scripts\jupiter\jup_d9_lev_ch_zaton_sr.ltx:
Код
[logic] active = sr_idle@control
[sr_idle@control] on_info = {+actor_go_from_zaton_to_jupiter =actor_on_level(jupiter)} %-actor_go_from_zaton_to_jupiter =teleport_actor(actor_doesnt_go_to_zaton_walk:actor_doesnt_go_to_zaton_look)% ;телепортирует актора при возвращении с Затона и забирает инфо actor_go_from_zaton_to_jupiter
on_actor_inside = {+jup_level_changer_to_zaton_finded -jup_level_changer_to_zaton_activated} sr_idle@inside_lc_na %=you_cant_leave_locat_message%, {+jup_level_changer_to_zaton_activated} sr_idle@teleport %+level_changer_need_choise%, sr_idle@inside_lc_na ;условия выполняются слева направо: 1) если нашли переход, но не активировали (нет разрешения) - выдаём сообщение you_cant_leave_locat_message и переходим в пустую секцию sr_idle@inside_lc_na (чтобы сообщение выдавалось только 1 раз). 2) если переход активирован - идем в секцию телепорта и выдаем инфо level_changer_need_choise. 3) Если вдруг в начале игры мы зашли в это место и еще не знаем, что здесь переход, то ничего и не происходит.
[sr_idle@teleport] on_info = {+level_changer_choise_yes} sr_idle@control %+actor_go_from_jupiter_to_zaton -level_changer_need_choise -level_changer_choise_yes =run_postprocess(black:6127:true) =forward_game_time(4) =teleport_actor(actor_go_to_zaton_walk:actor_go_to_zaton_look)% ;если выбран переход на Затон - выдаем инфо actor_go_from_jupiter_to_zaton, обнуляем инфо level_changer_need_choise и level_changer_choise_yes, затемняем экран, телепортируем ГГ в левел-чейнджер и переводим время вперед на 4 часа.
on_info2 = {+level_changer_choise_no} sr_idle@control %-level_changer_need_choise -level_changer_choise_no =teleport_actor(actor_doesnt_go_to_zaton_walk:actor_doesnt_go_to_zaton_look)% ;аналогично сбрасываем инфо и телепортируем ГГ обратно на локацию.
Точки actor_go_to_zaton_walk : actor_go_to_zaton_look, actor_doesnt_go_to_zaton_walk : actor_doesnt_go_to_zaton_look необходимо добавить в спаун (way_jupiter.ltx) как-то так:
Важно, чтобы у точек look, соответствующим точкам walk совпадали флаги: flags = 0x1.
Помните, всё начиналось с того, чтобы сделать окно подтверждения перехода, как в ТЧ? Так вот, заставить нормально работать его из логики рестриктора мне не удалось. Поэтому, запускать его мы будем в другом месте, окно будет выдавать инфопоршни level_changer_choise_yes или level_changer_choise_no, по которым мы и будем управлять переходом.
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Пункт шестой. GUI или окно управления. Графический интерфейс пользователя (GUI) - это любое окно или меню на экране, куда можно тыкать мышью, например и выбирать - переходить на другую локацию, или нет. Всё, что нам надо - создать две кнопки "Да" и "Нет". За GUI у нас будет отвечать файл scripts\ ui_level_changer.script. Интересный факт: несмотря на то, что окна выбора в ЗП нет, форма для него осталась: \configs\ui\ message_box.xml и message_box_16.xml, элемент <message_box_change_level>. Её и будем использовать, осталось только увеличить <message_text> и поставить font="graffiti32". Пропишем в scripts\ ui_level_changer.script следующие колл-бэки и функции, они и будут выдавать управляющие инфопоршни level_changer_choise_no и level_changer_choise_yes:
Код
function ui_level_changer:InitCallBacks_no() self:AddCallback("button_no", ui_events.BUTTON_CLICKED, self.OnButton_no_clicked, self) end
function ui_level_changer:OnButton_no_clicked() --;возврат на этот же уровень = точка выхода self:HideDialog() db.actor:give_info_portion("level_changer_choise_no") end
function ui_level_changer:InitCallBacks_yes() self:AddCallback("button_yes", ui_events.BUTTON_CLICKED, self.OnButton_yes_clicked, self) end
function ui_level_changer:OnButton_yes_clicked() --;переход на другой уровень = точка выхода self:HideDialog() db.actor:give_info_portion("level_changer_choise_yes") end
function level_changer_choise(info_id) if info_id == "level_changer_need_choise" then run_gui(this.ui_level_changer()) end end
Помните, в логике рестриктора выдавалось инфо level_changer_need_choise? Возвращаемся к колл-бэку на инфопоршни в файле scripts\ bind_stalker.script. В функцию actor_binder:info_callback(npc, info_id) дописываем ui_level_changer.level_changer_choise(info_id). Таким образом, мы и будем запускать GUI (run_gui(this.ui_level_changer())). Осталось только определить эту глобальную функцию в файле scripts\_g.script
Код
function run_gui(gui, close_inv) if close_inv == true then gui:ShowDialog(true) game_hide_menu() level.show_weapon(false) else gui:ShowDialog(true) end end
Пункт седьмой. Левел-Чейнджер. В оригинале "ЗП" левел-чейнджеры располагались где-то на недоступных простым смертным крышах. Мы поставим его просто за границей локации. Для снятия координат попадаем туда при помощи "Повелителя Зоны". Копируем в спауне (alife_jupiter.ltx) секцию левел-чейнджера (section_name = level_changer), присваиваем ей следующий за нашей последней секцией номер. ВАЖНО - имя левел-чейнджера должно оканчиваться на _level_changer, например jup_to_zaton_level_changer! Прописываем ему координаты на Юпитере, а также выходные координаты на Затоне (dest_game_vertex_id, dest_level_vertex_id, dest_position, dest_direction, dest_level_name = zaton). dest_graph_point можно не указывать. Несомненно, параметр dest_direction влияет на поворот Актора, но мне не удалось его удовлетворительно подобрать. Именно для того, чтобы после появления на уровне развернуть ГГ правильно и применяется телепорт в секции [sr_idle@control] управляющего рестриктора.
Пункт восьмой. Всё остальное. Осталось создать теперь уже на Затоне левел-чейнджер и управляющий рестриктор - в принципе, всё то же самое. На Затоне нет телепортирующих рестрикторов, однако жизнь портит рестриктор с логикой configs\scripts\zaton\zat_a1_logic.ltx. Вымарываем там половину, оставляем следующее:
[sr_idle@nil] ;При попадании на Затон в первый раз засчитывается задание "Попасть на Затон" и сразу выдаются инфопоршни на обнаружение и активацию рестриктора на обратный путь. Если вы любите поизмываться над ГГ и игроками - не давайте их здесь, а заставьте выполнить "пару заданий". Остальные инфо - сюжетные из оригинала.
Вот и всё! Новых переходов!
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Урок 55 Задача: Ограничение времени на выполнение квеста и вывод таймера с остатком времени на экран.
Введение: Помните, в "Тенях Чернобыля" были квесты, ограниченные по времени, иногда порядком портившие людям нервы? Возможно, из-за этого в "ЗП" отсутствует ограничение по времени на выполнение квестов. Тем не менее, иногда это ограничение может быть оправданно по сюжету и мне захотелось его восстановить. Простого решения, как добавить такую запись в ПДА, я не нашёл, и решил вместо этого выводить на экран таймер, на котором будет идти обратный отсчёт времени. Таймер должен продолжать идти при переходе с локации на локацию, правильно отражая перемотку времени, производимое в игре (переходы по локации и между ними, сон). Примечание: Если такой квест происходит у вас на одной локации, то можно обойтись штатными средствами (рестриктор с логикой [sr_timer] ). При этом, если вы уходите с локации, таймер исчезает, а когда снова заходите - таймер продолжает идти, как это было в Солянке на ЧАЭС. Но для наших целей придётся делать по-другому.
Пункт первый. Выдача задания.
Цитата
Всё стандартно - выдадим задание (configs\misc\ tm_zaton.ltx) из логики рестриктора configs\scripts\zaton\ zat_a1_logic.ltx при старте новой игры.
Пункт второй. Таймер.
Создаём файл scripts\ niv_timer.script и в нём создаём класс "niv_quest_timer", у которого будут следующие методы: save, load, start(info_id), и timer_update(), который включает в себя функции update_timer() и update_hud(). Одновременно редактируем файл scripts\ bind_stalker.script, как указано ниже.
start(info_id).
Код
function niv_quest_timer:start(info_id) if info_id == "time_limited_quest_started" then niv_quest_timer_active=true -- засекается стартовое игровое время self.timer_start_value = game.get_game_time() end end
Таймер запускается при получении инфопоршня "time_limited_quest_started" через колл-бэк на инфопрошни в файле bind_stalker.script
Код
function actor_binder:info_callback(npc, info_id) printf("*INFO*: npc='%s' id='%s'", npc:name(), info_id) niv_timer.niv_quest_timer:start(info_id) end
timer_update()
Код
function niv_quest_timer:timer_update() niv_quest_timer:update_timer() niv_quest_timer:update_hud() end
Пункт третий. Самое главное.
Чтобы таймер работал, как часы (гм, какой оборот речи, однако!), необходимо запомнить время старта. Это достигается следующей модификацией bind_stalker.script : 1) Добавляем менеджер таймера в: function actor_binder:__init (obj) super(obj)
2) Сохраняем переменную: function actor_binder:save(packet)
Код
self.niv_quest_timer_manager:save(packet)
3) Считываем её же: function actor_binder:load(reader)
Код
self.niv_quest_timer_manager:load(reader)
4) Сами методы save и load несложные:
Код
function niv_quest_timer:save(packet) utils.w_CTime(packet, self.timer_start_value) end
function niv_quest_timer:load(packet) self.timer_start_value = utils.r_CTime(packet) end
В каком формате сохраняется время, возвращаемое функцией game.get_game_time() можно посмотреть в файле utils.script, функция w_CTime.
Пункт четвёртый. Худ.
Вызывается на экран функциями типа
Код
function niv_quest_timer:hud_utils() if niv_quest_timer_active==true then add_hud("hud_timer",niv_quest_timer_value_string) add_hud("hud_timer_text") else niv_quest_timer:hud_release() end end
function niv_quest_timer:hud_release() release_hud("hud_timer") release_hud("hud_timer_text") end
Функции add_hud, release_hud и некоторые другие взяты из SGM (за что его автору выражается огромная благодарность) и находятся в файле _g.script. В процессе также были немного отредактированы описания "hud_timer" и "hud_timer_text" из файла configs\ui\ui_custom_msgs.xml
На этом обустройство таймера можно считать выполненным. Если вы обнаружите условия, при которых таймер сбивается или не работает, просьба писать автору. Да пребудет с Вами Сила выполнять задания в срок!
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Урок 56 Задача: GUI Итак, уважаемые, прежде чем приступить к этому уроку я вам советую прочесть статью от FantomICW, которая поможет вам научиться работать с текстурами GUI, правильно размещать соответствующие элементы Ну а если вы уже ознакомились, то давайте приступим к созданию окошка с новым элементом:шкала В игре примерно выглядит вот так.
Сегодня мы разберем как создается такой элемент Возьмем соответственно две основные текстуры Ссылка на скачивание
Рассматривать размещение элементов, координаты, коллбеки я не буду, перейду сразу к скриптовой части. Цель следующая: ГГ должен выставить ползунок шкалы в определенном месте и нажать кнопку. В том случае, если ГГ выставил ползунок "верно" и нажал на кнопку, то выдадим ему инфопоршень. Для начала определим, ту зону, в которой мы будем считать, что ползунок выставлен верно и соответственно код будет следующим
Код
----------------Прибор радиста-------------------------------------------------- class "radist_pribor" (CUIScriptWnd) --Регистрация нового класса
function radist_pribor:__init() super() self:InitControls()--Иницилизация класса. Ссылка к функции self:InitCallBacks()--Иницилизация класса. Ссылка к функции end
function radist_pribor:__finalize() --ф-ция завершения работы нового класса end
function radist_pribor:InitControls() --функция, отвечающая за элементы окна local xml = CScriptXmlInit() self:SetWndRect(Frect():set(0,0,1024,768)) --установка размеров файла xml:ParseFile("radist_pribor.xml") --парсим ui файл self.Element1 = xml:InitStatic("Element1", self) --регистрация первого элемента с текстурой self.Element2 = xml:InitStatic("Element1:Element2", self.Element1) --регистрация второго элемента с текстурой self.shkala = xml:InitTrackBar("Element1:Element2:shkala", self.Element2) --регистрация шкалы self:Register(xml:Init3tButton("Element1:button1", self.Element1), "button1") --регистрация кнопки
end
function radist_pribor:InitCallBacks() --ф-ции колбеков self:AddCallback("button1", ui_events.BUTTON_CLICKED, self.button1_button_clicked, self) --коллбек кнопки end
function radist_pribor:trackbar2_GetValue() --шкала. Получаем определенное значение return math.floor(0 + (self.shkala:GetFValue() * (100 - 0))) --возвращаем это значение end
function radist_pribor:button1_button_clicked() --ф-ция, при нажатии на кнопку local text = "Значение = "..tostring( self.shkala:GetFValue() ) --выведем на экран значение переменной news_manager.send_tip(db.actor,text,0,"ui_inGame2_Dolg_2",1000,nil,"sender") self:HideDialog() --скрыть окно end
function radist_gui(folder) folder:ShowDialog(true) end
Теперь заходим в игру, выставляем ползунок как хотим, нажимаем кнопку. На экран будет выведено значение переменной self.shkala:GetFValue() Запоминаем это число, затем выставляем ползунок в другом месте, на экране увидим новое значение. У меня грубо говоря получилось значение 0.4 и 0.5 Теперь сделаем проверку: если значение переменной self.shkala:GetFValue() больше 0.4 и меньше 0.5, то выдадим инфопоршень. Код будет следующим
Код
----------------Прибор радиста-------------------------------------------------- class "radist_pribor" (CUIScriptWnd) --Регистрация нового класса
function radist_pribor:__init() super() self:InitControls()--Иницилизация класса. Ссылка к функции self:InitCallBacks()--Иницилизация класса. Ссылка к функции end
function radist_pribor:__finalize() --ф-ция завершения работы нового класса end
function radist_pribor:InitControls() --функция, отвечающая за элементы окна local xml = CScriptXmlInit() self:SetWndRect(Frect():set(0,0,1024,768)) --установка размеров файла xml:ParseFile("radist_pribor.xml") --парсим ui файл self.Element1 = xml:InitStatic("Element1", self) --регистрация первого элемента с текстурой self.Element2 = xml:InitStatic("Element1:Element2", self.Element1) --регистрация второго элемента с текстурой self.shkala = xml:InitTrackBar("Element1:Element2:shkala", self.Element2) --регистрация шкалы self:Register(xml:Init3tButton("Element1:button1", self.Element1), "button1") --регистрация кнопки
end
function radist_pribor:InitCallBacks() --ф-ции колбеков self:AddCallback("button1", ui_events.BUTTON_CLICKED, self.button1_button_clicked, self) --коллбек кнопки end
function radist_pribor:trackbar2_GetValue() --шкала. Получаем определенное значение return math.floor(0 + (self.shkala:GetFValue() * (100 - 0))) --возвращаем это значение end
function radist_pribor:button1_button_clicked() --ф-ция, при нажатии на кнопку if self.shkala:GetFValue()>=0.4 and self.shkala:GetFValue()<=0.5 then --если значение переменной больше 0.4 и меньше 0.5, то db.actor:give_info_portion("actor_gui_info") --выдадим ГГ инфопоршень self:HideDialog() end end
function radist_gui(folder) folder:ShowDialog(true) end
Содержание файла radist_pribor.xml (подробно рассматривать не буду)
gui\svezist
gui\radio
ui_inGame2_Mp_bigbuttone get out of here
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Урок 57 Задача: Скриптовое действие на позиции НПС (вычисляем позицию НПС в реальном времени) Требуемая утилита:Notepad ++ для красивой подсветки синтаксиса Ссылка на справочный материал
Урок 58 Задача: GUI | Создания инвентарного Gui-комплекса + основы Gui Подготовка к действу
Подготовка к действу
- Paint Net (редактируем тестуры) - Notepad++ (рекомендую для редактирования текстовых файлов игры) - XnView (полезная прога, но необязательная, позволяет быстро просматривать текстуры в папке и снимать координаты) - Milkshape 3d (позволяет просматривать модели + проверять текстуры, необязательно) - Stalker Icon Editor (крайне рекомендуется)
Философия создания
Как я уже говорил, за основу мы берем реальную аптечку - АИ-2. Считаю, важно сделать наполнение нашего комплекса как можно более схожим с реальным. Поэтому, рекомендую внимательно почитать о наполнении в Википедии. А если леньки и нет желания проходить по моим следам, то читаем информацию ниже
Цитата
Противобактериальное средство № 2 (сульфадиметоксин 0,2 г.) — 1 удлинённый пенал без окраски на 15 таблеток; Радиозащитное средство № 2 (калия йодид 0,125 г.) — 1 пенал белого цвета на 10 таблеток; Противорвотное средство (этаперазин 0,006 г.) — 1 пенал голубого цвета на 6 таблеток; Противобактериальное средство № 1 (хлортетрациклин 0,006 г.) — 2 пенала без окраски с квадратными корпусами на 5 таблеток каждый; Радиозащитное средство № 1 (цистамин 0,2 г.) — 2 пенала малинового цвета на 6 таблеток каждый.
Опираясь на это мы будем делать иконки, текстуры и модели, конфиги предметов. Что касается самого комплекса - при нажатии кнопки выдачи медикамента, медикамент будет появляться в рюкзаке, а кнопка будет переставать действовать.
Практика
Откроем файл configs/misc/items.ltx, Где и пропишем новые "бустеры". Если точнее, то саму аптечку АИ-2 и ее составляющие:
Стандартные секции бустеров. Полезные свойства аптечки приводим к нулю. Она у нас уже не выполняет функции медикамента, как такового. Полезные свойства составляющих медикаментов я прописывал по их назначению. Конечно, параметра "тошнота" в игре нету, поэтому заменим это дело на "восстановление сил". На что стоит обратить внимание, это параметр eat_portions_num. Мы берем реальное количество порций каждого медикамента. Под это будут завязаны модели, иконки, функции гуи и конечно параметр в конфиге. Вот, например, указано, что на хлортетрациклин выделено 10 порций (2 пенала по 5 таблеток). Итого, в конечном итоге у нас на этот медикамент должно быть 10 порций. Поэтому в секции antibio_chlor в параметре eat_portions_num стоит 2. То есть, предмет можно использовать два раза. Вспоминаем таблицу умножения При нажатии на кнопку данного медикаменты, в рюкзак добавится 5 таких предметов. Итого, используется 10 раз. Теперь разберем секции: medkit_ai2 - секция аптечки АИ-2 antirad_kalium - калия йодид antirad_cystamine - цистамин antibio_sulfad - сульфадиметоксин antiemetic - этаперазин antibio_chlor - хлортетрациклин Значения иконок и моделей у меня уже выставлены новые, но к этому мы вернемся чуть позже. Давайте добавим нашим предметам описания и названия. Откроем файл configs/text/rus/st_items_equipment.xml. Там пропишем:
Код
<string id="st_antirad_kalium"> <text>Калия йодид</text> </string> <string id="st_antirad_kalium_descr"> <text>Препарат радиозащитного действия на основе (калия йодид)</text> </string> <string id="st_antirad_cystamine"> <text>Цистамин</text> </string> <string id="st_antirad_cystamine_descr"> <text>Препарат радиозащитного действия на основе (цистамин)</text> </string> <string id="st_antibio_sulfad"> <text>Сульфадиметоксин</text> </string> <string id="st_antibio_sulfad_descr"> <text>Противобактериальное средство (сульфадиметоксин)</text> </string> <string id="st_antibio_chlor"> <text>Хлортетрациклин</text> </string> <string id="st_antibio_chlor_descr"> <text>Противобактериальное средство (хлортетрациклин)</text> </string> <string id="st_antiemetic"> <text>Этаперазин</text> </string> <string id="st_antiemetic_descr"> <text>Противорвотное средство (этаперазин)</text> </string> <string id="st_medkit_ai2"> <text>АИ-2</text> </string> <string id="st_medkit_ai2"> <text>Аптечка индивидуальная "АИ-2"</text> </string>
На этом с основными конфигами все.
Начинаем творческие процессы. Для аптеяки я возьму старую иконку, она вполне годная, а вот для компонентов нужно бы подыскать...Редактировать иконки будем с помощью Paint Net и Stalker Icon Editor. Надеюсь, знаете, как ими пользоваться. А если не знаете, то рекомендую учиться. Хотя, SIE - прога уже проще некуда. Так вот, давайте подумаем. Если предмет можно использовать 2 раза, как, например, цистамин ака antirad_cystamine, значит иконка должна быть на две порции. Предлагаю это увидеть. Для цистамина я взял всем известную иконку антирада, кто автор, к сожалению, не знаю, но встречается часто:
На иконке видно две ампулы. Значит, оно идеально подходит. Примерно следуя такой философии нужно искать/создавать подходящие иконки. Напоминаю, иконки расположены в файле textures/ui/ui_icon_equipment.dds. Перемещать, копировать иконки, узнавать их координаты удобней в SIE. Идеальная утилита для этого. Я подготовил иконки следующим образом: - открыл свой ui_icon_equipment.dds и этот же файл из SGM 2.2 - в клеточку справа от иконки паспорта Дегтярева в своем файле скопировал стандартную иконку пси-блокады - еще правее иконку антирада из СГМ - еще правее иконку зелено-синего антидота из СГМ - за ней правее скопировал стандартную иконку радиопротектора - под иконку пси-блокады, которую мы только что поставили, вставил еще одну иконку антирада из СГМ Опять же, на словах объяснить сложно. Это нужно увидеть:
Сохраняем, закрываем прогу. Но далеко ее не прячем. Еще пригодиться. Что мы имеет на данный момент: у нас есть две готовые иконки (антирад, зелено-синий антидот) и три неготовые (второй антирад, пси-блокада, радиопротектор). Давайте исправлять три иконки. Открываем этот же файл в Paint Net. Выделяем иконки с помощью Лассо, в панели сверху выбираем Коррекция-->Оттенок и насыщенность, а дальше редактируем под себя. Я считаю, этот инструмент - самый подходящий для подобной цели. Но это не значит, что другие не надо использовать. Пробуйте, творите!
После того, как три иконки обработали, сохраняем. Можно еще раз открыть в SIE, и снять координаты. Сегодня вам повезло - координаты в конфиге правильные, и про философию количества я не забыл. В SIE мои иконки после редактирования выглядят так:
Если кто не знает, как вычислять координаты в этом редакторе, поясняю: выделяем иконку, кликаем правой кнопкой мышки, выбираем "Информация о выделении". Всплывет окошко с параметрами. Копируем их с заменой старых аналогичных параметров в конфиге предмета. Теперь, чтобы не запутывать вас, я даю вот такую таблицу, которая многое пояснит: Название секции--Кол. порций--Иконка
antirad_kalium--10--
antirad_cystamine--2--
[antibio_sulfad]--3--
antiemetic--2--
antibio_chlor--2--
На этом с иконками все.
Раз мы использовали стандартные иконки (те, что из СГМ, тоже были изготовлены из стандартных)с ретекстуром, значит можно использовать стандартные модели и текстуры с ретекстуром. Сразу давайте определимся, что новые модели нужны только для четырех медикаментов. Для аптечки берем старую модель аптечки, для антирада-цистамина стандартную модель антирада. Новые модели будем складывать в папку meshes\dynamics\equipments\medical с определенными названиями. Почему так? А потому, что мы указали нечто в конфигах медикаментов:
Как-то так. Как я уже говорил, модели будем брать стандартные, и прописывать им новую текстуру (самими текстурами займемся в следующей части). Я покажу на примере калиума, одну модель мы возьмем из СГМ, остальные две модели вы сможете сделать по таблице. Итак, из ресурсов СГМ берем модель meshes/dynamics/equipments/medical/drug_act_eye.ogf, скопируем ее в эту же папку наших ресурсов и переименуем на antirad_kalium. Также, копируем текстуру модели - sgm/item_psyhodelin.dds. Как я узнал, что именно эту тектсуру надо копировать? Открыл модель блокнотом и порылся там чуток, пока не увидел такую запись. Учтите, там изменена текстура только одного предмета. Значит, текстура можно будет в дальнейшем использовать. Поэтому, я предпочитаю поместить текстуру в папку textures/item и переименовать на item_medkitai2. Кроме того, в модели, запись
Код
sgm\item_psyhodelin
меняем на
Код
item\item_medkitai2
Кстати, таким образом мы и будем менять текстуру следующим моделям. Но! Не забываем, что количество символов в новой записи должно быть равным количеству их в старой. Проделаем подобное еще раз - с моделью для antibio_sulfad. Иконка у него, напоминаю, от антидота. Значит и модель от нее же. Копипастим модель drug_antidot.ogf (как-раз находится в нашей папке) и переименовываем на antibio_sulfad. Открываем блокнотом, запись
Код
item\item_medkit_4
меняем на
Код
item\item_medkit_5
Думаю, тут сложного ничего нет. Осталось проделать подобное для оставшихся медикаментов. Старая модель--Новая модель--Старая запись--Новая запись
drug_radioprotector.ogf--antiemetic.ogf--item\item_medkit_4--item\item_medkit_5 dev_antirad.ogf--antibio_chlor.ogf--item\item_medkit--item\item_medic1 С моделями закончили. Но не с текстурами. Мы же дали новые записи, то есть отсылки к новым, несуществующим пока текстурам. От отсутствия текстур игра вряд ли вылетит. Но согласитесь, фиолетовая густая масса - это не дело. Идем пилить текстуры
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Текстуры, или логическое продолжение моделей. Раз уж мы сегодня не создаем модели, иконки сами, с нуля, как положено, то давайте "погрешим" и с текстурами. Все-равно, смысл немного не в этом. А на создание качественной модели с нуля ушло бы еще немало времени. Давайте вернемся к прошлой части урока. Мы меняли через блокнот привязку к текстуре. У этого способа есть то ли минус, то ли плюс: даже в новой текстуре модель будет брать старые координаты. Пример. Если модель радиопротектора брала себе текстуру из файла item_medkit_4.dds по следующим
значит и в новой текстуре (item_medkit_5.dds) будут браться те же координаты. Но нам сейчас это полностью подходит. Копируем текстуру item_medkit_4.dds со всеми thm и бампами, переименовываем на item_medkit_5. А дальше открываем в Paint Net. Здесь мы будем править текстуры для моделей, у которых есть отсылка к этому файлу. То есть для antibio_sulfad и antiemetic. Процесс этот, опять же, творческий. Красим, как хотим. Нам нужно изменить текстуру радиопротекора (вверху, чуть правее) и текстуру красной части антидота (она почему-то берется от этикетки "Геркулеса"). Короче, у меня вышла такая текстура:
Текстуры делал по цвету соответственно иконкам. Нужно провести примерно такой же процесс с другой текстурой - item_medkit.dds. Копируем и переименовываем на item_medic1. Это уже будет текстура для antibio_chlor. Открываем новую текстуру и заменяем оттенки антирада:
Ура! Можно приступать у Gui!
Прежде всего наметим концепцию: - Gui-окошко будет не самым большим, примерно 600X400. - слева в столбик будут находиться иконки предметов (составляющих аптечки) - справа от каждого - название и количество - правее текста - кнопки использования - выше посредине название аптечки - ниже посредине кнопка выхода В таких случаях, если не можете представить это все в уме, не стыдитесь делать зарисовки на бумаге. Используем все тот же Paint Net. Можно еще и XnView использовать, чтобы быстро найти подходящие текстуры. Прежде всего я хотел бы заметить, что dds-файлы, в которых находятся текстуры окон Gui, должны быть размером равным какой-то степени двойки. Например, 1024 pix, 2048 pix...Создадим такой файл в папке textures/ui. Назовем его ui_medkit_ai2_gui.dds. Расширение - 1024X1024. Можно и в другую папку, но мне лично привычней Gui-элементы сохранять в папке, где есть только Gui-элементы. Теперь выделим все (Ctrl+A), и вырежем к днищу X-ray'а. А теперь, начинаем строить окошко. Я просмотрел текстуры из папки ui в XnView, и выбрал следующий участок из файла ui_actor_save_load.dds (СГМовский) для текстуры окошка:
Если у вас нету СГМ-ресурсов, не волнуйтесь, в файле ui_actor_pda.dds есть похожее окошко. Выделяем, копируем, вставляем в наш файл. Удобней всего придвинуть окошко к левому верхнему углу до упора. Теперь создадим столбик для наших иконок. Для этого идеально подойдут слоты артефактов их файла ui_actor_menu.dds:
Выделяем, копируем, вставляем в нашу текстуру. Разворачиваем на 90 градусов и ставим в левую часть окошка, в упор к нижнему левому углу внутренней рамки:
Теперь начинаем заполнять каждое окошко иконкой предмета. Возвращаемся к любимому ui_icon_equipment.dds, с помощью Лассо выделяем новую иконку, копируем, вставляем (рекомендую вставлять на новый слой) а окошко. Так проделываем со всеми. У меня в целом вышла во такая картина:
На этом с текстурами окошка, как таковыми, все. Но не спешите закрывать. Выделите финальное окошко, скопируйте, нажмите "Создать новый документ", вставьте окошко. Для чего это надо вы узнаете следующей части.
Итак, это одна из основных частей урока. Конфигурация Gui, где указано расположение всех элементов на экране, находится в файлах расширения XML. Поэтому, создадим в configs/ui файл ui_gui_elements.xml. Заполним его следующим образом:
Это уже готовая форма. Но просто дать людям копипаст - не есть пример хорошего модмейкерского тона. В первую очередь нужно объяснить, что и как. Разберем некоторые элементы. <?xml version="1.0" encoding="windows-1251" ?> - кодировка файла. Находится вне тегов. <gui> и </gui> - открывающий и закрывающий теги наполнения всего файла. Кстати, давайте определимся, что все в XML состоит из открывающих и закрывающих тегов и внутреннего наполнения. Итак, если мы хотим добавить гуи-форму, мы добавляем ее между основными тегами файла. В данном случае они называются gui. Хотя, многим тегам можно дать любое название. Теги такого типа - не исключение. Называйте их как угодно. Идем дальше. medkit - это уже теги нашей гуи-формы. Обратите внимание на эту строку:
Код
<medkit x="206" y="162" width="612" height="443">
Это основные параметры окна. x, y - расположение окна на экране по ширине и высоте (координаты берутся в пикселях по левому верхнему углу формы, а игровой размер экрана считается 1204х768 пикселей, это все стоит запомнить) width, height - ширина и высота окна на экране К этому мы вернемся. А пока смотрим ниже:
Это инициализация текстуры окна. Внимание, тег texture - системный, его менять нельзя! Это как-раз исключение. Теперь поясню, как берется текстура. Есть уже знакомый нам файл ui_medkit_ai2_gui.dds. В строке выше к нему указан путь. Если мы выделим окошко, которые недавно готовили, в Paint Net, то снизу можно увидеть надписи "Верхний левый угол области№ с координатами и "Размеры прямоугольника" с размерами в пикселях.
Координаты левого угла окошка в файле - 0 и 0. Это потому, что он стоит в левом углу самого файла. Помните, я говорил об этом, когда строили окошко? Короче, в значениях x и y внутри texture пишем по нулям. Размеры прямоугольника в Пэинте - 612х443. Тогда добавим эти значения в width и height в texture. Кстати, вы заметили, что ширина и высота текстуры окна и самого окна в игре - одинаковые? Думаю, это логично. Хотя, можно делать их разными...В большинстве случаев выходит тогда не очень... Теперь вопрос: а как я определил координаты для самого окна на экране? Просто. Окошко у нас будет посредине экрана. Значение x получаем так: ширина экрана-ширина окна/2. То есть 1024-612/2=206. Для высоты все аналогично, но со значением высот: 768-443/2=162. Идем дальше.
Это подсекция текста "Аптечка АИ-2", который будет посредине сверху. caption_medkit - меняемый тег. Расположение считывается примерно так же, как и выше, но с другого документа! Копируем окошко из файла текстуры в новый документ с таким же расширением, как и само окно. И координаты для всех текстов, кнопок снимаем там, ведь они находятся внутри формы.
Хочу заметить, что для текста размер выделенного прямоугольника не играет роли. Разбираем текст дальше: text font - шрифт текста st_medkit_ai2_descr - id текста, который будет показан. Здесь указан текст описания аптечки. Ниже идут тексты, которые будут находиться возле иконок предметов. Суть тегов такая же, текст будет новый, не инвентарный. Но с этим потом. Я решил сделать так, чтоб тексты стояли на одном уровне по оси x. Можно сделать это очень удобно: снимаем координаты для первого текста, переходим к инструменту "Перемещение области выделения", кнопкой "Вниз" на клавиатуре сместим выделение чуть ниже к другой иконке. Теперь уже нам важен только параметр y, а x - у всех одинаковый.
Идем дальше. Видим новые теги типа btn. Это кнопки. Теги редактируемые. Последняя кнопка в списке - btn_close находится в окошке внизу посредине. Можете проверить. Остальные кнопки - строго напротив текстов. Суть примерно такая: снимаем координаты первой кнопки напротив текста цистамина, ее параметр x задаем всем остальным таким кнопкам. А y каждой кнопке даем от текста, напротив которого находится кнопка.
Касательно кнопки осталось еще пару моментов разобрать.
Код
<texture>ui_inGame2_Mp_bigbuttone</texture>
Это текстура кнопки. Но ui_inGame2_Mp_bigbuttone была определена еще заранее в оригинальной игре. В Сталкере можно задавать текстурам свои id. Такой прием используется, чтобы потом их можно было удобней прописывать в другие конфиги, как, например, секции нпс в character_desc (иконки нпс) или как иконки заданий в tm_.... Мы сегодня этому не будем придавать значения, но если интересно, гляньте папку configs/ui/texres_desc. text font - уже известный параметр. Шрифт текста в кнопке. ui_st_take - текст кнопок взятия медикаментов. Пока такой не существует, мы его добавим. ui_st_close - текст кнопки закрытия. Тоже добавим. Сохраняем файл. Можно скопировать и копию переименовать на ui_gui_elements_16. Это для широкоформатников. Теперь откроем configs/text/rus/ui_st_other.xml (или любой другой текстовый файл) и доавим туда все новые текстовки для Gui: