Build independent Everon successor foundation and native regressions

This commit is contained in:
2026-09-19 01:37:41 +02:00
commit 2550bc0423
155 changed files with 15098 additions and 0 deletions
@@ -0,0 +1,111 @@
class ERR_IntelRequest
{
IEntity Actor;
int Attempts;
bool Accepted;
}
// Mission-owned inventory service. Physical folder identities are consumed once,
// even when transferred between players; owned inventory entities are not deleted.
class ERR_IntelService
{
protected ERR_GameMode m_Mode;
protected ref array<ref ERR_IntelRequest> m_Requests = {};
protected ref set<IEntity> m_Rolled = new set<IEntity>();
protected ref set<IEntity> m_Spent = new set<IEntity>();
void ERR_IntelService(ERR_GameMode mode) { m_Mode = mode; }
void RegisterGroup(SCR_AIGroup group)
{
if (!Replication.IsServer() || !group) return;
array<AIAgent> members = {};
group.GetAgents(members);
foreach (AIAgent member : members)
{
if (!member) continue;
IEntity actor = member.GetControlledEntity();
if (!ERR_Actors.Alive(actor) || ERR_Actors.Player(actor) || m_Rolled.Contains(actor)) continue;
m_Rolled.Insert(actor);
if (Math.RandomInt(0, 100) >= m_Mode.Settings().Get("aiIntelChancePercent")) continue;
if (m_Requests.Count() >= 256) continue;
ERR_IntelRequest request = new ERR_IntelRequest();
request.Actor = actor;
m_Requests.Insert(request);
}
}
protected void Folders(InventoryStorageManagerComponent inventory, out array<IEntity> folders)
{
folders.Clear();
SCR_PrefabNamePredicate predicate = new SCR_PrefabNamePredicate();
predicate.prefabName = ERR_FactionCatalog.IntelFolder();
inventory.FindItems(folders, predicate, EStoragePurpose.PURPOSE_ANY);
}
void Tick(float now)
{
if (!Replication.IsServer()) return;
int budget = 8;
for (int i = m_Requests.Count() - 1; i >= 0 && budget > 0; i--)
{
budget--;
ERR_IntelRequest request = m_Requests[i];
if (!ERR_Actors.Alive(request.Actor) || ERR_Actors.Player(request.Actor)) { m_Requests.Remove(i); continue; }
SCR_InventoryStorageManagerComponent inventory = SCR_InventoryStorageManagerComponent.Cast(request.Actor.FindComponent(SCR_InventoryStorageManagerComponent));
array<IEntity> folders = {};
if (inventory) Folders(inventory, folders);
if (!folders.IsEmpty()) { m_Requests.Remove(i); continue; }
request.Attempts++;
if (request.Attempts > 30)
{
Print("Rereintroduced [intel]: bounded assignment failed", LogLevel.WARNING);
m_Requests.Remove(i); continue;
}
if (inventory && !request.Accepted)
request.Accepted = inventory.TrySpawnPrefabToStorage(ERR_FactionCatalog.IntelFolder(), purpose: EStoragePurpose.PURPOSE_ANY);
}
array<IEntity> players = {};
ERR_Actors.Players(players);
foreach (IEntity player : players) Recover(player);
}
protected void Recover(IEntity player)
{
InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(player.FindComponent(InventoryStorageManagerComponent));
if (!inventory) return;
array<IEntity> folders = {};
Folders(inventory, folders);
foreach (IEntity folder : folders)
{
if (!folder || m_Spent.Contains(folder) || m_Spent.Count() >= 4096) continue;
array<ERR_LocationComponent> locations = {};
m_Mode.Locations(locations);
array<ERR_LocationComponent> eligible = {};
foreach (ERR_LocationComponent location : locations)
{
if (location && location.Kind() != ERR_LocationKind.PRISON && location.Kind() != ERR_LocationKind.EXTRACTION && location.Knowledge() < 2) eligible.Insert(location);
}
if (eligible.IsEmpty()) continue;
ERR_LocationComponent chosen = eligible.GetRandomElement();
if (!chosen.Discover(Math.RandomInt(0, 100), m_Mode.Settings().Get("intelRevealChancePercent"))) continue;
m_Spent.Insert(folder);
PrintFormat("Rereintroduced [intel]: player %1 recovered folder; location=%2 knowledge=%3", GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(player), chosen.Id(), chosen.Knowledge());
}
}
void Stop() { m_Requests.Clear(); m_Rolled.Clear(); m_Spent.Clear(); }
}
modded class ERR_GameMode
{
protected ref ERR_IntelService m_Intel;
protected override void EOnInit(IEntity owner)
{
super.EOnInit(owner);
if (SCR_Global.IsEditMode() || !Replication.IsServer()) return;
m_Intel = new ERR_IntelService(this);
OnGroup().Insert(m_Intel.RegisterGroup);
OnTick().Insert(m_Intel.Tick);
OnStop().Insert(m_Intel.Stop);
}
}