Integrate delivered HQ memory, finite physical convoy and RHS WCS dependencies
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
// Local evidence only. HQ must receive the resulting immutable status through
|
||||
// the normal radio route; sampling never writes the delivered watch roster.
|
||||
class ERR_HQStatusSampler
|
||||
{
|
||||
protected SCR_AIGroup m_Group;
|
||||
protected Faction m_Faction;
|
||||
protected string m_SourceId;
|
||||
protected int m_Strength;
|
||||
protected int m_Deaths;
|
||||
protected bool m_Bound;
|
||||
protected float m_LastSampleAt = -1;
|
||||
protected ref array<IEntity> m_Members = {};
|
||||
protected ref array<bool> m_Dead = {};
|
||||
protected ref array<bool> m_Released = {};
|
||||
protected ref array<AIAgent> m_Agents = {};
|
||||
bool Bound() { return m_Bound; }
|
||||
protected bool Eligible()
|
||||
{
|
||||
return Replication.IsServer() && m_Bound && m_Group && m_Faction
|
||||
&& m_Group.GetPlayerCount(true) == 0 && !m_Group.IsSlave() && m_Group.GetFaction() == m_Faction;
|
||||
}
|
||||
bool Bind(SCR_AIGroup group, string sourceId, int initialStrength, Faction enemyFaction)
|
||||
{
|
||||
if (!Replication.IsServer()) return false;
|
||||
if (m_Bound) return Eligible() && group == m_Group && sourceId == m_SourceId
|
||||
&& initialStrength == m_Strength && enemyFaction == m_Faction;
|
||||
if (!Replication.IsServer() || !group || !enemyFaction || sourceId.IsEmpty() || sourceId.Length() > 96
|
||||
|| initialStrength < 1 || initialStrength > 32 || group.GetPlayerCount(true) > 0
|
||||
|| group.IsSlave() || group.GetFaction() != enemyFaction) return false;
|
||||
m_Agents.Clear(); m_Members.Clear();
|
||||
group.GetAgents(m_Agents);
|
||||
if (m_Agents.Count() != initialStrength) { m_Agents.Clear(); return false; }
|
||||
foreach (AIAgent agent : m_Agents)
|
||||
{
|
||||
if (!agent) { m_Members.Clear(); return false; }
|
||||
IEntity actor = agent.GetControlledEntity();
|
||||
if (!ERR_Actors.Alive(actor) || ERR_Actors.Player(actor) || ERR_Actors.Group(actor) != group
|
||||
|| SCR_FactionManager.SGetFaction(actor) != enemyFaction || m_Members.Contains(actor))
|
||||
{ m_Members.Clear(); return false; }
|
||||
m_Members.Insert(actor);
|
||||
}
|
||||
m_Group = group; m_SourceId = sourceId; m_Strength = initialStrength; m_Faction = enemyFaction;
|
||||
for (int i = 0; i < initialStrength; i++) { m_Dead.Insert(false); m_Released.Insert(false); }
|
||||
m_Agents.Clear();
|
||||
m_Bound = true;
|
||||
return true;
|
||||
}
|
||||
// Call from the existing physical slow tick, not just each 180-second radio
|
||||
// cycle: after native corpse deletion, a null reference supplies no evidence.
|
||||
bool ObserveDeaths()
|
||||
{
|
||||
if (!Eligible()) return false;
|
||||
for (int i = 0; i < m_Members.Count(); i++)
|
||||
{
|
||||
if (m_Dead[i] || m_Released[i]) continue;
|
||||
IEntity actor = m_Members[i];
|
||||
if (!actor) continue;
|
||||
if (ERR_Actors.Player(actor) || SCR_FactionManager.SGetFaction(actor) != m_Faction)
|
||||
{ m_Released[i] = true; continue; }
|
||||
DamageManagerComponent damage = DamageManagerComponent.Cast(actor.FindComponent(DamageManagerComponent));
|
||||
if (!damage) continue;
|
||||
if (damage.IsDestroyed()) { m_Dead[i] = true; m_Deaths++; continue; }
|
||||
// A living member who left this group is no longer ours to account for.
|
||||
// Native death may detach a corpse, so group identity is checked after death.
|
||||
if (ERR_Actors.Group(actor) != m_Group) m_Released[i] = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
ERR_HQStatusReport Sample(float now, int messageId, IEntity caller)
|
||||
{
|
||||
if (!ERR_HQPursuitRules.Finite(now) || now < 0 || now < m_LastSampleAt || messageId <= 0
|
||||
|| !ObserveDeaths()) return null;
|
||||
int callerIndex = m_Members.Find(caller);
|
||||
if (!caller || callerIndex < 0 || m_Dead[callerIndex] || m_Released[callerIndex]
|
||||
|| ERR_Actors.Player(caller) || ERR_Actors.Group(caller) != m_Group
|
||||
|| SCR_FactionManager.SGetFaction(caller) != m_Faction || ERR_HQRadio.Capability(caller) <= 0) return null;
|
||||
vector position = m_Group.GetOrigin();
|
||||
if (!ERR_HQPursuitRules.PositionValid(position)) return null;
|
||||
ERR_HQStatusReport report = new ERR_HQStatusReport();
|
||||
report.SourceId = m_SourceId; report.MessageId = messageId; report.Position = position;
|
||||
report.Strength = m_Strength; report.ConfirmedLosses = m_Deaths; report.ObservedAt = now;
|
||||
for (int i = 0; i < m_Members.Count(); i++)
|
||||
{
|
||||
if (m_Dead[i] || m_Released[i]) continue;
|
||||
IEntity actor = m_Members[i];
|
||||
if (!ERR_Actors.Alive(actor) || ERR_Actors.Player(actor) || ERR_Actors.Group(actor) != m_Group
|
||||
|| SCR_FactionManager.SGetFaction(actor) != m_Faction) continue;
|
||||
report.Count++;
|
||||
if (ERR_Actors.CanFight(actor)) report.Fit++;
|
||||
}
|
||||
m_LastSampleAt = now;
|
||||
return report;
|
||||
}
|
||||
void Clear()
|
||||
{
|
||||
m_Group = null; m_Faction = null; m_SourceId = ""; m_Strength = 0; m_Deaths = 0;
|
||||
m_Bound = false; m_LastSampleAt = -1;
|
||||
m_Members.Clear(); m_Dead.Clear(); m_Released.Clear(); m_Agents.Clear();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user