Address code review.

This commit is contained in:
holychowders 2022-04-17 13:50:50 -05:00
parent 3a3e7d3055
commit dda85e4bc3
4 changed files with 39 additions and 24 deletions

View File

@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Themed Site CliffTown, hoodoo/arabic inspired stone structures inhabited by mountaineer NPCs. - Themed Site CliffTown, hoodoo/arabic inspired stone structures inhabited by mountaineer NPCs.
- NPCs now have rudimentary personalities - NPCs now have rudimentary personalities
- Added Belarusian translation - Added Belarusian translation
- Add FOV check for agents scanning for targets they are hostile to
### Changed ### Changed
@ -81,7 +82,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Convert giant trees to site2 - Convert giant trees to site2
- Add new upgraded travelers - Add new upgraded travelers
- Wallrunning - Wallrunning
- Add FOV check for agents scanning for targets they are hostile to
### Changed ### Changed

View File

@ -49,7 +49,8 @@ impl SpatialGrid {
} }
/// Get an iterator over the entities overlapping the provided axis aligned /// Get an iterator over the entities overlapping the provided axis aligned
/// bounding region. NOTE: for best optimization of the iterator use /// bounding region.
/// NOTE: for best optimization of the iterator use
/// `for_each` rather than a for loop. /// `for_each` rather than a for loop.
pub fn in_aabr<'a>(&'a self, aabr: Aabr<i32>) -> impl Iterator<Item = specs::Entity> + 'a { pub fn in_aabr<'a>(&'a self, aabr: Aabr<i32>) -> impl Iterator<Item = specs::Entity> + 'a {
let iter = |max_entity_radius, grid: &'a hashbrown::HashMap<_, _>, lg2_cell_size| { let iter = |max_entity_radius, grid: &'a hashbrown::HashMap<_, _>, lg2_cell_size| {

View File

@ -13,10 +13,9 @@ use crate::{
}, },
data::{AgentData, AttackData, Path, ReadData, Tactic, TargetData}, data::{AgentData, AttackData, Path, ReadData, Tactic, TargetData},
util::{ util::{
aim_projectile, are_our_owners_hostile, does_entity_see_other, aim_projectile, are_our_owners_hostile, does_entity_see_other, get_attacker_of_entity,
entity_looks_like_cultist, get_attacker_of_entity, get_entity_by_id, is_dead, get_entity_by_id, is_dead, is_dead_or_invulnerable, is_dressed_as_cultist,
is_dead_or_invulnerable, is_entity_a_village_guard, is_invulnerable, is_villager, is_invulnerable, is_village_guard, is_villager, stop_pursuing,
stop_pursuing,
}, },
}, },
}; };
@ -1434,7 +1433,7 @@ impl<'a> AgentData<'a> {
if is_villager(self.alignment) { if is_villager(self.alignment) {
if self.remembers_fight_with(target, read_data) { if self.remembers_fight_with(target, read_data) {
chat_villager_remembers_fighting(); chat_villager_remembers_fighting();
} else if entity_looks_like_cultist(target, read_data) { } else if is_dressed_as_cultist(target, read_data) {
chat("npc.speech.villager_cultist_alarm"); chat("npc.speech.villager_cultist_alarm");
} else { } else {
chat("npc.speech.menacing"); chat("npc.speech.menacing");
@ -1569,7 +1568,7 @@ impl<'a> AgentData<'a> {
let get_enemy = |entity: EcsEntity| { let get_enemy = |entity: EcsEntity| {
if self.is_entity_an_enemy(entity, read_data) { if self.is_entity_an_enemy(entity, read_data) {
Some(entity) Some(entity)
} else if self.defends_entity(entity, read_data) { } else if self.should_defend(entity, read_data) {
if let Some(attacker) = get_attacker_of_entity(entity, read_data) { if let Some(attacker) = get_attacker_of_entity(entity, read_data) {
if !is_alignment_passive_towards_entity(attacker) { if !is_alignment_passive_towards_entity(attacker) {
// aggro_on: attack immediately, do not warn/menace. // aggro_on: attack immediately, do not warn/menace.
@ -2398,10 +2397,10 @@ impl<'a> AgentData<'a> {
(entity != *self.entity) (entity != *self.entity)
&& (are_our_owners_hostile(self.alignment, alignment, read_data) && (are_our_owners_hostile(self.alignment, alignment, read_data)
|| self.remembers_fight_with(entity, read_data) || self.remembers_fight_with(entity, read_data)
|| self.is_villager_and_entity_is_cultist(entity, read_data)) || self.is_villager_and_is_entity_dressed_as_cultist(entity, read_data))
} }
fn defends_entity(&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);
let we_are_friendly = entity_alignment.map_or(false, |entity_alignment| { let we_are_friendly = entity_alignment.map_or(false, |entity_alignment| {
@ -2419,11 +2418,15 @@ impl<'a> AgentData<'a> {
matches!(entity_alignment, Some(Alignment::Owned(ouid)) if *self.uid == *ouid); matches!(entity_alignment, Some(Alignment::Owned(ouid)) if *self.uid == *ouid);
(we_are_friendly && we_share_species) (we_are_friendly && we_share_species)
|| (is_entity_a_village_guard(*self.entity, read_data) && is_villager(entity_alignment)) || (is_village_guard(*self.entity, read_data) && is_villager(entity_alignment))
|| self_owns_entity || self_owns_entity
} }
fn is_villager_and_entity_is_cultist(&self, entity: EcsEntity, read_data: &ReadData) -> bool { fn is_villager_and_is_entity_dressed_as_cultist(
is_villager(self.alignment) && entity_looks_like_cultist(entity, read_data) &self,
entity: EcsEntity,
read_data: &ReadData,
) -> bool {
is_villager(self.alignment) && is_dressed_as_cultist(entity, read_data)
} }
} }

View File

@ -132,7 +132,7 @@ pub fn is_villager(alignment: Option<&Alignment>) -> bool {
alignment.map_or(false, |alignment| matches!(alignment, Alignment::Npc)) alignment.map_or(false, |alignment| matches!(alignment, Alignment::Npc))
} }
pub fn is_entity_a_village_guard(entity: EcsEntity, read_data: &ReadData) -> bool { pub fn is_village_guard(entity: EcsEntity, read_data: &ReadData) -> bool {
read_data read_data
.stats .stats
.get(entity) .get(entity)
@ -164,6 +164,19 @@ pub fn positions_have_line_of_sight(pos_a: &Pos, pos_b: &Pos, read_data: &ReadDa
>= dist_sqrd >= dist_sqrd
} }
pub fn is_dressed_as_cultist(entity: EcsEntity, read_data: &ReadData) -> bool {
read_data
.inventories
.get(entity)
.map_or(false, |inventory| {
inventory
.equipped_items()
.filter(|item| item.tags().contains(&ItemTag::Cultist))
.count()
> 2
})
}
pub fn does_entity_see_other( pub fn does_entity_see_other(
agent: &Agent, agent: &Agent,
entity: EcsEntity, entity: EcsEntity,
@ -171,13 +184,13 @@ pub fn does_entity_see_other(
controller: &Controller, controller: &Controller,
read_data: &ReadData, read_data: &ReadData,
) -> bool { ) -> bool {
let stealth_coefficient = { let other_stealth_coefficient = {
let is_other_being_stealthy = read_data let is_other_stealthy = read_data
.char_states .char_states
.get(other) .get(other)
.map_or(false, CharacterState::is_stealthy); .map_or(false, CharacterState::is_stealthy);
if is_other_being_stealthy { if is_other_stealthy {
// TODO: We shouldn't have to check CharacterState. This should be factored in // TODO: We shouldn't have to check CharacterState. This should be factored in
// by the function (such as the one we're calling below) that supposedly // by the function (such as the one we're calling below) that supposedly
// computes a coefficient given stealthy-ness. // computes a coefficient given stealthy-ness.
@ -191,18 +204,16 @@ pub fn does_entity_see_other(
read_data.positions.get(entity), read_data.positions.get(entity),
read_data.positions.get(other), read_data.positions.get(other),
) { ) {
let dist = other_pos.0 - pos.0;
let dist_sqrd = other_pos.0.distance_squared(pos.0); let dist_sqrd = other_pos.0.distance_squared(pos.0);
let within_sight_dist = { let within_sight_dist = {
let sight_dist = agent.psyche.sight_dist / stealth_coefficient; let sight_dist = agent.psyche.sight_dist / other_stealth_coefficient;
dist_sqrd < sight_dist.powi(2) dist_sqrd < sight_dist.powi(2)
}; };
let within_fov = dist let within_fov = (other_pos.0 - pos.0)
.try_normalized() .try_normalized()
// FIXME: Should this be map_or(false)? .map_or(false, |v| v.dot(*controller.inputs.look_dir) > 0.15);
.map_or(true, |v| v.dot(*controller.inputs.look_dir) > 0.15);
within_sight_dist && positions_have_line_of_sight(pos, other_pos, read_data) && within_fov within_sight_dist && positions_have_line_of_sight(pos, other_pos, read_data) && within_fov
} else { } else {