-- ._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.- -- -- Tables of "human_0x" Prefix Assignments -- For the Campfire Convo Fix -- -- ._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.- local human_01_prefix = { -- Loners stalker_neutral_1 = true, stalker_neutral1a = true, stalker_neutral1b = true, stalker_neutral1c = true, stalker_neutral1d = true, stalker_neutral1e = true, stalker_neutral1f = true, stalker_neutral_1_mask = true, stalker_neutral1a_mask = true, stalker_neutral1b_mask = true, stalker_neutral1c_mask = true, stalker_neutral1d_mask = true, stalker_neutral1e_mask = true, stalker_neutral1f_mask = true, stalker_neutral_a = true, stalker_neutrala1 = true, stalker_neutrala2 = true, stalker_neutrala3 = true, stalker_neutrala4 = true, stalker_neutrala5 = true, stalker_neutrala6 = true, stalker_neutral_1_mas2 = true, stalker_neutral1a_mas2 = true, stalker_neutral1b_mas2 = true, stalker_neutral1c_mas2 = true, stalker_neutral1d_mas2 = true, stalker_neutral1e_mas2 = true, stalker_neutral1f_mas2 = true, stalker_neutral_3 = true, -- Bandits stalker_bandit_1 = true, stalker_bandit1a = true, stalker_bandit1b = true, stalker_bandit1c = true, stalker_band_2_mask = true, stalker_band2a_mask = true, stalker_bandit_2_mask = true, stalker_bandit2a_mask = true, stalker_bandit_2a = true, -- Military stalker_soldier_1 = true, stalker_soldier1b = true, stalker_soldier1c = true, stalker_soldier1d = true, stalker_soldier1e = true, stalker_soldier1f = true, stalker_soldier1g = true, -- Duty stalker_dolg_2 = true, stalker_dolg2a = true, stalker_dolggas_2 = true, stalker_dolggas2a = true, stalker_dolg_2_mas2 = true, stalker_dolg2a_mask = true, stalker_dolg_2_old = true, stalker_dolg2a_old = true, stalker_dolg2a_mas2 = true, stalker_dolg_2_mas4 = true, stalker_dolg2a_mas4 = true, stalker_dolg_0 = true, stalker_dolg2a_mas3 = true, stalker_dolg_1 = true, stalker_dolg1a = true, stalker_dolg1b = true, stalker_dolg1c = true, stalker_dolg1d = true, stalker_dolg_3 = true, stalker_dolg3b = true, -- Freedom stalker_freedom_2_mask = true, stalker_freedom2a_mask = true, stalker_freedom2b_mask = true, stalker_freedom_2_mas2 = true, stalker_freedom2a_mas2 = true, stalker_freedom2b_mas2 = true, stalker_freedom_2_mas4 = true, stalker_freedom2a_mas4 = true, stalker_freedom2b_mas4 = true, stalker_freedom_2_mas3 = true, stalker_freedom2a_mas3 = true, stalker_freedom2b_mas3 = true, -- Clear Sky stalker_nebo_r = true, stalker_nebo_r_mas2 = true, stalker_nebo_r2 = true, stalker_nebo_1 = true, stalker_nebo_a = true, stalker_neboa2 = true, stalker_nebo_b = true, -- Ecologists stalker_hero_1 = true, -- Mercs stalker_merc_2 = true, -- Monolith stalker_monolith_2 = true, stalker_monolith2 = true, stalker_monolith_2_old = true, stalker_monolith_3 = true, stalker_monolith_1 = true, stalker_monolith3a = true, stalker_monolith3b = true, stalker_monolith_4 = true, stalker_monolith4a = true, stalker_monolith4b = true, -- Special -- Cordon stalker_nimble = true, stalker_neytral_balon_1 = true, stalker_neytral_rukzak_3 = true, -- Marsh stalker_trader_nebo = true, stalker_nebo_2_face_4 = true, stalker_nebo_2_face_3 = true, -- Dark Valley stalker_bandit_tr = true, -- Jupiter stalker_neutral_nauchniy_face_3 = true, -- Bar stalker_dolg_mehanik = true, stalker_do_balon_3 = true, stalker_neytral_balon_6 = true, stalker_bar_security = true, -- Army W. stalker_freedom_4_face_1 = true, -- Yantar stalker_ucheniy_1 = true, stalker_prizrak = true, -- Zaton stalker_neutral_2_face_6 = true, stalker_bandit_3_face_2 = true, -- Pripyat stalker_soldier_1_face_1 = true, stalker_neutral_nauchniy_face_1 = true, stalker_soldier_ecolog_face_1 = true } local human_02_prefix = { -- Loners stalker_neutral_2_mask = true, stalker_neutral2a_mask = true, stalker_neutral2b_mask = true, stalker_neutral2c_mask = true, stalker_neutral2d_mask = true, stalker_neutral_2mask1 = true, stalker_neutral2amask1 = true, stalker_neutral2bmask1 = true, stalker_neutral2cmask1 = true, stalker_neutral2dmask1 = true, stalker_neutral_2mask2 = true, stalker_neutral2amask2 = true, stalker_neutral2bmask2 = true, stalker_neutral2cmask2 = true, stalker_neutral2dmask2 = true, stalker_neutral2e_mask = true, stalker_neutral2f_mask = true, stalker_neutral2emask1 = true, stalker_neutral2fmask1 = true, stalker_neutral2fmask2 = true, stalker_neutral2emask2 = true, stalker_neutral2gmask1 = true, stalker_neutral2gmask2 = true, stalker_neutral_2_mas2 = true, stalker_neutral2a_mas2 = true, stalker_neutral2b_mas2 = true, stalker_neutral2c_mas2 = true, stalker_neutral2d_mas2 = true, stalker_neutral2e_mas2 = true, stalker_neutral2f_mas2 = true, stalker_neutral_2_mas3 = true, stalker_neutral2a_mas3 = true, stalker_neutral2b_mas3 = true, stalker_neutral2c_mas3 = true, stalker_neutral2d_mas3 = true, stalker_neutral2e_mas3 = true, stalker_neutral2f_mas3 = true, stalker_neutral2g_mas2 = true, stalker_neutral2g_mas3 = true, stalker_neutral2g_mask = true, -- Bandits stalker_bandit_1_mask = true, stalker_bandit1a_mask = true, stalker_bandit1b_mask = true, stalker_bandit1c_mask = true, stalker_bandit_a = true, stalker_bandita1 = true, stalker_bandita2 = true, stalker_bandita3 = true, stalker_bandit_3 = true, stalker_bandit3a = true, stalker_bandit3b = true, stalker_bandit3c = true, stalker_bandit_4 = true, stalker_bandit4a = true, stalker_bandit4b = true, stalker_bandit4c = true, stalker_bandit5a = true, stalker_bandit5b = true, stalker_bandit5c = true, stalker_bandit5d = true, stalker_bandit_exo = true, -- Military stalker_soldier_2 = true, stalker_soldier_3_beret = true, stalker_soldier3a_beret = true, stalker_soldier3b_beret = true, stalker_soldier3c_beret = true, stalker_soldier3d_beret = true, stalker_soldier3e_beret = true, stalker_soldier3f_beret = true, stalker_soldier3g_beret = true, stalker_soldier3h_beret = true, stalker_soldier3i_beret = true, stalker_soldier3j_beret = true, stalker_soldier3k_beret = true, stalker_soldier_5_beret = true, stalker_soldier5a_beret = true, stalker_soldier5b_beret = true, stalker_soldier5c_beret = true, stalker_soldier5d_beret = true, stalker_soldier5f_beret = true, stalker_soldier5g_beret = true, stalker_soldier5h_beret = true, stalker_soldier5i_beret = true, stalker_soldier5j_beret = true, stalker_soldier5k_beret = true, -- Duty stalker_dolg3a = true, stalker_dolg3b = true, stalker_dolg_3 = true, stalker_dolgexo_4 = true, stalker_dolgexo4a = true, stalker_dolgexo4b = true, stalker_dolgexo4c = true, stalker_dolg_4 = true, stalker_dolg4a = true, stalker_dolg4b = true, stalker_dolg4c = true, -- Freedom stalker_freedom2a_mask = true, stalker_freedom2a_mas3 = true, stalker_freedom2b_mas3 = true, stalker_freedom2a_mas4 = true, stalker_freedom2b_mas4 = true, stalker_freedom_3 = true, stalker_freedom3a = true, stalker_free_0 = true, -- Clear Sky stalker_nebo_1 = true, stalker_nebo_s_mask = true, stalker_nebo_smask1 = true, stalker_nebo_smask2 = true, stalker_nebo_s_mas2 = true, stalker_nebo_s_mas3 = true, -- Ecologists -- NOTHING, YOU LOSE, GOOD DAY SIR -- Mercs -- NOTHING, YOU LOSE, GOOD DAY SIR -- Monolith stalker_monolith_2 = true, stalker_monolith_2_old = true, stalker_monolith_3 = true, stalker_monolith_1 = true, stalker_monolith3a = true, stalker_monolith3b = true, stalker_monolith_4 = true, stalker_monolith4a = true, stalker_monolith4b = true } local human_03_prefix = { -- Loners stalker_neutral_1_gas = true, stalker_neutral1a_gas = true, stalker_neutral1b_gas = true, stalker_neutral1c_gas = true, stalker_neutral1d_gas = true, stalker_neutral1e_gas = true, stalker_neutral1f_gas = true, stalker_neutral_2 = true, stalker_neutral2a = true, stalker_neutral2b = true, stalker_neutral2c = true, stalker_neutral2d = true, stalker_neutral_0 = true, stalker_neutral0a = true, stalker_neutral0b = true, stalker_neutral0c = true, stalker_neutral0d = true, stalker_neutral2e = true, stalker_neutral2f = true, stalker_neutral0e = true, stalker_neutral0f = true, stalker_neutral_2_old = true, stalker_neutral2a_old = true, stalker_neutral2b_old = true, stalker_neutral2c_old = true, stalker_neutral2d_old = true, stalker_neutral2e_old = true, stalker_neutral2f_old = true, stalker_neutral_2_merc = true, stalker_neutral2a_merc = true, stalker_neutral2b_merc = true, stalker_neutral2c_merc = true, stalker_neutral2d_merc = true, stalker_neutral2e_merc = true, stalker_neutral2f_merc = true, stalker_neutral_2_gp5 = true, stalker_neutral2a_gp5 = true, stalker_neutral2b_gp5 = true, stalker_neutral2c_gp5 = true, stalker_neutral2d_gp5 = true, stalker_neutral2e_gp5 = true, stalker_neutral2f_gp5 = true, stalker_neutral0g = true, stalker_neutral2g = true, stalker_neutral2g_gp5 = true, stalker_neutral2g_old = true, stalker_neutral2g_merc = true, stalker_neutral_nauchniy = true, stalker_neutral_3 = true, stalker_neutral_nauchni2 = true, stalker_neutral3a = true, stalker_neutral3b = true, stalker_neutral_nauchni3 = true, stalker_neutral_nauchni4 = true, stalker_neutral_4 = true, stalker_neutral4a = true, stalker_neutral4b = true, -- Bandits stalker_bandit_1_gas = true, stalker_bandit1a_gas = true, stalker_bandit1b_gas = true, stalker_bandit1c_gas = true, stalker_bandit_2 = true, stalker_bandit2a = true, stalker_bandit_2a = true, stalker_bandit2a_old = true, stalker_bandit_2a_merc = true, stalker_bandit_2a_gp5 = true, stalker_bandit6a = true, stalker_bandit6b = true, stalker_bandit6c = true, stalker_bandit6d = true, stalker_bandit6e = true, stalker_bandit6f = true, stalker_bandit6g = true, stalker_bandit6h = true, -- Military stalker_soldier_3 = true, stalker_soldier_4 = true, stalker_military_exo = true, stalker_soldier_5 = true, stalker_soldier4a = true, stalker_soldier5a = true, -- Duty -- NOTHING, YOU LOSE, GOOD DAY SIR -- Freedom stalker_freedom_0 = true, stalker_freedom1a = true, stalker_freedom_1 = true, stalker_freedom_2 = true, stalker_freedom2a = true, stalker_freedom2b = true, stalker_freedom2b_mask = true, stalker_freedom_2_old = true, stalker_freedom2a_old = true, stalker_freedom2b_old = true, stalker_free_0 = true, stalker_free0a = true, stalker_freedom_5 = true, stalker_freedom5a = true, stalker_freedom5b = true, stalker_freedom_3 = true, stalker_freedom_4 = true, stalker_freedom4a = true, stalker_freedom4b = true, stalker_freedom3a = true, -- Clear Sky stalker_nebo_r_mask = true, stalker_nebo_r_gas = true, stalker_nebo_s = true, stalker_nebo_s_old = true, stalker_nebo_s_merc = true, stalker_nebo_s_gp5 = true, stalker_nebo_2 = true, stalker_nebo_b = true, stalker_nebo2a = true, stalker_nebob2 = true, stalker_nebo2b = true, stalker_nebo_3 = true, stalker_nebo3a = true, stalker_nebo3b = true, stalker_nebo_seva_1 = true, stalker_nebo_seva_2 = true, stalker_nebo_exo_1 = true, -- Ecologists stalker_ecolog = true, stalker_ecolog_blue = true, stalker_ecolog_brown = true, stalker_ecolog_military = true, stalker_ecolog_white = true, stalker_ecolog_yellow = true, stalker_ecolog_guard = true, -- Mercs stalker_merc_2 = true, stalker_merc2a = true, stalker_merc2b = true, stalker_merc2c = true, stalker_mercen_2_mask = true, stalker_mercen2a_mask = true, stalker_mercen2b_mask = true, stalker_mercen2c_mask = true, stalker_merc_sun1 = true, stalker_merc_sun1_old = true, stalker_merc_sun1_merc = true, stalker_mercenary3 = true, stalker_mercenary4 = true, stalker_merc_4 = true, stalker_merc4a = true, stalker_mercexo_4 = true, stalker_mercexo4a = true, -- Monolith stalker_monolith_2 = true, -- Special -- Cordon loner_mechanic_stalker = true, -- Dead City stalker_ki_head_2 = true, stalker_merc_2_face_2 = true, } --'------------------------------------------------------------------------------------------------------------------- --' Ñõåìà îçâó÷êè --' àâòîð: Äèäåíêî Ðóñëàí (Stohe) --'-------------------------------------------------------------------------------------------------------------------- theme = {} local sounds_base = stalker_ids.sound_script + 10000 function id() sounds_base = sounds_base + 1 return sounds_base - 1 end --'-------------------------------------------------------------------------------------------------------------------- --' Êëàññ "çâóêîâàÿ êîëëåêöèÿ ñòàëêåðà" --'-------------------------------------------------------------------------------------------------------------------- class "npc_sound" function npc_sound:__init(snd_ini, section) --alun_utils.debug_write("npc_sound:__init %s",section) self.class_id = "npc_sound" --' Ïàðàìåòðû âû÷èòûâàíèÿ çâóêà self.prefix = snd_ini:r_bool_ex(section,"npc_prefix",false) self.path = snd_ini:r_string_ex(section,"path") or "" self.shuffle = snd_ini:r_string_ex(section,"shuffle") or "rand" self.group_snd = snd_ini:r_bool_ex(section,"group_snd",false) self.play_always = snd_ini:r_bool_ex(section,"play_always",false) self.is_combat_sound = snd_ini:r_bool_ex(section,"is_combat_sound",false) self.dont_save = snd_ini:r_bool_ex(section,"dont_save",false) self.story_ids = snd_ini:line_exist(section,"story_ids") and alun_utils.parse_list(snd_ini,section,"story_ids",true) or nil self.section = section --' Õðàíèò ïàðàìåòðû çâóêà äëÿ êàæäîãî NPC self.npc = {} self.played_id = nil -- Âðåìÿ çàäåðæêè íà÷àëà îòûãðûâàíèÿ çâóêà self.delay_sound = snd_ini:r_float_ex(section,"delay_sound") or 0 --' Èíòåðâàë ïðîèãðûâàíèÿ çâóêà local interval = parse_names(snd_ini:r_string_ex(section,"idle") or "3,5,100") self.min_idle = tonumber(interval[1]) self.max_idle = tonumber(interval[2]) self.rnd = tonumber(interval[3]) self.can_play_group_sound = true self.can_play_sound = {} self.sound_path = {} self.faction = snd_ini:r_string_ex(section,"faction") or "" self.point = snd_ini:r_string_ex(section,"point") or "" self.msg = snd_ini:r_string_ex(section,"message") or "" self.avail_communities = snd_ini:line_exist(section,"avail_communities") and alun_utils.parse_list(snd_ini,section,"avail_communities",true) or nil end function npc_sound:reset(npc_id) local npc = db.storage[npc_id] and db.storage[npc_id].object self.played_time = nil self.played_id = nil self.can_play_group_sound = true self.can_play_sound[npc_id] = true if npc ~= nil then npc:set_sound_mask(-1) npc:set_sound_mask(0) end if self.pda_snd_obj ~= nil then self.pda_snd_obj:stop() self.pda_snd_obj = nil end end function npc_sound: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:init_npc(npc) --alun_utils.debug_write(strformat("npc_sound:init_npc %s",npc and npc:name())) local npc_id = npc:id() self.sound_path[npc_id] = {} local character_prefix if self.prefix == false then character_prefix = npc:sound_prefix() npc:sound_prefix("characters_voice\\") elseif ( self.prefix == true ) and ( npc:sound_prefix() == "characters_voice\\" ) then local visual = npc:get_visual_name() local expl_str = alun_utils.str_explode(visual,"\\") local true_visual = expl_str[3] local faction = npc:character_community() if ( faction == "army" ) then faction = "military" end -- printf("NPC VISUAL: %s", true_visual) local human_prefix if ( human_03_prefix[true_visual] == true ) then human_prefix = "human_03\\" elseif ( human_02_prefix[true_visual] == true ) then human_prefix = "human_02\\" elseif ( human_01_prefix[true_visual] == true ) then human_prefix = "human_01\\" end if ( human_prefix ) then character_prefix = npc:sound_prefix() npc:sound_prefix("characters_voice\\" .. human_prefix .. faction .. "\\") end end -- printf("NPC NAME: %s", npc:name()) -- printf("SELF PREFIX: %s", self.prefix) -- printf("SOUND PREFIX: %s", npc:sound_prefix()) local f = getFS() -- First condition is for singular, un-numbered sound files. -- Second condition is for numbered sound files, ones that would typically be chosen at random. if f:exist("$game_sounds$",npc:sound_prefix()..self.path..".ogg") ~= nil then self.npc[npc_id] = {} self.npc[npc_id].id = id() self.sound_path[npc_id][1] = npc:sound_prefix()..self.path if self.is_combat_sound then self.npc[npc_id].max = npc:add_combat_sound(self.path, 64, snd_type.talk, 2, 1, self.npc[npc_id].id,"bip01_head") - 1 else self.npc[npc_id].max = npc:add_sound(self.path, 64, snd_type.talk, 2, 1, self.npc[npc_id].id) - 1 end else local num = 1 while f:exist("$game_sounds$",npc:sound_prefix()..self.path..num..".ogg") do -- printf("adding sound ["..npc:sound_prefix()..self.path..num.."] to table id = "..num) self.sound_path[npc_id][num] = npc:sound_prefix()..self.path..num num = num + 1 end if (num > 1) then self.npc[npc_id] = {} self.npc[npc_id].id = id() -- printf("Added sound [%s] for [%s]: %s", self.section, npc:section(), npc:sound_prefix() .. self.path) if self.is_combat_sound then self.npc[npc_id].max = npc:add_combat_sound(self.path, 64, snd_type.talk, 2, 1, self.npc[npc_id].id,"bip01_head") - 1 else self.npc[npc_id].max = npc:add_sound(self.path, 64, snd_type.talk, 2, 1, self.npc[npc_id].id) - 1 end elseif ( string.find( npc:section(), "sim_default" ) ) then -- printf("!Sound [%s] not found for [%s]: %s", self.section, npc:section(), npc:sound_prefix()..self.path) end end if not (self.npc[npc_id]) then return end if self.npc[npc_id].max == nil or self.npc[npc_id].max < 0 then abort("Couldnt find sounds %s with prefix %s", tostring(self.path), npc:sound_prefix()) return end if self.prefix == false then npc:sound_prefix(character_prefix) end if self.group_snd then self.can_play_group_sound = true else if self.can_play_sound[npc_id] ~= false then self.can_play_sound[npc_id] = true end end end function npc_sound:callback(npc_id) self.played_time = time_global() self.idle_time = math.random(self.min_idle, self.max_idle) * 1000 if self.group_snd then self.can_play_group_sound = true else self.can_play_sound[npc_id] = true end -- printf("npc_sound:callback!!!!!!!!") -- get_hud():RemoveCustomStatic("cs_subtitles_npc") local st = db.storage[npc_id] if st.active_scheme == nil then return end if st[st.active_scheme].signals == nil then return end -- Çàòû÷êà ïðîòèâ âîçìîæíîãî âûëåòà, êîãäà ïðèõîäèò êîëáåê îò çâóêà, êîòîðûé äàííûé ÍÏÑ íå èãðàåò. if self.npc[npc_id] == nil then return end if self.played_id == self.npc[npc_id].max and self.shuffle ~= "rnd" then --printf("npc [%s] signalled [theme_end] for snd [%s]", npc_id, self.section) st[st.active_scheme].signals["theme_end"] = true st[st.active_scheme].signals["sound_end"] = true else --printf("npc [%s] signalled [sound_end] for snd [%s]", npc_id, self.section) st[st.active_scheme].signals["sound_end"] = true end end function npc_sound:play(npc_id, faction, point, sound) --alun_utils.debug_write(strformat("npc_sound:play npc_id=%s faction=%s msg=%s",npc_id,faction,msg)) local npc = db.storage[npc_id] and db.storage[npc_id].object if npc == nil then printf("coudnt find npc!!!") return false end local npc_data = self.npc[npc_id] if not (npc_data) then return false end if (self.group_snd and self.can_play_group_sound == false or self.can_play_sound[npc_id] == false) then return false end if self.played_time ~= nil and time_global() - self.played_time < self.idle_time then return false end self.played_time = nil self.played_id = self:select_next_sound(npc_id) if self.played_id == -1 then return false end npc:play_sound(npc_data.id, self.delay_sound+0.06, self.delay_sound+0.05, 1, 0, self.played_id) local table_id = self.played_id + 1 local snd = self.sound_path[npc_id][table_id] if not (snd) then printf("sound_theme.npc_sound:play() snd is nil! %s",sound) return end if snd and npc:position():distance_to_sqr(db.actor:position()) >= 100 and getFS():exist("$game_sounds$", snd.."_pda.ogg") ~= nil then if self.pda_snd_obj ~= nil and self.pda_snd_obj:playing() then self.pda_snd_obj:stop() end self.pda_snd_obj = sound_object(snd.."_pda") --play_at_pos(CScriptGameObject *object, const Fvector &position, float delay, int flags) self.pda_snd_obj:play_at_pos(db.actor, vector():set(0,0,0), self.delay_sound, sound_object.s2d) self.pda_snd_obj.volume = 0.8 end --printf("snd_path is "..tostring(self.sound_path[npc_id][table_id])) local snd_st, num_copy = string.gsub(snd, "\\", "_") if self.group_snd then self.can_play_group_sound = false else self.can_play_sound[npc_id] = false end if not closecaption.sound(snd, sound_object(snd):length(), npc, faction, point, self.delay_sound) then if game.translate_string(snd_st) ~= snd_st then faction = faction or character_community(npc) if not point then point = npc:profile_name().."_name" if game.translate_string(point) == point then point = nil end end news_manager.send_sound(npc, faction, point, snd, snd_st, self.delay_sound) else news_manager.send_sound(npc, faction, point, snd, nil , self.delay_sound) end end return true end function npc_sound:select_next_sound(npc_id) local npc_data = self.npc[npc_id] if not (npc_data and npc_data.max) then return 0 end if self.shuffle == "rnd" then if npc_data.max == 0 then return 0 end if self.played_id ~= nil then 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 == -1 then return -1 end 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:stop(obj_id) local npc = db.storage[obj_id] and db.storage[obj_id].object if npc ~= nil and npc:alive() then npc:set_sound_mask(-1) npc:set_sound_mask(0) end if self.pda_snd_obj ~= nil and self.pda_snd_obj:playing() then self.pda_snd_obj:stop() self.pda_snd_obj = nil end end function npc_sound:save_state(m_data) if (self.dont_save) then return end if (self.played_id) or (self.group_snd and self.can_play_group_sound == false) then m_data[self.section] = empty_table(m_data[self.section]) m_data[self.section].played_id = self.played_id or nil m_data[self.section].can_play_group_sound = self.can_play_group_sound == false and false or nil end end function npc_sound:load_state(m_data) if not (m_data[self.section]) then return end self.played_id = m_data[self.section].played_id if (self.group_snd) then self.can_play_group_sound = m_data[self.section].can_play_group_sound ~= false and true or false end end function npc_sound:save(thread) --alun_utils.debug_write("npc_sound:save BEFORE") if self.dont_save then --alun_utils.debug_write("npc_sound:save AFTER 1") return end -- set_save_marker(thread, "save", false, "npc_sound") alun_utils.w_stpk(thread,"stringZ",tostring(self.played_id or nil),"npc_sound:save") if self.group_snd then thread:w_bool(self.can_play_group_sound == true) end --alun_utils.debug_write("npc_sound:save AFTER 2") -- set_save_marker(thread, "save", true, "npc_sound") end function npc_sound:load(thread) --alun_utils.debug_write("npc_sound:load BEFORE") if self.dont_save then --alun_utils.debug_write("npc_sound:load AFTER 1") return end -- set_save_marker(thread, "load", false, "npc_sound") local id = thread:r_stringZ() if(id~="nil") then self.played_id = tonumber(id) else self.played_id = nil end if self.group_snd then self.can_play_group_sound = thread:r_bool() end --alun_utils.debug_write("npc_sound:load AFTER 2") -- set_save_marker(thread, "load", true, "npc_sound") end function npc_sound:save_npc(thread, npc_id) --alun_utils.debug_write("npc_sound:save_npc BEFORE") if self.dont_save then --alun_utils.debug_write("npc_sound:save_npc AFTER 1") return end -- set_save_marker(thread, "save", false, "npc_sound_save_npc") if not self.group_snd then thread:w_bool(self.can_play_sound[npc_id] == true) end --alun_utils.debug_write("npc_sound:save_npc AFTER 2") -- set_save_marker(thread, "save", true, "npc_sound_save_npc") end function npc_sound:load_npc(thread, npc_id) --alun_utils.debug_write("npc_sound:load_npc BEFORE") if self.dont_save then --alun_utils.debug_write("npc_sound:load_npc AFTER 1") return end -- set_save_marker(thread, "load", false, "npc_sound_save_npc") if not self.group_snd then self.can_play_sound[npc_id] = thread:r_bool() end --alun_utils.debug_write("npc_sound:load_npc AFTER 2") -- set_save_marker(thread, "load", true, "npc_sound_save_npc") end --'-------------------------------------------------------------------------------------------------------------------- --' Êëàññ "çâóêîâàÿ êîëëåêöèÿ èãðîêà" --'-------------------------------------------------------------------------------------------------------------------- class "actor_sound" function actor_sound:__init(snd_ini, section) self.class_id = "actor_sound" --' Ïàðàìåòðû âû÷èòûâàíèÿ çâóêà self.stereo = snd_ini:r_bool_ex(section,"actor_stereo",false) self.prefix = snd_ini:r_bool_ex(section,"npc_prefix",false) self.path = snd_ini:r_string_ex(section,"path") or "" self.shuffle = snd_ini:r_string_ex(section,"shuffle") or "rnd" self.play_always = snd_ini:r_bool_ex(section,"play_always",false) self.section = section self.played_id = nil if self.prefix then self.path = "characters_voice\\"..self.path end --' Èíòåðâàë ïðîèãðûâàíèÿ çâóêà local interval = parse_names(snd_ini:r_string_ex(section,"idle") or "3,5,100") self.min_idle = tonumber(interval[1]) self.max_idle = tonumber(interval[2]) self.rnd = tonumber(interval[3]) self.sound = {} self.snd_obj = nil self.can_play_sound = true self.faction = snd_ini:r_string_ex(section,"faction") or "" self.point = snd_ini:r_string_ex(section,"point") or "" self.msg = snd_ini:r_string_ex(section,"message") or "" local f = getFS() if f:exist("$game_sounds$",self.path..".ogg") ~= nil then self.sound[1] = self.path else local num = 1 while f:exist("$game_sounds$",self.path..num..".ogg") do self.sound[num] = self.path..num num = num + 1 end end if #self.sound == 0 then abort("There are no sound collection with path: %s", self.path) end end function actor_sound:callback(npc_id) self.played_time = time_global() self.idle_time = math.random(self.min_idle, self.max_idle) * 1000 self.snd_obj = nil self.can_play_sound = true -- get_hud():RemoveCustomStatic("cs_subtitles_actor") -- printf("actor_sound:callback from [%s]", npc_id) local st = db.storage[npc_id] if st.active_scheme == nil then return end if st[st.active_scheme].signals == nil then -- printf("SOUND_THEME: There is no signals in this scheme [%s]", st.active_scheme) return end if self.played_id == #self.sound and self.shuffle ~= "rnd" then --printf("actor_sound:object [%s] signalled 'theme_end' in section [%s]", npc_id, st.active_section) st[st.active_scheme].signals["theme_end"] = true st[st.active_scheme].signals["sound_end"] = true else --printf("actor_sound:object [%s] signalled 'sound_end' in section [%s]", npc_id, st.active_section) st[st.active_scheme].signals["sound_end"] = true end end function actor_sound:is_playing () if(self.snd_obj~=nil) then return self.snd_obj:playing() else return false end end function actor_sound:play(npc, faction, point, sound) --printf("PLAY ACTOR SOUND") if (self.can_play_sound == false) then return false end if self.played_time ~= nil and time_global() - self.played_time < self.idle_time then return false end self.played_time = nil self.played_id = self:select_next_sound() if self.played_id == -1 then return false end local snd = self.sound[self.played_id] if not (snd) then printf("sound_theme.actor_sound:play() snd is nil! %s",sound) return end self.snd_obj = sound_object(snd) self.snd_obj.volume = 0.8 self.snd_obj:play_at_pos(db.actor, vector():set(0,0,0), 0, sound_object.s2d) self.snd_obj.volume = 0.8 self.can_play_sound = false local sender, sname if type(npc) ~= "userdata" then sender = db.actor else sender = npc sname = point end if not closecaption.sound(snd, self.snd_obj:length(), sender, faction, sname, 0) then news_manager.send_sound(nil, faction, point, snd) end return true end function actor_sound:reset(npc_id) self.played_time = nil self.played_id = nil end function actor_sound:select_next_sound() local sound_table_size = #self.sound if self.shuffle == "rnd" then if sound_table_size == 1 then return 1 end if self.played_id ~= nil then local played_id = math.random(1,sound_table_size - 1) if played_id >= self.played_id then return played_id + 1 end return played_id end return math.random(1,sound_table_size) end if self.shuffle == "seq" then if self.played_id == -1 then return -1 end if self.played_id == nil then return 1 end if self.played_id < sound_table_size then return self.played_id + 1 end return -1 end if self.shuffle == "loop" then if self.played_id == nil then return 1 end if self.played_id < sound_table_size then return self.played_id + 1 end return 1 end end function actor_sound:stop() if self.snd_obj ~= nil then self.snd_obj:stop() end end function actor_sound:save(thread) -- set_save_marker(thread, "save", false, "actor_sound") alun_utils.w_stpk(thread,"stringZ",tostring(self.played_id),"actor_sound:save") -- set_save_marker(thread, "save", true, "actor_sound") end function actor_sound:load(thread) -- set_save_marker(thread, "load", false, "actor_sound") local id = thread:r_stringZ() if(id~="nil") then self.played_id = tonumber(id) else self.played_id = nil end -- set_save_marker(thread, "load", true, "actor_sound") end function actor_sound:save_npc(thread) end function actor_sound:load_npc(thread) end function actor_sound:save_state(m_data) if (self.played_id) then m_data[self.section] = empty_table(m_data[self.section]) m_data[self.section].played_id = self.played_id end end function actor_sound:load_state(m_data) if not (m_data[self.section]) then return end self.played_id = m_data[self.section].played_id end --'-------------------------------------------------------------------------------------------------------------------- --' Êëàññ "çâóêîâàÿ êîëëåêöèÿ îáúåêòà" --'-------------------------------------------------------------------------------------------------------------------- class "object_sound" function object_sound:__init(snd_ini, section) self.class_id = "object_sound" --' Ïàðàìåòðû âû÷èòûâàíèÿ çâóêà self.path = snd_ini:r_string_ex(section,"path") or "" self.shuffle = snd_ini:r_string_ex(section,"shuffle") or "rnd" --' Èíòåðâàë ïðîèãðûâàíèÿ çâóêà local interval = parse_names(snd_ini:r_string_ex(section,"idle") or "3,5,100") self.min_idle = tonumber(interval[1]) self.max_idle = tonumber(interval[2]) self.rnd = tonumber(interval[3]) self.sound = {} self.snd_obj = nil self.can_play_sound = {} self.section = section self.played_id = nil self.faction = snd_ini:r_string_ex(section,"faction") or "" self.point = snd_ini:r_string_ex(section,"point") or "" self.msg = snd_ini:r_string_ex(section,"message") or "" local f = getFS() if f:exist("$game_sounds$",self.path..".ogg") ~= nil then self.sound[1] = self.path else local num = 1 while f:exist("$game_sounds$",self.path..num..".ogg") do self.sound[num] = self.path..num num = num + 1 end end if #self.sound == 0 then abort("There are no sound collection with path: %s", self.path) end end function object_sound:callback(npc_id) if not (self.cooldown) then self.cooldown = {} end if not (self.cooldown[npc_id]) then self.cooldown[npc_id] = time_global() + math.random(self.min_idle, self.max_idle) * 1000 end self.snd_obj = nil self.can_play_sound[npc_id] = true -- printf("object_sound:callback for object !!!!!!!!") -- get_hud():RemoveCustomStatic("cs_subtitles_object") local st = db.storage[npc_id] if not (st) then printf("object_sound:callback st is nil! how?") return end --printf("START object_sound:callback() %s scheme=%s st=%s signals=%s",st.object and st.object:name(),st.active_scheme,st[st.active_scheme],st[st.active_scheme].signals) if st.active_scheme == nil then return end if not (st[st.active_scheme] and st[st.active_scheme].signals) then return end if self.played_id == #self.sound and self.shuffle ~= "rnd" then st[st.active_scheme].signals["theme_end"] = true st[st.active_scheme].signals["sound_end"] = true else st[st.active_scheme].signals["sound_end"] = true end --printf("END object_sound:callback() %s",st.object and st.object:name()) end function object_sound:is_playing () if(self.snd_obj~=nil) then return self.snd_obj:playing() else return false end end function object_sound:play(obj_id, faction, point,sound) local obj = db.storage[obj_id] and db.storage[obj_id].object -- or level.object_by_id(obj_id) if obj == nil then return false end --printf("START object_sound:play() sound=%s %s[%s] can_play=%s",sound,obj:name(),obj_id,self.can_play_sound[obj_id] ~= false and true) if (self.can_play_sound[obj_id] == false) then return false end if (self.cooldown) then if (self.cooldown[obj_id] and time_global() < self.cooldown[obj_id]) then return false end self.cooldown[obj_id] = nil end self.played_id = self:select_next_sound() if self.played_id == -1 then return false end --printf("object played_id = %s", self.played_id) local snd = self.sound[self.played_id] if not (snd) then printf("sound_theme.object_sound:play() snd is nil! %s",sound) return end if snd and obj:position():distance_to_sqr(db.actor:position()) >= 5 and getFS():exist("$game_sounds$", snd.."_pda.ogg") ~= nil then self.pda_snd_obj = sound_object(snd.."_pda") self.pda_snd_obj:play_at_pos(db.actor, vector():set(0,0,0), 0, sound_object.s2d) self.pda_snd_obj.volume = 0.8 end self.snd_obj = sound_object(snd) self.snd_obj:play_at_pos(obj, obj:position(), 0, sound_object.s3d) self.can_play_sound[obj_id] = false if not closecaption.sound(snd, self.snd_obj:length(), obj, faction, point, 0) then news_manager.send_sound(nil, faction, point, snd) end --printf("END object_sound:play() sound=%s %s[%s]",sound,obj:name(),obj_id) return true end function object_sound:select_next_sound() local sound_table_size = #self.sound if self.shuffle == "rnd" then return math.random(1,sound_table_size) elseif self.shuffle == "seq" then if (self.played_id == nil) then return 1 elseif (self.played_id == -1) then return -1 elseif (self.played_id < sound_table_size) then return self.played_id + 1 else return -1 end elseif self.shuffle == "loop" then if self.played_id == nil then return 1 elseif self.played_id < sound_table_size then return self.played_id + 1 end return 1 end end function object_sound:stop() if self.snd_obj ~= nil then self.snd_obj:stop() end if self.pda_snd_obj ~= nil and self.pda_snd_obj:playing() then self.pda_snd_obj:stop() self.pda_snd_obj = nil end end function object_sound:save(thread) -- set_save_marker(thread, "save", false, "object_sound") alun_utils.w_stpk(thread,"stringZ",tostring(self.played_id),"object_sound:save") -- set_save_marker(thread, "save", true, "object_sound") end function object_sound:load(thread) -- set_save_marker(thread, "load", false, "object_sound") local id = thread:r_stringZ() if(id~="nil") then self.played_id = tonumber(id) else self.played_id = nil end -- set_save_marker(thread, "load", true, "object_sound") end function object_sound:save_npc(thread) end function object_sound:load_npc(thread) end function object_sound:save_state(m_data) if (self.played_id) then m_data[self.section] = empty_table(m_data[self.section]) m_data[self.section].played_id = self.played_id end end function object_sound:load_state(m_data) if not (m_data[self.section]) then return end self.played_id = m_data[self.section].played_id end --'-------------------------------------------------------------------------------------------------------------------- --' Êëàññ "çàöèêëåííûé çâóê" --'-------------------------------------------------------------------------------------------------------------------- class "looped_sound" function looped_sound:__init(snd_ini, section) self.class_id = "looped_sound" --' Ïàðàìåòðû âû÷èòûâàíèÿ çâóêà self.path = snd_ini:r_string_ex(section,"path") or "" self.sound = nil self.snd_obj = nil self.section = section local f = getFS() if f:exist("$game_sounds$",self.path..".ogg") ~= nil then self.sound = self.path end if self.sound == nil then abort("There are no looped sound with path: %s", self.path) end end function looped_sound:is_playing () if(self.snd_obj~=nil) then return self.snd_obj:playing() else return false end end function looped_sound:stop () if self.snd_obj ~= nil then self.snd_obj:stop() end end function looped_sound:set_volume (level) self.snd_obj.volume = level end function looped_sound:play(obj_id) local obj = db.storage[obj_id].object if obj == nil then return end self.snd_obj = self.snd_obj or sound_object(self.sound) self.snd_obj:play_at_pos(obj, obj:position(), 0, sound_object.s3d + sound_object.looped) return true end function looped_sound:save(thread) -- set_save_marker(thread, "save", false, "looped_sound") -- set_save_marker(thread, "save", true, "looped_sound") end function looped_sound:load(thread) -- set_save_marker(thread, "load", false, "looped_sound") -- set_save_marker(thread, "load", true, "looped_sound") end function looped_sound:save_npc(thread) end function looped_sound:load_npc(thread) end function looped_sound:save_state(m_data) end function looped_sound:load_state(m_data) end --'-------------------------------------------------------------------------------------------------------------------- --' Çàãðóçêà çâóêîâ --'-------------------------------------------------------------------------------------------------------------------- function load_sound() local snd_ini = ini_file("misc\\sound\\script_sound.ltx") local function itr(section) local level_list = snd_ini:line_exist(section,"levels") and alun_utils.parse_list(snd_ini,section,"levels",true) or nil if (level_list == nil or level_list[level.name()]) then local type = snd_ini:r_string_ex(section,"type") or "" if type == "npc" then theme[section] = theme[section] or npc_sound(snd_ini, section) elseif type == "actor" then theme[section] = theme[section] or actor_sound(snd_ini, section) elseif type == "3d" then theme[section] = theme[section] or object_sound(snd_ini, section) elseif type == "looped" then theme[section] = theme[section] or looped_sound(snd_ini, section) end end end snd_ini:section_for_each(itr) end --' Çàãðóçêà çâóêîâ ÍÏÑ function init_npc_sound(npc) for k,v in pairs(theme) do if v.init_npc then --printf("checking %s for %s (%s)", v.section, npc:name(), character_community(npc)) if (v.avail_communities == nil or v.avail_communities[character_community(npc)]) then if (v.story_ids == nil or v.story_ids[story_objects.get_story_objects_registry():get_story_id(npc:id()) or ""]) then v:init_npc(npc) end end end end end