use std::collections::HashMap; use std::fs::File; use serde_json::Value; use crate::entity::character::CharacterClass; #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] pub struct CharacterStats { pub hp: u16, pub atp: u16, pub mst: u16, pub evp: u16, pub dfp: u16, pub ata: u16, pub lck: u16, } #[derive(Default, Copy, Clone, Debug)] struct CharacterLevelEntry { hp: u32, atp: u32, mst: u32, evp: u32, dfp: u32, ata: u32, lck: u32, exp: u32, } pub struct CharacterLevelTable { table: HashMap, } impl Default for CharacterLevelTable { fn default() -> CharacterLevelTable { let file = File::open("data/char_stats.json").unwrap(); let json: Value = serde_json::from_reader(file).unwrap(); let mut table = HashMap::new(); for it in json.as_object().unwrap().iter(){ let cl = match it.0.as_str() { "HUmar" => CharacterClass::HUmar, "HUnewearl" => CharacterClass::HUnewearl, "HUcast" => CharacterClass::HUcast, "HUcaseal" => CharacterClass::HUcaseal, "RAmar" => CharacterClass::RAmar, "RAmarl" => CharacterClass::RAmarl, "RAcast" => CharacterClass::RAcast, "RAcaseal" => CharacterClass::RAcaseal, "FOmar" => CharacterClass::FOmar, "FOmarl" => CharacterClass::FOmarl, "FOnewm" => CharacterClass::FOnewm, "FOnewearl" => CharacterClass::FOnewearl, _ => panic!("unexpected class in char stats"), }; let mut statlist = [CharacterLevelEntry::default(); 200]; for (i, stat) in it.1.as_array().unwrap().iter().enumerate() { statlist[i] = CharacterLevelEntry { hp: stat["hp"].as_i64().unwrap() as u32, atp: stat["atp"].as_i64().unwrap() as u32, mst: stat["mst"].as_i64().unwrap() as u32, evp: stat["evp"].as_i64().unwrap() as u32, dfp: stat["dfp"].as_i64().unwrap() as u32, ata: stat["ata"].as_i64().unwrap() as u32, lck: stat["lck"].as_i64().unwrap() as u32, exp: stat["xp"].as_i64().unwrap() as u32, } } table.insert(cl, statlist); } CharacterLevelTable { table, } } } impl CharacterLevelTable { pub fn get_level_from_exp(&self, ch_class: CharacterClass, exp: u32) -> u32 { if let Some(statlist) = self.table.get(&ch_class) { statlist .iter() .filter(|stat| { stat.exp <= exp }) .count() as u32 } else { 0 } } pub fn get_stats_from_exp(&self, ch_class: CharacterClass, exp: u32) -> (u32, CharacterStats) { if let Some(statlist) = self.table.get(&ch_class) { statlist .iter() .filter(|stat| { stat.exp <= exp }) .fold((0, CharacterStats::default()), |acc, &k| { (acc.0 + 1, CharacterStats { hp: acc.1.hp + k.hp as u16, atp: acc.1.atp + k.atp as u16, mst: acc.1.mst + k.mst as u16, evp: acc.1.evp + k.evp as u16, dfp: acc.1.dfp + k.dfp as u16, ata: acc.1.ata + k.ata as u16, lck: acc.1.lck + k.lck as u16, }) }) } else { (0, CharacterStats::default()) } } } #[cfg(test)] mod test { use super::*; #[test] fn test_stat_levels() { let table = CharacterLevelTable::default(); assert!(table.get_stats_from_exp(CharacterClass::FOmarl, 0) == (1, CharacterStats { hp: 20, atp: 13, mst: 53, evp: 35, dfp: 10, ata: 15, lck: 10 })); assert!(table.get_stats_from_exp(CharacterClass::FOmarl, 1 << 17) == (36, CharacterStats { hp: 125, atp: 114, mst: 219, evp: 182, dfp: 42, ata: 213, lck: 10 })); } #[test] fn test_levels() { let table = CharacterLevelTable::default(); assert!(table.get_level_from_exp(CharacterClass::FOmarl, 0) == 1); assert!(table.get_level_from_exp(CharacterClass::FOmarl, 3000) == 8); assert!(table.get_level_from_exp(CharacterClass::FOmarl, 3200) == 9); } }