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
|
//! Traits and structures to analyze fights.
//!
//! Fights need different logic in order to determine specific data, for example each fight has a
//! different way to determine whether or not the Challenge Mote was activated, whether or not the
//! fight was successful, ...
//!
//! This module aims to unify that logic by providing the [`Analyzer`][Analyzer] trait, which
//! provides a unified interface to query this information. You can use
//! [`Log::analyzer`][Log::analyzer] or [`for_log`][for_log] to obtain an analyzer fitting for the
//! encounter that is represented by the log.
//!
//! Most of the time, you will be dealing with a dynamically dispatched version of
//! [`Analyzer`][Analyzer], that is either `&dyn Analyzer` or `Box<dyn Analyzer>`. Also keep in
//! mind that an analyzer keeps a reference to the log that it is analyzing, which can be accessed
//! through [`Analyzer::log`][Analyzer::log].
//!
//! The implementation of the different analyzers is split off in different submodules:
//! * [`raids`][raids] for the raid-related encounters.
//! * [`fractals`][fractals] for the fractal-specific encounters.
//! * [`strikes`][strikes] for the strike-mission specific encounters.
//!
//! Note that you should not create concrete analyzers on your own, as the behaviour is not
//! specified when you use a wrong analyzer for the given log. Rely only on
//! [`Log::analyzer`][Log::analyzer] (or [`for_log`][for_log]) and the methods defined in
//! [`Analyzer`][Analyzer].
use crate::{Encounter, Log};
pub mod fractals;
#[macro_use]
pub mod helpers;
pub mod raids;
pub mod strikes;
/// The outcome of a fight.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Outcome {
/// The fight succeeded.
Success,
/// The fight failed, i.e. the group wiped.
Failure,
}
impl Outcome {
/// A function that turns a boolean into an [`Outcome`][Outcome].
///
/// This is a convenience function that can help implementing
/// [`Analyzer::outcome`][Analyzer::outcome], which is also why this function returns an Option
/// instead of the outcome directly.
///
/// This turns `true` into [`Outcome::Success`][Outcome::Success] and `false` into
/// [`Outcome::Failure`][Outcome::Failure].
pub fn from_bool(b: bool) -> Option<Outcome> {
if b {
Some(Outcome::Success)
} else {
Some(Outcome::Failure)
}
}
}
/// An [`Analyzer`][Analyzer] is something that implements fight-dependent analyzing of the log.
///
/// For more information and explanations, see the [module level documentation][self].
pub trait Analyzer {
/// Returns a reference to the log being analyzed.
fn log(&self) -> &Log;
/// Checks whether the fight was done with the challenge mote activated.
fn is_cm(&self) -> bool;
/// Returns the outcome of the fight.
///
/// Note that not all logs need to have an outcome, e.g. WvW or Golem logs may return `None`
/// here.
fn outcome(&self) -> Option<Outcome>;
}
/// Returns the correct [`Analyzer`][Analyzer] for the given log file.
///
/// See also [`Log::analyzer`][Log::analyzer].
pub fn for_log<'l>(log: &'l Log) -> Option<Box<dyn Analyzer + 'l>> {
let boss = log.encounter()?;
match boss {
Encounter::ValeGuardian | Encounter::Gorseval | Encounter::Sabetha => {
Some(Box::new(raids::GenericRaid::new(log)))
}
Encounter::Slothasor | Encounter::BanditTrio | Encounter::Matthias => {
Some(Box::new(raids::GenericRaid::new(log)))
}
Encounter::KeepConstruct => Some(Box::new(raids::GenericRaid::new(log))),
Encounter::TwistedCastle => Some(Box::new(raids::TwistedCastle::new(log))),
Encounter::Xera => Some(Box::new(raids::Xera::new(log))),
Encounter::Cairn => Some(Box::new(raids::Cairn::new(log))),
Encounter::MursaatOverseer => Some(Box::new(raids::MursaatOverseer::new(log))),
Encounter::Samarog => Some(Box::new(raids::Samarog::new(log))),
Encounter::Deimos => Some(Box::new(raids::Deimos::new(log))),
Encounter::SoullessHorror => Some(Box::new(raids::SoullessHorror::new(log))),
Encounter::RiverOfSouls => Some(Box::new(raids::RiverOfSouls::new(log))),
Encounter::BrokenKing | Encounter::EaterOfSouls | Encounter::StatueOfDarkness => {
Some(Box::new(raids::GenericRaid::new(log)))
}
Encounter::VoiceInTheVoid => Some(Box::new(raids::Dhuum::new(log))),
Encounter::ConjuredAmalgamate => Some(Box::new(raids::ConjuredAmalgamate::new(log))),
Encounter::TwinLargos => Some(Box::new(raids::TwinLargos::new(log))),
Encounter::Qadim => Some(Box::new(raids::Qadim::new(log))),
Encounter::CardinalAdina => Some(Box::new(raids::CardinalAdina::new(log))),
Encounter::CardinalSabir => Some(Box::new(raids::CardinalSabir::new(log))),
Encounter::QadimThePeerless => Some(Box::new(raids::QadimThePeerless::new(log))),
Encounter::StandardKittyGolem
| Encounter::MediumKittyGolem
| Encounter::LargeKittyGolem => Some(Box::new(raids::GenericRaid::new(log))),
Encounter::Kanaxai => Some(Box::new(fractals::GenericFractal::new(log))),
Encounter::Ai => Some(Box::new(fractals::Ai::new(log))),
Encounter::Skorvald => Some(Box::new(fractals::Skorvald::new(log))),
Encounter::Artsariiv
| Encounter::Arkk
| Encounter::MAMA
| Encounter::Siax
| Encounter::Ensolyss => Some(Box::new(fractals::GenericFractal::new(log))),
Encounter::IcebroodConstruct
| Encounter::SuperKodanBrothers
| Encounter::FraenirOfJormag
| Encounter::Boneskinner
| Encounter::WhisperOfJormag => Some(Box::new(strikes::GenericStrike::new(log))),
Encounter::CaptainMaiTrin => Some(Box::new(strikes::CaptainMaiTrin::new(log))),
Encounter::Ankka => Some(Box::new(strikes::Ankka::new(log))),
Encounter::MinisterLi => Some(Box::new(strikes::MinisterLi::new(log))),
Encounter::Dragonvoid => Some(Box::new(strikes::Dragonvoid::new(log))),
}
}
|