Implement level wrapper type with setter functions

This commit is contained in:
Patrick Auernig 2023-08-16 15:24:01 +02:00
parent fe2f998810
commit 0c42c3c932
6 changed files with 98 additions and 49 deletions

81
crates/save/src/level.rs Normal file
View File

@ -0,0 +1,81 @@
use core::fmt;
use binrw::{BinRead, BinWrite};
use crate::{Error, Result};
pub const MAX_LEVEL_ID: u64 = 11;
pub const NAMES: [&str; MAX_LEVEL_ID as usize + 1] = [
"Chapter Select",
"Broken Bridge",
"Pink Desert",
"Sunken City",
"Underground",
"Tower",
"Snow",
"Paradise",
"Credits",
"Level Bryan",
"Level Matt",
"Level Chris",
];
#[derive(Debug, Clone, Copy, BinRead, BinWrite)]
pub struct Level {
#[br(assert(id <= MAX_LEVEL_ID))]
id: u64,
}
impl Level {
pub fn set_by_id(&mut self, id: u64) -> Result<()> {
if id > MAX_LEVEL_ID {
return Err(Error::LevelIdOutOfRange);
}
self.id = id;
Ok(())
}
pub fn set_by_name(&mut self, name: &str) -> Result<()> {
let id = NAMES
.iter()
.position(|&v| v == name)
.ok_or(Error::LevelNameNotFound)?;
self.id = id as u64;
Ok(())
}
pub fn wrapping_next(&self) -> Self {
let id = self.id + 1;
if id > MAX_LEVEL_ID {
Self { id: 0 }
} else {
Self { id }
}
}
pub fn wrapping_previous(&self) -> Self {
match self.id.checked_sub(1) {
Some(id) => Self { id },
None => Self { id: MAX_LEVEL_ID },
}
}
}
impl fmt::Display for Level {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", NAMES[self.id as usize])
}
}
impl AsRef<u64> for Level {
fn as_ref(&self) -> &u64 {
&self.id
}
}

View File

@ -1,5 +1,6 @@
mod companion; mod companion;
mod glyphs; mod glyphs;
mod level;
mod murals; mod murals;
mod symbol; mod symbol;
mod test; mod test;
@ -12,29 +13,15 @@ use std::path::{Path, PathBuf};
use binrw::{until_eof, BinRead, BinReaderExt, BinWriterExt}; use binrw::{until_eof, BinRead, BinReaderExt, BinWriterExt};
use chrono::{DateTime, NaiveDateTime, Utc}; use chrono::{DateTime, NaiveDateTime, Utc};
use level::Level;
use symbol::Symbol; use symbol::Symbol;
use crate::companion::{CompanionSymbols, CompanionWithId, Companions}; use crate::companion::{CompanionSymbols, CompanionWithId, Companions};
use crate::glyphs::Glyphs; use crate::glyphs::Glyphs;
pub use crate::level::NAMES as LEVEL_NAMES;
use crate::murals::Murals; use crate::murals::Murals;
pub const LEVEL_NAMES: [&str; 12] = [
"Chapter Select",
"Broken Bridge",
"Pink Desert",
"Sunken City",
"Underground",
"Tower",
"Snow",
"Paradise",
"Credits",
"Level Bryan",
"Level Matt",
"Level Chris",
];
pub type Result<T, E = Error> = std::result::Result<T, E>; pub type Result<T, E = Error> = std::result::Result<T, E>;
@ -46,6 +33,12 @@ pub enum Error {
#[error("Failed to serialize savefile")] #[error("Failed to serialize savefile")]
SerializationFailed(binrw::Error), SerializationFailed(binrw::Error),
#[error("Level id is out of range")]
LevelIdOutOfRange,
#[error("Level name was not found")]
LevelNameNotFound,
#[error("Symbol id is out of range")] #[error("Symbol id is out of range")]
SymbolIdOutOfRange, SymbolIdOutOfRange,
@ -89,8 +82,7 @@ pub struct Savefile {
#[br(count = 4)] #[br(count = 4)]
_unknown1: Vec<u8>, _unknown1: Vec<u8>,
#[br(assert(current_level <= 12))] pub current_level: Level,
pub current_level: u64,
pub total_collected_symbols: u32, pub total_collected_symbols: u32,
@ -190,10 +182,6 @@ impl Savefile {
}) })
} }
pub fn current_level_name(&self) -> &'static str {
LEVEL_NAMES[self.current_level as usize]
}
pub fn robe_color(&self) -> RobeColor { pub fn robe_color(&self) -> RobeColor {
if self.robe > 3 { if self.robe > 3 {
RobeColor::White RobeColor::White

View File

@ -18,7 +18,7 @@ fn general_info() {
assert_eq!(savefile.symbol.as_ref(), &7); assert_eq!(savefile.symbol.as_ref(), &7);
assert_eq!(savefile.scarf_length, 27); assert_eq!(savefile.scarf_length, 27);
assert_eq!(savefile.current_level, 1); assert_eq!(savefile.current_level.as_ref(), &1);
assert_eq!(savefile.total_collected_symbols, 107); assert_eq!(savefile.total_collected_symbols, 107);
assert_eq!(savefile.collected_symbols, 21); assert_eq!(savefile.collected_symbols, 21);
assert_eq!(savefile.journey_count, 21); assert_eq!(savefile.journey_count, 21);

View File

@ -59,7 +59,7 @@ fn edit_file(cur_savefile: &Savefile, args: &Args) -> Result<Savefile> {
} }
if let Some(val) = &args.current_level { if let Some(val) = &args.current_level {
savefile.current_level = LEVEL_NAMES.iter().position(|&v| v == val).unwrap() as u64; savefile.current_level.set_by_name(&val)?;
} }
if let Some(val) = args.symbol { if let Some(val) = args.symbol {

View File

@ -6,7 +6,7 @@ use std::path::Path;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use jrny_save::{RobeColor, Savefile, LEVEL_NAMES}; use jrny_save::{RobeColor, Savefile};
use ratatui::widgets::TableState; use ratatui::widgets::TableState;
use tracing::{debug, error}; use tracing::{debug, error};
use tui_input::Input; use tui_input::Input;
@ -171,13 +171,7 @@ impl State {
0 => savefile.journey_count = value.parse()?, 0 => savefile.journey_count = value.parse()?,
1 => savefile.total_companions_met = value.parse()?, 1 => savefile.total_companions_met = value.parse()?,
2 => savefile.total_collected_symbols = value.parse()?, 2 => savefile.total_collected_symbols = value.parse()?,
3 => { 3 => savefile.current_level.set_by_name(value)?,
let level_id = LEVEL_NAMES
.iter()
.position(|&v| v == value.trim_end())
.context("invalid level name")?;
savefile.current_level = level_id as u64;
}
4 => savefile.companions_met = value.parse()?, 4 => savefile.companions_met = value.parse()?,
5 => { 5 => {
let new_length = value.parse()?; let new_length = value.parse()?;
@ -222,14 +216,7 @@ impl State {
0 => savefile.journey_count += 1, 0 => savefile.journey_count += 1,
1 => savefile.total_companions_met += 1, 1 => savefile.total_companions_met += 1,
2 => savefile.total_collected_symbols += 1, 2 => savefile.total_collected_symbols += 1,
3 => { 3 => savefile.current_level = savefile.current_level.wrapping_next(),
let next_level = savefile.current_level + 1;
savefile.current_level = if next_level >= LEVEL_NAMES.len() as u64 {
0
} else {
savefile.current_level + 1
};
}
4 => savefile.companions_met += 1, 4 => savefile.companions_met += 1,
5 => { 5 => {
if savefile.scarf_length < 30 { if savefile.scarf_length < 30 {
@ -275,14 +262,7 @@ impl State {
savefile.total_collected_symbols = savefile.total_collected_symbols =
savefile.total_collected_symbols.saturating_sub(1) savefile.total_collected_symbols.saturating_sub(1)
} }
3 => { 3 => savefile.current_level = savefile.current_level.wrapping_previous(),
let next_level: i64 = savefile.current_level as i64 - 1;
savefile.current_level = if next_level < 0 {
LEVEL_NAMES.len() as u64 - 1
} else {
next_level as u64
};
}
4 => savefile.companions_met = savefile.companions_met.saturating_sub(1), 4 => savefile.companions_met = savefile.companions_met.saturating_sub(1),
5 => { 5 => {
if savefile.scarf_length > 0 { if savefile.scarf_length > 0 {

View File

@ -52,7 +52,7 @@ pub(super) fn render<'a>(state: &mut State, frame: &mut Frame, area: Rect) {
"Total Symbols Collected", "Total Symbols Collected",
savefile.total_collected_symbols.to_string(), savefile.total_collected_symbols.to_string(),
), ),
("Current Level", savefile.current_level_name().to_string()), ("Current Level", savefile.current_level.to_string()),
("Companions Met", savefile.companions_met.to_string()), ("Companions Met", savefile.companions_met.to_string()),
("Scarf Length", savefile.scarf_length.to_string()), ("Scarf Length", savefile.scarf_length.to_string()),
("Symbol Number", savefile.symbol.as_ref().to_string()), ("Symbol Number", savefile.symbol.as_ref().to_string()),