From ba8984e1a760b1fe76d284a5e94a8e295fc1702f Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 1 May 2023 12:16:40 +0100 Subject: [PATCH] Made NPC sentiment slightly more forgiving --- rtsim/src/data/sentiment.rs | 34 +++++++++++++++++++++++++--------- rtsim/src/rule/npc_ai.rs | 12 +++++++++++- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/rtsim/src/data/sentiment.rs b/rtsim/src/data/sentiment.rs index 45c5d9119d..de2d14ab99 100644 --- a/rtsim/src/data/sentiment.rs +++ b/rtsim/src/data/sentiment.rs @@ -56,15 +56,13 @@ pub struct Sentiments { impl Sentiments { /// Return the sentiment that is felt toward the given target. - pub fn toward(&self, target: impl Into) -> Sentiment { - self.map.get(&target.into()).copied().unwrap_or_default() + pub fn toward(&self, target: impl Into) -> &Sentiment { + self.map.get(&target.into()).unwrap_or(&Sentiment::DEFAULT) } - /// Change the sentiment toward the given target by the given amount, - /// capping out at the given value. - pub fn change_by(&mut self, target: impl Into, change: f32, cap: f32) { - let target = target.into(); - self.map.entry(target).or_default().change_by(change, cap); + /// Return the sentiment that is felt toward the given target. + pub fn toward_mut(&mut self, target: impl Into) -> &mut Sentiment { + self.map.entry(target.into()).or_default() } /// Progressively decay the sentiment back to a neutral sentiment. @@ -134,6 +132,7 @@ impl Sentiment { /// Substantial positive sentiments: NPC may go out of their way to help /// actors associated with the target, greet them, etc. pub const ALLY: f32 = 0.3; + const DEFAULT: Self = Self { positivity: 0 }; /// Very negative sentiments: NPC may confront the actor, get aggressive /// with them, or even use force against them. pub const ENEMY: f32 = -0.6; @@ -150,7 +149,7 @@ impl Sentiment { /// Minor positive sentiments: NPC might be more willing to provide /// information, give better trade deals, etc. pub const POSITIVE: f32 = 0.1; - /// Substantial positive sentiments: NPC may reject attempts to trade or + /// Substantial negative sentiments: NPC may reject attempts to trade or /// avoid actors associated with the target, insult them, but will not /// use physical force. pub const RIVAL: f32 = -0.3; @@ -161,7 +160,9 @@ impl Sentiment { fn value(&self) -> f32 { self.positivity as f32 * (1.0 / 126.0) } - fn change_by(&mut self, change: f32, cap: f32) { + /// Change the sentiment toward the given target by the given amount, + /// capping out at the given value. + pub fn change_by(&mut self, change: f32, cap: f32) { // There's a bit of ceremony here for two reasons: // 1) Very small changes should not be rounded to 0 // 2) Sentiment should never (over/under)flow @@ -176,6 +177,21 @@ impl Sentiment { } } + /// Limit the sentiment to the given value, either positive or negative. The + /// resulting sentiment is guaranteed to be less than the cap (at least, + /// as judged by [`Sentiment::is`]). + pub fn limit_below(&mut self, cap: f32) { + if cap > 0.0 { + self.positivity = self + .positivity + .min(((cap.min(1.0) * 126.0) as i8 - 1).max(0)); + } else { + self.positivity = self + .positivity + .max(((-cap.max(-1.0) * 126.0) as i8 + 1).min(0)); + } + } + fn decay(&mut self, rng: &mut impl Rng, dt: f32) { if self.positivity != 0 { // TODO: Find a slightly nicer way to have sentiment decay, perhaps even by diff --git a/rtsim/src/rule/npc_ai.rs b/rtsim/src/rule/npc_ai.rs index 45815c6a0c..588bf83dfc 100644 --- a/rtsim/src/rule/npc_ai.rs +++ b/rtsim/src/rule/npc_ai.rs @@ -972,7 +972,17 @@ fn check_inbox(ctx: &mut NpcCtx) -> Option { // killed. change *= -1.0; } - ctx.sentiments.change_by(killer, change, Sentiment::VILLAIN); + ctx.sentiments + .toward_mut(killer) + .change_by(change, Sentiment::VILLAIN); + } + + // This is a murder of a player. Feel bad for the player and stop + // attacking them. + if let Actor::Character(_) = actor { + ctx.sentiments + .toward_mut(actor) + .limit_below(Sentiment::ENEMY) } if ctx.sentiments.toward(actor).is(Sentiment::ENEMY) {