Войти на сайт Регистрация Лента форума Пользователи Правила сайта Поиск по форуму
Модератор форума: 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Дата: Пн, 31.12.2012, 20:37 | Сообщение # 121
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

tromm, Функция how_much_repair должна быть такой:
[cut]
Код
local function how_much_repair( item_name, item_condition )
   local ltx = system_ini()
   local cost = ltx:r_u32(item_name, "cost")
   local class = ltx:r_string(item_name, "class")
   local mech_community = ltx:r_string(mechanic_name, "community")
   local cof = 0.8
   if class == "E_STLK" then
    cof = 0.5
   else
    cof = 0.8
   end
   if mech_community then
    if guiders.actor_in_faction() == mech_community then   
     cost = 0
    end
   end
   return math.floor(cost*(1-item_condition)*cof)
end

В предложенном вами варианте:
Код
if actor_in_faction() == npc:character_community() then
cost = 0
end

две ошибки:
actor_in_faction() - эта функция не глобальная и так ее вызвать нельзя!
npc:character_community() - объект npc не определен в текущем скрипте и значит вызвать его метод character_community() не возможно.
[/cut]


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
АзазельДата: Сб, 05.01.2013, 04:54 | Сообщение # 122
Новичок
Пользователи
Сообщений: 77
Награды: 0
Репутация: [ 0 ]

Всем привет. Как подсказал denis2000 нашел в аддоне Енота скрипт. Но к сажелению мало что в нем понял. Каким образом можно вытянуть функции чтобы реализовать съемные колиматоры ?
 
makdmДата: Сб, 12.01.2013, 20:50 | Сообщение # 123
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

Всем привет!
COP 1.6.0.2.
Решил заспавнить БТР на локации через all.spawn. Секция m_car без логики.
Необходимо: в случае гибели БТР - выдача инфопорошня.

1. Подключил bind_physic_object.script, обойдя проверку на отсутствие логики.
[cut=Было] local ini = obj:spawn_ini()
-- Биндить предмет нет смысла, если у него нет секции logic
if not (ini and ini:section_exist("logic")) then
-- Прожектор нужно биндить даже без logic
if obj:clsid() ~= clsid.inventory_box then
return
end
end[/cut]

[cut=Стало]local name = obj:name()
if not string.find(name, "use_btr_2") then
local ini = obj:spawn_ini()
-- Биндить предмет нет смысла, если у него нет секции logic
if not (ini and ini:section_exist("logic")) then
-- Прожектор нужно биндить даже без logic
if obj:clsid() ~= clsid.inventory_box then
return
end
end
end[/cut]
2. В функции function generic_physics_binder:update(delta) подключил callback

[cut=Колобок] if string.find(self.object:name(), "use_btr_2") then
self.object:set_callback(callback.death, generic_physics_binder.death_callback, self)
end[/cut]
3. В функции function generic_physics_binder:death_callback(victim, who) прописал обработку события
[cut=Выдача инфопоршня] if victim and string.find(victim:name(), "use_btr_2") then
db.actor:give_info_portion("use_btr_2_dead")
end[/cut]
4. В игре уничтожил БТР.

Выдача поршня не произошла. Мало того - вообще не было вызова функции death_callback, хотя биндер прекратил обработку объекта.
В чём может быть проблема?


Терпение......
И все получится!
 
denis2000Дата: Вс, 13.01.2013, 14:26 | Сообщение # 124
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

makdm, Да, по мне все вроде стройно и логично, но не работает. Может поискать другой путь: назначить объекту story_id и проверять наличие объекта по этому параметру функцией в созданном для этого рестрикторе.

"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
makdmДата: Вс, 13.01.2013, 16:48 | Сообщение # 125
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

denis2000, спасибо, что откликнулся. Да, очередная загадка движка.
Вот решение - может кому-то и пригодится в модостроении.

В функции function generic_physics_binder:update(delta)
вместо подключения callback прописываем следующее

[cut=Временное решение] if string.find(self.object:name(), "use_btr_2") then
local script_car = self.object:get_car()
local health = script_car:GetfHealth()
if health and health < 0.05 then
db.actor:give_info_portion("use_btr_2_dead")
end
end[/cut]
Работает, как часы.

И такое можно использовать, подобная конструкция есть в обработчике bind_heli. denis2000


Терпение......
И все получится!
 
yakutiДата: Вс, 13.01.2013, 22:27 | Сообщение # 126
Отмычка
Пользователи
Сообщений: 46
Награды: 0
Репутация: [ 7 ]

научите плиз пользовать файлом lua_help, как писать скрипты.
Ещё вопрос подскажите функция свободного управляемого облета камеры в зп
 
ted80Дата: Вс, 13.01.2013, 22:48 | Сообщение # 127
Гражданский
Пользователи
Сообщений: 15
Награды: 0
Репутация: [ 0 ]

Доброго времени суток! У меня очередной глупый вопрос:
Есть скрипт сбора денег с трупов lootmoney
[cut noguest=lootmoney]function lootmoney(npc)
if npc ~= nil and not string.find(npc:section(),"arena") and npc:character_community()~="arena_enemy" then
local money = npc:money()
if money ~= nil and money ~=0 then
local deadmoney = money
local npc_rank
npc_rank = ranks.get_obj_rank_name(npc)
if npc_rank ~= nil then
if npc_rank == "novice" and deadmoney >=400 then deadmoney=math.random(25,400)
elseif npc_rank == "experienced" and deadmoney >=500 then deadmoney=math.random(50,500)
elseif npc_rank == "veteran" and deadmoney >=600 then deadmoney=math.random(100,600)
elseif npc_rank == "master" and deadmoney >=700 then deadmoney=math.random(200,700)
end[/cut]

как заставить его выдавать деньги в прямой зависимости от ранга нпс
то есть не рандомно:
if npc_rank == "novice" and deadmoney >=400 then deadmoney=math.random(25,400)

а вот так - убил нпс с рангом 35 - получил при обыске 35 р. убил мастера с рангом 952 - получил 952 р. ?
Еще раз простите за глупый вопрос

Большое спасибо все получилось

Опечатка! Шутка программиста: Я что должен с первого раза правильно писать, а компилятор на что? denis2000

biggrin




Сообщение отредактировал ted80 - Ср, 16.01.2013, 18:07
 
denis2000Дата: Вс, 13.01.2013, 23:16 | Сообщение # 128
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

yakuti, lua_help.script это просто справочник характерных для указанного класса объекта (C++ class) свойств (property) и функций (function). Обращение к свойству через"." обращение к функции через ":", если функция имеет передаваемые параметры то указаны их типы. Все!

yakuti, Несовместимые концепции "свободный" и "управляемый".

ted80, Судя по всему нужно что-то подобное:
Код
function lootmoney(npc)
    if npc ~= nil and not string.find(npc:section(),"arena") and npc:character_community()~="arena_enemy" then
     local money = npc:money()
     if money ~= nil and money ~=0 then
      local deadmoney = money
      local rank = round(npc:rank())
      if rank ~= nil and rank ~=0 then
       deadmoney = rank
      end
     end
    end
end


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
АзазельДата: Вт, 15.01.2013, 22:35 | Сообщение # 129
Новичок
Пользователи
Сообщений: 77
Награды: 0
Репутация: [ 0 ]

Не совсем уверен что пишу о скриптовой части. Просьба перенести пост если что то не так.
Заметил в ЧН в файле аномалий строку о спавне артефакта при её срабатывании. Конечно же поставив значение on вместо off я схлопотал чудный вылет. Поэтому таков вопрос. Возможно ли данное действие сделать с помощью скриптов ? Учитывая что нужно будет сделать несколько списков артефактов из которых будет производиться спавн.
 
denis2000Дата: Ср, 16.01.2013, 13:15 | Сообщение # 130
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Азазель, Сделал указанные вами правки и никакого вылета не получил. И как его можно получить если параметр spawn_blowout_artefacts ни движком, ни скриптами не используется!
По скриптовой реализации: каким образом планируете отслежывать срабатывание аномалии (хотябы в онлайне) для спавна артефакта из таблицы?


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
АзазельДата: Чт, 17.01.2013, 12:09 | Сообщение # 131
Новичок
Пользователи
Сообщений: 77
Награды: 0
Репутация: [ 0 ]

denis2000, Я скриптах полный нуль. Потому и спрашиваю. Помниться в SGM учебнике видел отслеживание но там были сталкеры. Которые с вероятностью превращались в зомби.

Прямого пути получить колбек на срабатывание аномалии нет, возможно есть обходной метод, но мне он не известен. denis2000
 
trommДата: Чт, 17.01.2013, 17:26 | Сообщение # 132
Отмычка
Пользователи
Сообщений: 28
Награды: 0
Репутация: [ 19 ]

Ребят ещё такой вопрос, кто нибудь знает как в ЧН сделать голод как в ТЧ, - пробовал ковырять моды, смог найти в них упоминания в файлахui_custom_msgs.xml записи [cut noguest]<hud_hunger1 x="698" y="720" width="52" height="39">
<texture x="1304" y="1103" width="52" height="39">ui\ui_hud</texture>
</hud_hunger1>
<hud_hunger2 x="698" y="720" width="52" height="39">
<texture x="1305" y="1165" width="52" height="39">ui\ui_hud</texture>
</hud_hunger2>
<hud_hunger3 x="698" y="720" width="52" height="39">
<texture x="1305" y="1222" width="52" height="39">ui\ui_hud</texture>
</hud_hunger3>[/cut]

в файле ui_hud.dds изображения 3х иконок голода(красную, желтую, зеленую), в файле ui_custom_msgs.xml я так понял отображены их координаты, понятное дело, что этих файлов мало, где-то какие-то скрипты ещё задействованы, только сколько не искал, понять пока не получается, сколько мануалов по ЧН не просматривал(на AMK, здесь и на прочих сайтах) нигде нет упоминания как правильно реализовать все это, надо бы прояснить ситуацию, или сделать урок по КМБ

Короче ковырял ещё сегодня моды cs по поводу голода(убил тучу времени смог найти кое что) из OGSM скрипт
ogsm_satiety.script полный текст такой[cut noguest]------------------------------ Copyright 2007-2010 DEXXX ------------------------------
----------------------------------- Эмулятор голода -----------------------------------

local snd = sound_object([[ambient\underground\rnd_giant]])

-- Проверяем нужно ли поесть. Вызывается каждые 6 игровых минут
function test_for_need_eat()
local tmp = ogsm.load_variable("eat", 0)
if tmp < 200 then
ogsm.save_variable("eat", tmp + 1)
end
ogsm.g_start_timer("eat",0,0,6)
eat_reduce_health()
end

-- Уменьшение здоровья при критическом голоде
function eat_reduce_health()
local tmp = ogsm.load_variable("eat",0)
if tmp > 150 then
if db.actor.health > 0.15 then
db.actor.health = - 0.15
end
if not snd:playing() then
snd:play_at_pos(db.actor, vector():set(0,0,0), 0, sound_object.s2d)
end
end
end

-- Поедание еды
function eat_item(oid, time)
if alife():object(oid)==nil then
local snd = sound_object([[food\inv_food]])
snd:play_no_feedback(db.actor,sound_object.s2d, 0, vector():set(0, 0, 0), 1.0)
local tmp = ogsm.load_variable("eat",0) - time*10
if tmp < 0 then tmp = 0 end
ogsm.save_variable("eat", tmp)
eat_reduce_health()
end
end

----------------------------------- Эмулятор голода -----------------------------------
------------------------------ Copyright 2007-2010 DEXXX ------------------------------[/cut]

из sgm cs файлы sgm_callbacks.script
там запись[cut noguest]elseif sect=="ananas" or sect=="vodka" or sect=="conserva" or sect=="kolbasa" or sect=="bread" or sect=="bun" then
param_satiety=sgm_functions.GetSatietySlakeFactor(sect)
sgm_functions.write_variable("satiety_factor",sgm_functions.read_variable("satiety_factor")-param_satiety)
end[/cut]

в sgm_effects.script строки[cut noguest]function effects_update()
local level_name=level.name()
local actor_pos=db.actor:position()
if sgm_flags.satiety_timer==0 and sgm_functions.read_variable("satiety_factor")~=nil and not has_alife_info("disable_satiety") then
sgm_functions.write_variable("satiety_factor",sgm_functions.read_variable("satiety_factor")+1)
sgm_flags.satiety_timer=time_global()+math.random(13000,21000)
end
if sgm_flags.satiety_damage==3 and sgm_flags.satiety_kick==0 and not has_alife_info("disable_satiety") then
local satiety_shot=hit()
satiety_shot.draftsman=db.actor
satiety_shot.type=hit.telepatic
satiety_shot.power=0.04
db.actor:hit(satiety_shot)
sgm_flags.satiety_kick=time_global()+math.random(2000,2100)
--/give_quick_news("satiety_kick".." currert="..db.actor.psy_health)
end[/cut]
в sgm_flags.script строки [cut noguest]satiety_timer=0
satiety_damage=0
satiety_kick=0[/cut]

в sgm_functions.script строки [cut noguest]function GetSatietySlakeFactor(section)
local ltx = system_ini()
local value = ltx:r_float(section,"satiety_slake_factor")
return value
end[/cut]
,а особенно заинтересовала запись в файле sgm_huds.script[cut noguest]if sgm_functions.read_variable("satiety_factor")~=nil then
if object_alive(db.actor) and not has_alife_info("disable_satiety") then
if sgm_functions.read_variable("satiety_factor")>=70 and sgm_functions.read_variable("satiety_factor")<120 then
check_hud("hud_hunger2")
check_hud("hud_hunger3")
hud:AddCustomStatic("hud_hunger1",true)
sgm_flags.satiety_damage=1
elseif sgm_functions.read_variable("satiety_factor")>=120 and sgm_functions.read_variable("satiety_factor")<200 then
check_hud("hud_hunger1")
check_hud("hud_hunger3")
hud:AddCustomStatic("hud_hunger2",true)
sgm_flags.satiety_damage=2
elseif sgm_functions.read_variable("satiety_factor")>=200 then
check_hud("hud_hunger1")
check_hud("hud_hunger2")
hud:AddCustomStatic("hud_hunger3",true)
sgm_flags.satiety_damage=3
elseif sgm_functions.read_variable("satiety_factor")<70 then
check_hud("hud_hunger1")
check_hud("hud_hunger2")
check_hud("hud_hunger3")
sgm_flags.satiety_damage=0
end
elseif (not object_alive(db.actor)) or has_alife_info("disable_satiety") then
if hud:GetCustomStatic("hud_hunger1")~=nil or hud:GetCustomStatic("hud_hunger2")~=nil or hud:GetCustomStatic("hud_hunger3")~=nil then
hud:RemoveCustomStatic("hud_hunger1")
hud:RemoveCustomStatic("hud_hunger2")
hud:RemoveCustomStatic("hud_hunger3")
end [/cut]

в файле sgm_info.script строки [cut noguest]if sgm_functions.read_variable("satiety_factor")==nil then
sgm_functions.write_variable("satiety_factor",0)
elseif sgm_functions.read_variable("satiety_factor")~=nil and sgm_functions.read_variable("satiety_factor")<0 then
sgm_functions.write_variable("satiety_factor",0)
end[/cut]

Короче это наверное не полный список, от всего этого каша в голове, как это все адаптировать под стандартный ЧН ?


Всё что мы есть - это результат наших мыслей

Сообщение отредактировал tromm - Пт, 18.01.2013, 01:34
 
АзазельДата: Пт, 18.01.2013, 18:32 | Сообщение # 133
Новичок
Пользователи
Сообщений: 77
Награды: 0
Репутация: [ 0 ]

denis2000, А если отлавливать срабатывание в конкретных зонах ? То есть сделать список координат в которых проверяется срабатывание аномалии.
 
denis2000Дата: Пт, 18.01.2013, 20:40 | Сообщение # 134
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Азазель, Срабатывание аномалии это событие, а проверить скриптом у аномалии можно какое либо свойство, ну или вызвать некоторую функцию.

"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
yakutiДата: Вт, 22.01.2013, 21:42 | Сообщение # 135
Отмычка
Пользователи
Сообщений: 46
Награды: 0
Репутация: [ 7 ]

Цитата (yakuti)
Ещё вопрос подскажите функция свободного управляемого облета камеры в зп

Управляемый в смысле. В ТЧ такое есть. Запускается управляемый облет камеры. Как вызвать этот облет не командой в консоле, а функцией?
 
Поиск: