Improve base guidance and qualify bounded aircraft route and hidden test lifecycle
This commit is contained in:
@@ -318,6 +318,10 @@ modded class ERR_GameMode
|
||||
if (m_ERRStartupFailure)
|
||||
{
|
||||
if (PreparationError().IsEmpty()) return;
|
||||
int presentation = ERR_NativePreparationStatusProbe.Tick(this, now);
|
||||
if (presentation < 0) { ERR_BaseCheck(false, "actual persistent startup-failure loading presentation within30seconds"); return; }
|
||||
if (presentation == 0) return;
|
||||
if (!ERR_BaseCheck(true, "actual failed-start loading widgets persist beyond17seconds with spinner hidden; diagnostic screenshot requested")) return;
|
||||
if (!ERR_BaseCheck(Phase() == ERR_Phase.PREPARING && !Active() && m_Stopped, "invalid faction setup stops services without starting the mission")) return;
|
||||
array<IEntity> players = {};
|
||||
ERR_Actors.Players(players);
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifdef WORKBENCH
|
||||
// Only the explicit startup-failure fixture calls this read-only observation.
|
||||
// No placeholder/widget creation, presentation calls or preparation-state writes.
|
||||
class ERR_NativePreparationStatusProbe
|
||||
{
|
||||
protected static ERR_GameMode s_Mode;
|
||||
protected static float s_Deadline;
|
||||
protected static float s_Since = -1;
|
||||
protected static float s_Last = -1;
|
||||
protected static float s_CaptureAt = -1;
|
||||
static int Tick(ERR_GameMode mode, float now)
|
||||
{
|
||||
if (s_Mode != mode)
|
||||
{
|
||||
s_Mode = mode; s_Deadline = now + 30000;
|
||||
s_Since = -1; s_Last = -1; s_CaptureAt = -1;
|
||||
}
|
||||
if (!mode || mode != ERR_GameMode.Get() || mode.Phase() != ERR_Phase.PREPARING || mode.PreparationError().IsEmpty() || now < 0 || now >= s_Deadline) return -1;
|
||||
SCR_RespawnSystemComponent respawn = SCR_RespawnSystemComponent.GetInstance();
|
||||
bool visible = respawn && respawn.ERR_ProbePreparationVisible(mode, true);
|
||||
if (s_Last >= 0 && (now < s_Last || now - s_Last > 1500)) s_Since = -1;
|
||||
s_Last = now;
|
||||
if (!visible) { s_Since = -1; return 0; }
|
||||
if (s_Since < 0) s_Since = now;
|
||||
// Exceed the old15-second hint lifetime; inspect the real widget every tick.
|
||||
if (now - s_Since < 17000) return 0;
|
||||
if (s_CaptureAt < 0)
|
||||
{
|
||||
System.MakeScreenshot("$logs:err-preparation-failure");
|
||||
s_CaptureAt = now;
|
||||
Print("ERR PREPARATION UI: actual failed-start title/body and hidden native spinner observed continuously for17seconds; screenshot requested");
|
||||
return 0;
|
||||
}
|
||||
if (now - s_CaptureAt < 500) return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -44,9 +44,17 @@ class ERR_ObjectiveText
|
||||
{
|
||||
array<ERR_LocationComponent> locations = {};
|
||||
mode.Locations(locations);
|
||||
bool roughRadio;
|
||||
foreach (ERR_LocationComponent location : locations)
|
||||
if (location.Kind() == ERR_LocationKind.RADIO && location.Knowledge() == 2)
|
||||
{
|
||||
if (!location || location.Kind() != ERR_LocationKind.RADIO) continue;
|
||||
if (location.Knowledge() == 2)
|
||||
return "The radio station is identified on your map. Reach its radio and complete the 'Contact extraction HQ' action to start the transmission.";
|
||||
if (location.Knowledge() == 1) roughRadio = true;
|
||||
}
|
||||
// Scan all sites before acknowledging rough intel: an identified radio wins.
|
||||
if (roughRadio)
|
||||
return "Intel recovered: a 500 m search square is now marked on the map. Use a carried field map to view it. Take a different intelligence folder into your inventory to pinpoint the radio; a folder already recovered cannot provide another clue. Try the other marked supply cache if needed. A close approach with a clear view can also identify the station.";
|
||||
return "Choose either marked supply cache. Take its intelligence folders into your own inventory to reveal the station on your map. If only a search area appears, take another folder. Each cache has enough folders; use the other if one is lost. If every folder is lost, a close approach with a clear view can identify the station itself. Nearby medical and guard sites can also be discovered by approaching with a clear view.";
|
||||
}
|
||||
if (phase == ERR_Phase.RADIO_DEFENCE)
|
||||
|
||||
@@ -229,7 +229,7 @@ modded class SCR_PlayerController
|
||||
{
|
||||
SCR_HintManagerComponent hints = SCR_HintManagerComponent.GetInstance();
|
||||
if (!hints) return; // retry on the existing monitor; do not lose the first hint
|
||||
hints.ShowCustom(ERR_ObserverGuidance.Message(m_ERRObserverReason, survivorAvailable), "Spectating", 12);
|
||||
if (!hints.ShowCustom(ERR_ObserverGuidance.Message(m_ERRObserverReason, survivorAvailable), "Spectating", 12)) return;
|
||||
m_ERRObserverReady = true;
|
||||
m_ERRShownObserverReason = m_ERRObserverReason;
|
||||
m_ERRShownObserverAvailable = survivorAvailable;
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
#ifndef WORKBENCH
|
||||
// Explicit ordinary-game observation only. No input, actor, menu or camera writes.
|
||||
class ERR_OrdinaryInputObserverRules
|
||||
{
|
||||
static bool Nonce(string nonce)
|
||||
{
|
||||
if (nonce.Length() < 1 || nonce.Length() > 32) return false;
|
||||
string allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
for (int i = 0; i < nonce.Length(); i++) if (!allowed.Contains(nonce[i])) return false;
|
||||
return true;
|
||||
}
|
||||
static bool Within(int start, int previous, int now, int samples)
|
||||
{
|
||||
return now >= start && now >= previous && now - start < 45000 && samples < 450;
|
||||
}
|
||||
static bool Stationary(float forward, vector input, vector velocity, float displacement)
|
||||
{
|
||||
return Math.AbsFloat(forward) <= 0.01 && input.Length() <= 0.01 && velocity.Length() <= 0.05 && displacement >= 0 && displacement <= 0.05;
|
||||
}
|
||||
}
|
||||
class ERR_OrdinaryInputObserver : Managed
|
||||
{
|
||||
protected static ref ERR_OrdinaryInputObserver s_Request;
|
||||
protected static bool s_Attempted;
|
||||
protected ERR_GameMode m_Mode;
|
||||
protected BaseWorld m_World;
|
||||
protected PlayerController m_Controller;
|
||||
protected IEntity m_Actor;
|
||||
protected CharacterControllerComponent m_Character;
|
||||
protected ref ERR_PlayerLife m_Life;
|
||||
protected UUID m_Account;
|
||||
protected int m_PlayerId;
|
||||
protected string m_Nonce;
|
||||
protected bool m_Screenshots;
|
||||
protected bool m_Finished;
|
||||
protected bool m_Ready;
|
||||
protected bool m_Opened;
|
||||
protected bool m_Closed;
|
||||
protected SCR_InventoryMenuUI m_Menu;
|
||||
protected int m_Start;
|
||||
protected int m_Previous;
|
||||
protected int m_Samples;
|
||||
protected int m_BaselineSince = -1;
|
||||
protected vector m_BaselineOrigin;
|
||||
protected float m_LastWorldTime;
|
||||
|
||||
protected static bool Enabled(out string nonce)
|
||||
{
|
||||
string project;
|
||||
if (!Replication.IsServer() || System.IsConsoleApp()) return false;
|
||||
if (!System.GetCLIParam("errOrdinaryScenario", project) || (project != "core" && project != "chat")) return false;
|
||||
return System.GetCLIParam("errOrdinaryInputObserve", nonce) && ERR_OrdinaryInputObserverRules.Nonce(nonce);
|
||||
}
|
||||
static void Queue(ERR_GameMode mode, PlayerController controller, IEntity actor)
|
||||
{
|
||||
string nonce;
|
||||
if (s_Attempted || !Enabled(nonce) || !GetGame() || !mode || !controller || !actor || !mode.Players()) return;
|
||||
ERR_PlayerLife life = mode.Players().CurrentActor(actor);
|
||||
if (!life) return;
|
||||
ERR_OrdinaryInputObserver request = new ERR_OrdinaryInputObserver();
|
||||
request.m_Mode = mode; request.m_World = GetGame().GetWorld();
|
||||
request.m_Controller = controller; request.m_Actor = actor;
|
||||
request.m_Character = CharacterControllerComponent.Cast(actor.FindComponent(CharacterControllerComponent));
|
||||
request.m_Life = life; request.m_Account = life.AccountId;
|
||||
request.m_PlayerId = controller.GetPlayerId(); request.m_Nonce = nonce;
|
||||
if (!request.Valid()) return;
|
||||
string screenshots;
|
||||
request.m_Screenshots = System.GetCLIParam("errOrdinaryInputScreenshots", screenshots) && screenshots == "1";
|
||||
request.m_Start = System.GetTickCount(); request.m_Previous = request.m_Start;
|
||||
request.m_LastWorldTime = request.m_World.GetWorldTime();
|
||||
s_Attempted = true; s_Request = request;
|
||||
mode.OnStop().Insert(request.Cancel);
|
||||
request.Record("QUEUED");
|
||||
GetGame().GetCallqueue().CallLater(request.Sample, 100, false);
|
||||
}
|
||||
protected bool Valid()
|
||||
{
|
||||
string nonce;
|
||||
if (!Enabled(nonce) || nonce != m_Nonce || !GetGame() || !m_Mode || m_Mode != ERR_GameMode.Get()) return false;
|
||||
if (!m_World || GetGame().GetWorld() != m_World || m_Mode.GetWorld() != m_World || !m_Mode.Active() || m_Mode.Phase() != ERR_Phase.PRISON) return false;
|
||||
if (!m_Controller || m_Controller != GetGame().GetPlayerController() || m_Controller.GetPlayerId() != m_PlayerId || m_PlayerId <= 0) return false;
|
||||
PlayerManager manager = GetGame().GetPlayerManager();
|
||||
if (!manager || manager.GetPlayerController(m_PlayerId) != m_Controller || manager.GetPlayerControlledEntity(m_PlayerId) != m_Actor || m_Controller.GetControlledEntity() != m_Actor) return false;
|
||||
if (!ERR_Actors.CanFight(m_Actor) || m_Actor.GetWorld() != m_World || !m_Mode.Players()) return false;
|
||||
if (!m_Character || m_Actor.FindComponent(CharacterControllerComponent) != m_Character || m_Character.IsUnconscious()) return false;
|
||||
ERR_PlayerLife current = m_Mode.Players().CurrentActor(m_Actor);
|
||||
return current && current == m_Life && current.AccountId == m_Account;
|
||||
}
|
||||
protected void Record(string detail)
|
||||
{
|
||||
PrintFormat("ERR INPUT OBSERVE: run=%1 sample=%2 real=%3 world=%4 %5", m_Nonce, m_Samples, System.GetTickCount(), m_LastWorldTime, detail);
|
||||
}
|
||||
protected void Capture(string suffix)
|
||||
{
|
||||
if (!m_Screenshots || !Valid()) return;
|
||||
System.MakeScreenshot("$logs:err-input-" + m_Nonce + "-" + suffix);
|
||||
Record("CAPTURE_REQUEST " + suffix);
|
||||
}
|
||||
// Snapshot sequencing is separate from native reads so its policy is executable.
|
||||
protected void Observe(int now, vector origin, float forward, vector input, vector velocity, bool inventoryOpen)
|
||||
{
|
||||
if (!m_Ready)
|
||||
{
|
||||
float displacement = vector.Distance(origin, m_BaselineOrigin);
|
||||
if (m_BaselineSince < 0) displacement = 0;
|
||||
if (inventoryOpen || now - m_Previous > 500 || !ERR_OrdinaryInputObserverRules.Stationary(forward, input, velocity, displacement))
|
||||
{
|
||||
m_BaselineSince = -1;
|
||||
return;
|
||||
}
|
||||
if (m_BaselineSince < 0) { m_BaselineSince = now; m_BaselineOrigin = origin; }
|
||||
if (now - m_BaselineSince < 2000) return;
|
||||
m_Ready = true; Record("READY"); Capture("baseline");
|
||||
}
|
||||
if (inventoryOpen && !m_Opened)
|
||||
{
|
||||
m_Opened = true; Record("INVENTORY_OPEN"); Capture("open");
|
||||
}
|
||||
else if (!inventoryOpen && m_Opened && !m_Closed)
|
||||
{
|
||||
m_Closed = true; Record("INVENTORY_CLOSED"); Capture("closed");
|
||||
}
|
||||
}
|
||||
protected void Sample()
|
||||
{
|
||||
if (m_Finished) return;
|
||||
if (!Valid()) { End("CANCELLED original-admission-lost"); return; }
|
||||
int now = System.GetTickCount();
|
||||
float worldTime = m_World.GetWorldTime();
|
||||
if (worldTime < m_LastWorldTime) { End("CANCELLED world-clock-reversed"); return; }
|
||||
m_LastWorldTime = worldTime;
|
||||
if (!ERR_OrdinaryInputObserverRules.Within(m_Start, m_Previous, now, m_Samples)) { End("FINISHED observation-bound"); return; }
|
||||
if (!GetGame().GetInputManager() || !GetGame().GetMenuManager()) { End("CANCELLED native-input-or-menu-unavailable"); return; }
|
||||
SCR_InventoryMenuUI menu = SCR_InventoryMenuUI.GetInventoryMenu();
|
||||
bool open;
|
||||
if (menu)
|
||||
{
|
||||
Widget root = menu.GetRootWidget();
|
||||
if (menu.GetCharacterController() != m_Character || !root || !root.IsVisible() || GetGame().GetMenuManager().GetTopMenu() != menu)
|
||||
{ End("CANCELLED inventory-context-mismatch"); return; }
|
||||
if (m_Opened && (m_Closed || menu != m_Menu)) { End("CANCELLED inventory-instance-replaced"); return; }
|
||||
open = true;
|
||||
}
|
||||
vector origin = m_Actor.GetOrigin();
|
||||
vector input = m_Character.GetMovementInput();
|
||||
vector velocity = m_Character.GetVelocity();
|
||||
float forward = GetGame().GetInputManager().GetActionValue("CharacterForward");
|
||||
m_Samples++;
|
||||
PrintFormat("ERR INPUT OBSERVE: run=%1 sample=%2 real=%3 world=%4 SAMPLE origin=%5 forward=%6 input=%7 velocity=%8 inventory=%9", m_Nonce, m_Samples, now, m_LastWorldTime, origin, forward, input, velocity, open);
|
||||
Observe(now, origin, forward, input, velocity, open);
|
||||
if (m_Opened && !m_Closed && menu) m_Menu = menu;
|
||||
m_Previous = now;
|
||||
if (m_Samples >= 450) { End("FINISHED sample-bound"); return; }
|
||||
GetGame().GetCallqueue().CallLater(Sample, 100, false);
|
||||
}
|
||||
protected void End(string reason)
|
||||
{
|
||||
if (m_Finished) return;
|
||||
m_Finished = true;
|
||||
Record(reason);
|
||||
if (GetGame() && GetGame().GetCallqueue()) GetGame().GetCallqueue().Remove(Sample);
|
||||
if (m_Mode) m_Mode.OnStop().Remove(Cancel);
|
||||
m_Mode = null; m_World = null; m_Controller = null; m_Actor = null;
|
||||
m_Character = null; m_Life = null; m_Menu = null;
|
||||
}
|
||||
void Cancel() { End("CANCELLED mission-or-world-stopped"); }
|
||||
static void ClearWorld()
|
||||
{
|
||||
if (s_Request) s_Request.Cancel();
|
||||
s_Request = null;
|
||||
// Process-wide single attempt: a restart cannot silently create new evidence.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -248,6 +248,7 @@ modded class ArmaReforgerScripted
|
||||
override protected void OnBeforeWorldCleanup()
|
||||
{
|
||||
ERR_OrdinaryScreenshotRequest.ClearWorld();
|
||||
ERR_OrdinaryInputObserver.ClearWorld();
|
||||
if (m_ERRDiagnosticLaunchRequest) m_ERRDiagnosticLaunchRequest.Cancel();
|
||||
m_ERRDiagnosticLaunchRequest = null;
|
||||
super.OnBeforeWorldCleanup();
|
||||
@@ -267,6 +268,7 @@ modded class ERR_GameMode
|
||||
if (!Players().CurrentActor(actor) || Phase() != ERR_Phase.PRISON) return;
|
||||
PrintFormat("ERR ORDINARY: local participant verified project=%1 phase=prison", project);
|
||||
ERR_OrdinaryScreenshotRequest.Queue(this, local, actor);
|
||||
ERR_OrdinaryInputObserver.Queue(this, local, actor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,13 @@ modded class SCR_PlayerController
|
||||
{
|
||||
ERR_GameMode mode = ERR_GameMode.Get();
|
||||
if (!mode) return;
|
||||
if (mode.Phase() != ERR_Phase.PREPARING && !GetControlledEntity()) return;
|
||||
if (mode.Phase() != ERR_Phase.PREPARING && (ERR_ObserverState() != ERR_ObserverReason.NONE || !ERR_Actors.Alive(GetControlledEntity()))) return;
|
||||
string message = ERR_ObjectiveText.Description(mode, false);
|
||||
if (message.IsEmpty()) return;
|
||||
if (m_ERRGuidePhase == mode.Phase() && m_ERRGuideMessage == message) return;
|
||||
SCR_HintManagerComponent hints = SCR_HintManagerComponent.GetInstance();
|
||||
if (!hints) return;
|
||||
if (!message.IsEmpty()) hints.ShowCustom(message, ERR_ObjectiveText.Title(mode.Phase()), 15);
|
||||
if (!hints.ShowCustom(message, ERR_ObjectiveText.Title(mode.Phase()), 15)) return;
|
||||
m_ERRGuidePhase = mode.Phase();
|
||||
m_ERRGuideMessage = message;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
// Local presentation attached to the native respawn loading placeholder.
|
||||
// No timer, camera, admission, or mission-state changes.
|
||||
modded class SCR_RespawnSystemComponent
|
||||
{
|
||||
protected Widget m_ERRPreparationParent;
|
||||
protected Widget m_ERRPreparationRoot;
|
||||
protected TextWidget m_ERRPreparationTitle;
|
||||
protected TextWidget m_ERRPreparationDescription;
|
||||
protected Widget m_ERRPreparationSpinner;
|
||||
protected bool m_ERRPreparationSpinnerHidden;
|
||||
protected bool m_ERRPreparationSpinnerWasVisible;
|
||||
protected string m_ERRPreparationLastTitle;
|
||||
protected string m_ERRPreparationLastDescription;
|
||||
|
||||
protected void ERR_ClearPreparationStatus()
|
||||
{
|
||||
if (m_ERRPreparationSpinnerHidden && m_ERRPreparationSpinner)
|
||||
m_ERRPreparationSpinner.SetVisible(m_ERRPreparationSpinnerWasVisible);
|
||||
m_ERRPreparationSpinnerHidden = false;
|
||||
m_ERRPreparationSpinner = null;
|
||||
if (m_ERRPreparationRoot) m_ERRPreparationRoot.RemoveFromHierarchy();
|
||||
m_ERRPreparationRoot = null;
|
||||
m_ERRPreparationParent = null;
|
||||
m_ERRPreparationTitle = null;
|
||||
m_ERRPreparationDescription = null;
|
||||
m_ERRPreparationLastTitle = "";
|
||||
m_ERRPreparationLastDescription = "";
|
||||
}
|
||||
|
||||
override void UpdateLoadingPlaceholder(float dt)
|
||||
{
|
||||
super.UpdateLoadingPlaceholder(dt);
|
||||
// Vanilla OnInit(IEntity owner) stores its owning mode in m_pGameMode.
|
||||
ERR_GameMode mode = ERR_GameMode.Get();
|
||||
if (System.IsConsoleApp() || !mode || m_pGameMode != mode || mode.Phase() != ERR_Phase.PREPARING || !m_wLoadingPlaceholder)
|
||||
{
|
||||
ERR_ClearPreparationStatus();
|
||||
return;
|
||||
}
|
||||
if (m_ERRPreparationParent != m_wLoadingPlaceholder || !m_ERRPreparationRoot || m_ERRPreparationRoot.GetParent() != m_wLoadingPlaceholder)
|
||||
{
|
||||
ERR_ClearPreparationStatus();
|
||||
if (!GetGame() || !GetGame().GetWorkspace()) return;
|
||||
m_ERRPreparationRoot = GetGame().GetWorkspace().CreateWidgets("{BCCAE287751344D9}UI/layouts/ERR/PreparationStatus.layout", m_wLoadingPlaceholder);
|
||||
if (!m_ERRPreparationRoot) return;
|
||||
m_ERRPreparationParent = m_wLoadingPlaceholder;
|
||||
m_ERRPreparationTitle = TextWidget.Cast(m_ERRPreparationRoot.FindAnyWidget("ERR_PreparationTitle"));
|
||||
m_ERRPreparationDescription = TextWidget.Cast(m_ERRPreparationRoot.FindAnyWidget("ERR_PreparationDescription"));
|
||||
if (!m_ERRPreparationTitle || !m_ERRPreparationDescription) { ERR_ClearPreparationStatus(); return; }
|
||||
m_ERRPreparationSpinner = m_wLoadingPlaceholder.FindAnyWidget("Spinner");
|
||||
}
|
||||
bool failed = !mode.PreparationError().IsEmpty();
|
||||
string title = "Preparing mission";
|
||||
if (failed) title = "Mission could not start";
|
||||
string description = ERR_ObjectiveText.Description(mode, false);
|
||||
if (title != m_ERRPreparationLastTitle)
|
||||
{
|
||||
m_ERRPreparationTitle.SetText(title);
|
||||
m_ERRPreparationLastTitle = title;
|
||||
}
|
||||
if (description != m_ERRPreparationLastDescription)
|
||||
{
|
||||
m_ERRPreparationDescription.SetText(description);
|
||||
m_ERRPreparationLastDescription = description;
|
||||
}
|
||||
if (failed && m_ERRPreparationSpinner && !m_ERRPreparationSpinnerHidden)
|
||||
{
|
||||
m_ERRPreparationSpinnerWasVisible = m_ERRPreparationSpinner.IsVisible();
|
||||
m_ERRPreparationSpinner.SetVisible(false);
|
||||
m_ERRPreparationSpinnerHidden = true;
|
||||
}
|
||||
else if (!failed && m_ERRPreparationSpinnerHidden)
|
||||
{
|
||||
if (m_ERRPreparationSpinner) m_ERRPreparationSpinner.SetVisible(m_ERRPreparationSpinnerWasVisible);
|
||||
m_ERRPreparationSpinnerHidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
override void DestroyLoadingPlaceholder()
|
||||
{
|
||||
ERR_ClearPreparationStatus();
|
||||
super.DestroyLoadingPlaceholder();
|
||||
}
|
||||
|
||||
#ifdef WORKBENCH
|
||||
protected bool ERR_PreparationWidgetVisible(Widget widget)
|
||||
{
|
||||
if (!widget || !widget.IsVisible()) return false;
|
||||
float width, height;
|
||||
widget.GetScreenSize(width, height);
|
||||
return width > 0 && height > 0;
|
||||
}
|
||||
// Inspect the actual production-created widgets, without creating or changing them.
|
||||
bool ERR_ProbePreparationVisible(ERR_GameMode mode, bool failed)
|
||||
{
|
||||
if (!mode || mode != ERR_GameMode.Get() || m_pGameMode != mode || !m_wLoadingPlaceholder || !m_wLoadingPlaceholder.IsVisible()) return false;
|
||||
if (!m_ERRPreparationRoot || m_ERRPreparationParent != m_wLoadingPlaceholder || m_ERRPreparationRoot.GetParent() != m_wLoadingPlaceholder || !m_ERRPreparationRoot.IsVisible()) return false;
|
||||
if (!ERR_PreparationWidgetVisible(m_ERRPreparationTitle) || !ERR_PreparationWidgetVisible(m_ERRPreparationDescription) || !ERR_PreparationWidgetVisible(m_ERRPreparationRoot)) return false;
|
||||
string title = "Preparing mission"; if (failed) title = "Mission could not start";
|
||||
if (m_ERRPreparationTitle.GetText() != title || m_ERRPreparationDescription.GetText() != ERR_ObjectiveText.Description(mode, false)) return false;
|
||||
if (failed) return m_ERRPreparationSpinner && m_ERRPreparationSpinnerHidden && !m_ERRPreparationSpinner.IsVisible();
|
||||
return !m_ERRPreparationSpinnerHidden;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
FrameWidgetClass {
|
||||
Name "ERR_PreparationStatus"
|
||||
Slot FrameWidgetSlot {
|
||||
Anchor 0.5 0.5 0.5 0.5
|
||||
OffsetLeft 0
|
||||
OffsetTop 0
|
||||
SizeX 900
|
||||
OffsetRight -900
|
||||
SizeY 240
|
||||
OffsetBottom -240
|
||||
Alignment 0.5 0.5
|
||||
}
|
||||
"Z Order" 10
|
||||
{
|
||||
TextWidgetClass {
|
||||
Name "ERR_PreparationTitle"
|
||||
Slot FrameWidgetSlot {
|
||||
Anchor 0 0 1 0
|
||||
OffsetLeft 0
|
||||
OffsetTop 0
|
||||
SizeY 58
|
||||
OffsetBottom -58
|
||||
}
|
||||
Color 1 1 1 1
|
||||
Text "Preparing mission"
|
||||
"Font Size" 32
|
||||
"Min Font Size" 32
|
||||
}
|
||||
TextWidgetClass {
|
||||
Name "ERR_PreparationDescription"
|
||||
Slot FrameWidgetSlot {
|
||||
Anchor 0 0 1 1
|
||||
OffsetLeft 0
|
||||
OffsetTop 70
|
||||
OffsetRight 0
|
||||
OffsetBottom 0
|
||||
}
|
||||
Color 1 1 1 1
|
||||
Text "Preparing mission sites and equipment. You will spawn when the mission is ready."
|
||||
"Font Size" 22
|
||||
"Min Font Size" 22
|
||||
Wrap 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
MetaFileClass {
|
||||
Name "{BCCAE287751344D9}UI/layouts/ERR/PreparationStatus.layout"
|
||||
Configurations {
|
||||
LayoutResourceClass PC {
|
||||
}
|
||||
LayoutResourceClass HEADLESS : PC {
|
||||
}
|
||||
LayoutResourceClass XBOX_ONE : PC {
|
||||
}
|
||||
LayoutResourceClass XBOX_SERIES : PC {
|
||||
}
|
||||
LayoutResourceClass PS4 : PC {
|
||||
}
|
||||
LayoutResourceClass PS5 : PC {
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user