Add appropriateness tests for staging PE kit, wearing form before gym, and returning to everyday clothes after the lesson.
114 lines
3.7 KiB
C#
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;
|
|
}
|
|
}
|