use crate::shared::player::*; use crate::shared::projectile::*; use crate::shared::*; use bevy::ecs::system::*; use bevy::utils::Duration; use std::ops::*; #[derive(Copy, Clone, PartialEq, Debug, Deserialize, Serialize)] pub enum Ability { Activated(ActivatedAbility), Directional(DirectionalAbility), Targeted(TargetedAbility), } #[derive(Copy, Clone, PartialEq, Debug, Deserialize, Serialize)] pub enum TargetedAbility { MeeleAttack, RangedAttack, } impl TargetedAbility { pub fn to_projectile( self, source_player: PlayerId, position: Vec2, target_player: PlayerId, ) -> Projectile { match self { TargetedAbility::MeeleAttack => Projectile { type_: ProjectileType::Instant(InstantProjectile { target_player }), source_player, damage: 5., }, TargetedAbility::RangedAttack => Projectile { type_: ProjectileType::Targeted(TargetedProjectile { target_player, position, }), source_player, damage: 6., }, } } } #[derive(Copy, Clone, PartialEq, Debug, Deserialize, Serialize)] pub enum ActivatedAbility { Speed, } #[derive(Copy, Clone, PartialEq, Debug, Deserialize, Serialize)] pub enum DirectionalAbility { Dash, Spear, } pub struct DirectionalAbilityActivation( pub fn(commands: &mut Commands, source_player: PlayerId, direction: Vec2) -> (), ); impl DirectionalAbility { pub fn activate(self) -> DirectionalAbilityActivation { match self { DirectionalAbility::Dash => DirectionalAbilityActivation(dash_activation), DirectionalAbility::Spear => DirectionalAbilityActivation(spear_activation), } } } fn dash_activation(commands: &mut Commands, source_player: PlayerId, direction: Vec2) { commands.add(move |world: &mut World| { world.run_system_once( move |players: Query<(Entity, &PlayerId)>, mut set: ParamSet<( Query<&mut PlayerPosition>, Query<(&PlayerId, &PlayerPosition)>, )>| { let Some(source_entity) = ({ let mut source_entity = None; for (entity, player_id) in players.iter() { if *player_id != source_player { continue; } source_entity = Some(entity); break; } source_entity }) else { return; }; let Some(source_position) = ({ let positions = set.p0(); if let Ok(position) = positions.get(source_entity) { Some(*position) } else { None } }) else { return; }; let dash_end = { let dash_targets = set.p1(); dash_collision( source_player, source_position.0, direction, 150., &dash_targets, ) }; let mut positions = set.p0(); if let Ok(mut position) = positions.get_mut(source_entity) { position.0 = dash_end; } }, ) }); } pub fn dash_collision( source_id: PlayerId, dash_start: Vec2, dash_direction: Vec2, dash_max_distance: f32, player_positions: &Query<(&PlayerId, &PlayerPosition)>, ) -> Vec2 { let mut dash_collision = dash_max_distance * dash_direction; let mut collision = false; for (player_id, position) in player_positions.iter() { if *player_id == source_id { continue; } let player_position = position.0 - dash_start; let player_projection = player_position.project_onto(dash_collision); let player_rejection = player_position - player_projection; let scalar_factor = player_projection.dot(dash_collision).signum() * player_projection.length() / dash_collision.length(); if scalar_factor < 0. || scalar_factor > 1.0 { continue; } if player_rejection.length() < 2. * PLAYER_RADIUS { collision = true; dash_collision = player_projection; } } if collision { dash_start + (dash_collision.length() - 2. * PLAYER_RADIUS) * dash_collision.normalize_or_zero() } else { dash_start + dash_max_distance * dash_direction } } fn spear_activation(commands: &mut Commands, source_player: PlayerId, direction: Vec2) { commands.add(move |world: &mut World| { world.run_system_once( move |mut commands: Commands, players: Query<(&PlayerId, &PlayerPosition)>| { for (id, position) in players.iter() { if *id != source_player { continue; } commands.spawn(ProjectileBundle::new(Projectile { type_: ProjectileType::Free(FreeProjectile { position: position.0, direction, starting_position: position.0, }), source_player, damage: 15., })); } }, ) }); } #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] pub enum AbilitySlot { A, Q, W, E, R, F, G, } impl AbilitySlot { pub fn to_label(self) -> &'static str { match self { AbilitySlot::A => "A", AbilitySlot::Q => "Q", AbilitySlot::W => "W", AbilitySlot::E => "E", AbilitySlot::R => "R", AbilitySlot::F => "F", AbilitySlot::G => "G", } } pub fn all() -> Vec { vec![ AbilitySlot::A, AbilitySlot::Q, AbilitySlot::W, AbilitySlot::E, AbilitySlot::R, AbilitySlot::F, AbilitySlot::G, ] } } impl Index for [Duration; 7] { type Output = Duration; fn index(&self, ability_slot: AbilitySlot) -> &Self::Output { &self[ability_slot as usize] } } impl IndexMut for [Duration; 7] { fn index_mut(&mut self, ability_slot: AbilitySlot) -> &mut Self::Output { &mut self[ability_slot as usize] } }