Implement level wrapper type with setter functions
This commit is contained in:
parent
fe2f998810
commit
0c42c3c932
81
crates/save/src/level.rs
Normal file
81
crates/save/src/level.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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()),
|
||||||
|
Loading…
Reference in New Issue
Block a user