mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Make selfish bastards ambush people when they're alone.
This commit is contained in:
parent
c6bcdd7a2c
commit
753a51e683
@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Changed
|
### Changed
|
||||||
- Use fluent for translations
|
- Use fluent for translations
|
||||||
- First tab on Login screen triggers username focus
|
- First tab on Login screen triggers username focus
|
||||||
|
- Certain NPCs will now attack when alone with victim
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
@ -706,6 +706,8 @@ impl PersonalityBase {
|
|||||||
* don't want everyone to be completely weird.
|
* don't want everyone to be completely weird.
|
||||||
*/
|
*/
|
||||||
pub fn to_personality(&self) -> Personality {
|
pub fn to_personality(&self) -> Personality {
|
||||||
|
let will_ambush = self.agreeableness < Personality::LOW_THRESHOLD
|
||||||
|
&& self.conscientiousness < Personality::LOW_THRESHOLD;
|
||||||
let mut chat_traits: EnumSet<PersonalityTrait> = EnumSet::new();
|
let mut chat_traits: EnumSet<PersonalityTrait> = EnumSet::new();
|
||||||
if self.openness > Personality::HIGH_THRESHOLD {
|
if self.openness > Personality::HIGH_THRESHOLD {
|
||||||
chat_traits.insert(PersonalityTrait::Open);
|
chat_traits.insert(PersonalityTrait::Open);
|
||||||
@ -752,12 +754,14 @@ impl PersonalityBase {
|
|||||||
}
|
}
|
||||||
Personality {
|
Personality {
|
||||||
personality_traits: chat_traits,
|
personality_traits: chat_traits,
|
||||||
|
will_ambush,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Personality {
|
pub struct Personality {
|
||||||
pub personality_traits: EnumSet<PersonalityTrait>,
|
pub personality_traits: EnumSet<PersonalityTrait>,
|
||||||
|
pub will_ambush: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(EnumSetType)]
|
#[derive(EnumSetType)]
|
||||||
|
@ -48,6 +48,7 @@ use common::{
|
|||||||
};
|
};
|
||||||
use common_base::prof_span;
|
use common_base::prof_span;
|
||||||
use common_ecs::{Job, Origin, ParMode, Phase, System};
|
use common_ecs::{Job, Origin, ParMode, Phase, System};
|
||||||
|
use itertools::Itertools;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use rayon::iter::ParallelIterator;
|
use rayon::iter::ParallelIterator;
|
||||||
use specs::{Entity as EcsEntity, Join, ParJoin, Read, WriteExpect, WriteStorage};
|
use specs::{Entity as EcsEntity, Join, ParJoin, Read, WriteExpect, WriteStorage};
|
||||||
@ -748,11 +749,44 @@ impl<'a> AgentData<'a> {
|
|||||||
agent.action_state.timer = 0.0;
|
agent.action_state.timer = 0.0;
|
||||||
let mut aggro_on = false;
|
let mut aggro_on = false;
|
||||||
|
|
||||||
|
// Search the area.
|
||||||
|
// TODO: choose target by more than just distance
|
||||||
|
let common::CachedSpatialGrid(grid) = self.cached_spatial_grid;
|
||||||
|
|
||||||
|
let entities_nearby = grid
|
||||||
|
.in_circle_aabr(self.pos.0.xy(), agent.psyche.search_dist())
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
let can_ambush = |entity: EcsEntity, read_data: &ReadData| {
|
||||||
|
let self_different_from_entity = || {
|
||||||
|
read_data
|
||||||
|
.uids
|
||||||
|
.get(entity)
|
||||||
|
.map_or(false, |eu| eu != self.uid)
|
||||||
|
};
|
||||||
|
if self.will_ambush()
|
||||||
|
&& self_different_from_entity()
|
||||||
|
&& !self.passive_towards(entity, read_data)
|
||||||
|
{
|
||||||
|
let surrounding_humanoids = entities_nearby
|
||||||
|
.iter()
|
||||||
|
.filter(|e| read_data.bodies.get(**e).map_or(false, |b| b.is_humanoid()))
|
||||||
|
.collect_vec();
|
||||||
|
surrounding_humanoids.len() == 2
|
||||||
|
&& surrounding_humanoids.iter().any(|e| **e == entity)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let get_pos = |entity| read_data.positions.get(entity);
|
let get_pos = |entity| read_data.positions.get(entity);
|
||||||
let get_enemy = |(entity, attack_target): (EcsEntity, bool)| {
|
let get_enemy = |(entity, attack_target): (EcsEntity, bool)| {
|
||||||
if attack_target {
|
if attack_target {
|
||||||
if self.is_enemy(entity, read_data) {
|
if self.is_enemy(entity, read_data) {
|
||||||
Some((entity, true))
|
Some((entity, true))
|
||||||
|
} else if can_ambush(entity, read_data) {
|
||||||
|
aggro_on = true;
|
||||||
|
Some((entity, true))
|
||||||
} else if self.should_defend(entity, read_data) {
|
} else if self.should_defend(entity, read_data) {
|
||||||
if let Some(attacker) = get_attacker(entity, read_data) {
|
if let Some(attacker) = get_attacker(entity, read_data) {
|
||||||
if !self.passive_towards(attacker, read_data) {
|
if !self.passive_towards(attacker, read_data) {
|
||||||
@ -822,13 +856,9 @@ impl<'a> AgentData<'a> {
|
|||||||
|| self.can_see_entity(agent, controller, entity, e_pos, read_data)
|
|| self.can_see_entity(agent, controller, entity, e_pos, read_data)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Search the area.
|
let target = entities_nearby
|
||||||
// TODO: choose target by more than just distance
|
.iter()
|
||||||
let common::CachedSpatialGrid(grid) = self.cached_spatial_grid;
|
.filter_map(|e| is_valid_target(*e))
|
||||||
|
|
||||||
let target = grid
|
|
||||||
.in_circle_aabr(self.pos.0.xy(), agent.psyche.search_dist())
|
|
||||||
.filter_map(is_valid_target)
|
|
||||||
.filter_map(get_enemy)
|
.filter_map(get_enemy)
|
||||||
.filter_map(|(entity, attack_target)| {
|
.filter_map(|(entity, attack_target)| {
|
||||||
get_pos(entity).map(|pos| (entity, pos, attack_target))
|
get_pos(entity).map(|pos| (entity, pos, attack_target))
|
||||||
@ -1632,6 +1662,14 @@ impl<'a> AgentData<'a> {
|
|||||||
|| (is_villager(self.alignment) && is_dressed_as_cultist(entity, read_data)))
|
|| (is_villager(self.alignment) && is_dressed_as_cultist(entity, read_data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn will_ambush(&self) -> bool {
|
||||||
|
self.health
|
||||||
|
.map_or(false, |h| h.current() / h.maximum() > 0.7)
|
||||||
|
&& self
|
||||||
|
.rtsim_entity
|
||||||
|
.map_or(false, |re| re.brain.personality.will_ambush)
|
||||||
|
}
|
||||||
|
|
||||||
fn should_defend(&self, entity: EcsEntity, read_data: &ReadData) -> bool {
|
fn should_defend(&self, entity: EcsEntity, read_data: &ReadData) -> bool {
|
||||||
let entity_alignment = read_data.alignments.get(entity);
|
let entity_alignment = read_data.alignments.get(entity);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user