diff options
author | Alexander Foremny <aforemny@posteo.de> | 2024-03-24 14:32:01 +0100 |
---|---|---|
committer | Alexander Foremny <aforemny@posteo.de> | 2024-03-24 14:34:41 +0100 |
commit | f7428e317d282856d05ffc37b6ba474c5e9973ce (patch) | |
tree | cf016b07c1145ad4b62c210eb739085c0639f407 /src/server.rs | |
parent | 1751960338fc7a08fec438a9b53c78118a35063a (diff) |
feat: damage types
Diffstat (limited to 'src/server.rs')
-rw-r--r-- | src/server.rs | 150 |
1 files changed, 90 insertions, 60 deletions
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<EntityMap>, mut commands: Commands, mut connection_manager: ResMut<ServerConnectionManager>, - 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<PlayerId>) = (|| match &projectile.type_ { + let (despawn, hit_target): (bool, Option<Entity>) = (|| 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::<Channel1, HealthChanged>( - 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::<Channel1, HealthChanged>( + HealthChanged(HealthEvent { + target_player: *hit_player_id, + health_gained: -applied_damage, + }), + NetworkTarget::All, + ); } } |