Complete phase 47 romance pack on generic orientation and affinity hooks.

Vanilla catalogs stay without crushes; a content pack ships the overlay so later mods can reuse it.
This commit is contained in:
Leonid Pershin
2026-08-20 10:42:42 +03:00
parent cb869e4977
commit d2911c3daf
43 changed files with 1840 additions and 29 deletions
+36
View File
@@ -0,0 +1,36 @@
using HSchool.People;
namespace HSchool.Simulation;
/// <summary>
/// Applies the catalog's affinity overlay after talk and morning opinion shifts.
/// No-ops when the catalog has no affinity rules.
/// </summary>
internal static class AffinitySystem
{
public static bool Apply(School school, IReadOnlyList<string>? justTalked = null)
{
if (school.Catalog is null || school.Roster is null)
{
return false;
}
var events = new List<AffinityEvent>();
events.AddRange(Affinity.Refresh(school.Catalog, school.Roster, school.Clock.Time));
if (justTalked is { Count: > 0 })
{
events.AddRange(Affinity.RebuffTalk(school.Catalog, school.Roster, justTalked, school.Clock.Time));
if (events.Count > 0)
{
events.AddRange(Affinity.Refresh(school.Catalog, school.Roster, school.Clock.Time));
}
}
foreach (var row in events)
{
school.AppendDayLog(new PersonLogEvent(row.PersonId, school.Clock.Time, row.Type, row.OtherId));
}
return events.Count > 0;
}
}
+29 -1
View File
@@ -31,7 +31,8 @@ public sealed record PersonLogEvent(string PersonId, DateTime Time, string Type,
ArgumentNullException.ThrowIfNull(catalog);
if (ThingDef is null)
{
return Type;
var emptyKey = TypeToLocaleKey(Type);
return catalog.HasText(locale, emptyKey) ? catalog.Text(locale, emptyKey) : Type;
}
if (Type.Equals(PersonLogTypes.ApparelReplaced, StringComparison.Ordinal))
@@ -85,8 +86,35 @@ public sealed record PersonLogEvent(string PersonId, DateTime Time, string Type,
return string.Format(CultureInfo.InvariantCulture, catalog.Text(locale, "TalkEnded"), topic);
}
var localeKey = TypeToLocaleKey(Type);
if (catalog.HasText(locale, localeKey))
{
var text = catalog.Text(locale, localeKey);
return string.Format(CultureInfo.InvariantCulture, text, ThingDef);
}
return Type;
}
private static string TypeToLocaleKey(string type)
{
var chars = new char[type.Length];
var length = 0;
var upper = true;
foreach (var character in type)
{
if (character == '-')
{
upper = true;
continue;
}
chars[length++] = upper ? char.ToUpperInvariant(character) : character;
upper = false;
}
return new string(chars, 0, length);
}
}
public readonly record struct PersonLogQuery(string? Search, bool Descending, int Page, int PageSize);
+3 -1
View File
@@ -360,7 +360,8 @@ public sealed class School : IDisposable
PresenceSystem.Enqueue(this, id);
}
foreach (var id in TalkCircleSystem.Apply(this, gameMinutes))
var talked = TalkCircleSystem.Apply(this, gameMinutes);
foreach (var id in talked)
{
PresenceSystem.Enqueue(this, id);
}
@@ -376,6 +377,7 @@ public sealed class School : IDisposable
PresenceSystem.DrainDecisions(this);
LessonLearningSystem.Apply(this, gameMinutes);
peopleChanged |= ApparelWear.Apply(this, gameMinutes, Clock.Time.AddMinutes(-gameMinutes));
peopleChanged |= AffinitySystem.Apply(this, talked);
}
return peopleChanged;