feat: Add quit callback support to engine and UI components

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-20 10:04:01 +01:00
parent 9b053e1c02
commit e060aef3f1
5 changed files with 59 additions and 3 deletions

View File

@@ -24,6 +24,7 @@ class WolfEngine {
this.menuBackgroundRgb = 0x890000,
this.menuPanelRgb = 0x590002,
this.onMenuExit,
this.onQuit,
this.onGameSelected,
this.onEpisodeSelected,
EngineAudio? engineAudio,
@@ -95,6 +96,9 @@ class WolfEngine {
/// Callback triggered when backing out of the top-level menu.
final void Function()? onMenuExit;
/// Callback triggered when the player explicitly selects QUIT.
final void Function()? onQuit;
/// Callback triggered whenever the active game changes from menu flow.
final void Function(WolfensteinData game)? onGameSelected;
@@ -330,8 +334,10 @@ class WolfEngine {
case WolfMenuMainAction.backToGame:
_resumeGame();
break;
case WolfMenuMainAction.backToDemo:
case WolfMenuMainAction.quit:
_quitProgram();
break;
case WolfMenuMainAction.backToDemo:
_exitTopLevelMenu();
break;
case WolfMenuMainAction.sound:
@@ -445,6 +451,14 @@ class WolfEngine {
onGameWon();
}
void _quitProgram() {
if (onQuit != null) {
onQuit!.call();
return;
}
_exitTopLevelMenu();
}
/// Wipes the current world state and builds a new floor from map data.
void _loadLevel({required bool preservePlayerState}) {
entities.clear();

View File

@@ -216,12 +216,16 @@ void main() {
expect(manager.selectedMainIndex, 0);
});
test('quit selection triggers top-level menu exit callback', () {
test('quit selection triggers dedicated quit callback', () {
final input = _TestInput();
int quitCalls = 0;
int exitCalls = 0;
final engine = _buildEngine(
input: input,
difficulty: null,
onQuit: () {
quitCalls++;
},
onMenuExit: () {
exitCalls++;
},
@@ -245,6 +249,32 @@ void main() {
engine.tick(const Duration(milliseconds: 16));
input.isInteracting = false;
expect(quitCalls, 1);
expect(exitCalls, 0);
});
test('backing out of the top-level menu uses menu-exit callback', () {
final input = _TestInput();
int quitCalls = 0;
int exitCalls = 0;
final engine = _buildEngine(
input: input,
difficulty: null,
onQuit: () {
quitCalls++;
},
onMenuExit: () {
exitCalls++;
},
);
engine.init();
input.isBack = true;
engine.tick(const Duration(milliseconds: 16));
input.isBack = false;
expect(quitCalls, 0);
expect(exitCalls, 1);
});
});
@@ -254,6 +284,7 @@ WolfEngine _buildMultiGameEngine({
required _TestInput input,
required Difficulty? difficulty,
void Function()? onMenuExit,
void Function()? onQuit,
}) {
final WolfensteinData retail = _buildTestData(
gameVersion: GameVersion.retail,
@@ -271,6 +302,7 @@ WolfEngine _buildMultiGameEngine({
engineAudio: _SilentAudio(),
onGameWon: () {},
onMenuExit: onMenuExit,
onQuit: onQuit,
);
}
@@ -278,6 +310,7 @@ WolfEngine _buildEngine({
required _TestInput input,
required Difficulty? difficulty,
void Function()? onMenuExit,
void Function()? onQuit,
}) {
return WolfEngine(
data: _buildTestData(gameVersion: GameVersion.retail),
@@ -288,6 +321,7 @@ WolfEngine _buildEngine({
engineAudio: _SilentAudio(),
onGameWon: () {},
onMenuExit: onMenuExit,
onQuit: onQuit,
);
}