Wire grade trail notices, dress mark factor, and truancy summons weights.

Lesson multipliers stay explicit in tests; poor marks and unexcused absences toast and may auto-summon, while illness stays excused.
This commit is contained in:
Leonid Pershin
2026-08-21 14:18:41 +03:00
parent 975ca4936e
commit 59a7023bc4
23 changed files with 762 additions and 13 deletions
@@ -0,0 +1,78 @@
using HSchool.Content;
using HSchool.People;
namespace HSchool.Simulation;
/// <summary>
/// After marks or absences: info toast, class-teacher log, and optional auto summons weight.
/// Illness absences do not become summons offenses.
/// </summary>
internal static class GradeTrailSystem
{
public static void AfterMark(School school, Person person)
{
if (school.Catalog?.BehaviorRules is not { } rules)
{
return;
}
TryReact(school, person, rules);
}
public static void AfterAbsent(School school, Person person, string? absenceReason)
{
if (school.Catalog?.BehaviorRules is not { } rules)
{
return;
}
if (GradeTrail.CountsAsSummonOffense(absenceReason)
&& OffenseMemory.Record(person, OffenseKinds.Truancy, school.Clock.Time, otherPersonId: null, rules))
{
school.RosterTalkDirty = true;
}
TryReact(school, person, rules);
}
private static void TryReact(School school, Person person, BehaviorDef rules)
{
if (!GradeTrail.IsPoor(person, rules))
{
return;
}
if (!school.TryClaimGradeTrailNotice(person.Id, school.Clock.Time.Date))
{
return;
}
school.RaiseWorldEvent(new WorldEvent(EventTriggers.PoorGradeTrail, person.Id));
var schoolClass = ClassOf(school, person);
if (schoolClass?.ClassTeacherId is { } teacherId)
{
school.AppendDayLog(new PersonLogEvent(
person.Id,
school.Clock.Time,
PersonLogTypes.ClassTeacherGradeNote,
teacherId));
}
if (rules.GradeTrailSummonChance > 0f)
{
DirectorSummonSystem.TryEnqueue(school, person.Id, rules.GradeTrailSummonChance);
}
}
private static SchoolClass? ClassOf(School school, Person person)
{
if (person.ClassId is null || school.Roster is null)
{
return null;
}
return school.Roster.Classes.FirstOrDefault(row =>
row.Id.Equals(person.ClassId, StringComparison.Ordinal));
}
}