use crate::FixedLengthWideString;
use bilge::prelude::*;
use binrw::{BinRead, BinWrite, binrw};
use paste::paste;
use vee_parse_macros::bitfield;
macro_rules! rvl_and_ntr {
( $(#[$attr:meta]) * $vis:vis struct $struct_name:ident { $($field_vis:vis $field_name:ident: $field_type:ty),* $(,)? }) => {
paste! {
#[binrw]
#[brw(big)]
$(#[$attr])*
$vis struct [<Rvl $struct_name>] {
$($field_vis $field_name: $field_type),*
}
#[binrw]
#[brw(little)]
$(#[$attr])*
$vis struct [<Ntr $struct_name>] {
$($field_vis $field_name: $field_type),*
}
}
};
}
#[bitsize(4)]
#[repr(u8)]
#[derive(FromBits, Debug, PartialEq)]
pub enum FavoriteColor {
Red = 0,
Orange = 1,
Yellow = 2,
YellowGreen = 3,
Green = 4,
Blue = 5,
SkyBlue = 6,
Pink = 7,
Purple = 8,
Brown = 9,
White = 10,
Black = 11,
#[fallback]
Invalid(u4),
}
#[bitsize(1)]
#[derive(FromBits, Debug, PartialEq)]
pub enum Gender {
Male,
Female,
}
#[bitfield(16)]
pub struct PersonalInfoField {
pub padding: u1,
pub gender: Gender,
pub birth_month: u4,
pub birth_day: u5,
pub favorite_color: FavoriteColor,
pub favorite: bool,
}
#[bitfield(16)]
pub struct FaceField {
pub face_type: u3,
pub face_color: u3,
pub face_tex: u4,
pub padding2: u3,
pub localonly: u1,
pub type_: u2,
}
#[bitfield(16)]
pub struct HairField {
pub hair_type: u7,
pub hair_color: u3,
pub hair_flip: u1,
pub padding3: u5,
}
#[bitfield(32)]
pub struct EyebrowField {
pub eyebrow_type: u5,
pub eyebrow_rotate: u5,
pub padding4: u6,
pub eyebrow_color: u3,
pub eyebrow_scale: u4,
pub eyebrow_y: u5,
pub eyebrow_x: u4,
}
#[bitfield(32)]
pub struct EyeField {
pub eye_type: u6,
pub eye_rotate: u5,
pub eye_y: u5,
pub eye_color: u3,
pub eye_scale: u4,
pub eye_x: u4,
pub padding5: u5,
}
#[bitfield(16)]
pub struct NoseField {
pub nose_type: u4,
pub nose_scale: u4,
pub nose_y: u5,
pub padding6: u3,
}
#[bitfield(16)]
pub struct MouthField {
pub mouth_type: u5,
pub mouth_color: u2,
pub mouth_scale: u4,
pub mouth_y: u5,
}
#[bitfield(16)]
pub struct GlassField {
pub glass_type: u4,
pub glass_color: u3,
pub glass_scale: u4,
pub glass_y: u5,
}
#[bitfield(16)]
pub struct FaceHairField {
pub mustache_type: u2,
pub beard_type: u2,
pub beard_color: u3,
pub beard_scale: u4,
pub beard_y: u5,
}
#[bitfield(16)]
pub struct MoleField {
pub mole_type: u1,
pub mole_scale: u4,
pub mole_y: u5,
pub mole_x: u5,
pub padding8: u1,
}
#[bitfield(64)]
pub struct CreateId {
pub flags: CreateIdFlags,
pub create_date_offset: u28,
pub addr_low: [u8; 4],
}
impl CreateId {
pub fn create_date_timestamp(&self) -> u32 {
const JAN_1_2006: u32 = 1136073600;
let offset = self.create_date_offset().as_u32();
(offset * 4) + JAN_1_2006
}
}
#[bitsize(2)]
#[derive(FromBits, Debug, PartialEq)]
pub enum CreateIdPlatform {
Rvl = 0b00,
Ctr = 0b01,
Ntr = 0b10,
Etc = 0b11,
}
#[bitfield(4)]
pub struct CreateIdFlags {
pub normal: bool,
pub field_1: bool,
pub temporary: bool,
pub field_3: bool,
}
impl CreateIdFlags {
pub fn platform(&self) -> CreateIdPlatform {
let bits = u2::from_u8(match (self.field_1(), self.field_3()) {
(false, false) => 0b00_u8,
(true, false) => 0b10,
(false, true) => 0b01,
(true, true) => 0b11,
});
CreateIdPlatform::from(bits)
}
}
rvl_and_ntr! {
#[derive(Debug)]
pub struct CharData {
pub personal_info: PersonalInfoField,
pub name: FixedLengthWideString<10>,
pub height: u8,
pub build: u8,
pub create_id: CreateId,
pub face: FaceField,
pub hair: HairField,
pub eyebrow: EyebrowField,
pub eye: EyeField,
pub nose: NoseField,
pub mouth: MouthField,
pub glass: GlassField,
pub face_hair: FaceHairField,
pub mole: MoleField,
pub creator_name: FixedLengthWideString<10>,
}
}
#[binrw]
#[brw(big)]
#[derive(Debug)]
pub struct RvlStoreData {
pub data: RvlCharData,
pub checksum: u16,
}
#[binrw]
#[brw(little)]
#[derive(Debug)]
pub struct NtrStoreData {
pub data: NtrCharData,
pub checksum: u16,
}