ColR_iT 171 Опубликовано 17 Марта 2012 (изменено) Переключаем музыку в работающем радио. Как именно, спавнить радио описано в этой же теме несколькими постами выше. Единственное, чтобы я посоветовал, это в принципе для схемы ph_sound использовать объекты с именем секции неphysic_object, а physic_destroyable_object, по одной простои причине - схема on_hit не работает с physic_object. Итак. Самым важным в этом небольшом туторе, как Вы уже сами могли догадаться, будет логика для нашего радио. Логику из секции спавна, лично я, вынес в отдельный файл, а именно logic_switch_radio.ltx. Выглядит она следующим образом: [logic] active = ph_sound@music_1 [ph_sound@music_1] tips = radio_switch snd = radio_music looped = true max_idle = 1000 on_use = ph_sound@music_2 [ph_sound@music_2] tips = radio_switch snd = radio looped = true max_idle = 1000 on_use = ph_sound@music_1 Логика здесь довольно проста. "Изюминка" в том, что мелодии можно переключать, т.е. подойдя к радио и нажав кнопку действия (по умолчанию F), логика перейдёт на следующую схему, тем самым меняя композицию.В том виде в котором данная логика приведена, она естественно работать не будет, поскольку, для схемы ph_sound не предусмотрен колбек на использование (юзание) предмета. Но дело это поправимо... Для этого мы просто напросто добавим его в нашу схему. Изобретать велосипед мы не будем, поэтому колбек мы скопируем из схемы ph_idle (ph_idle.script), там он есть, и впишем в схему ph_sound(ph_sound.script).Открываем файл ph_idle.script и ищем следующую функцию: function action_idle:use_callback(obj, actor) if self.st.on_use then if xr_logic.switch_to_section(self.object, self.st, xr_logic.pick_section_from_condlist(db.actor, self.object, self.st.on_use.condlist)) then return true end end end Это и есть непосредственно сам колбек. Также нас интересует строка в функции set_scheme, а именно (в дополнение к этому, рекомендую также скопировать ещё две строчки, которые обеспечат нас текстовой подсказкой при наведении на радио): st.on_use = xr_logic.cfg_get_condlist(ini, section, "on_use", npc) st.tips = utils.cfg_get_string(ini, section, "tips", npc, false, "", "") npc:set_tip_text(st.tips) Теперь вставляем всё это в аналогичные места в файле ph_sound.script, т.е.: Перед функцией snd_source:update(delta), вставляем колбек, предварительно изменив класс, т.е. буквы action_idle заменяем на snd_source, должно получится так: function snd_source:use_callback(obj, actor) if self.st.on_use then if xr_logic.switch_to_section(self.object, self.st, xr_logic.pick_section_from_condlist(db.actor, self.object, self.st.on_use.condlist)) then return true end end end Затем в функцию set_scheme, в самый её конец, вписываем скопированные строки из аналогичной функции "соседнего" файла. В итоге мы имеем для схемы ph_sound два дополнительных параметра:on_use - колбек на юзание;tips - подсказка при наведении. Кстати, текст для подсказки, можно вписать в файл config\text\rus\string_table_ui.xml по аналогии с имеющимися, в рассматриваемом примере он выгляди так: HTML <string id="radio_switch"><text>Переключить песню ($$ACTION_USE$$)</text></string> Собственно, всё. Кодовый тайник. Как многим известно в ТЧ есть возможность открывать двери при помощи нужного кода, вводя его на клавиатурной панели. Собственно эта самая панель и является ключевым элементом, самый интересный из которых набор кода. Отвечает за это действо схема ph_code (ph_code.script). При вводе пароля выдаётся инфопоршень, а в логике двери есть условие на наличие данного инфопоршня, при котором дверь откроется.Для тайников используется схема ph_idle, а для схемы ph_code как такового, перехода на другую схему нет.Т.е. вся загвоздка состоит в возможности перехода со схемы ph_code на другую.Ну что же давайте добавим эту возможность...Переход будем осуществлять непосредственно в параметре on_code, т.е. при вводе правильного пароля будет происходить переход на другую схему, при которой появится возможность использовать тайник по назначению.За работу параметра on_code отвечает метод OnNumberReceive, а именно вот эта проверка: if self.st.on_code then printf("ph_code <OnNumberReceive>: on_code [%s]", text) xr_logic.pick_section_from_condlist(db.actor, self.object, self.st.on_code.condlist) end Чтобы для данного параметра была возможность перехода на другую схему, эту проверку нужно заменить вот этой: if self.st.on_code ~= nil then printf("ph_code <OnNumberReceive>: on_code [%s]", text) --<# Возможность перехода на другую схему при правильном вводе пароля (on_code). local section = xr_logic.pick_section_from_condlist(db.actor, self.object, self.st.on_code.condlist) xr_logic.switch_to_section(self.object, self.st,section) return true --#> end Вот таким не хитрым способом добавляется возможность использовать схему ph_code для более широкого спектра действий.Теперь приступим непосредственно к тайнику. Для примера я взял синий ящик, который стоит у забора в Деревне новичков.Слегка изменил его секцию спавна: [2297] ; cse_abstract properties section_name = inventory_box name = level_prefix_inventory_box position = -212.106658935547,-20.0091133117676,-141.916839599609 direction = -0.0120084341615438,1.90779304504395,-0.0344137884676456 ; cse_alife_object properties game_vertex_id = 0 distance = 0 level_vertex_id = 594270 object_flags = 0xffffff3b custom_data = <<END [spawn] wpn_pm ammo_9x18_fmj [logic] cfg = scripts\coded_treasure.ltx END story_id = 2000 ; cse_visual properties visual_name = physics\equipment_cache\equipment_box_01_case Изменения коснулись лишь добавлением для него custom_data. (Секция spawn была добавлена для демонстрации). Логика выглядит следующим образом: [logic] active = ph_code@close [ph_code@close] code = 123 on_code = ph_idle@enable [ph_idle@enable] nonscript_usable = true tips = st_search_treasure Собственно всё. При вводе пароля "123" мы получим открытый тайник.Вот небольшое видео для демонстрации: Изменено 24 Сентября 2014 пользователем BFG 2 3 3 Поделиться этим сообщением Ссылка на сообщение
ColR_iT 171 Опубликовано 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 (изменено) "Динамическое подключение/отключение функций" Думаю многим известно, что такое файл 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 Поделиться этим сообщением Ссылка на сообщение