Merge branch 'holychowders/refactor_hostility_logic' into 'master'

Extract some retargeting logic.

See merge request veloren/veloren!3321
This commit is contained in:
Imbris 2022-04-11 17:49:43 +00:00
commit 9d521988b3

View File

@ -285,8 +285,8 @@ impl<'a> System<'a> for Sys {
.unwrap_or_else(Vec2::zero); .unwrap_or_else(Vec2::zero);
controller.push_basic_input(InputKind::Roll); controller.push_basic_input(InputKind::Roll);
} else { } else {
// Target an entity that's attacking us if the attack // Target an entity that's attacking us if the attack was recent and we have
// was recent and we have a health component // a health component
match health { match health {
Some(health) Some(health)
if read_data.time.0 - health.last_change.time.0 if read_data.time.0 - health.last_change.time.0
@ -300,9 +300,7 @@ impl<'a> System<'a> for Sys {
// means safezone), untarget them and idle. // means safezone), untarget them and idle.
if is_dead_or_invulnerable(attacker, &read_data) { if is_dead_or_invulnerable(attacker, &read_data) {
agent.target = None; agent.target = None;
} else if let Some(tgt_pos) = } else {
read_data.positions.get(attacker)
{
if agent.target.is_none() { if agent.target.is_none() {
controller.push_event(ControlEvent::Utterance( controller.push_event(ControlEvent::Utterance(
UtteranceKind::Angry, UtteranceKind::Angry,
@ -311,45 +309,12 @@ impl<'a> System<'a> for Sys {
// Determine whether the new target should be a priority // Determine whether the new target should be a priority
// over the old one (i.e: because it's either close or // over the old one (i.e: because it's either close or
// because they attacked us) // because they attacked us).
let more_dangerous_than_old_target = if agent.target.map_or(true, |target| {
agent.target.map_or(true, |old_tgt| { data.is_entity_more_dangerous_than_target(
if let Some(old_tgt_pos) = attacker, target, &read_data,
read_data.positions.get(old_tgt.target) )
{ }) {
// Fuzzy factor that makes it harder for
// players to cheese enemies by making them
// quickly flip aggro between two players.
// It
// does this by only switching aggro if the
// new target is closer to the enemy by a
// specific proportional threshold.
const FUZZY_DIST_COMPARISON: f32 = 0.8;
// Only switch to new target if it is closer
// than the old target, or if the old target
// had not triggered aggro (the new target
// has because damage always triggers it)
let old_tgt_not_threat = !old_tgt.aggro_on;
let old_tgt_further =
tgt_pos.0.distance(pos.0)
< old_tgt_pos.0.distance(pos.0)
* FUZZY_DIST_COMPARISON;
let new_tgt_hostile = read_data
.alignments
.get(attacker)
.zip(alignment)
.map_or(false, |(attacker, us)| {
us.hostile_towards(*attacker)
});
old_tgt_not_threat
|| (old_tgt_further && new_tgt_hostile)
} else {
true
}
});
// Select the attacker as the new target
if more_dangerous_than_old_target {
agent.target = Some(Target { agent.target = Some(Target {
target: attacker, target: attacker,
hostile: true, hostile: true,
@ -359,10 +324,13 @@ impl<'a> System<'a> for Sys {
} }
// Remember this attack if we're an RtSim entity // Remember this attack if we're an RtSim entity
if let Some(tgt_stats) = if let Some(attacker_stats) =
data.rtsim_entity.and(read_data.stats.get(attacker)) data.rtsim_entity.and(read_data.stats.get(attacker))
{ {
agent.add_enemy(&tgt_stats.name, read_data.time.0); agent.add_enemy(
&attacker_stats.name,
read_data.time.0,
);
} }
} }
} }
@ -2518,4 +2486,36 @@ impl<'a> AgentData<'a> {
fn below_flee_health(&self, agent: &Agent) -> bool { fn below_flee_health(&self, agent: &Agent) -> bool {
self.damage.min(1.0) < agent.psyche.flee_health self.damage.min(1.0) < agent.psyche.flee_health
} }
fn is_entity_more_dangerous_than_target(
&self,
entity: EcsEntity,
target: Target,
read_data: &ReadData,
) -> bool {
let entity_pos = read_data.positions.get(entity);
let target_pos = read_data.positions.get(target.target);
entity_pos.map_or(false, |entity_pos| {
target_pos.map_or(true, |target_pos| {
// Fuzzy factor that makes it harder for players to cheese enemies by making
// them quickly flip aggro between two players.
// It does this by only switching aggro if the entity is closer to the enemy by
// a specific proportional threshold.
const FUZZY_DIST_COMPARISON: f32 = 0.8;
let is_target_further = target_pos.0.distance(entity_pos.0)
< target_pos.0.distance(entity_pos.0) * FUZZY_DIST_COMPARISON;
let is_entity_hostile = read_data
.alignments
.get(entity)
.zip(self.alignment)
.map_or(false, |(entity, me)| me.hostile_towards(*entity));
// Consider entity more dangerous than target if entity is closer or if target
// had not triggered aggro.
!target.aggro_on || (is_target_further && is_entity_hostile)
})
})
}
} }