-- nv 070924 set quest_days 0 for unlimited quest time
quest_days = 0

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

-- nv 070924 set idle_time_days 0 for infinite delay
idle_time_days = 3

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 hash_to_id={}
local id_to_hash={}
local ct_to_hash={}
local hash_to_ct={}
-- хэш функция для строки (посмотреть литературу, на предмет оптимальной)
function stringhash(str)
  local mpl=1
  local hash=0
  for i=1,string.len(str),1 do
    local val=string.byte(string.sub(str,i,i))
    hash=hash+mpl*val
    mpl=mpl*2
    if mpl==512 then mpl=1 end
  end
  return bit_and(hash,65535)
end

class "CRandomTask"
function CRandomTask:__init()
  --' На конструкторе вычитываем LTX и создаем заготовки квестов.
  self.task_ini = ini_file("misc\\task_manager.ltx")
  self.task_phrase_id = 100

  --' Итерируемся по всем настройкам фраз
  if not self.task_ini:section_exist("list") then
    abort("There is no section [list] in task_manager.ltx")
  end
  local n = self.task_ini:line_count("list")
  local id, value = "",""
  local category = ""
	if idle_time_days == 0 then
		idle_time_days = 10000
	end

  --' начальная установка
  self.task_info = {}
  
  for i=0,n-1 do
    result, id, value = self.task_ini:r_line("list",i,"","")
    local hash=stringhash(id)
    if hash_to_id[hash] then
      abort("Collision! Hash:%d id1:%s id2:%s",hash,hash_to_id[hash],id)
    end
    hash_to_id[hash]=id
    id_to_hash[id]=hash
    -- amk.mylog("id:"..id.." hash:"..hash)
    
    if not self.task_ini:section_exist(id) then
      abort("There is no section [%s] in task_manager.ltx", id)
    end   

		self.task_info[tostring(id)]			= {}
		local curr_task_info					= self.task_info[tostring(id)]
    if not self.task_ini:line_exist(id, "type") then
      abort("Task manager error: no type in section [%s]", id)
    end

		curr_task_info.type			= self.task_ini:r_string(id, "type")			

		curr_task_info.name			= id
		if self.task_ini:line_exist(id, "parent") then
			curr_task_info.parent		= self.task_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
    local ct=curr_task_info.complex_type
    local cthash=stringhash(ct)
    if hash_to_ct[cthash] and hash_to_ct[cthash]~=ct then
      abort("Collision! Hash:%d ct1:%s ct2:%s",hash,hash_to_id[hash],id)
    end
    hash_to_ct[cthash]=ct
    ct_to_hash[ct]=cthash
    
		if self.task_ini:line_exist(id, "target") then
			curr_task_info.target		= self.task_ini:r_string(id, "target")
		end
		if self.task_ini:line_exist(id, "text") then
			curr_task_info.text			= self.task_ini:r_string(id, "text")
		end
		if self.task_ini:line_exist(id, "description") then
			curr_task_info.description	= self.task_ini:r_string(id, "description")				
		end
		curr_task_info.time				= utils.cfg_get_number(self.task_ini, id, "time", nil, false)

		curr_task_info.idle_time		= utils.cfg_get_number(self.task_ini, id, "idle_time", nil, false, 24*60*60) --' Время между выдачами задания (в игровых секундах)
		curr_task_info.prior			= utils.cfg_get_number(self.task_ini, id, "prior", nil, false, 0) --' Приоритет квеста, выдаются доступные квесты с наименьшим приоритетом
	
		if self.task_ini:line_exist(id, "init_condition") then
			curr_task_info.init_condition = xr_logic.parse_condlist(db.actor, "task_manager", "init_condition", self.task_ini:r_string(id, "init_condition"))
		end

		local sss = utils.cfg_get_string(self.task_ini, id, "reward_item", nil, false, "")
		if sss ~= nil then
			curr_task_info.reward_item = se_respawn.parse_names(sss) 
		else
			curr_task_info.reward_item = sss
		end
		curr_task_info.reward_money = utils.cfg_get_number(self.task_ini, id, "reward_money", nil, false)		
    -- Награда информацией
--    amk.mylog("reward info read")
    local reward_info=utils.cfg_get_string(self.task_ini, id, "reward_info", nil, false,"")   
    if reward_info=="" then reward_info=nil end
    curr_task_info.reward_info = reward_info
    if reward_info then
       self:read_info_reward_section(self.task_ini,reward_info,curr_task_info)
    end
--    amk.mylog("reward info read done")
    -- Диалог для квестовой жертвы
    curr_task_info.target_dialog = utils.cfg_get_string(self.task_ini, id, "target_dialog", nil, false,"")
    ----------------------
  
		if self.task_ini:line_exist(id, "community") then
			curr_task_info.community = self.task_ini:r_string(id, "community")
		end		

		curr_task_info.reward_rank			= utils.cfg_get_number(self.task_ini, id, "reward_rank", nil, false, 0)
		curr_task_info.reward_reputation	= utils.cfg_get_number(self.task_ini, id, "reward_reputation", nil, false)
		curr_task_info.reward_relation		= parse_key_value(utils.cfg_get_string(self.task_ini, id, "reward_relation", nil, false, ""))
		
		if self.task_ini:line_exist(id, "condlist") then
			curr_task_info.condlist			= xr_logic.parse_condlist(db.actor, "task_manager", "condlist", self.task_ini:r_string(id, "condlist"))
		else
			curr_task_info.condlist			= xr_logic.parse_condlist(db.actor, "task_manager", "condlist", "true")
		end		
	
		curr_task_info.need_return			= utils.cfg_get_bool(self.task_ini, id, "need_return", nil, false, true)

		curr_task_info.init_phrase_id		= self:gen_phrase_id()
		curr_task_info.desc_phrase_id		= self:gen_phrase_id()
		curr_task_info.yes_phrase_id		= self:gen_phrase_id()
		curr_task_info.no_phrase_id			= self:gen_phrase_id()
    curr_task_info.completed_phrase_id = self:gen_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_completed_phrase_id = {}
  self.task_id_by_desc_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
    --' По типу квеста
    if self.task_id_by_type[v.type] == nil then
      self.task_id_by_type[v.type] = {}
    end
    table.insert(self.task_id_by_type[v.type], k)

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

    --' По id фразы согласия на квест
    self.task_id_by_yes_phrase_id[tostring(v.yes_phrase_id)] = k
    self.task_id_by_completed_phrase_id[v.completed_phrase_id] = k
    self.task_id_by_desc_phrase_id[v.desc_phrase_id] = k
--    amk.mylog("task "..v.complex_type .. " id " .. v.completed_phrase_id)
    --' По id фразы выдачи квеста.
		self.task_id_by_init_phrase_id[tostring(v.init_phrase_id)] = k
    --' По самовыдаваемости
    if v.init_condition ~= nil then
      table.insert(self.task_id_self_inited, k)
    end
  end
end

--------- Награда информацией --------
function CRandomTask:read_info_reward_section(ini,sect,container)
--  amk.mylog("reading section "..sect)
  container.reward_info_portion=utils.cfg_get_string(ini,sect,"info_portion",nil,true,"")
  container.reward_info_dialog={}
  local phr=1
  while true do
    local phrase_id=utils.cfg_get_string(ini,sect,"phrase_"..phr,nil,false,"")
--    amk.mylog("phrase_"..phr.." is "..phrase_id)
    phr=phr+1
    if phrase_id==nil or phrase_id=="" then break end
    table.insert(container.reward_info_dialog,phrase_id)    
  end  
end
--------------------------------------

-- Что-то совершенно не нравится мне эта функция. Переделаю её. Тратить 5КБ из 7-ми на всякую ерунду - многовато
--[[
--' Сохранение
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
]]

    --' Статус квеста, может быть: "normal", "selected", "completed", "refused", "failed", "rewarded"
-- Ну и замечательно. Запишем его числом. - семикратная экономия.
local status_to_num={normal=0, selected=1, completed=2, refused=3, 
  failed=4, rewarded=5}
local num_to_status={[0]="normal", [1]="selected", [2]="completed", [3]="refused", 
  [4]="failed", [5]="rewarded"}

-- Будем записывать не id задания а его хеш - семикратная экономия.
function CRandomTask:save(p)
  printf("^^^ SAVE")
  -- Отметка того, что это новая версия формата.
  p:w_u8(255)
  --' Считаем количество записей
  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
    if not id_to_hash[k] then
      abort("Cannot find hash for id %s!",k)
    end
    p:w_u16(id_to_hash[k]) 
    p:w_bool(v.enabled) 
    p:w_bool(v.enabled_props)
    if not status_to_num[v.status] then
      abort("Wrong status '%s' for task %s!",v.status,k)
    end
    p:w_u8(status_to_num[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
    if not ct_to_hash[k] then
      abort("Cannot find hash for complex type %s!",k)
    end
    p:w_u16(ct_to_hash[k]) 
    if not id_to_hash[v] then
      abort("Cannot find hash for task id %s!",v)
    end
    p:w_u16(id_to_hash[v])
  end
end

--' Загрузка
function CRandomTask:load(p)
  printf("^^^ LOAD")
  --' Считаем количество записей
  local rt0=p:r_tell()
  local i = p:r_u8()
  amk.mylog("tasks "..i)
  if i~=255 then
    for k = 1,i do
      local id = p:r_stringZ() 
      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)
    end
    --' Та же самая процедура с активными тасками
    local i = p:r_u8()  
    amk.mylog("active "..i)
    for k = 1,i do
      local id = p:r_stringZ()
      self.active_task_by_type[id] = p:r_stringZ()  
    end
  else
    i=p:r_u8()
    for k = 1,i do
      local hash = p:r_u16() 
      local id=hash_to_id[hash]
      if not id then
        abort("Cannot find id for hash %d!",hash)
      end
      self.task_info[id].enabled = p:r_bool()
      self.task_info[id].enabled_props = p:r_bool()
      self.task_info[id].status = num_to_status[p:r_u8()]

      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)
    end
    --' Та же самая процедура с активными тасками
    i = p:r_u8()  
    amk.mylog("active "..i)
    for k = 1,i do
      local cthash = p:r_u16()
      local id=hash_to_ct[cthash]
      if not id then
        abort("Cannot find complex type for hash %d!",cthash)
      end
      local hash=p:r_u16()
      self.active_task_by_type[id] = hash_to_id[hash]
      if not self.active_task_by_type[id] then
        abort("Cannot find task id for hash %d!",hash)
      end
    end
    amk.mylog("Feel the difference.")
  end
  amk.mylog("size "..p:r_tell()-rt0)
end
--' Генератор уникальных ID для фраз
function CRandomTask:gen_phrase_id()
	self.task_phrase_id = self.task_phrase_id + 1
	return tostring(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
--' Есть ли игрока завершенные задания (которые осталось только сдать)
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
      return true
    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))

  local task_id=self.task_id_by_yes_phrase_id[p2]
  local task_desc = self.task_info[task_id]
  
  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[task_id].selected_target = task_desc.target_objects[math.random(table.getn(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[task_id].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)
    -- Добавим id сталкера в список целей
    if task_desc.target_dialog then
      amk_add_target_id_to_kill_targets(task_desc.selected_target,task_desc.target_dialog,task_id)
    end
    -------------------------------------
  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)
    objective:set_description(return_task_by_type[task_desc.type])

    objective:set_map_hint(return_task_by_type[task_desc.type])
    objective:set_map_location("blue_location")
    if not alife():story_object(tonumber(story_by_parent[task_desc.parent])) then
    -- Квестодателя прибили.
      return 
    end
    objective:set_object_id(alife():story_object(tonumber(story_by_parent[task_desc.parent])).id)
    task:add_objective(objective)
  end

  local time = 0
  if task_desc.time ~= nil then
		time = task_desc.time * 1000 * quest_days
	end
	-- all current init_condition tasks are auto-quest tasks
	if task_desc.init_condition ~= nil then
		time = task_desc.time * 1000 * autoquest_days
  end
  db.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
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"
  -- Удаляем цель из списка 
  amk_remove_target_id_from_kill_targets(self.task_info[self.active_task_by_type[task_desc.complex_type]].selected_target)
  -------------------------
  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:task_complete(p1, p2)
  if db.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))
    return false
  end

  if p2 == 0 then
    if not sel_task.need_return and sel_task.status == "completed" then
      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
        -- Сталкер убит. Удаляем его ид из списка  целей
        amk_remove_target_id_from_kill_targets(sel_task.selected_target)
        -------------------------------------------------
        self.task_info[self.active_task_by_type[p1]].status = "completed"
        return true
      end
    elseif string.find(p1, "artefact") ~= nil then
      if db.actor:object(sel_task.target) ~= nil then
        self.task_info[self.active_task_by_type[p1]].status = "completed"
        return true
      end
    elseif string.find(p1, "monster_part") ~= nil then
      if db.actor:object(sel_task.target) ~= nil then
        self.task_info[self.active_task_by_type[p1]].status = "completed"
        return true
      end
    elseif string.find(p1, "find_item") ~= nil then
      if db.actor:object(sel_task.target) ~= nil then
        self.task_info[self.active_task_by_type[p1]].status = "completed"
        return true
      end
    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))
      return false
    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

  -- Удаляем цель из списка
  local task_info=self.task_info[self.active_task_by_type[p1]]
  if task_info and task_info.selected_target then
    amk_remove_target_id_from_kill_targets(task_info.selected_target)
  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")
      db.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(db.actor, db.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 table.getn(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(db.actor, db.actor, self.task_info[v].init_condition) ~= nil
      then
        --' Нужно автоматически выдать квест
        self:action_give_task(db.actor, nil, nil, self.task_info[v].yes_phrase_id)
      end
    end
  end
end
--' Проверяется является ли текущий таск выданным игроку
function CRandomTask:active_task(actor, npc, p1, p2, p3)
  return self.task_info[self.task_id_by_init_phrase_id[p3]].status == "selected" or
          self.task_info[self.task_id_by_init_phrase_id[p3]].status == "completed"
end

function CRandomTask:make_task_failed(task_id)
  if self.task_info and self.task_info[task_id] then
    self.task_info[task_id].status="failed"
  end
end

-- Проверяется наличие квестовых предметов
function CRandomTask:completed_task(actor, npc, p1, p2, p3)
--  amk.mylog("Checking quest items p1 "..tostring(p1).." p2 "..tostring(p2).." p3 "..tostring(p3))
  if not p3 then return false end
--  amk.mylog("chp1")
  local tid=self.task_id_by_desc_phrase_id[p2]
--  amk.mylog("chp2")
  if not tid then return false end
--  amk.mylog("chp3")
  local task_desc=self.task_info[tid]
--  amk.mylog("chp4")
  if task_desc.status~="completed" then return false end
--  amk.mylog("chp5")
  local can_finish = true
  if task_desc.type == "artefact" then
    if db.actor:object(task_desc.target) == nil then
      can_finish = false
    end
  elseif task_desc.type == "monster_part" then
    if db.actor:object(task_desc.target) == nil then
      can_finish = false
    end
  elseif task_desc.type == "find_item" then
    if db.actor:object(task_desc.target) == nil then
      can_finish = false
    end
  end
--  amk.mylog("can finish " .. tostring(can_finish))
  return can_finish
end

--' Создается диалог актера, в котором будут выдаваться задания.
function CRandomTask:init_task_dialog(dlg, parent)
	local phr = dlg:AddPhrase("tm_seek_new_job","0","",-10000)
	local phrase_script = phr:GetPhraseScript()

	phr = dlg:AddPhrase("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 = dlg:AddPhrase("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 = dlg:AddPhrase(self.task_info[v].name, tostring(self.task_info[v].init_phrase_id), "1", -10000)		
		phrase_script = phr:GetPhraseScript()
		phrase_script:AddPrecondition("task_manager.precondition_task_avail")

		phr = dlg:AddPhrase(self.task_info[v].text, tostring(self.task_info[v].desc_phrase_id), tostring(self.task_info[v].init_phrase_id), -10000)
		--phrase_script = phr:GetPhraseScript()
		--phrase_script:AddAction("task_manager.show_reward")

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

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

	dlg:AddPhrase("tm_seek_job_abandon","3","1",-10000)
end
--' Функция, в которой будет выдаваться вещевая награда за выполненные квесты
function CRandomTask:task_reward(npc, actor, p1, p2)
--  amk.mylog("Rewarding p1 "..tostring(p1).." p2 "..tostring(p2))
  local parent = self:get_parent(npc) 
  local v=self.task_id_by_completed_phrase_id[p2]
--  amk.mylog("Rewarding ")

--  for k,v in pairs(self.active_task_by_type) do 
  if true then
    local task_desc = self.task_info[v]
    if task_desc.status == "completed" and task_desc.parent == parent then
      --' Забираем у игрока квестовый предмет.
      local can_finish = true
      if task_desc.type == "artefact" then
        if db.actor:object(task_desc.target) == nil then
          can_finish = false
        else
          dialogs.relocate_item_section(npc, task_desc.target, "out")
        end
      elseif task_desc.type == "monster_part" then
        if db.actor:object(task_desc.target) == nil then
          can_finish = false
        else
          dialogs.relocate_item_section(npc, task_desc.target, "out")
        end
      elseif task_desc.type == "find_item" then
        if db.actor:object(task_desc.target) == nil then
          can_finish = false
        else
          dialogs.relocate_item_section(npc, task_desc.target, "out")
        end
      end
  
      if can_finish == true 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
					--db.actor:change_character_reputation(db.actor:character_reputation() + task_desc.reward_reputation)
					db.actor:change_character_reputation(task_desc.reward_reputation)
        end

        if task_desc.reward_relation ~= nil then
          for kk,vv in pairs(task_desc.reward_relation) do
            relation_registry.change_community_goodwill (kk, db.actor:id(), tonumber(vv))
          end
        end

        if task_desc.reward_rank ~= nil then
          actor_stats.add_points("quests", task_desc.name, 1, task_desc.reward_rank)
          db.actor:set_character_rank(db.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
		db.actor:change_character_reputation(task_desc.reward_reputation)
  end

  if task_desc.reward_relation ~= nil then
    for kk,vv in pairs(task_desc.reward_relation) do
      relation_registry.change_community_goodwill (kk, db.actor:id(), tonumber(vv))
    end
  end

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

--[[
	phr = dlg:AddPhrase("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 = dlg:AddPhrase("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 = dlg:AddPhrase(self.task_info[v].name, tostring(self.task_info[v].init_phrase_id), "2", -10000)
    phrase_script = phr:GetPhraseScript()   
    phrase_script:AddPrecondition("task_manager.precondition_active_task")
    
		phr = dlg:AddPhrase("tm_"..parent.."_job_what", tostring(self.task_info[v].desc_phrase_id), tostring(self.task_info[v].init_phrase_id), -10000)
    
		phr = dlg:AddPhrase("tm_job_refuse", tostring(self.task_info[v].yes_phrase_id), tostring(self.task_info[v].desc_phrase_id), -10000)
    phrase_script = phr:GetPhraseScript()
    phrase_script:AddAction("task_manager.action_refuse_task")
    phrase_script:AddPrecondition("task_manager.precondition_notcompleted_task")
      
	phr = dlg:AddPhrase("tm_job_nothing", tostring(self.task_info[v].no_phrase_id), tostring(self.task_info[v].desc_phrase_id),-10000)
    phrase_script = phr:GetPhraseScript()
    phrase_script:AddPrecondition("task_manager.precondition_notcompleted_task")

    phr = dlg:AddPhrase("tm_job_completed", tostring(self.task_info[v].completed_phrase_id), tostring(self.task_info[v].desc_phrase_id),-10000)
    phrase_script = phr:GetPhraseScript()
    phrase_script:AddAction("task_manager.action_task_reward")
    phrase_script:AddPrecondition("task_manager.precondition_completed_task")

    if self.task_info[v].reward_info then
      local phrcnt=table.getn(self.task_info[v].reward_info_dialog)
      if phrcnt==0 then
        phrase_script:AddGiveInfo(self.task_info[v].reward_info_portion)
        phrase_script:AddAction("amk_dialogs.info_received")
      else
      -- Добавляем фразу. на случай наличия инфопорции. Иначе вылетит.
        phr = dlg:AddPhrase("...",self:gen_phrase_id(),tostring(self.task_info[v].completed_phrase_id),-10000)
        phrase_script = phr:GetPhraseScript()
        phrase_script:AddHasInfo(self.task_info[v].reward_info_portion)        
        
        local prid=tostring(self.task_info[v].completed_phrase_id)
        local first=true
      -- Добавляем диалог
        for i,p in ipairs(self.task_info[v].reward_info_dialog) do
          local cid=self:gen_phrase_id()
          phr=dlg:AddPhrase(p,cid,prid,-10000)
          prid=cid
          if first then
            first=false
            phrase_script = phr:GetPhraseScript()
            phrase_script:AddGiveInfo(self.task_info[v].reward_info_portion)
            phrase_script:AddAction("amk_dialogs.info_received")
            phrase_script:AddDontHasInfo(self.task_info[v].reward_info_portion)        
          end
        end
      end
    end
  end
--  amk.mylog("Done")
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
function CRandomTask:stats(obj)
  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, p2, p3, false)
end
function precondition_active_task(actor, npc, p1, p2, p3)
  return get_random_task():active_task(actor, npc, p1, p2, p3)
end
function precondition_completed_task(actor, npc, p1, p2, p3)
  return get_random_task():completed_task(actor, npc, p1, p2, p3)
end
function precondition_notcompleted_task(actor, npc, p1, p2, p3)
  return not get_random_task():completed_task(actor, npc, p1, p2, p3)
end

function precondition_vendor_can_task(npc, actor, p1, p2, p3)
  return get_random_task():parent_can_task(actor, npc, p1, p2, p3)
end
function precondition_vendor_cannot_task(npc, actor, p1, p2, p3)
  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, p2)
end
function action_refuse_task(npc, actor, p1, p2)
  get_random_task():action_refuse_task(npc, actor, p1, p2)
end
function action_task_reward(actor, npc, p1, p2)
  get_random_task():task_reward(npc, actor, p1, 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

function amk_add_target_id_to_kill_targets(id,dialog,task_id)
  local targets=amk.unpack_array_from_string(amk.load_variable("kill_targets",""))
  table.insert(targets,{id=id,dialog=dialog,task_id=task_id})
  amk.save_variable("kill_targets",amk.pack_array_to_string(targets))
end

function amk_remove_target_id_from_kill_targets(id)
  local targets=amk.unpack_array_from_string(amk.load_variable("kill_targets",""))
  for n,v in pairs(targets) do
    if v.id==id then
      table.remove(targets,n)
      break
    end
  end
  amk.save_variable("kill_targets",amk.pack_array_to_string(targets))
end

function amk_kill_targets()
  return amk.unpack_array_from_string(amk.load_variable("kill_targets",""))  
end

function make_task_failed(task_id)
  get_random_task():make_task_failed(task_id)  
end

