Add AI parent meetings after a class last lesson.
Class teachers rarely keep the homeroom; invited parents walk onto the map, opinions nudge, then parents leave OffCampus. No player schedule API.
This commit is contained in:
@@ -153,6 +153,14 @@ public sealed class School : IDisposable
|
||||
|
||||
internal int NextSummonOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Active parent meetings. Worker thread only — never HTTP. Cleared on morning / skip.
|
||||
/// </summary>
|
||||
internal List<ParentMeetingSession> ActiveParentMeetings { get; } = [];
|
||||
|
||||
/// <summary>Class ids that already rolled a meeting chance today (pass or fail).</summary>
|
||||
internal HashSet<string> ParentMeetingRolledToday { get; } = new(StringComparer.Ordinal);
|
||||
|
||||
/// <summary>
|
||||
/// A finished or interrupted circle wrote opinions onto the roster. <see cref="Tick"/>
|
||||
/// returns this so the worker persists <c>people.json</c> — same seam as morning dress.
|
||||
@@ -314,6 +322,7 @@ public sealed class School : IDisposable
|
||||
Clock.JumpTo(next.Value);
|
||||
TalkCircleSystem.AbandonAll(this);
|
||||
DirectorSummonSystem.ClearAll(this);
|
||||
ParentMeetingSystem.ClearAll(this);
|
||||
ResetDayLog();
|
||||
var peopleChanged = TryYearlyIntake(before, next.Value);
|
||||
peopleChanged |= TryApplicantRefresh();
|
||||
@@ -388,6 +397,7 @@ public sealed class School : IDisposable
|
||||
ResetDayLog();
|
||||
// Hung summons do not survive the work morning — same clear as skip empty.
|
||||
DirectorSummonSystem.ClearAll(this);
|
||||
ParentMeetingSystem.ClearAll(this);
|
||||
}
|
||||
|
||||
peopleChanged = TryYearlyIntake(before, Clock.Time);
|
||||
@@ -445,6 +455,29 @@ public sealed class School : IDisposable
|
||||
public string? DirectorSummonPresenceActionId(string personId) =>
|
||||
DirectorSummonSystem.PresenceActionId(DirectorSummonPresencePhase(personId));
|
||||
|
||||
/// <summary>
|
||||
/// Card label while walking to / sitting in a parent meeting without a live activity yet.
|
||||
/// </summary>
|
||||
public string? ParentMeetingPresenceActionId(string personId)
|
||||
{
|
||||
if (!ParentMeetingSystem.IsInMeeting(this, personId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var session = ActiveParentMeetings.FirstOrDefault(row =>
|
||||
row.TeacherId.Equals(personId, StringComparison.Ordinal)
|
||||
|| row.AttendeeIds.Contains(personId));
|
||||
if (session is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return session.InProgress && session.TeacherId.Equals(personId, StringComparison.Ordinal)
|
||||
? HSchool.Ai.ParentMeetings.MeetingAction
|
||||
: HSchool.Ai.ParentMeetings.GoingAction;
|
||||
}
|
||||
|
||||
private void RecordWorldEvents(DateTime before, DateTime after)
|
||||
{
|
||||
_worldEvents.AddRange(EventSystem.Detect(this, before, after));
|
||||
@@ -469,6 +502,7 @@ public sealed class School : IDisposable
|
||||
}
|
||||
|
||||
DirectorSummonSystem.Apply(this);
|
||||
ParentMeetingSystem.Apply(this);
|
||||
|
||||
PersonDayLog.Sync(this);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user