aboutsummaryrefslogtreecommitdiff
path: root/src/analyzers/raids/w5.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/analyzers/raids/w5.rs')
-rw-r--r--src/analyzers/raids/w5.rs88
1 files changed, 87 insertions, 1 deletions
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<Outcome> {
+ 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.