aboutsummaryrefslogtreecommitdiffstats
path: root/src/server.rs
diff options
context:
space:
mode:
authorLibravatar Alexander Foremny <aforemny@posteo.de>2024-03-24 14:32:01 +0100
committerLibravatar Alexander Foremny <aforemny@posteo.de>2024-03-24 14:34:41 +0100
commitf7428e317d282856d05ffc37b6ba474c5e9973ce (patch)
treecf016b07c1145ad4b62c210eb739085c0639f407 /src/server.rs
parent1751960338fc7a08fec438a9b53c78118a35063a (diff)
feat: damage types
Diffstat (limited to 'src/server.rs')
-rw-r--r--src/server.rs150
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,
+ );
}
}