diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/App.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/App.java index 817b772..c609650 100644 --- a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/App.java +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/App.java @@ -11,6 +11,7 @@ import thb.jeanluc.adventure.command.impl.HelpCommand; import thb.jeanluc.adventure.command.impl.InventoryCommand; import thb.jeanluc.adventure.command.impl.LookCommand; import thb.jeanluc.adventure.command.impl.MapCommand; +import thb.jeanluc.adventure.command.impl.QuestsCommand; import thb.jeanluc.adventure.command.impl.QuitCommand; import thb.jeanluc.adventure.command.impl.ReadCommand; import thb.jeanluc.adventure.command.impl.TakeCommand; @@ -70,6 +71,7 @@ public final class App { registry.register(new ReadCommand(), "read"); registry.register(new ExamineCommand(), "examine", "x", "inspect"); registry.register(new MapCommand(), "map", "m"); + registry.register(new QuestsCommand(), "quests", "log", "journal"); registry.register(new TalkCommand(), "talk", "speak"); registry.register(new GiveCommand(), "give"); registry.register(new HelpCommand(registry), "help", "?"); diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/command/impl/QuestsCommand.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/command/impl/QuestsCommand.java new file mode 100644 index 0000000..ffc2787 --- /dev/null +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/command/impl/QuestsCommand.java @@ -0,0 +1,21 @@ +package thb.jeanluc.adventure.command.impl; + +import thb.jeanluc.adventure.command.Command; +import thb.jeanluc.adventure.game.GameContext; +import thb.jeanluc.adventure.game.QuestEngine; + +import java.util.List; + +/** Shows the active and completed quests. Usage: {@code quests}. */ +public class QuestsCommand implements Command { + + @Override + public void execute(GameContext ctx, List args) { + ctx.getIo().showQuests(QuestEngine.viewOf(ctx)); + } + + @Override + public String help() { + return "quests - show your active and completed quests (alias: log, journal)"; + } +} 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 24210e3..0d5a5cb 100644 --- a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/game/Game.java +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/game/Game.java @@ -60,6 +60,7 @@ public class Game { } private void publishHud() { + QuestEngine.tick(ctx); ctx.getIo().setHud(new Hud( ctx.getPlayer().getCurrentRoom().getName(), ctx.getPlayer().getGold(), @@ -70,6 +71,7 @@ public class Game { ctx.getPlayer().getVisitedRoomIds(), ctx.getPlayer().getCurrentRoom()); ctx.getIo().setMap(map); + ctx.getIo().setQuests(QuestEngine.viewOf(ctx)); } /** diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/GameIO.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/GameIO.java index 060d88d..98584b0 100644 --- a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/GameIO.java +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/GameIO.java @@ -3,6 +3,8 @@ package thb.jeanluc.adventure.io; import thb.jeanluc.adventure.io.text.AsciiMap; import thb.jeanluc.adventure.io.text.Hud; import thb.jeanluc.adventure.io.text.MapView; +import thb.jeanluc.adventure.io.text.QuestText; +import thb.jeanluc.adventure.io.text.QuestView; import thb.jeanluc.adventure.io.text.Renderings; import thb.jeanluc.adventure.io.text.RoomView; import thb.jeanluc.adventure.io.text.StyledText; @@ -44,4 +46,14 @@ public interface GameIO { default void showMap(MapView view) { print(AsciiMap.render(view, true)); } + + /** Per-turn push of the quest log. GUI repaints its box; console ignores. */ + default void setQuests(QuestView view) { + // no-op + } + + /** On-demand quest log (the 'quests' command). Default renders styled text. */ + default void showQuests(QuestView view) { + print(QuestText.render(view)); + } } diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/text/QuestText.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/text/QuestText.java new file mode 100644 index 0000000..da1814e --- /dev/null +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/io/text/QuestText.java @@ -0,0 +1,29 @@ +package thb.jeanluc.adventure.io.text; + +/** Renders a {@link QuestView} as styled text for the console quest log. */ +public final class QuestText { + + private QuestText() { + } + + public static StyledText render(QuestView view) { + if (view.active().isEmpty() && view.completed().isEmpty()) { + return StyledText.of("You have no quests yet."); + } + StyledText.Builder b = StyledText.builder(); + b.heading("QUESTS"); + if (view.active().isEmpty()) { + b.plain("\n").dim(" (none active)"); + } + for (QuestEntry e : view.active()) { + b.plain("\n").heading(e.title()).plain("\n").exit(" -> ").plain(e.objective()); + } + if (!view.completed().isEmpty()) { + b.plain("\n\n").dim("Completed:"); + for (String t : view.completed()) { + b.plain("\n").dim(" ✓ " + t); + } + } + return b.build(); + } +} diff --git a/Semesterprojekt/src/test/java/thb/jeanluc/adventure/command/impl/QuestsCommandTest.java b/Semesterprojekt/src/test/java/thb/jeanluc/adventure/command/impl/QuestsCommandTest.java new file mode 100644 index 0000000..6b66023 --- /dev/null +++ b/Semesterprojekt/src/test/java/thb/jeanluc/adventure/command/impl/QuestsCommandTest.java @@ -0,0 +1,34 @@ +package thb.jeanluc.adventure.command.impl; + +import org.junit.jupiter.api.Test; +import thb.jeanluc.adventure.game.GameContext; +import thb.jeanluc.adventure.game.QuestEngine; +import thb.jeanluc.adventure.io.TestIO; +import thb.jeanluc.adventure.model.Condition; +import thb.jeanluc.adventure.model.Player; +import thb.jeanluc.adventure.model.Quest; +import thb.jeanluc.adventure.model.QuestStage; +import thb.jeanluc.adventure.model.Room; +import thb.jeanluc.adventure.model.World; + +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class QuestsCommandTest { + @Test + void showsActiveObjective() { + Quest q = new Quest("q", "My Quest", true, + List.of(new QuestStage("Do the thing", + List.of(new Condition(Condition.Type.FLAG, "x")), List.of())), List.of()); + World w = new World(Map.of(), Map.of(), Map.of(), "t", "w", Map.of("q", q)); + GameContext ctx = new GameContext(w, new Player(new Room("k", "K", "d"), 0), new TestIO()); + QuestEngine.tick(ctx); // auto-start + + new QuestsCommand().execute(ctx, List.of()); + + String out = ((TestIO) ctx.getIo()).allOutput(); + assertThat(out).contains("My Quest").contains("Do the thing"); + } +}