diff options
Diffstat (limited to 'src/server.rs')
-rw-r--r-- | src/server.rs | 174 |
1 files changed, 135 insertions, 39 deletions
diff --git a/src/server.rs b/src/server.rs index e3d5a72..b2f22b3 100644 --- a/src/server.rs +++ b/src/server.rs @@ -189,6 +189,10 @@ fn move_to_target(position: Vec2, target_position: Vec2, max_distance: f32) -> ( } } +fn move_along_direction(position: Vec2, direction: Vec2, distance: f32) -> Vec2 { + position + distance * direction +} + fn imperative_attack_approach( entity_map: Res<EntityMap>, mut players: Query<(&PlayerId, &mut Imperative)>, @@ -198,7 +202,7 @@ fn imperative_attack_approach( ) { for (id, mut imperative) in players.iter_mut() { match *imperative { - Imperative::Attack(AttackKey::A, target_player) => { + Imperative::AttackTarget(_, target_player) => { let Some(entity) = entity_map.0.get(&id.0) else { *imperative = Imperative::Idle; return; @@ -242,7 +246,7 @@ fn imperative_attack_attack( ) { for (id, mut imperative) in players.iter_mut() { match *imperative { - Imperative::Attack(AttackKey::A, target_player) => { + Imperative::AttackTarget(_, target_player) => { let Some(entity) = entity_map.0.get(&id.0) else { *imperative = Imperative::Idle; return; @@ -269,24 +273,54 @@ fn imperative_attack_attack( }; if cooldown.a_cooldown.is_zero() { cooldown.a_cooldown = Duration::from_secs_f32(1.5); - let instant = *champion == Champion::Meele; + let projectile_type = if *champion == Champion::Meele { + ProjectileType::Instant(InstantProjectile { target_player }) + } else { + ProjectileType::Targeted(TargetedProjectile { + target_player, + position: position.0, + }) + }; commands.spawn(ProjectileBundle { projectile: Projectile { - target_player, source_player: *id, damage: 4., - instant, + type_: projectile_type, }, - position: ProjectilePosition(if instant { - target_position.0 - } else { - position.0 - }), replicate: Replicate::default(), }); } } } + Imperative::AttackDirection(_, direction) => { + let Some(entity) = entity_map.0.get(&id.0) else { + *imperative = Imperative::Idle; + return; + }; + let Ok(position) = positions.get_mut(*entity) else { + *imperative = Imperative::Idle; + return; + }; + let Ok(mut cooldown) = cooldowns.get_mut(*entity) else { + *imperative = Imperative::Idle; + return; + }; + if cooldown.a_cooldown.is_zero() { + cooldown.a_cooldown = Duration::from_secs_f32(1.5); + commands.spawn(ProjectileBundle { + projectile: Projectile { + source_player: *id, + damage: 4., + type_: ProjectileType::Free(FreeProjectile { + position: position.0, + direction, + starting_position: position.0, + }), + }, + replicate: Replicate::default(), + }); + } + } _ => {} } } @@ -296,24 +330,40 @@ const PROJECTILE_SPEED: f32 = 150.; fn projectile_move( entity_map: Res<EntityMap>, - mut projectile_positions: Query<&mut ProjectilePosition>, player_positions: Query<&PlayerPosition>, - projectiles: Query<(Entity, &mut Projectile)>, + mut projectiles: Query<&mut Projectile>, time: Res<Time>, ) { - for (entity, projectile) in projectiles.iter() { - if let Some(target_entity) = entity_map.0.get(&projectile.target_player.0) { - if let Ok(mut position) = projectile_positions.get_mut(entity) { - if let Ok(target_position) = player_positions.get(*target_entity) { - let (new_position, _) = move_to_target( - position.0, - target_position.0, - PROJECTILE_SPEED * time.delta().as_secs_f32(), - ); - position.0 = new_position; + for mut projectile in projectiles.iter_mut() { + let new_type = match projectile.type_.clone() { + ProjectileType::Free(mut free_projectile) => { + let new_position = move_along_direction( + free_projectile.position, + free_projectile.direction, + PROJECTILE_SPEED * time.delta().as_secs_f32(), + ); + free_projectile.position = new_position; + ProjectileType::Free(free_projectile) + } + ProjectileType::Instant(instant_projectile) => { + ProjectileType::Instant(instant_projectile) + } + ProjectileType::Targeted(mut targeted_projectile) => { + if let Some(target_entity) = entity_map.0.get(&targeted_projectile.target_player.0) + { + if let Ok(target_position) = player_positions.get(*target_entity) { + let (new_position, _) = move_to_target( + targeted_projectile.position.clone(), + target_position.0, + PROJECTILE_SPEED * time.delta().as_secs_f32(), + ); + targeted_projectile.position = new_position; + } } + ProjectileType::Targeted(targeted_projectile) } - } + }; + projectile.type_ = new_type; } } @@ -322,25 +372,71 @@ fn projectile_despawn( mut commands: Commands, mut healths: Query<&mut Health>, player_positions: Query<&PlayerPosition>, - projectile_positions: Query<&ProjectilePosition>, + projectile_targets: Query<(&PlayerId, &PlayerPosition)>, projectiles: Query<(Entity, &mut Projectile)>, ) { for (entity, projectile) in projectiles.iter() { - let Some(target_entity) = entity_map.0.get(&projectile.target_player.0) else { - commands.entity(entity).despawn(); - return; - }; - let Ok(position) = projectile_positions.get(entity) else { - commands.entity(entity).despawn(); - return; - }; - let Ok(target_position) = player_positions.get(*target_entity) else { - commands.entity(entity).despawn(); - return; - }; - if position.0.distance(target_position.0) <= f32::EPSILON { - if let Ok(mut health) = healths.get_mut(*target_entity) { - health.0 = (health.0 - projectile.damage).max(0.); + let (despawn, maybe_target_player): (bool, Option<PlayerId>) = (|| match &projectile.type_ { + ProjectileType::Free(free_projectile) => { + let mut maybe_target_player = None; + let mut maybe_target_distance = None; + for (player, position) in projectile_targets.iter() { + if *player == projectile.source_player { + continue; + } + let distance = free_projectile.position.distance(position.0); + if distance > PLAYER_RADIUS { + continue; + } + match maybe_target_distance { + Some(old_distance) => { + if distance < old_distance { + maybe_target_player = Some(player); + maybe_target_distance = Some(distance); + } + } + None => { + maybe_target_player = Some(player); + maybe_target_distance = Some(distance); + } + } + } + if let Some(target_player) = maybe_target_player { + (true, Some(*target_player)) + } else { + ( + free_projectile + .position + .distance(free_projectile.starting_position) + >= 10000.0, + None, + ) + } + } + ProjectileType::Instant(instant_projectile) => { + (true, Some(instant_projectile.target_player)) + } + ProjectileType::Targeted(targeted_projectile) => { + let Some(target_entity) = entity_map.0.get(&targeted_projectile.target_player.0) + else { + return (true, None); + }; + let Ok(target_position) = player_positions.get(*target_entity) else { + return (true, None); + }; + ( + targeted_projectile.position.distance(target_position.0) <= f32::EPSILON, + Some(targeted_projectile.target_player), + ) + } + })(); + if despawn { + if let Some(target_player) = maybe_target_player { + if let Some(target_entity) = entity_map.0.get(&target_player.0) { + if let Ok(mut health) = healths.get_mut(*target_entity) { + health.0 = (health.0 - projectile.damage).max(0.); + } + } } commands.entity(entity).despawn(); } |