Persist talk opinions and pick topics by weight.

A finished circle never set Tick's peopleChanged bit, so people.json kept pre-talk numbers until morning drift. PickTopic compared a 0..total roll to a 0..1 cursor, so gossip almost never changed the subject.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-20 13:34:34 +03:00
co-authored by Cursor
parent 8d07b3606d
commit b38d0bb628
9 changed files with 298 additions and 2 deletions
+2 -2
View File
@@ -229,11 +229,11 @@ public static class TalkCircles
}
var total = candidates.Sum(pair => pair.Weight);
var roll = (seed & int.MaxValue) % Math.Max(1, (int)(total * 1000)) / 1000f;
var roll = Roll01(seed) * total;
var cursor = 0f;
foreach (var (topic, weight) in candidates.OrderBy(pair => pair.Topic.DefName, StringComparer.Ordinal))
{
cursor += weight / total;
cursor += weight;
if (roll <= cursor)
{
return topic.DefName;
+8
View File
@@ -136,6 +136,12 @@ public sealed class School : IDisposable
internal Dictionary<string, string> TalkCircleByPerson { get; } = new(StringComparer.Ordinal);
/// <summary>
/// A finished or interrupted circle wrote opinions onto the roster. <see cref="Tick"/>
/// returns this so the worker persists <c>people.json</c> — same seam as morning dress.
/// </summary>
internal bool RosterTalkDirty { get; set; }
internal void ResetDayLog()
{
_dayLog.Clear();
@@ -397,6 +403,8 @@ public sealed class School : IDisposable
peopleChanged |= AffinitySystem.Apply(this, talked);
}
peopleChanged |= RosterTalkDirty;
RosterTalkDirty = false;
return peopleChanged;
}
@@ -457,6 +457,7 @@ internal static class TalkCircleSystem
}
school.TalkCirclesById.Remove(circle.Id);
school.RosterTalkDirty = true;
}
private static bool TryCatchWhisper(School school, ActiveTalkCircle circle)