aboutsummaryrefslogtreecommitdiff
path: root/src/gamedata.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/gamedata.rs')
-rw-r--r--src/gamedata.rs149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/gamedata.rs b/src/gamedata.rs
new file mode 100644
index 0000000..c56af13
--- /dev/null
+++ b/src/gamedata.rs
@@ -0,0 +1,149 @@
+//! This module contains some low-level game data, such as different boss IDs.
+use std::{fmt, str::FromStr};
+use num_derive::FromPrimitive;
+
+/// Enum containing all bosses with their IDs.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, FromPrimitive)]
+pub enum Boss {
+ // Wing 1
+ ValeGuardian = 0x3C4E,
+ Gorseval = 0x3C45,
+ Sabetha = 0x3C0F,
+
+ // Wing 2
+ Slothasor = 0x3EFB,
+ Matthias = 0x3EF3,
+
+ // Wing 3
+ KeepConstruct = 0x3F6B,
+ /// Xera ID for phase 1.
+ ///
+ /// This is only half of Xera's ID, as there will be a second agent for the
+ /// second phase. This agent will have another ID, see
+ /// [`XERA_PHASE2_ID`](constant.XERA_PHASE2_ID.html).
+ Xera = 0x3F76,
+
+ // Wing 4
+ Cairn = 0x432A,
+ MursaatOverseer = 0x4314,
+ Samarog = 0x4324,
+ Deimos = 0x4302,
+
+ // Wing 5
+ SoullessHorror = 0x4D37,
+ Dhuum = 0x4BFA,
+
+ // Wing 6
+ ConjuredAmalgamate = 0xABC6,
+ LargosTwins = 0x5271,
+ Qadim = 0x51C6,
+
+ // Wing 7
+ CardinalAdina = 0x55F6,
+ CardinalSabir = 0x55CC,
+ QadimThePeerless = 0x55F0,
+
+ // 100 CM
+ Skorvald = 0x44E0,
+ Artsariiv = 0x461D,
+ Arkk = 0x455F,
+
+ // 99 CM
+ MAMA = 0x427D,
+ Siax = 0x4284,
+ Ensolyss = 0x4234,
+
+ // Strike missions
+ IcebroodConstruct = 0x568A,
+ VoiceOfTheFallen = 0x5747,
+ FraenirOfJormag = 0x57DC,
+ Boneskinner = 0x57F9,
+ WhisperOfJormag = 0x58B7,
+}
+
+
+/// Error for when converting a string to the boss fails.
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct ParseBossError(String);
+
+
+impl fmt::Display for ParseBossError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Invalid boss identifier: {}", self.0)
+ }
+}
+
+
+impl FromStr for Boss {
+ type Err = ParseBossError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let lower = s.to_lowercase();
+ match &lower as &str {
+ "vg" | "vale guardian" => Ok(Boss::ValeGuardian),
+ "gorse" | "gorseval" => Ok(Boss::Gorseval),
+ "sab" | "sabetha" => Ok(Boss::Sabetha),
+
+ "sloth" | "slothasor" => Ok(Boss::Slothasor),
+ "matthias" => Ok(Boss::Matthias),
+
+ "kc" | "keep construct" => Ok(Boss::KeepConstruct),
+ "xera" => Ok(Boss::Xera),
+
+ "cairn" => Ok(Boss::Cairn),
+ "mo" | "mursaat overseer" => Ok(Boss::MursaatOverseer),
+ "sam" | "sama" | "samarog" => Ok(Boss::Samarog),
+ "deimos" => Ok(Boss::Deimos),
+
+ "desmina" | "sh" => Ok(Boss::SoullessHorror),
+ "dhuum" => Ok(Boss::Dhuum),
+
+ "ca" | "conjured almagamate" => Ok(Boss::ConjuredAmalgamate),
+ "largos" | "twins" => Ok(Boss::LargosTwins),
+ "qadim" => Ok(Boss::Qadim),
+
+ "adina" | "cardinal adina" => Ok(Boss::CardinalAdina),
+ "sabir" | "cardinal sabir" => Ok(Boss::CardinalSabir),
+ "qadimp" | "peerless qadim" | "qadim the peerless" => Ok(Boss::QadimThePeerless),
+
+ "skorvald" => Ok(Boss::Skorvald),
+ "artsariiv" => Ok(Boss::Artsariiv),
+ "arkk" => Ok(Boss::Arkk),
+
+ "mama" => Ok(Boss::MAMA),
+ "siax" => Ok(Boss::Siax),
+ "ensolyss" => Ok(Boss::Ensolyss),
+
+ "icebrood" | "icebrood construct" => Ok(Boss::IcebroodConstruct),
+ "super kodan brothers" => Ok(Boss::VoiceOfTheFallen),
+ "fraenir" | "fraenir of jormag" => Ok(Boss::FraenirOfJormag),
+ "boneskinner" => Ok(Boss::Boneskinner),
+ "whisper" | "whisper of jormag" => Ok(Boss::WhisperOfJormag),
+
+ _ => Err(ParseBossError(s.to_owned()))
+ }
+ }
+}
+
+
+/// ID for Xera in the second phase.
+///
+/// The original Xera will despawn, and after the tower phase, a separate spawn
+/// will take over. This new Xera will have this ID. Care needs to be taken when
+/// calculating boss damage on this encounter, as both Xeras have to be taken
+/// into account.
+pub const XERA_PHASE2_ID: u16 = 0x3F9E;
+
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ pub fn test_parsing() {
+ assert_eq!("vg".parse(), Ok(Boss::ValeGuardian));
+ assert_eq!("VG".parse(), Ok(Boss::ValeGuardian));
+
+ assert!("vga".parse::<Boss>().is_err());
+ }
+}