use bevy::prelude::*; use serde::{Deserialize, Serialize}; use crate::{fighter::attack::AttackHitbox, math::int::FGi32}; pub mod importer; pub mod move_compiler; pub enum MoveAngleKind { Normal(FGi32), Sakurai, } #[derive(Asset, Reflect, Serialize, Deserialize)] pub struct FighterAttackScript { pub hitboxes: Vec, pub iasa_frame: Option, pub wont_autocancel_window: Option<(u32, u32)>, pub landing_duration: Option, pub use_root_motion: bool } impl FighterAttackScript { pub fn validate(&self) -> Result<(), String> { for hitbox in &self.hitboxes { hitbox.validate()?; } for (index, left) in self.hitboxes.iter().enumerate() { for right in self.hitboxes.iter().skip(index + 1) { if left.id == right.id && left.start_frame < right.end_frame && right.start_frame < left.end_frame { return Err(format!( "hitbox id {} has overlapping intervals {}..{} and {}..{}", left.id, left.start_frame, left.end_frame, right.start_frame, right.end_frame )); } } } if let Some(wont_autocancel_window) = self.wont_autocancel_window { if wont_autocancel_window.0 > wont_autocancel_window.1 { return Err("autocancel window end precedes its start".into()); } } Ok(()) } }