From 91902f7ddb1941a1bd078d786a52b91979fffc36 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Sat, 13 Nov 2021 20:32:14 +0100 Subject: Implement the River of Souls encounter --- src/analyzers/raids/mod.rs | 2 +- src/analyzers/raids/w5.rs | 88 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) (limited to 'src/analyzers/raids') diff --git a/src/analyzers/raids/mod.rs b/src/analyzers/raids/mod.rs index 7b636a7..824b957 100644 --- a/src/analyzers/raids/mod.rs +++ b/src/analyzers/raids/mod.rs @@ -16,7 +16,7 @@ mod w4; pub use w4::{Cairn, Deimos, MursaatOverseer, Samarog}; mod w5; -pub use w5::{Dhuum, SoullessHorror}; +pub use w5::{Dhuum, RiverOfSouls, SoullessHorror}; mod w6; pub use w6::{ConjuredAmalgamate, Qadim, TwinLargos}; diff --git a/src/analyzers/raids/w5.rs b/src/analyzers/raids/w5.rs index f914031..747bda2 100644 --- a/src/analyzers/raids/w5.rs +++ b/src/analyzers/raids/w5.rs @@ -1,7 +1,7 @@ //! Boss fight analyzers for Wing 5 (Hall of Chains) use crate::{ analyzers::{helpers, Analyzer, Outcome}, - EventKind, Log, + Encounter, EventKind, Log, }; pub const DESMINA_BUFF_ID: u32 = 47414; @@ -54,6 +54,92 @@ impl<'log> Analyzer for SoullessHorror<'log> { } } +/// Analyzer for the River of Souls escort event in Wing 5. +#[derive(Debug, Clone, Copy)] +pub struct RiverOfSouls<'log> { + log: &'log Log, +} + +impl<'log> RiverOfSouls<'log> { + pub fn new(log: &'log Log) -> Self { + RiverOfSouls { log } + } +} + +impl<'log> Analyzer for RiverOfSouls<'log> { + fn log(&self) -> &'log Log { + self.log + } + + fn is_cm(&self) -> bool { + false + } + + fn outcome(&self) -> Option { + const TRASH_IDS: &[u16] = &[0x4d97, 0x4bc7, 0x4d75, 0x4c05, 0x4bc8, 0x4cec]; + check_reward!(self.log); + + // First, let's get the Desmina NPC + let desmina = self + .log + .characters() + .find(|npc| npc.id() == Encounter::RiverOfSouls as u16)?; + + // We need to see when our friendly Desmina exited combat, because if she didn't, the event + // failed. + let exit_combat = self + .log + .events() + .iter() + .find(|e| matches!(e.kind(), &EventKind::ExitCombat { agent_addr } if agent_addr == desmina.addr())); + if exit_combat.is_none() { + return Some(Outcome::Failure); + } + + let trash_aware = self + .log + .characters() + .filter(|npc| TRASH_IDS.contains(&npc.id())) + .map(|npc| npc.last_aware()) + .filter(|&i| i != u64::MAX) + .max() + .unwrap_or(0); + + let desmina_despawn = self + .log() + .events() + .iter() + .find(|e| matches!(e.kind(), &EventKind::Despawn { agent_addr } if agent_addr == desmina.addr())); + + Outcome::from_bool( + trash_aware != 0 + && desmina_despawn.is_none() + // Add some leeway and see if we saw Desmina after all the trash was gone + && trash_aware + 500 <= desmina.last_aware() + && some_player_alive(self.log), + ) + } +} + +fn some_player_alive(log: &Log) -> bool { + let deaths_and_dcs = log + .events() + .iter() + .filter_map(|e| match *e.kind() { + EventKind::Despawn { agent_addr } => Some(agent_addr), + EventKind::ChangeDead { agent_addr } => Some(agent_addr), + _ => None, + }) + .filter(|&addr| { + log.agent_by_addr(addr) + .map(|a| a.kind().is_player()) + .unwrap_or(false) + }) + .count(); + + deaths_and_dcs < log.players().count() +} + pub const DHUUM_CM_HEALTH: u64 = 40_000_000; /// Analyzer for the second fight of Wing 5, Dhuum. -- cgit v1.2.3