mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-11-28 15:27:27 +00:00
Challenge fixes: saves, nikumaru timer, menu
This commit is contained in:
parent
49d14b58a3
commit
befac5db85
|
|
@ -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<u32> {
|
||||
if let Ok(mut data) = filesystem::user_open(ctx, "/290.rec") {
|
||||
fn load_time(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult<u32> {
|
||||
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)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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<String> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue