evtc/
strike.rs

1//! Bindings & utilities for any form of strikes (direct damage).
2
3use crate::{
4    event::{impl_common, CommonEvent},
5    extract::Extract,
6    Event, EventCategory, TryExtract,
7};
8use num_enum::{FromPrimitive, IntoPrimitive};
9
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12
13#[cfg(feature = "strum")]
14use strum::{Display, EnumCount, EnumIter, IntoStaticStr, VariantNames};
15
16/// Strike (direct damage) event.
17#[derive(Debug, Clone)]
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19pub struct StrikeEvent {
20    /// Common combat event information.
21    #[cfg_attr(feature = "serde", serde(flatten))]
22    pub common: CommonEvent,
23
24    /// Kind of strike.
25    pub strike: Strike,
26
27    /// Total damage inflicted.
28    pub total_damage: i32,
29
30    /// Damage inflicted to shields (barrier).
31    pub shield_damage: u32,
32
33    /// Whether target is currently downed.
34    pub target_downed: bool,
35}
36
37impl_common!(StrikeEvent);
38
39impl Extract for StrikeEvent {
40    #[inline]
41    unsafe fn extract(event: &Event) -> Self {
42        Self {
43            common: event.into(),
44            strike: event.result.into(),
45            total_damage: event.value,
46            shield_damage: event.overstack_value,
47            target_downed: event.is_offcycle == 1,
48        }
49    }
50}
51
52impl TryExtract for StrikeEvent {
53    #[inline]
54    fn can_extract(event: &Event) -> bool {
55        event.categorize() == EventCategory::Strike
56    }
57}
58
59/// Strike types.
60///
61/// *Arc calls this "combat result".*
62#[derive(
63    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, IntoPrimitive, FromPrimitive,
64)]
65#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
66#[cfg_attr(
67    feature = "strum",
68    derive(Display, EnumCount, EnumIter, IntoStaticStr, VariantNames)
69)]
70#[repr(u8)]
71pub enum Strike {
72    /// Normal damage strike.
73    ///
74    /// No crit, no glance.
75    Normal = 0,
76
77    /// Strike was critical.
78    Crit = 1,
79
80    /// Strike was glancing.
81    Glance = 2,
82
83    /// Strike was blocked.
84    ///
85    /// Due to Aegis, Chrono Shield 4 etc.
86    Block = 3,
87
88    /// Strike was evaded.
89    ///
90    /// Due to dodge, Mesmer Sword 2 etc.
91    Evade = 4,
92
93    /// Strike interrupted something.
94    Interrupt = 5,
95
96    /// Strike was absorbed.
97    ///
98    /// Usually due to an invulnerability like Guardian Renewed Focus.
99    Absorb = 6,
100
101    /// Strike missed.
102    ///
103    /// Due to blind etc.
104    Blind = 7,
105
106    /// Skill killed the target.
107    ///
108    /// Not a damage strike.
109    KillingBlow = 8,
110
111    /// Skill downed the target.
112    ///
113    /// Not a damage strike.
114    Downed = 9,
115
116    /// Skill dealt breakbar damage.
117    ///
118    /// Not a damage strike.
119    Breakbar = 10,
120
121    /// On-skill-activation event.
122    ///
123    /// Not a damage strike.
124    Activation = 11,
125
126    /// Skill crowd controlled the target.
127    ///
128    /// Not a damage strike.
129    CrowdControl = 12,
130
131    /// Unknown.
132    #[num_enum(catch_all)]
133    Unknown(u8),
134}
135
136impl Strike {
137    /// Whether the strike dealt health damage to the target.
138    #[inline]
139    pub const fn dealt_damage(&self) -> bool {
140        matches!(self, Self::Normal | Self::Crit | Self::Glance)
141    }
142}