diff options
| -rw-r--r-- | src/analyzers/mod.rs | 4 | ||||
| -rw-r--r-- | src/analyzers/strikes.rs | 77 | 
2 files changed, 79 insertions, 2 deletions
| diff --git a/src/analyzers/mod.rs b/src/analyzers/mod.rs index 8f9b1ff..c27fefa 100644 --- a/src/analyzers/mod.rs +++ b/src/analyzers/mod.rs @@ -131,11 +131,11 @@ pub fn for_log<'l>(log: &'l Log) -> Option<Box<dyn Analyzer + 'l>> {          | Encounter::SuperKodanBrothers          | Encounter::FraenirOfJormag          | Encounter::Boneskinner -        | Encounter::WhisperOfJormag -        | Encounter::Dragonvoid => Some(Box::new(strikes::GenericStrike::new(log))), +        | 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))),      }  } diff --git a/src/analyzers/strikes.rs b/src/analyzers/strikes.rs index 4c43016..9244124 100644 --- a/src/analyzers/strikes.rs +++ b/src/analyzers/strikes.rs @@ -241,3 +241,80 @@ impl<'log> Analyzer for MinisterLi<'log> {          Outcome::from_bool(phase_change_count >= Self::MINIMUM_PHASE_COUNT)      }  } + +/// Analyzer for the Dragonvoid/Harvest Temple strike. +#[derive(Debug, Clone, Copy)] +pub struct Dragonvoid<'log> { +    log: &'log Log, +} + +impl<'log> Dragonvoid<'log> { +    pub const EXPECTED_TARGET_OFF_COUNT: usize = 2; + +    /// Create a new [`Dragonvoid`] 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 { +        Dragonvoid { log } +    } +} + +impl<'log> Analyzer for Dragonvoid<'log> { +    fn log(&self) -> &Log { +        self.log +    } + +    fn is_cm(&self) -> bool { +        // EoD strike CMs are not implemented yet as of 2022-03-31 +        false +    } + +    fn outcome(&self) -> Option<Outcome> { +        // check_reward is pointless because the reward is delayed. + +        // First, we find the right agent_addr +        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) { +                    // We find the amount of target off switches that occurred after a target on +                    // switch. +                    let mut is_on = false; +                    let mut target_off_count = 0; + +                    // The nested loop over events is not ideal, but it is currently the easiest +                    // way to implement this logic without trying to cram it into a single loop. +                    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) +    } +} | 
