Войти на сайт Регистрация Лента форума Пользователи Правила сайта Поиск по форуму
Модератор форума: 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 по ссылке из шапки и соседнюю тему "Курс молодого бойца",
возможно Ваш вопрос уже рассматривался.


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


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

Цитата makdm ()
Ну дак это уже в SGM сделано. Посмотри файл sgm_deserves.ltx


Провел ряд экспериментов. Остановился на такой функции.

[cut=Функция]-- 'Создание наградного тайника с заполнением.
function create_deserve_rukzak(x,y,z,lv,gv,items_tbl)
local actor = db.actor
local items_table = {"ammo_9x18_fmj","ammo_9x19_fmj","ammo_12x70_buck","ammo_5.45x39_fmj","ammo_5.56x45_ss190","grenade_f1","grenade_rgd5",
"bandage","medkit","medkit_army","antirad","drug_booster","drug_coagulant","drug_psy_blockade","drug_antidot","drug_radioprotector","drug_anabiotic",
"bread","kolbasa","conserva","vodka","energy_drink"}
--if gv=escape or gv=esc then gv=1
--end
--if gv==esc or gv==escape then gv==1
--end
local sobj=alife():create("deserve_rukzak",vector():set(x,y,z),lv,gv)
alife():create("use_personal_rukzak",vector(),0,0,sobj.id)
if items_tbl~=nil then
local parse_first_table=utils.parse_spawns(items_tbl)
for k,v in pairs(parse_first_table) do
for i=1,v.prob do
alife():create(v.section,vector(),0,0,sobj.id)
end
end
end
if items_tbl~=nil then
for i = 1, 5+math.random(-2,3) do
alife():create(items_table[math.random(#items_table)],vector(),0,0,sobj.id)
end
else
for i = 1, 8+math.random(-3,5) do
alife():create(items_table[math.random(#items_table)],vector(),0,0,sobj.id)
end
end
level.map_add_object_spot_ser(sobj.id,"treasure","")
xr_effects.send_tip(db.actor,nil,{"st_found_new_treasure","got_ammo"})
end[/cut]

Спавн тайника вызываю строкой типа.

create_deserve_rukzak(-264.24667358398,-21.472173690796,-278.95037841797,5414,1,"wpn_abakan,wpn_addon_scope,ammo_5.45x39_ap,4")

Тайник кооректно спавнится, отображается на карте и засчитывается в статистику. Кроме постоянного, работает рандомное заполнение.

Хочу вместо гейм-вертекса в строке спавна писать

create_deserve_rukzak(-264.24667358398,-21.472173690796,-278.95037841797,5414,esc,"wpn_abakan,wpn_addon_scope,ammo_5.45x39_ap,4")

или

create_deserve_rukzak(-264.24667358398,-21.472173690796,-278.95037841797,5414,escape,"wpn_abakan,wpn_addon_scope,ammo_5.45x39_ap,4")

Соответственно, функция create_deserve_rukzak должна вместо esc или escape присвоить гейм-вертексу конкретное числовое значение. И заспавнить рюкзак. Это нужно, чтобы после подключения новых локаций, когда гейм-вертексы наверняка поменяются, не пришлось пересчитывать вертексы у всех спавнящихся тайников. Можно было бы поменять присваемое значение гейм-вертекса в этой функции.

Как это правильно сделать? Код

--if gv=escape or gv=esc then gv=1
--end
--if gv==esc or gv==escape then gv==1
--end

не работает. Игра просто не грузится. Вылет при выборе сейва для загрузки.

P.S. Проблему решил самостоятельно.


Сообщение отредактировал sergej5500 - Вс, 29.05.2016, 10:39
 
lychagin0Дата: Вс, 29.05.2016, 09:39 | Сообщение # 782
Легенда Зоны
Вольные сталкеры
Сообщений: 1303
Награды: 9
Репутация: [ 278 ]

sergej5500, Привет, не совсем понял одно: если рюкзак спавниться на локе с ГГ то может вот так

create("esc_heli_boss",db.actor:position().x+4,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id() ,db.actor:game_vertex_id())




Сообщение отредактировал lychagin0 - Вс, 29.05.2016, 09:41
 
sergej5500Дата: Вс, 29.05.2016, 10:11 | Сообщение # 783
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

Цитата lychagin0 ()
Привет, не совсем понял одно: если рюкзак спавниться на локе с ГГ то может вот так


Эта функция так же применяется для спавна рюкзаков после юзания флешек. Как в СГМ. Флешка может быть заюзана на другой локации.
 
makdmДата: Вс, 29.05.2016, 10:48 | Сообщение # 784
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

sergej5500, левел вертекс и гейм вертекс ЛЮБОЙ локации в игре можно получить с помощью такой функции.

Вызов функции для локации Бар:

local lv_id, gv_id = get_lvid_gvid_level( "l05_bar" ) -- здесь имя локации, как в папке levels

Код
function get_lvid_gvid_level( need_level )
        local gv_id = 0
    local lv_id = 0
    while game_graph():valid_vertex_id( gv_id ) do
  local level = alife():level_name( game_graph():vertex( gv_id ):level_id() )
  if level == need_level then
   lv_id = game_graph():vertex( gv_id ):level_vertex_id()
   break
  end
    gv_id = gv_id + 1
    end
return lv_id, gv_id
end


Терпение......
И все получится!


Сообщение отредактировал makdm - Вс, 29.05.2016, 10:58
 
sergej5500Дата: Вс, 29.05.2016, 20:15 | Сообщение # 785
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

Добрый вечер. Тестирую функцию спавна аномалии.

[cut=Функция]-- 'Спавн аномалии.
function create_anomaly(zone_name,zone_radius,x,y,z,lv,gv)
if z==nil and lv==nil and gv==nil then
local sobj=alife():create(zone_name,level.vertex_position(x),x,y)
else
local sobj = alife():create(zone_name,vector():set(x,y,z),lv,gv)
end
local packet = net_packet()
packet:w_begin(0)
sobj:STATE_Write(packet)
packet:r_seek(2)
local game_vertex_id = packet:r_u16()
local distance = packet:r_float()
local direct_control = packet:r_s32()
local level_vertex_id = packet:r_s32()
local object_flags = packet:r_s32()
local custom_data = packet:r_stringZ()
local story_id = packet:r_s32()
local spawn_story_id = packet:r_s32()
local shape_count = packet:r_u8()
for i = 1,shape_count do
local shape_type = packet:r_u8()
if shape_type == 0 then
local center = packet:r_vec3()
local radius = packet:r_float()
else
local box = packet:r_matrix()
end
end
local restrictor_type = packet:r_u8()
local max_power = packet:r_float()
local owner_id = packet:r_s32()
local enabled_time = packet:r_u32()
local disabled_time = packet:r_u32()
local start_time_shift = packet:r_u32()
local offline_interactive_radius = packet:r_float()
local artefact_spawn_count = packet:r_u16()
local artefact_position_offset = packet:r_s32()
local new_center = vector():set(0,0,0)
owner_id = bit_not(0)
restrictor_type = 3
max_power = 0
offline_interactive_radius = 30
artefact_spawn_count = 32
packet:w_begin(0)
packet:w_u16(game_vertex_id)
packet:w_float(distance)
packet:w_s32(direct_control)
packet:w_s32(level_vertex_id)
packet:w_s32(object_flags)
packet:w_stringZ(custom_data)
packet:w_s32(story_id)
packet:w_s32(spawn_story_id)
packet:w_u8(1)
packet:w_u8(0)
packet:w_vec3(new_center)
packet:w_float(zone_radius)
packet:w_u8(restrictor_type)
packet:w_float(max_power)
packet:w_s32(owner_id)
packet:w_u32(enabled_time)
packet:w_u32(disabled_time)
packet:w_u32(start_time_shift)
packet:w_float(offline_interactive_radius)
packet:w_u16(artefact_spawn_count)
packet:w_s32(artefact_position_offset)
packet:r_seek(2)
sobj:STATE_Read(packet,packet:w_tell())
return sobj
end[/cut]

Всякий раз получаю вылет на строке

sobj:STATE_Write(packet)

[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 : ...ld publishing\Зов Припяти\gamedata\scripts\_g.script:1108: attempt to index global 'sobj' (a nil value)

stack trace:
[/cut]

Если убрать из функции код

[cut=Код]if z==nil and lv==nil and gv==nil then
local sobj=alife():create(zone_name,level.vertex_position(x),x,y)
else
local sobj = alife():create(zone_name,vector():set(x,y,z),lv,gv)
end[/cut]

и оставить одну из двух строк,

local sobj=alife():create(zone_name,level.vertex_position(x),x,y)
local sobj = alife():create(zone_name,vector():set(x,y,z),lv,gv)

то функция отлично работает. В обоих вариантах. В чем может быть проблема.


Сообщение отредактировал sergej5500 - Вс, 29.05.2016, 20:18
 
makdmДата: Вс, 29.05.2016, 22:48 | Сообщение # 786
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

Цитата sergej5500 ()
if z==nil and lv==nil and gv==nil then
local sobj=alife():create(zone_name,level.vertex_position(x),x,y)
else
local sobj = alife():create(zone_name,vector():set(x,y,z),lv,gv)
end

Ну да к как написано, так и реализовано. biggrin

Делается это немного по другому, вот так:

local sobj = nil
if z==nil and lv==nil and gv==nil then
sobj=alife():create(zone_name,level.vertex_position(x),x,y)
else
sobj = alife():create(zone_name,vector():set(x,y,z),lv,gv)
end

З.Ы. Перепаковка нет-пакета написана неправильно. Как правильно - можно посмотреть в моде Припять. Точка Отсчёта.


Терпение......
И все получится!


Сообщение отредактировал makdm - Вс, 29.05.2016, 23:16
 
men_stalkerДата: Ср, 01.06.2016, 15:06 | Сообщение # 787
Инженер «Свободы»
Свобода
Сообщений: 184
Награды: 5
Репутация: [ 40 ]

Доброго времени суток, возникла проблема не выдаётся инфопоршень:
[cut=info_escape.xml]<info_portion id="c1_shift"></info_portion>
<info_portion id="c1_shift_1"></info_portion>
<info_portion id="c1_shift_2"></info_portion>
[/cut]
[cut=esc_c1_shift.ltx][logic]
active = sr_idle@zone1

[sr_idle@zone1]
on_info = {-c1_shift =dist_to_actor_ge(150)} sr_idle@zone2 %+c1_shift%

[sr_idle@zone2]
on_info = {+c1_shift =dist_to_actor_le(150)} sr_idle@zone3 %-c1_shift%

[sr_idle@zone3]
on_info = {-c1_shift_1 =dist_to_actor_ge(150)} sr_idle@zone4 %+c1_shift_1%

[sr_idle@zone4]
on_info = {+c1_shift_1 =dist_to_actor_le(150)} sr_idle@zone5 %-c1_shift_1%

[sr_idle@zone5]
on_info = {-c1_shift_2 =dist_to_actor_ge(150)} sr_idle@zone6 %+c1_shift_2%

[sr_idle@zone6]
on_info = {+c1_shift_2 =dist_to_actor_le(150)} sr_idle@zone1 %-c1_shift_2%[/cut]
P.S
Если проверять через диалог всё нормально
 
makdmДата: Ср, 01.06.2016, 17:24 | Сообщение # 788
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

men_stalker, биндер обрабатывает логику только тех рестрикторов, которые находятся он-лайн.
Ваш рестриктор точно он-лайн?


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

men_stalker, Для того чтобы эта логика хоть как то заработала switch_distance должна быть больше контрольной дистанции 150м.

"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
men_stalkerДата: Пн, 06.06.2016, 14:56 | Сообщение # 790
Инженер «Свободы»
Свобода
Сообщений: 184
Награды: 5
Репутация: [ 40 ]

denis2000, спасибо помогло.
makdm, только хотел задать вопрос рестриктор может быть не он-лайн? Если да, то как он выводится в он-лайн?

Добавлено (06.06.2016, 14:56)
---------------------------------------------
Здравствуйте, появился вопрос по дереву апгрейтов оружия у механика

Вот прописал так но у механика ветка на АКМ-74/2У не появлятся и вопрос про строку
discount_condlist = %=mech_discount(0.35)% - так можно, без инфопоршня и не надо прописывать =mech_discount(0.35)?

[cut=stalkers_upgrade_info][esc_c1_mehanik]

discount_condlist = %=mech_discount(0.35)%

[esc_c1_mehanik_upgr]

up_sect_firsta_ak74u = true
up_sect_firstc_ak74u = true
up_sect_firstd_ak74u = true
up_sect_firste_ak74u = true

up_sect_secona_ak74u = true
up_sect_seconc_ak74u = true
up_sect_secone_ak74u = true
up_sect_seconf_ak74u = true

up_sect_thirda_ak74u = true
up_sect_thirdc_ak74u = true
up_sect_thirdd_ak74u = true
up_sect_thirde_ak74u = true

up_sect_fourta_ak74u = false
up_sect_fourtc_ak74u = false
up_sect_fourte_ak74u = false
[/cut]


Сообщение отредактировал men_stalker - Пн, 06.06.2016, 14:58
 
sergej5500Дата: Пн, 06.06.2016, 15:27 | Сообщение # 791
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

men_stalker,

В секции esc_c1_mehanik должен быть список стволов, который механик может прокачивать.

[esc_c1_mehanik]
wpn_abakan
wpn_ak74
wpn_ak74u
...
 
men_stalkerДата: Вт, 07.06.2016, 11:45 | Сообщение # 792
Инженер «Свободы»
Свобода
Сообщений: 184
Награды: 5
Репутация: [ 40 ]

Здравствуйте, появился вопрос по диалогам. Диалог состоит из двух враз и он стартовый(<start_dialog>esc_c1_start_of_the_guard</start_dialog>), вторая фраза выводит из диалога, однако после первой фразы выскакивает break_dialog

[cut=dialogs_escape]<dialog id="esc_c1_start_of_the_guard">
<dont_has_info>esc_c1_start_of_the_story</dont_has_info>
<phrase_list>
<phrase id="0">
<text>esc_c1_start_of_the_guard</text>
<next>1</next>
</phrase>
<phrase id="1">
<text>esc_c1_start_of_the_guard</text>
<give_info>esc_c1_start_of_the_story_1</give_info>
<script_text>dialog_manager.create_bye_phrase</script_text>
<action>dialogs.break_dialog</action>
<is_final>1</is_final>
<give_info>esc_c1_start_of_the_story</give_info>
</phrase>
</phrase_list>
</dialog>[/cut]


Сообщение отредактировал men_stalker - Вт, 07.06.2016, 11:46
 
sergej5500Дата: Вт, 07.06.2016, 15:57 | Сообщение # 793
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

Цитата men_stalker ()
однако после первой фразы выскакивает break_dialog


Уберите из диалога строку <action>dialogs.break_dialog</action>

Добавлено (07.06.2016, 15:57)
---------------------------------------------

Цитата makdm ()
левел вертекс и гейм вертекс ЛЮБОЙ локации в игре можно получить с помощью такой функции.


А как ею пользоваться? Что писать в скрипте? Мой пример:

create_deserve_rukzak(-264.24667358398,-21.472173690796,-278.95037841797,5414,1,"wpn_abakan,wpn_addon_scope,ammo_5.45x39_ap,4")

5414 и 1 - левел и гейм вертексы точки спавна. Что писать вместо них? Как инициировать срабатывание Вашей функции и получить конкретное значение вертексов для локации escape?
 
makdmДата: Вт, 07.06.2016, 19:39 | Сообщение # 794
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

Цитата sergej5500 ()
А как ею пользоваться? Что писать в скрипте?

Так и пишите:

local lv_id, gv_id = get_lvid_gvid_level( "escape" )
create_deserve_rukzak(-264.24667358398,-21.472173690796,-278.95037841797,lv_id,gv_id,"wpn_abakan,wpn_addon_scope,ammo_5.45x39_ap,4")

Функцию get_lvid_gvid_level поместите в _G.script


Терпение......
И все получится!


Сообщение отредактировал makdm - Вт, 07.06.2016, 19:44
 
sergej5500Дата: Ср, 08.06.2016, 22:55 | Сообщение # 795
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

Добрый вечер.

Попробовал сделать в чистом Зове Припяти функцию принудительного засыпания главного героя после суток бодрствования. Добавил тестовые скрипты в bind_stalker. Их выдачу повесил на функцию actor_binder:update(delta)

[cut=Скрипты]function actor_binder:check_sleep_control_time()
if self.last_sleep_control_time == nil then
self.last_sleep_control_time = game.get_game_time()
end
if game.get_game_time():diffSec(self.last_sleep_control_time) > 86400 then
xr_effects.disable_ui_only(db.actor, nil)
level.add_cam_effector("camera_effects\\surge_02.anm", 10, false, "bind_stalker.sleep_callback")
level.add_pp_effector("surge_fade.ppe", 11, false)
_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")
self.last_sleep_control_time = game.get_game_time()
end
if give_info("sleep_active") then
self.last_sleep_control_time = game.get_game_time()
end
end

function sleep_callback()
level.add_cam_effector("camera_effects\\surge_01.anm", 10, false, "bind_stalker.sleep_callback2")
local rnd = math.random(6,12)
local m = surge_manager.get_surge_manager()
if(m.started) then
local tf = level.get_time_factor()
local diff_sec = math.ceil(game.get_game_time():diffSec(m.inited_time)/tf)
if(rnd>(m.surge_time-diff_sec)*tf) then
m.time_forwarded = true
m.ui_disabled = true
m:kill_all_unhided()
m:end_surge()
end
end
level.change_game_time(0,0,rnd)
level_weathers.get_weather_manager():forced_weather_change()
printf("sleep_callback: time forwarded on [%d]", rnd)
end[/cut]

Результат неплохой. Игрок засыпает отлично.

После сна в кровати таймер сбрасывается и начинает новый суточный цикл. Возник такой вопрос. Допустим, игрок спал в кровати 1 час. Для полноценного отдыха этого явно недостаточно. Можно ли отследить, сколько времени спал игрок? Если игрок спал 1 час, то на один час уменьшить таймер активности. Как отследить, сколько игрок проспал в постели?

И ещё один вопрос. Как в этой функции вызвать пошатывание игрока и расплывание предметов перед глазами через 20 часов активности? Какие скрипты подойдут?


Сообщение отредактировал sergej5500 - Ср, 08.06.2016, 22:59
 
Поиск: