sound: the later-era Sound_ CVar names, which three installed addons already wanted
`GetCVar("Sound_MusicVolume")` answered nil, so `Cinematic/Core.lua:3621` raised inside a
`format` and took the rest of its `PLAYER_LOGIN` handler — the music restore — with it. 2.x
renamed the sound CVars with a `Sound_` prefix and 1.12's names stayed what they are; Cinematic
is a multi-flavour addon and uses the modern spelling at **all 47** of its music sites, which
is the whole of its music-fade feature.
**This is a fix for the install, not a concession to the port.** Three addons already here ask
with the modern spelling and have been reading nil: DoiteAuras' editor and Tmog
(`Sound_MasterVolume`, `Sound_DialogVolume`, `Sound_EnableDialog`), SoftSpoken
(`Sound_EnableAllSound`, `Sound_SFXVolume`, `Sound_EnableSFX`).
Ten rows, each on the footing the `BackgroundSound` pair in this file already set: two names,
one knob, dispatched together in `sound/mod.rs`'s observer so the spellings cannot disagree
about a setting. Each default is its 1.12 sibling's, since they are the same setting twice.
Two honest compromises, labelled where they live: 1.12 has no dialogue channel, so
`Sound_DialogVolume` rides the SFX volume and `Sound_EnableDialog` the error-speech toggle; and
it has no SFX-only enable, so `Sound_EnableSFX` rides `MasterSoundEffects`, the only sound
enable it has. Riding what the mixer actually has beats inventing tracks it has not got.
**`GetCVarBool`** is absent from 1.12 on this repo's own evidence —
`reference/1.12-globals.tsv` is a capture of the real client's `_G` and carries `GetCVar` and
`GetCVarDefault` and nothing else of the family — and present in `ClassicAPI.dll`'s string
pool, so it belongs to the client this build announces itself as. It answers a real boolean, as
the name says, and **nil for a name with no row**, so "there is no such CVar" stays
distinguishable from "it is off". `Cinematic/Camera.lua:493` reads `ActionButtonUseKeyDown`
through it.
Not built, and deliberately: `IsMouseButtonDown`. `compat/classic_api/input.rs` already
declined it with the right reason — the only press state here is `Model::mouse_down_on`, which
the pointer layer fills *only* for a press that landed on a frame. `Cinematic/Camera.lua:612`
asks in order to spot a right-drag **on the world**, which is exactly what that map cannot see,
so answering from it would be wrong for the one caller. It wants a real mouse-button feed.
benilla-ui 2081 passed. Full chain green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -174,6 +174,73 @@ pub(crate) const REGISTERED: &[Registered] = &[
|
||||
// The race/sex refusal voice lines (`0x457877`), `SoundOptionsFrame.lua:3`; the master enable
|
||||
// greys it.
|
||||
same("EnableErrorSpeech", "1"),
|
||||
// ── The later-era `Sound_` spellings, each beside its 1.12 row above ─────────────────────
|
||||
//
|
||||
// 2.x renamed the sound CVars with a `Sound_` prefix and 1.12's names stayed what they are;
|
||||
// `sound/mod.rs`'s observer dispatches each pair to one knob, the arrangement the
|
||||
// `BackgroundSound` row below already uses, so the two spellings cannot disagree.
|
||||
//
|
||||
// **Not a concession to the ported addons.** Three already installed here ask with the modern
|
||||
// spelling and have been reading nil: DoiteAuras' editor and Tmog (`Sound_MasterVolume`,
|
||||
// `Sound_DialogVolume`, `Sound_EnableDialog`), SoftSpoken (`Sound_EnableAllSound`,
|
||||
// `Sound_SFXVolume`, `Sound_EnableSFX`). Cinematic uses it at all 47 of its music sites, which
|
||||
// is the whole of its music-fade feature; `GetCVar` answering nil there raised inside a
|
||||
// `format` at `Core.lua:3621` and took the rest of its `PLAYER_LOGIN` handler with it.
|
||||
//
|
||||
// Each default is its 1.12 sibling's, since they are the same setting under two names. The
|
||||
// dialogue pair is the exception worth reading: 1.12 has no separate dialogue channel, so
|
||||
// `Sound_DialogVolume` rides the SFX volume and `Sound_EnableDialog` the error-speech toggle
|
||||
// rather than inventing a track the mixer has not got.
|
||||
ours(
|
||||
"Sound_MasterVolume",
|
||||
"1",
|
||||
"the later-era spelling of MasterVolume; one knob, two names (sound/mod.rs)",
|
||||
),
|
||||
ours(
|
||||
"Sound_SFXVolume",
|
||||
"1",
|
||||
"the later-era spelling of SoundVolume; one knob, two names (sound/mod.rs)",
|
||||
),
|
||||
ours(
|
||||
"Sound_MusicVolume",
|
||||
"0.4",
|
||||
"the later-era spelling of MusicVolume; one knob, two names (sound/mod.rs)",
|
||||
),
|
||||
ours(
|
||||
"Sound_AmbienceVolume",
|
||||
"0.6",
|
||||
"the later-era spelling of AmbienceVolume; one knob, two names (sound/mod.rs)",
|
||||
),
|
||||
ours(
|
||||
"Sound_DialogVolume",
|
||||
"1",
|
||||
"1.12 has no dialogue channel; rides the SFX volume rather than inventing a track",
|
||||
),
|
||||
ours(
|
||||
"Sound_EnableMusic",
|
||||
"1",
|
||||
"the later-era spelling of EnableMusic; one knob, two names (sound/mod.rs)",
|
||||
),
|
||||
ours(
|
||||
"Sound_EnableAmbience",
|
||||
"1",
|
||||
"the later-era spelling of EnableAmbience; one knob, two names (sound/mod.rs)",
|
||||
),
|
||||
ours(
|
||||
"Sound_EnableAllSound",
|
||||
"1",
|
||||
"the later-era spelling of MasterSoundEffects, the Enable All Sound box",
|
||||
),
|
||||
ours(
|
||||
"Sound_EnableSFX",
|
||||
"1",
|
||||
"1.12 has no SFX-only toggle; rides MasterSoundEffects, the only sound enable it has",
|
||||
),
|
||||
ours(
|
||||
"Sound_EnableDialog",
|
||||
"1",
|
||||
"1.12's nearest is EnableErrorSpeech, the race/sex refusal lines; rides that",
|
||||
),
|
||||
// Not a 1.12 CVar or checkbox; the later-era name. The reference mutes on losing focus, music
|
||||
// included (`WM_ACTIVATE` to `0x7a4860`'s `FSOUND_SetMute(-3, active ? 0 : 1)`), so "0" is its
|
||||
// behaviour. The knob is `SoundConfig::background_sound`.
|
||||
|
||||
@@ -346,12 +346,24 @@ pub(crate) fn on_cvar(
|
||||
mut cut: ResMut<EffectCutArmed>,
|
||||
) {
|
||||
let v = ev.num();
|
||||
// The `Sound_`-prefixed spellings beside each 1.12 name are the later-era ones, on the footing
|
||||
// the `BackgroundSound` pair below already set: two names, one knob, so the two cannot
|
||||
// disagree. **They are not only the ported addons' concern** — three addons already installed
|
||||
// ask for them and have been getting nil: `Sound_MasterVolume`, `Sound_DialogVolume`,
|
||||
// `Sound_EnableDialog` and `Sound_EnableAllSound` (DoiteAuras' editor, Tmog, SoftSpoken),
|
||||
// `Sound_SFXVolume`/`Sound_EnableSFX` (SoftSpoken). Cinematic asks with the modern spelling at
|
||||
// all 47 of its music sites, which is its whole music-fade feature.
|
||||
match ev.key().as_str() {
|
||||
"mastervolume" => sound.master = v.clamp(0.0, 1.0),
|
||||
"soundvolume" => sound.sfx = v.clamp(0.0, 1.0),
|
||||
"musicvolume" => sound.music = v.clamp(0.0, 1.0),
|
||||
"ambiencevolume" => sound.ambience = v.clamp(0.0, 1.0),
|
||||
"mastersoundeffects" => {
|
||||
"mastervolume" | "sound_mastervolume" => sound.master = v.clamp(0.0, 1.0),
|
||||
"soundvolume" | "sound_sfxvolume" => sound.sfx = v.clamp(0.0, 1.0),
|
||||
"musicvolume" | "sound_musicvolume" => sound.music = v.clamp(0.0, 1.0),
|
||||
"ambiencevolume" | "sound_ambiencevolume" => sound.ambience = v.clamp(0.0, 1.0),
|
||||
// 1.12's own dialogue knob is the error-speech one, and there is no separate dialogue
|
||||
// volume; the modern pair maps onto what this client actually has rather than inventing a
|
||||
// channel the mixer has no track for.
|
||||
"sound_dialogvolume" => sound.sfx = v.clamp(0.0, 1.0),
|
||||
"sound_enabledialog" | "sound_enableerrorspeech" => sound.error_speech = v != 0.0,
|
||||
"mastersoundeffects" | "sound_enableallsound" | "sound_enablesfx" => {
|
||||
// The reference's flag store is edge-triggered (`7a657f: je` returns on an unchanged
|
||||
// value) and only the enabling edge reaches the stop (`7a67eb: test cl,cl`).
|
||||
let now = v != 0.0;
|
||||
@@ -360,8 +372,8 @@ pub(crate) fn on_cvar(
|
||||
}
|
||||
sound.enabled = now;
|
||||
}
|
||||
"enablemusic" => sound.music_enabled = v != 0.0,
|
||||
"enableambience" => sound.ambience_enabled = v != 0.0,
|
||||
"enablemusic" | "sound_enablemusic" => sound.music_enabled = v != 0.0,
|
||||
"enableambience" | "sound_enableambience" => sound.ambience_enabled = v != 0.0,
|
||||
"enableerrorspeech" => sound.error_speech = v != 0.0,
|
||||
// Two names, one knob. `Sound_EnableSoundWhenGameIsInBG` is the later-era Blizzard
|
||||
// spelling; `BackgroundSound` is SuperWoW's, and it is the one an addon on this server
|
||||
|
||||
@@ -189,6 +189,32 @@ pub(super) fn install(lua: &Lua) -> mlua::Result<Table> {
|
||||
Ok(t)
|
||||
}
|
||||
|
||||
/// `GetCVarBool(name)`: the bare global, which 1.12 has not got — the reference capture of the
|
||||
/// client's own `_G` (`reference/1.12-globals.tsv`) lists `GetCVar` and `GetCVarDefault` and
|
||||
/// nothing else of the family, while `ClassicAPI.dll` carries the name in its own string pool, so
|
||||
/// it is part of the client this build announces itself as.
|
||||
///
|
||||
/// A real boolean, as the name says and as upstream documents, and **nil for a name with no row**
|
||||
/// — so a caller can tell "there is no such CVar" from "it is off", which a blanket `false` would
|
||||
/// hide. `Cinematic/Camera.lua:493` reads `ActionButtonUseKeyDown` through it to decide whether
|
||||
/// its cast button fires on key down or up.
|
||||
pub(super) fn install_globals(lua: &Lua) -> mlua::Result<()> {
|
||||
lua.globals().set(
|
||||
"GetCVarBool",
|
||||
lua.create_function(|lua, name: Option<String>| {
|
||||
let model = lua.app_data_ref::<Model>().expect("model app_data");
|
||||
let Some(slot) = name.as_deref().and_then(|n| model.cvars.get(&key_of(n))) else {
|
||||
return Ok(mlua::Value::Nil);
|
||||
};
|
||||
// The same reading `GetCVar`'s consumers use: "0" and an empty value are off, anything
|
||||
// else is on, so "1", "0.4" and "true" all behave as the sound rows expect.
|
||||
let on = !matches!(slot.value.as_str(), "" | "0" | "0.0" | "false");
|
||||
Ok(mlua::Value::Boolean(on))
|
||||
})?,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::script::UiScript;
|
||||
|
||||
@@ -202,6 +202,13 @@ fn allowed_beyond_1_12() -> HashSet<&'static str> {
|
||||
// "spellIconID")`. 1.12 reaches an icon only through a spellbook slot, so a spell the
|
||||
// player does not know has no texture an addon can draw.
|
||||
"GetSpellIconTexture",
|
||||
// ClassicAPI's `GetCVarBool` (script/compat/classic_api/cvar.rs). Absent from 1.12 on this
|
||||
// file's own evidence — `reference/1.12-globals.tsv` is a capture of the real client's
|
||||
// `_G` and carries `GetCVar` and `GetCVarDefault` and nothing else of the family — and
|
||||
// present in `ClassicAPI.dll`'s string pool, so it is part of the client this build
|
||||
// announces itself as. `Cinematic/Camera.lua:493` reads `ActionButtonUseKeyDown` through
|
||||
// it; nil for a name with no row, so "no such CVar" stays distinguishable from "off".
|
||||
"GetCVarBool",
|
||||
// ClassicAPI's `GetSpellInfo` as a bare global (script/compat/classic_api/spell.rs), the
|
||||
// positional sibling of the table-returning `C_Spell.GetSpellInfo` — upstream lists "both
|
||||
// forms". Ten returns, the WotLK signature plus the appended spellID.
|
||||
|
||||
Reference in New Issue
Block a user