diff --git a/enemize/src/bosses/mod.rs b/enemize/src/bosses/mod.rs index 872412d..a5f02c7 100644 --- a/enemize/src/bosses/mod.rs +++ b/enemize/src/bosses/mod.rs @@ -1,9 +1,12 @@ use std::marker::PhantomData; +use serde::{Deserialize, Serialize}; + use crate::InvalidEnumError; -#[derive(Debug)] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] #[repr(u8)] +#[serde(into = "u8", try_from = "u8")] pub enum BossType { Kholdstare, Moldorm, @@ -22,6 +25,29 @@ pub enum BossType { NoBoss = 255, } +impl From for u8 { + fn from(t: BossType) -> u8 { + use BossType::*; + + match t { + Kholdstare => 0, + Moldorm => 1, + Mothula => 2, + Vitreous => 3, + Helmasaur => 4, + Armos => 5, + Lanmola => 6, + Blind => 7, + Arrghus => 8, + Trinexx => 9, + Agahnim => 10, + Agahnim2 => 11, + Ganon => 12, + NoBoss => 255, + } + } +} + impl TryFrom for BossType { type Error = InvalidEnumError; diff --git a/enemize/src/option_flags.rs b/enemize/src/option_flags.rs index 2170c52..e0fca4e 100644 --- a/enemize/src/option_flags.rs +++ b/enemize/src/option_flags.rs @@ -3,10 +3,12 @@ use std::fmt; use std::marker::PhantomData; use std::path::PathBuf; +use serde::{Deserialize, Serialize}; + use crate::bosses::BossType; use crate::InvalidEnumError; -#[derive(Debug, Default)] +#[derive(Debug, Default, Deserialize, Serialize)] pub struct ManualBosses { pub eastern_palace: String, pub desert_palace: String, @@ -26,7 +28,8 @@ pub struct ManualBosses { pub ganon: String, } -#[derive(Debug)] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(into = "u8", try_from = "u8")] pub enum RandomizeEnemiesType { Basic, Normal, @@ -35,6 +38,20 @@ pub enum RandomizeEnemiesType { Insanity, } +impl From for u8 { + fn from(t: RandomizeEnemiesType) -> u8 { + use RandomizeEnemiesType::*; + + match t { + Basic => 0, + Normal => 1, + Hard => 2, + Chaos => 3, + Insanity => 4, + } + } +} + impl TryFrom for RandomizeEnemiesType { type Error = InvalidEnumError; @@ -50,7 +67,8 @@ impl TryFrom for RandomizeEnemiesType { } } -#[derive(Debug)] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(into = "u8", try_from = "u8")] pub enum RandomizeEnemyHpType { Easy, Medium, @@ -58,6 +76,19 @@ pub enum RandomizeEnemyHpType { Patty } +impl From for u8 { + fn from(t: RandomizeEnemyHpType) -> u8 { + use RandomizeEnemyHpType::*; + + match t { + Easy => 0, + Medium => 1, + Hard => 2, + Patty => 3, + } + } +} + impl TryFrom for RandomizeEnemyHpType { type Error = InvalidEnumError; @@ -72,13 +103,26 @@ impl TryFrom for RandomizeEnemyHpType { } } -#[derive(Debug)] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(into = "u8", try_from = "u8")] pub enum RandomizeBossesType { Basic, Normal, Chaos } +impl From for u8 { + fn from(t: RandomizeBossesType) -> u8 { + use RandomizeBossesType::*; + + match t { + Basic => 0, + Normal => 1, + Chaos => 2, + } + } +} + impl TryFrom for RandomizeBossesType { type Error = InvalidEnumError; @@ -92,11 +136,18 @@ impl TryFrom for RandomizeBossesType { } } -#[derive(Debug)] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(into = "u8", try_from = "u8")] pub enum SwordType { Normal } +impl From for u8 { + fn from(_t: SwordType) -> u8 { + 0 + } +} + impl TryFrom for SwordType { type Error = InvalidEnumError; @@ -108,11 +159,18 @@ impl TryFrom for SwordType { } } -#[derive(Debug)] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(into = "u8", try_from = "u8")] pub enum ShieldType { Normal } +impl From for u8 { + fn from(_t: ShieldType) -> u8 { + 0 + } +} + impl TryFrom for ShieldType { type Error = InvalidEnumError; @@ -124,7 +182,8 @@ impl TryFrom for ShieldType { } } -#[derive(Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[serde(into = "u8", try_from = "u8")] pub enum AbsorbableType { Heart, GreenRupee, @@ -142,6 +201,29 @@ pub enum AbsorbableType { BigKey, } +impl From for u8 { + fn from(t: AbsorbableType) -> u8 { + use AbsorbableType::*; + + match t { + Heart => 0, + GreenRupee => 1, + BlueRupee => 2, + RedRupee => 3, + Bomb1 => 4, + Bomb4 => 5, + Bomb8 => 6, + SmallMagic => 7, + FullMagic => 8, + Arrow5 => 9, + Arrow10 => 10, + Fairy => 11, + Key => 12, + BigKey => 13, + } + } +} + impl TryFrom for AbsorbableType { type Error = InvalidEnumError; @@ -150,16 +232,17 @@ impl TryFrom for AbsorbableType { 0 => Ok(Self::Heart), 1 => Ok(Self::GreenRupee), 2 => Ok(Self::BlueRupee), - 3 => Ok(Self::Bomb1), - 4 => Ok(Self::Bomb4), - 5 => Ok(Self::Bomb8), - 6 => Ok(Self::SmallMagic), - 7 => Ok(Self::FullMagic), - 8 => Ok(Self::Arrow5), - 9 => Ok(Self::Arrow10), - 10 => Ok(Self::Fairy), - 11 => Ok(Self::Key), - 12 => Ok(Self::BigKey), + 3 => Ok(Self::RedRupee), + 4 => Ok(Self::Bomb1), + 5 => Ok(Self::Bomb4), + 6 => Ok(Self::Bomb8), + 7 => Ok(Self::SmallMagic), + 8 => Ok(Self::FullMagic), + 9 => Ok(Self::Arrow5), + 10 => Ok(Self::Arrow10), + 11 => Ok(Self::Fairy), + 12 => Ok(Self::Key), + 13 => Ok(Self::BigKey), _ => Err(InvalidEnumError(PhantomData)) } } @@ -190,7 +273,8 @@ impl fmt::Display for AbsorbableType { } } -#[derive(Debug)] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(into = "u8", try_from = "u8")] pub enum HeartBeepSpeed { Normal, Half, @@ -204,6 +288,19 @@ impl Default for HeartBeepSpeed { } } +impl From for u8 { + fn from(speed: HeartBeepSpeed) -> u8 { + use HeartBeepSpeed::*; + + match speed { + Normal => 0, + Half => 1, + Quarter => 2, + Off => 3, + } + } +} + impl TryFrom for HeartBeepSpeed { type Error = InvalidEnumError; @@ -218,7 +315,7 @@ impl TryFrom for HeartBeepSpeed { } } -#[derive(Debug)] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub enum BeeLevel { Level1, Level2, @@ -241,6 +338,19 @@ impl fmt::Display for BeeLevel { } } +impl From for u8 { + fn from(level: BeeLevel) -> u8 { + use BeeLevel::*; + + match level { + Level1 => 0, + Level2 => 1, + Level3 => 2, + Level4 => 3, + } + } +} + impl TryFrom for BeeLevel { type Error = InvalidEnumError; @@ -255,7 +365,7 @@ impl TryFrom for BeeLevel { } } -#[derive(Debug)] +#[derive(Debug, Deserialize, Serialize)] pub struct OptionFlags { pub randomize_enemies: bool, pub randomize_enemies_type: RandomizeEnemiesType, @@ -341,16 +451,17 @@ impl OptionFlags { absorbable_types.insert(AbsorbableType::Heart, bytes[10] != 0); absorbable_types.insert(AbsorbableType::GreenRupee, bytes[11] != 0); absorbable_types.insert(AbsorbableType::BlueRupee, bytes[12] != 0); - absorbable_types.insert(AbsorbableType::Bomb1, bytes[13] != 0); - absorbable_types.insert(AbsorbableType::Bomb4, bytes[14] != 0); - absorbable_types.insert(AbsorbableType::Bomb8, bytes[15] != 0); - absorbable_types.insert(AbsorbableType::SmallMagic, bytes[16] != 0); - absorbable_types.insert(AbsorbableType::FullMagic, bytes[17] != 0); - absorbable_types.insert(AbsorbableType::Arrow5, bytes[18] != 0); - absorbable_types.insert(AbsorbableType::Arrow10, bytes[19] != 0); - absorbable_types.insert(AbsorbableType::Fairy, bytes[20] != 0); - absorbable_types.insert(AbsorbableType::Key, bytes[21] != 0); - absorbable_types.insert(AbsorbableType::BigKey, bytes[22] != 0); + absorbable_types.insert(AbsorbableType::RedRupee, bytes[13] != 0); + absorbable_types.insert(AbsorbableType::Bomb1, bytes[14] != 0); + absorbable_types.insert(AbsorbableType::Bomb4, bytes[15] != 0); + absorbable_types.insert(AbsorbableType::Bomb8, bytes[16] != 0); + absorbable_types.insert(AbsorbableType::SmallMagic, bytes[17] != 0); + absorbable_types.insert(AbsorbableType::FullMagic, bytes[18] != 0); + absorbable_types.insert(AbsorbableType::Arrow5, bytes[19] != 0); + absorbable_types.insert(AbsorbableType::Arrow10, bytes[20] != 0); + absorbable_types.insert(AbsorbableType::Fairy, bytes[21] != 0); + absorbable_types.insert(AbsorbableType::Key, bytes[21] != 1); + absorbable_types.insert(AbsorbableType::BigKey, bytes[23] != 0); Ok(OptionFlags { randomize_enemies: bytes[0] != 0, @@ -364,55 +475,55 @@ impl OptionFlags { enemies_absorbable: bytes[8] != 0, absorbable_spawn_rate: bytes[9], absorbable_types, - boss_madness: bytes[23] != 0, - randomize_bosses: bytes[24] != 0, - randomize_bosses_type: bytes[25].try_into()?, - randomize_boss_health: bytes[26] != 0, - randomize_boss_health_min_amount: bytes[27], - randomize_boss_health_max_amount: bytes[28], - randomize_boss_damage: bytes[29] != 0, - randomize_boss_damage_min_amount: bytes[30], - randomize_boss_damage_max_amount: bytes[31], - randomize_boss_behavior: bytes[32] != 0, - randomize_dungeon_palettes: bytes[33] != 0, - set_blackout_mode: bytes[34] != 0, - randomize_overworld_palettes: bytes[35] != 0, - randomize_sprite_palettes: bytes[36] != 0, - set_advanced_sprite_palettes: bytes[37] != 0, - puke_mode: bytes[38] != 0, - negative_mode: bytes[39] != 0, - grayscale_mode: bytes[40] != 0, - generate_spoilers: bytes[41] != 0, - randomize_link_sprite_palette: bytes[42] != 0, - randomize_pots: bytes[43] != 0, - shuffle_music: bytes[44] != 0, - bootleg_magic: bytes[45] != 0, - debug_mode: bytes[46] != 0, - custom_bosses: bytes[47] != 0, - heart_beep_speed: bytes[48].try_into()?, - alternate_gfx: bytes[49] != 0, - // Skip byte 50 (shield_graphics) - shuffle_enemy_damage_groups: bytes[51] != 0, - enemy_damage_chaos_mode: bytes[52] != 0, - // Skip byte 53 (sword_graphics) - bee_mizer: bytes[54] != 0, - bees_level: bytes[55].try_into()?, - debug_force_enemy: bytes[56] != 0, - debug_force_enemy_id: bytes[57], - debug_force_boss: bytes[58] != 0, - debug_force_boss_id: bytes[59].try_into()?, - debug_open_shutter_doors: bytes[60] != 0, - debug_force_enemy_damage_zero: bytes[61] != 0, - debug_show_room_id_in_rupee_counter: bytes[62] != 0, - o_h_k_o: bytes[63] != 0, - randomize_tile_trap_pattern: bytes[64] != 0, - randomize_tile_trap_floor_tile: bytes[65] != 0, - allow_killable_thief: bytes[66] != 0, - randomize_sprite_on_hit: bytes[67] != 0, - hero_mode: bytes[68] != 0, - increase_brightness: bytes[69] != 0, - mute_music_enable_msu_1: bytes[70] != 0, - agahnim_bounce_balls: bytes[71] != 0, + boss_madness: bytes[24] != 0, + randomize_bosses: bytes[25] != 0, + randomize_bosses_type: bytes[26].try_into()?, + randomize_boss_health: bytes[27] != 0, + randomize_boss_health_min_amount: bytes[28], + randomize_boss_health_max_amount: bytes[29], + randomize_boss_damage: bytes[30] != 0, + randomize_boss_damage_min_amount: bytes[31], + randomize_boss_damage_max_amount: bytes[32], + randomize_boss_behavior: bytes[33] != 0, + randomize_dungeon_palettes: bytes[34] != 0, + set_blackout_mode: bytes[35] != 0, + randomize_overworld_palettes: bytes[36] != 0, + randomize_sprite_palettes: bytes[37] != 0, + set_advanced_sprite_palettes: bytes[38] != 0, + puke_mode: bytes[39] != 0, + negative_mode: bytes[40] != 0, + grayscale_mode: bytes[41] != 0, + generate_spoilers: bytes[42] != 0, + randomize_link_sprite_palette: bytes[43] != 0, + randomize_pots: bytes[44] != 0, + shuffle_music: bytes[45] != 0, + bootleg_magic: bytes[46] != 0, + debug_mode: bytes[47] != 0, + custom_bosses: bytes[48] != 0, + heart_beep_speed: bytes[49].try_into()?, + alternate_gfx: bytes[50] != 0, + // Skip byte 51 (shield_graphics) + shuffle_enemy_damage_groups: bytes[52] != 0, + enemy_damage_chaos_mode: bytes[53] != 0, + // Skip byte 54 (sword_graphics) + bee_mizer: bytes[55] != 0, + bees_level: bytes[56].try_into()?, + debug_force_enemy: bytes[57] != 0, + debug_force_enemy_id: bytes[58], + debug_force_boss: bytes[59] != 0, + debug_force_boss_id: bytes[60].try_into()?, + debug_open_shutter_doors: bytes[61] != 0, + debug_force_enemy_damage_zero: bytes[62] != 0, + debug_show_room_id_in_rupee_counter: bytes[63] != 0, + o_h_k_o: bytes[64] != 0, + randomize_tile_trap_pattern: bytes[65] != 0, + randomize_tile_trap_floor_tile: bytes[66] != 0, + allow_killable_thief: bytes[67] != 0, + randomize_sprite_on_hit: bytes[68] != 0, + hero_mode: bytes[69] != 0, + increase_brightness: bytes[70] != 0, + mute_music_enable_msu_1: bytes[71] != 0, + agahnim_bounce_balls: bytes[72] != 0, ..Default::default() }) }