mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-10 12:17:05 +00:00
Updated names relating to support conditions / effects.
Added documentation to `EffectCondition`. Changed `array_split` to behave like `array_split_mut`. Instead of using `?` on `Result<T, !>` , we use `Result::into_ok`.
This commit is contained in:
@@ -5,27 +5,27 @@
|
||||
//! # Layout
|
||||
//! The digimon card has a size of `0x138` bytes, and it's layout is the following:
|
||||
//!
|
||||
//! | 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 |
|
||||
//! | 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` | |
|
||||
//! | 0x1a | 0x1 | `u8` | Unknown | `unknown_1a` | Is `0` for all digimon |
|
||||
//! | 0x1b | 0x2 | `u16` | Health | `hp` | |
|
||||
//! | 0x1d | 0x1c | [`Move`] | Circle Move | `move_circle` | |
|
||||
//! | 0x39 | 0x1c | [`Move`] | Triangle move | `move_triangle` | |
|
||||
//! | 0x55 | 0x1c | [`Move`] | Cross move | `move_cross` | |
|
||||
//! | 0x71 | 0x20 | [`SupportCondition`] | First condition | `effect_conditions[0]` | |
|
||||
//! | 0x91 | 0x20 | [`SupportCondition`] | Second condition | `effect_conditions[1]` | |
|
||||
//! | 0xb1 | 0x10 | [`SupportEffect`] | First effect | `effects[0]` | |
|
||||
//! | 0xc1 | 0x10 | [`SupportEffect`] | Second effect | `effects[1]` | |
|
||||
//! | 0xd1 | 0x10 | [`SupportEffect`] | Third effect | `effects[2]` | |
|
||||
//! | 0xe1 | 0x1 | [`CrossMoveEffect`] | Cross move effect | `cross_move_effect` | |
|
||||
//! | 0xe2 | 0x1 | `u8` | Unknown | `unknown_e2` | |
|
||||
//! | 0xe3 | 0x1 | [`ArrowColor`] | Effect arrow color | `effect_arrow_color` | |
|
||||
//! | 0xe4 | 0x54 | `[[char; 0x15]; 4]` | Effect description lines | `effect_description` | Each line is` 0x15` bytes, split over 4 lines, each null terminated |
|
||||
//! | 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 |
|
||||
//! | 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` | |
|
||||
//! | 0x1a | 0x1 | `u8` | Unknown | `unknown_1a` | Is `0` for all digimon |
|
||||
//! | 0x1b | 0x2 | `u16` | Health | `hp` | |
|
||||
//! | 0x1d | 0x1c | [`Move`] | Circle Move | `move_circle` | |
|
||||
//! | 0x39 | 0x1c | [`Move`] | Triangle move | `move_triangle` | |
|
||||
//! | 0x55 | 0x1c | [`Move`] | Cross move | `move_cross` | |
|
||||
//! | 0x71 | 0x20 | [`EffectCondition`] | First condition | `effect_conditions[0]` | |
|
||||
//! | 0x91 | 0x20 | [`EffectCondition`] | Second condition | `effect_conditions[1]` | |
|
||||
//! | 0xb1 | 0x10 | [`Effect`] | First effect | `effects[0]` | |
|
||||
//! | 0xc1 | 0x10 | [`Effect`] | Second effect | `effects[1]` | |
|
||||
//! | 0xd1 | 0x10 | [`Effect`] | Third effect | `effects[2]` | |
|
||||
//! | 0xe1 | 0x1 | [`CrossMoveEffect`] | Cross move effect | `cross_move_effect` | |
|
||||
//! | 0xe2 | 0x1 | `u8` | Unknown | `unknown_e2` | |
|
||||
//! | 0xe3 | 0x1 | [`ArrowColor`] | Effect arrow color | `effect_arrow_color` | |
|
||||
//! | 0xe4 | 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, LittleEndian};
|
||||
@@ -40,8 +40,8 @@ use crate::game::{
|
||||
Level,
|
||||
Move,
|
||||
CrossMoveEffect,
|
||||
SupportCondition,
|
||||
SupportEffect,
|
||||
EffectCondition,
|
||||
Effect,
|
||||
ArrowColor,
|
||||
}
|
||||
};
|
||||
@@ -111,11 +111,11 @@ pub struct Digimon
|
||||
|
||||
/// The effect conditions
|
||||
#[serde(default)]
|
||||
pub effect_conditions: [Option<SupportCondition>; 2],
|
||||
pub effect_conditions: [Option<EffectCondition>; 2],
|
||||
|
||||
/// The effects themselves
|
||||
#[serde(default)]
|
||||
pub effects: [Option<SupportEffect>; 3],
|
||||
pub effects: [Option<Effect>; 3],
|
||||
}
|
||||
|
||||
/// Error type for [`Bytes::from_bytes`]
|
||||
@@ -173,23 +173,23 @@ pub enum FromBytesError
|
||||
|
||||
/// Unable to read the first effect condition
|
||||
#[display(fmt = "Unable to read the first effect condition")]
|
||||
EffectConditionFirst( #[error(source)] property::support_condition::FromBytesError ),
|
||||
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::support_condition::FromBytesError ),
|
||||
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::support_effect::FromBytesError ),
|
||||
EffectFirst( #[error(source)] property::effect::FromBytesError ),
|
||||
|
||||
/// Unable to read the second effect
|
||||
#[display(fmt = "Unable to read the second effect")]
|
||||
EffectSecond( #[error(source)] property::support_effect::FromBytesError ),
|
||||
EffectSecond( #[error(source)] property::effect::FromBytesError ),
|
||||
|
||||
/// Unable to read the third effect
|
||||
#[display(fmt = "Unable to read the third effect")]
|
||||
EffectThird( #[error(source)] property::support_effect::FromBytesError ),
|
||||
EffectThird( #[error(source)] property::effect::FromBytesError ),
|
||||
}
|
||||
/// Error type for [`Bytes::to_bytes`]
|
||||
#[derive(Debug)]
|
||||
@@ -238,25 +238,28 @@ impl Bytes for Digimon
|
||||
{
|
||||
// Get all byte arrays we need
|
||||
let bytes = util::array_split!(bytes,
|
||||
0x00..0x15 => name,
|
||||
0x15..0x17 => unknown_15,
|
||||
=0x17 => speciality_level,
|
||||
=0x18 => dp_cost,
|
||||
=0x19 => dp_give,
|
||||
=0x1a => unknown_1a,
|
||||
0x1b..0x1d => hp,
|
||||
0x1d..0x39 => move_circle,
|
||||
0x39..0x55 => move_triangle,
|
||||
0x55..0x71 => move_cross,
|
||||
0x71..0x91 => condition_first,
|
||||
0x91..0xb1 => condition_second,
|
||||
0xb1..0xc1 => effect_first,
|
||||
0xc1..0xd1 => effect_second,
|
||||
0xd1..0xe1 => effect_third,
|
||||
0xe1..0xe2 => cross_move_effect,
|
||||
0xe2..0xe3 => unknown_e2,
|
||||
0xe3..0xe4 => effect_arrow_color,
|
||||
0xe4..0x138 => effect_description,
|
||||
name : [0x15],
|
||||
unknown_15 : [0x2],
|
||||
speciality_level : 0x1,
|
||||
dp_cost : 0x1,
|
||||
dp_give : 0x1,
|
||||
unknown_1a : 0x1,
|
||||
hp : [0x2],
|
||||
move_circle : [0x1c],
|
||||
move_triangle : [0x1c],
|
||||
move_cross : [0x1c],
|
||||
condition_first : [0x20],
|
||||
condition_second : [0x20],
|
||||
effect_first : [0x10],
|
||||
effect_second : [0x10],
|
||||
effect_third : [0x10],
|
||||
cross_move_effect : 1,
|
||||
unknown_e2 : 1,
|
||||
effect_arrow_color : 1,
|
||||
effect_description_0: [0x15],
|
||||
effect_description_1: [0x15],
|
||||
effect_description_2: [0x15],
|
||||
effect_description_3: [0x15],
|
||||
);
|
||||
|
||||
// Return the struct after building it
|
||||
@@ -290,57 +293,53 @@ impl Bytes for Digimon
|
||||
|
||||
// 0x71 - 0x138
|
||||
effect_conditions: [
|
||||
(bytes.condition_first[2] != 0)
|
||||
.then(|| SupportCondition::from_bytes( bytes.condition_first ) )
|
||||
.transpose()
|
||||
Option::<EffectCondition>::from_bytes( bytes.condition_first )
|
||||
.map_err(FromBytesError::EffectConditionFirst)?,
|
||||
|
||||
(bytes.condition_second[2] != 0)
|
||||
.then(|| SupportCondition::from_bytes( bytes.condition_second ) )
|
||||
.transpose()
|
||||
Option::<EffectCondition>::from_bytes( bytes.condition_second )
|
||||
.map_err(FromBytesError::EffectConditionSecond)?,
|
||||
],
|
||||
|
||||
effects: [
|
||||
(bytes.effect_first[0] != 0)
|
||||
.then(|| SupportEffect::from_bytes( bytes.effect_first ) )
|
||||
(bytes.effect_first[0x0] != 0)
|
||||
.then(|| Effect::from_bytes( bytes.effect_first ) )
|
||||
.transpose()
|
||||
.map_err(FromBytesError::EffectFirst)?,
|
||||
|
||||
(bytes.effect_second[0] != 0)
|
||||
.then(|| SupportEffect::from_bytes( bytes.effect_second ) )
|
||||
(bytes.effect_second[0x0] != 0)
|
||||
.then(|| Effect::from_bytes( bytes.effect_second ) )
|
||||
.transpose()
|
||||
.map_err(FromBytesError::EffectSecond)?,
|
||||
|
||||
(bytes.effect_third[0] != 0)
|
||||
.then(|| SupportEffect::from_bytes( bytes.effect_third ) )
|
||||
(bytes.effect_third[0x0] != 0)
|
||||
.then(|| Effect::from_bytes( bytes.effect_third ) )
|
||||
.transpose()
|
||||
.map_err(FromBytesError::EffectThird)?,
|
||||
],
|
||||
|
||||
cross_move_effect: (bytes.cross_move_effect[0] != 0)
|
||||
.then(|| CrossMoveEffect::from_bytes( &bytes.cross_move_effect[0] ) )
|
||||
cross_move_effect: (*bytes.cross_move_effect != 0)
|
||||
.then(|| CrossMoveEffect::from_bytes( bytes.cross_move_effect ) )
|
||||
.transpose()
|
||||
.map_err(FromBytesError::CrossMoveEffect)?,
|
||||
|
||||
unknown_e2: bytes.unknown_e2[0],
|
||||
unknown_e2: *bytes.unknown_e2,
|
||||
|
||||
effect_arrow_color: (bytes.effect_arrow_color[0] != 0)
|
||||
.then(|| ArrowColor::from_bytes( &bytes.effect_arrow_color[0] ) )
|
||||
effect_arrow_color: (*bytes.effect_arrow_color != 0)
|
||||
.then(|| ArrowColor::from_bytes( bytes.effect_arrow_color ) )
|
||||
.transpose()
|
||||
.map_err(FromBytesError::ArrowColor)?,
|
||||
|
||||
effect_description: [
|
||||
util::read_null_ascii_string( &bytes.effect_description[0x00..0x15] )
|
||||
util::read_null_ascii_string( bytes.effect_description_0 )
|
||||
.map_err(FromBytesError::EffectDescriptionFirst)?
|
||||
.chars().collect(),
|
||||
util::read_null_ascii_string( &bytes.effect_description[0x15..0x2a] )
|
||||
util::read_null_ascii_string( bytes.effect_description_1 )
|
||||
.map_err(FromBytesError::EffectDescriptionSecond)?
|
||||
.chars().collect(),
|
||||
util::read_null_ascii_string( &bytes.effect_description[0x2a..0x3f] )
|
||||
util::read_null_ascii_string( bytes.effect_description_2 )
|
||||
.map_err(FromBytesError::EffectDescriptionThird)?
|
||||
.chars().collect(),
|
||||
util::read_null_ascii_string( &bytes.effect_description[0x3f..0x54] )
|
||||
util::read_null_ascii_string( bytes.effect_description_3 )
|
||||
.map_err(FromBytesError::EffectDescriptionFourth)?
|
||||
.chars().collect(),
|
||||
],
|
||||
@@ -410,16 +409,14 @@ impl Bytes for Digimon
|
||||
self.move_triangle.to_bytes( bytes.move_triangle ).map_err(ToBytesError::MoveTriangle)?;
|
||||
self. move_cross.to_bytes( bytes.move_cross ).map_err(ToBytesError::MoveCross )?;
|
||||
|
||||
// Support conditions
|
||||
// Note: Although support conditions and effects aren't written if they're None,
|
||||
// a bit pattern of all 0s is a valid pattern and means "None" to the game.
|
||||
if let Some(support_condition) = &self.effect_conditions[0] { support_condition.to_bytes( bytes.condition_first )?; }
|
||||
if let Some(support_condition) = &self.effect_conditions[1] { support_condition.to_bytes( bytes.condition_second )?; }
|
||||
// Effect conditions
|
||||
self.effect_conditions[0].to_bytes( bytes.condition_first ).into_ok();
|
||||
self.effect_conditions[1].to_bytes( bytes.condition_second ).into_ok();
|
||||
|
||||
// Support effects
|
||||
if let Some(support_effect) = &self.effects[0] { support_effect.to_bytes( bytes.effect_first )?; }
|
||||
if let Some(support_effect) = &self.effects[1] { support_effect.to_bytes( bytes.effect_second )?; }
|
||||
if let Some(support_effect) = &self.effects[2] { support_effect.to_bytes( bytes.effect_third )?; }
|
||||
// Effects
|
||||
if let Some(effect) = &self.effects[0] { effect.to_bytes( bytes.effect_first )?; }
|
||||
if let Some(effect) = &self.effects[1] { effect.to_bytes( bytes.effect_second )?; }
|
||||
if let Some(effect) = &self.effects[2] { effect.to_bytes( bytes.effect_third )?; }
|
||||
|
||||
// Cross move
|
||||
if let Some(move_cross) = self.cross_move_effect { move_cross.to_bytes( bytes.cross_move_effect )? };
|
||||
|
||||
@@ -93,14 +93,14 @@ use serde::Deserialize;
|
||||
SupportEffectCondition {
|
||||
rank: &'static str,
|
||||
digivolve_pos: u64,
|
||||
err: crate::game::card::property::support_condition::FromBytesError,
|
||||
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::support_effect::FromBytesError,
|
||||
err: crate::game::card::property::effect::FromBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
// Game
|
||||
use crate::game::util;
|
||||
use crate::game::Bytes;
|
||||
use crate::game::card::property::SupportCondition;
|
||||
use crate::game::card::property::SupportEffect;
|
||||
use crate::game::card::property::EffectCondition;
|
||||
use crate::game::card::property::Effect;
|
||||
use crate::game::card::property::ArrowColor;
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -56,16 +56,16 @@ use serde::Deserialize;
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct SupportEffects
|
||||
{
|
||||
first : Option<SupportEffect>,
|
||||
second: Option<SupportEffect>,
|
||||
third : Option<SupportEffect>,
|
||||
first : Option<Effect>,
|
||||
second: Option<Effect>,
|
||||
third : Option<Effect>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct SupportConditions
|
||||
{
|
||||
first : Option<SupportCondition>,
|
||||
second: Option<SupportCondition>,
|
||||
first : Option<EffectCondition>,
|
||||
second: Option<EffectCondition>,
|
||||
}
|
||||
|
||||
/// The error type thrown by `FromBytes`
|
||||
@@ -92,14 +92,14 @@ use serde::Deserialize;
|
||||
SupportCondition {
|
||||
rank: &'static str,
|
||||
item_pos: u64,
|
||||
err: crate::game::card::property::support_condition::FromBytesError,
|
||||
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::support_effect::FromBytesError,
|
||||
err: crate::game::card::property::effect::FromBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -176,26 +176,23 @@ use serde::Deserialize;
|
||||
} else { None },
|
||||
|
||||
conditions: SupportConditions {
|
||||
first: if bytes[0x19] != 0 { Some(
|
||||
SupportCondition::from_bytes( array_ref!(bytes, 0x19, 0x20) ).map_err(|err| FromBytesError::SupportCondition{ rank: "1st", item_pos: 0x19, err })?
|
||||
)} else { None },
|
||||
|
||||
second: if bytes[0x39] != 0 { Some(
|
||||
SupportCondition::from_bytes( array_ref!(bytes, 0x39, 0x20) ).map_err(|err| FromBytesError::SupportCondition{ rank: "2nd", item_pos: 0x39, err })?
|
||||
)} else { None },
|
||||
first: Option::<EffectCondition>::from_bytes( array_ref!(bytes, 0x19, 0x20) )
|
||||
.map_err(|err| FromBytesError::SupportCondition{ rank: "1st", item_pos: 0x19, err })?,
|
||||
second: Option::<EffectCondition>::from_bytes( array_ref!(bytes, 0x39, 0x20) )
|
||||
.map_err(|err| FromBytesError::SupportCondition{ rank: "2nd", item_pos: 0x39, err })?,
|
||||
},
|
||||
|
||||
effects: SupportEffects {
|
||||
first: if bytes[0x59] != 0 { Some(
|
||||
SupportEffect::from_bytes( array_ref!(bytes, 0x59, 0x10) ).map_err(|err| FromBytesError::SupportEffect{ rank: "1st", err })?
|
||||
Effect::from_bytes( array_ref!(bytes, 0x59, 0x10) ).map_err(|err| FromBytesError::SupportEffect{ rank: "1st", err })?
|
||||
)} else { None },
|
||||
|
||||
second: if bytes[0x69] != 0 { Some(
|
||||
SupportEffect::from_bytes( array_ref!(bytes, 0x69, 0x10) ).map_err(|err| FromBytesError::SupportEffect{ rank: "2nd", err })?
|
||||
Effect::from_bytes( array_ref!(bytes, 0x69, 0x10) ).map_err(|err| FromBytesError::SupportEffect{ rank: "2nd", err })?
|
||||
)} else { None },
|
||||
|
||||
third: if bytes[0x79] != 0 { Some(
|
||||
SupportEffect::from_bytes( array_ref!(bytes, 0x79, 0x10) ).map_err(|err| FromBytesError::SupportEffect{ rank: "3rd", err })?
|
||||
Effect::from_bytes( array_ref!(bytes, 0x79, 0x10) ).map_err(|err| FromBytesError::SupportEffect{ rank: "3rd", err })?
|
||||
)} else { None },
|
||||
},
|
||||
},
|
||||
@@ -249,8 +246,8 @@ use serde::Deserialize;
|
||||
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
|
||||
if let Some(support_condition) = &self.effects.conditions.first { support_condition.to_bytes( array_mut_ref!(bytes, 0x19, 0x20) )?; }
|
||||
if let Some(support_condition) = &self.effects.conditions.second { support_condition.to_bytes( array_mut_ref!(bytes, 0x39, 0x20) )?; }
|
||||
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
|
||||
|
||||
@@ -57,7 +57,7 @@ macro_rules! generate_enum_property_mod
|
||||
$( #[$enum_attr] )*
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
#[derive(::serde::Serialize, ::serde::Deserialize)]
|
||||
#[derive(derive_more::Display)]
|
||||
#[derive(::derive_more::Display)]
|
||||
$mod_vis enum $enum_name
|
||||
{
|
||||
$(
|
||||
@@ -112,234 +112,223 @@ macro_rules! generate_enum_property_mod
|
||||
}
|
||||
}
|
||||
|
||||
// Modules
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
generate_enum_property_mod!(
|
||||
pub mod slot {
|
||||
/// A player's card slots
|
||||
enum Slot
|
||||
{
|
||||
Hand ("Hand" ) => 0,
|
||||
Dp ("Dp" ) => 1,
|
||||
Online ("Online" ) => 2,
|
||||
Offline("Offline") => 3,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a slot"
|
||||
}
|
||||
}
|
||||
|
||||
pub mod arrow_color {
|
||||
/// A digimon effect's arrow color
|
||||
enum ArrowColor
|
||||
{
|
||||
Red ("Red" ) => 1,
|
||||
Green("Green") => 2,
|
||||
Blue ("Blue" ) => 3,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for an arrow color"
|
||||
}
|
||||
}
|
||||
|
||||
pub mod attack_type {
|
||||
/// A digimon's attack type
|
||||
enum AttackType
|
||||
{
|
||||
Circle ("Circle" ) => 0,
|
||||
Triangle("Triangle") => 1,
|
||||
Cross ("Cross" ) => 2,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for an attack type"
|
||||
}
|
||||
}
|
||||
|
||||
pub mod card_type {
|
||||
/// A card type
|
||||
enum CardType
|
||||
{
|
||||
Digimon ("Digimon" ) => 0,
|
||||
Item ("Item" ) => 1,
|
||||
Digivolve("Digivolve") => 2,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a card type"
|
||||
}
|
||||
generate_enum_property_mod!(
|
||||
pub mod slot {
|
||||
/// A player's card slots
|
||||
enum Slot
|
||||
{
|
||||
Hand ("Hand" ) => 0,
|
||||
Dp ("Dp" ) => 1,
|
||||
Online ("Online" ) => 2,
|
||||
Offline("Offline") => 3,
|
||||
|
||||
impl CardType
|
||||
_ => "Unknown byte 0x{:x} for a slot"
|
||||
}
|
||||
}
|
||||
|
||||
pub mod arrow_color {
|
||||
/// A digimon effect's arrow color
|
||||
enum ArrowColor
|
||||
{
|
||||
Red ("Red" ) => 1,
|
||||
Green("Green") => 2,
|
||||
Blue ("Blue" ) => 3,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for an arrow color"
|
||||
}
|
||||
}
|
||||
|
||||
pub mod attack_type {
|
||||
/// A digimon's attack type
|
||||
enum AttackType
|
||||
{
|
||||
Circle ("Circle" ) => 0,
|
||||
Triangle("Triangle") => 1,
|
||||
Cross ("Cross" ) => 2,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for an attack type"
|
||||
}
|
||||
}
|
||||
|
||||
pub mod card_type {
|
||||
/// A card type
|
||||
enum CardType
|
||||
{
|
||||
Digimon ("Digimon" ) => 0,
|
||||
Item ("Item" ) => 1,
|
||||
Digivolve("Digivolve") => 2,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a card type"
|
||||
}
|
||||
|
||||
impl CardType
|
||||
{
|
||||
/// Returns the byte size of the corresponding card
|
||||
#[must_use]
|
||||
pub const fn byte_size(self) -> usize
|
||||
{
|
||||
/// Returns the byte size of the corresponding card
|
||||
#[must_use]
|
||||
pub fn byte_size(self) -> usize
|
||||
match self
|
||||
{
|
||||
use crate::game::Bytes;
|
||||
|
||||
match self
|
||||
{
|
||||
Self::Digimon => std::mem::size_of::< <crate::game::card::Digimon as Bytes>::ByteArray >(),
|
||||
Self::Item => std::mem::size_of::< <crate::game::card::Item as Bytes>::ByteArray >(),
|
||||
Self::Digivolve => std::mem::size_of::< <crate::game::card::Digivolve as Bytes>::ByteArray >(),
|
||||
}
|
||||
Self::Digimon => std::mem::size_of::< <crate::game::card::Digimon as crate::game::Bytes>::ByteArray >(),
|
||||
Self::Item => std::mem::size_of::< <crate::game::card::Item as crate::game::Bytes>::ByteArray >(),
|
||||
Self::Digivolve => std::mem::size_of::< <crate::game::card::Digivolve as crate::game::Bytes>::ByteArray >(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod player_type {
|
||||
/// A player type
|
||||
enum PlayerType
|
||||
{
|
||||
Opponent("Opponent") => 0,
|
||||
Player ("Player" ) => 1,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a player type",
|
||||
}
|
||||
}
|
||||
|
||||
pub mod level {
|
||||
/// A digimon's level
|
||||
enum Level
|
||||
{
|
||||
Rookie ("Rookie" ) => 0,
|
||||
Armor ("Armor" ) => 1,
|
||||
Champion("Champion") => 2,
|
||||
Ultimate("Ultimate") => 3,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a level",
|
||||
}
|
||||
}
|
||||
|
||||
pub mod speciality {
|
||||
/// A digimon's speciality
|
||||
enum Speciality
|
||||
{
|
||||
Fire ("Fire" ) => 0,
|
||||
Ice ("Ice" ) => 1,
|
||||
Nature ("Nature" ) => 2,
|
||||
Darkness("Darkness") => 3,
|
||||
Rare ("Rare" ) => 4,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a speciality",
|
||||
}
|
||||
}
|
||||
|
||||
pub mod support_effect_operation {
|
||||
/// A digimon's support effect operation
|
||||
enum SupportEffectOperation
|
||||
{
|
||||
Addition ("Addition" ) => 0,
|
||||
Subtraction ("Subtraction" ) => 1,
|
||||
Multiplication("Multiplication") => 2,
|
||||
Division ("Division" ) => 3,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a support effect operation",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod player_type {
|
||||
/// A player type
|
||||
enum PlayerType
|
||||
{
|
||||
Opponent("Opponent") => 0,
|
||||
Player ("Player" ) => 1,
|
||||
|
||||
pub mod support_condition_operation {
|
||||
/// A digimon's support condition operation
|
||||
///
|
||||
/// # Todo
|
||||
/// These don't seem to be 100% right, the less than property, sometimes does less than number, might be a range check
|
||||
enum SupportConditionOperation
|
||||
{
|
||||
LessThanProperty ("Less than property" ) => 0,
|
||||
LessThanNumber ("Less than number" ) => 1,
|
||||
MoreThanProperty ("More than property" ) => 2,
|
||||
MoreThanNumber ("More than number" ) => 3,
|
||||
DifferentFromNumber("Different from number") => 4,
|
||||
EqualToNumber ("Equal to number" ) => 5,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a support condition operation",
|
||||
}
|
||||
_ => "Unknown byte 0x{:x} for a player type",
|
||||
}
|
||||
|
||||
pub mod cross_move_effect {
|
||||
/// A digimon's cross move effect
|
||||
enum CrossMoveEffect
|
||||
{
|
||||
FirstAttack("Attack first") => 1,
|
||||
|
||||
CircleTo0("Circle to 0" ) => 2,
|
||||
TriangleTo0("Triangle to 0") => 3,
|
||||
CrossTo0("Cross to 0" ) => 4,
|
||||
|
||||
CircleCounter("Circle counter" ) => 5,
|
||||
TriangleCounter("Triangle counter") => 6,
|
||||
CrossCounter("Cross counter" ) => 7,
|
||||
|
||||
Crash ("Crash" ) => 8,
|
||||
EatUpHP("Eat Up HP") => 9,
|
||||
Jamming("Jamming" ) => 10,
|
||||
|
||||
FireFoe3x("Fire Foe x3" ) => 11,
|
||||
IceFoe3x("Ice Foe x3" ) => 12,
|
||||
NatureFoe3x("Nature Foe x3" ) => 13,
|
||||
DarknessFoe3x("Darkness Foe x3") => 14,
|
||||
RareFoe3x("Rare Foe x3" ) => 15,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a cross move effect",
|
||||
}
|
||||
}
|
||||
|
||||
pub mod digimon_property {
|
||||
/// A digimon's property
|
||||
enum DigimonProperty
|
||||
{
|
||||
OwnSpeciality ("Own speciality" ) => 1,
|
||||
OpnSpeciality ("Opponent speciality" ) => 2,
|
||||
OwnHP ("Own HP" ) => 3,
|
||||
OpnHP ("Opponent HP" ) => 4,
|
||||
OwnCircleAttack ("Own circle attack" ) => 5,
|
||||
OpnCircleAttack ("Opponent circle attack" ) => 6,
|
||||
OwnTriangleAttack("Own triangle attack" ) => 7,
|
||||
OpnTriangleAttack("Opponent triangle attack") => 8,
|
||||
OwnCrossAttack ("Own cross attack" ) => 9,
|
||||
OpnCrossAttack ("Opponent cross attack" ) => 10,
|
||||
OwnAttack ("Own attack" ) => 11,
|
||||
OpnAttack ("Opponent attack" ) => 12,
|
||||
OwnLevel ("Own level" ) => 13,
|
||||
OpnLevel ("Opponent level" ) => 14,
|
||||
|
||||
OwnAttackType("Own attack type" ) => 17,
|
||||
OpnAttackType("Opponent attack type") => 18,
|
||||
|
||||
AttackOrder ("Attack order" ) => 20,
|
||||
CardsInOwnHand ("Cards in own hand" ) => 21,
|
||||
CardsInOpnHand ("Cards in opponent hand" ) => 22,
|
||||
CardsInOwnDpSlot ("Cards in own dp slot" ) => 23,
|
||||
CardsInOpnDpSlot ("Cards in opponent dp slot" ) => 24,
|
||||
CardsInOwnOffDeck("Cards in own offline deck" ) => 25,
|
||||
TempSlot ("Temp slot" ) => 26,
|
||||
CardsInOwnOnDeck ("Cards in own online deck" ) => 27,
|
||||
CardsInOpnOnDeck ("Cards in opponent online deck") => 28,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a digimon property",
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
pub mod level {
|
||||
/// A digimon's level
|
||||
enum Level
|
||||
{
|
||||
Rookie ("Rookie" ) => 0,
|
||||
Armor ("Armor" ) => 1,
|
||||
Champion("Champion") => 2,
|
||||
Ultimate("Ultimate") => 3,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a level",
|
||||
}
|
||||
}
|
||||
|
||||
// Complex
|
||||
pub mod moves;
|
||||
pub mod support_effect;
|
||||
pub mod support_condition;
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
pub mod speciality {
|
||||
/// A digimon's speciality
|
||||
enum Speciality
|
||||
{
|
||||
Fire ("Fire" ) => 0,
|
||||
Ice ("Ice" ) => 1,
|
||||
Nature ("Nature" ) => 2,
|
||||
Darkness("Darkness") => 3,
|
||||
Rare ("Rare" ) => 4,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a speciality",
|
||||
}
|
||||
}
|
||||
|
||||
pub mod effect_operation {
|
||||
/// A digimon's support effect operation
|
||||
enum EffectOperation
|
||||
{
|
||||
Addition ("Addition" ) => 0,
|
||||
Subtraction ("Subtraction" ) => 1,
|
||||
Multiplication("Multiplication") => 2,
|
||||
Division ("Division" ) => 3,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a support effect operation",
|
||||
}
|
||||
}
|
||||
|
||||
pub mod effect_condition_operation {
|
||||
/// A digimon's support condition operation
|
||||
///
|
||||
/// # Todo
|
||||
/// These don't seem to be 100% right, the less than property, sometimes does less than number, might be a range check
|
||||
enum EffectConditionOperation
|
||||
{
|
||||
LessThanProperty ("Less than property" ) => 0,
|
||||
LessThanNumber ("Less than number" ) => 1,
|
||||
MoreThanProperty ("More than property" ) => 2,
|
||||
MoreThanNumber ("More than number" ) => 3,
|
||||
DifferentFromNumber("Different from number") => 4,
|
||||
EqualToNumber ("Equal to number" ) => 5,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a support condition operation",
|
||||
}
|
||||
}
|
||||
|
||||
pub mod cross_move_effect {
|
||||
/// A digimon's cross move effect
|
||||
enum CrossMoveEffect
|
||||
{
|
||||
FirstAttack("Attack first") => 1,
|
||||
|
||||
CircleTo0("Circle to 0" ) => 2,
|
||||
TriangleTo0("Triangle to 0") => 3,
|
||||
CrossTo0("Cross to 0" ) => 4,
|
||||
|
||||
CircleCounter("Circle counter" ) => 5,
|
||||
TriangleCounter("Triangle counter") => 6,
|
||||
CrossCounter("Cross counter" ) => 7,
|
||||
|
||||
Crash ("Crash" ) => 8,
|
||||
EatUpHP("Eat Up HP") => 9,
|
||||
Jamming("Jamming" ) => 10,
|
||||
|
||||
FireFoe3x("Fire Foe x3" ) => 11,
|
||||
IceFoe3x("Ice Foe x3" ) => 12,
|
||||
NatureFoe3x("Nature Foe x3" ) => 13,
|
||||
DarknessFoe3x("Darkness Foe x3") => 14,
|
||||
RareFoe3x("Rare Foe x3" ) => 15,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a cross move effect",
|
||||
}
|
||||
}
|
||||
|
||||
pub mod digimon_property {
|
||||
/// A digimon's property
|
||||
enum DigimonProperty
|
||||
{
|
||||
OwnSpeciality ("Own speciality" ) => 1,
|
||||
OpnSpeciality ("Opponent speciality" ) => 2,
|
||||
OwnHP ("Own HP" ) => 3,
|
||||
OpnHP ("Opponent HP" ) => 4,
|
||||
OwnCircleAttack ("Own circle attack" ) => 5,
|
||||
OpnCircleAttack ("Opponent circle attack" ) => 6,
|
||||
OwnTriangleAttack("Own triangle attack" ) => 7,
|
||||
OpnTriangleAttack("Opponent triangle attack") => 8,
|
||||
OwnCrossAttack ("Own cross attack" ) => 9,
|
||||
OpnCrossAttack ("Opponent cross attack" ) => 10,
|
||||
OwnAttack ("Own attack" ) => 11,
|
||||
OpnAttack ("Opponent attack" ) => 12,
|
||||
OwnLevel ("Own level" ) => 13,
|
||||
OpnLevel ("Opponent level" ) => 14,
|
||||
|
||||
OwnAttackType("Own attack type" ) => 17,
|
||||
OpnAttackType("Opponent attack type") => 18,
|
||||
|
||||
AttackOrder ("Attack order" ) => 20,
|
||||
CardsInOwnHand ("Cards in own hand" ) => 21,
|
||||
CardsInOpnHand ("Cards in opponent hand" ) => 22,
|
||||
CardsInOwnDpSlot ("Cards in own dp slot" ) => 23,
|
||||
CardsInOpnDpSlot ("Cards in opponent dp slot" ) => 24,
|
||||
CardsInOwnOffDeck("Cards in own offline deck" ) => 25,
|
||||
TempSlot ("Temp slot" ) => 26,
|
||||
CardsInOwnOnDeck ("Cards in own online deck" ) => 27,
|
||||
CardsInOpnOnDeck ("Cards in opponent online deck") => 28,
|
||||
|
||||
_ => "Unknown byte 0x{:x} for a digimon property",
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// Complex
|
||||
pub mod moves; // Note: Can't be `move`, as it's a keyword
|
||||
pub mod effect;
|
||||
pub mod effect_condition;
|
||||
|
||||
// Exports
|
||||
pub use level::Level;
|
||||
pub use speciality::Speciality;
|
||||
pub use moves::Move;
|
||||
pub use cross_move_effect::CrossMoveEffect;
|
||||
|
||||
pub use digimon_property::DigimonProperty;
|
||||
|
||||
pub use support_effect::SupportEffect;
|
||||
pub use support_effect_operation::SupportEffectOperation;
|
||||
|
||||
pub use support_condition::SupportCondition;
|
||||
pub use support_condition_operation::SupportConditionOperation;
|
||||
|
||||
pub use effect_operation::EffectOperation;
|
||||
pub use effect_condition_operation::EffectConditionOperation;
|
||||
pub use card_type::CardType;
|
||||
pub use arrow_color::ArrowColor;
|
||||
|
||||
pub use attack_type::AttackType;
|
||||
pub use player_type::PlayerType;
|
||||
|
||||
pub use slot::Slot;
|
||||
pub use moves::Move;
|
||||
pub use effect::Effect;
|
||||
pub use effect_condition::EffectCondition;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
//! A digimon's support effect
|
||||
//!
|
||||
//! This module contains the [`SupportEffect`] struct, which describes a support effect.
|
||||
//! This module contains the [`Effect`] struct, which describes a support effect.
|
||||
//!
|
||||
//! # Layout
|
||||
//! Each support effect has a size of `0x10` bytes, and it's general layout is the following:
|
||||
//!
|
||||
//! | Offset | Size | Type | Name | Location | Details |
|
||||
//! |--------|------|----------------------|---------------------------|------------------------|---------------------------------------------------------------|
|
||||
//! | 0x0 | 0x1 | `bool` | Exists | N/A | If `0`, the effect does not exist |
|
||||
//! | 0x1 | 0x1 | N/A | Effect Type | N/A | Determines which [`SupportEffect`] variant is used. |
|
||||
//! | 0x2 | 0xe | N/A | Arguments | N/A | The arguments used for the current [`SupportEffect`] variant. |
|
||||
//! | Offset | Size | Type | Name | Location | Details |
|
||||
//! |--------|------|----------------------|---------------------------|------------------------|--------------------------------------------------------|
|
||||
//! | 0x0 | 0x1 | `bool` | Exists | N/A | If `0`, the effect does not exist |
|
||||
//! | 0x1 | 0x1 | N/A | Effect Type | N/A | Determines which [`Effect`] variant is used. |
|
||||
//! | 0x2 | 0xe | N/A | Arguments | N/A | The arguments used for the current [`Effect`] variant. |
|
||||
|
||||
// byteorder
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
@@ -19,7 +19,7 @@ use crate::game::{
|
||||
Bytes,
|
||||
util,
|
||||
card::property::{
|
||||
self, DigimonProperty, SupportEffectOperation, AttackType, PlayerType, Slot
|
||||
self, DigimonProperty, EffectOperation, AttackType, PlayerType, Slot
|
||||
},
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ use crate::game::{
|
||||
#[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
|
||||
pub enum Effect
|
||||
{
|
||||
/// Changes a property of either digimon
|
||||
///
|
||||
@@ -63,7 +63,7 @@ pub enum SupportEffect
|
||||
x: u16,
|
||||
y: u16,
|
||||
|
||||
op: SupportEffectOperation,
|
||||
op: EffectOperation,
|
||||
},
|
||||
|
||||
/// A player uses an attack type
|
||||
@@ -86,7 +86,7 @@ pub enum SupportEffect
|
||||
b: Option<DigimonProperty>,
|
||||
c: Option<DigimonProperty>,
|
||||
|
||||
op: SupportEffectOperation,
|
||||
op: EffectOperation,
|
||||
},
|
||||
|
||||
/// Moves cards from a slot to another
|
||||
@@ -178,9 +178,9 @@ pub enum FromBytesError
|
||||
|
||||
/// Unknown operation argument
|
||||
#[display(fmt = "Unknown operation argument")]
|
||||
Operation( #[error(source)] property::support_effect_operation::FromBytesError ),
|
||||
Operation( #[error(source)] property::effect_operation::FromBytesError ),
|
||||
|
||||
/// Unknown attack type for [`SupportEffect::UseAttack`]
|
||||
/// Unknown attack type for [`Effect::UseAttack`]
|
||||
#[display(fmt = "Unknown attack type")]
|
||||
UseAttackAttackType( #[error(source)] property::attack_type::FromBytesError ),
|
||||
|
||||
@@ -189,7 +189,7 @@ pub enum FromBytesError
|
||||
EffectType { byte: u8 },
|
||||
}
|
||||
|
||||
impl Bytes for SupportEffect
|
||||
impl Bytes for Effect
|
||||
{
|
||||
type ByteArray = [u8; 0x10];
|
||||
|
||||
@@ -218,6 +218,8 @@ impl Bytes for SupportEffect
|
||||
.then(|| DigimonProperty::from_bytes( &bytes[0x6] ))
|
||||
.transpose()
|
||||
.map_err(FromBytesError::ThirdProperty);
|
||||
|
||||
// Lower byte of `x` contains the attack type
|
||||
let get_attack_type = || AttackType::from_bytes( &bytes[0xa] ) // Lower byte of `x`
|
||||
.map_err(FromBytesError::UseAttackAttackType);
|
||||
|
||||
@@ -226,7 +228,7 @@ impl Bytes for SupportEffect
|
||||
let y = LittleEndian::read_u16( &bytes[0xc..0xe] );
|
||||
|
||||
// The operation argument
|
||||
let op = SupportEffectOperation::from_bytes( &bytes[0xf] )
|
||||
let op = EffectOperation::from_bytes( &bytes[0xf] )
|
||||
.map_err(FromBytesError::Operation)?;
|
||||
|
||||
// Check what the effect type is
|
||||
@@ -240,7 +242,6 @@ impl Bytes for SupportEffect
|
||||
}),
|
||||
|
||||
|
||||
// Lower byte of `x` contains the attack type
|
||||
16 => Ok( Self::UseAttack{ player: Player , attack: get_attack_type()? }),
|
||||
17 => Ok( Self::UseAttack{ player: Opponent, attack: get_attack_type()? }),
|
||||
|
||||
@@ -313,14 +314,14 @@ impl Bytes for SupportEffect
|
||||
#[allow(clippy::unneeded_field_pattern)] // Placeholder
|
||||
match self {
|
||||
Self::ChangeProperty { property, a, b, c, x, y, op } => {
|
||||
property.to_bytes(bytes.effect_type)?;
|
||||
property.to_bytes(bytes.effect_type).into_ok();
|
||||
*bytes.effect_type -= 1;
|
||||
if let Some(a) = a { a.to_bytes(bytes.a)?; }
|
||||
if let Some(b) = b { b.to_bytes(bytes.b)?; }
|
||||
if let Some(c) = c { c.to_bytes(bytes.c)?; }
|
||||
if let Some(a) = a { a.to_bytes(bytes.a).into_ok(); }
|
||||
if let Some(b) = b { b.to_bytes(bytes.b).into_ok(); }
|
||||
if let Some(c) = c { c.to_bytes(bytes.c).into_ok(); }
|
||||
LittleEndian::write_u16(bytes.x, *x);
|
||||
LittleEndian::write_u16(bytes.y, *y);
|
||||
op.to_bytes(bytes.op)?;
|
||||
op.to_bytes(bytes.op).into_ok();
|
||||
},
|
||||
|
||||
Self::UseAttack { player: _, attack: _ } => todo!(),
|
||||
162
src/game/card/property/effect_condition.rs
Normal file
162
src/game/card/property/effect_condition.rs
Normal file
@@ -0,0 +1,162 @@
|
||||
//! A digimon's effect condition
|
||||
//!
|
||||
//! This module contains the [`EffectCondition`] struct, which describes a condition for an effect.
|
||||
//!
|
||||
//! # Layout
|
||||
//! Each support condition has a size of `0x20` bytes, and it's layout is the following:
|
||||
//!
|
||||
//! | Offset | Size | Type | Name | Location | Details |
|
||||
//! |--------|------|------------------------------|---------------------------|--------------- |------------------------------------------------------------------------------------|
|
||||
//! | 0x0 | 0x0 | `bool` | Misfire | `misfire` | If the condition throws a misfire when false |
|
||||
//! | 0x1 | 0x1 | `u8` | | | Always zero |
|
||||
//! | 0x2 | 0x1 | [`DigimonProperty`] | Property compare | `property_cmp` | The property to compare to for the condition (or 0 if the condition doesn't exist) |
|
||||
//! | 0x3 | 0x5 | `[u8; 0x5]` | | `unknown_3` | Unknown |
|
||||
//! | 0x8 | 0x1 | `DigimonProperty` | Property argument | `arg_property` | Property argument for the comparation |
|
||||
//! | 0x9 | 0xb | `[u8; 0xb]` | | `unknown_9` | Unknown |
|
||||
//! | 0x14 | 0x2 | `u16` | Number argument | `arg_num` | Number argument for the comparation |
|
||||
//! | 0x16 | 0x4 | `[u8; 0x4]` | | `unknown_16` | Unknown |
|
||||
//! | 0x1a | 0x1 | [`EffectConditionOperation`] | Operation | `operation` | Operation to use for the comparation |
|
||||
//! | 0x1b | 0x5 | `[u8; 0x5]` | | `unknown_1b` | Unknown |
|
||||
|
||||
// byteorder
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
// Crate
|
||||
use crate::game::{
|
||||
Bytes,
|
||||
card::property::{
|
||||
self, DigimonProperty, EffectConditionOperation
|
||||
},
|
||||
//util,
|
||||
};
|
||||
|
||||
/// A digimon's support effect condition
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct EffectCondition
|
||||
{
|
||||
/// If the effect should throw a misfire when false
|
||||
misfire: bool,
|
||||
|
||||
/// The property to compare to
|
||||
property_cmp: DigimonProperty,
|
||||
|
||||
/// The property argument
|
||||
arg_property: Option<DigimonProperty>,
|
||||
|
||||
/// The number argument
|
||||
arg_num: u16,
|
||||
|
||||
/// The operation
|
||||
operation: EffectConditionOperation,
|
||||
|
||||
// Unknown
|
||||
unknown_3 : [u8; 0x5],
|
||||
unknown_9 : [u8; 0xb],
|
||||
unknown_16: [u8; 0x4],
|
||||
unknown_1b: [u8; 0x5],
|
||||
}
|
||||
|
||||
/// The error type thrown by `FromBytes`
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display, err_impl::Error)]
|
||||
pub enum FromBytesError
|
||||
{
|
||||
/// Unable to read the condition
|
||||
#[display(fmt = "Unable to read the effect condition")]
|
||||
Condition( #[error(source)] property::digimon_property::FromBytesError ),
|
||||
|
||||
/// Unable to read a property argument
|
||||
#[display(fmt = "Unable to read the property argument")]
|
||||
PropertyArgument( #[error(source)] property::digimon_property::FromBytesError ),
|
||||
|
||||
/// Unable to read the effect operation
|
||||
#[display(fmt = "Unable to read the effect operation")]
|
||||
Operation( #[error(source)] property::effect_condition_operation::FromBytesError ),
|
||||
}
|
||||
|
||||
// Bytes
|
||||
impl Bytes for Option<EffectCondition>
|
||||
{
|
||||
type ByteArray = [u8; 0x20];
|
||||
|
||||
type FromError = FromBytesError;
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError>
|
||||
{
|
||||
// If we have no property comparation, return None
|
||||
if bytes[0x2] == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// Else build the type
|
||||
Ok( Some( EffectCondition {
|
||||
misfire: (bytes[0x0] != 0),
|
||||
property_cmp: DigimonProperty::from_bytes( &bytes[0x2] )
|
||||
.map_err(FromBytesError::Condition)?,
|
||||
|
||||
arg_property: (bytes[0x8] != 0)
|
||||
.then(|| DigimonProperty::from_bytes( &bytes[0x8] ))
|
||||
.transpose()
|
||||
.map_err(FromBytesError::PropertyArgument)?,
|
||||
|
||||
arg_num: LittleEndian::read_u16( &bytes[0x14..0x16] ),
|
||||
|
||||
operation: EffectConditionOperation::from_bytes( &bytes[0x1a] )
|
||||
.map_err(FromBytesError::Operation)?,
|
||||
|
||||
unknown_3: [ bytes[0x3], bytes[0x4], bytes[0x5], bytes[0x6], bytes[0x7] ],
|
||||
|
||||
unknown_9: [
|
||||
bytes[0x9], bytes[0xa ], bytes[0xb ], bytes[0xc ], bytes[0xd ], bytes[0xe],
|
||||
bytes[0xf], bytes[0x10], bytes[0x11], bytes[0x12], bytes[0x13]
|
||||
],
|
||||
|
||||
unknown_16: [ bytes[0x16], bytes[0x17], bytes[0x18], bytes[0x19] ],
|
||||
|
||||
unknown_1b: [ bytes[0x1b], bytes[0x1c], bytes[0x1d], bytes[0x1e], bytes[0x1f] ],
|
||||
}))
|
||||
}
|
||||
|
||||
type ToError = !;
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError>
|
||||
{
|
||||
// If we don't exist, write a `0` on the property comparation and return
|
||||
let cond = match self {
|
||||
Some(cond) => cond,
|
||||
None => {
|
||||
bytes[0x2] = 0;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// 0x0 - Misfire
|
||||
bytes[0x0] = if cond.misfire { 1 } else { 0 };
|
||||
|
||||
// 0x1 - Always zero
|
||||
bytes[0x1] = 0;
|
||||
|
||||
// 0x2 - Condition
|
||||
cond.property_cmp.to_bytes(&mut bytes[0x2]).into_ok();
|
||||
|
||||
// 0x3..0x8 - Unknown[0..5]
|
||||
//bytes[0x3..0x8].copy_from_slice( &self.unknown[0..5] );
|
||||
|
||||
// 0x8 - Type arg / 0 if None
|
||||
if let Some(type_arg) = cond.arg_property {
|
||||
type_arg.to_bytes(&mut bytes[0x8]).into_ok();
|
||||
}
|
||||
else { bytes[0x8] = 0; }
|
||||
|
||||
// 0x9..0x14 - Unknown[0x5..0x10]
|
||||
//bytes[0x9..0x14].copy_from_slice( &self.unknown[0x5..0x10] );
|
||||
|
||||
// 0x14..0x16 - Number arg
|
||||
LittleEndian::write_u16(&mut bytes[0x14..0x16], cond.arg_num);
|
||||
|
||||
// 0x1a - Operation arg
|
||||
cond.operation.to_bytes(&mut bytes[0x1a]).into_ok();
|
||||
|
||||
// And return OK
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
//! A digimon's move
|
||||
//!
|
||||
//! This module contains the [`Move`] struct, which describes a generic move.
|
||||
//! This module contains the [`Move`] struct, which describes a generic move over the triangle, circle or cross.
|
||||
//!
|
||||
//! # Layout
|
||||
//! Each move has a size of `0x1c` bytes, and it's layout is the following:
|
||||
@@ -32,7 +32,7 @@ pub struct Move
|
||||
unknown: u32,
|
||||
}
|
||||
|
||||
/// Error type for [`Bytes::FromBytes`]
|
||||
/// Error type for [`Bytes::from_bytes`]
|
||||
#[derive(Debug, derive_more::Display, err_impl::Error)]
|
||||
pub enum FromBytesError
|
||||
{
|
||||
@@ -41,7 +41,7 @@ pub enum FromBytesError
|
||||
Name( #[error(source)] util::ReadNullAsciiStringError ),
|
||||
}
|
||||
|
||||
/// Error type for [`Bytes::ToBytes`]
|
||||
/// Error type for [`Bytes::to_bytes`]
|
||||
#[derive(Debug, derive_more::Display, err_impl::Error)]
|
||||
pub enum ToBytesError
|
||||
{
|
||||
@@ -58,9 +58,9 @@ impl Bytes for Move
|
||||
type FromError = FromBytesError;
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError>
|
||||
{
|
||||
// And return the move
|
||||
// Return the move
|
||||
Ok( Self {
|
||||
name : util::read_null_ascii_string( &bytes[0x6..0x1c] )
|
||||
name : util::read_null_ascii_string( &bytes[0x6..0x1c] )
|
||||
.map_err(FromBytesError::Name)?
|
||||
.chars().collect(),
|
||||
power : LittleEndian::read_u16( &bytes[0x0..0x2] ),
|
||||
@@ -83,7 +83,7 @@ impl Bytes for Move
|
||||
.map_err(ToBytesError::Name)?;
|
||||
|
||||
// Then write the power and the unknown
|
||||
LittleEndian::write_u16(bytes.power , self.power );
|
||||
LittleEndian::write_u16(bytes.power , self.power);
|
||||
LittleEndian::write_u32(bytes.unknown, self.unknown);
|
||||
|
||||
// And return Ok
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
//! A digimon's support condition
|
||||
//!
|
||||
//! This module contains the [`SupportCondition`] struct, which describes a condition for a support effect.
|
||||
//!
|
||||
//! # Layout
|
||||
//! Each support condition has a size of `0x20` bytes, and it's layout is the following:
|
||||
//!
|
||||
//! TODO: Layout
|
||||
//! | Offset | Size | Type | Name | Location | Details |
|
||||
//! |--------|------|----------------------|---------------------------|------------------------|-----------------------------------|
|
||||
|
||||
// byteorder
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
// Crate
|
||||
use crate::game::{
|
||||
Bytes,
|
||||
card::property::{
|
||||
self, DigimonProperty, SupportConditionOperation
|
||||
},
|
||||
};
|
||||
|
||||
/// A digimon's support effect condition
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct SupportCondition
|
||||
{
|
||||
/// If the effect should throw a misfire if the condition isn't met
|
||||
misfire: bool,
|
||||
|
||||
/// The condition type
|
||||
cond: DigimonProperty,
|
||||
|
||||
/// The type argument
|
||||
type_arg: Option<DigimonProperty>,
|
||||
|
||||
/// The number argument
|
||||
num_arg: u16,
|
||||
|
||||
/// The operation
|
||||
operation: SupportConditionOperation,
|
||||
|
||||
/// Unknown
|
||||
unknown: [u8; 16],
|
||||
}
|
||||
|
||||
/// The error type thrown by `FromBytes`
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display, err_impl::Error)]
|
||||
pub enum FromBytesError
|
||||
{
|
||||
/// Unable to read the condition
|
||||
#[display(fmt = "Unable to read the effect condition")]
|
||||
Condition( #[error(source)] property::digimon_property::FromBytesError ),
|
||||
|
||||
/// Unable to read a property argument
|
||||
#[display(fmt = "Unable to read the property argument")]
|
||||
PropertyArgument( #[error(source)] property::digimon_property::FromBytesError ),
|
||||
|
||||
/// Unable to read the effect operation
|
||||
#[display(fmt = "Unable to read the effect operation")]
|
||||
Operation( #[error(source)] property::support_condition_operation::FromBytesError ),
|
||||
}
|
||||
|
||||
// Bytes
|
||||
impl Bytes for SupportCondition
|
||||
{
|
||||
type ByteArray = [u8; 0x20];
|
||||
|
||||
type FromError = FromBytesError;
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError>
|
||||
{
|
||||
// Get the condition
|
||||
let cond = DigimonProperty::from_bytes( &bytes[0x2] )
|
||||
.map_err(FromBytesError::Condition)?;
|
||||
|
||||
// And return the move
|
||||
Ok( Self {
|
||||
misfire: (bytes[0x0] != 0),
|
||||
cond,
|
||||
|
||||
type_arg: (bytes[0x8] != 0)
|
||||
.then(|| DigimonProperty::from_bytes( &bytes[0x8] ))
|
||||
.transpose()
|
||||
.map_err(FromBytesError::PropertyArgument)?,
|
||||
|
||||
num_arg: LittleEndian::read_u16( &bytes[0x14..0x16] ),
|
||||
|
||||
operation: SupportConditionOperation::from_bytes( &bytes[0x1a] )
|
||||
.map_err(FromBytesError::Operation)?,
|
||||
|
||||
unknown: [
|
||||
bytes[0x3], bytes[0x4], bytes[0x5], bytes[0x6], bytes[0x7],
|
||||
|
||||
bytes[0x9], bytes[0xa ], bytes[0xb ], bytes[0xc ], bytes[0xd ], bytes[0xe],
|
||||
bytes[0xf], bytes[0x10], bytes[0x11], bytes[0x12], bytes[0x13],
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
type ToError = !;
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError>
|
||||
{
|
||||
// 0x0 - Misfire
|
||||
bytes[0x0] = if self.misfire { 1 } else { 0 };
|
||||
|
||||
// 0x1 - Always zero
|
||||
bytes[0x1] = 0;
|
||||
|
||||
// 0x2 - Condition
|
||||
self.cond.to_bytes(&mut bytes[0x2])?;
|
||||
|
||||
// 0x3..0x8 - Unknown[0..5]
|
||||
bytes[0x3..0x8].copy_from_slice( &self.unknown[0..5] );
|
||||
|
||||
// 0x8 - Type arg / 0 if None
|
||||
if let Some(type_arg) = self.type_arg {
|
||||
type_arg.to_bytes(&mut bytes[0x8])?;
|
||||
}
|
||||
else { bytes[0x8] = 0; }
|
||||
|
||||
// 0x9..0x14 - Unknown[0x5..0x10]
|
||||
bytes[0x9..0x14].copy_from_slice( &self.unknown[0x5..0x10] );
|
||||
|
||||
// 0x14..0x16 - Number arg
|
||||
LittleEndian::write_u16(&mut bytes[0x14..0x16], self.num_arg);
|
||||
|
||||
// 0x1a - Operation arg
|
||||
self.operation.to_bytes(&mut bytes[0x1a])?;
|
||||
|
||||
// And return OK
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -44,10 +44,12 @@ use crate::{
|
||||
io::{address::Data, GameFile},
|
||||
game::{
|
||||
card::{
|
||||
self,
|
||||
Digimon, Item, Digivolve,
|
||||
property::{self, CardType},
|
||||
},
|
||||
Bytes,
|
||||
util,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -90,15 +92,15 @@ impl Table {
|
||||
|
||||
/// Error type for [`Table::deserialize`]
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
#[derive(derive_more::Display, err_impl::Error)]
|
||||
pub enum DeserializeError {
|
||||
/// Unable to seek game file
|
||||
#[display(fmt = "Unable to seek game file to card table")]
|
||||
Seek( std::io::Error ),
|
||||
Seek( #[error(source)] std::io::Error ),
|
||||
|
||||
/// Unable to read table header
|
||||
#[display(fmt = "Unable to read table header")]
|
||||
ReadHeader( std::io::Error ),
|
||||
ReadHeader( #[error(source)] 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")]
|
||||
@@ -126,6 +128,7 @@ pub enum DeserializeError {
|
||||
#[display(fmt = "Unable to read card header for card id {}", id)]
|
||||
ReadCardHeader {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
@@ -133,6 +136,7 @@ pub enum DeserializeError {
|
||||
#[display(fmt = "Unknown card type for card id {}", id)]
|
||||
UnknownCardType {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: property::card_type::FromBytesError,
|
||||
},
|
||||
|
||||
@@ -140,35 +144,22 @@ pub enum DeserializeError {
|
||||
#[display(fmt = "Unable to read card footer for card id {}", id)]
|
||||
ReadCardFooter {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: std::io::Error,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::error::Error for DeserializeError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::Seek(err) |
|
||||
Self::ReadHeader(err) |
|
||||
Self::ReadCardHeader { err, .. } |
|
||||
Self::ReadCardFooter { err, .. } => Some(err),
|
||||
Self::UnknownCardType { err, .. } => Some(err),
|
||||
Self::HeaderMagic { .. } |
|
||||
Self::TooManyCards { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type for [`Table::serialize`]
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display)]
|
||||
#[derive(derive_more::Display, err_impl::Error)]
|
||||
pub enum SerializeError {
|
||||
/// Unable to seek game file
|
||||
#[display(fmt = "Unable to seek game file to card table")]
|
||||
Seek( std::io::Error ),
|
||||
Seek( #[error(source)] std::io::Error ),
|
||||
|
||||
/// Unable to write table header
|
||||
#[display(fmt = "Unable to write table header")]
|
||||
WriteHeader( std::io::Error ),
|
||||
WriteHeader( #[error(source)] std::io::Error ),
|
||||
|
||||
/// There were too many cards
|
||||
#[display(fmt = "Too many cards in table ({} digimon, {} item, {} digivolve, {} / {} bytes max)",
|
||||
@@ -186,31 +177,37 @@ pub enum SerializeError {
|
||||
digivolve_cards: usize,
|
||||
},
|
||||
|
||||
/// Unable to write card header
|
||||
#[display(fmt = "Unable to write card header for card id {}", id)]
|
||||
WriteCardHeader {
|
||||
/// Unable to write a card
|
||||
#[display(fmt = "Unable to write card with id {}", id)]
|
||||
WriteCard {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
/// Unable to write card footer
|
||||
#[display(fmt = "Unable to write card footer for card id {}", id)]
|
||||
WriteCardFooter {
|
||||
/// Unable to serialize a digimon card
|
||||
#[display(fmt = "Unable to serialize digimon card with id {}", id)]
|
||||
DigimonCard {
|
||||
id: usize,
|
||||
err: std::io::Error,
|
||||
#[error(source)]
|
||||
err: card::digimon::ToBytesError,
|
||||
},
|
||||
|
||||
/// Unable to write an item card
|
||||
#[display(fmt = "Unable to write item card with id {}", id)]
|
||||
ItemCard {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: card::item::ToBytesError,
|
||||
},
|
||||
|
||||
/// Unable to write a digivolve card
|
||||
#[display(fmt = "Unable to write digivolve card with id {}", id)]
|
||||
DigivolveCard {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: card::digivolve::ToBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::error::Error for SerializeError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::Seek(err) |
|
||||
Self::WriteHeader(err) |
|
||||
Self::WriteCardHeader { err, .. } |
|
||||
Self::WriteCardFooter { err, .. } => Some(err),
|
||||
Self::TooManyCards { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Table {
|
||||
@@ -340,168 +337,89 @@ impl Table {
|
||||
file.seek( std::io::SeekFrom::Start( u64::from( Self::START_ADDRESS ) + 0x8 ) )
|
||||
.map_err(SerializeError::Seek)?;
|
||||
|
||||
// Function to write a card to file
|
||||
fn write_card<R: Read + Write + Seek, C: Bytes>(_file: &mut GameFile<R>, _card: &C, _cur_id: usize) {
|
||||
/*
|
||||
// Get the bytes
|
||||
let mut bytes = [0u8; <C as Bytes>::BUF_BYTE_SIZE];
|
||||
card.to_bytes(&mut bytes)
|
||||
.expect("Unable to get digimon as bytes");
|
||||
|
||||
// Write the digimon buffer
|
||||
file.write_all(&bytes)
|
||||
.expect("Unable to write digimon card");
|
||||
|
||||
// And write the 'next' section
|
||||
let mut buf = [0u8; 0x4];
|
||||
|
||||
match idx {
|
||||
num if num + 1 == self.digimons.len() => CardType::Item .to_bytes( &mut buf[0x3..0x4] )?,
|
||||
_ => CardType::Digimon.to_bytes( &mut buf[0x3..0x4] )?,
|
||||
}
|
||||
|
||||
LittleEndian::write_u16( &mut buf[0x1..0x3], cur_id+1);
|
||||
|
||||
file.write_all(&buf)
|
||||
.expect("");
|
||||
*/
|
||||
}
|
||||
|
||||
// Write all digimon, items and digivolves
|
||||
for (id, digimon) in self.digimons.iter().enumerate() {
|
||||
write_card(file, digimon, id);
|
||||
for (rel_id, digimon) in self.digimons.iter().enumerate() {
|
||||
// Current id through the whole table
|
||||
let cur_id = rel_id;
|
||||
|
||||
// Card bytes
|
||||
let mut card_bytes = [0; 0x3 + CardType::Digimon.byte_size() + 0x1];
|
||||
let bytes = util::array_split_mut!(&mut card_bytes,
|
||||
header_id : [0x2],
|
||||
header_type: 1,
|
||||
digimon : [CardType::Digimon.byte_size()],
|
||||
footer : 1,
|
||||
);
|
||||
|
||||
// Write the header
|
||||
LittleEndian::write_u16( bytes.header_id, cur_id as u16 );
|
||||
CardType::Digimon.to_bytes( bytes.header_type )?;
|
||||
|
||||
// Write the digimon
|
||||
digimon.to_bytes( bytes.digimon )
|
||||
.map_err(|err| SerializeError::DigimonCard { id: cur_id, err })?;
|
||||
|
||||
// Write the footer
|
||||
*bytes.footer = 0;
|
||||
|
||||
file.write_all(&card_bytes)
|
||||
.map_err(|err| SerializeError::WriteCard { id: cur_id, err })?;
|
||||
}
|
||||
for (id, item) in self.items.iter().enumerate() {
|
||||
write_card(file, item, self.digimons.len() + id);
|
||||
for (rel_id, item) in self.items.iter().enumerate() {
|
||||
// Current id through the whole table
|
||||
let cur_id = self.digimons.len() + rel_id;
|
||||
|
||||
// Card bytes
|
||||
let mut card_bytes = [0; 0x3 + CardType::Item.byte_size() + 0x1];
|
||||
let bytes = util::array_split_mut!(&mut card_bytes,
|
||||
header_id : [0x2],
|
||||
header_type: 1,
|
||||
item : [CardType::Item.byte_size()],
|
||||
footer : 1,
|
||||
);
|
||||
|
||||
// Write the header
|
||||
LittleEndian::write_u16( bytes.header_id, cur_id as u16 );
|
||||
CardType::Item.to_bytes( bytes.header_type )?;
|
||||
|
||||
// Write the item
|
||||
item.to_bytes( bytes.item )
|
||||
.map_err(|err| SerializeError::ItemCard { id: cur_id, err })?;
|
||||
|
||||
// Write the footer
|
||||
*bytes.footer = 0;
|
||||
|
||||
file.write_all(&card_bytes)
|
||||
.map_err(|err| SerializeError::WriteCard { id: cur_id, err })?;
|
||||
}
|
||||
for (id, digivolve) in self.digivolves.iter().enumerate() {
|
||||
write_card(file, digivolve, self.digimons.len() + self.items.len() + id);
|
||||
for (rel_id, digivolve) in self.digivolves.iter().enumerate() {
|
||||
// Current id through the whole table
|
||||
let cur_id = self.digimons.len() + self.items.len() + rel_id;
|
||||
|
||||
// Card bytes
|
||||
let mut card_bytes = [0; 0x3 + CardType::Digivolve.byte_size() + 0x1];
|
||||
let bytes = util::array_split_mut!(&mut card_bytes,
|
||||
header_id : [0x2],
|
||||
header_type: 1,
|
||||
item : [CardType::Digivolve.byte_size()],
|
||||
footer : 1,
|
||||
);
|
||||
|
||||
// Write the header
|
||||
LittleEndian::write_u16( bytes.header_id, cur_id as u16 );
|
||||
CardType::Digivolve.to_bytes( bytes.header_type )?;
|
||||
|
||||
// Write the digivolve
|
||||
digivolve.to_bytes( bytes.item )
|
||||
.map_err(|err| SerializeError::DigivolveCard { id: cur_id, err })?;
|
||||
|
||||
// Write the footer
|
||||
*bytes.footer = 0;
|
||||
|
||||
file.write_all(&card_bytes)
|
||||
.map_err(|err| SerializeError::WriteCard { id: cur_id, err })?;
|
||||
}
|
||||
|
||||
/*
|
||||
enum Card<'a> {
|
||||
Digimon (&'a Digimon ),
|
||||
Item (&'a Item ),
|
||||
Digivolve(&'a Digivolve),
|
||||
}
|
||||
|
||||
// Then write all cards
|
||||
for (idx, card) in std::iter::empty()
|
||||
.chain(self.digimons .iter().map(Card::Digimon ))
|
||||
.chain(self.items .iter().map(Card::Item ))
|
||||
.chain(self.digivolves.iter().map(Card::Digivolve))
|
||||
.enumerate()
|
||||
{
|
||||
let bytes = match card {
|
||||
Card::Digimon(digimon) => {
|
||||
let mut bytes = [0; Digimon::BUF_BYTE_SIZE];
|
||||
digimon.to_bytes(&mut bytes);
|
||||
&bytes as &[u8]
|
||||
},
|
||||
_ => &[],
|
||||
};
|
||||
|
||||
// Write the buffer
|
||||
file.write_all(&bytes)
|
||||
.expect("Unable to write card");
|
||||
|
||||
// And write the 'next' section
|
||||
let mut buf = [0u8; 0x4];
|
||||
|
||||
match idx {
|
||||
num if num + 1 == self.digimons.len() => CardType::Item .to_bytes( &mut buf[0x3..0x4] )?,
|
||||
_ => CardType::Digimon.to_bytes( &mut buf[0x3..0x4] )?,
|
||||
}
|
||||
|
||||
LittleEndian::write_u16( &mut buf[0x1..0x3], (idx+1) as u16);
|
||||
|
||||
file.write_all(&buf)
|
||||
.expect("");
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// The current id
|
||||
let mut cur_id = 0u16;
|
||||
|
||||
|
||||
|
||||
|
||||
// Then write all cards, first digimon, then items, then digivolves
|
||||
for (idx, digimon) in self.digimons.iter().enumerate()
|
||||
{
|
||||
// Get the bytes
|
||||
let mut bytes = [0u8; Digimon::BUF_BYTE_SIZE as usize];
|
||||
digimon.to_bytes(&mut bytes)
|
||||
.expect("Unable to get digimon as bytes");
|
||||
|
||||
// Write the digimon buffer
|
||||
file.write_all(&bytes)
|
||||
.expect("Unable to write digimon card");
|
||||
|
||||
// And write the 'next' section
|
||||
let mut buf = [0u8; 0x4];
|
||||
|
||||
match idx {
|
||||
num if num + 1 == self.digimons.len() => CardType::Item .to_bytes( &mut buf[0x3..0x4] )?,
|
||||
_ => CardType::Digimon.to_bytes( &mut buf[0x3..0x4] )?,
|
||||
}
|
||||
|
||||
LittleEndian::write_u16( &mut buf[0x1..0x3], cur_id+1);
|
||||
|
||||
file.write_all(&buf)
|
||||
.expect("");
|
||||
|
||||
cur_id += 1;
|
||||
}
|
||||
|
||||
for (idx, item) in self.items.iter().enumerate()
|
||||
{
|
||||
// Get the bytes
|
||||
let mut bytes = [0u8; Item::BUF_BYTE_SIZE as usize];
|
||||
item.to_bytes(&mut bytes).unwrap();//.map_err(|err| SerializeError::ConvertItem{id: cur_id, err})?;
|
||||
|
||||
// Write the item buffer
|
||||
file.write_all(&bytes).unwrap();//.map_err(|err| SerializeError::WriteItem{id: cur_id, err})?;
|
||||
|
||||
// And write the 'next' section
|
||||
let mut buf = [0u8; 0x4];
|
||||
|
||||
match idx {
|
||||
num if num + 1 == self.items.len() => { CardType::Digivolve.to_bytes( &mut buf[0x3..0x4] )?; }
|
||||
_ => { CardType::Item .to_bytes( &mut buf[0x3..0x4] )?; }
|
||||
}
|
||||
|
||||
LittleEndian::write_u16( &mut buf[0x1..0x3], cur_id+1);
|
||||
|
||||
file.write_all(&buf).unwrap();//.map_err(|err| SerializeError::NextEntryInfo{ id: cur_id, err })?;
|
||||
|
||||
cur_id += 1;
|
||||
}
|
||||
|
||||
for (idx, digivolve) in self.digivolves.iter().enumerate()
|
||||
{
|
||||
// Get the bytes
|
||||
let mut bytes = [0u8; Digivolve::BUF_BYTE_SIZE as usize];
|
||||
digivolve.to_bytes(&mut bytes).unwrap();//.map_err(|err| SerializeError::ConvertDigivolve{id: cur_id, err})?;
|
||||
|
||||
// Write the digimon buffer
|
||||
file.write_all(&bytes).unwrap();//.map_err(|err| SerializeError::WriteDigivolve{id: cur_id, err})?;
|
||||
|
||||
// And write the 'next' section
|
||||
let mut buf = [0u8; 0x4];
|
||||
|
||||
match idx {
|
||||
num if num + 1 == self.digivolves.len() => { CardType::Digimon .to_bytes( &mut buf[0x3..0x4] )?; LittleEndian::write_u16( &mut buf[0x1..0x3], 0 ); }
|
||||
_ => { CardType::Digivolve.to_bytes( &mut buf[0x3..0x4] )?; LittleEndian::write_u16( &mut buf[0x1..0x3], cur_id+1); }
|
||||
}
|
||||
|
||||
file.write_all(&buf).unwrap();//.map_err(|err| SerializeError::NextEntryInfo{ id: cur_id, err })?;
|
||||
|
||||
cur_id += 1;
|
||||
}
|
||||
*/
|
||||
|
||||
// And return Ok
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -9,42 +9,47 @@
|
||||
|
||||
pub macro array_split {
|
||||
(
|
||||
$arr:ident,
|
||||
$arr:expr,
|
||||
$(
|
||||
$( $start:literal..$end:literal => $arr_name:tt )?
|
||||
$( =$location:literal => $val_name:tt )?
|
||||
,
|
||||
)*
|
||||
$name:ident :
|
||||
|
||||
$( [$arr_size:expr] )?
|
||||
$( $val_size:literal )?
|
||||
|
||||
),* $(,)?
|
||||
) => {{
|
||||
#![allow(clippy::used_underscore_binding)]
|
||||
#![allow(clippy::ptr_offset_with_cast )]
|
||||
|
||||
// Struct holding all fields
|
||||
struct __Fields<'a, T> {
|
||||
struct Fields<'a, T> {
|
||||
$(
|
||||
$( $arr_name: &'a [T; $end - $start], )?
|
||||
$( $val_name: &'a T, )?
|
||||
$name:
|
||||
|
||||
$( &'a [T; $arr_size], )?
|
||||
$( &'a T, #[cfg(os = "Os that does not exist")] __field: [u8; $val_size], )?
|
||||
)*
|
||||
}
|
||||
|
||||
// Get everything from `array_refs`
|
||||
let (
|
||||
$(
|
||||
$( $arr_name, )?
|
||||
$( $val_name, )?
|
||||
)*
|
||||
$name
|
||||
),*
|
||||
) = ::arrayref::array_refs!(
|
||||
$arr,
|
||||
$(
|
||||
$( $end - $start )?
|
||||
$( 1 + (0 * $location) )?
|
||||
$( $arr_size )?
|
||||
$( $val_size )?
|
||||
),*
|
||||
);
|
||||
|
||||
// And return the fields
|
||||
__Fields {
|
||||
Fields {
|
||||
$(
|
||||
$( $arr_name, )?
|
||||
$( $val_name: &( $val_name[0] ), )?
|
||||
$name
|
||||
$( : &( $name[$val_size - $val_size] ) )?
|
||||
,
|
||||
)*
|
||||
}
|
||||
}}
|
||||
@@ -52,19 +57,20 @@ pub macro array_split {
|
||||
|
||||
pub macro array_split_mut {
|
||||
(
|
||||
$arr:ident,
|
||||
$arr:expr,
|
||||
$(
|
||||
$name:ident :
|
||||
|
||||
$( [$arr_size:literal] )?
|
||||
$( [$arr_size:expr] )?
|
||||
$( $val_size:literal )?
|
||||
|
||||
),* $(,)?
|
||||
) => {{
|
||||
#![allow(clippy::used_underscore_binding)]
|
||||
#![allow(clippy::ptr_offset_with_cast )]
|
||||
|
||||
// Struct holding all fields
|
||||
struct __Fields<'a, T> {
|
||||
struct Fields<'a, T> {
|
||||
$(
|
||||
$name:
|
||||
|
||||
@@ -87,7 +93,7 @@ pub macro array_split_mut {
|
||||
);
|
||||
|
||||
// And return the fields
|
||||
__Fields {
|
||||
Fields {
|
||||
$(
|
||||
$name
|
||||
$( : &mut ( $name[$val_size - $val_size] ) )?
|
||||
|
||||
@@ -239,7 +239,9 @@ impl<R: Read + Write + Seek> Seek for GameFile<R>
|
||||
data_offset
|
||||
))
|
||||
),
|
||||
SeekFrom::End(_) => { todo!(); }
|
||||
SeekFrom::End(_) => {
|
||||
todo!("SeekFrom::End isn't currently implemented");
|
||||
}
|
||||
};
|
||||
|
||||
// Seek to the real position and get where we are right now
|
||||
|
||||
12
src/lib.rs
12
src/lib.rs
@@ -30,6 +30,8 @@
|
||||
bool_to_option,
|
||||
decl_macro,
|
||||
stmt_expr_attributes,
|
||||
unwrap_infallible,
|
||||
const_if_match,
|
||||
)]
|
||||
|
||||
// Lints
|
||||
@@ -50,8 +52,11 @@
|
||||
clippy::identity_op, // Makes sense sometimes for symmetry
|
||||
clippy::items_after_statements, // Sometimes we only introduce items when we first use them.
|
||||
clippy::unseparated_literal_suffix, // We only separate them when they are long
|
||||
clippy::diverging_sub_expression, // We use `?` on `Result<T, !>` for extracting the result currently, once a method is done for it, we'll use it.
|
||||
clippy::match_same_arms, // Sometimes we separate them for clarify and order
|
||||
clippy::missing_errors_doc, // We provide documentation on errors on the error type itself
|
||||
clippy::todo, // Code that is incomplete should be tagged as such.
|
||||
clippy::unreachable, // Some code should be unreachable and panic when reached.
|
||||
clippy::integer_arithmetic, // Come on now, we need to use numbers to program
|
||||
|
||||
// TODO: Deal with casts eventually
|
||||
clippy::cast_possible_wrap,
|
||||
@@ -62,10 +67,7 @@
|
||||
clippy::missing_docs_in_private_items,
|
||||
clippy::as_conversions,
|
||||
clippy::indexing_slicing,
|
||||
clippy::integer_arithmetic,
|
||||
clippy::unreachable,
|
||||
clippy::todo,
|
||||
clippy::missing_errors_doc,
|
||||
|
||||
)]
|
||||
|
||||
// Modules
|
||||
|
||||
Reference in New Issue
Block a user