aboutsummaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
authorDaniel Schadt <kingdread@gmx.de>2020-05-08 14:22:22 +0200
committerDaniel Schadt <kingdread@gmx.de>2020-05-08 14:25:29 +0200
commita14ae10762a0dd1b7ef4c6e6293eced7c03d007f (patch)
treec22387ffc05a069b54eaeeaf53668eb3bba6bd46 /src/lib.rs
parentd8da3812b1884be490333bcc62632ddaec41fd56 (diff)
downloadevtclib-a14ae10762a0dd1b7ef4c6e6293eced7c03d007f.tar.gz
evtclib-a14ae10762a0dd1b7ef4c6e6293eced7c03d007f.tar.bz2
evtclib-a14ae10762a0dd1b7ef4c6e6293eced7c03d007f.zip
add first support for determining CMs
This still needs a bit of work, as some of them are untested (Conjured Amalgamate, Fractal CMs).
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs84
1 files changed, 84 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index e28e740..ebf211d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -66,6 +66,7 @@
//! While there are legitimate use cases for writing/modification support, they are currently not
//! implemented (but might be in a future version).
+use std::collections::HashMap;
use std::convert::TryFrom;
use std::marker::PhantomData;
@@ -79,6 +80,7 @@ pub mod event;
pub use event::{Event, EventKind};
pub mod gamedata;
+use gamedata::CmTrigger;
pub use gamedata::{Boss, EliteSpec, Profession};
/// Any error that can occur during the processing of evtc files.
@@ -775,6 +777,56 @@ impl Log {
///
/// Use those functions only if necessary, and prefer to cache the result if it will be reused!
impl Log {
+ /// Check whether the fight was done with challenge mote activated.
+ ///
+ /// This function always returns `false` if
+ /// * The fight was done without CM
+ /// * The fight does not have a CM
+ /// * We cannot determine whether the CM was active
+ /// * The boss is not known
+ pub fn is_cm(&self) -> bool {
+ let trigger = self
+ .encounter()
+ .map(Boss::cm_trigger)
+ .unwrap_or(CmTrigger::Unknown);
+ match trigger {
+ CmTrigger::HpThreshold(hp_threshold) => {
+ for event in self.events() {
+ if let EventKind::MaxHealthUpdate {
+ agent_addr,
+ max_health,
+ } = *event.kind()
+ {
+ if self.is_boss(agent_addr) && max_health >= hp_threshold as u64 {
+ return true;
+ }
+ }
+ }
+ false
+ }
+
+ CmTrigger::BuffPresent(wanted_buff_id) => {
+ for event in self.events() {
+ if let EventKind::BuffApplication { buff_id, .. } = *event.kind() {
+ if buff_id == wanted_buff_id {
+ return true;
+ }
+ }
+ }
+ false
+ }
+
+ CmTrigger::TimeBetweenBuffs(buff_id, threshold) => {
+ let tbb = time_between_buffs(&self.events, buff_id);
+ tbb != 0 && tbb <= threshold
+ }
+
+ CmTrigger::Always => true,
+
+ CmTrigger::None | CmTrigger::Unknown => false,
+ }
+ }
+
/// Get the timestamp of when the log was started.
///
/// The returned value is a unix timestamp in the local time zone.
@@ -915,3 +967,35 @@ fn set_agent_masters(data: &raw::Evtc, agents: &mut [Agent]) -> Result<(), EvtcE
}
Ok(())
}
+
+fn time_between_buffs(events: &[Event], wanted_buff_id: u32) -> u64 {
+ let mut time_maps: HashMap<u64, Vec<u64>> = HashMap::new();
+ for event in events {
+ if let EventKind::BuffApplication {
+ destination_agent_addr,
+ buff_id,
+ ..
+ } = event.kind()
+ {
+ if *buff_id == wanted_buff_id {
+ time_maps
+ .entry(*destination_agent_addr)
+ .or_default()
+ .push(event.time());
+ }
+ }
+ }
+ let timestamps = if let Some(ts) = time_maps.values().max_by_key(|v| v.len()) {
+ ts
+ } else {
+ return 0;
+ };
+ timestamps
+ .iter()
+ .zip(timestamps.iter().skip(1))
+ .map(|(a, b)| b - a)
+ // Arbitrary limit to filter out duplicated buff application events
+ .filter(|x| *x > 50)
+ .min()
+ .unwrap_or(0)
+}