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

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

@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")

====================================================
Критика и предложения приветствуются! Я просто не знаю, может так и вовсе неэффективно/медленно работает, или еще что, я пока не замерял.

Изменено пользователем Карлан
  • Нравится 2
Ссылка на комментарий

 

Dennis_Chikin, ну очевидно же, что вот так:

 

 

Не, если в particle_object передать не существующий путь, то игра вылетит. 

 

Насчёт функции чтения всех параметров - она действительно удобная, но есть один недочёт - при необходимости получить всего 1 параметр из конфига ты скопом считываешь сразу 30-40, причём каждый раз. На глаз это не заметно, но с точки зрения оптимизации это ужасно.

 

Тут есть несколько вариантов:

1) Почему бы тебе просто не написать свою функцию-обёртку над system_ini()

Я например использую такую:

local cost = _u.ltx(секция, "cost", "num")

 

2) Чтобы не считывать каждый раз значение из конфига, ты можешь считать их один раз (при первом вызове) и занести в таблицу. А при следующих вызовах этой пары секция-строка просто сразу возвращать уже значение из таблицы. 

 

Пример можно глянуть здесь: http://pastebin.com/iT9ztQik

(На самом деле я не знаю есть ли особая разница в скорости - считывать ли значения каждый раз или один раз и сохранять их в таблицу. но я юзаю второй вариант)

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

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

Ссылка на комментарий

@*Shoker*, да да, я чето блин загрузился под ночь, тоже думал написать функцию как ты предложил, только не знал как передавать тип параметра, точно, можно же так как у тебя, тогда да, мой вариант хромает. Но все же я его оставлю, иногда бывает нужно несколько параметров скопом получить, тут писать кучу строк лень. Завтра я тогда доделаю и свой вариант и немного под себя подправлю твой, и выложу два кода, для получения всех параметров - мой, и для получения одного-двух параметров - твой. :) Кстати я сейчас понял как в свой вариант засунуть на место oObj таблицу с итемами, завтра все реализую, и выложу, спасибо за альтернативные варианты. 

 

Из соображений оптимизации кода лучше все параметры считывать единожды когда нужно, разумеется не сохраняя в сейв :)

Изменено пользователем Карлан
  • Нравится 1
Ссылка на комментарий

@*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, но он считывает все в алфавитном порядке, и не удобно будет далее работать с параметрами, или я чего-то не понял и нагородил индусский код.

Изменено пользователем Карлан
Ссылка на комментарий

Привет всем, есть скриптовый диалог. Вот кусок:

    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. А что движок так с каждой репликой что-ли? Проверяет есть ли файл с текстом диалога?

Ссылка на комментарий

Насчет многострочного текста с прокруткой - нашел одно решение, правда опять с оговоркой.

в 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)

Т.е. примерно так - создаем многострочный статик, на него выводим требуемый текст. Создаем скроллбар, на него аттачим ранее созданный статик, скроллбар обеспечивает нам прокрутку.

Все вроде заработало, но есть одна оговорочка - скролл происходит до конца статика, на который выводим текст, а текст может занимать места меньше\больше по высоте, чем высота статика. Мал-мал некрасиво.

Буду искать решение, может кто какие мысли\подсказки выскажет ???
 

Изменено пользователем AndreySol
Ссылка на комментарий

@Dennis_Chikin, проверить возможность создания партикла вроде как не имеет решения.

Единственное что может как-то обезопасить - распарсить скриптом particles.xr и проверить наличие в нем нужной строки. Однако, если партикл состаавной, то и это может не спасти от ошибки.

 

@Старлей, скриптовые (как и обычные) диалоги оперируют идентификаторами, а не самими текстами. Убери game.translate_string и будет тебе "как исправить".

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

 

  TЕЕсть скриптовое окно, по типу окна ввода пароля при использовании кодового замка. Хочу сделать для него обработку управления кнопками как у инветарных ящиков - нажал назначенную в настройках на действие "Использовать" кнопу , ящик открылся, нажал повторно ту-же кнопу или Esc, ящик закрылся. С обработкой кнопы Esc (DIK_ESCAPE) проблем нет, а вот как быть с кнопой "Использовать" ? Ведь ее игрок может переопределить в настройках как захочет, значит надо как-то получить текущую настройку. Подскажите.

  • Нравится 1
Ссылка на комментарий

Попробуй что нибудь придумать с 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, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

Ссылка на комментарий

@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
конечно, если по этому параметру на самом деле лежит число, то надо будет дополнительно перевести его в числовой тип. Изменено пользователем Viнt@rь
Ссылка на комментарий

 

 


конечно, если по этому параметру на самом деле лежит число, то надо будет дополнительно перевести его в числовой тип.

 

Это мне и не давало написать нормальную функцию, сейчас тоже до этого додумался и переделал функцию по другому, получилось нечто подобие твоей, гораздо экономичнее(по строкам) и удобнее. И да, в строке у loadstring скобки писать не нужно, и используется она вместе с assert, что у тебя тоже не указано. Свои коды более не выкладываю :) За сим предлагаю закрыть данный вопрос.

Ссылка на комментарий

@Карлан, хз, но использование loadstring проходит прекрасно и без assert, так же и в случае ошибки в переданной строке, в логе видно вполне понятное описание ошибки... А по поводу скобок - как уже говорил, подзабыл как именно правильно, давненько не кодил под "сталк", а тем более с использованием этой функции.

По поводу самих функций получения параметров, вариантов множество, я же использую простейшие обертки, приведенные мною в первом спойлере на эту тему, далее написанная функция, написана за минут 5, большую половину строк в ней занимают комментарии и примеры разных вариаций/альтернативных способов... Я так понял, что ты завязался на втором примере с функцией GetParam?

Ссылка на комментарий

Прошу помочь с вопросом. Совсем запуталься. В случае, если мы скриптово заспавним у ГГ предмет и после также скриптово его сьедим, сработает ли коллбек юзания у ГГ или нет?

Ссылка на комментарий

 

И да, в строке у loadstring скобки писать не нужно

 

 

На самом деле это "фича" Lua, любую функцию можно вызывать как со скобками так и без, правда вроде как если без скобок, то передать можно лишь один аргумент (а если без аргументов или больше чем один, то по моему вообще не вызовется). В тонкости не вдавался. Например можно abort("text"), а можно abort "text"

Если просто написать abort без скобок то ничего не будет. (точнее мы просто получим ссылку на функцию)

 

assert же просто если первым аргументом идёт false (или nil), то крэшает игру и пишет какую то фразу в лог.

Например assert(false, "yes") крэшнет игру и напишет в логе "yes", если вызывать с одним аргументом, то будет писать "assertion failed!"

Так что это не более чем узкоспециализированный аналог abort()-а в сталкере.

 

И кста, просто для тех кто вдруг не знает, если изменять скрипты, то не обязательно выходить из игры, достаточно лишь перезагрузить сохранение и они соберутся заново. Очень экономит время. 

 

Прошу помочь с вопросом. Совсем запуталься. В случае, если мы скриптово заспавним у ГГ предмет и после также скриптово его сьедим, сработает ли коллбек юзания у ГГ или нет?

 

Ну а что мешает проверить. :)

Скорее всего сработает, на крайняк если юзаешь предмет скриптово, то в этот момент можешь запоминать ID использованного предмета, и в колбеке на использование проверять этот момент. 

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

Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

Мастер аномалий на свою заднюю точку.

Ссылка на комментарий

Прошу помочь с вопросом. Совсем запуталься. В случае, если мы скриптово заспавним у ГГ предмет и после также скриптово его сьедим, сработает ли коллбек юзания у ГГ или нет?

Скорее всего нет, т.к. на момент спавна предмет еще будет в оффлайне.

Ставь колбек на выход в онлайн, после чего кушай. Ну и колбек на юз тогда сработает конечно.

Ссылка на комментарий

Делаю систему использования противогаза а-ля 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

 

 

Изменено пользователем Akella-96 aka SvD

AWRP : Re - Load 0.2 ©

Ссылка на комментарий

 

 


как можно запомнить состояние предыдущего противогаза

Храни состояние в кастомдате. Кастомдату можно записать нетпактетами, а читать можно даже без нетпакетов. При записи кастомдаты можно не заморачиваться на перевод в оффлайн/онлайн. Клиентский объект не заметит этих манипуляций с серверным объектом. Только не используй чтение кастомдаты из клиентского объекта, поскольку она не будет синхронизироваться с серверным.

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Ссылка на комментарий

@Malandrinus, спасибо, конечно, но я почти ни слова не понял  :crazy: . Можно, если не трудно, поправить мою функцию? Если что - можно в ЛС.

  • Нравится 1

AWRP : Re - Load 0.2 ©

Ссылка на комментарий

 

 

Подскажите, как можно запомнить состояние предыдущего противогаза, чтобы потом выставить его новому?
Ответ же очевиден - сохраняй как тебе удобно!

Состояние предмета - число (0.0 ... 1.0) и считав его с прежнего предмета хранить можно и в локальной переменной и в глобальной. Если требуется сохранить в сэйве  - то и тут хоть в pstor актору можно засунуть, хоть в отдельный файл... Записывать в кастомдату(?), хм..., я бы не стал... Писать старому предмету - так он же должен быть удален. Писать новому - так его же еще нет, а если есть, то проще сразу выставить требуемое состояние.

 

Судя по приведенным кускам кодов, в функции del_antigas(params) вроде как  раз и должно выставляться "прежнее состояние", где под params и подразумевается переданное на вход функции число, соответствующее требуемому состоянию нового предмета. Вот только запуск этой функции через дебри "старомодных" amk-таймеров скорее всего ошибочен, перепутаны аргументы, да и не позволяют эти таймеры передавать "пользовательские данные" (gas_cond) в качестве аргументов. AMK-таймеры принимают аргументами: имя таймера, временнЫе значения и имя функции, которую должен вызвать таймер, и не принимают иного.

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

"Но иногда найдется вдруг чудак, этот чудак все сделает не так ..."© Машина времени

Ссылка на комментарий

Akella-96 aka SvD

 

Если я правильно понял, то в ф-ции del_antigas у Вас происходит спаун нового противогаза с секцией "helm_respirator_wo_filter" и удаление старого противогаза с секцией "helm_respirator" ? И если я опять правильно понял, то надо состояние противогаза "helm_respirator" установить для противогаза "helm_respirator_wo_filter" ?

Ссылка на комментарий

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

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   1 пользователь

AMK-Team.ru

×
×
  • Создать...