-- nv130130 - properly handle find tasks where object found but not present while at vendor
-- nv140407 separated return task types for better map hint management
-- nv150424 clsid tweak
-- nv160803 some code streamlining
-- nv170408 use global actor, 0 for actor id

-- nv 070924 set quest_time_factor 0 for unlimited quest time
quest_time_factor = 3

-- nv 070924 set autoquest_time_factor 0 for unlimited time
autoquest_time_factor = 0

-- nv 070924 set idle_time_factor 0 for infinite delay
idle_time_factor = 2

-- nv 070924 set this to false if you don't want to know what you'll get
show_quest_rewards = true

-- nv 071130 set false if you don't want to permit player to bypass quests
allow_task_rejection = true

-- nv 071130 set true if you want to see changes to your standing with factions
show_relation_changes = false

local random_task = nil

local parent_by_story = {
	[003] = "trader",
	[500] = "barman",
	[902] = "ecolog",
	[507] = "dolg",
	[707] = "freedom",
	[006] = "wolf",
	[004] = "shustriy",
	[510] = "drunk_dolg",
	[504] = "hunter",
	[518] = "zastava_commander",
	[506] = "petrenko",
	[607] = "lisiy",
	[515] = "mercenary"
}

local story_by_parent = {
	trader						= 003,
	barman						= 500,
	ecolog						= 902,
	dolg						= 507,
	freedom						= 707,
	wolf						= 006,
	shustriy					= 004,
	drunk_dolg					= 510,
	hunter						= 504,
	zastava_commander			= 518,
	petrenko					= 506,
	lisiy						= 607,
	mercenary					= 515
}

local return_task_by_type = {
	eliminate_lager = "return_for_reward",
	defend_lager = "return_for_reward",
	kill_stalker = "return_for_reward",
	artefact = "return_for_reward_bring",
	monster_part = "return_for_reward_bring",
	find_item = "return_for_reward_bring"}

local return_location = {
	return_for_reward = "blue_location",
	return_for_reward_bring = "blue_location_2"
}

local game_version = -1

local table_insert = table.insert
local table_remove = table.remove

class "CRandomTask"
function CRandomTask:AddPhrase(dlg, name, phrase_id, phr_id_2, offset)
	if game_version == 6 then
		return dlg:AddPhrase(name, phrase_id, phr_id_2, offset)
	elseif game_version >= 7 then
		local phr2string;
		if phr_id_2 == -1 then
				phr2string = ""
		else
				phr2string = tostring(phr_id_2)
		end
		return dlg:AddPhrase(name, tostring(phrase_id), phr2string, offset)
	else
		dbglog("Incompatible game_version:  %s",tostring(game_version))
		get_console():execute("quit")
	end
end

function CRandomTask:__init()
	game_version = _z.game_version()
	--' На конструкторе вычитываем LTX и создаем заготовки квестов.
	local ini = ini_file("misc\\task_manager.ltx")
	local task_phrase_id = 100 --phrases will be numbered from 101
	local result, id, value -- nv150404 make result local

	local function get_field_number(field, default)
		return (ini:line_exist(id, field) and ini:r_float(id, field)) or default
	end

	--' Итерируемся по всем настройкам фраз
	if not ini:section_exist("list") then
		assert(ini:section_exist("list"), "There is no section [list] in task_manager.ltx")
	end

	-- nv160803 converted to just in-line use instead
	--' Генератор уникальных ID для фраз
	-- local function get_next_phrase_id()
		-- task_phrase_id = task_phrase_id + 1
		-- return task_phrase_id
	-- end

	local n = ini:line_count("list")
	if idle_time_factor == 0 then
		idle_time_factor = 10000
	end
	local idle_time_factor_seconds = idle_time_factor * 86400

	--' начальная установка
	self.task_info = {}

	for i=0,n-1 do
		result, id, value	= ini:r_line("list",i,"","")

		if not ini:section_exist(id) then
			abort("There is no section [%s] in task_manager.ltx", id)
			return
		end

		self.task_info[id]			= {}
		local curr_task_info		= self.task_info[id]

		if not ini:line_exist(id, "type") then
			abort("Task manager error: no type in section [%s]", id)
			return
		end

		curr_task_info.type			= ini:r_string(id, "type")

		curr_task_info.name			= id
		if ini:line_exist(id, "parent") then
			curr_task_info.parent		= ini:r_string(id, "parent")
			curr_task_info.complex_type = curr_task_info.type .. "_" .. self.task_info[id].parent
		else
			curr_task_info.parent		= "nil"
			curr_task_info.complex_type = curr_task_info.type
		end
		if ini:line_exist(id, "target") then
			curr_task_info.target		= ini:r_string(id, "target")
		end
		if ini:line_exist(id, "text") then
			curr_task_info.text			= ini:r_string(id, "text")
		end
		if ini:line_exist(id, "description") then
			curr_task_info.description	= ini:r_string(id, "description")
		end
		-- curr_task_info.time				= utils.cfg_get_number(ini, id, "time", nil, false)
		curr_task_info.time				= get_field_number("time")

		-- curr_task_info.idle_time	= utils.cfg_get_number(ini, id, "idle_time", nil, false, 86400*idle_time_factor) --' Время между выдачами задания (в игровых секундах)
		curr_task_info.idle_time	= get_field_number("idle_time", idle_time_factor_seconds) --' Время между выдачами задания (в игровых секундах)
		-- curr_task_info.prior		= utils.cfg_get_number(ini, id, "prior", nil, false, 0) --' Приоритет квеста, выдаются доступные квесты с наименьшим приоритетом
		curr_task_info.prior		= get_field_number("prior", 0) --' Приоритет квеста, выдаются доступные квесты с наименьшим приоритетом

		if ini:line_exist(id, "init_condition") then
			-- swap the calls for xr_logic.parse_condlist_q(src) and xr_logic.parse_condlist(db.actor, etc) to see more details about your error
			-- curr_task_info.init_condition = xr_logic.parse_condlist(db.actor, "task_manager", "init_condition", ini:r_string(id, "init_condition"))
			curr_task_info.init_condition = xr_logic.parse_condlist_q(ini:r_string(id, "init_condition"))
		end

		-- local sss = utils.cfg_get_string(ini, id, "reward_item", nil, false, "")
		local sss = (ini:line_exist(id, "reward_item") and ini:r_string(id, "reward_item")) or nil
		if sss ~= nil then
			curr_task_info.reward_item = se_respawn.parse_names(sss)
		else
			curr_task_info.reward_item = nil --sss
		end
		-- curr_task_info.reward_money = utils.cfg_get_number(ini, id, "reward_money", nil, false)
		curr_task_info.reward_money = get_field_number("reward_money")

		if ini:line_exist(id, "community") then
			curr_task_info.community = ini:r_string(id, "community")
		end

		-- curr_task_info.reward_rank			= utils.cfg_get_number(ini, id, "reward_rank", nil, false, 0)
		curr_task_info.reward_rank			= get_field_number("reward_rank", 0)
		-- curr_task_info.reward_reputation	= utils.cfg_get_number(ini, id, "reward_reputation", nil, false)
		curr_task_info.reward_reputation	= get_field_number("reward_reputation")
		-- curr_task_info.reward_relation		= parse_key_value(utils.cfg_get_string(ini, id, "reward_relation", nil, false, ""))
		curr_task_info.reward_relation		= parse_key_value((ini:line_exist(id, "reward_relation") and ini:r_string(id, "reward_relation")) or nil)

		if ini:line_exist(id, "condlist") then
			-- swap the calls for xr_logic.parse_condlist_q(src) and xr_logic.parse_condlist(db.actor, etc) to see more details about your error
			-- curr_task_info.condlist			= xr_logic.parse_condlist(db.actor, "task_manager", "condlist", ini:r_string(id, "condlist"))
			curr_task_info.condlist			= xr_logic.parse_condlist_q(ini:r_string(id, "condlist"))
		else
			curr_task_info.condlist			= xr_logic.parse_condlist_q("true")
		end

		-- curr_task_info.need_return			= utils.cfg_get_bool(ini, id, "need_return", nil, false, true)
		if ini:line_exist(id, "need_return") then
			curr_task_info.need_return = ini:r_bool(id, "need_return")
		else
			curr_task_info.need_return = true
		end

		-- curr_task_info.init_phrase_id = get_next_phrase_id()
		-- curr_task_info.desc_phrase_id = get_next_phrase_id()
		-- curr_task_info.yes_phrase_id = get_next_phrase_id()
		-- curr_task_info.no_phrase_id = get_next_phrase_id()
		-- curr_task_info.never_phrase_id = get_next_phrase_id()

		task_phrase_id = task_phrase_id + 1
		curr_task_info.init_phrase_id = task_phrase_id
		task_phrase_id = task_phrase_id + 1
		curr_task_info.desc_phrase_id = task_phrase_id
		task_phrase_id = task_phrase_id + 1
		curr_task_info.yes_phrase_id = task_phrase_id
		task_phrase_id = task_phrase_id + 1
		curr_task_info.no_phrase_id = task_phrase_id
		task_phrase_id = task_phrase_id + 1
		curr_task_info.never_phrase_id = task_phrase_id


		--' По умолчанию квест доступен для выдачи
		curr_task_info.enabled				= true
		--' Доступен ли квест по своим свойствам. По умолчанию всегда недоступен.
		--' Этот параметр зависит от наличия целей для квестов и того срабатывает ли прекондишн квеста
		curr_task_info.enabled_props		= false

		--' Статус квеста, может быть: "normal", "selected", "completed", "refused", "failed", "rewarded"
		curr_task_info.status				= "normal"
	end

	--' Создание дополнительных ассоциативных таблиц для облегчения поиска
	self.task_id_by_type = {}
	self.task_id_by_parent = {}
	self.task_id_by_yes_phrase_id = {}
	self.task_id_by_never_phrase_id = {}
	self.task_id_by_init_phrase_id = {}
	self.active_task_by_type = {}
	self.task_id_self_inited = {}
	for k,v in pairs(self.task_info) do
		--' По типу квеста
		value = self.task_id_by_type[v.type] -- reuse local var
		if value == nil then
			value = {}
			self.task_id_by_type[v.type] = value
		end
		-- table.insert(self.task_id_by_type[v.type], k)
		value[#value+1] = k

		--' По типу вендора
		value = self.task_id_by_parent[v.parent]
		if value == nil then
			value = {}
			self.task_id_by_parent[v.parent] = value
		end
		-- table.insert(self.task_id_by_parent[v.parent], k)
		value[#value+1] = k

		--' По id фразы согласия на квест
		self.task_id_by_yes_phrase_id[v.yes_phrase_id] = k
		self.task_id_by_never_phrase_id[v.never_phrase_id] = k
		--' По id фразы выдачи квеста.
		self.task_id_by_init_phrase_id[v.init_phrase_id] = k
		--' По самовыдаваемости
		if v.init_condition ~= nil then
			-- table.insert(self.task_id_self_inited, k)
			self.task_id_self_inited[#self.task_id_self_inited+1] = k
		end
	end
end
--' Сохранение
function CRandomTask:save(p)
	-- printf("^^^ SAVE")
	--' Считаем количество записей
	local i = 0
	for k,v in pairs(self.task_info) do
		i = i + 1
	end
	p:w_u8(i)
	for k,v in pairs(self.task_info) do
		p:w_stringZ(k)
		p:w_bool(v.enabled)
		p:w_bool(v.enabled_props)
		p:w_stringZ(v.status)
		p:w_u32(v.selected_target or -1)
		utils.w_CTime(p, v.last_task_time)
	end

	--' Та же самая процедура с активными тасками
	i = 0
	for k,v in pairs(self.active_task_by_type) do
		i = i + 1
	end
	p:w_u8(i)
	for k,v in pairs(self.active_task_by_type) do
		p:w_stringZ(k)
		p:w_stringZ(v)
	end
end
--' Загрузка
function CRandomTask:load(p)
	-- printf("^^^ LOAD")
	--' Считаем количество записей

	local i = p:r_u8()
	for k = 1,i do
		local id = p:r_stringZ()
		-- if id ~= nil and self.task_info[id] ~= nil then
		if self.task_info[id] == nil then
			assert(self.task_info[id] ~= nil, "\n   In task_manager.script:load(): self.task_info[id] == nil for id="..id.."\n   ==> corrupt save or bad task_manager.ltx")
		end
		self.task_info[id].enabled = p:r_bool()
		self.task_info[id].enabled_props = p:r_bool()
		self.task_info[id].status = p:r_stringZ()

		local selected_target = p:r_u32()
		if selected_target ~= -1 then
			self.task_info[id].selected_target = selected_target
		end
		self.task_info[id].last_task_time = utils.r_CTime(p)

		if self.task_info[id].type == "defend_lager" then
			local defend_object = alife():object(self.task_info[id].selected_target)
			local sm_ini = defend_object:spawn_ini()
			self.task_info[id].defend_target = utils.cfg_get_number(sm_ini, "random_task", "defend_target", nil, true)
		end
		-- end
	end

	--' Та же самая процедура с активными тасками
	local i = p:r_u8()
	for k = 1,i do
		local id = p:r_stringZ()
		self.active_task_by_type[id] = p:r_stringZ()
	end
end
-- nv160803 this function is only needed at initialization - moved there
-- --' Генератор уникальных ID для фраз
-- function CRandomTask:get_id()
	-- self.task_phrase_id = self.task_phrase_id + 1
	-- return self.task_phrase_id
-- end
--' Возвращает идентификатор вендора, с которым мы говорим
function CRandomTask:get_parent(npc)
	local story_id = npc:story_id()
	if parent_by_story[story_id] == nil then
		abort("Task manager error: wrong parent story_id[%s]", story_id)
	end
	return parent_by_story[story_id]
end
--' Может ли вендор выдать квест
function CRandomTask:parent_can_task(actor, npc, p1, p2, p3)
	local parent = self:get_parent(npc)
	local avail = false
	self:task_avail(actor, npc, nil, nil, nil, "reset")
	for k,v in pairs(self.task_id_by_parent[parent]) do
		if self:task_avail(actor, npc, nil, nil, self.task_info[v].init_phrase_id, true) then
			avail = true
		end
	end
	return avail
end
--' Есть ли у игрока хоть одно задание от данного вендора
function CRandomTask:active_parent_task(actor, npc)
	local parent = self:get_parent(npc)
	for k,v in pairs(self.active_task_by_type) do
--		printf("active_parent_task: %s", tostring(v))
--		printf("active_parent_task: parent = %s", tostring(self.task_info[v].parent))
--		printf("active_parent_task: status = %s", tostring(self.task_info[v].status))
		if self.task_info[v].parent == parent and
		  (self.task_info[v].status == "selected" or
		   self.task_info[v].status == "completed")
		then
			return true
		end
	end
	return false
end
-- obtaining items can complete tasks, but reward dependent on actually returning them to vendor
function CRandomTask:is_find_task(sel_task)
	if string.find(sel_task.type, "artefact") ~= nil then
		return true
	elseif string.find(sel_task.type, "monster_part") ~= nil then
		return true
	elseif string.find(sel_task.type, "find_item") ~= nil then
		return true
	end
	return false
end
--' Есть ли игрока завершенные задания (которые осталось только сдать)
function CRandomTask:have_completed_job(actor, npc)
	-- print_table(self.active_task_by_type)
	local parent = self:get_parent(npc)
	for k,v in pairs(self.active_task_by_type) do
--		printf("have_completed_job: %s", tostring(v))
--		printf("have_completed_job: parent = %s", tostring(self.task_info[v].parent))
--		printf("have_completed_job: status = %s", tostring(self.task_info[v].status))

		if self.task_info[v].parent == parent and
		   self.task_info[v].status == "completed"
		then
			-- if not a find task, job is completed as is
			if not self:is_find_task(self.task_info[v]) then return true end
			-- else player must still have item
			-- dbglog("have_completed_job: checking for requested item - "..self.task_info[v].target)
			return actor:object(self.task_info[v].target) ~= nil
		end
	end
	return false
end
--' Выдача квеста игроку
function CRandomTask:action_give_task(actor, npc, p1, p2)
	local task = CGameTask()

	-- printf("p1 = %s p2 = %s", tostring(p1), tostring(p2))
	-- dbglog("task_manager.script:action_give_task():  p1 = %s p2 = %s", tostring(p1), tostring(p2))

	local task_desc = self.task_info[self.task_id_by_yes_phrase_id[p2]]

	task:load(task_desc.complex_type)
	task:set_title(task_desc.type)

	local oo = task:get_objective(0)
	oo:set_article_id(task_desc.description)

	local objective = SGameTaskObjective(task,1)
	objective:set_description(task_desc.name)
	--' Выбираем текущую цель квеста
	if task_desc.target_objects ~= nil then
		self.task_info[self.task_id_by_yes_phrase_id[p2]].selected_target = task_desc.target_objects[math.random(#task_desc.target_objects)]
		-- printf("TARGET DEBUG INFO")
		-- printf("selected = %s", tostring(self.task_info[self.task_id_by_yes_phrase_id[p2]].selected_target))
		-- print_table(task_desc.target_objects)
	end

	if task_desc.type == "eliminate_lager" then
		objective:set_map_hint(task_desc.text)
		objective:set_map_location("eliminate_lager_location")
		objective:set_object_id(task_desc.selected_target)
	elseif task_desc.type == "defend_lager" then
		objective:set_map_hint(task_desc.text)
		objective:set_map_location("defend_lager_location")
		objective:set_object_id(task_desc.selected_target)

		local defend_object = alife():object(task_desc.selected_target)
		local sm_ini = defend_object:spawn_ini()
		self.task_info[self.task_id_by_yes_phrase_id[p2]].defend_target = utils.cfg_get_number(sm_ini, "random_task", "defend_target", nil, true)
	elseif task_desc.type == "kill_stalker" then
		objective:set_map_hint(task_desc.text)
		objective:set_map_location("kill_stalker_location")
		objective:set_object_id(task_desc.selected_target)
	elseif task_desc.type == "find_item" then
		objective:set_map_hint(task_desc.text)
		objective:set_map_location("find_item_location")
		objective:set_object_id(task_desc.selected_target)
	end
	objective:add_complete_func("task_manager.task_complete")
	task:add_objective(objective)

	if task_desc.need_return then
		objective = SGameTaskObjective(task,2)
		local return_type = return_task_by_type[task_desc.type]
		objective:set_description(return_type)
		-- nv080630 more useful info (revised; see nv140407 below)
		-- objective:set_map_hint(return_task_by_type[task_desc.type])
		local return_string = game.translate_string(return_type)
		-- nv080630 don't stack location spots that don't go away
		-- objective:set_object_id(alife():story_object(tonumber(story_by_parent[task_desc.parent])).id)
		local task_parent_id = alife():story_object(tonumber(story_by_parent[task_desc.parent])).id
		-- local spot_location = "blue_location" -- now could be "blue_location_2"
		-- nv140407 split the two return types into separate categories, still using same marker
		if level.map_has_object_spot(task_parent_id, return_location[return_type]) == 0 then
			-- nv140407 no same-type return task pending - we can add details for this one
			return_string = return_string.."\\n%c[255,160,160,160]"..game.translate_string(task_desc.name)
		end
		objective:set_map_hint(return_string)
		objective:set_map_location(return_location[return_type])
		objective:set_object_id(task_parent_id)
		task:add_objective(objective)
	end

	local time = 0
	if task_desc.time ~= nil then
		time = task_desc.time * 1000 * quest_time_factor
		-- all current init_condition tasks are auto-quest tasks
		if task_desc.init_condition ~= nil then
			time = task_desc.time * 1000 * autoquest_time_factor
		end
	end
	actor:give_task(task,time,false)

	--' дизаблим все остальные задания данного типа, так как игрок не может одновременно обладать двумя заданиями одного типа.
	self.task_info[self.task_id_by_yes_phrase_id[p2]].status = "selected"
	self.active_task_by_type[task_desc.complex_type] = self.task_id_by_yes_phrase_id[p2]
	for k,v in pairs(self.task_info) do
		if v.complex_type == task_desc.complex_type then
			v.enabled = false
		end
	end
	-- dbglog("Task given")
end
--' Отказ игроком от квеста
function CRandomTask:action_refuse_task(actor, npc, p1, p2)
	local task_desc = self.task_info[self.task_id_by_yes_phrase_id[p2]]

	--' Делаем доступными все задания данного типа
	self.task_info[self.task_id_by_yes_phrase_id[p2]].status = "refused"
	self.task_info[self.active_task_by_type[task_desc.complex_type]].selected_target = nil
	for k,v in pairs(self.task_info) do
		if v.complex_type == task_desc.complex_type then
			v.enabled = true
		end
	end
end
function CRandomTask:action_reject_task(actor, npc, p1, p2)
	-- the task rejection id, p2, is used to identify the task
	local task_desc = self.task_info[self.task_id_by_never_phrase_id[p2]]

	if task_desc == nil then
		dbglog("task desc is a nil value")
		return
	end
	-- push the task out for idle_time (default 1 day)
	self.task_info[self.task_id_by_never_phrase_id[p2]].last_task_time = game.get_game_time()
	for k,v in pairs(self.task_info) do
		if v.complex_type == task_desc.complex_type then
			v.enabled = true
		end
	end
end
--' Проверяем, не выполнен ли таск
function CRandomTask:task_complete(p1, p2)
	if actor == nil then
		return false
	end

	local sel_task = self.task_info[self.active_task_by_type[p1]]
	if sel_task == nil then
		-- printf("!!!")
		-- print_table(self.active_task_by_type)
		-- printf("!!!")
		-- print_table(self.task_info)
		abort("WRONG RANDOM TASK %s %s", tostring(p1), tostring(p2))
		get_console():execute("quit")
		return
	end

	if p2 == 0 then
		if not sel_task.need_return and sel_task.status == "completed" then
			-- give out the reward on the spot
			if sel_task.reward_money ~= nil and sel_task.reward_money > 0 then
				local parent = alife():story_object(story_by_parent[sel_task.parent])
				dialogs.relocate_money(parent, sel_task.reward_money, "in")
			end
			if sel_task.reward_reputation ~= nil then
				local rep = actor:character_reputation()
				actor:change_character_reputation(sel_task.reward_reputation)
				if show_relation_changes then
					_z.nvDebug("random task rep change: "..sel_task.type.."\\n"..rep.." + ".. sel_task.reward_reputation.." = "..actor:character_reputation())
				end
			end

			if sel_task.reward_relation ~= nil then
				for kk,vv in pairs(sel_task.reward_relation) do
					relation_registry.change_community_goodwill (kk, 0, tonumber(vv)) --db.actor:id(), tonumber(vv))
					if show_relation_changes then
						_z.nvDebug("relation change: "..sel_task.type.."\\n"..kk..": ".. tostring(vv) .." => "..tostring(relation_registry.community_goodwill (kk, 0, tonumber(vv))))
					end
				end
			end

			if sel_task.reward_rank ~= nil then
				actor_stats.add_points("quests", sel_task.name, 1, sel_task.reward_rank)
				actor:set_character_rank(actor:character_rank() + sel_task.reward_rank)
			end
			self.task_info[self.active_task_by_type[p1]].last_task_time = game.get_game_time()
			return true
		end
		if sel_task.status == "rewarded" then
			self.task_info[self.active_task_by_type[p1]].last_task_time = game.get_game_time()
			return true
		end
	end

	if p2 == 1 then
		if string.find(p1, "eliminate_lager") ~= nil then
			local oo = alife():object(sel_task.selected_target)
			if oo and oo.gulag:get_population_comed() == 0 then
				self.task_info[self.active_task_by_type[p1]].status = "completed"
				return true
			end
		elseif string.find(p1, "defend_lager") ~= nil then
			--' Квест выполнен потому что рейд прекратился
			if xr_gulag.getGulagState(sel_task.defend_target) == 0 then
				self.task_info[self.active_task_by_type[p1]].status = "completed"
				return true
			end
		elseif string.find(p1, "kill_stalker") ~= nil then
			local oo = alife():object(sel_task.selected_target)

			--' Проверка бага
			if oo == nil then
				-- printf("selected_target = %s", tostring(sel_task.selected_target))
				abort("OBJ = nil for task %s", tostring(self.active_task_by_type[p1]))
			elseif oo.alive == nil then
				-- printf("OBJ.ALIVE = nil for task %s", tostring(self.active_task_by_type[p1]))
				abort("OBJ.NAME = %s", obj:name())
			end

			if oo and oo:alive() == false then
				self.task_info[self.active_task_by_type[p1]].status = "completed"
				return true
			end
		elseif self:is_find_task(sel_task) and actor:object(sel_task.target) ~= nil then
			--artefact, monster_part, find_item
			self.task_info[self.active_task_by_type[p1]].status = "completed"
			return true
		end
	end

	return false
end
--' Проверяем, не профейлен ли таск
function CRandomTask:task_fail(p1, p2)
	if p2 == 0 then
		local sel_task = self.task_info[self.active_task_by_type[p1]]

		if sel_task == nil then
			-- printf("!!!")
			-- print_table(self.active_task_by_type)
			-- printf("!!!")
			-- print_table(self.task_info)
			abort("WRONG RANDOM TASK %s %s", tostring(p1), tostring(p2))
			get_console():execute("quit")
			return
		end

		--' Проверяем что жив, выдавший квест.
		local parent = alife():story_object(story_by_parent[sel_task.parent])
		if parent == nil or (parent.alive ~= nil and not parent:alive()) then
			self.task_info[self.active_task_by_type[p1]].status = "failed"
			self.task_info[self.active_task_by_type[p1]].last_task_time = game.get_game_time()
			return true
		end

		if sel_task.status == "refused" or sel_task.status == "failed" then
			self.task_info[self.active_task_by_type[p1]].last_task_time = game.get_game_time()
			return true
		end
		if string.find(p1, "defend_lager") ~= nil then
			if alife():object(sel_task.selected_target).gulag:get_population_comed() == 0 then
				self.task_info[self.active_task_by_type[p1]].status = "failed"
				self.task_info[self.active_task_by_type[p1]].last_task_time = game.get_game_time()
				return true
			end
		end
	end
	return false
end
--' Обнуление переменных при завершении или провале таска
function CRandomTask:task_callback(p1, p2, state)
	if p2 ~= 0 then
		return
	end

	if self.active_task_by_type[p1] == nil then
		return
	end

	if state == task.completed then
		self.task_info[self.active_task_by_type[p1]].status = "normal"
		--' восстановление других заданий данного типа
		for k,v in pairs(self.task_info) do
			if v.complex_type == self.task_info[self.active_task_by_type[p1]].complex_type then
				v.enabled = true
			end
		end
		self.active_task_by_type[p1] = nil

	elseif state == task.fail then
		self.task_info[self.active_task_by_type[p1]].status = "normal"

		--' восстановление других заданий данного типа
		for k,v in pairs(self.task_info) do
			if v.complex_type == self.task_info[self.active_task_by_type[p1]].complex_type then
				v.enabled = true
			end
		end
		self.active_task_by_type[p1] = nil
	end
end
--' Выводит список доступных квестов
function CRandomTask:action_task_show(npc, actor)
	local parent = self:get_parent(npc)
	for k,v in pairs(self.task_id_by_parent[parent]) do
		if self:task_avail(actor, npc, nil, nil, self.task_info[v].init_phrase_id, false) then
			local task_texture, task_rect = get_texture_info("ui_icons_task_"..self.task_info[v].type, "ui_iconsTotal_locations")
			actor:give_talk_message(game.translate_string(self.task_info[v].name), task_texture, task_rect,"iconed_trade_info")
		end
	end
end
--' Проверка доступен ли текущий таск для выдачи
function CRandomTask:task_avail(actor, npc, p1, p2, p3, calculate)
	local task_desc = self.task_info[self.task_id_by_init_phrase_id[p3]]
	--' Если calculate == true то нужно проверять check_task_props, инача просто вернуть значения.
	if calculate == "reset" then
		self.current_parent_type_prior = {}
		return
	elseif calculate == true then
		self:check_task_props(self.task_id_by_init_phrase_id[p3])

		local t = task_desc.enabled and task_desc.enabled_props and task_desc.init_condition == nil

		--' Устанавливать обрезания по приоритетам тут.
		if t == true and (self.current_parent_type_prior[task_desc.complex_type] == nil or
		   self.current_parent_type_prior[task_desc.complex_type] > task_desc.prior )
		then
			self.current_parent_type_prior[task_desc.complex_type] = task_desc.prior
		end

		return t
	end

--'	printf("@@@prior %s -> %s [%s]", task_desc.complex_type, task_desc.prior, tostring(calculate))
--'	print_table(self.current_parent_type_prior)

	if self.current_parent_type_prior[task_desc.complex_type] ~= nil and
	   self.current_parent_type_prior[task_desc.complex_type] < task_desc.prior then
		return false
	end

--'	printf("@@@avail %s", tostring(self.task_id_by_init_phrase_id[p3]))
--'	printf("@@@enabled %s", tostring(self.task_info[self.task_id_by_init_phrase_id[p3]].enabled))
--'	printf("@@@enabled_props %s", tostring(self.task_info[self.task_id_by_init_phrase_id[p3]].enabled_props))

	return task_desc.enabled and
		   task_desc.enabled_props and
		   task_desc.init_condition == nil
end
--' Проверка свойств таска
function CRandomTask:check_task_props(task_id)
	--' Проверка по активным заданиям данного типа у вендора.
	if self.active_task_by_type[self.task_info[task_id].complex_type] ~= nil then
		self.task_info[task_id].enabled_props = false
		return
	end

	--' Проверка по кондлисту
	if xr_logic.pick_section_from_condlist(actor, actor, self.task_info[task_id].condlist) == nil then
		self.task_info[task_id].enabled_props = false
		return
	end

	--' Проверка по таймауту
	if self.task_info[task_id].last_task_time ~= nil and
		game.get_game_time():diffSec(self.task_info[task_id].last_task_time) < self.task_info[task_id].idle_time
	then
		self.task_info[task_id].enabled_props = false
		return
	end

	--' проверка по таргету
	if self.task_info[task_id].type == "eliminate_lager" then
		if self.task_info[task_id].target_objects == nil then
			self.task_info[task_id].enabled_props = false
			return
		end
		for k,v in pairs(self.task_info[task_id].target_objects) do
			local gulag = alife():object(v).gulag
			if gulag:get_population_comed() > 0 then
				self.task_info[task_id].enabled_props = true
				return
			end
		end
		self.task_info[task_id].enabled_props = false
		return
	elseif self.task_info[task_id].type == "defend_lager" then
		if self.task_info[task_id].target_objects == nil then
			self.task_info[task_id].enabled_props = false
			return
		end
		for k,v in pairs(self.task_info[task_id].target_objects) do
			local defend_object = alife():object(v)
			local sm_ini = defend_object:spawn_ini()
			local defend_target = utils.cfg_get_number(sm_ini, "random_task", "defend_target", nil, true)
			if xr_gulag.getGulagState(defend_target) == 1 then
				self.task_info[task_id].enabled_props = true
				return
			end
		end
		self.task_info[task_id].enabled_props = false
		return
	elseif self.task_info[task_id].type == "kill_stalker" then
		if self.task_info[task_id].target_objects == nil then
			self.task_info[task_id].enabled_props = false
			return
		end
		for k,v in pairs(self.task_info[task_id].target_objects) do
			local obj = alife():object(v)

			--' Проверка бага
			if obj ~= nil and obj.alive == nil then
				-- printf("OBJ.ALIVE = nil for task %s", task_id)
				-- print_table(self.task_info[task_id].target_objects)
				abort("OBJ.NAME = %s", obj:name())
			end

			if obj ~= nil and
			   obj:alive() == true
			then
				self.task_info[task_id].enabled_props = true
				return
			else
				table_remove(self.task_info[task_id].target_objects, k)
			end
		end
		self.task_info[task_id].enabled_props = false
		return
	elseif self.task_info[task_id].type == "find_item" then
		if self.task_info[task_id].target_objects == nil or #self.task_info[task_id].target_objects == 0 then
			self.task_info[task_id].enabled_props = false
			return
		end
		for k,v in pairs(self.task_info[task_id].target_objects) do
			local obj = alife():object(v)
			if obj ~= nil then
				--' Нужно игнорировать предметы, которые находяться у вендоров.
				if obj.parent_id ~= nil then
					for kk,vv in pairs(parent_by_story) do
						local parent = alife():story_object(kk)
						if parent ~= nil and obj.parent_id == parent.id then
							--' Игнорим предмет
							self.task_info[task_id].enabled_props = false
							return
						end
					end
				end

				self.task_info[task_id].enabled_props = true
				return
			end
			self.task_info[task_id].enabled_props = false
			return
		end
	else
		self.task_info[task_id].enabled_props = true
		return
	end
end
--' Проверяем можем ли мы сейчас выдать какой либо самоинициализующийся таск
function CRandomTask:actor_update()
	for k,v in pairs(self.task_id_self_inited) do
		if self.task_info[v].status == "normal" then
			self:check_task_props(v)
			if self.task_info[v].enabled_props == true and
			   self.task_info[v].enabled == true and
			   xr_logic.pick_section_from_condlist(actor, actor, self.task_info[v].init_condition) ~= nil
			then
				-- ' Нужно автоматически выдать квест
				self:action_give_task(actor, nil, nil, self.task_info[v].yes_phrase_id)
			end
		end
	end
end
--' Проверяется является ли текущий таск выданным игроку
-- nv130130 tweaked to support found task item not in inventory
function CRandomTask:active_task(actor, npc, p1, p2, p3)
	local this_task = self.task_info[self.task_id_by_init_phrase_id[p3]]
	if this_task.status == "selected" then
		return true
	elseif this_task.status == "completed" then
		if self:is_find_task(this_task) then
			-- task is active if you don't have the found item to turn in
			return actor:object(this_task.target) == nil
		end
	end
	return false
end
--' Создается диалог актера, в котором будут выдаваться задания.
function CRandomTask:init_task_dialog(dlg, parent)
	local phr = self:AddPhrase(dlg,"tm_seek_new_job",0,-1,-10000)
	local phrase_script = phr:GetPhraseScript()

	phr = self:AddPhrase(dlg,"tm_"..parent.."_list_job",1,0,-10000)
	phrase_script = phr:GetPhraseScript()
	phrase_script:AddAction("task_manager.action_task_show")
	phrase_script:AddPrecondition("task_manager.precondition_vendor_can_task")

	phr = self:AddPhrase(dlg,"tm_"..parent.."_has_no_job",2,0,-10000)
	phrase_script = phr:GetPhraseScript()
	phrase_script:AddPrecondition("task_manager.precondition_vendor_cannot_task")

	for k,v in pairs(self.task_id_by_parent[parent]) do
		phr = self:AddPhrase(dlg,self.task_info[v].name, self.task_info[v].init_phrase_id, 1, -10000)
		phrase_script = phr:GetPhraseScript()
		phrase_script:AddPrecondition("task_manager.precondition_task_avail")

		phr = self:AddPhrase(dlg,self.task_info[v].text, self.task_info[v].desc_phrase_id, self.task_info[v].init_phrase_id, -10000)
		-- SHOW_REWARD MOD BEGIN
		if show_quest_rewards then
			show_reward.add_reward_display(phr)
		end
		-- SHOW_REWARD MOD END

		phr = self:AddPhrase(dlg,"tm_seek_job_yes", self.task_info[v].yes_phrase_id, self.task_info[v].desc_phrase_id, -10000)
		phrase_script = phr:GetPhraseScript()
		phrase_script:AddAction("task_manager.action_give_task")

		phr = self:AddPhrase(dlg,"tm_seek_job_no", self.task_info[v].no_phrase_id, self.task_info[v].desc_phrase_id, -10000)

		if allow_task_rejection then
			phr = self:AddPhrase(dlg,"tm_seek_job_never", self.task_info[v].never_phrase_id, self.task_info[v].desc_phrase_id, -10000)
			phrase_script = phr:GetPhraseScript()
			phrase_script:AddAction("task_manager.action_reject_task")
		end
	end

	self:AddPhrase(dlg,"tm_seek_job_abandon",3,1,-10000)
end
--' Функция, в которой будет выдаваться вещевая награда за выполненные квесты
function CRandomTask:task_reward(npc, actor, p1, p2)
	local parent = self:get_parent(npc)
	for k,v in pairs(self.active_task_by_type) do
		local task_desc = self.task_info[v]
		if task_desc.status == "completed" and task_desc.parent == parent then
			--' Забираем у игрока квестовый предмет.
			local can_finish = true
			if self:is_find_task(task_desc) then --artefact, monster_part, find_item
				can_finish = actor:object(task_desc.target) ~= nil
				if can_finish then
					dialogs.relocate_item_section(npc, task_desc.target, "out")
				end
			end

			if can_finish then
				self.task_info[v].status = "rewarded"

				if task_desc.reward_money ~= nil then
					dialogs.relocate_money(npc, task_desc.reward_money, "in")
				end

				if task_desc.reward_item ~= nil then
					for kk,vv in pairs(task_desc.reward_item) do
						dialogs.relocate_item_section(npc, vv, "in")
					end
				end

				if task_desc.reward_reputation ~= nil then
					local rep = actor:character_reputation()
					actor:change_character_reputation(task_desc.reward_reputation)
					if show_relation_changes then
						_z.nvDebug("random task rep change: "..task_desc.type.."\\n"..rep.." + ".. task_desc.reward_reputation.." = "..actor:character_reputation())
					end
				end

				if task_desc.reward_relation ~= nil then
					for kk,vv in pairs(task_desc.reward_relation) do
						relation_registry.change_community_goodwill (kk, 0, tonumber(vv)) --db.actor:id(), tonumber(vv))
						if show_relation_changes then
							_z.nvDebug("relation change: "..task_desc.type.."\\n"..kk..": ".. tostring(vv) .." => "..tostring(relation_registry.community_goodwill (kk, 0, tonumber(vv))))
						end
					end
				end

				if task_desc.reward_rank ~= nil then
					actor_stats.add_points("quests", task_desc.name, 1, task_desc.reward_rank)
					actor:set_character_rank(actor:character_rank() + task_desc.reward_rank)
				end
			end
		end
	end
end
--' Функция, в которой будет выдаваться вещевая награда за выполненные сторилайновые квесты
function CRandomTask:task_reward_storyline(task)
	local task_desc = self.task_info[task:get_id()]
	if task_desc == nil or task_desc.type ~= "storyline" then
		return
	end

	if task_desc.reward_reputation ~= nil then
		local rep = actor:character_reputation()
		actor:change_character_reputation(task_desc.reward_reputation)
		if show_relation_changes then
			_z.nvDebug("storyline task rep change: "..task_desc.type.."\\n"..rep.." + ".. task_desc.reward_reputation.." = "..actor:character_reputation())
		end
	end

	if task_desc.reward_relation ~= nil then
		for kk,vv in pairs(task_desc.reward_relation) do
			relation_registry.change_community_goodwill (kk, 0, tonumber(vv)) --db.actor:id(), tonumber(vv))
			if show_relation_changes then
				_z.nvDebug("relation change: "..task_desc.type.."\\n"..kk..": ".. tostring(vv) .." => "..tostring(relation_registry.community_goodwill (kk, 0, tonumber(vv))))
			end
		end
	end

	if task_desc.reward_rank ~= nil then
		actor_stats.add_points("quests", task_desc.name, 1, task_desc.reward_rank)
		actor:set_character_rank(actor:character_rank() + task_desc.reward_rank)
	end
end
--' Создается диалог актера, в котором будут приниматься задания
function CRandomTask:init_reward_dialog(dlg, parent)
	local phr = self:AddPhrase(dlg,"tm_reward_job",0,-1,-10000)
	local phrase_script = phr:GetPhraseScript()

	phr = self:AddPhrase(dlg,"tm_"..parent.."_job_complete", 1, 0, -10000)
	phrase_script = phr:GetPhraseScript()
	phrase_script:AddAction("task_manager.action_task_reward")
	phrase_script:AddPrecondition("task_manager.precondition_have_completed_job")

	phr = self:AddPhrase(dlg,"tm_"..parent.."_job_ask", 2, 0, -10000)
	phrase_script = phr:GetPhraseScript()
	phrase_script:AddPrecondition("task_manager.precondition_dont_have_completed_job")


	-- Список возможных квестов трейдера.
	for k,v in pairs(self.task_id_by_parent[parent]) do
		phr = self:AddPhrase(dlg,self.task_info[v].name, self.task_info[v].init_phrase_id, 2, -10000)
		phrase_script = phr:GetPhraseScript()
		phrase_script:AddPrecondition("task_manager.precondition_active_task")

		phr = self:AddPhrase(dlg,"tm_"..parent.."_job_what", self.task_info[v].desc_phrase_id, self.task_info[v].init_phrase_id, -10000)

		phr = self:AddPhrase(dlg,"tm_job_refuse", self.task_info[v].yes_phrase_id, self.task_info[v].desc_phrase_id, -10000)
		phrase_script = phr:GetPhraseScript()
		phrase_script:AddAction("task_manager.action_refuse_task")

		phr = self:AddPhrase(dlg,"tm_job_nothing", self.task_info[v].no_phrase_id, self.task_info[v].desc_phrase_id,-10000)
	end

end

--' Регистрация целей для квестов.
function CRandomTask:register_target(obj)
	if IsStalker(obj) then
		--' Возможно регистрируется цель для квеста "убить сталкера"
		for k,v in pairs(self.task_id_by_type["kill_stalker"]) do
			if obj.alive ~= nil and obj:alive() == true and
				obj:profile_name() == self.task_info[v].target
			then
				if self.task_info[v].target_objects == nil then
					self.task_info[v].target_objects = {}
				end
--				printf("@@@register new target %s[%s] for task %s", obj:name(), obj.id, v)
				table_insert(self.task_info[v].target_objects, obj.id)
			end
		end

	elseif obj:clsid() == clsid_smart_terrain then
		--' Возможно регистрируется цель для квеста "вынести лагерь"
		for k,v in pairs(self.task_id_by_type["eliminate_lager"]) do
			if obj:name() == self.task_info[v].target then
				if self.task_info[v].target_objects == nil then
					self.task_info[v].target_objects = {}
				end
				table_insert(self.task_info[v].target_objects, obj.id)
			end
		end
		--' Либо регистрируется цель для квеста "защитить лагерь"
		for k,v in pairs(self.task_id_by_type["defend_lager"]) do
			if obj:name() == self.task_info[v].target then
				--' Проверка что в кастом дате указано от кого защищать
				local sm_ini = obj:spawn_ini()
				local defend_target = utils.cfg_get_number(sm_ini, "random_task", "defend_target", nil, true)
				if self.task_info[v].target_objects == nil then
					self.task_info[v].target_objects = {}
				end
				table_insert(self.task_info[v].target_objects, obj.id)
			end
		end

	else
		--' Возможно регистрируется цель для квеста "найти предмет"
		for k,v in pairs(self.task_id_by_type["find_item"]) do
			if obj:section_name() == self.task_info[v].target then
				if self.task_info[v].target_objects == nil then
					self.task_info[v].target_objects = {}
				end
				table_insert(self.task_info[v].target_objects, obj.id)
			end
		end
	end
end
--' ОТРегистрация целей для квестов.
function CRandomTask:unregister_target(obj)
	if IsStalker(obj) then
		--' Возможно регистрируется цель для квеста "убить сталкера"
		for k,v in pairs(self.task_id_by_type["kill_stalker"]) do
			if self.task_info[v].target_objects ~= nil then
				for kk,vv in pairs(self.task_info[v].target_objects) do
					if vv == obj.id then
						table_remove(self.task_info[v].target_objects, vv)
					end
				end
			end
		end
	elseif obj:clsid() == clsid_smart_terrain then
	else
		--' Возможно регистрируется цель для квеста "найти предмет"
		for k,v in pairs(self.task_id_by_type["find_item"]) do
			if self.task_info[v].target_objects ~= nil then
				for kk,vv in pairs(self.task_info[v].target_objects) do
					if vv == obj.id then
						table_remove(self.task_info[v].target_objects, vv)
					end
				end
			end
		end
	end
end
--[[ -- nv 111220 remove unused functions
function CRandomTask:stats(obj)
	dbglog("Task statistics requested!")
	_z.nvdebug("Task statistics requested!")
	printf("### TASK STATISTIC ###")
	for k,v in pairs(self.task_info) do
		if v.init_condition ~= nil then
			printf("[%s] %s : %s", v.status, k, tostring(v.enabled_props))
			print_table(v.init_condition)
		end
	end
end
--]]
function get_random_task()
	if random_task == nil then
		random_task = CRandomTask()
	end
	return random_task
end


function init_trader_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "trader")
end
function init_barman_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "barman")
end
function init_ecolog_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "ecolog")
end
function init_dolg_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "dolg")
end
function init_freedom_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "freedom")
end


function init_shustriy_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "shustriy")
end
function init_lisiy_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "lisiy")
end
function init_hunter_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "hunter")
end
function init_drunk_dolg_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "drunk_dolg")
end
function init_petrenko_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "petrenko")
end
function init_wolf_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "wolf")
end
function init_zastava_commander_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "zastava_commander")
end
function init_mercenary_task_dialog(dlg)
	get_random_task():init_task_dialog(dlg, "mercenary")
end



function init_trader_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "trader")
end
function init_barman_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "barman")
end
function init_ecolog_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "ecolog")
end
function init_dolg_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "dolg")
end
function init_freedom_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "freedom")
end



function init_shustriy_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "shustriy")
end
function init_lisiy_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "lisiy")
end
function init_hunter_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "hunter")
end
function init_drunk_dolg_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "drunk_dolg")
end
function init_petrenko_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "petrenko")
end
function init_wolf_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "wolf")
end
function init_zastava_commander_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "zastava_commander")
end
function init_mercenary_reward_dialog(dlg)
	get_random_task():init_reward_dialog(dlg, "mercenary")
end


function has_active_vendor_task(actor, npc)
	return get_random_task():active_parent_task(actor, npc)
end
function precondition_task_avail(actor, npc, p1, p2, p3)
	return get_random_task():task_avail(actor, npc, p1, tonumber(p2), tonumber(p3), false)
end
function precondition_active_task(actor, npc, p1, p2, p3)
	return get_random_task():active_task(actor, npc, p1, tonumber(p2), tonumber(p3))
end

function precondition_vendor_can_task(npc, actor, p1, p2, p3)
	-- p2, p3 not currently used, so no conversion done
	return get_random_task():parent_can_task(actor, npc, p1, p2, p3)
end
function precondition_vendor_cannot_task(npc, actor, p1, p2, p3)
	-- p2, p3 not currently used, so no conversion done
	return not get_random_task():parent_can_task(actor, npc, p1, p2, p3)
end
function precondition_have_completed_job(npc, actor, p1, p2, p3)
	return get_random_task():have_completed_job(actor, npc)
end
function precondition_dont_have_completed_job(npc, actor, p1, p2, p3)
	return not get_random_task():have_completed_job(actor, npc)
end

function action_task_show(npc, actor)
	get_random_task():action_task_show(npc, actor)
end
function action_give_task(actor, npc, p1, p2)
	get_random_task():action_give_task(actor, npc, p1, tonumber(p2))
end
function action_reject_task(actor, npc, p1, p2)
	get_random_task():action_reject_task(actor, npc, p1, tonumber(p2))
end
function action_refuse_task(npc, actor, p1, p2)
	get_random_task():action_refuse_task(npc, actor, p1, tonumber(p2))
end
function action_task_reward(actor, npc, p1, p2)
	get_random_task():task_reward(actor, npc, p1, tonumber(p2))
end
function reward_by_task(task)
	get_random_task():task_reward_storyline(task)
end

function task_complete(p1, p2)
	return get_random_task():task_complete(p1, p2)
end
function task_fail(p1, p2)
	return get_random_task():task_fail(p1, p2)
end
function task_callback(p1, p2, state)
	return get_random_task():task_callback(p1, p2, state)
end

function actor_update()
	get_random_task():actor_update()
end


function save(p)
	get_random_task():save(p)
end
function load(p)
	get_random_task():load(p)
end
function clear_task_manager()
	random_task	 = nil
end
