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

Скриптование


Svoboда

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

IQDDD на Янтаре поставлен обычный рестриктор с share box и логикой [sr_psy_antenna]. Почитай "Настройка логики", там понятно написано.

 

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

Параметр offset отвечает за смещение координат относительно осей. Например если задан shape box, то offset отвечает за поворот этого прямоугольника по осям(соответственно)х,y,z.

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


Ссылка на сообщение

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

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


Ссылка на сообщение
...можно ли задать неписям логику Kamp, не используя гулаг...

Можно. Сначала нужно исключить возможность попадания в гулаг. Для этого в логике пишется секция :

[smart_terrains]

none = true

Далее логика пишется таким образом :

[logic]

active = kamp

[kamp]

center_point = *** (***-это имя точки, вокруг которой НПС садятся. Располагать её можно где угодно, не только у костра. Название этой точки должно быть уникальным, т.к. она прописывается в way_"уровень".ltх)

radius = * (*-радиус в метрах от точки center_point, в пределах которого НПС будут садится. Можно не указывать. По умолчанию 2 метра)

path_walk = ***_task (Можно не прописывать, если точка center_point находится не в центре костра. *** - то же название, что и указано в center_point, с добавлением _task. Эта точка тоже прописывается в way_"уровень".ltх, но координаты указываются на некотором расстоянии от center_point. Эта строка нужна для того, чтобы при переходе из оффлайн НПС не попадали в костер и не получали хит, а выходили в этой точке)

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


Ссылка на сообщение
...смысл сообщения был в том, что "значения нет вообще", а не то, что оно равно nil...иногда был вылет в такой ситуации:

fun1(fun2())

О, вот и хороший пример. Спасибо.

Р.S.

При вскрытии luа5.1.dll в сообщениях об ошибках используется словосочитание "no value". Что-то не хватило ума его проэмулировать.

Теперь могу :-)

 

...если нужно вернуть логическое значение - верните nil или false, но не "ничего".

 

И не только в движке встречаются "непонятки". Я не раз попадал в подобные ситуации и в "чистом" Luа.

Как раз замена значений, например, объявленных локальных переменных на конкретное значение , прекращало серию "непонятных" ошибок.

Так что хочу подтвердить - (конечно ситуация ситуации рознь, но...) лучше используйте какое-либо значение.

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

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


Ссылка на сообщение
Иногда просматривая примеры логики из ресурсов игры,сталкиваюсь с командами и оверрайдами ,не описаными ни в одном справочнике

Там много чего есть непонятного.

Когда-то написал скрипт (никаких великих целей не ставил, поэтому потратил на него минут ... несколько), которым просмотрел папки config\scripts и config\misk и выбрал название всех секций и все записи, используемые в каждой из секций.

До этого я считал, что знаю достаточно о логике :-)

All_sections_SoC

Правда писал специально для SciTE, поэтому на расширение не обращайте внимания

Да и на значения тоже. Мне главнее были ключи.

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

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


Ссылка на сообщение

TRAMP14

Тебе же выше уже объяснили почему не работает.

 

А теперь вот что.

Допустим ты без костюма и статик не установлен.

(Смотрим в любой из функций)

1. Одеваешь костюм :

if item_in_slot ~= nil then -- Истина (костюм уже надет - не равен NIL)

...

if cs == nil then -- Истина (статик пока не установлен)

hud:AddCustomStatic("okul", true) --установить статик

2. Снимаешь костюм :

if item_in_slot ~= nil then -- Ложь (Слот уже пуст - равен NIL)

...

end

end -- функция отработала, НО !

Костюм уже снят, а кто статик будет удалять?

 

Ну и наконец, даже если бы работало, то всё это получилось достаточно затратно в ресурсах.

Можно сделать не только одной функцией, но и оптимизировать. Например :

function HandlerStatic()
    local hud = get_hud()
    local item_in_slot = db.actor:item_in_slot(6)
    local cs
    --Если установлен хотя бы один из статиков, задать переменной "cs" значение, отличное от "лжи"
    if hud:GetCustomStatic("nov_outfit") then
        cs = "nov_outfit"
    elseif hud:GetCustomStatic("okul") then
        cs = "okul"
    elseif hud:GetCustomStatic("protivgaza") then
        cs = "protivgaza"
    elseif hud:GetCustomStatic("shlem") then
        cs = "shlem"
    end
    -- Проверить, надет ли броник...
    if item_in_slot then -- если надет...
        if cs then return end -- ...и есть статик - прекратить работу функции
        local item_section = item_in_slot:section()
        if  item_section == "specops_outfit" or item_section == "military_outfit" then
            cs = "nov_outfit"
        elseif item_section == "outfit_exo_m1" or item_section == "exo_outfit" then
            cs = "protivgaza"
        elseif item_section == "dolg_scientific_outfit" or item_section == "ecolog_outfit" or
               item_section == "protection_outfit" or item_section == "scientific_outfit" then
            cs = "okul"
        else cs = "nov_outfit" -- предполагаю что тут все остальные костюмы. Может ошибаюсь.
        end
        -- если надет и нет статика, то установить статик
        hud:AddCustomStatic(cs, true)
    elseif not cs then return -- если броник не надет и нет статика, то прекратить работу функции
    else -- если броник не надет и есть статик, то удалить статик
        hud:RemoveCustomStatic(cs)
    end
end

 

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

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


Ссылка на сообщение

TRAMP14

В принципе всё верно, и хотя в таблице мало полей, я бы всё-таки после функции спавна поставил break :

if  common == k then
    alife():create(v, pos, lv, gv, id)
    break
end

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

 

Как вариант можно сделать и без pairs.

local tbl = {bandit = "medkit", stalker = "antirad", killer = "vodka"}
local item = tbl[common]
if item then
    alife():create(item, pos, lv, gv, id)
end

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


Ссылка на сообщение
А если его убрать ничего не будет? Я собственно и ставить его не хотел, но.....

Если не знаешь Lua - изучай. Если не хочешь - верь чекеру.

Я его писал с использованием стандартной библиотеки Иерусалимски. Т.е. ошибки не придумывал.

Конечно можно предположить что при написании кривые руки были у меня и у автора Lua, но только не у тебя. Так?

Если не так и если чекер говорит что после return ... должен стоять end, то может быть так оно и есть?

Ну а если возникнет вопрос "Почему?", то см. первую строку этого сообщения.

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


Ссылка на сообщение

А кто сказал что rеturn лишний? Может лишнее то, что после него?

Всё зависит от того, что именно ты хотел сделать.

Но в любом случае метод тыка ("Не хотел ставить, но решил ...") в скриптовнии не проходит.

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

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

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


Ссылка на сообщение

TRAMP14

Использование string.find обязательное условие? Если нет, то можно хотя бы так :

local name = mob:section()
local val = tbl_part.name
if val then
    spawn(val[1], val[2])
end

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


Ссылка на сообщение

draguno

Cм. lua_help.script

С++ class game_object

...

function item_in_slot(number)

...

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

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


Ссылка на сообщение

Ulman

Хотел подробнее?...

Оператор for определяет цикл, который выполняет блок кода, до тех пор, пока переменная(ые) этого цикла не достигнет некоего значения (об этом ниже).

В lua существует две формы записи оператора for.

 

1. Простая форма. Блок кода выполняется до тех пор, пока переменная цикла, изменяющаяся в арифметической прогрессии, не достигнет установленного порога

for i=1,10,1 do
...
end

for - оператор, определяющий начало цикла.

 

i - переменная цикла. Эта переменная является локальной для данного цикла. Т.е обьявлять её специально (local i) не нужно. Из того как ты задал вопрос скажу, что имя этой переменной можно задавать абсолютно любое, хоть матом, но только согласно синтаксиса Lua.

 

1,10,1 - для переменной i устанавливаются пороги значений

1 - счёт начинается с единицы

10 - счёт заканчивается при достижении значения 10 (включительно)

1 - шаг счёта В данном примере переменной i будет последовательно присвоены все значения от 1 до 10, т.е. цикл отработает 10 раз. Если установить шаг, например, в значение 2, то переменной i, при каждом обороте цикла будет присваиваться каждое второе значение,относительно предыдущего. Т.е. значения переменной будут равны 1,3,5,7 и 9 - цикл отработает 5 раз. Если это значение не указать (for i=1,10 dо), то оно по умолчанию будет равно 1.

 

do - начало блока

 

end - конец блока

 

... - То, что между do и end называется телом блока. Это тело, собственно, и будет выполняться столько раз, сколько указано в пределах значений. Например если в данном примере вместо "..." записать alife():create(bla_bla), то этих самых "bla_bla" заспавниться 10 штук.

 

Считать можно и в обратном порядке. Например от 10 до 1 :

for i=10,1,-1 do
...
end

В этом случае шаг (-1) указывать обязательно

 

2. Расширенная форма (твой вопрос). На каждом обороте для получения нового значения переменной цикла вызывается функция-итератор. Цикл заканчивается, когда итератор возвратит nil.

for var in func() do
...
end

for - оператор, определяющий цикл

var - переменная цикла (локальная для данного цикла)

func() - любая функция, которая возвращает функцию-итератор, находящуюся внутри неё.

 

На каждом шаге этого цикла вызывается входящая в func() функция-итератор, которая в свою очередь возвращает некоторое значение или nil. Если возвращенное значение – nil, то выполнение цикла прекращается, в противном случае значение записывается в переменную цикла (var). Затем выполняется тело блока, и весь процесс повторяется.

Функция-итератор может возвращать и множество значений (столько, сколько заложил в неё программист), поэтому правильнее записать так :

for var1, var2, ..., varN in func() do
...
end

Функцию func() можно написать и самому, но в стандартной библиотеке lua уже есть готовые функции для работы с таблицами (pairs, ipairs, insert и т.д.)

В твоём вопросе используется одна из таких функций - pairs.

Эта функция возвращает функцию-итератор next (которая, кстати, тоже входит в состав стандартной библиотеки lua).

Вот эта самая next и присваивает найденные значения переменным var1...varN.

Сама функция next при каждом обороте возвращает только два значения, соответствующие ключу и значению в некой, передаваемой в функцию pairs, таблице.

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

for k, v
for n, c
for inum, infop

В первую указанную переменную записывается ключ таблицы, во вторую её значение.

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

for key in pairs(t) do
...
end

Дальше в качестве факультатива. Покажу эту спрятанную функцию-итератор.

Для итерирования по элементам массива существует стандартная функция ipairs

Она перебирает элементы таблицы начиная с ключа под номером 1.

local t = {'a', 'b', 'c'}
for k,v in ipairs(t) do
    print(k,v)
end

Данный код напечатает следующее :

1 a
2 b
3 c

Напишем итератор, который будет перебирать элементы в обратном порядке :

function bpairs(table)
    local count = #table + 1
    return  function ()
                count = count - 1
                if table[count] then
                    return count, table[count]
                end
            end
end

Как видишь функция bpairs возвращает (return) анонимную функцию. Она и есть итератор.

Теперь проверим :

for k,v in bpairs(t) do
    print(k,v)
end

В результате :

3 c
2 b
1 a

 

 

 

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

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


Ссылка на сообщение

Может кому интересно?

 

Когда-то кто-то (и не один) спрашивал, - "Можно ли приостановить выполнение функции?"

Ковырялся в таблице _G СТАЛКЕР-а и наткнулся на поле coroutine и вспомнил тут же про упоминание о coroutine в безымянном файле *.script.

В общем проверил. Можно.

Если кому нужно - обращайтесь, а если это уже было - удалите, плз, пост.

 

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


Ссылка на сообщение

Artos

Не знаю, писать ли тутор, или по ходу дела будет видно.

Coroutine мало кому известны, поэтому покажу как проверял, а потом уже, наверное, будут вопросы, ответы на которые и введут в курс дела.

Хотя не уверен что кому-то понадобиться.

 

Пошел по самому быстрому пути (несчастный bind_stalker :) ). Решил для наглядности прерывать цикл.

В качестве "генератора" вызовов использовал не менее несчастный "update(delta)".

Каждые 5 секунд прерывал работу цикла и затем снова продолжал:

.....
co = coroutine.create(function (a)
                          for i=1,10 do
                              coroutine.yield(a+i)
                          end
                      end)
                        
local ttt  = time_global()

function actor_binder:update(delta)
    if time_global() - ttt >= 5000 then
        if coroutine.status(co) ~= "dead" then
            local _, result = coroutine.resume(co, 5)
            if result then
                news_manager.send_tip(db.actor, result)
            end
        end
        ttt = time_global()+5000
    end
.....

В результате каждые 5 секунд выводились сообщение 5,6,7,8 ... 15.

Прошу заметить, что целью было не осуществление перебора (для этого есть более простые способы).

Смысл coroutine в том, что (например) при первом обороте цикл останавливается, и ждёт до тех пор, пока не произойдёт следующий вызов. Игра идёт своим чередом дальше.

и вызывать можно хоть отсюда. хоть из другого скрипта - не важно. Важно задать имя подпрограммы (co) глобально, чтобы была возможность последующего вызова из любого скрипта.

 

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

Забыл сказать, что на момент остановки можно получать текущие данные, а в момент запуска-продолжения передавать новые для обработки.

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

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


Ссылка на сообщение

"Поисследовал" я это дело уже давно, только почему-то убедил себя в том, раз уж нет ни IО, ни DЕВUG, то и СОRОUTINЕ путь заказан.

Тут получается так, что основная задача уже не сам факт возможности прерывания выполнения функции, а сохранение и восстановление (после загрузки например) текущего состояния и данных.

Хорошо если эти данные простого типа (числа, стринги, булевы значения).

А если данные какого-то объекта (или же сам объект), который на момент работы своей очереди выполнения подпрограммы существовал, потом был удалён? И при загрузке текущего состояния нужны будут либо сам объект, либо его данные?

Короче, подумаю над этим.

Про работу СОRОUTINЕ постараюсь сегодня рассказать подробнее.

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


Ссылка на сообщение

Artos

Вот что ты мне напомнил ненароком. Нужно внести эту информацию в справочник :

 

coroutine не даёт возможности многопоточности. Подпрограммы выполнятся так же как и обычные функции - в одном потоке.

 

А вот "размазать по времени" вполне можно.

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


Ссылка на сообщение

В любом справочнике по luа. В сети их не так уж и мало.

Правда сухие фразы определений это плохой помощник для новичка.

Может прийдет вдохновение - напишу подробнее.

 

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

ИМХО, раз что-то задано - то это должно иметь приоритет над дефолтными установками. Заодно можно добавить контроль заданных стрингов для сепаратора и/или патерна (порой и это желательно).

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

И если я сам пишу код, то наверняка знаю что, куда и как писать. И зачем мне думать, что кто-то там полезет в него и накосячит. Я, например, могу пожертвовать этим ради скорости. Не знают - нечего лезть.

 

Т.е. вот это :

local sPatt = '[%w%_]+' --/ дефолтный патерн (разделение по 'словам')
  --/ если задан сепаратор: разделяем по сепаратору
  if type(sDiv) == "string" then
    sPatt = '%s*([^'..sDiv..']+)%s*' --/ по разделителю (исключая начальные и заключительные пробелы)
  --/ если указан шаблон: используем шаблон
  elseif type(sPattern) == "string" then
    sPatt = sPattern
  end

Я записал бы так (пусть, например, паттерн будет приоритетнее сепаратора):

local sPatt = sPattern or sDiv and '%s*([^'..sDiv..']+)%s*' or '[%w%_]+'

А если уж ставил бы проверки, то тотальные.

Первой же строкой что-то типа :

if not sStr then return '' end

sDiv экранировать спец. символы (вдруг кто-то забыл, не знал)

sPattern в локальной функции сделал бы проверку на корректность составления паттерна (то, что я до сих пор не внёс в script Syntax Checker)

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

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


Ссылка на сообщение

Artos

Да я вот тоже до сих пор ломаю голову, зачем нужно вот это :

elseif type(Mode) == "number" then --//таблица '[idx] = число или стринг'
        for sValue in sStr:gmatch(sPatt) do
        tRet[#tRet+1] = tonumber(sValue) or sValue
        end
    end

 

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


Ссылка на сообщение

singapur22

Поступил по твоей аналогии и заключил все варианты в функции.

Оставил общую таблицу как "точку отсчёта".

a = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaa" --100 символов
b = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbb" --100 символов
c = "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
cccccccccccccccccccccccc" --100 символов
d = "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
dddddddddddddddddddddddd" --100 символов
e = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeee" --100 символов

tb = {a, b, c, d, e} -- общая для всех таблица

function f_t(tb)
    t = os.clock()
    local q
    for i=1, 1000000 do
        q = table.concat(tb)
    end
    t2 = os.clock() - t
    print("table", t2)
end

function f_c(a,b,c,d,e)
    t = os.clock()
    local q
    for i=1, 1000000 do
        q = a..b..c..d..e
    end
    t2 = os.clock() - t
    print("concat", t2)
end

function f_f(...)
    t = os.clock()
    local q
    for i=1, 1000000 do
        q = string.format("%s%s%s%s%s", ...)
    end
    print("format", os.clock() - t)
end

f_t(tb)
f_c(unpack(tb))
f_f(unpack(tb))

Ускорилось. Теперь показания выглядят так :

table     0.921
concat    0.594
format    1.344

 

 

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

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


Ссылка на сообщение

Artos

Наверное следует вспомнить про дедушку Эйнштейна.

Если смотреть относительно заранее проинициализированных строками переменных, то простая конкатенация конечно будет работать быстрее, чем tаblе.соnсаt, для использования которого необходимо понести накладные расходы на создание массива.

Если же смотреть относительно заранее созданой таблицы с массивом конкатенируемых строк, то быстрее будет tаblе.соnсаt, т.к. расход понесет простая конкатенация, для выполнения которой нужно выбирать значения из таблицы.

В общем нужно исходить из конкретных ситуаций.

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


Ссылка на сообщение
  • Недавно просматривали   0 пользователей

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