use std::convert::{From, Into}; use std::collections::HashMap; use serde::{Serialize, Deserialize}; use libpso::packet::ship::{UpdateConfig, WriteInfoboard, KeyboardConfig, GamepadConfig}; use libpso::character::settings::{DEFAULT_PALETTE_CONFIG, DEFAULT_TECH_MENU, DEFAULT_KEYBOARD_CONFIG1, DEFAULT_KEYBOARD_CONFIG2, DEFAULT_KEYBOARD_CONFIG3, DEFAULT_KEYBOARD_CONFIG4, DEFAULT_GAMEPAD_CONFIG}; use crate::entity::item::tech::Technique; use crate::entity::account::UserAccountId; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, enum_utils::FromStr, derive_more::Display, Serialize, Deserialize, Default)] pub enum CharacterClass { #[default] HUmar, HUnewearl, HUcast, HUcaseal, RAmar, RAmarl, RAcast, RAcaseal, FOmar, FOmarl, FOnewm, FOnewearl, } // TODO: TryFrom impl From for CharacterClass { fn from(f: u8) -> CharacterClass { match f { 0 => CharacterClass::HUmar, 1 => CharacterClass::HUnewearl, 2 => CharacterClass::HUcast, 3 => CharacterClass::RAmar, 4 => CharacterClass::RAcast, 5 => CharacterClass::RAcaseal, 6 => CharacterClass::FOmarl, 7 => CharacterClass::FOnewm, 8 => CharacterClass::FOnewearl, 9 => CharacterClass::HUcaseal, 10 => CharacterClass::FOmar, 11 => CharacterClass::RAmarl, _ => panic!("unknown class") } } } impl From for u8 { fn from(other: CharacterClass) -> u8 { match other { CharacterClass::HUmar => 0, CharacterClass::HUnewearl => 1, CharacterClass::HUcast => 2, CharacterClass::RAmar => 3, CharacterClass::RAcast => 4, CharacterClass::RAcaseal => 5, CharacterClass::FOmarl => 6, CharacterClass::FOnewm => 7, CharacterClass::FOnewearl => 8, CharacterClass::HUcaseal => 9, CharacterClass::FOmar => 10, CharacterClass::RAmarl => 11, } } } impl CharacterClass { pub fn is_human(&self) -> bool { matches!(self, CharacterClass::HUmar | CharacterClass::RAmar | CharacterClass::RAmarl | CharacterClass::FOmar | CharacterClass::FOmarl) } pub fn is_newman(&self) -> bool { matches!(self, CharacterClass::HUnewearl | CharacterClass::FOnewm | CharacterClass::FOnewearl) } pub fn is_android(&self) -> bool { matches!(self, CharacterClass::HUcast | CharacterClass::HUcaseal | CharacterClass::RAcast | CharacterClass::RAcaseal) } } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, enum_utils::FromStr, derive_more::Display, Serialize, Deserialize, Default)] pub enum SectionID { #[default] Viridia, Greenill, Skyly, Bluefull, Purplenum, Pinkal, Redria, Oran, Yellowboze, Whitill, } impl From for SectionID { fn from(id: u8) -> SectionID { match id { 0 => SectionID::Viridia, 1 => SectionID::Greenill, 2 => SectionID::Skyly, 3 => SectionID::Bluefull, 4 => SectionID::Purplenum, 5 => SectionID::Pinkal, 6 => SectionID::Redria, 7 => SectionID::Oran, 8 => SectionID::Yellowboze, 9 => SectionID::Whitill, _ => panic!(), } } } impl From for u8 { fn from(other: SectionID) -> u8 { match other { SectionID::Viridia => 0, SectionID::Greenill => 1, SectionID::Skyly => 2, SectionID::Bluefull => 3, SectionID::Purplenum => 4, SectionID::Pinkal => 5, SectionID::Redria => 6, SectionID::Oran => 7, SectionID::Yellowboze => 8, SectionID::Whitill => 9, } } } #[derive(Clone, Debug, Default)] pub struct CharacterAppearance { pub costume: u16, pub skin: u16, pub face: u16, pub head: u16, pub hair: u16, pub hair_r: u16, pub hair_g: u16, pub hair_b: u16, pub prop_x: f32, pub prop_y: f32, } #[derive(Clone, Debug)] pub struct TechLevel(pub u8); #[derive(Clone, Debug, Default)] pub struct CharacterTechniques { pub techs: HashMap } impl CharacterTechniques { pub fn set_tech(&mut self, tech: Technique, level: TechLevel) { self.techs.insert(tech, TechLevel(level.0 - 1)); } // from_bytes pub fn as_bytes(&self) -> [u8; 20] { self.techs.iter() .fold([0xFF; 20], |mut techlist, (tech, level)| { let index = tech.as_value(); techlist[index as usize] = level.0; techlist }) } } #[derive(Debug, Clone)] pub struct CharacterConfig { pub raw_data: [u8; 0xE8], } impl Default for CharacterConfig { fn default() -> CharacterConfig { CharacterConfig { raw_data: DEFAULT_PALETTE_CONFIG, } } } impl CharacterConfig { pub fn update(&mut self, new_config: &UpdateConfig) { self.raw_data = new_config.config; } pub fn as_bytes(&self) -> [u8; 0xE8] { self.raw_data } } #[derive(Debug, Clone)] pub struct CharacterInfoboard { pub board: [u16; 172], } impl Default for CharacterInfoboard { fn default() -> CharacterInfoboard { CharacterInfoboard { board: [0; 172] } } } impl CharacterInfoboard { pub fn as_bytes(&self) -> [u16; 172] { self.board } pub fn update_infoboard(&mut self, new_board: &WriteInfoboard) { self.board = libpso::utf8_to_utf16_array!(new_board.message, 172); } } #[derive(Debug, Clone, Default)] pub struct CharacterGuildCard { pub description: String, } #[derive(Debug, Clone)] pub struct CharacterTechMenu { pub tech_menu: [u8; 40], } impl Default for CharacterTechMenu { fn default() -> CharacterTechMenu { CharacterTechMenu { tech_menu: DEFAULT_TECH_MENU, } } } impl CharacterTechMenu { pub fn as_bytes(&self) -> [u8; 40] { self.tech_menu } } #[derive(Clone, Default, Debug)] pub struct CharacterMaterials { pub power: u32, pub mind: u32, pub def: u32, pub evade: u32, pub luck: u32, pub hp: u32, pub tp: u32, } #[derive(Clone, Debug)] pub struct CharacterKeyboardConfig { pub keyboard_config: [u8; 0x16C], } impl Default for CharacterKeyboardConfig { fn default() -> CharacterKeyboardConfig { CharacterKeyboardConfig { keyboard_config: DEFAULT_KEYBOARD_CONFIG1, } } } impl CharacterKeyboardConfig { fn new(preset: usize) -> CharacterKeyboardConfig { match preset { 1 => { CharacterKeyboardConfig { keyboard_config: DEFAULT_KEYBOARD_CONFIG1, } }, 2 => { CharacterKeyboardConfig { keyboard_config: DEFAULT_KEYBOARD_CONFIG2, } }, 3 => { CharacterKeyboardConfig { keyboard_config: DEFAULT_KEYBOARD_CONFIG3, } }, 4 => { CharacterKeyboardConfig { keyboard_config: DEFAULT_KEYBOARD_CONFIG4, } }, _ => { CharacterKeyboardConfig { keyboard_config: DEFAULT_KEYBOARD_CONFIG1, } }, } } pub fn update(&mut self, new_config: &KeyboardConfig) { self.keyboard_config = new_config.keyboard_config; } pub fn as_bytes(&self) -> [u8; 0x16C] { self.keyboard_config } } #[derive(Clone, Debug)] pub struct CharacterGamepadConfig { pub gamepad_config: [u8; 0x38], } impl Default for CharacterGamepadConfig { fn default() -> CharacterGamepadConfig { CharacterGamepadConfig { gamepad_config: DEFAULT_GAMEPAD_CONFIG, } } } impl CharacterGamepadConfig { pub fn update(&mut self, new_config: &GamepadConfig) { self.gamepad_config = new_config.gamepad_config; } pub fn as_bytes(&self) -> [u8; 0x38] { self.gamepad_config } } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default, derive_more::Display)] pub struct CharacterEntityId(pub u32); #[derive(Clone)] pub struct NewCharacterEntity { pub user_id: UserAccountId, pub slot: u32, pub name: String, pub exp: u32, pub char_class: CharacterClass, pub section_id: SectionID, pub appearance: CharacterAppearance, pub techs: CharacterTechniques, pub config: CharacterConfig, pub info_board: CharacterInfoboard, pub guildcard: CharacterGuildCard, pub materials: CharacterMaterials, pub tech_menu: CharacterTechMenu, pub option_flags: u32, pub keyboard_config: CharacterKeyboardConfig, pub gamepad_config: CharacterGamepadConfig, } impl NewCharacterEntity { pub fn new(user: UserAccountId, keyboard_config_preset: usize,) -> NewCharacterEntity { NewCharacterEntity { user_id: user, slot: 0, name: "".into(), exp: 0, char_class: CharacterClass::HUmar, section_id: SectionID::Viridia, appearance: CharacterAppearance::default(), techs: CharacterTechniques::default(), config: CharacterConfig::default(), info_board: CharacterInfoboard::default(), guildcard: CharacterGuildCard::default(), materials: CharacterMaterials::default(), tech_menu: CharacterTechMenu::default(), option_flags: 0, keyboard_config: CharacterKeyboardConfig::new(keyboard_config_preset), gamepad_config: CharacterGamepadConfig::default(), } } } #[derive(Clone, Default, Debug)] pub struct CharacterEntity { pub id: CharacterEntityId, pub user_id: UserAccountId, pub slot: u32, pub name: String, pub exp: u32, pub char_class: CharacterClass, pub section_id: SectionID, pub appearance: CharacterAppearance, pub techs: CharacterTechniques, pub config: CharacterConfig, pub info_board: CharacterInfoboard, pub guildcard: CharacterGuildCard, pub materials: CharacterMaterials, pub tech_menu: CharacterTechMenu, pub option_flags: u32, pub keyboard_config: CharacterKeyboardConfig, pub gamepad_config: CharacterGamepadConfig, }