#ifdef WORKBENCH class ERR_PreparationExitProbe { static int s_Pauses, s_ExitAt; static bool s_Armed, s_Clean, s_Ended, s_Complete; static void Finish() { if (!s_Armed || !s_Clean || !s_Ended || s_Complete || System.GetTickCount() - s_ExitAt >= 5000) return; s_Complete = true; Check(true, "native gameplay end after exit click and menu-listener cleanup observed"); Print("ERR SMOKE COMPLETE: preparation-exit native gameplay-end transition"); } static bool Enabled() { string outcome; return System.GetCLIParam("errSmokeOutcome", outcome) && outcome == "preparation-exit"; } static bool Check(bool ok, string detail) { if (ok) Print("ERR SMOKE PASS: preparation exit " + detail); else Print("ERR SMOKE FAIL: preparation exit " + detail, LogLevel.ERROR); return ok; } } modded class ERR_GameMode { override protected void StartScenario() { if (ERR_PreparationExitProbe.Enabled()) { FailPreparation("Fixture: no safe navigable prison. Checks: water=120; uneven ground=30"); return; } super.StartScenario(); } } modded class SCR_RespawnSystemComponent { bool ERR_TestUnderlayHidden() { return m_wLoadingPlaceholder && !m_wLoadingPlaceholder.IsVisible(); } } modded class PauseMenuUI { protected bool m_ERRExitTestClosed; override void OnMenuUpdate(float tDelta) { super.OnMenuUpdate(tDelta); if (!ERR_PreparationExitProbe.Enabled() || m_ERRExitTestClosed) return; m_ERRExitTestClosed = true; SCR_RespawnSystemComponent respawn = SCR_RespawnSystemComponent.GetInstance(); if (!ERR_PreparationExitProbe.Check(IsFocused() && respawn && respawn.ERR_TestUnderlayHidden(), "native pause has focus and black underlay remains hidden")) return; ERR_PreparationExitProbe.s_Pauses++; Close(); } } modded class ERR_PreparationFailureMenu { protected float m_ERRExitTestAge; protected int m_ERRExitTestStage; override void OnMenuUpdate(float tDelta) { super.OnMenuUpdate(tDelta); if (!ERR_PreparationExitProbe.Enabled() || !IsFocused() || m_ERRExitTestStage < 0) return; m_ERRExitTestAge += tDelta; if (m_ERRExitTestAge < 1) return; m_ERRExitTestAge = 0; if (m_ERRExitTestStage == 0) { SCR_RespawnSystemComponent respawn = SCR_RespawnSystemComponent.GetInstance(); if (!ERR_PreparationExitProbe.Check(Visible(m_Mode) && m_Bound && respawn && respawn.ERR_TestUnderlayHidden(), "real focused error menu has both bound buttons, exact error and hidden loading layer")) { m_ERRExitTestStage = -1; return; } m_ERRExitTestStage = 1; m_PauseButton.m_OnClicked.Invoke(m_PauseButton); return; } if (m_ERRExitTestStage == 1) { if (!ERR_PreparationExitProbe.Check(ERR_PreparationExitProbe.s_Pauses == 1 && Failed(m_Mode), "pause button returns to the same failed round without admitting a player")) { m_ERRExitTestStage = -1; return; } m_ERRExitTestStage = 2; OnBack(); // Actual handler bound to MenuBack; no physical key-input claim. return; } if (m_ERRExitTestStage == 2) { if (!ERR_PreparationExitProbe.Check(ERR_PreparationExitProbe.s_Pauses == 2, "bound Back handler opens native pause and restores failure-menu focus")) { m_ERRExitTestStage = -1; return; } m_ERRExitTestStage = 3; ERR_PreparationExitProbe.s_Armed = true; ERR_PreparationExitProbe.s_ExitAt = System.GetTickCount(); m_ReturnButton.m_OnClicked.Invoke(m_ReturnButton); } } override void OnMenuClose() { super.OnMenuClose(); if (ERR_PreparationExitProbe.s_Armed) { ERR_PreparationExitProbe.s_Clean = !m_Bound && !m_Mode && !m_ReturnButton && !m_PauseButton; PrintFormat("ERR EXIT TEST: menu closed; cleaned=%1", ERR_PreparationExitProbe.s_Clean); ERR_PreparationExitProbe.Finish(); } } } modded class ArmaReforgerScripted { override void OnGameEnd() { bool expected = ERR_PreparationExitProbe.Enabled() && ERR_PreparationExitProbe.s_Armed && System.GetTickCount() - ERR_PreparationExitProbe.s_ExitAt < 5000; super.OnGameEnd(); if (!expected) return; // Runner shutdown cannot qualify the exit button. ERR_PreparationExitProbe.s_Ended = true; Print("ERR EXIT TEST: native gameplay ended after the real exit button"); ERR_PreparationExitProbe.Finish(); } } #endif