use bevy::prelude::*;
use de_core::gamestate::GameState;
use parry3d::query::Ray;
use crate::{
health::{HealthSet, LocalUpdateHealthEvent},
sightline::LineOfSight,
trail::LocalLaserTrailEvent,
AttackingSet,
};
pub(crate) struct LaserPlugin;
impl Plugin for LaserPlugin {
fn build(&self, app: &mut App) {
app.add_event::<LaserFireEvent>().add_systems(
Update,
fire.run_if(in_state(GameState::Playing))
.in_set(AttackingSet::Fire)
.before(HealthSet::Update),
);
}
}
#[derive(Event)]
pub(crate) struct LaserFireEvent {
attacker: Entity,
ray: Ray,
max_toi: f32,
damage: f32,
}
impl LaserFireEvent {
#[allow(dead_code)]
pub(crate) fn new(attacker: Entity, ray: Ray, max_toi: f32, damage: f32) -> Self {
Self {
attacker,
ray,
max_toi,
damage,
}
}
fn attacker(&self) -> Entity {
self.attacker
}
fn ray(&self) -> &Ray {
&self.ray
}
fn max_toi(&self) -> f32 {
self.max_toi
}
fn damage(&self) -> f32 {
self.damage
}
}
fn fire(
mut fires: EventReader<LaserFireEvent>,
sightline: LineOfSight,
mut health: EventWriter<LocalUpdateHealthEvent>,
mut trail: EventWriter<LocalLaserTrailEvent>,
) {
for fire in fires.read() {
let observation = sightline.sight(fire.ray(), fire.max_toi(), fire.attacker());
trail.send(LocalLaserTrailEvent::new(Ray::new(
fire.ray().origin,
observation.toi() * fire.ray().dir,
)));
if let Some(entity) = observation.entity() {
health.send(LocalUpdateHealthEvent::new(entity, -fire.damage()));
}
}
}