Перейти к контенту

Справочник по функциям и классам


Рекомендуемые сообщения

malandrinus, я попробовал по 10 раз по 10 через некоторый промежуток времени, привязал к таймеру, все отлично, Просто делал динам.аномалии, принцип примитивный. Скрипт ищет нужные секции, и удаляет их (перебор каждого из 65565 айди и сравнения его с секциями, которые задал) и вторая чать просто спавнит их.Когда пробовал по 100 за раз , рано или поздно, происходили вылеты(лог есть, но только стак трэк и все), а сейчас через таймер амк сделал примитивный цикл, по 10 шт, пока все отлично, уже 125 раз на данный момент переспавним, оббегал всю локацию. Норм, и во время спавна (я туда посыл новости приписал) даже не подвисает нисколько.

 

Единственно хотел спросить. Вергас как-то мне сказал, что если один скрипт (сам файл ил другое что-то) будет содержать очень много всяких функций, которые будут вызываться из разных мест, то будет переполнение стэков. Так вот у меня вопрос. Если я разделю один скрипт( 92 кб, там много чего) на несколько частей, то как это повлияет на работу скрипта\игры, будут ли тормоза? или лучше все в одном крипте хранить?

Что-то кончается, что-то начинается...

Ссылка на комментарий

Vano_Santuri,

По-моему никак это ни на что не повлияет. Дели или объединяй скрипты как тебе удобно. На мой взгляд, реально вызвать переполнение стека только если зациклить рекурсивный вызов. Типа такого:

function fun()
   fun() -- сама себя вызывает до бесконечности
end

fun() -- здесь получишь вылет с сообщением "stack overflow"

Для вылета в данном случае потребовалось 16 тыс. итераций. Я думаю, можно попытаться вызвать переполнение стека, если распаковать длинную таблицу и сунуть её как список аргументов. Но это всё нетривиальные случаи, как правило такой ситуации быть не должно.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

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

 

Допустим у меня есть пачка функций. Нужно написать такую функцию, что когда я её вызываю , она рандомно выбирает любую функцию из той пачки и вызывает её.

 

Можно примерчик? А то у меня фантазии не хватило, получилось сделать через

 

if math.random(0,1)>0.5 then

........

 

и так в несколько этажей, очень неудобно. Можно ли как-нибудь бахнуть все функции списочком, присвоить им циферки, и чтоб функция выбирала циферку, и запускала функцию, которая соответствует выбранной цифре?

Изменено пользователем Vano_Santuri

Что-то кончается, что-то начинается...

Ссылка на комментарий

local funcs = {
[1] = function()....end,
[2] = function()....end,
[3] = function()....end,
[4] = function()....end,
[5] = function()....end
}

function call()
funcs[math.random(#funcs)]
end

math.random(0,1) = math.random() - и вернет 0 или 1.

нету смысла писать > 0.5 - это дольше обрабатывается чем == 1

====

и все-таки вопрос-то не сюда,а в ковырялку.

====

нет,Ray, ну вот зачем ты это написал и дал человеку код,который гораздо сложнее того,что он просит,если я уже дал внятный ответ? ;)

===

Ты преподом чтоли работаешь?

Изменено пользователем Monnoroch
Ссылка на комментарий
local funcs = {
[1] = function()....end,
...
}

В данном случае индексы указывать не надо. Автонумерация от единицы и так получится. Т.е. достаточно как-то так:

local funcs = {
fun1,
fun2,
fun3,
...
}

 

Зато конструкция вида:

local funcs = {
[<ключ1>] = function1,
[<ключ2>] = function2,
[<ключ3>] = function3,
...
}

вполне заменяет недостающий оператор switch. Это может радикально ускорить выполнение некоторых фрагментов, если заменить этим убогие километровые списки из if - else.

 

Что касается неподходящей темы, то я с этим не согласен. Не помню, говорил или нет, но желание было замутить здесь статейку другую по "advanced Lua", где в том числе обсуждались бы и такие вопросы. Потому что смотреть на код порой просто больно. Теми же таблицами похоже что сами разработчики научились пользоваться только в ЗП =)

 

Добавлено через 13 мин.:

Раз пошла такая пьянка. Комрады, не пишите плиз соединение нескольких строк так:

res = a..b..c..d..e

Это очень медленно, поскольку на каждую операцию конкатенации приходится вычисление суммарной длины и выделение памяти под новую строку.

Вместо этого используйте string.format:

res = string.format("%s%s%s%s%s",a,b,c,d,e)

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

Способ первый даёт N^2 время вычисления, где N - число соединяемых строк. Способ второй - N. Регрессия производительности может быть совершенно чудовищная. Не говоря уже о фрагментации памяти.

 

Так можно соединять и заранее неизвестное число строк. Если надо, напишу как именно.

  • Нравится 1
 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

Ясно, только один момент :

 

[<ключ1>] = function1,

 

<ключ1> - что подрузумевается под этим? произвольное слово? Или что-то другое.

 

И еще вопрос, допустим идет вызов функции на какое-то условие :

 

function has_info()
if db.actor:has_info("info") then
.................
end
end

 

Вызов пошел, если поршень есть, то скрипт срабатывает, а вот если поршня еще нет, то скрипт не срабатывает? и возвращает false ? Или это ему надо еще дописать? И несет ли такая форма записи нагрузку на память?

Изменено пользователем Vano_Santuri

Что-то кончается, что-то начинается...

Ссылка на комментарий
<ключ1> - что подрузумевается под этим? произвольное слово?

Ключом может быть любая переменная, кроме значения nil: числа, строки, булевские, таблицы, функции и пользовательские объекты.

 

И несет ли такая форма записи нагрузку на память?
Вопрос некорректно поставлен. Какую-то нагрузку несёт любое шевеление. Другое дело, какую нагрузку несёт этот вариант по сравнению с каким-то другим. С чем ты его сравниваешь?

 

 

возвращает false ? Или это ему надо еще дописать?
пока ты не напишешь return true или return false (ну или что-то другое - все зависит от задачи) функция ничего возвращать не должна.

Если замутили таки функцию и надо вернуть true/false, то довольно часто можно обойтись без возврата false. Если ничего не возвращать, то это эквивалентно возврату nil. А nil в свою очередь в логических выражениях однозначно интерпретируется как false (согласно синтаксису языка). Впрочем, в данном случае это будет скорее трюкачеством.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

Ray,

совершенно согласен насчёт читабельности. Но я чего завёлся-то, такой код стимулирует по аналогии писать в вырожденном случае кошмарную конструкцию вида:

if <лог. выр.> then
    return true
else
    return false
end

Посему я бы написал тот фрагмент так:

function has_info()
    local has_info = db.actor:has_info("info")
    if has_info then
      .................
    end
    return has_info
end

Что в вырожденном случае (при отсутствии действия по условию) приводит к более вразумительному коду.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

Ray,

стиль дурной, согласен. Но к ошибке в данном случае это не приведёт, поскольку как обычно локальные переменные перекрывают глобальные. Сама функция внутри себя становится недоступна, но в данном случае рекурсия не нужна.

 

ЗЫ: Это индикатор =) К концу недели способность рожать "длинные мнемоничные идентификаторы" сильно снижается.

 

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

Внесу небольшую лепту для желающих получить список вертексов - гейм и левел.

 

Скрытый текст

 Написал пару функций которые при активации формируют таблицу со списком - как вы ее потом будете использовать - это уже ваша проблема.

 

Получаем набор вертексов для каждого уровня.

(набор разумеется не весь - а только тех левел вертексов, которые ассоциированы c гейм вертексами в файле game_graph )

 

Скрытый текст
local lvtab ={}

function LevelVertexId()
	--for i =0, 3511 do   --можно и так делать. Номера гейм вертексов можно узнать из файла game_graph который конвертируется в txt прогой ggtool и тотал коммандером.
	--метод game_graph():valid_vertex_id(i)  в данном случае делает тоже самое - подтверждает что гейм вертекс с таким то номером существует.

	local i = 0
	while game_graph():valid_vertex_id(i) do   
		local lv = game_graph():vertex(i):level_vertex_id()  --получаем левел вертекс по гейм вертексу 
		--получаем имя уровня по его номеру из секции в  game_graph
		local ln = alife():level_name(game_graph():vertex(i):level_id())  
		if not lvtab[ln] then  
			lvtab[ln] ={}   
		end
		table.insert(lvtab[ln], lv)   --заполняем таблицу
		i = i+1
	end
end

 

 

таблица заполняется в таком виде: ключ- имя уровня, значение - таблица с данными для этого уровня.

[имя_уровня] ={номер, номер, номер и т.д}

 

так как выводить всю таблицу скажем на экран возможным не представляется, я выводил только минимальные и максимальные значения вертексов для каждого уровня.

Вот такой функцией, для которой нужно в файле ui_custom_msgs.xml создать блок с координатами вывода текста.

типа такого

 

<cs_debug  x="200" y="180" width="600" height="100" complex_mode="1">
	<text font="letterica16"  r="240" g="217" b="182" a="255" align="l"/>
</cs_debug>
 

(функцию вывода данных я активировал через первую функцию)

function diapason()
	local text =""

	for k, v in pairs(lvtab) do 
		local n =  table_maxn(v)
		local min_v = math.min(unpack(v)) 
		local max_v= math.max(unpack(v))
		local str = "Уровень ["..k.."]"
		local num = "число индексов ["..n.."]"
		local str = string.format("%s %s %s %s", str, min_v, max_v, num)
		text= text..str.."\\n" 
	end     

	local hud = get_hud()
	hud:AddCustomStatic("cs_debug", true)
	hud:GetCustomStatic("cs_debug"):wnd():SetTextST(text)
	hud:GetCustomStatic("cs_debug").m_endTime = time_global()/1000 + 180
end

 

По аналогии с функцией получения левел вертексов можно сделать и функцию получения гейм вертексов и так же заполнить таблицу.

 

Скрытый текст
local gvtab ={}

function GameVertexId()
	local i = 0
	while game_graph():valid_vertex_id(i) do
		local ln = alife():level_name(game_graph():vertex(i):level_id())
		if  not  gvtab[ln] then
			gvtab[ln] ={}
		end
		table.insert(gvtab[ln], i) 
		i = i+1
	end
	this.diapason_gv()  --вызываем функцию для вывода данных на экран
end

 

 

и точно такую же функцию для вывода минимального и максимального значения гейм вертексов для каждого уровня.

Так как геймвертексы идут неразрывно - то мы имея этот диапазон получаем точный список гейм вертеков для каждого уровня - от первого значения до последнего. Всего в игре как вы поняли 3512 гейм вертексов - от нулевого до 3511-го.

function diapason_gv()
	local text =""

	for k, v in pairs(gvtab) do 
		local n =  table_maxn(v)
		local min_v = math.min(unpack(v)) 
		local max_v= math.max(unpack(v))
		local str = "Уровень ["..k.."]"
		local num = "число индексов ["..n.."]"
		local str = string.format("%s %s %s %s", str, min_v, max_v, num)
		text= text..str.."\\n" 
    end     

	local hud = get_hud()
	hud:AddCustomStatic("cs_debug", true)
	hud:GetCustomStatic("cs_debug"):wnd():SetTextST(text)
	hud:GetCustomStatic("cs_debug").m_endTime = time_global()/1000 + 180
end
 

Выводится также мин. и макс. значения - чего в данном случае вполне достаточно.

 

чуть не забыл - так как в сталкере не работает функция table.maxn() - которая возвращает кол-во целочисленных индексов в таблице, то я пользуюсь ее самопальным аналогом, (который считает индексы всех типов - хоть числовые, хоть строковые - причем для числовых не важно идут ли они в математическом порядке или вразнобой) вызывая там где надо table_maxn(имя таблицы)

function table_maxn(tbl)
	local k = 0
	for _, v in pairs(tbl) do
		k = k + 1
	end
	return k
end

 

Полученные таким образом таблицы можно динамически использовать прямо в игре для соответствующих целей.

 


Небольшое дополнение по методам:

Скрытый текст
game_graph() --метод определения файла game.graph

vertex(*gvid*) --метод определения секции в данном файле (гейм_вертекс)

level.vertex_position(*lvid*)
возвращает векторную  позицию по левел вертексу. Применим только к активной локации. 

game_graph():vertex(*gvid*):level_point()
возвращает позицию по гейм вертексу  - локальную. (точнее говоря возвращается позиция самого гейм вертекса из соответствующей ему секции в файле game.graph)
Можно определять на любых локациях (активных/не активных).

game_graph():vertex(*gvid*):game_point()
также возвращает позицию по гейм вертексу  - только мировую(относительно всей карты игры).

game_graph():vertex(*gvid*):level_vertex_id()
возвращает  левел-вертекс по гейм-вертексу. 

alife():level_name(*level_id*)
возвращает имя уровня по его числовому идентификатору. Аргументом может служить метод приведенный ниже.

game_graph():vertex(*gvid*):level_id()
возвращает  числовой идентификатор уровня по гейм вертексу 

game_graph():valid_vertex_id(*gvid*)
возвращает boolean - true\false  -существует или нет геймвертекс

 

 

Изменено пользователем Kirgudu
Ссылка на комментарий

Сегодня опишу пару мелких, но полезных классов.

 

Скрытый текст

Класс предназначен для точного измерения времени выполнения фрагмента кода. Если мы попытаемся для этих целей использовать функции времени игры, то выясним, что в пределах работы скрипта время "замирает". Т.е. вызовы, скажем, game.time() дадут одинаковые значения. А значит воспользоваться этими функциями для измерения времени выполнения скрипта не выйдет. Поэтому и нужен отдельный механизм.

Скрытый текст
class profile_timer {
    profile_timer (); -- конструктор, как и для большинства других классов, доступен как глобальная функция
    profile_timer (profile_timer&); -- конструктор, создающий копию существующего таймера

    profile_timer* operator +(const profile_timer&, profile_timer); -- можно сложить два таймера, получится третий с суммарным временем
    void start(); -- запуск таймера, намерянное время обнуляется
    void stop(); -- остановка таймера
    float time() const; -- получение измеренного времени в микросекундах
    function __tostring(profile_timer&); -- вроде есть, но что возвращает - неясно. Но точно не строку
    bool operator <(const profile_timer&, profile_timer); -- сравнение двух таймеров по накопленному времени
};

 

 

Использовать просто:

 

local t = profile_timer()
t:start()
-- измеряемый фрагмент
t:stop()

log(t:time())

 

 

Скрытый текст

Класс предназначен для установки колбеков на выход объектов в онлайн. Может быть полезен к примеру для двухфазного спавна когда надо сначала создать объект, а затем что-то сделать при его переходе в онлайн. Только надо учесть, что установленный колбек не сохраняется при сохранении/загрузке, поэтому годится в основном для спавна в инвентарь ГГ или рядом с ним.

 

Экземпляр такого класса всего один и получается вызовом level.client_spawn_manager().

 

Скрытый текст
class client_spawn_manager {
    void add(int <id отслеживаемого объекта>, -- на какой объект ставим коллбек
             int <id актора>, -- непонятный аргумент, я ставил его каким угодно, по всей видимости игнорируется, по крайней мере в сингле
             fun&); -- сам колбек
    void add(int <id отслеживаемого объекта>, 
             int <id актора>, 
             fun&, 
             object); -- дополнительный аргумент для передачи в колбек
    void remove(int <id отслеживаемого объекта>, int <id актора>); -- убрать установленный колбек
};

 

 

 Здесь fun - это функция следующего вида:

function spawn_callback(
                   first, -- ранее переданный последний аргумент
                   id, -- идентификатор клиентского объекта
                   obj) -- клиентский объект, на который сработал колбек
end
 

Если колбек устанавливался второй функцией без дополнительного аргумента, то и в колбек будут переданы только id и obj.

 

Пример:

local function spawn_callback(first, id, obj)
    ...
end

local obj = sim:create("some_item", pos, lvid, gvid)
level.client_spawn_manager():add( obj.id, -1, spawn_callback, 1.1)
 

 

Изменено пользователем Kirgudu
 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

Monnoroch,

Это всего лишь строки. Всё, что между квадратными скобками - это строковый литерал. Игнорируются все специальные символы. Переносы строк, табуляции и пр. интерпретируются без всяких изменений. Собственно длинный комментарий:

--[[

...

]]

- это на самом деле тот-же короткий, просто два минуса комментируют "длинную строку", заключённую между [[...]]

 

В качестве открывающей и закрывающей скобок можно использовать также скобки вида [===[...]===], где количество знаков "равно" - это так называемый "уровень" строки. Нужно это с единственной целью включать в строки также и возможные последовательности ']]', ']=]' и т.д. Просто выбираете уровень, для которого закрывающая скобка уж точно в вашей строке не попадётся.

 

Добавлено:

Выше я не совсем понятно написал. Специальные символы игнорируются не в том смысле, что пропускаются, а в том смысле, что не разбивают длинную строку. Т.е. попросту попадают в строковый литерал без изменений. К примеру, здесь в приведённой строке:

[[начало строки
продолжение на новой строке
    продолжение на новой строке после символа табуляции]]

будут два символа переноса и один символ табуляции, что можно было бы иначе сделать так:

"начало строки\nпродолжение на новой строке\n\tпродолжение на новой строке после символа табуляции"

 

 

 

Изменено пользователем malandrinus
 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

Спасиюо.

Есть 2 ф-я чтения из конфига для строк:

 

function r_string_wq(string, string);--возвращает строку

function r_string(string, string);--возвращает строку

 

Видимо одна из них читает такую длинную строку?

Первая?

Ссылка на комментарий

Monnoroch,

я в своё время по использованию никакой разницы не нашёл, хотя думал, что "wq" означает что-то вроде "without quotes". Может просто терпения не хватило найти разницу. Однако обе функции совершенно точно убивают пробелы и табуляции, а в ltx файле не бывает многострочных параметров, так что прочитать с их помощью длинную строку не получится. Если нужна длинная строка надо использовать связку с xml и translate_string.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

malandrinus, Хмм,а как правильно читать actor_visual у броника,чтобы после его же записать в нетпакет НПСу?

 

local aTbl = amkII_rdpk.amkReadStalker(alife():object(oNpcId))

aTbl.sVisualName = system_ini():r_string_wq(sSect,"actor_visual")

amkII_wrpk.amkWriteStalker(aTbl, alife():object(oNpcId))

 

Вот просто чтение и сразу запись.

Я подозреваю,что надо както сконвертировать простую строку в эту.

какие вообще операции можно с ней производить?И как?

 

[[]]..[[]] - это можно?string.format() можно?

 

Вообще,что с ней можно вытворять,кроме коментирования?

Изменено пользователем Monnoroch
Ссылка на комментарий

ещё три точки может означать какой либо параметр.. Без ограничений и итп. и в виде [...] и передачи на функцию может послужить вызовом по имение данных из таблицы...

Строковые функции большой раздел.. Можно из одной строки и скобок сделать нечто невообразимое.

Формат и gsub посмотри.. по ману луа который malandrinus, давал тут, посмотри со второй по четвертую страницу ..

Ссылка на комментарий

malandrinus и всем кому интересно.

нашел на диске статью

 

Скрипты в игре «Сталкер»

Документация для гейм-дизайнеров и скриптописателей

 

В игре используется скриптовый язык Lua, поэтому необходимо воспользоваться его документацией для дальнейшего прочтения этого документа (S:\GameData\Scripts\manual.html)

Из игры в Lua вынесены следующие классы и глобальные функции:

a. Базовые функции на C++

i. log(<string_to_print>)

1. выводит в лог строку

ii. flush()

1. сохраняет лог на диск, работает очень медленно, в Release версии вообще отключена

iii. device()

1. получить экземпляр класса render_device (описание смотрите ниже)

iv. system_ini() – возвращает указатель ini_file на system.ltx

v. alife_simulator *alife() – возвращает указатель на симулятор

vi. game.time()

1. получить игровое время в миллисекундах

vii. level.object(<object_name>)

1. получить экземпляр класса game_object по имени объекта

viii. level.actor()

1. получить экземпляр класса game_object актёра

ix. level.get_weather()

1. возвращает строку – имя текущей погоды

x. level.set_weather(<weather_name>)

1. устанавливает погоду

xi. level.set_time_factor(<time_factor>)

1. устанавливает game time factor

xii. level.get_time_factor()

1. возвращает текущий game time factor

xiii. level.cover_in_direction(<vertex_id>,<direction>)

1. возвращает прикрытость в заданном узле в заданном направлении

xiv. level.vertex_in_direction(<vertex_id>,<direction>,<max_distance>)

1. возвращает ноду в заданном напрвалении

xv. level.rain_factor()

1. возвращает, насколько идёт дождь (0..1)

xvi. level.patrol_path_exists(<patrol_path_name>)

1. возвращает, существует ли патрульный путь.

xvii. level.vertex_position(<vertex_id>) – возвращает центр AI-ноды

b. Базовые функции на Lua

i. printf

1. форматированный вывод данных, аналог printf в C++ (с ограничениями)

ii. wait()

1. ждать до следующего обновления скрипта

iii. wait(<time_to_wait>)

1. ждать заданное в миллисекундах время до следующего обновления скрипта

iv. wait_game(<game_time_to_wait>)

1. ждать заданное в миллисекундах игровое время до следующего обновления скрипта

v. action(<object>,<action1>,…)

1. Добавить объекту object в очередь заданий новое с переданными под-action-ами (смотрите примеры)

c. Классы C++

i. vector

1. класс трёхмерный вектор, имеет следующие члены, методы:

x,y,z – компоненты вектора

set – установить значения компонент вектора по заданным значениям (три числа, вектор)

add – добавить вектор

sub – отнять вектор

mul – умножить покомпонентно на вектор

div – поделить покомпонентно на вектор

… - есть ещё штук 30 других, но вы вряд ли будете ими пользоваться........

 

Дмитрий Ясенев

12.10.2003

 

Надеюсь чем-то поможет

полная версия

http://ifolder.ru/16937470

Ссылка на комментарий

Информация для создателей скриптов

Составитель: Andrey Fidrya (Zmey), af@svitonline.com

В каждом скрипте должны быть:

 

action:initialize() – вызывается в момент включения схемы по GOAP.

Инициализировать переменные здесь НЕЛЬЗЯ. Нужно провести установку callback-ов, которые будет использовать скрипт. В самом конце функции нужно вызвать acton:reset_scheme()

 

action:reset_scheme() – вызывается в момент включения схемы другим скриптом (gulag и т.п.), также вызывается из initialize при включении схемы по GOAP

Вся инициализация должна производиться в reset_scheme(), а не в initialize()!

 

action:finalize() – вызывается в момент выключения схемы по GOAP. Снять проставленные в initialize callback-и.

 

function add_to_binder(npc, char_ini) – биндит схему, только если char_ini == nil (это значит, что биндинг запрошен другим скриптом), или сущестует секция с именем скрипта в custom_data, которая передана как char_ini.

 

function set_scriptname(параметры) – настройка параметров скрипта. Параметры, вместо которых передан nil, берутся из customdata персонажа.

 

Работа с customdata:

 

При чтении полей customdata, если поле не найдено, нужно выдавать сообщение об ошибке, а не тихо отключать скрипт. Сделать это можно с помощью функции xr_utils.abort(“сообщение”, параметры), которая действует аналогично printf, но выводит сообщение в MessageBox и останавливает игру.

Чтобы не переписывать парсинг заново в каждом скрипте, можно воспользоваться функциями из xr_utils:

function conf_get_bool(char_ini, section, field, override, object, mandatory)

function conf_get_string(char_ini, section, field, override, object, mandatory)

function conf_get_number(char_ini, section, field, override, object, mandatory)

Например:

st.enabled = utils.conf_get_bool(char_ini, "guard", "enabled", enable, object, true)

Пример использования можно посмотреть в xr_guard.

Описание параметров – в xr_utils в месте, где определена функция.

В случае возникновения вопросов - обращаться к Змею (af@svitonline.com).

 

Перемещение:

 

За перемещение отвечает movement manager.

 

Пример использования – xr_walker.script.

 

1) В _init создается экземпляр movement manager-а:

self.move_mgr = move_mgr.move_mgr()

 

2) В initialize грузим информацию о путях из их имен:

self.path_walk_info = utils.path_parse_waypoints(self.st.path_walk)

self.path_look_info = utils.path_parse_waypoints(self.st.path_look)

 

3) В reset_scheme инициализируем movement manager:

function move_mgr:reset(path_walk, path_walk_info, path_look, path_look_info,

team, mode, move_cb_info)

 

Здесь

team – команда для синхронизации нескольких персонажей (произвольная текстовая строка)

 

mode – таблица, поля которой задают начальный режим перемещения:

{ crouch = true/false, run = true/false, danger=true/false }

 

move_cb_info – таблица, поля которой задают информацию о callback-методе, который будет вызван, если персонаж прибыл в точку, в которой установлено значение ret: { obj = объект, func = функция }

obj – ссылка на объект класса, которому принадлежит функция, или nil, если функция определена вне класса.

func – ссылка на функцию, которая будет вызвана.

 

Поля team, mode, move_cb задавать не обязательно.

 

4) В execute:

self.move_mgr:update()

 

5) В finalize:

self.move_mgr:finalize()

 

Переключение скорости и режима перемещения до прибытия в первый вейпоинт.

 

Для того, чтобы сменить режим движения до прибытия в первый вейпоинт пути (например, переключиться с ходьбы на бег при каких-то условиях), выполните в своем скрипте в любой момент после reset-а:

 

// ВНИМАНИЕ – вызывать update_movement_state при last_index

// не равном nil недопустимо!

if self.move_mgr.last_index == nil then

self.move_mgr.running = true / false

self.move_mgr.danger = true / false

self.move_mgr.crouch = true / false

self.move_mgr:update_movement_state()

end

 

Примечание: в большинстве случаев переключать режим перемещения не понадобится. Рекомендуется задавать стартовый режим перемещения с помощью параметра mode функции reset(), а не менять его вышеописанным способом.

 

Использование callback:

 

Функция-callback может быть как свободной функцией, так и членом класса.

Прототип свободной функции имеет следующий вид:

function my_callback(self, mode, number)

Прототип функции класса:

function class:my_callback(mode, number)

 

Здесь в качестве первого параметра (self) будет передано значение поля obj таблицы move_cb_info, т.е. фактически это объект, которому принадлежит функция-callback.

 

Параметр mode может быть одним из:

move_mgr.arrival_before_rotation – если поле ret было задано в path_walk и коллбек был вызван сразу же по прибытию персонажа в точку, ДО поворота.

move_mgr.arrival_after_rotation – если поле ret было задано в path_look и коллбек был вызван после прибытия в точку path_walk и поворота в соответствующую точку path_look (в которой был задан ret).

 

number – значение поля ret.

 

В коллбеке можно прервать движение персонажа (остановить его, но нежелательно сбрасывать пути) и выполнять свои custom действия (апдейты movement manager-а при этом вызывать не нужно по понятным причинам). Для прерывания нормальной работы схемы с целью вмешательства в перемещение, нужно вернуть значение true из callback-а, после чего перестать вызывать апдейты. Если это не сделать – значения, которые Вы установите персонажу в коллбеке могут быть сбиты схемой сразу же по возврату из Вашего коллбека! Чтобы продолжить затем движение по маршруту, вызовите:

self.move_mgr:update_movement_state() – это включит бег или ходьбу (в зависимости от настроек последней точки, в которой был персонаж)

После чего продолжайте вызывать апдейты movement manager-а как обычно.

 

Перед вызовом update_movement_state, можно также явно задать режим перемещения:

self.move_mgr.running = true / false

self.move_mgr.danger = true / false

self.move_mgr.crouch = true / false

 

Если коллбек выполняет задачи, никак не влияющие на перемещение и персонажа в целом (например, просто ставит info portion), то из коллбека нужно вернуть nil или false. Вызов коллбека тогда останется для схемы незамеченным.

 

Взаимодействие path_walk c path_look:

 

Прийдя на точку path_walk, где установлена какая-то комбинация флажков, сталкер найдет такую же комбинацию флажков в path_look и посмотрит в эту точку. Если же ни один флажок не установлен, сталкер пойдет дальше не останавливаясь.

 

Проверка текущего состояния персонажа:

 

Часто с персонажем должны взаимодействовать другие персонажи, например, follower-ы командира должны знать его состояние.

 

Движется ли персонаж в данный момент можно узнать, опросив у move_mgr переменную moving.

if self.move_mgr.moving then движется end

 

При этом, если moving == true, можно узнать подробности о перемещении:

if self.move_mgr.crouch then идет в присяде end

if self.move_mgr.running then бежит end

if self.move_mgr.danger then находится в состоянии danger end

 

Если moving == false, то:

if self.move_mgr.standing_crouch then сидит end

if self.move_mgr.standing_danger then сидит в состоянии danger end

 

Задание имен вейпоинтов:

 

Имя вейпоинта должно иметь следующий вид:

имя|поле=значение|поле=значение|…

Первое слово является именем и игнорируется парсером. Остальные фразы, разделенные символом '|' будут обработаны.

Пример имен:

wp00|a=hide

wp01

wp02|a=hide|s=weather

и т.д.

 

Примечание:

Если задано имя поля, но не задано значение – автоматически парсер подставит true.

Т.е. не надо писать “wp0|r=true|d=true”, достаточно просто написать “wp0|r|d”.

 

Флаги пути path_walk:

 

n = 0 .. 9999 – номер точки синхронизации. Рекомендуется первой точке задавать значение 0, остальным – числа по возрастанию с произвольным шагом. Прийдя в точку с большим n, сталкер будет ждать отстающих напарников. Примечание: сталкер дожидается опаздывающих напарников _только_ в точках остановки (т.е. только в тех местах, где точка path_walk имеет общие флаги с одной из точек path_look).

Внимание – для поддержки зацикленных маршрутов, сталкеры на точке с минимальным n дожидаются сталкеров на точке с максимальным n. Поэтому минимальное количество точек синхронизации для корректной работы схемы должно составлять 3 точки или больше!

 

s = имя_звуковой_схемы – пробегая через эту точку, сталкер включит указанную звуковую схему. Звук стартует ДО начала поворота и старта анимации. Для того, чтобы звук стартовал синхронно с анимацией – задавайте его в path_look соответствующей точки, а не в path_walk. Если нужно стартовать звук одновременно с ЛЮБОЙ из анимаций в этой точке, можно воспользоваться параметром sa.

 

sp = с какой вероятностью будет проигран звук (по умолчанию 100)

 

sa = true – ждать начала анимации в точке, прежде чем стартовать проигрывание звука (по умолчанию false).

 

sc = true – разрешить проигрывать звуки схемы неоднократно (по умолчанию false).

 

sf, st – временной интервал повторения фраз из выбранной звуковой схемы в секундах (по умолчанию от 5 до 10 сек).

 

c = true – дальше перемещаться в присяде (по умолчанию false)

 

r = true – дальше перемещаться бегом (по умолчанию false)

 

d = true – перемещаться в состоянии danger (по умолчанию false)

 

ds = имена_диалогов – имена диалогов, которые разрешено стартовать начиная с этой точки (разрешение действует до следующей точки). Имена задаются в виде текстовой строки, разделенной запятыми: ds=bandits_talk,weather_talk и т.д.

 

ret = число – сразу же по прибытии в точку вызывает зарегистрированный при инициализации movement manager-а callback с этим числом в качестве второго аргумента.

 

w = имя_walk_пути – переводит схему на новый path_walk. Рекомендуется также задать новый path_look с помощью параметра ”l”, иначе текущий path_look будет сброшен. Персонаж идет на стартовую точку с режимом перемещения, заданным в точке с параметром “w”. Настройки функции коллбека при переключении пути сохраняются.

 

l = имя_look_пути - сбросит схему на новый path_look. Задавать параметр “l” нужно вместе с параметром ”w”, иначе “l” будет проигнорирован. По умолчанию path_look при смене path_walk будет сброшен.

 

Флаги пути path_look:

 

p = 100 – вероятность, с которой персонаж посмотрит именно в эту точку. Значения p всех возможных точек суммируются, т.е. если у одной точки p = 100, а у другой 300, то персонаж посмотрит в первую с вероятностью 25%! (т.е. 100 из 400).

Рекомендуется задавать p так, чтобы их сумма составляла 100.

По умолчанию у всех точек p = 100.

 

a = анимация, которую проиграет персонаж, посмотрев в эту точку (по умолчанию idle). Для того, чтобы персонаж стоял в точке без анимации, задайте значение nil: “a=nil”

 

c = true – смотреть в точку в присяде (по умолчанию используется значение одноименного поля из path_walk)

 

d = true – смотреть в точку в состоянии danger (по умолчанию используется значение одноименного поля из path_walk)

 

att = 1 или 2 – номер атаки (основная, вспомогательная). Можно использовать вместо анимации (например ”a=nil|att=1”), можно вместе с анимацией (”a=стреляем_в_потолок|att=1»).

 

t = время, которое персонаж будет ждать, играя анимацию или стреляя (по умолчанию 5000). Если требуется ждать бесконечно долго (например, это финальная точка пути), нужно задать t равным “-1”.

Примечание: если персонаж ждет синхронизации в точке, то он будет играть анимацию столько времени, сколько нужно для того, чтобы дождаться напарников, но только по прибытию всех напарников на точки засечет заданное в ”t” время. Исключение составляет стрельба – персонаж не станет стрелять сразу по прибытию в точку, а сперва дождется напарников, а потом уже начнет стрелять в течение заданного времени.

 

s = имя - звук, который персонаж разово проиграет, посмотрев в эту точку.

 

sp = с какой вероятностью будет проигран звук (по умолчанию 100)

 

sl = имя_прожектора – если задано, то при повороте в указанную точку персонаж также повернет и прожектор в неё.

 

ret = число – после поворота в целевую точку вызывает зарегистрированный при инициализации movement manager-а callback с числом ret в качестве второго аргумента. При этом время ожидания (поле t) игнорируется, т.е. после того как callback вызовет update_movement_state – персонаж сразу же пойдет дальше.

 

Добавлено:

Информация для создателей скриптов

Составитель: Andrey Fidrya (Zmey), af@svitonline.com

 

В каждом скрипте должны быть:

 

action:initialize() – вызывается в момент включения схемы по GOAP.

Инициализировать переменные здесь НЕЛЬЗЯ. Нужно провести установку callback-ов, которые будет использовать скрипт. В самом конце функции нужно вызвать acton:reset_scheme()

 

action:reset_scheme() – вызывается в момент включения схемы другим скриптом (gulag и т.п.), также вызывается из initialize при включении схемы по GOAP

Вся инициализация должна производиться в reset_scheme(), а не в initialize()!

 

action:finalize() – вызывается в момент выключения схемы по GOAP. Снять проставленные в initialize callback-и.

 

function add_to_binder(npc, char_ini) – биндит схему, только если char_ini == nil (это значит, что биндинг запрошен другим скриптом), или сущестует секция с именем скрипта в custom_data, которая передана как char_ini.

 

function set_scriptname(параметры) – настройка параметров скрипта. Параметры, вместо которых передан nil, берутся из customdata персонажа.

 

Работа с customdata:

 

При чтении полей customdata, если поле не найдено, нужно выдавать сообщение об ошибке, а не тихо отключать скрипт. Сделать это можно с помощью функции xr_utils.abort(“сообщение”, параметры), которая действует аналогично printf, но выводит сообщение в MessageBox и останавливает игру.

Чтобы не переписывать парсинг заново в каждом скрипте, можно воспользоваться функциями из xr_utils:

function conf_get_bool(char_ini, section, field, override, object, mandatory)

function conf_get_string(char_ini, section, field, override, object, mandatory)

function conf_get_number(char_ini, section, field, override, object, mandatory)

Например:

st.enabled = utils.conf_get_bool(char_ini, "guard", "enabled", enable, object, true)

Пример использования можно посмотреть в xr_guard.

Описание параметров – в xr_utils в месте, где определена функция.

В случае возникновения вопросов - обращаться к Змею (af@svitonline.com).

 

Перемещение:

 

За перемещение отвечает movement manager.

 

Пример использования – xr_walker.script.

 

1) В _init создается экземпляр movement manager-а:

self.move_mgr = move_mgr.move_mgr()

 

2) В initialize грузим информацию о путях из их имен:

self.path_walk_info = utils.path_parse_waypoints(self.st.path_walk)

self.path_look_info = utils.path_parse_waypoints(self.st.path_look)

 

3) В reset_scheme инициализируем movement manager:

function move_mgr:reset(path_walk, path_walk_info, path_look, path_look_info,

team, mode, move_cb_info)

 

Здесь

team – команда для синхронизации нескольких персонажей (произвольная текстовая строка)

 

mode – таблица, поля которой задают начальный режим перемещения:

{ crouch = true/false, run = true/false, danger=true/false }

 

move_cb_info – таблица, поля которой задают информацию о callback-методе, который будет вызван, если персонаж прибыл в точку, в которой установлено значение ret: { obj = объект, func = функция }

obj – ссылка на объект класса, которому принадлежит функция, или nil, если функция определена вне класса.

func – ссылка на функцию, которая будет вызвана.

 

Поля team, mode, move_cb задавать не обязательно.

 

4) В execute:

self.move_mgr:update()

 

5) В finalize:

self.move_mgr:finalize()

 

Переключение скорости и режима перемещения до прибытия в первый вейпоинт.

 

Для того, чтобы сменить режим движения до прибытия в первый вейпоинт пути (например, переключиться с ходьбы на бег при каких-то условиях), выполните в своем скрипте в любой момент после reset-а:

 

// ВНИМАНИЕ – вызывать update_movement_state при last_index

// не равном nil недопустимо!

if self.move_mgr.last_index == nil then

self.move_mgr.running = true / false

self.move_mgr.danger = true / false

self.move_mgr.crouch = true / false

self.move_mgr:update_movement_state()

end

 

Примечание: в большинстве случаев переключать режим перемещения не понадобится. Рекомендуется задавать стартовый режим перемещения с помощью параметра mode функции reset(), а не менять его вышеописанным способом.

 

Использование callback:

 

Функция-callback может быть как свободной функцией, так и членом класса.

Прототип свободной функции имеет следующий вид:

function my_callback(self, mode, number)

Прототип функции класса:

function class:my_callback(mode, number)

 

Здесь в качестве первого параметра (self) будет передано значение поля obj таблицы move_cb_info, т.е. фактически это объект, которому принадлежит функция-callback.

 

Параметр mode может быть одним из:

move_mgr.arrival_before_rotation – если поле ret было задано в path_walk и коллбек был вызван сразу же по прибытию персонажа в точку, ДО поворота.

move_mgr.arrival_after_rotation – если поле ret было задано в path_look и коллбек был вызван после прибытия в точку path_walk и поворота в соответствующую точку path_look (в которой был задан ret).

 

number – значение поля ret.

 

В коллбеке можно прервать движение персонажа (остановить его, но нежелательно сбрасывать пути) и выполнять свои custom действия (апдейты movement manager-а при этом вызывать не нужно по понятным причинам). Для прерывания нормальной работы схемы с целью вмешательства в перемещение, нужно вернуть значение true из callback-а, после чего перестать вызывать апдейты. Если это не сделать – значения, которые Вы установите персонажу в коллбеке могут быть сбиты схемой сразу же по возврату из Вашего коллбека! Чтобы продолжить затем движение по маршруту, вызовите:

self.move_mgr:update_movement_state() – это включит бег или ходьбу (в зависимости от настроек последней точки, в которой был персонаж)

После чего продолжайте вызывать апдейты movement manager-а как обычно.

 

Перед вызовом update_movement_state, можно также явно задать режим перемещения:

self.move_mgr.running = true / false

self.move_mgr.danger = true / false

self.move_mgr.crouch = true / false

 

Если коллбек выполняет задачи, никак не влияющие на перемещение и персонажа в целом (например, просто ставит info portion), то из коллбека нужно вернуть nil или false. Вызов коллбека тогда останется для схемы незамеченным.

 

Взаимодействие path_walk c path_look:

 

Прийдя на точку path_walk, где установлена какая-то комбинация флажков, сталкер найдет такую же комбинацию флажков в path_look и посмотрит в эту точку. Если же ни один флажок не установлен, сталкер пойдет дальше не останавливаясь.

 

Проверка текущего состояния персонажа:

 

Часто с персонажем должны взаимодействовать другие персонажи, например, follower-ы командира должны знать его состояние.

 

Движется ли персонаж в данный момент можно узнать, опросив у move_mgr переменную moving.

if self.move_mgr.moving then движется end

 

При этом, если moving == true, можно узнать подробности о перемещении:

if self.move_mgr.crouch then идет в присяде end

if self.move_mgr.running then бежит end

if self.move_mgr.danger then находится в состоянии danger end

 

Если moving == false, то:

if self.move_mgr.standing_crouch then сидит end

if self.move_mgr.standing_danger then сидит в состоянии danger end

 

Задание имен вейпоинтов:

 

Имя вейпоинта должно иметь следующий вид:

имя|поле=значение|поле=значение|…

Первое слово является именем и игнорируется парсером. Остальные фразы, разделенные символом '|' будут обработаны.

Пример имен:

wp00|a=hide

wp01

wp02|a=hide|s=weather

и т.д.

 

Примечание:

Если задано имя поля, но не задано значение – автоматически парсер подставит true.

Т.е. не надо писать “wp0|r=true|d=true”, достаточно просто написать “wp0|r|d”.

 

Флаги пути path_walk:

 

n = 0 .. 9999 – номер точки синхронизации. Рекомендуется первой точке задавать значение 0, остальным – числа по возрастанию с произвольным шагом. Прийдя в точку с большим n, сталкер будет ждать отстающих напарников. Примечание: сталкер дожидается опаздывающих напарников _только_ в точках остановки (т.е. только в тех местах, где точка path_walk имеет общие флаги с одной из точек path_look).

Внимание – для поддержки зацикленных маршрутов, сталкеры на точке с минимальным n дожидаются сталкеров на точке с максимальным n. Поэтому минимальное количество точек синхронизации для корректной работы схемы должно составлять 3 точки или больше!

 

s = имя_звуковой_схемы – пробегая через эту точку, сталкер включит указанную звуковую схему. Звук стартует ДО начала поворота и старта анимации. Для того, чтобы звук стартовал синхронно с анимацией – задавайте его в path_look соответствующей точки, а не в path_walk. Если нужно стартовать звук одновременно с ЛЮБОЙ из анимаций в этой точке, можно воспользоваться параметром sa.

 

sp = с какой вероятностью будет проигран звук (по умолчанию 100)

 

sa = true – ждать начала анимации в точке, прежде чем стартовать проигрывание звука (по умолчанию false).

 

sc = true – разрешить проигрывать звуки схемы неоднократно (по умолчанию false).

 

sf, st – временной интервал повторения фраз из выбранной звуковой схемы в секундах (по умолчанию от 5 до 10 сек).

 

c = true – дальше перемещаться в присяде (по умолчанию false)

 

r = true – дальше перемещаться бегом (по умолчанию false)

 

d = true – перемещаться в состоянии danger (по умолчанию false)

 

ds = имена_диалогов – имена диалогов, которые разрешено стартовать начиная с этой точки (разрешение действует до следующей точки). Имена задаются в виде текстовой строки, разделенной запятыми: ds=bandits_talk,weather_talk и т.д.

 

ret = число – сразу же по прибытии в точку вызывает зарегистрированный при инициализации movement manager-а callback с этим числом в качестве второго аргумента.

 

w = имя_walk_пути – переводит схему на новый path_walk. Рекомендуется также задать новый path_look с помощью параметра ”l”, иначе текущий path_look будет сброшен. Персонаж идет на стартовую точку с режимом перемещения, заданным в точке с параметром “w”. Настройки функции коллбека при переключении пути сохраняются.

 

l = имя_look_пути - сбросит схему на новый path_look. Задавать параметр “l” нужно вместе с параметром ”w”, иначе “l” будет проигнорирован. По умолчанию path_look при смене path_walk будет сброшен.

 

Флаги пути path_look:

 

p = 100 – вероятность, с которой персонаж посмотрит именно в эту точку. Значения p всех возможных точек суммируются, т.е. если у одной точки p = 100, а у другой 300, то персонаж посмотрит в первую с вероятностью 25%! (т.е. 100 из 400).

Рекомендуется задавать p так, чтобы их сумма составляла 100.

По умолчанию у всех точек p = 100.

 

a = анимация, которую проиграет персонаж, посмотрев в эту точку (по умолчанию idle). Для того, чтобы персонаж стоял в точке без анимации, задайте значение nil: “a=nil”

 

c = true – смотреть в точку в присяде (по умолчанию используется значение одноименного поля из path_walk)

 

d = true – смотреть в точку в состоянии danger (по умолчанию используется значение одноименного поля из path_walk)

 

att = 1 или 2 – номер атаки (основная, вспомогательная). Можно использовать вместо анимации (например ”a=nil|att=1”), можно вместе с анимацией (”a=стреляем_в_потолок|att=1»).

 

t = время, которое персонаж будет ждать, играя анимацию или стреляя (по умолчанию 5000). Если требуется ждать бесконечно долго (например, это финальная точка пути), нужно задать t равным “-1”.

Примечание: если персонаж ждет синхронизации в точке, то он будет играть анимацию столько времени, сколько нужно для того, чтобы дождаться напарников, но только по прибытию всех напарников на точки засечет заданное в ”t” время. Исключение составляет стрельба – персонаж не станет стрелять сразу по прибытию в точку, а сперва дождется напарников, а потом уже начнет стрелять в течение заданного времени.

 

s = имя - звук, который персонаж разово проиграет, посмотрев в эту точку.

 

sp = с какой вероятностью будет проигран звук (по умолчанию 100)

 

sl = имя_прожектора – если задано, то при повороте в указанную точку персонаж также повернет и прожектор в неё.

 

ret = число – после поворота в целевую точку вызывает зарегистрированный при инициализации movement manager-а callback с числом ret в качестве второго аргумента. При этом время ожидания (поле t) игнорируется, т.е. после того как callback вызовет update_movement_state – персонаж сразу же пойдет дальше

 

Изменено пользователем AKKK1
  • Нравится 1
Ссылка на комментарий

AKKK1,

всё это из билда 1935. К сожалению, бОльшая часть этой информации непосредственно не применима к последним билдам. Хотя несомненная польза есть - помогает хоть какие-то идеи получить.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   1 пользователь

  • Куратор(ы) темы:

×
×
  • Создать...