From 0978345648cf9cdad6222f583dd21497b409d07e Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Sun, 28 Jun 2020 17:22:43 +0200 Subject: start implementing analyzers It turns out that the different encounters do require quite some encounter-specific logic, not only to determine whether the CM was activated, but also to determine whether the fight was successful, the duration of the fight, later the phases, ... Wrapping all of this in pre-defined "triggers" (like CmTrigger) feels like it will be a bit unfitting, so with this patch we have introduced the evtclib::Analyzer, which can be used to analyze the fights. Currently, the whole CM detection logic has been moved to this new interface, and soon we also want the success-detection logic in there. The tests pass and the interface of Log::is_cm is unchanged. --- src/analyzers/raids/mod.rs | 11 +++++ src/analyzers/raids/w4.rs | 116 +++++++++++++++++++++++++++++++++++++++++++++ src/analyzers/raids/w5.rs | 62 ++++++++++++++++++++++++ src/analyzers/raids/w6.rs | 87 ++++++++++++++++++++++++++++++++++ src/analyzers/raids/w7.rs | 86 +++++++++++++++++++++++++++++++++ 5 files changed, 362 insertions(+) create mode 100644 src/analyzers/raids/mod.rs create mode 100644 src/analyzers/raids/w4.rs create mode 100644 src/analyzers/raids/w5.rs create mode 100644 src/analyzers/raids/w6.rs create mode 100644 src/analyzers/raids/w7.rs (limited to 'src/analyzers/raids') diff --git a/src/analyzers/raids/mod.rs b/src/analyzers/raids/mod.rs new file mode 100644 index 0000000..91b0dba --- /dev/null +++ b/src/analyzers/raids/mod.rs @@ -0,0 +1,11 @@ +mod w4; +pub use w4::{Cairn, Deimos, MursaatOverseer, Samarog}; + +mod w5; +pub use w5::{Dhuum, SoullessHorror}; + +mod w6; +pub use w6::{ConjuredAmalgamate, LargosTwins, Qadim}; + +mod w7; +pub use w7::{CardinalAdina, CardinalSabir, QadimThePeerless}; diff --git a/src/analyzers/raids/w4.rs b/src/analyzers/raids/w4.rs new file mode 100644 index 0000000..efdab8f --- /dev/null +++ b/src/analyzers/raids/w4.rs @@ -0,0 +1,116 @@ +//! Boss fight analyzers for Wing 4 (Bastion of the Penitent). +use crate::{ + analyzers::{helpers, Analyzer}, + Log, +}; + +pub const CAIRN_CM_BUFF: u32 = 38_098; + +/// Analyzer for the first fight of Wing 4, Cairn. +/// +/// The CM is detected by the presence of the buff representing the countdown before which you have +/// to use your special action skill. +#[derive(Debug, Clone, Copy)] +pub struct Cairn<'log> { + log: &'log Log, +} + +impl<'log> Cairn<'log> { + pub fn new(log: &'log Log) -> Self { + Cairn { log } + } +} + +impl<'log> Analyzer for Cairn<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + helpers::buff_present(self.log, CAIRN_CM_BUFF) + } +} + +pub const MO_CM_HEALTH: u64 = 30_000_000; + +/// Analyzer for the second fight of Wing 4, Mursaat Overseer. +/// +/// The CM is detected by the boss's health, which is higher in the challenge mote. +#[derive(Debug, Clone, Copy)] +pub struct MursaatOverseer<'log> { + log: &'log Log, +} + +impl<'log> MursaatOverseer<'log> { + pub fn new(log: &'log Log) -> Self { + MursaatOverseer { log } + } +} + +impl<'log> Analyzer for MursaatOverseer<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + helpers::boss_health(self.log) + .map(|h| h >= MO_CM_HEALTH) + .unwrap_or(false) + } +} + +pub const SAMAROG_CM_HEALTH: u64 = 40_000_000; + +/// Analyzer for the third fight of Wing 4, Samarog. +/// +/// The CM is detected by the boss's health, which is higher in the challenge mote. +#[derive(Debug, Clone, Copy)] +pub struct Samarog<'log> { + log: &'log Log, +} + +impl<'log> Samarog<'log> { + pub fn new(log: &'log Log) -> Self { + Samarog { log } + } +} + +impl<'log> Analyzer for Samarog<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + helpers::boss_health(self.log) + .map(|h| h >= SAMAROG_CM_HEALTH) + .unwrap_or(false) + } +} + +pub const DEIMOS_CM_HEALTH: u64 = 42_000_000; + +/// Analyzer for the fourth fight of Wing 4, Deimos. +/// +/// The CM is detected by the boss's health, which is higher in the challenge mote. +#[derive(Debug, Clone, Copy)] +pub struct Deimos<'log> { + log: &'log Log, +} + +impl<'log> Deimos<'log> { + pub fn new(log: &'log Log) -> Self { + Deimos { log } + } +} + +impl<'log> Analyzer for Deimos<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + helpers::boss_health(self.log) + .map(|h| h >= DEIMOS_CM_HEALTH) + .unwrap_or(false) + } +} diff --git a/src/analyzers/raids/w5.rs b/src/analyzers/raids/w5.rs new file mode 100644 index 0000000..b8c3f3c --- /dev/null +++ b/src/analyzers/raids/w5.rs @@ -0,0 +1,62 @@ +//! Boss fight analyzers for Wing 5 (Hall of Chains) +use crate::{ + analyzers::{helpers, Analyzer}, + Log, +}; + +pub const DESMINA_BUFF_ID: u32 = 47414; +pub const DESMINA_MS_THRESHOLD: u64 = 11_000; + +/// Analyzer for the first fight of Wing 5, Soulless Horror (aka. Desmina). +/// +/// The CM is detected by the time between applications of the Necrosis debuff, which is applied at +/// a faster rate when the challenge mote is active. +#[derive(Debug, Clone, Copy)] +pub struct SoullessHorror<'log> { + log: &'log Log, +} + +impl<'log> SoullessHorror<'log> { + pub fn new(log: &'log Log) -> Self { + SoullessHorror { log } + } +} + +impl<'log> Analyzer for SoullessHorror<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + let tbb = helpers::time_between_buffs(self.log, DESMINA_BUFF_ID); + tbb > 0 && tbb <= DESMINA_MS_THRESHOLD + } +} + +pub const DHUUM_CM_HEALTH: u64 = 40_000_000; + +/// Analyzer for the second fight of Wing 5, Dhuum. +/// +/// The CM is detected by the boss's health, which is higher in the challenge mote. +#[derive(Debug, Clone, Copy)] +pub struct Dhuum<'log> { + log: &'log Log, +} + +impl<'log> Dhuum<'log> { + pub fn new(log: &'log Log) -> Self { + Dhuum { log } + } +} + +impl<'log> Analyzer for Dhuum<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + helpers::boss_health(self.log) + .map(|h| h >= DHUUM_CM_HEALTH) + .unwrap_or(false) + } +} diff --git a/src/analyzers/raids/w6.rs b/src/analyzers/raids/w6.rs new file mode 100644 index 0000000..c4e5b1a --- /dev/null +++ b/src/analyzers/raids/w6.rs @@ -0,0 +1,87 @@ +//! Boss fight analyzers for Wing 6 (Mythwright Gambit) +use crate::{ + analyzers::{helpers, Analyzer}, + Log, +}; + +pub const CA_CM_BUFF: u32 = 53_075; + +/// Analyzer for the first fight of Wing 6, Conjured Amalgamate. +/// +/// The CM is detected by the presence of the buff that the player targeted by the laser has. +#[derive(Debug, Clone, Copy)] +pub struct ConjuredAmalgamate<'log> { + log: &'log Log, +} + +impl<'log> ConjuredAmalgamate<'log> { + pub fn new(log: &'log Log) -> Self { + ConjuredAmalgamate { log } + } +} + +impl<'log> Analyzer for ConjuredAmalgamate<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + helpers::buff_present(self.log, CA_CM_BUFF) + } +} + +pub const LARGOS_CM_HEALTH: u64 = 19_200_000; + +/// Analyzer for the second fight of Wing 6, Largos Twins. +/// +/// The CM is detected by the boss's health, which is higher in the challenge mote. +#[derive(Debug, Clone, Copy)] +pub struct LargosTwins<'log> { + log: &'log Log, +} + +impl<'log> LargosTwins<'log> { + pub fn new(log: &'log Log) -> Self { + LargosTwins { log } + } +} + +impl<'log> Analyzer for LargosTwins<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + helpers::boss_health(self.log) + .map(|h| h >= LARGOS_CM_HEALTH) + .unwrap_or(false) + } +} + +pub const QADIM_CM_HEALTH: u64 = 21_100_000; + +/// Analyzer for the third fight of Wing 6, Qadim. +/// +/// The CM is detected by the boss's health, which is higher in the challenge mote. +#[derive(Debug, Clone, Copy)] +pub struct Qadim<'log> { + log: &'log Log, +} + +impl<'log> Qadim<'log> { + pub fn new(log: &'log Log) -> Self { + Qadim { log } + } +} + +impl<'log> Analyzer for Qadim<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + helpers::boss_health(self.log) + .map(|h| h >= QADIM_CM_HEALTH) + .unwrap_or(false) + } +} diff --git a/src/analyzers/raids/w7.rs b/src/analyzers/raids/w7.rs new file mode 100644 index 0000000..a8319a3 --- /dev/null +++ b/src/analyzers/raids/w7.rs @@ -0,0 +1,86 @@ +//! Boss fight analyzers for Wing 6 (Mythwright Gambit) +use crate::{ + analyzers::{helpers, Analyzer}, + Log, +}; + +pub const ADINA_CM_HEALTH: u64 = 24_800_000; + +/// Analyzer for the first fight of Wing 7, Cardinal Adina. +/// +/// The CM is detected by the boss's health, which is higher in the challenge mote. +#[derive(Debug, Clone, Copy)] +pub struct CardinalAdina<'log> { + log: &'log Log, +} + +impl<'log> CardinalAdina<'log> { + pub fn new(log: &'log Log) -> Self { + CardinalAdina { log } + } +} + +impl<'log> Analyzer for CardinalAdina<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + helpers::boss_health(self.log) + .map(|h| h >= ADINA_CM_HEALTH) + .unwrap_or(false) + } +} + +pub const SABIR_CM_HEALTH: u64 = 32_400_000; + +/// Analyzer for the second fight of Wing 7, Cardinal Sabir. +/// +/// The CM is detected by the boss's health, which is higher in the challenge mote. +#[derive(Debug, Clone, Copy)] +pub struct CardinalSabir<'log> { + log: &'log Log, +} + +impl<'log> CardinalSabir<'log> { + pub fn new(log: &'log Log) -> Self { + CardinalSabir { log } + } +} + +impl<'log> Analyzer for CardinalSabir<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + helpers::boss_health(self.log) + .map(|h| h >= SABIR_CM_HEALTH) + .unwrap_or(false) + } +} + +pub const QADIMP_CM_HEALTH: u64 = 51_000_000; + +#[derive(Debug, Clone, Copy)] +pub struct QadimThePeerless<'log> { + log: &'log Log, +} + +impl<'log> QadimThePeerless<'log> { + pub fn new(log: &'log Log) -> Self { + QadimThePeerless { log } + } +} + +impl<'log> Analyzer for QadimThePeerless<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + helpers::boss_health(self.log) + .map(|h| h >= QADIMP_CM_HEALTH) + .unwrap_or(false) + } +} -- cgit v1.2.3 From 962e2b9f8e17a50c7d7d37a424591b0df62f265c Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Thu, 23 Jul 2020 02:47:52 +0200 Subject: implement proper outcome for w1-w4 It turns out that `was_rewarded` is a pretty bad heuristic if you ever kill a boss a second time per week (basically, was_rewarded=false does not imply that the boss was unsuccessful). Therefore, we need a proper detection of when a fight failed and when a fight succeeded. This is the first batch that implements this as part of the Analyzer trait for bosses of wings 1 to 4. --- src/analyzers/raids/mod.rs | 34 +++++++++++++++ src/analyzers/raids/w3.rs | 30 +++++++++++++ src/analyzers/raids/w4.rs | 102 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 src/analyzers/raids/w3.rs (limited to 'src/analyzers/raids') diff --git a/src/analyzers/raids/mod.rs b/src/analyzers/raids/mod.rs index 91b0dba..33d54ce 100644 --- a/src/analyzers/raids/mod.rs +++ b/src/analyzers/raids/mod.rs @@ -1,3 +1,11 @@ +use crate::{ + analyzers::{helpers, Analyzer, Outcome}, + Log, +}; + +mod w3; +pub use w3::Xera; + mod w4; pub use w4::{Cairn, Deimos, MursaatOverseer, Samarog}; @@ -9,3 +17,29 @@ pub use w6::{ConjuredAmalgamate, LargosTwins, Qadim}; mod w7; pub use w7::{CardinalAdina, CardinalSabir, QadimThePeerless}; + +/// A generic raid analyzer that works for bosses without special interactions. +#[derive(Debug, Clone, Copy)] +pub struct GenericRaid<'log> { + log: &'log Log, +} + +impl<'log> GenericRaid<'log> { + pub fn new(log: &'log Log) -> Self { + GenericRaid { log } + } +} + +impl<'log> Analyzer for GenericRaid<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + false + } + + fn outcome(&self) -> Option { + Outcome::from_bool(helpers::boss_is_dead(self.log)) + } +} diff --git a/src/analyzers/raids/w3.rs b/src/analyzers/raids/w3.rs new file mode 100644 index 0000000..82c007d --- /dev/null +++ b/src/analyzers/raids/w3.rs @@ -0,0 +1,30 @@ +use crate::{ + analyzers::{helpers, Analyzer, Outcome}, + Log, +}; + +/// Analyzer for the final fight of Wing 3, Xera. +#[derive(Debug, Clone, Copy)] +pub struct Xera<'log> { + log: &'log Log, +} + +impl<'log> Xera<'log> { + pub fn new(log: &'log Log) -> Self { + Xera { log } + } +} + +impl<'log> Analyzer for Xera<'log> { + fn log(&self) -> &Log { + self.log + } + + fn is_cm(&self) -> bool { + false + } + + fn outcome(&self) -> Option { + Outcome::from_bool(helpers::players_exit_after_boss(self.log)) + } +} diff --git a/src/analyzers/raids/w4.rs b/src/analyzers/raids/w4.rs index efdab8f..e753e49 100644 --- a/src/analyzers/raids/w4.rs +++ b/src/analyzers/raids/w4.rs @@ -1,7 +1,7 @@ //! Boss fight analyzers for Wing 4 (Bastion of the Penitent). use crate::{ - analyzers::{helpers, Analyzer}, - Log, + analyzers::{helpers, Analyzer, Outcome}, + EventKind, Log, }; pub const CAIRN_CM_BUFF: u32 = 38_098; @@ -29,6 +29,10 @@ impl<'log> Analyzer for Cairn<'log> { fn is_cm(&self) -> bool { helpers::buff_present(self.log, CAIRN_CM_BUFF) } + + fn outcome(&self) -> Option { + Outcome::from_bool(helpers::boss_is_dead(self.log)) + } } pub const MO_CM_HEALTH: u64 = 30_000_000; @@ -57,6 +61,10 @@ impl<'log> Analyzer for MursaatOverseer<'log> { .map(|h| h >= MO_CM_HEALTH) .unwrap_or(false) } + + fn outcome(&self) -> Option { + Outcome::from_bool(helpers::boss_is_dead(self.log)) + } } pub const SAMAROG_CM_HEALTH: u64 = 40_000_000; @@ -85,6 +93,10 @@ impl<'log> Analyzer for Samarog<'log> { .map(|h| h >= SAMAROG_CM_HEALTH) .unwrap_or(false) } + + fn outcome(&self) -> Option { + Outcome::from_bool(helpers::boss_is_dead(self.log)) + } } pub const DEIMOS_CM_HEALTH: u64 = 42_000_000; @@ -113,4 +125,90 @@ impl<'log> Analyzer for Deimos<'log> { .map(|h| h >= DEIMOS_CM_HEALTH) .unwrap_or(false) } + + fn outcome(&self) -> Option { + // The idea for Deimos is that we first need to figure out when the 10% split happens (if + // it even happens), then we can find the time when 10%-Deimos becomes untargetable and + // then we can compare this time to the player exit time. + + let split_time = deimos_10_time(self.log); + // We never got to 10%, so this is a fail. + if split_time == 0 { + return Some(Outcome::Failure); + } + + let at_address = deimos_at_address(self.log); + if at_address == 0 { + return Some(Outcome::Failure); + } + + let mut player_exit = 0u64; + let mut at_exit = 0u64; + for event in self.log.events() { + match event.kind() { + EventKind::ExitCombat { agent_addr } + if self + .log + .agent_by_addr(*agent_addr) + .map(|a| a.kind().is_player()) + .unwrap_or(false) + && event.time() >= player_exit => + { + player_exit = event.time(); + } + + EventKind::Targetable { + agent_addr, + targetable, + } if *agent_addr == at_address && !targetable && event.time() >= at_exit => { + at_exit = event.time(); + } + + _ => (), + } + } + + // Safety margin + Outcome::from_bool(player_exit > at_exit + 1000) + } +} + +// Extracts the timestamp when Deimos's 10% phase started. +// +// This function may panic when passed non-Deimos logs! +fn deimos_10_time(log: &Log) -> u64 { + let mut first_aware = 0u64; + + for event in log.events() { + if let EventKind::Targetable { targetable, .. } = event.kind() { + if *targetable { + first_aware = event.time(); + println!("First aware: {}", first_aware); + } + } + } + + first_aware +} + +// Returns the attack target address for the 10% Deimos phase. +// +// Returns 0 when the right attack target is not found. +fn deimos_at_address(log: &Log) -> u64 { + for event in log.events().iter().rev() { + if let EventKind::AttackTarget { + agent_addr, + parent_agent_addr, + .. + } = event.kind() + { + let parent = log.agent_by_addr(*parent_agent_addr); + if let Some(parent) = parent { + if Some("Deimos") == parent.as_gadget().map(|g| g.name()) { + return *agent_addr; + } + } + } + } + 0 } -- cgit v1.2.3 From 4c02181067e789e41eb95c6f6e954e4de6277dc1 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Thu, 23 Jul 2020 03:00:53 +0200 Subject: implement Analyzer::outcome for wing 5 --- src/analyzers/raids/w5.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'src/analyzers/raids') diff --git a/src/analyzers/raids/w5.rs b/src/analyzers/raids/w5.rs index b8c3f3c..b9668b7 100644 --- a/src/analyzers/raids/w5.rs +++ b/src/analyzers/raids/w5.rs @@ -1,11 +1,12 @@ //! Boss fight analyzers for Wing 5 (Hall of Chains) use crate::{ - analyzers::{helpers, Analyzer}, - Log, + analyzers::{helpers, Analyzer, Outcome}, + EventKind, Log, }; pub const DESMINA_BUFF_ID: u32 = 47414; pub const DESMINA_MS_THRESHOLD: u64 = 11_000; +pub const DESMINA_DEATH_BUFF: u32 = 895; /// Analyzer for the first fight of Wing 5, Soulless Horror (aka. Desmina). /// @@ -31,6 +32,21 @@ impl<'log> Analyzer for SoullessHorror<'log> { let tbb = helpers::time_between_buffs(self.log, DESMINA_BUFF_ID); tbb > 0 && tbb <= DESMINA_MS_THRESHOLD } + + fn outcome(&self) -> Option { + Outcome::from_bool(self.log.events().iter().any(|event| { + if let EventKind::BuffApplication { + buff_id, + destination_agent_addr, + .. + } = event.kind() + { + self.log.is_boss(*destination_agent_addr) && *buff_id == DESMINA_DEATH_BUFF + } else { + false + } + })) + } } pub const DHUUM_CM_HEALTH: u64 = 40_000_000; @@ -59,4 +75,8 @@ impl<'log> Analyzer for Dhuum<'log> { .map(|h| h >= DHUUM_CM_HEALTH) .unwrap_or(false) } + + fn outcome(&self) -> Option { + Outcome::from_bool(helpers::boss_is_dead(self.log)) + } } -- cgit v1.2.3 From dcf1b948b953fb17db16eafcdd30f0a25301171f Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Thu, 23 Jul 2020 17:18:56 +0200 Subject: implement Analyzer::outcome for wing 6 --- src/analyzers/raids/w6.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) (limited to 'src/analyzers/raids') diff --git a/src/analyzers/raids/w6.rs b/src/analyzers/raids/w6.rs index c4e5b1a..cc39403 100644 --- a/src/analyzers/raids/w6.rs +++ b/src/analyzers/raids/w6.rs @@ -1,10 +1,12 @@ //! Boss fight analyzers for Wing 6 (Mythwright Gambit) use crate::{ - analyzers::{helpers, Analyzer}, - Log, + analyzers::{helpers, Analyzer, Outcome}, + gamedata::{KENUT_ID, NIKARE_ID}, + EventKind, Log, }; pub const CA_CM_BUFF: u32 = 53_075; +pub const ZOMMOROS_ID: u16 = 21_118; /// Analyzer for the first fight of Wing 6, Conjured Amalgamate. /// @@ -28,6 +30,23 @@ impl<'log> Analyzer for ConjuredAmalgamate<'log> { fn is_cm(&self) -> bool { helpers::buff_present(self.log, CA_CM_BUFF) } + + fn outcome(&self) -> Option { + for event in self.log.events() { + if let EventKind::Spawn { agent_addr } = event.kind() { + if self + .log + .agent_by_addr(*agent_addr) + .and_then(|a| a.as_character()) + .map(|a| a.id() == ZOMMOROS_ID) + .unwrap_or(false) + { + return Some(Outcome::Success); + } + } + } + Some(Outcome::Failure) + } } pub const LARGOS_CM_HEALTH: u64 = 19_200_000; @@ -56,6 +75,33 @@ impl<'log> Analyzer for LargosTwins<'log> { .map(|h| h >= LARGOS_CM_HEALTH) .unwrap_or(false) } + + fn outcome(&self) -> Option { + let mut nikare_dead = false; + let mut kenut_dead = false; + + for event in self.log.events() { + if let EventKind::ChangeDead { agent_addr } = event.kind() { + let agent = if let Some(agent) = self + .log + .agent_by_addr(*agent_addr) + .and_then(|a| a.as_character()) + { + agent + } else { + continue; + }; + + if agent.id() == NIKARE_ID { + nikare_dead = true; + } else if agent.id() == KENUT_ID { + kenut_dead = true; + } + } + } + + Outcome::from_bool(kenut_dead && nikare_dead) + } } pub const QADIM_CM_HEALTH: u64 = 21_100_000; @@ -84,4 +130,8 @@ impl<'log> Analyzer for Qadim<'log> { .map(|h| h >= QADIM_CM_HEALTH) .unwrap_or(false) } + + fn outcome(&self) -> Option { + Outcome::from_bool(helpers::players_exit_after_boss(self.log)) + } } -- cgit v1.2.3 From d290abac857fd88008afcde1d76fc70fe33ca605 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Thu, 23 Jul 2020 17:23:03 +0200 Subject: implement Analyzer::outcome for wing 7 --- src/analyzers/raids/w7.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/analyzers/raids') diff --git a/src/analyzers/raids/w7.rs b/src/analyzers/raids/w7.rs index a8319a3..54073a3 100644 --- a/src/analyzers/raids/w7.rs +++ b/src/analyzers/raids/w7.rs @@ -1,6 +1,6 @@ //! Boss fight analyzers for Wing 6 (Mythwright Gambit) use crate::{ - analyzers::{helpers, Analyzer}, + analyzers::{helpers, Analyzer, Outcome}, Log, }; @@ -30,6 +30,10 @@ impl<'log> Analyzer for CardinalAdina<'log> { .map(|h| h >= ADINA_CM_HEALTH) .unwrap_or(false) } + + fn outcome(&self) -> Option { + Outcome::from_bool(helpers::boss_is_dead(self.log)) + } } pub const SABIR_CM_HEALTH: u64 = 32_400_000; @@ -58,6 +62,10 @@ impl<'log> Analyzer for CardinalSabir<'log> { .map(|h| h >= SABIR_CM_HEALTH) .unwrap_or(false) } + + fn outcome(&self) -> Option { + Outcome::from_bool(helpers::boss_is_dead(self.log)) + } } pub const QADIMP_CM_HEALTH: u64 = 51_000_000; @@ -83,4 +91,8 @@ impl<'log> Analyzer for QadimThePeerless<'log> { .map(|h| h >= QADIMP_CM_HEALTH) .unwrap_or(false) } + + fn outcome(&self) -> Option { + Outcome::from_bool(helpers::boss_is_dead(self.log)) + } } -- cgit v1.2.3 From 75f5ce065efb6a186570b365c88e564871915d76 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Thu, 23 Jul 2020 17:57:59 +0200 Subject: more documentation & adjustments --- src/analyzers/raids/mod.rs | 11 +++++++++++ src/analyzers/raids/w7.rs | 1 + 2 files changed, 12 insertions(+) (limited to 'src/analyzers/raids') diff --git a/src/analyzers/raids/mod.rs b/src/analyzers/raids/mod.rs index 33d54ce..39fb823 100644 --- a/src/analyzers/raids/mod.rs +++ b/src/analyzers/raids/mod.rs @@ -1,3 +1,9 @@ +//! Analyzers for raid logs. +//! +//! Most of the fights can use the [`GenericRaid`][GenericRaid] analyzer. The exception to this are +//! fights which have a Challenge Mote (Wing 4, Wing 5, Wing 6, Wing 7), and fights which need to +//! use a different method to determine their outcome (Xera, Deimos, Soulless Horror, Conjured +//! Amalgamate, Qadim). use crate::{ analyzers::{helpers, Analyzer, Outcome}, Log, @@ -19,6 +25,11 @@ mod w7; pub use w7::{CardinalAdina, CardinalSabir, QadimThePeerless}; /// A generic raid analyzer that works for bosses without special interactions. +/// +/// This analyzer always returns `false` for the Challenge Mote calculation. +/// +/// The outcome of the fight is determined by whether the boss agent has a death event - which +/// works for a lot of fights, but not all of them. #[derive(Debug, Clone, Copy)] pub struct GenericRaid<'log> { log: &'log Log, diff --git a/src/analyzers/raids/w7.rs b/src/analyzers/raids/w7.rs index 54073a3..480c303 100644 --- a/src/analyzers/raids/w7.rs +++ b/src/analyzers/raids/w7.rs @@ -70,6 +70,7 @@ impl<'log> Analyzer for CardinalSabir<'log> { pub const QADIMP_CM_HEALTH: u64 = 51_000_000; +/// Analyzer for the final fight of Wing 7, Qadim The Peerless. #[derive(Debug, Clone, Copy)] pub struct QadimThePeerless<'log> { log: &'log Log, -- cgit v1.2.3 From f6717fc45188870341e9b6185ef5f3102f5a96ae Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Fri, 24 Jul 2020 14:09:51 +0200 Subject: more documentation --- src/analyzers/raids/mod.rs | 4 ++++ src/analyzers/raids/w3.rs | 4 ++++ src/analyzers/raids/w4.rs | 16 ++++++++++++++++ src/analyzers/raids/w5.rs | 8 ++++++++ src/analyzers/raids/w6.rs | 12 ++++++++++++ src/analyzers/raids/w7.rs | 12 ++++++++++++ 6 files changed, 56 insertions(+) (limited to 'src/analyzers/raids') diff --git a/src/analyzers/raids/mod.rs b/src/analyzers/raids/mod.rs index 39fb823..bb3824b 100644 --- a/src/analyzers/raids/mod.rs +++ b/src/analyzers/raids/mod.rs @@ -36,6 +36,10 @@ pub struct GenericRaid<'log> { } impl<'log> GenericRaid<'log> { + /// Create a new [`GenericRaid`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { GenericRaid { log } } diff --git a/src/analyzers/raids/w3.rs b/src/analyzers/raids/w3.rs index 82c007d..1b80b8d 100644 --- a/src/analyzers/raids/w3.rs +++ b/src/analyzers/raids/w3.rs @@ -10,6 +10,10 @@ pub struct Xera<'log> { } impl<'log> Xera<'log> { + /// Create a new [`Xera`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { Xera { log } } diff --git a/src/analyzers/raids/w4.rs b/src/analyzers/raids/w4.rs index e753e49..310b26f 100644 --- a/src/analyzers/raids/w4.rs +++ b/src/analyzers/raids/w4.rs @@ -16,6 +16,10 @@ pub struct Cairn<'log> { } impl<'log> Cairn<'log> { + /// Create a new [`Cairn`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { Cairn { log } } @@ -46,6 +50,10 @@ pub struct MursaatOverseer<'log> { } impl<'log> MursaatOverseer<'log> { + /// Create a new [`MursaatOverseer`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { MursaatOverseer { log } } @@ -78,6 +86,10 @@ pub struct Samarog<'log> { } impl<'log> Samarog<'log> { + /// Create a new [`Samarog`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { Samarog { log } } @@ -110,6 +122,10 @@ pub struct Deimos<'log> { } impl<'log> Deimos<'log> { + /// Create a new [`Deimos`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { Deimos { log } } diff --git a/src/analyzers/raids/w5.rs b/src/analyzers/raids/w5.rs index b9668b7..578cea8 100644 --- a/src/analyzers/raids/w5.rs +++ b/src/analyzers/raids/w5.rs @@ -18,6 +18,10 @@ pub struct SoullessHorror<'log> { } impl<'log> SoullessHorror<'log> { + /// Create a new [`SoullessHorror`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { SoullessHorror { log } } @@ -60,6 +64,10 @@ pub struct Dhuum<'log> { } impl<'log> Dhuum<'log> { + /// Create a new [`Dhuum`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { Dhuum { log } } diff --git a/src/analyzers/raids/w6.rs b/src/analyzers/raids/w6.rs index cc39403..8701a63 100644 --- a/src/analyzers/raids/w6.rs +++ b/src/analyzers/raids/w6.rs @@ -17,6 +17,10 @@ pub struct ConjuredAmalgamate<'log> { } impl<'log> ConjuredAmalgamate<'log> { + /// Create a new [`ConjuredAmalgamate`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { ConjuredAmalgamate { log } } @@ -60,6 +64,10 @@ pub struct LargosTwins<'log> { } impl<'log> LargosTwins<'log> { + /// Create a new [`LargosTwins`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { LargosTwins { log } } @@ -115,6 +123,10 @@ pub struct Qadim<'log> { } impl<'log> Qadim<'log> { + /// Create a new [`Qadim`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { Qadim { log } } diff --git a/src/analyzers/raids/w7.rs b/src/analyzers/raids/w7.rs index 480c303..bdfadd6 100644 --- a/src/analyzers/raids/w7.rs +++ b/src/analyzers/raids/w7.rs @@ -15,6 +15,10 @@ pub struct CardinalAdina<'log> { } impl<'log> CardinalAdina<'log> { + /// Create a new [`CardinalAdina`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { CardinalAdina { log } } @@ -47,6 +51,10 @@ pub struct CardinalSabir<'log> { } impl<'log> CardinalSabir<'log> { + /// Create a new [`CardinalSabir`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { CardinalSabir { log } } @@ -77,6 +85,10 @@ pub struct QadimThePeerless<'log> { } impl<'log> QadimThePeerless<'log> { + /// Create a new [`QadimThePeerless`] analyzer for the given log. + /// + /// **Do not** use this method unless you know what you are doing. Instead, rely on + /// [`Log::analyzer`]! pub fn new(log: &'log Log) -> Self { QadimThePeerless { log } } -- cgit v1.2.3