В этой теме на конкретных примерах (Уроках) разбирается весь процесс создания мода.
Правила работы в теме: Любой пользователь обладающий опытом и знаниями в модостроение, создает урок по определенной теме (отражено в задаче урока), после этого описывает выполнение поставленной задачи в виде отдельного файла и (или) напрямую в своем посте спрятав его под спойлер. В дополнении к уроку желательно выложить содержимое папки gamedata с выполненным уроком, чтобы пользователь скачав его мог проверить правильность выполнения урока самостоятельно. Обсуждение уроков ведется в теме: "Общие вопросы модостроения". Также в данной теме могут быть размещены дополнительные материалы помогающие пользователю освоить все аспекты модостроения.
Будем пытаться не использовать специфические файлы, поэтому можно работать в чистом ЗП, SGM и т.д. **
Не рекомендуется размещать информацию автором которой вы не являетесь, но если она полезна для пользователей сайта указывайте автора. Не рекомендуется размещать информацию доступную на других ресурсах повещенных модостроению - пользователи и так смогут ее найти. Запрещено размещать непроверенную информацию. В любом случае модераторы раздела оставляют за собой право удалить пост с Уроком или Справочной информацией в случае нарушения автором правил данного форума или правил данной темы.
*В любом уроке, вопросы рассмотренные полно в предыдущем уроке, могут быть описаны весьма сжато, поэтому при возникновении вопросов, прежде всего посмотрите предыдущие. ** Если нет специальных пояснений то урок делался на чистом ЗП 1.6002, в противном случае указан мод и версия для которой урок предназначен.
[cut=Рекомендации по оформлению]1. Заголовок сообщения из которого понятно назначение поста (Урок, Справочная информация или другое) 2. Если это урок то он должен иметь четко обозначенную задачу и желательно иметь ссылку на файл с выполненным уроком, для того чтобы выполняющие его могли скачать и посмотреть выполнение урока на примере. 3. Придерживайтесь устоявшейся цветовой схемы: а) Путь к файлу и (или) имя файла - Зеленый б) Имя параметра, функции и т.п. в файле - Желтый в) Не рекомендуется использовать оранжевый - это цвет комментариев кураторов раздела и к тому же близок к цвету ссылок. 4. Куски кодов и конфигурационных файлов обязательно помещайте в контейнер
Код
Исходный текст файла
. 5. Выделение текста изменением размера шрифта, его типом на усмотрение автора, главное не перебарщивать.[/cut]
Тема предназначена только для публикации уроков и справочной информации, вопросы в другой теме! Флуд и оффтоп будет наказан без предупреждения, а пост удалён, что бы там не находилось.
Эти 0 пользователя(ей) поблагодарили tracker за это полезное сообщение:
В строке <menu_sound random="4"> число "4" - колисество проигрываемых песен, а <menu_music>music\menu_1</menu_music> путь к музыкальному файлу относительно папки sounds\, в нашем случае это файл sounds\music\menu_1.ogg
Те-же самые действия проделываем и в файле ui_mm_main_16 для широкоформатных мониторов
Далее идём по адресу sounds\music\ и вставляем туда выбранные вами песни, соответственно названия песен меняем на menu_1, menu_2, menu_3 и menu_4
Примечание: *.ogg - формат музыкальных файлов.
Вы можете создать большее количество проигрываемых мелодий, указывая их число и прописывая путь к ним.
Поправил оформление, подкорректировал текст. XOBAH Я проверил, значение menu_sound random можно не менять - все равно нормально работает. denis2000
Урок 26 (Материал из S.T.A.L.K.E.R. Inside Wiki.) Задача: Сделать доступной возможность, снятия денег с трупов для Теней Чернобыля
В этой теме я напишу как сделать так что бы можно было снимать деньги с трупов. Для этого, идём по адресу gamedata\script\ Нам надо файл treasure_manager.script В этом файле находим такие строки
Code
--' Юзание инициатора (возможность выдать тайник) function CTreasure:use(npc) printf("TREASURE USE")
После строки --printf("TREASURE USE")-- пишем
Code
if (npc and db.actor) then lootmoney.lootmoney(npc) end
У нас должно выйти
Code
--' Юзание инициатора (возможность выдать тайник) function CTreasure:use(npc) printf("TREASURE USE")
if (npc and db.actor) then lootmoney.lootmoney(npc) end
Теперь создаём файл lootmoney.script и в нём пишем
Code
function lootmoney(npc) if npc ~= nil and not string.find(npc:section(),"arena") and npc:character_community()~="arena_enemy" then local money = npc:money() if money ~= nil and money ~=0 then local deadmoney = money
local npc_rank npc_rank = ranks.get_obj_rank_name(npc) if npc_rank ~= nil then if npc_rank == "novice" and deadmoney >=400 then deadmoney=math.random(25,400) elseif npc_rank == "experienced" and deadmoney >=500 then deadmoney=math.random(50,500) elseif npc_rank == "veteran" and deadmoney >=600 then deadmoney=math.random(100,600) elseif npc_rank == "master" and deadmoney >=700 then deadmoney=math.random(200,700) end end local news_texti = "\\n%c[255,255,0,0]Мёртвый сталкер: %c[default]"..npc:character_name().."\\n%c[255,255,0,0]Обнаружено денег: %c[default]"..game.translate_string(tostring(deadmoney).."руб.") db.actor:give_game_news(news_texti, "ui\\ui_iconsTotal", Frect():set(0,0,83,47), 1, 4000) db.actor:give_money(deadmoney) game_stats.money_quest_update(deadmoney) npc:give_money(-money) game_stats.money_quest_update(-money) end end end
Всё заходим в игру и пробуем :-)
Урок 27 (Автор KD87) Задача: Зарегестрировать в скриптах, подключённую локацию к ЗП.
Итак, мы подключили локацию к Зову Припяти, но на ней не происходят выбросы не летают вороны и т.д. Чтобы исправить эту оплошность, нам надо зарегестрировать локацию в скриптах.
Для того чтобы на локации работали некоторые скриптовые фишки, необходимо ее правильно прописать в скриптах.
Примечание: В этом туторе я прописывал кордон. Поэтому вместо l01_escape напишите имя своей локации.
Урок 28 (автор: Cromm Cruac; перевел на русский и дополнил: XOBAH) Задача: Разобраться с описанием текстур в xml-файлах на примере прицела, а также добавить новый
I. Как это работает
a) Текстуры прицелов
Текстуры прицелов представляют собой графические файлы разрешением 1024х1024 в формате dds
b) Файл configs\ui\textures_descr\ui_ingame.xml
Здесь описывают размеры сегментов\участков прицела в DDS-текстуре. Например:
Code
<file name="wpn\wpn_crosshair_l85"> <!-- Имя файла относительно папки textures\ из которого будут браться сегменты\участки --> <texture id="wpn_crosshair_l85" x="0" y="0" width="1024" height="1024" /> <!-- ID сегмента, для дальнейшего использования в описании. X, Y - координаты левого верхнего угла сегмента. Width, Height - Ширина и высота сегмента соответсвенно --> </file>
Большинство из них используют только один участок, охватывающий всю текстуру, но некоторые имеют два дополнительных: wpn_crosshair_add_l и wpn_crosshair_add_r. Это дополнительные участки, которые появляются на правой и левой стороне экрана в широкоформатном режиме. Например:
Файл scopes.xml используется при стандартном формате монитора (4:3, 5:4), а scopes_16.xml в широкоэкранном (16:10, 16:9)
Первый файл содержит только "главные" текстуры, определенные выше в ui_ingame.xml, масштабируемыми до разрешения 1024x768, который является своего рода «эталоном» всех элементов GUI (пользовательского интерфейса). Этот размер затем автоматически масштабируется до установленного разрешения экрана. Например:
Code
<wpn_crosshair x="0" y="0" width="1024" height="768"> <!-- wpn_crosshair - это название прицельной сетки для параметра scope_texture --> <auto_static x="0" y="0" width="1024" height="768" stretch="1"> <!-- stretch="1" - параметр который отвечает за то, будет ли текстура подгонятся под размеры статического сегмента (="1") или нет (="0") --> <texture>wpn_crosshair</texture> <!-- В значении принимается ID сегмента из файла ui_ingame.xml --> </auto_static> </wpn_crosshair>
Во втором начинаются лестницы тегов. Опять же, «эталон» составляет 1024x768, но это масштабируется до широкоэкранного режима (1280x768), а затем переходит в установленное разрешение. Так что мы должны поделить ширину текстуры на 0.8 (1024\0.8=1280) и переместить ее в центр. Кроме того, мы добавляем по бокам правый и левый сегменты wpn_crosshair_add_l и wpn_crosshair_add_r Например:
II. Добавление нового прицела Добавим новый прицел, типа "Gnomys"
a) Текстура
Берем текстуру в пропорции 4:3 (1024x768, 1360x1024, возможно 1280x1024) выключаем опцию "Сохранять пропорции", чтобы изменить разрешение на 1024x1024. Мы сохраняем файл в textures\WPN\my_crosshair.dds как DXT5, 8bit альфа, MIP-Maps - нет.
b) Определяем участок
В файле configs\ui\textures_descr\ui_ingame.xml определяем участок текстуры с дополнительными частями на левый и правый сегмент. Мы должны сделать это, потому что если вы будете использовать стандартные сегменты прицел будет иметь 2 черных полосы в широкоэкранном режиме. Поэтому, вместо wpn_crosshair пишем my_crosshair. Добавляем:
Для теста, пропишем наш прицел Винторезу. Открываем файл configs\weapons\w_vintorez.ltx и изменяем параметр scope_texture на scope_texture = my_crosshair
Запускаем игру и любуемся новым прицелом. ##### Примечание: Описанный выше метод описания текстур подходит для всех элементов GUI во всех играх серии STALKER, и может быть использован для создания собственного HUD'-a
Эти 0 пользователя(ей) поблагодарили XOBAH за это полезное сообщение:
Урок 29 (автор: Vano_Santuri), (взято с форума AMK Team, много спойлеров) Задача: Познать азы скриптования, научиться самому писать примитивные скрипты в Сталкере
Я не профессионал, я не программист, я не изучал официальную справку по Lua, я не считаю себя гением и еще кем-либо. В данном топе вы найдете готовые, самые используемые скриптовые функции, начальные сведения по скриптованию, научитесь писать примитивные скрипты(хотя их такими не назовешь), но я не смогу передать вам мой образ мышления и способность находить ответы на многие вопросы самому методом общего анализа...
(Данный материал я считаю своей интеллектуальной собственностью, если вы хотите опубликовать его еще где-то, то обязательно указывайте автора(да и пора бы уже научиться всегда указывать авторов, даже без требования) и не так: "ой забыл", "где-то видел", "какой-то чувак", а ник. Если вам понравился материал, можете и ссылку на данный форум скинуть(замаскировав под гиперссылку с текстом), я буду только благодарен.)
[cut=Урок первый. Что такое скрипт?] 1. Все файлы скрипты находятся в папке gamedata\scrips. 2. Файл скрипта - это текстовый файл имеющий расширение .script. 3. В С.Т.А.Л.К.Е.Р используется немного изменённый скриптовый язык Lua 5.1. 4. Для редактирования скриптов я советую NotePad c++, данная программа имеет подсветку синтаксиса для многих языков, в том числе и для Lua. Чтобы активировать подсветку нажмите клините Стиль - Lua. 5. Чтобы закоментировать строку (код игры не будет ёё читать) , необходимо перед строкой поставить -- . Если вы хотите закоментировать кусок (много строк) то --[[ .... ]] , ваш текст будет закоментирован. [/cut]
[cut=Начнём...] 1)Создадим свой my.scripts и поместим его в папку scrips. Откроем с помощью НотПада и настроим подсветку. 2) Внутри файла-скрипта должны содержаться только КОД скрипта и ваши ЗАКОМЕНТИРОВАННЫе пометки. Если будет лишний текст, т.е какие-то знаки и слова, то будет вылет на этот скрипт. Так как код игры полностью собирает весь скрипт в стек и выбирает только то, что вы задали, но если будет мусор, то игра не воспримет код. 3)Архитектур. Для создания функций нужны лишь знания синтаксиса и игровые методы и глобальные функции(которые записаны в движке) можете почитать lua_help.script, но я советую посетить тему на АМК. Там собраны все методы, классы и полное их описание. 4) Функция. Это то, что будет делать игра. [/cut]
[cut=Любая функция начинается со слов]
function my_function() ... end
И заканчивается тегом end. Этот тег означает конец функции, сравнения, он закрывающий и обязателен. Я советую при составлении функций , чтобы не забыть чего-нибудь, писать скелет извне, т.е сначала функция, потом закрывающий тег, и по нарастающей во внутрь. () -Обязательный элемент. Позже расскажу как передавать переменные через этот тег.Между окончание функции и этим тегом ПРОБЕЛА НЕТ.
Обращаю внимание, что все функции вызываются из других скриптов. Допустим нам из одного скрипта, нужно вызвать(запустить функцию в другом) для этого мы пишем название скрипта . название функции в скрипте (парметр если есть) my.my_function()
[/cut]
[cut=Объявляем перменные и глобальные.]
Чтобы объявить какой-либо элемент для функции локальным используется тег local local helth = db.actor.helth Т.е мы расшифровали helth, и показали, что это значение db.actor.helth. Если вы хотите вставить слово или свой текст нужно заключить слово в кавычки. local helth = "Уровень здоровья." Если вы хотите вставить слово с кавычками или свой текст нужно сделать так: local helth = "\"Уровень здоровья."\" Чтобы объявить глобальну нужно всего лишь сделать так helth = db.actor.helth
Глобальные можно объявлять вначале скрипта и она будет сохранятся в коде, в памяти процесса (если я правильно понял) Переменная объявляется только перед функцией и логическими выражениями, где используется переменная и её использует только та функция, перед которой она объявляется (На пальцах перед строкой с вашей функцией). Т.е еслии функция простая без логических решений(if, elseif, for и.т.д) То ставим перед функцией, если же есть переменная, которая находится в теле такого логического решения, то она ставится строго перед этим логическим решением!
local helth = db.actor.helth function my_function() ... end
Чтобы сосчитать значение переменной из другого скрипта достаточно в другом скрипте сделать так: text="Я иду гулять по бродвею" Теперь в нашем скрипте вызываем этот параметр local pisanina = название скрипта . text () - При таком обращении этот тег НЕ СТАВИТСЯ !
[/cut]
[cut=Смысловые значения функций.]
if ..... then .... end Перевожу Если что-то то конец тега. Пример:
if db.actor.psy==0.5 then db.actor:kill(db.actor) end Если пси-здоровье ГГ - половина, то мы его убиваем. Полная функция:
function my_function() if db.actor.psy==0.5 then db.actor:kill(db.actor) end end
[/cut]
[cut=Переделал с переменными(Для чего нужны объявления?):]
local acter = db.actor function my_function() local psy_zdorovie = acter.psy if psy_zdorovie==0.5 then acter:kill(acter) end end Что я сделал? Обозначил кусок db.actor локальной acter. А acter.psy (db.actor)+.psy равносильно db.actor.psy
Вы поняли? Я поразбивал куски на локальные и код получился короче, функция имеет куда меньше знаков и удобнее к пониманию. ВНИМАНИЕ!!!! Переменные должны объявлятся так, чтобы самое то, к чему обращаются было известно. Допустим...
local psy_zdorovie = acter.psy Нам нужна эта acter перменная, и мы ДОЛЖНЫ ОБЪЯВИТЬ её перед переменной local psy_zdorovie = acter.psy Мы ее и объявили local acter = db.actor Думаю смысл понятен?
[/cut]
[cut=Комбинации логических выражений.]
if ...... then 1 действие. else 2 действие. end
Перевод: Если подходит условие то 1 действие иначе (т.е условие не выполняется) 2 действие конец тега Пример:
function my_function() if db.actor.psy==0.5 then db.actor:kill(db.actor) else db.actor.give_info_portion("info") end end
Если пси-здоровье актора равно половине, то мы его убиваем, если же значение другое(любое) , то даем ему инфопоршень.
[/cut]
[cut=Проверка нескольких условий]
Допустим нам нужно проверить несколько условий: Чтобы они все выполнялись!
if (db.actor) and (db.actor.helth==1) and (db.actor.psy ==0.5) then действие end Функция сработает если есть актор и здоровье актора полное и псиздоровье половина.
Тег and - означает И . Если один из элементов не выполняется, то функция не срабатывает. Кстати - это ленивый метод, как писал Kamikaze, если не выполняется первый элемент, то другие - уже не просчитывааются. Т.е. не загнружается процесс....
Если подходит хоть один элемент. if (db.actor) or (db.actor.helth==1) or (db.actor.psy ==0.5) then действие end
Тег or обозначает ИЛИ. Или один, или другой. Функция сработает при условии соответствия хоть одного элемента. Так же ленивый метод. Проверяет до получения утвердительного решения, потом проверка не идет.
[/cut]
[cut=Цепочка elseif.]
Данный метод заменяет перебор через таблицу. Отличается простотой и потерей производительности.
if ...... then самое основное действие elseif ...... then действие 1 elseif ...... then действие 2 elseif ...... then действие 3 elseif ...... then действие 4 elseif ...... then действие 5 end Здесь представлен перебор elseif иначе если, т.е не подходит первый вариант, мы проверяем второй и так по цепочке , до первого подходящего(где выполняется заданное условие), если же ни одно не подойдет, то ничего не произойдет. Если бы мы просто в функции написали кучу
function perebor() if ..... then действие end if ..... then действие end if ..... then действие end if ..... then действие end if ..... then действие end if ..... then действие end end
То ничего хорошего не вышло бы. Так как проверялись бы все функции. А в первом варианте до первого попавшегося...
[/cut]
[cut=Переменная nil]
Пременная нил указывает, что объекта , условия, да чего угодно НЕТ, его не существует. ВСЕГДА проверяйте некоторые объекты на nil Во первых это актор. Можно написать
if (db.actor ~= nil) then .... end
Но правильнее и эстетичнее, сразу писать так.
if (db.actor) then .... end
Проверкой советую проверять многие элементы, так как в игре они зачастую не существуют в определенные моменты...
При обращении к функция из сторонних скриптов(других скрипт-файлов) я советую проверять на наличие этих скриптов:
if имя скрипта then ...... end
if my then ...... end
И делайте всегда, потому как, просто удалите этот скрипт из каталога и не надо будет мучаться с переписыванием других скриптов.
[/cut]
[cut=Рандом.]
Числовой.
math.random(1,100) Данная функция рандомно выберет число от 1 до 100. Сначала ставится наименьшее, потом наибольшее. Если ставить десятичные , допустим (0.0005, 1), то перебуеруться ВСЕ значения, т.е числа с несколькими знаками, ТАК ДЕЛАТЬ НЕ НУЖНО. вы перегрузите некоторые элементы кода. Использование
if math.random(0,1) < 1 then действие end Если выбранное число меньше 1, то срабатывает функция.
Или так.
if math.random(0,1) < 1 then действие else ......
end Добвавляется другое действие. Советую брать целые числа от 1 до 10 для создания процентного срабатывания, но лучше 0 и 1.
Текстовый.
Допустим вы отправляете сообщение и хотите выбрать рандомный текст. Создается таблица с вашими переменными (Это может быть и секция для спавна, и слово, и любая другая переменная)
local my frazi = {"ага","да","нет!","конечно","несомненно"}
Так создается примитивная таблица, каждый элмент записывается в кавычках и отделяется отдельно. Далее, обозначаем за переменную которая нам нужна. Допустим в функции вам нужна пременная text. Мы и пишем . localtext = my frazi[#(my frazi)] И пр и срабатывании функции, обращении к переменной text, выберается рандомная переменная из таблицы my frazi.
[/cut]
[cut=Перебор, повтор действия.]
for i=1, 5000 do действие end
Это цикл, который прокрутнет ваше действие 5000 раз. Переменная i любая буква, число 5000 обозначает количество циклов(сколько раз пройдет ваше действие).
[/cut]
[cut=Передача параметра.]
Допустим мы сделали такую функцию
-- удаляем объект из игры(Взято из АМК )
function remove(remove_item) if remove_item~=nil then alife():release(alife():object(remove_item:id()), true) return true end return false end remove_item - это наш параметр, в данном случае это секция объекта, которую нужно удалить. (немного по секция , если это уникальный объект, то это то,ч то в его конфиге, если нет, то нужно искать другим методом) Нам нужно удалить уникального НПС vasek Если функция находится в скрипте, где мы хотим удалить объект, то пишем
Code
remove(vasek)
Если в другом скрипте, то
Code
имя скрипта.remove(vasek)
Вот такой пример передачи параметра, передавать можно что угодно и как угодно. Было бы воображение.
[/cut]
[cut=Возвращение значений.]
Допустим, идет проверка и если она оканчивается удачно, то функция должна вернуть одну переменную, если нет, то другую.
function my() ifproverka() == true then .....
end end
functionproverka() if db.actor then return true else return false end
Т.е мы хотим проверить наличие актора(можно что угодно). Создаем функцию proverka, она работает так, если актор есть - возвращает(return) одну переменную, в данном случае true (Может быть любая другая) , если проверка не проходит, то возвращается false, а нашей первой my() стоит условие на то, что проверка вернет true ifproverka() == true then Вот так, если вернет, то сработает первая функция.
[/cut]
[cut=Как их вызывать? Функции.]
Функции вызваются из других скриптов, нужно лишь найти место. Если она вызывается постоянно. То нужно пихать в колбэк на апдет в bind_stalker.script
[cut=Кусок кода]
Code
function actor_binder:update(delta) object_binder.update(self, delta)
if string.find(command_line(), "-designer") then return end
if self.already_jumped==false and jump_level.need_jump==true and (device().frame > self.spawn_frame+2000) then jump_level.try_to_jump() self.already_jumped = true return end
-- Вызов апдейта переноса игрока проводником if travel_func ~= nil then travel_func() end
-- DEBUG slowdown --slowdown.update() local time = time_global() game_stats.update (delta, self.object) -- апдейт погоды self.weather_manager:update()
-- Обновление отключения ввода с клавиатуры. if self.st.disable_input_time ~= nil and game.get_game_time():diffSec(self.st.disable_input_time) >= self.st.disable_input_idle then level.enable_input() self.st.disable_input_time = nil end
-- Апдейт прятание оружия игрока во время диалога if self.object:is_talking() then if self.weapon_hide_in_dialog == false then self.object:hide_weapon() printf("hiding weapon!!!") self.weapon_hide_in_dialog = true end else if self.weapon_hide_in_dialog == true then printf("restoring weapon!!!") self.object:restore_weapon() self.weapon_hide_in_dialog = false end end -- Апдейт прятание оружия игрока в зоне sr_no_weapon if check_for_weapon_hide_by_zones() == true then if self.weapon_hide == false then printf("hiding weapon!!!") self.object:hide_weapon() self.weapon_hide = true end else if self.weapon_hide == true then printf("restoring weapon!!!") self.object:restore_weapon() self.weapon_hide = false end end
-- обновление пси-антенны if sr_psy_antenna.psy_antenna then sr_psy_antenna.psy_antenna:update(delta) end --[[ --' Вывод сообщения о большой радиации if self.object.radiation >= 0.7 then local hud = get_hud() local custom_static = hud:GetCustomStatic("cs_radiation_danger") if custom_static == nil then hud:AddCustomStatic("cs_radiation_danger", true) hud:GetCustomStatic("cs_radiation_danger"):wnd():TextControl():SetTextST("st_radiation_danger") end else local hud = get_hud() local custom_static = hud:GetCustomStatic("cs_radiation_danger") if custom_static ~= nil then hud:RemoveCustomStatic("cs_radiation_danger") end end ]]--
if self.bCheckStart then printf("SET DEFAULT INFOS") if not has_alife_info("global_dialogs") then self.object:give_info_portion("global_dialogs") end if not has_alife_info("level_changer_icons") then self.object:give_info_portion("level_changer_icons") end self.bCheckStart = false
-- if self.actor_weapon_on_start == true then -- db.actor:activate_slot(3) -- self.actor_weapon_on_start = false -- end end -- device().precache_frame == 0 and if not self.loaded_slot_applied then self.object:activate_slot(self.loaded_active_slot) self.loaded_slot_applied = true end xr_s.on_actor_update(delta)
if(self.surge_manager) then if(self.f_surge_manager_loaded ~= true) then self.surge_manager:initialize() self.f_surge_manager_loaded = true end if(self.surge_manager.levels_respawn[level.name()]) then self.surge_manager:respawn_artefacts_and_replace_anomaly_zone() end self.surge_manager:update() end -- Апдейт доступности для симуляции. simulation_objects.get_sim_obj_registry():update_avaliability(alife():actor())
if not self.loaded then get_console():execute("dump_infos") self.loaded = true end treasure_manager.get_treasure_manager():update()
if not(primary_objects_filled) then pda.fill_primary_objects() primary_objects_filled = true end pda.fill_sleep_zones() --СЮДА в САМЫЙ КОНЕЦ end
В том же скрипте есть колбэки на взятие, потерю, использование предметов. Нужно лишь искать..... Этим вы займетесь сами, или спросите у меня...
В диалогах можно вызывать через тег (без () )
Code
<action> имя скрипта.функция</action>
[/cut]
Есть еще способы через логику, но они вам сейчас не нужны, а как понадобятся, вы сами их найдете. В этом деле главное терпение , находчивость и желание. Коды за вас никто писать не будет. В лучшем случае дадут пару советов и пошлют http://www.lua.ru/. А в обычном скажут, руки не оттуда растут....
Возможны неточности.
Сообщение отредактировал Gonta - Вс, 20.11.2011, 13:53
Эти 0 пользователя(ей) поблагодарили Gonta за это полезное сообщение:
Урок 30 (автор GEONEZIS) Задача: Данный урок посвящен созданию и добавлению новых бронекостюмов в S.T.A.L.K.E.R. Зов Припяти. Полный разбор будет приведен на примере мода Geonezis Addon for SGM 1.7.
Для начала необходимо разобрать секции конфигурационного файла стандартных костюмов и шлемов в Зове Припяти. Для примера рассмотрим секцию легкого костюма Свободы и Противогаза ШМС из оригинальной игры. Не рекомендуется изменять те параметры по которым не даны комментарии.
Для этого откроем файл outfit.ltx- путь (S.T.A.L.K.E.R. Зов Припяти\gamedata\configs\misc\) и найдем там следующме секции:
[cut=Секция бронекостюма] ;--------------------------------------------------------------------------------------------- ; ЛЕГКИЙ КОСТЮМ СВОБОДЫ ;--------------------------------------------------------------------------------------------- [svoboda_light_outfit]:outfit_base - - название секции костюма, именно к нему игра будет обращаться . outfit_base- базовый, родительский класс (изменять его строго не рекомендуется). GroupControlSection = spawn_group ---секция спавн группы discovery_dependency = ----- $spawn = "outfit\svoboda_light_outfit"---- тут прописывается секция самого спавна ;$prefetch = 32 class = E_STLK--- класс cform = skeleton ----- форма visual = dynamics\outfit\svoboda_light_outfit—путь к модели модели и сама модель, используемая для костюма, лежащего в виде предмета. actor_visual = actors\stalker_hero\stalker_hero_freedom_1.ogf--- путь к модели и сама модель, используемая для ГГ когда на нем надет данный костюм. player_hud_section = actor_hud_03-----секция худа рук ГГ. указывает на использованную секцию в которой прописана модель рук ГГ при одевании данного костюма. ef_equipment_type = 3--- параметр типа. Незнаю за что он точно отвечает- варьируется от 2 да 5 в зависимости от вида костюма. 2- для научного, 3- для большинства остальных, 4- для тяжелых (милитари, долг), 5- экзоскелет inv_name = svoboda_light_outfit_name-------секция имени костюма. Ссылается на текст из xml-файла с названием. inv_name_short = svoboda_light_outfit_name-------секция имени костюма при наведении на предмет. Аналогичен предыдущему параметру. description = svoboda_light_outfit_description-----секция описания костюма. Ссылается на текст из xml-файла с описанием. inv_weight = 4.0-------------вес бронекостюма в инвентаре. inv_grid_width = 2------------ширина иконки в файле ui_icon_equipment.dds inv_grid_height = 3------------ высота иконки в файле ui_icon_equipment.dds inv_grid_x = 12----------положение по оси Х в файле ui_icon_equipment.dds inv_grid_y = 13---------- положение по оси Y в файле ui_icon_equipment.dds upgr_icon_x = 6----------- положение по оси Х в файле ui_actor_armor.dds upgr_icon_y = 455----------- положение по оси Y в файле ui_actor_armor.dds upgr_icon_width = 302----------- ширина иконки апгрейда в файле ui_actor_armor.dds upgr_icon_height = 117----------- высота иконки апгрейда в файле ui_actor_armor.dds full_icon_name = npc_icon_svoboda_light_outfit-----------секция названия иконки cost = 6500------------цена костюма slot = 6------слот full_scale_icon = 10,11; --------иконка сталкера в костюме в полный рост immunities_sect = sect_svoboda_light_outfit_immunities----------ниже прописаны секции параметров защиты владельца от различных типов воздействий, обеспечиваемые костюмом при его ношении. ; LOW RESISTANCE burn_protection = 0.0700----------- защита от воздействия огня (костры, аномалия "Жарка".) shock_protection = 0.250---------- защита от поражения электричеством. radiation_protection = 0.0035-------------- защита от радиации. chemical_burn_protection = 0.0375--------- защита от химического воздействия. telepatic_protection = 0.0-------------- защита от пси-воздействия. strike_protection = 0.22---------------- защита от ударов (наносятся мутантами, например, псевдогигантом). explosion_protection = 0.25---------------- защита от взрывов/осколков. wound_protection = 0.22----------- защита от ранений (наносятся мутантами, например, собаками, кровососами и т.д.). hit_fraction_actor = 0.6 bones_koeff_protection = actor_armor_light--------коэфициент пулестойкости artefact_count = 2------------количество интегрированных контейнеров для артефактов control_inertion_factor = 1.2 power_loss = 0.6 upgrades = up_gr_firstab_svoboda_light_outfit, up_gr_seconab_svoboda_light_outfit, up_gr_thirdab_svoboda_light_outfit-------применяемые апгрейды installed_upgrades =------------установленные апгрейды upgrade_scheme = upgrade_scheme_svoboda_light_outfit------вся схема апгрейдов в окне модификации
[sect_svoboda_light_outfit_immunities]- коэффициенты иммунитета самого костюма, то есть - то, насколько сильно он сам подвержен повреждениям от различных типов воздействий. burn_immunity = 0.05 - защита от воздействия огня (костры,аномалия "Жарка" и т.д.) strike_immunity = 0.0 - защита от ударов (наносятся мутантами, например, псевдогигантом) shock_immunity = 0.05 - защита от поражения электричеством. wound_immunity = 0.05 - - защита от ранений (наносятся мутантами, например, собаками, кровососами и т.д.) radiation_immunity = 0.0--- защита от радиации. telepatic_immunity = 0.0 - защита от пси-воздействия (например, присутствие контроллера серьезно влияет на psy_health) chemical_burn_immunity = 0.05 - защита от химического воздействия. explosion_immunity = 0.05 --- - защита от взрывов/осколков. fire_wound_immunity = 0.015------- - защита от огнестрельного оружия.
sprint_allowed = false---------разрешен ли бег. helmet_avaliable = false---------разрешено ли ношение шлема additional_inventory_weight = 30-----------на сколько увеличивается максимально переносимый вес. nightvision_sect = effector_nightvision_1-------------секция использованного ПНВ [/cut]
[cut=Секция шлема] ;--------------------------------------------------------------------------------------------- ; ПРОТИВОГАЗ ШМС ;--------------------------------------------------------------------------------------------- [helm_respirator]:helmet - название секции шлема,именно к нему игра будет обращаться.helmet - базовый, родительский класс (изменять его строго не рекомендуется). $spawn = "outfit\helm_respirator" - тут прописывается секция спавна visual = dynamics\outfit\helm_respirator – путь к модели и сама модель предмета противогаза control_inertion_factor = 1.0 - управление инершион фактором inv_name = st_helm_respirator - секция имени костюма. ссылается на текст из xml-файла с названием. inv_name_short = st_helm_respirator - секция имени костюма при наведении на предмет. аналогичен предыдущему параметру. description = st_helm_respirator_descr - секция описания костюма. Ссылается на текст из xml-файла с описанием.
inv_weight = 4.0 - Вес шлема
inv_grid_width = 2 - ширина иконки в ui_icon_equipment.dds inv_grid_height = 2 - высота иконки в ui_icon_equipment.dds inv_grid_x = 4 - положение по Х в ui_icon_equipment.dds inv_grid_y = 18 - положение по У в ui_icon_equipment.dds
upgr_icon_x = 20 - тут всё тоже самое но только для иконки Апгрейда - ui_actor_armor.dds upgr_icon_y = 619 - тут всё тоже самое но только для иконки Апгрейда - ui_actor_armor.dds upgr_icon_width = 106 - тут всё тоже самое но только для иконки Апгрейда - ui_actor_armor.dds upgr_icon_height = 149 - тут всё тоже самое но только для иконки Апгрейда - ui_actor_armor.dds
cost = 1000 - цена
immunities_sect = sect_helm_respirator_immunities – используемые секции иммунитета bones_koeff_protection = actor_helm_respirator - защита головы ГГ
telepatic_protection = 0.0200 – доп. защита придаваемая ГГ от телепатии radiation_protection = 0.0015 - доп. защита придаваемая ГГ от радиации chemical_burn_protection = 0.0500 - доп. защита придаваемая ГГ от химических воздействий
upgrades = up_gr_firstab_helm_respirator - это код на апгрейд installed_upgrades =-------установленные апгрейды upgrade_scheme = upgrade_scheme_helm_respirator - это код на схему апгрейдов
[sect_helm_respirator_immunities] - коэффициенты иммунитета самого шлема, то есть - то, насколько сильно он сам подвержен повреждениям от различных типов воздействий. по значениям каждого типа
burn_immunity = 0.04 - защита от воздействия огня (костры,аномалия "Жарка" и т.д.) strike_immunity = 0.0 - защита от ударов (наносятся мутантами, например, псевдогигантом) shock_immunity = 0.04 - ащита от поражения электричеством. wound_immunity = 0.0 - защита от ранений (наносятся мутантами, например, собаками, кровососами и т.д.) wound_2_immunity = 0.0 - защита от ранений (наносятся мутантами, например, собаками, кровососами и т.д.) radiation_immunity = 0.0 - защита от радиации. telepatic_immunity = 0.0 - защита от пси-воздействия (например, присутствие контроллера серьезно влияет на psy_health) chemical_burn_immunity = 0.04 - защита от химического воздействия. explosion_immunity = 0.04 - защита от взрывов/осколков. fire_wound_immunity = 0.04 - защита от огнестрельного оружия.
[/cut]
Знание значений всех этих параметров конфигов необходимы для создания своего собственного бронекостюма.
Теперь приступим к созданию и добавлению нового бронекостюма в мод.
В качестве примера я буду использовать изолирующий бронекостюм Гагарин- (автор ruslan_3d) Для его добавления необходимо будет вносить изменения в следующие файлы (в скобках приведен путь к файлу), либо же добавить сами файлы:
Прежде всего необходимо разместить модели и текстуры необходимые для добавления костюма. Предположим все они уже есть- мы их взяли из другого мода, либо же сделали сами. Имеем: - модель визуала для НПС назовем файл ogf-модели stalker_soldier_izol_1.ogf. Разместим ее в \gamedata\meshes\actors\stalker_soldier\ - модели предмета костюма пусть будет ogf-файл soldier_izol_1_outfit.ogf. Разместим ее в \gamedata\meshes\dynamics\outfit\ - текстуры для этих моделей разместим по прописанному в них пути. в данном случае все текстурные файлы, бампы (act_stalker_soldier_izol_1.dds, act_stalker_soldier_izol_1.thm, act_stalker_soldieri1_bump#.dds, act_stalker_soldieri1_bump.dds) разместим в \gamedata\textures\act\ - модель рук ГГ при одевании добавляемого костюма. пусть это будет ogf-файл wpn_hand_i1.ogf. разместим ее в папку с остальными моделями рук gamedata\meshes\dynamics\weapons\wpn_hand\ там же создадим и добавим конфигурационный файл wpn_hand_i1.ltx- его содержимое можно целиком копировать из подобного. - текстуры для рук в данном случае файл act_armi1.dds разместим в \gamedata\textures\act\
Если мы используем свои модели- то текстуры для них необходимо размещать в той папке путь в которой прописан в ней. Просмотреть его можно через milkshape 3d, ogf-viewer, notepad++. Если эти текстуры будут расположены в других папках- то в игре мы увидим синие неоттекстурированные модели.
Следующий шаг. Создаем основную секцию конфига бронекостюма в outfit.ltx. В SGM она имеет некоторые отличия от стандартной:
Отдельно здесь рассмотрим секции: - mod_soldier_izol_1 – добавляется только в sgm, в оригинальном ЗП- не нужна. Прописывается в файле sgm_sections.ltx. код:
- cost_soldier_izol_1_outfit- секция цены бронника. В чистом ЗП достаточно в основной конфиг просто добавить строчку
Code
cost = 75000.
В sgm все цены вынесены в отдельный файл costs.ltx прописываем в нем код:
Code
[cost_soldier_izol_1_outfit] cost = 75000
В остальном же основной конфиг в sgm и зп практичеки идентичны. Еще одно отличие это в секции upgrades. В чистом ЗП она будет иметь несколько другой вид- связано это с тем что SGM добавляет возможность ставить абсолютно все возможные ветки апгрейдов в отличие от оригинала.
Создаем секцию защиты от повреждений которая будет соответсвовать данному костюму. (actor_armor_soldier_izol_1)
Открываем файл damages.ltx и прописываем в нем следующий код:
В данном случае это секция является полностью наследственным обьектом от родительских классов actor_body_damage_heavy и actor_head_damage_battle- то бишь будет иметь те же показатели и параметры что и они. В принципе можно использовать и другие из обозначенных в файле ранее (actor_body_damage_exo, actor_body_damage_sci, actor_head_damage_tactic…..) либо же обьявить свою собственную со своими параметрами... К примеру такие:
В ней указан путь к модели и сама модель худа рук используемая в данном бронике, которую мы добавили ранее.
текстовые файлы- прописываем секции названия и описания. Откроем файл st_items_outfit.xml и прописываем в нем следующий код обоих секций:
Code
<string id="soldier_izol_1_outfit_name"> <text>Армейский изолирующий бронекостюм Гагарин</text> </string> <string id="soldier_izol_1_outfit_description"> <text>%c[default]Характеристики переноса:\n%c[255,238,153,26]• %c[default]Мин. переносимый вес = 57.5 кг\n%c[255,238,153,26]• %c[default]Макс. переносимый вес = 67.5 кг\n%c[default]Характеристики защиты:\n%c[255,238,153,26]• %c[default]Пулестойкость = 60%\n%c[default]Армейский изолирующий бронекостюм «ГАГАРИН», созданный для проведения штурмовых операций в экстремальных условиях Зоны. Снабжён внешним изоляционным покрытием и системой дыхания замкнутого цикла, основным элементом которой является модификация противогаза ГП-17. Благодаря подобному решению великолепно защищает от аномальных воздействий. Основой броневой защиты является модификация жилетов серии Форт Редут Т7, которая обеспечивает прекрасную защиту от оболочечных пуль и осколков, при этом не снижает подвижности владельца. Несмотря на великолепные защитные свойства с точки зрения сталкеров обладает следующими недостатками: малым переносимым весом и отсутствием встроенных контейнеров для артефактов.</text> </string>
Думаю здесь особые комментарии излишни. Основное это недопустить синтаксических ошибок в структуре xml-файла и проверить соответсвие имен секций здесь и в основном конфиге. Пропишем новую основную ogf-модель в файле prefetch_single.ltx Код следующий:
Code
actors\stalker_soldier\stalker_soldier_izol_1
В принципе на этом основная настройка конфига завершена. Следующим этапом будет обьявление апгрейдов и прочие настройки. По апгрейдам. В принципе можно особо с этим не заморачиваться, а прописать стандартную схему апгрейдов от любого другого бронекостюма. В конфиге это секции upgrade_scheme и upgrades.
Однако рассмотрим более сложный вариант где необходимо будет самому создавать и прописывать линейку апгрейдов.
1. создадим сам файл апгрейдов - o_stalker_heavy_1_up.ltx
Рассмотрим полностью участок его кода и дадим некоторые комментарии по прописанным в нем секциям.
[up_fifthf_soldier_izol_1_outfit] scheme_index = 2, 7 known = 1 effects = section = up_sect_fifthf_soldier_izol_1_outfit property = prop_night_vision precondition_functor = inventory_upgrades.precondition_functor_a precondition_parameter = a & b effect_functor = inventory_upgrades.effect_functor_a effect_parameter = something_here prereq_functor = inventory_upgrades.prereq_functor_a prereq_tooltip_functor = inventory_upgrades.prereq_tooltip_functor_a prereq_params = name = st_up_resp_c1_name description = st_up_resp_c1_descr icon = ui_inGame2_upgrade_soldier_izol_1_outfit_22 .................................... [up_gr_fifthe_soldier_izol_1_outfit] elements = up_fifthe_soldier_izol_1_outfit [up_gr_fifthf_soldier_izol_1_outfit] elements = up_fifthf_soldier_izol_1_outfit
[/cut]
Теперь попытаюсь вкратце пояснить что это все означает и как это вообще едят. Также считаю изначально нужно обьявить что при создании и добавлении своей линейки апгрейдов- в ориг. ЗП- они имеют незначительно другую структуру, немного отличную от приведенной выше. (связанно с тем что в sgm на костюм ставятся все апгрейды)
Всего для нашего костюма автором было создано 22 секции уникальных апгрейдов. Каждая из них отдельно объявлена и закомментирована.
Изначально прописываются основная секция изменяемых свойств. К примеру рассмотрим:
Code
[up_sect_fifthf_soldier_izol_1_outfit] cost = 10500 value = +3 nightvision_sect = effector_nightvision_3
Это основная секция в которой указывается цена (cost), значение (value- влияние на интегрированный параметр) и устанавливаемый апгрейд. В данном случае это ПНВ 3-его поколения. Остальные 21 секции расписаны по подобному образу.
[cut=Некоторые используемые в них параметры:] -additional_inventory_weight- сколько дополнительного веса может перенести ГГ в данном костюме при установке апгрейда. -power_restore_speed- параметр восстановления выносливости -shock_protection, burn_protection, chemical_burn_protection, radiation_protection, telepatic_protection- доп защита от радио-, химио-, огне-,электро- и прочих повреждений. - artefact_count- кол-во дополнительных контейнеров для артефактов - nightvision_sect- секция используемого ПНВ - strike_protection, explosion_protection, wound_protection- защата от взрывов ударов и прочего - bleeding_restore_speed- параметр скорости остановки кровотечения - health_restore_speed- параметр скорости восстановления здоровья - immunities_sect_add- в нем прописывается секция параметров увеличения устойчивости самого костюма к различным воздействиям (в данном случае sect_soldier_izol_1_outfit_immunities_add- обьявлена в основном конфиге) - bones_koeff_protection_add- дополнительный коэффициент прибавляемой секции пулестойкости актора. Эти секции прописываются в damages.ltx (в данном случае это actor_armor_heavy_add_3) [/cut]
Дальше:
Обьявленная в начале секция прописывается в сам апгрейд. Вот его примерный код:
[up_fifthf_soldier_izol_1_outfit] scheme_index = 2, 7------------- порядковый номер колонки и ячейка (счет с нуля) для иконки в схеме апгрейда known = 1----------- извстен или нет апгрейд механикам (параметр по умолчанию 1) (лучше не изменять) effects =-------- следующий апгрейд в линейке апгрейдов (апгрейд может содержать несколько элементов) (в sgm-не заполнен) section = up_sect_fifthf_soldier_izol_1_outfit--------- имя используемой основной секции обьявленной выше. property = prop_night_vision-------------то свойство которое редактируется данным апгрейдом precondition_functor = inventory_upgrades.precondition_functor_a----------функция предусловия апгрейда (вызывается из файла inventory_upgrades.script) precondition_parameter = a & b------параметр предусловия (не изменять) effect_functor = inventory_upgrades.effect_functor_a----------------функция применения апгрейда (отнимания денег, вызывается из файла inventory_upgrades.script) effect_parameter = something_here-------параметр для предудущей функции prereq_functor = inventory_upgrades.prereq_functor_a---------------функция отображения нужных средств для обьекта (вызывается из файла inventory_upgrades.script) prereq_tooltip_functor = inventory_upgrades.prereq_tooltip_functor_a--------- функция не используется (отображение нужного типа инструментов) prereq_params = name = st_up_resp_c1_name------------имя апгрейда- прописано в xml- файле description = st_up_resp_c1_descr-----------описание апгрейда- прописано в xml- файле icon = ui_inGame2_upgrade_soldier_izol_1_outfit_22------иконка для апгрейда
[cut=некоторые свойства] Некоторые свойсва для апгрейдов (параметр property) Устанавливается в зависимости от вида апгрейда то есть на что он влияет. Также возможна установка нескольких параметров одновременно если до того в основной секции были прописаны несколько свойств. - prop_armor--------секция пулестойкости для актора - prop_durability---- повышение стойкости самого костюма к воздействиям - prop_damage----защита от взрывов, ударов - prop_electro-----электро защита - prop_thermo----термо защита - prop_chem-------хим. защата - prop_radio-------радиозащита - prop_power------выносливость - prop_psy---------пси-защита - prop_tonnage---------доп. переносимый вес - prop_restore_bleeding------остановка кровотечения - prop_restore_health------востановление здоровья - prop_artefact---------контейнеры для артефактов - prop_night_vision-------ПНВ [/cut]
И собственно сама схема апгрейда. Например:
Code
[up_gr_fifthf_soldier_izol_1_outfit] elements = up_fifthf_soldier_izol_1_outfit
Она же прописывается в основном конфиге костюма, может содержать несколько элементов.
Так, с основными апгрейдами разобрались. Теперь необходимо прописать в игре созданную схему апгрейдов.
1. Открываем файл item_upgrades.ltx и добавляем в него следующий код:
Code
#include "misc\outfit_upgrades\o_soldier_izol_1_up.ltx" Этим самым мы подключили файл o_soldier_izol_1_up.ltx к остальным
2.В файле inventory_upgrade.xml и inventory_upgrade_16.xml (для широкоформата) прописывается схема координат размещения клеток и колонок апгрейдов в меню окна модификации у техника. В секции ячейки (cell) x,y - координаты левого верхнего угла иконки,point_x, point_y - координаты точки-указателя места апгрейда на картинке с костюмом.
4. теперь необходимо прописать все наши апгрейды, а также собственно способность проведения усовершенсвования нового костюма у техников. - в файле inventory_upgrades.ltx прописываем имя секции броника soldier_izol_1_outfit этим самым мы добавили наш костюм в общий список предметов на которые распространяются возможность проведения усовершенствований - в файле stalkers_upgrade_info.ltx чуть посложнее. В этом файле расписана секция конфига для каждого техника в игре. Добавим к примеру возможность проведения модифицирования нашего бронника Кардану.
Сначала также допишем в общий список предметов имя костюма - soldier_izol_1_outfit Потом закоментируем сами апгрейды в секции [jup_b217_stalker_tech_upgr]
Так, ну и естественно необходимо не забыть внести изменения во все текстурные файлы - добавить туда иконку костюма для инвентаря, для апгрейда, иконки самих апгрейдов. Можно это проводить на любом этапе- от этого зависит настройка координат в некоторых файлах.
Добавление в торговлю- тут не буду ничего подробно расписывать- слишком много файлов это затрагивает- для примера можно прописать их в trade_zat_b30_stalker_trader.ltx по образу и подобию остальных броников.
Последний этап- редактирование скриптов.
1. Добавим наш новый бронник
Code
"soldier_izol_1_outfit"
в файл ui_mod_spawner.script (только для sgm) 2. Для того чтобы в случае если на акторе будет одет новый костюм и ГГ попытается при этом вступить в разговор с Германом (первый диалог на квест поиска изолятора в тоннеле) последний не отсылал его за хорошим костюмом нужно в файле dialogs_jupiter.script найти функцию jup_b1_actor_have_good_suit и дописать в нее следующую строчку:
Code
["soldier_izol_1_outfit"] = true,
3. Для того чтобы в новой костюме был возможен поход в Припять найдем в файле dialogs_jupiter.script функции jup_b15_actor_sci_outfit и jup_b15_no_actor_sci_outfit - добавим туда слующую строку-
Code
db.actor:object("soldier_izol_1_outfit")~=nil
и в файле xr_conditions.script в функции jup_b218_actor_outfit_precond также добавим строку
Code
db.actor:object("soldier_izol_1_outfit")~=nil
4. Дабавим наш бронник в схему обыска трупов- откроем файл xr_corpse_detection.script и таблицу допишем следующую строчку
Code
lootable_table["soldier_izol_1_outfit"] = true
На этом все. Осталось для эксперемента прописать броник у ГГ в самом начале игры ( в character_desc_general.xml) и протестить что у нас получилось.
Переделал урок по общепринятому образцу. denis2000 Смерти Вопреки Spectrum Project AP_Prodaction
Сообщение отредактировал GEONEZIS - Пн, 09.01.2012, 18:55
Эти 0 пользователя(ей) поблагодарили Geonezis за это полезное сообщение:
Урок 31 (автор GEONEZIS) Задача: Данный урок посвящен обучению принципу построения и работы с диалогами в игре на примере Зова Припяти.
Все диалоги в STALKER создаются по средствам языка разметки XML. Хранятся они в специальных XML- файлах. Соответственно изначально скажу несколько слов про этот язык.
XML – представляет собой расширяемый язык разметки. Файл XML - документ, в котором использованы теги для определения объектов и их атрибутов. Форматирование данных напоминает язык разметки HTML-документов. Но в отличие от HTML, в XML используются теги, которые задаются пользователями.
Структура XML-документа представляет собой дерево элементов. Некоторые элементы имеют содержимое и атрибуты.
Например,
Code
<cell id="number">value</ cell >
Здесь <cell>,</cell> - открывающий и закрывающий теги элемента, id- атрибут, number - значение атрибута,value - содержимое.
XML-файлы и файлы других расширений, основанные на языке XML, получили очень широкое распространение. В XML-файлах хранятся самые различные данные - от настроек приложений до баз данных. Файлы на основе XML используются для обмена информацией в Интернете и между программами (для этого данный язык разметки и был изначально задуман). Т.к. файлы формата XML содержат текстовые данные, их можно легко отредактировать в любом текстовом редакторе. Например Notepad++
Теперь собственно приступим к разбору и созданию диалогов в игре S.T.A.L.K.E.R. Зов Припяти. 1. Базовые сведения.
Для создания своего диалога нам потребуются два файла. Первый это сам файл диалога- в котором будет отображаться его структура. Второй- это файл с текстами- где будут находиться его фразы на русском языке. Для начала не будем создавать и подключать свои собственный XML- файлы для диалогов, а используем уже имеющиеся в игре.
Файлы с самими диалогами храняться в S.T.A.L.K.E.R. - Зов Припяти\gamedata\configs\gameplay\
Файлы с готовыми фразами на русском языке в S.T.A.L.K.E.R. - Зов Припяти\gamedata\configs\text\rus\
Откроем два файла- st_dialogs_zaton.xml и dialogs_zaton.xml. К примеру будем редактировать их программой Notepad++
Рассмотрим общую структуру построения диалогов на простейших примерах.
- Создадим самый простой диалог в две фразы:
В файл dialogs_zaton.xml в самом низу то тега </game_dialogs> добавим следующий код:
Это скелет нашего диалога. Рассмотим конкретно что означает каждая строчка. Буду давать пояснение для “полного” тега.
Code
<dialog id="…………."> ... </dialog>
Собственно это сам диалог- его начало с указанием уникального имени (в примере это first_test_dialog) и закрывающий тег в конце.
Code
<phrase_list> .............. </phrase_list>
Дословно- список фраз. Внутри него будут располагаться сами фразы.
Code
<phrase id="….."> ………………… </phrase>
Простейшая фраза диалога. Каждая фраза диалога имеет свой уникальный порядковый номер внутри него. Отсчет номера фразы начитается с 0. Дальше порядковые номера задает сам пользователь. Желательно для самого себя выбрать последовательную систему нумерации фраз, для удобства в написании диалога.
Code
<text>……………..</text>
Тег текста- внутри него будет расположено уникальное название секции на английском языке (также имеющая свою порядковую последовательность) для связи со вторым XML- файлом с русскими фразами.
Code
<next>……</next>
Тег следующей фразы. Внутри него указывается уникальной номер следующий фразы диалога.
Теперь пропишем русские фразы для нашего диалога. Открываем файл st_dialogs_zaton.xml И в самом конце до тега </string_table> прописываем следующий код
Это тег текстовой фразы. В нем внутри тегов <text>……………..</text> будет приводиться русский текст. Уникальное имя фразы должно соответсвовать внутреннему значению тегов <text>……………..</text> Из основного файла (в нашем случае это first_test_dialog_ )
Некоторые пояснения: 1. первая фраза в диалоге такой структуры будет принадлежать ГГ (майору Дягтереву). 2. данный диалог является зацикленным- тобишь будет всегда повторяться.
В процессе продолжения урока буду рассказывать как изменить то что указано в пояснениях.
Теперь осталось только добавить этот диалог какому-нибудь НПС. К примеру Бороде. Для этого откроем файл character_desc_zaton.xml (S.T.A.L.K.E.R. - Зов Припяти\gamedata\configs\gameplay\) найдем в нем секцию НПС Бороды <specific_character id="zat_a2_stalker_barmen" team_default="1"> … </specific_character> и добавим наш диалог
Инфопорции в игре играют едва ли не ключевую роль. По сути дела это еденица информации несущая в себе определенный смысл. Инфопорции используются практичеки во всех диалогах. Они имеют свое уникальное имя. Прописываются также в XML-файлах. К примеру мы будем их добавлять в файл-info_zaton.xml. (\gamedata\configs\gameplay\)
От наличия или отсутствия той или иной инфопорции будет зависить какие фразы будут генерироваться в диалоге. Также в диалоге будет происходить выдача, либо запрет тех инфопорций которые используются для других целей.
Приведу основные операции над инфопорциями в диалогах:
- <give_info>zat_info_test_1</give_info> - выдача инфопорции с именем, записанным в теле тега. - <has_info> zat_info_test_1</has_info> - проверка на наличие инфопорции с именем, записанным в теле тега. - <dont_has_info> zat_info_test_1</dont_has_info> - проверка на отсутствие инфопорции с именем, записанным в теле тега.
- Теперь перепишем самый первый диалог так чтобы он исчезал после его прочтения.
В данном примере перед началом списка фраз стоит тег обеспечивающий блок диалога при наличии инфопорции с именем zat_info_test_1. Соответсвенно ее выдача происходит внутри диалога.
В завершении этого вводного урока подробно рассмотрим и прокомментируем один готовый диалог из оригинальной игры.
Этот диалог принадлежит Султану. Вот его фразы на русском языке чтобы было понятно о чем в нем речь.
Code
<string id="zat_b7_bandit_boss_sultan_b30_start_actor_dialog_0"> <text>Борода должен мне денег. Сыч сказал, что ты можешь помочь.</text> </string> <string id="zat_b7_bandit_boss_sultan_b30_start_actor_dialog_1"> <text>Могу, есть мыслишка... Расклад такой: обламываем Бороде бизнес, я его беру под себя, ты получаешь долю и свой бабос. Идет?</text> </string> <string id="zat_b7_bandit_boss_sultan_b30_start_actor_dialog_2"> <text>Фиг там. Нет возможности на него повлиять. Хотел пережать ему каналы поставок, так этот гад бородатый всё равно где-то достал «Компас». Считай, у него всё бархатом... пока что.</text> </string> <string id="zat_b7_bandit_boss_sultan_b30_start_actor_dialog_11"> <text>Идёт.</text> </string> <string id="zat_b7_bandit_boss_sultan_b30_start_actor_dialog_111"> <text>Тогда твое дело - узнать, что за дела Борода вертит конкретно сейчас. Похерим ему каналы поставок, и все будет в ажуре.</text> </string> <string id="zat_b7_bandit_boss_sultan_b30_start_actor_dialog_12"> <text>Я подумаю.</text> </string> <string id="zat_b7_bandit_boss_sultan_b30_start_actor_dialog_121"> <text>Учти, много думать - вредно для здоровья.</text> </string>
Итак: 1. <has_info>zat_b30_owl_to_sultan</has_info> - говорит о том что для появлении этого диалога у Султана необходиио начичии инфопорции zat_b30_owl_to_sultan. 2. <dont_has_info>zat_b30_actor_with_sultan</dont_has_info>- значит диалог не будет доступен в случае наличия выданной инфопорции zat_b30_actor_with_sultan. 3. после генерации первой фразы происходит разветвление диалога и выбор ветки в зависимости от наличия или отсутсвия поршня zat_b30_barmen_got_af соответсвенно в диалоге это <dont_has_info>zat_b30_barmen_got_af</dont_has_info> и <has_info>zat_b30_barmen_got_af</has_info> В случае наличия этого поршня выбирается фраза с айди номером 2, в противоположном случае фраза с айди номером 1. 4. первый вариант ведет к завершению диалога, второй же так же имеет разветвление на фразы с идентификаторами 11 и 12. 5. При выборе одной из этих фраз будет доступно повторение диалога или же его окончательное завершение происходящее после выдачи инфопорции <give_info>zat_b30_actor_with_sultan</give_info>
Смерти Вопреки Spectrum Project AP_Prodaction
Сообщение отредактировал GEONEZIS - Чт, 09.02.2012, 15:39
Эти 0 пользователя(ей) поблагодарили Geonezis за это полезное сообщение:
Создаем скрипт scripts\use_corps.script с функцией on_use_corpse(npc) в которой будем выдавать деньги при юзаньи трупа НПС. Функция приблизительно текая:
Код
function on_use_corpse(npc) local extract_value=0 local npc_rank = ranks.get_obj_rank_name(npc) if npc_rank~=nil then if npc_rank=="novice" then extract_value=math.random(10,50)+math.random(5,25) elseif npc_rank=="experienced" then extract_value=math.random(20,100)+math.random(10,50) elseif npc_rank=="veteran" then extract_value=math.random(100,200)+math.random(50,100) elseif npc_rank=="master" then extract_value=math.random(200,500)+math.random(100,250) end if extract_value ~= 0 then local bringed_money=math.floor(extract_value) db.actor:give_money(bringed_money) news_manager.send_tip(db.actor,"Получены деньги "..tostring(bringed_money),0,"kingpin",4000,nil) end end end
extract_value - количество "извлеченных" денег, npc_rank - ранг НПС. Далее проверяем, что ранг существует и равен одному из четырех вариантов. В зависимости от ранга назначаем случайную сумму (двойное использование генератора случайных чисел повышает разнообразие вариантов). Потом округляем сумму, выдаем деньги ГГ и посылаем сообщение о количестве "снятых" денег. Осталось только вызывать функцию при первом юзаньи мертвого НПС. Давайте скопируем файл scripts\xr_motivator.script из ресурсов игры и начнем его редактировать. Для начала в функции motivator_binder:use_callback(obj, who) после
Код
if self.st.active_section then xr_logic.issue_event(self.object, self.st[self.st.active_scheme], "use_callback", obj, who) end
добавим:
Код
else if self.once_use_processed == false then self.once_use_processed = true use_corps.on_use_corpse(self.object) end
Функция motivator_binder:use_callback(obj, who) - вызывается каждый раз при юзаньи НПС, мы добавили вызов своей функции в случае если НПС не жив (тоесть мертв). К тому же ввели параметр once_use_processed - показывающий что текущий НПС уже был юзан (чтобы не выдавать деньги до бесконечности). Теперь нужно про инициализировать параметр и обеспечить его сохранение и загрузку: Инициализация: В функции motivator_binder:__init (obj) super(obj) добавим
Код
self.once_use_processed = false
Сохранение: В функции
Код
motivator_binder:save(packet)
после
Код
trade_manager.save(self.object, packet)
добавим
Код
packet:w_bool(self.once_use_processed)
Загрузка: В функции
Код
motivator_binder:load(reader)
после
Код
trade_manager.load(self.object, reader)
добавим
Код
self.once_use_processed = reader:r_bool()
Все можно проверять.
Урок 32 (автор denis2000) Задача: Перенос моделей оружия из ТЧ в ЧН/ЗП. Модели рук при этом будут из ТЧ, а модели рук ЧН/ЗП будут не видны! Файл с заданием "Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..." (Чугунный всадник)
Эти 0 пользователя(ей) поблагодарили denis2000 за это полезное сообщение:
Урок 33 (автор GEONEZIS) Задача: Данный урок посвящен обучению принципу построения однотипного квеста на одновременный поиск двух разных предметов в Зове Припяти.
Итак, предположим нам необходимо создать простой квест для Зова Припяти на одновременный поиск двух различных предметов. Пусть идея квеста будет такой: Сыч дает ГГ поручение найти два артефакта Снежинка и Пламя. Необходимые для редактирования файлы: 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 3. конфигурационные в (gamedata\configs\text\rus\) - st_dialogs_zaton.xml - st_quests_zaton.xml 4. скриптовый в (gamedata\scripts\) - dialogs_zaton.script Для начала создадим два простеньких диалога для выдачи и завершения квеста.
В файл dialogs_zaton.xml в самом низу добавим два диалога:
Ну и чтобы понимать о чем в диалогах идет речь сразу пропишем их транскрипцию в файле st_dialogs_zaton.xml
Code
<string id="zat_b30_owl_stalker_trader_small_quests_0"> <text>Есть какое дело?</text> </string> <string id="zat_b30_owl_stalker_trader_small_quests_1"> <text>Нужны артефакты Пламя и Снежинка. Достанешь, хорошо заплачу.</text> </string> <string id="zat_b30_owl_stalker_trader_small_quests_2"> <text>Нет, друг- сам ищи.</text> </string> <string id="zat_b30_owl_stalker_trader_small_quests_3"> <text>Сделаю.</text> </string> <string id="zat_b30_owl_stalker_trader_small_quests_4"> <text>Вот и отлично.</text> </string> <string id="zat_b30_owl_stalker_trader_small_quests_5"> <text>Я нашел артефакты, наш уговор в силе?</text> </string> <string id="zat_b30_owl_stalker_trader_small_quests_6"> <text>Да, отличная работа, давай артефакты сюда.</text> </string> <string id="zat_b30_owl_stalker_trader_small_quests_7"> <text>Держи.</text> </string> <string id="zat_b30_owl_stalker_trader_small_quests_8"> <text>Вот твои деньги.</text> </string> <string id="zat_b30_owl_stalker_trader_small_quests_9"> <text>Бывай.</text> </string>
Теперь разберем по порядку то что добавили.
Диалог на выдачу квеста имеет следующую элементарную структуру:
- ГГ предлагают задание и он на выбор может отказаться от него, тогда второй раз диалог уже не будет доступен. Либо же согласиться на исполение. - Соответсвенно происходит выдача инфопоршней zat_b30_owl_stalker_trader_quest_init (при старте квеста) и zat_b30_owl_stalker_trader_quest_no_quest (при отказе от выполнения). - Наличие в диалоге тегов <dont_has_info>имя поршня</dont_has_info> обеспечивает его блокировку при выборе одной из веток. - Наличие прекондишина <precondition>dialogs_zaton.zat_b30_owl_stalker_trader_have_arts</precondition> также блокирует стартовый диалог при наличии квестовых предметов (в данном случае это артефакты) в рюкзаке ГГ. - акшион <action>dialogs_zaton.zat_b30_owl_stalker_trader_give_quest</action> обеспечивает выдачу квеста.
Теперь поясню особенности второго диалога:
- наличие тега <has_info>zat_b30_owl_stalker_trader_quest_init</has_info> обеспечивает возможность инициализации диалога после выдачи квеста. - наличие <dont_has_info>zat_b30_owl_stalker_trader_quest_end</dont_has_info> обеспечивает блокировку диалога после завершение квеста. - прекондишн <precondition>dialogs_zaton.zat_b30_owl_stalker_trader_have_arts</precondition> обеспечивает блокирование диалога до момента наличия в инвентаре ГГ нужных квестовых предметов. - акшионы <action>dialogs_zaton.zat_b30_owl_stalker_trader_relocates_arts</action> и <action>dialogs_zaton.zat_b30_owl_stalker_trader_relocates_money_to_actor</action> обеспечивают передачу квестовых предметов от ГГ к НПС, и последующего денежного вознаграждения для ГГ от него.
Объявим используемые инфопоршни в info_zaton.xml Добавим в конце файла код:
Code
<!-- New quest --> <info_portion id="zat_b30_owl_stalker_trader_quest_no_quest"></info_portion> <info_portion id="zat_b30_owl_stalker_trader_quest_init"></info_portion> <info_portion id="zat_b30_owl_stalker_trader_quest_end"></info_portion>
Добавим наши диалоги НПС (В данном случае Сычу) для этого в файл character_desc_zaton.xml в его профиль <specific_character id="zat_b30_owl_stalker_trader" team_default="1"> добавим две строки диалогов
С диалогами и инфопоршнями разобрались теперь раccмотрим необходимые скриптовые функции:
В файл dialogs_zaton.script добавим код
Code
function zat_b30_owl_stalker_trader_give_quest() task_manager.get_task_manager():give_task("geonezis_zat_b30_owl_quest") end
function zat_b30_owl_stalker_trader_have_arts(first_speaker, second_speaker) return ((db.actor:object("af_ice") ~= nil) and (db.actor:object("af_fire") ~= nil)) end
function zat_b30_owl_stalker_trader_not_have_arts(first_speaker, second_speaker) return ((db.actor:object("af_ice") == nil) and (db.actor:object("af_fire") == nil)) end
function zat_b30_owl_stalker_trader_relocates_arts(first_speaker, second_speaker) dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, "af_ice") dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, "af_fire") end
function zat_b30_owl_stalker_trader_relocates_money_to_actor(first_speaker, second_speaker) dialogs.relocate_money_to_actor(first_speaker, second_speaker, 30000) end
Теперь по порядку разберем эти функции:
- zat_b30_owl_stalker_trader_give_quest - выдача квеста - zat_b30_owl_stalker_trader_have_arts - возвращает true при проверки на наличие в инвентаре ГГ двух необходимвх предметов (в данном случае артефактов af_ice и af_fire) - zat_b30_owl_stalker_trader_not_have_arts- возвращает false при аналогичной проверке. - zat_b30_owl_stalker_trader_relocates_arts- передача НПС артефактов - zat_b30_owl_stalker_trader_relocates_money_to_actor- выдача денежной награды ГГ.
Разберем то что происходит в процессе выполнения квеста и собственно его структуру.
- [geonezis_zat_b30_owl_quest] - название задение в таск менеджере - icon = ui_inGame2_Kontrakt_s_uchenimi - иконка квеста (в данном случае от задания Контракт с Учеными) - prior = 2 - приоретет задания - storyline = false - сюжеткный ли квест или нет - title = - заголовки при обновлении задания - descr = - дескрипшины при обновлении задания - target = - цели, метки квеста при его обьнавлении. - condlist_0 =- кондишн (спец. условия) в квесте (в данном случае один на завершение)
Основная особенность задания это последовательная проверка структурных условий посредством функции actor_has_item(...). Это вызываемая из xr_conditions.script функция на проверку наличия у актора того или иного предмета. Соответсвенно в структуре этого квеста используют два варианта когда значениее функции false (!actor_has_item(...)) и true (=actor_has_item(...))
В квесте рассматриваются все возможные сочетания вариантов наличия или отсутсвия найденного того или иного предмета.
1. когда нет ни одного. 2. первый (арт снежинка) есть, второго (арт пламя) нет. 3. первого нет, второй есть 4. оба есть.
Соответсвенно в независимости от того какой арт был найден первым- произойдет точное обновление дескрипшина и титла задания с указанием текущего состояния. Также если игрок выложит из инвентаря уже найденный арт, то задание будет обновляться снова. Метка на цели в квесте (Сыч) появиться только при наличии обоих предметов.
По выдачи инфопоршня zat_b30_owl_stalker_trader_quest_end квест будет завершен.
Пропишим рускую транскрипцию дескрипшинов и тайтлов квеста в st_quests_zaton.xml
Code
<string id="zat_b30_owl_stalker_trader_small_quest_title_0"> <text>Поручение Сыча: найти артефакты Снежинка и Пламя</text> </string> <string id="zat_b30_owl_stalker_trader_small_quest_text_0"> <text>Сыч попросил найти для него два арта- Снежинка и Пламя.</text> </string> <string id="zat_b30_owl_stalker_trader_small_quest_title_1"> <text>Поручение Сыча: найти артефакт Снежинка</text> </string> <string id="zat_b30_owl_stalker_trader_small_quest_text_1"> <text>Артефакт Пламя найден. Найдите Снежинку.</text> </string> <string id="zat_b30_owl_stalker_trader_small_quest_title_2"> <text>Поручение Сыча: найти артефакт Пламя</text> </string> <string id="zat_b30_owl_stalker_trader_small_quest_text_2"> <text>Артефакт Снежинка найден. Найдите Пламя.</text> </string> <string id="zat_b30_owl_stalker_trader_small_quest_title_3"> <text>Поручение Сыча: передайте найденные артефакты Сычу.</text> </string> <string id="zat_b30_owl_stalker_trader_small_quest_text_3"> <text>Оба артефакта найдено. Отдайте их Сычу, и заберите награду.</text> </string>
По желанию для проверки в character_desc_general.xml при старте ГГ пропишем нужный арты.
Урок 34 (автор GEONEZIS) Задача: Данный урок посвящен обучению принципу построения квестов с использованием рестрикторов в Зове Припяти.
Предположим нам необходимо реализовать квест следующего типа: ГГ будет выдано задание на извлечение определенного предмета из физического обьекта на локации. Пусть будет такой вариант: Сыч дает Дягтереву задание на изьятие из старой антенны и генератора на ВНЗ Круг различных деталей. Для осуществления подобных заданий необходимо использовать рестрикторы. Данный тип квестов в корне отличается от простых, когда по заданным меткам необходимо было просто подобрать заспавненные ранее предметы. Необходимые для редактирования файлы: 1. конфигурационные в (gamedata\configs\gameplay\) -character_desc_zaton.xml -dialogs_zaton.xml -info_zaton.xml 2. конфигурационные в (gamedata\configs\misc\) - tm_zaton.ltx - quest_items.ltx - death_generic.ltx 3. конфигурационные в (gamedata\configs\text\rus\) - st_dialogs_zaton.xml - st_quests_zaton.xml - ui_st_screen.xml - st_items_quest.xml 4. конфигурационные в (gamedata\configs\ui\) - game_tutorials.xml 5. логики рескрипторов в (gamedata\configs\scripts\zaton\) - zat_restr_logic_1.ltx - zat_restr_logic_2.ltx 6. скриптовый в (gamedata\scripts\) - dialogs_zaton.script - xr_effects.script - ui_si.script 7. Спавн в файле all.spawn (gamedata\spawns\) - alife_zaton.ltx Для начала добавим один общий диалог на выдачу и завершения квеста. (В принципе можно было не усложнять и сделать два простых диалога, но рассмотрим более сложный вариант)
В файл dialogs_zaton.xml в самом низу добавим диалог:
Ну и чтобы понимать о чем в диалогах идет речь сразу пропишем русскую транскрипцию фраз в файле st_dialogs_zaton.xml
Code
<string id="zat_b106_stalker_sich_test_quest_dialog_0"> <text>Я по поводу работы.</text> </string> <string id="zat_b106_stalker_sich_test_quest_dialog_1"> <text>Работы, хм. Ах да забыл. Есть у меня одно поручение. Нужно сходить на ВНЗ Круг и снять показатели нескольких старых приборов. С одной антенны и старого генератора. Ну что, согласен?</text> </string> <string id="zat_b106_stalker_sich_test_quest_dialog_11"> <text>Да, сделаю.</text> </string> <string id="zat_b106_stalker_sich_test_quest_dialog_12"> <text>Пока есть другие дела.</text> </string> <string id="zat_b106_stalker_sich_test_quest_dialog_112"> <text>Отлично, жду. Награду достойную получишь.</text> </string> <string id="zat_b106_stalker_sich_test_quest_dialog_2"> <text>Ну что, сделал что я просил?</text> </string> <string id="zat_b106_stalker_sich_test_quest_dialog_4"> <text>Нет, работаю над этим.</text> </string> <string id="zat_b106_stalker_sich_test_quest_dialog_3"> <text>Да. Все сделано.</text> </string> <string id="zat_b106_stalker_sich_test_quest_dialog_331"> <text>Отлично, давай сюда приборы.</text> </string> <string id="zat_b106_stalker_sich_test_quest_dialog_332"> <text>Забирай.</text> </string> <string id="zat_b106_stalker_sich_test_quest_dialog_333"> <text>Вот твоя награда. Успехов сталкер.</text> </string> <string id="zat_b106_stalker_sich_test_quest_dialog_334"> <text>Бывай.</text> </string>
Теперь разберем по порядку то что добавили.
Диалог на выдачу и завершение квеста имеет следующую структуру: 1. Первая часть диалога на выдачу задания. (ветка <next>1</next>) - ГГ предлагают задание и он на выбор может временно отказаться от него, тогда диалог будет доступен во второй раз. Либо же согласиться на исполение. - Соответсвенно при согласии происходит выдача инфопоршня zat_b106_sich_quest_begin (при старте квеста) и выдача самого квеста через актшион <action>dialogs_zaton.zat_b106_sich_give_tasks</action>. - На этом генерация ветки диалога на выдачу задания будет заблокирована, из-за наличия во фразе 1 условия <dont_has_info>zat_b106_sich_quest_begin</dont_has_info> 2. Вторая часть диалога доступная уже после взятия задания. - Ее генерация происходит путем активации ветки (<next>2</next>), первая фраза которой будет доступна только полсе старта задания то есть наличия условия <has_info>zat_b106_sich_quest_begin</has_info> - Следующие фразы будут доступны также на выбор (<next>3</next> и <next>4</next>) Фраза 4 будет доступна сразу же после взятия квеста- она будет являться закрывающей диалог (акшион <action>dialogs.break_dialog</action>). Генерируется она путем наличия условия <dont_has_info>zat_b106_sich_quest_restr_2</dont_has_info> Эта фраза сообщает о том что ГГ еще не выполнил задание. - Фраза 3 которая является веткой завершения диалога будет доступна только при наличии условия <has_info>zat_b106_sich_quest_restr_2</has_info> (этот инфопоршень мы получим в процессе выполнения квеста) при этом фраза 4 будет заблокирована. - в треьей фразе будет происходить выдача условия <give_info>zat_b106_sich_quest_complete</give_info> обеспечивающего завершение квеста и полное блокирование диалога. - также отметим наличие акшионов <action>dialogs_zaton.zat_b106_sich_quest_relocate_item</action> и <action>dialogs_zaton.zat_b106_sich_quest_relocate_reward</action> отвечающих за передачу квестовых предметов и выдачу награды.
Объявим используемые инфопоршни в info_zaton.xml. Добавим в конце файла код:
Добавим наш диалог НПС (В данном случае Сычу) для этого в файл character_desc_zaton.xmlв его профиль <specific_character id="zat_b30_owl_stalker_trader" team_default="1"> добавим строку диалога
С диалогами и инфопоршнями разобрались теперь добавим необходимые для выполнения квеста предметы, а также файлы связанный с ними.
В файл quest_items.ltx пропишем две секции предметов zat_b206_sich_quest_item_1 и zat_b206_sich_quest_item_2. Оба предмета являются квестовым- невозможна их продажа и выкладывание из инвентаря
- Имена секций рестикторов должны быть уникальны (как собственное имя, так и порядковое внутри алл спавна) - Они должны иметь тип 3 - Координаты точки спавна рестикторов должны задаваться рядом с тем обектом на локации который мы будем использовать. (position, level_vertex_id, game_vertex_id) - story_id = zat_restr_2_id- уникальный айди номер рестриктора на который будет выставляться квестовая метка. - shape0- общий тип и размер зоны рестриктора- при изменении числовых значений можно как увеличить, так и уменьшить радиус активной зоны вблизи юзаемого предмета. - cfg = scripts\zaton\zat_restr_logic_2.ltx- путь к файлу логики рестриктора.
Теперь пропишем логики рестрикторов. Рассмотрим только одну- вторая создается по образу первой. Создадим файл zat_restr_logic_1.ltx И пропишем в него следующий код:
Опишем что означает эта логика и по какому принципу она строиться:
- всего логика имеет три секции это sr_idle@start- она же изначально активная, [sr_idle@tutorial] по исполнению гайм туториала, [sr_idle@nil]- нулевое значение логики. - основной принцип работы это проверка наличия двух условий- это старт квеста (zat_b106_sich_quest_begin) и наличия актора в зоне рестиктора =actor_in_zone(zat_test_quest_restrictor_1) при их соблидение подается команда на старт туториала юзания предмета %=run_tutorial(zat_sich_quest_1_tutor)% - если актор находился в зоне рестиктора, но потом вышел из нее !actor_in_zone(zat_test_quest_restrictor_1) происходит выдача команды на остановку туториала %=stop_tutorial% и возвращение логики в исходное стартовое состоянии. Запуск или остановку туториала можно проследить по активации надписи юзания предмета. - соотвестсвенно в независимости от того какая секция логики активна при выдаче инфопоршня zat_b106_sich_quest_restr_1 происходит обнуление логики рестиктора. Дальнейшая работа туториалов в ней будет невозможно.
Текст активирущийся при юзании рестриктора буде прописан в ui_st_screen.xml
Основные параметры это: - <action id="use" finalize="1">xr_effects.zat_sich_quest_1</action> выполняемое действие по скрипту xr_effects.zat_sich_quest_1 - zat_sich_quest_tips- текст сообщения перед юзанием
В файл xr_effects.script пропишем скрипты исполняемые при юзании рескриптора.
Code
function zat_sich_quest_1(actor, npc) if xr_conditions.actor_in_zone(actor, npc, {"zat_test_quest_restrictor_1"}) then db.actor:give_info_portion("zat_b106_sich_quest_restr_1") give_actor(db.actor,nil,{"zat_b206_sich_quest_item_1"}) end end function zat_sich_quest_2(actor, npc) if xr_conditions.actor_in_zone(actor, npc, {"zat_test_quest_restrictor_2"}) then db.actor:give_info_portion("zat_b106_sich_quest_restr_2") give_actor(db.actor,nil,{"zat_b206_sich_quest_item_2"}) end end
-Происходит проверка наличия актора в зоне zat_test_quest_restrictor_1 и если оно истинно тогда происходит выдача инфопоршня zat_b106_sich_quest_restr_1 и спавн в рюкзак ГГ айтема zat_b206_sich_quest_item_1
С рестрикторами разобрались. Теперь пропишем остальные скриптовые функции:
В файле dialogs_zaton.script добавим следующие функции:
Code
function zat_b106_sich_give_tasks(first_speaker, second_speaker) task_manager.get_task_manager():give_task("geonezis_zat_b206_sich_example_task") end
function zat_b106_sich_quest_relocate_item(first_speaker, second_speaker) local items_table = { "zat_b206_sich_quest_item_1", "zat_b206_sich_quest_item_2", } for k,v in pairs(items_table) do if db.actor:object(v) ~= nil then dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, v) end end end
function zat_b106_sich_quest_relocate_reward(first_speaker, second_speaker) dialogs.relocate_money_to_actor(first_speaker, second_speaker, 5000) end
Поясним их:
- Выдача квеста - Передача квестовых предметов неписю - Выдача ГГ награды за квест
Так и собственно в завершении осталось расписать сам квест:
- квест исполняется в три этапа- сначала мы юзаем рестриктор 1, потом после этого второй и в завершении отдаем полученные предметы заказчику. соответсвенно метки перемещаются с zat_restr_1_id на zat_restr_2_id и в завершении на Сыча zat_b30_owl_stalker_trader_id. При этом же обновляются тайтлы и дескрипшины этапов задания. Основные условия их изменения это выдача или же остутсвие двух основных инфопоршней zat_b106_sich_quest_restr_1 (получаемого при юзании первого рестриктора) и zat_b106_sich_quest_restr_2 (второго) - задание завершается при выдаче инфопоршня zat_b106_sich_quest_complete - квест будет провален если после его старта НПС заказчика стал враждебен по отношению к ГГ =is_squad_enemy_to_actor(zat_b30_owl_stalker_trader_squad) - по завершению квеста происходит повышение репутации у сталкеров %=inc_faction_goodwill_to_actor(stalker:50)%
В файле st_quests_zaton.xml пропишем тайтлы и дескрипшины квеста:
Code
<string id="zat_b206_sich_example_title0"> <text>Задание Сыча: извлеките компонент из старой антенны.</text> </string> <string id="zat_b206_sich_example_text0"> <text>Необходимо отправиться на ВНЗ Круг и извлечь деталь обьекта со старой антенны.</text> </string> <string id="zat_b206_sich_example_title1"> <text>Задание Сыча: извлеките вторую деталь со старого генератора</text> </string> <string id="zat_b206_sich_example_text1"> <text>Заберите вторую необходимую заказчику деталь.</text> </string> <string id="zat_b206_sich_example_title2"> <text>Задание Сыча: отдайте заказчику найденные детали.</text> </string> <string id="zat_b206_sich_example_text2"> <text>Передайте все старые детали и компоненты Сычу.</text> </string>
На этом урок добавления подобного класса заданий завершен.
Урок 35 (Автор denis2000) Задача: Создание осветительно-сигнального устройства (добавление нового уникального предмета в игру). Файл с выполненным заданием Видео скачать [cut=Видео][/cut]
1. Введение. Для создания осветительно-сигнального устройства (на подобии химических люминисцентных источников света из MW2) нам понадобиться прежде всего определиться с базовым объектом на основе которого это возможно сделать - тут особо неизчего выбирать классов объектов которые могут обладать худом и которые ГГ может бросить всего два: болт и граната, но класс болт не обладает возможностью излучать свет (по крайней мере реализация такой возможности потребует больших усилий). Остается класс граната - у класса возможен ХУД (тоесть держание в руках ГГ), есть возможность броска ГГ, есть возможность излучения света, и т.п., к сожалению есть и два минуса - движком закреплено за объектами этого класса эффект взрыва (сотрясение камеры во время уничтожения объекта) и остающиеся на поверхности локации волл-марки типа explosion_marks (отключить эти эффекты возможно только в движке). Но ничего страшного будем считать что в нашем предмете есть небольшой детонационный заряд который собственно приводит его в рабочее состояние разрушая пререгородку между двухкомпонентным наполнителем который смешиваясь при детонации начинает излучать свет. Теперь собственно что нужно сделать: Создать ХУД и мироую модель объекта, создать анимации для объекта и рук (возможно использование существующих), создать звуки (возможно использовать существующие), создать текстуру (или использовать существующую), создть партиклы для эфектности к стати ими можно скрыть волл-марки (или используйте существующие), создать конфигурационный файл предмета, создать иконку и текстовые параметры названия и описания.
2. Создадим модель объекта на базе гранаты РГД5 (бес претензии на подробное руководство по созданию 3D объектов, просто общие моменты). а) Импортируем в MilkShape 3D модель wpn_rgd5_hud.ogf. б) Удалим все меши оставив только скелет. в) Создадим меш - цилиндр и назначим ему материал в котором пропишем текстуру (и при необходимости проиведем корректировку наложения текстуры на меш) я использовал текстуру glas\glas_dirt и сделал цилиндр таким чтобы он приблизительно соответствовал размерам исходной гранаты для того чтобы использовать ее-же анимации при необходимости. г) Привяжем меш к базовому суставу скелета wpn_body. д) Экспортируем модель в формат *.object e) Для создания мировой медели загрузим модель созданную в MilkShape 3D в SDK и привяжем к базовому суставу шейп (опять же цилиндрический) - это физическая поверхность нашего объекта она должна быть немного больше визуальной, експортируем модель в файл wpn_palka.ogf ж) Для создания ХУД модели загрузим модель созданную в MilkShape 3D в SDK и присоединим файл с анимациями wpn_f1_hud_animation.omf експортируем модель в файл wpn_palka_hud.ogf
3. Создавать анимации, текстуры и звуки мне не потребовалось - я использовал те что есть, но вероятно вам придется создавать свои.
4. Создание партиклов. С партиклами было сложнее хотя я и выбрал Партикл-групп которая уже была в исходном файле particles.xr, но она оказалась зацикленной, а это помешело использовать ее для моих целей. Значит нужно редактировать, приступим: а) Запустите ParticleEditor из комплекта SDK (если сразу после открытия программы список партиклей не пустой очистите папку ***SDK\editors\rawdata\particles от стандартных партиклей и загрузите програму снова) б) Откройте в нем файл particles.xr (теперь можно сохранить распакованные партикли припомощи кнопки Save в директорию ***SDK\editors\rawdata\particles) в) Теперь выберем партикл - мне понравилась группа static\net_base_green, но она зацикленная. г) Для исправления необходимо клонировать группу (чтобы не поламать группу - мало ли где она используется) и партикл-еффекты которые в ней используються д) В клонированной группе редактируем партикл-эффекты, прежде всего заменяем на клонированные и ставим во всех эффектах галочку TimeLimit ниже выбираем длительность эффекта - Value. е) В клонированной группе cтавим параметр TimeLimit таким же как и Value в эффектах. Теперь все эффекты и группа в целом ограничена по времени вашем значением. ж) Сохраните файл particles.xr в корень своей gamedata.
5. Самое главное создать конфирурационный файл предмета: а) Скопируем файл w_rgd5.ltx и переименуем например в w_palka.ltx (внесем ссылку а него в weapons.ltx). б) Приступим к редактированию параметров Изменим следующие параметры: [palka]- имя базовой секции detonation_threshold_hit= 0 - хит для детонации объекта $spawn = "weapons\grenades\palka" - параметр для SDK где искать объект в списке объектов visual = dynamics\weapons\wpn_palka\wpn_palka.ogf - мировая модель inv_name = st_palka - Имя предмета inv_name_short = st_palka description = st_palka_descr - Описание предмета inv_grid_width = 2 - Координаты иконки предмета inv_grid_height = 2 - Координаты иконки предмета inv_grid_x = 14 - Координаты иконки предмета inv_grid_y = 23 - Координаты иконки предмета hud = palka_hud - имя секции настроек ХУДа предмета destroy_time = 3500 - время в мс между броском и детонацией blast = 0 - Уровень хита от взрава blast_r = 0 - Радиус взрава blast_impulse = 0 - Импульс от взрыва blast_impulse_factor = 0 - Коэфф импульса от взрыва frags = 0 - Количество осколков frags_r = 0 - Радиус разлета осколков frag_hit = 0 - Хит от попадания осколка frag_hit_impulse = 0 - Импульс от попадания осколка hit_type_blast = strike - Тип хита от взрыва (несущественно) up_throw_factor = 0 explode_particles = static\net_base_green - партиклы проигрываемые в месте взрыва light_color= 0.5,2.0,0.5 - цвет световой вспышки RGB (в данном случае кислотный зеленый свет) light_range = 40.0 - Растояние распространения света определяет яркость light_time = 300 - Время световой вспышки в сек fragment_speed = 0 - Скорость разлета фрагментов explode_duration = 300 - подолжительность взрыва и соответственно световой вспышки в сек snd_explode = device\door_stop - Звук взрыва [palka_hud]:hud_base - Имя секции настроек ХУДа предмета item_visual = dynamics\weapons\wpn_palka\wpn_palka_hud.ogf - визуал предмета в руках ГГ (ХУД модель)
6. Иконки и тексты. Создайте иконку и поместите ее в файле ui_icon_equipment.dds и также строковые параметры st_palka, st_palka_descr например в файле st_items_weapons.xml.
"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..." (Чугунный всадник)
Эти 0 пользователя(ей) поблагодарили denis2000 за это полезное сообщение:
Урок 28a (Автор: xardaslich) Задача: Адаптация "подгон" текстур прицельных сеток с "нестандартным" соотношением сторон ("ширина"\"высота") под стандартные 1024 на 1024 пикселя. Урок выложен в формате .pdf в виде иллюстрированного руководства. Урок 28а
Эти 0 пользователя(ей) поблагодарили xardaslich за это полезное сообщение:
Урок 37(Автор: Niafa) Задача: разбор принципов и особенностей 3д моделирования для игры S.T.A.L.K.E.R. на примере создания артефакта с прозрачной текстурой.
Урок 13а (автор ДеМЬян) Задача: Создать тайник на Затоне через all.spawn. Способ второй. Файл с отработанным примером
Когда я пытался создать тайник по способу описанному в уроке 13 - у меня ничего не получилось. И я пошел слегка другим путем.
Итак, мы имеем распакованный all.spawn, ищем файл alife_zaton. В файле, есть такая строчка:
Код
[52] - номер, дабы не повторяться, мы напишем 5200000
; cse_abstract properties - секция, не трогать! section_name = inventory_box - имя секции, не трогать! name = level_prefix_inventory_box_0000 - имя, можно написать что угодно position = -447.109985351563, -6.13000011444092, 183.639999389648 - позиция тайника на карте direction = -0.062830001115799, -2.99324011802673, -0.169295996427536 - направление ("взгляд" и т.д.) можно написать 0, 0, 0 version = 128 - не трогать! script_version = 12 - не трогать!
; cse_alife_object properties game_vertex_id = 0 - гайм ай ди тайника distance = 0 level_vertex_id = 293223 - левел вертекс ай ди object_flags = 0xffffff3b custom_data = <<END [spawn] - что спавнится в тайнике wpn_pb ammo_9x18_pmm medkit_army drug_antidot END
; cse_visual properties visual_name = dynamics\equipment_cache\equipment_box_02_case - вид тайника (об этом чуть позднее)
; cse_alife_inventory_box properties tip = inventory_box_use
На примере тайника под номером 52 мы создадим свой.
Код
[520000] ; Тайник с AWM ; cse_abstract properties section_name = inventory_box name = Тайник от ДеМЬян-а. position = 119.18574523926,-7.3469276428223,180.75785827637 direction = 0, 0, 0 version = 128 script_version = 12
; cse_alife_inventory_box properties tip = inventory_box_use
Я создал тайник с AWM на "Скадовске".
Теперь рассмотрим визуал тайника. Идем, например, в папку: gamedata\meshes\dynamics\devices. Теперь с помощью OGFViewer выбираем полюбившийся по виду тайник и копируем путь этого тайника в секцию visual_name. Готово! Тайник заспаунен!
Урок 1б (автор ДеМЬян) Задача: Создать торговца-NPC привязанного к одной точке. *необходим отработанный пример из урока 1 Файл с отработанным примером
Урок работает ТОЛЬКО на SGM 1.7 - 2.2 Сейчас мы научимся создавать торговца. Я буду опираться на Урок 1. Делаем все как в первом уроке. Доходим до пункта 6. Создаем файл с логикой персонажа zat_sh_nikitka_skadovsk.ltx в каталоге \gamedata\configs\scripts\sh\
И прописываем вот такую логику:
Код
[logic] active = move@trader trade = misc\trade\zat_sh_nikitka_skadovsk.ltx
[logic] active = move@trader - активная секция логики (та которая включается в первую очередь) trade = misc\trade\zat_sh_nikitka_skadovsk.ltx - его файл торговли (об этом позже). level_spot = trader - иконка торговца для НПС на миникарте
[move@trader] move_dest_number = 1160053 - это level_vertex на котором стоит НПС move_look_vertex = 2.4362614154816 - это level_vertex в направлении которого смотрит НПС move_state_when_center = ward_noweap - имя анимации проигрываемой когда НПС стоит на своей точке move_state_when_move = walk - имя анимации НПС в движении move_combat_disable = true - не двигаться в случае атаки move_home_teleport = true - телепортироваться на точку разрешено (быстрый возврат НПС на свою точку) meet = meet invulnerable = true
Теперь перейдем к спавну нашего торговца. Идем в gamedata\scripts, находим там файл sgm_world. Этот файл альтернатива all.spawn, так что огромное спасибо Николаю, за такой подарок. Итак, открываем. Этот файл отвечает за спавн тайников и NPC. Нас сейчас интересует именно NPC. Ищем нужную категорию (в нашем случае это Затон), жмем на Enter и прописываем так же как и у других персонажей:
Обратите внимание, "zat_sh_nikitka_skadovsk" это название секции спавна персонажа, а цифры - это точные координаты места спауна нашего NPC (я координаты в SGM снимаю кнопкой Координировать), координаты представлены так: X,Y,Z,Level_vertex,Game_vertex.
Если в логике и в SGM_world левел вертекс будут отличаться, то наш персонаж просто телепортируется в место, указанное на координатах в логике.
Теперь начнем мудрить с файлом торговли. Идем в папку gamedata\configs\misc\trade, создаем файл zat_sh_nikitka_skadovsk.ltx. Зайдем, например, в файл trade_zat_a2_barmen и скопируем все содержимое в наш файл zat_sh_nikitka_skadovsk.ltx. Если хотите - подкорректируйте содержимое этого файла.
В принципе все, NPC будет стоять на месте спауна и встречать нас с теплыми объятиями. Ах, да, зайдем снова в файл character_desc_sh_zat.xml (\gamedata\configs\gameplay\) и кое что подредактируем:
Код
<?xml version='1.0' encoding="windows-1251"?> <xml> <!-- zat_sh_nikitka_skadovsk --> <specific_character id="zat_sh_nikitka_skadovsk" team_default = "1"> <name>ДеМЬян</name> - имя можно написать любое (оно отображается!!!) <icon>ui_inGame2_neutral_2</icon> <map_icon x="1" y="0"> </map_icon> <bio>Опытный сталкер. Детальная информация отсутствует.</bio> <class>zat_sh_nikitka_skadovsk</class> <community>stalker</community> <terrain_sect>stalker_terrain</terrain_sect> <snd_config>characters_voice\human_02\military\</snd_config> <rank>70</rank> <money min="5000" max="10000" infinitive="1"/> - количество денег. У торговца они должны быть бесконечные, сами понимаете.
<reputation>0</reputation> <visual>actors\stalker_neutral\stalker_neutral_9</visual> <supplies> [spawn] \n - содержимое рюкзака, это он не будет продавать (но будет использовать). wpn_awm_camo = 1 \n ammo_7.62x51_fmj = 3 \n wpn_pb \n ammo_9x18_pmm = 1 \n grenade_f1 = 3 \n wpn_binoc = 1 \n </supplies> <actor_dialog>actor_break_dialog</actor_dialog> - это "диалог" обязателен, чтобы потом не пожалеть. </specific_character> </xml>
Вот и все, теперь вы создали NPC - торговца на Скадовске, который стоит около Сыча и торгует таким же барахлом, что и Бармен.
Удачи вам в модостроении!
Исправил ошибочные утверждения и неточности. denis2000
Сообщение отредактировал ДеМЬян - Чт, 22.03.2012, 19:46
Эти 0 пользователя(ей) поблагодарили ДеМЬян за это полезное сообщение: