using System.Text.Json.Serialization; using HSchool.Content; namespace HSchool.People; /// Stable kind ids written into and listed on . public static class OffenseKinds { public const string Quarrel = "quarrel"; public const string Fight = "fight"; public const string Reprimand = "reprimand"; public static string LocaleKey(string kind) => kind switch { Quarrel => "OffenseQuarrel", Fight => "OffenseFight", Reprimand => "OffenseReprimand", _ => "Offense" + char.ToUpperInvariant(kind[0]) + kind[1..], }; } /// One remembered misconduct. Sparse list on the person — not a discipline score. public sealed class OffenseRecord { public required string Kind { get; init; } public required DateTime Time { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? OtherPersonId { get; init; } } /// Appends recent offenses and drops the oldest when over the BehaviorDef ceiling. public static class OffenseMemory { public static bool IsEnabled(string kind, BehaviorDef rules) { foreach (var allowed in rules.OffenseMemoryKinds) { if (allowed.Equals(kind, StringComparison.Ordinal)) { return true; } } return false; } public static bool Record(Person person, string kind, DateTime time, string? otherPersonId, BehaviorDef rules) { ArgumentNullException.ThrowIfNull(person); ArgumentNullException.ThrowIfNull(rules); ArgumentException.ThrowIfNullOrWhiteSpace(kind); if (rules.OffenseMemoryMax <= 0 || !IsEnabled(kind, rules)) { return false; } var list = person.Offenses; if (list is null) { list = []; person.Offenses = list; } list.Add(new OffenseRecord { Kind = kind, Time = DateTime.SpecifyKind(time, DateTimeKind.Utc), OtherPersonId = string.IsNullOrWhiteSpace(otherPersonId) ? null : otherPersonId, }); while (list.Count > rules.OffenseMemoryMax) { list.RemoveAt(0); } return true; } public static string? OtherParticipant(string personId, string? victimId, IReadOnlyList members) { if (victimId is not null && !victimId.Equals(personId, StringComparison.Ordinal) && members.Contains(victimId, StringComparer.Ordinal)) { return victimId; } foreach (var member in members) { if (!member.Equals(personId, StringComparison.Ordinal)) { return member; } } return null; } }