Enhance school day structure and decision-making for lunch breaks
- Updated `ai.md` to clarify the mechanics of hunger restoration and the importance of lunch breaks in the school schedule. - Revised `schedule.md` to detail the new lunch break structure, allowing for separate sittings for different grade levels. - Enhanced `Decision.cs` and `DecisionPlanner.cs` to incorporate logic for lunch breaks, ensuring that students only leave lessons during their designated lunch windows. - Updated `DayFrameDef` and related classes to support multiple lunch breaks and validate their configurations. - Adjusted tests to validate the new decision-making logic regarding lunch breaks and hunger management, ensuring robust functionality. - Improved localization strings to reflect changes in the school day structure and lunch functionalities.
This commit is contained in:
@@ -38,7 +38,8 @@ public readonly record struct ActorState(
|
||||
bool BoundToLesson,
|
||||
string? DutyRoom,
|
||||
IReadOnlyDictionary<string, float> Needs,
|
||||
Intent Intent);
|
||||
Intent Intent,
|
||||
bool LunchWindowOpen = false);
|
||||
|
||||
/// <summary>
|
||||
/// Picks a goal by weight and plans walk-then-do. No world, no clock — a table of inputs to an
|
||||
@@ -56,6 +57,14 @@ public static class DecisionPlanner
|
||||
/// <summary>Need at zero. Beats a lesson so a desperate toilet trip leaves class.</summary>
|
||||
public const float NeedWeightAtZero = 20f;
|
||||
|
||||
/// <summary>
|
||||
/// A sitting during this parallel's own lunch break. Above <see cref="DutyTravelWeight"/> so
|
||||
/// lunch beats walking on to the next room, below <see cref="DutyLessonWeight"/> so it never
|
||||
/// pulls anybody out of a lesson. Lunch is a timetable, not an urge: waiting for hunger to
|
||||
/// cross the threshold made the juniors miss their sitting and starve all afternoon.
|
||||
/// </summary>
|
||||
public const float LunchWeight = 6f;
|
||||
|
||||
public static Decision Decide(
|
||||
DefCatalog catalog,
|
||||
MapLayout map,
|
||||
@@ -193,19 +202,33 @@ public static class DecisionPlanner
|
||||
NeedDef need,
|
||||
float threshold)
|
||||
{
|
||||
if (need.Abstract || !state.Needs.TryGetValue(need.DefName, out var value) || value >= threshold)
|
||||
if (need.Abstract || !state.Needs.TryGetValue(need.DefName, out var value))
|
||||
{
|
||||
return Intent.None;
|
||||
}
|
||||
|
||||
var urgent = value < threshold;
|
||||
|
||||
// ActionForNeed already refuses a sitting outside its window, so an action that comes back
|
||||
// Lunch means this person's own break is open right now.
|
||||
var action = ActionForNeed(catalog, state, need.DefName);
|
||||
if (action is null || RoomFor(catalog, map, walks, state, occupied, action) is null)
|
||||
if (action is null || (!urgent && !action.Lunch))
|
||||
{
|
||||
return Intent.None;
|
||||
}
|
||||
|
||||
if (RoomFor(catalog, map, walks, state, occupied, action) is null)
|
||||
{
|
||||
return Intent.None;
|
||||
}
|
||||
|
||||
var span = Math.Max(threshold, 0.0001f);
|
||||
var weight = (threshold - value) / span * NeedWeightAtZero;
|
||||
var weight = urgent ? (threshold - value) / span * NeedWeightAtZero : 0f;
|
||||
if (action.Lunch)
|
||||
{
|
||||
weight = Math.Max(weight, LunchWeight);
|
||||
}
|
||||
|
||||
return new Intent(GoalKind.Need, need.DefName, weight, action.DefName);
|
||||
}
|
||||
|
||||
@@ -312,6 +335,14 @@ public static class DecisionPlanner
|
||||
continue;
|
||||
}
|
||||
|
||||
// A sitting is only on offer during this person's own lunch break. Outside it hunger
|
||||
// keeps building instead of pulling somebody out of a lesson — that is what keeps the
|
||||
// canteen from filling with the whole school at once.
|
||||
if (action.Lunch && !state.LunchWindowOpen)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (best is null || action.NeedGain > best.NeedGain)
|
||||
{
|
||||
best = action;
|
||||
|
||||
Reference in New Issue
Block a user