use std::collections::HashMap;
use crate::{AgentKind, EventKind, Log};
macro_rules! check_reward {
($log:expr) => {
let log: &Log = $log;
if log.was_rewarded() {
return Some(crate::analyzers::Outcome::Success);
}
};
}
pub fn boss_health(log: &Log) -> Option<u64> {
let mut health: Option<u64> = None;
for event in log.events() {
if let EventKind::MaxHealthUpdate {
agent_addr,
max_health,
} = *event.kind()
{
if log.is_boss(agent_addr) {
health = health.map(|h| h.max(max_health)).or(Some(max_health));
}
}
}
health
}
pub fn boss_is_dead(log: &Log) -> bool {
log.events().iter().any(
|ev| matches!(ev.kind(), EventKind::ChangeDead { agent_addr } if log.is_boss(*agent_addr)),
)
}
pub fn players_exit_after_boss(log: &Log) -> bool {
let mut player_exit = 0u64;
let mut boss_exit = 0u64;
for event in log.events() {
if let EventKind::ExitCombat { agent_addr } = event.kind() {
let agent = if let Some(a) = log.agent_by_addr(*agent_addr) {
a
} else {
continue;
};
match agent.kind() {
AgentKind::Player(_) if event.time() >= player_exit => {
player_exit = event.time();
}
AgentKind::Character(_)
if event.time() >= boss_exit && log.is_boss(*agent_addr) =>
{
boss_exit = event.time();
}
_ => (),
}
}
}
boss_exit != 0 && player_exit > boss_exit + 1000
}
pub fn buff_present(log: &Log, wanted_buff_id: u32) -> bool {
for event in log.events() {
if let EventKind::BuffApplication { buff_id, .. } = *event.kind() {
if buff_id == wanted_buff_id {
return true;
}
}
}
false
}
pub fn time_between_buffs(log: &Log, wanted_buff_id: u32) -> u64 {
let mut time_maps: HashMap<u64, Vec<u64>> = HashMap::new();
for event in log.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)
.filter(|x| *x > 50)
.min()
.unwrap_or(0)
}