Make the base escape mission independent and add native objectives
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
SCR_MissionHeader {
|
||||
World "{B6C516F86302C679}Worlds/ERR_Everon.ent"
|
||||
SystemsConfig "{C50579A2EC48E8EF}Configs/Systems/MissionSystems.conf"
|
||||
m_sName "Rereintroduced: Everon Base (development)"
|
||||
m_sAuthor "Rereintroduced contributors"
|
||||
m_sDescription "Independent base escape mission using vanilla Reforger. Companion addons optional. Development scenario."
|
||||
m_sGameMode "Escape"
|
||||
m_iPlayerCount 12
|
||||
m_eSaveTypes 0
|
||||
m_bShowInScenarioMenu 1
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
MetaFileClass {
|
||||
Name "{AD62322D5213C440}Missions/ERR_Everon_Base.conf"
|
||||
Configurations {
|
||||
ResourceClass PC {
|
||||
}
|
||||
ResourceClass HEADLESS : PC {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Base mission discovery: recovering physical documents works without companions.
|
||||
// The Intel addon optionally assigns extra documents to enemy inventories.
|
||||
class ERR_DiscoveryService
|
||||
{
|
||||
protected ERR_GameMode m_Mode;
|
||||
protected ref set<IEntity> m_Spent = new set<IEntity>();
|
||||
void ERR_DiscoveryService(ERR_GameMode mode) { m_Mode = mode; }
|
||||
static 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;
|
||||
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_Spent.Clear(); }
|
||||
}
|
||||
@@ -12,6 +12,8 @@ class ERR_GameMode : SCR_BaseGameMode
|
||||
[RplProp()]
|
||||
protected float m_DefenceSince = -1;
|
||||
protected ref ERR_Settings m_Settings;
|
||||
protected ref ERR_DiscoveryService m_Discovery;
|
||||
protected ref ERR_Objectives m_Objectives;
|
||||
protected ref ERR_PlayerRoster m_Roster = new ERR_PlayerRoster();
|
||||
protected ref ERR_CommandService m_Command;
|
||||
protected ref array<ERR_LocationComponent> m_Locations = {};
|
||||
@@ -37,6 +39,16 @@ class ERR_GameMode : SCR_BaseGameMode
|
||||
ERR_PlayerRoster Players() { return m_Roster; }
|
||||
ERR_Settings Settings() { return m_Settings; }
|
||||
ERR_CommandService Command() { return m_Command; }
|
||||
ERR_Objectives Objectives() { return m_Objectives; }
|
||||
float EscapeRadius() { return m_EscapeRadius; }
|
||||
bool DefenceOccupied() { return m_DefenceSince >= 0; }
|
||||
int DefenceSecondsRemaining()
|
||||
{
|
||||
if (!m_Settings) return 0;
|
||||
int duration = m_Settings.Get("radioDefenceSeconds");
|
||||
if (m_DefenceSince < 0) return duration;
|
||||
return Math.Max(0, Math.Ceil(duration - (GetWorld().GetWorldTime() - m_DefenceSince) / 1000.0));
|
||||
}
|
||||
ScriptInvoker OnPhaseChanged() { return m_OnPhaseChanged; }
|
||||
ScriptInvoker OnTick() { return m_OnTick; }
|
||||
ScriptInvoker OnStop() { return m_OnStop; }
|
||||
@@ -124,6 +136,13 @@ class ERR_GameMode : SCR_BaseGameMode
|
||||
if (!System.IsConsoleApp()) GetGame().GetCallqueue().CallLater(BindLocalObserver, 250, true);
|
||||
if (!Replication.IsServer()) return;
|
||||
m_Settings = new ERR_Settings();
|
||||
m_Discovery = new ERR_DiscoveryService(this);
|
||||
OnTick().Insert(m_Discovery.Tick);
|
||||
OnStop().Insert(m_Discovery.Stop);
|
||||
m_Objectives = new ERR_Objectives(this);
|
||||
OnPhaseChanged().Insert(m_Objectives.PhaseChanged);
|
||||
OnTick().Insert(m_Objectives.Tick);
|
||||
OnStop().Insert(m_Objectives.Stop);
|
||||
m_Command = CreateCommandService();
|
||||
GetGame().GetCallqueue().CallLater(ServerTick, 1000, true);
|
||||
GetGame().GetCallqueue().CallLater(StartScenario, 1500, false);
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
// Explicit local engine fixture, excluded from game/server builds.
|
||||
#ifdef WORKBENCH
|
||||
modded class ERR_GameMode
|
||||
{
|
||||
protected int m_ERRBaseStep;
|
||||
protected float m_ERRBaseDeadline;
|
||||
protected float m_ERRBaseWait;
|
||||
protected IEntity m_ERRBasePlayer;
|
||||
protected ERR_LocationComponent m_ERRBaseRadio;
|
||||
protected ref array<IEntity> m_ERRBaseDocuments = {};
|
||||
|
||||
protected override void EOnInit(IEntity owner)
|
||||
{
|
||||
super.EOnInit(owner);
|
||||
string enabled;
|
||||
if (SCR_Global.IsEditMode() || !Replication.IsServer() || !System.GetCLIParam("errBaseSmoke", enabled) || enabled != "1") return;
|
||||
m_ERRBaseDeadline = GetWorld().GetWorldTime() + 150000;
|
||||
OnPhaseChanged().Insert(ERR_BaseResult);
|
||||
GetGame().GetCallqueue().CallLater(ERR_BaseTick, 500, true);
|
||||
Print("ERR BASE SMOKE: core-only scripted escape; not manual or multiplayer acceptance");
|
||||
}
|
||||
protected bool ERR_BaseCheck(bool condition, string detail)
|
||||
{
|
||||
if (condition) { Print("ERR SMOKE PASS: base " + detail); return true; }
|
||||
Print("ERR SMOKE FAIL: base " + detail, LogLevel.ERROR);
|
||||
GetGame().GetCallqueue().Remove(ERR_BaseTick);
|
||||
return false;
|
||||
}
|
||||
protected void ERR_BaseMove(vector position)
|
||||
{
|
||||
vector transform[4];
|
||||
m_ERRBasePlayer.GetWorldTransform(transform);
|
||||
transform[3] = ERR_Actors.Ground(position);
|
||||
ChimeraCharacter.Cast(m_ERRBasePlayer).Teleport(transform);
|
||||
}
|
||||
protected ERR_UnlockPrisonAction ERR_BaseLock(IEntity entity)
|
||||
{
|
||||
BaseActionsManagerComponent manager = BaseActionsManagerComponent.Cast(entity.FindComponent(BaseActionsManagerComponent));
|
||||
if (manager)
|
||||
{
|
||||
array<BaseUserAction> actions = {};
|
||||
manager.GetActionsList(actions);
|
||||
foreach (BaseUserAction action : actions)
|
||||
{
|
||||
ERR_UnlockPrisonAction lock = ERR_UnlockPrisonAction.Cast(action);
|
||||
if (lock) return lock;
|
||||
}
|
||||
}
|
||||
IEntity child = entity.GetChildren();
|
||||
while (child)
|
||||
{
|
||||
ERR_UnlockPrisonAction lock = ERR_BaseLock(child);
|
||||
if (lock) return lock;
|
||||
child = child.GetSibling();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
protected void ERR_BaseResult(ERR_Phase previous, ERR_Phase current)
|
||||
{
|
||||
if (!ERR_MissionRules.Terminal(current)) return;
|
||||
GetGame().GetCallqueue().Remove(ERR_BaseTick);
|
||||
if (!ERR_BaseCheck(current == ERR_Phase.VICTORY && m_ERRBaseStep == 5, "escape and restart reached without companion services")) return;
|
||||
Print("ERR SMOKE COMPLETE: core-only escape");
|
||||
}
|
||||
protected void ERR_BaseTick()
|
||||
{
|
||||
float now = GetWorld().GetWorldTime();
|
||||
if (now > m_ERRBaseDeadline) { ERR_BaseCheck(false, "timeout at " + m_ERRBaseStep.ToString()); return; }
|
||||
if (now < m_ERRBaseWait) return;
|
||||
if (m_ERRBaseStep == 0)
|
||||
{
|
||||
array<IEntity> players = {};
|
||||
ERR_Actors.Players(players, true);
|
||||
if (players.Count() != 1 || Phase() != ERR_Phase.PRISON) return;
|
||||
m_ERRBasePlayer = players[0];
|
||||
DamageManagerComponent.Cast(m_ERRBasePlayer.FindComponent(DamageManagerComponent)).EnableDamageHandling(false);
|
||||
if (!ERR_BaseCheck(Objectives() && Objectives().Current() && Objectives().Current().GetTaskName() == "Escape the prison", "native prison objective exists")) return;
|
||||
if (!ERR_BaseCheck(Command() == null, "no companion HQ or support controller loaded")) return;
|
||||
if (!ERR_BaseCheck(vector.DistanceXZ(m_ERRBasePlayer.GetOrigin(), PrisonPosition()) < 5, "prisoner spawned in authored prison")) return;
|
||||
foreach (ERR_LocationComponent location : m_Locations)
|
||||
if (location.Kind() == ERR_LocationKind.RADIO) m_ERRBaseRadio = location;
|
||||
ERR_UnlockPrisonAction lock;
|
||||
foreach (IEntity entity : m_OwnedEntities)
|
||||
{
|
||||
if (!entity) continue;
|
||||
if (!lock) lock = ERR_BaseLock(entity);
|
||||
if (entity.GetPrefabData() && entity.GetPrefabData().GetPrefabName() == ERR_FactionCatalog.IntelFolder()) m_ERRBaseDocuments.Insert(entity);
|
||||
}
|
||||
if (!ERR_BaseCheck(lock && m_ERRBaseRadio && m_ERRBaseDocuments.Count() == 2 && ERR_Actors.Alive(m_ExtractionVehicle), "gate, clues, radio and helicopter created by core")) return;
|
||||
ERR_BaseMove(lock.GetOwner().GetOrigin() + "1 0 1");
|
||||
lock.PerformAction(lock.GetOwner(), m_ERRBasePlayer);
|
||||
if (!ERR_BaseCheck(Phase() == ERR_Phase.RADIO_SEARCH, "gate action begins escape")) return;
|
||||
if (!ERR_BaseCheck(m_Settings.Set("radioDefenceSeconds", 30), "test defence duration accepted")) return;
|
||||
SCR_Task prisonTask = SCR_TaskSystem.GetTaskFromTaskID(ERR_Objectives.Id(ERR_Phase.PRISON), false);
|
||||
if (!ERR_BaseCheck(prisonTask && prisonTask.GetTaskState() == SCR_ETaskState.COMPLETED, "previous native objective completes on phase change")) return;
|
||||
if (!ERR_BaseCheck(Objectives().Current().GetTaskUIVisibility() == SCR_ETaskUIVisibility.LIST_ONLY, "search objective does not expose a hidden site")) return;
|
||||
m_ERRBaseStep = 1;
|
||||
}
|
||||
else if (m_ERRBaseStep == 1 || m_ERRBaseStep == 2)
|
||||
{
|
||||
SCR_InventoryStorageManagerComponent inventory = SCR_InventoryStorageManagerComponent.Cast(m_ERRBasePlayer.FindComponent(SCR_InventoryStorageManagerComponent));
|
||||
if (!ERR_BaseCheck(inventory && inventory.TryInsertItem(m_ERRBaseDocuments[m_ERRBaseStep - 1]), "physical clue recovered")) return;
|
||||
m_ERRBaseStep++;
|
||||
m_ERRBaseWait = now + 2500;
|
||||
}
|
||||
else if (m_ERRBaseStep == 3)
|
||||
{
|
||||
if (!ERR_BaseCheck(Objectives().Current().GetTaskDescription().Contains("identify the radio station on your map. Reach"), "objective guidance reacts to discovered radio")) return;
|
||||
if (!ERR_BaseCheck(m_ERRBaseRadio.Knowledge() == 2, "documents identify radio without Intel addon")) return;
|
||||
ERR_BaseMove(m_ERRBaseRadio.Position() + "2 0 0");
|
||||
m_ERRBaseStep = 30;
|
||||
m_ERRBaseWait = now + 1000;
|
||||
}
|
||||
else if (m_ERRBaseStep == 30)
|
||||
{
|
||||
if (!ERR_BaseCheck(TuneRadio(m_ERRBasePlayer, m_ERRBaseRadio), "identified radio accepts transmission")) return;
|
||||
m_ERRBaseStep = 31;
|
||||
m_ERRBaseWait = now + 5000;
|
||||
}
|
||||
else if (m_ERRBaseStep == 31)
|
||||
{
|
||||
if (!ERR_BaseCheck(DefenceOccupied() && DefenceSecondsRemaining() > 0 && DefenceSecondsRemaining() < 30 && Objectives().Current().GetTaskDescription().Contains("seconds remaining"), "native objective reports advancing radio progress")) return;
|
||||
ERR_BaseMove(m_ERRBaseRadio.Position() + "90 0 0");
|
||||
m_ERRBaseStep = 32;
|
||||
m_ERRBaseWait = now + 2500;
|
||||
}
|
||||
else if (m_ERRBaseStep == 32)
|
||||
{
|
||||
if (!ERR_BaseCheck(!DefenceOccupied() && DefenceSecondsRemaining() == 30 && Objectives().Current().GetTaskDescription().Contains("interrupted"), "objective reports interruption and reset")) return;
|
||||
ERR_BaseMove(m_ERRBaseRadio.Position() + "2 0 0");
|
||||
m_ERRBaseStep = 4;
|
||||
m_ERRBaseWait = now + 33000;
|
||||
}
|
||||
else if (m_ERRBaseStep == 4)
|
||||
{
|
||||
if (!ERR_BaseCheck(Phase() == ERR_Phase.EXTRACTION, "radio defence reveals extraction")) return;
|
||||
CompartmentAccessComponent access = CompartmentAccessComponent.Cast(m_ERRBasePlayer.FindComponent(CompartmentAccessComponent));
|
||||
BaseCompartmentSlot slot = access.FindFreeCompartment(m_ExtractionVehicle, ECompartmentType.PILOT);
|
||||
if (!ERR_BaseCheck(slot && access.GetInVehicle(m_ExtractionVehicle, slot, true, -1, ECloseDoorAfterActions.INVALID, false), "player physically boards extraction helicopter")) return;
|
||||
m_ERRBaseStep = 5;
|
||||
m_ERRBaseWait = now + 3000;
|
||||
}
|
||||
else if (m_ERRBaseStep == 5)
|
||||
{
|
||||
if (!ERR_BaseCheck(CompartmentAccessComponent.GetVehicleIn(m_ERRBasePlayer) == m_ExtractionVehicle, "extraction requires real occupancy")) return;
|
||||
vector transform[4];
|
||||
m_ExtractionVehicle.GetWorldTransform(transform);
|
||||
transform[3] = m_EscapeCenter + Vector(m_EscapeRadius + 100, 150, 0);
|
||||
m_ExtractionVehicle.SetWorldTransform(transform);
|
||||
m_ERRBaseWait = now + 4000;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,90 @@
|
||||
// Server-owned presentation adapter: mission rules decide progress, native tasks
|
||||
// replicate it. Companion addons neither create nor advance these objectives.
|
||||
class ERR_Objectives
|
||||
{
|
||||
protected ERR_GameMode m_Mode;
|
||||
protected SCR_Task m_Current;
|
||||
protected string m_LastDescription;
|
||||
protected bool m_Stopped;
|
||||
|
||||
void ERR_Objectives(ERR_GameMode mode) { m_Mode = mode; }
|
||||
SCR_Task Current() { return m_Current; }
|
||||
static string Id(ERR_Phase phase) { return "erri-mission-" + phase.ToString(); }
|
||||
|
||||
void PhaseChanged(ERR_Phase previous, ERR_Phase current)
|
||||
{
|
||||
if (!Replication.IsServer() || m_Stopped) return;
|
||||
SCR_TaskSystem tasks = SCR_TaskSystem.GetInstance();
|
||||
if (!tasks) { Print("Rereintroduced: native task system missing", LogLevel.ERROR); return; }
|
||||
if (m_Current)
|
||||
{
|
||||
SCR_ETaskState result = SCR_ETaskState.COMPLETED;
|
||||
if (current == ERR_Phase.DEFEAT) result = SCR_ETaskState.FAILED;
|
||||
tasks.SetTaskState(m_Current, result);
|
||||
}
|
||||
m_Current = null;
|
||||
if (ERR_MissionRules.Terminal(current)) return;
|
||||
string title;
|
||||
if (current == ERR_Phase.PRISON) title = "Escape the prison";
|
||||
else if (current == ERR_Phase.RADIO_SEARCH) title = "Locate the radio station";
|
||||
else if (current == ERR_Phase.RADIO_DEFENCE) title = "Defend the radio transmission";
|
||||
else if (current == ERR_Phase.EXTRACTION) title = "Escape Everon by helicopter";
|
||||
if (title.IsEmpty()) return;
|
||||
m_Current = tasks.CreateTask("{1D0F815858EE24AD}Prefabs/Tasks/BaseTask.et", Id(current), title, Description());
|
||||
if (!m_Current) { Print("Rereintroduced: objective creation failed", LogLevel.ERROR); return; }
|
||||
// Location markers use the discovery registry. A task cannot expose an unknown site.
|
||||
tasks.SetTaskUIVisibility(m_Current, SCR_ETaskUIVisibility.LIST_ONLY);
|
||||
m_Mode.Own(m_Current);
|
||||
m_LastDescription = "";
|
||||
Tick(GetGame().GetWorld().GetWorldTime());
|
||||
}
|
||||
|
||||
protected string Description()
|
||||
{
|
||||
ERR_Phase phase = m_Mode.Phase();
|
||||
if (phase == ERR_Phase.PRISON)
|
||||
return "Collect supplies and the field map inside the prison. Pick the gate lock, then get clear of the guards.";
|
||||
if (phase == ERR_Phase.RADIO_SEARCH)
|
||||
{
|
||||
array<ERR_LocationComponent> locations = {};
|
||||
m_Mode.Locations(locations);
|
||||
foreach (ERR_LocationComponent location : locations)
|
||||
if (location.Kind() == ERR_LocationKind.RADIO && location.Knowledge() == 2)
|
||||
return "The recovered documents identify the radio station on your map. Reach the station and tune its radio to start the transmission.";
|
||||
return "Recover the two documents on the guard's table outside the prison gate. Carry them to identify the radio station on your map.";
|
||||
}
|
||||
if (phase == ERR_Phase.RADIO_DEFENCE)
|
||||
{
|
||||
int seconds = m_Mode.DefenceSecondsRemaining();
|
||||
if (!m_Mode.DefenceOccupied())
|
||||
return string.Format("Transmission interrupted. Keep a conscious survivor within 60 metres of the radio for %1 seconds. Leaving resets progress.", seconds);
|
||||
// Update at most once per five-second interval; do not broadcast every frame.
|
||||
int displayed = Math.Ceil(seconds / 5.0) * 5;
|
||||
return string.Format("Transmission in progress: up to %1 seconds remaining. Keep a conscious survivor within 60 metres of the radio. Leaving resets progress.", displayed);
|
||||
}
|
||||
if (phase == ERR_Phase.EXTRACTION)
|
||||
return string.Format("Reach the helicopter marked on your map. Board and fly beyond %1 kilometres from the prison. Everyone aboard escapes; survivors left behind do not.", m_Mode.EscapeRadius() / 1000.0);
|
||||
return "";
|
||||
}
|
||||
|
||||
void Tick(float now)
|
||||
{
|
||||
if (!Replication.IsServer() || m_Stopped || !m_Current) return;
|
||||
string description = Description();
|
||||
if (description != m_LastDescription)
|
||||
{
|
||||
m_Current.SetTaskDescription(description);
|
||||
m_LastDescription = description;
|
||||
}
|
||||
SCR_TaskSystem tasks = SCR_TaskSystem.GetInstance();
|
||||
if (!tasks) return;
|
||||
array<int> players = {};
|
||||
GetGame().GetPlayerManager().GetPlayers(players);
|
||||
foreach (int playerId : players)
|
||||
{
|
||||
SCR_TaskExecutor executor = SCR_TaskSystem.TaskExecutorFromPlayerID(playerId);
|
||||
if (executor && !m_Current.IsTaskAssignedTo(executor)) tasks.AssignTask(m_Current, executor, true);
|
||||
}
|
||||
}
|
||||
void Stop() { m_Stopped = true; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
[WorkbenchPluginAttribute(name: "Validate Rereintroduced base", wbModules: {"WorldEditor"})]
|
||||
class ERR_ValidateBaseWorldPlugin : WorldEditorPlugin
|
||||
{
|
||||
override void RunCommandline()
|
||||
{
|
||||
string play;
|
||||
WorldEditor editor = Workbench.GetModule(WorldEditor);
|
||||
if (editor && System.GetCLIParam("errPlay", play) && play == "1") editor.SwitchToGameMode();
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,12 @@ class ERR_IntelRequest
|
||||
bool Accepted;
|
||||
}
|
||||
|
||||
// Mission-owned inventory service. Physical folder identities are consumed once,
|
||||
// even when transferred between players; owned inventory entities are not deleted.
|
||||
// Optional enemy inventory distribution. Core owns recovery and discovery.
|
||||
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)
|
||||
@@ -34,13 +32,6 @@ class ERR_IntelService
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -53,7 +44,7 @@ class ERR_IntelService
|
||||
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 (inventory) ERR_DiscoveryService.Folders(inventory, folders);
|
||||
if (!folders.IsEmpty()) { m_Requests.Remove(i); continue; }
|
||||
request.Attempts++;
|
||||
if (request.Attempts > 30)
|
||||
@@ -64,36 +55,10 @@ class ERR_IntelService
|
||||
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(); }
|
||||
void Stop() { m_Requests.Clear(); m_Rolled.Clear(); }
|
||||
}
|
||||
|
||||
modded class ERR_GameMode
|
||||
|
||||
Reference in New Issue
Block a user