Add lesson whispers, teacher catch chance, and after-bell teacher talk.

Whispering cuts lesson skill gain from BehaviorDef; a teacher in the room may interrupt into a discipline circle, and pedagogy scales the pupil's opinion of the teacher.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-20 10:35:31 +03:00
co-authored by Cursor
parent cb869e4977
commit f7d5e0c042
22 changed files with 1061 additions and 36 deletions
+43 -2
View File
@@ -333,7 +333,7 @@ internal static class PresenceSystem
: slot.Kind == DaySlotKind.Lesson && lessons.Any(lesson => lesson.Period == slot.Index);
if (activity.IsActive && TalkActions.IsTalk(activity.ActionId))
{
if (!bound)
if (!bound || TalkActions.IsWhisper(activity.ActionId))
{
return null;
}
@@ -432,7 +432,48 @@ internal static class PresenceSystem
presence = PresenceStepper.StartWalk(presence, walks, decision.WalkTo, headingHome: false);
}
return decision.StartAction is not null && !activity.IsActive ? decision.StartAction : null;
if (decision.StartAction is not null && !activity.IsActive)
{
return decision.StartAction;
}
if (!activity.IsActive
&& decision.WalkTo is null
&& ShouldStartWhisper(school, person, state))
{
return TalkActions.Whisper;
}
return null;
}
private static bool ShouldStartWhisper(School school, Person person, ActorState state)
{
if (!state.BoundToLesson
|| !person.IsStudent
|| state.IsWalking
|| state.NodeId is null
|| state.DutyRoom is null
|| !state.NodeId.Equals(state.DutyRoom, StringComparison.Ordinal))
{
return false;
}
var location = school.Map?.NodeDef(state.NodeId);
if (location is null || !location.Equals("Classroom", StringComparison.Ordinal))
{
return false;
}
var rules = school.Catalog?.BehaviorRules;
var chance = (rules?.WhisperStartChance ?? 0.12f) * TalkCircles.Initiative(person.Traits, school.Catalog!);
var roll = TalkCircles.Roll01(
Seed.Mix(
school.PeopleSeed,
person.Id,
DateOnly.FromDateTime(school.Clock.Time).DayNumber,
Seed.WhisperSalt + (school.Clock.Time.Minute / 2)));
return TalkCircles.WhisperCaught(roll, chance, 0.5f, 1f);
}
private static Dictionary<(string Node, string Thing), int> SnapshotOccupied(School school, string exceptId)