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

Использование предметов актором


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

Денис, смотри.

 

Условно разделил на три части. Правильно ли, что на три? Правильно ли вообще разделил?

 

К остальным академикам вопрос: не хотите ли что-то добавить в рамках темы? Напомню, Денис рассматривает коллбэки получения и потери предметов, take_item_from_box(), on_trade(), on_item_take(), как узнать куда положили или кому передали предмет.

Если по теме имеется что добавить - пишите, пожалуйста.

 

 

Исторически сложилось, что разные события, случающиеся с актором, обрабатываются в bind_stalker скрипт. Опять же, исторически, в нем есть несколько коллбэков, отвечающих за получение и потерю предметов:

 

function actor_binder:take_item_from_box( box, item )

function actor_binder:on_trade( item, sell_bye, money )

function actor_binder:on_item_take( item )

function actor_binder:on_item_drop( item )

function actor_binder:on_use_object( item )

 

По идее, на этом статью можно было бы и закончить, поскольку все вполне прозрачно из названий функций, но для тех, кому лень смотреть скрипты, добавлю, что ставятся они вот как-то так:

 

function actor_binder:reinit()
	log( "info", "reinit" )
	object_binder.reinit( self )
	pstor = {}
	st = { ["pstor"] = pstor }
	self.st = st
	db.storage[0] = st

	self.next_restrictors_update_time = -10000
	actor:set_callback( callback.inventory_info,	self.info_callback,	self )
	actor:set_callback( callback.article_info,	self.article_callback,	self )
	actor:set_callback( callback.on_item_take,	self.on_item_take,	self )
	actor:set_callback( callback.on_item_drop,	self.on_item_drop,	self )
	actor:set_callback( callback.trade_sell_buy_item,self.on_trade,	self )

	actor:set_callback( callback.task_state,	self.task_callback,	self )
	actor:set_callback( callback.level_border_enter,self.level_border_enter,self )
	actor:set_callback( callback.level_border_exit,	self.level_border_exit,	self )
	actor:set_callback( callback.take_item_from_box,self.take_item_from_box,self )
	actor:set_callback( callback.use_object,	self.on_use_object,	self )
	actor:set_callback( callback.death,		self.death_callback,	self )

	log( "info", "reinit, done" )
end

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

 

Снимаются колбэки так:

 

function actor_binder:net_destroy()
	local log_level = smart_terrain.get_log_level() or 100
	if log_level < 20 and log_level >= 2 then
		smart_terrain.disable_log()
		if se_stalker.disable_log then se_stalker.disable_log() end
		if se_monster.disable_log then se_monster.disable_log() end
		xr_gulag.disable_log()
	end

	local remove_from_ranking = actor_stats.remove_from_ranking
	if remove_from_ranking then remove_from_ranking( 0 ) end
	sr_light.clean_up()

	actor:set_callback( callback.inventory_info )	-- чистим колл-бэки ( устанавливаются в nil )
	actor:set_callback( callback.article_info )
	actor:set_callback( callback.on_item_take )
	actor:set_callback( callback.on_item_drop )
	actor:set_callback( callback.trade_sell_buy_item )

	actor:set_callback( callback.task_state )
	actor:set_callback( callback.level_border_enter )
	actor:set_callback( callback.level_border_exit )
	actor:set_callback( callback.take_item_from_box )
	actor:set_callback( callback.use_object )
	actor:set_callback( callback.death )

	if psy_antenna then
		psy_antenna:destroy()
		sr_psy_antenna.psy_antenna = false
	end

	xr_sound.stop_all_sound_object()
	db.del_actor( actor )
	_G.actor = nil
	object_binder.net_destroy( self )
end

- надо это, чтобы игра не вылетала при уничтожении объекта (в данном случае - при завершении/перезагрузке).

 

Далее будет в порядке графомании расписано, что с этими коллбэками вообще можно делать, а заодно - как их стоило бы переписать для вящего удобства и чтобы перестать уже насиловать процессор.

Да, в случае очистки коллбэков магическое nil, типа actor:set_callback( callback.article_info, nil ) вроде не требуется. По крайней мере, я никаких негативных эффектов пока не увидел. Но, возможно, ошибаюсь, и эффекты просто пока не вылезли.

А вообще за код вида "== nil" и "~= nil" надо давать сразу 35 лет строгого расстрела. Вот чтоб каждое утро в 6 часов, невзирая на погоду, выводили и расстреливали, поскольку требуется явно определять переменные и явно возвращать из вызываемых функций это самый nil

Почему здесь везде actor а не db.actor? Потому что код пал жертвой рефакторинга, и актор определяется раз и навсегда в глобальном пространстве:

function actor_binder:__init( npc ) super( npc )
	_G.actor = self.object
	db.add_actor( actor )
	self.is_saved = false
end

 

***

 

function actor_binder:take_item_from_box( box, item )

function actor_binder:on_trade( item, sell_bye, money )

function actor_binder:on_item_take( item )

С первым все понятно. Срабатывает при взятии предметов из ящиков. На входе - объект ящика и объект собственно предмета.

Кстати, если сюда прицепить телепортацию актора на другой конец локации - ящик уйдет в офлайн, и объект станет невалидным. Со всеми вытекающими. Впрочем, знаменитый вылет с буквами e ;) случается, по-моему, еще раньше. Да, если при этом уничтожать, скажем, взятую из ящика гранату, будет примерно то же самое. И вообще, прежде чем делать что-либо дальше с ящиком или предметом - закройте ящик через level.hide_indicators() или подождите, пока игрок его сам закроет.

Что же с ней можно сделать еще - это переписать простыни о 100500 строк всяких странных if ... then ... и вызовы 100500 скриптов, которые в нее обычно суют, следующим образом:

 

local t_takebox, t_takebox_sid, t_takebox_any = {}, {}, {}

function add_on_take_box( f, sect )	-- ( функция, true - проверка на sid ящика )
	if sect then
		if sect == true then table_insert( t_takebox_sid, f )
		elseif t_takebox[sect] then table_insert( t_takebox[sect], f )
		else t_takebox[sect] = { f }
		end
	else table_insert( t_takebox_any, f )
	end
end

function actor_binder:take_item_from_box( box, item )
	local sid = box:story_id()
	if sid then	-- dc: а что, nil бывает ?
		for i, v in ipairs( t_takebox_sid ) do v( box, item ) end
	end
	if item and t_takebox[item:section()] then
		for i, v in ipairs( t_takebox[item:section()] ) do v( box, item ) end
	end
	for i, v in ipairs( t_takebox_any ) do v( box, item ) end

	if level.map_has_object_spot( box:id(), "crlc_big" ) ~= 0 then	-- amk.on_item_take_from_box
		level.map_remove_object_spot( box:id(), "crlc_big" )
	end
end

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

 

on_trade() - обычно здесь бывает что-то типа

function actor_binder:on_trade( item, sell_bye, money )
	if sell_bye then game_stats.money_trade_update( money )
	else game_stats.money_trade_update( -money )
	end
end
, и в общем-то больше ничего не нужно. Но если, например, переписывать "квесты" типа "принеси мне 100500 AK-100, а я дам тебе за это фантик от конфеты - можешь его облизать" - эта функция нам пригодится. ;)

 

А вот про on_item_take() - отдельная телега.

 

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

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

Зато, имеем медленную и печальную загрузку, когда игрок привык таскать на себе по полтонны хлама, а аффтар мода, традиционно, повесил на этот вызов 100500 if ... then ...

Переписывавем традиционно:

 

local on_take_t, on_take_any, on_take_n = {}, {}, 0

function add_on_take( f, sect )	-- ( функция, nil ) - для любых секций, либо ( f, секция )
	if sect then
		local t = on_take_t[sect]
		if t then table_insert( t, f )
		else on_take_t[sect] = { f }
		end
	else on_take_n = on_take_n + 1; on_take_any[on_take_n] = f
	end
end


function actor_binder:on_item_take( item )
	-- log( "info", "on_item_take" )
	ltasks_proceed()

	for i = 1, on_take_n do on_take_any[i]( item ) end
	local t = on_take_t[item:section()]
	if t then
		for i = 1, #t do t[i]( item ) end
	end

	if level.map_has_object_spot( item:id(), "red_location" ) ~= 0 then
		level.map_remove_object_spot( item:id(), "red_location" )
	end
	-- log( "info", "on_item_take, done" )
end

вызов level_tasks, кстати, тоже надо отсюда убрать.

 

 

***

 

А теперь самое вкусное. Я так до сих пор и не понял, зачем люди вешают все-все на

function actor_binder:on_item_drop( item ),

потом пишут секцию, или, что еще хуже, id этого item в pstor актора, а потом запускают какие-то аццкие таймеры с аццкими проверками на неизвестно что для неизвестных объектов, у которых id случайно совпало с сохраненным, когда есть function actor_binder:on_use_object( item ), срабатывающий именно на использование.

Но, кстати, да, on_item_drop() при этом тоже срабатывает.

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

С использованием все понятно. А вот как узнать, куда положили или кому передали предмет? Или просто выбросили? Или он по какой-то мистической причине просто исчез?

А элементарно (если мы отслеживаем еще и использование через on_use_object(), и ведем табличку, скажем inv_used[]):

 

local sect = item:section()
	-- log( "info", "on_item_lost: %s", sect )

	local id = item:id()
	if inv_used[id] then inv_used[id] = nil	-- использован
		-- log( "info", "on_item_lost: %s, used", sect )
	else
		local obj = sim:object( id )
		if obj then
			if ( obj.parent_id or 65535 ) == 65535 then	-- выброшен
				-- log( "info", "on_item_lost: %s, drop", sect )
				for i = 1, on_drop_n do on_drop_t.any[i]( item ) end
				if on_drop_t[sect] then
					for i, f in ipairs( on_drop_t[sect] ) do f( item ) end
				end
			-- else log( "info", "on_item_lost: %s, new parent: %s", sect, obj.parent_id )
			end
		-- else	log( "info", "on_item_lost: %s, deleted", sect )
	end	end

- это кусочек менеджера инвентаря, который отслеживает выбрасывание предметов, и, в свою очередь, запускает всякие варки артефактов и прочие нанопульты. ;)

В принципе, сюда же можно запихать и всякое переодевание и перевооружение неписей, но не нужно, поскольку если про парламент, как не место для дискуссий - еще спорно, то Зона - совершенно точно - не для стриптиза. Впрочем, это совсем другая тема.

 

А пока просто следует запомнить, что таймеры - не нужны.

Кстати, вот полный скрипт менеджера, с учетом пояса, перепаковки чего попало во что угодно, и еще всяким странным: https://dl.dropboxusercontent.com/u/27871782/inv_manager.script

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

 

local on_drop_t, on_drop_any, on_drop_n = {}, {}, 0

function add_on_drop( f, sect )	-- ( функция, nil ) - для любых секций, либо ( f, секция )
	if sect then
		local t = on_drop_t[sect]
		if t then table_insert( t, f )
		else on_drop_t[sect] = { f }
		end
	else on_drop_n = on_drop_n + 1; on_drop_any[on_drop_n] = f
	end
end


function actor_binder:on_item_drop( item )
	-- log( "info", "on_item_drop" )
	ltasks_proceed()

	for i = 1, on_drop_n do on_drop_any[i]( item ) end
	local t = on_drop_t[item:section()]
	if t then
		for i = 1, #t do t[i]( item ) end
	end
	-- log( "info", "on_item_drop, done" )
end


local on_use_t, on_use_n = { ["any"] = {} }, 0

function add_on_use( f, sect )	-- ( функция, nil ) - для любых секций, либо ( f, секция )
	if sect then
		local t = on_use_t[sect]
		if t then t[#t + 1] = f
		else on_use_t[sect] = { f }
		end
	else on_use_n = on_use_n + 1; on_use_t.any[on_use_n] = f
	end
end


function actor_binder:on_use_object( item )
	local sect = item:section()
	log( "info", "on_use, item: %s", sect )

	for i = 1, on_use_n do on_use_t.any[i]( item ) end
	if on_use_t[sect] then
		for i, f in ipairs( on_use_t[sect] ) do f( item ) end
	end
end

На этом, в общем-то, все.

И немедленно выпил. ©

 

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


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

 

 

Мне одному кажется, что в отредактированном варианте что-то пропало ?

По-моему, ничего.

 

 

Ну и удаление разбивки читабельность отнюдь не улучшает.

Это о чем? Я вроде не удалял ничего. Вот редактор при копипасте иногда чудеса вытворяет с лишними строками и пробелами - это может быть...

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


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

@Desertir, не отклоняемся ли от темы? Может, в отдельную перенести? Или это здесь очень даже к месту?

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


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

 

 

Денис рассматривает коллбэки получения и потери предметов, take_item_from_box(), on_trade(), on_item_take(), как узнать куда положили или кому передали предмет.

Я правильно понимаю круг вопросов? Если вписывается, то нужно добавить это в текст, если нет - то создать отдельную статейку. либо расширить круг вопросов в рамках этой статьи.

Просто помните, мы говорили, что, конечно, одно цепляется за другое, но так мы никогда не остановимся? Вот этого и стоит опасаться. :)

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


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

@Dennis_Chikin

ИСПОЛЬЗОВАНИЕ ПРЕДМЕТОВ АКТОРОМ

 

Какие коллбэки отвечают за получение и потерю предметов? Как эти коллбэки ставятся и снимаются? Для чего нужны и как работают take_item_from_box(), on_trade(), on_item_take()? Как узнать, куда положили или кому передали предмет? Ответы на эти вопросы - в статье ниже.

 

Исторически сложилось, что разные события, случающиеся с актором, обрабатываются в bind_stalker скрипт. Опять же, исторически, в нем есть несколько коллбэков, отвечающих за получение и потерю предметов:

 

function actor_binder:take_item_from_box( box, item )

function actor_binder:on_trade( item, sell_bye, money )

function actor_binder:on_item_take( item )

function actor_binder:on_item_drop( item )

function actor_binder:on_use_object( item )

 

По идее, на этом статью можно было бы и закончить, поскольку все вполне прозрачно из названий функций, но для тех, кому лень смотреть скрипты, добавлю, что ставятся они вот как-то так:

 

function actor_binder:reinit()
	log( "info", "reinit" )
	object_binder.reinit( self )
	pstor = {}
	st = { ["pstor"] = pstor }
	self.st = st
	db.storage[0] = st

	self.next_restrictors_update_time = -10000
	actor:set_callback( callback.inventory_info,	self.info_callback,	self )
	actor:set_callback( callback.article_info,	self.article_callback,	self )
	actor:set_callback( callback.on_item_take,	self.on_item_take,	self )
	actor:set_callback( callback.on_item_drop,	self.on_item_drop,	self )
	actor:set_callback( callback.trade_sell_buy_item,self.on_trade,	self )

	actor:set_callback( callback.task_state,	self.task_callback,	self )
	actor:set_callback( callback.level_border_enter,self.level_border_enter,self )
	actor:set_callback( callback.level_border_exit,	self.level_border_exit,	self )
	actor:set_callback( callback.take_item_from_box,self.take_item_from_box,self )
	actor:set_callback( callback.use_object,	self.on_use_object,	self )
	actor:set_callback( callback.death,		self.death_callback,	self )

	log( "info", "reinit, done" )
end

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

 

Снимаются колбэки так:

 

function actor_binder:net_destroy()
	local log_level = smart_terrain.get_log_level() or 100
	if log_level < 20 and log_level >= 2 then
		smart_terrain.disable_log()
		if se_stalker.disable_log then se_stalker.disable_log() end
		if se_monster.disable_log then se_monster.disable_log() end
		xr_gulag.disable_log()
	end

	local remove_from_ranking = actor_stats.remove_from_ranking
	if remove_from_ranking then remove_from_ranking( 0 ) end
	sr_light.clean_up()

	actor:set_callback( callback.inventory_info )	-- чистим колл-бэки ( устанавливаются в nil )
	actor:set_callback( callback.article_info )
	actor:set_callback( callback.on_item_take )
	actor:set_callback( callback.on_item_drop )
	actor:set_callback( callback.trade_sell_buy_item )

	actor:set_callback( callback.task_state )
	actor:set_callback( callback.level_border_enter )
	actor:set_callback( callback.level_border_exit )
	actor:set_callback( callback.take_item_from_box )
	actor:set_callback( callback.use_object )
	actor:set_callback( callback.death )

	if psy_antenna then
		psy_antenna:destroy()
		sr_psy_antenna.psy_antenna = false
	end

	xr_sound.stop_all_sound_object()
	db.del_actor( actor )
	_G.actor = nil
	object_binder.net_destroy( self )
end

- надо это, чтобы игра не вылетала при уничтожении объекта (в данном случае - при завершении/перезагрузке).

 

Далее будет в порядке графомании расписано, что с этими коллбэками вообще можно делать, а заодно - как их стоило бы переписать для вящего удобства и чтобы перестать уже насиловать процессор.

Да, в случае очистки коллбэков магическое nil, типа actor:set_callback( callback.article_info, nil ) вроде не требуется. По крайней мере, я никаких негативных эффектов пока не увидел. Но, возможно, ошибаюсь, и эффекты просто пока не вылезли.

А вообще за код вида "== nil" и "~= nil" надо давать сразу 35 лет строгого расстрела. Вот чтоб каждое утро в 6 часов, невзирая на погоду, выводили и расстреливали, поскольку требуется явно определять переменные и явно возвращать из вызываемых функций это самый nil

Почему здесь везде actor а не db.actor? Потому что код пал жертвой рефакторинга, и актор определяется раз и навсегда в глобальном пространстве:

function actor_binder:__init( npc ) super( npc )
	_G.actor = self.object
	db.add_actor( actor )
	self.is_saved = false
end

***

function actor_binder:take_item_from_box( box, item )

function actor_binder:on_trade( item, sell_bye, money )

function actor_binder:on_item_take( item )

С первым все понятно. Срабатывает при взятии предметов из ящиков. На входе - объект ящика и объект собственно предмета.

Кстати, если сюда прицепить телепортацию актора на другой конец локации - ящик уйдет в офлайн, и объект станет невалидным. Со всеми вытекающими. Впрочем, знаменитый вылет с буквами e ;) случается, по-моему, еще раньше. Да, если при этом уничтожать, скажем, взятую из ящика гранату, будет примерно то же самое. И вообще, прежде чем делать что-либо дальше с ящиком или предметом - закройте ящик через level.hide_indicators() или подождите, пока игрок его сам закроет.

Что же с ней можно сделать еще - это переписать простыни о 100500 строк всяких странных if ... then ... и вызовы 100500 скриптов, которые в нее обычно суют, следующим образом:

 

local t_takebox, t_takebox_sid, t_takebox_any = {}, {}, {}

function add_on_take_box( f, sect )	-- ( функция, true - проверка на sid ящика )
	if sect then
		if sect == true then table_insert( t_takebox_sid, f )
		elseif t_takebox[sect] then table_insert( t_takebox[sect], f )
		else t_takebox[sect] = { f }
		end
	else table_insert( t_takebox_any, f )
	end
end

function actor_binder:take_item_from_box( box, item )
	local sid = box:story_id()
	if sid then	-- dc: а что, nil бывает ?
		for i, v in ipairs( t_takebox_sid ) do v( box, item ) end
	end
	if item and t_takebox[item:section()] then
		for i, v in ipairs( t_takebox[item:section()] ) do v( box, item ) end
	end
	for i, v in ipairs( t_takebox_any ) do v( box, item ) end

	if level.map_has_object_spot( box:id(), "crlc_big" ) ~= 0 then	-- amk.on_item_take_from_box
		level.map_remove_object_spot( box:id(), "crlc_big" )
	end
end

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

 

on_trade() - обычно здесь бывает что-то типа

function actor_binder:on_trade( item, sell_bye, money )
	if sell_bye then game_stats.money_trade_update( money )
	else game_stats.money_trade_update( -money )
	end
end
, и в общем-то больше ничего не нужно. Но если, например, переписывать "квесты" типа "принеси мне 100500 AK-100, а я дам тебе за это фантик от конфеты - можешь его облизать" - эта функция нам пригодится. ;)

 

А вот про on_item_take() - отдельная телега.

 

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

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

Зато, имеем медленную и печальную загрузку, когда игрок привык таскать на себе по полтонны хлама, а аффтар мода, традиционно, повесил на этот вызов 100500 if ... then ...

Переписывавем традиционно:

 

local on_take_t, on_take_any, on_take_n = {}, {}, 0

function add_on_take( f, sect )	-- ( функция, nil ) - для любых секций, либо ( f, секция )
	if sect then
		local t = on_take_t[sect]
		if t then table_insert( t, f )
		else on_take_t[sect] = { f }
		end
	else on_take_n = on_take_n + 1; on_take_any[on_take_n] = f
	end
end


function actor_binder:on_item_take( item )
	-- log( "info", "on_item_take" )
	ltasks_proceed()

	for i = 1, on_take_n do on_take_any[i]( item ) end
	local t = on_take_t[item:section()]
	if t then
		for i = 1, #t do t[i]( item ) end
	end

	if level.map_has_object_spot( item:id(), "red_location" ) ~= 0 then
		level.map_remove_object_spot( item:id(), "red_location" )
	end
	-- log( "info", "on_item_take, done" )
end

вызов level_tasks, кстати, тоже надо отсюда убрать.

 

***

А теперь самое вкусное. Я так до сих пор и не понял, зачем люди вешают все-все на

function actor_binder:on_item_drop( item ),

потом пишут секцию, или, что еще хуже, id этого item в pstor актора, а потом запускают какие-то аццкие таймеры с аццкими проверками на неизвестно что для неизвестных объектов, у которых id случайно совпало с сохраненным, когда есть function actor_binder:on_use_object( item ), срабатывающий именно на использование.

Но, кстати, да, on_item_drop() при этом тоже срабатывает.

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

С использованием все понятно. А вот как узнать, куда положили или кому передали предмет? Или просто выбросили? Или он по какой-то мистической причине просто исчез?

А элементарно (если мы отслеживаем еще и использование через on_use_object(), и ведем табличку, скажем inv_used[]):

 

local sect = item:section()
	-- log( "info", "on_item_lost: %s", sect )

	local id = item:id()
	if inv_used[id] then inv_used[id] = nil	-- использован
		-- log( "info", "on_item_lost: %s, used", sect )
	else
		local obj = sim:object( id )
		if obj then
			if ( obj.parent_id or 65535 ) == 65535 then	-- выброшен
				-- log( "info", "on_item_lost: %s, drop", sect )
				for i = 1, on_drop_n do on_drop_t.any[i]( item ) end
				if on_drop_t[sect] then
					for i, f in ipairs( on_drop_t[sect] ) do f( item ) end
				end
			-- else log( "info", "on_item_lost: %s, new parent: %s", sect, obj.parent_id )
			end
		-- else	log( "info", "on_item_lost: %s, deleted", sect )
	end	end

- это кусочек менеджера инвентаря, который отслеживает выбрасывание предметов, и, в свою очередь, запускает всякие варки артефактов и прочие нанопульты. ;)

В принципе, сюда же можно запихать и всякое переодевание и перевооружение неписей, но не нужно, поскольку если про парламент, как не место для дискуссий - еще спорно, то Зона - совершенно точно - не для стриптиза. Впрочем, это совсем другая тема.

 

А пока просто следует запомнить, что таймеры - не нужны.

Кстати, вот полный скрипт менеджера, с учетом пояса, перепаковки чего попало во что угодно, и еще всяким странным: https://dl.dropboxusercontent.com/u/27871782/inv_manager.script

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

 

local on_drop_t, on_drop_any, on_drop_n = {}, {}, 0

function add_on_drop( f, sect )	-- ( функция, nil ) - для любых секций, либо ( f, секция )
	if sect then
		local t = on_drop_t[sect]
		if t then table_insert( t, f )
		else on_drop_t[sect] = { f }
		end
	else on_drop_n = on_drop_n + 1; on_drop_any[on_drop_n] = f
	end
end


function actor_binder:on_item_drop( item )
	-- log( "info", "on_item_drop" )
	ltasks_proceed()

	for i = 1, on_drop_n do on_drop_any[i]( item ) end
	local t = on_drop_t[item:section()]
	if t then
		for i = 1, #t do t[i]( item ) end
	end
	-- log( "info", "on_item_drop, done" )
end


local on_use_t, on_use_n = { ["any"] = {} }, 0

function add_on_use( f, sect )	-- ( функция, nil ) - для любых секций, либо ( f, секция )
	if sect then
		local t = on_use_t[sect]
		if t then t[#t + 1] = f
		else on_use_t[sect] = { f }
		end
	else on_use_n = on_use_n + 1; on_use_t.any[on_use_n] = f
	end
end


function actor_binder:on_use_object( item )
	local sect = item:section()
	log( "info", "on_use, item: %s", sect )

	for i = 1, on_use_n do on_use_t.any[i]( item ) end
	if on_use_t[sect] then
		for i, f in ipairs( on_use_t[sect] ) do f( item ) end
	end
end

На этом, в общем-то, все.

И немедленно выпил. ©

 

Рецензия: @lsclon

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

 

  • Спасибо 1
  • Полезно 2

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


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

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