mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-11 20:48:11 +00:00
Added more errors to game::card::table.
Started work on `game::deck::table`.
This commit is contained in:
@@ -23,4 +23,5 @@ pub mod deck;
|
||||
|
||||
// Exports
|
||||
pub use bytes::Bytes;
|
||||
pub use card::Digimon;
|
||||
pub use card::{Digimon, Digivolve, Item};
|
||||
pub use deck::Deck;
|
||||
|
||||
@@ -137,6 +137,40 @@ pub enum DeserializeError {
|
||||
err: property::card_type::FromBytesError,
|
||||
},
|
||||
|
||||
/// Unable to read a card
|
||||
#[display(fmt = "Unable to read {} with id {}", card_type, id)]
|
||||
ReadCard {
|
||||
id: usize,
|
||||
card_type: CardType,
|
||||
|
||||
#[error(source)]
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
/// Unable to deserialize a digimon card
|
||||
#[display(fmt = "Unable to deserialize digimon card with id {}", id)]
|
||||
DigimonCard {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: card::digimon::FromBytesError,
|
||||
},
|
||||
|
||||
/// Unable to deserialize an item card
|
||||
#[display(fmt = "Unable to deserialize item card with id {}", id)]
|
||||
ItemCard {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: card::item::FromBytesError,
|
||||
},
|
||||
|
||||
/// Unable to deserialize a digivolve card
|
||||
#[display(fmt = "Unable to deserialize digivolve card with id {}", id)]
|
||||
DigivolveCard {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: card::digivolve::FromBytesError,
|
||||
},
|
||||
|
||||
/// Unable to read card footer
|
||||
#[display(fmt = "Unable to read card footer for card id {}", id)]
|
||||
ReadCardFooter {
|
||||
@@ -175,33 +209,49 @@ pub enum SerializeError {
|
||||
digivolve_cards: usize,
|
||||
},
|
||||
|
||||
/// Unable to write a card
|
||||
#[display(fmt = "Unable to write card with id {}", id)]
|
||||
WriteCard {
|
||||
/// Unable to write a digimon card
|
||||
#[display(fmt = "Unable to write digimon card with id {}", id)]
|
||||
WriteDigimonCard {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
/// Unable to serialize a digimon card
|
||||
#[display(fmt = "Unable to serialize digimon card with id {}", id)]
|
||||
DigimonCard {
|
||||
/// Unable to write an item card
|
||||
#[display(fmt = "Unable to write item card with id {}", id)]
|
||||
WriteItemCard {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
/// Unable to write a digivolve card
|
||||
#[display(fmt = "Unable to write digivolve card with id {}", id)]
|
||||
WriteDigivolveCard {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
/// Unable to parse a digimon card
|
||||
#[display(fmt = "Unable to parse digimon card with id {}", id)]
|
||||
ParseDigimonCard {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: card::digimon::ToBytesError,
|
||||
},
|
||||
|
||||
/// Unable to write an item card
|
||||
#[display(fmt = "Unable to write item card with id {}", id)]
|
||||
ItemCard {
|
||||
/// Unable to parse an item card
|
||||
#[display(fmt = "Unable to parse item card with id {}", id)]
|
||||
ParseItemCard {
|
||||
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 {
|
||||
/// Unable to parse a digivolve card
|
||||
#[display(fmt = "Unable to parse digivolve card with id {}", id)]
|
||||
ParseDigivolveCard {
|
||||
id: usize,
|
||||
#[error(source)]
|
||||
err: card::digivolve::ToBytesError,
|
||||
@@ -275,20 +325,23 @@ impl Table {
|
||||
match card_type {
|
||||
CardType::Digimon => {
|
||||
let mut digimon_bytes = [0; std::mem::size_of::<<Digimon as Bytes>::ByteArray>()];
|
||||
file.read_exact(&mut digimon_bytes).expect("Unable to read digimon bytes");
|
||||
let digimon = Digimon::from_bytes(&digimon_bytes).expect("Unable to parse digimon bytes");
|
||||
file.read_exact(&mut digimon_bytes)
|
||||
.map_err(|err| DeserializeError::ReadCard { id: cur_id, card_type, err })?;
|
||||
let digimon = Digimon::from_bytes(&digimon_bytes).map_err(|err| DeserializeError::DigimonCard { id: cur_id, err })?;
|
||||
digimons.push(digimon);
|
||||
},
|
||||
CardType::Item => {
|
||||
let mut item_bytes = [0; std::mem::size_of::<<Item as Bytes>::ByteArray>()];
|
||||
file.read_exact(&mut item_bytes).expect("Unable to read item bytes");
|
||||
let item = Item::from_bytes(&item_bytes).expect("Unable to parse item bytes");
|
||||
file.read_exact(&mut item_bytes)
|
||||
.map_err(|err| DeserializeError::ReadCard { id: cur_id, card_type, err })?;
|
||||
let item = Item::from_bytes(&item_bytes).map_err(|err| DeserializeError::ItemCard { id: cur_id, err })?;
|
||||
items.push(item);
|
||||
},
|
||||
CardType::Digivolve => {
|
||||
let mut digivolve_bytes = [0; std::mem::size_of::<<Digivolve as Bytes>::ByteArray>()];
|
||||
file.read_exact(&mut digivolve_bytes).expect("Unable to read digivolve bytes");
|
||||
let digivolve = Digivolve::from_bytes(&digivolve_bytes).expect("Unable to parse digivolve bytes");
|
||||
file.read_exact(&mut digivolve_bytes)
|
||||
.map_err(|err| DeserializeError::ReadCard { id: cur_id, card_type, err })?;
|
||||
let digivolve = Digivolve::from_bytes(&digivolve_bytes).map_err(|err| DeserializeError::DigivolveCard { id: cur_id, err })?;
|
||||
digivolves.push(digivolve);
|
||||
},
|
||||
}
|
||||
@@ -372,13 +425,14 @@ impl Table {
|
||||
// Write the digimon
|
||||
digimon
|
||||
.to_bytes(bytes.digimon)
|
||||
.map_err(|err| SerializeError::DigimonCard { id: cur_id, err })?;
|
||||
.map_err(|err| SerializeError::ParseDigimonCard { id: cur_id, err })?;
|
||||
|
||||
// Write the footer
|
||||
*bytes.footer = 0;
|
||||
|
||||
log::debug!("[Card Header] Writing Digimon with id {}", cur_id);
|
||||
file.write_all(&card_bytes).map_err(|err| SerializeError::WriteCard { id: cur_id, err })?;
|
||||
file.write_all(&card_bytes)
|
||||
.map_err(|err| SerializeError::WriteDigimonCard { id: cur_id, err })?;
|
||||
}
|
||||
for (rel_id, item) in self.items.iter().enumerate() {
|
||||
// Current id through the whole table
|
||||
@@ -398,13 +452,15 @@ impl Table {
|
||||
CardType::Item.to_bytes(bytes.header_type)?;
|
||||
|
||||
// Write the item
|
||||
item.to_bytes(bytes.item).map_err(|err| SerializeError::ItemCard { id: cur_id, err })?;
|
||||
item.to_bytes(bytes.item)
|
||||
.map_err(|err| SerializeError::ParseItemCard { id: cur_id, err })?;
|
||||
|
||||
// Write the footer
|
||||
*bytes.footer = 0;
|
||||
|
||||
log::debug!("[Card Header] Writing Item with id {}", cur_id);
|
||||
file.write_all(&card_bytes).map_err(|err| SerializeError::WriteCard { id: cur_id, err })?;
|
||||
file.write_all(&card_bytes)
|
||||
.map_err(|err| SerializeError::WriteItemCard { id: cur_id, err })?;
|
||||
}
|
||||
for (rel_id, digivolve) in self.digivolves.iter().enumerate() {
|
||||
// Current id through the whole table
|
||||
@@ -426,13 +482,14 @@ impl Table {
|
||||
// Write the digivolve
|
||||
digivolve
|
||||
.to_bytes(bytes.item)
|
||||
.map_err(|err| SerializeError::DigivolveCard { id: cur_id, err })?;
|
||||
.map_err(|err| SerializeError::ParseDigivolveCard { id: cur_id, err })?;
|
||||
|
||||
// Write the footer
|
||||
*bytes.footer = 0;
|
||||
|
||||
log::debug!("[Card Header] Writing Digivolve with id {}", cur_id);
|
||||
file.write_all(&card_bytes).map_err(|err| SerializeError::WriteCard { id: cur_id, err })?;
|
||||
file.write_all(&card_bytes)
|
||||
.map_err(|err| SerializeError::WriteDigivolveCard { id: cur_id, err })?;
|
||||
}
|
||||
|
||||
// And return Ok
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
//! Deck
|
||||
|
||||
// Modules
|
||||
pub mod deck;
|
||||
pub mod table;
|
||||
|
||||
// Exports
|
||||
pub use deck::Deck;
|
||||
pub use table::Table;
|
||||
|
||||
@@ -1,363 +1,8 @@
|
||||
// Crate
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Game
|
||||
use crate::game::util;
|
||||
use crate::game::Bytes;
|
||||
use crate::game::FromBytes;
|
||||
use crate::game::ToBytes;
|
||||
use crate::game::card::property::Speciality;
|
||||
use crate::game::card::property::Level;
|
||||
use crate::game::card::property::Move;
|
||||
use crate::game::card::property::CrossMoveEffect;
|
||||
use crate::game::card::property::SupportEffectCondition;
|
||||
use crate::game::card::property::SupportEffect;
|
||||
use crate::game::card::property::ArrowColor;
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
//! Decks
|
||||
|
||||
// byteorder
|
||||
use byteorder::ByteOrder;
|
||||
use byteorder::LittleEndian;
|
||||
|
||||
// Macros
|
||||
|
||||
use serde::Serialize;
|
||||
use serde::Deserialize;
|
||||
use contracts::*;
|
||||
|
||||
// Types
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// A digimon card
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Digimon
|
||||
{
|
||||
/// The basic info of the digimon
|
||||
pub basic: Basic,
|
||||
|
||||
/// The moves
|
||||
pub moves: Moves,
|
||||
|
||||
/// The effects
|
||||
pub effects: Effects,
|
||||
}
|
||||
|
||||
/// The basic properties of a digimon
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Basic
|
||||
{
|
||||
pub name: String,
|
||||
pub speciality: Speciality,
|
||||
pub level: Level,
|
||||
pub dp_cost: u8,
|
||||
pub dp_give: u8,
|
||||
pub hp: u16,
|
||||
|
||||
pub unknown: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Moves
|
||||
{
|
||||
pub circle: Move,
|
||||
pub triangle: Move,
|
||||
pub cross: Move,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Effects
|
||||
{
|
||||
pub unknown: u8,
|
||||
|
||||
pub cross_move: CrossMoveEffect,
|
||||
|
||||
pub description: [String; 4],
|
||||
pub arrow_color: Option<ArrowColor>,
|
||||
|
||||
pub conditions: SupportEffectConditions,
|
||||
pub effects : SupportEffects,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SupportEffects
|
||||
{
|
||||
pub first : Option<SupportEffect>,
|
||||
pub second: Option<SupportEffect>,
|
||||
pub third : Option<SupportEffect>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SupportEffectConditions
|
||||
{
|
||||
pub first : Option<SupportEffectCondition>,
|
||||
pub second: Option<SupportEffectCondition>,
|
||||
}
|
||||
|
||||
/// 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::NullTerminatedStringError ),
|
||||
|
||||
/// Unable to read the speciality
|
||||
#[display(fmt = "Unable to read the speciality")]
|
||||
Speciality( crate::game::card::property::speciality::UnknownSpeciality ),
|
||||
|
||||
/// Unable to read the level
|
||||
#[display(fmt = "Unable to read the level")]
|
||||
Level( crate::game::card::property::level::UnknownLevel ),
|
||||
|
||||
/// Unable to read the effect arrow color
|
||||
#[display(fmt = "Unable to read the effect arrow color")]
|
||||
EffectArrowColor( crate::game::card::property::arrow_color::UnknownArrowColor ),
|
||||
|
||||
/// 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::NullTerminatedStringError,
|
||||
},
|
||||
|
||||
/// Unable to read cross move effect
|
||||
#[display(fmt = "Unable to read the cross move effect")]
|
||||
CrossMoveEffect( crate::game::card::property::cross_move_effect::UnknownCrossMoveEffect ),
|
||||
|
||||
/// Unable to read a support effect condition
|
||||
#[display(fmt = "Unable to read the {0} support effect condition [digimon:0x{1:x}]", rank, digimon_pos)]
|
||||
SupportEffectCondition {
|
||||
rank: &'static str,
|
||||
digimon_pos: u64,
|
||||
|
||||
|
||||
err: crate::game::card::property::support_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,
|
||||
},
|
||||
|
||||
/// Unable to read a move
|
||||
#[display(fmt = "Unable to read the {} move", name)]
|
||||
Move {
|
||||
name: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::moves::FromBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
/// The error type thrown by `ToBytes`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum ToBytesError
|
||||
{
|
||||
/// The name was too 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,
|
||||
},
|
||||
|
||||
/// Unable to write a move
|
||||
#[display(fmt = "Unable to write the {} move", name)]
|
||||
Move {
|
||||
name: &'static str,
|
||||
|
||||
|
||||
err: crate::game::card::property::moves::ToBytesError,
|
||||
},
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Impl
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Bytes
|
||||
impl Bytes for Digimon
|
||||
{
|
||||
const BUF_BYTE_SIZE : usize = 0x138;
|
||||
}
|
||||
|
||||
// From bytes
|
||||
#[contract_trait]
|
||||
impl FromBytes for Digimon
|
||||
{
|
||||
type Output = Result<Self, FromBytesError>;
|
||||
|
||||
fn from_bytes(bytes: &[u8]) -> Self::Output
|
||||
{
|
||||
// Assert some fields are 0
|
||||
//assert_eq!(bytes[0x1a], 0);
|
||||
|
||||
// And return the struct
|
||||
Ok( Digimon {
|
||||
basic: Basic {
|
||||
name: util::read_null_terminated_string( &bytes[0x0..0x15] ).map_err(FromBytesError::NameToString)?.to_string(),
|
||||
|
||||
speciality: Speciality::from_bytes( &[(bytes[0x17] & 0xF0) >> 4] ).map_err(FromBytesError::Speciality)?,
|
||||
level : Level::from_bytes( &[ bytes[0x17] & 0x0F ] ).map_err(FromBytesError::Level )?,
|
||||
|
||||
dp_cost: bytes[0x18],
|
||||
dp_give: bytes[0x19],
|
||||
|
||||
hp: LittleEndian::read_u16( &bytes[0x1b..0x1d] ),
|
||||
|
||||
unknown: LittleEndian::read_u16( &bytes[0x15..0x17] ),
|
||||
},
|
||||
|
||||
moves: Moves {
|
||||
circle : Move::from_bytes( &bytes[0x1d..0x39] ).map_err(|err| FromBytesError::Move{ name: "circle" , err })?,
|
||||
triangle: Move::from_bytes( &bytes[0x39..0x55] ).map_err(|err| FromBytesError::Move{ name: "triangle", err })?,
|
||||
cross : Move::from_bytes( &bytes[0x55..0x71] ).map_err(|err| FromBytesError::Move{ name: "cross" , err })?,
|
||||
},
|
||||
|
||||
effects: Effects {
|
||||
cross_move: CrossMoveEffect::from_bytes( &[ bytes[0xe1] ] ).map_err(FromBytesError::CrossMoveEffect)?,
|
||||
|
||||
description: [
|
||||
util::read_null_terminated_string( &bytes[0x0e4..0x0f9] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "1st", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x0f9..0x10e] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "2nd", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x10e..0x123] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "3rd", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x123..0x138] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "4th", err })?.to_string(),
|
||||
],
|
||||
|
||||
arrow_color: if bytes[0xe3] != 0 {
|
||||
Some( ArrowColor::from_bytes( &bytes[0xe3..0xe4] ).map_err(FromBytesError::EffectArrowColor)? )
|
||||
} else { None },
|
||||
|
||||
conditions: SupportEffectConditions {
|
||||
first: if bytes[0x73] != 0 { Some(
|
||||
SupportEffectCondition::from_bytes( &bytes[0x71..0x91] ).map_err(|err| FromBytesError::SupportEffectCondition{ rank: "1st", digimon_pos: 0x71, err })?
|
||||
)} else { None },
|
||||
|
||||
second: if bytes[0x93] != 0 { Some(
|
||||
SupportEffectCondition::from_bytes( &bytes[0x91..0xb1] ).map_err(|err| FromBytesError::SupportEffectCondition{ rank: "2nd", digimon_pos: 0x91, err })?
|
||||
)} else { None },
|
||||
},
|
||||
|
||||
effects: SupportEffects {
|
||||
first: if bytes[0xb1] != 0 { Some(
|
||||
SupportEffect::from_bytes( &bytes[0xb1..0xc1] ).map_err(|err| FromBytesError::SupportEffect{ rank: "1st", err })?
|
||||
)} else { None },
|
||||
|
||||
second: if bytes[0xc1] != 0 { Some(
|
||||
SupportEffect::from_bytes( &bytes[0xc1..0xd1] ).map_err(|err| FromBytesError::SupportEffect{ rank: "2nd", err })?
|
||||
)} else { None },
|
||||
|
||||
third: if bytes[0xd1] != 0 { Some(
|
||||
SupportEffect::from_bytes( &bytes[0xd1..0xe1] ).map_err(|err| FromBytesError::SupportEffect{ rank: "3rd", err })?
|
||||
)} else { None },
|
||||
},
|
||||
|
||||
unknown: bytes[0xe2],
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// To bytes
|
||||
#[contract_trait]
|
||||
impl ToBytes for Digimon
|
||||
{
|
||||
type Output = Result<(), ToBytesError>;
|
||||
|
||||
fn to_bytes(&self, bytes: &mut [u8]) -> Self::Output
|
||||
{
|
||||
// Assert the size is right
|
||||
assert_eq!(bytes.len(), Self::BUF_BYTE_SIZE);
|
||||
|
||||
// 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
|
||||
});
|
||||
|
||||
// Write the speciality and level bytes
|
||||
{
|
||||
let (mut speciality_byte, mut level_byte) = ( [0u8], [0u8] );
|
||||
|
||||
self.basic.speciality.to_bytes(&mut speciality_byte);
|
||||
self.basic.level .to_bytes(&mut level_byte);
|
||||
|
||||
// Merge them
|
||||
bytes[0x17] = (speciality_byte[0] << 4) | level_byte[0];
|
||||
}
|
||||
|
||||
// DP / +P
|
||||
bytes[0x18] = self.basic.dp_cost;
|
||||
bytes[0x19] = self.basic.dp_give;
|
||||
|
||||
// Health
|
||||
LittleEndian::write_u16(&mut bytes[0x1b..0x1d], self.basic.hp);
|
||||
|
||||
LittleEndian::write_u16(&mut bytes[0x15..0x17], self.basic.unknown);
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Moves
|
||||
self.moves.circle .to_bytes(&mut bytes[0x1d..0x39]).map_err(|err| ToBytesError::Move{ name: "circle" , err })?;
|
||||
self.moves.triangle.to_bytes(&mut bytes[0x39..0x55]).map_err(|err| ToBytesError::Move{ name: "triangle", err })?;
|
||||
self.moves.cross .to_bytes(&mut bytes[0x55..0x71]).map_err(|err| ToBytesError::Move{ name: "cross" , err })?;
|
||||
|
||||
// Effects
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Write the support effects
|
||||
for (index, line) in self.effects.description.iter().enumerate()
|
||||
{
|
||||
bytes[0x0e4 + (0x15 * index) .. 0x0f9 + (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
|
||||
});
|
||||
}
|
||||
|
||||
self.effects.cross_move.to_bytes(&mut bytes[0xe1..0xe2]);
|
||||
|
||||
bytes[0xe2] = self.effects.unknown;
|
||||
|
||||
if let Some(arrow_color) = self.effects.arrow_color { arrow_color.to_bytes( &mut bytes[0xe3..0xe4] ); }
|
||||
|
||||
// If they are None, 0 is a valid value for the conditions
|
||||
if let Some(support_effect_condition) = &self.effects.conditions.first { support_effect_condition.to_bytes(&mut bytes[0x71..0x91]); }
|
||||
if let Some(support_effect_condition) = &self.effects.conditions.second { support_effect_condition.to_bytes(&mut bytes[0x91..0xb1]); }
|
||||
|
||||
|
||||
// If they are None, 0 is a valid value for the effects
|
||||
if let Some(support_effect) = &self.effects.effects.first { support_effect.to_bytes(&mut bytes[0xb1..0xc1]); }
|
||||
if let Some(support_effect) = &self.effects.effects.second { support_effect.to_bytes(&mut bytes[0xc1..0xd1]); }
|
||||
if let Some(support_effect) = &self.effects.effects.third { support_effect.to_bytes(&mut bytes[0xd1..0xe1]); }
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Return the bytes
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// A deck
|
||||
#[derive(Debug)]
|
||||
#[derive(::serde::Serialize, ::serde::Deserialize)]
|
||||
pub struct Deck {
|
||||
pub cards: [u16; 30],
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@ use std::io::{Read, Seek, Write};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
// Crate
|
||||
use crate::io::{address::Data, GameFile};
|
||||
use crate::{
|
||||
game::Deck,
|
||||
io::{address::Data, GameFile},
|
||||
};
|
||||
|
||||
/// The decks table, where all decks are stored
|
||||
///
|
||||
@@ -21,70 +24,35 @@ pub struct Table {
|
||||
decks: Vec<Deck>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(::serde::Serialize, ::serde::Deserialize)]
|
||||
pub struct Deck {
|
||||
cards: [u16; 30],
|
||||
}
|
||||
|
||||
// Constants
|
||||
impl Table {
|
||||
/// The start address of the decks table
|
||||
const DECK_TABLE_START_ADDRESS: Data = Data::from_u64(0x21a6808);
|
||||
}
|
||||
|
||||
/// Error type for `Table::new`
|
||||
/// Error type for [`Table::deserialize`]
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display, err_impl::Error)]
|
||||
pub enum NewError {
|
||||
/// Could not seek tothe beginning of the deck table
|
||||
#[display(fmt = "Could not seek to the beginning of the deck table")]
|
||||
SeekTableBegin(#[error(source)] std::io::Error),
|
||||
pub enum DeserializeError {
|
||||
/// Unable to seek game file
|
||||
#[display(fmt = "Unable to seek game file to card table")]
|
||||
Seek(#[error(source)] std::io::Error),
|
||||
|
||||
/// Unable to read table header
|
||||
#[display(fmt = "Unable to read table header")]
|
||||
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")]
|
||||
HeaderMagic { magic: u32 },
|
||||
*/
|
||||
/// Could not read a deck entry from the deck table
|
||||
#[display(fmt = "Unable to fully read a deck entry (The file was too small)")]
|
||||
DeckEntry(#[error(source)] std::io::Error),
|
||||
|
||||
/*
|
||||
/// Could not constructs a deck
|
||||
#[display(fmt = "Could not construct a deck from the deck table")]
|
||||
DeckConstruction( crate::game::deck::deck::FromBytesError ),
|
||||
*/
|
||||
/// Could not read the next entry info
|
||||
#[display(fmt = "Unable to fully read next entry info (The file was too small)")]
|
||||
NextEntryInfo(#[error(source)] std::io::Error),
|
||||
/*
|
||||
/// The deck table was malformed
|
||||
#[display(fmt = "The deck table is malformed")]
|
||||
MalformedTable( crate::game::deck::property::deck_type::UnknownDeckType ),
|
||||
*/
|
||||
}
|
||||
|
||||
/// Error type for `Table::write_to_file`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum WriteError {
|
||||
/// The deck table was too big
|
||||
#[display(fmt = "The deck table was too big (is {}, should be 65536 max)", _0)]
|
||||
TooManyDeck(usize),
|
||||
/*
|
||||
/// Unable to convert a deck to bytes
|
||||
#[display(fmt = "Unable to convert deck with id {} to bytes", id)]
|
||||
UnableToConvertDeckToBytes {
|
||||
id: u16,
|
||||
err: crate::game::deck::deck::ToBytesError,
|
||||
},
|
||||
|
||||
/// Unable to write deck entry
|
||||
#[display(fmt = "Unable to write deck entry with id {}", id)]
|
||||
UnableToWriteDeckEntry {
|
||||
id: u16,
|
||||
err: std::io::Error,
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
||||
impl Table {
|
||||
pub fn new<F>(game_file: &mut GameFile<F>) -> Result<Self, NewError>
|
||||
pub fn deserialize<F>(game_file: &mut GameFile<F>) -> Result<Self, DeserializeError>
|
||||
where
|
||||
F: Read + Write + Seek,
|
||||
{
|
||||
@@ -94,14 +62,14 @@ impl Table {
|
||||
// Seek to the beginning of the deck table
|
||||
game_file
|
||||
.seek(std::io::SeekFrom::Start(u64::from(Self::DECK_TABLE_START_ADDRESS)))
|
||||
.map_err(NewError::SeekTableBegin)?;
|
||||
.map_err(DeserializeError::Seek)?;
|
||||
|
||||
// Then loop until we're at the end of the table
|
||||
//'table_loop: loop
|
||||
for _ in 0..100 {
|
||||
// Read the deck
|
||||
let mut buf = [0u8; 110];
|
||||
game_file.read_exact(&mut buf).map_err(NewError::DeckEntry)?;
|
||||
game_file.read_exact(&mut buf).map_err(DeserializeError::DeckEntry)?;
|
||||
|
||||
// And construct the deck
|
||||
let deck = Deck {
|
||||
@@ -123,38 +91,4 @@ impl Table {
|
||||
// And return the table
|
||||
Ok(Self { decks })
|
||||
}
|
||||
|
||||
/*
|
||||
/// Writes this table to a dcb bin file
|
||||
pub fn write_to_file<F>(&self, _game_file: &mut GameFile<F>) -> Result<(), WriteError>
|
||||
where
|
||||
F: Read + Write + Seek
|
||||
{
|
||||
/*
|
||||
// If the table length is bigger than 0xFFFF, return err
|
||||
if self.decks.len() > 0xFFFF { return Err( TableWriteError::TooManyDeck( self.decks.len() ) ); }
|
||||
|
||||
// Go through all deck and write them
|
||||
// Note: We write them in the order they appear in the array,
|
||||
// because this is the same way we read them.
|
||||
for (id, deck) in self.decks.iter().enumerate()
|
||||
{
|
||||
// Convert `id` to a u16
|
||||
let id = id as u16;
|
||||
|
||||
// Get the bytes
|
||||
let mut bytes = [0u8; Deck::BUF_BYTE_SIZE];
|
||||
deck.to_bytes(&mut bytes).map_err(|err| TableWriteError::UnableToConvertDeckToBytes{id, err})?;
|
||||
|
||||
// Seek to the right address in the table
|
||||
Self::seek_deck_table(game_file, id as u16)?;
|
||||
|
||||
// And write the deck buffer
|
||||
game_file.write_all(&bytes).map_err(|err| TableWriteError::UnableToWriteDeckEntry{id, err})?;
|
||||
}
|
||||
*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -17,8 +17,11 @@ pub macro array_split {
|
||||
|
||||
),* $(,)?
|
||||
) => {{
|
||||
#![allow(clippy::used_underscore_binding)]
|
||||
#![allow(clippy::ptr_offset_with_cast )]
|
||||
#![allow(
|
||||
clippy::used_underscore_binding,
|
||||
clippy::ptr_offset_with_cast,
|
||||
clippy::indexing_slicing,
|
||||
)]
|
||||
|
||||
// Struct holding all fields
|
||||
struct Fields<'a, T> {
|
||||
@@ -65,8 +68,11 @@ pub macro array_split_mut {
|
||||
|
||||
),* $(,)?
|
||||
) => {{
|
||||
#![allow(clippy::used_underscore_binding)]
|
||||
#![allow(clippy::ptr_offset_with_cast )]
|
||||
#![allow(
|
||||
clippy::used_underscore_binding,
|
||||
clippy::ptr_offset_with_cast,
|
||||
clippy::indexing_slicing,
|
||||
)]
|
||||
|
||||
// Struct holding all fields
|
||||
struct Fields<'a, T> {
|
||||
|
||||
@@ -54,14 +54,15 @@
|
||||
clippy::unreachable, // Some code should be unreachable and panic when reached.
|
||||
clippy::integer_arithmetic, // Come on now, we need to use numbers to program
|
||||
clippy::shadow_same, // Useful when taking arguments such as `value: impl AsRef<T>` / `let value = value.as_ref();`
|
||||
clippy::module_inception, // Sometimes module organization causes this
|
||||
clippy::missing_docs_in_private_items, // Not all private items are documented on purpose
|
||||
clippy::indexing_slicing, // False-positives on arrays
|
||||
|
||||
// TODO: Deal with casts eventually
|
||||
clippy::as_conversions,
|
||||
clippy::cast_possible_wrap,
|
||||
clippy::cast_sign_loss,
|
||||
clippy::cast_possible_truncation,
|
||||
// TODO: Remove these once all modules are ported
|
||||
clippy::missing_docs_in_private_items,
|
||||
clippy::as_conversions,
|
||||
clippy::indexing_slicing,
|
||||
)]
|
||||
|
||||
// Modules
|
||||
|
||||
Reference in New Issue
Block a user