Enhance protocol and simulation features with activity tracking and behavior definitions
- Updated protocol documentation to include new `activity` and `activityLabel` fields in the person card response, reflecting real-time activity status. - Introduced `BehaviorDef` to define behavior rules, including need thresholds and lesson skill gains, enhancing AI decision-making. - Revised the `DefCatalog` to incorporate behavior definitions and updated validation logic to ensure proper behavior handling. - Enhanced the simulation to manage presence and activity states, allowing for more dynamic interactions within the school environment. - Updated tests to validate the new activity tracking and behavior functionalities, ensuring robust performance and reliability. - Improved localization strings to support new activity and behavior features, enhancing user experience.
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
using HSchool.Content;
|
||||
|
||||
namespace HSchool.Ai;
|
||||
|
||||
/// <summary>One in-progress action. <see cref="ActionId"/> is null when the person is idle.</summary>
|
||||
public readonly record struct ActivityProgress(string? ActionId, string? Thing, float RemainingMinutes)
|
||||
{
|
||||
public static ActivityProgress Idle { get; } = new(null, null, 0f);
|
||||
|
||||
public bool IsActive => ActionId is not null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start, countdown and refill for one action. Occupancy is a count check — two people cannot
|
||||
/// take the last chair. Simulation copies this onto components; the library has no world.
|
||||
/// </summary>
|
||||
public static class ActionStepper
|
||||
{
|
||||
public static ActivityProgress Begin(ActionDef def)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(def);
|
||||
var thing = string.IsNullOrWhiteSpace(def.Thing) ? null : def.Thing;
|
||||
return new ActivityProgress(def.DefName, thing, def.Minutes);
|
||||
}
|
||||
|
||||
public static ActivityProgress Advance(ActivityProgress activity, float minutes, out bool completed)
|
||||
{
|
||||
if (!activity.IsActive)
|
||||
{
|
||||
completed = false;
|
||||
return activity;
|
||||
}
|
||||
|
||||
var left = activity.RemainingMinutes - minutes;
|
||||
if (left <= 0f)
|
||||
{
|
||||
completed = true;
|
||||
return ActivityProgress.Idle;
|
||||
}
|
||||
|
||||
completed = false;
|
||||
return activity with { RemainingMinutes = left };
|
||||
}
|
||||
|
||||
public static bool CanOccupy(int available, int occupied) => occupied < available;
|
||||
|
||||
public static float ApplyNeedGain(float current, ActionDef action, NeedDef need)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(action);
|
||||
ArgumentNullException.ThrowIfNull(need);
|
||||
return Math.Clamp(current + action.NeedGain, need.Min, need.Max);
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,6 @@ public readonly record struct DayPlan(DateOnly Day, DateTime? AppearAt, DateTime
|
||||
|
||||
public static class DayPlans
|
||||
{
|
||||
private const int ExtraRollMax = 7;
|
||||
|
||||
public static DayPlan Build(
|
||||
DefCatalog catalog,
|
||||
WalkGraph walks,
|
||||
@@ -111,7 +109,15 @@ public static class DayPlans
|
||||
private static int SlackMinutes(DefCatalog catalog, Person person, int schoolSeed, DateOnly day)
|
||||
{
|
||||
var rng = new Random(Seed.Mix(schoolSeed, person.Id, day.DayNumber, Seed.CommuteSalt));
|
||||
var extra = rng.Next(0, ExtraRollMax);
|
||||
var min = 0;
|
||||
var max = 6;
|
||||
if (catalog.BehaviorRules is { } rules)
|
||||
{
|
||||
min = rules.CommuteSlackMin;
|
||||
max = rules.CommuteSlackMax;
|
||||
}
|
||||
|
||||
var extra = rng.Next(min, max + 1);
|
||||
foreach (var name in person.Traits)
|
||||
{
|
||||
if (catalog.Traits.TryGetValue(name, out var trait))
|
||||
|
||||
Reference in New Issue
Block a user