--'-------------------------------------------------------------------------------------------------------------------
--' AI Additions
--' îáùàÿ îçâó÷êà ïåðñîíàæåé
--' Rulix aka Bak
--' 10.03.2016
--'--------------------------------------------------------------------------------------------------------------------
local nstl = 64
local theme = {}
local mute_npcs = {}

local function id()
	return sound_theme.id()
end

function load_sounds()
	stalker_ids.sound_enemy_killed_or_wounded = stalker_ids.sound_enemy_critically_wounded+1	-- fix wrong export id
	local snd_ini = ini_file([[misc\ai_additions\rx_script_sound.ltx]])
	ASSERTX(snd_ini:section_exist("list"),"There is no section [list] in rx_script_sound.ltx")
	local n = snd_ini:line_count("list")
	local result,section,value
	for i=0,n-1 do
		result,section,value  = snd_ini:r_line("list",i,"","")
		if theme[section] == nil and (value == '' or _G[value] ~= nil) then
			theme[section] = npc_sound_generic(snd_ini,section)
		end
	end
	mute_npcs = rx_utils.collect_sections(snd_ini,{"mute_characters"},nil,true)
end

--' Èãðàòü òåìó
function set_sound_play(npc_id,sound,cb_func)
	local snd_theme = theme[sound]
	if not snd_theme then
		rx_ai.printf("set_sound_play. Wrong sound theme [%s], npc[%s]", tostring(sound), npc_id)
		return
	end
	if xr_sound.sound_table[npc_id] == nil then
		if snd_theme:play(npc_id) then
			snd_theme.npc[npc_id].cb = cb_func
			xr_sound.sound_table[npc_id] = snd_theme
			return true
		end
--	else
--		rx_ai.printf("rx_sound: cannot play sound [%s] because i'm [%s] already play snd [%s]",sound,npc_id,xr_sound.sound_table[npc_id].path)
	end
end

class "npc_sound_generic"
function npc_sound_generic:__init(snd_ini,section)
	self.section = section
	--' Õðàíèò ïàðàìåòðû çâóêà äëÿ êàæäîãî NPC
	self.npc = {}
	--' Ïàðàìåòðû âû÷èòûâàíèÿ çâóêà
	self.internal_type = stalker_ids[rx_utils.read_from_ini(snd_ini,section,"sound","_nil",1)]
	if not self.internal_type then
		self.prefix = rx_utils.read_from_ini(snd_ini,section,"npc_prefix",true,0)
		self.path = rx_utils.read_from_ini(snd_ini,section,"path","",1)
		self.shuffle = rx_utils.read_from_ini(snd_ini,section,"shuffle","rnd",1)
--		self.is_combat_sound = rx_utils.read_from_ini(snd_ini,section,"is_combat_sound",false,0) or nil
		self.pda_snd = rx_utils.read_from_ini(snd_ini,section,"pda_snd",false,0) or nil
		self.type = snd_type[rx_utils.read_from_ini(snd_ini,section,"type","_nil",1)]
	end
	self.group_snd = rx_utils.read_from_ini(snd_ini,section,"group_snd",false,0) or nil
	-- Âðåìÿ çàäåðæêè íà÷àëà îòûãðûâàíèÿ çâóêà
	local delay = rx_utils.parse_list(snd_ini,section,"delay_sound",nil,true)
	self.min_delay = delay[1] or 0
	self.max_delay = delay[2] or self.min_delay
	--' Èíòåðâàë ïðîèãðûâàíèÿ çâóêà
	local interval = rx_utils.parse_list(snd_ini,section,"idle",nil,true)
	self.min_idle = interval[1]
	self.max_idle = interval[2]
	self.rnd = interval[3]/100
	if snd_ini:line_exist(section,"avail_communities") then
		self.avail_communities = rx_utils.parse_list(snd_ini,section,"avail_communities",true)
	end
	if self.group_snd then
		self.can_play_group_sound = true
	end
end
function npc_sound_generic:init_npc(npc)
	if self.internal_type then
		self.npc[npc:id()] = {}
		return
	end
	
	local f = getFS()
	local character_prefix	
	if self.prefix == false then
		character_prefix = npc:sound_prefix()
		npc:sound_prefix("characters_voice\\")
	end

	local npc_data = {}
	npc_data.id = id()
	npc_data.max = npc:add_sound(self.path, nstl, self.type or snd_type.monster_talk, 1, 1, npc_data.id, "bip01_head") - 1	-- priority 2 mask 1?
	if npc_data.max < 0 then
		npc_data = nil
	elseif self.pda_snd then
		npc_data.path = {}
		if f:exist("$game_sounds$",npc:sound_prefix()..self.path..".ogg") ~= nil then
			npc_data.path[1] = npc:sound_prefix()..self.path
		else
			local num = 1
			while f:exist("$game_sounds$",npc:sound_prefix()..self.path..num..".ogg") do
				npc_data.path[num] = npc:sound_prefix()..self.path..num
				num = num + 1
			end
		end
	end
	self.npc[npc:id()] = npc_data

	if character_prefix then
		npc:sound_prefix(character_prefix)
	end
end
function npc_sound_generic:play(npc_id,override)
	local npc = db.storage[npc_id] and db.storage[npc_id].object
	if npc == nil then
		rx_ai.printf("sound[%s]:coudnt find npc!!!",npc_id)
		return false
	end
	if not override and npc:active_sound_count() > 0 then
		return false
	end
	local npc_data = self.npc[npc_id]
	if not npc_data then
		return false
	end
	-- êòî-òî óæå ãîâîðèò ãðóïïîâîé çâóê
	if self.group_snd and not self.can_play_group_sound then
		return false
	end
	-- íå ïîâåçëî ñêàçàòü
	if math.random() > self.rnd then
		return false
	end
	-- âðåìÿ åù¸ íå ïðèøëî
	if npc_data.played_time and time_global()-npc_data.played_time < self.idle_time then
		return false
	end
	npc_data.played_time = nil
	-- åñëè ñòàíäàðòíûé çâóê - êîìàíäà èãðàòü
	if self.internal_type then
		if self.group_snd then
			self.can_play_group_sound = false
		end
		local _ = override == 0 and stop_sounds_on_combat(npc) or override and stop_sounds(npc)
		npc:play_sound(self.internal_type, self.max_delay, self.min_delay)
		return true
	end
	--' Âûáîð çâóêà, êîòîðûé èãðàòü.
	self.played_id = self:select_next_sound(npc_data)
	-- çâóêîâ íåò, èëè ïîñëåäîâàòåëüíîñòü óæå îòûãðàíà
	if self.played_id == -1 then
		return false
	end
	if self.group_snd then
		self.can_play_group_sound = false
	end
	local _ = override == 0 and stop_sounds_on_combat(npc) or override and stop_sounds(npc)
	-- play_sound (u32 internal_type, u32 max_start_time, u32 min_start_time, u32 max_stop_time, u32 min_stop_time, u32 id)
	npc:play_sound(npc_data.id, self.max_delay, self.min_delay, 1, 0, self.played_id)
	-- ïðîâåðêà íà ñóùåñòâîâàíèå çâóêà äóáëèðóþùåãî îñíîâíîé ïî ÏÄÀ. Åñëè îí åñòü òî èãðàòü è åãî.
	if self.pda_snd then
		local snd = npc_data.path[self.played_id+1]
		if snd and getFS():exist("$game_sounds$",snd.."_pda.ogg") ~= nil and npc:position():distance_to_sqr(db.actor:position()) >= 100 then
			if self.pda_snd_obj ~= nil and self.pda_snd_obj:playing() then
				self.pda_snd_obj:stop()
			end
			self.pda_snd_obj = rx_utils.get_sound(snd.."_pda")
			self.pda_snd_obj:play_at_pos(db.actor, vector():set(0,0,0), self.max_delay, sound_object.s2d)
			self.pda_snd_obj.volume = 0.8
		end
	end
	return true
end
function npc_sound_generic:select_next_sound(npc_data)
	if npc_data.max < 0 then
		return -1
	end
	if self.shuffle == "rnd" then
		if npc_data.max == 0 then
			return 0
		end
		if self.played_id ~= nil then
			if npc_data.max == 1 then
				return 1-self.played_id
			end
			local played_id = math.random(0,npc_data.max-1)
			if played_id >= self.played_id then
				return played_id + 1
			end
			return played_id
		end
		return math.random(0,npc_data.max)
	end
	if self.shuffle == "seq" then
		if self.played_id == nil then
			return 0
		end
		if self.played_id < npc_data.max then
			return self.played_id + 1
		end
		return -1
	end
	if self.shuffle == "loop" then
		if self.played_id == nil then
			return 0
		end
		if self.played_id < npc_data.max then
			return self.played_id + 1
		end
		return 0
	end
end
function npc_sound_generic:callback(npc_id)
	if self.group_snd then
		self.can_play_group_sound = true
	end
	self.idle_time = math.random(self.min_idle,self.max_idle) * 1000
	local npc_data = self.npc[npc_id]
	if npc_data then
		npc_data.played_time = time_global()
		if npc_data.cb then
			npc_data.cb[1](npc_data.cb[2],self)
			npc_data.cb = nil
		end
	end
end
function npc_sound_generic:reset(npc_id)
	local npc = db.storage[npc_id] and db.storage[npc_id].object
	self.npc[npc_id].played_time = nil
	self.played_id = nil
	if self.group_snd then
		self.can_play_group_sound = true
	end
	stop_sounds(npc)
	if self.pda_snd_obj ~= nil then
		self.pda_snd_obj:stop()
		self.pda_snd_obj = nil
	end
end
function npc_sound_generic:is_playing(npc_id)
--  Ïðîâåðêà èãðàåòñÿ ëè ñåé÷àñ çâóê ó íïñ
	local obj = db.storage[npc_id] and db.storage[npc_id].object
	if obj == nil then
		return false
	end
	return obj:active_sound_count() ~= 0 or (self.pda_snd_obj and self.pda_snd_obj:playing())
end
function npc_sound_generic:stop(obj_id)
	local npc = db.storage[obj_id] and db.storage[obj_id].object
	stop_sounds(npc)
	if self.pda_snd_obj and self.pda_snd_obj:playing() then
		self.pda_snd_obj:stop()
		self.pda_snd_obj = nil
	end
end

--' Çàãðóçêà çâóêîâ ÍÏÑ
function init_npc_sound(npc)
	if not (mute_npcs[npc:name()] or mute_npcs[npc:profile_name()] or mute_npcs.all_story and rx_utils.is_story_object(npc)) then
		local comm = npc:character_community()
		for _,s in pairs(theme) do
			if not s.avail_communities or s.avail_communities[comm] then
				s:init_npc(npc)
			end
		end
	end
end

--' Äëÿ óáèðàíèÿ çâóêîâ ïðè ïåðåêëþ÷åíèè ñ áîåâûõ ñõåì íà êîìáàò ïëàííåð
function block_alarm_sound(npc)
	if npc:best_enemy() and not xr_sound.sound_table[npc:id()] then
		npc:set_fastcall(stop_sounds,npc)
	end
	if not state_mgr.is_idle(npc) then
		npc:motivation_action_manager():action(xr_actions_id.state_mgr+1).block_sound = true
	end
end

function stop_sounds(obj)
	if obj and obj:alive() then
		obj:set_sound_mask(-1)
		obj:set_sound_mask(0)
	end
	return true
end
---[[
--'--------------------------------------------------------------------------------------------------------------------
--' êëàññ äëÿ ïðîèãðûâàíèÿ çâóêîâ èç êîíôèãà îáúåêòà
--'--------------------------------------------------------------------------------------------------------------------
class "dihud_sound"
function dihud_sound:__init(section,name,typ,read_delay)
	self.st = {}
	self.type = typ
	local inif = system_ini()
	local k,sline = 0,name
	while inif:line_exist(section,sline) do
		k = k+1
		self.st[k] = rx_utils.parse_list(inif,section,sline,nil,true)
		if not read_delay then
			self.st[k][3] = nil
		end
		sline = name..k
	end
end

function dihud_sound:play(obj,pos,delay,volume)
	local s = self.st[math.random(#self.st)]
	if s and s[1] and s[1] ~= "" then
		local snd = rx_utils.get_sound(s[1])
		local dly = (delay or 0)+(s[3] or 0)
		if pos then
			snd:play_at_pos(obj,pos,dly,self.type or sound_object.s3d)
		else
			snd:play(obj,dly,self.type or sound_object.s3d)
		end
		if volume or s[2] then
			snd.volume = (volume or 1)*(s[2] or 1)
		end
	end
end
--]]