Avoid negative bounds in harm checks

* disallow_harm -> allow_harm to avoid negative reasoning since it mostly
requires double negation in code
* allow_harm -> may_harm to specify side-effect free
This commit is contained in:
juliancoffee 2021-07-31 20:53:09 +03:00
parent 44916383c6
commit 4766450258
8 changed files with 49 additions and 36 deletions

View File

@ -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::<f32>() < 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"))]

View File

@ -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() }

View File

@ -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())
},
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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,
};

View File

@ -888,7 +888,7 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, 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<f32>, 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<f32>, 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<f32>, 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);
}
}