--'-------------------------------------------------------------------------------------------------------------------
--' Схема озвучки
--' автор: Диденко Руслан (Stohe)
--'--------------------------------------------------------------------------------------------------------------------
--function printf()
--end
sound_table = {}
function set_sound_play(npc_id, sound, faction, point)
if not (sound and sound_theme.theme[sound]) then
callstack()
printf("set_sound_play. Wrong sound theme [%s], npc[%s]", tostring(sound), npc_id)
return
end
local snd_theme = sound_theme.theme[sound]
if snd_theme.class_id == "looped_sound" then
printf("You trying to play sound [%s] which type is looped", sound)
end
if sound_table[npc_id] == nil or snd_theme.play_always == true then
if (sound_table[npc_id] and sound_table[npc_id].reset) then
sound_table[npc_id]:reset(npc_id)
end
if snd_theme:play(npc_id, faction, point,sound) then
sound_table[npc_id] = snd_theme
end
end
return sound_table[npc_id] and sound_table[npc_id].snd_obj
end
function update(npc_id)
if not sound_table[npc_id] then
return
end
if not(sound_table[npc_id]:is_playing(npc_id)) then
sound_table[npc_id]:callback(npc_id)
sound_table[npc_id] = nil
end
end
looped_sound = {}
function play_sound_looped(npc_id, sound)
--alun_utils.debug_write(strformat("xr_sound:play_sound_looped %s",sound))
local snd_theme = sound_theme.theme[sound]
if snd_theme == nil then
printf("ERROR: play_sound_looped. Wrong sound theme [%s], npc[%s]", tostring(sound), npc_id)
return
end
if snd_theme.class_id ~= "looped_sound" then
printf("ERROR: You trying to play sound [%s] which type is not looped", sound)
return
end
if looped_sound[npc_id] ~= nil and looped_sound[npc_id][sound] ~= nil and looped_sound[npc_id][sound]:is_playing(npc_id) then
return
end
if snd_theme:play(npc_id) then
--printf("PLAY2. looped theme[%s] object[%s]", tostring(sound), npc_id)
if looped_sound[npc_id] == nil then
looped_sound[npc_id] = {}
end
looped_sound[npc_id][sound] = snd_theme
end
end
function stop_sound_looped(npc_id, sound)
if not (looped_sound[npc_id]) then
return
end
if sound then
if type(looped_sound[npc_id][sound]) ~= "string" then
if looped_sound[npc_id][sound] and looped_sound[npc_id][sound]:is_playing(npc_id) then
--printf("looped sound ["..tostring(sound).."] stop for obj [%s]",npc_id)
looped_sound[npc_id][sound]:stop()
looped_sound[npc_id][sound] = nil
end
end
else
for k,v in pairs(looped_sound[npc_id]) do
if v and type(v) ~= "string" and v:is_playing(npc_id) then
--printf("looped sound ["..tostring(k).."] stop for obj [%s]",npc_id)
v:stop()
end
end
looped_sound[npc_id] = nil
end
end
function set_volume_sound_looped(npc_id, sound, level)
if looped_sound[npc_id] then
if looped_sound[npc_id][sound] and looped_sound[npc_id][sound]:is_playing(npc_id) then
--printf("looped sound ["..tostring(sound).."] for obj ["..npc_id.."] set volume "..level)
looped_sound[npc_id][sound]:set_volume(level)
end
end
end
function actor_save_state(m_data)
--alun_utils.debug_write("actor_save_state")
m_data.xr_sound = empty_table(m_data.xr_sound)
for k,v in pairs(sound_theme.theme) do
v:save_state(m_data.xr_sound)
end
m_data.xr_sound.sound_table = {}
for k,v in pairs(sound_table) do
m_data.xr_sound.sound_table[k] = v.section
end
m_data.xr_sound.looped_sound = {}
for k,v in pairs(looped_sound) do
m_data.xr_sound.looped_sound[k] = {}
for kk,vv in pairs(looped_sound[k]) do
m_data.xr_sound.looped_sound[k][kk] = true
end
end
end
function actor_load_state(m_data)
if not (m_data.xr_sound) then
return
end
for k,v in pairs(sound_theme.theme) do
v:load_state(m_data.xr_sound)
end
for k,v in pairs(m_data.xr_sound.sound_table) do
if (sound_theme.theme[v]) then
sound_table[k] = sound_theme.theme[v]
end
end
for k,v in pairs(m_data.xr_sound.looped_sound) do
looped_sound[k] = {}
for kk,vv in pairs(m_data.xr_sound.looped_sound[k]) do
if (sound_theme.theme[kk]) then
looped_sound[k][kk] = sound_theme.theme[kk]
end
end
end
m_data.xr_sound = nil
end
function actor_save(stpk)
set_save_marker(stpk, "save", false, "sound_actor_save")
for k,v in pairs(sound_theme.theme) do
v:save(stpk)
end
local n = 0
for k,v in pairs(sound_table) do
n = n + 1
end
alun_utils.w_stpk(stpk,"u16",n,"sound table count")
for k,v in pairs(sound_table) do
alun_utils.w_stpk(stpk,"u16",k,"sound table:sound_id")
alun_utils.w_stpk(stpk,"stringZ",v.section,"sound table:sound section")
end
n = 0
for k,v in pairs(looped_sound) do
n = n + 1
end
alun_utils.w_stpk(stpk,"u16",n,"looped sound count")
for k,v in pairs(looped_sound) do
alun_utils.w_stpk(stpk,"u16",k,"sound table:looped sound_id")
n = 0
for kk,vv in pairs(looped_sound[k]) do
n = n + 1
end
alun_utils.w_stpk(stpk,"u16",n,"sound table:looped "..n)
for kk,vv in pairs(looped_sound[k]) do
alun_utils.w_stpk(stpk,"stringZ",kk,"sound table:looped "..n.." section")
end
end
set_save_marker(stpk, "save", true, "sound_actor_save")
end
function actor_load(stpk)
set_save_marker(stpk, "load", false, "sound_actor_save")
for k,v in pairs(sound_theme.theme) do
v:load(stpk)
end
sound_table = {}
local n = stpk:r_u16()
for i = 1,n do
local id = stpk:r_u16()
local theme = stpk:r_stringZ()
-- sound_table[id] = stpk:r_stringZ()
sound_table[id] = sound_theme.theme[theme]
end
looped_sound = {}
n = stpk:r_u16()
for i = 1,n do
local id = stpk:r_u16()
looped_sound[id] = {}
n = stpk:r_u16()
for i = 1,n do
local sound = stpk:r_stringZ()
-- looped_sound[id][sound] = stpk:r_stringZ()
looped_sound[id][sound] = sound_theme.theme[sound]
end
end
set_save_marker(stpk, "load", true, "sound_actor_save")
end
function npc_save_state(id,m_data)
--alun_utils.debug_write("npc_save_state")
m_data.xr_sound = empty_table(m_data.xr_sound)
for k,v in pairs(sound_theme.theme) do
v:save_state(m_data.xr_sound)
end
end
function npc_load_state(id,m_data)
if not (m_data.xr_sound) then
return
end
for k,v in pairs(sound_theme.theme) do
v:load_state(m_data.xr_sound)
end
m_data.xr_sound = nil
end
function save_npc(stpk, npc_id)
--alun_utils.debug_write("xr_sound:save_npc")
set_save_marker(stpk, "save", false, "sound_npc_save")
for k,v in pairs(sound_theme.theme) do
v:save_npc(stpk, npc_id)
end
set_save_marker(stpk, "save", true, "sound_npc_save")
end
function load_npc(stpk, npc_id)
--alun_utils.debug_write("xr_sound:load_npc")
set_save_marker(stpk, "load", false, "sound_npc_save")
for k,v in pairs(sound_theme.theme) do
v:load_npc(stpk, npc_id)
end
set_save_marker(stpk, "load", true, "sound_npc_save")
end
function stop_all_sounds()
for k,v in pairs(sound_table) do
if(type(v)~="string") then
v:stop()
end
end
for k,v in pairs(looped_sound) do
for k,v in pairs(looped_sound[k]) do
if v and v:is_playing(npc_id) then
printf("looped sound ["..tostring(k).."] stopped ")
v:stop()
end
end
end
end
function stop_sounds_by_id(obj_id)
local sound = sound_table[obj_id]
if sound and sound.stop then
sound:stop(obj_id)
end
local looped_snd = looped_sound[obj_id]
if looped_snd then
for k,v in pairs(looped_snd) do
if v and v:is_playing(obj_id) then
v:stop(obj_id)
end
end
end
end
---------------------------------------------------------------------------------------------------------------------
-- Схема озвучки
-- автор: Диденко Руслан (Stohe)
-- update: Чугай Александр (Chugai)
----------------------------------------------------------------------------------------------------------------------
key_by_id = {}
group_idle = {}
--function printf()
--end
function get_sound(path, tt, npc)
if path == nil then return nil end
if path.exec == nil then
-- чтение настроек темы
tt.into_id = path.into_id
tt.into_max = path.max_ids[npc:id()].into_max
tt.into_last = nil
tt.rnd_id = path.rnd_id
tt.rnd_max = path.max_ids[npc:id()].rnd_max
tt.rnd_last = nil
tt.min_snd = path.min_snd
tt.max_snd = path.max_snd
tt.rnd_snd = path.rnd_snd
else
get_sound(path.types[path.exec(path.types, npc)], tt, npc)
end
end
-- Формирование ключа персонажа
function get_key(npc)
local key
-- формирование ключа
local overrides = xr_logic.generic_scheme_overrides(npc)
if overrides and
overrides.soundgroup
then
key = overrides.soundgroup
else
key = utils.to_str(npc:id())
end
-- апдейт таблиц
не менять!
if xr_sound.key_by_id[npc:id()] ~= key then
if xr_sound.group_idle[xr_sound.key_by_id[npc:id()]] ~= nil then
xr_sound.group_idle[xr_sound.key_by_id[npc:id()]].num_in_group = xr_sound.group_idle[xr_sound.key_by_id[npc:id()]].num_in_group - 1
end
xr_sound.key_by_id[npc:id()] = key
if xr_sound.group_idle[key] == nil then
xr_sound.group_idle[key] = {num_in_group = 1}
else
xr_sound.group_idle[key].num_in_group = xr_sound.group_idle[key].num_in_group + 1
end
end
return key
end
-----------------------------------------------------------------------------------------------------------------------------------
-- Установка и распарсивание тем в файлы.
-----------------------------------------------------------------------------------------------------------------------------------
function set_sound(npc, sound, now, into_timeout)
-- printf("*SND* [%s] try to change SND to [%s]", npc:name(), tostring(sound))
local npc_id = npc:id()
if (db.sound[npc_id] == nil or
db.sound[npc_id].theme ~= sound) or
now == true
then
-- if db.sound[npc_id] == nil then
-- printf("*SND* change SND [_] to [%s] for [%s]", tostring(sound), npc:name())
-- else
-- printf("*SND* change SND [%s] to [%s] for [%s]", tostring(db.sound[npc_id].theme), tostring(sound), npc:name())
-- end
-- Туточки надобно распарсить имена тем в их id
if sound == nil then sound = "" end
if db.sound[npc_id] == nil then db.sound[npc_id] = {} end
db.sound[npc_id].theme = sound
db.sound[npc_id].snd = parse_names(sound)
if db.sound[npc_id].last_snd == nil then
db.sound[npc_id].last_snd = {}
else
local snd_table = {}
local t = 0
for k,v in pairs(db.sound[npc_id].snd) do
snd_table[t] = {}
get_sound(sound_theme.theme[v], snd_table[t], npc)
t = t + 1
end
for k,v in pairs(snd_table) do
if v.into_id then db.sound[npc_id].last_snd[v.into_id] = nil end
if v.rnd_id then db.sound[npc_id].last_snd[v.rnd_id] = nil end
end
end
-- Устанавливаем входную паузу
local key = get_key(npc)
xr_sound.group_idle[key].begin = time_global()
if into_timeout then
xr_sound.group_idle[key].idle = into_timeout
else
xr_sound.group_idle[key].idle = 0
end
if now == true then
stop_play_sound(npc)
end
end
end
function play_sound(npc, themes, timeout)
--alun_utils.debug_write(strformat("xr_sound:play_sound %s",npc and npc:name()))
-- нужно составить список тем
local snd_table = {}
local t = 0
for k,v in pairs(themes) do
snd_table[t] = {}
if sound_theme.theme[v] ~= nil then
snd_table[t].theme = v
get_sound(sound_theme.theme[v], snd_table[t], npc)
else
printf("ERROR: ILLEGAL PLAY SOUND!!! %s for %s", v, npc:name())
end
t = t + 1
end
--printf("*")
--print_table(snd_table)
if t == 0 then return end
-- из списка тем выбираем одну.
local snd = snd_table[math.random(0, t-1)]
if snd ~= nil then
--printf("!")
--print_table(snd)
if snd.min_snd == nil then return end
local npc_id = npc:id()
local group_table = xr_sound.group_idle[get_key(npc)]
group_table.idle = math.random(snd.min_snd, snd.max_snd)*1000
if group_table.last_snd == nil then
group_table.last_snd = {}
end
-- необходимо ли нам играть into или rnd звуки
if snd.into_max ~= nil and
snd.into_max > 0
then
if db.sound[npc_id].last_snd[snd.into_id] == snd.into_max - 1 then
if snd.into_cycled == true then
db.sound[npc_id].last_snd[snd.into_id] = nil
else
return
end
end
-- играем входные
if db.sound[npc_id].last_snd[snd.into_id] == nil then db.sound[npc_id].last_snd[snd.into_id] = -1 end
--printf("*SND* play seq [%s] for [%s]", db.sound[npc_id].last_snd[snd.into_id]+1, npc:name())
process_tutor_on_sound(snd.theme)
npc:play_sound(snd.into_id, 1, 0, 1, 0, db.sound[npc_id].last_snd[snd.into_id]+1)
db.sound[npc_id].last_snd[snd.into_id] = db.sound[npc_id].last_snd[snd.into_id] + 1
--printf("*SND* play seq [%s] for [%s]", db.sound[npc_id].last_snd[snd.into_id], npc:name())
return
end
if snd.rnd_max ~= nil and
snd.rnd_max > 0
then
-- играем рандомные
local s = 0
if snd.rnd_max == 1 then
s = 0
else
-- Если прошлый раз проигрывался такой же набор тем
-- то учитывать последний звук для группы.
-- if db.sound[npc_id].last_snd[snd.rnd_id] ~= nil then
if group_table.last_snd[snd.rnd_id] ~= nil then
s = math.random(0, snd.rnd_max-2)
if s >= group_table.last_snd[snd.rnd_id] then s = s + 1 end
else
s = math.random(0, snd.rnd_max-1)
end
end
if timeout == nil then
timeout = 0
end
--printf("*SND* play rnd [%s] for [%s]", s, npc:name())
process_tutor_on_sound(snd.theme)
npc:play_sound(snd.rnd_id, timeout+1, timeout, 1, 0, s)
--db.sound[npc_id].last_snd[snd.rnd_id] = s
group_table.last_snd[snd.rnd_id] = s
end
end
end
function get_last_IDS(npc, theme)
local last_table = db.sound[npc:id()].last_snd
local snd_table = {}
if sound_theme.theme[theme] ~= nil then
get_sound(sound_theme.theme[theme], snd_table, npc)
end
--printf("LAST INTO ID for [%s] = [%s], max [%s]", theme, last_table[snd_table.into_id], snd_table.into_max)
return last_table[snd_table.into_id], snd_table.into_max
end
function process_tutor_on_sound(theme)
end
--' Actor sound player
local actor_sound = {}
function set_actor_sound(sound)
--printf("*ACTOR SND* try to change SND to [%s]", tostring(sound))
if actor_sound.theme ~= sound then
--' Туточки надобно распарсить имена тем в их id
if sound == nil then sound = "" end
actor_sound.theme = sound
actor_sound.begin = nil
this.set_actor_sound_factor(1)
end
end
function set_actor_sound_factor(factor)
local theme = sound_theme.actor_theme[actor_sound.theme]
if theme ~= nil then
actor_sound.min_snd = theme.min_snd * factor
actor_sound.max_snd = theme.max_snd * factor
end
end
function update_actor()
local theme = sound_theme.actor_theme[actor_sound.theme]
if theme == nil then return end
if table.getn(theme.sounds) == 0 then
return
end
if actor_sound.begin == nil or
time_global() - actor_sound.begin >= actor_sound.idle
then
actor_sound.begin = time_global()
--' Тут надо отыграть звук
local sound = theme.sounds[math.random(table.getn(theme.sounds))]
if sound ~= nil then
sound:play(db.actor, 0, sound_object.s2d)
end
actor_sound.idle = math.random(actor_sound.min_snd, actor_sound.max_snd)
end
end
-- modified by Alundaio (original: ????)
--' Таблица для хранения созданных саунд обжектов.
--' type = [random|seq|looped]
local ltx = ini_file("plugins\\xr_sound.ltx")
function get_sound_object(theme, t_type)
if not (ph_snd_themes) then
ph_snd_themes = {}
ph_snd_themes[theme] = alun_utils.collect_section(ltx,theme)
--printf("collect theme=%s",theme)
end
if (not ph_snd_themes or not ph_snd_themes[theme]) then
--printf("no ph_snd_themes theme=%s",theme)
return
end
if not (sound_object_by_theme) then
sound_object_by_theme = {}
end
if (not sound_object_by_theme[theme])then
sound_object_by_theme[theme] = {}
end
if t_type == nil then
t_type = "random"
end
--' Выбор следующего айдишника
local play_id = -1
local table_size = #ph_snd_themes[theme]
if (table_size == 0) then
return
end
--printf("tablesize = %s theme=%s",table_size,theme)
if sound_object_by_theme[theme].last_id == nil then
if t_type == "random" then
if table_size >= 2 then
play_id = math.random(1, table_size)
else
play_id = 1
end
else
play_id = 1
end
else
if t_type == "random" then
if table_size >= 2 then
play_id = math.random(1, table_size - 1)
if play_id >= sound_object_by_theme[theme].last_id then play_id = play_id + 1 end
else
play_id = 1
end
else
if sound_object_by_theme[theme].last_id < table_size then
play_id = sound_object_by_theme[theme].last_id + 1
else
if type == "looped" then
play_id = 1
end
end
end
end
--printf("SOUND_OBJECT: selected id [%s] for theme [%s], type [%s], size [%s]", tostring(play_id), tostring(theme), tostring(type), table_size)
if play_id == -1 then
return
end
--' Проверяем создан ли у нас соответствующий саунд обжект или его надо создать
if sound_object_by_theme[theme][play_id] == nil then
if type(ph_snd_themes[theme][play_id]) == "table" then
sound_object_by_theme[theme][play_id.."_r"] = get_safe_sound_object(ph_snd_themes[theme][play_id][1].."_r")
sound_object_by_theme[theme][play_id.."_l"] = get_safe_sound_object(ph_snd_themes[theme][play_id][1].."_l")
else
sound_object_by_theme[theme][play_id] = get_safe_sound_object(ph_snd_themes[theme][play_id])
end
end
sound_object_by_theme[theme].last_id = play_id
--' Возвращаем саунд обжект
if type(ph_snd_themes[theme][play_id]) == "table" then
return sound_object_by_theme[theme][play_id.."_r"], sound_object_by_theme[theme][play_id.."_l"]
else
return sound_object_by_theme[theme][play_id]
end
end
local sound_object_by_path = {}
--' Обертка вокруг функции, возвращающий звуковой объект.
function get_safe_sound_object(path)
if sound_object_by_path[path] == nil then
sound_object_by_path[path] = sound_object(path)
end
return sound_object_by_path[path]
end
function stop_all_sound_object()
for k,v in pairs(sound_object_by_path) do
if v:playing() then
v:stop()
end
end
end
function clear_all_sound_object()
sound_object_by_theme = {}
end