diff --git a/common/src/combat.rs b/common/src/combat.rs index a3a66c81be..56f8b12dfa 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -74,7 +74,7 @@ pub struct TargetInfo<'a> { #[derive(Clone, Copy)] pub struct AttackOptions { pub target_dodging: bool, - pub avoid_harm: bool, + pub may_harm: bool, pub target_group: GroupTarget, } @@ -181,7 +181,7 @@ impl Attack { ) -> bool { let AttackOptions { target_dodging, - avoid_harm, + may_harm, target_group, } = options; @@ -192,11 +192,11 @@ impl Attack { // it should avoid such "damage" or effect let avoid_damage = |attack_damage: &AttackDamage| { matches!(attack_damage.target, Some(GroupTarget::OutOfGroup)) - && (target_dodging || avoid_harm) + && (target_dodging || !may_harm) }; let avoid_effect = |attack_effect: &AttackEffect| { matches!(attack_effect.target, Some(GroupTarget::OutOfGroup)) - && (target_dodging || avoid_harm) + && (target_dodging || !may_harm) }; let is_crit = thread_rng().gen::() < self.crit_chance; let mut is_applied = false; @@ -456,16 +456,15 @@ impl Attack { } } -/// Checks if we should avoid negative effects from one player to another +/// Checks if we should allow negative effects from one player to another // FIXME: handle pets? // This code works only with players. // You still can kill someone's pet and // you still can be killed by someone's pet -pub fn avoid_player_harm(attacker: Option<&Player>, target: Option<&Player>) -> bool { - if let (Some(attacker), Some(target)) = (attacker, target) { - return attacker.disallow_harm(target); - } - false +pub fn may_harm(attacker: Option<&Player>, target: Option<&Player>) -> bool { + attacker + .zip(target) + .map_or(true, |(attacker, target)| attacker.may_harm(target)) } #[cfg(not(target_arch = "wasm32"))] diff --git a/common/src/comp/player.rs b/common/src/comp/player.rs index 183e2dc21d..76db8ddc55 100644 --- a/common/src/comp/player.rs +++ b/common/src/comp/player.rs @@ -24,7 +24,7 @@ pub struct Player { } impl BattleMode { - pub fn allow_harm(self, other: Self) -> bool { + pub fn may_harm(self, other: Self) -> bool { matches!((self, other), (BattleMode::PvP, BattleMode::PvP)) } } @@ -43,12 +43,7 @@ impl Player { /// Simple as tea, if they don't want the tea, don't make them drink the /// tea. /// You can make tea for yourself though. - pub fn allow_harm(&self, other: &Player) -> bool { - self.battle_mode.allow_harm(other.battle_mode) || self.uuid == other.uuid - } - - /// Inverse of `allow_harm`. Read its doc to learn more. - pub fn disallow_harm(&self, other: &Player) -> bool { !self.allow_harm(other) } + pub fn may_harm(&self, other: &Player) -> bool { self.battle_mode.may_harm(other.battle_mode) } pub fn is_valid(&self) -> bool { Self::alias_validate(&self.alias).is_ok() } diff --git a/common/systems/src/aura.rs b/common/systems/src/aura.rs index 1d9f2cb3a0..f9201b3d8d 100644 --- a/common/systems/src/aura.rs +++ b/common/systems/src/aura.rs @@ -170,21 +170,29 @@ fn activate_aura( // Add other specific buff conditions here _ => true, }; - let avoid_harm = || { + + // TODO: this check will disable friendly fire with PvE switch. + // + // Which means that you can't apply debuffs on you and your group + // even if it's intented mechanics. + // + // Not that we have this for now, but think about this + // when we will add this. + let may_harm = || { let owner = match source { BuffSource::Character { by } => { read_data.uid_allocator.retrieve_entity_internal(by.into()) }, _ => None, }; - owner.map_or(false, |attacker| { + owner.map_or(true, |attacker| { let attacker = read_data.players.get(attacker); let target = read_data.players.get(target); - combat::avoid_player_harm(attacker, target) + combat::may_harm(attacker, target) }) }; - conditions_held && (kind.is_buff() || !avoid_harm()) + conditions_held && (kind.is_buff() || may_harm()) }, }; diff --git a/common/systems/src/beam.rs b/common/systems/src/beam.rs index 959c61cd7f..86854bd814 100644 --- a/common/systems/src/beam.rs +++ b/common/systems/src/beam.rs @@ -214,14 +214,14 @@ impl<'a> System<'a> for Sys { }; - let avoid_harm = combat::avoid_player_harm( + let may_harm = combat::may_harm( beam_owner.and_then(|owner| read_data.players.get(owner)), read_data.players.get(target), ); let attack_options = AttackOptions { // No luck with dodging beams target_dodging: false, - avoid_harm, + may_harm, target_group, }; diff --git a/common/systems/src/melee.rs b/common/systems/src/melee.rs index aefdee9db1..433f6b48c5 100644 --- a/common/systems/src/melee.rs +++ b/common/systems/src/melee.rs @@ -162,14 +162,14 @@ impl<'a> System<'a> for Sys { char_state: read_data.char_states.get(target), }; - let avoid_harm = combat::avoid_player_harm( + let may_harm = combat::may_harm( read_data.players.get(attacker), read_data.players.get(target), ); let attack_options = AttackOptions { target_dodging, - avoid_harm, + may_harm, target_group, }; diff --git a/common/systems/src/projectile.rs b/common/systems/src/projectile.rs index 941e6f6254..4b48cf0d4d 100644 --- a/common/systems/src/projectile.rs +++ b/common/systems/src/projectile.rs @@ -281,7 +281,7 @@ fn dispatch_hit( }); } - let avoid_harm = combat::avoid_player_harm( + let may_harm = combat::may_harm( owner.and_then(|owner| read_data.players.get(owner)), read_data.players.get(target), ); @@ -290,7 +290,7 @@ fn dispatch_hit( // They say witchers can dodge arrows, // but we don't have witchers target_dodging: false, - avoid_harm, + may_harm, target_group: projectile_target_info.target_group, }; diff --git a/common/systems/src/shockwave.rs b/common/systems/src/shockwave.rs index 6e6a66bd65..86ad74eca7 100644 --- a/common/systems/src/shockwave.rs +++ b/common/systems/src/shockwave.rs @@ -209,14 +209,14 @@ impl<'a> System<'a> for Sys { char_state: read_data.character_states.get(target), }; - let avoid_harm = combat::avoid_player_harm( + let may_harm = combat::may_harm( shockwave_owner.and_then(|owner| read_data.players.get(owner)), read_data.players.get(target), ); let attack_options = AttackOptions { // Trying roll during earthquake isn't the best idea target_dodging: false, - avoid_harm, + may_harm, target_group, }; diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index ea10d993ad..c9e4fbff3f 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -888,7 +888,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o char_state: char_state_b_maybe, }; - let avoid_harm = combat::avoid_player_harm( + let may_harm = combat::may_harm( owner_entity.and_then(|owner| players.get(owner)), players.get(entity_b), ); @@ -896,7 +896,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o // cool guyz maybe don't look at explosions // but they still got hurt, it's not Hollywood target_dodging: false, - avoid_harm, + may_harm, target_group, }; @@ -929,11 +929,22 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o 1.0 - distance_squared / explosion.radius.powi(2) }; - let avoid_harm = || { + // Player check only accounts for PvP/PvE flag. + // + // But bombs are intented to do + // friendly fire. + // + // What exactly friendly fire is subject to discussion. + // As we probably want to minimize possibility of being dick + // even to your group members, the only exception is when + // you want to harm yourself. + // + // This can be changed later. + let may_harm = || { owner_entity.map_or(false, |attacker| { - let attacker = players.get(attacker); - let target = players.get(entity_b); - combat::avoid_player_harm(attacker, target) + let attacker_player = players.get(attacker); + let target_player = players.get(entity_b); + combat::may_harm(attacker_player, target_player) || attacker == entity_b }) }; if strength > 0.0 { @@ -944,7 +955,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o if is_alive { effect.modify_strength(strength); - if !(effect.is_harm() && avoid_harm()) { + if !effect.is_harm() || may_harm() { server.state().apply_effect(entity_b, effect.clone(), owner); } }