record last challenge attempts

This commit is contained in:
Sallai József 2022-08-14 14:19:46 +03:00
parent 290068dd37
commit b1d578c0b4
9 changed files with 95 additions and 42 deletions

View File

@ -55,7 +55,8 @@
"start": "Start",
"no_replay": "No Replay",
"replay_best": "Replay Best",
"delete_replay": "Delete Replay"
"replay_last": "Replay Last",
"delete_replay": "Delete Best Replay"
},
"options_menu": {
@ -162,6 +163,8 @@
"cancel": "(Esc to cancel)"
},
"rumble": "Rumble:",
"reset_confirm": "Reset...",
"reset_confirm_menu_title": "Reset controls?"
}

View File

@ -49,7 +49,8 @@
"start": "スタート",
"no_replay": "ノーリプレイ",
"replay_best": "ベストプレイを再生",
"delete_replay": "リプレイを削除"
"replay_last": "最後のプレイを再生",
"delete_replay": "ベストリプレイを削除"
},
"options_menu": {
"graphics": "グラフィック",
@ -154,6 +155,8 @@
"cancel": "(Escキーを押してキャンセル)"
},
"rumble": "ランブル",
"reset_confirm": "リセット",
"reset_confirm_menu_title": "ボタンをリセットしますか?"
}

View File

@ -11,7 +11,7 @@ use crate::framework::keyboard::ScanCode;
use crate::framework::vfs::OpenOptions;
use crate::input::replay_player_controller::{KeyState, ReplayController};
use crate::player::Player;
use crate::shared_game_state::{ReplayState, SharedGameState};
use crate::shared_game_state::{ReplayKind, ReplayState, SharedGameState};
#[derive(Clone)]
pub struct Replay {
@ -46,26 +46,42 @@ impl Replay {
}
}
pub fn stop_recording(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
pub fn stop_recording(
&mut self,
state: &mut SharedGameState,
ctx: &mut Context,
is_new_record: bool,
) -> GameResult {
state.replay_state = ReplayState::None;
self.write_replay(state, ctx)?;
self.write_replay(state, ctx, ReplayKind::Last)?;
if is_new_record {
self.write_replay(state, ctx, ReplayKind::Best)?;
}
Ok(())
}
pub fn initialize_playback(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
pub fn initialize_playback(
&mut self,
state: &mut SharedGameState,
ctx: &mut Context,
replay_kind: ReplayKind,
) -> GameResult {
if !self.is_active {
state.replay_state = ReplayState::Playback;
self.read_replay(state, ctx)?;
state.replay_state = ReplayState::Playback(replay_kind);
self.read_replay(state, ctx, replay_kind)?;
state.game_rng.load_state(self.rng_seed);
self.is_active = true;
}
Ok(())
}
fn write_replay(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
fn write_replay(&mut self, state: &mut SharedGameState, ctx: &mut Context, replay_kind: ReplayKind) -> GameResult {
if let Ok(mut file) = filesystem::open_options(
ctx,
[state.get_rec_filename(), ".rep".to_string()].join(""),
[state.get_rec_filename(), replay_kind.get_suffix()].join(""),
OpenOptions::new().write(true).create(true),
) {
file.write_u16::<LE>(0)?; // Space for versioning replay files
@ -77,8 +93,9 @@ impl Replay {
Ok(())
}
fn read_replay(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
if let Ok(mut file) = filesystem::user_open(ctx, [state.get_rec_filename(), ".rep".to_string()].join("")) {
fn read_replay(&mut self, state: &mut SharedGameState, ctx: &mut Context, replay_kind: ReplayKind) -> GameResult {
if let Ok(mut file) = filesystem::user_open(ctx, [state.get_rec_filename(), replay_kind.get_suffix()].join(""))
{
self.replay_version = file.read_u16::<LE>()?;
self.rng_seed = file.read_u64::<LE>()?;
@ -120,7 +137,7 @@ impl GameEntity<(&mut Context, &mut Player)> for Replay {
self.keylist.push(inputs);
}
ReplayState::Playback => {
ReplayState::Playback(_) => {
let pause = ctx.keyboard_context.is_key_pressed(ScanCode::Escape) && (self.tick - self.resume_tick > 3);
let next_input = if pause { 1 << 10 } else { *self.keylist.get(self.tick).unwrap_or(&0) };
@ -153,7 +170,7 @@ impl GameEntity<(&mut Context, &mut Player)> for Replay {
match state.replay_state {
ReplayState::None => {}
ReplayState::Playback => {
ReplayState::Playback(_) => {
state.font.draw_text_with_shadow(
"PLAY".chars(),
x,

View File

@ -430,7 +430,8 @@ impl ControlsMenu {
self.main.set_entry(MainMenuEntry::Rumble, MenuEntry::Hidden);
} else {
self.selected_controller = controller_type;
self.main.set_entry(MainMenuEntry::Rumble, MenuEntry::Toggle("Rumble".to_string(), rumble));
self.main
.set_entry(MainMenuEntry::Rumble, MenuEntry::Toggle(state.t("menus.controls_menu.rumble"), rumble));
}
} else {
self.selected_controller = controller_type;

View File

@ -78,12 +78,12 @@ impl PlayerCountMenu {
fn update_sizes(&mut self, state: &SharedGameState) {
self.coop_menu.update_width(state);
self.coop_menu.update_height();
self.coop_menu.x = ((state.canvas_size.0 - self.coop_menu.width as f32) / 2.3).floor() as isize;
self.coop_menu.x = ((state.canvas_size.0 - self.coop_menu.width as f32) / 2.0).floor() as isize;
self.coop_menu.y = 30 + ((state.canvas_size.1 - self.coop_menu.height as f32) / 2.0).floor() as isize;
self.skin_menu.update_width(state);
self.skin_menu.update_height();
self.skin_menu.x = ((state.canvas_size.0 - self.coop_menu.width as f32) / 2.3).floor() as isize;
self.skin_menu.x = ((state.canvas_size.0 - self.coop_menu.width as f32) / 2.0).floor() as isize;
self.skin_menu.y = 30 + ((state.canvas_size.1 - self.coop_menu.height as f32) / 2.0).floor() as isize;
}

View File

@ -1633,8 +1633,10 @@ impl Scene for GameScene {
self.drop_player2();
}
if state.mod_path.is_some() && state.replay_state == ReplayState::Playback {
self.replay.initialize_playback(state, ctx)?;
if state.mod_path.is_some() {
if let ReplayState::Playback(replay_kind) = state.replay_state {
self.replay.initialize_playback(state, ctx, replay_kind)?;
}
}
self.npc_list.set_rng_seed(state.game_rng.next());
@ -1724,8 +1726,10 @@ impl Scene for GameScene {
}
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
if !self.pause_menu.is_paused() && state.replay_state == ReplayState::Playback {
self.replay.tick(state, (ctx, &mut self.player1))?;
if !self.pause_menu.is_paused() {
if let ReplayState::Playback(_) = state.replay_state {
self.replay.tick(state, (ctx, &mut self.player1))?;
}
}
self.player1.controller.update(state, ctx)?;

View File

@ -14,7 +14,9 @@ use crate::menu::settings_menu::SettingsMenu;
use crate::menu::{Menu, MenuEntry, MenuSelectionResult};
use crate::scene::jukebox_scene::JukeboxScene;
use crate::scene::Scene;
use crate::shared_game_state::{GameDifficulty, MenuCharacter, ReplayState, Season, SharedGameState, TileSize};
use crate::shared_game_state::{
GameDifficulty, MenuCharacter, ReplayKind, ReplayState, Season, SharedGameState, TileSize,
};
use crate::stage::{BackgroundType, NpcType, Stage, StageData, StageTexturePaths, Tileset};
#[derive(PartialEq, Eq, Copy, Clone)]
@ -61,7 +63,7 @@ impl Default for ChallengesMenuEntry {
pub enum ConfirmMenuEntry {
Title,
StartChallenge,
ReplayBest,
Replay(ReplayKind),
DeleteReplay,
Back,
}
@ -248,8 +250,8 @@ impl Scene for TitleScene {
self.confirm_menu.push_entry(ConfirmMenuEntry::Title, MenuEntry::Disabled("".to_owned()));
self.confirm_menu
.push_entry(ConfirmMenuEntry::StartChallenge, MenuEntry::Active(state.t("menus.challenge_menu.start")));
self.confirm_menu
.push_entry(ConfirmMenuEntry::ReplayBest, MenuEntry::Disabled(state.t("menus.challenge_menu.no_replay")));
self.confirm_menu.push_entry(ConfirmMenuEntry::Replay(ReplayKind::Best), MenuEntry::Hidden);
self.confirm_menu.push_entry(ConfirmMenuEntry::Replay(ReplayKind::Last), MenuEntry::Hidden);
self.confirm_menu.push_entry(ConfirmMenuEntry::DeleteReplay, MenuEntry::Hidden);
self.confirm_menu.push_entry(ConfirmMenuEntry::Back, MenuEntry::Active(state.t("common.back")));
self.confirm_menu.selected = ConfirmMenuEntry::StartChallenge;
@ -356,9 +358,9 @@ impl Scene for TitleScene {
self.confirm_menu.set_entry(ConfirmMenuEntry::Title, MenuEntry::Disabled(mod_name));
if state.has_replay_data(ctx) {
if state.has_replay_data(ctx, ReplayKind::Best) {
self.confirm_menu.set_entry(
ConfirmMenuEntry::ReplayBest,
ConfirmMenuEntry::Replay(ReplayKind::Best),
MenuEntry::Active(state.t("menus.challenge_menu.replay_best")),
);
self.confirm_menu.set_entry(
@ -366,13 +368,21 @@ impl Scene for TitleScene {
MenuEntry::Active(state.t("menus.challenge_menu.delete_replay")),
);
} else {
self.confirm_menu.set_entry(
ConfirmMenuEntry::ReplayBest,
MenuEntry::Disabled(state.t("menus.challenge_menu.no_replay")),
);
self.confirm_menu
.set_entry(ConfirmMenuEntry::Replay(ReplayKind::Best), MenuEntry::Hidden);
self.confirm_menu.set_entry(ConfirmMenuEntry::DeleteReplay, MenuEntry::Hidden);
}
if state.has_replay_data(ctx, ReplayKind::Last) {
self.confirm_menu.set_entry(
ConfirmMenuEntry::Replay(ReplayKind::Last),
MenuEntry::Active(state.t("menus.challenge_menu.replay_last")),
);
} else {
self.confirm_menu
.set_entry(ConfirmMenuEntry::Replay(ReplayKind::Last), MenuEntry::Hidden);
}
self.nikumaru_rec.load_counter(state, ctx)?;
self.current_menu = CurrentMenu::ChallengeConfirmMenu;
}
@ -391,14 +401,14 @@ impl Scene for TitleScene {
state.replay_state = ReplayState::Recording;
self.current_menu = CurrentMenu::PlayerCountMenu;
}
MenuSelectionResult::Selected(ConfirmMenuEntry::ReplayBest, _) => {
MenuSelectionResult::Selected(ConfirmMenuEntry::Replay(kind), _) => {
state.difficulty = GameDifficulty::Normal;
state.replay_state = ReplayState::Playback;
state.replay_state = ReplayState::Playback(kind);
state.reload_resources(ctx)?;
state.start_new_game(ctx)?;
}
MenuSelectionResult::Selected(ConfirmMenuEntry::DeleteReplay, _) => {
state.delete_replay_data(ctx)?;
state.delete_replay_data(ctx, ReplayKind::Best)?;
self.current_menu = CurrentMenu::ChallengesMenu;
}
MenuSelectionResult::Selected(ConfirmMenuEntry::Back, _) | MenuSelectionResult::Canceled => {

View File

@ -1755,8 +1755,8 @@ impl TextScriptVM {
TSCOpCode::STC => {
let new_record = game_scene.nikumaru.save_counter(state, ctx)?;
if new_record && state.replay_state == ReplayState::Recording {
game_scene.replay.stop_recording(state, ctx)?;
if state.replay_state == ReplayState::Recording {
game_scene.replay.stop_recording(state, ctx, new_record)?;
}
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);

View File

@ -243,11 +243,26 @@ pub enum MenuCharacter {
Sue,
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum ReplayKind {
Best,
Last,
}
impl ReplayKind {
pub fn get_suffix(&self) -> String {
match self {
ReplayKind::Best => ".rep".to_string(),
ReplayKind::Last => ".last.rep".to_string(),
}
}
}
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum ReplayState {
None,
Recording,
Playback,
Playback(ReplayKind),
}
#[derive(PartialEq, Eq, Copy, Clone)]
@ -805,13 +820,13 @@ impl SharedGameState {
}
}
pub fn has_replay_data(&self, ctx: &mut Context) -> bool {
filesystem::user_exists(ctx, [self.get_rec_filename(), ".rep".to_string()].join(""))
pub fn has_replay_data(&self, ctx: &mut Context, replay_kind: ReplayKind) -> bool {
filesystem::user_exists(ctx, [self.get_rec_filename(), replay_kind.get_suffix()].join(""))
}
pub fn delete_replay_data(&self, ctx: &mut Context) -> GameResult {
if self.has_replay_data(ctx) {
filesystem::user_delete(ctx, [self.get_rec_filename(), ".rep".to_string()].join(""))?;
pub fn delete_replay_data(&self, ctx: &mut Context, replay_kind: ReplayKind) -> GameResult {
if self.has_replay_data(ctx, replay_kind) {
filesystem::user_delete(ctx, [self.get_rec_filename(), replay_kind.get_suffix()].join(""))?;
}
Ok(())
}