Войти на сайт Регистрация Лента форума Пользователи Правила сайта Поиск по форуму
Модератор форума: denis2000, FantomICW  
Модостроение. Редактирование и создание скриптов
denis2000Дата: Пн, 10.10.2011, 21:17 | Сообщение # 1
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Редактирование и создание скриптов

Редактирование и создание скриптов на языке LUA

Если у вас появились вопросы по применению скриптов в игре. Задавайте их в этой теме - умные головы,
модосторители и просто разбирающиеся в программировании люди вам ответят.


Много интересного материала здесь (wiki), Lua_help.script, Help из SDK 0.7

Сборник модостроения ЗП v10.10.11 (автор: XOBAH): *.CHM, *.HTML
[cut noguest=Если у вас не открывается файл CHM]Если у вас не открывается файл:
1. Запустите [Пуск]=>[Выполнить] (либо хот-кей [WIN]+[R])
2. Введите команду (без кавычек) "regsvr32 %windir%\system32\hhctrl.ocx"
3. Если вылезло окно об успешном завершении вы все сделали правильно и можете перезагружать компьютер (а может и не надо)
Также: файлы МОГУТ не открываться если в пути к файлу есть: символы кириллицы, "_", "#"
Также: есть не стандартные программы-просмоторщики CHM файлов. Например: FBReader[/cut]

[cut=Где найти лог игры после вылета]Что такое LOG ошибки, и как мне его найти?
Это система отладки происходивших вылетов, которая подается игрой в форме текста, хотя не всегда.
Для того чтоб найти LOG необходимо зайти вот сюда:

В Win хр лог находится:

C:\Documents and Settings\All Users\Документы\S.T.A.L.K.E.R. - Зов Припяти\logs

Затем открываете первый файл в формате TXT, и в нем отбираете с низу 25 строчек. После кидаете эти 25 строчек в сообщение на форум.

В Win7 лог находится C:\Users\Public\Documents\S.T.A.L.K.E.R. - Зов Припяти\logs

Путь к папке с логом можно найти открыв файл fsgame.ltx который находится в корневой директории ЗП, за это отвечает строка:
...
$app_data_root$ = true | false| $fs_root$| users\
(тут мы указываем что папка пользователя, будет хранится рядом с Fsgame.ltx)
...
$logs$ = true| false| $app_data_root$| logs\
(а тут мы указываем что в папке пользователя, в подпапке Logs будут храниться наши логи)
...
[/cut][cut=Получение более подробной информации о вылете (ХОВАН)]
Открываем файл _g.script и ищем такую функцию: function abort(fmt, ...)
Там есть заккомментированная строчка "--error_log(reason)", ее и надо расскомментировать, должно получиться вот так:
Code
function abort(fmt, ...)
                             local reason = string.format(fmt, ...)
                             error_log(reason)
end

Вот для примера два одинаковых вылета, первый с функцией по умолчанию, второй - с поправленной функцией

Первый:
Code
Expression    : !m_error_code
Function      : raii_guard::~raii_guard
File          : D:\prog_repository\sources\trunk\xrServerEntities\script_storage.cpp
Line          : 748
Description   : ....a.l.k.e.r. - Зов Припяти\gamedata\scripts\_g.script:478: bad argument #2 to 'format' (string expected, got nil)

Второй:
Code
Expression    : 0
Function      : ErrorLog
File          : D:\prog_repository\sources\trunk\xrServerEntities\script_engine_script.cpp
Line          : 49
Description   : 'Attempt to read a non-existant string field 'path_walk' in section 'walker@mechanic'

[/cut]


Перед тем, как задать вопрос в этой теме, прочтите все предыдущие страницы,
статьи в wiki по ссылке из шапки и соседнюю тему "Курс молодого бойца",
возможно Ваш вопрос уже рассматривался.


Если произошел вылет - выкладываем лог! Вопрос ставим четко, не забываем указывать версию игры, установленные моды их версии, установленные фиксы модов и подробно ваши правки.
Помните чем подробнее вопрос, тем точнее ответ.


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
denis2000Дата: Чт, 09.06.2016, 08:21 | Сообщение # 796
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Цитата sergej5500 ()
Как отследить, сколько игрок проспал в постели?

В функции sleep_callback() параметр rnd = math.random(6,12)
В скрипте ui_sleep_dialog.script в функции dream_callback() параметр hours = sleep_control.time_track:GetIValue()
Цитата sergej5500 ()
вызвать пошатывание игрока и расплывание предметов перед глазами...Какие скрипты подойдут?

level.add_complex_effector(Имя_эффекта, ИД_эффекта) конечно.
Или по отдельности level.add_pp_effector и level.add_cam_effector


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
sergej5500Дата: Чт, 09.06.2016, 09:33 | Сообщение # 797
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

denis2000,

За помощь спасибо.

Цитата denis2000 ()
В функции sleep_callback() параметр rnd = math.random(6,12)


Функция sleep_callback() обеспечивает принудительное засыпание игрока после суток активности. Я спрашивал про сон в постели. Спальное место на Скадовске или Янове.
 
denis2000Дата: Чт, 09.06.2016, 10:02 | Сообщение # 798
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Цитата sergej5500 ()
Я спрашивал про сон в постели. Спальное место на Скадовске или Янове.

Я таки написал оба варианта.


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
sergej5500Дата: Пт, 10.06.2016, 00:23 | Сообщение # 799
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

denis2000,

Попробовал применить параметр hours.

Мои правки.

[cut=bind_stalker]
function actor_binder:check_sleep_control()
if self.check_sleep_control_time == nil then
self.check_sleep_control_time = game.get_game_time()
end
if game.get_game_time():diffSec(self.check_sleep_control_time) > 86400 then
xr_effects.disable_ui(db.actor, nil)
level.add_cam_effector("camera_effects\\sleep.anm", 10, false, "bind_stalker.dream_callback")
level.add_pp_effector("sleep_fade.ppe", 11, false)
db.actor:give_info_portion("actor_is_sleeping")
_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")
surge_manager.resurrect_skip_message()
self.check_sleep_control_time = game.get_game_time()
end
end

function dream_callback()
level.add_cam_effector("camera_effects\\sleep.anm", 10, false, "bind_stalker.dream_callback2")
local hours = math.random(6,9)
level.change_game_time(0,hours/3600,0)
level_weathers.get_weather_manager():forced_weather_change()
surge_manager.get_surge_manager().time_forwarded = true
if(surge_manager.is_started() and level_weathers.get_weather_manager().weather_fx) then
level.stop_weather_fx()
-- level_weathers.get_weather_manager():select_weather(true)
level_weathers.get_weather_manager():forced_weather_change()
end
db.actor.power = 1
printf("dream_callback: time forwarded on [%d]", hours)
end

function dream_callback2()
xr_effects.enable_ui(db.actor, nil)
get_console():execute("snd_volume_music "..tostring(_G.mus_vol))
get_console():execute("snd_volume_eff "..tostring(_G.amb_vol))
_G.amb_vol = 0
_G.mus_vol = 0
end[/cut]

Этот код работает. Игрок засыпает принудительно.

[cut=ui_sleep_dialog]
function dream_callback()
level.add_cam_effector("camera_effects\\sleep.anm", 10, false, "ui_sleep_dialog.dream_callback2")
local hours = sleep_control.time_track:GetIValue()
level.change_game_time(0,hours,0)
level_weathers.get_weather_manager():forced_weather_change()
surge_manager.get_surge_manager().time_forwarded = true
if(surge_manager.is_started() and level_weathers.get_weather_manager().weather_fx) then
level.stop_weather_fx()
-- level_weathers.get_weather_manager():select_weather(true)
level_weathers.get_weather_manager():forced_weather_change()
end
db.actor.power = 1
printf("dream_callback: time forwarded on [%d]", hours)
if hours >= 7 then
game.get_game_time():diffSec(self.check_sleep_control_time)==60
else
game.get_game_time():diffSec(self.check_sleep_control_time) == game.get_game_time():diffSec(self.check_sleep_control_time) - hours*3600
end
end

function dream_callback2()
xr_effects.enable_ui(db.actor, nil)
get_console():execute("snd_volume_music "..tostring(_G.mus_vol))
get_console():execute("snd_volume_eff "..tostring(_G.amb_vol))
_G.amb_vol = 0
_G.mus_vol = 0
db.actor:give_info_portion("tutorial_sleep")
disable_info("actor_is_sleeping")
disable_info("sleep_active")
end[/cut]

Получил лог

[cut=Лог]FATAL ERROR

[error]Expression : !m_error_code
[error]Function : raii_guard::~raii_guard
[error]File : D:\prog_repository\sources\trunk\xrServerEntities\script_storage.cpp
[error]Line : 748
[error]Description : ...shing\Зов Припяти\gamedata\scripts\xr_effects.script:2850: attempt to index global 'ui_sleep_dialog' (a nil value)


stack trace:
[/cut]

Ошибка где то в коде

if hours >= 7 then
game.get_game_time():diffSec(self.check_sleep_control_time)==60
else
game.get_game_time():diffSec(self.check_sleep_control_time) == game.get_game_time():diffSec(self.check_sleep_control_time) - hours*3600
end


Но я её не вижу.
 
denis2000Дата: Пт, 10.06.2016, 08:35 | Сообщение # 800
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Цитата sergej5500 ()
Но я её не вижу.

Вот ошибка:
Код
game.get_game_time():diffSec(self.check_sleep_control_time)==60

И вот ошибка:
Код
game.get_game_time():diffSec(self.check_sleep_control_time) == game.get_game_time():diffSec(self.check_sleep_control_time) - hours*3600

Бинарная переменная не может быть оператором!


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
sergej5500Дата: Пт, 10.06.2016, 09:30 | Сообщение # 801
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

Цитата denis2000 ()
Бинарная переменная не может быть оператором!


Как тогда ей поменять значение?
 
denis2000Дата: Пт, 10.06.2016, 12:00 | Сообщение # 802
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

sergej5500, Кому ей? Объясните, что вам требуется.

"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
sergej5500Дата: Пт, 10.06.2016, 12:12 | Сообщение # 803
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

Цитата denis2000 ()
Объясните, что вам требуется.


Я добавил в игру таймер check_sleep_control_time. После суточной активности (без сна) он принудительно усыпит игрока на 6-9 часов.

Если игрок спал в кровать 7 и более часов, то таймеру нужно присвоить значение 0. Игрок выспался.

Если игрок спал меньше 7 часов, то значение таймера нужно уменьшить на кол-во часов, которые проспал игрок.

Реально ли это сделать?
 
denis2000Дата: Пт, 10.06.2016, 14:25 | Сообщение # 804
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

sergej5500, Я понимаю что вы хотите сделать глобально! Я не понимаю что вы конкретно хотели добиться вот этими строками:
Код
if hours >= 7 then
game.get_game_time():diffSec(self.check_sleep_control_time)==60
else
game.get_game_time():diffSec(self.check_sleep_control_time) == game.get_game_time():diffSec(self.check_sleep_control_time) - hours*3600
end


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
sergej5500Дата: Пт, 10.06.2016, 14:51 | Сообщение # 805
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

Цитата denis2000 ()
Я не понимаю что вы конкретно хотели добиться вот этими строками:


Хотел поменять значение таймера.
 
denis2000Дата: Пт, 10.06.2016, 22:35 | Сообщение # 806
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

sergej5500, Таймер у вас вот:
Цитата
if game.get_game_time():diffSec(self.check_sleep_control_time) > 86400 then

self.check_sleep_control_time - это дата/время последнего сна ГГ.
Причем self.check_sleep_control_time в скрипте ui_sleep_dialog.script и self.check_sleep_control_time в скрипте bind_stalker.script это РАЗНЫЕ переменные!


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
sergej5500Дата: Сб, 18.06.2016, 17:10 | Сообщение # 807
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

Добрый день.

Имеется объект inventory_box с логикой. При удалении игрока на определённую дистанцию объект должен удалить своё содержимое. Написал функцию. Функция вызывается из логики этого бокса.

on_info2 = {=dist_to_actor_ge(10)} %=utilizators_clean%

[cut=Функция]
function utilizators_clean(box,victim)
local function calc(box,item)
if item~=nil then
if alife():object(item:id()) then
alife():release(alife():object(item:id()),true)
end
end
end
box:iterate_inventory_box(calc,box)
end
[/cut]

Функция не работает. Или чистит инвентарь игрока. Как её поправить, чтобы заработала?
 
makdmДата: Сб, 18.06.2016, 17:26 | Сообщение # 808
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

sergej5500, вместо

function utilizators_clean(box,victim)

должно быть

function utilizators_clean(actor, box)


Терпение......
И все получится!
 
sergej5500Дата: Вс, 19.06.2016, 16:40 | Сообщение # 809
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

Добрый день. Хочу вернуться к вопросу, который задавал несколькими постами выше. О принудительном засыпании игрока. Частично решил задачу.

[cut=_g.script]
-- 'Прибавить к pstor-счетчику цифру.
function IncCounter(counter_name,add_value)
if ReadVariable(counter_name)==nil then WriteVariable(counter_name,0) end
if add_value==nil then add_value=1 end
if ReadVariable(counter_name)~=nil then
local counter=ReadVariable(counter_name)
WriteVariable(counter_name,counter+add_value)
end
end

-- 'Отнять от pstor-счетчика цифру.
function DecCounter(counter_name,add_value)
if ReadVariable(counter_name)==nil then WriteVariable(counter_name,0) end
if add_value==nil then add_value=1 end
if ReadVariable(counter_name)~=nil then
local counter=ReadVariable(counter_name)
WriteVariable(counter_name,counter-add_value)
end
end

-- 'Запись pstor переменной.
function WriteVariable(params_name,value)
if value==nil then
ClearVariable(params_name)
else
local opt=ReloadParams(params_name)
PstorStore(db.actor,opt,value)
end
end

-- 'Чтение pstor переменной.
function ReadVariable(params_name)
local opt=ReloadParams(params_name)
return PstorRetrieve(db.actor,opt)
end

-- 'Удаление pstor переменной.
function ClearVariable(params_name)
local opt=ReloadParams(params_name)
if db.storage[db.actor:id()].pstor[opt] then
db.storage[db.actor:id()].pstor[opt]=nil
end
end

function PstorStore(obj,varname,val)
if obj==nil then return nil end
local sub_id=obj:id()
if db.storage[sub_id].pstor==nil then
db.storage[sub_id].pstor={}
end
db.storage[sub_id].pstor[varname]=val
end

function PstorRetrieve(obj,varname)
if obj==nil then return nil end
local sub_id=obj:id()
if db.storage[sub_id].pstor~=nil then
local val=db.storage[sub_id].pstor[varname]
if val~=nil then
return val
end
end
return nil
end

function ReloadParams(params)
return params
end
[/cut]

[cut=bind_stalker]function actor_binder:actor_universal_binder()
if self.actor_universal_time == nil then
self.actor_universal_time = game.get_game_time()
end
if game.get_game_time():diffSec(self.actor_universal_time) > 60 then
addon_binder.actor_update()
self.actor_universal_time = game.get_game_time()
end
end
[/cut]

Таймер запускает скрипт контроля один раз в минуту.

[cut=addon_binder]function actor_update()
actor_sleep_control()
end

function actor_sleep_control()
if ReadVariable("universal_sleep_factot") == nil then
WriteVariable("universal_sleep_factot",1)
else
IncCounter("universal_sleep_factot")
end
addon_binder.universal_sleep_control()
end

function universal_sleep_control()
if ReadVariable("universal_sleep_factot") >= 1440 then
xr_effects.disable_ui(db.actor, nil)
level.add_cam_effector("camera_effects\\sleep.anm", 10, false, "addon_binder.dream_callback")
level.add_pp_effector("sleep_fade.ppe", 11, false)
db.actor:give_info_portion("actor_is_sleeping")
_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")
surge_manager.resurrect_skip_message()
end
end

function dream_callback()
level.add_cam_effector("camera_effects\\sleep.anm", 10, false, "addon_binder.dream_callback2")
local hours = math.random(6,10)
level.change_game_time(0,hours,0)
level_weathers.get_weather_manager():forced_weather_change()
surge_manager.get_surge_manager().time_forwarded = true
if (surge_manager.is_started() and level_weathers.get_weather_manager().weather_fx) then
level.stop_weather_fx()
-- level_weathers.get_weather_manager():select_weather(true)
level_weathers.get_weather_manager():forced_weather_change()
end
db.actor.power = 1
printf("dream_callback: time forwarded on [%d]", hours)
WriteVariable("universal_sleep_factot",1)
end

function dream_callback2()
xr_effects.enable_ui(db.actor, nil)
get_console():execute("snd_volume_music "..tostring(_G.mus_vol))
get_console():execute("snd_volume_eff "..tostring(_G.amb_vol))
_G.amb_vol = 0
_G.mus_vol = 0
db.actor:give_info_portion("tutorial_sleep")
disable_info("actor_is_sleeping")
disable_info("sleep_active")
end

[/cut]

[cut=ui_sleep_dialog]function dream_callback()
level.add_cam_effector("camera_effects\\sleep.anm", 10, false, "ui_sleep_dialog.dream_callback2")
local hours = sleep_control.time_track:GetIValue()
level.change_game_time(0,hours,0)
level_weathers.get_weather_manager():forced_weather_change()
surge_manager.get_surge_manager().time_forwarded = true
if(surge_manager.is_started() and level_weathers.get_weather_manager().weather_fx) then
level.stop_weather_fx()
-- level_weathers.get_weather_manager():select_weather(true)
level_weathers.get_weather_manager():forced_weather_change()
end
db.actor.power = 1
printf("dream_callback: time forwarded on [%d]", hours)
if ReadVariable("universal_sleep_factot") == nil then
WriteVariable("universal_sleep_factot",1)
end
if hours >= 6 then
WriteVariable("universal_sleep_factot",1)
else
DecCounter("universal_sleep_factot",hours*60)
end
--if not ReadVariable("universal_sleep_factot") > 1 then
--WriteVariable("universal_sleep_factot",1)
--end
end[/cut]

В игре фигурирует счетчик universal_sleep_factot. Она возрастает один раз в минуту на единицу. Когда она увеличится до 1440, игрок уснет принудительно. Это всё работает. При сне в постели значение счетчика уменьшается. За это отвечает скрипт

if ReadVariable("universal_sleep_factot") == nil then
WriteVariable("universal_sleep_factot",1)
end
if hours >= 6 then
WriteVariable("universal_sleep_factot",1)
else
DecCounter("universal_sleep_factot",hours*60)
end
--if not ReadVariable("universal_sleep_factot") > 1 then
--WriteVariable("universal_sleep_factot",1)
--end

Возникает вопрос, что будет, если счётчик примет отрицательное значение. Я написал проверку. Но игра этот код

if not ReadVariable("universal_sleep_factot") > 1 then
WriteVariable("universal_sleep_factot",1)
end

не принимает. Вылет с логом

[cut=Лог]FATAL ERROR

[error]Expression : !m_error_code
[error]Function : raii_guard::~raii_guard
[error]File : D:\prog_repository\sources\trunk\xrServerEntities\script_storage.cpp
[error]Line : 748
[error]Description : ...\Зов Припяти\gamedata\scripts\ui_sleep_dialog.script:153: attempt to compare number with boolean


stack trace:[/cut]

153 строка --if not ReadVariable("universal_sleep_factot") > 1 then

Без этой проверки всё работает.

Как правильно проверить, не принял ли счётчик отрицательное значение?
 
denis2000Дата: Вс, 19.06.2016, 19:22 | Сообщение # 810
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Цитата sergej5500 ()
attempt to compare number with boolean

ReadVariable("universal_sleep_factot") возвращает бинарную переменную, а вы ее сравниваете с числом, что не возможно в данной версии Матрицы.


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
Поиск: