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

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

Включая и автосейв?

При любом сохранении.

 

Разумеется, хранилище может переполняться от того, что туда пишется слишком много данных. Максимальный размер net-пакета (в том числе актора) в ТЧ равен 8192 байта, в ЧН/ЗП вдвое больше. Обрати внимание на содержимое скопированной тобой функции save_old(): в net-пакет актора что-то пишут менеджеры погоды, тайников и заданий, радара и детектора. Много? Без детального изучения неизвестно. Плюс запись текущих настроек. Плюс pstor, то есть хранилище, в которое пихали данные все, кому не лень. Посмотри в твоей же clean_pstor(): из pstor вычищаются аномалии, таймеры, прочие служебные переменные - на всё это нужно место в net-пакете актора. А сколько в твоём моде других, неучтённых здесь мест использования штатных функций записи/чтения xr_logic.pstor_store() и xr_logic.pstor_retrieve()? То-то и оно. Увлёкся, записал лишнее - опаньки, вышли за 8 килобайт.

 

Потому и начали придумывать альтернативные варианты. Подробнее о разных скриптовых способах записи данных можно прочитать здесь: http://www.amk-team.ru/forum/topic/6185-skriptovanie/page-209#entry694323

Изменено пользователем Kirgudu
  • Спасибо 3
Ссылка на комментарий

 

 

таймеры,

А можно про таймеры подробнее? В смысле, в какой момент начинается заполнение пакета: при первом вызове таймера или как-то раньше/в другое время?

  • Спасибо 1

Сталкер - наше всё!

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

в какой момент начинается заполнение пакета

В пстор при старте таймера пишется три перменных. Вот здесь они чистятся:

 

amk.del_variable("rt"..i)

amk.del_variable("rt"..i.."d")

amk.del_variable("rt"..i.."p")

amk.del_variable("gt"..i)

amk.del_variable("gt"..i.."d")

amk.del_variable("gt"..i.."p")

 

 

rt* - реального времени, gt* - игрового.

  • Спасибо 2

Аддон для ОП-2.09.2: Яндекс/Google/GitHub

naxac.gif

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

Такая проблема: вот логика НПЦ

 

 

 

 
[logic]
active = remark@1
on_hit = hit
 
[remark@1]
target = actor
no_move = true
 
[remark@2]
target = actor
no_move = true
 
[hit]
on_info = {+gauss_online} remark@2 %+sar_brut_death =make_suicide%
on_info2 = %+sar_brut_death =make_suicide%

Вот сама функция, которая должна выполняться:

 

function make_suicide(actor, npc)

news_manager.send_tip(db.actor, "триггер смерти", nil, nil, 20000)
npc:kill(npc)
end

 

Но она не выполняться. Ни одно из условий в hit не работет. Как так то?


UPD1. Такое дело - НПЦ бессмертный, ему выставлены конфиги иммунитета наподобие Сахарова. Делаю вывод - хиты просто по нему не проходят. Сделал его смертным - всё заработало. Нашел xr_hit.script дабы сделать передачу id стрелка, даже если дамаг = 0. Что я там только не делал, даже в xr_motivator заглянул. Не помогло, хотя там есть строчки с комментариями мол дамага 0, игнорим... А что-то сделать нужно!

Не соответствует правилам.

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

Ребятки, проконсультируйте. Тут совсем нетривиальная проблема.

В отдельном файле объявил переменную.

 

Допустим в test_scr объявил -  local test = 0

Из другого в теле какой-либо функции : test_scr.test = 1

В итоге после проверки всё равно test равен 0

Где я ошибся?

Не соответствует правилам.

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

@CRAZY_STALKER666, так важно ещё в какой области ты переменную объявляешь - мб она у тебя перезаписывается последующим вызовом скрипта.

Ссылка на комментарий
Допустим в test_scr объявил -  local test = 0 Из другого в теле какой-либо функции : test_scr.test = 1 В итоге после проверки всё равно test равен 0

Файл test_scr.script

_G.test = 0

Файл sample.script

test = 1

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

Добрый день. Есть фон(background) и на нём статик(icon):

xml:InitStatic("background:icon", self.background)

Как мне этому статику поменять текстуру по условию при открытии этого окна? С помощью конструктора(ООП)?

Ссылка на комментарий
Как мне этому статику поменять текстуру по условию при открытии этого окна?

Раз за почти 12 часов реального времени на этот пустяшный вопрос из корифеев никто не ответил, попробую я, игзой.

 

Это не только просто, а просто очень просто. Во сказал! Здесь возможны 2 варианта реализации, при любом из которых вы должны иметь готовые текстуры всех статиков.

Если Вы являетесь ярым сторонником xml, то смотрите вариант 1. Если же Вам все едино, "что камым, что Колыма", то вариант 2.

 

Ремарка: Я сильно смеялся тут недавно, когда читал (где уже не помню) дискуссию сторонников и противников xml и скриптового подходов в скриптинге. Ну дети прямо, прости меня Всевышний. Не вмешивался потому, что "висел" тогда на 99% наказаний, а, если бы встрял, то точно был бы отлучён от тела этого ресурса. Да и сейчас эту тему развивать не буду.

 

Исходим из того, что имеется xml файл описания текстур (если Вы не знаете, что это такое, то дальше читать вообще не имеет смысла)

В xml файле описания окна прописываете несколько разных тегов вашего статика:

<background>
    <icon_1 [нужные вам агрументы]>
        <texture>icon1</texture>
    </icon_1>
    <icon_2 [нужные вам агрументы]>
        <texture>icon2</texture>
    </icon_2>
    <icon_3 [нужные вам агрументы]>
        <texture>icon3</texture>
    </icon_3>
</background>

В файле скрипта окна пишите:

if условие_1 then
	xml:InitStatic("background:icon_1", self.background)
elseif условие_2 then
	xml:InitStatic("background:icon_2", self.background)
elseif условие_3 then
	xml:InitStatic("background:icon_3", self.background)
end

Это всё.

 

Это чисто скриптовое решение. Файл xml не требуется. Предполагается, что все ваши текстуры находятся в отдельных файлай dds и находиться в папке texture/ui. Можно их объединить и в один. Это увеличит код на пару строк. Каких сообразите сами, или подождите пару месяцев (с меня снимут необонованные штрафы и я опубликую коды пакета графических примитивов UI, которые легко решают все подобные проблемы) тогда Вам и это не понадобится.

Итак, приступаем.

В файле скрипта окна пишите:

local icon = CUIStatic() -- автоудаление можно не задавать т.к. мы объявили её локальной
background:AttachChild(icon)
icon:Init([инициализируем позицию и размеры])
if условие_1 then
	icon:InitTexture("ui\\icon_1")
elseif условие_2 then
	icon:InitTexture("ui\\icon_2")
elseif условие_3 then
	icon:InitTexture("ui\\icon_3")
end
icon:SetStretchTexture(true) -- подгоняем текстуру под заданные параметры

Вы будете смеяться, но это опять всё.

 

А про ООП в Сталкере и Lua забудьте. Здесь нет классов в обычном их понимании. Есть псевдоклассы (я ими тоже широко пользуюсь), но это совсем другая песня. В конструкторы классов движка можно попасть только через исходники (они есть) или другими извращениями, но это, для Сталкера, путь в никуда, как-бы некоторые себя этим не тешили.

Удачи.

Изменено пользователем Serge!
  • Спасибо 1
Ссылка на комментарий

По проблеме из поста #8024.

На бессмертных НПЦ не срабатывала схема xr_hit.

Вот полный скрипт нового xr_hit. Вдруг кто еще с такой проблемой столкнется...

 

 

class "action_process_hit"

function action_process_hit:__init(obj, storage)
self.object = obj
self.st = storage
end

function action_process_hit:hit_callback(obj, amount, local_direction, who, bone_index)
--if amount == 0 then
-- FIXME if_then_else
-- --printf("[%s] hit by [%s]: 0 damage, ignoring", obj:name(), if_then_else(who, who:name(), ""))
---db.storage[obj:id()].hit.who = who:id()
--return
--end
if who or amount == 0 then
printf("[%s] hit by [%s]", obj:name(), who:name())
news_manager.send_tip(db.actor, "!!"..obj:name().." hit by "..who:name().."!!", 0, "default", 10000)
db.storage[obj:id()].hit.who = who:id()
else
printf("[%s] hit by [unknown]", victim:name())
db.storage[obj:id()].hit.who = -1
end
if db.storage[self.object:id()].active_scheme then
if xr_logic.try_switch_to_another_section(obj, self.st, db.actor) then
return
end
end
end

----------------------------------------------------------------------------------------------------------------------
-- binder
----------------------------------------------------------------------------------------------------------------------
function add_to_binder(npc, ini, scheme, section, storage)
local new_action = this.action_process_hit(npc, storage)
storage.action = new_action
end

function set_hit_checker(npc, ini, scheme, section)
local st = xr_logic.assign_storage_and_bind(npc, ini, scheme, section)
st.logic = xr_logic.cfg_get_switch_conditions(ini, section, npc)

-- НЕ СТАВИТЬ hit callback напрямую - получаем его из motivator-а через
-- event в подписанном на него action-е:
--npc:set_callback(callback.hit, st.action.hit_callback, st.action)
xr_logic.subscribe_action_for_events(npc, st, st.action)
end

function disable_scheme(npc, scheme)
-- При отключении схемы, нужно снять подписку, чтобы hit callback перестал
-- передаваться:
--npc:set_callback(callback.hit, nil)
local st = db.storage[npc:id()][scheme]
if st then
xr_logic.unsubscribe_action_from_events(npc, st, st.action)
end
end

 

Добавлено Kirgudu,

Ссылки вида #8024 давать бессмысленно. Один спереди удалённый пост, и всё съезжает. Вот и сейчас пост #8024 - от naxac.

Добавлено Kirgudu,

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

Не соответствует правилам.

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

Такие вопросы:

1. Каков номер слота под артефакты в ТЧ. Пробовал 0, -1. В system.ltx вообще упоминания не нашел, да и там пояснения к слотам какие-то неверные...

2. Как соранить набор вещей ГГ, а потом выдать их ему в ящике? Знаю, что так работает Арена, но я немного не разобрался...

Не соответствует правилам.

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

@CRAZY_STALKER666, 1. Если ты имеешь в виду пояс, то пояс - это не слот, и номера у него нет. А активировать артефакт можно из первого или второго слота. Может, и из других тоже.

2. actor:transfer_item(item, box)

где item - предмет, box - ящик. Например так

 

function transfer_all_to_box()
  local box = level_object_by_sid(12345) -- 12345 - стори-ид ящика
  db.actor:iterate_inventory(function (actor, item)
    actor:transfer_item(item, box)
  end,
  db.actor)
end
  • Нравится 1
  • Полезно 1

Аддон для ОП-2.09.2: Яндекс/Google/GitHub

naxac.gif

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

Тогда перефразирую вопрос - как отследить появление определенного артефакта на поясе у ГГ?

Не соответствует правилам.

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

 

 

как отследить появление определенного артефакта на поясе у ГГ?

Движковой ф-ции для этого в ТЧ нет. Вроде есть какой-то костыльно-скриптовый способ отследить объекты на поясе, если память не подводит - от Kirgudu. Спроси у него...

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

@CRAZY_STALKER666, если мне склероз не изменяет, то:

Надо заспавнить в инвентарь предмет и потом перебирать инвентарь через iterate_inventory. Предметы, которые будут передаваться в итератор после заспавненного, будут либо в слотах, либо на поясе. Проверяешь их - если не в слоте, значит на поясе. Далее сверяешь то, что получилось с тем, что было на предыдущей проверке. В солянке, по крайней мере, используется такой метод - файл inventory.script. Единственное - именно момент перемещения предмета на пояс не отловить.

А в проекте X-Ray Extensions добавлены каллбэки для актера на перемещение предметов между слотами, рюкзаком и поясом.

Аддон для ОП-2.09.2: Яндекс/Google/GitHub

naxac.gif

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

@CRAZY_STALKER666, дополню пост naxac'а. А точнее содержание файла:

need_update = true

local belt = {}
local belt_id = {}
local belt_status = false
local inventory_open = false
local separator_spawned = false
local separator = "separator"
local af_idol_monolita_on_belt = false

local debug = false
local flag



function update()

	if (need_update == false) or has_alife_info("paused_on_load") then return end

	if debug == true and belt_status == true then get_console():execute("belt_status=false") end
	belt_status = false

	-- Спавним разделяющий елемент
	if (separator_spawned == false) then
		alife():create(separator,
			db.actor:position(),
			db.actor:level_vertex_id(),
			db.actor:game_vertex_id(),
			db.actor:id())
		separator_spawned = true
		if debug == true then get_console():execute("separator_spawned") end
		return
	end

	belt = {}
	belt_id = {}
	flag = 0

	-- Сканируем инвентарь
	db.actor:inventory_for_each(scan_inv)
--	вместо количества теперь идет проверка по иммунитетам
--	remove_duplicate()
	check_immunities()
	check_idol_monolita()
	
	need_update = false

	-- Удаляем разделяющий елемент
	db.actor:inventory_for_each(del_separator)
	separator_spawned = false

	if debug == true and belt_status == false then get_console():execute("belt_status=true") end
	belt_status = true

	if debug == true then
		for i,k in pairs(belt) do
			get_console():execute(i.."="..k)
		end
	end
	
end

-- Перебор предметов инвентаря
function scan_inv(item)
	local section = item:section()

	if section == separator then
		flag = 1
		return
	end

	if flag == 1 then
		if slot_item(item) ~= nil then
			flag = 2
		else
			insert_to_table(belt, section)
			belt_id[item:id()] = true
		end
	end
end

-- Добавление в таблицу
function insert_to_table(tbl, section)
	if tbl[section] == nil then
		tbl[section] = 1
	else
		tbl[section] = tbl[section] + 1
	end
end

-- Удаление из таблицы
function remove_from_table(tbl, section)
	if tbl[section] == 1 then
		tbl[section] = nil
	else
		tbl[section] = tbl[section] - 1
	end
end

-- Удаление разделяющего предмета
function del_separator(item)
	if item:section() == separator then
		alife():release(alife():object(item:id()), true)
		if debug == true then get_console():execute("separator_removed") end
	end
end

-- Определение налечия предмета в одном из слотов
function slot_item(item)
	for i=0,12 do
		local obj = db.actor:item_in_slot(i)
		if obj and item:id() == obj:id() then
			return i
		end
	end

	return nil
end

-- Поднятие предмета
function on_item_take(item)
	if item:section() == separator then return end

	if (inventory_open == false) then
		if (separator_spawned == true) then
			db.actor:inventory_for_each(del_separator)
			separator_spawned = false
		end

		need_update = true
		if debug == true then get_console():execute("item_take") end
	end
end

-- Выброс предмета
function on_item_drop(item)
	if item:section() == separator then return end

	if (inventory_open == false) then
		if (separator_spawned == true) then
			db.actor:inventory_for_each(del_separator)
			separator_spawned = false
		end

		need_update = true
		if debug == true then get_console():execute("item_drop") end
	end
end

-- Открытие/закрытие инвентаря
function on_inventory_info(info_id)
	if info_id == "ui_inventory" then
		inventory_open = true
		if debug == true then get_console():execute("inventory_open") end

	elseif info_id == "ui_inventory_hide" then
		inventory_open = false
		need_update = true
		if debug == true then get_console():execute("inventory_close") end
	end
end

--[[
function check_blood()
--   if belt_status == true then
      if belt["af_blood"]~=nil and belt["af_blood"]>0 then -- то есть когда параметр пояса[af_blood] равен 1, 2, 3.. Сколько навесишь Камней.
             amk.send_tip("Кровь Камня на поясе")
          end
--   end
end
]]

--[[
local unique_sect =
{
["af_caterpillar"] = true,
["af_arhara_globus"] = true,
["af_vyvert_green"] = true,
["af_blood_green"] = true,
["af_dummy_spring_red"] = true,
["af_dummy_battery_red"] = true,
["af_dummy_pellicle_red"] = true,
["af_babka_3"] = true,
["af_babka_4"] = true,
["af_armor_4"] = true,
["af_cry_3"] = true,
["af_dik_4"] = true,
["af_kol_3"] = true,
["af_kol_4"] = true,
["af_pudd_4"] = true,
["af_spirit_3"] = true,
["af_spirit_4"] = true,
["af_gold_fish"] = true,
["af_eye_voron"] = true
}

--оставляет на поясе по одному(фиг,теперь двум) артефакту каждого вида
function remove_duplicate()
	local t = check_duplicate()
	for k, v in pairs(belt_id) do
		local sobj = alife():object(k)
		if sobj then
			local sect = sobj:section_name()
			--if is_unique(sobj:clsid()) and t[sect] ~= nil  and t[sect] > 0 then
			--if is_unique(sect) and t[sect] ~= nil  and t[sect] > 0 then
			if unique_sect[sect] and t[sect] ~= nil and t[sect] > 0 then
				alife():release(sobj, true)
				local text="Убраны лишние артефакты "..game.translate_string(amk.get_inv_name(sect)).." с пояса"
				news_manager.send_tip(db.actor, text, nil, nil, nil)
				amk.spawn_item_in_inv(sect, db.actor)
				t[sect] = t[sect] - 1
			end
		end
	end
end

--собирает инфу о дупликатах на поясе
--возвращает таблицу вида [секция арта] = <количество лишних артов>
function check_duplicate()
	local result = {}
	for k, v in pairs(belt) do
		if v > 2 then
			result[k] = v - 2
		end
	end
	return result
end
]]

--возвращает true, если предмет должен быть на поясе в единственном числе
--function is_unique(section)
	--[[local result = false
        for i=1,table.getn(unique_sect) do
            if section == unique_sect[i] then
                result = true
                break
            end
        end]]

	
	--return (section ~= nil and unique_sect[section] == true)
	--return result
--end


-- Проверка на иммунитеты и удаление с пояса лишних артов
local imm_limits = {100, 86, 73, 60}
local imm_limit, sobj, sect, imm_sect, bad_imm

local immunities = {
{sect="burn_immunity",name="Ожог",total=0},
{sect="strike_immunity",name="Удар",total=0},
{sect="shock_immunity",name="Электрошок",total=0},
{sect="wound_immunity",name="Разрыв",total=0},
{sect="radiation_immunity",name="Радиация",total=0},
{sect="telepatic_immunity",name="Телепатия",total=0},
{sect="chemical_burn_immunity",name="Химический ожог",total=0},
{sect="explosion_immunity",name="Взрыв",total=0},
{sect="fire_wound_immunity",name="Пулестойкость",total=0}
}

function check_immunities()
	if db.actor:object("af_invul") then return end

	imm_limit = imm_limits[level.get_game_difficulty()+1]
	
	repeat
		-- считаем иммунитеты
		total_immunities()
		
		-- проверяем иммунитеты
		bad_imm = bad_immunity()
		if bad_imm then 
			-- есть перебор в иммунитете - удаляем лишний арт и вновь считаем иммунитеты
			imm_remove_art(bad_imm)
		else
			-- все ок
			break
		end
	until false
end

function imm_remove_art(imm)
	for k, v in pairs(belt_id) do
		sobj = alife():object(k)
		if sobj then
			sect = sobj:section_name()
			imm_sect = rx_utils.read_from_ini(nil, sect, "hit_absorbation_sect", nil, 1)
			if imm_sect and rx_utils.read_from_ini(nil, imm_sect, immunities[imm].sect, 1, 3) < 1 then -- арт увеличивает иммунитет
				alife():release(sobj, true)
				amk.spawn_item_in_inv(sect, db.actor)
				remove_from_table(belt, sect)
				belt_id[k] = nil
				news_manager.send_tip(db.actor, "Для текущего уровня сложности создаваемый артефактами имммунитет "..immunities[imm].name.." не должен превышать "..tostring(imm_limit).."%. Артефакт "..game.translate_string(amk.get_inv_name(sect)).." убран с пояса.", nil, "nano", 20000)
				return
			end
		end
	end
end

function bad_immunity()
	for i=1,#immunities do
		if immunities[i].total > imm_limit then
			return i
		end
	end
	return nil
end

function total_immunities()
	for i=1,#immunities do
		immunities[i].total = 0
	end
	for k, v in pairs(belt_id) do
		sobj = alife():object(k)
		if sobj then
			sect = sobj:section_name()
			imm_sect = rx_utils.read_from_ini(nil, sect, "hit_absorbation_sect", nil, 1)
			if imm_sect then
				-- считаем иммунитеты
				for i=1,#immunities do
					immunities[i].total = immunities[i].total+100-math.floor(rx_utils.read_from_ini(nil, imm_sect, immunities[i].sect, 1, 3)*100+0.1)
				end
			end
		end
	end
end

-- предмет на поясе
function on_belt(sect)
	return belt[sect]
end

function items_on_belt()
	local count = 0
	for k,v in pairs(belt) do
		count = count+v
	end
	return count
end

function is_free_belt_slot()
	return items_on_belt() < rx_utils.read_from_ini(nil, "inventory", "max_belt", 1, 3)
end

function get_free_belt_slot()
	if is_free_belt_slot() then return end
	
	local sect
	
	for k,v in pairs(belt_id) do
		sect = level.object_by_id(k):section()
		
		if not string.find(sect, "bioradar") and sect ~= "af_invul" and rx_utils.read_from_ini(nil, sect, "class", "", 1) ~= "D_SIMDET" then
			alife():release(alife():object(k), true)
			amk.spawn_item_in_inv(sect, db.actor)
			remove_from_table(belt, sect)
			belt_id[k] = nil
			return
		end
	end
end

-- Идол Монолита на поясе
function check_idol_monolita()
	if not has_alife_info("snp_shadows_start") or has_alife_info("snp_shadows_done") then return end

	if belt["af_idol_monolita"] then
		if not af_idol_monolita_on_belt then
			-- одели арт
			af_idol_monolita_on_belt = true
			level.set_weather("grey")
		end
	else
		af_idol_monolita_on_belt = false
	end
end 

 

 

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

Большое спасибо! Но увы, такие дикие костыли использовать не могу в моде, народ обидеться)

Не соответствует правилам.

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

@CRAZY_STALKER666, Зря Вы так резко отмахиваетесь. Метод void inventory_for_each(function *iterator) это не единственный, но в вашем случае самый оптимальный способ решить свои проблемы. Разумеется в приведёном примере надо выкинуть98% кода, но такой подход активно используется в модах. Вы же не думаете, что являетесь единственным, кто сталкивался с такой задачей?

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

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

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

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

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

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

Войти

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

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

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

AMK-Team.ru

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