e4s-sdk/gamedata/scripts/sound_manager.script
2026-06-17 23:06:51 +03:00

282 lines
No EOL
7.9 KiB
Text

---------------------------------------------------------------------------------------------------------------------
-- Ñõåìà îòûãðûâàíèÿ ñâÿçíûõ çâóêîâûõ ïîñëåäîâàòåëüíîñòåé.
-- àâòîð: Äèäåíêî Ðóñëàí (Stohe)
----------------------------------------------------------------------------------------------------------------------
--' Òàáëèöà ñîäåðæèò ìåíåäæåðû èñòîðèé
local sound_managers = {}
local story_ltx = ini_file("misc\\sound_stories.ltx")
--' Çâóêîâîé ìåíåäæåð ñîäåðæèò â ñåáå ñïèñîê ïåðñîíàæåé, êîòîðûå ìîãóò ðàññêàçàòü èñòîðèþ ïî ðîëÿì.
class "sound_manager"
function sound_manager:__init(id)
self.id = tostring(id)
self.npc = {} --'Òàáëèöà ïåðñîíàæåé, çàðåãèñòðèðîâàííûõ â ñàóíäìåíåäæåð
self.storyteller = nil --'Êòî ÿâëÿåòñÿ ðàññêàç÷èêîì
self.story = nil --'Êàêóþ èñòîðèþ áóäåò îòûãðûâàòü äàííûé ìåíåäæåð. Îäèí ìåíåäæåð óìååò îòûãðûâàòü òîëüêî îäíó èñòîðèþ.
self.last_playing_npc = nil
self.phrase_timeout = nil --' Õðàíèò âðåìÿ íà÷àëà ïàóçû ìåæäó ôðàçàìè.
self.phrase_idle = 0 --' Õðàíèò äëèíó ïàóçû ìåæäó ôðàçàìè.
end
--' Çàðåãèñòðèðîâàòü ÍÏÑ.
function sound_manager:register_npc(npc_id)
printf("Register sm npc [%s]:[%s]", self.id, npc_id)
table.insert(self.npc, {npc_id = npc_id})
--print_table(self.npc)
end
--' Îòðåãèñòðèðîâàòü íïñ
function sound_manager:unregister_npc(npc_id)
printf("UnRegister sm npc [%s]:[%s]", self.id, npc_id)
if self.last_playing_npc == npc_id and
xr_sound.sound_table[self.last_playing_npc]
then
-- Óäàëÿåòñÿ ÷óâàê, êîòîðûé ùàñ ãîâîðèò ôðàçó. Íóæíî îáðóáèòü èñòîðèþ
self.story = nil
xr_sound.sound_table[self.last_playing_npc]:stop(npc_id)
end
if self.storyteller == npc_id then
self.storyteller = nil
end
local remove_id = nil
for k,v in pairs(self.npc) do
if v.npc_id == npc_id then
remove_id = k
break
end
end
if remove_id ~= nil then
table.remove(self.npc, remove_id)
end
--print_table(self.npc)
end
--' Óñòàíîâèòü íïñ, êàê ðàçêàç÷èêà.
function sound_manager:set_storyteller(npc_id)
self.storyteller = npc_id
--printf("Set storyteller sm [%s] = [%s]", self.id, npc_id)
end
--' Îáíîâëåíèå
function sound_manager:update()
--printf("Updating sm [%s]", self.id)
if self.story == nil then
--printf("no story")
return
end
--' Æäåì ïîêà íå çàêîí÷èòñÿ óæå íà÷àòûé çâóê
if xr_sound.sound_table[self.last_playing_npc] ~= nil then
--printf("wait sound")
-- !!! Åñëè â áîþ - îáðóáèòü çâóê è ñàóíäòåìó
if db.storage[self.last_playing_npc] and db.storage[self.last_playing_npc].object:best_enemy() ~= nil then
self.story = nil
xr_sound.sound_table[self.last_playing_npc]:stop(self.last_playing_npc)
end
return
end
--' Óñòàíàâëèâàåì òàéìàóò îæèäàíèÿ ìåæäó ôðàçàìè.
local t_global = time_global()
if self.phrase_timeout == nil then
self.phrase_timeout = t_global
end
if t_global - self.phrase_timeout < self.phrase_idle then
--printf("wait time")
return
end
--' Âûáèðàåì ñëåäóþùóþ ôðàçó.
local next_phrase = self.story:get_next_phrase()
--'  òåìå çàêîí÷èëèñü ôðàçû
if next_phrase == nil then
--printf("no phrase")
return
end
local npc = nil
local tn = #self.npc
if tn == 0 then
--printf("no npc")
return
end
--' Âûáèðàåì ïåðñîíàæà, êîòîðûé ñêàæåò ôðàçó
if next_phrase.who == "teller" then
--' ôðàçà ðàññêàç÷èêà
if self.storyteller == nil then
self:choose_random_storyteller()
end
npc = self.storyteller
elseif next_phrase.who == "reaction" then
--' Ôðàçà êîãî óãîäíî, êðîìå ðàññêàç÷èêà
local teller_id = 0
for k,v in pairs(self.npc) do
if v.npc_id == self.storyteller then
teller_id = k
break
end
end
if tn >= 2 then
local id = math.random(1,tn-1)
if id >= teller_id then
id = id + 1
end
npc = self.npc[id].npc_id
else
npc = self.npc[1].npc_id
end
elseif next_phrase.who == "reaction_all" then
local npc_id = nil
for k,v in pairs(self.npc) do
if v.npc_id ~= self.storyteller then
xr_sound.set_sound_play(v.npc_id, next_phrase.theme)
npc_id = v.npc_id
end
end
self.last_playing_npc = npc_id
self.phrase_timeout = nil
self.phrase_idle = next_phrase.timeout * 1000
return
else
--' Ôðàçà êîãî óãîäíî.
npc = self.npc[math.random(1,#self.npc)].npc_id
end
if(npc==nil or db.storage[npc]==nil) then
return
end
-- !!! Åñëè â áîþ - îáðóáèòü çâóê è ñàóíäòåìó
if db.storage[npc].object:best_enemy() ~= nil and xr_sound.sound_table[npc] ~= nil then
self.story = nil
xr_sound.sound_table[npc]:stop(npc)
return
end
printf("Speaking sm [%s] npc[%s] phrase[%s]", self.id, npc, next_phrase.theme)
--' Êåøèðóåì êòî ïðîèçíîñèò ôðàçó, ÷òîáû îòëàâëèâàòü êîãäà îí çàêîí÷èò
self.last_playing_npc = npc
--' Ïðîèçíîñèì ôðàçó
if next_phrase.theme ~= "nil" then
if(self.story and self.story.id=="squad_counter_attack") then
local npc = alife():object(npc)
local board = sim_board.get_sim_board()
if(npc) and (board) then
local our_squad = get_object_squad(npc)
if(our_squad) then
local our_smart = our_squad.smart_id
local task = task_manager.get_task_manager():get_tasks_by_smart(our_smart)
if(next_phrase.who~="teller") then
local enemy_faction = task.counter_attack_community
xr_sound.set_sound_play(npc.id, next_phrase.theme, enemy_faction)
self.phrase_timeout = nil
self.phrase_idle = next_phrase.timeout * 1000
return
end
xr_sound.set_sound_play(npc.id, next_phrase.theme, our_squad.player_id, our_smart)
self.phrase_timeout = nil
self.phrase_idle = next_phrase.timeout * 1000
return
end
end
end
xr_sound.set_sound_play(npc, next_phrase.theme)
end
self.phrase_timeout = nil
self.phrase_idle = next_phrase.timeout * 1000
end
--' Ðàíäîìíûé âûáîð ðàçêàç÷èêà (âûçûâàåòñÿ åñëè íà ìîìåíò ðàññêàçà ðàññêàç÷èêà íåò)
function sound_manager:choose_random_storyteller()
self.storyteller = self.npc[math.random(1,#self.npc)].npc_id
end
--' Çàêîí÷èë ëè ñàóíä ìåíåäæåð èãðàòü ñâîþ èñòîðèþ
function sound_manager:is_finished()
if self.story == nil then
return true
end
return self.story:is_finished()
end
--' Óñòàíîâèòü êàêóþ èñòîðèþ ìåíåäæåð äîëæåí îòûãðàòü
function sound_manager:set_story(story_id)
self.story = CStory(story_id)
--printf("Set story sm [%s] = [%s]", self.id, story_id)
end
--' Ñîçäàòü íîâûé ñàóíä-ìåíåäæåð. Íóæíî ïåðåäàòü óíèêàëüíûé àéäèøíèê
function get_sound_manager(id)
if sound_managers[id] == nil then
sound_managers[id] = sound_manager(id)
end
return sound_managers[id]
end
--' Êëàññ "èñòîðèÿ". Ñîäåðæèò äåðåâî ôðàç. Ó êàæäîé ôðàçû óêàçàíî äîëæåí ëè åå ãîâîðèòü ðàññêàç÷èê èëè ñëóøàòåëè.
class "CStory"
function CStory:__init(story_id)
--printf("Creating story [%s]", tostring(story_id))
if not story_ltx:section_exist(story_id) then
abort("There is no story [%s] in sound_stories.ltx", tostring(story_id))
end
self.replics = {}
--' Âû÷èòûâàåì øàáëîí èñòîðèè èç ini ôàéëà
local n = story_ltx:line_count(story_id)
local id, value = "",""
for i=0,n-1 do
result, id, value = story_ltx:r_line(story_id,i,"","")
local t = parse_names(value)
if t[1] ~= "teller" and t[1] ~= "reaction" and t[1] ~= "reaction_all" then
abort("Wrong fist field [%s] in story [%s]", tostring(t[1]), tostring(story_id))
end
self.replics[i] = {who = t[1], theme = t[2], timeout = t[3]}
end
self.id = tostring(story_id)
self.max_phrase_count = n-1
self.next_phrase = 0
--print_table(self.replics)
end
--' Çàêîí÷åíà ëè èñòîðèÿ
function CStory:is_finished()
return self.next_phrase > self.max_phrase_count
end
--' Ðåñåò èñòîðèè
function CStory:reset_story()
self.next_phrase = 0
end
--' Âîçâðàùàåò ñëåäóþùóþ ôðàçó
function CStory:get_next_phrase()
local phrase = self.replics[self.next_phrase]
self.next_phrase = self.next_phrase + 1
return phrase
end