fix(quests): tick the escort engine before the quest engine; guard the valve

Two independent world-logic bugs:

- Game.publishHud ticked QuestEngine before EscortEngine, so the twins_reunited
  flag set by the escort was only observed a full turn later. On the turn the
  twins were reunited, 'quests' still listed the objective as active.

- The valve_wheel/valve recipe had neither 'consume' nor 'requires', so it could
  be repeated indefinitely, minting a fresh ceramic fuse every time. It now
  requires notFlag cellar_drained and explains itself once the cellar is dry.
This commit is contained in:
2026-07-14 12:38:35 +02:00
parent cc2221121d
commit 8f6ee80f30
2 changed files with 16 additions and 3 deletions

View File

@@ -7,7 +7,6 @@ import thb.jeanluc.adventure.command.CommandRegistry;
import thb.jeanluc.adventure.command.ParsedCommand; import thb.jeanluc.adventure.command.ParsedCommand;
import thb.jeanluc.adventure.io.text.Hud; import thb.jeanluc.adventure.io.text.Hud;
import thb.jeanluc.adventure.io.text.MapView; import thb.jeanluc.adventure.io.text.MapView;
import thb.jeanluc.adventure.map.MapLayout;
import thb.jeanluc.adventure.model.Ending; import thb.jeanluc.adventure.model.Ending;
import java.util.Optional; import java.util.Optional;
@@ -35,7 +34,11 @@ public class Game {
/** Optional onboarding guide; null in normal/loaded play. */ /** Optional onboarding guide; null in normal/loaded play. */
private TutorialGuide tutorialGuide; private TutorialGuide tutorialGuide;
/** Wires the interactive tutorial (New Game only). */ /**
* Wires the interactive tutorial (New Game only).
*
* @param tutorialGuide the guide to run alongside the loop
*/
public void setTutorialGuide(TutorialGuide tutorialGuide) { public void setTutorialGuide(TutorialGuide tutorialGuide) {
this.tutorialGuide = tutorialGuide; this.tutorialGuide = tutorialGuide;
} }
@@ -96,9 +99,15 @@ public class Game {
} }
} }
/**
* Ticks the per-turn engines and republishes the whole view state — HUD,
* map, quest panel, and room music — to the IO channel.
*/
private void publishHud() { private void publishHud() {
QuestEngine.tick(ctx); // EscortEngine first: it sets flags (e.g. twins_reunited) that
// QuestEngine's stage-completion conditions read in the same turn.
EscortEngine.tick(ctx); EscortEngine.tick(ctx);
QuestEngine.tick(ctx);
ctx.getIo().setHud(new Hud( ctx.getIo().setHud(new Hud(
ctx.getPlayer().getCurrentRoom().getName(), ctx.getPlayer().getCurrentRoom().getName(),
ctx.getPlayer().getGold(), ctx.getPlayer().getGold(),

View File

@@ -13,8 +13,12 @@
- a: valve_wheel - a: valve_wheel
b: valve b: valve
produce: fuse produce: fuse
requires:
- { notFlag: cellar_drained }
effects: effects:
- { setFlag: cellar_drained } - { setFlag: cellar_drained }
failText: |
The cellar is already drained; the valve turns freely on nothing.
response: | response: |
You fit the wheel and crank it hard. The valve groans, the black water You fit the wheel and crank it hard. The valve groans, the black water
drops away — and a ceramic fuse, washed loose, settles at your feet. drops away — and a ceramic fuse, washed loose, settles at your feet.