From f7428e317d282856d05ffc37b6ba474c5e9973ce Mon Sep 17 00:00:00 2001 From: Alexander Foremny Date: Sun, 24 Mar 2024 14:32:01 +0100 Subject: feat: damage types --- src/server.rs | 150 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 90 insertions(+), 60 deletions(-) (limited to 'src/server.rs') diff --git a/src/server.rs b/src/server.rs index 01dfe93..4169178 100644 --- a/src/server.rs +++ b/src/server.rs @@ -478,39 +478,46 @@ fn projectile_despawn( entity_map: Res, mut commands: Commands, mut connection_manager: ResMut, - mut healths: Query<&mut Health>, - player_positions: Query<&PlayerPosition>, projectiles: Query<(Entity, &mut Projectile)>, - projectile_targets: Query<(&PlayerId, &PlayerPosition, &Shape)>, + mut targets: Query<( + Entity, + &PlayerId, + &PlayerPosition, + &Shape, + &EffectiveStats, + &mut Health, + )>, ) { for (entity, projectile) in projectiles.iter() { - let (despawn, maybe_target_player): (bool, Option) = (|| match &projectile.type_ { + let (despawn, hit_target): (bool, Option) = (|| match &projectile.type_ { ProjectileType::Free(free_projectile) => { - let mut maybe_target_player = None; - let mut maybe_target_distance = None; - for (player, position, player_shape) in projectile_targets.iter() { - if *player == projectile.source_player { + let mut closest_target: Option<(Entity, f32)> = None; + for ( + target_entity, + target_player_id, + target_player_position, + target_shape, + _target_effective_stats, + _target_health, + ) in targets.iter() + { + if *target_player_id == projectile.source_player { continue; } - let distance = free_projectile.position.distance(position.0); - if distance > player_shape.radius { + let target_distance = + free_projectile.position.distance(target_player_position.0); + if target_distance > target_shape.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); - } + let target_is_closer = closest_target + .map(|(_, closest_distance)| target_distance < closest_distance) + .unwrap_or(true); + if target_is_closer { + closest_target = Some((target_entity, target_distance)); } } - if let Some(target_player) = maybe_target_player { - (true, Some(*target_player)) + if let Some((target_entity, _)) = closest_target { + (true, Some(target_entity)) } else { ( free_projectile @@ -522,56 +529,79 @@ fn projectile_despawn( } } ProjectileType::Instant(instant_projectile) => { - (true, Some(instant_projectile.target_player)) + let Some(target_entity) = entity_map.0.get(&instant_projectile.target_player.0) + else { + return (true, None); + }; + (true, Some(*target_entity)) } 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 { + let Ok(( + target_entity, + _target_player_id, + target_player_position, + target_shape, + _target_effective_stats, + _target_health, + )) = targets.get(*target_entity) + else { return (true, None); }; - ( - targeted_projectile.position.distance(target_position.0) <= f32::EPSILON, - Some(targeted_projectile.target_player), - ) + if targeted_projectile + .position + .distance(target_player_position.0) + < target_shape.radius + { + (true, Some(target_entity)) + } else { + (false, None) + } } })(); 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) { - let damage = match projectile.type_ { - ProjectileType::Free(FreeProjectile { - position, - starting_position, - max_distance, - scale_damage: Some((min_multiplier, max_multiplier)), - .. - }) => { - let distance_traveled = - position.distance(starting_position) / max_distance; - let multiplier = - min_multiplier.lerp(max_multiplier, distance_traveled); - multiplier * projectile.damage - } - _ => projectile.damage, - }; - health.apply_damage(damage); - let _ = connection_manager - .send_message_to_target::( - HealthChanged(HealthEvent { - target_player, - health_gained: -damage, - }), - NetworkTarget::All, - ); - } - } - } commands.entity(entity).despawn(); } + let Some(hit_entity) = hit_target else { + continue; + }; + let Ok(( + _hit_entity, + hit_player_id, + _hit_player_position, + _hit_shape, + hit_effective_stats, + mut hit_health, + )) = targets.get_mut(hit_entity) + else { + continue; + }; + let damage = match projectile.type_ { + ProjectileType::Free(FreeProjectile { + position, + starting_position, + max_distance, + scale_damage: Some((min_multiplier, max_multiplier)), + .. + }) => { + let distance_traveled = position.distance(starting_position) / max_distance; + let multiplier = min_multiplier.lerp(max_multiplier, distance_traveled); + projectile.damage.scale(multiplier) + } + _ => projectile.damage, + }; + let applied_damage = damage.apply(hit_effective_stats.0); + hit_health.apply_damage(applied_damage); + let _ = connection_manager.send_message_to_target::( + HealthChanged(HealthEvent { + target_player: *hit_player_id, + health_gained: -applied_damage, + }), + NetworkTarget::All, + ); } } -- cgit v1.2.3