172 lines
4.8 KiB
C#
172 lines
4.8 KiB
C#
using UnityEngine;
|
|
|
|
namespace IdleSpectator;
|
|
|
|
/// <summary>
|
|
/// Soft FamilyPack sticky tips. Cold-starts only from real relationship mutations
|
|
/// (<see cref="EmitFromActor"/>); <see cref="Tick"/> only refreshes the current pack scene.
|
|
/// Join/leave/form one-shot prose stays on <see cref="RelationshipInterestFeed"/>.
|
|
/// </summary>
|
|
public static class FamilyInterestFeed
|
|
{
|
|
/// <summary>Warm-social band - below notice milestones so unit events can cut in.</summary>
|
|
private const float PackEventStrength = 44f;
|
|
|
|
public static void Tick()
|
|
{
|
|
if (!AgentHarness.LiveFeedsAllowed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Do not poll every living family - that hogged the camera.
|
|
// Only keep the active pack scene fresh while FamilyPack owns the shot.
|
|
InterestCandidate current = InterestDirector.CurrentCandidate;
|
|
if (current == null || current.Completion != InterestCompletionKind.FamilyPack)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Actor follow = current.FollowUnit;
|
|
if (follow == null || !follow.isAlive())
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (follow.hasFamily() && follow.family != null)
|
|
{
|
|
TryRegisterFamily(follow.family, softRefresh: true);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// After a join/form beat, optionally open a soft sticky pack scene for the living family.
|
|
/// </summary>
|
|
public static void EmitFromActor(Actor subject)
|
|
{
|
|
if (!AgentHarness.LiveFeedsAllowed || subject == null || !subject.isAlive())
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (!subject.hasFamily() || subject.family == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
TryRegisterFamily(subject.family, softRefresh: false);
|
|
}
|
|
catch
|
|
{
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
private static bool TryRegisterFamily(Family family, bool softRefresh)
|
|
{
|
|
if (!LiveEnsemble.TryBuildFamily(family, out LiveEnsemble ensemble) || ensemble == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Solo families are not a pack scene - leave to FixedDwell phase tips.
|
|
if (ensemble.SideA == null || ensemble.SideA.Count < 2)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Actor follow = ensemble.Focus;
|
|
if (follow == null || !follow.isAlive())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
DiscreteEventEntry entry = EventCatalog.Relationship.GetOrFallback("family_group_join");
|
|
if (!EventCatalog.IsCameraWorthy(entry))
|
|
{
|
|
InterestDropLog.Record("createsInterest=false", "family_pack");
|
|
return false;
|
|
}
|
|
|
|
string familyId = "";
|
|
try
|
|
{
|
|
familyId = family.getID().ToString();
|
|
}
|
|
catch
|
|
{
|
|
familyId = "";
|
|
}
|
|
|
|
string key = "family:pack:" + (familyId ?? EventFeedUtil.SafeId(follow).ToString());
|
|
string label = EventReason.FamilyPack(ensemble);
|
|
if (string.IsNullOrEmpty(label))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Vector3 position = Vector3.zero;
|
|
try
|
|
{
|
|
position = follow.current_position;
|
|
}
|
|
catch
|
|
{
|
|
position = Vector3.zero;
|
|
}
|
|
|
|
// Soft cluster: short hold, warm-social strength (never combat-class 82).
|
|
float strength = PackEventStrength;
|
|
if (entry.EventStrength > 0f && entry.EventStrength < PackEventStrength)
|
|
{
|
|
strength = Mathf.Clamp(entry.EventStrength, 28f, PackEventStrength);
|
|
}
|
|
|
|
InterestCandidate registered = EventFeedUtil.Register(
|
|
key,
|
|
"relationship",
|
|
entry.Category,
|
|
label,
|
|
"live_family",
|
|
strength,
|
|
position,
|
|
follow,
|
|
related: ensemble.Related,
|
|
minWatch: 4f,
|
|
maxWatch: 12f,
|
|
completion: InterestCompletionKind.FamilyPack);
|
|
if (registered == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
registered.CorrelationKey = key;
|
|
StickyScoreboard.TryLockFromEnsemble(registered.Sticky, ensemble);
|
|
StickyScoreboard.Refresh(
|
|
registered,
|
|
ensemble,
|
|
position,
|
|
StickyScoreboard.FamilyTheaterRadius);
|
|
registered.Label = EventReason.FamilyPack(ensemble);
|
|
registered.ParticipantCount = ensemble.ParticipantCount;
|
|
registered.AssetId = "live_family";
|
|
// Pack size must not inflate TotalScore via combat mass bonuses.
|
|
registered.NotableParticipantCount = 0;
|
|
InterestScoring.ScoreCheap(registered);
|
|
if (!softRefresh)
|
|
{
|
|
InterestDropLog.Record("family_pack_open", key);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|