--[[
Изменения script_version:
	4 - сохранение поля job_online
	5 - сохранение поля was_in_smart_terrain
]]
-- nv170320, nv170414 some optimizations, clean-up

--------------------
-- nv170413 there are only two consumers of xr_spawner.check_spawn(), se_car and se_monster - 
-- for speed this small function replaces xr_spawner.check_spawn()

local spawn_list = {}

function check_spawn(s_object)
	local s_object_id = s_object.id
	local spawn = spawn_list[s_object_id]
	if spawn == nil then
		spawn = {
			cond = xr_logic.cfg_get_condlist(s_object:spawn_ini(), "spawner", "cond", s_object),
			npc = nil
			}
		spawn_list[s_object_id] = spawn
	end
	if actor ~= nil then
		if spawn.cond ~= nil then
			if spawn.npc == nil then
				spawn.npc = level.object_by_id(s_object_id)
			end   
			if xr_logic.pick_section_from_condlist(actor, spawn.npc, spawn.cond.condlist) ~= nil then
				return true
			else
				spawn.npc = nil
				return false 
			end
		else
			return true
		end
	end
	-- if actor is nil
	spawn.npc = nil
	return false
end


--------------------
class "se_monster" (cse_alife_monster_base)
--------------------
function se_monster:__init (section) super (section)
	self.ini = nil
	self.ini_initialized = false

	self.spawner_present = false

	self.smart_terrain_conditions = nil
	self.smart_terrain_conditions_initialized = false

	self.check_distance = false
	self.min_distance   = 150

	-- этот флаг берётся из работы смарта
	-- true     = всегда в онлайне
	-- false    = всегда в офлайне
	-- condlist = условие, которое отпределяет true или false
	-- nil      = смарту всё равно
	self.job_online          = nil
	self.job_online_condlist = nil

	-- посещал ли сталкер хоть один smart_terrain
	self.was_in_smart_terrain = false
end
--------------------
function se_monster:get_ini()
	if not self.ini_initialized then
		self.ini             = self:spawn_ini ()
		self.ini_initialized = true

		self.spawner_present = self.ini:section_exist ("spawner")

		if self.ini ~= nil and self.spawner_present == true then
			if self.ini:line_exist ("spawner", "check_distance") == true then
				self.check_distance = self.ini:r_bool ("spawner", "check_distance")
				if self.check_distance == nil then self.check_distance = false end
				if self.ini:line_exist ("spawner", "min_distance") == true then
					self.min_distance = self.ini:r_u32 ("spawner", "min_distance")
				end
			end

			if self.min_distance == nil then
				local sys = system_ini()
				if sys ~= nil and sys:line_exist ("alife", "switch_distance") == true then
					self.min_distance = sys:r_u32 ("alife", "switch_distance") - 50
					if self.min_distance == nil then
						self.min_distance = 150
					else
						if self.min_distance <= 50 then
							abort ("SE_MONSTER - SWITCH DISTANCE IS TOO SMALL !!!")
						end
					end
				else
					self.min_distance = 150
				end
			end
		end
	end
end
--------------------
function se_monster:get_job_online()
	if self.job_online_condlist == nil then
		return self.job_online
	else
		return xr_logic.pick_section_from_condlist(db.actor_proxy, self, self.job_online) ~= nil
	end
end
--------------------
function se_monster:can_switch_offline ()
	if self:get_job_online() ~= nil then
		return not self:get_job_online()
	else
		return cse_alife_monster_base.can_switch_offline (self)
	end
end
--------------------
function se_monster:can_switch_online ()
	if self:get_job_online() ~= nil then
		return self:get_job_online()
	end

--'	self:get_ini()

	--стандартная проверка у родителя, если нет спавнера или игрок помер
	if self.ini == nil or self.spawner_present == false then --or (db.actor ~= nil and db.actor:alive () == false)
		--if self.ini == nil or self.spawner_present == false or db.actor == nil
		return cse_alife_monster_base.can_switch_online (self)
	end

	if self.online == false then
		-- если игрока нет, то в оффлайн
		if actor == nil or actor:alive() == false then return false end

		--если задана дистанция проверки, то проверим.
		if self.check_distance == true then
			--printf ("Check distance")
			--получим позицию.
			local pos = level.vertex_position (self.m_level_vertex_id)
			-- проверим дистанцию до игрока. если меньше требуемой, то от винта
			if pos:distance_to (actor:position ()) < self.min_distance then
				--printf ("Check distance 1")
				return false
			end
		end
			--все проверки прошли - финал, вызов спавнера
		-- return xr_spawner.check_spawn(self) and cse_alife_monster_base.can_switch_online (self) -- use local function
		return check_spawn(self) and cse_alife_monster_base.can_switch_online (self)
	else
		if actor == nil or actor:alive() == false then return true end
		-- if xr_spawner.check_spawn(self) == true then
		if check_spawn(self) == true then
			return true
		end
		if self.check_distance == true then
			local pos = level.vertex_position (self.m_level_vertex_id)
			-- проверим дистанцию до игрока. если больше требуемой, то от винта
			if pos:distance_to (actor:position ()) > self.min_distance then
				return false
			end
		end
		return cse_alife_monster_base.can_switch_online (self)
	end
end
--------------------
function se_monster:STATE_Write(packet)
	cse_alife_monster_base.STATE_Write (self, packet)

	if self.job_online == true then
		packet:w_u8(0)
	elseif self.job_online == false then
		packet:w_u8(1)
	elseif self.job_online == nil then
		packet:w_u8(2)
	else
		packet:w_u8(3)
		packet:w_stringZ(self.job_online_condlist)
	end

	packet:w_bool(self.was_in_smart_terrain)
end
--------------------
function se_monster:STATE_Read(packet, size)
	cse_alife_monster_base.STATE_Read (self, packet, size)

	if self.script_version >= 4 then
		local t = packet:r_u8()

		if t == 0 then
			self.job_online = true
		elseif t == 1 then
			self.job_online = false
		elseif t == 2 then
			self.job_online = nil
		else
			self.job_online_condlist = packet:r_stringZ()

			-- swap the calls for xr_logic.parse_condlist_q(src) and xr_logic.parse_condlist(nil, etc) to see more details about your error
			-- self.job_online = xr_logic.parse_condlist(nil, "se_monster:STATE_Read", "job_online", self.job_online_condlist)
			self.job_online = xr_logic.parse_condlist_q(self.job_online_condlist)
		end
	end

	if self.script_version >= 5 then
		self.was_in_smart_terrain = packet:r_bool()
	end
end
--------------------
function se_monster:on_before_register()
	self:fill_exclusives()
end
--------------------
function se_monster:on_register()
	cse_alife_monster_base.on_register( self )

	--'self:fill_exclusives()

	--' Нарисовать мапспот с собой
--'	if self:alive() and sim_statistic.show_monster_spot == true then
--'		local community, rank = sim_statistic.getNpcType(self)
--'		level.map_add_object_spot_ser(self.id, "alife_presentation_monstr", self:name().." "..community)
--'	end
end
--------------------
function se_monster:on_unregister()
	cse_alife_monster_base.on_unregister( self )

	--' Убрать мапспот с собой
--'	if sim_statistic.show_monster_spot == true then
--'		local community, rank = sim_statistic.getNpcType(self)
--'		level.map_remove_object_spot(self.id, "alife_presentation_monstr")
--'	end

	smart_terrain.unregister_npc(self)
end
--------------------
function se_monster:on_death(killer)
	cse_alife_monster_base.on_death(self, killer)

	--[[ -- nv170320 not currently used
	--' Убрать мапспот с собой
	if sim_statistic.show_monster_spot == true then
		local community, rank = sim_statistic.getNpcType(self)
		level.map_remove_object_spot(self.id, "alife_presentation_monstr")
	end
--]]

----- Live stalker ranking addon - BEGIN -----
	if IsStalker(killer) and killer:clsid() ~= clsid_actor then
		local self_clsid = self:clsid()
		local community = killer:community()
		if community ~= "monolith" and community ~= "zombied" then
			local kill_bonus = math.floor(self:rank() / 400) + 1
			if self_clsid == clsid.pseudodog_s or self_clsid == clsid_bloodsucker_s then
				kill_bonus = kill_bonus + 1
			end
			if self_clsid == clsid_snork_s or self_clsid == clsid_controller_s then
				kill_bonus = kill_bonus + 2
			end
			killer:set_rank(killer:rank() + kill_bonus)
		end
	end
----- Live stalker ranking addon -  END  -----
end
--------------------
function se_monster:fill_exclusives()
	self:get_ini()
	self.smart_terrain_conditions             = smart_terrain.read_smart_terrain_conditions( self )

	if self.smart_terrain_conditions then
		for name, condlist in pairs(self.smart_terrain_conditions) do
			smart_terrain.exclusives[name] = (smart_terrain.exclusives[name] or 0) + 1
		end
	end
end
