Карлан 1 049 Опубликовано 19 Октября 2013 Поделиться Опубликовано 19 Октября 2013 (изменено) @Dennis_Chikin, ну очевидно же, что вот так: local pObj = particles_object(string*) if pObj then ... end ====================================================Итак, не претендуя на гениальность представляю набросок функции получения различных конфиговых параметров предметов, функция полностью не дописана, пока работаю над этим, как допишу выложу полную версию: --/ ----------------------------------------------------------------- --/ by Карлан --/ Получение параметров объекта-итема --// oObj - юзердата, секция или номер слота итема | ini - путь до конфига через двойной сплеш(\\) --/ ----------------------------------------------------------------- function fGetItemParameters(oObj, ini) --/< параметр ini входит как заглушка багам несовпадения названий секций, иначе я не могу выпрямить руки пользователям данной функции if ini then sini = ini_file(ini) end local gTbl = {} --// таблица с ключами-параметрами итема local oSection if oObj then --// на передачу таблицы с итемами ума не хватило сделать, т.к. в итоговую таблицу будут писаться значения последнего итема, а не всех if type(oObj) == 'userdata' then printf('userdata') gTbl.userdata = oObj --// только в этом случае есть юзердата #!# oSection = oObj:section() elseif type(oObj) == 'string' then printf('string') oSection = oObj elseif (type(oObj) == 'number' and (oObl > 0 and oObj <= 10)) then printf('number') oSection = db.actor:item_in_slot(oObj):section() end end if oSection and sini:section_exist(oSection) then --// на всякий случай --// Базовые параметры для всех типов итемов gTbl.section = oSection gTbl.class = sini:r_string(oSection, "class") or "" gTbl.clsid = sini:r_clsid(oSection, "class") or nil gTbl.visual = sini:r_string(oSection, "visual") or "" gTbl.inv_name = sini:r_string(oSection, "inv_name") or "" gTbl.real_name = game.translate_string(sini:r_string(oSection, "inv_name")) or "" gTbl.inv_name_short = sini:r_string(oSection, "inv_name_short") or "" gTbl.real_name_short = game.translate_string(sini:r_string(oSection, "inv_name_short")) or "" gTbl.description = sini:r_string(oSection, "description") or "" gTbl.real_description = game.translate_string(sini:r_string(oSection, "description")) or "" gTbl.weight = sini:r_float(oSection, "inv_weight") or 0 gTbl.cost = sini:r_u32(oSection, "cost") or 0 --/ (cost > 0 or 4294967296) gTbl.icon_width = sini:r_u32(oSection, "inv_grid_width") or 0 gTbl.icon_height = sini:r_u32(oSection, "inv_grid_height") or 0 gTbl.icon_x = sini:r_u32(oSection, "inv_grid_x") or 0 gTbl.icon_y = sini:r_u32(oSection, "inv_grid_y") or 0 --// Индивидуальные параметры if string.find(oSection,"ammo_") then --// вот для таких случаев и нужна заглушка gTbl.box_size = sini:r_u32(oSection, "box_size") or 0 gTbl.explosive = sini:r_string(oSection, "explosive") or "" gTbl.tracer = sini:r_string(oSection, "tracer") or "" if gTbl.explosive == "on" then local explode_particles = string.split(sini:r_string(oSection, "explode_particles"), ",", false) for i=1, #explode_particles do gTbl["explode_particles"..i] = explode_particles[i] end end if gTbl.tracer == "on" then gTbl.tracers_color_id = sini:r_u32(oSection, "tracers_color_ID") or 0 end end if string.find(oSection,"outfit") then gTbl.actor_visual = sini:r_string(oSection, "actor_visual") or "" gTbl.full_icon_name = sini:r_string(oSection, "full_icon_name") or "" local full_scale_icon = string.split(sini:r_string(oSection, "full_scale_icon"), ",", false) --// вот этот параметр нахер нужен я не знаю, но сделаю на всякий случай gTbl.full_icon_name_x = tonumber(full_scale_icon[1]) or 0 gTbl.full_icon_name_y = tonumber(full_scale_icon[2]) or 0 gTbl.nightvision_sect = sini:r_string(oSection, "nightvision_sect") or "" gTbl.bones_protection = sini:r_string(oSection, "bones_koeff_protection") or "" --// protection and immunity local pai = {"burn", "strike", "shock", "wound", "radiation", "telepatic", "chemical_burn", "explosion", "fire_wound"} for i=1,#pai do gTbl[i.."_protection"] = sini:r_float(oSection, i.."_protection") or 0 gTbl[i.."_immunity"] = sini:r_float(oSection, i.."_immunity") or 0 end end if string.find(oSection,"wpn_") then end end return gTbl end Внимание! Для работы функции требуется lua_extension.script.Не знаю кому как, но мне гораздо удобнее получать параметры вот так: local ItemParams = GetItemParameters(obj) local cost = ItemParams.cost ,нежели вот так: local cost = system_ini():r_u32(obj:section(), "cost") ====================================================Критика и предложения приветствуются! Я просто не знаю, может так и вовсе неэффективно/медленно работает, или еще что, я пока не замерял. Изменено 19 Октября 2013 пользователем Карлан 2 Ссылка на комментарий
*Shoker* 322 Опубликовано 19 Октября 2013 Поделиться Опубликовано 19 Октября 2013 (изменено) Dennis_Chikin, ну очевидно же, что вот так: Не, если в particle_object передать не существующий путь, то игра вылетит. Насчёт функции чтения всех параметров - она действительно удобная, но есть один недочёт - при необходимости получить всего 1 параметр из конфига ты скопом считываешь сразу 30-40, причём каждый раз. На глаз это не заметно, но с точки зрения оптимизации это ужасно. Тут есть несколько вариантов: 1) Почему бы тебе просто не написать свою функцию-обёртку над system_ini() Я например использую такую: local cost = _u.ltx(секция, "cost", "num") 2) Чтобы не считывать каждый раз значение из конфига, ты можешь считать их один раз (при первом вызове) и занести в таблицу. А при следующих вызовах этой пары секция-строка просто сразу возвращать уже значение из таблицы. Пример можно глянуть здесь: http://pastebin.com/iT9ztQik (На самом деле я не знаю есть ли особая разница в скорости - считывать ли значения каждый раз или один раз и сохранять их в таблицу. но я юзаю второй вариант) Изменено 19 Октября 2013 пользователем *Shoker* Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О Мастер аномалий на свою заднюю точку. Ссылка на комментарий
Карлан 1 049 Опубликовано 20 Октября 2013 Поделиться Опубликовано 20 Октября 2013 (изменено) @*Shoker*, да да, я чето блин загрузился под ночь, тоже думал написать функцию как ты предложил, только не знал как передавать тип параметра, точно, можно же так как у тебя, тогда да, мой вариант хромает. Но все же я его оставлю, иногда бывает нужно несколько параметров скопом получить, тут писать кучу строк лень. Завтра я тогда доделаю и свой вариант и немного под себя подправлю твой, и выложу два кода, для получения всех параметров - мой, и для получения одного-двух параметров - твой. Кстати я сейчас понял как в свой вариант засунуть на место oObj таблицу с итемами, завтра все реализую, и выложу, спасибо за альтернативные варианты. Из соображений оптимизации кода лучше все параметры считывать единожды когда нужно, разумеется не сохраняя в сейв Изменено 20 Октября 2013 пользователем Карлан 1 Ссылка на комментарий
Карлан 1 049 Опубликовано 20 Октября 2013 Поделиться Опубликовано 20 Октября 2013 (изменено) @*Shoker*, как заказывал, теперь можно получать все параметры скопом, можно получить один параметр, и есть флаг получения спецпараметров(например box_size и иже с ним для патронов). Парсинг таблицы с итемами я не сделал, т.к. мне лень переписывать всю функцию --/ ----------------------------------------------------------------- --// by Карлан --/ Получение параметров объекта-итема --// oObj - юзердата, секция или номер слота итема | ini - путь до конфига через двойной сплеш(\\) --/ ----------------------------------------------------------------- function fGetItemParameters(oObj, sValue, sValue_param, bSpecParam, ini) --/< параметр ini входит как заглушка багам несовпадения названий секций, иначе я не могу выпрямить руки пользователям данной функции if ini then sini = ini_file(ini) end if not bSpecParam then bSpecParam = false end local gTbl = {} --// таблица с ключами-параметрами итема local gTbl_value = {} --// таблица с параметрами ключа строки нескольких параметров local oSection if oObj then --// на передачу таблицы с итемами ума не хватило сделать, т.к. в итоговую таблицу будут писаться значения последнего итема, а не всех if type(oObj) == 'userdata' then if not sValue then gTbl.userdata = oObj end--// только в этом случае есть юзердата #!# oSection = oObj:section() elseif type(oObj) == 'string' then oSection = oObj elseif (type(oObj) == 'number' and (oObl > 0 and oObj <= 10)) then oSection = db.actor:item_in_slot(oObj):section() end end if oSection and sini:section_exist(oSection) and not(sValue and sValue_param) then --// на всякий случай --// Базовые параметры для всех типов итемов gTbl.section = oSection gTbl.class = sini:r_string(oSection, "class") or "" gTbl.clsid = sini:r_clsid(oSection, "class") or nil gTbl.visual = sini:r_string(oSection, "visual") or "" gTbl.inv_name = sini:r_string(oSection, "inv_name") or "" gTbl.real_name = game.translate_string(sini:r_string(oSection, "inv_name")) or "" gTbl.inv_name_short = sini:r_string(oSection, "inv_name_short") or "" gTbl.real_name_short = game.translate_string(sini:r_string(oSection, "inv_name_short")) or "" gTbl.description = sini:r_string(oSection, "description") or "" gTbl.real_description = game.translate_string(sini:r_string(oSection, "description")) or "" gTbl.weight = sini:r_float(oSection, "inv_weight") or 0 gTbl.cost = sini:r_u32(oSection, "cost") or 0 --/ (cost > 0 or 4294967296) gTbl.icon_width = sini:r_u32(oSection, "inv_grid_width") or 0 gTbl.icon_height = sini:r_u32(oSection, "inv_grid_height") or 0 gTbl.icon_x = sini:r_u32(oSection, "inv_grid_x") or 0 gTbl.icon_y = sini:r_u32(oSection, "inv_grid_y") or 0 --// Индивидуальные параметры if bSpecParam then if string.find(oSection,"ammo_") then --// вот для таких случаев и нужна заглушка gTbl.box_size = sini:r_u32(oSection, "box_size") or 0 gTbl.explosive = sini:r_string(oSection, "explosive") or "" gTbl.tracer = sini:r_string(oSection, "tracer") or "" if gTbl.explosive == "on" then local explode_particles = string.split(sini:r_string(oSection, "explode_particles"), ",", false) for i=1, #explode_particles do gTbl["explode_particles"..i] = explode_particles[i] end end if gTbl.tracer == "on" then gTbl.tracers_color_id = sini:r_u32(oSection, "tracers_color_ID") or 0 end end if string.find(oSection,"outfit") then gTbl.actor_visual = sini:r_string(oSection, "actor_visual") or "" gTbl.full_icon_name = sini:r_string(oSection, "full_icon_name") or "" local full_scale_icon = string.split(sini:r_string(oSection, "full_scale_icon"), ",", false) --// вот этот параметр нахер нужен я не знаю, но сделаю на всякий случай gTbl.full_icon_name_x = tonumber(full_scale_icon[1]) or 0 gTbl.full_icon_name_y = tonumber(full_scale_icon[2]) or 0 gTbl.nightvision_sect = sini:r_string(oSection, "nightvision_sect") or "" gTbl.bones_protection = sini:r_string(oSection, "bones_koeff_protection") or "" --// protection and immunity local pai = {"burn", "strike", "shock", "wound", "radiation", "telepatic", "chemical_burn", "explosion", "fire_wound"} for i=1,#pai do gTbl[i.."_protection"] = sini:r_float(oSection, i.."_protection") or 0 gTbl[i.."_immunity"] = sini:r_float(oSection, i.."_immunity") or 0 end end if string.find(oSection,"wpn_") then end end return gTbl --// Все не нужны elseif (oSection and sini:section_exist(oSection)) and (sValue and sValue_param and type(sValue) == 'string' and type(sValue_param) == 'string') then if sValue_param ~= "table" then if sValue_param == "float" then sValue = sini:r_float(oSection, sValue) end if sValue_param == "string" then sValue = sini:r_string(oSection, sValue) end if sValue_param == "string_wq" then sValue = sini:r_string_wq(oSection, sValue) end if sValue_param == "num" then sValue = sini:r_s32(oSection, sValue) end if sValue_param == "pnum" then sValue = sini:r_u32(oSection, sValue) end if sValue_param == "bool" then sValue = sini:r_bool(oSection, sValue) end if sValue_param == "vector" then sValue = sini:r_vector(oSection, sValue) end return sValue else sValue = string.split(sini:r_string(oSection, sValue), ",", false) for i=1, #sValue do gTbl_value["sValue_"..i] = sValue[i] end return gTbl_value end end end Примеры вызовов: GetItemParameters("novice_outfit") --// получить базовые параметры GetItemParameters("novice_outfit", nil, nil, true) --// получить все параметры GetItemParameters("novice_outfit", nil, nil, true, "misc\\outfit.ltx") --// получить все параметры из указанного файла GetItemParameters("novice_outfit", "cost", "pnum", false, "misc\\outfit.ltx") --// получить указанный параметр из нужной секции определенного файла Как дойдут руки, перепишу функцию, чтобы можно было таблицей итемы загонять и получать для них скопом все секции, так же есть в планах сделать вызов типа: local ItemParams = GetItemParameters({["bandage"] = "cost, weight", ["medkit"] = "inv_name, real_name" }) Просто, но надо все переписывать P.S. для считывания всех параметров, разумеется, можно было использовать r_line, но он считывает все в алфавитном порядке, и не удобно будет далее работать с параметрами, или я чего-то не понял и нагородил индусский код. Изменено 20 Октября 2013 пользователем Карлан Ссылка на комментарий
Старлей 88 Опубликовано 20 Октября 2013 Поделиться Опубликовано 20 Октября 2013 Привет всем, есть скриптовый диалог. Вот кусок: txt=game.translate_string("dialog_os_psi_artefact_1") phrase = dialog:AddPhrase(txt,"info","0",0) Игра крешиться: Expression : fatal error Function : xray::core::detail::strconcat_error::process File : E:\priquel\sources\engine\xrCore\string_concatenations.cpp Line : 34 Description : <no expression> Arguments : buffer overflow: cannot concatenate strings(1): [d:\stalker clear sky\gamedata\sounds\][ characters_voice\dialogs\{тут идет текст диалога непонятными символами}..ogg] Строка dialog_os_psi_artefact_1 есть в .xml файле с переводом, длина строки 421 символ, 2 точки перед ogg в логе, я так понимаю, потому что в конце предложения есть точка. Как это исправить? Я видел диалоги гораздо большей длины, которые не вылетали... Вылет встречал как-то и в обычном диалоге... А этот появился из неоткуда, работало, работало - да перестало. P.S. А что движок так с каждой репликой что-ли? Проверяет есть ли файл с текстом диалога? Ray Of Hope - кооператив сталкера OldStory Ссылка на комментарий
AndreySol 215 Опубликовано 20 Октября 2013 Поделиться Опубликовано 20 Октября 2013 (изменено) Насчет многострочного текста с прокруткой - нашел одно решение, правда опять с оговоркой. в xml-описании: <!-- скроллбар многострочного текста --> <st_descr_scroll x="0" y="0" width="200" height="150" always_show_scroll="0"/> <!-- статик многострочного текста --> <st_descr_text x="0" y="0" width="215" height="250"> <text font="letterica16" align="l" complex_mode="1" x="1" y="1" a="250" r="0" g="0" b="0"></text> </st_descr_text> Высота статика для текста должна быть больше высоты скроллбара. далее, в скриптах: self.st_descr_text = xml:InitStatic("st_descr_text", nil) -- статик с текстом -- self.st_descr_scroll = xml:InitScrollView("st_descr_scroll",self) -- скроллбар этого статика -- self.st_descr_scroll:SetAutoDelete(true) self.st_descr_scroll:AddWindow(self.st_descr_text,true) self.st_descr_text:SetText(...) self.st_descr_scroll:Show(true) Т.е. примерно так - создаем многострочный статик, на него выводим требуемый текст. Создаем скроллбар, на него аттачим ранее созданный статик, скроллбар обеспечивает нам прокрутку. Все вроде заработало, но есть одна оговорочка - скролл происходит до конца статика, на который выводим текст, а текст может занимать места меньше\больше по высоте, чем высота статика. Мал-мал некрасиво. Буду искать решение, может кто какие мысли\подсказки выскажет ??? Изменено 20 Октября 2013 пользователем AndreySol Ссылка на комментарий
Artos 99 Опубликовано 20 Октября 2013 Поделиться Опубликовано 20 Октября 2013 @Dennis_Chikin, проверить возможность создания партикла вроде как не имеет решения. Единственное что может как-то обезопасить - распарсить скриптом particles.xr и проверить наличие в нем нужной строки. Однако, если партикл состаавной, то и это может не спасти от ошибки. @Старлей, скриптовые (как и обычные) диалоги оперируют идентификаторами, а не самими текстами. Убери game.translate_string и будет тебе "как исправить". "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
AndreySol 215 Опубликовано 20 Октября 2013 Поделиться Опубликовано 20 Октября 2013 TЕЕсть скриптовое окно, по типу окна ввода пароля при использовании кодового замка. Хочу сделать для него обработку управления кнопками как у инветарных ящиков - нажал назначенную в настройках на действие "Использовать" кнопу , ящик открылся, нажал повторно ту-же кнопу или Esc, ящик закрылся. С обработкой кнопы Esc (DIK_ESCAPE) проблем нет, а вот как быть с кнопой "Использовать" ? Ведь ее игрок может переопределить в настройках как захочет, значит надо как-то получить текущую настройку. Подскажите. 1 Ссылка на комментарий
*Shoker* 322 Опубликовано 20 Октября 2013 Поделиться Опубликовано 20 Октября 2013 Попробуй что нибудь придумать с dik_to_bind() local bind = dik_to_bind(dik) if bind == key_bindings.kQUIT then self:OnButton_close_clicked() endВ Lua_help смотри C++ class key_bindings. Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О Мастер аномалий на свою заднюю точку. Ссылка на комментарий
Viнt@rь 50 Опубликовано 20 Октября 2013 Поделиться Опубликовано 20 Октября 2013 (изменено) @AndreySol, вот код из моей энциклопедии для ЗП, элемент, где содержится описание предмета: Скриптовая часть: --* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -- * CItemForm * --* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * class "CItemForm" (CUIListBoxItem) function CItemForm:__init() super() self:SetTextColor(GetARGB(255, 216, 186, 140)) self.sStr = self:GetTextItem() self.sStr:SetFont(GetFontLetterica18Russian()) self.sStr:SetEllipsis(true) end function CNotepad:InitControls() ... self.oDescrList = oCXml:InitListBox("dialog_down:descr_list", self.oDialogDown) ... oCXml:InitWindow("dialog_down:descr_wnd:size", 0, oCWindow) self.oDescrSize = vector2():set(oCWindow:GetWidth(), oCWindow:GetHeight()) ... end function CNotepad:FillDescr(sItemDescr) local aStrgs = StrSplitByLen(sItemDescr, self.bWide and 78 or 85) for k,v in pairs(aStrgs) do local oCItemForm = CItemForm() oCItemForm:SetWndSize(self.oDescrSize) oCItemForm.sStr:SetFont(GetFontLetterica16Russian()) oCItemForm.sStr:SetWndPos(vector2():set(0,0)) oCItemForm.sStr:SetWndSize(self.oDescrSize) oCItemForm.sStr:SetText(v) self.oDescrList:AddExistingItem(oCItemForm) end end ... function CNotepad:OnListItemClicked() self.oDescrList:Clear() self.oDescrList:ScrollToBegin() ... --utils --[[ -- разделяет строку на строки заданной длины(iLen) -- @param string sStr строка -- @param integer iLen длина строки -- @param string sDiv разделитель -- @param boolean bClear обрезать пробелы -- @return table --]] function StrSplitByLen(sStr,iLen,sDiv,bClear) if type(iLen) ~= 'number' then iLen = 1 end if type(sDiv) ~= 'string' then sDiv = " " end local iLenDiv = sDiv:len() local sStr = sStr or "" local tRet = {} --/ субцикл выделения одной строки заданной длины local GetDivPos = function() if sStr:len() > iLen then local iPosDiv = sStr:find(sDiv,1,true) local iPos = iPosDiv while iPosDiv and iPosDiv <= iLen+1 do iPos = iPosDiv iPosDiv = sStr:find(sDiv,iPosDiv+iLenDiv,true) end return iPos end return nil end --/ основной(общий) цикл разделения исходной строки на строки заданной длины local iPos = GetDivPos() while iPos do local sLine = sStr:sub(1,iPos-1) sStr = sStr:sub(iPos+iLenDiv) table.insert(tRet, (not bClear and sLine) or sLine:match('^%s*(.*%S)')) iPos = GetDivPos() end --/ остаток: if sStr ~= "" and sStr ~= sDiv then table.insert(tRet, (not bClear and sStr) or sStr:match('^%s*(.*%S)')) end --/ возвращаем таблицу со строками заданной длины return tRet end и часть разметки: <descr_list x="422" y="317" width="467" height="378" item_height="18" always_show_scroll="0"> <font font="letterica16" x="0" y="10"/> </descr_list> <descr_wnd> <size width="477" height="22"/> </descr_wnd> Карлан, ИМХО много лишнего, все же можно сделать гораздо проще, для вытягивания параметров можно написать обертки, на подобии этих: --[[ -- Read***(iSec,sLin,fIni) -- функции предназначены для чтения значений -- @param string iSec имя секции -- @param string sLin имя строки -- @param string fIni имя ини файла -- @return boolen/string/number --]] function ReadBool(iSec,sLin,fIni) if not fIni then fIni=system_ini() end return fIni:r_bool(iSec,sLin) end function ReadString(iSec,sLin,fIni) if not fIni then fIni=system_ini() end return fIni:r_string(iSec,sLin) end function ReadStringWq(iSec,sLin,fIni) if not fIni then fIni=system_ini() end return fIni:r_string_wq(iSec,sLin) end function ReadFloat(iSec,sLin,fIni) if not fIni then fIni=system_ini() end return fIni:r_float(iSec,sLin) end function ReadNum(iSec,sLin,fIni) if not fIni then fIni=system_ini() end return fIni:r_u32(iSec,sLin) end function ReadLine(iSec,sLin,fIni) if not fIni then fIni=system_ini() end return fIni:r_line(iSec,sLin,"",nil) end --[[ -- Get***(iSec,sLin,fIni) -- функции предназначены для получения значений -- @param string iSec имя секции -- @param string sLin имя строки -- @param string fIni имя ини файла -- @return boolen/integer --]] function GetSectionExist(iSec,fIni) if not fIni then fIni=system_ini() end return fIni:section_exist(iSec) end function GetLineExist(iSec,sLin,fIni) if not fIni then fIni=system_ini() end return fIni:line_exist(iSec,sLin) end function GetLineCount(iSec,fIni) if not fIni then fIni=system_ini() end return fIni:line_count(iSec) end --[[ -- @param string iSec имя секции(через system_ini()) -- @return string/number --]] function GetItemName(iSec) return ReadString(iSec,"inv_name") end function GetItemDescr(iSec) return ReadString(iSec,"description") end function GetItemIconX(iSec) return ReadNum(iSec,"inv_grid_x") end function GetItemIconY(iSec) return ReadNum(iSec,"inv_grid_y") end function GetItemIconW(iSec) return ReadNum(iSec,"inv_grid_width") end function GetItemIconH(iSec) return ReadNum(iSec,"inv_grid_height") end function GetItemWeight(iSec) return ReadFloat(iSec,"inv_weight") end function GetItemCost(iSec) return ReadNum(iSec,"cost") end function GetItemSlot(iSec) return ReadNum(iSec,"slot") end function GetAmmoBoxSize(iSec) return ReadNum(iSec,"box_size") end function GetBoostTime(iSec) return ReadFloat(iSec,"boost_time") end затем, вокруг них написать более глобальную обертку function GetParams(oObj, ...) -- немного твоего кода, для большей универсальности local sSection, oIni local tRet = {} local aArgs = {...} if oObj then if type(oObj) == 'userdata' then sSection = oObj:section() elseif type(oObj) == 'string' then sSection = oObj elseif (type(oObj) == 'number' and (oObl > 0 and oObj <= 10)) then sSection = db.actor:item_in_slot(oObj):section() end end end -- узнаем, указан ли путь к ini файлу? -- вообще не вижу смысла, указывать путь к ini, если это предмет, который может использывать ГГ(одежка/артефакт/оружие и тд) -- но раз у тебя есть этот параметр, то вот кусок кода, как можно узнать, есть ли в табличке путь к ini if next(aArgs) then for i = 1, #aArgs do if tostring(aArgs[i]):match('(.+)%.(%w+)') then -- путь указан, смотрим в нем oIni = ini_file(aArgs[i]) table.remove(i) -- удалим из таблички строку с ini файлом break end end end oIni = oIni or system_ini() -- ini файл не указан local tParamForFunc = { ["inv_name"] = GetItemName -- как альтернативный вариант ["inv_name"] = ReadString } -- для функции loadstring local tParamForFunc2 = { ["inv_name"] = "GetItemName()" -- как альтернативный вариант ["inv_name"] = "ReadString()" } if next(aArgs) then -- не пустая ли табличка? for i = 1, #aArgs do -- тут есть несколько способов, ниже я их опишу -- 1 способ tRet[aArgs[i]] = _G["Get_"..aArgs[i]](sSection) -- при этом функции должны иметь имена в виде Get_название_параметра, к примеру Get_inv_name(sSection) -- 2 способ tRet[aArgs[i]] = _G[tParamForFunc[aArgs[i]]](sSection) -- то есть, с использыванием таблички соответствий параметр = функция -- 3 и 4 способы такие же как и первые 2, только используем функцию loadstring -- вот только тут не помню, нужно ли дописывать скобки к строке функции или нет на всякий случай приведу все возможные варианты tRet[aArgs[i]] = loadstring("Get_"..aArgs[i].."('"..sSection.."')")() -- 1 tRet[aArgs[i]] = loadstring("Get_"..aArgs[i].."(...)")(sSection) -- 2 tRet[aArgs[i]] = loadstring("Get_"..aArgs[i].."()")(sSection) -- 3 tRet[aArgs[i]] = loadstring("Get_"..aArgs[i])(sSection) -- 4 -- с использованием таблички соответствий и соответственно тут тоже надо крутить скобки и параметр, как и выше tRet[aArgs[i]] = loadstring(tParamForFunc2[aArgs[i]])() -- для альтернативного варианта tRet[aArgs[i]] = _G[tParamForFunc[aArgs[i]]](sSection,aArgs[i]) -- тогда не нужно писать обертки tRet[aArgs[i]] = loadstring(tParamForFunc2[aArgs[i]])()(sSection,aArgs[i]) -- еще раз советую обратить внимание и проверить как именно правильно работает loadstring, так как я точно не помню -- думаю, если тебе все же нужен ini, то переделать оберки не составит труда, если же обертки не использывать, а использывать функции, как указано в альтернативном варианте, -- то просто передавать третим параметром наш ini end else -- если таблчика все же пустая, будем считать, что нужно получить все параметры tRet["inv_name"] = GetItemName(sSection) -- и так дальше end return tRet end -- а уже вокруг нее можно написать еще 1 функцию для получения параметров нескольких предметов сразу -- получить из таблички параметр не составляет труда -- пример использывания: local tParams = GetParams("novice_outfit", "inv_name", "description") -- получит 2 параметра local tParams = GetParams("novice_outfit") -- получит все параметры -- пример получения параметров из таблички local sItemName = tParams.inv_name local sItemDescr = tParams.description -- альтернатива local sItemName = tParams["inv_name"] local sItemDescr = tParams["description"] в итоге, если надо получить 1 параметр - используем одиночные обертки, надо получить больше параметров, уже как захочет пользователь, то ли использовать несколько одиночных функций, на крайняк, как вариант, можно использывать 1 обертку которая считает любой параметр в строку: function GetParam(iSec,sParam) return ReadString(iSec,sParam) endконечно, если по этому параметру на самом деле лежит число, то надо будет дополнительно перевести его в числовой тип. Изменено 20 Октября 2013 пользователем Viнt@rь GUI для конвертера от бардака(всего и вся в форматы сдк) Полезный утиль-"Utilits pack(mod)" Ссылка на комментарий
Карлан 1 049 Опубликовано 20 Октября 2013 Поделиться Опубликовано 20 Октября 2013 конечно, если по этому параметру на самом деле лежит число, то надо будет дополнительно перевести его в числовой тип. Это мне и не давало написать нормальную функцию, сейчас тоже до этого додумался и переделал функцию по другому, получилось нечто подобие твоей, гораздо экономичнее(по строкам) и удобнее. И да, в строке у loadstring скобки писать не нужно, и используется она вместе с assert, что у тебя тоже не указано. Свои коды более не выкладываю За сим предлагаю закрыть данный вопрос. Ссылка на комментарий
Viнt@rь 50 Опубликовано 20 Октября 2013 Поделиться Опубликовано 20 Октября 2013 @Карлан, хз, но использование loadstring проходит прекрасно и без assert, так же и в случае ошибки в переданной строке, в логе видно вполне понятное описание ошибки... А по поводу скобок - как уже говорил, подзабыл как именно правильно, давненько не кодил под "сталк", а тем более с использованием этой функции. По поводу самих функций получения параметров, вариантов множество, я же использую простейшие обертки, приведенные мною в первом спойлере на эту тему, далее написанная функция, написана за минут 5, большую половину строк в ней занимают комментарии и примеры разных вариаций/альтернативных способов... Я так понял, что ты завязался на втором примере с функцией GetParam? GUI для конвертера от бардака(всего и вся в форматы сдк) Полезный утиль-"Utilits pack(mod)" Ссылка на комментарий
panzyuza 41 Опубликовано 21 Октября 2013 Поделиться Опубликовано 21 Октября 2013 Прошу помочь с вопросом. Совсем запуталься. В случае, если мы скриптово заспавним у ГГ предмет и после также скриптово его сьедим, сработает ли коллбек юзания у ГГ или нет? AVS_LOCATION_MOD Ссылка на комментарий
*Shoker* 322 Опубликовано 21 Октября 2013 Поделиться Опубликовано 21 Октября 2013 (изменено) И да, в строке у loadstring скобки писать не нужно На самом деле это "фича" Lua, любую функцию можно вызывать как со скобками так и без, правда вроде как если без скобок, то передать можно лишь один аргумент (а если без аргументов или больше чем один, то по моему вообще не вызовется). В тонкости не вдавался. Например можно abort("text"), а можно abort "text" Если просто написать abort без скобок то ничего не будет. (точнее мы просто получим ссылку на функцию) assert же просто если первым аргументом идёт false (или nil), то крэшает игру и пишет какую то фразу в лог. Например assert(false, "yes") крэшнет игру и напишет в логе "yes", если вызывать с одним аргументом, то будет писать "assertion failed!" Так что это не более чем узкоспециализированный аналог abort()-а в сталкере. И кста, просто для тех кто вдруг не знает, если изменять скрипты, то не обязательно выходить из игры, достаточно лишь перезагрузить сохранение и они соберутся заново. Очень экономит время. Прошу помочь с вопросом. Совсем запуталься. В случае, если мы скриптово заспавним у ГГ предмет и после также скриптово его сьедим, сработает ли коллбек юзания у ГГ или нет? Ну а что мешает проверить. Скорее всего сработает, на крайняк если юзаешь предмет скриптово, то в этот момент можешь запоминать ID использованного предмета, и в колбеке на использование проверять этот момент. Изменено 21 Октября 2013 пользователем *Shoker* Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О Мастер аномалий на свою заднюю точку. Ссылка на комментарий
RayTwitty 492 Опубликовано 1 Ноября 2013 Поделиться Опубликовано 1 Ноября 2013 Прошу помочь с вопросом. Совсем запуталься. В случае, если мы скриптово заспавним у ГГ предмет и после также скриптово его сьедим, сработает ли коллбек юзания у ГГ или нет?Скорее всего нет, т.к. на момент спавна предмет еще будет в оффлайне. Ставь колбек на выход в онлайн, после чего кушай. Ну и колбек на юз тогда сработает конечно. Ссылка на комментарий
Akella-96 aka SvD 35 Опубликовано 1 Ноября 2013 Поделиться Опубликовано 1 Ноября 2013 (изменено) Делаю систему использования противогаза а-ля Metro 2033. Застрял на моменте спавна противогаза. Даже если противогаз покоцали, при окончании срока действия фильтра, спавнится абсолютно целый противогаз. Подскажите, как можно запомнить состояние предыдущего противогаза, чтобы потом выставить его новому? Коллбэк на юзание фильтра : local antigas = ActorHasItem("helm_respirator_wo_filter") local gas_cond = antigas:condition() if antigas then awrp_cop.g_start_timer("del_antigas",0,0,15,gas_cond) awrp_cop.send_tip("Срок действия фильтра - 15 минут",nil,nil,5,"actor") SpawnItemInInv("helm_respirator") local se_obj = alife():object(antigas:id()) alife():release(se_obj,true) else awrp_cop.send_tip("У вас нет противогаза!",nil,nil,5,"actor") SpawnItemInInv("filtr") end И функция удаления противогаза с фильтром (дабы заспавнить противогаз без фильтра) function del_antigas(params) local antigas = ActorHasItem("helm_respirator") if antigas then local sobj = SpawnItemInInv("helm_respirator_wo_filter") level.client_spawn_manager():add( sobj.id, 0, function(id,obj) obj:set_condition( tonumber(params) ) end) local se_obj = alife():object(antigas:id()) alife():release(se_obj,true) awrp_cop.send_tip("Срок действия фильтра закончился.",nil,nil,5,"actor") if awrp_cop.has_g_timer("del_antigas") then awrp_cop.stop_g_timer("del_antigas") end end end Таймер -- cтарт таймера в игровом времени function g_start_timer(name,delay_d,delay_h,delay_m,action) local time=level.get_time_days()*60*24+level.get_time_hours()*60+level.get_time_minutes() --time in game minutes if delay_d==nil or delay_h==nil or delay_m==nil then return false end if action==nil then action="" end local a=1 while db.storage[db.actor:id()].pstor["gt"..a] do a=a+1 if a>100 then return false end end awrp.write_variable("gt"..a,name) awrp.write_variable("gt"..a.."d",time+delay_d*60*24+delay_h*60+delay_m) awrp.write_variable("gt"..a.."p",action) return true end Изменено 1 Ноября 2013 пользователем Akella-96 aka SvD AWRP : Re - Load 0.2 © Ссылка на комментарий
Malandrinus 615 Опубликовано 1 Ноября 2013 Поделиться Опубликовано 1 Ноября 2013 как можно запомнить состояние предыдущего противогаза Храни состояние в кастомдате. Кастомдату можно записать нетпактетами, а читать можно даже без нетпакетов. При записи кастомдаты можно не заморачиваться на перевод в оффлайн/онлайн. Клиентский объект не заметит этих манипуляций с серверным объектом. Только не используй чтение кастомдаты из клиентского объекта, поскольку она не будет синхронизироваться с серверным. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Akella-96 aka SvD 35 Опубликовано 1 Ноября 2013 Поделиться Опубликовано 1 Ноября 2013 @Malandrinus, спасибо, конечно, но я почти ни слова не понял . Можно, если не трудно, поправить мою функцию? Если что - можно в ЛС. 1 AWRP : Re - Load 0.2 © Ссылка на комментарий
Artos 99 Опубликовано 1 Ноября 2013 Поделиться Опубликовано 1 Ноября 2013 Подскажите, как можно запомнить состояние предыдущего противогаза, чтобы потом выставить его новому?Ответ же очевиден - сохраняй как тебе удобно!Состояние предмета - число (0.0 ... 1.0) и считав его с прежнего предмета хранить можно и в локальной переменной и в глобальной. Если требуется сохранить в сэйве - то и тут хоть в pstor актору можно засунуть, хоть в отдельный файл... Записывать в кастомдату(?), хм..., я бы не стал... Писать старому предмету - так он же должен быть удален. Писать новому - так его же еще нет, а если есть, то проще сразу выставить требуемое состояние. Судя по приведенным кускам кодов, в функции del_antigas(params) вроде как раз и должно выставляться "прежнее состояние", где под params и подразумевается переданное на вход функции число, соответствующее требуемому состоянию нового предмета. Вот только запуск этой функции через дебри "старомодных" amk-таймеров скорее всего ошибочен, перепутаны аргументы, да и не позволяют эти таймеры передавать "пользовательские данные" (gas_cond) в качестве аргументов. AMK-таймеры принимают аргументами: имя таймера, временнЫе значения и имя функции, которую должен вызвать таймер, и не принимают иного. Т.о. нужно или использовать иной тип таймеров, позволяющий передавать (и при необходимости запоминать у себя в базе) нужный аргумент, или выносить полученный параметр 'gas_cond' наружу (из функции) и снаружи и читать функцией 'del_antigas' "Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени Ссылка на комментарий
AndreySol 215 Опубликовано 1 Ноября 2013 Поделиться Опубликовано 1 Ноября 2013 Akella-96 aka SvD Если я правильно понял, то в ф-ции del_antigas у Вас происходит спаун нового противогаза с секцией "helm_respirator_wo_filter" и удаление старого противогаза с секцией "helm_respirator" ? И если я опять правильно понял, то надо состояние противогаза "helm_respirator" установить для противогаза "helm_respirator_wo_filter" ? Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти