From 4a1a3f3eccc22fdd1314321678f7383f4a2e2ed4 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 5 Nov 2020 16:48:04 -0600 Subject: [PATCH] Roll now gives i-frames. --- common/src/comp/character_state.rs | 14 +++++++++++++ common/src/sys/beam.rs | 25 ++++++++++++++++++++---- common/src/sys/melee.rs | 22 +++++++++++++++++---- common/src/sys/projectile.rs | 18 +++++++++++++++-- common/src/sys/shockwave.rs | 15 +++++++++++--- server/src/events/entity_manipulation.rs | 9 ++++++++- 6 files changed, 89 insertions(+), 14 deletions(-) diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index f1b7e91502..e90ad1d404 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -145,6 +145,20 @@ impl CharacterState { // Check if state is the same without looking at the inner data std::mem::discriminant(self) == std::mem::discriminant(other) } + + pub fn is_invincible(&self) -> bool { + if let CharacterState::Roll(data) = self { + use utils::StageSection; + match data.stage_section { + StageSection::Buildup => data.static_data.buildup_iframes, + StageSection::Movement => data.static_data.movement_iframes, + StageSection::Recover => data.static_data.recover_iframes, + _ => false, + } + } else { + false + } + } } impl Default for CharacterState { diff --git a/common/src/sys/beam.rs b/common/src/sys/beam.rs index 0642e0e9f7..d5cd98eb98 100644 --- a/common/src/sys/beam.rs +++ b/common/src/sys/beam.rs @@ -1,7 +1,7 @@ use crate::{ comp::{ - group, Beam, BeamSegment, Body, Energy, EnergyChange, EnergySource, Health, HealthChange, - HealthSource, Last, Loadout, Ori, Pos, Scale, + group, Beam, BeamSegment, Body, CharacterState, Energy, EnergyChange, EnergySource, Health, + HealthChange, HealthSource, Last, Loadout, Ori, Pos, Scale, }, event::{EventBus, ServerEvent}, state::{DeltaTime, Time}, @@ -34,6 +34,7 @@ impl<'a> System<'a> for Sys { ReadStorage<'a, Energy>, WriteStorage<'a, BeamSegment>, WriteStorage<'a, Beam>, + ReadStorage<'a, CharacterState>, ); fn run( @@ -56,6 +57,7 @@ impl<'a> System<'a> for Sys { energies, mut beam_segments, mut beams, + char_states, ): Self::SystemData, ) { let mut server_emitter = server_bus.emitter(); @@ -112,7 +114,16 @@ impl<'a> System<'a> for Sys { }; // Go through all other effectable entities - for (b, uid_b, pos_b, last_pos_b_maybe, scale_b_maybe, health_b, body_b) in ( + for ( + b, + uid_b, + pos_b, + last_pos_b_maybe, + scale_b_maybe, + health_b, + body_b, + char_state_b_maybe, + ) in ( &entities, &uids, &positions, @@ -121,6 +132,7 @@ impl<'a> System<'a> for Sys { scales.maybe(), &healths, &bodies, + char_states.maybe(), ) .join() { @@ -134,6 +146,9 @@ impl<'a> System<'a> for Sys { let rad_b = body_b.radius() * scale_b; let height_b = body_b.height() * scale_b; + // Check if entity is immune to damage + let is_invincible = char_state_b_maybe.map_or(false, |c_s| c_s.is_invincible()); + // Check if it is a hit let hit = entity != b && !health_b.is_dead @@ -160,7 +175,9 @@ impl<'a> System<'a> for Sys { for (target, damage) in beam_segment.damages.iter() { if let Some(target) = target { - if *target != target_group { + if *target != target_group + || (!matches!(target, GroupTarget::InGroup) && is_invincible) + { continue; } } diff --git a/common/src/sys/melee.rs b/common/src/sys/melee.rs index c22371a9d4..0377765c63 100644 --- a/common/src/sys/melee.rs +++ b/common/src/sys/melee.rs @@ -1,5 +1,5 @@ use crate::{ - comp::{buff, group, Attacking, Body, Health, Loadout, Ori, Pos, Scale}, + comp::{buff, group, Attacking, Body, CharacterState, Health, Loadout, Ori, Pos, Scale}, event::{EventBus, LocalEvent, ServerEvent}, metrics::SysMetrics, span, @@ -31,6 +31,7 @@ impl<'a> System<'a> for Sys { ReadStorage<'a, Loadout>, ReadStorage<'a, group::Group>, WriteStorage<'a, Attacking>, + ReadStorage<'a, CharacterState>, ); fn run( @@ -49,6 +50,7 @@ impl<'a> System<'a> for Sys { loadouts, groups, mut attacking_storage, + char_states, ): Self::SystemData, ) { let start_time = std::time::Instant::now(); @@ -72,8 +74,15 @@ impl<'a> System<'a> for Sys { attack.applied = true; // Go through all other entities - for (b, pos_b, scale_b_maybe, health_b, body_b) in - (&entities, &positions, scales.maybe(), &healths, &bodies).join() + for (b, pos_b, scale_b_maybe, health_b, body_b, char_state_b_maybe) in ( + &entities, + &positions, + scales.maybe(), + &healths, + &bodies, + char_states.maybe(), + ) + .join() { // 2D versions let pos2 = Vec2::from(pos.0); @@ -85,6 +94,9 @@ impl<'a> System<'a> for Sys { let scale_b = scale_b_maybe.map_or(1.0, |s| s.0); let rad_b = body_b.radius() * scale_b; + // Check if entity is invincible + let is_invincible = char_state_b_maybe.map_or(false, |c_s| c_s.is_invincible()); + // Check if it is a hit if entity != b && !health_b.is_dead @@ -106,7 +118,9 @@ impl<'a> System<'a> for Sys { for (target, damage) in attack.damages.iter() { if let Some(target) = target { - if *target != target_group { + if *target != target_group + || (!matches!(target, GroupTarget::InGroup) && is_invincible) + { continue; } } diff --git a/common/src/sys/projectile.rs b/common/src/sys/projectile.rs index 0e4a8b2a07..023a7ce998 100644 --- a/common/src/sys/projectile.rs +++ b/common/src/sys/projectile.rs @@ -1,8 +1,8 @@ use crate::{ comp::{ buff::{BuffChange, BuffSource}, - projectile, EnergyChange, EnergySource, Group, HealthSource, Loadout, Ori, PhysicsState, - Pos, Projectile, Vel, + projectile, CharacterState, EnergyChange, EnergySource, Group, HealthSource, Loadout, Ori, + PhysicsState, Pos, Projectile, Vel, }, event::{EventBus, LocalEvent, ServerEvent}, metrics::SysMetrics, @@ -35,6 +35,7 @@ impl<'a> System<'a> for Sys { WriteStorage<'a, Projectile>, ReadStorage<'a, Loadout>, ReadStorage<'a, Group>, + ReadStorage<'a, CharacterState>, ); fn run( @@ -53,6 +54,7 @@ impl<'a> System<'a> for Sys { mut projectiles, loadouts, groups, + char_states, ): Self::SystemData, ) { let start_time = std::time::Instant::now(); @@ -102,6 +104,18 @@ impl<'a> System<'a> for Sys { continue; } + // Checks if entity is immune to damage + // TODO: When projectiles are reduced down to a collection of (target, effect)s, + // move this check there so that future projectiles intended for allies cannot + // be dodged by those allies + let entity_invincible = uid_allocator + .retrieve_entity_internal(other.into()) + .and_then(|e| char_states.get(e)) + .map_or(false, |c_s| c_s.is_invincible()); + if entity_invincible { + continue; + } + for effect in projectile.hit_entity.drain(..) { match effect { projectile::Effect::Damage(target, damage) => { diff --git a/common/src/sys/shockwave.rs b/common/src/sys/shockwave.rs index de13dfc17a..5d02caa340 100644 --- a/common/src/sys/shockwave.rs +++ b/common/src/sys/shockwave.rs @@ -1,7 +1,7 @@ use crate::{ comp::{ - group, Body, Health, HealthSource, Last, Loadout, Ori, PhysicsState, Pos, Scale, Shockwave, - ShockwaveHitEntities, + group, Body, CharacterState, Health, HealthSource, Last, Loadout, Ori, PhysicsState, Pos, + Scale, Shockwave, ShockwaveHitEntities, }, event::{EventBus, LocalEvent, ServerEvent}, state::{DeltaTime, Time}, @@ -36,6 +36,7 @@ impl<'a> System<'a> for Sys { ReadStorage<'a, PhysicsState>, WriteStorage<'a, Shockwave>, WriteStorage<'a, ShockwaveHitEntities>, + ReadStorage<'a, CharacterState>, ); fn run( @@ -59,6 +60,7 @@ impl<'a> System<'a> for Sys { physics_states, mut shockwaves, mut shockwave_hit_lists, + char_states, ): Self::SystemData, ) { let mut server_emitter = server_bus.emitter(); @@ -131,6 +133,7 @@ impl<'a> System<'a> for Sys { health_b, body_b, physics_state_b, + char_state_b_maybe, ) in ( &entities, &uids, @@ -141,6 +144,7 @@ impl<'a> System<'a> for Sys { &healths, &bodies, &physics_states, + char_states.maybe(), ) .join() { @@ -176,6 +180,9 @@ impl<'a> System<'a> for Sys { GroupTarget::OutOfGroup }; + // Check if entity is immune to damage + let is_invincible = char_state_b_maybe.map_or(false, |c_s| c_s.is_invincible()); + // Check if it is a hit let hit = entity != b && !health_b.is_dead @@ -193,7 +200,9 @@ impl<'a> System<'a> for Sys { if hit { for (target, damage) in shockwave.damages.iter() { if let Some(target) = target { - if *target != target_group { + if *target != target_group + || (!matches!(target, GroupTarget::InGroup) && is_invincible) + { continue; } } diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 91717fd532..05c42172fd 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -647,7 +647,14 @@ pub fn handle_explosion( .get(entity_b) .map_or(false, |h| !h.is_dead); - if is_alive { + let is_invincible = ecs + .read_storage::() + .get(entity_b) + .map_or(false, |c_s| c_s.is_invincible()); + + if is_alive + && (matches!(target, Some(GroupTarget::InGroup)) || !is_invincible) + { effect.modify_strength(strength); server.state().apply_effect(entity_b, effect, owner); // Apply energy change