Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Скрипты
GAMEINATOR forums > S.T.A.L.K.E.R. > Мастерская: создание модов для S.T.A.L.K.E.R.
Страницы: 1, 2, 3, 4, 5, 6
aka_sektor
Цитата(RayTwitty @ 05.12.2017, 20:15) *
ставить колбек

Да, там ниже это и предложили: http://www.amk-team.ru/forum/topic/8806-co...;comment=350365

Вот только с колбеком on_item_take есть косяк, описанный в этом посте: http://www.amk-team.ru/forum/topic/6185-sk...comment=1122162

Цитата(RayTwitty @ 05.12.2017, 20:15) *
надо делать на net_spawn

Можешь показать?

Вообще, предложили дописать проверку актера на nil, вот так:
Код
function sad_predateli_pda()
if db.actor ~= nil and db.actor:object("sad_mudak_pda") ~= nil and not db.actor:has_info("sad_predateli_info") then
db.actor:give_info_portion("sad_predateli_info")
end
end


UPD:
Проверил - больше не вылетает.
RayTwitty
Запамятовал, ключом таблицы в Lua может быть только строка или целое число?))

upd:
Цитата
Тип table (таблица) реализует ассоциативные массивы, это значит, что массив может быть проиндексирован не только числами, но и любым Lua значением, кроме nil и NaN. (Not a Number специальное значение для представления неопределенных и непредставимых числовых результатов, таких как 0/0.) Таблицы могут быть гетерогенными (разнородными); т.е. могут содержать значения всех типов (кроме nil). Любой ключ со значением nil не считается частью таблицы. И наоборот, любой ключ, не являющийся частью таблицы, имеет ассоциированное значение nil.

Действительно работает))
Код
local t1 = { [1] = "one" }

local t2 = { [t1] = "two" }

print(t2[t1]) --> "two"

Хотя на практике я не встречал, чтобы в качестве ключей использовалось что-то отличное от числа или строки.
TIGER_VLAD
Цитата(RayTwitty @ 27.05.2018, 17:00) *
Запамятовал, ключом таблицы в Lua может быть только строка или целое число?))

upd:
Цитата
Тип table (таблица) реализует ассоциативные массивы, это значит, что массив может быть проиндексирован не только числами, но и любым Lua значением, кроме nil и NaN. (Not a Number специальное значение для представления неопределенных и непредставимых числовых результатов, таких как 0/0.) Таблицы могут быть гетерогенными (разнородными); т.е. могут содержать значения всех типов (кроме nil). Любой ключ со значением nil не считается частью таблицы. И наоборот, любой ключ, не являющийся частью таблицы, имеет ассоциированное значение nil.

Действительно работает))
Код
local t1 = { [1] = "one" }

local t2 = { [t1] = "two" }

print(t2[t1]) --> "two"

Хотя на практике я не встречал, чтобы в качестве ключей использовалось что-то отличное от числа или строки.


А еще для строковых ключей квадратные скобки можно не указывать:
local my_t = {green="зеленый", yellow="желтый", red="красный"}
kiperenok
Объясните пожалуйста синтаксис второй строчки кода, что делает двоеточие ? Вообще интересует синтаксис двоеточия в Lua.

local visualMonitor = require( "com.ponywolf.visualMonitor" ) -- к локальной переменной visualMonitor подключить файл visualMonitor
local visMon = visualMonitor:new()
RayTwitty
Цитата(kiperenok @ 09.06.2018, 19:56) *
Объясните пожалуйста синтаксис второй строчки кода, что делает двоеточие ?

Обращение к полю. Погугли операторы и метатаблицы Lua.

Вот неплохое руководство по Lua: https://yadi.sk/d/4EUvTWhzdnAve
kiperenok
Цитата(RayTwitty @ 09.06.2018, 20:14) *
Цитата(kiperenok @ 09.06.2018, 19:56) *
Объясните пожалуйста синтаксис второй строчки кода, что делает двоеточие ?

Обращение к полю. Погугли операторы и метатаблицы Lua.

Вот неплохое руководство по Lua: https://yadi.sk/d/4EUvTWhzdnAve

А так это просто книга Роберта Иерусалимски - просто интерактиваная. Спасибо что скинул ссылку. Че то бегло пробежался по метатаблицам и такого не увидел sad.gif
abramcumner
Цитата(kiperenok @ 09.06.2018, 20:22) *
Че то бегло пробежался по метатаблицам и такого не увидел sad.gif

А в операторах нет оператора двоеточие и в метатаблицах нет smile.gif
Двоеточие это синтаксический сахар для сокращения записи.
Запись
local visMon = visualMonitor:new()
эквивалентна
local visMon = visualMonitor.new(visualMonitor)

То есть объект перед двоеточием передается первым параметром в функцию.
А при объявлении функции через двоеточие в функцию добавляется первый аргумент self.

https://www.lua.org/manual/5.3/manual.html#3.4.11
Цитата
The colon syntax is used for defining methods, that is, functions that have an implicit extra parameter self. Thus, the statement
function t.a.b.c:f (params) body end
is syntactic sugar for
t.a.b.c.f = function (self, params) body end
kiperenok
abramcumner помоги со следующим: rolleyes.gif

function instance:touch(event)
self.xScale, self.yScale = 0.95, 0.95
end


Как я это понял - self это первый скрытый параметр у функции, тогда получается у функции touch первым аргументом идет instance, а вторым event.
Тогда self.xScale равносильно instance.xScale ?
Neo][
kiperenok, по вопросу - в зависимости от того, как вызываешь touch и да, и нет smile.gif
Если вызываешь, как instance:touch(ev) или instance.touch(instance, ev) то да, если же как instance.touch(other_table, ev) то нет.

Я думаю эта ссыль отвечает на все вопросы )
kiperenok
Цитата(Neo][ @ 19.06.2018, 14:33) *
Я думаю эта ссыль отвечает на все вопросы )

Не в моем случае laugh.gif Там все на английском.
abramcumner
Цитата(kiperenok @ 19.06.2018, 14:07) *
Как я это понял - self это первый скрытый параметр у функции, тогда получается у функции touch первым аргументом идет instance, а вторым event.
Тогда self.xScale равносильно instance.xScale ?

Да, все правильно. Но это странный подход - разбирать код таким образом smile.gif
Тебе абревиатура ООП о чем-нибудь говорит? Объекты там, классы.

Цитата
Не в моем случае laugh.gif Там все на английском.

RayTwitty давал ссылку на эту же книгу на русском smile.gif
kiperenok
Цитата(abramcumner @ 19.06.2018, 16:12) *
RayTwitty давал ссылку на эту же книгу на русском smile.gif

Нашел в книге на русском эту главу, прочитал - вот теперь все понятно. Всем кто помог БОЛЬШОЕ спасибо ! wink.gif
atanda
Последняя luabind на текущий момент 0.7.1(2014 год) судя соурсфоржу и гиту. Проект в каком либо виде поддерживается на данный момент?
Marafonec
Парни, может кто подсказать в чем кроется проблема?
Вот такой код
Код
for cf, sec in string.gmatch(str, "%s*([%\%.-_%w]+)%s*%|%s*([-_%w]+)%s*") do
валит игру с логом:
Код
SCRIPT SYNTAX ERROR:
c:\ogsr\gamedata\scripts\_utils.script:225: invalid escape sequence near '"%s*([%'

Использую недавно вышедший движок OGSR x64. На оригинальном движке ТЧ этот код работает безо вских проблем.
Trollz0r
Небось старый луа просто тихо удалял бекслеш, а новый уже не переваривает кривые ескейп-последовательности и хочет, чтобы ты экранировал \. Попробуй добавить ещё один бекслеш перед существующим. Хз как в огср, но в обычном луа5.3 оно вывелось без ошибок: https://rextester.com/live/XSSP38105


А что вообще должна делать эта регулярка?
abramcumner
Цитата(Люпус Эст @ 28.09.2019, 01:37) *
А что вообще должна делать эта регулярка?

Ищет пары слов, разделенные вертикальной чертой.
Marafonec
Цитата(Люпус Эст @ 28.09.2019, 01:37) *
Попробуй добавить ещё один бекслеш перед существующим.
Спасибо, помогло.

Цитата(Люпус Эст @ 28.09.2019, 01:37) *
Хз как в огср, но в обычном луа5.3 оно вывелось без ошибок
Судя по логу: "--LUA version: [LuaJIT 2.1.0-beta3]"

Цитата(Люпус Эст @ 28.09.2019, 01:37) *
А что вообще должна делать эта регулярка?
+++
--/summary/>> функция парсинга параметров файла "overrides_by_schemes.ltx"
function getTableValuesParam(str)
local all_els = {}
--'парсим скриптовые таблицы
for ft in string.gmatch(str, '%"%s*([-_%.%w]+)%s*%"') do
local base_tbl, file_name
local tbl_name = ft
for f, t in string.gmatch(ft, "([-_%w]+)%.([-_%w]+)") do
file_name = f
tbl_name = t
end
if file_name and tbl_name then
base_tbl = _G[file_name] and _G[file_name][tbl_name]
else
base_tbl = _G[ft]
end
if type(base_tbl) == "table" then
for k in pairs(base_tbl) do
table.insert(all_els, k)
end
end
end
--'парсим конфиговые списки параметров
for cf, sec in string.gmatch(str, "%s*([%\\%.-_%w]+)%s*%|%s*([-_%w]+)%s*") do
--'"%s*([%'
local ini = ini_file(cf)
if ini and ini:section_exist(sec) then
do
local ind = 0
repeat
local valid, id, value = ini:r_line(sec, ind, "", "")
if valid then
table.insert(all_els, id.." >> "..value)
end
ind = ind + 1
until (not valid)
end
end
end
--'парсим дополнительные параметры
for pm, list in string.gmatch(str, "%s*([%+%-])%s*%{%s*([-_%s%,%w]+)%s*%}") do
for el in string.gmatch(list, "%s*([^%,%s][-_%w]+)%s*") do
if pm == "+" then
table.insert(all_els, el)
end
if pm == "-" then
local ind = 0
for i, v in ipairs(all_els) do
if v == el then
ind = i
break
end
end
if ind > 0 and all_els[ind] then
table.remove(all_els, ind)
end
end
end
end
return all_els
end

Pavel_Blend
Я сегодня ещё раз начал вникать в луа. Частично прочитал несколько небольших учебников. Появились вопросы:

1) что это за слово class? Понятно, что создаёт класс, но в Notepad++ это ключевое слово даже не подсвечивается цветом. Такое ощущение, что эта вещь есть только в сталкеровских скриптах. Это слово class ведь не стандартная для языка часть?

2) как в луа работает система модулей и пакетов? В книжках пишут, что нужно использовать require. Но в сталкерских скриптах нету ни одного require. Я заметил, что модули используются без импорта. Например, если в папке gamedata\scripts есть файл my_module.script, то чтобы использовать функции из этого модуля, нужно сразу (без импорта) к ним обращаться: my_module.my_funct()
В питоне с модулями всё по-другому. Их всегда нужно импортировать так: import my_module, а потом использовать так: my_module.my_funct(). Но в луа я не совсем понимаю, как обращаться к коду из вне. Всё как волшебство какое-то. Пишем my_module.my_funct() и он сам импортируется что ли?

3) откуда растут ноги у скриптов сталкера? Какой скрипт вызывается самым первым? Что является началом работы скриптов?

4) как скриптом вывести в игровую консоль сообщение? printf вроде не работает.
abramcumner
Цитата(Pavel_Blend @ 14.11.2019, 17:07) *
1) что это за слово class? Понятно, что создаёт класс, но в Notepad++ это ключевое слово даже не подсвечивается цветом. Такое ощущение, что эта вещь есть только в сталкеровских скриптах. Это слово class ведь не стандартная для языка часть?

Это магия луа+луабинд.
Луа: при вызове функции с одним строковым(таблицей) параметром можно опускать скобки. Записи class("se_stalker") и class "se_stalker" эквивалентны.
Луабинд: добавляет функцию class и прочую обвязку. См. luabind open.cpp

Цитата
2) как в луа работает система модулей и пакетов? В книжках пишут, что нужно использовать require. Но в сталкерских скриптах нету ни одного require. Я заметил, что модули используются без импорта. Например, если в папке gamedata\scripts есть файл my_module.script, то чтобы использовать функции из этого модуля, нужно сразу (без импорта) к ним обращаться: my_module.my_funct()
В питоне с модулями всё по-другому. Их всегда нужно импортировать так: import my_module, а потом использовать так: my_module.my_funct(). Но в луа я не совсем понимаю, как обращаться к коду из вне. Всё как волшебство какое-то. Пишем my_module.my_funct() и он сам импортируется что ли?

Это магия движка. Если не находится таблица my_module, пытается подгрузить из одноименного файла .script.

Цитата
3) откуда растут ноги у скриптов сталкера? Какой скрипт вызывается самым первым? Что является началом работы скриптов?

Формально наверное _G.script. Но скрипты, привязанные к серверным и клиентским объектам, диалогам и прочему, вызываются "сами по себе".

Цитата
4) как скриптом вывести в игровую консоль сообщение? printf вроде не работает.

Если собрать движок без дефайна MASTER_GOLD работает и printf и log. Если на оригинальном движке, то только через console():execute("load ~~~"..escape(msg)). Типа загружаешь несуществующий сейв, движок ругается на его отсутствие и выводит твою строку smile.gif В принципе во всех модах есть уже готовая функция log/dbglog.
Modera
Цитата(abramcumner @ 14.11.2019, 17:29) *
Это магия луа+луабинд.
Луа: при вызове функции с одним строковым(таблицей) параметром можно опускать скобки. Записи class("se_stalker") и class "se_stalker" эквивалентны.
Луабинд: добавляет функцию class и прочую обвязку. См. luabind open.cpp

Ещё стоит упомянуть что это функция возвращает функцию в которую передаётся базовый класс в скобках.
Это уже граничит с чёрной магией, но луабинд целиком на ней построен, так что не страшно.
atanda
Цитата(Pavel_Blend @ 14.11.2019, 17:07) *
3) откуда растут ноги у скриптов сталкера? Какой скрипт вызывается самым первым? Что является началом работы скриптов?

Я тоже задавался этим вопросом, но после анализа(возможно, плохого) исходников пришёл к выводу, что фактически ничего не является началом работы. Каждый скрипт уникален и не предполагает наличие соседей. При загрузки скрипта, чтобы не конфликтовали глобальные переменные, для содержимого(функций, глоб. переменных) создаётся отдельное пространство имён. Далее скрипт исполняется, при обращении к несуществующей на момент исполнения таблице, например, my_script, действия продолжаются рекурсивно.
RayTwitty
Цитата(Pavel_Blend @ 14.11.2019, 17:07) *
2) как в луа работает система модулей и пакетов?

В сталкерском луа вообще нет как таковых модулей и пакетов. Обращаемся сразу, никаких импортов, инклудов, запросов и т.д. С этим намного проще, чем в чистых языках.
Pavel_Blend
Меня ещё удивил то факт, что можно обращаться к некоторым функциям, не указывая модуля, в котором они хранятся. Например, функция printf хранится в файле _g.script, а вызывать из других скриптов её можно так: printf(), а не так _g.printf(). Ещё видел другую функцию (не printf), которая так же использовалась.
RayTwitty
Цитата(Pavel_Blend @ 14.11.2019, 20:37) *
Меня ещё удивил то факт, что можно обращаться к некоторым функциям, не указывая модуля, в котором они хранятся.

Это касается содержимого только _g скрипта. g - global
Pavel_Blend
Продолжаю изучать луа. Кое что изучил, но всё равно не могу писать скрипты для сталкера. Какой способ изучения лучше всего выбрать, чтобы начать программировать для сталкера? Я пока думаю так:

1) читаю учебник "Программирование на языке Lua. Третье издание. (рус)" (ссылка в шапке данной темы), чтобы изучить чистый луа (без сталкеровских классов/функций) (или есть более полная/лучшая книга на русском?)

2) изучить стандартную библиотеку луа (на удивление она оказалась крошечной, по сравнению со стандартной библиотекой python)

3) как-то изучить сталкеровские функции/классы по lua_help.script

Наверное, самое трудное - это 3 пункт. Так как информация в lua_help.script не многословная и в сети нету полной документации.

Пока я остановился на первом пункте. И получилось сделать свой первый скрипт:
https://github.com/PavelBlend/stalker-lua-s...r/dm_reader.lua

Он считывает бинарные данные из dm файлов, помещает их в таблицу и печатает в консоль.

Ещё пытался изучать скрипты от модов, но ничего не понял. Изучал nlc7 и удивился скриптам, а именно sak_dialog.script и sak.script. Эти скрипты имеют несколько тысяч строк кода. Один в 9 тысяч, другой в 11 тысяч. Как разработчики умудряются с такими скриптами работать? Я бы разделил бы их на куски по 100-500 строк. Наверняка диалоги можно было бы разбить по локациям.
abramcumner
Цитата(Pavel_Blend @ 16.11.2019, 21:54) *
Ещё пытался изучать скрипты от модов, но ничего не понял.

А зачем моды, лучше с оригинала начать тогда.
На АМК есть тема с разбором lua_help: https://www.amk-team.ru/forum/topic/7450-sp...iyam-i-klassam/
В ней если не все описано, то очень многое.

Цитата
Изучал nlc7 и удивился скриптам, а именно sak_dialog.script и sak.script. Эти скрипты имеют несколько тысяч строк кода. Один в 9 тысяч, другой в 11 тысяч. Как разработчики умудряются с такими скриптами работать? Я бы разделил бы их на куски по 100-500 строк. Наверняка диалоги можно было бы разбить по локациям.

Диалоги и так разбиты по локациям(config/gameplay/dialogs_*.xml), в скриптах вспомогательная обвязка. Из-за того, что в оригинале из диалога в скриптовую функцию нельзя передать аргументы, приходится плодить кучу функций, которые вызывают одну и ту же функцию, но с разными аргументами. А если делать какой-нибудь бартер/выбор награды/починку на диалогах, то количество скриптовых функций разрастается в геометрической прогрессии. Смысла разбивать диалоговые функции по разным файлам нет, и пишутся и читаются они наоборот: сначала диалог, потом функция. Точно также и функции для логики.

atanda
Цитата(Pavel_Blend @ 16.11.2019, 21:54) *
Изучал nlc7 и удивился скриптам, а именно sak_dialog.script и sak.script

Вполне возможно, что alpet'ом была написана на дельфях утилита для создания диалогов и в ней можно было бы писать экшены, а потом утилита сама записывала функции в файлик.
RayTwitty
Pavel_Blend, может стоит сначала изучить файловую структуру игры? Не просто где конфиги и где скрипты, а более детально - диалоги, предметы, существа, UI, тексты и т.д. А по модам изучать смысла мало - как правило там лютый ахтунг, который только добавит вопросов.
Gaz24
Добрый день. Вопрос по поводу скриптов и аи-схем. Как определить, что НПС в определенный момент времени ведет огонь через менеджер состояний или другой метод?
Pavel_Blend
Такой вопрос возник:

движок сталкера добавляет функции в луа, которые равноправны функциям из базовой библиотеки? То есть например, есть функции pairs, getmetatable, next, которые находятся в базовой библиотеке. И чтобы их вызвать, достаточно написать getmetatable(). Но есть функции, которые предоставляются другими библиотеками, доступ к которым осуществляется не просто find, а string.find или math.abs. То есть нужно писать имя библиотеки и ставить точку, после которой идёт имя функции. Так вот, движок сталкера добавляет функции в базовую библиотеку, и чтобы использовать эти функции, не нужно писать имя библиотеки и точку. Например, есть такие функции, как vector(). Я ведь всё правильно понял? Ну, что движок xray добавляет новые функции именно в базовую библиотеку.

И ещё вопрос: есть ли у кого xml файл для Notepad++, который добавляет подсветку синтаксиса lua вместе со всеми сталкеровскими функциями? И чтобы сталкеровские функции были отличны по цвету от стандартных. Просто у меня не получается добавить новые ключевые слова в файл langs.xml. Notepad их просто игнорирует. Поэтому мне нужен отдельный xml файл с User Defined Language с описанием всего синтаксиса луа + сталкеровские функции.
atanda
Цитата(Pavel_Blend @ 18.11.2019, 23:46) *
Ну, что движок xray добавляет новые функции именно в базовую библиотеку.

Смысл верен, только всё немного не так: "регистрация" происходит не в "базовой библиотеке", а в глобальном пространстве имён "_G", т.е. вызывая string.find, ты фактически делаешь _G["string"].find. Луа проходится по таблице и ищет соответствующее пространство имён, в данном случае "string".
Pavel_Blend
atanda, понятно. А для notepad++ ни кто не добавлял сталкеровские функции? Для новичков было бы удобнее. Так как большая часть кода в сталкере - это вызов функций, добавленных из движка.
atanda
Примерно так:

или создавать свои файлы синтаксиса.
abramcumner
Pavel_Blend, https://ap-pro.ru/forum/105-10388-1
Pavel_Blend
abramcumner, по твоей ссылке есть только автозавершение и проверка синтаксиса. Мне нужна подсветка синтаксиса сталкеровских функций. Только нужно, чтобы цвет отличался от стандартных функций.
RayTwitty
Цитата(Pavel_Blend @ 19.11.2019, 00:21) *
Мне нужна подсветка синтаксиса сталкеровских функций. Только нужно, чтобы цвет отличался от стандартных функций.

Такого вроде не существует. Единственное что я например делал, так это ассоциацию файлов .script с lua-синтаксисом (в оригинальном луа расширение .lua).

Цитата(Pavel_Blend @ 18.11.2019, 23:46) *
Так вот, движок сталкера добавляет функции в базовую библиотеку, и чтобы использовать эти функции, не нужно писать имя библиотеки и точку. Например, есть такие функции, как vector().

Ну так самописный вектор они в глобальную загнали, поэтому нет никаких "библиотек". В луа/сталке тут более уместно пространства имен.

Цитата(atanda @ 18.11.2019, 23:54) *
Луа проходится по таблице и ищет соответствующее пространство имён, в данном случае "string".

А еще, при однозначном определении типа, можно прям как в питоне вызывать напрямую))
Код
local t = "lol"
t:find("kek")
atanda
Цитата(RayTwitty @ 19.11.2019, 00:51) *
можно прям как в питоне вызывать напрямую

Это больше похоже на синтаксический сахар. rolleyes.gif
Pavel_Blend
Цитата(RayTwitty @ 19.11.2019, 00:51) *
Цитата(Pavel_Blend @ 19.11.2019, 00:21) *
Мне нужна подсветка синтаксиса сталкеровских функций. Только нужно, чтобы цвет отличался от стандартных функций.

Такого вроде не существует. Единственное что я например делал, так это ассоциацию файлов .script с lua-синтаксисом (в оригинальном луа расширение .lua).

а в каком текстовом редакторе есть возможность добавить новые ключевые слова в lua, чтобы они были произвольного цвета, отличного от цвета стандартных функций? И как получить список всех функций, которые добавил движок в луа сталкера? Я пробовал пройтись по значениям из _G таблицы, но в ней, помимо си++ функций есть обычные скрипты, стандартные луа функции и прочее. Единственный способ - это извлекать имена из lua_help.script?
Pavel_Blend
Получилось заставить Notepad++ читать более 4 наборов ключевых слов. Добавил ключевые слова из сталкеровского движка. Теперь они подсвечиваются розовым цветом. Но я не всё добавил. И так же добавилось кое-что лишнее. Например, функция printf. Она определена в файле _G.script и по идее не должна подсвечиваться розовым цветом. Как я узнал список ключевых слов: запустил игру и вызвал скрипт, который выводил в файл все ключи таблицы _G. Там много чего лишнего. А не добавились методы классов. На скриншоте видно, что слово object_binder подсвечено цветом, а net_spawn - нет. Нужно сделать подсветку метода net_spawn и всех других методов сталкеровских классов. Но вот как узнать список всех классов методов?
Shoкer
Pavel_Blend, открой скрипт lua_help.script из оригинальной игры. Там будет всё то, что экспортируется из движка. Всё остальное создаётся напрямую в скриптах.
Ещё много полезного есть здесь - https://www.amk-team.ru/forum/topic/7450-sp...iyam-i-klassam/ , хотя писалось достаточно давно, ещё до исходников движка.
NanoBot-AMK
Кстати, функции типа object_binder.update(self, delta) можно спокойно исключить, это просто пустышки, которые ничего не делают, кроме времени(2-3 мксек). Исключения только для метода net_spawn, там это нужно.
Gaz24
Хотел добавить свою аи-схему, которая запускается во время боя. Все подключил, добавил эвалуатор, работает. А вот экшен не работает от слова совсем. В чем могла быть ошибка?

Код
Код
local base = xr_evaluators_id.combat_new_base
local eval_on_combat = base + 0

base = xr_actions_id.combat_new_base
local act_on_combat = base + 0
----------------------------------------------------------------------------------------------------------------------
-- модификация xr_combat
----------------------------------------------------------------------------------------------------------------------
class "evaluator_mod_combat" (property_evaluator)

function evaluator_mod_combat:__init(name,storage) super (nil, name)
    self.st = storage
end

function evaluator_mod_combat:evaluate()
    local cond = self.object:motivation_action_manager():current_action_id() == stalker_ids.action_combat_planner
    --news_manager.send_tip(db.actor, self.object:character_name())
    return cond
end

----------------------------------------------------------------------------------------------------------------------
class "action_mod_combat" (action_base)

function action_mod_combat:__init(name,storage) super (nil, name)
    self.st = storage
end

function action_mod_combat:initialize()
    action_base.initialize(self)
    news_manager.send_tip(db.actor, 1)
end

function action_mod_combat:execute()
    action_base.execute(self)
end

function action_mod_combat:finalize()
    action_base.finalize(self)
end

----------------------------------------------------------------------------------------------------------------------
-- binder
----------------------------------------------------------------------------------------------------------------------
function add_to_binder(npc, ini, scheme, section, storage)
    local manager = npc:motivation_action_manager()

    manager:add_evaluator( eval_on_combat, this.evaluator_mod_combat("eval_mod_combat",storage) )

    local action = this.action_mod_combat("act_mod_combat",storage)
    --action:add_precondition(world_property(stalker_ids.property_alive, true))
    manager:add_action(act_on_combat, action)
end
abramcumner
Цитата(Gaz24 @ 23.11.2019, 07:39) *
Хотел добавить свою аи-схему, которая запускается во время боя. Все подключил, добавил эвалуатор, работает. А вот экшен не работает от слова совсем. В чем могла быть ошибка?

Он и не должен работать, ты же экшен никак в GOAP не встроил:
1. твоему экшену надо добавить прекондишен и эффект. Например, что он вызывается, когда world_property(eval_on_combat) = true и обещает перевести world_property(eval_on_combat) в false.
2. добавить существующему экшену прекондишен world_property(eval_on_combat) = false, например к stalker_ids.action_combat_planner

Тогда НПЦ попытается в очередной раз попытается решить загадку зоны; увидит, что ему мешает world_property(eval_on_combat) = true(пункт 2); для устранения такой неприятности у него есть твой экшен(пункт 1) и НПЦ запустит твой экшен.

Посмотри на аи-схемы из оригинала или из модов. Там есть оба пункта.
Gaz24
abramcumner, я со своим эвалуатором использовал изначально, поэтому другой запустил. Сделал так, как ты посоветовал. Все равно экшен не срабатывает. Я может плохо написал из-за своего непонимания.

Код
Код
local action = manager:action(stalker_ids.action_combat_planner)
action:add_precondition(world_property(world_property(eval_on_combat), true))
local action = this.action_mod_combat("act_mod_combat",storage)
action:add_effect(world_property(world_property(eval_on_combat), false))
manager:add_action(act_on_combat, action)
abramcumner
Gaz24, не так. К сожалению не могу найти статью по аи-схемам в сталкере.

Смотри цель любого сталкера - решить загадку зоны, это world_property(puzzleSolved)=true, такой эффект есть у экшена xr_actions_id.alife. Но у него есть прекондишены: жив, нет врагов и тд. Планировщик НПЦ смотрит, как решить загадку зоны, она решается экшеном stalker_ids.action_alife. У него есть прекондишены, планировщик их проверяет. Если все выполнены, то нпц решает загадку зоны, игра заканчивается(в том самом билде). Если не выполнены, то планировщик ищет экшен, который выполнит прекондишен. У него опять проверяет прекондишены, ищет новый экшен,... В итоге доходит до экшена, который может сейчас выполнить и который ведет к решению загадки зоны.

Например логика и гулаги подрубаются так: к экшену xr_actions_id.alife добавляется прекондишен типа "need_remark"=false, а action_remark умеет переводить need_remark в false. Сначала отыграй анимку, а потом можешь решать загадку зоны.

Теперь по-твоему коду. Ты combat_planner`у добавил прекондишен eval_on_combat=true. Планировщик будет искать экшен, который переводит eval_on_combat в true. Но такого нет - act_mod_combat переводит eval_on_combat в false. Надо в эффекте поменять false на true. После этого твой экшен должен начать бесконечно вызываться. Ну и для срабатывания твоего экшена нужен враг, без него боевка и не будет запускаться.

И так не надо писать "world_property(world_property(eval_on_combat), true)", просто "world_property(eval_on_combat, true)".

Сейчас по идее аи-схема должна зависать. Если запустить такой скрипт на отладочном движке, то в лог будет выведен дамп с указанием, что пошло не так.
Gaz24
abramcumner, заработало, спасибо. Правда с прекондишенами надо поиграться. А так, осознал.

Если ты говорил про эту статью, то я на нее очень сильно опирался, но из-за своего косяка вообще не понимал.
RayTwitty
В дополнение к посту про class ini_file

uint64<class_id> r_clsid(string<section>, string<line>) - возвращает id класса по имени класса (т.е. вызов ini:r_clsid(obj:section(), "class") полностью эквивалентен вызову obj:clsid()).
string<result> r_string_wq(string<section>, string<line>) - тоже самое что и стандартный r_string, только этот метод убирает ещё и кавычки.
Пример
Код
[mysection]
param = "myvalue"

------------------

print(ini:r_string("mysection", "param"))
print(ini:r_string_wq("mysection", "param"))

Результаты
Код
"myvalue"
myvalue
vector<result> r_vector(string<section>, string<line>) - разбивает строку вида "param = number,number,number" и возвращает сформированный из этих компонентов вектор.
int32<result> r_s32(string<section>, string<line>) - возвращает 4-байтовое целое число в диапазоне [-2.147.483.648, 2.147.483.647].
uint32<result> r_u32(string<section>, string<line>) - возвращает 4-байтовое беззнаковое целое число в диапазоне [0, 4.294.967.295].
int<item_id> r_token(string<section>, string<line>, token_list*) - довольно интересный метод, который работает следующим образом:
Открыть
Допустим, у нас имеется токен (лист с именами и их идентификаторами):
Код
local my_token = token_list()
my_token:add("value1", 0)
my_token:add("value2", 1)
my_token:add("value3", 2)

И имеется конфиг со строкой:
Код
[mysection]
param = value2

Нам нужно выяснить, какому идентификатору соответствует это значение (и соответствует ли вообще). Читаем:
Код
local item_id = ini:r_token("mysection", "param", my_token)
log(item_id)

Результат
Код
1

(что соответствует value2 = 1).
Если значение в конфиге не соответствует никакому значению из токена, то вернет ноль.

И ещё, сразу сюда же - метод ini_file* create_ini_file(string<file_text>)
Собственно создает конфиг-файл. После чего, с ним можно работать как и с обычным конфигом:
Код
local ini = create_ini_file("[mysection]\nmyparam = value")


З.Ы. Это перенос моего старого поста с другого форума. Пусть будет и здесь.
Diesel
Вопрос по скрипту ОГСМ ogsm_rt_manager.script. В игре, с локациями ЧН, вылета не было. Вылет идёт по спавну в алспавн мертвого сталкера на новой локации.

--Регистрация целей для тасков типа kill_stalker
function CRandomTask:register_target(obj)
if IsStalker(obj) then
for k,v in pairs(self.task_id_by_type["kill_stalker"]) do -- !!! ТУТ ВЫЛЕТ !!!
if obj.alive ~= nil and obj:alive() == true and
obj:profile_name() == self.task_info[v].target
then
if self.task_info[v].target_objects == nil then
self.task_info[v].target_objects = {}
end
table.insert(self.task_info[v].target_objects, obj.id)
end
end
end
end

Если выпиливаю полностью тело функции, то срабатывает нормально. А вообще это что за тема задумана такая?


Может перечисление локаций ЧН сделать, типа такого?
if level.name() == "agroprom_underground" then

Или куда то надо новую локацию прописать или трупы? Тупизна меня обуяла.

А там еще ака Bak намутил rx_wmgr.script - что на сивой кобыле не проехать.

Короче, для нового уровня - ОГСМ - это Ж...
Diesel
Кто желает разобраться в хитросплетениях диалога. Вылет идёт когда раненому даю аптечку в ЧН (мод SGM).
Вылетает рандомно. В интернетах разумного ответа нет.

FATAL ERROR

[error]Expression : !phrase_dialog->m_PhraseVector.empty()
[error]Function : CPhraseDialog::SayPhrase
[error]File : .\PhraseDialog.cpp
[error]Line : 146
[error]Description : No available phrase to say, dialog[dm_hello_dialog]


stack trace:

0023:0077B1D3 xrCore.dll, xrDebug::backend(), x:\source_scs602\components\engine\xrcore\xrdebugnew.cpp, 278
0023:0077B381 xrCore.dll, xrDebug::fail(), x:\source_scs602\components\engine\xrcore\xrdebugnew.cpp, 366
0023:046E1113 xrGame.dll, CPhraseDialog::SayPhrase(), x:\source_scs602\components\engine\xrgame\phrasedialog.cpp, 146
0023:046E432A xrGame.dll, CPhraseDialogManager::SayPhrase(), x:\source_scs602\components\engine\xrgame\phrasedialogmanager.cpp, 77
0023:0490187A xrGame.dll, CUITalkWnd::SayPhrase(), x:\source_scs602\components\engine\xrgame\ui\uitalkwnd.cpp, 304
0023:04901D3F xrGame.dll, CUITalkWnd::UpdateQuestions(), x:\source_scs602\components\engine\xrgame\ui\uitalkwnd.cpp, 139
0023:04901EDA xrGame.dll, CUITalkWnd::Update(), x:\source_scs602\components\engine\xrgame\ui\uitalkwnd.cpp, 218
0023:04902317 xrGame.dll, CUITalkWnd::InitTalkDialog(), x:\source_scs602\components\engine\xrgame\ui\uitalkwnd.cpp, 83
0023:04902408 xrGame.dll, CUITalkWnd::Show(), x:\source_scs602\components\engine\xrgame\ui\uitalkwnd.cpp, 240
0023:048E81ED xrGame.dll, CDialogHolder::StartMenu(), x:\source_scs602\components\engine\xrgame\uidialogholder.cpp, 77
0023:048E82E8 xrGame.dll, CDialogHolder::StartStopMenu(), x:\source_scs602\components\engine\xrgame\uidialogholder.cpp, 224
0023:04960A28 xrGame.dll, CUIGameSP::StartTalk(), x:\source_scs602\components\engine\xrgame\uigamesp.cpp, 157
0023:046A956F xrGame.dll, CActor::RunTalkDialog(), x:\source_scs602\components\engine\xrgame\actor_communication.cpp, 210
0023:046A97B8 xrGame.dll, CActor::TryToTalk(), x:\source_scs602\components\engine\xrgame\actor_communication.cpp, 194
0023:046BCFA3 xrGame.dll, CActor::ActorUse(), x:\source_scs602\components\engine\xrgame\actorinput.cpp, 402
0023:046BD47C xrGame.dll, CActor::IR_OnKeyboardPress(), x:\source_scs602\components\engine\xrgame\actorinput.cpp, 144
0023:0468189B xrGame.dll, CLevel::IR_OnKeyboardPress(), x:\source_scs602\components\engine\xrgame\level_input.cpp, 416
0023:00411A02 xrEngine.exe, CInput::KeyUpdate(), x:\source_scs602\components\engine\xrengine\xr_input.cpp, 201

Движковый вылет

bool CPhraseDialog::SayPhrase (DIALOG_SHARED_PTR& phrase_dialog, const shared_str& phrase_id)
{
THROW(phrase_dialog->IsInited());

phrase_dialog->m_SaidPhraseID = phrase_id;

bool first_is_speaking = phrase_dialog->FirstIsSpeaking();
phrase_dialog->m_bFirstIsSpeaking = !phrase_dialog->m_bFirstIsSpeaking;

const CGameObject* pSpeakerGO1 = smart_cast<const CGameObject*>(phrase_dialog->FirstSpeaker()); VERIFY(pSpeakerGO1);
const CGameObject* pSpeakerGO2 = smart_cast<const CGameObject*>(phrase_dialog->SecondSpeaker()); VERIFY(pSpeakerGO2);
if(!first_is_speaking) std::swap(pSpeakerGO1, pSpeakerGO2);

CPhraseGraph::CVertex* phrase_vertex = phrase_dialog->data()->m_PhraseGraph.vertex(phrase_dialog->m_SaidPhraseID);
THROW(phrase_vertex);

CPhrase* last_phrase = phrase_vertex->data();

//вызвать скриптовую присоединенную функцию
//активируется после сказанной фразы
//первый параметр - тот кто говорит фразу, второй - тот кто слушает
last_phrase->GetScriptHelper()->Action(pSpeakerGO1, pSpeakerGO2, *phrase_dialog->m_DialogId, phrase_id.c_str());

//больше нет фраз, чтоб говорить
phrase_dialog->m_PhraseVector.clear();
if(phrase_vertex->edges().empty())
{
phrase_dialog->m_bFinished = true;
}
else
{
//обновить список фраз, которые сейчас сможет говорить собеседник
for(xr_vector<CPhraseGraph::CEdge>::const_iterator it = phrase_vertex->edges().begin();
it != phrase_vertex->edges().end();
it++)
{
const CPhraseGraph::CEdge& edge = *it;
CPhraseGraph::CVertex* next_phrase_vertex = phrase_dialog->data()->m_PhraseGraph.vertex(edge.vertex_id());
THROW (next_phrase_vertex);
shared_str next_phrase_id = next_phrase_vertex->vertex_id();
if(next_phrase_vertex->data()->GetScriptHelper()->Precondition(pSpeakerGO2, pSpeakerGO1, *phrase_dialog->m_DialogId, phrase_id.c_str(), next_phrase_id.c_str()))
{
phrase_dialog->m_PhraseVector.push_back(next_phrase_vertex->data());
#ifdef DEBUG
if(psAI_Flags.test(aiDialogs))
{
LPCSTR phrase_text = next_phrase_vertex->data()->GetText();
shared_str id = next_phrase_vertex->data()->GetID();
Msg("----added phrase text [%s] phrase_id=[%s] id=[%s] to dialog [%s]", phrase_text, phrase_id, id, phrase_dialog->m_DialogId.c_str());
}
#endif
}

}

R_ASSERT2 (
!phrase_dialog->m_PhraseVector.empty(),
make_string(
"No available phrase to say, dialog[%s]",
*phrase_dialog->m_DialogId
)

);

//упорядочить списко по убыванию благосклонности
std::sort(phrase_dialog->m_PhraseVector.begin(),
phrase_dialog->m_PhraseVector.end(), PhraseGoodwillPred);
}



//сообщить CDialogManager, что сказана фраза
//и ожидается ответ
if(first_is_speaking)
phrase_dialog->SecondSpeaker()->ReceivePhrase(phrase_dialog);
else
phrase_dialog->FirstSpeaker()->ReceivePhrase(phrase_dialog);


return phrase_dialog?!phrase_dialog->m_bFinished:true;
}


Ну, и дебильный вопрос: нафига здесь в движке ассерт? У меня за 10 лет, только на аптечках и вылетало.
Pavel_Blend
Недавно возобновил изучение луа. Вот вроде бы проще питона, но как-то труднее его изучить. Может из-за того, что желание изучать меньше. В общем пытаюсь хоть что-то сделать в скриптах. Максимум удалось вывести сообщение в консоль. При изучении нужно знать две вещи: сам луа и собственно функции движка (в блендере это называется API, наверное в X-Ray это тоже API в виде lua функций).
С первым вроде бы понятно, информацию найти можно, а вот со вторым труднее. Читал на АМК посты по функциям и ничего не понятно.

В общем вопросы (эти вопросы по ТЧ скриптам):

как вообще можно встроить свои собственные скрипты в сталкер? Я пока знаю, что можно в диалогах прописать вызов скрипта и функции. А какие ещё способы есть?

И как сделать редактор погоды в игре? Чтобы нажать клавишу, после чего появятся интерфейс с крутилками (которые управляются клавиатурой), который будет в углу и не будет загораживать обзор и при появлении этих крутилок можно спокойно перемещаться по локации (то есть движение мыши не блокируется, как это происходит при открытии инвентаря). И как сделать печать изменённых параметров погоды на экран (чтобы можно было сделать скрин параметров, а потом переписать их в конфиг)?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.