Teach AI how to forgive

This commit is contained in:
juliancoffee 2021-07-14 18:26:29 +03:00
parent 325acc9daf
commit b6460f6c61
4 changed files with 35 additions and 6 deletions

View File

@ -22,6 +22,7 @@ impl Component for RtSimEntity {
pub enum RtSimEvent {
AddMemory(Memory),
SetMood(Memory),
ForgetEnemy(String),
PrintMemories,
}

View File

@ -500,6 +500,14 @@ pub struct Brain {
impl Brain {
pub fn add_memory(&mut self, memory: Memory) { self.memories.push(memory); }
pub fn forget_enemy(&mut self, to_forget: &str) {
self.memories.retain(|memory| {
!matches!(
&memory.item,
MemoryItem::CharacterFight {name, ..} if name == to_forget)
})
}
pub fn remembers_mood(&self) -> bool {
self.memories
.iter()
@ -538,8 +546,8 @@ impl Brain {
pub fn remembers_fight_with_character(&self, name_to_remember: &str) -> bool {
self.memories.iter().any(|memory| {
matches!(
&memory.item,
MemoryItem::CharacterFight { name, .. } if name == name_to_remember)
&memory.item,
MemoryItem::CharacterFight { name, .. } if name == name_to_remember)
})
}
}

View File

@ -82,6 +82,12 @@ impl RtSim {
.map(|entity| entity.brain.add_memory(memory));
}
pub fn forget_entity_enemy(&mut self, entity: RtSimId, name: &str) {
if let Some(entity) = self.entities.get_mut(entity) {
entity.brain.forget_enemy(name);
}
}
pub fn set_entity_mood(&mut self, entity: RtSimId, memory: Memory) {
self.entities
.get_mut(entity)

View File

@ -14,7 +14,7 @@ use common::{
invite::{InviteKind, InviteResponse},
item::{
tool::{AbilitySpec, ToolKind},
Item, ItemDesc, ItemKind, ConsumableKind,
ConsumableKind, Item, ItemDesc, ItemKind,
},
skills::{AxeSkill, BowSkill, HammerSkill, SceptreSkill, Skill, StaffSkill, SwordSkill},
Agent, Alignment, BehaviorCapability, BehaviorState, Body, CharacterAbility,
@ -418,6 +418,11 @@ impl<'a> System<'a> for Sys {
if let Some(tgt_health) = read_data.healths.get(target) {
// If target is dead, leave it
if tgt_health.is_dead {
if let Some(tgt_stats) =
data.rtsim_entity.and(read_data.stats.get(target))
{
rtsim_forget_enemy(&tgt_stats.name, agent);
}
relax(agent, controller, event_emitter);
// If the target is hostile
// (either based on alignment or if
@ -473,9 +478,8 @@ impl<'a> System<'a> for Sys {
};
data.attack(agent, controller, &target_data, &read_data);
// Remember this encounter if an RtSim entity
if let Some(tgt_stats) = data
.rtsim_entity
.and_then(|_| read_data.stats.get(attacker))
if let Some(tgt_stats) =
data.rtsim_entity.and(read_data.stats.get(attacker))
{
rtsim_new_enemy(&tgt_stats.name, agent, &read_data);
}
@ -524,6 +528,9 @@ impl<'a> System<'a> for Sys {
RtSimEvent::AddMemory(memory) => {
rtsim.insert_entity_memory(rtsim_entity.0, memory.clone());
},
RtSimEvent::ForgetEnemy(name) => {
rtsim.forget_entity_enemy(rtsim_entity.0, &name);
},
RtSimEvent::SetMood(memory) => {
rtsim.set_entity_mood(rtsim_entity.0, memory.clone());
},
@ -4125,6 +4132,13 @@ fn rtsim_new_enemy(target_name: &str, agent: &mut Agent, read_data: &ReadData) {
}));
}
fn rtsim_forget_enemy(target_name: &str, agent: &mut Agent) {
agent
.rtsim_controller
.events
.push(RtSimEvent::ForgetEnemy(target_name.to_owned()));
}
fn can_see_tgt(terrain: &TerrainGrid, pos: &Pos, tgt_pos: &Pos, dist_sqrd: f32) -> bool {
terrain
.ray(pos.0 + Vec3::unit_z(), tgt_pos.0 + Vec3::unit_z())