diff --git a/src/components/nikumaru.rs b/src/components/nikumaru.rs index 7324847..121a77a 100644 --- a/src/components/nikumaru.rs +++ b/src/components/nikumaru.rs @@ -1,7 +1,7 @@ -use byteorder::{LE, ReadBytesExt, WriteBytesExt}; +use byteorder::{ReadBytesExt, WriteBytesExt, LE}; use crate::common::Rect; -use crate::components::draw_common::{Alignment, draw_number, draw_number_zeros}; +use crate::components::draw_common::{draw_number, draw_number_zeros, Alignment}; use crate::entity::GameEntity; use crate::frame::Frame; use crate::framework::context::Context; @@ -24,8 +24,8 @@ impl NikumaruCounter { NikumaruCounter { tick: 0, shown: false } } - fn load_time(&mut self, ctx: &mut Context) -> GameResult { - if let Ok(mut data) = filesystem::user_open(ctx, "/290.rec") { + fn load_time(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + if let Ok(mut data) = filesystem::user_open(ctx, state.get_290_filename()) { let mut ticks: [u32; 4] = [0; 4]; for iter in 0..=3 { @@ -54,7 +54,9 @@ impl NikumaruCounter { } fn save_time(&mut self, new_time: u32, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { - if let Ok(mut data) = filesystem::open_options(ctx, "/290.rec", OpenOptions::new().write(true).create(true)) { + if let Ok(mut data) = + filesystem::open_options(ctx, state.get_290_filename(), OpenOptions::new().write(true).create(true)) + { let mut ticks: [u32; 4] = [new_time; 4]; let mut random_list: [u8; 4] = [0; 4]; @@ -78,16 +80,18 @@ impl NikumaruCounter { Ok(()) } - pub fn load_counter(&mut self, ctx: &mut Context) -> GameResult { - self.tick = self.load_time(ctx)? as usize; + pub fn load_counter(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { + self.tick = self.load_time(state, ctx)? as usize; if self.tick > 0 { self.shown = true; + } else { + self.shown = false; } Ok(()) } pub fn save_counter(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { - let old_record = self.load_time(ctx)? as usize; + let old_record = self.load_time(state, ctx)? as usize; if self.tick < old_record || old_record == 0 { self.save_time(self.tick as u32, state, ctx)?; } diff --git a/src/menu/save_select_menu.rs b/src/menu/save_select_menu.rs index 9d11056..9066d59 100644 --- a/src/menu/save_select_menu.rs +++ b/src/menu/save_select_menu.rs @@ -47,7 +47,7 @@ impl SaveSelectMenu { self.delete_confirm = Menu::new(0, 0, 75, 0); for (iter, save) in self.saves.iter_mut().enumerate() { - if let Ok(data) = filesystem::user_open(ctx, state.get_save_filename(iter + 1)) { + if let Ok(data) = filesystem::user_open(ctx, state.get_save_filename(iter + 1).unwrap_or("".to_string())) { let loaded_save = GameProfile::load_from_save(data)?; save.current_map = loaded_save.current_map; @@ -122,7 +122,10 @@ impl SaveSelectMenu { CurrentMenu::DeleteConfirm => match self.delete_confirm.tick(controller, state) { MenuSelectionResult::Selected(1, _) => { state.sound_manager.play_sfx(17); // Player Death sfx - filesystem::user_delete(ctx, state.get_save_filename(self.save_menu.selected + 1))?; + filesystem::user_delete( + ctx, + state.get_save_filename(self.save_menu.selected + 1).unwrap_or("".to_string()), + )?; self.save_menu.entries[self.save_menu.selected] = MenuEntry::NewSave; self.current_menu = CurrentMenu::SaveMenu; } diff --git a/src/mod_list.rs b/src/mod_list.rs index 50e0be3..b033405 100644 --- a/src/mod_list.rs +++ b/src/mod_list.rs @@ -171,4 +171,12 @@ impl ModList { -1 } } + + pub fn get_name_from_path(&self, mod_path: String) -> &str { + if let Some(mod_sel) = self.mods.iter().find(|x| x.path == mod_path) { + &mod_sel.name + } else { + "NoName" + } + } } diff --git a/src/scene/title_scene.rs b/src/scene/title_scene.rs index a12e0e5..7324b2e 100644 --- a/src/scene/title_scene.rs +++ b/src/scene/title_scene.rs @@ -5,7 +5,6 @@ use crate::entity::GameEntity; use crate::frame::Frame; use crate::framework::context::Context; use crate::framework::error::GameResult; -use crate::framework::graphics; use crate::input::combined_menu_controller::CombinedMenuController; use crate::input::touch_controls::TouchControlType; use crate::map::Map; @@ -25,8 +24,7 @@ enum CurrentMenu { OptionMenu, SaveSelectMenu, ChallengesMenu, - StartGame, - LoadGame, + ChallengeConfirmMenu, } pub struct TitleScene { @@ -36,6 +34,7 @@ pub struct TitleScene { main_menu: Menu, save_select_menu: SaveSelectMenu, challenges_menu: Menu, + confirm_menu: Menu, settings_menu: SettingsMenu, background: Background, frame: Frame, @@ -74,6 +73,7 @@ impl TitleScene { main_menu: Menu::new(0, 0, 100, 0), save_select_menu: SaveSelectMenu::new(), challenges_menu: Menu::new(0, 0, 150, 0), + confirm_menu: Menu::new(0, 0, 150, 0), settings_menu, background: Background::new(), frame: Frame::new(), @@ -166,10 +166,15 @@ impl Scene for TitleScene { } self.challenges_menu.push_entry(MenuEntry::Active("< Back".to_string())); + self.confirm_menu.push_entry(MenuEntry::Disabled("".to_owned())); + self.confirm_menu.push_entry(MenuEntry::Active("Start".to_owned())); + self.confirm_menu.push_entry(MenuEntry::Active("< Back".to_owned())); + self.confirm_menu.selected = 1; + self.controller.update(state, ctx)?; self.controller.update_trigger(); - self.nikumaru_rec.load_counter(ctx)?; + self.nikumaru_rec.load_counter(state, ctx)?; self.update_menu_cursor(state, ctx)?; Ok(()) @@ -236,62 +241,70 @@ impl Scene for TitleScene { } CurrentMenu::SaveSelectMenu => { let cm = &mut self.current_menu; + let rm = if state.mod_path.is_none() { CurrentMenu::MainMenu } else { CurrentMenu::ChallengesMenu }; self.save_select_menu.tick( &mut || { - *cm = CurrentMenu::MainMenu; + *cm = rm; }, &mut self.controller, state, ctx, )?; } - CurrentMenu::StartGame => { - if self.tick == 10 { - state.reset_skip_flags(); - state.start_new_game(ctx)?; - } - } - CurrentMenu::LoadGame => { - if self.tick == 10 { - state.load_or_start_game(ctx)?; - } - } CurrentMenu::ChallengesMenu => { let last_idx = self.challenges_menu.entries.len() - 1; match self.challenges_menu.tick(&mut self.controller, state) { MenuSelectionResult::Selected(idx, _) => { if last_idx == idx { + state.mod_path = None; + self.nikumaru_rec.load_counter(state, ctx)?; self.current_menu = CurrentMenu::MainMenu; } else if let Some(mod_info) = state.mod_list.mods.get(idx) { state.mod_path = Some(mod_info.path.clone()); if mod_info.save_slot >= 0 { self.save_select_menu.init(state, ctx)?; + self.nikumaru_rec.load_counter(state, ctx)?; self.current_menu = CurrentMenu::SaveSelectMenu; } else { - state.reload_resources(ctx)?; - state.start_new_game(ctx)?; + let mod_name = mod_info.name.clone(); + self.confirm_menu.width = + (state.font.text_width(mod_name.chars(), &state.constants).max(50.0) + 32.0) as u16; + self.confirm_menu.entries[0] = MenuEntry::Disabled(mod_name); + self.nikumaru_rec.load_counter(state, ctx)?; + self.current_menu = CurrentMenu::ChallengeConfirmMenu; } } } MenuSelectionResult::Canceled => { + state.mod_path = None; + self.nikumaru_rec.load_counter(state, ctx)?; self.current_menu = CurrentMenu::MainMenu; } _ => (), } } + CurrentMenu::ChallengeConfirmMenu => match self.confirm_menu.tick(&mut self.controller, state) { + MenuSelectionResult::Selected(1, _) => { + state.reload_resources(ctx)?; + state.start_new_game(ctx)?; + } + MenuSelectionResult::Selected(2, _) | MenuSelectionResult::Canceled => { + self.current_menu = CurrentMenu::ChallengesMenu; + } + _ => (), + }, } + self.confirm_menu.update_height(); + self.confirm_menu.x = ((state.canvas_size.0 - self.confirm_menu.width as f32) / 2.0).floor() as isize; + self.confirm_menu.y = ((state.canvas_size.1 + 30.0 - self.confirm_menu.height as f32) / 2.0).floor() as isize; + self.tick += 1; Ok(()) } fn draw(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult { - if self.current_menu == CurrentMenu::StartGame || self.current_menu == CurrentMenu::LoadGame { - graphics::clear(ctx, Color::from_rgb(0, 0, 0)); - return Ok(()); - } - self.background.draw(state, ctx, &self.frame, &self.textures, &self.stage)?; { @@ -313,9 +326,9 @@ impl Scene for TitleScene { match self.current_menu { CurrentMenu::MainMenu => self.main_menu.draw(state, ctx)?, CurrentMenu::ChallengesMenu => self.challenges_menu.draw(state, ctx)?, + CurrentMenu::ChallengeConfirmMenu => self.confirm_menu.draw(state, ctx)?, CurrentMenu::OptionMenu => self.settings_menu.draw(state, ctx)?, CurrentMenu::SaveSelectMenu => self.save_select_menu.draw(state, ctx)?, - _ => {} } Ok(()) diff --git a/src/shared_game_state.rs b/src/shared_game_state.rs index cf6193d..b67feac 100644 --- a/src/shared_game_state.rs +++ b/src/shared_game_state.rs @@ -6,15 +6,15 @@ use chrono::{Datelike, Local}; use crate::bmfont_renderer::BMFontRenderer; use crate::caret::{Caret, CaretType}; use crate::common::{ControlFlags, Direction, FadeState}; -use crate::components::draw_common::{Alignment, draw_number}; +use crate::components::draw_common::{draw_number, Alignment}; use crate::engine_constants::EngineConstants; -use crate::framework::{filesystem, graphics}; use crate::framework::backend::BackendTexture; use crate::framework::context::Context; use crate::framework::error::GameResult; use crate::framework::graphics::{create_texture_mutable, set_render_target}; use crate::framework::keyboard::ScanCode; use crate::framework::vfs::OpenOptions; +use crate::framework::{filesystem, graphics}; #[cfg(feature = "hooks")] use crate::hooks::init_hooks; use crate::input::touch_controls::TouchControls; @@ -23,8 +23,8 @@ use crate::npc::NPCTable; use crate::profile::GameProfile; use crate::rng::XorShift; use crate::scene::game_scene::GameScene; -use crate::scene::Scene; use crate::scene::title_scene::TitleScene; +use crate::scene::Scene; #[cfg(feature = "scripting-lua")] use crate::scripting::lua::LuaScriptingState; use crate::scripting::tsc::credit_script::{CreditScript, CreditScriptVM}; @@ -404,41 +404,45 @@ impl SharedGameState { } pub fn save_game(&mut self, game_scene: &mut GameScene, ctx: &mut Context) -> GameResult { - if let Ok(data) = filesystem::open_options( - ctx, - self.get_save_filename(self.save_slot), - OpenOptions::new().write(true).create(true), - ) { - let profile = GameProfile::dump(self, game_scene); - profile.write_save(data)?; + 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); + profile.write_save(data)?; + } else { + log::warn!("Cannot open save file."); + } } else { - log::warn!("Cannot open save file."); + log::info!("Mod has saves disabled."); } Ok(()) } pub fn load_or_start_game(&mut self, ctx: &mut Context) -> GameResult { - if let Ok(data) = filesystem::user_open(ctx, self.get_save_filename(self.save_slot)) { - match GameProfile::load_from_save(data) { - Ok(profile) => { - self.reset(); - let mut next_scene = GameScene::new(self, ctx, profile.current_map as usize)?; + if let Some(save_path) = self.get_save_filename(self.save_slot) { + if let Ok(data) = filesystem::user_open(ctx, save_path) { + match GameProfile::load_from_save(data) { + Ok(profile) => { + self.reset(); + let mut next_scene = GameScene::new(self, ctx, profile.current_map as usize)?; - profile.apply(self, &mut next_scene, ctx); + profile.apply(self, &mut next_scene, ctx); - #[cfg(feature = "scripting-lua")] - self.lua.reload_scripts(ctx)?; + #[cfg(feature = "scripting-lua")] + self.lua.reload_scripts(ctx)?; - self.next_scene = Some(Box::new(next_scene)); - return Ok(()); - } - Err(e) => { - log::warn!("Failed to load save game, starting new one: {}", e); + self.next_scene = Some(Box::new(next_scene)); + return Ok(()); + } + Err(e) => { + log::warn!("Failed to load save game, starting new one: {}", e); + } } + } else { + log::warn!("No save game found, starting new one..."); } } else { - log::warn!("No save game found, starting new one..."); + log::info!("Mod has saves disabled."); } self.start_new_game(ctx) @@ -554,20 +558,29 @@ impl SharedGameState { } } - pub fn get_save_filename(&mut self, slot: usize) -> String { + pub fn get_save_filename(&mut self, slot: usize) -> Option { if let Some(mod_path) = &self.mod_path { let save_slot = self.mod_list.get_save_from_path(mod_path.to_string()); if save_slot < 0 { - return "/ModSaveDump.dat".to_owned(); + return None; } else if save_slot > 0 { - return format!("/Mod{}_Profile{}.dat", save_slot, slot); + return Some(format!("/Mod{}_Profile{}.dat", save_slot, slot)); } } if slot == 1 { - return "/Profile.dat".to_owned(); + return Some("/Profile.dat".to_owned()); } else { - return format!("/Profile{}.dat", slot); + return Some(format!("/Profile{}.dat", slot)); + } + } + + pub fn get_290_filename(&self) -> String { + if let Some(mod_path) = &self.mod_path { + let name = self.mod_list.get_name_from_path(mod_path.to_string()); + return format!("/{}.rec", name); + } else { + return "/290.rec".to_string(); } } }