Wire sick-teacher stay-home into cancelled lessons.

Heavy flu keeps the assigned teacher off the day plan; pupils get 48/73 no-teacher marks and a one-shot LessonCancelled notice instead of silent empty rooms.
This commit is contained in:
Leonid Pershin
2026-08-21 14:17:37 +03:00
parent e40bec3aa3
commit b314f50112
12 changed files with 366 additions and 9 deletions
@@ -54,6 +54,8 @@ internal static class LessonLearningSystem
teacherSkills[identity.Id] = personSkills.Values;
});
RaiseSickTeacherLessons(school, places, weekday, slot.Index);
world.Query(
in People,
(ref PersonIdentity identity, ref PersonSkills skills, ref PersonTraits traits, ref PersonNeeds needs, ref PersonRoles roles, ref Presence presence, ref PersonActivity activity) =>
@@ -208,6 +210,56 @@ internal static class LessonLearningSystem
&& teacher.NodeId is not null
&& teacher.NodeId.Equals(roomId, StringComparison.Ordinal);
/// <summary>
/// One school toast per class slot when the assigned teacher stayed home sick (slice 15).
/// Uses the morning day plan — re-rolling <see cref="DiseaseEffects.ShouldStayHome"/> at
/// lesson time can flip after severity ticks. Toilet trips keep the per-pupil log only.
/// </summary>
private static void RaiseSickTeacherLessons(
School school,
Dictionary<string, Presence> places,
int weekday,
int period)
{
if (school.Timetable is null || school.Roster is null || school.Catalog is null)
{
return;
}
foreach (var lesson in school.Timetable.Lessons)
{
if (lesson.Day != weekday || lesson.Period != period)
{
continue;
}
if (TeacherStandingIn(places, lesson.TeacherId, lesson.RoomId))
{
continue;
}
if (!school.Plans.TryGetValue(lesson.TeacherId, out var plan) || plan.Comes)
{
continue;
}
var teacher = school.Roster.People.FirstOrDefault(row =>
row.Id.Equals(lesson.TeacherId, StringComparison.Ordinal));
if (teacher is null
|| DiseaseEffects.StayHomeChance(teacher, school.Catalog, school.Clock.Time) <= 0f)
{
continue;
}
if (!school.TryClaimLessonNoTeacherEvent(lesson.ClassId, school.Clock.Time.Date, lesson.Period))
{
continue;
}
school.RaiseWorldEvent(new WorldEvent(EventTriggers.LessonNoTeacher, lesson.TeacherId));
}
}
private static LessonPlacement? CurrentLesson(School school, Person person, int weekday, int period)
{
foreach (var lesson in Duty.LessonsToday(person, ClassOf(school, person), school.Timetable, weekday))
+11
View File
@@ -19,6 +19,7 @@ public sealed class School : IDisposable
private readonly List<PersonLogEvent> _dayLog = [];
private readonly HashSet<string> _lessonLogOnce = new(StringComparer.Ordinal);
private readonly HashSet<string> _lessonMarkOnce = new(StringComparer.Ordinal);
private readonly HashSet<string> _lessonNoTeacherEventOnce = new(StringComparer.Ordinal);
private readonly List<WorldEvent> _worldEvents = [];
internal School(int id, string name, DateTime startDate, DefCatalog? catalog, MapLayout? map)
@@ -176,6 +177,7 @@ public sealed class School : IDisposable
LoggedActivity.Clear();
_lessonLogOnce.Clear();
_lessonMarkOnce.Clear();
_lessonNoTeacherEventOnce.Clear();
LastAttendanceSlot = null;
}
@@ -205,6 +207,15 @@ public sealed class School : IDisposable
return _lessonMarkOnce.Add(key);
}
/// <summary>
/// One school toast per class lesson slot when the assigned teacher stays home sick.
/// </summary>
internal bool TryClaimLessonNoTeacherEvent(string classId, DateTime day, int period)
{
var key = string.Concat(classId, "\0", day.ToString("yyyy-MM-dd"), "\0", period.ToString());
return _lessonNoTeacherEventOnce.Add(key);
}
public void QueueDecision(string personId)
{
ObjectDisposedException.ThrowIf(_disposed, this);