Это популярное сообщение. Zander_driver 10 333 Опубликовано 21 Августа 2015 Это популярное сообщение. Поделиться Опубликовано 21 Августа 2015 (изменено) Раньше в этой теме находились всякие полезности. Соответствующие определенным правилам и требованиям, которые были указаны в шапке. Но т.к. со временем в тему стали постить материалы не соответствующие этим требованиям - шапка более не имеет смысла. В старых постах еще может быть что-то полезное, в новых по всей видимости - вряд ли. Изменено 1 Декабря 2021 пользователем Zander_driver Привел в соответствие современным реалиям. 2 4 4 12 Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine. Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист. AMD Ryzen 9 7950X (16 ядер, 32 потока, 5.75 ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD. Ссылка на комментарий
RayTwitty 492 Опубликовано 23 Сентября 2015 Поделиться Опубликовано 23 Сентября 2015 (изменено) https://yadi.sk/d/4EUvTWhzdnAve https://yadi.sk/d/wzSTaTNVh8Eeb Документация Lua от Nazgool. Какая из версий актуальная - не знаю. З.Ы. когда же люди научатся оформлять и правильно выкладывать свои работы, а не только писать их?.. Изменено 23 Сентября 2015 пользователем RayTwitty 1 Ссылка на комментарий
Serge! 127 Опубликовано 23 Сентября 2015 Поделиться Опубликовано 23 Сентября 2015 Внесу и свои три копейки) не уверен, что требуются такие сложности (свои классы и т.д. и т.п.), в реальной жизни все, как правило, намного проще...К примеру, имеем таблицу соответствия кодов символов разных раскладок, типаtbl_code = {[097] = 244, -- a --> ф[098] = 232, -- b --> и...}имеем языковой флаг режима ввода текста, типаmode_lang = true -- false - Eng; true - Руси дале просто при вводе проверяем и добавляем в строку либо английский, либо русский символif mode_lang then str = str.. string.char(tbl_code[csim])else str = str.. string.char(csim) endпри переключении режима ввода (варианты самые различные: от кнопок до "горячих" клавиш), просто переключаем флагmode_lang = not mode_lang 1 1 Ссылка на комментарий
abramcumner 1 148 Опубликовано 23 Сентября 2015 Поделиться Опубликовано 23 Сентября 2015 З.Ы. когда же люди научатся оформлять и правильно выкладывать свои работы, а не только писать их?.. http://www.amk-team.ru/forum/index.php?showtopic=11584 Куда уж правильней Ссылка на комментарий
Serge! 127 Опубликовано 23 Сентября 2015 Поделиться Опубликовано 23 Сентября 2015 Почему идея? Я таким пользуюсь. Чтобы не творить велосипед, вот полная таблица перекодировки. А остальное? Вы же все профи. Все вопросы по ограничению к DS. local tbl_ansii = { [ 039 ] = 253, -- ' --> э [ 044 ] = 225, -- , --> б [ 046 ] = 254, -- . --> ю [ 047 ] = 046, -- / --> . [ 058 ] = 198, -- : --> Ж [ 059 ] = 230, -- ; --> ж [ 060 ] = 193, -- < --> Б [ 062 ] = 222, -- > --> Ю [ 065 ] = 212, -- A --> Ф [ 066 ] = 200, -- B --> И [ 067 ] = 209, -- C --> С [ 068 ] = 194, -- D --> В [ 069 ] = 211, -- E --> У [ 070 ] = 192, -- F --> А [ 071 ] = 207, -- G --> П [ 072 ] = 208, -- H --> Р [ 073 ] = 216, -- I --> Ш [ 074 ] = 206, -- J --> О [ 075 ] = 203, -- K --> Л [ 076 ] = 196, -- L --> Д [ 077 ] = 220, -- M --> Ь [ 078 ] = 210, -- N --> Т [ 079 ] = 217, -- O --> Щ [ 080 ] = 199, -- P --> З [ 081 ] = 201, -- Q --> Й [ 082 ] = 202, -- R --> К [ 083 ] = 219, -- S --> Ы [ 084 ] = 197, -- T --> Е [ 085 ] = 195, -- U --> Г [ 086 ] = 204, -- V --> М [ 087 ] = 214, -- W --> Ц [ 088 ] = 215, -- X --> Ч [ 089 ] = 205, -- Y --> Н [ 090 ] = 223, -- Z --> Я [ 091 ] = 245, -- [ --> х [ 093 ] = 250, -- ] --> ъ [ 097 ] = 244, -- a --> ф [ 098 ] = 232, -- b --> и [ 099 ] = 241, -- c --> с [ 100 ] = 226, -- d --> в [ 101 ] = 243, -- e --> у [ 102 ] = 224, -- f --> а [ 103 ] = 239, -- g --> п [ 104 ] = 240, -- h --> р [ 105 ] = 248, -- i --> ш [ 106 ] = 238, -- j --> о [ 107 ] = 235, -- k --> л [ 108 ] = 228, -- l --> д [ 109 ] = 252, -- m --> ь [ 110 ] = 242, -- n --> т [ 111 ] = 249, -- o --> щ [ 112 ] = 231, -- p --> з [ 113 ] = 233, -- q --> й [ 114 ] = 234, -- r --> к [ 115 ] = 251, -- s --> ы [ 116 ] = 229, -- t --> е [ 117 ] = 227, -- u --> г [ 118 ] = 236, -- v --> м [ 119 ] = 246, -- w --> ц [ 120 ] = 247, -- x --> ч [ 121 ] = 237, -- y --> н [ 122 ] = 255, -- z --> я [ 123 ] = 213, -- { --> Х [ 125 ] = 218, -- } --> Ъ } 1 1 Ссылка на комментарий
Serge! 127 Опубликовано 23 Сентября 2015 Поделиться Опубликовано 23 Сентября 2015 (изменено) ...если это не CUIEditBox из Сталкера. нет, это именно оттуда ...если это не CUIEditBox из Сталкера. а, если это не это, то и вообще проблем нет. т.к. уже прозвучали намёки на флуд с моей стороны, то привожу полный код скрипта,который реализует всё о чём я сказал в сообщении #55.Код таблицы перекодировки я уже приводил раньше. В скрипте она подключается из внешнего файла (мне так удобнее). --[[--------------------------------------------------ui_money_wnd.scriptAuthors: Serge!Version: 1.02015------------------------------------------------------Описание:Ввод кириллицы в EditBoxПлатформа: ТЧ (1.0.0.4)Используется: внешний файл com_dlg.script------------------------------------------------------Содержание:Необходим скрипт com_dlg.script--]]---------------------------------------------------- Предопределённые данныеlocal t_lang = com_tbl.tbl_ansii-- точка входа из внешних скриптов (ui_money_wnd.main())function main()super_dlg = ui_test_edit_wnd.ui_test_edit()level.start_stop_menu(super_dlg, true)end-- определяем класс и активируем егоclass "ui_test_edit" (CUIScriptWnd)function ui_test_edit:__init() super()self:InitControls()self:InitCallBacks()endfunction ui_test_edit:__finalize() end-- инициализируем элементы и переменные классаfunction ui_test_edit:InitControls()self:Init(400,325,240,103)local xml = CScriptXmlInit() -- создаем класс для файла описанияxml:ParseFile("ui_edit_wnd.xml") -- подключаем файл описания элементов окнаxml:InitStatic("edit_dlg_fon", self) -- устанавливаем статик фона-- регистрируем элементы окна-- кнопкиlocal ctrl = xml:Init3tButton("edit_btn_exit", self) -- Отменаself:Register(ctrl, "btn_1")self.btn_lan = xml:Init3tButton("edit_btn_lan", self) -- язык вводаself.mode_lang = trueself.btn_lan:SetText("Рус")self:Register(self.btn_lan, "btn_2")local ctrl = xml:Init3tButton("edit_btn_clr", self) -- очистить полеself:Register(ctrl, "btn_3")-- поле вводаself.str_edit = xml:InitEditBox("edit_str", self)self:Register(self.str_edit, "str_edit")endfunction ui_test_edit:InitCallBacks()self:AddCallback("btn_1", ui_events.BUTTON_CLICKED, self.OnButton_CANCEL, self)self:AddCallback("btn_2", ui_events.BUTTON_CLICKED, self.OnButton_LANG, self)self:AddCallback("btn_3", ui_events.BUTTON_CLICKED, self.OnButton_CLEAR, self)self:AddCallback("str_edit", ui_events.EDIT_TEXT_CHANGED, self.OnEdit_CHANGED, self)end-- выбор языкаfunction ui_test_edit:OnButton_LANG()self.mode_lang = not self.mode_langif self.mode_lang then self.btn_lan:SetText("Рус")else self.btn_lan:SetText("Eng") endend-- поле вводаfunction ui_test_edit:OnEdit_CHANGED()local txt = self.str_edit:GetText()if self.mode_lang thenlocal copy_txt, cls = ""for n = 1, string.len(txt) docls = string.byte(txt, n)if t_lang[cls] ~= nil then copy_txt = copy_txt..string.char(t_lang[cls])else copy_txt = copy_txt..string.char(cls) endendself.str_edit:SetText(copy_txt)endend-- очистить поле вводаfunction ui_test_edit:OnButton_CLEAR()self.str_edit:SetText("")end-- Выйтиfunction ui_test_edit:OnButton_CANCEL()level.start_stop_menu(self, true)end-- клавишыfunction ui_test_edit:OnKeyboard(dik, keyboard_action)CUIScriptWnd.OnKeyboard(self,dik,keyboard_action)local bind = dik_to_bind(dik)local console = get_console()if keyboard_action == ui_events.WINDOW_KEY_PRESSED thenif dik == DIK_keys.DIK_ESCAPE thenself:OnButton_CANCEL()endendreturn trueendP.S. Это упрощённая демо-версия. В реальной жизни он немного усложнен проверками на ввод смешанного текста, но это уже частности.забыл вставить каритнку с результатом.http://j-p-g.net/if/2015/09/25/0141137001443202007.jpg Изменено 14 Октября 2015 пользователем Black Hawk Ссылка на комментарий
Nazgool 250 Опубликовано 2 Октября 2015 Поделиться Опубликовано 2 Октября 2015 (изменено) Функция string.lower с поддержкой кириллицы Поскольку Сталкер работает с кодировкой ANSI, и последовательность символов в этой кодировке вполне линейна (кроме символов 'Ё' - 'ё'), то функции 'lower' и 'upper' можно записать альтернативно : local _lower = string.lower local _upper = string.upper function string.lower(s) return _lower(s:gsub("([А-Я])",function(c) return string.char(c:byte()+32) end):gsub("Ё", "ё")) end function string.upper(s) return _upper(s:gsub("([а-я])",function(c) return string.char(c:byte()-32) end):gsub("ё", "Ё")) end Господа, я все понимаю, мы тут все программисты и сами себе все пишем. Ну например так : --[[ ---------------------------------------------------------------------------------------------- File : lua_xml.lua Copyright : 2015 © Prosectors Mod Author : Gerald Franz, www.viremo.de Copyright (C) 2007-2010 Editors : Nazgool, nazgool@ukr.net Charsi OGSE Team Description: Набор функций для работы с xml-файлами. В таблицу _G добавляется пространство _G.xml (edition by Nazgool) Из оригинальной библиотеки удалена LuaXml_lib.dll. Функции из неё (за иключением registerCode) переписаны на lua. --]] ---------------------------------------------------------------------------------------------- module '_G' xml = {} -- symbolic name for tag index, this allows accessing the tag by var[xml.TAG] xml.TAG = 0 local symbols = { ['\000'] = '\000', ['\001'] = '\001', ['\002'] = '\002', ['\003'] = '\003', ['\004'] = '\004', ['\005'] = '\005', ['\006'] = '\006', ['\007'] = '\007', ['\008'] = '\008', ['\009'] = '\009', ['\010'] = '\010', ['\011'] = '\011', ['\012'] = '\012', ['\013'] = '\013', ['\014'] = '\014', ['\015'] = '\015', ['\016'] = '\016', ['\017'] = '\017', ['\018'] = '\018', ['\019'] = '\019', ['\020'] = '\020', ['\021'] = '\021', ['\022'] = '\022', ['\023'] = '\023', ['\024'] = '\024', ['\025'] = '\025', ['\026'] = '\026', ['\027'] = '\027', ['\028'] = '\028', ['\029'] = '\029', ['\030'] = '\030', ['\031'] = '\031', ['\032'] = '\032', ['\033'] = '\033', ['\034'] = '"', -- кавычка " ['\035'] = '\035', ['\036'] = '\036', ['\037'] = '\037', ['\038'] = '&', -- амперсанд & ['\039'] = '\039', ['\040'] = '\040', ['\041'] = '\041', ['\042'] = '\042', ['\043'] = '\043', ['\044'] = '\044', ['\045'] = '\045', ['\046'] = '\046', ['\047'] = '\047', ['\048'] = '\048', ['\049'] = '\049', ['\050'] = '\050', ['\051'] = '\051', ['\052'] = '\052', ['\053'] = '\053', ['\054'] = '\054', ['\055'] = '\055', ['\056'] = '\056', ['\057'] = '\057', ['\058'] = '\058', ['\059'] = '\059', ['\060'] = '<', -- левая угловая скобка < ['\061'] = '\061', ['\062'] = '>', -- правая угловая скобка > ['\063'] = '\063', ['\064'] = '\064', ['\065'] = '\065', ['\066'] = '\066', ['\067'] = '\067', ['\068'] = '\068', ['\069'] = '\069', ['\070'] = '\070', ['\071'] = '\071', ['\072'] = '\072', ['\073'] = '\073', ['\074'] = '\074', ['\075'] = '\075', ['\076'] = '\076', ['\077'] = '\077', ['\078'] = '\078', ['\079'] = '\079', ['\080'] = '\080', ['\081'] = '\081', ['\082'] = '\082', ['\083'] = '\083', ['\084'] = '\084', ['\085'] = '\085', ['\086'] = '\086', ['\087'] = '\087', ['\088'] = '\088', ['\089'] = '\089', ['\090'] = '\090', ['\091'] = '\091', ['\092'] = '\092', ['\093'] = '\093', ['\094'] = '\094', ['\095'] = '\095', ['\096'] = '\096', ['\097'] = '\097', ['\098'] = '\098', ['\099'] = '\099', ['\100'] = '\100', ['\101'] = '\101', ['\102'] = '\102', ['\103'] = '\103', ['\104'] = '\104', ['\105'] = '\105', ['\106'] = '\106', ['\107'] = '\107', ['\108'] = '\108', ['\109'] = '\109', ['\110'] = '\110', ['\111'] = '\111', ['\112'] = '\112', ['\113'] = '\113', ['\114'] = '\114', ['\115'] = '\115', ['\116'] = '\116', ['\117'] = '\117', ['\118'] = '\118', ['\119'] = '\119', ['\120'] = '\120', ['\121'] = '\121', ['\122'] = '\122', ['\123'] = '\123', ['\124'] = '\124', ['\125'] = '\125', ['\126'] = '\126', ['\127'] = '\127', ['\128'] = '\128', ['\129'] = '\129', ['\130'] = '\130', ['\131'] = '\131', ['\132'] = '\132', ['\133'] = '\133', ['\134'] = '\134', ['\135'] = '\135', ['\136'] = '\136', ['\137'] = '\137', ['\138'] = '\138', ['\139'] = '\139', ['\140'] = '\140', ['\141'] = '\141', ['\142'] = '\142', ['\143'] = '\143', ['\144'] = '\144', ['\145'] = '\145', ['\146'] = '\146', ['\147'] = '\147', ['\148'] = '\148', ['\149'] = '\149', ['\150'] = '\150', ['\151'] = '\151', ['\152'] = '\152', ['\153'] = '\153', ['\154'] = '\154', ['\155'] = '\155', ['\156'] = '\156', ['\157'] = '\157', ['\158'] = '\158', ['\159'] = '\159', ['\160'] = ' ' , -- неразрывный пробел ['\161'] = '¡' , -- перевернутый восклицательный знак ['\162'] = '¢' , -- цент ['\163'] = '£' , -- фунт стерлингов ['\164'] = '¤', -- знак денежной единицы ¤ ['\165'] = '¥' , -- йена ['\166'] = '¦', -- вертикальная черта ¦ ['\167'] = '§' , -- параграф § ['\168'] = '¨' , -- диереза ['\169'] = '©' , -- знак авторского права © ['\170'] = 'ª' , -- показатель женского рода ['\171'] = '«' , -- открывающая двойная угловая кавычка « ['\172'] = '¬' , -- знак отрицания ¬ ['\173'] = '' , -- мягкий перенос ['\174'] = '®' , -- охраняемый знак ® ['\175'] = '¯' , -- надчеркивание ['\176'] = '°' , -- градус ° ['\177'] = '±', -- плюс-минус ± ['\178'] = '²' , -- вторая степень ['\179'] = '³' , -- третья степень ['\180'] = '´' , -- острое ударение ['\181'] = 'µ' , -- знак микро µ ['\182'] = '¶' , -- конец абзаца ¶ ['\183'] = '·', -- средняя точка · ['\184'] = '¸' , -- седиль ['\185'] = '¹' , -- единица в верхнем индексе ['\186'] = 'º' , -- показатель мужского рода ['\187'] = '»' , -- закрывающая двойная угловая кавычка » ['\188'] = '¼', -- одна четвертая ['\189'] = '½', -- одна вторая ['\190'] = '¾', -- три четверти ['\191'] = '¿', -- перевернутый вопросительный знак ['\192'] = '\192', ['\193'] = '\193', ['\194'] = '\194', ['\195'] = '\195', ['\196'] = '\196', ['\197'] = '\197', ['\198'] = '\198', ['\199'] = '\199', ['\200'] = '\200', ['\201'] = '\201', ['\202'] = '\202', ['\203'] = '\203', ['\204'] = '\204', ['\205'] = '\205', ['\206'] = '\206', ['\207'] = '\207', ['\208'] = '\208', ['\209'] = '\209', ['\210'] = '\210', ['\211'] = '\211', ['\212'] = '\212', ['\213'] = '\213', ['\214'] = '\214', ['\215'] = '\215', ['\216'] = '\216', ['\217'] = '\217', ['\218'] = '\218', ['\219'] = '\219', ['\220'] = '\220', ['\221'] = '\221', ['\222'] = '\222', ['\223'] = '\223', ['\224'] = '\224', ['\225'] = '\225', ['\226'] = '\226', ['\227'] = '\227', ['\228'] = '\228', ['\229'] = '\229', ['\230'] = '\230', ['\231'] = '\231', ['\232'] = '\232', ['\233'] = '\233', ['\234'] = '\234', ['\235'] = '\235', ['\236'] = '\236', ['\237'] = '\237', ['\238'] = '\238', ['\239'] = '\239', ['\240'] = '\240', ['\241'] = '\241', ['\242'] = '\242', ['\243'] = '\243', ['\244'] = '\244', ['\245'] = '\245', ['\246'] = '\246', ['\247'] = '\247', ['\248'] = '\248', ['\249'] = '\249', ['\250'] = '\250', ['\251'] = '\251', ['\252'] = '\252', ['\253'] = '\253', ['\254'] = '\254', ['\255'] = '\255', } function xml.encode(str) if type(str)~="string" then return end return str:gsub('.', symbols) end function xml.eval (str) if type(str)~="string" then return end local data = {} str = str:gsub('%s-<!%-%-.-%-%->', '') -- убрать комментарии str = str:gsub('%s-<%?xml.-%?>' , '') -- убрать заголовок если есть local function parse_str(str, parent) local tag, prop, rest = str:match("<%s-([%w_]+)%s*(.-)>(.-)$") if tag then local child = {[0] = tag} table.insert(parent, child) for key, value in prop:gmatch('(%S+)="(%S+)"') do child[key] = value end if prop:match('/$') then -- самозакрывающийся тег parse_str(rest, parent) else -- закрывающий тег str, rest = rest:match('^%s*(.-)%s-</%s-'..tag..'%s->(.-)$') child[1] = str:match('^%s-<') and parse_str(str, child) or str parse_str(rest, parent) end return child end end parse_str(str, data) return setmetatable(data[1],{__index=xml, __tostring=xml.str}) or nil end function xml.load (root_alias, local_path) local fs = getFS() local path = fs:update_path(root_alias, local_path) local file = io.open(path) if file then -- файл в распакованном виде на диске local str = file:read('*a') file:close() return xml.eval(str) elseif fs:exist(path) then -- файл в архиве file = fs:r_open(path) local chars = {} local index = 1 local _char = string.char while not file:r_eof() do chars[index] = _char(file:r_u8()) index = index + 1 end return xml.eval(table.concat(chars)) end return nil end -- sets or returns tag of a LuaXML object function xml.tag(var,tag) if type(var) ~= "table" then return end if not tag then return var[0] end var[0] = tag end -- creates a new LuaXML object either by setting the metatable of an existing Lua table or by setting its tag function xml.new(arg) local tag = (type(arg)=="string" and arg) local var = (type(arg)=="table" and arg) or {[0]=tag} return setmetatable(var, {__index=xml, __tostring=xml.str}) end -- appends a new subordinate LuaXML object to an existing one, optionally sets tag function xml.append(var,tag) if type(var)~="table" then return end local arg = xml.new(tag) var[#var+1] = arg return arg end -- converts any Lua var into an XML string function xml.str(var,indent,tagValue) if not var then return end local indent = indent or 0 local indentStr = "" for i = 1,indent do indentStr = indentStr.." " end local tableStr = "" if type(var)=="table" then local tag = var[0] or tagValue or type(var) local s = indentStr.."<"..tag for k,v in pairs(var) do -- attributes if type(k)=="string" then if type(v)=="table" and k~="_M" then -- otherwise recursiveness imminent tableStr = tableStr..xml.str(v,indent+1,k) else s = s.." "..k.."=\""..encode(tostring(v)).."\"" end end end if #var==0 and #tableStr==0 then s = s.." />\n" elseif #var==1 and type(var[1])~="table" and #tableStr==0 then -- single element s = s..">"..encode(tostring(var[1])).."</"..tag..">\n" else s = s..">\n" for k,v in ipairs(var) do -- elements if type(v)=="string" then s = s..indentStr.." "..encode(v).." \n" else s = s..xml.str(v,indent+1) end end s=s..tableStr..indentStr.."</"..tag..">\n" end return s else local tag = type(var) return indentStr.."<"..tag.."> "..encode(tostring(var)).." </"..tag..">\n" end end -- saves a Lua var as xml file function xml.save(var, filename) if var and filename and #filename ~= 0 then local file = io.open(filename, 'w') if file then file:write("<?xml version=\"1.0\" encoding=\"windows-1251\"?>\n\n") file:write(xml.str(var)) file:close() return true else filename = filename:gsub('\\', '/') local dir, path, name = string.match(filename, '^([^/]+)(.-)([^/]+)$') local cur_dir = lfs.currentdir() for node in string.gmatch(path, "[^/]+") do dir = dir .. '/'.. node if not lfs.chdir(dir) then lfs.mkdir(dir) end end lfs.chdir(cur_dir) xml.save(var, filename) end end return false end -- Function 'xml.find' ---------------------- local function is_value (obj, value) for _, v in pairs(obj) do if v == value then return true end end return false end local function is_key(obj,key,value) if value then return obj[key]==value end return obj[key] ~= nil end local function is_tag(obj,tag,key,value) if obj[0]==tag then if key then return is_key(obj,key,value) elseif value then return is_value(obj,value) end return true end return false end local function check(obj, tag, key, value) if tag then return is_tag(obj,tag,key,value) elseif key then return is_key(obj,key,value) elseif value then return is_value(obj,value) end return true end local function parse(obj, tag, key, value, index, parent) if check(obj, tag, key, value) then setmetatable(obj,{__index=xml, __tostring=xml.str}) coroutine.yield(obj, index, parent) end -- recursively parse subtags: for k,v in ipairs(obj) do if type(v)=="table" then parse(v, tag, key, value, k, obj) end end end local thread = nil function xml.find (obj, tag, key, val) -- check input: if type(obj)~="table" then return nil end tag = (type(tag)=="string") and #tag>0 and tag key = (type(key)=="string") and #key>0 and key val = (type(val)=="string") and #val>0 and val if tag then local tag1,tag2 = tag:match("(.-).+)") if tag1 then local res = xml.find(obj, tag1) or {} setmetatable(res,{__index=xml, __tostring=xml.str}) return xml.find(res, tag2, key, val) end end thread = coroutine.create(parse) return select(2,coroutine.resume(thread, obj, tag, key, val)) end function xml.next() if coroutine.status(thread)=='dead' then return end return select(2,coroutine.resume(thread)) end function xml.remove(obj, tag, key, val) if type(obj)~="table" then return nil end if type(tag)=="string" and #tag==0 then tag=nil end local _,index = obj:find(tag, key, val) if not index then return end return table.remove(obj,index) end Ну а подключать можно по-разноному. Как *script, или как *.lua, или ... да мало ли кому как нужно. Какая из версий актуальная - не знаю. Что значит какая? Первая ссылка это учебник по lua 5.1 плюс некоторые моменты про lua 5.2 А вторая - справочник по lua 5.1 взятый из руссифицированной сборки LuaForWindows. Обе пока актуальны. когда же люди научатся оформлять и правильно выкладывать свои работы, а не только писать их?.. Не, ну это уже ... сами назовите как-нибудь. Написать выходит ерунда. Главное правильно презентовапть. Да-а-а. Напиши, отдай, а теперь ещё разжуй и вообще "сделай всё за меня". Так что-ли? Изменено 2 Октября 2015 пользователем Nazgool 1 Ссылка на комментарий
HESH 64 Опубликовано 3 Октября 2015 Поделиться Опубликовано 3 Октября 2015 На всякий случай перезалил: by Nazgool Ссылка на комментарий
Это популярное сообщение. Romz 142 Опубликовано 9 Октября 2015 Это популярное сообщение. Поделиться Опубликовано 9 Октября 2015 (изменено) По результатам прикручивания se_stor к ЗП, получился комплект скриптов и инструкций se_stor от 09.09.2013, lua_helper, m_timers от 23.09.2013 и lua_extension от 29.09.2013, для чистой ЗП, с учётом минимального вмешательства в игру (т.е. без изменения методов сохранения данных в модулях, кроме bind_actor) Скорее всего, на ЧН тоже подойдёт, с минимальными изменениями. Изменено 9 Октября 2015 пользователем Romz 3 2 Шаман - СисАдмин Всяко-разно: для ЧН Ссылка на комментарий
Romz 142 Опубликовано 11 Октября 2015 Поделиться Опубликовано 11 Октября 2015 Снова перезалил архив, ссылка та же. Указал необходимость удаления/закомменчивания xr_statistic и sr_psy_antenna в оригинальных методах сохранения в bind_stalker, т.к. они сохраняются в чанках 2 Шаман - СисАдмин Всяко-разно: для ЧН Ссылка на комментарий
Serge! 127 Опубликовано 13 Октября 2015 Поделиться Опубликовано 13 Октября 2015 (изменено) Класс "Список_Значений" а-ля 1С. Все описания и инструкции в коде, поэтому длинновато. --[[-------------------------------------------------- valueList.script Authors: Serge! Version: 1.0 ------------------------------------------------------ Description: Класс "СписокЗначений" ------------------------------------------------------ Connection: Тип "значения" допускается только string или number. Перед использованием во внешних скриптах объект класса valueList необходимо создать командой: valst = valueList and valueList.valueList([mode, nameFile]) or nil Параметры: . <mode, nameFile> - Необязательные. mode - флаг режима пред/пост формирования списка. True - при создании экземпляра класса, список заполняется содержанием из файла указанного в <nameFile>. False - перед очисткой, содержание списка сохраняется в файле <nameFile>. --]]-------------------------------------------------- -- локальные параметры и функции local lst = {} local curID = 0 local isValue = function(val) return (val and (type(val) == "string" or type(val) == "number")) and true or false end local isBool = function(var) return var ~= nil and var ~= 0 and var ~= false and var ~= '' end local defDir = '$fs_root$\\' local SOC = system_ini():r_string("script","current_server_entity_version") < '8' -- true - ТЧ; false - ЧН, ЗП local getRandName = function() return (tostring(function() end):gsub('.','',10)) end -- определение и инициализация класса class "valueList" function valueList:__init(mode, nameFile) if isBool(nameFile) then self.mode = mode self.nameFile = nameFile if mode then self:Restore(nameFile) end end end function valueList:__finalize() if isBool(self.nameFile) and not self.mode then self:Save(self.nameFile) end end --[[ Определить размер списка. Позволяет определить общее количество элементов в списке. Возвращает численное значение или 0 для пустого списка ]] function valueList:GetListSize() return #lst end --[[ Позволяет установить (если требуется) и/или считать текущее значение шндекса строки списка. Возвращает текущее значение индекса до его изменения. Если заданное значение больше размера списка, то индекс не изменяется Параметры: <ns> - Необязательный параметр. Новое текущее значение индекса в списке. Возвращаемое значение: текушая позиция ]] function valueList:CurSel(ns) local old = curID curID = (ns and ns <= #lst) and ns or old return curID end --[[ Добавить значение в список. Метод добавляет значение и его символьное представление в конец списка. Символьное представление значения должно быть уникальным. Если такое представление уже есть в списке, то значение не добавляется. Параметры: <val> - Выражение со значением, которое добавляется в список. <str> - Необязательный параметр. Строка, содержащая задаваемое символьное представление добавляемого значения. Если опущен, то строка заполняется значением по умолчанию. Возвращаемое значение: true - действие выполнено; false - нет. ]] function valueList:AddValue(val, str) local out = false if isValue(val) and not isBool(self:FindName(str)) then table.insert(lst,{}) curID = #lst lst[curID].val = val; lst[curID].name = str or tostring(type(val))..'_'..tostring(curID) out = true end return out end --[[ Вставить значение в указанную позицию списка. Добавляет значение и его символьное представление в указанную позицию списка заданное число раз. Если заданная позиция превышает размер списка, то значения вставляются в его конец. Символьное представление значения должно быть уникальным. Если такое представление уже есть в списке, то значение не добавляется. Параметры: <val> - Выражение со значением, которое добавляется в список. <str> - Необязательный параметр. Строка, содержащая задаваемое символьное представление добавляемого значения. Если опущен, то строка заполняется значением по умолчанию. <pos> - Необязательный параметр. Номер позиции в вписке, начиная с которой будут вставляться значения. Если больше длины списка или опушен, то в конец. <num> - Необязательный параметр. Количество повторов. Если опущен, то 1 Возвращаемое значение: true - действие выполнено; false - нет. ]] function valueList:InsertValue( val, str, pos, num) local out if isValue(val) and not isBool(self:FindName(str)) then num = num and num or 1 pos = (pos and pos <= #lst) and pos or #lst + 1 for i = 1, num do table.insert(lst,pos,{}) lst[pos].val = val; lst[pos].name = str or tostring(type(val))..'_'..tostring(curID) pos = pos + 1 end out = true end curID = #lst return isBool(out) end --[[ Определить номер позиции в списке для элемента, имеющего заданное значение. С помощью метода FindValue можно определить номер позиции в списке для элемента, имеющего значение <val>. Строка с найденным элементом становится текущей. Параметры: <val> - Выражение со значением, которое требуется найти в списке. Возвращаемое значение: Номер позиции в списке, где расположено требуемое значение. Если значение не найдено, то — 0. ]] function valueList:FindValue(val) local out = 0 if isValue(val) then for k,v in pairs(lst) do if v.val == val then curID = k return k end end end return out end --[[ Определить номер позиции в списке для элемента, имеющего заданное символьное представление значения. С помощью метода FindValue можно определить номер позиции в списке для элемента, имеющего значение <name>. Строка с найденным элементом становится текущей. Параметры: <name> - Выражение содержащее символьное представление значения, которое требуется найти в списке. Возвращаемое значение: Номер позиции в списке, где расположено требуемое значение. Если не найдено, то — 0. ]] function valueList:FindName(name) local out = 0 for k,v in pairs(lst) do if v.name == name then curID = k return k end end return out end --[[ Получить значение элемента по его индексу в списке. Метод находит и возвращает значение находяшееся в заданной позиции. Позиция найденного значения становится текущей. Параметры: <id> - Числовое выражение — номер элемента в списке, значение которого будет возвращено. Номер позиции может быть от 1 до количества элементов в списке. <str> - Идентификатор переменной в которую (если передан) будет возвращено строковое выражение, содержащее символьное представление получаемого значения. Возвращаемое значение: Полученное значение из списка или nil. ]] function valueList:GetValueById(id, str) local out = nil if lst[id] then out = lst[id].val if str then str = lst[id].name end curID = id end return out end --[[ Получить символьное представление элемента по его индексу в списке. Метод находит и возвращает символьное представление элемента находяшегосяся в заданной позиции. Позиция найденного значения становится текущей. Параметры: <id> - Числовое выражение — номер элемента в списке, значение которого будет возвращено. Номер позиции может быть от 1 до количества элементов в списке. Возвращаемое значение: Полученное символьное представление или пустая строка. ]] function valueList:GetNameById(id) local out = '' if lst[id] then out = lst[id].name; curID = id end return out end --[[ Установить значение в указанной позиции списка. Метод устанавливает значения и его символьные лредставления элементов, начиная с указанной позиции списка, заданное число повторов. Имеющиеся в списке до вызова метода значения, будут заменнены. Если позиция больше размера списка, то значения будут добавлены в конец. Текущей становится позиция последнего вставленного элемента. Параметры: <pos> - Номер позиции в вписке, начиная с которой будут устанавливаться значения. Если больше длины списка, то в конец. <val> - Выражение со значением, которое устанавливается в список. <str> - Необязательный параметр. Строка, содержащая задаваемое символьное представление значения. Если опущен, то строка заполняется значением по умолчанию. <num> - Необязательный параметр. Количество повторов. Если опущен, то 1 Возвращаемое значение: нет. ]] function valueList:SetValue(pos, val, str, num) if isValue(val) and not isBool(self:FindName(str)) then num = num and num or 1 pos = (pos and pos <= #lst) and pos or #lst + 1 for i = 1, num do if pos > #lst then table.insert(lst,{}) end lst[pos].val = val; lst[pos].name = str or tostring(type(val))..'_'..tostring(curID) pos = pos + 1 end curID = pos - 1 end end --[[ Получить значение элемента по указанному символьному представлению. Метод возвращает значение по указанному представлению. Если значения с таким представлением нет, то возвращается пустое значение. Параметры: <str> - Строка, содержащая задаваемое символьное представление значения. Возвращаемое значение: Значение из списка или nil. ]] function valueList:Get(str) local out = nil for k,v in pairs(lst) do if v.name == str then return v.val end end return out end --[[ Установить значение с указанным представлением. Метод устанавливает в списке значение с указанным представлением, если значение с таким представлением уже есть — изменятеся значение, если нет — добавляется в конец списка значение с указанным представлением. Параметры: <str> - Строка, содержащая задаваемое символьное представление значения. <val> - Выражение со значением, которое устанавливается в список. Возвращаемое значение: Нет. ]] function valueList:Set(str, val) if isValue(val) then for k,v in pairs(lst) do if v.name == str then v.val = val return end end table.insert(lst,{}) curID = #lst; lst[curID].val = val; lst[curID].name = str end end --[[ Удалить значение в указанной позиции списка. Метод удаляет заданное количество значений, начиная с указаний позиции. Параметры: <pos> - Числовое выражение — номер позиции в списке, начиная с которой будут удалены значения. Номер позиции может быть от 1 до количества элементов в списке. <num> - Необязательный параметр. Числовое выражение — количество повторов. По умолчанию — 1. Возвращаемое значение: Нет. ]] function valueList:RemoveValue(pos, num) num = num and num or 1 local endPos = ((pos+num-1) <= #lst) and pos+num-1 or #lst for i = pos, endPos do table.remove(lst, i) end curID = pos end --[[ Удалить все элементы спискаа. Метод удаляет все элементы списка. Параметры: Нет Возвращаемое значение: Нет. ]] function valueList:RemoveAll() curID = 0 lst = {} end --[[ Проверяет вхождение в список указанного значения. Метод оптимизирует проверку принадлежности при массовых последовательных сравнениях, если между сравнениями сам список значений не меняется. Параметры: <val> - Выражение со значением, которое проверяется на вхождение в список. Возвращаемое значение: true — если проверяемое значение входит в список; false — если не входит. ]] function valueList:ValueInList(val) return isBool(self:FindValue(val)) end --[[ Проверяет вхождение в список указанного символьного представления. Метод оптимизирует проверку принадлежности при массовых последовательных сравнениях, если между сравнениями сам список значений не меняется. Параметры: <name> - Выражение со значением символьного представления, которое проверяется на вхождение в список. Возвращаемое значение: true — если проверяемое представление входит в список; false — если не входит. ]] function valueList:NameInList(name) return isBool(self:FindName(name)) end --[[ Загрузить/выгрузить список сначений. Метод позволяет загрузить или выгрузить список значений в другой список. Можно задать начальные индекси строк и их количество. Параметры: <list> - Значение типа "Список значений", в которое нужно загрузить/выгрузить данные. Если переданное значение пустое (nil), то при выгрузке будет создан новый объект типа «Список значений». При выгрузке в этот параметр будет помещен список с добавленными позициями. <mode> - Флаг устанавливающий направление: true - загрузка; false - выгрузка. <pos_b> - Необязательный параметр. Индекс начальной позиции в базовом списке, с которой надо начинать загрузку/выгрузку. Значение по умолчанию: 1 - при выгрузке; длина_списка+1 - при загрузке. <pos_c> - Необязательный параметр. Индекс начальной позиции в подключаемом списке, с которой надо начинать загрузку/выгрузку. Значение по умолчанию: длина_списка+1 - при загрузке в него; 1 - при выгрузке из него. <num> - Необязательный параметр. Числовое выражение — количество загружаемых/выгружаемых строк. По умолчанию — весь список. Возвращаемое значение: true — если операция успешна; false — если нет. ]] function valueList:LoadUnload(list, mode, pos_b, pos_c, num) list = (list and type(list) == "table") and list or {} if mode and not isBool(#list) then return false end pos_b = pos_b and pos_b or (mode and 1 or #tbl+1) pos_c = pos_c and pos_c or (mode and #list or 1) local source, pos_source = mode and list or tbl, mode and pos_c or pos_b -- источник local sink, pos_sink = mode and tbl or list, mode and pos_b or pos_c -- приемник num = num and num or (mode and #list or #tbl) for n = 1, num do table.insert(sink,pos_sink,{}) sink[pos_sink].var = source[pos_source].var; sink[pos_sink].name = source[pos_source].name pos_sink = pos_sink + 1; pos_source = pos_source + 1 end if not mode then list = sink end return true end --[[ Сохранить список во внешний файл. Метод сохраняет список значений в текстовый файл на диске. Если функции в качестве параметра передается полное имя файла, то файл сохраняется в заданной папке. Если передается только имя, то в корневой папке с установленной игрой (папка по умолчанию). Если файл с таким именем уже существует, то он будет перезаписан без каких-либо запросов и подтверждений. Если параметр имени файла опущен, то имя файла будет сгенерировано автоматически (это приемлемо только при отладке, т.к. для использования такого имени требуется правка текста этого или вызываюшего скрипта). Файл будет сохраняться в папке по умолчанию. Параметры: <nf> - Строка, содержащая имя сохраняемого файла или nil. Возвращаемое значение: true — если операция успешна; false — если нет. Примечание: Для ТЧ требуется наличние пакета RvP. Если его нет, то вылетов не будет, но и никаких действий произведено тоже не будет. ]] function valueList:Save(fn) local out = false if SOC and m_netpk and not isBool(_G.io) then RvP() else return out end if not isBool(fn) then fn = defDir..getRandName()..'.vlt' end -- генерируем случайное имя local fs = io.open(fn,'w') if isBool(fs) then local str, tv for k,v in pairs(lst) do tv = (type(v.val) == 'string') and 's' or 'n' str = string.format("%s|%s|%s\n",tv,tostring(v.val),v.name) fs:write(str) end fs:flush() fs:close() out = true end return out end --[[ Восстановить список из внешнего файла. Метод восстановить список значений из ранее сохраненного текстовый файла на диске. Если функции в качестве параметра передается полное имя файла, то файл восстанвливается из файла в заданной папке. Если передается только имя, то из корневой папки с установленной игрой (папка по умолчанию). Если файл с таким именем нет, то никаких действий не производится. Параметры: <nf> - Строка, содержащая имя файла. Возвращаемое значение: true — если операция успешна; false — если нет. Примечание: Для ТЧ требуется наличние пакета RvP. Если его нет, то вылетов не будет, но и никаких действий произведено тоже не будет. ]] function valueList:Restore(fn) local t = {} if not isBool(_G.io) then if m_netpk then RvP() else return t end end local fs = io.open(fn,'r') if isBool(fs) then fs:close() local tstr for line in io.lines(fn) do tstr = {} for par in line:gfind("%s*([^|]+)%s*") do table.insert(tstr,par) end table.insert(t,{}) t.val = tstr[1] == 's' and tstr[2] or tonumber(tstr[2]) t.name = tstr[3] end fs:close() end return t end Если подобное кому-то надо, то оформю в соответствии с правилами форума аналогичный "Таблица_Значений".У него функционал поболее. Изменено 20 Октября 2015 пользователем Murarius Ссылка на комментарий
Это популярное сообщение. naxac 2 445 Опубликовано 21 Октября 2015 Это популярное сообщение. Поделиться Опубликовано 21 Октября 2015 (изменено) Скрипт ищет в конфигах секции всех игровых объектов и возвращает таблицу секций, сортированных по классам (в скобках - название поля таблицы): - оружие (weapons), - аммуниция (ammo), - обвесы (addons), - костюмы/шлемы (outfits), - арефакты (artefacts), - квестовые предметы (quest_items), - остальные предметы (items), - монстры (mobs), - нпс (stalkers), - автомобили (cars), - аномалии (anomalies), - остальные, которым категории не нашлось (other) Если в Луа присутствует пространство имен io, то в папке конфигов будет создан файл 'all_sections.ltx' со списком всех секций по категориям. Взможное применение - создание 'спавнеров' к модам (чтобы в ручную не искать секции). Получаем таблицу: local t = collect_sections.main()!!! Для того, чтобы прочитались все конфиги, ресурсы игры должны быть распакованы !!! Платформа: ТЧ, ЧН, ЗП. Скачать: ссылка Изменено 21 Октября 2015 пользователем naxac 5 1 1 Аддон для ОП-2.09.2: Яндекс/Google/GitHub Ссылка на комментарий
Это популярное сообщение. Kirgudu 1 207 Опубликовано 26 Октября 2015 Это популярное сообщение. Поделиться Опубликовано 26 Октября 2015 Навеяно помощью @Romz по прикручиванию se_stor к ЗП, результатом чего стал его объединённый комплект скриптов. Он всем хорош, однако, во-первых, предназначен только для ЗП, а во-вторых, предлагает подключение, например, m_timers даже в том случае, если таймеры не нужны, а нужно только универсальное хранилище. Здесь я хочу выложить немного другой комплект модулей @Artos'a, содержащий не все модули сразу, а каждый модуль по отдельности. При этом: реализована полная совместимость модулей между собой (можно интегрировать их в мод в любых необходимых сочетаниях); подключение и работа всех модулей протестированы во всех частях игры; для модуля универсального хранилища (se_stor) добавлено 3 разных примера подключения - для ТЧ, ЧН и ЗП соответственно. Примеры эти 100% рабочие, не требуют никакой доработки напильником. Достаточно в нужных местах добавить/закомментировать указанные куски кода. модуль se_stor доработан так, что теперь он позволяет не только сохранять в чанках те внешние модули, у которых есть публичные методы save/load, но и указывать кастомные названия соответствующих методов. Таким образом, теперь можно больше данных, сохраняемых в оригинале в нет-пакете главного героя, перенести в универсальное хранилище. В добавленных примерах подключения это отражено. Состав: lua_helper - различные часто употребляемые и/или полезные функции которые могут использоваться модмейкерами. m_netpk - интерфейс чтения/записи net-пакетов. m_timers - менеджер универсальных таймеров. se_stor - универсальное хранилище данных произвольного размера. Последнее обновление: 10.11.2024 Комплект мультиплатформенных модулей для S.T.A.L.K.E.R. SoC/CS/CoP Автор: @Artos (+ по рекурсии те авторы, работы которых Artos использовал, см. readme к соотв. модулям) Доработка модулей и синхронизация их между собой: @Kirgudu Исправление найденных в некоторых модулях ошибок: @Charsi, @Kirgudu, @naxac, @dsh, ... Состав: lua_helper - различные часто употребляемые и/или полезные функции которые могут использоваться модмейкерами. m_netpk - интерфейс чтения/записи net-пакетов. m_timers - менеджер универсальных таймеров. se_stor - универсальное хранилище данных произвольного размера. Добавляемые в оригинальные файлы игры фрагменты кода, а также наименования некоторых внутренних функций модулей, используемых в других местах, приведены к единому стандарту. Таким образом, подключать модули можно по отдельности или в любых сочетаниях, необходимых в конкретном случае, без опасений насчёт совместимости. Подключение всех модулей и их работа проверены мной во всех частях игры. В общий сборник включён использовавшийся для этого дополнительный скрипт (test_modules.script). Для разового тестирования можно добавить его вызов, например, на кнопку меню или при первом апдейте актора. Пример (первый апдейт актора, проверка подключения всех четырёх модулей), bind_stalker.script: function actor_binder:update(delta) --/ ... все строки функции if not test_modules_executed and test_modules and type(test_modules.execute) == 'function' and device().precache_frame < 2 then test_modules.execute("lua_helper", "m_netpk", "se_stor", "m_timers") test_modules_executed = true end end Результат в логе, если все модули подключены правильно: test_modules::>[lua_helper]_success! test_modules::>[lua_extension]_success! test_modules::>[m_netpk]_success! test_modules::>[se_stor]_success! test_modules::>[m_timers]_success! lua_helper - https://yadi.sk/d/1_J1HVZsu7Jgy, обновлено 09.05.2017 m_netpk - https://yadi.sk/d/GtYsSbjnxqdtp, обновлено 10.11.2024 se_stor - https://yadi.sk/d/a38PlQdju7Jhr, обновлено 10.08.2016 m_timers - https://yadi.sk/d/FWJkTnAMu7Jhg, обновлено 09.05.2017 Общий комплект + скрипт для тестирования - https://yadi.sk/d/p69RQkBMu7JgR, обновлено 13.06.2017 6 8 8 Инструмент Ссылка на комментарий
Kirgudu 1 207 Опубликовано 10 Ноября 2015 Поделиться Опубликовано 10 Ноября 2015 (изменено) Обнаружена и исправлена критическая ошибка в модуле универсального хранилища se_stor, приводившая к периодической невозможности сохранить в чанках данные всех подключённых внешних модулей. Ссылки те же (обновлены комплект se_stor и общий комплект). За помощь в тестировании спасибо @Romz. Изменено 10 Ноября 2015 пользователем Kirgudu 1 Инструмент Ссылка на комментарий
Kirgudu 1 207 Опубликовано 18 Ноября 2015 Поделиться Опубликовано 18 Ноября 2015 (изменено) @Zander_driver, если чувствуется, что это может кому-нибудь пригодиться, почему бы и нет? Хотя могут и помидорами закидать... Раз уж так вышло, что я недавно взял на себя посильную доводку модулей Артоса, позволю себе слегка прокомментировать обновлённую шапку. Установка модулей Artos`a на ЗПТут не просто установка модулей на ЗП, а, во-первых, сами модули (самая свежая их версия, с исправленными ошибками), во-вторых, модули полностью адаптированы ко всем платформам (естественно, для чистой игры) и в-третьих, некоторые кроссмодульные функции приведены к единому стилю, то есть сочетать модули между собой можно как угодно. Следует рекомендовать их скачивать именно из этого поста. Модули Артоса и xStreamА вот тут как раз лежат устаревшие модули Артоса, с одной стороны более приближённые к оригиналу автора, но с другой - с ошибками. Именно поэтому я бы их не рекомендовал, если кто-то не готов доработать самостоятельно. комплект скриптов и инструкций se_stor от 09.09.2013, lua_helper, m_timers от 23.09.2013 и lua_extension от 29.09.2013, для чистой ЗПВ этом общем комплекте от @Romz также использовался устаревший se_stor, неправильно работающий с чанками на платформах ЧН/ЗП. Старичок m_net_utilsДля своего времени штука была хорошая, но сейчас уже сильно устарела, да и не без ошибок. Разве только кому-то позарез нужна именно старая версия... Изменено 19 Ноября 2015 пользователем Kirgudu 2 Инструмент Ссылка на комментарий
Serge! 127 Опубликовано 20 Ноября 2015 Поделиться Опубликовано 20 Ноября 2015 набор инструментов управляемого массового спавна/респавна надо кому?...< пропущено > ... Хотя с другой стороны это же банальщина которую наверняка каждый сам сделал. Если смотреть со стороны вас - профи, то, как было отмечено, они "могут и помидорами закидать". А, если смотреть с другой стороны, тех которые только начинают в этом разбирать, то это очень даже хорошо и полезно. На чём же они еще могут учиться? Я думаю, что эта ветка форума в основном и должна быть сориентирована именно на эту категорию. Выкладывайте, кому-то обязательно пригодится. 1 Ссылка на комментарий
RayTwitty 492 Опубликовано 29 Ноября 2015 Поделиться Опубликовано 29 Ноября 2015 (изменено) -- функция возвращает название части тела по номеру кости. Часто используется в хит-колбеках НПС. function get_body_part_by_bone_index(bone_index) if bone_index then if bone_index < 5 then return "left_foot" elseif bone_index < 9 then return "right_foot" elseif bone_index < 11 then return "torso" elseif bone_index < 18 then return "head" elseif bone_index < 31 then return "left_hand" elseif bone_index < 40 then return "right_hand" end end end -- сравнивает два угла в радианах с погрешностью второго угла function radians_cmp(angle1, angle2, range_min, range_max) range_min = angle2 - range_min range_max = angle2 + range_max if range_max > 1.57 then range_max = -4.71 + (range_max - 1.57) end if range_min < -4.71 then range_min = 1.57 - (range_min - 4.71) end return angle1 > range_min and angle1 < range_max endНа счет последнего не знаю, использовал давно, возможно есть стандартный аналог или можно лучше написать. Но по крайней мере, все работало. Изменено 29 Ноября 2015 пользователем RayTwitty Ссылка на комментарий
TIGER_VLAD 361 Опубликовано 29 Ноября 2015 Поделиться Опубликовано 29 Ноября 2015 @RayTwitty, Точно не уверен, но вроде бы 18й bone_index это "torso" и : if bone_index >= 31 and bone_index <= 42 --(а не 40) then return "right_hand". Ссылка на комментарий
Serge! 127 Опубликовано 16 Декабря 2015 Поделиться Опубликовано 16 Декабря 2015 (изменено) Расширение базовой библиотеки Lua string. Наверное такое будет полезно начинающим и тем кто не очень себя уверенно чувствует в применении шаблонов. Остальные могут пропустить. Если требуется подробное описание и примеры применения, то (они у меня есть, но это занимает значительный объем) могу добавить и это. --[[-------------------------------------------------- _s.script Authors: Serge! Version: 1.0 2015 ------------------------------------------------------ Описание: Расширение таблицы string стандартной библиотеки Lua "Работа со строками" (string manipulation). Для любой "чистой" платформы "Сталкера" с версией Lua не ниже 5.1 и модификаций игр на их основе. Вызовы функций производятся способами принятыми при работе со строковыми данными: sting.Метод(str [,arg]) или str:Метод([arg]). Все передаваемые аргументы проверяются/приводятся к требуемому типу. Легко расширяется при появлении дополнительных потребностей или, наоборот, урезается до требуемого уровня. Для этого надо просто добавить новые функции или закомментировать/удалить имеющиеся. Также допускается выборочное использование отдельных функций или только их содержательного наполнения. ------------------------------------------------------ Подключение: Поместить данный файл в папку gamedata\scripts\ с установленной игрой. В любой из скриптов, которые запускаются при загрузке/старте игры, или скрипт, где планируется использование этих методов, добавить строки: if not sstring then dofile(getFS():update_path("$game_data$","scripts\\_s.script")) end --]]-------------------------------------------------- ---- глобальная переменная (флаг подключения) sstring = true ---- локальные переменные local tblW = function (str) t = {}; for w in tostring(str):gmatch("%s-(%S+)%s-") do t[#t+1] = w end; return t end local ssep = [[!@#$%*.:;,-?/|\]] ---- строка (последовательность символов между началом и концом строки) -- Проверить строку на наличие значащих символов (не пустая строка) --function string.sNotBlk(s) return (tostring(s):find('%S')) and true or false end string.sNotBlk = function(s) return (tostring(s):find('^(%S)')) and true or false end -- Отбросить в строке стоящие слева пробелы string.sTrimL = function(s) return (tostring(s):gsub("^%s+",'')) or s end -- Отбросить в строке стоящие справа пробелы string.sTrimR = function(s) return (tostring(s):gsub("%s*$",'')) or s end -- Отбросить в строке пробелы, стоящие слева и справа string.sTrim = function(s) return (tostring(s):gsub('^%s*(.-)%s*$', '%1')) or s end -- Выбрать в строке символы слева string.sLeft = function(s, n) return tostring(s):sub(1,tonumber(n)) or s end -- Выбрать в строке символы справа string.sRight = function(s, n) return tostring(s):sub(tonumber(-n)) or s end -- Выбрать подстроку string.sMid = function(s, ind ,n) s,ind,n = tostring(s),tonumber(ind),tonumber(n); return (n and s:sub(ind,ind+n-1) or s:sub(ind)) or s end -- Преобразовать строку в массив входящих в неё символов string.sArrayCh = function(s) t = {}; for w in tostring(s):gmatch('.') do table.insert(t,w) end; return t end -- Преобразовать строку в массив кодов входящих в неё символовв string.sArrayCode = function(s) t = {}; for ch in tostring(s):gmatch('.') do table.insert(t,string.byte(ch)) end; return t end -- Получить строку кодов входящих в неё символов string.sStrCode = function(s) t = {}; for ch in tostring(s):gmatch('.') do table.insert(t,string.byte(ch)) end; return string.sNotBlk(s) and '\\'..table.concat(t,'\\') or t end ---- символ (символ или последовательность любых символов, если противное специально не оговорено) -- Получить количество вхождений символа (символов) в строку string.sCountCh = function(s, ch) _,b = tostring(s):gsub(tostring(ch), ''); return b or 0 end -- Получить первое вхождение символа (подстроки) в строку string.sFindCh = function(s, ch) return (tostring(s):find(tostring(ch))) or 0 end -- Получить все вхождения символа (последовательности символов) в строку string.sFindChAll = function(s, ch, mode) local s,ch,n,t,p = tostring(s),tostring(ch),1,{}; repeat p = (s:find(ch,n)); if p then table.insert(t,p) n = p+#ch else n = n+#s end until n>#s; return #t>0 and (mode and table.concat(t,',') or t) or (mode and '' or t) end -- Получить символ в заданной позиции строки string.sGetCh = function(s, ind) return tostring(s):match('.', tonumber(ind)) or '' end -- Вставить символ (символы) в заданную позицию строки string.sInsCh = function(s, ch, ind) s = tostring(s); ind = tonumber(ind) return s:sLeft(ind-1)..tostring(ch)..s:sRight(#s-ind+1) end -- Заменить первое вхождение символа (последовательность символов) в строке на заданный символ (последовательность символов) string.sRepCh = function(s, sm, srp) rep = srp and tostring(srp) or ''; return (tostring(s):gsub(tostring(sm), rep, 1)) or s end -- Заменить все вхождения символа (или последовательности символов) в строке на заданный символ (последовательность символов) string.sRepChAll = function(s, sm, srp) rep = srp and tostring(srp) or ''; return (tostring(s):gsub(tostring(sm), rep)) or s end -- Заменить символ (последовательность символов) в заданной позиции строки string.sRepChInd = function(s, sm, ind) t = s:sArrayCh(); t[tonumber(ind)] = tostring(sm); return table.concat(t) or s end -- слово (последовательность символов ограниченная пробелами, а также началом и концом строки) string.sCountW = function(s) return #tblW(s) or 0 end -- Получить массив слов string.sArrayW = function(s) return tblW(s) end -- Получить первое слово string.sFirstW = function(s) return tostring(s):match('^%s?(%S+)%s') or s end -- Получить последнее слово string.sLastW = function(s) return tostring(s):match("(%S+)%s-$") or s end -- Получить слово по индексу string.sMidW = function(s, ind) id = tonumber(ind); return s:sArrayW()[id <= sCountW(s) and id or 0] or '' end -- Удалить первое слово string.sclrFirstW = function(s) return tostring(s):gsub("%s-(%S+)%s+",'',1) or s end -- Удалить последнее слово string.sclrLastW = function(s) return tostring(s):gsub("%s+(%S+)%s-$",'',1) or s end -- Удалить слово по индексу string.sclrMidW = function(s,ind) t = tblW(s); table.remove(t,tonumber(ind) or 0); return table.concat(t,' ') or s end -- подстрока -- Проверить строку на наличие символов разделителей (из заданного набора) string.sIsSep = function(s) return (tostring(s):find('['..ssep..']')) and true or false end -- Проверяет есть ли разделитель из заданного набора в определённой позиции строки string.sIsSepInd = function(s,ind) return ((ssep:find(tostring(s):match('.',tonumber(ind))))) and true or false end -- Проверяет является ли символ в позиции строки из заданного набора string.sIsChSep = function(ch) return (ssep:find(tostring(ch))) and true or false end -- Получить количество подстрок в строке с разделителем string.sCountSep = function(s, ss) _,b = tostring(s):gsub(tostring(ss),''); return b end -- Получить массив подстрок из строки с разделителем string.sArraySub = function(s, sep) t = {}; sep = sep and tostring(sep) or ','; for w in tostring(s):gfind("%s*([^"..sep.."]+)%s*") do table.insert(t,w:sTrim()) end; return t end -- Получить подстроку по индексу из строки с разделителями string.sSubInd = function(s, sep, ind) return tostring(s):sArraySub(sep)[tonumber(ind)] or '' end -- Вставить подстроку в строку с разделителями в заданную позицию string.sInsSub = function(s, sub, ind) t = s:sArraySub(); table.insert(t, tostring(sub), tonumber(id)); return table.concat(t) or s end -- Преобразовать строку в массив подстрок заданной длины (без разделения слов) string.sText = function(s, n) local rez = {} for sub in tostring(s):gmatch("([^%\n]+)") do rez[#rez+1] = sub end if not n then return rez end local st, t, len, start, last = {} for _,sub in pairs(rez) do t, len, start, last = sub:sArrayW(), 0, 1, 1 while last <= #t do len = len + #t[last] if len >= n then st[#st+1] = table.concat(t,' ', start, last-1); len, start = 0, last else last = last + 1; len = len + 1 end end st[#st+1] = table.concat(t,' ', start) end return st end и ещё одна функция (чуть подправил под общий стиль) от Artos, которую вычитал где-то в старых постах на этом ресурсе -- Artos --/ конвертер числа (number) в 'dec' или 'hex' строку (string) string.Num2Str = function(iNum) --/< любое число, применяемое в игре Сталкер if iNum == math.modf(iNum) then --/ целочисленное? local iAbs = math.abs(iNum) --/ модуль числа if iAbs > 9 then --/ число 2-x и более разрядное? --/ степень ближайшего к модулю бОльшего числа кратного 10-ти local iLv = math.floor(math.log10(iAbs+1)) if iAbs >= 10^iLv and iAbs < 2^(4*iLv) then --/ разрядность 'dec' > 'hex'? if iNum >= 0 then --/ не отрицательное? return string.format('%X', iAbs) --/> 'hex'-строка end --/ отрицательное - упаковываем со знаком return "-" .. string.format('%X', iAbs) --/> 'hex'-строка со знаком end end end return tostring(iNum) --/> 'dec'-строка end Описание к функциям из этого поста, от автора: https://yadi.sk/d/3e6oJoTVsbAgp Изменено 18 Июня 2016 пользователем Zander_driver 3 Ссылка на комментарий
Zander_driver 10 333 Опубликовано 20 Декабря 2015 Автор Поделиться Опубликовано 20 Декабря 2015 Расширение функционала ранее выложенного модуля assembly_dialogs. Добавлено удобное автоматическое формирование "разных ответов нпс" на вопрос ГГ. Берем тот же самый assembly_dialogs.script, в конец файла добавляем следующий код: local phrasedialog_profiles = { } function set_profile_data(profile, data) phrasedialog_profiles[profile] = data end function get_profile_data(profile) return phrasedialog_profiles[profile] end function Generic_block_question_to_npc(dlgdata, setgs) --[[ Блок имитирует разнообразие ответов нпс на вопросы ГГ. Структура: Актор НПС (Вопрос) (ответ 1) (ответ 2)... Для актора на самом деле формируется энное число фраз, с одним и тем же текстом вопроса. Доступна будет одна из них. Какой будет дан ответ на вопрос, определяется до того как вопрос будет задан. Однако игрок ответа не знает. До запуска блока, должна быть сгенерирована таблица доступа по профилю (см. set_profile_data) cdвоего рода "оперативная память" диалога. в нее заносится число, являющееся вариантом ответа, на вопрос в случае если он будет задан. Таким образом, для актора станет доступна из этого блока единственная фраза с этим вопросом, и предопределяющая требуемый ответ нпс. ]] local profile, actortext, count, npcreplyes, actions, mode = setgs[1], setgs[2], setgs[3], setgs[4], setgs[5], setgs[6] local phr_tbl, phr_k, dlg, block_name, block_input_key = dlgdata[1], dlgdata[2], dlgdata[3], dlgdata[4], dlgdata[5] -- assembly_phrase_ex(text, phr_tbl, phr_k, dlg, phrase_key, input_key, a_tbl, p_tbl) local a = 1 local e_table = {} while a < (count + 1) do local xxx = a local F = function() return assembly_dialogs.get_profile_data(profile) == xxx end _G.din_functions_dlg[string.format("%s_%i_access", profile, xxx)] = F local a_phr_key = string.format("%s_a_%i", block_name, xxx) local p_tbl = { [1] = string.format("din_functions_dlg.%s_%i_access", profile, xxx) } assembly_dialogs.assembly_phrase_ex(actortext, phr_tbl, phr_k, dlg, a_phr_key, block_input_key, {}, p_tbl) phr_k = phr_k + 1 local npc_phr_key = string.format("%s_b_%i", block_name, xxx) assembly_dialogs.assembly_phrase_ex(npcreplyes[xxx], phr_tbl, phr_k, dlg, npc_phr_key, a_phr_key, actions[xxx] or {}, {}) phr_k = phr_k + 1 table.insert(e_table, npc_phr_key) a = a + 1 end if mode == 1 then --- свести все выходы в одну фразу local exit_id = string.format("%s_e", block_name) for k, v in pairs(e_table) do phr_tbl[phr_k] = dlg:AddPhrase("", assembly_dialogs.dia(exit_id), assembly_dialogs.dia(v), 0) phr_k = phr_k + 1 end phr_tbl[phr_k] = dlg:AddPhrase("", assembly_dialogs.dia(exit_id.."nd"), assembly_dialogs.dia(exit_id), 0) phr_k = phr_k + 1 return {phr_k, {exit_id.."nd"}} else --- вернуть все варианты ответа в качестве выходов. return {phr_k, e_table} end end Как это работает: на самом деле для актора формируется несколько фраз с одним и тем же вопросом, но с разными прекондишенами, так что доступна будет всегда только одна. А из них уже следуют фразы нпс - разные, и с разными ответами.До того как будет произнесена фраза-вопрос, в любой фразе до этого, необходимо вызвать функцию которая и определит, какой же ответ будет выдан, какая ветка с вопросом будет доступна. function test_generic_question(phr_tbl, phr_k, dlg, block_name, block_input_key) local d_set = {phr_tbl, phr_k, dlg, block_name, block_input_key} local mode_set = { [1] = "test_profile", [2] = "test_question", [3] = 4, [4] = { "que_1", "que_2", "que_3", "que_4" }, [5] = {}, [6] = 1 } return assembly_dialogs.Generic_block_question_to_npc(d_set, mode_set) end function test_run() assembly_dialogs.set_profile_data("test_profile", math.random(1,4)) end Здесь test_run - это та самая функция, которая определит какой же ответ будет выдан. В данном случае используется просто рандом, но, можно учесть какие угодно факторы. Указывается профиль "test_profile" - определяющий, на какой именно вопрос мы генерируем ответы. И передается число, порядковый номер ответа.test_generic_question - функция, которая настраивает и вызывает автоматическое формирование вопроса и ответов. Принимаемые и возвращаемые аргументы у нее соответствуют стандартным требованиям, предъявляемым к фунциям формирующим диалоговые блоки (см. модуль сборки диалогов, "диалоговые блоки - скриптерам"). Впрочем если вы не сильны в скриптах, на них можно вовсе не обращать внимания. Менять их вам не придется, они останутся в таком же виде для любых ваших целей.Менять по своему усмотрению тут можно и нужно вот что: local mode_set = { [1] = "test_profile", [2] = "test_question", [3] = 4, [4] = { "que_1", "que_2", "que_3", "que_4" }, [5] = {}, [6] = 1 } Это таблица настроек вопроса и ответов.1 - профиль. определяет, что за вопрос. должен совпадать с профилем, указанным в функции вычисления ответа.2 - текст фразы вопроса актора. может быть идентификатором из xml-файлов. 3 - число вариантов ответа 4 - тексты вариантов ответа. могут быть идентификаторами из xml-файлов. 5 - таблица, для указания скриптовых функций, вызываемых при различных ответах нпс. можно оставить пустой как в примере. а можно например сделать так: [5] = { {}, {}, {"my_script.func_1", "my_script.func_2"}, {} }, Тогда при 1-м, 2-м, и 4-м вариантах ответа, не будет вызываться ничего, а при 3-м варианте ответа будут вызваны две функции, адрес которых указан в третьей подтаблице.при этом здесь так же, при формировании диалога работает проверка что данные функции существуют - опечатки вам не грозят, вы о них сразу узнаете.6 - если единица, то все варианты ответа будут сведены в один единственный выход из диалогового блока. если ноль, то будет сформировано столько разных выходов из блока, сколько задано вариантов ответа. ; в какой то фразе до самого вопроса a1 = assembly_dialogs.test_run ; подключаем блок вопроса с ответами block2 = assembly_dialogs.test_generic_question, nhb 2 1 Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine. Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист. AMD Ryzen 9 7950X (16 ядер, 32 потока, 5.75 ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD. Ссылка на комментарий
НаноБот 742 Опубликовано 26 Декабря 2015 Поделиться Опубликовано 26 Декабря 2015 (изменено) https://yadi.sk/d/dZNjgRAtinEjU Вер. 1.14 Скрипт для тайминга скриптов имеющий апдейт. Для ТЧ(1.000*), ЧН(1.5.*), ЗП(1.6.*). Для ТЧ возможно может работать и в предрелизных билдах, на лост альфе не тестировался. Для определения общей загрузки скриптами ЦП, используется алгоритм следующий: в начале фрейма самый первый скрипт (апдейт актора) запускает общий таймер и каждый следующий скрипт отработав, запоминает время, и если в тайминг включён скрипт который выполнился самым последним (как правило это сам апдейт этого скрипта) , то фиксируем общее время выполнения скриптовой части движка. Время обычно это не мало, 40-60%, а на пустом уровне 12%(ТЧ), не зря разработчики жаловались на движок XRay, что слишком за скриптован. Замеченные проблемы, может конфликтовать с некоторыми скриптами отрабатывающие эффекты поедание съедобных предметов. https://yadi.sk/d/sdLew6XKqLuzF Вер. 1.15 Тайминг скриптов. Устранил вылет из-за отсутствия функции round в моде OGSE 0693, заменена на math.floor. Немного возросло быстродействия скрипта. Изменено 21 Августа 2017 пользователем НаноБот объединил посты 1 1 ...в конце концов, важен лишь, машинный код. СТАЛКЕР только для ПК! Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти