Tris 9 Опубликовано 3 Августа 2012 Поделиться Опубликовано 3 Августа 2012 (изменено) Как изменить эффекты при нахождении в оазисе [ЗП] В скрипте xr_effects (по default) на строке 2688 есть функция:Она и отвечает за эффекты в оазисе. function oasis_heal() local d_health = 0.005 local d_power = 0.01 local d_bleeding = 0.05 local d_radiation = -0.05 if(db.actor.health<1) then db.actor.health = d_health end if(db.actor.power<1) then db.actor.power = d_power end if(db.actor.radiation>0) then db.actor.radiation = d_radiation end if(db.actor.bleeding>0) then db.actor.bleeding = d_bleeding end db.actor.satiety = 0.01 end например, так: function oasis_heal() local d_health = 0.005 local d_power = 0.01 local d_bleeding = 0.05 local d_radiation = 0.05 if(db.actor.health<1) then db.actor.health = d_health end if(db.actor.power<1) then db.actor.power = d_power end if(db.actor.radiation>0) then db.actor.radiation = d_radiation end if(db.actor.bleeding>0) then db.actor.bleeding = d_bleeding end db.actor.satiety = 0.01 end теперь находясь в оазисе, радиация будет прибавляться. Как сделать изношенное снаряжение в начале игры ЗП В скрипте xr_effects есть такая функция:(Находится она на строке: 2787)Она и отвечает за изношенность предметов. function damage_actor_items_on_start(actor, npc) local actor = db.actor local obj = actor:object("helm_respirator") if obj ~= nil then obj:set_condition(0.8) end obj = actor:object("stalker_outfit") if obj ~= nil then obj:set_condition(0.76) end obj = actor:object("wpn_pm_actor") if obj ~= nil then obj:set_condition(0.9) end obj = actor:object("wpn_ak74u") if obj ~= nil then obj:set_condition(0.7) end end Если вы добавили в начало игры новое оружие, можно расширить функцию например так: function damage_actor_items_on_start(actor, npc) local actor = db.actor local obj = actor:object("helm_respirator") if obj ~= nil then obj:set_condition(0.8) end obj = actor:object("stalker_outfit") if obj ~= nil then obj:set_condition(0.76) end obj = actor:object("wpn_pm_actor") if obj ~= nil then obj:set_condition(0.9) end obj = actor:object("wpn_ak74u") if obj ~= nil then obj:set_condition(0.7) end obj = actor:object("wpn_vintorez") if obj ~= nil then obj:set_condition(0.7) end end Теперь добавленное оружие тоже будет немного повреждено. Изменено 19 Сентября 2014 пользователем World_Stalker 1 • Dead Forgetting Zone • Мои работы. Обновление: 24.08.2012 Ссылка на комментарий
Старлей 88 Опубликовано 30 Августа 2012 Поделиться Опубликовано 30 Августа 2012 (изменено) [ЧН] Спавн сквадов и их параметры Все параметры вытащил из sim_squad_scripted.script, итак следующие параметры можно указать в ltx-файлах squad_descr_* [squad_name] ;Имя сквада auto_id = true/false ;Автоматический выбор командира faction = army ;группировка npc = npc_1, npc_2, npc_3, npc_4, npc_5 ;НПС target_smart = smart_terrain_name ;Смарт в который пойдет отряд on_death = %+infoportion% ;Инфа после смерти отряда attack_power = 400 ;Число прибавляеющееся при атаке на смарт(чем больше тем лучше) invulnerability = true/false ;Бессмертие relationship = friend/enemy/neutral ;Отношение к ГГ sympathy = 0.1 ;Симпатия show_spot = true/false ;Показывать отметку на карте always_walk = true/false ;Состояние в котором передвигается отряд spawn_point = spawn_point_smart ;Спавн точка смарта Изменено 19 Сентября 2014 пользователем World_Stalker 4 Ray Of Hope - кооператив сталкера OldStory Ссылка на комментарий
Отшельник12 12 Опубликовано 7 Сентября 2012 Поделиться Опубликовано 7 Сентября 2012 (изменено) Внесу и свою лепту которую все знают кроме новичков разве что. Лезем в файл gamedata\configs\weapons\weapons.ltxпод секцией [ammo_base] есть строка: ;belt = true; меняем её на это: belt = true И можем вешать патроны на пояс. Когда там нет игра автоматом берёт из рюкзака.В зп на версии 1.6.00 при смене автоматных патронов на патроны для дробовика случался вылет stace trase. Но вроде бы только один раз. Изменено 19 Сентября 2014 пользователем World_Stalker Ссылка на комментарий
proger_Dencheek 6 Опубликовано 8 Октября 2012 Поделиться Опубликовано 8 Октября 2012 (изменено) Язык программирования Lua. Учебник для начинающих.Скачать в формате .txtВзято с сайта:http://big.vip-zone.su/doc/devel/lua.xml Изменено 19 Сентября 2014 пользователем World_Stalker Ссылка на комментарий
Это популярное сообщение. ColR_iT 171 Опубликовано 13 Ноября 2012 Это популярное сообщение. Поделиться Опубликовано 13 Ноября 2012 "Горячие клавиши" Пролог Я несколько сомневался стоит ли размещать статью здесь, ведь по сути это просто копи-паст, но тем не менее оставить это без внимания я не смог. К тому же "рекламу" такому стоит сделать и я думаю многие со мной согласятся. Экспозиция С самой зари модостроения многие задавались вопросом: можно ли осуществить горячие клавиши назначенные на пользовательские действия? Ответ за частую был отрицательным. Никаких функций разработчики не предоставили, а методы для тех горячих клавиши, что используются игрой прописаны в движке. Нужно было как-то находить выход из сложившейся ситуации, ведь горячие клавиши предоставляли бы весьма обширный потенциал... Завязка Говоря правду, игра предоставляет возможность отслеживать нажатие клавиши, правда происходит это только для элементов оконных классов, один из которых - это экран главного меню. В нём можно произвести определённое действие закреплённое за определённой клавишей. Но тот факт, что для использования клавиш необходимо выходить в главное меню - подвергало сомнениям использование данного метода в геймплее, это скорее могло пригодиться в отладочных целях. Со временем была найдена ещё одна клавиша, нажатие которой можно отловить, причём непосредственно во время игрового процесса. Это клавиша Tab. Ведь именно она при нажатии отображает название текущего задания на экране. И вот именно этим моментом и воспользовались модостроители. Дело в том, что имя задания выводится не просто текстом, а посредством так называемого элемента "кастом статик" (custom static), дабы не углубляться в дебри терминологии, назовём это окошком, только с прозрачной рамкой, и внутри которого и отображается текст. Окошко это имеет имя - main_task. Именно благодаря этому можно отследить наличие на экране в данный момент времени присутствие этого статика, что определяет нажатие клавиши Tab. Но и это не было идеальным решением. С этим появлялись некоторые неудобства, в частности использование нужных действий в строго определённой ситуации. Данный способ весьма успешно используется в моде OGSE 0692, в нём клавиша Tab используется в качестве задействования пулемёта в БТР, открывание багажника, в других случаях применение антирадина. Казалось бы всё хорошо, но все эти манипуляции требуют строгих условий: для включения пулемёта - нахождение главного героя в БТР, для открытия багажника - нахождение главного героя позади авто, при этом каждое действие автоматически исключало другие варианты последствия нажатия клавиши. В данной ситуации, исключая мелкие неувязки, этот метод весьма к стати. Но что если нужно привязывать и другие действия, такие как: поедание еды, применение алкоголя - организовать эти действия на работе одной клавиши весьма не простая задача, а в данном случае и не реализуемая. Развитие действия Через некоторое время, на сцене появляется Keylogger. Динамически подключаемая библиотека, позволяющий отслеживать нажатие клавиш и сопутствующие этому действия. Библиотека хоть и решала проблему с нехваткой горячих клавиш, но почему-то не набрала популярности среди модостроя. Ещё позже появляются правки xrGame.dll, которые в полной мере могут повторить тот же функционал. Всё это весьма полезно, за что авторам данных изобретений большое спасибо. Но что на счёт реализовать подобное скриптово, лишь стандартными методами и способами, которые может предоставить нам игра? В очередной раз скажете "нет"? Не торопитесь ... Кульминация - Привет, как дела? - Привет! Хорошо всё. - Ты когда нибудь слышал о консольной команде bind_console? - Нет, а для чего она? - Позволяет назначить выполнение консольной команды на клавишу. - Здорово! Это ведь можно ... Это можно реализовать полноценный перехватчик нажатия клавиш. Изречение: "Всё гениальное - просто" - и здесь нашло своё место. Идея довольно проста. Консольная команда bind_console, присутствующая в игре ещё с билда 1957, позволяет назначить выполнение другой консольной команды на незадействованную клавишу на клавиатуре. Это означает, что вот такая строка набранная в консоле: bind_console demo_record 1 knumpad0 назначит консольную команду demo_record со значением 1 на клавишу "0" на цифровой клавиатуре. Таким образом на любую клавишу можно назначить любую консольную команду. "Ну и для чего?" - скажете Вы - "Ведь консольные команды не позволяют выполнять функции из скриптов!" - и в этом Вы будете абсолютно правы. Но! Стандартные функции позволяют получить значение передаваемое консольной команде, а поскольку назначить на клавишу мы можем любую консольную команду, то достаточно использовать ту, которая не задействована в сингл игре. И такая команда есть - mm_net_player_name - задаёт имя игрока в мультиплеере. Если собрать эти сведения воедино, то для полноты картины необходимо в качестве параметра передавать идентификатор нажатой кнопки и отлавливать это значение на апдейте. Финал Метод работает на любой версии игры, однако нельзя использовать уже задействованные клавиши, т.к. они будут переопределены на другое действие. Следует также помнить, что при открытом диалоговом окне оно перехватывает обработку клавиш и нажатия не отлавливаются. local con = nil -- переменная для объекта консоли local con_command = "mm_net_player_name" -- консольная команда local def_value = "_" -- значение по умолчанию - символ подчеркивания function update() if not con then -- инициализируем схему con = get_console() -- кешируем консоль con:execute( con_command .." ".. def_value ) -- инициализируем дефотлным значением, т.к. кнопка не нажата for k,v in pairs(_G[script_name()]) do -- перебираем функции в текущем файле -- v это функция и её имя является кодом клавиши if type(v)=='function' and DIK_keys[string.upper(k)] then local key = "k"..string.gsub(k,"dik_","") -- формируем ключ и con:execute("bind_console "..con_command.." "..k.." "..key) -- биндим кнопку на него end end else -- получаем из консоли значение параметра для нашей команды local str = con:get_string(con_command) -- если оно не является значением по умолчанию -- и в этом файле есть функция с таким именем, то выполняем её if str~=def_value and this[str] then this[str]() con:execute(con_command.." "..def_value) -- записываем значение по умолчанию end end end function dik_numpad0() news_manager.send_tip(db.actor,"нажали кнопку numpad0") end function dik_numpad1() news_manager.send_tip(db.actor,"нажали кнопку numpad1") end function dik_numpad2() news_manager.send_tip(db.actor,"нажали кнопку numpad2") end При нажатии клавиш "0", "1" или "2" цифровой клавиатуры будет выведено соответствующее каждой кнопке сообщение. Помните способ организации горячей клавиши посредством кнопки Tab? Аналогичным способом можно отслеживать не только нажатие но и отпускание клавиши. В этом нам поможет ещё одна консольная команда bind_sec, позволяющая определить вторую горячую клавишу на одно и то же действие. local con = nil local con_command = "mm_net_player_name" local def_value = "_" local act_key = "" -- последняя нажатая клавиша function update() if not con then con = get_console() con:execute(con_command .." " .. def_value) for k,v in pairs(_G[script_name()]) do if type(v)=='function' and DIK_keys[string.upper(k)] then local key = "k"..string.gsub(k,"dik_","") con:execute("bind_console "..con_command.." "..k.." "..key) end end else local str = con:get_string(con_command) if str~=def_value and this[str] then this[str]() con:execute(con_command .." " .. def_value) --отлова отпускания -- биндим на показ статика активного квеста нажатую кнопку con:execute("bind_sec scores k"..string.gsub(str,"dik_","")) -- если статик ещё не показан, то показываем его -- он будет висеть пока не отпущена клавиша local cs = get_hud():GetCustomStatic("main_task") or get_hud():AddCustomStatic("main_task") -- задаем 100% прозрачность тексту, чтоб не светился без нужды cs:wnd():SetTextColor(0,240,217,182) act_key = str -- запоминаем нажатую кнопку news_manager.send_tip(db.actor,"нажали "..act_key) end end -- отлов отпускания local cs = get_hud():GetCustomStatic("main_task") if act_key~="" and not cs then -- была нажата клавиша, а статика нет con:execute("unbind_sec scores") news_manager.send_tip(db.actor,"отпустили "..act_key) act_key="" end end function dik_numpad0() end function dik_numpad1() end function dik_numpad2() end При нажатии клавиши "0" на дополнительной клавиатуре будет выведено сообщение "нажали 0", а при отпускании - "отпустили 0". Функцию update вызываем из колбека update класса actor_binder, иными словами - из апдейта биндера актора. Имена функций берутся из класса-перечисления DIK_keys, описание которого можно найти в lua_help.script. Титры Авторы: Charsi & Shadows. Оригинал статьи на S.T.A.L.K.E.R. Inside Wiki: ссылка. 7 1 Ссылка на комментарий
Это популярное сообщение. ColR_iT 171 Опубликовано 5 Февраля 2013 Это популярное сообщение. Поделиться Опубликовано 5 Февраля 2013 (изменено) "Динамическое подключение/отключение функций" Думаю многим известно, что такое файл bind_stalker.script. В этом файле прописан класс actor_binder обрабатывающий действия актора. Всего в классе семнадцать методов. Коротко расскажу о назначении каждого: bind_stalker.script Скрытый текст __init - вызывается единожды при создании экземпляра класса, т.е. в случае актора - один раз при начале новой игры;net_spawn - вызывается при спавне актора, т.е. при загрузке (загрузка сохранения, переход между локациями);net_destroy - противоположный предыдущему метод. Вызывается при удалении актора. В игре это единственный момент - момент перед загрузкой другой локации во время перехода;reinit - вызывается после net_spawn и представляет из себя инициализацию объекта актора. Примечателен метод тем, что в нём устанавливаются колбеки;take_item_from_box - вызывается, когда ГГ берёт вещи из объекта inventory_box;level_border_enter - вызывается, когда ГГ входит в разрешенную границу уровня;level_border_exit - вызывается, когда ГГ покидает разрешенную границу уровня;Как именно определяются границы уровня я не знаю. Но эти колбеки нужны для схемы xr_detector.script, которая в свою очередь реагирует на данные действия повышением уровня радиации, когда мы заходим в запрещённую зону на границе уровня.info_callback - вызывается при выдачи ГГ любой инфопорции;on_trade - вызывается при нажатии кнопки "Торговать" в акне торговли;article_callback - вызывается во время выдачи статьи в энциклопедии;on_item_take - вызывается в момент появления в инвентаре ГГ любого предмета;on_item_drop - противоположный предыдущему метод. Вызывается, когда из инвентаря удаляется любой предмет;task_callback - вызывается для обработки заданий в ПДА. В какие именно моменты это происходит сказать сложно, скорее всего с некоторой периодичностью;map_location_added_callback - вызывается во время установки какой-либо метки на карте ПДА;update - знаменитый "апдейт". Вызывается движком постоянно, довольно часто (несколько десятков раз в секунду);save - вызывается при сохранении;load - соответственно при загрузке. Самым частым в использовании является метод update. Именно в него неосведомлённый модостроитель порою "заталкивает" такое, что волосы становятся дыбом, и невероятно часто данный метод используют для одноразовых "заданий", прописывая проверку инфопорции, чтобы результат не проверялся несколько раз, но тем не менее проверка продолжает выполняться. А что если использовать updateпо требованию и когда необходимость в нём отпадает - убирать проверку? Как? Оказывается не очень то и сложно...Таковым функционалом обладает файл xr_s.script из папки скриптов ЧН или ЗП. Знающий скрипты человек, уделив некоторое внимание данному файлу, сам поймёт как его использовать, не знающий - будет долго всматриваться в код в поисках знакомых слов. Ничего страшного в этом нет - самообразование всегда похвально, я же помогу Вам разобраться в коде окончательно.Идея скрипта как раз в том и состоит, чтобы в нужный момент подключить любую функцию к одному из колбеков, включая update, и когда необходимость в функции отпадёт - убрать её от туда, тем самым избавив колбек от лишней работы. При этом список колбеков можно свободно расширить, и подключать функцию можно вообще по сути куда угодно. Итак, давайте разберём файл более подробно. xr_s.script Скрытый текст Сразу скажу, что в файле присутствуют функции, которые не относятся к "подключению" функций, поэтому речь пойдёт только о тех функциях, которые нам понадобятся.Таблица callbacks.Таблица состоящая из пары ключ - значение, где ключом выступает имя колбека в который подключается функция, значение - это таблица содержащая параметры для нашей функции, если она их требует. Звучит сложно, но Вы поймёте на примере, который будет ниже.Далее идут две функции:function register_callback (name, func, userobj)Функция "регистрирует" нашу функцию в указанном колбеке.Принимает следующие параметры:name - называние колбека из таблицы callbacks в который мы подключаем нашу функцию;func - ссылка на нашу функцию. Указывается её имя без кавычек! Если функция находится в другом файле, ты в ссылке через точку указывается и модуль в котором расположена функцию;userobj - параметры, которые принимает наша функцию. Если параметров несколько, то нужно передавать параметры в таблице.function unregister_callback (name, func)Функция удаляет нашу функцию из указанного колбека.Принимает следующие параметры:name - называние колбека из таблицы callbacks из которого мы удаляем нашу функцию;func - ссылка на нашу функцию. Указывается её имя без кавычек! Если функция находится в другом файле, ты в ссылке через точку указывается и модуль в котором расположена функцию.Далее идут одиннадцать однотипных функций. Их нужно вписывать по сути в одноимённые функции в скриптах. Т.е. к примеру функция on_actor_update нужно вписывать в метод update биндера актора (файл bind_stalker.script). Вот некоторые соответствия того, какую функцию из xr_s.script куда прописывать и какой "колбек" из таблицы callbacks использовать впоследствии: Скрытый текст Имя функции из xr_s.script -> Имя функции куда вписывать -> Какой "колбек" из таблицы использовать для подключения/отключения on_actor_update -> actor_binder:update (bind_stalker.script) -> updateon_game_load -> actor_binder:net_spawn (bind_stalker.script) -> game_loadon_actor_destroy -> actor_binder:net_destroy (bind_stalker.script) -> actor_destroyon_npc_hit -> motivator_binder:hit_callback (xr_motivator.script) -> npc_hiton_monster_hit -> generic_object_binder:hit_callback (bind_monster.script) -> monster_hiton_main_menu_on -> main_menu:__init (ui_main_menu.script) -> main_menu_onon_main_menu_off -> main_menu:OnButton_return_game (ui_main_menu.script) -> main_menu_offon_item_drop -> actor_binder:on_item_drop (bind_stalker.script) -> item_drop Подозреваю, что вышеизложенный текст, не для всех является простым, но изложить доступно словами всю идею, не отклоняясь от основной мысли (динамическое "включение" функций) достаточно сложно. Я стараюсь, на сколько это возможно, придерживаться этого компромисса, поэтому, если Вам не понятен текст выше, прочитайте его ещё раз, чтобы у Вас была теория "на уме", а не бегать в последствии глазами по тексту - так Вам же будет проще. Перейдём, так сказать, к делу...В качестве примера приведу решение того, как реализовать убирание оружия во время приёма аптечки. Вопрос достаточно часто задают в соседней теме, поэтому это будет актуально, интересно, а самое главное наглядно отобразит основную идею динамического "включения" функций. Realization Скрытый текст Сначала, расскажу алгоритм, т.е. как это реализуется "на словах".Нужно отследить момент использования аптечки; затем запустить таймер, на время которого убирать оружие; и по окончании работы таймера, дать возможность вновь им пользоваться.А теперь реализация...Момент использования аптечки можно отследить в колбеке актора on_item_drop, но это будет не совсем правильно, так как убираться оружие будет и тогда, когда мы просто выбросим/переложим/продадим аптечку, а нам этого не нужно. Поэтому мы используем колбек именно на использование предмета use_object. В ЗП он есть, в ТЧ также есть, т.е. предусмотрен движком, но не используется. Если Вы делаете это для ТЧ, то нужно добавить метод в биндер актора, который будет отрабатывать во время использования предмета. Делается это так:В методе reinit того же биндера установим колбек на "юз", прописав вот это в тело метода:self.object:set_callback(callback.use_object, self.use_inventory_item, self)А также в метод net_destroy добавить вот такую строку:self.object:set_callback(callback.use_object, nil)Теперь нам нужно добавить сам метод. В любое место файла (но НЕ во внутрь какой-либо функции!!!), например перед строкой:function actor_binder:update(delta)добавьте следующий код:function actor_binder:use_inventory_item(obj)endИменно эта функция, а точнее метод биндера, будет вызываться, когда вы будете использовать какой-то предмет.Нас интересует конкретно аптечка, при этом не важно какая: простая, армейская или научная. Чтобы не прописывать три условия, проверяющие секции аптечек на соответствие, мы используем одну, в которой проверим, что в секции присутствует слово "medkit". Это будет чуть быстрее и универсальнее. Универсальность заключается в том, что Вы можете добавить новые медпрепараты и если Вы хотите того же эффекта и от них, Вам достаточно задать название секции со словом "medkit", например "medkit_special" или "special_medkit". Проверка выглядит так:if string.find(obj:section(), "medkit") thenendЭту проверку нужно добавить в ново созданный (в случае ТЧ) метод use_inventory_item.Момент использования аптечки мы отследили. Теперь нужно запустить таймер на время работы которого убирать оружие. Вот здесь и выходит на передний план функции файла xr_s.script.Сама функция реализующая таймер не сложна и выглядит так (предположим, что она находится в файле use_med.script):function MedkitUsing(userObj)--# Прячем оружие.bind_stalker.hide_weapon()--# Проверим работает ли ещё таймер?--# userObj[1] - время начала работы таймера;--# userObj[2] - время работы таймера (мсек)if time_global() > userObj[1] + userObj[2] then--# Работа таймера закончена - покажем оружие.bind_stalker.restore_weapon()endendПринимает в качестве параметра таблицу с двумя элементами: первый - это время запуска, второй - время работы таймера в миллисекундах.Эту функцию нужно "вешать" на апдейт, т.к. нужно постоянно проверять значение таймера. Если просто вставить это как есть, то, во-первых - нужно прописывать дополнительную проверку, что использована аптечка, во-вторых - проверяться условие будет всегда. Поэтому подключим её динамически.В проверку использования аптечки в колбеке use_object нужно добавить вот такой вызов:xr_s.register_callback("update", use_med.MedkitUsing, {time_global(), 4000})Что это всё означает? Я описывал эту функцию, теперь для ясности давайте сопоставим переданные параметры с описанием выше:"update" - это name, т.е. имя "колбека" из таблицы callbacks;use_med.MedkitUsing - это ссылка на функцию, которую мы "включаем". Обратите внимание на способ подключения, указывается в каком файле находится функция и не пишется никаких скобок, не говоря уже о параметрах;{time_global(), 4000} - помните я говорил, что функция принимает таблицу из двух элементов? Так вот это они и есть. Таблица передаётся в качестве параметра в нашу функцию.Добавив такой вызов, функция начнёт работать на ближайшем апдейте. Всё хорошо - функция отрабатывает, когда мы используем аптечку, но как остановить работу, чтобы разгрузить апдейт? Здесь нам поможет функция unregister_callback из файла xr_s.script. Нужно вписать вызов этой функции в том месте, где работа таймера закончена. После строки:bind_stalker.restore_weapon()допишите:xr_s.unregister_callback ("update", use_med.MedkitUsing)Параметры передаваемые идентичны предыдущей только лишь отсутствуют параметры, т.к. в них нет надобности.По окончании работы таймера, появиться возможность пользоваться оружием и функция "выключится" разгрузив тем самым апдейт.Как видите - всё просто, даже слишком. На самом деле это не всё. В апдейт всё же придётся навсегда вписать вызов одной функции, это функция on_actor_update из файла xr_s.script. Именно эта функция будет проверять есть ли у нас другие функции которые требуется подключить к апдейту. Здесь возможно расхождение в понимании того, что же мы делаем и вообще для чего, для чего делать проверку, если задача стоит в том, чтобы избавиться от неё?В данном примере это сопоставимо с обычной проверкой использовали ли мы аптечку или нет на самом апдейте. А что если таких "примеров" несколько - три, пять, десять? Вот именно здесь данный способ вне конкуренции. Одна проверка, которая контролирует десяток-другой вызовов, при этом те функции, которые не нуждаются в работе находятся "в спящем режиме", если так можно сказать и не используют ресурсы требуемые на постоянную проверку - "а нужно ли нам работать?". Пример вышел тривиальным, но более чем наглядным. Естественно его можно развить, добавить медленное восстановление здоровья, ограничить возможность использования нескольких аптечек подряд, пока работает таймер и т.д. Развитие функционала уже выходит за рамки "урока", поэтому это остаётся на Ваших плечах.Всё работает без вылетов, лично преверял на ТЧ 1.0006. Хотя это и предполагается на ТЧ, но работать будет и на ЧН и на ЗП. Изменено 17 Декабря 2017 пользователем Murarius 6 3 Ссылка на комментарий
Сталкер Лом 356 Опубликовано 20 Марта 2013 Поделиться Опубликовано 20 Марта 2013 (изменено) Ставим новые метки в ПДА [ЗП]Дело было как ни странно, днём... Появилась необходимость поставить метки переходов с одной локации на другую - покопавшись малость в теме "ковырялки ЗП" увидел, что до меня были такие попытки создания меток, но по-крупному копаться в скриптах я не люблю по причине неопытности в скриптах - решил сделать сам. Для начала идём в pda.script:После таблицы под названием sleep_zones_tbl добавим ещё одну, должно получиться так: local sleep_zones_tbl = { {target = "zat_a2_sr_sleep_id", hint = "st_ui_pda_sleep_place"}, {target = "jup_a6_sr_sleep_id", hint = "st_ui_pda_sleep_place"}, {target = "pri_a16_sr_sleep_id", hint = "st_ui_pda_sleep_place"}, {target = "escape_podval_sr_sleep_id", hint = "st_ui_pda_sleep_place"}, {target = "garbage_base_sr_sleep_1_id", hint = "st_ui_pda_sleep_place"}, {target = "garbage_base_sr_sleep_2_id", hint = "st_ui_pda_sleep_place"}, {target = "garbage_dolg_zastava_sr_sleep_id", hint = "st_ui_pda_sleep_place"}, } -- это таблица отметок спального места, её мы не трогаем local level_changer_tbl = { {target = "perehod_darks_esc", hint="perehod_darks_esc_name"}, {target = "id_перехода", hint="надпись над переходом"}, } --А это наша новая таблица, содержащие переходы и надписи над ними После этой добавки идём в самый конец файла и добавляем саму функцию показания перехода function fill_level_changers() for k,v in pairs(level_changer_tbl) do local obj_id = get_story_object_id(v.target) if(obj_id) then level.map_add_object_spot(obj_id, "level_changer_up", v.hint) end end end Где, ui_inGame2_icon_level_changer - имя значка нашего перехода, можно поставить из оригинальной игры, но я создам свойИтак, теперь нам нужно создать вызов нашей функции - далеко ходить не будем (ибо лень ): находим функцию fill_primary_objects и добавляем вызов нашей: function fill_primary_objects() for k,v in pairs(primary_objects_tbl) do local obj_id = get_story_object_id(v.target) if(obj_id) then level.map_add_object_spot(obj_id, "primary_object", v.hint) end end change_anomalies_names() fill_sleep_zones() fill_level_changers() --Вот вызов нашей функции end Со скриптами мы закончили, теперь нужно создать наш переход и текст к нему.Для того, чтобы наш переход отображался нужно придать ему id, для этого создадим его секцию в all.spawn, но с одной добавкой: [8057] ; cse_abstract properties section_name = level_changer name = perehod_darks_esc position = -618.825927,-2.623994,-380.298706 direction = 0,0,0 cse_abstract__unk1_h16 = 0x1 ; cse_alife_object properties game_vertex_id = 1789 distance = 0 level_vertex_id = 404 object_flags = 0xffffff3e custom_data = <<END ;Вот тут и нужно добавить его id, а далее - как раньше [story_object] story_id = perehod_darks_esc END ; cse_shape properties shapes = shape0 shape0:type = sphere shape0:offset = 0,0,0 shape0:radius = 6 ; cse_alife_space_restrictor properties restrictor_type = 3 ; cse_alife_level_changer properties dest_game_vertex_id = 1407 dest_level_vertex_id = 593260 dest_position = 363.344421,15.172136,-39.722797 dest_direction = 0,0,0 dest_level_name = l01_escape dest_graph_point = start_actor_01 silent_mode = 1 ; se_level_changer properties Идём в st_land_names.xml и добавляем в конец файла описания наших переходов: <!-- Переходы --> <string id="perehod_darks_esc_name"> <text>На Кордон</text> </string> <!-- Переходы --> - Результат Собственно всё, таким образом можно создать не только отметки переходов, но и для чего-другого с разными иконками (в данном случае, ну никак иконки "спального места" и "интересного места" под переход не подходили) - допустим, для любителей "читерки", можно добавить отметку к укрытиям (добавив в секцию укрытия в all.spawn строки присвоения id) или чего-другого, это зависит от потребности. Изменено 19 Сентября 2014 пользователем World_Stalker 2 Работы на Artstation - https://www.artstation.com/artist/stalker_lom Ссылка на комментарий
FantomICW 678 Опубликовано 11 Мая 2013 Поделиться Опубликовано 11 Мая 2013 (изменено) Создание инвентарного комплекса в чистом ЗП Файл с отработанным примером Перед тем, как начать урок, я хочу сказать, что скриптовой частью я обязан товарищу Ховану и Николаю Болтову. Именно благодаря их скриптам я нашел способ сделать подобную вещь! Огромное им спасибо! А теперь перейдем к уроку. Файлы, которые нам потребуются: - 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. Настроим его так, как нам этого захочется. [medkit_complex]:booster $spawn = "food and drugs\medkit_complex" visual = dynamics\devices\dev_aptechka\dev_aptechka_mid.ogf description = st_medkit_complex_desc inv_name = st_medkit_complex inv_name_short = st_medkit_complex inv_weight = 1.8 inv_grid_width = 2 inv_grid_height = 2 inv_grid_x = 10 inv_grid_y = 27 cost = 30000 attach_angle_offset = 0.440521, 1.378287, -0.644026 attach_position_offset = 0.104196, -0.010821, 0.076969 attach_bone_name = bip01_r_hand auto_attach = false bone_name = bip01_r_hand position_offset = 0.0,0.0,0.0 angle_offset = 1.570790,1.570790,3.92699 use_sound = interface\inv_medkit Долго здесь зацикливаться не будем. Все элементарно. Могу только сказать, что при использовании будет проигрываться звук аптечки, а модель взяли армейской аптечки. 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 На этом урок заканчивается. Осталось только прописать пак ГГ и протестировать! Изменено 11 Мая 2013 пользователем FantomICW 2 2 Ссылка на комментарий
Сталкер Лом 356 Опубликовано 23 Июля 2013 Поделиться Опубликовано 23 Июля 2013 (изменено) Добавление новых кнопок в ПДА (ЗП) Примечание: Сей "фокус" можно проделывать только с правками от проекта X-Ray extensions, а конкретно, с правками ПДА. Итак, всё-таки захотели мы создать вкладку в ПДА. Но не знаем как. Проблемы, согласен. Вот некоторая часть решения этой проблемы: 1. Заходим в pda.xml, ищем таблицу: <tab x="443" y="57" width="468" height="27"><button x="0" y="0" width="172" height="27" id="eptTasks" hint="pda_btn_quests_hint" frame_mode="0"> <text align="c" vert_align="c" x="0" y="0" width="157" height="27" font="letterica16">pda_btn_quests</text> <texture>ui_inGame2_pda_button</texture> <text_color> <t r="255" g="255" b="255"/> <d r="255" g="255" b="255"/> <e r="200" g="200" b="200"/> <h r="170" g="170" b="170"/> </text_color></button><button x="148" y="0" width="172" height="27" id="eptRanking" hint="pda_btn_ranking_hint" frame_mode="0"> <text align="c" vert_align="c" x="0" y="0" font="letterica16">pda_btn_ranking</text> <texture>ui_inGame2_pda_button</texture> <text_color> <t r="255" g="255" b="255"/> <d r="255" g="255" b="255"/> <e r="200" g="200" b="200"/> <h r="170" g="170" b="170"/> </text_color></button><button x="296" y="0" width="172" height="27" id="eptLogs" hint="pda_btn_logs_hint" frame_mode="0"> <text align="c" vert_align="c" x="0" y="0" font="letterica16">pda_btn_logs</text> <texture>ui_inGame2_pda_button</texture> <text_color> <t r="255" g="255" b="255"/> <d r="255" g="255" b="255"/> <e r="200" g="200" b="200"/> <h r="170" g="170" b="170"/> </text_color></button></tab> 2. Для лучшего понимания, разберём это дело по блокам: Это блок является "колбой", в которой находятся кнопки в ПДА: <tab x="Смещение колбы по Х" y="Смещение колбы по У" width="Ширина колбы" height="Высота колбы"></tab> А этот блок как раз и является кнопкой: <button x="Смещение кнопки по Х" y="Смещение кнопки по У" width="Ширина" height="Высота" id="Уникальное Айди (id) кнопки" hint="Подсказка, всплывающая при наведении на кнопку" frame_mode="0"> <text align="c" vert_align="c" x="0" y="0" font="letterica16">Ссылка на текст-описание кнопки</text> <texture>Имя текстуры кнопки</texture> <text_color> <!-- Цветовые настройки текста в кнопке --> <t r="255" g="255" b="255"/> <d r="255" g="255" b="255"/> <e r="200" g="200" b="200"/> <h r="170" g="170" b="170"/> </text_color></button> 3. А теперь приступим к созданию новой кнопки: В колбе, содержащей кнопки, нужно изменить параметр "Смещения по Х", отняв от значения число, равное значению "Смещения кнопки по Х" от ВТОРОЙ кнопки: <tab x="296" y="57" width="468" height="27"></tab> А так же, нужно к параметру "width="468"" (и последующему значению, если добавляете больше одной кнопки) прибавить число 172, которое равно ширине кнопки. Первый пункт делается для того, чтобы новая кнопка не "налезала" на другие части ПДА (Часы, другие кнопки и т.п.), а второй, чтобы кнопка была в "колбе" и была активной, то есть, доступной для нажимания. Делается это для того, чтобы новая кнопка не "налезала" на другие части ПДА (Часы, другие кнопки и т.п.). Далее, создадим саму кнопку (в данном случае для энциклопедии): <button x="444" y="0" width="172" height="27" id="eptEncyclopedia" hint="pda_btn_encyclopedia_hint" frame_mode="0"> <text align="c" vert_align="c" x="0" y="0" font="letterica16">pda_btn_encyclopedia</text> <texture>ui_inGame2_pda_button</texture> <text_color> <t r="255" g="255" b="255"/> <d r="255" g="255" b="255"/> <e r="200" g="200" b="200"/> <h r="170" g="170" b="170"/> </text_color></button> Всё, кнопка создана и функционирует, её название некоректно отображается ("pda_btn_encyclopedia" вместо "Энциклопедия"), исправим это. 4. Идём в файл configs\text\rus\ui_st_pda.xml и добавим две секции в самый конец: <string id="pda_btn_encyclopedia"> <text>Энциклопедия</text></string><string id="pda_btn_encyclopedia_hint"> <text>Открыть энциклопедию</text></string> (Здесь, для энциклопедии, а вам нужно вписать ссылку на свою кнопку и её название по образцу). Всё, теперь кнопка работает, даже отображается корректно, но не открывает новый раздел: когда нажимаем на неё, то перед нами остаётся предыдущая активная вкладка, хоть и наша новая кнопка активна. Вот объяснение этого явления от тов. @Malandrinus: Текущее содержимое окна при активации свой кнопки не убирается, поэтому придётся закрывать его своим содержимым с помощью помещения диалога поверх окна. К сожалению, получение текущего окна в ЧН и ЗП стало невозможно и пока решения этой проблемы не видно.Так что новой вкладки мы не получим - только кнопочка. Даже не расскажу, как это окно сделать, т.к. я пробовал и у меня, пока, ничего не вышло. Будем пытаться, а пока - всё.P.S. Вот так это будет выглядеть: P.P.S. Добавлена информация, из за отсутствия которой не функционировала кнопка. Изменено 19 Сентября 2013 пользователем ColR_iT Работы на Artstation - https://www.artstation.com/artist/stalker_lom Ссылка на комментарий
Viktor_Kris 24 Опубликовано 26 Июля 2013 Поделиться Опубликовано 26 Июля 2013 (изменено) Файлы для работы:Из распакованного all.spawn'а:alife_локация.ltxА также скрипты из gamedata\scripts :pda.scriptxr_effects.scriptsПриступим:1) Открываем alife_локация и добавляем секцию: [1867] ; номер секции ; cse_abstract properties section_name = space_restrictor name = ваше_название_места position = -180.277893066406,9.41139984130859,77.5603179931641 ;нужная позиция (в данном случае - домик в Изумрудном) direction = 0,0,0 ; cse_alife_object properties level_vertex_id=1233171 ; левел_вертекс game_vertex_id=13 ; гейм_вертекс distance = 9.09999942779541 object_flags = 0xffffff2e custom_data = <[story_object] story_id = ваше_название_места_id [logic] cfg = scripts\sr_sleep.ltx END ; cse_shape properties shapes = shape0,shape1 shape0:type = box shape0:axis_x = 3.85299897193909,0,0 shape0:axis_y = 0,2.51200008392334,0 shape0:axis_z = 0,0,6.23259878158569 shape0:offset = 0,0,0 shape1:type = box shape1:axis_x = 3.16719889640808,0,0 shape1:axis_y = 0,2.51200008392334,0 shape1:axis_z = 0,0,4.87539911270142 shape1:offset = -3.29999589920044,0,-0.199996992945671 ; cse_alife_space_restrictor properties restrictor_type = 3 Закрываем. 2) Заходим в pda.script, ищем: { {target = "zat_a2_sr_sleep_id", hint = "st_ui_pda_sleep_place"}, {target = "jup_a6_sr_sleep_id", hint = "st_ui_pda_sleep_place"}, {target = "pri_a16_sr_sleep_id", hint = "st_ui_pda_sleep_place"}, } и меняем на это: { {target = "zat_a2_sr_sleep_id", hint = "st_ui_pda_sleep_place"}, {target = "jup_a6_sr_sleep_id", hint = "st_ui_pda_sleep_place"}, {target = "pri_a16_sr_sleep_id", hint = "st_ui_pda_sleep_place"}, {target = "ваше_название_места_id", hint = "st_ui_pda_sleep_place"}, } Закрываем 3) Открываем xr_effects.script, ищем: function sleep(actor, npc) local sleep_zones = { "zat_a2_sr_sleep", "jup_a6_sr_sleep", "pri_a16_sr_sleep", "actor_surge_hide_2" } и меняем на это: function sleep(actor, npc) local sleep_zones = { "ваше_название_места", "zat_a2_sr_sleep", "jup_a6_sr_sleep", "pri_a16_sr_sleep", "actor_surge_hide_2" } Всё, можно запускать игру и проверять! Изменено 19 Сентября 2014 пользователем World_Stalker 2 1 Ссылка на комментарий
Сталкер Лом 356 Опубликовано 30 Июля 2013 Поделиться Опубликовано 30 Июля 2013 Создание энциклопедии для ПДА в ЗП.Примечание: Аналогично предыдущему уроку, энциклопедию реализовать можно только при помощи проекта X-Ray extensions. Для того, чтобы кнопка энциклопедии появилась, нужно выполнить мой предыдущий урок "Добавление новых кнопок в ПДА (ЗП)".Ссылка на готовую энциклопедию+видеодемонстрация: http://rghost.ru/47774542 Как мы уже знаем из слов тов. malandrinus, "родные" для ПДА вкладки нам нужно будет закрывать собственной. Для этого нам нужен свой GUI и нам нужна "ловля" инфопоршня при открытии вкладки. Мастерить велосипед самому мне не понравилось: хоть уроки по GUI есть, но мне показалось, что с моим опытом я могу сделать только несколько окошечек, не более. Про вкладку в ПДА, которая соответствовала бы стилю нашего электронного друга я вообще даже не мечтал, поэтому взял наработки тов. DEXXX (записная книжка в ЧН) и Geonezis (Энциклопедия оружия, на основе предыдущей работы). Скачиваем готовую энциклопедию, там есть пометки, для понимания, как это всё работает, тут объясню чуть подробней. Адаптация: С другими модами (и с оригиналом) конфликтуют только два скрипта: _g.script и bind_stalker.script. В _g.script добавлены глобальные функции: function run_gui(gui, close_inv) --Функция для запуска GUI, в нашем случае, энциклопедии if close_inv == true then gui:ShowDialog(true) game_hide_menu() level.show_weapon(false) else gui:ShowDialog(true) end end function GetString(id) --Функция для инициализации имён if not(id) then return "" end return game.translate_string(id) end А в bind_stalker.script добавлен вызов скрипта, который отлавливает инфопоршень при открытии вкладки энциклопедии: function actor_binder:update(delta) gui_callbacks.on_info() --Вызов нашего "Ловчего поршней" object_binder.update(self, delta) ... Всё, адаптация пройдена - должна функционировать. А теперь - как этой с энциклопедией работать. Допустим, мы решили добавить нового мутанта - Тарк (Tark). Делается это так: Добавляем этого мутанта в таблицу мутантов, что в скрипте gui_main.script: local pda_enc_mutants={ "Mutant_boar", "Flesh", "Pseudo_flesh", "Tark", --Вот он "Bloodsucker", ... Теперь, от выбранного нами имени будет зависеть, как будет называться текстура-иконка, текст с описанием, название мутанта на "человеческом" языке (а не на машинном) и и название инфопоршня, при получении которого мы получим статью в энциклопедию. Текстура должна иметь следующее имя: ui_enc_#Имя мутанта# . Текст с описанием: enc_#Имя мутанта#. Название будет равно Имени мутанта. А инфопоршень будет "величаться": #Имя мутанта#_info. Для лучшей ориентации и унификации, подобная структура, описанная выше, будет актуальна и для мутанта и для группировок и для всего остального. Думаю, так будет лучше. Как я говорил ранее, инфопоршень нужно выдавать через что-либо: диалоги, награды за задания, "отловы" на то, что вы кого-то убили, либо некоторая вероятность получения поршня при обыске трупов. Парт-текстура, по умолчанию, читается из файла ui_pda_encyclopedia.dds. Если хотим добавить иконку, то нужно вставить в файл иконку (по умолчанию, она должна быть 165 на 107 пикселей, иначе будет растянута\сплющена), измерить её координаты по аналогии с прудыдущими и задать имя, как я уже описал выше. Описание и название указывается в фале configs\text\rus\st_notepad.xml. В принципе, можно вставить в другой файл, но лучше соблюдать порядок - вам же будет лучше. Всё, на этом я удаляюсь - пользуйтесь и указывайте авторов. Доброй Зоны, сталкеры. 2 2 Работы на Artstation - https://www.artstation.com/artist/stalker_lom Ссылка на комментарий
Akella-96 aka SvD 35 Опубликовано 10 Августа 2013 Поделиться Опубликовано 10 Августа 2013 (изменено) Небольшой пак уроков от меня (всего два урока, позже будут еще). Оба урока в формате .doc. • Добавление абсолютно новых ящиков на классе inventory_box • Показываем состояние здоровья ГГ в процентах Надеюсь, они окажутся полезными. Скачать : http://rghost.ru/48034494 Изменено 19 Сентября 2014 пользователем World_Stalker 3 AWRP : Re - Load 0.2 © Ссылка на комментарий
RayTwitty 502 Опубликовано 24 Сентября 2013 Поделиться Опубликовано 24 Сентября 2013 (изменено) Это не урок, просто небольшие памятки по некоторым вещам, которые мне были нужны. Вся информация взята из оригинальных файлов ТЧ. Настройки костей у динамического источника света Настройки комментариев у звуков монстров (в различных состояниях) Конечно, это все несложно выяснить самому, но иной раз надоест все это запоминать или куда-то записывать... З.Ы. такое вообще надо бы оформить в таблицу, но мне было лень это делать, поэтому как есть Изменено 24 Сентября 2013 пользователем Shadows 4 Ссылка на комментарий
Старлей 88 Опубликовано 3 Ноября 2013 Поделиться Опубликовано 3 Ноября 2013 (изменено) Отключение интро-ролика, и последующий его запуск. Примечание: Теоретически это должно работать на всех частях сталкера, но я буду показывать на примере Чистого неба. Итак, начнем. Нам требуется отключить интро-ролик после начала новой игры. Проблема в том, что запуск ролика движковый, поэтому придется изощряться. Находим в файле configs/ui/ui_movies.xml секцию "intro_game". И приводим ее к такому виду: <intro_game> <global_wnd x="0" y="0" width="1024" height="768"> <auto_static x="0" y="0" width="1024" height="768" stretch="1"> <texture>intro\intro_back</texture> </auto_static> </global_wnd> <item type="video"> <sound>$no_sound.ogg</sound> <delay>0</delay> <pause_state>off</pause_state> <function_on_stop>xr_effects.darkness</function_on_stop> <video_wnd x="0" y="0" width="1024" height="768" stretch="1"> <texture x="0" y="1" width="1280" height="954">intro\intro_back</texture> </video_wnd> </item> </intro_game> Первая часть работы сделана. Теперь при начале новой игры интро-ролика не будет. А что если нам надо его запустить впоследствии? Для этого создаем в этом же файле новую секцию, intro_game2, к примеру. И пишем в ней: <intro_game2> <play_each_item>1</play_each_item> <global_wnd x="0" y="0" width="1024" height="768"> <_auto_static x="0" y="0" width="1024" height="768" stretch="1"> <window_name>back</window_name> <texture>intro\intro_back</texture> </_auto_static> </global_wnd> <item type="video"> <sound>characters_voice\scenario\video\intro</sound> <pause_state>on</pause_state> <function_on_stop>xr_effects.start_marsh_intro</function_on_stop> <video_wnd x="0" y="0" width="1024" height="768" stretch="1"> <texture x="1" y="1" width="628" height="358">intro\intro_half</texture> </video_wnd> <background x="0" y="0" width="1024" height="768" stretch="1"> <texture>intro\intro_back</texture> </background> </item> <item type="image"> <length_sec>5</length_sec> <pause_state>off</pause_state> <main_wnd> <auto_static start_time="0" length_sec="5" x="0" y="0" width="1230" height="768" light_anim="intro_1" light_anim_cyclic="0" la_alpha="1" la_texture="1" stretch="1"> <window_name>w1</window_name> <texture>intro\intro_back</texture> </auto_static> </main_wnd> </item> </intro_game2> Обратите внимание на поле: <function_on_stop>xr_effects.start_marsh_intro</function_on_stop> Здесь указывается функция, которая будет запущена по истечению туториала. Но мы всего лишь создали новый туториал, теперь его надо запустить. Для удобства можно поместить функцию в xr_effects.script function go_intro() game.start_tutorial("intro_game2") end Дальше остается только запустить эту функцию, как это сделать - выбор на ваше усмотрение. Изменено 19 Сентября 2014 пользователем World_Stalker 3 Ray Of Hope - кооператив сталкера OldStory Ссылка на комментарий
Waljok 9 Опубликовано 7 Апреля 2014 Поделиться Опубликовано 7 Апреля 2014 (изменено) Так как я начинающий модостроитель, но всё же поделюсь кое-каким опытом. Когда добавляете новую функцию с приёмом-отдачей, то всегда пишите функцию отдачи первой. Дело в том, что Меченому-Стрелку никто в Зоне не верит и сначала все требуют нужный кому либо предмет. Сначала я не понимал, почему у меня не срабатывает функция. Но я вовремя вспомнил, что в солянке сначала ГГ отдаёт что-либо, а потом получает награду. Попробовал функцию отдачи прописать первой и - вауля, скрипт срабатывает. Может быть, кому нибудь пригодится. Изменено 19 Сентября 2014 пользователем World_Stalker 1 Весёлые люди - это не те, кто постоянно весёлые, а те, кто веселится даже в самых худших ситуациях. Ссылка на комментарий
Это популярное сообщение. Сталкер Лом 356 Опубликовано 17 Апреля 2014 Это популярное сообщение. Поделиться Опубликовано 17 Апреля 2014 (изменено) Работа с Sound_occluder.Примечание: искал (не очень тщательно) в интернете более-менее подробную инструкцию по Окклюдеру, но не нашёл. Пожалуй, черкну тут для чего он нужен и как его использовать.Итак, вы сделали тоннель под землёй, но не отдельной локацией, а как небольшое дополнение к другой, например, как у меня: Сделали, скомпилили локацию для пробы, но находясь в тоннеле мы слышим, как на асфальте плоти доедают бандюка, смачно чавкая и хрюкая, ещё гудение трансформатора в комнатушке, шум ветра от елей (если они являются статичным звуком на локации), а если мы на поверхности, то слышим, как в тоннеле шуршат крысы и скрепит, вращаясь, лампочка. Не порядок.Вот для этих целей и существуют и sound_occluder - для отсечения звуков, находящихся "по ту сторону" плоскости окклюдера. Это работает как для ГГ, так и для NPC. Можно сделать окклюдер в виде плоскостей, коробок и т.п. и в СДК расставлять так, как нужно, но в данном случае, геометрия сложная и с так плоскостями придётся повозиться, поэтому сделаем в 3д редакторе. Я этот тоннель делал в Милке, там буду делать и окклюдер. Вот:Кстати говоря, эту модель можно будет использовать и для HOM, для лучшей оптимизации.Теперь настроим Occluder (и HOM. если вы захотели поставить и её) в СДК: И ещё во вкладке Surface нужно указать параметр "2 Sided". Объект станет синим и полупрозрачным - значит, что Окклюдер готов, осталось разместить его в нужном месте.Для того, чтобы расположить окклюдер на том же месте ,что и наш тоннель, нам нужно скопировать (ctrl+c, ctrl+v) наш тоннель и, выбрав один из них, нажать Enter и в поле Reference заменить исходную модель на наш sound_occluder, должно получится так: Вот и всё, теперь на локации будут отсекаться звуки, проигрываемые за окклюдером, но не все!Sound_occluder в сталкере не отсекает ambient (окружение), так как эти звуки проигрываются в позиции ГГ. Так же не отсекаются все собственные звуки ГГ, что логично. Так же окклюдер в сталкере не совершенен: в реальности, если мы находимся в том же тоннеле, то звук мы бы слышали, но тихо и со стороны выхода из него, а вот в сталкере мы не будем слышать ничего. Так же и с NPC - сли за стеной с окклюдером будет хрюкать кабан, то NPC его не услышит. Да и мы тоже...Ссылка на скачивание архива со статьёй+иллюстрации: https://yadi.sk/d/vC18bUaZX5c7X Изменено 19 Сентября 2014 пользователем World_Stalker оформил 3 2 Работы на Artstation - https://www.artstation.com/artist/stalker_lom Ссылка на комментарий
Это популярное сообщение. FantomICW 678 Опубликовано 25 Июля 2014 Это популярное сообщение. Поделиться Опубликовано 25 Июля 2014 (изменено) Квест на убийство мутанта через туториал ("Press F To Win")Платформа: Сталкер Зов Припяти 1.6.02Автор: FantomICW, использованы наработки для Смерти ВопрекиУровень сложности: средний (не для самых зелёных новичков) Введение Приветствую! К своему Дню рождения (26.07) я хотел бы преподнести Сталкер-сообществу еще один небольшой подарок. В этот раз мое внимание привлекла тема, недавно затронутая в "Вопроснице"...Относительно недавно пользователь ap-pro Telnov1996 задал один вопрос:Можно ли организовать скриптовые сцены борьбы с мутантами, работающие по принципу 'Press "F" to win'?К обсуждению подключились уважаемый Dorian23Grey и, собственно, я сам. Ситуация выходит следующая:1. Во-первых, на X-Ray сцены с анимациями в стиле CoD, Metro и т. д. делать не очень удобно, как таковые.2. Требуется иметь отличные умения в анимации объектов.3. Нужно настроить взаимодействие логики с таймерами и анимации.На данный момент такое мало кто реализовывал. Однако, вариант, когда ГГ подходит к мутанту, запускается туториал с последующим выполнением убийства, - вполне реализуемая фишка. Сегодня об этом и пойдет речь.Пускай, на Затоне в пределах Северного озера поселился уникальный болотный псевдогигант, которому совершенно плевать на пули сталкеров. Единственный быстрый способ его устранить - активировать гравитационный артефакт. Когда ГГ подойдет к мутанту с артефактом, запустится туториал с надписью "Активировать артефакт". При нажатии F, запустится функция, которая создаст на месте мутанта партикл разрыва от грави-аномалии. Подготовка к действу - Paint Net, Adobe Photoshop или другой редактор текстур (если кто-то будет создавать мутанту уникальную текстуру)- Notepad++ Опять же, если желаете сделать для своего мутанта уникальную текстуру, пожалйста. Как по мне, то новую модель или текстуру стоит сделать, ибо супер-крутой псевдогиг должен как-то выделяться среди своих сородичей. Я сделал условный "ретекстур" (в кавычках, потому что ляпнуть чуток крови и "узеленить" текстуру - ретекстуром назвать нельзя) монстра под болото.:Если кому нужна текстура, ловите (бамп подключен стандартный). Для хорошего эффекта разрыва тела в аномалии, я буду использовать некоторые партиклы от АМК: amk\\blow_body amk\\zomb_explode У кого они есть (или есть альтернативный вариант) - супер, отлично. У кого их нету - не волнуйтесь, чуть позже я загружу готовый particles.xr, а пока приложу два варианта таблицы партиклов для обоих случаев. Если вы работаете не в СДК, а с ACDC, то вам нужно будет снять координаты для места, где будет сидеть мутант. Само место действия (примерно) показвыаю на карте:Я прошел немного вперед к воде, снял координаты: -19.00901222229,-7.0012526512146,526.37811279297,907875,47 Практика 1. В configs/gameplay/dialogs_zaton.xml добавим два новых диалога: <dialog id="zat_super_psevdogig_take_task_dialog"> <!--Взятие квеста--> <dont_has_info>psevdogig_task_dialog_done</dont_has_info> <phrase_list> <phrase id="0"> <text>zat_super_psevdogig_take_task_dialog_0</text> <next>1</next> </phrase> <phrase id="1"> <text>zat_super_psevdogig_take_task_dialog_1</text> <next>2</next> </phrase> <phrase id="2"> <text>zat_super_psevdogig_take_task_dialog_2</text> <next>3</next> </phrase> <phrase id="3"> <text>zat_super_psevdogig_take_task_dialog_3</text> <next>4</next> </phrase> <phrase id="4"> <text>zat_super_psevdogig_take_task_dialog_4</text> <next>5</next> </phrase> <phrase id="5"> <text>zat_super_psevdogig_take_task_dialog_5</text> <give_info>psevdogig_task_dialog_done</give_info> <action>dialogs_zaton.give_super_psevdogig_task</action> <!--Выдаем задание и артефакт--> </phrase> </phrase_list> </dialog> <dialog id="zat_super_psevdogig_task_end_dialog"> <has_info>zat_super_psevdogig_af_activation</has_info> <dont_has_info>psevdogig_task_finished</dont_has_info> <phrase_list> <phrase id="0"> <text>zat_super_psevdogig_task_end_dialog_0</text> <next>1</next> </phrase> <phrase id="1"> <text>zat_super_psevdogig_task_end_dialog_1</text> <give_info>psevdogig_task_finished</give_info> <action>dialogs_zaton.give_super_psevdogig_task_reward</action> <!--Выдаем награду--> </phrase> </phrase_list> </dialog> 2. Пропишем их Бороде (секция zat_a2_stalker_barmen, файл character_desc_zaton.xml): <actor_dialog>zat_super_psevdogig_take_task_dialog</actor_dialog> <actor_dialog>zat_super_psevdogig_task_end_dialog</actor_dialog> 3. В configs/text/rus/st_dialogs_zaton.xml поместим текстовку диалогов: <string id="zat_super_psevdogig_take_task_dialog_0"> <text>Как дела, Борода? Есть новости какие-то?</text> </string> <string id="zat_super_psevdogig_take_task_dialog_1"> <text>Здравствуй. Новость-не новость, а у нас на Северном озере поселился какой-то убер-псевдогигант, который не дает сталкерам (да и псевдоплотям, что уж тут говорить) покоя...Тварь неубиваемая какая-то. Посоветовавшись с Гонтой, решили попробовать его (я про псевдогиганта) активацией артефакта ликвидировать. Подходящий артефакт у меня вот есть, а смельчака для этого задания найти не можем...</text> </string> <string id="zat_super_psevdogig_take_task_dialog_2"> <text>Знаешь, я мог бы вам помочь.</text> </string> <string id="zat_super_psevdogig_take_task_dialog_3"> <text>Ты с Цементного завода рухнул? Да эта хрень тебя может в псевдочебурек превратить...А кто мне будет все те же арты таскать? На ком Лоцман зарабатывать будет? Короче, ты уверен?</text> </string> <string id="zat_super_psevdogig_take_task_dialog_4"> <text>Уверен. Мне скучно, прост)00)).</text> </string> <string id="zat_super_psevdogig_take_task_dialog_5"> <text>Ну, окей, удачи. Вот тебе "Грави" для активации. Будь аккуратен.</text> </string> <string id="zat_super_psevdogig_task_end_dialog_0"> <text>Все, старик. Нету больше твоего убер-псевдогигабайта.</text> </string> <string id="zat_super_psevdogig_task_end_dialog_1"> <text>Вах, слушай, молодец какой! Молоток! Возьми себе печеньку.</text> </string> С диалогами все. Здесь все просто, поэтому детально рассказывать о них не буду. Если же эта часть показалась Вам сложной, то, простите, этот урок не совсем для Вашего уровня знаний. 1. В configs/misc/tm_zaton.ltx добавим секция квеста: [zat_super_psevdogig_task] icon = ui_inGame2_Logovo_krovososov prior = 10 storyline = false title = {+zat_super_psevdogig_af_activation} zat_super_psevdogig_task_2, zat_super_psevdogig_task_1 descr = {+zat_super_psevdogig_af_activation} zat_super_psevdogig_task_2_text, at_super_psevdogig_task_1_text target = {+zat_super_psevdogig_af_activation} zat_a2_stalker_barmen, zat_super_psevdogig_squad condlist_0 = {+psevdogig_task_finished} complete Немного разбора:- иконка стоит от миссии на устранение логова кровососов- задание имеет две стадии: часть на устранение мутанта и часть, которая требует поговорить с Бородой (на эту часть обновление происходит при получении инфопорции zat_super_psevdogig_af_activation, мы к ней вернемся позже)- в первой части метка задания падает на сквад мутанта (его story_id - zat_super_psevdogig_squad), во второй - на Бороду- квест заканчивается при получении инфы psevdogig_task_finished, которая выдается в уже созданном нами диалогеКак видите, квест по структуре очень простой.2. Прописываем в configs/text/rus/st_quests_zaton.xml его текстовую часть: <string id="zat_super_psevdogig_task_1"> <text>Помощь криворуким: устранить убер-псевдогиганта</text> </string> <string id="zat_super_psevdogig_task_1_text"> <text>Я оказался прав: все сталкеры на Затоне - криворукие болваны. Теперь мне нужно за них устранить очень крутого мутанта на Северном озере.</text> </string> <string id="zat_super_psevdogig_task_2"> <text>Помощь криворуким: сломать Бороде нос</text> </string> <string id="zat_super_psevdogig_task_2_text"> <text>Хочу сказать пару ласковых слов Бороде. Какого фига это барыго в экзе не сказало мне, что меня на озере ждет не убер-псевдогигант, а жирная зеленая Гидра Затонская?</text> </string> Переходим к конфигам мутанта. 1. Файл configs/creatures/m_giant.ltx. Сделаем секцию нашего уникального псевдогиганта. Она будет почти аналогичная обычному гиганту: [super_psevdogig]:m_gigant_e $spawn = "monsters\gigants\super_psevdogig" visual = monsters\psevdogigant\psevdogigant_uber ;Это моя новая модель corpse_visual = monsters\psevdogigant\psevdogigant_uber_dead ;Это тоже rank = 50 ;Увеличим ранг spec_rank = strong ;Псевдик Стронг! radiation_pp_effector_name = postprocess_acidic ;Выставим кислотный постпроцесс attack_params = super_psevdogig_attack_params ;Новая секция параметрво атаки [super_psevdogig_attack_params] ;Тут усилен импульс ;-------------------------------------------------------------------------------------------------------------------------------------------- - ; anim | time[0..1] | hit_power | impulse | impulse_dir (x,y,z) | Field of hit_test (left,right, top, bottom) | Test Dist ;-------------------------------------------------------------------------------------------------------------------------------------------- - ;Bite stand_attack_0 = 0.25, 0.9, 200, 0.5, 1.0, 0.5, -0.8, 0.8, -1.8, 1.8, 2.6 ;Left leg Strike stand_attack_1 = 0.40, 0.9, 150, 5.0, 2.5, 4.0, -0.6, 0.6, -1.8, 1.8, 3.2 ;Bite2 stand_attack_2 = 0.25, 0.9, 200, 0.5, 1.0, 5.0, -0.8, 0.8, -1.8, 1.8, 2.6 stand_attack_run_0= 0.5, 0.9, 600, 0.5, 1.0, 5.0, -0.6, 1.3, -1.8, 1.8, 3.3 jump_attack_1 = 0.1, 2.00, 1600, 0.5, 1.0, 5.0, -1.0, 1.3, -1.6, 1.6, 5.5 2. Дальше требуется создать мутанту сквад в configs/misc/squad_descr_zaton.xml: [zat_super_psevdogig_squad]:online_offline_group faction = monster_special npc = super_psevdogig ;НПС в скваде - наш псевдогигант target_smart = zat_sim_2 ;Целевой смарт - полуостров на Северном озере spawn_point = zat_sim_2_giant_home ;Спавн поинт - поинт "логова" для мутанта story_id = zat_super_psevdogig_squad ;Sid совпадает с названием секции (ваш Кэп) 1. Прежде всего, открываем файл логики смарта полуострова - configs/scripts/zaton/smart/zat_sim_2.ltx, и внизу добавляем секцию exclusive с ссылкой на эксклюзивную логику гиганта: [exclusive] giant = zaton\zat_sim_2_super_psevdogig.ltx Итак, логика нашего мутанта называется giant.2. Переходим к самой логике. Создаем файл zaton\zat_sim_2_super_psevdogig.ltx. Заполняем его: [logic@giant] ;Название логики - giant (смотрите выше) suitable = {=target_squad_name(zat_super_psevdogig_squad)} true ;Логика доступна только для монстра из нашего сквада monster_job = true prior = 200 active = mob_home@giant [mob_home@giant] on_info = %=restore_health% ;Здоровье мутанта постоянно пополняется ;Если дистаниция до ГГ меньше 7 метров, в наличии есть квестовый артефакт, а активного туториала нету, то запускается туториал убийства: on_info2 = {=dist_to_actor_le(7) =actor_has_item(super_psevdogig_af_gravi) !has_active_tutorial} %=run_tutorial(zat_super_psevdogig_af_tutor)% ;Если дистаниция до ГГ больше 7 метров, в наличии есть квестовый артефакт, а туториал запущен, то запускается туториал убийства: on_info3 = {=dist_to_actor_ge(7) =actor_has_item(super_psevdogig_af_gravi) =has_active_tutorial} %=stop_tutorial% ;При получении инфы "zat_super_psevdogig_af_activation", убиваем НПС функцией "kill_npc" из xr_effects.script: on_info4 = {+zat_super_psevdogig_af_activation} %=kill_npc% ;При получении инфы "zat_super_psevdogig_af_activation_begin", удаляем НПС вообще и запускаем партиклы аномалии/разрыва новой функцией on_info5 = {+zat_super_psevdogig_af_activation_begin} %=zat_super_psevdogig_explode_2% path_home = giant_home ;В way_zaton.ltx это - zat_sim_2_giant_home ("логово") ;Настройки охраны "логова": home_min_radius = 20 home_max_radius = 50 aggressive = true 3. Настало время использовать ранее снятые координаты. Распаковываем all.spawn с ACDC или же используем СДК Левел Эдитор, чтоб создать точку для монстра в way_zaton.ltx: [zat_sim_2_giant_home] points = p0 p0:name = wp00 p0:flags = 0x1 p0:position = -19.00901222229,-7.0012526512146,526.37811279297 p0:game_vertex_id = 47 p0:level_vertex_id = 907875 Собираем спавн. 1. В логике мы уже упомянули предмет super_psevdogig_af_gravi. Это секция квестового артефакта, который мы якобы будем активировать. Открываем configs/misc/quest_items.ltx, и добавляем туда его: [super_psevdogig_af_gravi]:device_pda visual = dynamics\artefacts\af_gravi.ogf description = st_af_gravi_descr inv_name = st_af_gravi_name inv_name_short = st_af_gravi_name inv_weight = 0.5 inv_grid_x = 15 inv_grid_y = 0 cost = 12000 can_trade = false ;Нельзя продать quest_item = true ;Нельзя выбросить story_id = super_psevdogig_af_gravi Стандартная секция квестового предмета с "родителем" device_pda.2. Также в логике мы объявили запуск туториала: %=run_tutorial(zat_super_psevdogig_af_tutor)% Все туториалы игры прописываются в configs/ui/game_tutorials.xml. Вам, вполне возможно, секция ниже может показаться какой-то странной штукой. На самом деле, там все просто, но, считаю, это лучше разбирать в отдельных уроках по худу и гуи, поэтому сейчас можете не забивать голову. Самые важные параметры я укажу: <zat_super_psevdogig_af_tutor> <!--Название--> <global_wnd/> <item> <disabled_key>quit</disabled_key> <length_sec/> <!--При нажатии F, запускается функция xr_effects.zat_super_psevdogig_explode_1--> <action id="use" finalize="1">xr_effects.zat_super_psevdogig_explode_1</action> <guard_key>use</guard_key> <!----Ниже уже другие параметры--> <grab_input>0</grab_input> <main_wnd> <!--Всякие параметры текста. Я задал 32 шрифт и красный цвет по RGB. Секция текста - st_tutor_af_activation--> <auto_static start_time="0" length_sec="5000" x="512" y="660" width="300" height="60" alignment="c" stretch="1"la_cyclic="1" la_texture="1" la_alpha="1"> <text font="graffiti32" r="225" g="36" b="36" a="255" align="c">st_tutor_af_activation</text> </auto_static> </main_wnd> </item> </zat_super_psevdogig_af_tutor> <!--Тут секция туториала заканчивается--> 3. Дальше добавим секцию текста st_tutor_af_activation, к примеру, в ui_st_screen.xml: <string id="st_tutor_af_activation"> <text>Активировать артефакт ($$ACTION_USE$$)</text> </string> $$ACTION_USE$$ означает клавишу "Использовать". Это F по умолчанию 1. Начнем с диалогов. В каждом из двух мы запускаем по одной функции. Обе функции в dialogs_zaton.script. Первая: function give_super_psevdogig_task(first_speaker, second_speaker) dialogs.relocate_item_section_to_actor(first_speaker, second_speaker, "super_psevdogig_af_gravi") --Выдаем "Грави" task_manager.get_task_manager():give_task("zat_super_psevdogig_task") --Выдаем задание xr_effects.create_squad(nil, nil, {"zat_super_psevdogig_squad", "zat_sim_2"}) --Спавним сквад монстра на смарте "zat_sim_2" end Во второй будем выдавать награду: function give_super_psevdogig_task_reward(first_speaker, second_speaker) local items_pack = { {item = "energy_drink", amount = 2}, {item = "medkit_army", amount = 3}, {item = "antirad", amount = 2}, {item = "vodka", amount = 1}, {item = "conserva", amount = 3}, } for k,v in pairs(items_pack) do dialogs.relocate_item_section_to_actor(first_speaker, second_speaker, v.item, v.amount) end dialogs.relocate_money_to_actor(first_speaker, second_speaker, 3000) end Используем условно сложную таблицу items_pack. Каждый ее элемент состоит из двух пунктов:item - секция предметаamount - количество, которое нужно выдатьДалее некий цикл в виде стандартногоfor k,v in pairs(название_таблицы) doЭто означает, что функция ниже может выполниться для каждого элемента таблицы (v). У нас это: dialogs.relocate_item_section_to_actor(first_speaker, second_speaker, v.item, v.amount) Обратите внимание на v.item и v.amount.Ну, а в выдаче денег не вижу ничего сложного.2. Последнее, что нам нужно сделать, - это две функции: одна выдается при использовании туториала, а вторая - из логики. В xr_effects.script добавляем первую функцию: function zat_super_psevdogig_explode_1(actor, npc) db.actor:give_info_portion("zat_super_psevdogig_af_activation_begin") --Выдаем инфу remove_item(actor, npc, {"super_psevdogig_af_gravi"}) --Забираем у ГГ артефакт (он же активируется) end Опять же, ничего сложного. Два простых действия. Единственное, замечу, что remove_item - это тоже функция из xr_effects.script. Теперь добавляем вторую: function zat_super_psevdogig_explode_2(actor, npc) local fx_table_1 = { [1] = {particle = particles_object("anomaly2\\gravity_blast_final00")}, [2] = {particle = particles_object("anomaly2\\gravity_blast_03")}, [3] = {particle = particles_object("anomaly2\\gravity_blast_05")}, } local npc_position = npc:position() for i = 1,3 do fx_table_1[i].particle:play_at_pos(npc_position) end db.actor:give_info_portion("zat_super_psevdogig_af_activation") remove_squad(nil, nil, {"zat_super_psevdogig_squad"}) local fx_table_2 = { [1] = {particle = particles_object("anomaly2\\body_tear_00")}, [2] = {particle = particles_object("amk\\blow_body")}, [3] = {particle = particles_object("amk\\zomb_explode")}, } for i = 1,3 do fx_table_2[i].particle:play_at_pos(npc_position) end end У нас есть две таблицы. Каждая имеет три партикла (каждый партикл в функциях ниже объявляется так: таблица.particle). Зачем нужно было делить из на две таблицы? Просто лучше, чтоб партиклы грави-аномалии начали играться чуть раньше партиклов разрыва тела. Цикл здесь задан немного по-другому: for i = 1,3 do Гляньте на пронумерованные элементы таблиц, и все станет с этим циклом ясно.Также надо заметить, что, поскольку функция вызывается прямо из логики НПС, мы можем задать удобную локальную переменную для объявления позиции данного НПС в реальном времени: local npc_position = npc:position() Кто не понял, вот это npc, после которого двоеточие, - это и есть псевдогигант. Гляньте на аргументы функции:(actor, npc)Итак, мы используем локальную переменную для выполнения функции с циклом/таблицей: fx_table_1[i].particle:play_at_pos(npc_position) Задействована движковая функция play_at_pos, предназначенная конкретно для партиклов.Если у Вас нету партиклов АМК, то вторую таблицу изменяем: local fx_table_2 = { [1] = {particle = particles_object("anomaly2\\body_tear_00")}, [2] = {particle = particles_object("anomaly2\\body_tear_01")}, [3] = {particle = particles_object("anomaly2\\body_tear_02")}, } Вот и все, со всем разобрались. Смотрим результат. Результат Чуть позже я также дополню материал, чтоб при ликвидации псевдогиганта игрались некоторые звуки аномалий и его самого...Итого, ничего сверхсложного или особенного мы не сделали, но...Представьте, что мы можем использовать такую схему в связке с анимационной схваткой с химерой или сосычем. Основы есть, есть и то, к чему нужно стремиться. На самом деле, мы еще не успели перелопатить весь моддинг, не так ли? На этом урок закончен. Всем большое спасибо! Изменено 25 Июля 2014 пользователем Murarius 4 1 Ссылка на комментарий
Это популярное сообщение. Akella-96 aka SvD 35 Опубликовано 8 Августа 2014 Это популярное сообщение. Поделиться Опубликовано 8 Августа 2014 (изменено) В темные времена, когда у меня были перебои с интернетом, я сохранял Web - страницы на ПК, чтобы можно было просматривать их, когда интернет отключен. Так и появился данный пак статей о SDK 0.7, в основном о Level Editor и постройке локации. Может, кому пригодится - если тоже перебои с подключением к сети, да и просто не надо будет искать. https://yadi.sk/d/gQX8KGT6ZK6AU Изменено 19 Сентября 2014 пользователем World_Stalker 7 8 6 1 AWRP : Re - Load 0.2 © Ссылка на комментарий
Это популярное сообщение. FantomICW 678 Опубликовано 22 Декабря 2014 Это популярное сообщение. Поделиться Опубликовано 22 Декабря 2014 (изменено) Список шрифтов для UI Платформа: Сталкер Зов Припяти 1.6.02Автор: FantomICW ВведениеВсем привет. Пожалуй, есть вопросы по модостроению, которые мучили меня месяцами. Один из них - список доступных для использования игровых шрифтов. Некоторые ресурсы в гугле предлагают открыть файл configs/fonts.ltx, но я так и не понял, каким образом эта вещь читается движком: названия "фонтов" не совпадают с тем, что используются в интерфейсе. Итого, данный вопрос будет пока что раскрыт наполовину. Тем не менее, благодаря исходникам движка 1.6.02, мне удалось докопаться до того самого места, где "регистрируются" реально работающие шрифты!Предлагаю ознакомиться с этим небольшим справочником Справочная информация Собственно, "регистрация" шрифтов проходит в файле UIXmlInit.cpp. Строки 29-43 содержат определение переменных для большой части названий шрифтов (чуть ниже мы увидим, как эти переменные используются): #define ARIAL_FONT_NAME "arial" #define MEDIUM_FONT_NAME "medium" #define SMALL_FONT_NAME "small" #define GRAFFITI19_FONT_NAME "graffiti19" #define GRAFFITI22_FONT_NAME "graffiti22" #define GRAFFITI32_FONT_NAME "graffiti32" #define GRAFFITI50_FONT_NAME "graffiti50" #define LETTERICA16_FONT_NAME "letterica16" #define LETTERICA18_FONT_NAME "letterica18" #define LETTERICA25_FONT_NAME "letterica25" #define DI_FONT_NAME "di" Структура: #define ПЕРЕМЕННАЯ "название" Сама "регистрация" проходит в этом же файле, в функции InitFont: bool CUIXmlInit::InitFont(CUIXml &xml_doc, LPCSTR path, int index, u32 &color, CGameFont *&pFnt) { color = GetColor (xml_doc, path, index, 0xff); LPCSTR font_name = xml_doc.ReadAttrib(path, index, "font", NULL); if(!font_name) { pFnt = NULL; return false; }else { if(!xr_strcmp(font_name, GRAFFITI19_FONT_NAME)) { pFnt = UI().Font().pFontGraffiti19Russian; } else if(!xr_strcmp(font_name, GRAFFITI22_FONT_NAME)) { pFnt = UI().Font().pFontGraffiti22Russian; } else if(!xr_strcmp(font_name, GRAFFITI32_FONT_NAME)) { pFnt = UI().Font().pFontGraffiti32Russian; } else if(!xr_strcmp(font_name, GRAFFITI50_FONT_NAME)) { pFnt = UI().Font().pFontGraffiti50Russian; } else if(!xr_strcmp(font_name, "arial_14")) { pFnt = UI().Font().pFontArial14; } else if(!xr_strcmp(font_name, MEDIUM_FONT_NAME)) { pFnt = UI().Font().pFontMedium; } else if(!xr_strcmp(font_name, SMALL_FONT_NAME)) { pFnt = UI().Font().pFontStat; } else if(!xr_strcmp(font_name, LETTERICA16_FONT_NAME)) { pFnt = UI().Font().pFontLetterica16Russian; } else if(!xr_strcmp(font_name, LETTERICA18_FONT_NAME)) { pFnt = UI().Font().pFontLetterica18Russian; } else if(!xr_strcmp(font_name, LETTERICA25_FONT_NAME)) { pFnt = UI().Font().pFontLetterica25; } else if(!xr_strcmp(font_name, DI_FONT_NAME)) { pFnt = UI().Font().pFontDI; }else { R_ASSERT3(0,"unknown font",font_name); pFnt = NULL; } } return true; } Что можно вынести интересного:- знакомые переменные- arial_14 не использует переменную, как другие шрифты- есть функция R_ASSERT: R_ASSERT3(0,"unknown font",font_name); pFnt = NULL; "arial_17" "medium" "small" "graffiti19" "graffiti22" "graffiti32" "graffiti50" "letterica16" "letterica18" "letterica25" Надеюсь, информация пригодится! Спасибо за внимание и удачи! Изменено 22 Декабря 2014 пользователем FantomICW 1 4 1 3 Ссылка на комментарий
Это популярное сообщение. ツМаLinK@ツ 35 Опубликовано 27 Декабря 2014 Это популярное сообщение. Поделиться Опубликовано 27 Декабря 2014 Всем привет, в этой статье я расскажу, как сделать рюкзак - тайник типа АМКшного. Начнем мы с создания необходимых секций в конфигах. Открываем config\creatures\spawn_sections.ltx и добавляем секцию: [taynik_sect]:taynik visual = equipments\item_rukzak radius = 1Это тот тайник, который и будет спавниться при юзании предмета.Далее config\misc\devices.ltx. В него пишем: [taynik] GroupControlSection = spawn_group discovery_dependency = $spawn = "devices\inventory box" class = O_INVBOX cform = skeleton visual = physics\box\expl_dinamit.ogf script_binding = bind_physic_object.initСекцию лучше не трогать, она содержит в себе необходимые для тайника функции. Именно на нее мы ссылались в секции спавна.В этом-же файле добавляем секцию предмета, который будем юзать: [rukzak_taynik]:identity_immunities GroupControlSection = spawn_group discovery_dependency = $spawn = "food and drugs\kolbasa" $prefetch = 8 class = II_FOOD cform = skeleton visual = equipments\item_rukzak.ogf description = taynik_desc inv_name = taynik_name inv_name_short = taynik_name inv_weight = 0.5 inv_grid_width = 2 inv_grid_height = 3 inv_grid_x = 12 inv_grid_y = 32 cost = 1000 attach_angle_offset = 0.440521, 1.378287, -0.644026 ; eatable item eat_health = 0 eat_satiety = 0 eat_power = 0 eat_radiation = 0 wounds_heal_perc = 0 eat_portions_num = -1 attach_position_offset = 0.104196, -0.010821, 0.076969 attach_bone_name = bip01_r_hand auto_attach = false // should be deleted after update bone_name = bip01_r_hand position_offset = 0.0,0.0,0.0 angle_offset = 1.570790,1.570790,3.92699 ; food item slot = 4 animation_slot = 4 ;hud item hud = wpn_vodka_hudТут мы создали предмет. Небольшая оговорочка: иконку к моду я прописала NLCшную, при желании можно сделать самому, это описано в куче статей.С конфигами закончили, теперь самое важное - скрипты! Создаем свой скрипт, например kristi.script и в него пишем: function spawn_item(obj) local pos = db.actor:position() local dir = db.actor:direction() local gver = db.actor:game_vertex_id() local lver = db.actor:level_vertex_id() alife():create(obj, pos:add(dir:mul(1)), lver, gver) end kristi.spawn_item("taynik_sect") - это функция спавна нашего тайника под ногами актора.Идем в bind_stalker.script и ищем функцию function actor_binder:reinit().В ее конце, после строки self.object:set_callback(callback.take_item_from_box, self.take_item_from_box, self) ставим свой коллбэк на юзание итема: self.object:set_callback(callback.use_object, self.taynik_spawn, self)В этом-же файле например после функции function actor_binder:load(reader) (после task_manager.load(reader)self.actor_detector:load(reader) end) пишем: function actor_binder:taynik_spawn(obj, who) if obj then if obj:section() == "rukzak_taynik" then kristi.spawn_item("taynik_sect") end end endГотово! Если мы все сделали правильно, то при использовании предмета rukzak_taynik у нас под ногами заспавнится пустой тайничок в который можно сложить хабар.Да и не забудьте добавить предмету описание! С уважением ツМаLinK@ツ. Всё отлично работает, но... Но, к сожалению, если тайник нам больше не нужен, мы не можем забрать рюкзак обратно. Исправим это. Открываем файл bind_stalker.scriptи в нём находим функцию actor_binder:take_item_from_box(box, item). В ней в самом конце добавляем такой код: -- если это наш тайник, и он пустой, т.е. мы забрали из него последни предмет, то... if box:section() == "taynik_sect" and box:is_inv_box_empty() then level.start_stop_menu(level.main_input_receiver(), true) -- закрываем окно "обыскивания тайника" alife():release(alife():object(box:id()), true) -- удаляем тайник alife():create("rukzak_taynik",db.actor:position(),db.actor:level_vertex_id(),db.actor:game_vertex_id(),db.actor:id()) -- спавним рюкзак в инвентарь endВот и всё. Теперь, когда забираем все вещи из своего тайника, рюкзак возвращается к гг в инвентарь, а тайник исчезает. Сумела восстановить одну схему вертолетов, а именно, при стрельбе в вертолет, он начнет ответную атаку! Открываем файлbind_heli.script Ищем там вот такую строку: -- если обидчик актёр или сталкер, то сделать его своим врагом if enemy_cls_id == clsid.actor or enemy_cls_id == clsid.script_stalker then -- if not self.st.combat.enemy_id then -- self.st.combat.enemy_id = enemy_id -- endУдаляем коментарии...Все,теперь сохраняйте,запускайте игру,возьмите задание волка,бегите к вагончику,стреляйте в вертолет и бегите!!! Добавлено Murarius, 27 Декабря 2014 Рекомендуется к изучению: Правила форума, п. 2.9 Спасибо. 3 9 1 1 1 Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти