Keep defender-victim opinions as allies after a quarrel.

The clash penalty applied to every pair except defender looking at the victim, so the person being helped disliked the defender like a second enemy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-20 18:15:55 +03:00
co-authored by Cursor
parent 15017ad9a6
commit 9972b30257
4 changed files with 83 additions and 5 deletions
+21 -5
View File
@@ -1056,11 +1056,7 @@ internal static class TalkCircleSystem
OpinionStore.Get(person, other.Id) ?? 0);
var now = OpinionStore.Get(person, other.Id) ?? 0;
var shift = delta;
if (circle.VictimId is not null
&& other.Id.Equals(circle.VictimId, StringComparison.Ordinal)
&& circle.OpinionBaseline.TryGetValue(PairKey(person.Id, circle.VictimId), out var viewOfVictim)
&& Conflict.ShouldDefend(viewOfVictim, rules)
&& !person.Id.Equals(circle.VictimId, StringComparison.Ordinal))
if (AllyOfVictim(circle, person.Id, rules) && AllyOfVictim(circle, other.Id, rules))
{
shift = Math.Max(2, -delta / 4);
}
@@ -1076,6 +1072,26 @@ internal static class TalkCircleSystem
}
}
/// <summary>
/// Victim and anyone who joined on their side. Clash penalty is for opposite sides; allies
/// get a small plus instead — otherwise the victim's view of the defender falls like a fight.
/// </summary>
private static bool AllyOfVictim(ActiveTalkCircle circle, string personId, BehaviorDef? rules)
{
if (circle.VictimId is null)
{
return false;
}
if (personId.Equals(circle.VictimId, StringComparison.Ordinal))
{
return true;
}
return circle.OpinionBaseline.TryGetValue(PairKey(personId, circle.VictimId), out var viewOfVictim)
&& Conflict.ShouldDefend(viewOfVictim, rules);
}
private static void ApplyApology(School school, IReadOnlyList<Person> people, BehaviorDef? rules)
{
foreach (var person in people)