diff --git a/src/game.rs b/src/game.rs index 8802be3..b3d07ac 100644 --- a/src/game.rs +++ b/src/game.rs @@ -15,7 +15,7 @@ //#![allow(clippy::missing_docs_in_private_items)] // A lot of our private items are simple digimon types, so they don't need documentation // Modules -#[macro_use] pub mod util; +mod util; pub mod bytes; pub mod card; diff --git a/src/game/card/digimon.rs b/src/game/card/digimon.rs index dc148fd..ff2ae48 100644 --- a/src/game/card/digimon.rs +++ b/src/game/card/digimon.rs @@ -1,6 +1,6 @@ //! A digimon card //! -//! This module stores the [`Digimon`] struct, which describes a digimon card. +//! This module contains the [`Digimon`] struct, which describes a digimon card. //! //! # Layout //! The digimon card has a size of `0x138` bytes, and it's layout is the following: @@ -8,7 +8,7 @@ //! | Offset | Size | Type | Name | Location | Details | //! |--------|------|---------------------|---------------------------|------------------------|-------------------------------------------------------------------------------------| //! | 0x0 | 0x15 | `[char; 0x15]` | Name | `name` | Null-terminated | -//! | 0x15 | 0x2 | `u16` | Unknown | `unknown_15` | Most likely contains the digimon's model | +//! | 0x15 | 0x2 | `u16` | Unknown | `unknown_15` | | //! | 0x17 | 0x1 | `u8` | Speciality & Level | `speciality level` | The bottom nibble of this byte is the level, while the top nibble is the speciality | //! | 0x18 | 0x1 | `u8` | DP | `dp_cost` | | //! | 0x19 | 0x1 | `u8` | +P | `dp_give` | | @@ -81,11 +81,6 @@ pub struct Digimon /// `+P` in the game. pub dp_give: u8, - // Unknown fields - pub unknown_1a: u8, - pub unknown_15: u16, - pub unknown_e2: u8, - /// The digimon's circle move pub move_circle: Move, @@ -116,6 +111,11 @@ pub struct Digimon /// The effects themselves #[serde(default)] pub effects: [Option; 3], + + // Unknown fields + pub unknown_1a: u8, + pub unknown_15: u16, + pub unknown_e2: u8, } /// Error type for [`Bytes::from_bytes`] @@ -249,7 +249,7 @@ impl Bytes for Digimon type FromError = FromBytesError; fn from_bytes(bytes: &Self::ByteArray) -> Result { - // Get all byte arrays we need + // Split bytes let bytes = util::array_split!(bytes, name : [0x15], unknown_15 : [0x2], @@ -277,13 +277,10 @@ impl Bytes for Digimon // Return the struct after building it Ok( Self { - // 0x0 - 0x1d name: util::read_null_ascii_string(bytes.name) .map_err(FromBytesError::Name)? .chars().collect(), - unknown_15: LittleEndian::read_u16(bytes.unknown_15), - speciality: Speciality::from_bytes( &( (bytes.speciality_level & 0xF0) >> 4 ) ) .map_err(FromBytesError::Speciality)?, @@ -292,11 +289,10 @@ impl Bytes for Digimon dp_cost : *bytes.dp_cost, dp_give : *bytes.dp_give, - unknown_1a: *bytes.unknown_1a, hp: LittleEndian::read_u16( bytes.hp ), - // 0x1d - 0x71 + // Moves move_circle: Move::from_bytes( bytes.move_circle ) .map_err(FromBytesError::MoveCircle)?, move_triangle: Move::from_bytes( bytes.move_triangle ) @@ -304,7 +300,7 @@ impl Bytes for Digimon move_cross: Move::from_bytes( bytes.move_cross ) .map_err(FromBytesError::MoveCross)?, - // 0x71 - 0x138 + // Effects effect_conditions: [ Option::::from_bytes( bytes.condition_first ) .map_err(FromBytesError::EffectConditionFirst)?, @@ -327,8 +323,6 @@ impl Bytes for Digimon cross_move_effect: Option::::from_bytes(bytes.cross_move_effect) .map_err(FromBytesError::CrossMoveEffect)?, - unknown_e2: *bytes.unknown_e2, - effect_arrow_color: Option::::from_bytes(bytes.effect_arrow_color) .map_err(FromBytesError::ArrowColor)?, @@ -346,13 +340,18 @@ impl Bytes for Digimon .map_err(FromBytesError::EffectDescriptionFourth)? .chars().collect(), ], + + // Unknown + unknown_15: LittleEndian::read_u16(bytes.unknown_15), + unknown_1a: *bytes.unknown_1a, + unknown_e2: *bytes.unknown_e2, }) } type ToError = ToBytesError; fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> { - // Get all byte arrays we need + // Split bytes let bytes = util::array_split_mut!(bytes, name : [0x15], unknown_15 : [0x2], @@ -378,13 +377,10 @@ impl Bytes for Digimon effect_description_3: [0x15], ); - // name + // Name util::write_null_ascii_string(self.name.as_ref(), bytes.name) .map_err(ToBytesError::Name)?; - // unknown_15 - LittleEndian::write_u16(bytes.unknown_15, self.unknown_15); - // Speciality / Level { let (mut speciality_byte, mut level_byte) = ( 0u8, 0u8 ); @@ -401,9 +397,6 @@ impl Bytes for Digimon *bytes.dp_cost = self.dp_cost; *bytes.dp_give = self.dp_give; - // Unknown - *bytes.unknown_1a = self.unknown_1a; - // Health LittleEndian::write_u16(bytes.hp, self.hp); @@ -424,9 +417,6 @@ impl Bytes for Digimon // Cross move Option::::to_bytes(&self.cross_move_effect, bytes.cross_move_effect).into_ok(); - // Unknown - *bytes.unknown_e2 = self.unknown_e2; - // Support arrow color Option::::to_bytes(&self.effect_arrow_color, bytes.effect_arrow_color).into_ok(); @@ -440,6 +430,11 @@ impl Bytes for Digimon util::write_null_ascii_string(self.effect_description[3].as_ref(), bytes.effect_description_3) .map_err(ToBytesError::EffectDescriptionFourth)?; + // Unknown + LittleEndian::write_u16(bytes.unknown_15, self.unknown_15); + *bytes.unknown_1a = self.unknown_1a; + *bytes.unknown_e2 = self.unknown_e2; + // Return Ok Ok(()) } diff --git a/src/game/card/item.rs b/src/game/card/item.rs index c0ff5be..486b8f1 100644 --- a/src/game/card/item.rs +++ b/src/game/card/item.rs @@ -1,258 +1,279 @@ -//! Item - -// Crate -//-------------------------------------------------------------------------------------------------- - // Game - use crate::game::util; - use crate::game::Bytes; - use crate::game::card::property::EffectCondition; - use crate::game::card::property::Effect; - use crate::game::card::property::ArrowColor; -//-------------------------------------------------------------------------------------------------- - -// Array-ref -use arrayref::{array_ref, array_mut_ref}; +//! An item card +//! +//! This module contains the [`Item`] struct, which describes an item card. +//! +//! # Layout +//! The item card has a size of `0xde` bytes, and it's layout is the following: +//! +//! | Offset | Size | Type | Name | Location | Details | +//! |--------|------|---------------------|---------------------------|------------------------|-------------------------------------------------------------------------------------| +//! | 0x0 | 0x15 | `[char; 0x15]` | Name | `name` | Null-terminated | +//! | 0x15 | 0x4 | `u32` | Unknown | `unknown_15` | | +//! | 0x19 | 0x20 | [`EffectCondition`] | First condition | `effect_conditions[0]` | | +//! | 0x39 | 0x20 | [`EffectCondition`] | Second condition | `effect_conditions[1]` | | +//! | 0x59 | 0x10 | [`Effect`] | First effect | `effects[0]` | | +//! | 0x69 | 0x10 | [`Effect`] | Second effect | `effects[1]` | | +//! | 0x79 | 0x10 | [`Effect`] | Third effect | `effects[2]` | | +//! | 0x89 | 0x1 | [`ArrowColor`] | Effect arrow color | `effect_arrow_color` | | +//! | 0x8a | 0x54 | `[[char; 0x15]; 4]` | Effect description lines | `effect_description` | Each line is` 0x15` bytes, split over 4 lines, each null terminated | // byteorder -use byteorder::ByteOrder; -use byteorder::LittleEndian; +use byteorder::{ByteOrder, LittleEndian}; -// Macros -use serde::Serialize; -use serde::Deserialize; +// Crate +use crate::game::{ + util, + Bytes, + card::property::{ + self, + EffectCondition, + Effect, + ArrowColor, + } +}; -// Types -//-------------------------------------------------------------------------------------------------- - /// A item card - #[derive(Debug, Serialize, Deserialize)] - pub struct Item - { - /// The basic info of the item - pub basic: Basic, - - /// The effects - effects: Effects, - } +/// A item card +#[derive(PartialEq, Eq, Clone, Hash, Debug)] +#[derive(serde::Serialize, serde::Deserialize)] +pub struct Item +{ + /// The digimon's name + /// + /// An ascii string with 20 characters at most + pub name: ascii::AsciiString, - /// The basic properties of a item - #[derive(Debug, Serialize, Deserialize)] - pub struct Basic - { - pub name: String, - - pub unknown: u16, - } + /// The digimon's effect description. + /// + /// The description is split along 4 lines, each + /// being an ascii string with 20 characters at most. + pub effect_description: [ascii::AsciiString; 4], - #[derive(Debug, Serialize, Deserialize)] - struct Effects - { - description: [String; 4], - arrow_color: Option, - - conditions: SupportConditions, - effects : SupportEffects, - } + /// The effect arrow color + #[serde(default)] + pub effect_arrow_color: Option, - #[derive(Debug, Serialize, Deserialize)] - struct SupportEffects - { - first : Option, - second: Option, - third : Option, - } + /// The effect conditions + #[serde(default)] + pub effect_conditions: [Option; 2], - #[derive(Debug, Serialize, Deserialize)] - struct SupportConditions - { - first : Option, - second: Option, - } + /// The effects themselves + #[serde(default)] + pub effects: [Option; 3], - /// 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 read the effect arrow color - #[display(fmt = "Unable to read the effect arrow color")] - EffectArrowColor( crate::game::card::property::arrow_color::FromBytesError ), - - /// Unable to convert one of the support effect descriptions to a string - #[display(fmt = "Unable to convert the {} support effect description to a string", rank)] - SupportEffectDescriptionToString { - rank: &'static str, - err: util::ReadNullTerminatedStringError, - }, - - /// Unable to read a support effect condition - #[display(fmt = "Unable to read the {0} support effect condition [item:0x{1:x}]", rank, item_pos)] - SupportCondition { - rank: &'static str, - item_pos: u64, - err: crate::game::card::property::effect_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::effect::FromBytesError, - }, - } - - impl std::error::Error for FromBytesError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::NameToString(err) | - Self::SupportEffectDescriptionToString{err, ..} => Some(err), - - Self::EffectArrowColor(err) => Some(err), - Self::SupportCondition{err, ..} => Some(err), - Self::SupportEffect{err, ..} => Some(err), - } - } - } - - /// The error type thrown by `ToBytes` - #[derive(Debug, derive_more::Display)] - pub enum ToBytesError - { - /// The name was too big to be written to file - #[display(fmt = "The name \"{}\" is too long to be written to file (max is 20)", _0)] - NameTooLong( String ), - - /// The name was too big to be written to file - #[display(fmt = "The {0} support effect description \"{1}\" is too long to be written to file (max is 21)", rank, string)] - SupportEffectDescriptionTooLong { - rank: &'static str, - string: String, - }, - } - - impl std::error::Error for ToBytesError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::NameTooLong(..) | - Self::SupportEffectDescriptionTooLong{ .. } => None, - } - } - } -//-------------------------------------------------------------------------------------------------- + // Unknown fields + pub unknown_15: u32, +} -// Impl -//-------------------------------------------------------------------------------------------------- - // Bytes - impl Bytes for Item +/// Error type for [`Bytes::from_bytes`] +#[derive(Debug)] +#[derive(derive_more::Display, err_impl::Error)] +pub enum FromBytesError +{ + /// Unable to read the digimon name + #[display(fmt = "Unable to read the digimon name")] + Name( #[error(source)] util::ReadNullAsciiStringError ), + + /// Unable to read the first support effect description + #[display(fmt = "Unable to read the first line of the effect description")] + EffectDescriptionFirst( #[error(source)] util::ReadNullAsciiStringError ), + + /// Unable to read the second support effect description + #[display(fmt = "Unable to read the second line of the effect description")] + EffectDescriptionSecond( #[error(source)] util::ReadNullAsciiStringError ), + + /// Unable to read the third support effect description + #[display(fmt = "Unable to read the third line of the effect description")] + EffectDescriptionThird( #[error(source)] util::ReadNullAsciiStringError ), + + /// Unable to read the fourth support effect description + #[display(fmt = "Unable to read the fourth line of the effect description")] + EffectDescriptionFourth( #[error(source)] util::ReadNullAsciiStringError ), + + /// An unknown effect arrow color was found + #[display(fmt = "Unknown effect arrow color found")] + ArrowColor( #[error(source)] property::arrow_color::FromBytesError ), + + /// Unable to read the first effect condition + #[display(fmt = "Unable to read the first effect condition")] + EffectConditionFirst( #[error(source)] property::effect_condition::FromBytesError ), + + /// Unable to read the second effect condition + #[display(fmt = "Unable to read the second effect condition")] + EffectConditionSecond( #[error(source)] property::effect_condition::FromBytesError ), + + /// Unable to read the first effect + #[display(fmt = "Unable to read the first effect")] + EffectFirst( #[error(source)] property::effect::FromBytesError ), + + /// Unable to read the second effect + #[display(fmt = "Unable to read the second effect")] + EffectSecond( #[error(source)] property::effect::FromBytesError ), + + /// Unable to read the third effect + #[display(fmt = "Unable to read the third effect")] + EffectThird( #[error(source)] property::effect::FromBytesError ), +} + +/// Error type for [`Bytes::to_bytes`] +#[derive(Debug)] +#[derive(derive_more::Display, err_impl::Error)] +pub enum ToBytesError +{ + /// Unable to write the digimon name + #[display(fmt = "Unable to write the digimon name")] + Name( #[error(source)] util::WriteNullAsciiStringError ), + + /// Unable to write the first support effect description + #[display(fmt = "Unable to write the first line of the effect description")] + EffectDescriptionFirst( #[error(source)] util::WriteNullAsciiStringError ), + + /// Unable to write the second support effect description + #[display(fmt = "Unable to write the second line of the effect description")] + EffectDescriptionSecond( #[error(source)] util::WriteNullAsciiStringError ), + + /// Unable to write the third support effect description + #[display(fmt = "Unable to write the third line of the effect description")] + EffectDescriptionThird( #[error(source)] util::WriteNullAsciiStringError ), + + /// Unable to write the fourth support effect description + #[display(fmt = "Unable to write the fourth line of the effect description")] + EffectDescriptionFourth( #[error(source)] util::WriteNullAsciiStringError ), + + /// Unable to write the first effect + #[display(fmt = "Unable to write the first effect")] + EffectFirst( #[error(source)] property::effect::ToBytesError ), + + /// Unable to write the second effect + #[display(fmt = "Unable to write the second effect")] + EffectSecond( #[error(source)] property::effect::ToBytesError ), + + /// Unable to write the third effect + #[display(fmt = "Unable to write the third effect")] + EffectThird( #[error(source)] property::effect::ToBytesError ), +} + + +impl Bytes for Item +{ + type ByteArray = [u8; 0xde]; + + type FromError = FromBytesError; + fn from_bytes(bytes: &Self::ByteArray) -> Result { - type ByteArray = [u8; 0xde]; + // Split bytes + let bytes = util::array_split!(bytes, + name : [0x15], + unknown_15 : [0x4], + condition_first : [0x20], + condition_second : [0x20], + effect_first : [0x10], + effect_second : [0x10], + effect_third : [0x10], + effect_arrow_color : 1, + effect_description_0: [0x15], + effect_description_1: [0x15], + effect_description_2: [0x15], + effect_description_3: [0x15], + ); - type FromError = FromBytesError; - fn from_bytes(bytes: &Self::ByteArray) -> Result - { - // Assert some fields are 0 - //assert_eq!(bytes[0x1a], 0); - - // And return the struct - Ok( Self { - basic: Basic { - name: util::read_null_terminated_string( &bytes[0x0..0x15] ).map_err(FromBytesError::NameToString)?.to_string(), - - unknown: LittleEndian::read_u16( &bytes[0x15..0x17] ), - }, - - effects: Effects { - description: [ - util::read_null_terminated_string( &bytes[0x8a..0x9f] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "1st", err })?.to_string(), - util::read_null_terminated_string( &bytes[0x9f..0xb4] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "2nd", err })?.to_string(), - util::read_null_terminated_string( &bytes[0xb4..0xc9] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "3rd", err })?.to_string(), - util::read_null_terminated_string( &bytes[0xc9..0xde] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "4th", err })?.to_string(), - ], - - arrow_color: if bytes[0x89] != 0 { - Some( ArrowColor::from_bytes( &bytes[0x89] ).map_err(FromBytesError::EffectArrowColor)? ) - } else { None }, - - conditions: SupportConditions { - first: Option::::from_bytes( array_ref!(bytes, 0x19, 0x20) ) - .map_err(|err| FromBytesError::SupportCondition{ rank: "1st", item_pos: 0x19, err })?, - second: Option::::from_bytes( array_ref!(bytes, 0x39, 0x20) ) - .map_err(|err| FromBytesError::SupportCondition{ rank: "2nd", item_pos: 0x39, err })?, - }, - - effects: SupportEffects { - first: Option::::from_bytes( array_ref!(bytes, 0x59, 0x10) ) - .map_err(|err| FromBytesError::SupportEffect{ rank: "1st", err })?, - second: Option::::from_bytes( array_ref!(bytes, 0x69, 0x10) ) - .map_err(|err| FromBytesError::SupportEffect{ rank: "2nd", err })?, - third: Option::::from_bytes( array_ref!(bytes, 0x79, 0x10) ) - .map_err(|err| FromBytesError::SupportEffect{ rank: "3rd", err })?, - }, - }, - }) - } - - type ToError = ToBytesError; - fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> - { - // Basic - //-------------------------------------------------------------------------------------------------- - // Write the name - bytes[0x0..0x15].copy_from_slice( &{ - // Check if our name is too big - if self.basic.name.len() >= 0x15 { return Err( ToBytesError::NameTooLong( self.basic.name.clone() ) ); } - - // Else make the buffer and copy everything over - let mut buf = [0u8; 0x15]; - buf[ 0..self.basic.name.len() ].copy_from_slice( self.basic.name.as_bytes() ); - buf - }); - - LittleEndian::write_u16(&mut bytes[0x15..0x17], self.basic.unknown); - //-------------------------------------------------------------------------------------------------- + // And return the struct + Ok( Self { + name: util::read_null_ascii_string(bytes.name) + .map_err(FromBytesError::Name)? + .chars().collect(), // Effects - //-------------------------------------------------------------------------------------------------- - // Write the support effects - for (index, line) in self.effects.description.iter().enumerate() - { - bytes[0x8a + (0x15 * index) .. 0x9f + (0x15 * index)].copy_from_slice( &{ - // If the line is too big, return Err - if line.len() >= 0x15 { - return Err( ToBytesError::SupportEffectDescriptionTooLong { - rank: match index { - 0 => "1st", 1 => "2nd", - 2 => "3rd", 3 => "4th", - _ => unreachable!(), - }, - - string: line.clone() - }); - } - - let mut buf = [0u8; 0x15]; - buf[ 0..line.len() ].copy_from_slice( line.as_bytes() ); - buf - }); - } + effect_conditions: [ + Option::::from_bytes( bytes.condition_first ) + .map_err(FromBytesError::EffectConditionFirst)?, - if let Some(arrow_color) = self.effects.arrow_color { arrow_color.to_bytes( &mut bytes[0x89] ).expect("Unable to convert arrow color to bytes"); } - - // If they are None, 0 is a valid value for the conditions - self.effects.conditions.first .to_bytes( array_mut_ref!(bytes, 0x19, 0x20) )?; - self.effects.conditions.second.to_bytes( array_mut_ref!(bytes, 0x39, 0x20) )?; - - - // If they are None, 0 is a valid value for the effects - self.effects.effects.first .to_bytes( array_mut_ref!(bytes, 0x59, 0x10) ).expect("TODO"); - self.effects.effects.second.to_bytes( array_mut_ref!(bytes, 0x69, 0x10) ).expect("TODO"); - self.effects.effects.third .to_bytes( array_mut_ref!(bytes, 0x79, 0x10) ).expect("TODO"); - //-------------------------------------------------------------------------------------------------- + Option::::from_bytes( bytes.condition_second ) + .map_err(FromBytesError::EffectConditionSecond)?, + ], - // Return the bytes - Ok(()) - } + effects: [ + Option::::from_bytes( bytes.effect_first ) + .map_err(FromBytesError::EffectFirst)?, + + Option::::from_bytes( bytes.effect_second ) + .map_err(FromBytesError::EffectSecond)?, + + Option::::from_bytes( bytes.effect_third ) + .map_err(FromBytesError::EffectThird)?, + ], + + effect_arrow_color: Option::::from_bytes(bytes.effect_arrow_color) + .map_err(FromBytesError::ArrowColor)?, + + effect_description: [ + util::read_null_ascii_string( bytes.effect_description_0 ) + .map_err(FromBytesError::EffectDescriptionFirst)? + .chars().collect(), + util::read_null_ascii_string( bytes.effect_description_1 ) + .map_err(FromBytesError::EffectDescriptionSecond)? + .chars().collect(), + util::read_null_ascii_string( bytes.effect_description_2 ) + .map_err(FromBytesError::EffectDescriptionThird)? + .chars().collect(), + util::read_null_ascii_string( bytes.effect_description_3 ) + .map_err(FromBytesError::EffectDescriptionFourth)? + .chars().collect(), + ], + + // Unknown + unknown_15: LittleEndian::read_u32(bytes.unknown_15), + }) } -//-------------------------------------------------------------------------------------------------- + + type ToError = ToBytesError; + fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> + { + // Split bytes + let bytes = util::array_split_mut!(bytes, + name : [0x15], + unknown_15 : [0x4], + condition_first : [0x20], + condition_second : [0x20], + effect_first : [0x10], + effect_second : [0x10], + effect_third : [0x10], + effect_arrow_color : 1, + effect_description_0: [0x15], + effect_description_1: [0x15], + effect_description_2: [0x15], + effect_description_3: [0x15], + ); + + // Name + util::write_null_ascii_string(self.name.as_ref(), bytes.name) + .map_err(ToBytesError::Name)?; + + // Effect conditions + self.effect_conditions[0].to_bytes( bytes.condition_first ).into_ok(); + self.effect_conditions[1].to_bytes( bytes.condition_second ).into_ok(); + + // Effects + self.effects[0].to_bytes( bytes.effect_first ).map_err(ToBytesError::EffectFirst )?; + self.effects[1].to_bytes( bytes.effect_second ).map_err(ToBytesError::EffectSecond)?; + self.effects[2].to_bytes( bytes.effect_third ).map_err(ToBytesError::EffectThird )?; + + // Support arrow color + Option::::to_bytes(&self.effect_arrow_color, bytes.effect_arrow_color).into_ok(); + + // effect_description + util::write_null_ascii_string(self.effect_description[0].as_ref(), bytes.effect_description_0) + .map_err(ToBytesError::EffectDescriptionFirst)?; + util::write_null_ascii_string(self.effect_description[1].as_ref(), bytes.effect_description_1) + .map_err(ToBytesError::EffectDescriptionSecond)?; + util::write_null_ascii_string(self.effect_description[2].as_ref(), bytes.effect_description_2) + .map_err(ToBytesError::EffectDescriptionThird)?; + util::write_null_ascii_string(self.effect_description[3].as_ref(), bytes.effect_description_3) + .map_err(ToBytesError::EffectDescriptionFourth)?; + + // Unknown + LittleEndian::write_u32(bytes.unknown_15, self.unknown_15); + + // Return Ok + Ok(()) + } +} diff --git a/src/game/card/property/effect.rs b/src/game/card/property/effect.rs index bee14d4..d3c2c88 100644 --- a/src/game/card/property/effect.rs +++ b/src/game/card/property/effect.rs @@ -411,7 +411,7 @@ impl Bytes for Effect (Player , DpSlot, OfflineDeck) => 36, (Opponent, DpSlot, OfflineDeck) => 37, - (_, &source, &destination) => return Err(ToBytesError::InvalidMoveCards { source, destination }), + (_, &source, &destination) => return Err( ToBytesError::InvalidMoveCards { source, destination } ), }; LittleEndian::write_u16(bytes.y, *count); } diff --git a/src/game/util.rs b/src/game/util.rs index 658ef95..f2b1369 100644 --- a/src/game/util.rs +++ b/src/game/util.rs @@ -126,21 +126,6 @@ pub macro array_split_mut { } } } - - /// Error type for `write_null_terminated_string` - #[derive(Debug, derive_more::Display)] - #[display(fmt = "The string was too long to write to the buffer ({0} / {1})", string_size, buf_size)] - pub struct WriteNullTerminatedStringError - { - /// The string size - string_size: usize, - - /// The buffer size - buf_size: usize, - } - - // No source - impl std::error::Error for WriteNullTerminatedStringError { } //-------------------------------------------------------------------------------------------------- // Impl @@ -167,42 +152,6 @@ pub macro array_split_mut { // Else try to conver the buffer into a utf8 str. Ok( std::str::from_utf8( buf ).map_err(ReadNullTerminatedStringError::Utf8)? ) } - - /// Writes a string to a buffer with a null terminator and returns it - /// - /// # Details - /// Will reserve the last byte after the string for a null, none of - /// the bytes after it will be touched. - /// - /// # Errors - /// - `TooLong`: If the string is too long for the buffer - pub fn write_null_terminated_string<'a>(string: &'_ str, buf: &'a mut [u8]) -> Result<&'a mut [u8], WriteNullTerminatedStringError> - { - // Check if the string is too big - // Note: This also catches the case where they're both 0 - if string.len() >= buf.len() { return Err( WriteNullTerminatedStringError{ string_size: string.len(), buf_size: buf.len() } ); } - - // Else copy everything over - buf[ 0..string.len() ].copy_from_slice( string.as_bytes() ); - - // Set the last byte of the string as null - buf[ string.len() ] = 0; - - // And return the buffer - Ok( buf ) - } - - /// Returns an ordinal string from a u64 - #[must_use] - pub fn as_ordinal(num: u64) -> String - { - format!("{0}{1}", num, match num % 10 { - 1 => "st", - 2 => "nd", - 3 => "rd", - _ => "th", - }) - } //--------------------------------------------------------------------------------------------------