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

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

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

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  -существует или нет геймвертекс

 

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

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

 

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

[spoiler=Описание класса profile_timer из lua_help]

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())

 

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

 

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

[spoiler=Описание класса client_spawn_manager из lua_help]

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)

 

 

Плагины 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

 

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

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

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

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

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

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

Войти

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

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

    Ни один зарегистрированный пользователь не просматривает эту страницу.

AMK-Team.ru

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