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
use crate::{Activation, BuffRemove, Event, StateChange};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg(feature = "strum")]
use strum::{Display, EnumCount, EnumIter, IntoStaticStr, VariantNames};

/// Possible [`Event`] categories.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
    feature = "strum",
    derive(Display, EnumCount, EnumIter, IntoStaticStr, VariantNames)
)]
pub enum EventCategory {
    /// State change event.
    ///
    /// See variants of [`StateChange`] for details.
    StateChange,

    /// Activation (cast) event.
    ///
    /// `is_activation` contains [`Activation`] (except [`Activation::None`]).
    ///
    /// For [`Activation::Start`] and [`Activation::QuicknessUnused`]:
    /// `value` contains the duration at which all "significant" effects associated with the cast have happened (for example damage hits).
    /// `buff_dmg` contains the duration at which control is expected to be returned to the character (for example aftercasts).
    ///
    /// For [`Activation::CancelFire`] and [`Activation::CancelCancel`]:
    /// `value` contains the time spent in animation.
    /// `buff_dmg` contains the duration of the scaled (as if not affected) time spent.
    ///
    /// `dst_agent` contains x/y of target of skill effect.
    /// `overstack_value` contains z of target of skill effect.
    ///
    /// All durations and times are given in milliseconds.
    ///
    /// For skill data see [`SkillInfo`](crate::skill::SkillInfo) and [`SkillTiming`](crate::skill::SkillTiming).
    Activation,

    /// Buff removed.
    ///
    /// `is_buffremove` contains [`BuffRemove`] (except [`BuffRemove::None`]).
    /// `skill_id` contains the buff id.
    /// `buff` will be non-zero.
    ///
    /// `src_agent` is agent that had buff removed.
    /// `dst_agent` is the agent that caused the buff to be removed.
    ///
    /// `value` contains the remaining time on the removed buff calculated as duration.
    /// `buff_dmg` contains the remaining time on the removed buff calculated as intensity
    /// *Warning: this can overflow on [`BuffRemove::All`], use as sum check only!*
    ///
    /// For [`BuffRemove::All`] `result` contains the number of stacks removed
    ///
    /// For [`BuffRemove::Single`] `pad61` to `pad64` contains the buff instance id of buff removed.
    ///
    /// For buff data see [`BuffInfo`](crate::buff::BuffInfo) and [`BuffFormula`](crate::buff::BuffFormula).
    BuffRemove,

    /// Buff applied.
    ///
    /// `skill_id` contains the buff id.
    /// `buff` will be non-zero.
    ///
    /// `value` contains the duration in milliseconds applied.
    /// `pad61` to `pad64` contains the buff instance id of the buff applied.
    /// `is_shields` contains the stack active status.
    ///
    /// If `is_offcycle == 0`, `overstack_value` contains the duration of the existing buff stack that is expected to be replaced.
    /// If `is_offcycle != 0`, `overstack_value` contains the new duration of the existing buff stack and `value` contains the duration change (no new buff stack added).
    ///
    /// For buff data see [`BuffInfo`](crate::buff::BuffInfo) and [`BuffFormula`](crate::buff::BuffFormula).
    BuffApply,

    /// Buff damage.
    ///
    /// `skill_id` contains the buff id.
    /// `buff` will be non-zero.
    ///
    /// `buff_dmg` contains the damage dealt in Arc's damage simulation.
    /// If `is_offcycle == 0`, damage is accumulated by tick (for example Bleeding tick).
    /// If `is_offcycle != 0`, damage is accumulated reactively (for example Confusion damage on skill use).
    /// `result` contains `0` if expected to hit, `1` for invulnerability by buff and `2`/`3`/`4` for invulnerability by skill.
    ///
    /// For buff data see [`BuffInfo`](crate::buff::BuffInfo) and [`BuffFormula`](crate::buff::BuffFormula).
    BuffDamage,

    /// Direct damage strike.
    ///
    /// `value` contains the combined shield (barrier) and health damage dealt.
    /// `overstack_value` contains the shield (barrier) damage dealt.
    /// `is_offcycle == 1` if target is currently downed.
    /// `result` contains [`Strike`](crate::Strike).
    Strike,
}

impl From<&Event> for EventCategory {
    #[inline]
    fn from(event: &Event) -> Self {
        let statechange = event.get_statechange();
        if statechange == StateChange::None
            || (statechange == StateChange::BuffInitial && event.buff != 18)
        {
            if event.get_activation() != Activation::None {
                EventCategory::Activation
            } else if event.get_buffremove() != BuffRemove::None {
                EventCategory::BuffRemove
            } else if event.buff != 0 {
                if event.buff_dmg == 0 {
                    EventCategory::BuffApply
                } else {
                    EventCategory::BuffDamage
                }
            } else {
                EventCategory::Strike
            }
        } else {
            EventCategory::StateChange
        }
    }
}