mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-08 19:34:27 +00:00
Added various lints.
Removed `Structure` interface.
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
//! Game Data
|
||||
//!
|
||||
//! The game module is where all of the game data is defined, this game data
|
||||
//! can read from the [GameFile](crate::io::GameFile) in the `io` module.
|
||||
//! can read from the [`GameFile`](crate::io::GameFile) in the `io` module.
|
||||
//!
|
||||
//! Some notable types within this module are [CardTable](crate::game::card::Table), the table which
|
||||
//! stores all cards and [DeckTable](crate::game::deck::Table), the table which stores all cards available.
|
||||
//! Some notable types within this module are [`CardTable`](crate::game::card::Table), the table which
|
||||
//! stores all cards and [`DeckTable`](crate::game::deck::Table), the table which stores all cards available.
|
||||
//!
|
||||
//! # Strings
|
||||
//! A lot of types in this module have strings that they must read and write from the game.
|
||||
@@ -17,8 +17,6 @@
|
||||
// Modules
|
||||
#[macro_use] pub mod util;
|
||||
|
||||
pub mod structure;
|
||||
|
||||
pub mod bytes;
|
||||
pub mod from_bytes;
|
||||
pub mod to_bytes;
|
||||
@@ -32,6 +30,5 @@ pub mod deck;
|
||||
pub use bytes::Bytes;
|
||||
pub use from_bytes::FromBytes;
|
||||
pub use to_bytes::ToBytes;
|
||||
pub use structure::Structure;
|
||||
|
||||
pub use card::Digimon;
|
||||
|
||||
@@ -5,27 +5,30 @@
|
||||
//! # Layout
|
||||
//! The digimon card has a size of 0x138 bytes, and it's layout is the following:
|
||||
//!
|
||||
//! | Offset | Size | Name | Location | Details |
|
||||
//! |--------|------|---------------------------|------------------------------|-------------------------------------------------------------------------------------|
|
||||
//! | 0x0 | 0x15 | Name | basic.name | |
|
||||
//! | 0x15 | 0x2 | Unknown | basic.unknown_1 | Most likely contains the digimon's model |
|
||||
//! | 0x17 | 0x1 | Speciality & Level | basic.speciality basic.level | The bottom nibble of this byte is the level, while the top nibble is the speciality |
|
||||
//! | 0x18 | 0x1 | DP | basic.dp_cost | |
|
||||
//! | 0x19 | 0x1 | +P | basic.dp_give | |
|
||||
//! | 0x1a | 0x1 | Unknown | basic.unknown_0 | Is `0` for all digimon |
|
||||
//! | 0x1b | 0x2 | Health | basic.hp | |
|
||||
//! | 0x1d | 0x1c | Circle Move | moves.circle | |
|
||||
//! | 0x39 | 0x1c | Triangle move | moves.triangle | |
|
||||
//! | 0x55 | 0x1c | Cross move | moves.cross | |
|
||||
//! | 0x71 | 0x20 | First condition | effects.conditions.first | |
|
||||
//! | 0x91 | 0x20 | Second condition | effects.conditions.second | |
|
||||
//! | 0xb1 | 0x10 | First effect | support.effects.first | |
|
||||
//! | 0xc1 | 0x10 | Second effect | support.effects.second | |
|
||||
//! | 0xd1 | 0x10 | Third effect | support.effects.third | |
|
||||
//! | 0xe1 | 0x1 | Cross move effect | support.cross_move | |
|
||||
//! | 0xe2 | 0x1 | Unknown | support.unknown | |
|
||||
//! | 0xe3 | 0x1 | Effect arrow color | effects.arrow_color | |
|
||||
//! | 0xe4 | 0x54 | Effect description lines | effects.description | Each line is `0x15` bytes, split over 4 lines |
|
||||
//! | Offset | Size | Type | Name | Location | Details |
|
||||
//! |--------|------|----------------------|---------------------------|--------------------------------|-------------------------------------------------------------------------------------|
|
||||
//! | 0x0 | 0x15 | `char[0x15]` | Name |` basic.name` | |
|
||||
//! | 0x15 | 0x2 | `u16` | Unknown |` basic.unknown_1` | Most likely contains the digimon's model |
|
||||
//! | 0x17 | 0x1 | `u8` | Speciality & Level |` basic.speciality basic.level` | The bottom nibble of this byte is the level, while the top nibble is the speciality |
|
||||
//! | 0x18 | 0x1 | `u8` | DP |` basic.dp_cost` | |
|
||||
//! | 0x19 | 0x1 | `u8` | +P |` basic.dp_give` | |
|
||||
//! | 0x1a | 0x1 | `u8` | Unknown |` basic.unknown_0` | Is` 0` for all digimon |
|
||||
//! | 0x1b | 0x2 | `u16` | Health |` basic.hp` | |
|
||||
//! | 0x1d | 0x1c | [`Move`] | Circle Move |` moves.circle` | |
|
||||
//! | 0x39 | 0x1c | [`Move`] | Triangle move |` moves.triangle` | |
|
||||
//! | 0x55 | 0x1c | [`Move`] | Cross move |` moves.cross` | |
|
||||
//! | 0x71 | 0x20 | [`SupportCondition`] | First condition |` effects.conditions.first` | |
|
||||
//! | 0x91 | 0x20 | [`SupportCondition`] | Second condition |` effects.conditions.second` | |
|
||||
//! | 0xb1 | 0x10 | [`SupportEffect`] | First effect |` support.effects.first` | |
|
||||
//! | 0xc1 | 0x10 | [`SupportEffect`] | Second effect |` support.effects.second` | |
|
||||
//! | 0xd1 | 0x10 | [`SupportEffect`] | Third effect |` support.effects.third` | |
|
||||
//! | 0xe1 | 0x1 | [`CrossMoveEffect`] | Cross move effect |` support.cross_move` | |
|
||||
//! | 0xe2 | 0x1 | `u8` | Unknown |` support.unknown` | |
|
||||
//! | 0xe3 | 0x1 | [`ArrowColor`] | Effect arrow color |` effects.arrow_color` | |
|
||||
//! | 0xe4 | 0x54 | `char[0x15][4]` | Effect description lines |` effects.description` | Each line is` 0x15` bytes, split over 4 lines |
|
||||
|
||||
// byteorder
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
// Crate
|
||||
use crate::game::{
|
||||
@@ -36,211 +39,205 @@ use crate::game::{
|
||||
}
|
||||
};
|
||||
|
||||
// byteorder
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
/// A digimon card
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Digimon
|
||||
{
|
||||
/// The basic info of the digimon
|
||||
pub basic: Basic,
|
||||
|
||||
/// The moves
|
||||
pub moves: Moves,
|
||||
|
||||
/// The support
|
||||
pub support: Support,
|
||||
}
|
||||
|
||||
// Types
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// A digimon card
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Digimon
|
||||
{
|
||||
/// The basic info of the digimon
|
||||
pub basic: Basic,
|
||||
|
||||
/// The moves
|
||||
pub moves: Moves,
|
||||
|
||||
/// The support
|
||||
pub support: Support,
|
||||
}
|
||||
/// The basic properties of a digimon
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Basic
|
||||
{
|
||||
pub name: String,
|
||||
pub speciality: Speciality,
|
||||
pub level: Level,
|
||||
pub hp: u16,
|
||||
|
||||
/// The basic properties of a digimon
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Basic
|
||||
{
|
||||
pub name: String,
|
||||
pub speciality: Speciality,
|
||||
pub level: Level,
|
||||
pub hp: u16,
|
||||
|
||||
/// `DP` in the game.
|
||||
pub dp_cost: u8,
|
||||
|
||||
/// `+P` in the game.
|
||||
pub dp_give: u8,
|
||||
|
||||
// Unknown fields
|
||||
pub unknown_0: u8,
|
||||
pub unknown_1: u16,
|
||||
}
|
||||
/// `DP` in the game.
|
||||
pub dp_cost: u8,
|
||||
|
||||
/// The moves a digimon has
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Moves
|
||||
{
|
||||
pub circle : Move,
|
||||
pub triangle: Move,
|
||||
pub cross : Move,
|
||||
}
|
||||
/// `+P` in the game.
|
||||
pub dp_give: u8,
|
||||
|
||||
/// The support effect of a digimon
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Support
|
||||
{
|
||||
/// Unknown field
|
||||
pub unknown: u8,
|
||||
|
||||
/// The cross move effect
|
||||
pub cross_move: Option<CrossMoveEffect>,
|
||||
|
||||
/// The effect description
|
||||
pub description: [String; 4],
|
||||
|
||||
/// The effect arrow color
|
||||
pub arrow_color: Option<ArrowColor>,
|
||||
|
||||
/// The effect conditions
|
||||
pub conditions: SupportConditions,
|
||||
|
||||
/// The effects themselves
|
||||
pub effects: SupportSupport,
|
||||
}
|
||||
// Unknown fields
|
||||
pub unknown_0: u8,
|
||||
pub unknown_1: u16,
|
||||
}
|
||||
|
||||
/// The moves a digimon has
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Moves
|
||||
{
|
||||
pub circle : Move,
|
||||
pub triangle: Move,
|
||||
pub cross : Move,
|
||||
}
|
||||
|
||||
/// The support effect of a digimon
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Support
|
||||
{
|
||||
/// Unknown field
|
||||
pub unknown: u8,
|
||||
|
||||
/// All of the support effects
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct SupportSupport
|
||||
{
|
||||
pub first : Option<SupportEffect>,
|
||||
pub second: Option<SupportEffect>,
|
||||
pub third : Option<SupportEffect>,
|
||||
}
|
||||
/// The cross move effect
|
||||
pub cross_move: Option<CrossMoveEffect>,
|
||||
|
||||
/// All of the support effect conditions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct SupportConditions
|
||||
{
|
||||
pub first : Option<SupportCondition>,
|
||||
pub second: Option<SupportCondition>,
|
||||
}
|
||||
/// The effect description
|
||||
pub description: [String; 4],
|
||||
|
||||
/// The error type thrown by [`FromBytes`]
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum FromBytesError
|
||||
{
|
||||
/// Unable to convert name to a string
|
||||
#[display(fmt = "Unable to convert name to a string")]
|
||||
NameToString( util::ReadNullTerminatedStringError ),
|
||||
|
||||
/// Unable to convert one of the support effect descriptions to a string
|
||||
#[display(fmt = "The {} support effect description could not be converted to a string", rank)]
|
||||
SupportEffectDescriptionToString {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
err: util::ReadNullTerminatedStringError,
|
||||
},
|
||||
|
||||
/// An unknown speciality was found
|
||||
#[display(fmt = "Unknown speciality found")]
|
||||
UnknownSpeciality( crate::game::card::property::speciality::UnknownSpeciality ),
|
||||
|
||||
/// An unknown level was found
|
||||
#[display(fmt = "Unknown level found")]
|
||||
UnknownLevel( crate::game::card::property::level::UnknownLevel ),
|
||||
|
||||
/// An unknown effect arrow color was found
|
||||
#[display(fmt = "Unknown effect arrow color found")]
|
||||
UnknownEffectArrowColor( crate::game::card::property::arrow_color::UnknownArrowColor ),
|
||||
|
||||
/// An unknown cross move effect was found
|
||||
#[display(fmt = "Unknown cross move effect found")]
|
||||
UnknownCrossMoveEffect( crate::game::card::property::cross_move_effect::UnknownCrossMoveEffect ),
|
||||
|
||||
/// Unable to read a support effect condition
|
||||
#[display(fmt = "Unable to read the {0} support effect condition", rank)]
|
||||
SupportCondition {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::support_condition::FromBytesError,
|
||||
},
|
||||
|
||||
/// Unable to read a support effect
|
||||
#[display(fmt = "Unable to read the {} support effect", rank)]
|
||||
SupportEffect {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::support_effect::FromBytesError,
|
||||
},
|
||||
|
||||
/// Unable to read a move
|
||||
#[display(fmt = "Unable to read the {} move", name)]
|
||||
Move {
|
||||
name: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::moves::FromBytesError,
|
||||
},
|
||||
}
|
||||
/// The effect arrow color
|
||||
pub arrow_color: Option<ArrowColor>,
|
||||
|
||||
/// The error type thrown by `ToBytes`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum ToBytesError
|
||||
{
|
||||
/// The name was too long to be written to file
|
||||
#[display(fmt = r#"The name "{}" is too long to be written to file"#, name)]
|
||||
NameTooLong {
|
||||
name: String,
|
||||
|
||||
|
||||
err: crate::game::util::WriteNullTerminatedStringError,
|
||||
},
|
||||
|
||||
/// The name was not ascii
|
||||
#[display(fmt = r#"The name "{}" is not valid ascii"#, name)]
|
||||
NameNotAscii {
|
||||
name: String,
|
||||
},
|
||||
/// The effect conditions
|
||||
pub conditions: SupportConditions,
|
||||
|
||||
/// The effects themselves
|
||||
pub effects: SupportSupport,
|
||||
}
|
||||
|
||||
/// All of the support effects
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct SupportSupport
|
||||
{
|
||||
pub first : Option<SupportEffect>,
|
||||
pub second: Option<SupportEffect>,
|
||||
pub third : Option<SupportEffect>,
|
||||
}
|
||||
|
||||
/// All of the support effect conditions
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct SupportConditions
|
||||
{
|
||||
pub first : Option<SupportCondition>,
|
||||
pub second: Option<SupportCondition>,
|
||||
}
|
||||
|
||||
/// The error type thrown by [`FromBytes`]
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum FromBytesError
|
||||
{
|
||||
/// Unable to convert name to a string
|
||||
#[display(fmt = "Unable to convert name to a string")]
|
||||
NameToString( util::ReadNullTerminatedStringError ),
|
||||
|
||||
/// Unable to convert one of the support effect descriptions to a string
|
||||
#[display(fmt = "The {} support effect description could not be converted to a string", rank)]
|
||||
SupportEffectDescriptionToString {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
|
||||
/// A support effect description was too long to be written to file
|
||||
#[display(fmt = r#"The {0} support effect description "{1}" is too long to be written to file"#, rank, string)]
|
||||
SupportEffectDescriptionTooLong {
|
||||
string: String,
|
||||
rank: String,
|
||||
|
||||
|
||||
err: crate::game::util::WriteNullTerminatedStringError,
|
||||
},
|
||||
|
||||
/// A support effect description was not ascii
|
||||
#[display(fmt = r#"The {0} support effect description "{1}" is not valid ascii"#, rank, name)]
|
||||
SupportEffectDescriptionNotAscii {
|
||||
name: String,
|
||||
rank: String,
|
||||
},
|
||||
err: util::ReadNullTerminatedStringError,
|
||||
},
|
||||
|
||||
/// An unknown speciality was found
|
||||
#[display(fmt = "Unknown speciality found")]
|
||||
UnknownSpeciality( crate::game::card::property::speciality::UnknownSpeciality ),
|
||||
|
||||
/// An unknown level was found
|
||||
#[display(fmt = "Unknown level found")]
|
||||
UnknownLevel( crate::game::card::property::level::UnknownLevel ),
|
||||
|
||||
/// An unknown effect arrow color was found
|
||||
#[display(fmt = "Unknown effect arrow color found")]
|
||||
UnknownEffectArrowColor( crate::game::card::property::arrow_color::UnknownArrowColor ),
|
||||
|
||||
/// An unknown cross move effect was found
|
||||
#[display(fmt = "Unknown cross move effect found")]
|
||||
UnknownCrossMoveEffect( crate::game::card::property::cross_move_effect::UnknownCrossMoveEffect ),
|
||||
|
||||
/// Unable to read a support effect condition
|
||||
#[display(fmt = "Unable to read the {0} support effect condition", rank)]
|
||||
SupportCondition {
|
||||
rank: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::support_condition::FromBytesError,
|
||||
},
|
||||
|
||||
/// Unable to read a support effect
|
||||
#[display(fmt = "Unable to read the {} support effect", rank)]
|
||||
SupportEffect {
|
||||
rank: &'static str,
|
||||
|
||||
/// Unable to write a move
|
||||
#[display(fmt = "Unable to write the {} move", name)]
|
||||
Move {
|
||||
name: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::moves::ToBytesError,
|
||||
},
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
err: crate::game::card::property::support_effect::FromBytesError,
|
||||
},
|
||||
|
||||
/// Unable to read a move
|
||||
#[display(fmt = "Unable to read the {} move", name)]
|
||||
Move {
|
||||
name: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::moves::FromBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
/// The error type thrown by `ToBytes`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum ToBytesError
|
||||
{
|
||||
/// The name was too long to be written to file
|
||||
#[display(fmt = r#"The name "{}" is too long to be written to file"#, name)]
|
||||
NameTooLong {
|
||||
name: String,
|
||||
|
||||
|
||||
err: crate::game::util::WriteNullTerminatedStringError,
|
||||
},
|
||||
|
||||
/// The name was not ascii
|
||||
#[display(fmt = r#"The name "{}" is not valid ascii"#, name)]
|
||||
NameNotAscii {
|
||||
name: String,
|
||||
},
|
||||
|
||||
|
||||
|
||||
/// A support effect description was too long to be written to file
|
||||
#[display(fmt = r#"The {0} support effect description "{1}" is too long to be written to file"#, rank, string)]
|
||||
SupportEffectDescriptionTooLong {
|
||||
string: String,
|
||||
rank: String,
|
||||
|
||||
|
||||
err: crate::game::util::WriteNullTerminatedStringError,
|
||||
},
|
||||
|
||||
/// A support effect description was not ascii
|
||||
#[display(fmt = r#"The {0} support effect description "{1}" is not valid ascii"#, rank, name)]
|
||||
SupportEffectDescriptionNotAscii {
|
||||
name: String,
|
||||
rank: String,
|
||||
},
|
||||
|
||||
|
||||
|
||||
/// Unable to write a move
|
||||
#[display(fmt = "Unable to write the {} move", name)]
|
||||
Move {
|
||||
name: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::moves::ToBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
// Impl
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -257,8 +254,16 @@ use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error>
|
||||
{
|
||||
// Note: We can't use `TryInto` because it only supports arrays up to 32
|
||||
// SAFETY: Safe as we checked the length
|
||||
assert!(bytes.len() == Self::BUF_BYTE_SIZE);
|
||||
let bytes: &[u8; Self::BUF_BYTE_SIZE] = unsafe {
|
||||
#[allow(clippy::as_conversions)]
|
||||
&*( bytes.as_ptr() as *const [u8; Self::BUF_BYTE_SIZE] )
|
||||
};
|
||||
|
||||
// Return the struct after building it
|
||||
Ok( Digimon {
|
||||
Ok( Self {
|
||||
// 0x0 - 0x1d
|
||||
basic: Basic {
|
||||
name : util::read_null_terminated_string( &bytes[0x0..0x15] ) .map_err(FromBytesError::NameToString)?.to_string(),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! Digivolve
|
||||
|
||||
// Crate
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Game
|
||||
@@ -142,7 +144,7 @@ use serde::Deserialize;
|
||||
|
||||
fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error>
|
||||
{
|
||||
Ok( Digivolve {
|
||||
Ok( Self {
|
||||
basic: Basic {
|
||||
name: util::read_null_terminated_string( &bytes[0x0..0x15] ).map_err(FromBytesError::NameToString)?.to_string(),
|
||||
},
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! Item
|
||||
|
||||
// Crate
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Game
|
||||
@@ -142,7 +144,7 @@ use serde::Deserialize;
|
||||
//assert_eq!(bytes[0x1a], 0);
|
||||
|
||||
// And return the struct
|
||||
Ok( Item {
|
||||
Ok( Self {
|
||||
basic: Basic {
|
||||
name: util::read_null_terminated_string( &bytes[0x0..0x15] ).map_err(FromBytesError::NameToString)?.to_string(),
|
||||
|
||||
|
||||
@@ -151,15 +151,16 @@
|
||||
impl CardType
|
||||
{
|
||||
/// Returns the byte size of the corresponding card
|
||||
#[must_use]
|
||||
pub fn card_byte_size(self) -> usize
|
||||
{
|
||||
use crate::game::Bytes;
|
||||
|
||||
match self
|
||||
{
|
||||
CardType::Digimon => <crate::game::card::Digimon as Bytes>::BUF_BYTE_SIZE,
|
||||
CardType::Item => <crate::game::card::Item as Bytes>::BUF_BYTE_SIZE,
|
||||
CardType::Digivolve => <crate::game::card::Digivolve as Bytes>::BUF_BYTE_SIZE,
|
||||
Self::Digimon => <crate::game::card::Digimon as Bytes>::BUF_BYTE_SIZE,
|
||||
Self::Item => <crate::game::card::Item as Bytes>::BUF_BYTE_SIZE,
|
||||
Self::Digivolve => <crate::game::card::Digivolve as Bytes>::BUF_BYTE_SIZE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ use byteorder::LittleEndian;
|
||||
fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error>
|
||||
{
|
||||
// And return the move
|
||||
Ok( Move {
|
||||
Ok( Self {
|
||||
name : util::read_null_terminated_string( &bytes[0x6..0x1c] ).map_err(FromBytesError::NameToString)?.to_string(),
|
||||
power : LittleEndian::read_u16( &bytes[0x0..0x2] ),
|
||||
unknown: LittleEndian::read_u32( &bytes[0x2..0x6] ),
|
||||
|
||||
@@ -76,7 +76,7 @@ use byteorder::{ByteOrder, LittleEndian};
|
||||
let cond = DigimonProperty::from_bytes( &bytes[0x2..0x3] ).map_err(FromBytesError::Condition)?;
|
||||
|
||||
// And return the move
|
||||
Ok( SupportCondition {
|
||||
Ok( Self {
|
||||
misfire: { bytes[0x0] != 0 },
|
||||
cond,
|
||||
|
||||
@@ -112,10 +112,12 @@ use byteorder::{ByteOrder, LittleEndian};
|
||||
bytes[0x1] = 0;
|
||||
|
||||
// 0x2 - Condition
|
||||
self.cond.to_bytes(&mut bytes[0x2..0x3])?;
|
||||
#[allow(clippy::diverging_sub_expression)] { // False positive
|
||||
self.cond.to_bytes(&mut bytes[0x2..0x3])?;
|
||||
}
|
||||
|
||||
// 0x3..0x8 - Unknown[0..5]
|
||||
for i in 0..5 { bytes[0x3 + i] = self.unknown[0 + i]; }
|
||||
bytes[0x3..0x8].copy_from_slice( &self.unknown[0..5] );
|
||||
|
||||
// 0x8 - Type arg / 0 if None
|
||||
if let Some(type_arg) = self.type_arg {
|
||||
@@ -124,13 +126,15 @@ use byteorder::{ByteOrder, LittleEndian};
|
||||
else { bytes[0x8] = 0; }
|
||||
|
||||
// 0x9..0x14 - Unknown[5..16]
|
||||
for i in 0..11 { bytes[0x9 + i] = self.unknown[5 + i]; }
|
||||
bytes[0x9..0x14].copy_from_slice( &self.unknown[5..16] );
|
||||
|
||||
// 0x14..0x16 - Number arg
|
||||
LittleEndian::write_u16(&mut bytes[0x14..0x16], self.num_arg);
|
||||
|
||||
// 0x1a - Operation arg
|
||||
self.operation.to_bytes(&mut bytes[0x1a..0x1b])?;
|
||||
#[allow(clippy::diverging_sub_expression)] { // False positive
|
||||
self.operation.to_bytes(&mut bytes[0x1a..0x1b])?;
|
||||
}
|
||||
|
||||
// And return OK
|
||||
Ok(())
|
||||
|
||||
@@ -1,19 +1,32 @@
|
||||
// Crate
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Game
|
||||
use crate::game::{Bytes, FromBytes, ToBytes};
|
||||
use crate::game::card::property::{DigimonProperty, SupportEffectOperation, AttackType, PlayerType, Slot};
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
//! Support effects
|
||||
|
||||
// Lints
|
||||
#![allow(
|
||||
// We have a lot of `a, b, c, x, y` from the formulas,
|
||||
// but we can't change those names since they're the actual
|
||||
// names of the variables in the formulas
|
||||
clippy::many_single_char_names
|
||||
)]
|
||||
|
||||
// byteorder
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
game::{
|
||||
Bytes, FromBytes, ToBytes,
|
||||
card::property::{DigimonProperty, SupportEffectOperation, AttackType, PlayerType, Slot},
|
||||
},
|
||||
};
|
||||
|
||||
// Types
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// A digimon's support effects
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
// TODO: Move this `allow` to the variant once clippy allows
|
||||
#[allow(clippy::pub_enum_variant_names)] // `Effect` on `VoidOpponentSupportEffect` isn't refering to the enum
|
||||
pub enum SupportEffect
|
||||
{
|
||||
/// Changes a property of either digimon
|
||||
@@ -218,54 +231,56 @@ use byteorder::{ByteOrder, LittleEndian};
|
||||
match effect_type_byte
|
||||
{
|
||||
0..=13 => {
|
||||
Ok( SupportEffect::ChangeProperty {
|
||||
Ok( Self::ChangeProperty {
|
||||
// Note: unwrapping is fine here because we know that `effect_type_byte+1` is between 1 and 14 inclusive
|
||||
property: DigimonProperty::from_bytes( &[ effect_type_byte+1 ] ).unwrap(),
|
||||
property: DigimonProperty::from_bytes( &[ effect_type_byte+1 ] )
|
||||
.expect("Unable to get digimon property from bytes"),
|
||||
a, b, c, x, y, op,
|
||||
})
|
||||
},
|
||||
|
||||
16 => { Ok( SupportEffect::UseAttack{ player: PlayerType::Player , attack: AttackType::from_bytes( &[x as u8] ) .map_err(FromBytesError::AttackType)? } ) },
|
||||
17 => { Ok( SupportEffect::UseAttack{ player: PlayerType::Opponent, attack: AttackType::from_bytes( &[x as u8] ) .map_err(FromBytesError::AttackType)? } ) },
|
||||
// Take lower byte from `x` for these
|
||||
16 => { Ok( Self::UseAttack{ player: PlayerType::Player , attack: AttackType::from_bytes( &[x.to_le_bytes()[0]] ) .map_err(FromBytesError::AttackType)? } ) },
|
||||
17 => { Ok( Self::UseAttack{ player: PlayerType::Opponent, attack: AttackType::from_bytes( &[x.to_le_bytes()[0]] ) .map_err(FromBytesError::AttackType)? } ) },
|
||||
|
||||
|
||||
25 => { Ok( SupportEffect::SetTempSlot{ a, b, c, op } ) },
|
||||
25 => { Ok( Self::SetTempSlot{ a, b, c, op } ) },
|
||||
|
||||
26 => { Ok( SupportEffect::MoveCards{ player: PlayerType::Player , source: Slot::Hand , destination: Slot::Offline, count: y } ) },
|
||||
27 => { Ok( SupportEffect::MoveCards{ player: PlayerType::Opponent, source: Slot::Hand , destination: Slot::Offline, count: y } ) },
|
||||
26 => { Ok( Self::MoveCards{ player: PlayerType::Player , source: Slot::Hand , destination: Slot::Offline, count: y } ) },
|
||||
27 => { Ok( Self::MoveCards{ player: PlayerType::Opponent, source: Slot::Hand , destination: Slot::Offline, count: y } ) },
|
||||
|
||||
30 => { Ok( SupportEffect::MoveCards{ player: PlayerType::Player , source: Slot::Hand , destination: Slot::Online , count: y } ) },
|
||||
31 => { Ok( SupportEffect::MoveCards{ player: PlayerType::Opponent, source: Slot::Hand , destination: Slot::Online , count: y } ) },
|
||||
30 => { Ok( Self::MoveCards{ player: PlayerType::Player , source: Slot::Hand , destination: Slot::Online , count: y } ) },
|
||||
31 => { Ok( Self::MoveCards{ player: PlayerType::Opponent, source: Slot::Hand , destination: Slot::Online , count: y } ) },
|
||||
|
||||
32 => { Ok( SupportEffect::MoveCards{ player: PlayerType::Player , source: Slot::Online , destination: Slot::Offline, count: y } ) },
|
||||
33 => { Ok( SupportEffect::MoveCards{ player: PlayerType::Opponent, source: Slot::Online , destination: Slot::Offline, count: y } ) },
|
||||
32 => { Ok( Self::MoveCards{ player: PlayerType::Player , source: Slot::Online , destination: Slot::Offline, count: y } ) },
|
||||
33 => { Ok( Self::MoveCards{ player: PlayerType::Opponent, source: Slot::Online , destination: Slot::Offline, count: y } ) },
|
||||
|
||||
34 => { Ok( SupportEffect::MoveCards{ player: PlayerType::Player , source: Slot::Offline, destination: Slot::Online , count: y } ) },
|
||||
35 => { Ok( SupportEffect::MoveCards{ player: PlayerType::Opponent, source: Slot::Offline, destination: Slot::Online , count: y } ) },
|
||||
34 => { Ok( Self::MoveCards{ player: PlayerType::Player , source: Slot::Offline, destination: Slot::Online , count: y } ) },
|
||||
35 => { Ok( Self::MoveCards{ player: PlayerType::Opponent, source: Slot::Offline, destination: Slot::Online , count: y } ) },
|
||||
|
||||
36 => { Ok( SupportEffect::MoveCards{ player: PlayerType::Player , source: Slot::Dp , destination: Slot::Offline, count: y } ) },
|
||||
37 => { Ok( SupportEffect::MoveCards{ player: PlayerType::Opponent, source: Slot::Dp , destination: Slot::Offline, count: y } ) },
|
||||
36 => { Ok( Self::MoveCards{ player: PlayerType::Player , source: Slot::Dp , destination: Slot::Offline, count: y } ) },
|
||||
37 => { Ok( Self::MoveCards{ player: PlayerType::Opponent, source: Slot::Dp , destination: Slot::Offline, count: y } ) },
|
||||
|
||||
|
||||
42 => { Ok( SupportEffect::ShuffleOnlineDeck{ player: PlayerType::Player } ) },
|
||||
43 => { Ok( SupportEffect::ShuffleOnlineDeck{ player: PlayerType::Opponent } ) },
|
||||
42 => { Ok( Self::ShuffleOnlineDeck{ player: PlayerType::Player } ) },
|
||||
43 => { Ok( Self::ShuffleOnlineDeck{ player: PlayerType::Opponent } ) },
|
||||
|
||||
44 => { Ok( SupportEffect::VoidOpponentSupportEffect ) },
|
||||
45 => { Ok( SupportEffect::VoidOpponentSupportOptionEffect ) },
|
||||
44 => { Ok( Self::VoidOpponentSupportEffect ) },
|
||||
45 => { Ok( Self::VoidOpponentSupportOptionEffect ) },
|
||||
|
||||
46 => { Ok( SupportEffect::PickPartnerCard ) },
|
||||
46 => { Ok( Self::PickPartnerCard ) },
|
||||
|
||||
47 => { Ok( SupportEffect::CycleOpponentAttackType ) },
|
||||
47 => { Ok( Self::CycleOpponentAttackType ) },
|
||||
|
||||
48 => { Ok( SupportEffect::KoDigimonRevives{ health: y } ) },
|
||||
48 => { Ok( Self::KoDigimonRevives{ health: y } ) },
|
||||
|
||||
49 => { Ok( SupportEffect::DrawCards{ player: PlayerType::Player , count: y } ) },
|
||||
50 => { Ok( SupportEffect::DrawCards{ player: PlayerType::Opponent, count: y } ) },
|
||||
49 => { Ok( Self::DrawCards{ player: PlayerType::Player , count: y } ) },
|
||||
50 => { Ok( Self::DrawCards{ player: PlayerType::Opponent, count: y } ) },
|
||||
|
||||
51 => { Ok( SupportEffect::OwnAttackBecomesEatUpHP ) },
|
||||
51 => { Ok( Self::OwnAttackBecomesEatUpHP ) },
|
||||
|
||||
52 => { Ok( SupportEffect::AttackFirst{ player: PlayerType::Player } ) },
|
||||
53 => { Ok( SupportEffect::AttackFirst{ player: PlayerType::Opponent } ) },
|
||||
52 => { Ok( Self::AttackFirst{ player: PlayerType::Player } ) },
|
||||
53 => { Ok( Self::AttackFirst{ player: PlayerType::Opponent } ) },
|
||||
|
||||
_ => Err( FromBytesError::UnknownEffectType{ byte: effect_type_byte } ),
|
||||
}
|
||||
@@ -280,10 +295,13 @@ use byteorder::{ByteOrder, LittleEndian};
|
||||
fn to_bytes(&self, _bytes: &mut [u8]) -> Result<(), Self::Error>
|
||||
{
|
||||
// Match which effect we are
|
||||
todo!()
|
||||
/*
|
||||
match self
|
||||
{
|
||||
_ => { unimplemented!(); }
|
||||
_ => { todo!(); }
|
||||
}
|
||||
*/
|
||||
|
||||
// Return Ok
|
||||
//Ok(())
|
||||
|
||||
@@ -8,34 +8,36 @@
|
||||
//! The digimon table has a max size of [0x14950](Table::MAX_BYTE_SIZE), but does not
|
||||
//! necessary use all of this space, but it does follow this layout:
|
||||
//!
|
||||
//! | Offset | Size | Type | Name | Details |
|
||||
//! |--------|----------|---------------|----------------------|-------------------------------------------------------------------------|
|
||||
//! | 0x0 | 0x4 | u32 | Magic | Always contains the string "0ACD" (= [0x44434130](Table::HEADER_MAGIC)) |
|
||||
//! | 0x4 | 0x2 | u16 | Number of digimon | |
|
||||
//! | 0x6 | 0x1 | u8 | Number of items | |
|
||||
//! | 0x7 | 0x1 | u8 | Number of digivolves | |
|
||||
//! | 0x8 | variable | \[CardEntry\] | Card Entries | A contigous array of [Card Entry](#card-entry-layout) |
|
||||
//! | Offset | Size | Type | Name | Details |
|
||||
//! |--------|----------|-----------------|----------------------|-------------------------------------------------------------------------|
|
||||
//! | 0x0 | 0x4 | u32 | Magic | Always contains the string "0ACD" (= [0x44434130](Table::HEADER_MAGIC)) |
|
||||
//! | 0x4 | 0x2 | u16 | Number of digimon | |
|
||||
//! | 0x6 | 0x1 | u8 | Number of items | |
|
||||
//! | 0x7 | 0x1 | u8 | Number of digivolves | |
|
||||
//! | 0x8 | variable | \[`CardEntry`\] | Card Entries | A contigous array of [Card Entry](#card-entry-layout) |
|
||||
//!
|
||||
//! # Card Entry Layout
|
||||
//! Each card entry consists of a header of the card
|
||||
//!
|
||||
//! | Offset | Size | Type | Name | Details |
|
||||
//! |--------|----------|------------------------------------|-----------------|----------------------------------------------|
|
||||
//! | 0x0 | 0x3 | [Card Header](#card-header-layout) | Card Header | The card's header |
|
||||
//! | 0x3 | variable | | Card | Either a [Digimon], [Item] or [Digivolve] |
|
||||
//! | ... | 0x1 | u8 | Null terminator | A null terminator for the card (must be `0`) |
|
||||
//! | Offset | Size | Type | Name | Details |
|
||||
//! |--------|----------|--------------------------------------|-----------------|----------------------------------------------|
|
||||
//! | 0x0 | 0x3 | [`Card Header`](#card-header-layout) | Card Header | The card's header |
|
||||
//! | 0x3 | variable | | Card | Either a [Digimon], [Item] or [Digivolve] |
|
||||
//! | ... | 0x1 | u8 | Null terminator | A null terminator for the card (must be `0`) |
|
||||
//!
|
||||
//! # Card Header Layout
|
||||
//! The card header determines which type of card this card entry has.
|
||||
//!
|
||||
//! | Offset | Size | Type | Name | Details |
|
||||
//! |--------|------|------------|-----------|--------------------------------------------------|
|
||||
//! | 0x0 | 0x2 | u16 | Card id | This card's ID |
|
||||
//! | 0x2 | 0x1 | [CardType] | Card type | The card type ([Digimon], [Item] or [Digivolve]) |
|
||||
//!
|
||||
//! # Todo
|
||||
//! [Table] might be changed from it's [Table::new] and [Table::write_to_file] interface to
|
||||
//! using the [ToBytes](crate::game::ToBytes) and [FromBytes](crate::game::FromBytes) traits, once it is fully figured out.
|
||||
//! | Offset | Size | Type | Name | Details |
|
||||
//! |--------|------|--------------|-----------|--------------------------------------------------|
|
||||
//! | 0x0 | 0x2 | u16 | Card id | This card's ID |
|
||||
//! | 0x2 | 0x1 | [`CardType`] | Card type | The card type ([Digimon], [Item] or [Digivolve]) |
|
||||
|
||||
// Io Traits
|
||||
use std::io::{Read, Write, Seek};
|
||||
|
||||
// byteorder
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
// Dcb
|
||||
use crate::{
|
||||
@@ -46,16 +48,9 @@ use crate::{
|
||||
property::{CardType, card_type::UnknownCardType},
|
||||
},
|
||||
Bytes, FromBytes,
|
||||
Structure,
|
||||
}
|
||||
};
|
||||
|
||||
// Io Traits
|
||||
use std::io::{Read, Write, Seek};
|
||||
|
||||
// byteorder
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
/// The table storing all cards
|
||||
#[derive(Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
@@ -81,46 +76,10 @@ impl Table {
|
||||
pub const HEADER_MAGIC: u32 = 0x44434130;
|
||||
}
|
||||
|
||||
// Error type for [`Table::from_game_file`]
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
pub enum TableFromGameFileError {
|
||||
/// Unable to seek game file
|
||||
#[display(fmt = "Unable to seek game file")]
|
||||
Seek( std::io::Error ),
|
||||
|
||||
/// Unable to deserialize table
|
||||
#[display(fmt = "Unable to deserialize table from game file")]
|
||||
Deserialize( DeserializeError ),
|
||||
}
|
||||
|
||||
impl std::error::Error for TableFromGameFileError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::Seek (err) => Some(err),
|
||||
Self::Deserialize(err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Constructors
|
||||
impl Table {
|
||||
/// Retrieves the card table from a game file
|
||||
pub fn from_game_file<R: Read + Write + Seek>(game_file: &mut GameFile<R>) -> Result<Table, TableFromGameFileError> {
|
||||
// Seek to the table address
|
||||
game_file.seek( std::io::SeekFrom::Start( u64::from( Self::START_ADDRESS ) ) )
|
||||
.map_err(TableFromGameFileError::Seek)?;
|
||||
|
||||
// Deserialize it and return it
|
||||
let table = Table::deserialize(game_file)
|
||||
.map_err(TableFromGameFileError::Deserialize)?;
|
||||
Ok(table)
|
||||
}
|
||||
}
|
||||
|
||||
// Utils
|
||||
impl Table {
|
||||
/// Returns how many cards are in this table
|
||||
#[must_use]
|
||||
pub fn card_count(&self) -> usize {
|
||||
self.digimons .len() +
|
||||
self.items .len() +
|
||||
@@ -129,13 +88,17 @@ impl Table {
|
||||
}
|
||||
|
||||
|
||||
/// Error type for [`<Table as Structure>::DeserializeError`]
|
||||
/// Error type for [`Structure::DeserializeError`]
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
pub enum DeserializeError {
|
||||
/// Unable to seek game file
|
||||
#[display(fmt = "Unable to seek game file to card table")]
|
||||
Seek( std::io::Error ),
|
||||
|
||||
/// Unable to read table header
|
||||
#[display(fmt = "Unable to read table header")]
|
||||
ReadTableHeader( std::io::Error ),
|
||||
ReadHeader( std::io::Error ),
|
||||
|
||||
/// The magic of the table was wrong
|
||||
#[display(fmt = "Found wrong table header magic (expected {:x}, found {:x})", Table::HEADER_MAGIC, "magic")]
|
||||
@@ -148,11 +111,9 @@ pub enum DeserializeError {
|
||||
"digimon_cards",
|
||||
"item_cards",
|
||||
"digivolve_cards",
|
||||
r#"
|
||||
digimon_cards * (0x3 + Digimon ::BUF_BYTE_SIZE + 0x1) +
|
||||
" digimon_cards * (0x3 + Digimon ::BUF_BYTE_SIZE + 0x1) +
|
||||
item_cards * (0x3 + Item ::BUF_BYTE_SIZE + 0x1) +
|
||||
digivolve_cards * (0x3 + Digivolve::BUF_BYTE_SIZE + 0x1)
|
||||
"#,
|
||||
digivolve_cards * (0x3 + Digivolve::BUF_BYTE_SIZE + 0x1)",
|
||||
Table::MAX_BYTE_SIZE
|
||||
)]
|
||||
TooManyCards {
|
||||
@@ -186,7 +147,8 @@ pub enum DeserializeError {
|
||||
impl std::error::Error for DeserializeError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::ReadTableHeader(err) |
|
||||
Self::Seek(err) |
|
||||
Self::ReadHeader(err) |
|
||||
Self::ReadCardHeader { err, .. } |
|
||||
Self::ReadCardFooter { err, .. } => Some(err),
|
||||
Self::UnknownCardType { err, .. } => Some(err),
|
||||
@@ -196,23 +158,21 @@ impl std::error::Error for DeserializeError {
|
||||
}
|
||||
}
|
||||
|
||||
impl Structure for Table {
|
||||
type SerializeError = !;
|
||||
type DeserializeError = DeserializeError;
|
||||
|
||||
fn size() -> (usize, Option<usize>) {
|
||||
(Self::HEADER_BYTE_SIZE, Some(Self::MAX_BYTE_SIZE))
|
||||
}
|
||||
|
||||
fn deserialize<R: Read + Write + Seek>(file: &mut GameFile<R>) -> Result<Self, Self::DeserializeError> {
|
||||
impl Table {
|
||||
/// Deserializes the card table from a game file
|
||||
pub fn deserialize<R: Read + Write + Seek>(file: &mut GameFile<R>) -> Result<Self, DeserializeError> {
|
||||
// Seek to the table
|
||||
file.seek( std::io::SeekFrom::Start( u64::from( Self::START_ADDRESS ) ) )
|
||||
.map_err(DeserializeError::Seek)?;
|
||||
|
||||
// Read header
|
||||
let mut header_bytes = [0u8; 0x8];
|
||||
file.read_exact(&mut header_bytes)
|
||||
.map_err(Self::DeserializeError::ReadTableHeader)?;
|
||||
.map_err(DeserializeError::ReadHeader)?;
|
||||
|
||||
// Check if the magic is right
|
||||
let magic = LittleEndian::read_u32( &header_bytes[0x0..0x4] );
|
||||
if magic != Table::HEADER_MAGIC { return Err( Self::DeserializeError::HeaderMagic{ magic } ); }
|
||||
if magic != Self::HEADER_MAGIC { return Err( DeserializeError::HeaderMagic{ magic } ); }
|
||||
|
||||
// Then check the number of each card
|
||||
let digimon_cards = LittleEndian::read_u16( &header_bytes[0x4..0x6] ) as usize;
|
||||
@@ -226,7 +186,7 @@ impl Structure for Table {
|
||||
let table_size = digimon_cards * (0x3 + Digimon ::BUF_BYTE_SIZE + 0x1) +
|
||||
item_cards * (0x3 + Item ::BUF_BYTE_SIZE + 0x1) +
|
||||
digivolve_cards * (0x3 + Digivolve::BUF_BYTE_SIZE + 0x1);
|
||||
if table_size > Table::MAX_BYTE_SIZE { return Err( Self::DeserializeError::TooManyCards {
|
||||
if table_size > Self::MAX_BYTE_SIZE { return Err( DeserializeError::TooManyCards {
|
||||
digimon_cards,
|
||||
item_cards,
|
||||
digivolve_cards,
|
||||
@@ -244,12 +204,12 @@ impl Structure for Table {
|
||||
// Read card header bytes
|
||||
let mut card_header_bytes = [0u8; 0x3];
|
||||
file.read_exact(&mut card_header_bytes)
|
||||
.map_err(|err| Self::DeserializeError::ReadCardHeader { id: cur_id, err })?;
|
||||
.map_err(|err| DeserializeError::ReadCardHeader { id: cur_id, err })?;
|
||||
|
||||
// Read the header
|
||||
let card_id = LittleEndian::read_u16( &card_header_bytes[0x0..0x2] );
|
||||
let card_type = CardType::from_bytes( &card_header_bytes[0x2..0x3] )
|
||||
.map_err(|err| Self::DeserializeError::UnknownCardType{ id: cur_id, err } )?;
|
||||
.map_err(|err| DeserializeError::UnknownCardType{ id: cur_id, err } )?;
|
||||
|
||||
// If the card id isn't what we expected, log warning
|
||||
if usize::from(card_id) != cur_id {
|
||||
@@ -287,21 +247,21 @@ impl Structure for Table {
|
||||
// Skip null terminator
|
||||
let mut null_terminator = [0; 1];
|
||||
file.read_exact(&mut null_terminator)
|
||||
.map_err(|err| Self::DeserializeError::ReadCardFooter { id: cur_id, err })?;
|
||||
.map_err(|err| DeserializeError::ReadCardFooter { id: cur_id, err })?;
|
||||
if null_terminator[0] != 0 {
|
||||
log::warn!("Card with id {}'s null terminator was {} instead of 0", cur_id, null_terminator[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the table
|
||||
Ok( Table {
|
||||
Ok( Self {
|
||||
digimons,
|
||||
items,
|
||||
digivolves,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize<R: Read + Write + Seek>(&self, _file: &mut GameFile<R>) -> Result<(), Self::SerializeError> {
|
||||
pub fn serialize<R: Read + Write + Seek>(&self, _file: &mut GameFile<R>) -> Result<(), !> {
|
||||
todo!();
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! Deck
|
||||
|
||||
// Modules
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
//pub mod deck;
|
||||
|
||||
@@ -47,7 +47,7 @@ use serde::Deserialize;
|
||||
|
||||
/// Error type for `Table::new`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum TableNewError
|
||||
pub enum NewError
|
||||
{
|
||||
/// Could not seek tothe beginning of the deck table
|
||||
#[display(fmt = "Could not seek to the beginning of the deck table")]
|
||||
@@ -78,7 +78,7 @@ use serde::Deserialize;
|
||||
*/
|
||||
}
|
||||
|
||||
impl std::error::Error for TableNewError {
|
||||
impl std::error::Error for NewError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::SeekTableBegin(err) |
|
||||
@@ -90,7 +90,7 @@ use serde::Deserialize;
|
||||
|
||||
/// Error type for `Table::write_to_file`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum TableWriteError
|
||||
pub enum WriteError
|
||||
{
|
||||
/// The deck table was too big
|
||||
#[display(fmt = "The deck table was too big (is {}, should be 65536 max)", _0)]
|
||||
@@ -127,7 +127,7 @@ use serde::Deserialize;
|
||||
// Constructors
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Reads the deck table from a dcb bin file
|
||||
pub fn new<F>(game_file: &mut GameFile<F>) -> Result<Table, TableNewError>
|
||||
pub fn new<F>(game_file: &mut GameFile<F>) -> Result<Self, NewError>
|
||||
where
|
||||
F: Read + Write + Seek
|
||||
{
|
||||
@@ -136,7 +136,7 @@ use serde::Deserialize;
|
||||
|
||||
|
||||
// Seek to the beginning of the deck table
|
||||
game_file.seek( std::io::SeekFrom::Start( u64::from( Table::DECK_TABLE_START_ADDRESS) ) ).map_err(TableNewError::SeekTableBegin)?;
|
||||
game_file.seek( std::io::SeekFrom::Start( u64::from( Self::DECK_TABLE_START_ADDRESS) ) ).map_err(NewError::SeekTableBegin)?;
|
||||
|
||||
// Then loop until we're at the end of the table
|
||||
//'table_loop: loop
|
||||
@@ -144,15 +144,15 @@ use serde::Deserialize;
|
||||
{
|
||||
// Read the deck
|
||||
let mut buf = [0u8; 110];
|
||||
game_file.read_exact(&mut buf).map_err(TableNewError::DeckEntry).unwrap();
|
||||
game_file.read_exact(&mut buf)
|
||||
.map_err(NewError::DeckEntry)?;
|
||||
|
||||
// And construct the deck
|
||||
let deck = Deck {
|
||||
cards: {
|
||||
let mut cards_buf = [0u16; 30];
|
||||
|
||||
for card_id in 0..30
|
||||
{
|
||||
for card_id in 0..30 {
|
||||
cards_buf[card_id] = LittleEndian::read_u16( &buf[0x0 + card_id*2 .. 0x2 + card_id*2] );
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ use serde::Deserialize;
|
||||
}
|
||||
|
||||
// And return the table
|
||||
Ok( Table {
|
||||
Ok( Self {
|
||||
decks,
|
||||
})
|
||||
}
|
||||
@@ -173,8 +173,9 @@ use serde::Deserialize;
|
||||
|
||||
// Write
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
/// Writes this table to a dcb bin file
|
||||
pub fn write_to_file<F>(&self, _game_file: &mut GameFile<F>) -> Result<(), TableWriteError>
|
||||
pub fn write_to_file<F>(&self, _game_file: &mut GameFile<F>) -> Result<(), WriteError>
|
||||
where
|
||||
F: Read + Write + Seek
|
||||
{
|
||||
@@ -204,6 +205,7 @@ use serde::Deserialize;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
*/
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
//! Game structure informations and serialization / deserialization
|
||||
|
||||
// Std
|
||||
use std::{
|
||||
io::{Read, Write, Seek},
|
||||
error::Error,
|
||||
};
|
||||
|
||||
// Crate
|
||||
use crate::io::GameFile;
|
||||
|
||||
/// Trait that stores information about a game structure
|
||||
pub trait Structure
|
||||
where
|
||||
Self: Sized
|
||||
{
|
||||
/// Error type for [`Self::serialize`]
|
||||
type SerializeError: Error;
|
||||
|
||||
/// Error type for [`Self::deserialize`]
|
||||
type DeserializeError: Error;
|
||||
|
||||
/// Returns the size of this structure
|
||||
fn size() -> (usize, Option<usize>);
|
||||
|
||||
/// Attempts to deserialize this data structure from a game file
|
||||
fn deserialize<R: Read + Write + Seek>(file: &mut GameFile<R>) -> Result<Self, Self::DeserializeError>;
|
||||
|
||||
/// Attempts to serialize the structure to the game file
|
||||
fn serialize<R: Read + Write + Seek>(&self, file: &mut GameFile<R>) -> Result<(), Self::SerializeError>;
|
||||
}
|
||||
@@ -132,6 +132,7 @@
|
||||
}
|
||||
|
||||
/// Returns an ordinal string from a u64
|
||||
#[must_use]
|
||||
pub fn as_ordinal(num: u64) -> String
|
||||
{
|
||||
format!("{0}{1}", num, match num % 10 {
|
||||
|
||||
@@ -11,4 +11,3 @@ pub mod address;
|
||||
|
||||
// Exports
|
||||
pub use game_file::GameFile;
|
||||
pub use address::Data as DataAddress;
|
||||
|
||||
@@ -15,8 +15,7 @@ pub use data::Data;
|
||||
|
||||
/// Error type for `TryFrom<Real> for Data`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum RealToDataError
|
||||
{
|
||||
pub enum RealToDataError {
|
||||
/// Occurs when the Real is outside of the data section of the sector
|
||||
#[display(fmt = "The real address {} could not be converted to a data address as it is not in the data section", _0)]
|
||||
OutsideDataSection(Real),
|
||||
@@ -31,11 +30,10 @@ impl std::error::Error for RealToDataError {
|
||||
}
|
||||
|
||||
// Real -> Data
|
||||
impl std::convert::TryFrom<Real> for Data
|
||||
{
|
||||
impl std::convert::TryFrom<Real> for Data {
|
||||
type Error = RealToDataError;
|
||||
|
||||
fn try_from(real_address: Real) -> Result<Data, Self::Error>
|
||||
fn try_from(real_address: Real) -> Result<Self, Self::Error>
|
||||
{
|
||||
// If the real address isn't in the data section, then return err
|
||||
if !real_address.in_data_section() { return Err( Self::Error::OutsideDataSection(real_address) ); }
|
||||
@@ -47,7 +45,7 @@ impl std::convert::TryFrom<Real> for Data
|
||||
// The data address is just converting the real_sector
|
||||
// to a data_sector and subtracting the header from the
|
||||
// real offset to get the data offset
|
||||
Ok( Data::from(
|
||||
Ok( Self::from(
|
||||
Real::SECTOR_BYTE_SIZE * real_sector + // Base of data sector
|
||||
real_sector_offset - Real::HEADER_BYTE_SIZE // Data offset
|
||||
))
|
||||
@@ -57,7 +55,7 @@ impl std::convert::TryFrom<Real> for Data
|
||||
// Data -> Real
|
||||
impl From<Data> for Real
|
||||
{
|
||||
fn from(data_address: Data) -> Real
|
||||
fn from(data_address: Data) -> Self
|
||||
{
|
||||
// Get the sector and offset
|
||||
let data_sector = data_address.sector();
|
||||
@@ -65,9 +63,9 @@ impl From<Data> for Real
|
||||
|
||||
// Then the real address is just convering the data_sector
|
||||
// to a real_sector and adding the header plus the offset
|
||||
Real::from(
|
||||
Real::SECTOR_BYTE_SIZE * data_sector + // Base of real sector
|
||||
Real::HEADER_BYTE_SIZE + // Skip header
|
||||
Self::from(
|
||||
Self::SECTOR_BYTE_SIZE * data_sector + // Base of real sector
|
||||
Self::HEADER_BYTE_SIZE + // Skip header
|
||||
data_sector_offset // Offset inside data sector
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,127 +3,101 @@
|
||||
// Address
|
||||
use crate::io::address::Real;
|
||||
|
||||
// Types
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// A type for defining addresses on the data parts of `.bin` file.
|
||||
///
|
||||
/// # Details
|
||||
/// All addresses of type `Data` will represent the position
|
||||
/// within *only* the data sections on the file.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Data(u64);
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// A type for defining addresses on the data parts of `.bin` file.
|
||||
///
|
||||
/// # Details
|
||||
/// All addresses of type `Data` will represent the position
|
||||
/// within *only* the data sections on the file.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Data(u64);
|
||||
|
||||
// Impl
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
impl Data
|
||||
{
|
||||
// Constructors
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Constructs a data address from it's representation in u64
|
||||
///
|
||||
/// # Note
|
||||
/// `address` is not a real address, but a data address represented in `u64`
|
||||
pub const fn from_u64(address: u64) -> Self {
|
||||
Self( address )
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Conversions
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Returns the sector associated with this address
|
||||
pub fn sector(self) -> u64
|
||||
{
|
||||
u64::from(self) / Real::DATA_BYTE_SIZE
|
||||
}
|
||||
|
||||
/// Returns the offset into the data section of this address
|
||||
pub fn offset(self) -> u64
|
||||
{
|
||||
u64::from(self) % Real::DATA_BYTE_SIZE
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
impl Data
|
||||
{
|
||||
/// Constructs a data address from it's `u64` representation
|
||||
#[must_use]
|
||||
pub const fn from_u64(address: u64) -> Self {
|
||||
Self(address)
|
||||
}
|
||||
|
||||
// Conversions from and into u64
|
||||
impl From<Data> for u64 { fn from(address: Data) -> u64 { address.0 } }
|
||||
impl From<u64 > for Data { fn from(address: u64 ) -> Data { Data(address) } }
|
||||
/// Returns the sector associated with this address
|
||||
#[must_use]
|
||||
#[allow(clippy::integer_division)] // We want to get the whole division
|
||||
pub fn sector(self) -> u64 {
|
||||
u64::from(self) / Real::DATA_BYTE_SIZE
|
||||
}
|
||||
|
||||
// Operations
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Data + Offset
|
||||
impl std::ops::Add<i64> for Data
|
||||
{
|
||||
type Output = Data;
|
||||
|
||||
fn add(self, offset: i64) -> Data
|
||||
{
|
||||
if offset > 0 {
|
||||
self + (offset as u64)
|
||||
} else {
|
||||
self - (-offset as u64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Data += Offset
|
||||
impl std::ops::AddAssign<i64> for Data
|
||||
{
|
||||
fn add_assign(&mut self, offset: i64) { *self = *self + offset; }
|
||||
}
|
||||
|
||||
// Data + absolute
|
||||
impl std::ops::Add<u64> for Data
|
||||
{
|
||||
type Output = Data;
|
||||
|
||||
fn add(self, absolute: u64) -> Data {
|
||||
Self::from( self.0 + absolute )
|
||||
}
|
||||
}
|
||||
|
||||
// Data += absolute
|
||||
impl std::ops::AddAssign<u64> for Data
|
||||
{
|
||||
fn add_assign(&mut self, absolute: u64) { *self = *self + absolute; }
|
||||
}
|
||||
|
||||
// Data - absolute
|
||||
impl std::ops::Sub<u64> for Data
|
||||
{
|
||||
type Output = Data;
|
||||
|
||||
fn sub(self, absolute: u64) -> Data {
|
||||
Self::from( self.0 - absolute )
|
||||
}
|
||||
}
|
||||
|
||||
// Data -= absolute
|
||||
impl std::ops::SubAssign<u64> for Data
|
||||
{
|
||||
fn sub_assign(&mut self, absolute: u64) { *self = *self - absolute; }
|
||||
}
|
||||
|
||||
// Data - Data
|
||||
impl std::ops::Sub<Data> for Data
|
||||
{
|
||||
type Output = i64;
|
||||
|
||||
fn sub(self, address: Data) -> i64
|
||||
{
|
||||
// TODO: Do this another way?
|
||||
self.0 as i64 -
|
||||
address.0 as i64
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Returns the offset into the data section of this address
|
||||
#[must_use]
|
||||
pub fn offset(self) -> u64 {
|
||||
u64::from(self) % Real::DATA_BYTE_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
// Conversions from and into u64
|
||||
impl From<Data> for u64 { fn from(address: Data) -> Self { address.0 } }
|
||||
impl From<u64 > for Data { fn from(address: u64 ) -> Self { Self(address) } }
|
||||
|
||||
// Data + Offset
|
||||
impl std::ops::Add<i64> for Data
|
||||
{
|
||||
type Output = Self;
|
||||
|
||||
// Display
|
||||
impl std::fmt::Display for Data
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
|
||||
{
|
||||
write!(f, "{:x}", u64::from(*self))
|
||||
fn add(self, offset: i64) -> Self {
|
||||
if offset > 0 {
|
||||
self + (offset as u64)
|
||||
} else {
|
||||
self - (-offset as u64)
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// Data += Offset
|
||||
impl std::ops::AddAssign<i64> for Data
|
||||
{
|
||||
fn add_assign(&mut self, offset: i64) { *self = *self + offset; }
|
||||
}
|
||||
|
||||
// Data + absolute
|
||||
impl std::ops::Add<u64> for Data {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, absolute: u64) -> Self {
|
||||
Self::from( self.0 + absolute )
|
||||
}
|
||||
}
|
||||
|
||||
// Data += absolute
|
||||
impl std::ops::AddAssign<u64> for Data {
|
||||
fn add_assign(&mut self, absolute: u64) { *self = *self + absolute; }
|
||||
}
|
||||
|
||||
// Data - absolute
|
||||
impl std::ops::Sub<u64> for Data {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, absolute: u64) -> Self {
|
||||
Self::from( self.0 - absolute )
|
||||
}
|
||||
}
|
||||
|
||||
// Data -= absolute
|
||||
impl std::ops::SubAssign<u64> for Data {
|
||||
fn sub_assign(&mut self, absolute: u64) { *self = *self - absolute; }
|
||||
}
|
||||
|
||||
// Data - Data
|
||||
impl std::ops::Sub<Data> for Data {
|
||||
type Output = i64;
|
||||
|
||||
fn sub(self, address: Self) -> i64 {
|
||||
self.0 as i64 -
|
||||
address.0 as i64
|
||||
}
|
||||
}
|
||||
|
||||
// Display
|
||||
impl std::fmt::Display for Data {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:x}", u64::from(*self))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
|
||||
/// A type for defining addresses on the `.bin` file.
|
||||
///
|
||||
/// # Details
|
||||
/// All addresses of type `Real` will represent the *real* position
|
||||
/// on the file.
|
||||
/// All real addresses will depict the actual position
|
||||
/// within the game file, including headers from the `.bin` file format.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(derive_more::From, derive_more::Into)]
|
||||
pub struct Real(u64);
|
||||
|
||||
// Constants
|
||||
impl Real
|
||||
{
|
||||
impl Real {
|
||||
/// The number of bytes within a whole sector
|
||||
pub const SECTOR_BYTE_SIZE: u64 = 2352;
|
||||
|
||||
@@ -33,76 +32,66 @@ impl Real
|
||||
pub const DATA_RANGE: std::ops::Range<u64> = Self::DATA_START .. Self::DATA_END;
|
||||
}
|
||||
|
||||
impl Real
|
||||
{
|
||||
impl Real {
|
||||
/// Returns the real sector associated with this address
|
||||
#[must_use]
|
||||
#[allow(clippy::integer_division)] // We want to get the whole division
|
||||
pub fn sector(self) -> u64 {
|
||||
u64::from(self) / Self::SECTOR_BYTE_SIZE
|
||||
}
|
||||
|
||||
/// Returns the real offset into the sector of this address
|
||||
/// Returns the offset into the sector of this address
|
||||
#[must_use]
|
||||
pub fn offset(self) -> u64 {
|
||||
u64::from(self) % Self::SECTOR_BYTE_SIZE
|
||||
}
|
||||
|
||||
/// Returns the real end address of the data section
|
||||
/// Returns the address of the end of the data section in this sector.
|
||||
#[must_use]
|
||||
pub fn data_section_end(self) -> Self {
|
||||
// Get the sector
|
||||
let real_sector = self.sector();
|
||||
|
||||
// The end of the real data section is after the header and data sections
|
||||
Self::from(
|
||||
Real::SECTOR_BYTE_SIZE * real_sector + // Beginning of sector
|
||||
Real::HEADER_BYTE_SIZE + // Skip Header
|
||||
Real:: DATA_BYTE_SIZE // Skip Data
|
||||
Self::SECTOR_BYTE_SIZE * real_sector + // Beginning of sector
|
||||
Self::HEADER_BYTE_SIZE + // Skip Header
|
||||
Self:: DATA_BYTE_SIZE // Skip Data
|
||||
)
|
||||
}
|
||||
|
||||
/// Checks if a real address lies within the data section
|
||||
/// Checks if this address is within the real data section
|
||||
#[must_use]
|
||||
pub fn in_data_section(self) -> bool {
|
||||
// If our offset is within the data range
|
||||
Self::DATA_RANGE.contains( &self.offset() )
|
||||
}
|
||||
}
|
||||
|
||||
// Conversions from and into u64
|
||||
impl From<Real> for u64 { fn from(address: Real) -> u64 { address.0 } }
|
||||
impl From<u64 > for Real { fn from(address: u64 ) -> Real { Real(address) } }
|
||||
|
||||
// Conversions from and into i64
|
||||
impl From<Real> for i64 { fn from(address: Real) -> i64 { u64::from(address ) as i64 } }
|
||||
impl From<i64 > for Real { fn from(address: i64 ) -> Real { Real::from(address as u64) } }
|
||||
// Real + Offset
|
||||
impl std::ops::Add<i64> for Real {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, offset: i64) -> Self {
|
||||
Self::from( ( u64::from(self) as i64 + offset) as u64 )
|
||||
}
|
||||
}
|
||||
|
||||
// Operations
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Real + Offset
|
||||
impl std::ops::Add<i64> for Real
|
||||
{
|
||||
type Output = Real;
|
||||
|
||||
fn add(self, offset: i64) -> Real
|
||||
{
|
||||
Self::from( i64::from(self) + offset )
|
||||
}
|
||||
}
|
||||
// Real += Offset
|
||||
impl std::ops::AddAssign<i64> for Real {
|
||||
fn add_assign(&mut self, offset: i64) { *self = *self + offset; }
|
||||
}
|
||||
|
||||
// Real - Real
|
||||
impl std::ops::Sub<Real> for Real
|
||||
{
|
||||
type Output = i64;
|
||||
|
||||
// Real += Offset
|
||||
impl std::ops::AddAssign<i64> for Real
|
||||
{
|
||||
fn add_assign(&mut self, offset: i64) { *self = *self + offset; }
|
||||
fn sub(self, address: Self) -> i64 {
|
||||
u64::from(self) as i64 - u64::from(address) as i64
|
||||
}
|
||||
|
||||
// Real - Real
|
||||
impl std::ops::Sub<Real> for Real
|
||||
{
|
||||
type Output = i64;
|
||||
|
||||
fn sub(self, address: Real) -> i64
|
||||
{
|
||||
i64::from(self) - i64::from(address)
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
|
||||
// Display
|
||||
|
||||
@@ -239,7 +239,7 @@ impl<R: Read + Write + Seek> Seek for GameFile<R>
|
||||
data_offset
|
||||
))
|
||||
),
|
||||
SeekFrom::End(_) => { unimplemented!(); }
|
||||
SeekFrom::End(_) => { todo!(); }
|
||||
};
|
||||
|
||||
// Seek to the real position and get where we are right now
|
||||
|
||||
42
src/lib.rs
42
src/lib.rs
@@ -2,8 +2,8 @@
|
||||
//! a PSX game.
|
||||
//!
|
||||
//! # Modules
|
||||
//! `dcb` split itself into 2 main modules, [io], which interacts with the game file
|
||||
//! as well as general input / output operations and [game], which is where most of
|
||||
//! `dcb` splits itself into 2 main modules, [`io`], which interacts with the game file
|
||||
//! as well as general input / output operations and [`game`], which is where most of
|
||||
//! the game's data types are defined.
|
||||
//!
|
||||
//! # Example
|
||||
@@ -14,7 +14,7 @@
|
||||
//! ```no_run
|
||||
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! # use std::fs::File;
|
||||
//! let mut game_file = dcb::GameFile::from_reader( File::open("resources/Digimon Digital Card Battle.bin")? );
|
||||
//! let mut game_file = dcb::GameFile::from_reader( File::open("Digimon Digital Card Battle.bin")? );
|
||||
//! let card_table = dcb::game::card::Table::new( &mut game_file )?;
|
||||
//! println!("Card table: {:?}", card_table);
|
||||
//! # Ok(())
|
||||
@@ -22,9 +22,12 @@
|
||||
//! ```
|
||||
|
||||
// Features
|
||||
#![feature(seek_convenience)]
|
||||
#![feature(never_type)]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(
|
||||
seek_convenience,
|
||||
never_type,
|
||||
trait_alias,
|
||||
unsized_locals,
|
||||
)]
|
||||
|
||||
// Lints
|
||||
#![warn(
|
||||
@@ -32,6 +35,33 @@
|
||||
clippy::pedantic,
|
||||
clippy::nursery,
|
||||
)]
|
||||
#![allow(
|
||||
clippy::missing_inline_in_public_items, // Dubious lint
|
||||
clippy::implicit_return, // We prefer tail returns where possible
|
||||
clippy::shadow_reuse, // Very useful for arguments `arg: impl Into<U>; let arg = arg.into()`
|
||||
clippy::if_not_else, // Sometimes it's easier to read with a negation
|
||||
clippy::result_expect_used,
|
||||
clippy::option_expect_used, // We use `.expect` when there is no safe alternative and the program is corrupt
|
||||
clippy::unreadable_literal, // More important to be able to copy the number with no formatting than it being readable
|
||||
clippy::multiple_inherent_impl, // We prefer to separate certain methods by type and insert error types in between methods
|
||||
clippy::identity_op, // Makes sense sometimes for symmetry
|
||||
|
||||
// TODO: Deal with casts eventually
|
||||
clippy::cast_possible_wrap,
|
||||
clippy::cast_sign_loss,
|
||||
clippy::cast_possible_truncation,
|
||||
|
||||
// TODO: Remove these once all modules are ported
|
||||
clippy::missing_docs_in_private_items,
|
||||
clippy::as_conversions,
|
||||
clippy::panic,
|
||||
clippy::indexing_slicing,
|
||||
clippy::unseparated_literal_suffix,
|
||||
clippy::integer_arithmetic,
|
||||
clippy::unreachable,
|
||||
clippy::todo,
|
||||
clippy::missing_errors_doc,
|
||||
)]
|
||||
|
||||
// Modules
|
||||
pub mod io;
|
||||
|
||||
Reference in New Issue
Block a user