500 lines
17 KiB
Rust
500 lines
17 KiB
Rust
use std::collections::HashMap;
|
|
use serde::{Serialize, Deserialize};
|
|
use crate::entity::item::tool::ToolType;
|
|
use std::io::Read;
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct MagStats {
|
|
feed_table: u32,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct MagFeedTable {
|
|
def: i32,
|
|
pow: i32,
|
|
dex: i32,
|
|
mnd: i32,
|
|
iq: i32,
|
|
syn: i32,
|
|
}
|
|
|
|
lazy_static::lazy_static! {
|
|
static ref MAG_STATS: HashMap<MagType, MagStats> = {
|
|
let mut f = std::fs::File::open("data/item_stats/mag_stats.toml").unwrap();
|
|
let mut s = String::new();
|
|
f.read_to_string(&mut s).unwrap();
|
|
|
|
let mag_stats: HashMap<String, MagStats> = toml::from_str(&s).unwrap();
|
|
mag_stats.into_iter()
|
|
.map(|(name, stats)| {
|
|
(name.parse().unwrap(), stats)
|
|
})
|
|
.collect::<HashMap<MagType, MagStats>>()
|
|
};
|
|
|
|
static ref MAG_FEEDING_TABLES: Vec<HashMap<ToolType, MagFeedTable>> = {
|
|
let mut f = std::fs::File::open("data/item_stats/mag_feed_table.toml").unwrap();
|
|
let mut s = String::new();
|
|
f.read_to_string(&mut s).unwrap();
|
|
|
|
let mut feed: HashMap<String, Vec<HashMap<String, MagFeedTable>>> = toml::from_str(&s).unwrap();
|
|
let feed = feed.remove("feedtable".into()).unwrap();
|
|
feed.into_iter()
|
|
.map(|table| {
|
|
table.into_iter()
|
|
.map(|(tool, stats)| {
|
|
(tool.parse().unwrap(), stats)
|
|
})
|
|
.collect()
|
|
})
|
|
.collect::<Vec<HashMap<ToolType, MagFeedTable>>>()
|
|
};
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub enum ItemParseError {
|
|
InvalidMagType,
|
|
InvalidMagBytes,
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, enum_utils::FromStr, derive_more::Display)]
|
|
pub enum MagType {
|
|
Mag,
|
|
Varuna,
|
|
Mitra,
|
|
Surya,
|
|
Vayu,
|
|
Varaha,
|
|
Kama,
|
|
Ushasu,
|
|
Apsaras,
|
|
Kumara,
|
|
Kaitabha,
|
|
Tapas,
|
|
Bhirava,
|
|
Kalki,
|
|
Rudra,
|
|
Marutah,
|
|
Yaksa,
|
|
Sita,
|
|
Garuda,
|
|
Nandin,
|
|
Ashvinau,
|
|
Ribhava,
|
|
Soma,
|
|
Ila,
|
|
Durga,
|
|
Vritra,
|
|
Namuci,
|
|
Sumba,
|
|
Naga,
|
|
Pitri,
|
|
Kabanda,
|
|
Ravana,
|
|
Marica,
|
|
Soniti,
|
|
Preta,
|
|
Andhaka,
|
|
Bana,
|
|
Naraka,
|
|
Madhu,
|
|
Churel,
|
|
Robochao,
|
|
OpaOpa,
|
|
Pian,
|
|
Chao,
|
|
ChuChu,
|
|
KapuKapu,
|
|
AngelsWing,
|
|
DevilsWing,
|
|
Elenor,
|
|
MarkIII,
|
|
MasterSystem,
|
|
Genesis,
|
|
SegaSaturn,
|
|
Dreamcast,
|
|
Hamburger,
|
|
PanzersTail,
|
|
DevilsTail,
|
|
Deva,
|
|
Rati,
|
|
Savitri,
|
|
Rukmin,
|
|
Pushan,
|
|
Diwari,
|
|
Sato,
|
|
Bhima,
|
|
Nidra,
|
|
GeungSi,
|
|
Tellusis,
|
|
StrikerUnit,
|
|
Pioneer,
|
|
Puyo,
|
|
Moro,
|
|
Rappy,
|
|
Yahoo,
|
|
GaelGiel,
|
|
Agastya,
|
|
}
|
|
|
|
impl MagType {
|
|
pub fn value(&self) -> [u8; 3] {
|
|
match self {
|
|
MagType::Mag => [0x02, 0x00, 0x00],
|
|
MagType::Varuna => [0x02, 0x01, 0x00],
|
|
MagType::Mitra => [0x02, 0x02, 0x00],
|
|
MagType::Surya => [0x02, 0x03, 0x00],
|
|
MagType::Vayu => [0x02, 0x04, 0x00],
|
|
MagType::Varaha => [0x02, 0x05, 0x00],
|
|
MagType::Kama => [0x02, 0x06, 0x00],
|
|
MagType::Ushasu => [0x02, 0x07, 0x00],
|
|
MagType::Apsaras => [0x02, 0x08, 0x00],
|
|
MagType::Kumara => [0x02, 0x09, 0x00],
|
|
MagType::Kaitabha => [0x02, 0x0A, 0x00],
|
|
MagType::Tapas => [0x02, 0x0B, 0x00],
|
|
MagType::Bhirava => [0x02, 0x0C, 0x00],
|
|
MagType::Kalki => [0x02, 0x0D, 0x00],
|
|
MagType::Rudra => [0x02, 0x0E, 0x00],
|
|
MagType::Marutah => [0x02, 0x0F, 0x00],
|
|
MagType::Yaksa => [0x02, 0x10, 0x00],
|
|
MagType::Sita => [0x02, 0x11, 0x00],
|
|
MagType::Garuda => [0x02, 0x12, 0x00],
|
|
MagType::Nandin => [0x02, 0x13, 0x00],
|
|
MagType::Ashvinau => [0x02, 0x14, 0x00],
|
|
MagType::Ribhava => [0x02, 0x15, 0x00],
|
|
MagType::Soma => [0x02, 0x16, 0x00],
|
|
MagType::Ila => [0x02, 0x17, 0x00],
|
|
MagType::Durga => [0x02, 0x18, 0x00],
|
|
MagType::Vritra => [0x02, 0x19, 0x00],
|
|
MagType::Namuci => [0x02, 0x1A, 0x00],
|
|
MagType::Sumba => [0x02, 0x1B, 0x00],
|
|
MagType::Naga => [0x02, 0x1C, 0x00],
|
|
MagType::Pitri => [0x02, 0x1D, 0x00],
|
|
MagType::Kabanda => [0x02, 0x1E, 0x00],
|
|
MagType::Ravana => [0x02, 0x1F, 0x00],
|
|
MagType::Marica => [0x02, 0x20, 0x00],
|
|
MagType::Soniti => [0x02, 0x21, 0x00],
|
|
MagType::Preta => [0x02, 0x22, 0x00],
|
|
MagType::Andhaka => [0x02, 0x23, 0x00],
|
|
MagType::Bana => [0x02, 0x24, 0x00],
|
|
MagType::Naraka => [0x02, 0x25, 0x00],
|
|
MagType::Madhu => [0x02, 0x26, 0x00],
|
|
MagType::Churel => [0x02, 0x27, 0x00],
|
|
MagType::Robochao => [0x02, 0x28, 0x00],
|
|
MagType::OpaOpa => [0x02, 0x29, 0x00],
|
|
MagType::Pian => [0x02, 0x2A, 0x00],
|
|
MagType::Chao => [0x02, 0x2B, 0x00],
|
|
MagType::ChuChu => [0x02, 0x2C, 0x00],
|
|
MagType::KapuKapu => [0x02, 0x2D, 0x00],
|
|
MagType::AngelsWing => [0x02, 0x2E, 0x00],
|
|
MagType::DevilsWing => [0x02, 0x2F, 0x00],
|
|
MagType::Elenor => [0x02, 0x30, 0x00],
|
|
MagType::MarkIII => [0x02, 0x31, 0x00],
|
|
MagType::MasterSystem => [0x02, 0x32, 0x00],
|
|
MagType::Genesis => [0x02, 0x33, 0x00],
|
|
MagType::SegaSaturn => [0x02, 0x34, 0x00],
|
|
MagType::Dreamcast => [0x02, 0x35, 0x00],
|
|
MagType::Hamburger => [0x02, 0x36, 0x00],
|
|
MagType::PanzersTail => [0x02, 0x37, 0x00],
|
|
MagType::DevilsTail => [0x02, 0x38, 0x00],
|
|
MagType::Deva => [0x02, 0x39, 0x00],
|
|
MagType::Rati => [0x02, 0x3A, 0x00],
|
|
MagType::Savitri => [0x02, 0x3B, 0x00],
|
|
MagType::Rukmin => [0x02, 0x3C, 0x00],
|
|
MagType::Pushan => [0x02, 0x3D, 0x00],
|
|
MagType::Diwari => [0x02, 0x3E, 0x00],
|
|
MagType::Sato => [0x02, 0x3F, 0x00],
|
|
MagType::Bhima => [0x02, 0x40, 0x00],
|
|
MagType::Nidra => [0x02, 0x41, 0x00],
|
|
MagType::GeungSi => [0x02, 0x42, 0x00],
|
|
MagType::Tellusis => [0x02, 0x44, 0x00],
|
|
MagType::StrikerUnit => [0x02, 0x45, 0x00],
|
|
MagType::Pioneer => [0x02, 0x46, 0x00],
|
|
MagType::Puyo => [0x02, 0x47, 0x00],
|
|
MagType::Moro => [0x02, 0x48, 0x00],
|
|
MagType::Rappy => [0x02, 0x49, 0x00],
|
|
MagType::Yahoo => [0x02, 0x4A, 0x00],
|
|
MagType::GaelGiel => [0x02, 0x4B, 0x00],
|
|
MagType::Agastya => [0x02, 0x4C, 0x00],
|
|
}
|
|
}
|
|
|
|
pub fn parse_type(data: [u8; 3]) -> Result<MagType, ItemParseError> {
|
|
match data {
|
|
[0x02, 0x00, 0x00] => Ok(MagType::Mag),
|
|
[0x02, 0x01, 0x00] => Ok(MagType::Varuna),
|
|
[0x02, 0x02, 0x00] => Ok(MagType::Mitra),
|
|
[0x02, 0x03, 0x00] => Ok(MagType::Surya),
|
|
[0x02, 0x04, 0x00] => Ok(MagType::Vayu),
|
|
[0x02, 0x05, 0x00] => Ok(MagType::Varaha),
|
|
[0x02, 0x06, 0x00] => Ok(MagType::Kama),
|
|
[0x02, 0x07, 0x00] => Ok(MagType::Ushasu),
|
|
[0x02, 0x08, 0x00] => Ok(MagType::Apsaras),
|
|
[0x02, 0x09, 0x00] => Ok(MagType::Kumara),
|
|
[0x02, 0x0A, 0x00] => Ok(MagType::Kaitabha),
|
|
[0x02, 0x0B, 0x00] => Ok(MagType::Tapas),
|
|
[0x02, 0x0C, 0x00] => Ok(MagType::Bhirava),
|
|
[0x02, 0x0D, 0x00] => Ok(MagType::Kalki),
|
|
[0x02, 0x0E, 0x00] => Ok(MagType::Rudra),
|
|
[0x02, 0x0F, 0x00] => Ok(MagType::Marutah),
|
|
[0x02, 0x10, 0x00] => Ok(MagType::Yaksa),
|
|
[0x02, 0x11, 0x00] => Ok(MagType::Sita),
|
|
[0x02, 0x12, 0x00] => Ok(MagType::Garuda),
|
|
[0x02, 0x13, 0x00] => Ok(MagType::Nandin),
|
|
[0x02, 0x14, 0x00] => Ok(MagType::Ashvinau),
|
|
[0x02, 0x15, 0x00] => Ok(MagType::Ribhava),
|
|
[0x02, 0x16, 0x00] => Ok(MagType::Soma),
|
|
[0x02, 0x17, 0x00] => Ok(MagType::Ila),
|
|
[0x02, 0x18, 0x00] => Ok(MagType::Durga),
|
|
[0x02, 0x19, 0x00] => Ok(MagType::Vritra),
|
|
[0x02, 0x1A, 0x00] => Ok(MagType::Namuci),
|
|
[0x02, 0x1B, 0x00] => Ok(MagType::Sumba),
|
|
[0x02, 0x1C, 0x00] => Ok(MagType::Naga),
|
|
[0x02, 0x1D, 0x00] => Ok(MagType::Pitri),
|
|
[0x02, 0x1E, 0x00] => Ok(MagType::Kabanda),
|
|
[0x02, 0x1F, 0x00] => Ok(MagType::Ravana),
|
|
[0x02, 0x20, 0x00] => Ok(MagType::Marica),
|
|
[0x02, 0x21, 0x00] => Ok(MagType::Soniti),
|
|
[0x02, 0x22, 0x00] => Ok(MagType::Preta),
|
|
[0x02, 0x23, 0x00] => Ok(MagType::Andhaka),
|
|
[0x02, 0x24, 0x00] => Ok(MagType::Bana),
|
|
[0x02, 0x25, 0x00] => Ok(MagType::Naraka),
|
|
[0x02, 0x26, 0x00] => Ok(MagType::Madhu),
|
|
[0x02, 0x27, 0x00] => Ok(MagType::Churel),
|
|
[0x02, 0x28, 0x00] => Ok(MagType::Robochao),
|
|
[0x02, 0x29, 0x00] => Ok(MagType::OpaOpa),
|
|
[0x02, 0x2A, 0x00] => Ok(MagType::Pian),
|
|
[0x02, 0x2B, 0x00] => Ok(MagType::Chao),
|
|
[0x02, 0x2C, 0x00] => Ok(MagType::ChuChu),
|
|
[0x02, 0x2D, 0x00] => Ok(MagType::KapuKapu),
|
|
[0x02, 0x2E, 0x00] => Ok(MagType::AngelsWing),
|
|
[0x02, 0x2F, 0x00] => Ok(MagType::DevilsWing),
|
|
[0x02, 0x30, 0x00] => Ok(MagType::Elenor),
|
|
[0x02, 0x31, 0x00] => Ok(MagType::MarkIII),
|
|
[0x02, 0x32, 0x00] => Ok(MagType::MasterSystem),
|
|
[0x02, 0x33, 0x00] => Ok(MagType::Genesis),
|
|
[0x02, 0x34, 0x00] => Ok(MagType::SegaSaturn),
|
|
[0x02, 0x35, 0x00] => Ok(MagType::Dreamcast),
|
|
[0x02, 0x36, 0x00] => Ok(MagType::Hamburger),
|
|
[0x02, 0x37, 0x00] => Ok(MagType::PanzersTail),
|
|
[0x02, 0x38, 0x00] => Ok(MagType::DevilsTail),
|
|
[0x02, 0x39, 0x00] => Ok(MagType::Deva),
|
|
[0x02, 0x3A, 0x00] => Ok(MagType::Rati),
|
|
[0x02, 0x3B, 0x00] => Ok(MagType::Savitri),
|
|
[0x02, 0x3C, 0x00] => Ok(MagType::Rukmin),
|
|
[0x02, 0x3D, 0x00] => Ok(MagType::Pushan),
|
|
[0x02, 0x3E, 0x00] => Ok(MagType::Diwari),
|
|
[0x02, 0x3F, 0x00] => Ok(MagType::Sato),
|
|
[0x02, 0x40, 0x00] => Ok(MagType::Bhima),
|
|
[0x02, 0x41, 0x00] => Ok(MagType::Nidra),
|
|
[0x02, 0x42, 0x00] => Ok(MagType::GeungSi),
|
|
[0x02, 0x44, 0x00] => Ok(MagType::Tellusis),
|
|
[0x02, 0x45, 0x00] => Ok(MagType::StrikerUnit),
|
|
[0x02, 0x46, 0x00] => Ok(MagType::Pioneer),
|
|
[0x02, 0x47, 0x00] => Ok(MagType::Puyo),
|
|
[0x02, 0x48, 0x00] => Ok(MagType::Moro),
|
|
[0x02, 0x49, 0x00] => Ok(MagType::Rappy),
|
|
[0x02, 0x4A, 0x00] => Ok(MagType::Yahoo),
|
|
[0x02, 0x4B, 0x00] => Ok(MagType::GaelGiel),
|
|
[0x02, 0x4C, 0x00] => Ok(MagType::Agastya),
|
|
_ => Err(ItemParseError::InvalidMagType),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum MagModifier {
|
|
FeedMag{
|
|
food: ToolType,
|
|
},
|
|
BankMag, // when putting a mag in the bank it truncates the values which has applications when raising degenerate mags
|
|
MagCell(ToolType),
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
|
pub enum PhotonBlast {
|
|
Farlla,
|
|
Estlla,
|
|
Leilla,
|
|
Pilla,
|
|
Golla,
|
|
MyllaYoulla,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct Mag {
|
|
pub mag: MagType,
|
|
def: u16,
|
|
pow: u16,
|
|
dex: u16,
|
|
mnd: u16,
|
|
pub synchro: u8,
|
|
iq: u8,
|
|
photon_blast: [Option<PhotonBlast>; 3],
|
|
pub color: u8,
|
|
modifiers: Vec<MagModifier>,
|
|
}
|
|
|
|
|
|
impl Mag {
|
|
pub fn baby_mag(skin: u16) -> Mag {
|
|
Mag {
|
|
mag: MagType::Mag,
|
|
def: 500,
|
|
pow: 0,
|
|
dex: 0,
|
|
mnd: 0,
|
|
synchro: 20,
|
|
iq: 0,
|
|
photon_blast: [None; 3],
|
|
color: (skin % 18) as u8,
|
|
modifiers: Vec::new(),
|
|
}
|
|
}
|
|
|
|
pub fn as_bytes(&self) -> [u8; 16] {
|
|
let mut result = [0; 16];
|
|
result[0..3].copy_from_slice(&self.mag.value());
|
|
result[3] = self.photon_blast_value();
|
|
result[4..6].copy_from_slice(&self.def.to_le_bytes());
|
|
result[6..8].copy_from_slice(&self.pow.to_le_bytes());
|
|
result[8..10].copy_from_slice(&self.dex.to_le_bytes());
|
|
result[10..12].copy_from_slice(&self.mnd.to_le_bytes());
|
|
result[12] = self.synchro;
|
|
result[13] = self.iq;
|
|
result[14] = self.photon_blast_count();
|
|
result[15] = self.color;
|
|
result
|
|
}
|
|
|
|
fn photon_blast_value(&self) -> u8 {
|
|
let mut photon_blast_list = vec![PhotonBlast::Farlla,
|
|
PhotonBlast::Estlla,
|
|
PhotonBlast::Golla,
|
|
PhotonBlast::Pilla,
|
|
PhotonBlast::Leilla,
|
|
PhotonBlast::MyllaYoulla];
|
|
let mut photon_blast: u8 = 0;
|
|
|
|
if let Some(ref pb_mid) = self.photon_blast[0] {
|
|
match *pb_mid {
|
|
PhotonBlast::Farlla => {},
|
|
PhotonBlast::Estlla => photon_blast |= 1,
|
|
PhotonBlast::Golla => photon_blast |= 2,
|
|
PhotonBlast::Pilla => photon_blast |= 3,
|
|
PhotonBlast::Leilla => photon_blast |= 4,
|
|
PhotonBlast::MyllaYoulla => photon_blast |= 5,
|
|
}
|
|
|
|
photon_blast_list.retain(|k| k != pb_mid);
|
|
}
|
|
if let Some(ref pb_right) = self.photon_blast[1] {
|
|
match *pb_right {
|
|
PhotonBlast::Farlla => {}
|
|
PhotonBlast::Estlla => photon_blast |= 1 << 3,
|
|
PhotonBlast::Golla => photon_blast |= 2 << 3,
|
|
PhotonBlast::Pilla => photon_blast |= 3 << 3,
|
|
PhotonBlast::Leilla => photon_blast |= 4 << 3,
|
|
PhotonBlast::MyllaYoulla => photon_blast |= 5 << 3,
|
|
}
|
|
|
|
photon_blast_list.retain(|k| k != pb_right);
|
|
}
|
|
if let Some(ref pb_left) = self.photon_blast[2] {
|
|
if let Some(pos) = photon_blast_list.iter().position(|k| k == pb_left) {
|
|
photon_blast |= (pos as u8) << 6;
|
|
};
|
|
}
|
|
|
|
photon_blast
|
|
}
|
|
|
|
fn photon_blast_count(&self) -> u8 {
|
|
let mut count = 0;
|
|
for i in 0..3 {
|
|
if let Some(_) = self.photon_blast[i] {
|
|
count |= 1 << i
|
|
};
|
|
}
|
|
count
|
|
}
|
|
|
|
pub fn from_bytes(data: [u8; 16]) -> Result<Mag, ItemParseError> {
|
|
let m = MagType::parse_type([data[0], data[1], data[2]]);
|
|
if m.is_ok() {
|
|
let mut def = u16::from_le_bytes([data[4], data[5]]);
|
|
let mut pow = u16::from_le_bytes([data[6], data[7]]);
|
|
let mut dex = u16::from_le_bytes([data[8], data[9]]);
|
|
let mut mind = u16::from_le_bytes([data[10], data[11]]);
|
|
|
|
if (def/100 + dex/100 + pow/100 + mind/100) > 200 {
|
|
def = 0;
|
|
pow = 0;
|
|
dex = 0;
|
|
mind = 0;
|
|
}
|
|
|
|
let sync = data[12] % 121; // TODO: handle invalid values.
|
|
let iq = data[13] % 201; // TODO: handle invalid values.
|
|
|
|
Ok(Mag{
|
|
mag: m.unwrap(),
|
|
def: def,
|
|
pow: pow,
|
|
dex: dex,
|
|
mnd: mind,
|
|
synchro: sync,
|
|
iq: iq,
|
|
photon_blast: [None, None, None], // TODO: actually get PBs from bytes
|
|
color: data[15] % 18,
|
|
modifiers: Vec::new(),
|
|
})
|
|
}
|
|
else {
|
|
Err(ItemParseError::InvalidMagBytes) // TODO: error handling if wrong bytes are given
|
|
}
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
use std::io::Read;
|
|
|
|
#[test]
|
|
fn test_load_mag_stats() {
|
|
let mut f = std::fs::File::open("data/item_stats/mag_stats.toml").unwrap();
|
|
let mut s = String::new();
|
|
f.read_to_string(&mut s).unwrap();
|
|
|
|
let mags: HashMap<String, MagStats> = toml::from_str(&s).unwrap();
|
|
let _mags = mags.into_iter()
|
|
.map(|(name, stats)| {
|
|
(name.parse().unwrap(), stats)
|
|
})
|
|
.collect::<HashMap<MagType, MagStats>>();
|
|
}
|
|
|
|
#[test]
|
|
fn test_load_mag_feed_table() {
|
|
let mut f = std::fs::File::open("data/item_stats/mag_feed_table.toml").unwrap();
|
|
let mut s = String::new();
|
|
f.read_to_string(&mut s).unwrap();
|
|
|
|
let mut feed: HashMap<String, Vec<HashMap<String, MagFeedTable>>> = toml::from_str(&s).unwrap();
|
|
let feed = feed.remove("feedtable".into()).unwrap();
|
|
let _feed = feed.into_iter()
|
|
.map(|table| {
|
|
table.into_iter()
|
|
.map(|(tool, stats)| {
|
|
(tool.parse().unwrap(), stats)
|
|
})
|
|
.collect()
|
|
})
|
|
.collect::<Vec<HashMap<ToolType, MagFeedTable>>>();
|
|
}
|
|
|
|
}
|