145 lines
4.1 KiB
C
145 lines
4.1 KiB
C
// A radio's category is protected in the stock gadget component.
|
|
modded class SCR_RadioComponent
|
|
{
|
|
bool ERR_IsHQManpack()
|
|
{
|
|
return m_iRadioCategory == ERadioCategory.MANPACK;
|
|
}
|
|
}
|
|
|
|
class ERR_HQRadio
|
|
{
|
|
// 0: no radio, 1: basic radio, 2: manpack. Inventory is checked live.
|
|
static int Capability(IEntity character)
|
|
{
|
|
if (!ERR_Actors.CanFight(character))
|
|
return 0;
|
|
InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(character.FindComponent(InventoryStorageManagerComponent));
|
|
if (!inventory)
|
|
return 0;
|
|
array<IEntity> items = {};
|
|
inventory.GetItems(items);
|
|
int result;
|
|
foreach (IEntity item : items)
|
|
{
|
|
if (!item || !item.FindComponent(BaseRadioComponent))
|
|
continue;
|
|
result = 1;
|
|
SCR_RadioComponent gadget = SCR_RadioComponent.Cast(item.FindComponent(SCR_RadioComponent));
|
|
if (gadget && gadget.ERR_IsHQManpack())
|
|
return 2;
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// HQ uses entity identity only for matching observations, never for its origin.
|
|
// Visible details are captured at intake and copied as scalar snapshots.
|
|
// Reports and orders contain immutable observed coordinates and timestamps.
|
|
class ERR_HQReport
|
|
{
|
|
int MessageId;
|
|
IEntity Target;
|
|
SCR_AIGroup Source;
|
|
vector Position;
|
|
vector Velocity;
|
|
float ObservedAt = -1;
|
|
float LastSent = -60000;
|
|
float PerceptionStamp = -1;
|
|
bool HasVelocity;
|
|
bool Engaged;
|
|
bool Distress;
|
|
int SeenEscapists = -1;
|
|
string TravelMode = "unknown";
|
|
string SeenWeapons = "unknown";
|
|
float DetailsObservedAt = -1;
|
|
|
|
ERR_HQReport Snapshot()
|
|
{
|
|
ERR_HQReport copy = new ERR_HQReport();
|
|
copy.MessageId = MessageId;
|
|
copy.Target = Target;
|
|
copy.Source = Source;
|
|
copy.Position = Position;
|
|
copy.Velocity = Velocity;
|
|
copy.ObservedAt = ObservedAt;
|
|
copy.Engaged = Engaged;
|
|
copy.Distress = Distress;
|
|
copy.HasVelocity = HasVelocity;
|
|
copy.SeenEscapists = SeenEscapists;
|
|
copy.TravelMode = TravelMode;
|
|
copy.SeenWeapons = SeenWeapons;
|
|
copy.DetailsObservedAt = DetailsObservedAt;
|
|
return copy;
|
|
}
|
|
|
|
string TravelDirection()
|
|
{
|
|
if (!HasVelocity)
|
|
return "unknown";
|
|
if (Velocity.Length() < 0.5)
|
|
return "stationary";
|
|
float x = Math.AbsFloat(Velocity[0]);
|
|
float z = Math.AbsFloat(Velocity[2]);
|
|
string northSouth = "N";
|
|
string eastWest = "E";
|
|
if (Velocity[2] < 0)
|
|
northSouth = "S";
|
|
if (Velocity[0] < 0)
|
|
eastWest = "W";
|
|
if (x < z * 0.414214)
|
|
return northSouth;
|
|
if (z < x * 0.414214)
|
|
return eastWest;
|
|
return northSouth + eastWest;
|
|
}
|
|
|
|
string Description(float now, bool brief = false)
|
|
{
|
|
if (Distress)
|
|
return string.Format("Distress at friendly X=%1 Z=%2; enemy details unknown (%3s ago)", Math.Round(Position[0]), Math.Round(Position[2]), Math.Round(Math.Max(0, now - ObservedAt) / 1000));
|
|
string count = "count unknown";
|
|
if (SeenEscapists >= 0)
|
|
count = "at least " + SeenEscapists.ToString() + " spotted nearby";
|
|
string motion = "speed/direction unknown";
|
|
if (HasVelocity)
|
|
{
|
|
float speed = Math.Round(Velocity.Length() * 10) / 10.0;
|
|
float azimuth = Math.Atan2(Velocity[0], Velocity[2]) * Math.RAD2DEG;
|
|
if (azimuth < 0)
|
|
azimuth += 360;
|
|
int heading = Math.Round(azimuth);
|
|
motion = string.Format("%1 km/h, azimuth %2 degrees (%3)", Math.Round(speed * 3.6), heading % 360, TravelDirection());
|
|
}
|
|
string details = count + "; " + TravelMode + "; " + motion + "; seen weapons: " + SeenWeapons;
|
|
if (brief)
|
|
return details;
|
|
string velocity = "unknown";
|
|
if (HasVelocity)
|
|
velocity = string.Format("[%1,%2] m/s", Math.Round(Velocity[0] * 10) / 10.0, Math.Round(Velocity[2] * 10) / 10.0);
|
|
return string.Format("X=%1 Z=%2: %3; vector X/Z=%4 (%5s ago)", Math.Round(Position[0]), Math.Round(Position[2]), details, velocity, Math.Round(Math.Max(0, now - ObservedAt) / 1000));
|
|
}
|
|
|
|
static vector Predict(vector position, vector velocity, float seconds)
|
|
{
|
|
vector offset = velocity * Math.Clamp(seconds, 0, 20);
|
|
offset[1] = 0;
|
|
if (offset.Length() > 300)
|
|
offset = offset.Normalized() * 300;
|
|
return position + offset;
|
|
}
|
|
|
|
int Priority(float now)
|
|
{
|
|
if (Distress)
|
|
return 0;
|
|
if (now - ObservedAt <= 15000)
|
|
{
|
|
if (Engaged)
|
|
return 3;
|
|
return 2;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|