Implement phase 35 dress appropriateness and school rules.
Adds outfit evaluation, morning home dressing, locker-room ChangeClothes with day-log events, PE/weather AI goals, dress-rules API, and tests.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
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);
|
||||
}
|
||||
|
||||
var next = lessons.Where(lesson => lesson.Period > slot.Index).OrderBy(lesson => lesson.Period).FirstOrDefault();
|
||||
if (next is not null)
|
||||
{
|
||||
return ApparelDresser.ModeForLesson(next.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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user