mod arrow; mod gun; mod thrown; use crate::{ GameState, aim::AimTarget, global_observer, heads::ActiveHeads, heads_database::HeadsDatabase, hitpoints::Hit, physics_layers::GameLayer, player::{Player, PlayerBodyMesh}, sounds::PlaySound, tb_entities::EnemySpawn, }; use avian3d::prelude::*; use bevy::prelude::*; use serde::{Deserialize, Serialize}; #[derive(Component)] pub struct Projectile { pub owner_head: usize, } #[derive(Event, Reflect)] pub enum TriggerState { Active, Inactive, } #[derive(Event, Reflect)] pub struct TriggerCashHeal; #[derive(Debug, Copy, Clone, PartialEq, Reflect, Default, Serialize, Deserialize)] pub enum HeadAbility { #[default] None, Arrow, Thrown, Gun, } #[derive(Debug, Reflect, Clone, Copy)] pub struct TriggerData { target: Option, dir: Dir3, rot: Quat, pos: Vec3, target_layer: GameLayer, head: usize, } impl TriggerData { pub fn new( target: Option, dir: Dir3, rot: Quat, pos: Vec3, target_layer: GameLayer, head: usize, ) -> Self { Self { target, dir, rot, pos, target_layer, head, } } } #[derive(Event, Reflect)] pub struct TriggerGun(pub TriggerData); #[derive(Event, Reflect)] pub struct TriggerArrow(pub TriggerData); #[derive(Event, Reflect)] pub struct TriggerThrow(pub TriggerData); pub fn plugin(app: &mut App) { app.add_plugins(gun::plugin); app.add_plugins(thrown::plugin); app.add_plugins(arrow::plugin); app.add_systems(Update, enemy_hit.run_if(in_state(GameState::Playing))); global_observer!(app, on_trigger_state); } fn enemy_hit( mut commands: Commands, mut collision_event_reader: EventReader, query_shot: Query<&Projectile>, query_npc: Query<&EnemySpawn>, heads_db: Res, ) { for CollisionStarted(e1, e2) in collision_event_reader.read() { if !query_shot.contains(*e1) && !query_shot.contains(*e2) { continue; } if !query_npc.contains(*e1) && !query_npc.contains(*e2) { continue; } let (enemy_entity, projectile) = if query_npc.contains(*e1) { (*e1, query_shot.get(*e2)) } else { (*e2, query_shot.get(*e1)) }; if let Ok(head) = projectile.map(|p| p.owner_head) { let damage = heads_db.head_stats(head).damage; commands.entity(enemy_entity).trigger(Hit { damage }); } } } fn on_trigger_state( trigger: Trigger, mut commands: Commands, player_rot: Query<&Transform, With>, player_query: Query<(&Transform, &AimTarget), With>, mut active_heads: Query<&mut ActiveHeads, With>, heads_db: Res, time: Res