// TODO: ch_class to CharacterClass enum // TODO: section_id to SectionId enum // TODO: techniques to enum use psopacket::PSOPacketData; use crate::{PSOPacketData, PacketParseError}; #[repr(u32)] #[derive(Copy, Clone, Hash, PartialEq, Eq)] pub enum Class { HUmar, HUnewearl, HUcast, HUcaseal, RAmar, RAmarl, RAcast, RAcaseal, FOmar, FOmarl, FOnewm, FOnewearl, } impl std::convert::From for Class { fn from(f: u8) -> Class { match f { 0 => Class::HUmar, 1 => Class::HUnewearl, 2 => Class::HUcast, 3 => Class::RAmar, 4 => Class::RAcast, 5 => Class::RAcaseal, 6 => Class::FOmarl, 7 => Class::FOnewm, 8 => Class::FOnewearl, 9 => Class::HUcaseal, 10 => Class::RAmarl, 11 => Class::FOmar, _ => panic!("unknown class") } } } pub enum SectionID { Viridia, Greenill, Skyly, Bluefull, Purplenum, Pinkal, Redria, Oran, Yellowboze, Whitill, } #[derive(PSOPacketData, Copy, Clone)] #[repr(C)] pub struct Character { pub atp: u16, pub mst: u16, pub evp: u16, pub hp: u16, pub dfp: u16, pub ata: u16, pub lck: u16, pub _unknown1: u16, pub _unknown2: [u32; 2], pub level: u32, pub exp: u32, pub meseta: u32, pub guildcard: [u8; 16], pub _unknown3: [u32; 2], pub name_color: u32, pub model: u8, pub _unused: [u8; 11], pub play_time: u32, pub name_color_checksum: u32, pub section_id: u8, pub ch_class: u8, pub v2flags: u8, pub version: u8, pub v1flags: u32, 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, pub name: [u16; 16], pub config: [u8; 0xE8], pub techniques: [u8; 0x14], } impl Character { pub fn as_select_screen(self) -> SelectScreenCharacter { SelectScreenCharacter { exp: self.exp, level: self.level, guildcard: self.guildcard, _unknown: self._unknown3, name_color: self.name_color, model: self.model, _unused: [0; 15], name_color_checksum: self.name_color_checksum, section_id: self.section_id, ch_class: self.ch_class, v2flags: self.v2flags, version: self.version, v1flags: self.v1flags, costume: self.costume, skin: self.skin, face: self.face, head: self.head, hair: self.hair, hair_r: self.hair_r, hair_g: self.hair_g, hair_b: self.hair_b, prop_x: self.prop_x, prop_y: self.prop_y, name: self.name, play_time: self.play_time, } } } impl std::default::Default for Character { fn default() -> Character { Character::from_bytes(&mut std::io::Cursor::new([0; 0x190].to_vec())).unwrap() } } #[derive(Copy, Clone, Debug, PartialEq, Default)] #[repr(C)] pub struct SelectScreenCharacter { pub exp: u32, pub level: u32, pub guildcard: [u8; 16], pub _unknown: [u32; 2], pub name_color: u32, pub model: u8, pub _unused: [u8; 15], pub name_color_checksum: u32, pub section_id: u8, pub ch_class: u8, pub v2flags: u8, pub version: u8, pub v1flags: u32, 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, pub name: [u16; 16], pub play_time: u32, } impl SelectScreenCharacter { pub const SIZE: usize = 0x7C; pub fn from_le_bytes(bytes: [u8; 0x7C]) -> Result { unsafe { Ok(std::mem::transmute(bytes)) } } pub fn to_le_bytes(&self) -> [u8; 0x7C] { unsafe { std::mem::transmute(*self) } } pub fn as_character(&self) -> Character { Character { exp: self.exp, level: self.level, guildcard: self.guildcard, _unknown3: self._unknown, name_color: self.name_color, model: self.model, name_color_checksum: self.name_color_checksum, section_id: self.section_id, ch_class: self.ch_class, v2flags: self.v2flags, version: self.version, v1flags: self.v1flags, costume: self.costume, skin: self.skin, face: self.face, head: self.head, hair: self.hair, hair_r: self.hair_r, hair_g: self.hair_g, hair_b: self.hair_b, prop_x: self.prop_x, prop_y: self.prop_y, name: self.name, play_time: self.play_time, _unknown1: 0, _unknown2: [0; 2], _unused: [0; 11], atp: 0, mst: 0, evp: 0, hp: 0, dfp: 0, ata: 0, lck: 0, config: [0; 0xE8], meseta: 0, techniques: [0; 0x14], } } } #[derive(PSOPacketData, Default, Copy, Clone)] pub struct InventoryItem { pub equipped: u16, pub tech: u8, pub material_count: u8, // in items 7 - 11 material usage values are stored here pub flags: u32, pub data1: [u8; 12], pub item_id: u32, pub data2: [u8; 4], } #[derive(PSOPacketData, Default, Copy, Clone)] pub struct BankItem { pub data1: [u8; 12], pub item_id: u32, pub data2: [u8; 4], pub amount: u16, pub flags: u16, } #[derive(PSOPacketData, Default, Copy, Clone)] pub struct Inventory { pub item_count: u8, pub hp_mats_used: u8, pub tp_mats_used: u8, pub language: u8, pub items: [InventoryItem; 30], } #[derive(PSOPacketData, Copy, Clone)] pub struct Bank { pub item_count: u32, pub meseta: u32, pub items: [BankItem; 200], } impl std::default::Default for Bank { fn default() -> Bank { Bank::from_bytes(&mut std::io::Cursor::new([0; 0x12C8].to_vec())).unwrap() } } #[derive(PSOPacketData, Copy, Clone)] pub struct KeyTeamConfig { pub _unknown: [u8; 0x114], pub keyboard_config: [u8; 0x16C], pub joystick_config: [u8; 0x38], pub guildcard: u32, pub team_id: u32, pub team_info: [u32; 2], pub team_priv: u16, pub _reserved: u16, pub team_name: [u16; 16], pub team_flag: [u8; 2048], //pub team_rewards: [u32; 2], pub team_rewards: u32, } impl std::default::Default for KeyTeamConfig { fn default() -> KeyTeamConfig { KeyTeamConfig::from_bytes(&mut std::io::Cursor::new([0; 0xAF4].to_vec())).unwrap() } } #[derive(PSOPacketData, Copy, Clone)] pub struct Player { pub inventory: Inventory, pub character: Character, pub c_rank: [u8; 0x174], pub info_board: [u16; 172], pub blacklist: [u32; 30], pub autoreply: [u16; 172], } #[derive(PSOPacketData, Copy, Clone)] pub struct FullCharacter { pub inventory: Inventory, pub character: Character, pub _unknown1: [u8; 16], pub option_flags: u32, pub quest_data1: [u8; 520], pub bank: Bank, pub guildcard: u32, pub name: [u16; 24], pub team_name: [u16; 16], pub guildcard_desc: [u16; 88], pub _reserved1: u8, pub _reserved2: u8, pub section_id: u8, pub char_class: u8, pub _unknown2: u32, pub symbol_chats: [u8; 0x4E0], pub shortcuts: [u8; 2624], pub autoreply: [u16; 172], pub info_board: [u16; 172], pub _unknown3: [u8; 28], pub challenge_data: [u8; 320], pub tech_menu: [u8; 40], pub _unknown4: [u8; 44], pub quest_data2: [u8; 88], pub key_team_config: KeyTeamConfig, } impl std::default::Default for FullCharacter { fn default() -> FullCharacter { FullCharacter::from_bytes(&mut std::io::Cursor::new([0; 0x3998].to_vec())).unwrap() } } #[derive(PSOPacketData, Copy, Clone)] pub struct DBChar { pub inventory: Inventory, pub character: Character, pub quest_data1: [u8; 520], pub bank: Bank, pub guildcard_desc: [u16; 88], pub autoreply: [u16; 172], pub info_board: [u16; 172], pub challenge_data: [u8; 320], pub tech_menu: [u8; 40], pub quest_data2: [u8; 88], } #[derive(PSOPacketData, Copy, Clone)] pub struct DBOpts { pub blocked: [u32; 30], pub keyboard_config: [u8; 0x16C], pub joystick_config: [u8; 0x38], pub option_flags: u32, pub shortcuts: [u8; 0xA40], pub symbol_chats: [u8; 0x4E0], pub team_name: [u16; 16], }