Update decision-making phase and enhance localization for presence tracking
- Marked tasks as complete in the decision-making phase documentation, indicating readiness for implementation. - Updated the README to reflect the completion status of the decision-making phase. - Enhanced localization strings to include new presence tracking features, improving user experience. - Revised the game screen logic to display real-time presence status, including walking states for individuals. - Added tests to validate the new localization strings and presence functionalities, ensuring robust performance.
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
using Arch.Core;
|
||||
using HSchool.Ai;
|
||||
using HSchool.Content;
|
||||
using HSchool.People;
|
||||
using HSchool.Schedule;
|
||||
|
||||
namespace HSchool.Simulation;
|
||||
|
||||
/// <summary>
|
||||
/// Grows skills for people who are actually in the lesson: at the room, not walking, not off
|
||||
/// doing something else. The formula lives in <see cref="HSchool.Ai.LessonLearning"/>.
|
||||
/// </summary>
|
||||
internal static class LessonLearningSystem
|
||||
{
|
||||
private static readonly QueryDescription People =
|
||||
new QueryDescription().WithAll<PersonIdentity, PersonSkills, PersonTraits, PersonNeeds, PersonRoles, Presence, PersonActivity>();
|
||||
|
||||
public static void Apply(School school, double gameMinutes)
|
||||
{
|
||||
if (school.Catalog is null || school.Timetable is null || school.Roster is null || gameMinutes <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var rules = school.Catalog.BehaviorRules;
|
||||
if (rules is null || rules.LessonSkillPerHour <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var slot = SchoolDay.At(school.Catalog, school.Clock.Time, school.SchoolWeekDays);
|
||||
if (slot.Kind != DaySlotKind.Lesson)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var hours = (float)(gameMinutes / 60d);
|
||||
var weekday = SchoolDay.WeekdayIndex(school.Clock.Time);
|
||||
var catalog = school.Catalog;
|
||||
var world = school.World;
|
||||
world.Query(
|
||||
in People,
|
||||
(ref PersonIdentity identity, ref PersonSkills skills, ref PersonTraits traits, ref PersonNeeds needs, ref PersonRoles roles, ref Presence presence, ref PersonActivity activity) =>
|
||||
{
|
||||
if (activity.IsActive || presence.NodeId is null || presence.Path.Length > 0 || presence.RemainingMinutes > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var personId = identity.Id;
|
||||
var person = school.Roster.People.FirstOrDefault(row => row.Id.Equals(personId, StringComparison.Ordinal));
|
||||
if (person is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var lesson = CurrentLesson(school, person, weekday, slot.Index);
|
||||
if (lesson is null
|
||||
|| !presence.NodeId.Equals(lesson.RoomId, StringComparison.Ordinal)
|
||||
|| !catalog.Subjects.TryGetValue(lesson.Subject, out var subject))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var hunger = needs.Values.GetValueOrDefault("Hunger", 1f);
|
||||
foreach (var share in subject.Skills)
|
||||
{
|
||||
if (!catalog.Skills.TryGetValue(share.Skill, out var skill)
|
||||
|| skill.Abstract
|
||||
|| !skills.Values.TryGetValue(share.Skill, out var current))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
skills.Values[share.Skill] = LessonLearning.Gain(
|
||||
current,
|
||||
skill,
|
||||
share.Share,
|
||||
rules.LessonSkillPerHour,
|
||||
hours,
|
||||
hunger,
|
||||
TraitOffset(catalog, traits, share.Skill));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static LessonPlacement? CurrentLesson(School school, Person person, int weekday, int period)
|
||||
{
|
||||
foreach (var lesson in Duty.LessonsToday(person, ClassOf(school, person), school.Timetable, weekday))
|
||||
{
|
||||
if (lesson.Period == period)
|
||||
{
|
||||
return lesson;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static SchoolClass? ClassOf(School school, Person person)
|
||||
{
|
||||
if (person.ClassId is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return school.Roster?.Classes.FirstOrDefault(row => row.Id.Equals(person.ClassId, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private static int TraitOffset(DefCatalog catalog, PersonTraits traits, string skill)
|
||||
{
|
||||
var offset = 0;
|
||||
foreach (var name in traits.Ids)
|
||||
{
|
||||
if (!catalog.Traits.TryGetValue(name, out var trait))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var modifier in trait.SkillModifiers)
|
||||
{
|
||||
if (modifier.Skill.Equals(skill, StringComparison.Ordinal))
|
||||
{
|
||||
offset += modifier.Offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user