Войти на сайт Регистрация Лента форума Пользователи Правила сайта Поиск по форуму
Модератор форума: 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Дата: Чт, 10.09.2015, 12:19 | Сообщение # 661
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

Добрый день.

В аддоне Время Альянса есть функция

[cut=Функция]
function send_message(actor, npc, p)
--' p[1] - id текста сообщения из папки text\rus
--' p[2] - story_id сендера
--' p[3] - id имени сендера из папки text\rus
--' p[4] - длительность показа сообщения в миллисек, по-умолчанию 5 секунд.
--' =send_message(p[1]:p[2]:p[3]:p[4]) - вызов функции
if p == nil then
abort("Wrong parameters in 'send_message' function!!!")
end
if p[4] == nil then p[4] = 5000 end
local news_text = game.translate_string(p[1])
local news_caption = game.translate_string(p[3])
local showtime = p[4]
local sender = get_story_object(p[2])
local texture = "ui_iconsTotal_grouping"
if sender then
texture = sender:character_icon()
end
xr_sound.set_sound_play(db.actor:id(), "pda_tips")
db.actor:give_game_news(news_caption, news_text, texture, 0, showtime, 0)
end[/cut]

Скопировал её в чистый Зов Припяти. Попробовал выдать тестовую СМС от Бороды. Функция сработала. Но показывается дефолтная иконка персонажа.



Можно ли доработать функцию, чтобы показывалась иконка персонажа-отправителя? Что и в каких файлах нужно поправить?
 
denis2000Дата: Чт, 10.09.2015, 12:51 | Сообщение # 662
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

sergej5500, Ничего править не нужно, функция позволяет выводить иконку персонажа:
--' p[1] - id текста сообщения из папки text\rus
--' p[2] - story_id сендера
--' p[3] - id имени сендера из папки text\rus
--' p[4] - длительность показа сообщения в миллисек, по-умолчанию 5 секунд.
--' =send_message(p[1]:p[2]:p[3]:p[4]) - вызов функции

local sender = get_story_object(p[2])
if sender then
texture = sender:character_icon()
end
db.actor:give_game_news(news_caption, news_text, texture, 0, showtime, 0)


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

Цитата denis2000 ()
Ничего править не нужно, функция позволяет выводить иконку персонажа


Должна. Но не выводит. Может, я что-то не так делаю?

Вызов сообщения.

%=send_message(zat_a2_stalker_barmen_test:zat_a2_stalker_barmen:zat_a2_stalker_barmen_name:30000)%

[cut=Секции Бороды]

[zat_a2_stalker_barmen]:stalker
$spawn = "respawn\zat_a2_stalker_barmen"
character_profile = zat_a2_stalker_barmen
story_id = zat_a2_stalker_barmen

<specific_character id="zat_a2_stalker_barmen" team_default="1">
<name>zat_a2_stalker_barmen_name</name>
<icon>ui_inGame2_Boroda</icon>
<map_icon x="1" y="0">
</map_icon>
<bio>Опытный сталкер. Детальная информация отсутствует.</bio>
<class>zat_a2_stalker_barmen</class>
<community>stalker</community>
<terrain_sect>stalker_terrain</terrain_sect>
<snd_config>characters_voice\human_02\stalker\</snd_config>
<rank>60</rank>
<reputation>300</reputation>
<money min="480000" max="480000" infinitive="1" />
<visual>actors\stalker_neutral\stalker_neutral_3_face_1</visual>
<supplies>

[spawn] \n
wpn_sig550 \n
ammo_5.56x45_ap = 1 \n
wpn_beretta \n
ammo_9x19_fmj = 1 \n
grenade_rgd5 = 3 \n

#include "gameplay\character_items_3_nl.xml"
#include "gameplay\character_food.xml"
#include "gameplay\character_drugs_3.xml"
</supplies>
#include "gameplay\character_criticals_4.xml"

<start_dialog>zat_a2_stalker_barmen_start_dialog</start_dialog>

<actor_dialog>zat_a2_linker_b14_quest_init</actor_dialog>
<actor_dialog>zat_a2_linker_b14_quest_done</actor_dialog>
<actor_dialog>zat_a2_linker_b14_quest_strange_item</actor_dialog>
<actor_dialog>zat_a2_linker_b14_quest_sell_artefact</actor_dialog>
<actor_dialog>zat_a2_linker_b14_quest_wrong</actor_dialog>
<actor_dialog>zat_b57_barmen_about_bloodsucker_lair_dialog</actor_dialog>
<actor_dialog>zat_b57_barman_reward_dialog</actor_dialog>
<actor_dialog>zat_b22_barmen_about_vampire_actor1</actor_dialog>
<actor_dialog>zat_b22_barmen_about_vampire_actor2</actor_dialog>
<actor_dialog>zat_b22_barmen_about_vampire_actor3</actor_dialog>
<actor_dialog>zat_b22_barmen_about_vampire_actor4</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_b7_actor_start</actor_dialog>
<actor_dialog>zat_b22_barmen_b5_daring_quest_stalkers</actor_dialog>
<actor_dialog>zat_b22_barmen_about_after_quest_b5_dealer_actor4</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_b30_about_new_detector</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_b30_about_compass</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_b30_compass_give_dialog</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_b30_compass_double_dialog</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_b30_compass_revert_dialog</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_b30_take_business_actor_dialog</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_army</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_about_sci_guards</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_about_sci_helpers</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_b30_about_halfart_jup_b1</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_oasis_art_sell</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_b52_about_snag</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_b52_about_nimble</actor_dialog>
<actor_dialog>zat_a2_linker_b29_actor_info</actor_dialog>
<actor_dialog>zat_a2_linker_b29_actor_get_adv_task</actor_dialog>
<actor_dialog>zat_a2_linker_b29_actor_give_adv_task</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_b30_take_money_actor_dialog</actor_dialog>
<actor_dialog>zat_a2_stalker_barmen_actor_info</actor_dialog>

<actor_dialog>actor_break_dialog</actor_dialog>

</specific_character>[/cut]

На экране вижу это. Иконки Бороды нет.

 
makdmДата: Пт, 11.09.2015, 18:05 | Сообщение # 664
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

sergej5500, дело в том, что движковый метод character_icon() работает только с клиентским классом объекта, т.е. возвращает иконку, если объект находится он-лайн.
Если у тебя Борода в офф-лайн, то будет выводиться дефолтная иконка.

Для вывода иконки Бороды, если он офф-лайн, необходимо явно указывать его иконку в скрипте.


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

Добрый день.

Подключил Кордон к чистому ЗП. Написал такой рестриктор.

[cut=Логика][logic]
active = sr_idle@start

[sr_idle@start]
on_actor_inside = sr_idle@task_1 %=send_message(st_esc_b1_monster_attack_start_sms:esc_b1_stalker_commander:esc_b1_stalker_commander_name:20000) +esc_b1_monster_attack_task_start =give_task(esc_b1_monster_attack_task)%

[sr_idle@task_1]
on_game_timer = 30 | sr_idle@task_2

[sr_idle@task_2]
on_info = {-esc_b1_monster_attack_start_save} %+esc_b1_monster_attack_start_save =scenario_autosave(st_save_esc_b1_monster_attack_start)%
on_info2 = {+esc_b1_monster_attack_start_save} sr_idle@task_3

[sr_idle@task_3]
on_game_timer = 95 | sr_idle@task_4 %=set_counter(esc_b1_monster_attack_count:0)%

[sr_idle@task_4]
on_info = {=counter_greater(esc_b1_monster_attack_count:7)} sr_idle@task_8 %=send_message(st_esc_b1_monster_attack_final_sms:esc_b1_stalker_commander:esc_b1_stalker_commander_name:20000) +esc_b1_monster_attack_task_final%, sr_idle@task_5

[sr_idle@task_5]
on_info = {~55} sr_idle@task_6 %=create_squad(esc_b1_monster_attack_1_squad:esc_b1)%, sr_idle@task_6 %=create_squad(esc_b1_monster_attack_2_squad:esc_b1)%

[sr_idle@task_6]
on_game_timer = 65 | sr_idle@task_7

[sr_idle@task_7]
on_info = {!squad_exist(esc_b1_monster_attack_squad)} sr_idle@task_4 %=inc_counter(esc_b1_monster_attack_count:1)%

[sr_idle@task_8][/cut]

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

Возникла пара вопросов. Как в скрипте выдачи награды за квест проверить текущее значение счетчика для вычисления наградной суммы? В СГМ можно было воспользоваться кодом типа.

[cut=Код]function esc_b1_monster_attack_task_complete(actor,npc)
local reward=1000
if sgm_functions.read_variable("esc_b1_monster_attack_death_all_count") ~= nil then
reward=reward + sgm_functions.read_variable("esc_b1_monster_attack_death_all_count")*300
end
if sgm_functions.read_variable("esc_b1_army_death_all_count") ~= nil then
reward=reward - sgm_functions.read_variable("esc_b1_army_death_all_count")*500
end
if reward>0 then
dialogs.relocate_money(npc,reward,"in")
end
if reward>1500 then
give_random_treasure()
give_secret(1)
end
give_reward("medkit_army",2)
give_reward("ammo_5.45x39_ap",2)
end[/cut]

За каждого убитого врага платят по 300. За погибшего союзника штраф 500. Как аналогичную по смыслу функцию написать в чистом ЗП?

Можно ли удалить переменные после завершения квеста? Чтобы они не висели в сохранениях. Какой функцией можно воспользоваться?
 
makdmДата: Вс, 27.09.2015, 15:33 | Сообщение # 666
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

sergej5500, вот так будет для ЗП, правда функции give_reward, give_random_treasure, give_secret нужно добавить в _g.script

Код

function esc_b1_monster_attack_task_complete(actor,npc)
--Награда в деньгах по дефолту
  local reward_0 = 1000
   
--Читаем счётчики и вычисляем награду
  local reward_1 = xr_logic.pstor_retrieve( actor, "esc_b1_monster_attack_death_all_count", 0 )
  local reward_2 = xr_logic.pstor_retrieve( actor, "esc_b1_army_death_all_count", 0 )
  local reward = reward_0 + reward_1*300 - reward_2*500
   
--Выдаём награду в деньгах и тайниках
  if reward > 0 then  
   dialogs.relocate_money(npc,reward,"in")  
  end  
  if reward > 1500 then  
   give_random_treasure()  
   give_secret(1)  
  end
   
--Выдаём награду в натур продуктах  
  give_reward("medkit_army",2)  
  give_reward("ammo_5.45x39_ap",2)  

-- Удаляем счётчики  
  db.storage[ actor:id() ].pstor[ "esc_b1_monster_attack_death_all_count" ] = nil
  db.storage[ actor:id() ].pstor[ "esc_b1_army_death_all_count" ] = nil

end


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

makdm,

Попробовал предложенную функцию. В таком виде.

[cut=Код]function esc_b1_monster_attack_task_reward(actor,npc)
local reward_1 = 3000
local reward_2 = xr_logic.pstor_retrieve(actor,"esc_b1_monster_attack_count_2",0)
local reward_3 = xr_logic.pstor_retrieve(actor,"esc_b1_monster_attack_count_3",0)
local reward = reward_1 + reward_2*300 - reward_3*500
if reward > 0 then
dialogs.relocate_money(npc,reward,"in")
end
give_reward("medkit_army",2)
give_reward("ammo_5.45x39_ap",2)
end[/cut]

Результат нулевой. Получаю 3000. Такое впечатление, что параметры esc_b1_monster_attack_count_2 и esc_b1_monster_attack_count_3 не читаются или обнуляются.

В квесте три параметра.

esc_b1_monster_attack_count_1 -- число сквдов монстров, уничтоженных в квесте. Параметр точно не равен нулю. Об этом можно судить по нормальной работе рестриктора квеста. Квест обновляется при уничтожении 7 сквадов.

esc_b1_monster_attack_count_2 -- число убитых игроком монстров.
esc_b1_monster_attack_count_3 -- число погибших сталкеров.

Пробовал вставлять в наградную функцию esc_b1_monster_attack_count_1, число заведомо не равное нулю. Результат один. Параметры не читаются.
 
makdmДата: Пн, 28.09.2015, 06:54 | Сообщение # 668
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

Цитата sergej5500 ()
Такое впечатление, что параметры esc_b1_monster_attack_count_2 и esc_b1_monster_attack_count_3 не читаются или обнуляются.

А где и как пишутся эти параметры?

Обычно их пишут в логике НПС, где при смерти НПС срабатывает счётчик. Например для сталкеров:

on_death = death

[death]
on_info = {=killed_by_actor} %=inc_counter(esc_b1_monster_attack_count_3)%


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


Сообщение отредактировал makdm - Пн, 28.09.2015, 07:08
 
sergej5500Дата: Пн, 28.09.2015, 09:43 | Сообщение # 669
Полевой Исследователь
Ученые сталкеры
Сообщений: 3793
Награды: 29
Репутация: [ 1355 ]

Цитата makdm ()
А где и как пишутся эти параметры?


Счетчик погибших сквадов. В рестрикторе квеста.

[sr_idle@task_7]
on_info = {!squad_exist(esc_b1_monster_attack_squad)} sr_idle@task_4 %=inc_counter(esc_b1_monster_attack_count_1:1)%

Счетчик погибших монстров. Вызывается из логики монстров.

on_death = mob_death

[mob_death]
on_info = {=killed_by_actor +esc_b1_monster_attack_task_start -esc_b1_monster_attack_task_final -esc_b1_monster_attack_task_fail} %=inc_counter(esc_b1_monster_attack_count_2:1)%

Счетчик погибших сталкеров. Работает из логики ствлкеров.

on_death = death

[death]
on_info = {+esc_b1_monster_attack_task_start -esc_b1_monster_attack_task_final -esc_b1_monster_attack_task_fail} %=inc_counter(esc_b1_monster_attack_count_3:1)%

Я в предыдущем посте писал, что вставлял в наградную функцию первый счетчик. Число погибших сквадов. Он заведомо не равен 0. Рестриктор переключается на "получить награду" после отстрела 7 сквадов монстров. Так что первый счетчик работает верно. И он ненулевой. Но и с ним наградная функция не работает.
 
makdmДата: Пн, 28.09.2015, 13:20 | Сообщение # 670
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

sergej5500, тогда откуда вызывается функция esc_b1_monster_attack_task_reward ???
Если из диалога, то естественно всё будет равно нулю.

Если функция вызывается из диалога то должна быть такой:

function esc_b1_monster_attack_task_reward( first_speaker, second_speaker )

local reward_1 = 3000
local reward_2 = xr_logic.pstor_retrieve( db.actor,"esc_b1_monster_attack_count_2",0 )
local reward_3 = xr_logic.pstor_retrieve( db.actor,"esc_b1_monster_attack_count_3",0 )
local reward = reward_1 + reward_2*300 - reward_3*500
if reward > 0 then
dialogs.relocate_money( first_speaker, reward, "in" )
end
give_reward("medkit_army",2)
give_reward("ammo_5.45x39_ap",2)
end

Если награда не будет выдана, то замени first_speaker на second_speaker

dialogs.relocate_money( second_speaker, reward, "in" )


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

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

В чистом ЗП сделал квест на защиту базы от монстров. После завершения квеста вокруг валялось много убитых мутантов.





Такое впечатление, что трупы монстров не убираются. Делал сейвы, бегал на другой конец локации. Монстры валяются, как были.

Зов Припяти чистый. Файлы, отвечающие за уборку трупов, никак не правились.

Как улучшить уборку трупов монстров?
 
makdmДата: Сб, 03.10.2015, 22:51 | Сообщение # 672
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

sergej5500, в чистом ЗП уборка трупов монстров не предусмотрена разрабами.
Для уборки трупов нужно открыть файл bind_monster.script и в методе
generic_object_binder:death_callback(victim, who)

написать

release_body_manager.get_release_body_manager():moving_dead_body(self.object)


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

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

В СГМ реализована фишка. Неписи плохо видят ночью.

Можно ли её перенести на чистую игру. Параметр eye_range в чистом ЗП в скриптах не задействован.
 
makdmДата: Ср, 14.10.2015, 07:33 | Сообщение # 674
Рожденный в СССР
Разработчики
Сообщений: 1294
Награды: 29
Репутация: [ 1909 ]

sergej5500, в файле xr_motivator.script в методе motivator_binder:update(delta) пишешь:

if in_time_interval(21,7) then
self.object:set_fov(90)
self.object:set_range(50)
else
self.object:set_fov(180)
self.object:set_range(100)
end

Ночью будут хуже видеть в два раза, чем днём.


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

makdm,

За помощь спасибо. Но у разных неписей разный радиус обзора. У сталкеров 100 метров. У зомбированных 50 (примерно).
Это прописано в конфигах.

Строка self.object:set_range(100) не выставит всем неписям 100 метров обзора?
 
Поиск: