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

Скриптование


Svoboда

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

Какое сильное колдунство… В оригинальном коде всего одно упоминание такого callback'а, и то в качестве теста. Всем спасибо, противная недоработка наконец-то "подпернута" костылем.

Поделиться этим сообщением


Ссылка на сообщение

Я опять встрял, и не могу понять, во что именно… Есть две функции: одна привязана к "info_callback" и спавнит предмет в момент начала торговли, другая запускается после спавна предмета и должна получить его id. Как только я пытаюсь добавить в аргументы второй функции "info_id" для дальнейших действий на основании инфо-поршней из основного колбэка, функция перестает видеть созданный объект, хотя вызывается строго после его создания. Может ли проблема быть в том. что в первой функции создаются два объекта, а колбэк только на одном?

Код ниже, требуется передать (info_id) в функцию "transfer".

Spoiler



function box_id(sect)
	for i = 0, 65535 do
		local obj = level.object_by_id(i)
		if obj and obj:section() == sect then
			return obj:id()
		end
	end
end

function box_spawn(info_id)
	local act = db.actor
	if info_id == "ui_trade" then
		local act_pos = act:position()

		alife():create( "box_ex", vector():set( (act_pos.x + 1), (act_pos.y), (act_pos.z) ),
			act:level_vertex_id(), act:game_vertex_id() )

		local spawn = alife():create( "box_eq", vector():set( (act_pos.x), (act_pos.y), (act_pos.z + 1) ),
			act:level_vertex_id(), act:game_vertex_id() )
		level.client_spawn_manager():add(spawn.id, -1, transfer)
	end
end

function transfer()
	local act = db.actor
	local box_1 = box_id("box_eq")
	local box_2 = box_id("box_ex")

	if box_1 and box_2 then
		news_manager.send_tip(act, "spawned")
	else
		news_manager.send_tip(act, "missing")
	end
end

 

 

 

Переделал вызовы так, чтобы "info_id" читался непосредственно в "bind_stalker", а функция, зависящая от спавна, только перебрасывала предметы. С одной коробкой работает, с двумя – не переносятся предметы из второй коробки, хотя id второй коробки читается правильно и предметы _в_ эту коробку точно переносятся, если что-нибудь купить (коробки на время теста не удаляются). Посмотрите, пожалуйста, кто-нибудь, где я косячу: https://drive.google.com/open?id=1ak0_jspeRXxoTxxHIDLCe-J0-Psp41DS

Поделиться этим сообщением


Ссылка на сообщение

@Kirgudu Не "возможно", а так и есть – надо дождаться выхода в онлайн, чтобы потом переносить объекты в созданные коробки. Ссылку на id я могу передать только на один объект в одном колбэке, поэтому второй все равно придется искать через перебор (если только колбэк не понимает две пары аргументов "id, obj"). Во втором посте как раз вариант с прямой передачей одного id вместо ссылки на info_id общего колбэка.

Поделиться этим сообщением


Ссылка на сообщение

@AndreySol Попробовал создать два объекта в одной функции – получается два тестовых сообщения с разными id объектов. Это предполагаемый результат, или как-то можно передать две пары "id, obj" в одном вызове функции?

Spoiler

function drop_check(obj) -- [bind_stalker] on_item_drop(obj)
	if obj:section() == "hand_radio" then
		spawn()
	end
end

function spawn()
	local act = db.actor 
	local item = { "bandage", "medkit" }
	for k, v in pairs(item) do
		local spawn = alife():create(v, act:position(), act:level_vertex_id(), act:game_vertex_id())
		level.client_spawn_manager():add(spawn.id, -1, test_msg)
	end
end

function test_msg(id, obj)
	news_manager.send_tip(db.actor, "obj: " .. obj:section() .. ", id: " .. id)
end

 

Поделиться этим сообщением


Ссылка на сообщение

Вопрос по функции transfer_item: ссылка дается на секцию предмета, и если в инвентаре несколько предметов с одинаковыми секциями, часто передается не тот, что в слоте. Попытка сослаться на id() вместо секции (как в варианте alife():release) делает функцию "пустышкой" – вылета нет, но и эффекта тоже никакого. Какую проверку можно ввести для точного определения предмета?

Spoiler

function items_out(box_id)
	local act = db.actor
	local box = level.object_by_id(box_id)
	local n = {1, 2, 6}
	for k, v in pairs(n) do
		local slot = act:item_in_slot(v)
		if slot then
			act:transfer_item( act:object( slot:section() ), box ) -- здесь ошибка
		end
	end
end

 

 

Поделиться этим сообщением


Ссылка на сообщение

@AndreySol Есть контакт. Уже не помню, где я нашел образец с секцией, но это явно сбило меня с толку.

Изменено пользователем Norman Eisenherz

Поделиться этим сообщением


Ссылка на сообщение

Здрасьте.

 

При использовании скрипта для исключения экипированных предметов на время торговли/обыска случается вылет со ссылкой на слоты экипировки в порядке "пистолет > автомат > броня" (при наличии), если открыть и тут же закрыть труп или контейнер. Можно ли эту ошибку обойти в самом коде?

Триггер скрипта – info_callback в [bind_stalker.script]

Spoiler

Expression    : e_entity->ID_Parent == id_parent
Function      : xrServer::Process_event_reject
File          : E:\stalker\sources\trunk\xr_3da\xrGame\xrServer_process_event_reject.cpp
Line          : 23
Description   : wpn_sig22029705
Arguments     : single_player

Spoiler

local act = db.actor
local box_1 = 0
local box_2 = 0


-- // проверка наличия активного противника в радиусе охвата мини-карты // --
function enemy()
	for i = 0, 65535 do
		local obj = level.object_by_id(i)
		if obj and obj:alive()
		and ( obj:relation(act) == game_object.enemy or IsMonster(obj) )
		and obj:position():distance_to( act:position() ) < 30 then
			return true
		end
	end
	return false
end


-- // спавн коробок и отслеживание ввода в онлайн // --
function spawn_box_1(info_id)
	if info_id == "ui_trade" or info_id == "ui_car_body" then
		local act_pos = act:position()
		local spawn = alife():create( "box_eq", vector():set( (act_pos.x + 1), (act_pos.y), (act_pos.z + 1) ),
			act:level_vertex_id(), act:game_vertex_id() )
		level.client_spawn_manager():add(spawn.id, -1, transfer_out)
	end
end

function spawn_box_2(info_id)
	if info_id == "ui_trade_hide" or info_id == "ui_car_body_hide" then
		local act_pos = act:position()
		local spawn = alife():create( "box_ex", vector():set( (act_pos.x + 1), (act_pos.y), (act_pos.z + 1) ),
			act:level_vertex_id(), act:game_vertex_id() )
		level.client_spawn_manager():add(spawn.id, -1, transfer_back)
	end
end


-- // перенос предметов // --
function transfer_out(id, obj)
	box_1 = id
--	news_manager.send_tip(act, "out_1: " .. box_1)
	items_out(box_1)
end

function transfer_back(id, obj)
	box_2 = id
--	news_manager.send_tip(act, "out_2: " .. box_2)
	items_out(box_2)
--	news_manager.send_tip(act, "back_1:" .. box_1)
	items_back(box_1)
	spawn_dl()
end

function spawn_dl() -- костыль для задержки на время переноса предметов в доп. коробку
	local act_pos = act:position()
	local spawn = alife():create( "box_dl", vector():set( (act_pos.x + 1), (act_pos.y), (act_pos.z + 1) ),
			act:level_vertex_id(), act:game_vertex_id() )
		level.client_spawn_manager():add(spawn.id, -1, transfer_end)
end

function transfer_end(id, obj)
	alife():release( alife():object(id) )	-- удаление костыля
--	news_manager.send_tip(act, "back_2:" .. box_2)
	items_back(box_2)

	if enemy() == false then
--		news_manager.send_tip(act, "все тихо, выбор болта")
		act:activate_slot(5)
	elseif enemy() == true and act:item_in_slot(2):section() == "wpn_vintorez" and act:item_in_slot(1) then
		act:activate_slot(2)		-- небольшая правка - винторез стабильно пролетает в слоты до пистолетов
	end
end


-- // перенос предметов в коробку // --
function items_out(box_id)
	local box = level.object_by_id(box_id)
	local n = {1, 2, 6}
	for k, v in pairs(n) do
		local slot = act:item_in_slot(v)
		if slot then
			act:transfer_item(slot, box)
		end
	end
end

-- // перенос предметов из коробки и ее удаление // --
function items_back(box_id)
	local box = level.object_by_id(box_id)
	local storage = {}

	for i = 0, 65535 do
		local obj = level.object_by_id(i)
		if obj and obj:parent() and obj:parent():id() == box_id then
			table.insert(storage, i)
		end
	end

	if next(storage) ~= nil then
		for k, v in pairs(storage) do
			local item = level.object_by_id(v)
			box:transfer_item(item, act)
		end
--	else news_manager.send_tip(act, "empty box")
	end

	alife():release( alife():object(box_id) )
end

 

 

Изменено пользователем Norman Eisenherz

Поделиться этим сообщением


Ссылка на сообщение

Здрасьте.

 

Слепил уборщик бесхозного оружия:

• вызов из [scripts\bind_stalker.script] actor_binder:net_spawn(data);

• удалять все, кроме списка исключений;

• на текущей локации удалять, если рядом нет трупов;

• на других локациях удалять просто так.

 

Проблема: если вызывать скрипт каким-нибудь триггером (сброс бинта, например) в уже прогруженной локации, то ближайшие трупы учитываются и пушки, соответственно, лежат на месте. При вызове из "net_spawn" трупы в процессе прогрузки не обнаруживаются.

Вариант 1: https://drive.google.com/open?id=1-K5gPW3q3AUPN1bGXfEjBZ1Uj8kecjwh

 

Добавил задержку запуска через level.client_spawn_manager: трупы обнаруживаются и при вызове из "net_spawn", хотя задержка всего ничего.

Вариант 2: https://drive.google.com/open?id=1eEcuoF9Daw150FPWxpsAkXodliqAE2x1

 

Выходит, трупы на текущей локации загружаются чуть позже ГГ. Как это обойти без костылей?

Поделиться этим сообщением


Ссылка на сообщение

@naxac Старый уборщик всего и вся от мифического Сяка так и сделан, и я тоже планирую добраться до такой схемы. Но вопрос с загрузкой трупов остается.

Поделиться этим сообщением


Ссылка на сообщение

Проблема: к серверному объекту невозможно применить проверку if not obj:alive(), хотя такая проверка есть в коде от Сяка.

 

Код оригинального уборщика (солянка 2010):

Spoiler

	for a=1,65534,1 do
	local obj = alife():object(a)
			if obj and game_graph():valid_vertex_id(obj.m_game_vertex_id)then
				local obj_clsid = obj:clsid()
		local obj_level = game_graph():vertex(obj.m_game_vertex_id):level_id()

				if IAmAStalker[obj_clsid] and obj_level~=actor_level then
				if not obj:alive() then 

 

 

Мой код:

Spoiler

	local act_lv = game_graph():vertex( act:game_vertex_id() ):level_id()

	local bodies = {}

	for i = 0, 65535 do
		local obj = alife():object(i)
		if obj and game_graph():valid_vertex_id( obj.m_game_vertex_id ) then
			local obj_lv = game_graph():vertex( obj.m_game_vertex_id ):level_id()

			if IsStalker(obj) and obj_lv == act_lv then
				if not obj:alive() then
					table.insert(bodies, obj)
				end
			end

 

 

Изменено пользователем Norman Eisenherz

Поделиться этим сообщением


Ссылка на сообщение

Попробовал проверку через свойство вместо метода:

if IsStalker(obj) and not obj.alive and obj_lv == act_lv

Обнаруживается единственный труп – сам Меченый. Настоящие трупы и еще живые NPC в список не попадают. Меченый – вампир? :shok2:

  • Смешно 2

Поделиться этим сообщением


Ссылка на сообщение

@naxac То, что в другом коде работает, я знаю, но я ловлю вылет с ошибкой "attempt to call method 'alive' (a nil value)". Может, вообще не в этой проверке ошибка? Вот последняя версия (пока что "not obj.alive"): https://drive.google.com/open?id=1-K5gPW3q3AUPN1bGXfEjBZ1Uj8kecjwh

Поделиться этим сообщением


Ссылка на сообщение

@naxac Просмотрел, что кроме шага еще и отсчет с 1 начинается. В таком виде работает даже без задержки запуска.

Поделиться этим сообщением


Ссылка на сообщение

Здрасьте.

 

Сделал иконку состояния брони (набор статиков) с вызовом из function actor_binder:update(delta): на двух старых сейвах статик загружается и успешно работает, еще примерно на 10 старых сейвах и в новой игре не загружается, а при попытке сохранения и перезагрузки игры приводит к вылету с одним из двух приведенных ниже сообщений. Методом исключения удалось выяснить, что статикам мешает работать уборщик – мешает даже не перебором объектов на сервере, а конкретно той частью, которая удаляет бесхозное оружие. Добавил к запуску уборщика условие if device().precache_frame <= 1 – проблема разрешилась, но все-таки хочется знать, что вызывало эту проблему.

ТЧ 1.0006, без глобальных модов.

https://drive.google.com/open?id=1Yp4s8CvySYUsv0j2EolZYWdAan0JHsfN

Spoiler

Expression    : fatal error
Function      : CScriptEngine::lua_error
File          : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp
Line          : 73
Description   : <no expression>
Arguments     : LUA error: ...ow of chernobyl\gamedata\scripts\bind_stalker.script:411: attempt to concatenate field '?' (a nil value)

 

для справки – указанная строка [bind_stalker.script] (с модами): get_console():execute("g_game_difficulty "..game_difficulty_by_num[game_difficulty])


Expression    : fatal error
Function      : CScriptEngine::lua_error
File          : E:\stalker\sources\trunk\xr_3da\xrGame\script_engine.cpp
Line          : 73
Description   : <no expression>
Arguments     : LUA error: ...alker shadow of chernobyl\gamedata\scripts\_g.script:20: bad argument #2 to 'format' (string expected, got no value)

 

Поделиться этим сообщением


Ссылка на сообщение

@naxac Можно ли подробнее? Куда копать?

Потестил еще: условие precache_frame привело к тому, что теперь уборщик не срабатывает на текущей локации.

@mole venomous Нет-пакеты я точно не трогал.

Поделиться этим сообщением


Ссылка на сообщение

@naxac Проверил еще раз уборщик – старая логика действительно должна была сбоить: проверяется расстояние до 1-го трупа из списка, объект (возможно) удаляется, потом проверяется расстояние от этого же объекта до 2-го, 3-го трупа и т. д., и тот же объект снова удаляется (по крайней мере, делается такая попытка).

Оператор break можно поставить только на негативное условие: если при переборе расстояний найдено значение меньше 5 , то закончить перебор для данного объекта и перейти к следующему, в противном случае удалить объект и перейти к следующему. Не до конца понимаю, как это правильно оформить, чтобы проверка не стопорилась на первом же значении > 5.

Пошел другим путем: создать таблицу расстояний от текущего объекта до всех трупов, взять минимум, сравнить его с заданной величиной (5) и удалить, если этот минимум больше.

Spoiler

        if next(wpn_near) ~= 0 then
            for i = 1, #wpn_near do
                local del = wpn_near[i]
                if del.position:distance_to(act:position()) > 10 then
                    if next(bodies) ~= 0 then
                        local distance = {}
                        for j = 1, #bodies do
                            local dist = del.position:distance_to(bodies[j].position)
                            table.insert(distance, dist)
                        end

                        table.sort(distance)
                        if distance[1] > 5 then
                            alife():release(del)
                        end
                    else
                        alife():release(del)
                    end
                end
            end
        end

 

 

@AndreySol Если функций несколько, лучше обозначать такие переменные в каждой из них или в общей области?

Поделиться этим сообщением


Ссылка на сообщение

@WinCap Кроме способа перебора (ну и еще остановки), это опять старая логика: "если до первого трупа в списке > 5 метров, то удалить оружие". Должно быть "если до всех трупов на локации > 5 метров, тогда удалять".

Поделиться этим сообщением


Ссылка на сообщение
  • Недавно просматривали   0 пользователей

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