use localized soundtrack names

This commit is contained in:
József Sallai 2024-03-24 00:57:56 +02:00
parent 7630a9b60e
commit 9c95b20f5c
6 changed files with 140 additions and 48 deletions

View File

@ -207,7 +207,7 @@ pub struct AnimatedFace {
#[derive(Debug, Clone)]
pub struct ExtraSoundtrack {
pub name: String,
pub id: String,
pub path: String,
pub available: bool,
}
@ -1613,10 +1613,10 @@ impl EngineConstants {
font_path: "csfont.fnt".to_owned(),
font_space_offset: 0.0,
soundtracks: vec![
ExtraSoundtrack { name: "Remastered".to_owned(), path: "/base/Ogg11/".to_owned(), available: false },
ExtraSoundtrack { name: "New".to_owned(), path: "/base/Ogg/".to_owned(), available: false },
ExtraSoundtrack { name: "Famitracks".to_owned(), path: "/base/ogg17/".to_owned(), available: false },
ExtraSoundtrack { name: "Ridiculon".to_owned(), path: "/base/ogg_ridic/".to_owned(), available: false },
ExtraSoundtrack { id: "remastered".to_owned(), path: "/base/Ogg11/".to_owned(), available: false },
ExtraSoundtrack { id: "new".to_owned(), path: "/base/Ogg/".to_owned(), available: false },
ExtraSoundtrack { id: "famitracks".to_owned(), path: "/base/ogg17/".to_owned(), available: false },
ExtraSoundtrack { id: "ridiculon".to_owned(), path: "/base/ogg_ridic/".to_owned(), available: false },
],
music_table: vec![
"xxxx".to_owned(),

View File

@ -95,7 +95,7 @@ fn default_true() -> bool {
#[inline(always)]
fn current_version() -> u32 {
24
25
}
#[inline(always)]
@ -347,6 +347,18 @@ impl Settings {
self.allow_strafe = true;
}
if self.version == 24 {
self.version = 25;
self.soundtrack = match self.soundtrack.as_str() {
"Organya" => "organya".to_owned(),
"Remastered" => "remastered".to_owned(),
"New" => "new".to_owned(),
"Famitracks" => "famitracks".to_owned(),
"Ridiculon" => "ridiculon".to_owned(),
_ => self.soundtrack.clone(),
}
}
if self.version != initial_version {
log::info!("Upgraded configuration file from version {} to {}.", initial_version, self.version);
}

View File

@ -21,7 +21,9 @@ use crate::game::profile::GameProfile;
#[cfg(feature = "scripting-lua")]
use crate::game::scripting::lua::LuaScriptingState;
use crate::game::scripting::tsc::credit_script::{CreditScript, CreditScriptVM};
use crate::game::scripting::tsc::text_script::{ScriptMode, TextScript, TextScriptEncoding, TextScriptExecutionState, TextScriptVM};
use crate::game::scripting::tsc::text_script::{
ScriptMode, TextScript, TextScriptEncoding, TextScriptExecutionState, TextScriptVM,
};
use crate::game::settings::Settings;
use crate::game::stage::StageData;
use crate::graphics::bmfont::BMFont;
@ -408,7 +410,7 @@ impl SharedGameState {
for soundtrack in constants.soundtracks.iter_mut() {
if filesystem::exists(ctx, &soundtrack.path) {
log::info!("Enabling soundtrack {} from {}.", soundtrack.name, soundtrack.path);
log::info!("Enabling soundtrack {} from {}.", soundtrack.id, soundtrack.path);
soundtrack.available = true;
}
}
@ -420,11 +422,11 @@ impl SharedGameState {
let locale = SharedGameState::get_locale(&constants, &settings.locale).unwrap_or_default();
if (locale.code == "jp" || locale.code == "en") && constants.is_base() {
constants.textscript.encoding = TextScriptEncoding::ShiftJIS
constants.textscript.encoding = TextScriptEncoding::ShiftJIS
} else {
constants.textscript.encoding = TextScriptEncoding::UTF8
constants.textscript.encoding = TextScriptEncoding::UTF8
}
let font = BMFont::load(&constants.base_paths, &locale.font.path, ctx, locale.font.scale).or_else(|e| {
log::warn!("Failed to load font, using built-in: {}", e);
BMFont::load(&vec!["/".to_owned()], "builtin/builtin_font.fnt", ctx, 1.0)
@ -573,9 +575,9 @@ impl SharedGameState {
if let Some(locale) = SharedGameState::get_locale(&self.constants, &self.settings.locale) {
self.loc = locale;
if (self.loc.code == "jp" || self.loc.code == "en") && self.constants.is_base() {
self.constants.textscript.encoding = TextScriptEncoding::ShiftJIS
self.constants.textscript.encoding = TextScriptEncoding::ShiftJIS
} else {
self.constants.textscript.encoding = TextScriptEncoding::UTF8
self.constants.textscript.encoding = TextScriptEncoding::UTF8
}
}
@ -647,7 +649,12 @@ impl SharedGameState {
Ok(())
}
pub fn save_game(&mut self, game_scene: &mut GameScene, ctx: &mut Context, target_player: Option<TargetPlayer>) -> GameResult {
pub fn save_game(
&mut self,
game_scene: &mut GameScene,
ctx: &mut Context,
target_player: Option<TargetPlayer>,
) -> GameResult {
if let Some(save_path) = self.get_save_filename(self.save_slot) {
if let Ok(data) = filesystem::open_options(ctx, save_path, OpenOptions::new().write(true).create(true)) {
let profile = GameProfile::dump(self, game_scene, target_player);
@ -896,6 +903,18 @@ impl SharedGameState {
out_locale
}
pub fn get_localized_soundtrack_name(&self, id: &str) -> String {
if id == "organya" {
return self.loc.t("soundtrack.organya").to_owned();
}
self.constants
.soundtracks
.iter()
.find(|s| s.id == id)
.map_or_else(|| id.to_owned(), |s| self.loc.t(format!("soundtrack.{}", s.id).as_str()).to_owned())
}
pub fn tt(&self, key: &str, args: &[(&str, &str)]) -> String {
return self.loc.tt(key, args);
}

View File

@ -500,18 +500,21 @@ impl SettingsMenu {
);
self.sound.push_entry(
SoundMenuEntry::Soundtrack,
MenuEntry::Active(
state.tt(
"menus.options_menu.sound_menu.soundtrack",
&[("soundtrack", state.settings.soundtrack.as_str())],
),
),
MenuEntry::Active(state.loc.tt(
"menus.options_menu.sound_menu.soundtrack",
&[("soundtrack", state.get_localized_soundtrack_name(&state.settings.soundtrack).as_str())],
)),
);
self.sound.push_entry(SoundMenuEntry::Back, MenuEntry::Active(state.loc.t("common.back").to_owned()));
let mut soundtrack_entries =
state.constants.soundtracks.iter().filter(|s| s.available).map(|s| s.name.to_owned()).collect_vec();
soundtrack_entries.push("Organya".to_owned());
let mut soundtrack_entries = state
.constants
.soundtracks
.iter()
.filter(|s| s.available)
.map(|s| state.loc.t(format!("soundtrack.{}", s.id).as_str()).to_owned())
.collect_vec();
soundtrack_entries.push(state.loc.t("soundtrack.organya").to_owned());
if let Ok(dir) = filesystem::read_dir(ctx, "/Soundtracks/") {
for entry in dir {
@ -882,7 +885,7 @@ impl SettingsMenu {
for (id, entry) in &self.soundtrack.entries {
if let MenuEntry::Active(soundtrack) = entry {
if soundtrack == &state.settings.soundtrack {
if soundtrack == &state.get_localized_soundtrack_name(&state.settings.soundtrack) {
active_soundtrack = *id;
let _ = state.settings.save(ctx);
break;
@ -937,12 +940,28 @@ impl SettingsMenu {
CurrentMenu::SoundtrackMenu => match self.soundtrack.tick(controller, state) {
MenuSelectionResult::Selected(SoundtrackMenuEntry::Soundtrack(_), entry) => {
if let MenuEntry::Active(name) = entry {
state.settings.soundtrack = name.to_owned();
state.settings.soundtrack = state
.constants
.soundtracks
.iter()
.find(|s| state.loc.t(format!("soundtrack.{}", s.id).as_str()) == name)
.map_or_else(|| name.to_owned(), |s| s.id.clone());
if state.settings.soundtrack == "Organya" {
state.settings.soundtrack = "organya".to_owned()
}
let _ = state.settings.save(ctx);
self.sound.set_entry(
SoundMenuEntry::Soundtrack,
MenuEntry::Active(format!("Soundtrack: {}", state.settings.soundtrack)),
MenuEntry::Active(state.loc.tt(
"menus.options_menu.sound_menu.soundtrack",
&[(
"soundtrack",
state.get_localized_soundtrack_name(&state.settings.soundtrack).as_str(),
)],
)),
);
state.sound_manager.reload_songs(&state.constants, &state.settings, ctx)?;
}

View File

@ -3,6 +3,7 @@ use itertools::Itertools;
use crate::common::Color;
use crate::common::Rect;
use crate::components::background::Background;
use crate::engine_constants::ExtraSoundtrack;
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::framework::filesystem;
@ -16,10 +17,43 @@ use crate::input::combined_menu_controller::CombinedMenuController;
use crate::scene::title_scene::TitleScene;
use crate::scene::Scene;
#[derive(Clone, Debug)]
pub enum JukeboxSoundtrackKind {
Organya,
Extra(ExtraSoundtrack),
Custom(String),
}
impl JukeboxSoundtrackKind {
pub fn eq_str(&self, other: &str) -> bool {
match self {
JukeboxSoundtrackKind::Organya => other == "organya",
JukeboxSoundtrackKind::Extra(s) => other == s.id,
JukeboxSoundtrackKind::Custom(s) => other == s,
}
}
pub fn to_localized_string(&self, state: &mut SharedGameState) -> String {
match self {
JukeboxSoundtrackKind::Organya => state.loc.t("soundtrack.organya").to_owned(),
JukeboxSoundtrackKind::Extra(s) => state.loc.t(format!("soundtrack.{}", s.id).as_str()).to_owned(),
JukeboxSoundtrackKind::Custom(s) => s.clone(),
}
}
pub fn to_id(&self) -> String {
match self {
JukeboxSoundtrackKind::Organya => "organya".to_owned(),
JukeboxSoundtrackKind::Extra(s) => s.id.clone(),
JukeboxSoundtrackKind::Custom(s) => s.clone(),
}
}
}
pub struct JukeboxScene {
selected_song: u16,
song_list: Vec<String>,
soundtracks: Vec<String>,
soundtracks: Vec<JukeboxSoundtrackKind>,
selected_soundtrack: usize,
controller: CombinedMenuController,
background: Background,
@ -79,17 +113,26 @@ impl Scene for JukeboxScene {
.cloned()
.collect();
let mut soundtrack_entries =
state.constants.soundtracks.iter().filter(|s| s.available).map(|s| s.name.to_owned()).collect_vec();
soundtrack_entries.push("Organya".to_owned());
let mut soundtrack_entries = state
.constants
.soundtracks
.iter()
.filter(|s| s.available)
.map(|s| JukeboxSoundtrackKind::Extra(s.clone()))
.collect_vec();
soundtrack_entries.push(JukeboxSoundtrackKind::Organya);
if let Ok(dir) = filesystem::read_dir(ctx, "/Soundtracks/") {
for entry in dir {
if filesystem::is_dir(ctx, &entry) {
let filename = entry.file_name().unwrap().to_string_lossy().to_string();
if !soundtrack_entries.contains(&filename) {
soundtrack_entries.push(filename);
if soundtrack_entries
.iter()
.find(|s| matches!(s, JukeboxSoundtrackKind::Custom(s) if s == &filename))
.is_none()
{
soundtrack_entries.push(JukeboxSoundtrackKind::Custom(filename.clone()));
}
}
}
@ -98,7 +141,7 @@ impl Scene for JukeboxScene {
self.soundtracks = soundtrack_entries.clone();
let selected_soundtrack_index =
self.soundtracks.iter().position(|s| s == &state.settings.soundtrack).unwrap_or(0);
self.soundtracks.iter().position(|s| s.eq_str(&state.settings.soundtrack)).unwrap_or(0);
self.selected_soundtrack = selected_soundtrack_index;
self.previous_pause_on_focus_loss_setting = state.settings.pause_on_focus_loss;
@ -150,13 +193,13 @@ impl Scene for JukeboxScene {
if self.controller.trigger_shift_left() {
self.selected_soundtrack = self.selected_soundtrack.checked_sub(1).unwrap_or(self.soundtracks.len() - 1);
state.settings.soundtrack = self.soundtracks[self.selected_soundtrack].to_string();
state.settings.soundtrack = self.soundtracks[self.selected_soundtrack].to_id();
state.sound_manager.reload_songs(&state.constants, &state.settings, ctx)?;
}
if self.controller.trigger_shift_right() {
self.selected_soundtrack = (self.selected_soundtrack + 1) % self.soundtracks.len();
state.settings.soundtrack = self.soundtracks[self.selected_soundtrack].to_string();
state.settings.soundtrack = self.soundtracks[self.selected_soundtrack].to_id();
state.sound_manager.reload_songs(&state.constants, &state.settings, ctx)?;
}
@ -284,9 +327,9 @@ impl Scene for JukeboxScene {
// Write Soundtrack name
let text = &state.settings.soundtrack;
let text = self.soundtracks[self.selected_soundtrack].to_localized_string(state);
state.font.builder().center(state.canvas_size.0).y(20.0).shadow(true).draw(
text,
text.as_str(),
ctx,
&state.constants,
&mut state.texture_set,

View File

@ -11,8 +11,8 @@ use num_traits::clamp;
use crate::engine_constants::EngineConstants;
use crate::framework::context::Context;
use crate::framework::error::{GameError, GameResult};
use crate::framework::error::GameError::{AudioError, InvalidValue};
use crate::framework::error::{GameError, GameResult};
use crate::framework::filesystem;
use crate::framework::filesystem::File;
use crate::game::settings::Settings;
@ -286,20 +286,19 @@ impl SoundManager {
paths.insert(0, "/Soundtracks/".to_owned() + &settings.soundtrack + "/");
if let Some(soundtrack) =
constants.soundtracks.iter().find(|s| s.available && s.name == settings.soundtrack)
if let Some(soundtrack) = constants.soundtracks.iter().find(|s| s.available && s.id == settings.soundtrack)
{
paths.insert(0, soundtrack.path.clone());
}
let songs_paths = paths.iter().map(|prefix| {
[
#[cfg(feature = "ogg-playback")]
#[cfg(feature = "ogg-playback")]
(
SongFormat::OggMultiPart,
vec![format!("{}{}_intro.ogg", prefix, song_name), format!("{}{}_loop.ogg", prefix, song_name)],
),
#[cfg(feature = "ogg-playback")]
#[cfg(feature = "ogg-playback")]
(SongFormat::OggSinglePart, vec![format!("{}{}.ogg", prefix, song_name)]),
(SongFormat::Organya, vec![format!("{}{}.org", prefix, song_name)]),
]
@ -307,7 +306,7 @@ impl SoundManager {
for songs in songs_paths {
for (format, paths) in
songs.iter().filter(|(_, paths)| paths.iter().all(|path| filesystem::exists(ctx, path)))
songs.iter().filter(|(_, paths)| paths.iter().all(|path| filesystem::exists(ctx, path)))
{
match format {
SongFormat::Organya => {
@ -385,7 +384,7 @@ impl SoundManager {
Box::new(song_intro),
Box::new(song_loop),
))
.unwrap();
.unwrap();
return Ok(());
}
@ -597,8 +596,8 @@ fn run<T>(
device: cpal::Device,
config: cpal::StreamConfig,
) -> GameResult<cpal::Stream>
where
T: cpal::SizedSample + cpal::FromSample<u16>,
where
T: cpal::SizedSample + cpal::FromSample<u16>,
{
let sample_rate = config.sample_rate.0 as f32;
let channels = config.channels as usize;
@ -732,7 +731,7 @@ fn run<T>(
assert!(new_speed > 0.0);
speed = new_speed;
#[cfg(feature = "ogg-playback")]
ogg_engine.set_sample_rate((sample_rate / new_speed) as usize);
ogg_engine.set_sample_rate((sample_rate / new_speed) as usize);
org_engine.set_sample_rate((sample_rate / new_speed) as usize);
}
Ok(PlaybackMessage::SetSongVolume(new_volume)) => {
@ -895,7 +894,7 @@ fn run<T>(
}
},
err_fn,
None
None,
);
if stream_result.is_err() {