---------------------------------------------------------------------------------------------------- -- Szinkronfeliratok ---------------------------------------------------------------------------------------------------- -- Készítette: ·f·i· csoport -- Mr. Fusion (mrf_of_vsb@hotmail.com) -- The Sweet Little 16-bit (tsl16b@freemail.hu) -- edited: Alundaio 11/23/2013 ---------------------------------------------------------------------------------------------------- -- caption type override table -- snd_id = {cc_type, showtime, sendericon, faction, name, distance_limit} -- cc_type = -1: incoming message, -2: memo, -3: sending message, -4: (none) local ini local function opt_menu_on_accept(menu,opt,con) local tabs = {["none"] = 0, ["storyonly"] = 1, ["all"] = 2} local rcap = tabs[menu.tab_captioning:GetActiveId()] ini:w_value("closecaption","cc_npc",(rcap > 0)) ini:w_value("closecaption","cc_vrb",(rcap > 1)) ini:w_value("closecaption","cc_icc",menu.check_closedcaptions:GetCheck() and true) ini:save() end local function opt_menu_on_init(menu) local xml = menu.xml menu.cap_captioning = xml:InitStatic("tab_sound:cap_captioning", menu.dlg_sound) menu.tab_captioning = xml:InitTab("tab_sound:tab_captioning", menu.dlg_sound) menu:Register(menu.tab_captioning, "tab_captioning") menu.cap_closedcaptions = xml:InitStatic("tab_sound:cap_check_closed_captions", menu.dlg_sound) menu.check_closedcaptions = xml:InitCheck("tab_sound:check_closed_captions", menu.dlg_sound) local function OnCCOptionChange() local tabs = {["none"] = 0, ["storyonly"] = 1, ["all"] = 2} menu.check_closedcaptions:Enable(tabs[menu.tab_captioning:GetActiveId()] > 0) end menu:AddCallback("tab_captioning", ui_events.TAB_CHANGED, OnCCOptionChange, self) end local function opt_menu_on_set_values(menu,opt) local tabs = {"none", "storyonly", "all"} local cc_npc = ini:r_value("closecaption","cc_npc",1,false) local cc_vrb = ini:r_value("closecaption","cc_vrb",1,false) local cc_icc = ini:r_value("closecaption","cc_icc",1,false) menu.tab_captioning:SetActiveTab(tabs[(cc_npc and 1 or 0) * (cc_vrb and 2 or 1) + 1]) menu.check_closedcaptions:SetCheck(cc_icc == true) tabs = {["none"] = 0, ["storyonly"] = 1, ["all"] = 2} menu.check_closedcaptions:Enable(tabs[menu.tab_captioning:GetActiveId()] > 0) end -- called directly from axr_main function main_menu_on_quit() UnregisterScriptCallback("opt_menu_on_set_values",opt_menu_on_set_values) UnregisterScriptCallback("opt_menu_on_init",opt_menu_on_init) UnregisterScriptCallback("opt_menu_on_accept",opt_menu_on_accept) end -- called directly from axr_main function main_menu_on_init() ini = axr_main.config if not (ini:section_exist("closecaption")) then ini:w_value("closecaption","cc_npc",true) -- Display subtitles of scenario sounds in-game ini:w_value("closecaption","cc_vrb",false) -- Display more subtitles of NPC sentences in-game ini:w_value("closecaption","cc_icc",false) -- Display closed captions of sound effects in-game ini:save() end RegisterScriptCallback("opt_menu_on_set_values",opt_menu_on_set_values) RegisterScriptCallback("opt_menu_on_init",opt_menu_on_init) RegisterScriptCallback("opt_menu_on_accept",opt_menu_on_accept) end local snd_ids = { ["cc_effect-device-door_start"] = {9, 1500, nil, nil, nil, 20}, ["cc_effect-device-door_closing"] = {9, 1500, nil, nil, nil, 20}, ["cc_effect-device-door_stop"] = {9, 1500, nil, nil, nil, 20}, ["cc_effect-device-metal_small_open"] = {9, 1500, nil, nil, nil, 15}, ["cc_effect-device-power_switch"] = {9, 1500}, ["cc_effect-device-radio_call"] = {9, 2500}, ["cc_effect-device-wood_large_open"] = {9, 1500, nil, nil, nil, 10}, ["cc_effect-device-wood_large_close_start"] = {9, 1500, nil, nil, nil, 10}, ["cc_effect-ambient-blowout_begin"] = {9, 2500}, ["cc_effect-anomaly-steam_blowout"] = {9, nil, nil, nil, nil, 25}, ["cc_effect-weapons-n_desert_eagle_shot"] = {9, 1000, nil, nil, nil, 30}, -- scene triggered at around 25m ["cc_effect-music-guitar_"] = {9, 3500, nil, nil, nil, 15}, ["cc_effect-music-harmonica_"] = {9, 3500, nil, nil, nil, 15}, ["cc_effect-laughter_"] = {9, 2500, nil, nil, nil, 15}, ["cc_effect-ambient-zaton-zat_b38_bloodsucker_roar"] = {6, 3500}, ["cc_effect-ambient-zaton-zat_b38_electro_box_door"] = {9, 1500}, ["cc_effect-ambient-zaton-zat_b38_electro_box_switch"] = {9, 1500}, ["cc_effect-ambient-zaton-zat_b38_elevator_door"] = {9}, ["cc_effect-ambient-zaton-zat_b38_cop_elevator_landing"] = {9}, ["cc_effect-ambient-zaton-zat_b38_lock_sound"] = {9}, ["cc_effect-ambient-zaton-zat_b57_bloodsucker_roar"] = {6, 3500}, ["cc_effect-ambient-jupiter-jup_b16_oasis_noise"] = {9, 1250}, ["cc_effect-ambient-jupiter-jup_b41_steam"] = {9}, ["cc_effect-ambient-jupiter-jup_b46_spatial_bubble_idle"] = {9}, ["cc_effect-ambient-jupiter-jup_b46_spatial_bubble_rupture"] = {9}, ["cc_effect-ambient-jupiter-jup_b219_generator_start"] = {9, 2500}, ["cc_effect-ambient-jupiter-jup_b219_underpass_opening"] = {9, 4000}, ["cc_effect-ambient-underpass-pas_b400_elevator_off"] = {9}, ["cc_effect-ambient-pripyat-pri_a25_blow_up_door_peep"] = {9, 4000}, ["cc_effect-ambient-pripyat-pri_a25_freezer_knock"] = {9, 1800, nil, nil, nil, 14}, -- ***** Zaton ***** --- Skadovsk announcements ["zat_a2_base_megaphone_1"] = {8}, ["zat_a2_base_megaphone_2"] = {8}, ["zat_a2_base_megaphone_3"] = {8}, ["zat_a2_stalker_barmen_surge_phase_1"] = {-1, nil, "ui_inGame2_Boroda", "stalker", "zat_a2_stalker_barmen_name"}, -- actor override ["zat_a2_stalker_barmen_surge_phase_2"] = {-1, nil, "ui_inGame2_Boroda", "stalker", "zat_a2_stalker_barmen_name"}, -- actor override ["zat_a2_stalker_barmen_after_surge"] = {-1, nil, "ui_inGame2_Boroda", "stalker", "zat_a2_stalker_barmen_name"}, -- actor override --- Order ready at Nimble (actor override) ["zat_b51_stalker_nimble_order"] = {-1, nil, "ui_inGame2_neutral_1", "stalker", "st_zat_a2_stalker_nimble_name"}, -- ***** Jupiter ***** --- Janov announcements ["jup_a6_base_megaphone_1"] = {8}, ["jup_a6_base_megaphone_2"] = {8}, ["jup_a6_base_megaphone_3"] = {8}, ["jup_a6_stalker_medik_phase_1"] = {-1, nil, "ui_inGame2_Kostoprav", "stalker", "jup_a6_stalker_medik"}, -- actor override ["jup_a6_stalker_medik_phase_2"] = {-1, nil, "ui_inGame2_Kostoprav", "stalker", "jup_a6_stalker_medik"}, -- actor override ["jup_a6_stalker_medik_after_surge"] = {-1, nil, "ui_inGame2_Kostoprav", "stalker", "jup_a6_stalker_medik"}, -- actor override --- Sci bunker announcements ["jup_b41_bunker_megaphone_1"] = {8}, ["jup_b41_bunker_megaphone_2"] = {8}, ["jup_b41_bunker_megaphone_3"] = {8}, --- Anomaly measurement sequence (actor override) ["jup_b6_stalker_1_first_measurement_in_progress"] = {-1, 3000, "ui_inGame2_neutral_2", "stalker", ""}, ["jup_b6_stalker_1_first_measurement_done"] = {-1, 5000, "ui_inGame2_neutral_2", "stalker", ""}, ["jup_b6_stalker_1_measurements_done"] = {-1, 3500, "ui_inGame2_neutral_2", "stalker", ""}, -- ***** Underpass ***** -- ***** Pripyat ***** --- Army base announcements ["pri_a17_kovalsky_surge_phase_1"] = {-1, nil, "ui_inGame2_Kovalskiy", "army", "pri_a17_military_colonel_kovalski_name"}, -- actor override ["pri_a17_kovalsky_surge_phase_2"] = {-1, nil, "ui_inGame2_Kovalskiy", "army", "pri_a17_military_colonel_kovalski_name"}, -- actor override ["pri_a17_kovalsky_after_surge"] = {-1, nil, "ui_inGame2_Kovalskiy", "army", "pri_a17_military_colonel_kovalski_name"}, -- actor override } local snd_groups = { ["cc_fight"] = {6, 1250, nil, nil, nil, 50}, ["cc_wounded"] = {9, 2500, nil, nil, nil, 35}, } local last_caption_category = "" local longest_caption_ends = 0 local delayed_cc = {} function sound(_sound, showtime, sender, sender_faction, sender_id, delay_sound) if not (ini) then ini = axr_main and axr_main.config if not (ini) then return end end local cc_npc = ini:r_value("closecaption","cc_npc",1,false) local cc_vrb = ini:r_value("closecaption","cc_vrb",1,false) local cc_icc = ini:r_value("closecaption","cc_icc",1,false) if cc_npc == true then local current_time = time_global() local split_sound_string = {} local i = 1 for w in string.gmatch(_sound, "[%w_]+") do split_sound_string[i] = w i = i + 1 end local cc_id, cc_category if split_sound_string[1] == "characters_voice" then if split_sound_string[2] == "scenario" then if not cc_vrb then if string.match(split_sound_string[4], "_greeting_%d") or string.match(split_sound_string[4], "_farewell_") then return true end end cc_category = "cc_scenario" cc_id = split_sound_string[4] elseif string.match(split_sound_string[2], "human_0") then if split_sound_string[4] == "states" then if split_sound_string[5] == "meet" then if (current_time > longest_caption_ends) or (last_caption_category ~= "cc_scenario") then if string.match(split_sound_string[6], "meet_use") then if #delayed_cc >= 1 then if delay_sound < 0 then delay_sound = -delay_sound - 501 end else local gt = time_global() + 500 table.insert(delayed_cc, {_sound, showtime, sender, sender_faction, sender_id, -delay_sound - 1, dt = gt}) RegisterScriptCallback("actor_on_update", on_actor_update_cc) return true end else if not cc_vrb then return true end end if db.actor:is_talking() then return true end cc_category = "cc_generic" cc_id = cc_category .. "-" .. split_sound_string[3] .. "-" .. split_sound_string[6] else return true end else return false end elseif split_sound_string[4] == "reactions" then if split_sound_string[5] == "story" then if cc_icc then cc_category = "cc_effect" cc_id = cc_category .. "-" .. split_sound_string[6] cc_id = string.gsub(cc_id, "_%d+$", "_") else return true end else return false end elseif split_sound_string[4] == "help" then if split_sound_string[5] == "wounded_heavy" then if cc_icc then cc_category = "cc_wounded" cc_id = cc_category .. "-" .. split_sound_string[3] .. "-" .. "help" else return true end else return false end elseif split_sound_string[4] == "fight" then if split_sound_string[5] == "attack" then if cc_icc then cc_category = "cc_fight" cc_id = cc_category .. "-" .. split_sound_string[3] .. "-" .. "attack" else return true end else return false end else -- add any special "human_0x" cases here if string.match(split_sound_string[#split_sound_string], "pas_b400_") then cc_category = "cc_scenario" cc_id = split_sound_string[#split_sound_string] else return false end end else return false end elseif split_sound_string[1] == "device" or split_sound_string[1] == "ambient" then if cc_icc then cc_category = "cc_effect" cc_id = cc_category for i = 1, #split_sound_string do cc_id = cc_id .. "-" .. split_sound_string[i] end else return true end elseif split_sound_string[1] == "music" then if cc_icc then cc_category = "cc_effect" cc_id = cc_category for i = 1, #split_sound_string do cc_id = cc_id .. "-" .. split_sound_string[i] end cc_id = string.gsub(cc_id, "_%d+$", "_") else return true end else -- add any special full soundpath match cases here if _sound == "anomaly\\steam_blowout" then if cc_icc then cc_category = "cc_effect" cc_id = cc_category .. "-anomaly-steam_blowout" else return true end elseif _sound == "weapons\\n_desert_eagle_shot" then if cc_icc then cc_category = "cc_effect" cc_id = cc_category .. "-weapons-n_desert_eagle_shot" else return true end else return false end end local cc_text = game.translate_string(cc_id) if cc_text == cc_id then cc_text = "[...]" -- if (DEV_DEBUG) then -- printf("Missing CC: %s",cc_id) -- end else local distance_limit = 10001 local cc_type if sender_faction == "object" then cc_type = 9 else cc_type = -1 end if not showtime then showtime = 5000 elseif showtime < 2000 then showtime = 2000 end if not delay_sound then delay_sound = 0 end local override if snd_ids[cc_id] then override = snd_ids[cc_id] elseif snd_groups[cc_category] then override = snd_groups[cc_category] end if override then if override[1] then cc_type = override[1] end if override[2] then showtime = override[2] end if override[3] then sender = override[3] end if override[4] then sender_faction = override[4] end if override[5] then sender_id = override[5] end if override[6] then distance_limit = override[6] end end if cc_type == "t" then cc_display_tutorial(cc_id) return true elseif cc_type > 0 then if type(sender) == "userdata" then if distance_between_safe(sender, db.actor) < distance_limit then cc_display_normal(cc_id, showtime, cc_type) end else cc_display_normal(cc_id, showtime, cc_type) end return true else if type(sender) == "userdata" then local distance = distance_between_safe(sender, db.actor) if distance < distance_limit then if cc_type == -1 and distance < 12 then cc_type = -4 end else return true end end cc_display_radio(sender, sender_faction, sender_id, showtime, cc_text, delay_sound, cc_type) last_caption_category = cc_category if current_time + showtime + delay_sound + 1000 > longest_caption_ends then longest_caption_ends = current_time + showtime + delay_sound + 1000 end return true end end end end local colors = { [1] = "closecaption_1", [2] = "closecaption_2", [3] = "closecaption_3", [4] = "closecaption_4", [5] = "cs_subtitles_npc", [6] = "closecaption_6", [7] = "cs_subtitles_actor", [8] = "cs_subtitles_object", [9] = "closecaption_9", [10] = "cs_subtitles", } local cc_on = {0, 0, 0, 0} function cc_display_normal(cc_id, showtime, color) local time_now = time_global() local time_ccend = (time_now + showtime + 300) / 1000 if color == 0 then for i,v in ipairs(cc_on) do if v <= time_now then color = i break end end if color == 0 then color = 1 end end local tmpl = colors[color] local tmpls = tmpl .. "_shadow" local hud = get_hud() if (hud) then hud:AddCustomStatic(tmpls, true) local custom_static_shadow = hud:GetCustomStatic(tmpls) hud:AddCustomStatic(tmpl, true) local custom_static = hud:GetCustomStatic(tmpl) if custom_static_shadow ~= nil then custom_static_shadow:wnd():TextControl():SetTextST(cc_id) custom_static_shadow.m_endTime = time_ccend end if custom_static ~= nil then custom_static:wnd():TextControl():SetTextST(cc_id) custom_static.m_endTime = time_ccend end if color <= #cc_on then cc_on[color] = time_ccend * 1000 end end end local msgtypes = {"st_tip", "st_memo", "st_sending_msg", ""} function cc_display_radio(sender, sender_faction, sender_id, showtime, cc_text, delay_sound, cc_type) local msg_type = msgtypes[-cc_type] local texture, faction, name if (type(sender) == "userdata" and IsStalker(sender) and sender:id() ~= 0) then texture = sender:character_icon() if sender:profile_name() ~= "actor" then faction = game.translate_string(sender:character_community()) end name = sender:character_name() elseif type(sender) == "table" then texture = string.sub(sender[math.random(1, #sender)], 1) end if sender_faction then faction = game.translate_string(sender_faction) end if sender_id then if sender_id == "!" then name = sender_unidentified() else name = game.translate_string(sender_id) end end local news_caption = "" if msg_type and msg_type ~= "" then news_caption = game.translate_string(msg_type) end if faction and faction ~= "" then if news_caption ~= "" then news_caption = news_caption .. " - " .. faction else news_caption = faction end end if name and name ~= "" then if news_caption ~= "" then news_caption = news_caption .. " - " .. name else news_caption = name end end if news_caption ~= "" then news_caption = news_caption..":" end local clr = "%c[ui_2]" db.actor:give_game_news(news_caption, clr .. cc_text, texture, delay_sound+500, showtime, 1) return true end function cc_display_tutorial(cc_id) local running = game.has_active_tutorial() if running == false then game.start_tutorial(cc_id) end end function read_cc_ini() -------- Read values for closecaptions local cc = "closecaption" local cc_npc, cc_vrb, cc_icc = false, false, false cc_npc = load_variable("cc_npc", 0) if cc_npc == 0 then local ini = ini_file("misc\\closecaption.ltx") cc_npc = ini:r_bool_ex(cc, "cc_ingame_npc",false) cc_vrb = ini:r_bool_ex(cc, "cc_ingame_vrb",false) cc_icc = ini:r_bool_ex(cc, "cc_ingame_cc",false) db.cc_npc = cc_npc db.cc_vrb = cc_vrb db.cc_icc = cc_icc save_variable("cc_icc", cc_icc) save_variable("cc_vrb", cc_icc) save_variable("cc_npc", cc_npc) else cc_vrb = load_variable("cc_vrb", cc_vrb) cc_icc = load_variable("cc_icc", cc_icc) db.cc_npc = cc_npc db.cc_vrb = cc_vrb db.cc_icc = cc_icc end end function on_actor_update_cc() if #delayed_cc >= 1 then if time_global() >= delayed_cc[1].dt then local d = delayed_cc[1] closecaption.sound(d[1], d[2], d[3], d[4], d[5], d[6]) table.remove(delayed_cc, 1) end else UnregisterScriptCallback("actor_on_update", on_actor_update_cc) end end -- Preconditions for SSU communication scene of STALKER: Call Of Pripyat function both_heli_info() return has_alife_info("zat_b101_both_heli_info") and db.cc_npc == true end function not_both_heli_info() return (not has_alife_info("zat_b101_both_heli_info")) and db.cc_npc == true end function cc_npc_disabled() if not (ini) then ini = axr_main and axr_main.config if not (ini) then return end end return ini:r_value("closecaption","cc_npc",1,false) ~= true end function is_cc_npc_enabled() if not (ini) then ini = axr_main and axr_main.config if not (ini) then return end end return ini:r_value("closecaption","cc_npc",1,false) == true end function get_game_version() -- detect real game version local ver = 1600 if dialogs_jupiter.zat_b106_trapper_reward ~= nil then -- v1.6.01 addition local GSver = _G.main_menu.get_main_menu():GetGSVer() ver = tonumber((string.gsub(GSver, "%p", ""))) if (ver == nil) or (ver < 1600) then ver = 1601 end end return ver end function sender_unidentified() local senders = { "", -- a couple of random chars from charset below "st_msgfrom_err1", -- "[sender unknown]" "st_msgfrom_err2", -- "" "st_msgfrom_err3", -- "=?Network failure" "st_msgfrom_err1", -- "[sender unknown]" "", -- a couple of random chars from charset below } msg = senders[math.random(1, #senders)] if msg ~= "" then return game.translate_string(msg) else local length = 7 + math.random(1, 7) local charset = "@AÁBCDEÉFGHIÍJKLMNOÓÖÕPQRSTUÚÜÛVWXYZ" .. "`aábcdeéfghiíjklmnoóöõpqrstuúüûvwxyz" .. [[!"#&'()*+,-./0123456789:;<=>?^_{|}]] .. "~€‚„…‰ŒŽ‘’“”•–—™žŸ¡¢£¥§¨©ª«­®¯°±²³´µ" .. "¶·¸¹º»¼½¾¿ÀÂÃÄÅÆÇÈÊËÌÎÏÐÑÒÔרÙÝÞßàâã" .. "äåæçèêëìîïðñòô÷øùýþÿ" local result = {} for i = 1, length do local r = math.random(1, charset:len()) result[i] = string.sub(charset, r, r) end return table.concat(result) end end -- Code portions from the excellent AMK mod -- function save_variable(variable_name, value) utils.save_var(db.actor, variable_name, value) end function load_variable(variable_name, value_if_not_found) return utils.load_var(db.actor, variable_name, value_if_not_found) end function del_variable(variable_name) if db.storage[db.actor:id()].pstor[variable_name] then db.storage[db.actor:id()].pstor[variable_name] = nil end end ----------------------------------------------