mod guid;
mod old;
pub use self::guid::*;
pub use self::old::*;
use crate::extract::transmute_field;
use crate::{extract::Extract, Event, Position, StateChange, TryExtract};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Effect {
pub time: u64,
pub effect_id: u32,
pub owner: u64,
pub moving_platform: u8,
pub location: EffectLocation,
pub duration: u32,
pub tracking_id: u32,
pub orientation: EffectOrientation,
}
impl Effect {
#[inline]
pub fn is_end(&self) -> bool {
self.effect_id == 0
}
}
impl Extract for Effect {
#[inline]
unsafe fn extract(event: &Event) -> Self {
let effect_id = event.skill_id;
let duration = transmute_field!(event.affinity as u32);
let tracking_id = transmute_field!(event.is_buffremove as u32);
let orientation = transmute_field!(event.is_shields as [i16; 3]);
Self {
time: event.time,
effect_id,
owner: event.src_agent,
moving_platform: event.is_flanking,
location: EffectLocation::extract(event),
duration,
tracking_id,
orientation: orientation.into(),
}
}
}
impl TryExtract for Effect {
#[inline]
fn can_extract(event: &Event) -> bool {
event.get_statechange() == StateChange::Effect
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum EffectLocation {
Agent(u64),
Position(Position),
}
impl Extract for EffectLocation {
#[inline]
unsafe fn extract(event: &Event) -> Self {
if event.dst_agent != 0 {
Self::Agent(event.dst_agent)
} else {
let pos = transmute_field!(event.value as [f32; 3]);
Self::Position(pos.into())
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EffectOrientation {
pub x: i16,
pub y: i16,
pub z: i16,
}
impl EffectOrientation {
pub const RATIO: f32 = 1000.0;
pub const MAX: f32 = i16::MAX as f32 / Self::RATIO;
pub const MIN: f32 = i16::MIN as f32 / Self::RATIO;
#[inline]
pub const fn new(x: i16, y: i16, z: i16) -> Self {
Self { x, y, z }
}
#[inline]
pub fn from_floats(x: f32, y: f32, z: f32) -> Self {
Self::new(Self::to_int(x), Self::to_int(y), Self::to_int(z))
}
#[inline]
pub fn to_float(int: i16) -> f32 {
int as f32 / Self::RATIO
}
#[inline]
pub fn to_int(float: f32) -> i16 {
(float * Self::RATIO).round() as i16
}
#[inline]
pub fn as_position(&self) -> Position {
Position::new(
Self::to_float(self.x),
Self::to_float(self.y),
Self::to_float(self.z),
)
}
#[inline]
pub fn as_rotation_matrix(&self) -> [[f32; 3]; 3] {
self.as_position().as_rotation_matrix()
}
#[inline]
pub fn rotate(&self, vector: Position) -> Position {
self.as_position().rotate(vector)
}
}
impl From<[i16; 3]> for EffectOrientation {
#[inline]
fn from(value: [i16; 3]) -> Self {
let [x, y, z] = value;
Self::new(x, y, z)
}
}
impl From<EffectOrientation> for [i16; 3] {
#[inline]
fn from(orientation: EffectOrientation) -> Self {
[orientation.x, orientation.y, orientation.z]
}
}
impl From<EffectOrientation> for Position {
#[inline]
fn from(orientation: EffectOrientation) -> Self {
orientation.as_position()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn orientation() {
let orient = EffectOrientation::from_floats(12.345, 6.789, 0.0);
assert_eq!(orient, EffectOrientation::new(12345, 6789, 0));
}
#[test]
fn orientation_round() {
assert_eq!(EffectOrientation::to_int(30.9999), 31000);
}
#[test]
fn orientation_saturate() {
let orient = EffectOrientation::from_floats(12345.0, -6789.0, 0.0);
assert_eq!(orient, EffectOrientation::new(i16::MAX, i16::MIN, 0));
}
}