Перейти к содержанию
Arkada

Полезные функции для скриптов сталкера

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

 

Полезные функции для скриптов сталкера.
Автор темы: liner

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

Если вы используете материал из этой темы, то пожалуйста, не удаляйте копирайты и оставляйте благодарность автору(ам), ведь это элементарная этика модостроения!

 

Спойлер

Платформы: СS, CoP
Автор: liner

--Есть ли у НПС все заданные предметы?
--число предметов не ограничено

function has_items(npc,...) --секции предметов
    local t = {...}
    local function calc(q,itm)
        local sect = itm:section()
        for k,v in pairs(t) do
            if sect == v then
                v = nil
                return
            end
        end
    end

    npc:iterate_inventory(calc)
    return table.getn(t) == 0 --все элементы таблицы должны быть nil
end

Как использовать:
has_items(db.actor,"medkit","bandage","wpn_pm")                    <CAI_Stalker*, ...<string>>


Спойлер

Платформы: SoC (под сомнением), CS, CoP
Автор: Suhar_
Функция удаляет из инвентаря непися несколько предметов

function remove_item_count(who, item_section, count)
    local current_count = count
    local function remove(tmp, item)
        if item:section()==item_section and (current_count>0) then
            current_count = current_count - 1
            -- Переходим от игрового объекта к серверному объекту через его айди
            -- Удаляем серверный объект

            alife():release(alife():object(item:id()), true)
        elseif current_count<=0 then
            return
        end
    end

    who:iterate_inventory(remove)
end

Как использовать:
remove_item_count(нпс_или_актор, секция_предмета_который_будем_удалять, сколько_штук_удалить)
<CGameObject*,string,number>


Спойлер

Платформы: SoC, CS, CoP
Автор: liner
Прочитать из секции в каком-то файле строчку, и, если этой строчки/секции не существует, вернуть значение по умолчанию, которое задаётся пользователем. Иначе функция вернёт то, что прочитала из секции.

ВНИМАНИЕ!!! ДЛЯ ЭТОЙ ФУНКЦИИ НУЖНО ПОДКЛЮЧИТЬ ФУНКЦИЮ toboolean. ОНА В ЭТОЙ ТЕМЕ!!!

function READ_EX(r_type,sect,what,default_val,ini)
    if not ini then
        ini = system_ini()
    end
    if not ini:section_exist(sect) or not ini:line_exist(sect,what) then
        return default_val
    end --если до сюдова, значит есть нужные параметры
    if r_type == "number" then
        return ini:r_u32(sect,what)
    elseif r_type == "string" then
        return ini:r_string(sect,what)
    elseif r_type == "float" then
        return ini:r_float(sect,what)
    elseif r_type == "bool" then
        return
toboolean(ini:r_string(sect,what))
    elseif r_type == "s32" then
        return
ini:r_s32(sect,what)
    else
        return nil
    end
end


Как использовать:
                                                                                                            (НЕОБЯЗАТЕЛЬНО)             (НЕОБЯЗАТЕЛЬНО)
READ_EX(тип,чтения, секция, какую_строчку_прочитать, значение_по_умолчанию, файл_из_которого_будем_читать)
<string,string,string,any,CIniFile*>
READ_EX("float", "damage_head_40", "bip01_neck", 0.5) --Если в секции damage_head_40 есть строчка bip01_neck, то функция вернёт значение этой строчки, а иначе заданное значение по умолчанию 0.5


Спойлер

Платформы: SoC, CS, CoP
Автор: liner
Зафиксировать число между двумя диапазонами
Если число не входит в диапазон, то это число становится минимальным числом диапазона, если оно было меньше минимума, и, соответственно, максимум - если исходное число больше максимума.


function clamp(value, min, max)
    if min ~= nil and value<min then
        return min
    elseif max ~= nil and value>max then
        return max
    end
    return value
end

Как использовать:
clamp(исходное_число,минимум (необязательно),максимум (необязательно))          <number,number,number>
clamp(7.7, 6.02, 7.5)          --output: 7.5
clamp(14,15,16)                 --output: 15
clamp(0,8)                           --output: 8
clamp(-3,nil,-5)                    --output: -5


Спойлер

Платформы: SoC (под сомнением), CS, CoP
Автор: makdm, liner
Вывести нужный текст чуть выше центра экрана с заданным временем его исчезновения

local a_show = true
function HudMsg(text_center, sTime) --Copyright makdm, liner
    if sTime == nil then sTime = 5 end
    local hud = get_hud()
    local timer_text = time_global() + sTime*1000
    if a_show == true then
        a_show = false
        hud:HideActorMenu()
        local cs_text = hud:GetCustomStatic("not_enough_money_mine")
        if cs_text then
            hud:RemoveCustomStatic("not_enough_money_mine")
        end
        hud:AddCustomStatic("not_enough_money_mine", true)
        cs_text = hud:GetCustomStatic("not_enough_money_mine")
        cs_text:wnd():TextControl():SetText(game.translate_string(text_center))
        level.add_call(
            function ()
            if timer_text < time_global() then
                return true
            end
            end
,
            function ()
                hud:RemoveCustomStatic("not_enough_money_mine")
                a_show = true
            end
        )
    end
end


Как использовать:
HudMsg(стринг_ид_текста_который_нужно_вывести, время_показа_в_секундах)         <string,number>


Спойлер

Платформы: SoC, CS, CoP
Автор: liner

function give_item(sect,count)
    if count==nil or count == 1 then
        return alife():create(sect,db.actor:position(),db.actor:level_vertex_id(),db.actor:game_vertex_id(),ACT_ID)
    else
        local act = db.actor
        local pos,lv,gv,id = act:position(),act:level_vertex_id(),act:game_vertex_id(),act:id()
        for i=1, count do
            alife():create(sect,pos,lv,gv,id)
        end
    end
end


Как использовать:
give_item(секция_предмета, количество_которое_надо_заспаунить(необязательно, по умолчанию 1))      <string,number>


Спойлер

Платформы: SoC, CS, CoP
Автор: liner

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

function LOADVOID(funct, ...)
    return loadstring(tostring(funct))(...)
end

Как использовать:
LOADVOID(имя_функции, аргументы_которые_нужно_передать_в_функцию (НЕОБЯЗАТАЛЬЕНО))   <string, any>
LOADVOID("sim_squad_scripted.init()", true)          --эквивалентно коду: sim_squad_scripted.init(true)


Спойлер

Платформы: CS, CoP
Автор: Suhar_
Добавить метку на объект по его ID на карту (пда и/или миникарту, зависит от настроек спота)

function add_spot_on_map(obj_id, location_name, descr)
    if level.map_has_object_spot(obj_id,location_name)==0 then
        if descr==nil then
            descr=""
        end
        level.map_add_object_spot_ser(obj_id, location_name, descr)
    end
end

Как использовать:
add_spot_on_map(ID объекта, имя_спота, описание_спота(необязательно))           <number,string,string>
add_spot_on_map(3280, "alife_secondary_presentation_stalker", game.translate_string("st_squad_spot_descr"))


Спойлер

Платформы: SoC, CS, CoP
Автор: liner
Посчитать количество заданных символов в строке

function calc_symbols(str,symbol)
    local n = 0
    for s in str:gmatch(symbol) do
        n = n + 1
    end
    return n
end

Как использовать:
calc_symbols(текст, символы_в_тексте_которые_надо_посчитать)          <string,string>
calc_symbols("abc inferno base", "a")                   --output: 2


Спойлер

Платформы: SoC, CS, CoP
Автор: liner
Преобразовать аргумент в булеан (true или false).
ВНИМАНИЕ!!! ДЛЯ ЭТОЙ ФУНКЦИИ НУЖНО ПОДКЛЮЧИТЬ ФУНКЦИЮ string.filter. ОНА В ЭТОЙ ТЕМЕ!!!
function toboolean(arg)
    if arg ~= nil then
        if type(arg) == "string" then
            arg = string.filter(arg) --убираем все отступы и пробелы из строки
        end
        if arg=="true" or tonumber(arg) == 1 or arg == "on" or arg == true then return true end
        if arg=="false" or tonumber(arg) == 0 or arg == "off" or arg == false then return false end
    end
    return nil
end


Как использовать:
toboolean(любой аргумент типа bool или number или string)
toboolean(1)        --output: true
toboolean("0")     --outpit: false
toboolean(nil)      --output: nil


Спойлер

Платформы: SoC, CS, CoP
Автор: Suhar_

Распарсить строку через символ "запятая"

ВНИМАНИЕ!!! ДЛЯ ЭТОЙ ФУНКЦИИ НУЖНО ПОДКЛЮЧИТЬ ФУНКЦИЮ string.explode. ОНА В ЭТОЙ ТЕМЕ!!!
function parse_by_comma(s)
    s = string.gsub(s," ", "") --удаляем пробелы
    s = string.gsub(s,"    ", "") --удаляем табуляции
    s = string.explode(",", s, false)
    return s
end

Как использовать:
parse_by_comma(текст)          <string>
parse_by_comma("s,u,b,b")       --output: таблица вида
--{
--    [1] = "s",
--    [2] = "u",
--    [3] = "b",
--    [4] = "b"
--}


Спойлер

Платформы: SoC, CS, CoP
Автор: Bak
Разбить строку на элементы с помощью специального ключа

ВНИМАНИЕ!!! ДЛЯ ЭТОЙ ФУНКЦИИ НУЖНО ПОДКЛЮЧИТЬ ФУНКЦИЮ trim. ОНА В ЭТОЙ ТЕМЕ!!!
function string.explode(div,str,clear)
    local t={}
    local cpt = string.find(str,div,1,true)
    if cpt then
        repeat
            if clear then
                table.insert(t,trim(string.sub(str,1,cpt-1)))
            else
                table.insert(t,string.sub(str,1,cpt-1))
            end
            str = string.sub(str,cpt+string.len(div))
            cpt = string.find(str,div,1,true)
        until cpt==nil
    end
    if clear then
        table.insert(t,trim(str))
    else
        table.insert(t,str)
    end
    return t
end

Как использовать:

string.explode(специальный ключ, строка, булеан использовать ли функцию trim)     <string,string,boolean>
string.explode("$", "el1$el2$el3&&@#&@&$null")          --output: таблица вида
--{
--   [1] = "el1",
--   [2] = "el2",
--   [3] = "el3&&@#&@&",
--   [4] = "null"
--}


Спойлер

Платформы: SoC, CS, CoP
Автор: ??? (утерян)

Удаление пробелов в начале и конце строки
function trim(s)
    return(string.gsub(s,"^%s*(.-)%s*$","%1"))
end
Как вызывать:

trim(текст)                      <string>
trim(" аболтус   !   ")         --output:аболтус   !


Спойлер

Автор функции: liner
Платформы: SoC, CS, CoP
Среднее арифметическое чисел (aср = a1 + a2+ a3 +... : n, где n - количество чисел)

function math.avr(...)
    local t = {...}
    local sum = 0
    for _,v in pairs(t) do
        sum = sum + v
    end
    return sum / #t
end

Как использовать:
math.avr(любые числа)                     <number>
math.avr(3, 5, 18, 30) --output: 14


Спойлер

Платформы: SoC, CS, CoP
Автор: liner

Получить тип данных аргумента. Внимание! Возвращаемый тип данных зависит ОТ ЗНАЧЕНИЯ ЧИСЛА!!!
ВНИМАНИЕ!!! У ФУНКЦИИ ЕСТЬ СУЩЕСТВЕННЫЙ МИНУС: ФУНКЦИЯ НИКОГДА НЕ ВЕРНЁТ "<float>", ПОТОМУ ЧТО Я НЕ ЗНАЮ, КАК ЭТО СДЕЛАТЬ БЕЗ math.type (а эта функция с версии Lua 5.3)!

function typeid(arg)
    local t = type(arg)
    if t == "string" then
        return "<string>"
    elseif t == "boolean" then
        return "<bool>"
    elseif t == "number" then
--liner: available since version Lua 5.3 ((
--        if math.type(arg) == "float" then
--            return "<float>"
--        end

        --unsigned integer
        if arg >= 0 then
            if arg <= 255 then
                return "<u8>"
            elseif arg <= 65535 then
                return "<u16>"
            elseif arg <= 4294967295 then
                return "<u32>"
            end
        --signed integer
        elseif arg >= -2147483648 and arg < -32768 then
            return "<s32>"
        elseif arg >= -32768 and arg < -128 then
            return "<s16>"
        elseif arg >= -128 then
            return "<s8>"
        end
    elseif t == "table" then
        return "<table>"
    elseif t == "userdata" then
        return "<object>"
    end
    return "<undefined>" --default
end

Как использовать:
typeid(любой один аргумент)
typeid(7)                 --output: <u8>
typeid(256)            --output: <u16>
typeid({1234, 2458, "sl"})            --output: <table>
И тому подобное...


Спойлер

Автор: liner
Платформы: SoC (под сомнением), CS, CoP

Комплексный вызов функции с доп. аргументами для функции (полное название: complex call with settings)
данная функция вызывает переданную функцию несколько раз с теми аргументами,
которые были переданы в ... и передаёт ещё дополнительно во все функции аргументы
из настройки_передачи.

_cjm = "`" --Эту переменную нужно объявить в _G, если cws_call используется повсеместно.
function cws_call(funct,settings,...)
    local t = {...}
    local s_size = #settings --кэшируем размер таблицы
    local lst = 1
    for i = 1, #t do
        if t == _cjm then
            local ct = {}
            for j = lst, i-1 do
                table.insert(ct,t[j])
            end
            for j = 1, s_size do
                table.insert(ct,settings[j])
            end
            lst = i + 1
            funct(select(1,unpack(ct)))
        end
    end
    local ct = {select(lst,...)}
    for j = 1, s_size do
        table.insert(ct,settings[j])
    end
    funct(select(1,unpack(ct)))
end

Как использовать:
cws_call(ссылка на функцию,{настройки_передачи},аргументы)               <function, table, ...>
cws_call(print,{"THIRD ARGUMENT","end"}, 1,_cjm,"GO!",0,0)

Где _cjm - разделитель, до него все аргументы будут переданы в функцию (в данном
случае это print)

Прошлый cws_call эквивалентен коду:
print(1,"THIRD ARGUMENT","end")
print("GO!",0,0,"THIRD ARGUMENT","end")

Изменено пользователем liner
  • Лайк 4
  • Мастер! 7
  • Спасибо 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
 
Спойлер

Автор: Suhar_

string.filter = function (str)
    str = string.gsub(str, " ", "") --пробелы
    str = string.gsub(str, "    ", "") --табуляция
    return str
end

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
 
Спойлер

Автор: liner
Платформы: SoC, CS, CoP
ВНИМАНИЕ! ДЛЯ РАБОТЫ КОДА НИЖЕ НУЖНА ФУНКЦИЯ parse_by_comma. ОНА В ЭТОЙ ТЕМЕ!
Описание: через скрипт выдать несколько предметов при использовании предмета.
Для того, чтобы этот скрипт сработал, нужно:
1. Скопировать вот этот блок кода
 


--Создать предметы для актёра
	--Задавать нужно в виде:
	--give = medkit,2,bandage,1 (две аптечки, один бинт)
	--или
	--give = medkit,bandage (одна аптечка, один бинт)
	--единичку можно не писать.
	local sect = obj:section()
	if system_ini():line_exist(sect,"give") then
		local p = parse_by_comma(system_ini():r_string(sect,"give"))
		local t_items = {}
		for i = 1, #p do
			if not tonumber(p[i]) then
				t_items[i] = {p[i],tonumber(p[i+1]) or 1}
			end
		end
		local pos, lvid, gvid, sim = db.actor:position(),db.actor:level_vertex_id(),db.actor:game_vertex_id(), alife()
		for i,v in pairs(t_items) do
			for j = 1, v[2] do
				sim:create(v[1],pos,lvid,gvid,0)
			end
		end
	end

2. Вставить в скрипт bind_stalker в метод use_inventory_item в самый конец блока кода (перед последним end) скопированное
3. В конфиге прописать нужные параметры. Например, для тестов я делал:
В секции [medkit] прописал следующее:
СНИЗУ СИНТАКСИС
give = bandage, 2
Мне выдалось два бинта.
give = bandage,antirad,wpn_pm
Мне выдалось: бинт, антирад, и ПМ.

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

 

Изменено пользователем liner
  • Мастер! 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
 

Не кисло.

  • Печаль 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

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

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу