Merge branch 'review/slice-9-ab-recheck'

This commit is contained in:
Leonid Pershin
2026-08-20 17:33:02 +03:00
6 changed files with 164 additions and 14 deletions
+25
View File
@@ -369,6 +369,31 @@ public static class TalkCircles
BehaviorDef? rules) =>
Math.Clamp(current + (rules?.TalkLanguageSkillPerHour ?? 0.005f) * hours, skill.Range.Min, skill.Range.Max);
/// <summary>
/// Enemies do not sit in the same circle. RankInvitees only looks at the initiator when
/// forming; a later join is a self-invite, so either side already treating the other as an
/// enemy is enough to refuse.
/// </summary>
public static bool JoinerFits(Person joiner, IReadOnlyList<Person> members, BehaviorDef? rules)
{
foreach (var member in members)
{
if (member.Id.Equals(joiner.Id, StringComparison.Ordinal))
{
continue;
}
joiner.Opinions.TryGetValue(member.Id, out var fromJoiner);
member.Opinions.TryGetValue(joiner.Id, out var fromMember);
if (IsEnemy(fromJoiner, rules) || IsEnemy(fromMember, rules))
{
return false;
}
}
return true;
}
/// <summary>Invite priority: friends, classmates, others. Enemies never invited.</summary>
public static IReadOnlyList<string> RankInvitees(
Person initiator,
+27 -13
View File
@@ -147,10 +147,10 @@ internal static class TalkCircleSystem
return TryStartPhone(school, person, nodeId, action);
}
var existing = FindOpenCircle(school, nodeId, actionId);
if (existing is not null)
var existing = FindOpenCircle(school, nodeId, actionId, person);
if (existing is not null && JoinCircle(school, existing, personId, action))
{
return JoinCircle(school, existing, personId, action);
return true;
}
return TryStartGroup(school, person, nodeId, action);
@@ -319,6 +319,14 @@ internal static class TalkCircleSystem
return false;
}
var sitting = circle.Members
.Select(id => school.Roster!.People.First(row => row.Id.Equals(id, StringComparison.Ordinal)))
.ToArray();
if (!TalkCircles.JoinerFits(person, sitting, rules))
{
return false;
}
circle.Members.Add(personId);
circle.Members.Sort(StringComparer.Ordinal);
school.TalkCircleByPerson[personId] = circle.Id;
@@ -326,20 +334,26 @@ internal static class TalkCircleSystem
return true;
}
private static ActiveTalkCircle? FindOpenCircle(School school, string nodeId, string actionId)
private static ActiveTalkCircle? FindOpenCircle(School school, string nodeId, string actionId, Person joiner)
{
var rules = school.Catalog!.BehaviorRules;
var max = TalkCircles.MaxSize(actionId, rules, [], school.Catalog);
foreach (var circle in school.TalkCirclesById.Values)
{
if (circle.NodeId.Equals(nodeId, StringComparison.Ordinal)
&& circle.ActionId.Equals(actionId, StringComparison.Ordinal)
&& circle.RemainingMinutes > 0)
if (!circle.NodeId.Equals(nodeId, StringComparison.Ordinal)
|| !circle.ActionId.Equals(actionId, StringComparison.Ordinal)
|| circle.RemainingMinutes <= 0
|| circle.Members.Count >= max)
{
var rules = school.Catalog!.BehaviorRules;
var max = TalkCircles.MaxSize(actionId, rules, [], school.Catalog);
if (circle.Members.Count < max)
{
return circle;
}
continue;
}
var sitting = circle.Members
.Select(id => school.Roster!.People.First(row => row.Id.Equals(id, StringComparison.Ordinal)))
.ToArray();
if (TalkCircles.JoinerFits(joiner, sitting, rules))
{
return circle;
}
}