use crate::{
analyzers::{helpers, Analyzer, Outcome},
gamedata::Boss,
EventKind, Log,
};
#[derive(Debug, Clone, Copy)]
pub struct GenericStrike<'log> {
log: &'log Log,
}
impl<'log> GenericStrike<'log> {
pub fn new(log: &'log Log) -> Self {
GenericStrike { log }
}
}
impl<'log> Analyzer for GenericStrike<'log> {
fn log(&self) -> &Log {
self.log
}
fn is_cm(&self) -> bool {
false
}
fn outcome(&self) -> Option<Outcome> {
Outcome::from_bool(helpers::boss_is_dead(self.log))
}
}
#[derive(Debug, Clone, Copy)]
pub struct CaptainMaiTrin<'log> {
log: &'log Log,
}
impl<'log> CaptainMaiTrin<'log> {
pub const ECHO_OF_SCARLET_BRIAR: u16 = 24_768;
pub const ECHO_OF_SCARLET_BRIAR_CM: u16 = 25_247;
pub const DETERMINED_ID: u32 = 895;
pub const MAI_CM_HEALTH: u64 = 8_000_000;
pub fn new(log: &'log Log) -> Self {
CaptainMaiTrin { log }
}
}
impl<'log> Analyzer for CaptainMaiTrin<'log> {
fn log(&self) -> &Log {
self.log
}
fn is_cm(&self) -> bool {
helpers::boss_health(self.log).unwrap_or_default() > Self::MAI_CM_HEALTH
}
fn outcome(&self) -> Option<Outcome> {
check_reward!(self.log);
let scarlet = self.log.characters().find(|npc| {
npc.id() == Self::ECHO_OF_SCARLET_BRIAR || npc.id() == Self::ECHO_OF_SCARLET_BRIAR_CM
});
let scarlet = match scarlet {
Some(s) => s,
None => return Some(Outcome::Failure),
};
let mai = self
.log
.characters()
.find(|npc| npc.id() == Boss::CaptainMaiTrin as u16)?;
for event in self.log.events() {
if let EventKind::BuffApplication {
destination_agent_addr,
buff_id,
..
} = event.kind()
{
if *buff_id == Self::DETERMINED_ID
&& *destination_agent_addr == mai.addr()
&& event.time() > scarlet.first_aware()
{
return Some(Outcome::Success);
}
}
}
Some(Outcome::Failure)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Ankka<'log> {
log: &'log Log,
}
impl<'log> Ankka<'log> {
pub const DETERMINED_ID: u32 = CaptainMaiTrin::DETERMINED_ID;
pub const DURATION_CUTOFF: i32 = i32::MAX;
pub const EXPECTED_PHASE_COUNT: usize = 3;
pub const ANKKA_CM_HEALTH: u64 = 50_000_000;
pub fn new(log: &'log Log) -> Self {
Ankka { log }
}
}
impl<'log> Analyzer for Ankka<'log> {
fn log(&self) -> &Log {
self.log
}
fn is_cm(&self) -> bool {
helpers::boss_health(self.log).unwrap_or_default() > Self::ANKKA_CM_HEALTH
}
fn outcome(&self) -> Option<Outcome> {
check_reward!(self.log);
let ankka = self
.log
.characters()
.find(|npc| npc.id() == Boss::Ankka as u16)?;
let phase_change_count = self
.log
.events()
.iter()
.filter(|event| {
if let EventKind::BuffApplication {
destination_agent_addr,
buff_id,
duration,
..
} = event.kind()
{
*buff_id == Self::DETERMINED_ID
&& *destination_agent_addr == ankka.addr()
&& *duration == Self::DURATION_CUTOFF
} else {
false
}
})
.count();
Outcome::from_bool(phase_change_count == Self::EXPECTED_PHASE_COUNT)
}
}
#[derive(Debug, Clone, Copy)]
pub struct MinisterLi<'log> {
log: &'log Log,
}
impl<'log> MinisterLi<'log> {
pub const DETERMINED_ID: u32 = 762;
pub const MINIMUM_PHASE_COUNT: usize = 3;
pub fn new(log: &'log Log) -> Self {
MinisterLi { log }
}
}
impl<'log> Analyzer for MinisterLi<'log> {
fn log(&self) -> &Log {
self.log
}
fn is_cm(&self) -> bool {
false
}
fn outcome(&self) -> Option<Outcome> {
check_reward!(self.log);
let li = self
.log
.characters()
.find(|npc| npc.id() == Boss::MinisterLi as u16)?;
let phase_change_count = self
.log
.events()
.iter()
.filter(|event| {
if let EventKind::BuffApplication {
destination_agent_addr,
buff_id,
..
} = event.kind()
{
*buff_id == Self::DETERMINED_ID && *destination_agent_addr == li.addr()
} else {
false
}
})
.count();
Outcome::from_bool(phase_change_count >= Self::MINIMUM_PHASE_COUNT)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Dragonvoid<'log> {
log: &'log Log,
}
impl<'log> Dragonvoid<'log> {
pub const EXPECTED_TARGET_OFF_COUNT: usize = 2;
pub fn new(log: &'log Log) -> Self {
Dragonvoid { log }
}
}
impl<'log> Analyzer for Dragonvoid<'log> {
fn log(&self) -> &Log {
self.log
}
fn is_cm(&self) -> bool {
false
}
fn outcome(&self) -> Option<Outcome> {
let mut first_voids = None;
for event in self.log.events() {
if let EventKind::AttackTarget {
agent_addr,
parent_agent_addr,
..
} = event.kind()
{
if first_voids.is_none() {
first_voids = Some(parent_agent_addr);
} else if first_voids != Some(parent_agent_addr) {
let mut is_on = false;
let mut target_off_count = 0;
for e in self.log.events() {
if let EventKind::Targetable {
agent_addr: taa,
targetable,
} = e.kind()
{
if *taa != *agent_addr {
continue;
}
if *targetable {
is_on = true;
} else if !targetable && is_on {
target_off_count += 1;
}
}
}
if target_off_count == Self::EXPECTED_TARGET_OFF_COUNT {
return Some(Outcome::Success);
}
}
}
}
Some(Outcome::Failure)
}
}