From 00d3f97c9b284a49cfc2157989a93be172bb3383 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Mon, 1 Jun 2026 22:09:06 +0200 Subject: [PATCH] fix(game): suppress endings while the tutorial is active A command during the walkthrough (e.g. use front_door -> fled) no longer ends the game mid-tutorial; a pending ending fires once the tutorial finishes or is skipped. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../java/thb/jeanluc/adventure/game/Game.java | 5 +++ .../adventure/game/GameTutorialTest.java | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/game/Game.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/game/Game.java index 0e4fd42..ed191de 100644 --- a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/game/Game.java +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/game/Game.java @@ -84,6 +84,11 @@ public class Game { /** Ends the game if any ending's conditions are met, printing its screen. */ private void maybeEnd() { + // Don't end the game (win or lose) while the player is still in the tutorial — + // a pending ending fires once the walkthrough finishes or is skipped. + if (tutorialGuide != null && tutorialGuide.isActive()) { + return; + } Ending e = EndingEngine.triggered(ctx); if (e != null) { ctx.getIo().print(EndingEngine.render(e, ctx, ctx.getSession().getTurn())); diff --git a/Semesterprojekt/src/test/java/thb/jeanluc/adventure/game/GameTutorialTest.java b/Semesterprojekt/src/test/java/thb/jeanluc/adventure/game/GameTutorialTest.java index 43a10ea..9eb5466 100644 --- a/Semesterprojekt/src/test/java/thb/jeanluc/adventure/game/GameTutorialTest.java +++ b/Semesterprojekt/src/test/java/thb/jeanluc/adventure/game/GameTutorialTest.java @@ -5,6 +5,8 @@ import thb.jeanluc.adventure.command.CommandParser; import thb.jeanluc.adventure.command.CommandRegistry; import thb.jeanluc.adventure.command.impl.LookCommand; import thb.jeanluc.adventure.io.TestIO; +import thb.jeanluc.adventure.model.Condition; +import thb.jeanluc.adventure.model.Ending; import thb.jeanluc.adventure.model.Player; import thb.jeanluc.adventure.model.Room; import thb.jeanluc.adventure.model.Tutorial; @@ -44,4 +46,34 @@ class GameTutorialTest { assertThat(out).contains("STEP1-OK"); // first 'look' advanced step 1 assertThat(out).contains("Tutorial skipped"); // 'skip' ended it before step 2 finished } + + @Test + void endingsAreSuppressedWhileTutorialActiveAndFireAfter() { + Room kitchen = new Room("kitchen", "Kitchen", "d"); + Ending fled = new Ending("fled", "Fled", false, + List.of(new Condition(Condition.Type.FLAG, "fled")), "ENDING-TEXT"); + World w = new World(Map.of("kitchen", kitchen), Map.of(), Map.of(), + "t", "w", Map.of(), List.of(fled)); + TestIO io = new TestIO(); + io.enqueue("look"); // completes the 1-step tutorial; then EOF ends run() + GameContext ctx = new GameContext(new GameSession(w, new Player(kitchen, 0), "s"), io); + ctx.getState().set("fled"); // ending condition already met from the start + + CommandRegistry registry = new CommandRegistry(); + registry.register(new LookCommand(), "look", "l"); + + Tutorial t = new Tutorial("INTRO", + List.of(new TutorialStep("do look", "look", 0, "STEP1-OK", "hint")), "TIPS"); + Game game = new Game(ctx, registry, new CommandParser()); + game.setTutorialGuide(new TutorialGuide(t, registry)); + + game.run(); + + String out = io.allOutput(); + // The 'look' was processed -> the pre-loop ending did NOT stop the game first. + assertThat(out).contains("STEP1-OK"); + // After the tutorial finished, the ending fired. + assertThat(out).contains("ENDING-TEXT"); + assertThat(out.indexOf("STEP1-OK")).isLessThan(out.indexOf("ENDING-TEXT")); + } }