Files
h-school/src/HSchool.Simulation/ApparelPresence.cs
T
Leonid Pershin e461a9f3e4 Fix PE change-clothes interruption and post-PE mode detection.
Add appropriateness tests for staging PE kit, wearing form before gym, and returning to everyday clothes after the lesson.
2026-08-20 06:31:41 +03:00

114 lines
3.7 KiB
C#

using HSchool.Ai;
using HSchool.Content;
using HSchool.People;
using HSchool.Schedule;
namespace HSchool.Simulation;
/// <summary>Builds apparel goal inputs for the decision planner.</summary>
internal static class ApparelPresence
{
public static ApparelActor Build(School school, Person person, SchoolClass? schoolClass)
{
if (school.Catalog is null || !person.IsStudent && !person.IsStaff)
{
return default;
}
var mode = ModeAt(school, person, schoolClass);
var issues = ApparelDresser.CurrentIssues(school, person, mode);
var kind = ApparelGoals.Classify(issues);
var room = ChangingRoomNode(school, person);
return new ApparelActor(person.Female, issues, kind, room);
}
public static void EnqueueOnWeatherChange(School school, OutdoorWeather before, OutdoorWeather after)
{
if (before.Tenths == after.Tenths && before.Precipitation == after.Precipitation)
{
return;
}
foreach (var person in school.Roster!.People.OrderBy(row => row.Id, StringComparer.Ordinal))
{
school.DecisionQueue.Enqueue(person.Id);
}
}
internal static ApparelMode ModeAt(School school, Person person, SchoolClass? schoolClass)
{
if (school.Catalog is null || school.Timetable is null)
{
return ApparelMode.Everyday;
}
var slot = SchoolDay.At(school.Catalog, school.Clock.Time, school.SchoolWeekDays);
var day = SchoolDay.WeekdayIndex(school.Clock.Time);
var lessons = Duty.LessonsToday(person, schoolClass, school.Timetable, day);
if (lessons.Count == 0)
{
return ApparelMode.Everyday;
}
if (slot.Kind == DaySlotKind.Lesson)
{
var current = lessons.FirstOrDefault(lesson => lesson.Period == slot.Index);
return ApparelDresser.ModeForLesson(current?.Subject);
}
if (slot.Kind == DaySlotKind.Break)
{
var justEnded = lessons.FirstOrDefault(lesson => lesson.Period == slot.Index);
if (justEnded is not null && ApparelDresser.ModeForLesson(justEnded.Subject) == ApparelMode.Pe)
{
return ApparelMode.Everyday;
}
var next = lessons.Where(lesson => lesson.Period > slot.Index).OrderBy(lesson => lesson.Period).FirstOrDefault();
if (next is not null)
{
return ApparelDresser.ModeForLesson(next.Subject);
}
return ApparelMode.Everyday;
}
var nextLesson = lessons.Where(lesson => lesson.Period > slot.Index).OrderBy(lesson => lesson.Period).FirstOrDefault();
if (nextLesson is not null)
{
return ApparelDresser.ModeForLesson(nextLesson.Subject);
}
var previous = lessons.Where(lesson => lesson.Period < slot.Index).OrderByDescending(lesson => lesson.Period).FirstOrDefault();
if (previous is not null && ApparelDresser.ModeForLesson(previous.Subject) == ApparelMode.Pe)
{
return ApparelMode.Everyday;
}
return ApparelMode.Everyday;
}
internal static string? ChangingRoomNode(School school, Person person)
{
if (person.LockerRoomId is { } assigned)
{
return assigned;
}
if (school.Map is null || school.Catalog is null)
{
return null;
}
var want = ApparelDresser.ChangingRoomDef(person.Female);
if (want is null)
{
return null;
}
return school.Map.Rooms
.FirstOrDefault(room => room.Def.Equals(want, StringComparison.Ordinal))
?.Id;
}
}