Николай1 1 Опубликовано 11 Апреля 2015 Поделиться Опубликовано 11 Апреля 2015 Здравствуйте! Сегодня решил попробовать свои силы в создании модов для Сталкера, так как это моя любимая игра. Когда-то раньше пробовал, но почему-то забросил...Я в основном занимаюсь Web-программированием, а сегодня попробовал скрипты, минут за 20 сделал такую штуку, как механизм событий и их обработчиков, это что-то вроде биндинга, но по-другому работает.Принцип сейчас покажу в коде: function handler() -- Тут всякий код end function handler2() -- Тут всякий код end setHander("test_action", handler) setHander("test_action", handler2) setAction("test_acton") -- Будет выполнен код из функций handler() и hander2() Такая штука будет очень полезна, когда нужно обработать какое-то событие в моде и вся эта система должна содержаться в порядке.Вызывать события можно вообще любые:setAction("bla-bla-bla"). Если нет обработчиков, то ничего не произойдёт, но ошибок не будетРегистрировать обработчики можно в любом месте любого скрипта, будет работать.Например при заходе на локацию вызывать событие on_location_zaton, тогда можно будет событие обрабатывать.В общем система очень простая и полезная, можно много применений найти. Её можно использовать в любой версии Сталкера, так как она использует только возможности языка LuaТакже в приведённом коде есть ещё некоторые функции, они может и не самые полезные, но их тоже можно использовать.Я хочу заделать что-то вроде прослойки между теми скриптовыми функциями, что сейчас есть и модами, чтобы облегчить использование некоторых возможностей. Мог объяснить не очень понятно, просто спать уже хочу... Критикуйте) буду только рад Как вам моя идея? Есть ли у неё перспективы?Если есть предложения, чего бы ещё сделать, предлагайте) --[[ MOD TOOLS 0.0.1 Инструменты для облегчения модификаций Разработчик: Николай1 ]] -- Массив с обработчиками hooks = {} --[[ Вызов события. Вызов происходит корректно и не вызывает ошибок, даже если не было зарегистрировано обработчиков для этого события. В таком случае функция возвращает false action_name [String] - название события Пример: setAction("test_action") ]] function setAction(action_name) if hooks[action_name] == nil then return false end for action,hook in pairs(hooks[action_name]) do hook() end end --[[ Добавление обработчика к событию. Можно добавлять много обработчиков для одного события action_name [String] - название события handler [Callback] - функция-обаботчик Пример: function handler() -- Тут всякий код end function handler2() -- Тут всякий код end setHander("test_action", handler) setHander("test_action", handler2) ]] function setHandler(action_name, handler) if hooks[action_name] == nil then hooks[action_name] = {} end table.insert(hooks[action_name], handler) end --[[ Эта функция лишняя, её использовал для теста механизма событий ]] function route() setAction("test") end -- Создать предмет под ногами игрока -- [String] item - код предмета, например medkit -- [Int] count - количиство предметов function spawnNearActor(item, count) if count == nil then alife():create(item, db.actor:position(), db.actor:level_vertex_id(), db.actor:game_vertex_id()) else for i = 1, count do alife():create(item, db.actor:position(), db.actor:level_vertex_id(), db.actor:game_vertex_id()) end end end -- Создать предмет в инвентаре игрока -- [String] item - код предмета, например medkit function addToActorInventory(item, count) addToInventory(item, db.actor:id(), db.actor:position(), db.actor:game_vertex_id(), count); end -- Создать предмет в инвентаре -- [String] item - код предмета, например medkit -- [Int] character_id - ID персонажа, которому нужно создать предмет -- [Vector] position - координаты добавления объекта -- [Int] game_vertex_id - game_vertex_id для создания предмета -- [Int] count - количиство предметов function addToInventory(item, character_id, position, game_vertex_id, count) if count == nil or count == 1 then alife():create(item, position, 1, game_vertex_id, character_id) else for i = 1, count do alife():create(item, position, 1, game_vertex_id, character_id) end end end -- Сохранить значение переменной -- [String] variable_name - название переменной -- [Mixed] value - значение переменной function setVar(variable_name, value) xr_logic.pstor_store(db.actor, variable_name, value) end -- Получить значение переменной -- [String] variable_name - название переменной -- [Mixed] default_value - значение по-умолчанию, значение переменной, которое будет возвращено, -- если переменной не существует function getVar(variable_name, default_value) return xr_logic.pstor_retrieve(db.actor, variable_name, default_value) end --[[ Действия с переменной с помощью одной функции variable_name [String] - название переменной value [Mixed] - значение переменной (или значение по-умолчанию) is_set [Bool] - флаг создания переменной. Если стоит 1 - будет использовано действие "Сохранить значение переменной" Примеры использования: Получение значения переменной: var("test_var", false) -- Второй аргумент - значение по-умолчанию var("test_var", false, false) -- Третив аргумент - отключение флага установки переменной Установка значения переменной var("test_var", "test_value", true) ]] function var(variable_name, value, is_set) -- Если is_set не задан, ставим false if (is_set == nil) then is_set = false end if (is_set == false) then -- Если is_set равен 0 или false, то получаем значение переменной return _getVar(variable_name, value) else -- Если стоит флаг создания, то устанавливаем значение переменной return _setVar(variable_name, value) end end --[[ Выполнить какую-либо функцию заданное число раз ]] --[[ function runFunction(func, count, ...) if count == nil or count = 1 then func(arg) else for i = 1, count do func(arg) end end end ]] Добавлено Dennis_Chikin, 12 Апреля 2015 Пока будет здесь,ибо не очень понятны перспективы отдельной темы. 1 Ссылка на комментарий
Desertir 202 Опубликовано 13 Апреля 2015 Поделиться Опубликовано 13 Апреля 2015 Как вам моя идея? Есть ли у неё перспективы?Такое уже есть, как минимум в двух экземплярах - это я еще не особо осведомлённый в делах скриптового моддинга. Но на еще один велосипед посмотреть можно, сарказма тут нет, ибо так оно и есть. 1. Убило название функции для срабатывания события - setAction. Установить действие? Иногда называют такие методы fire или fireEvent, но не setAction. 2. Нет передачи аргументов в хендлеры. 3. Нет прерывания срабатывания событий (в цикле). 4. Симпатичное комментирование кода, конкретно описание аргументов + тип. ТЧ 1.0004. SAP и Trans mod github Ссылка на комментарий
Kirgudu 1 207 Опубликовано 13 Апреля 2015 Поделиться Опубликовано 13 Апреля 2015 (изменено) @Николай1, начинание благое, жаль только припозднилось года этак на 2-3.Но если удастся предложить что-то действительно новое и полезное - всем будет только хорошо. Для начала рекомендую изучить аналогичные решения, уже предложенные другими авторами, коих даже больше, чем указал @Desertir. Можно сделать общий поиск по форуму слова «event». Или поискать отдельные варианты: "Песочница" от @xStream, слот-сигнальная система от @Malandrinus, были ещё частные реализации от @Artos и, кажется, @Monnoroch и @Viнt@rь. Изменено 13 Апреля 2015 пользователем Kirgudu Инструмент Ссылка на комментарий
AndrewMor 527 Опубликовано 15 Апреля 2015 Поделиться Опубликовано 15 Апреля 2015 Кто объяснит, как в цикле for отловить последнюю итерацию? function take_money(pid) local cond = 5000local col = 0local count = db.actor:object_count() - 1if has_alife_info("ui_car_body") thenfor i=0, count dolocal item = db.actor:object(i)if item:section() == "pack_money" thenlocal sobj = alife():object(item:id())if sobj thencol = col + 1db.actor:give_money(cond)alife():release(sobj,true)endendendendend Нужно вывести итоговое значение переменной col. Пробовал проверку сделать if i=count then . . . end так вылетает. Сталкер - наше всё! Ссылка на комментарий
Kirgudu 1 207 Опубликовано 15 Апреля 2015 Поделиться Опубликовано 15 Апреля 2015 @AndrewMor, как минимум "if i==count then", чтобы не вылетало. А во-вторых, после окончания действия цикла (перед закрывающим функцию "end") в переменной col как раз и будет нужное значение, можно делать с ним что угодно. 1 Инструмент Ссылка на комментарий
AndrewMor 527 Опубликовано 15 Апреля 2015 Поделиться Опубликовано 15 Апреля 2015 как минимум "if i==count then", чтобы не вылетало. Блин, ну конечно. Привычка, что "=" - это сравнение. Спасибо. Kirgudu, переписал функцию так: function take_money(pid)local cond = 5000local col = 0local count = db.actor:object_count() - 1if has_alife_info("ui_car_body") thenfor i=0, count dolocal item = db.actor:object(i)if item:section() == "pack_money" thenlocal sobj = alife():object(item:id())if sobj thencol = col + 1alife():release(sobj,true)endendif i == count and col ~= 0 thencond = cond * coldb.actor:give_money(cond)local text = "Найдено денег - "..condnews_manager.send_tip(db.actor, cond, nil, nil, 30000)endendendend но сообщение выводится не один раз, как задумывал, а столько раз, сколько нужного предмета попало в рюкзак. А если перед закрывающим функцию end вывод вписать, то вообще ничего не выводится. Почему? Сталкер - наше всё! Ссылка на комментарий
Kirgudu 1 207 Опубликовано 15 Апреля 2015 Поделиться Опубликовано 15 Апреля 2015 Потому что переменая i существует только внутри цикла, а вне его равна nil. Оставь только проверку на col ~= 0. Инструмент Ссылка на комментарий
AndrewMor 527 Опубликовано 15 Апреля 2015 Поделиться Опубликовано 15 Апреля 2015 @Kirgudu, А всё равно выводится не одно сообщение, а несколько. Я так понимаю, что биндер отслеживает получение первого предмета и идет подсчет в цикле. Выводится сообщение. Далее отслеживается получение предмета номер 2, опять цикл и вывод сообщения. Ну и так далее. А как бы мне сделать, чтобы выводилось только одно, итоговое сообщение? Сталкер - наше всё! Ссылка на комментарий
Kirgudu 1 207 Опубликовано 15 Апреля 2015 Поделиться Опубликовано 15 Апреля 2015 @AndrewMor, ты б объяснил толком, что хочешь сделать. Инструмент Ссылка на комментарий
AndrewMor 527 Опубликовано 15 Апреля 2015 Поделиться Опубликовано 15 Апреля 2015 @Kirgudu, при взятии денег из схрона прибавлять их к общим деньгам ГГ, взятые деньги из рюкзака долой, а потом выводить сообщение о полученной сумме целиком. Эта моя функция вызывается из биндера on_take_item. Сталкер - наше всё! Ссылка на комментарий
Карлан 1 049 Опубликовано 15 Апреля 2015 Поделиться Опубликовано 15 Апреля 2015 @AndrewMor, как-то так лучше сделать: function take_money(obj) if obj:section() == 'money_500' then alife():release(alife:object(obj.fov and obj:id() or obj.id)) db.actor:give_money(500) news_manager.send_tip(db.actor, "Получено 500 рублей.", nil, nil, 10000) end end При желании рандомизировать, циклы тут точно не нужны, лишняя нагрузка. 1 1 Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 15 Апреля 2015 Поделиться Опубликовано 15 Апреля 2015 "при взятии денег из схрона прибавлять их к общим деньгам ГГ" Если деньги - это предмет, то вешаем вызов на on_take_item_from_box(). Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Карлан 1 049 Опубликовано 15 Апреля 2015 Поделиться Опубликовано 15 Апреля 2015 @Dennis_Chikin, лучше на обретение. Какая разница откуда ты их получил если алгоритм для всего один и тот же? Будь-то труп, тайник или любой другой способ. 1 Ссылка на комментарий
J.A.A. 2 Опубликовано 16 Апреля 2015 Поделиться Опубликовано 16 Апреля 2015 Ребята, помощь нужна. Мне нужно заспавнить physic_destroyable_object. Через all.spawn всё красиво, но есть одно "НО" - не работает функция [spawner]. Может быть через скрипт как-то можно его спавнить, а то я что-то не догоняю... PS Всем мир! Пишу мод с неповторимым сюжетом. Нужны "модельеры" Заинтересованным писать в ЛС Ссылка на комментарий
AndrewMor 527 Опубликовано 16 Апреля 2015 Поделиться Опубликовано 16 Апреля 2015 Мне нужно заспавнить physic_destroyable_object. Через all.spawn всё красиво, но есть одно "НО" - не работает функция [spawner]. Насколько я помню, секция spawner работает только для НПС и монстров. Сталкер - наше всё! Ссылка на комментарий
AndrewMor 527 Опубликовано 18 Апреля 2015 Поделиться Опубликовано 18 Апреля 2015 Всем привет, опять я со своей проблемой по деньгам. В bind.stalker.script в биндере take_item_from_box пишу: money.take_money(item) Мой скрипт: function take_money(pid) db.actor:iterate_inventory(is_item, db.actor)endfunction is_item(npc, item)local cond = math.ceil(math.random(28,70)*100)local section = item:section()if item:section() == "pack_money" thenlocal sobj = alife():object(item:id())if sobj thenalife():release(sobj,true)db.actor:give_money(cond)local text = "Найдено денег - "..cond.."\\nВсего денег - "..db.actor:money()news_manager.send_tip(db.actor, text, nil, nil, 30000)endendend Или так: function take_money(pid)local cond = math.ceil(math.random(28,70)*100)local count = db.actor:object_count() - 1for i=0, count dolocal item = db.actor:object(i)if item:section() == "pack_money" thenlocal sobj = alife():object(item:id())if sobj thendb.actor:give_money(cond)local text = "Найдено денег - "..cond.."\\nВсего денег - "..db.actor:money()news_manager.send_tip(db.actor, text, nil, nil, 30000)alife():release(sobj,true)endendendend Результат один и тот же: первый предмет, берущийся из ящика, не обрабатывается. Остается в рюкзаке. Соответственно, если в ящике 8 предметов, то обрабатываются только 7, один остается в инвентаре. Почему? Сталкер - наше всё! Ссылка на комментарий
Карлан 1 049 Опубликовано 18 Апреля 2015 Поделиться Опубликовано 18 Апреля 2015 @AndrewMor, зачем ты спрашиваешь? Я тебе сказал как нужно сделать, но ты упорно продолжаешь делать по своему. Ты понимаешь как работает коллбек? В общем, как говорится, "если не можешь - значит не нужно"(с). 1 Ссылка на комментарий
AndrewMor 527 Опубликовано 18 Апреля 2015 Поделиться Опубликовано 18 Апреля 2015 @Карлан, Я делал, как ты посоветовал, и все равно не работает. PS: ты бы лучше объяснил, что где не так. В общем, спасибо за "помощь". Карлан, по твоему совету при обыске трупа вылет: Expression : fatal errorFunction : CScriptEngine::lua_errorFile : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cppLine : 73Description : Arguments : LUA error: ...blishing\s.t.a.l.k.e.r\gamedata\scripts\money.script:39: attempt to index global 'alife' (a function value) Сталкер - наше всё! Ссылка на комментарий
Карлан 1 049 Опубликовано 18 Апреля 2015 Поделиться Опубликовано 18 Апреля 2015 @AndrewMor, скобки добавить не додумался? Я же не точный код дал, а набросок. 1 Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 18 Апреля 2015 Поделиться Опубликовано 18 Апреля 2015 function take_money(pid) db.actor:iterate_inventory(is_item, db.actor) end Жуть какая... Собственно, то, что получаем - это и есть искомый предмет. Все. Получаем id, получаем объект, удаляем. Больше ничего не надо. Ни каких итераций. Единственный момент - после того, как удалили, ни каких действий в :on_что-попало() быть не должно. Собственно, я в статье про использование именно по-этому и сделал выбор нужной функции по таблице. Ну и продолжение трэда можно в курилке посмотреть. Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти