Room.dark + Item.light flags, a Light helper (isLit/carryingLight), and command gating: can't enter a dark room without a lit light source; look/take/examine obscured in the dark; HUD light field wired. Entry-gate prevents soft-locks. Demo: dark dungeon needs the lit lamp. Fuel/timed light out of scope. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3.9 KiB
Spec: Licht & Dunkelheit (Mechanik-Erweiterung)
Stand: 2026-05-31. Kleine Mechanik aus dem Spine (#3 der Mechanik-Liste), die das Fundament (Flags/Items) nutzt. Strenge: Modell B (Dunkelheit blockiert).
1. Kontext & Ziel
Dunkle Räume sollen den schaltbaren lamp sinnvoll machen: Ohne aktive
Lichtquelle kann man einen dunklen Raum nicht betreten, nichts sehen
(look), und nichts aufnehmen/untersuchen. Die HUD-Zeile light: on/off wird
endlich verdrahtet.
2. Scope
In Scope:
Room.dark(Bool, optional),Item.light(Bool, optional).Light-Helper:isLit,carryingLight.- Command-Gating:
go(Eintritt),look,take,examine; HUD-lightOn. - Demo: Dungeon dunkel → Lampe nötig.
Out of Scope: Lampen-Brennstoff/zeitlich begrenztes Licht; Lichtradius über Räume hinweg; Zufall.
3. Daten (rückwärtskompatibel)
Room.dark:@Setter-Feld (defaultfalse), kein Konstruktor-Argument → keine Test-Brüche. VomRoomFactoryausRoomDto.darkgesetzt. YAML:dark: true.Item.light:booleanam abstraktenItem(via@SuperBuilder), defaultfalse. VomItemFactoryausItemDto.lightgesetzt. YAML:light: true.- Aktive Lichtquelle =
item.lightund (kein Switchable oderSwitchableItem.isOn()). Dielampleuchtet also nur eingeschaltet.
4. Helper Light (game)
static boolean isLit(GameContext ctx, Room room) {
if (!room.isDark()) return true;
return hasActiveLight(player-inventory) || hasActiveLight(room-items);
}
static boolean carryingLight(GameContext ctx); // aktive Lichtquelle im Inventar
hasActiveLight(items) iteriert; isActiveLight(item) = item.isLight() &&
(!(item instanceof SwitchableItem s) || s.isOn()).
Räume gelten als beleuchtet, wenn sie nicht dunkel sind oder eine aktive Lichtquelle getragen wird oder im Raum liegt.
5. Command-Gating (Modell B)
| Command | Verhalten bei dunklem, unbeleuchtetem Zielraum/aktuellem Raum |
|---|---|
GoCommand |
Eintritt blockiert, wenn !isLit(ctx, target): Hinweis-Text, kein Wechsel. (Lichträume bleiben immer betretbar → kein Soft-Lock, Rückzug stets möglich.) |
LookCommand |
!isLit(ctx, current) → „It's pitch black; you can't make anything out." statt RoomView (Fall: Lampe ging im Raum aus). |
TakeCommand |
!isLit(ctx, current) → „It's too dark to see that." |
ExamineCommand |
!isLit(ctx, current) → „It's too dark to see that." |
| HUD | lightOn = Light.carryingLight(ctx) (in Game.publishHud). |
Erlaubt im Dunkeln bleiben: inventory, drop, use (z. B. Lampe anzünden),
quests, map, help. So kann man eine getragene Lampe im Dunkeln anzünden.
6. Fehlerbehandlung / Soft-Lock
Eintrittssperre statt Innen-Sperre: Man betritt einen dunklen Raum nur mit
Licht. Geht das Licht drinnen aus, sind look/take/examine blockiert, aber der
Rückweg in einen hellen Raum bleibt (Zielraum hell → isLit true). Kein Soft-Lock.
7. Demo
lamp:light: true(bereits schaltbar;use lamp→ an).dungeon:dark: true; der Generator steht dort. Ablauf:take lamp→use lamp(an) →go south(jetzt betretbar) →use generator. HUD zeigtlight: on, sobald die Lampe brennt. Gibt man die Lampe später dem alten Mann, verliert man das Licht (thematisch).
8. Testing
Light.isLit: nicht dunkel → hell; dunkel ohne Licht → dunkel; dunkel + getragene brennende Lampe → hell; dunkel + Lampe aus → dunkel; dunkel + brennende Lampe im Raum → hell.carryingLight.- Command-Gates:
goin dunklen Raum ohne Licht blockt, mit brennender Lampe ok;look/takeim dunklen Raum blockt. - End-to-End (Konsole):
go southohne Licht blockt;take lamp/use lamp/go southbetritt; HUDlight: on.
9. Offene Detailfragen (in Implementierung)
- Genauer Hinweis-Text der Eintrittssperre (nennt
use lamp).