evtc\effect/
effect51.rs
1use crate::extract::transmute_field;
2use crate::AgentId;
3use crate::{extract::Extract, Event, Position, StateChange, TryExtract};
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone)]
10#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11pub struct Effect51 {
12 pub time: u64,
14
15 pub source: AgentId,
17
18 pub effect_id: u32,
22
23 pub moving_platform: u8,
25
26 pub location: EffectLocation,
28
29 pub duration: u32,
31
32 pub tracking_id: u32,
34
35 pub orientation: EffectOrientation,
37}
38
39impl Effect51 {
40 #[inline]
42 pub fn is_end(&self) -> bool {
43 self.effect_id == 0
44 }
45}
46
47impl Extract for Effect51 {
48 #[inline]
49 unsafe fn extract(event: &Event) -> Self {
50 let effect_id = event.skill_id;
51 let duration = transmute_field!(event.affinity as u32);
52 let tracking_id = transmute_field!(event.is_buffremove as u32);
53 let orientation = transmute_field!(event.is_shields as [i16; 3]);
54
55 Self {
56 time: event.time,
57 effect_id,
58 source: AgentId::from_src(event),
59 moving_platform: event.is_flanking,
60 location: EffectLocation::extract(event),
61 duration,
62 tracking_id,
63 orientation: orientation.into(),
64 }
65 }
66}
67
68impl TryExtract for Effect51 {
69 #[inline]
70 fn can_extract(event: &Event) -> bool {
71 event.get_statechange() == StateChange::Effect51
72 }
73}
74
75#[derive(Debug, Clone, PartialEq)]
77#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
78pub enum EffectLocation {
79 Agent(u64),
80 Position(Position),
81}
82
83impl Extract for EffectLocation {
84 #[inline]
85 unsafe fn extract(event: &Event) -> Self {
86 if event.dst_agent != 0 {
87 Self::Agent(event.dst_agent)
88 } else {
89 let pos = transmute_field!(event.value as [f32; 3]);
90 Self::Position(pos.into())
91 }
92 }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq)]
99#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
100pub struct EffectOrientation {
101 pub x: i16,
102 pub y: i16,
103 pub z: i16,
104}
105
106impl EffectOrientation {
107 pub const RATIO: f32 = 1000.0;
109
110 pub const MAX: f32 = i16::MAX as f32 / Self::RATIO;
114
115 pub const MIN: f32 = i16::MIN as f32 / Self::RATIO;
119
120 #[inline]
122 pub const fn new(x: i16, y: i16, z: i16) -> Self {
123 Self { x, y, z }
124 }
125
126 #[inline]
128 pub fn from_floats(x: f32, y: f32, z: f32) -> Self {
129 Self::new(Self::to_int(x), Self::to_int(y), Self::to_int(z))
130 }
131
132 #[inline]
134 pub fn to_float(int: i16) -> f32 {
135 int as f32 / Self::RATIO
136 }
137
138 #[inline]
140 pub fn to_int(float: f32) -> i16 {
141 (float * Self::RATIO).round() as i16
142 }
143
144 #[inline]
146 pub fn as_position(&self) -> Position {
147 Position::new(
148 Self::to_float(self.x),
149 Self::to_float(self.y),
150 Self::to_float(self.z),
151 )
152 }
153
154 #[inline]
156 pub fn as_rotation_matrix(&self) -> [[f32; 3]; 3] {
157 self.as_position().as_rotation_matrix()
158 }
159
160 #[inline]
162 pub fn rotate(&self, vector: Position) -> Position {
163 self.as_position().rotate(vector)
164 }
165}
166
167impl From<[i16; 3]> for EffectOrientation {
168 #[inline]
169 fn from(value: [i16; 3]) -> Self {
170 let [x, y, z] = value;
171 Self::new(x, y, z)
172 }
173}
174
175impl From<EffectOrientation> for [i16; 3] {
176 #[inline]
177 fn from(orientation: EffectOrientation) -> Self {
178 [orientation.x, orientation.y, orientation.z]
179 }
180}
181
182impl From<EffectOrientation> for Position {
183 #[inline]
184 fn from(orientation: EffectOrientation) -> Self {
185 orientation.as_position()
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn orientation() {
195 let orient = EffectOrientation::from_floats(12.345, 6.789, 0.0);
196 assert_eq!(orient, EffectOrientation::new(12345, 6789, 0));
197 }
198
199 #[test]
200 fn orientation_round() {
201 assert_eq!(EffectOrientation::to_int(30.9999), 31000);
202 }
203
204 #[test]
205 fn orientation_saturate() {
206 let orient = EffectOrientation::from_floats(12345.0, -6789.0, 0.0);
207 assert_eq!(orient, EffectOrientation::new(i16::MAX, i16::MIN, 0));
208 }
209}