-- I was to lazy to store actual version (like 1.2) in table local dub_version = 5 -- In case addon loaded multiple times (when bundled with character addons, for -- instance) -- -- On second thought, maybe bundling such addons with characters is a bad idea, -- if you don't want dependency hell... -- -- On third thought, loading this lua before all addons that may contain older -- dub version will surely solve these problems :D if dub_loaded then -- Previous 2 versions used boolean to indicate that dub is loaded, so -- i'll replace it with number so lua don't complain about "attempt to -- compare boolean with number" -- -- ... And yes, i know that 'if bool == true' is stupid, but in this -- specific case that can be a number, so thats same as checking -- 'if type(dub_loaded) == "boolean"' if dub_loaded == true then rawset(_G, "dub_loaded", 1) end -- Not sure if i/someone else will update this addon that much that version -- missmatch would actually lead to problems, but its better to warn about -- that than just silently ignore if dub_loaded < dub_version then error("Older version of KL_CharDub loaded, this may lead to problems") end return end rawset(_G, "dub_loaded", dub_version) local dub = {} local skinsounds = { SKSKWIN, SKSKLOSE, SKSKPAN1, SKSKPAN2, SKSKATK1, SKSKATK2, SKSKBST1, SKSKBST2, SKSKSLOW, SKSKHITM, SKSKPOWR, } local config = "dub.cfg" local config_loaded = false local config_tosave = false local dub_enabled = CV_RegisterVar({ name = "dub_enabled", defaultvalue = "On", possiblevalue = CV_OnOff, }) local dub_soundoffhack = CV_RegisterVar({ name = "dub_soundoffhack", defaultvalue = "On", possiblevalue = CV_OnOff, }) local dub_debug = CV_RegisterVar({ name = "dub_debug", defaultvalue = "Off", possiblevalue = CV_OnOff, }) local function dprint(...) if dub_debug.value then print(...) end end -- Hopefully that will be added one day local S_StopSoundByNum = rawget(_G, "S_StopSoundByNum") if S_StopSoundByNum == nil then S_StopSoundByNum = function() COM_BufInsertText(consoleplayer, "sounds Off; sounds On") end end local function freeslotDubSfx(soundid, soundname) local soundnum = _G[soundname] or freeslot(soundname) if soundid == SKSKGLOAT then S_Sfx[soundnum].flags = S_Sfx[soundnum].flags | SF_X8AWAYSOUND | SF_NOINTERRUPT end return soundnum end local function freeslotDubEntry(soundid, entry) if type(entry) == "string" then return freeslotDubSfx(soundid, entry) else local sounds = {} for _, soundname in ipairs(entry) do table.insert(sounds, freeslotDubSfx(soundid, soundname)) end return sounds end end local function pickDubEntry(entry, random) if type(entry) == "number" then return entry else return entry[random % #entry + 1] end end local function XS_PlayingGlobally(sfx) if not S_IdPlaying(sfx) then return false end for player in players.iterate do if player.mo and S_SoundPlaying(player.mo, sfx) then return false end end return true end local function loadConfig() if config_loaded or not consoleplayer then return end local file = io.open(config, "r") -- No config :( if not file then config_loaded = true return end for line in file:lines() do COM_BufInsertText(consoleplayer, line) end config_loaded = true file:close() end local function saveConfig() if not consoleplayer then return end config_tosave = false local file = io.open(config, "w") if not file then return end file:write("dub_enabled "..dub_enabled.string..'\n') file:write("dub_soundoffhack "..dub_soundoffhack.string..'\n') if consoleplayer.dub_choice ~= nil then for skin, choice in pairs(consoleplayer.dub_choice) do file:write("dub "..skin.." "..choice..'\n') end end file:close() end COM_AddCommand("dub", function(player, skin, choice) if player.dub_choice == nil then player.dub_choice = {} end if skin == nil then CONS_Printf(player, "Usage: \129dub\128 <\130skin\128> [\131dub\128]") CONS_Printf(player, "Check \129dub_list\128 for all available dubs") elseif choice == nil then if dub[skin] == nil then CONS_Printf(player, "\134This skin does not have any custom dub") return end local skin_dubs = {"default"} for dubname, _ in pairs(dub[skin]) do table.insert(skin_dubs, dubname) end CONS_Printf(player, "available dubs for skin \130"..skin.."\128: \131"..table.concat(skin_dubs, ", ")) else if dub[skin] == nil then CONS_Printf(player, "\134This skin does not have any custom dub") return end if choice == "default" then player.dub_choice[skin] = nil CONS_Printf(player, "Custom dub for skin \130"..skin.." \133disabled") config_tosave = config_loaded -- To not cause config to be saved immideately after loading return end if dub[skin][choice] == nil then CONS_Printf(player, "Dub \131"..choice.." \133does not exist\128 for skin \130"..skin) return end player.dub_choice[skin] = choice CONS_Printf(player, "Set dub \131"..choice.."\128 for skin \130"..skin) config_tosave = config_loaded end end) COM_AddCommand("dub_list", function(player) local dubs = {"Skins with custom dubs:"} for skin, _ in pairs(dub) do local skin_dubs = {} for dubname, _ in pairs(dub[skin]) do table.insert(skin_dubs, dubname) end table.insert(dubs, "\130"..skin.."\128: \131"..table.concat(skin_dubs, ", ")) end if #dubs == 1 then CONS_Printf(player, "\134There are no dubs yet...") else CONS_Printf(player, table.concat(dubs, "\n")) end end) local function DUB_GetSkinSound(player, skinsound) if player.mo == nil then return end local random = P_RandomFixed() local psounds = skins[player.mo.skin].soundsid if not dub_enabled.value or player.dub_choice == nil or player.dub_choice[player.mo.skin] == nil then return psounds[skinsound] end local pdub = dub[player.mo.skin][player.dub_choice[player.mo.skin]] if pdub == nil then return psounds[skinsound] end return pickDubEntry(pdub[skinsound], random) or psounds[skinsound] end local function DUB_GetWinSound(player) return DUB_GetSkinSound(player, SKSKWIN) end local function DUB_GetLoseSound(player) return DUB_GetSkinSound(player, SKSKLOSE) end local function DUB_GetBoostSound(player) local skinsound = SKSKBST1 + P_RandomKey(2) return DUB_GetSkinSound(player, skinsound) end local function DUB_GetHurtSound(player) local skinsound = SKSKPAN1 + P_RandomKey(2) return DUB_GetSkinSound(player, skinsound) end local function DUB_GetAttackSound(player) local skinsound = SKSKATK1 + P_RandomKey(2) return DUB_GetSkinSound(player, skinsound) end local function DUB_GetHitEmSound(player) return DUB_GetSkinSound(player, SKSKHITM) end local function DUB_GetGloatSound(player) return DUB_GetSkinSound(player, SKSKPOWR) end local function DUB_RegisterDub(skin, dubname, dubvoices) if dubname == "default" then error("dub name 'default' is reserved") end skin = skin:lower() if dub[skin] == nil then dub[skin] = {} end dub[skin][dubname] = {} for soundid, entry in pairs(dubvoices) do dub[skin][dubname][soundid] = freeslotDubEntry(soundid, entry) end end rawset(_G, "DUB_GetSkinSound", DUB_GetSkinSound) rawset(_G, "DUB_GetWinSound", DUB_GetWinSound) rawset(_G, "DUB_GetLoseSound", DUB_GetLoseSound) rawset(_G, "DUB_GetBoostSound", DUB_GetBoostSound) rawset(_G, "DUB_GetHurtSound", DUB_GetHurtSound) rawset(_G, "DUB_GetAttackSound", DUB_GetAttackSound) rawset(_G, "DUB_GetGloatSound", DUB_GetGloatSound) rawset(_G, "DUB_GetHitEmSound", DUB_GetHitEmSound) rawset(_G, "DUB_RegisterDub", DUB_RegisterDub) -- Fuck you CV_CALL local saved_dub_enabled = dub_enabled.value local saved_dub_soundoffhack = dub_soundoffhack.value addHook("ThinkFrame", function() if not config_loaded then loadConfig() end if saved_dub_enabled ~= dub_enabled.value then config_tosave = true end if saved_dub_soundoffhack ~= dub_soundoffhack.value then config_tosave = true end saved_dub_enabled = dub_enabled.value saved_dub_soundoffhack = dub_soundoffhack.value if config_tosave then saveConfig() end end) addHook("ThinkFrame", function() -- Always roll random for synch reasons local random = P_RandomFixed() if not dub_enabled.value then return end for player in players.iterate do if player.mo ~= nil and player.mo.valid and player.dub_choice ~= nil and player.dub_choice[player.mo.skin] ~= nil then local pdub = dub[player.mo.skin][player.dub_choice[player.mo.skin]] local psounds = skins[player.mo.skin].soundsid for _, sound in ipairs(skinsounds) do if pdub[sound] ~= nil then local dubsound = pickDubEntry(pdub[sound], random) if S_SoundPlaying(player.mo, psounds[sound]) then local debugstr = "Stop sound '"..sfxinfo[psounds[sound]].name.."' for skin '"..player.mo.skin.."'" S_StopSoundByID(player.mo, psounds[sound]) if sound ~= SKSKPOWR or not S_SoundPlaying(player.mo, dubsound) then S_StartSound(player.mo, dubsound) debugstr = debugstr..", replace it with '"..sfxinfo[dubsound].name.."'" end dprint(debugstr) end end end end end if dub_soundoffhack.value then for i = 0, splitscreen do local displayplayer = displayplayers[i] if displayplayer and displayplayer.mo ~= nil and displayplayer.mo.valid and displayplayer.dub_choice ~= nil and displayplayer.dub_choice[displayplayer.mo.skin] ~= nil then local pdub = dub[displayplayer.mo.skin][displayplayer.dub_choice[displayplayer.mo.skin]] local psounds = skins[displayplayer.mo.skin].soundsid for _, sound in ipairs(skinsounds) do if pdub[sound] ~= nil then local dubsound = pickDubEntry(pdub[sound], random) if XS_PlayingGlobally(psounds[sound]) then S_StopSoundByNum(psounds[sound]) S_StartSound(nil, dubsound, displayplayer) dprint("Globally stop sound '"..sfxinfo[psounds[sound]].name .."' for skin '"..displayplayer.mo.skin.."', replace it with '" ..sfxinfo[dubsound].name.."'") end end end end end end end)