Nazgool 250 Опубликовано 9 Июня 2009 IQDDD на Янтаре поставлен обычный рестриктор с share box и логикой [sr_psy_antenna]. Почитай "Настройка логики", там понятно написано. Добавлено через 7 мин.: Параметр offset отвечает за смещение координат относительно осей. Например если задан shape box, то offset отвечает за поворот этого прямоугольника по осям(соответственно)х,y,z. Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 3 Июля 2009 Подскажите, пожалуйста, как работать с подшаблонами LUА. В официальном мануале написано, что они "сохраняются для дальнейшего использования". А сам процесс их использования для меня так и остался не понятен. Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 28 Августа 2009 ...можно ли задать неписям логику 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. Эта строка нужна для того, чтобы при переходе из оффлайн НПС не попадали в костер и не получали хит, а выходили в этой точке) Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 24 Января 2011 (изменено) ...смысл сообщения был в том, что "значения нет вообще", а не то, что оно равно nil...иногда был вылет в такой ситуации: fun1(fun2()) О, вот и хороший пример. Спасибо. Р.S. При вскрытии luа5.1.dll в сообщениях об ошибках используется словосочитание "no value". Что-то не хватило ума его проэмулировать. Теперь могу :-) ...если нужно вернуть логическое значение - верните nil или false, но не "ничего". И не только в движке встречаются "непонятки". Я не раз попадал в подобные ситуации и в "чистом" Luа. Как раз замена значений, например, объявленных локальных переменных на конкретное значение , прекращало серию "непонятных" ошибок. Так что хочу подтвердить - (конечно ситуация ситуации рознь, но...) лучше используйте какое-либо значение. Изменено 24 Января 2011 пользователем Gun12 Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 24 Января 2011 (изменено) Иногда просматривая примеры логики из ресурсов игры,сталкиваюсь с командами и оверрайдами ,не описаными ни в одном справочнике Там много чего есть непонятного. Когда-то написал скрипт (никаких великих целей не ставил, поэтому потратил на него минут ... несколько), которым просмотрел папки config\scripts и config\misk и выбрал название всех секций и все записи, используемые в каждой из секций. До этого я считал, что знаю достаточно о логике :-) All_sections_SoC Правда писал специально для SciTE, поэтому на расширение не обращайте внимания Да и на значения тоже. Мне главнее были ключи. Изменено 24 Января 2011 пользователем Gun12 Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 12 Февраля 2011 (изменено) 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 Изменено 12 Февраля 2011 пользователем Gun12 Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 26 Марта 2011 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 Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 4 Мая 2011 А если его убрать ничего не будет? Я собственно и ставить его не хотел, но..... Если не знаешь Lua - изучай. Если не хочешь - верь чекеру. Я его писал с использованием стандартной библиотеки Иерусалимски. Т.е. ошибки не придумывал. Конечно можно предположить что при написании кривые руки были у меня и у автора Lua, но только не у тебя. Так? Если не так и если чекер говорит что после return ... должен стоять end, то может быть так оно и есть? Ну а если возникнет вопрос "Почему?", то см. первую строку этого сообщения. Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 5 Мая 2011 (изменено) А кто сказал что rеturn лишний? Может лишнее то, что после него? Всё зависит от того, что именно ты хотел сделать. Но в любом случае метод тыка ("Не хотел ставить, но решил ...") в скриптовнии не проходит. Если уж тебе и захотелось его куда-то присобачить, то необходимо было хоть документацию почитать, чтобы точно знать куда и когда писать. Изменено 5 Мая 2011 пользователем Gun12 Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 31 Мая 2011 TRAMP14 Использование string.find обязательное условие? Если нет, то можно хотя бы так : local name = mob:section() local val = tbl_part.name if val then spawn(val[1], val[2]) end Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 11 Июня 2011 (изменено) draguno Cм. lua_help.script С++ class game_object ... function item_in_slot(number) ... Изменено 11 Июня 2011 пользователем Gun12 Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 20 Августа 2011 (изменено) 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 Изменено 20 Августа 2011 пользователем Gun12 Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 29 Августа 2011 Может кому интересно? Когда-то кто-то (и не один) спрашивал, - "Можно ли приостановить выполнение функции?" Ковырялся в таблице _G СТАЛКЕР-а и наткнулся на поле coroutine и вспомнил тут же про упоминание о coroutine в безымянном файле *.script. В общем проверил. Можно. Если кому нужно - обращайтесь, а если это уже было - удалите, плз, пост. Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 29 Августа 2011 (изменено) 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 мин.: Забыл сказать, что на момент остановки можно получать текущие данные, а в момент запуска-продолжения передавать новые для обработки. Изменено 29 Августа 2011 пользователем Gun12 Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 30 Августа 2011 "Поисследовал" я это дело уже давно, только почему-то убедил себя в том, раз уж нет ни IО, ни DЕВUG, то и СОRОUTINЕ путь заказан. Тут получается так, что основная задача уже не сам факт возможности прерывания выполнения функции, а сохранение и восстановление (после загрузки например) текущего состояния и данных. Хорошо если эти данные простого типа (числа, стринги, булевы значения). А если данные какого-то объекта (или же сам объект), который на момент работы своей очереди выполнения подпрограммы существовал, потом был удалён? И при загрузке текущего состояния нужны будут либо сам объект, либо его данные? Короче, подумаю над этим. Про работу СОRОUTINЕ постараюсь сегодня рассказать подробнее. Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 2 Сентября 2011 Artos Вот что ты мне напомнил ненароком. Нужно внести эту информацию в справочник : coroutine не даёт возможности многопоточности. Подпрограммы выполнятся так же как и обычные функции - в одном потоке. А вот "размазать по времени" вполне можно. Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 5 Сентября 2011 (изменено) В любом справочнике по 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) Изменено 5 Сентября 2011 пользователем Gun12 Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 5 Сентября 2011 Artos Да я вот тоже до сих пор ломаю голову, зачем нужно вот это : elseif type(Mode) == "number" then --//таблица '[idx] = число или стринг' for sValue in sStr:gmatch(sPatt) do tRet[#tRet+1] = tonumber(sValue) or sValue end end Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 6 Сентября 2011 (изменено) 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 Изменено 6 Сентября 2011 пользователем Gun12 Поделиться этим сообщением Ссылка на сообщение
Nazgool 250 Опубликовано 7 Сентября 2011 Artos Наверное следует вспомнить про дедушку Эйнштейна. Если смотреть относительно заранее проинициализированных строками переменных, то простая конкатенация конечно будет работать быстрее, чем tаblе.соnсаt, для использования которого необходимо понести накладные расходы на создание массива. Если же смотреть относительно заранее созданой таблицы с массивом конкатенируемых строк, то быстрее будет tаblе.соnсаt, т.к. расход понесет простая конкатенация, для выполнения которой нужно выбирать значения из таблицы. В общем нужно исходить из конкретных ситуаций. Поделиться этим сообщением Ссылка на сообщение