1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
//! Boss fight analyzers for Wing 6 (Mythwright Gambit)
use crate::{
analyzers::{helpers, Analyzer, Outcome},
gamedata::Boss,
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.
///
/// 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> {
/// 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 }
}
}
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)
}
fn outcome(&self) -> Option<Outcome> {
check_reward!(self.log);
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;
/// 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 TwinLargos<'log> {
log: &'log Log,
}
impl<'log> TwinLargos<'log> {
/// Create a new [`TwinLargos`] 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 {
TwinLargos { log }
}
}
impl<'log> Analyzer for TwinLargos<'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)
}
fn outcome(&self) -> Option<Outcome> {
check_reward!(self.log);
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() == Boss::Nikare as u16 {
nikare_dead = true;
} else if agent.id() == Boss::Kenut as u16 {
kenut_dead = true;
}
}
}
Outcome::from_bool(kenut_dead && nikare_dead)
}
}
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> {
/// 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 }
}
}
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)
}
fn outcome(&self) -> Option<Outcome> {
check_reward!(self.log);
Outcome::from_bool(helpers::players_exit_after_boss(self.log))
}
}
|