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
use crate::{
    event::{impl_common, CommonEvent},
    extract::Extract,
    Event, EventCategory, TryExtract,
};

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

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

/// Buff apply event.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BuffApplyEvent {
    /// Common combat event information.
    #[cfg_attr(feature = "serde", serde(flatten))]
    pub common: CommonEvent,

    /// Kind of buff application/extension.
    pub apply: BuffApplyKind,

    /// Stack active status.
    pub stack_active: u8,

    /// Buff stack (instance) id.
    pub stack_id: u32,
}

impl_common!(BuffApplyEvent);

impl Extract for BuffApplyEvent {
    #[inline]
    unsafe fn extract(event: &Event) -> Self {
        Self {
            common: event.into(),
            apply: BuffApplyKind::extract(event),
            stack_active: event.is_shields,
            stack_id: event.get_pad_id(),
        }
    }
}

impl TryExtract for BuffApplyEvent {
    #[inline]
    fn can_extract(event: &Event) -> bool {
        event.categorize() == EventCategory::BuffApply
    }
}

/// Buff apply behavior.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "kind"))]
#[cfg_attr(
    feature = "strum",
    derive(Display, EnumCount, EnumIter, IntoStaticStr, VariantNames)
)]
#[repr(u8)]
pub enum BuffApplyKind {
    /// New stack applied or existing stack replaced.
    Apply {
        /// Applied duration.
        duration: i32,

        /// Duration of removed stack, if any.
        removed_duration: u32,
    },

    /// Existing stack extended.
    Extend {
        /// New stack duration.
        new_duration: u32,

        /// Duration change.
        duration_change: i32,
    },
}

impl Extract for BuffApplyKind {
    #[inline]
    unsafe fn extract(event: &Event) -> Self {
        if event.is_offcycle == 0 {
            Self::Apply {
                duration: event.value,
                removed_duration: event.overstack_value,
            }
        } else {
            Self::Extend {
                new_duration: event.overstack_value,
                duration_change: event.value,
            }
        }
    }
}