feat: darkness gating for go/look/take/examine + HUD light
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package thb.jeanluc.adventure.command.impl;
|
|||||||
|
|
||||||
import thb.jeanluc.adventure.command.Command;
|
import thb.jeanluc.adventure.command.Command;
|
||||||
import thb.jeanluc.adventure.game.GameContext;
|
import thb.jeanluc.adventure.game.GameContext;
|
||||||
|
import thb.jeanluc.adventure.game.Light;
|
||||||
import thb.jeanluc.adventure.model.Npc;
|
import thb.jeanluc.adventure.model.Npc;
|
||||||
import thb.jeanluc.adventure.model.item.Item;
|
import thb.jeanluc.adventure.model.item.Item;
|
||||||
|
|
||||||
@@ -20,6 +21,10 @@ public class ExamineCommand implements Command {
|
|||||||
ctx.getIo().write("Examine what?");
|
ctx.getIo().write("Examine what?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!Light.isLit(ctx, ctx.getPlayer().getCurrentRoom())) {
|
||||||
|
ctx.getIo().write("It's too dark to see that.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
String id = args.getFirst();
|
String id = args.getFirst();
|
||||||
Optional<Item> item = ctx.getPlayer().findItem(id);
|
Optional<Item> item = ctx.getPlayer().findItem(id);
|
||||||
if (item.isEmpty()) {
|
if (item.isEmpty()) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package thb.jeanluc.adventure.command.impl;
|
|||||||
import thb.jeanluc.adventure.command.Command;
|
import thb.jeanluc.adventure.command.Command;
|
||||||
import thb.jeanluc.adventure.game.Conditions;
|
import thb.jeanluc.adventure.game.Conditions;
|
||||||
import thb.jeanluc.adventure.game.GameContext;
|
import thb.jeanluc.adventure.game.GameContext;
|
||||||
|
import thb.jeanluc.adventure.game.Light;
|
||||||
import thb.jeanluc.adventure.model.Direction;
|
import thb.jeanluc.adventure.model.Direction;
|
||||||
import thb.jeanluc.adventure.model.ExitLock;
|
import thb.jeanluc.adventure.model.ExitLock;
|
||||||
import thb.jeanluc.adventure.model.Room;
|
import thb.jeanluc.adventure.model.Room;
|
||||||
@@ -39,6 +40,11 @@ public class GoCommand implements Command {
|
|||||||
ctx.getIo().write(lock.blocked());
|
ctx.getIo().write(lock.blocked());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!Light.isLit(ctx, next.get())) {
|
||||||
|
ctx.getIo().write("It's pitch black beyond the doorway — you need a lit light source "
|
||||||
|
+ "(try lighting your lamp with 'use lamp').");
|
||||||
|
return;
|
||||||
|
}
|
||||||
ctx.getPlayer().setCurrentRoom(next.get());
|
ctx.getPlayer().setCurrentRoom(next.get());
|
||||||
new LookCommand().execute(ctx, List.of());
|
new LookCommand().execute(ctx, List.of());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package thb.jeanluc.adventure.command.impl;
|
|||||||
import thb.jeanluc.adventure.command.Command;
|
import thb.jeanluc.adventure.command.Command;
|
||||||
import thb.jeanluc.adventure.game.Conditions;
|
import thb.jeanluc.adventure.game.Conditions;
|
||||||
import thb.jeanluc.adventure.game.GameContext;
|
import thb.jeanluc.adventure.game.GameContext;
|
||||||
|
import thb.jeanluc.adventure.game.Light;
|
||||||
import thb.jeanluc.adventure.io.text.RoomView;
|
import thb.jeanluc.adventure.io.text.RoomView;
|
||||||
import thb.jeanluc.adventure.model.DescriptionState;
|
import thb.jeanluc.adventure.model.DescriptionState;
|
||||||
import thb.jeanluc.adventure.model.Direction;
|
import thb.jeanluc.adventure.model.Direction;
|
||||||
@@ -21,6 +22,10 @@ public class LookCommand implements Command {
|
|||||||
@Override
|
@Override
|
||||||
public void execute(GameContext ctx, List<String> args) {
|
public void execute(GameContext ctx, List<String> args) {
|
||||||
Room room = ctx.getPlayer().getCurrentRoom();
|
Room room = ctx.getPlayer().getCurrentRoom();
|
||||||
|
if (!Light.isLit(ctx, room)) {
|
||||||
|
ctx.getIo().write("It's pitch black; you can't make anything out. You need a light source.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
List<String> items = room.getItems().values().stream().map(Item::getName).toList();
|
List<String> items = room.getItems().values().stream().map(Item::getName).toList();
|
||||||
List<String> npcs = room.getNpcs().values().stream().map(Npc::getName).toList();
|
List<String> npcs = room.getNpcs().values().stream().map(Npc::getName).toList();
|
||||||
List<String> exits = room.getExits().keySet().stream().map(Direction::getLabel).toList();
|
List<String> exits = room.getExits().keySet().stream().map(Direction::getLabel).toList();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package thb.jeanluc.adventure.command.impl;
|
|||||||
|
|
||||||
import thb.jeanluc.adventure.command.Command;
|
import thb.jeanluc.adventure.command.Command;
|
||||||
import thb.jeanluc.adventure.game.GameContext;
|
import thb.jeanluc.adventure.game.GameContext;
|
||||||
|
import thb.jeanluc.adventure.game.Light;
|
||||||
import thb.jeanluc.adventure.model.Room;
|
import thb.jeanluc.adventure.model.Room;
|
||||||
import thb.jeanluc.adventure.model.item.Item;
|
import thb.jeanluc.adventure.model.item.Item;
|
||||||
|
|
||||||
@@ -20,6 +21,10 @@ public class TakeCommand implements Command {
|
|||||||
ctx.getIo().write("Take what?");
|
ctx.getIo().write("Take what?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!Light.isLit(ctx, ctx.getPlayer().getCurrentRoom())) {
|
||||||
|
ctx.getIo().write("It's too dark to see that.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
String itemId = args.getFirst();
|
String itemId = args.getFirst();
|
||||||
Room room = ctx.getPlayer().getCurrentRoom();
|
Room room = ctx.getPlayer().getCurrentRoom();
|
||||||
Optional<Item> taken = room.removeItem(itemId);
|
Optional<Item> taken = room.removeItem(itemId);
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class Game {
|
|||||||
ctx.getPlayer().getCurrentRoom().getName(),
|
ctx.getPlayer().getCurrentRoom().getName(),
|
||||||
ctx.getPlayer().getGold(),
|
ctx.getPlayer().getGold(),
|
||||||
turn,
|
turn,
|
||||||
false));
|
Light.carryingLight(ctx)));
|
||||||
MapView map = MapLayout.compute(
|
MapView map = MapLayout.compute(
|
||||||
ctx.getWorld(),
|
ctx.getWorld(),
|
||||||
ctx.getPlayer().getVisitedRoomIds(),
|
ctx.getPlayer().getVisitedRoomIds(),
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package thb.jeanluc.adventure.command.impl;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import thb.jeanluc.adventure.game.GameContext;
|
||||||
|
import thb.jeanluc.adventure.io.TestIO;
|
||||||
|
import thb.jeanluc.adventure.model.Direction;
|
||||||
|
import thb.jeanluc.adventure.model.Player;
|
||||||
|
import thb.jeanluc.adventure.model.Room;
|
||||||
|
import thb.jeanluc.adventure.model.item.SwitchableItem;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class DarknessTest {
|
||||||
|
private SwitchableItem lamp(boolean on) {
|
||||||
|
return SwitchableItem.builder().id("lamp").name("Lamp").description("d")
|
||||||
|
.state(on).onText("on").offText("off").light(true).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void cannotEnterDarkRoomWithoutLight() {
|
||||||
|
Room hall = new Room("hall", "Hall", "d");
|
||||||
|
Room cave = new Room("cave", "Cave", "d");
|
||||||
|
cave.setDark(true);
|
||||||
|
hall.addExit(Direction.NORTH, cave);
|
||||||
|
Player p = new Player(hall, 0);
|
||||||
|
GameContext ctx = new GameContext(null, p, new TestIO());
|
||||||
|
|
||||||
|
new GoCommand().execute(ctx, List.of("north"));
|
||||||
|
assertThat(p.getCurrentRoom()).isEqualTo(hall);
|
||||||
|
assertThat(((TestIO) ctx.getIo()).allOutput()).containsIgnoringCase("pitch black");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void canEnterDarkRoomWithLitLamp() {
|
||||||
|
Room hall = new Room("hall", "Hall", "d");
|
||||||
|
Room cave = new Room("cave", "Cave", "d");
|
||||||
|
cave.setDark(true);
|
||||||
|
hall.addExit(Direction.NORTH, cave);
|
||||||
|
Player p = new Player(hall, 0);
|
||||||
|
p.addItem(lamp(true));
|
||||||
|
GameContext ctx = new GameContext(null, p, new TestIO());
|
||||||
|
|
||||||
|
new GoCommand().execute(ctx, List.of("north"));
|
||||||
|
assertThat(p.getCurrentRoom()).isEqualTo(cave);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void lookAndTakeAreBlockedInTheDark() {
|
||||||
|
Room cave = new Room("cave", "Cave", "d");
|
||||||
|
cave.setDark(true);
|
||||||
|
Player p = new Player(cave, 0);
|
||||||
|
TestIO io = new TestIO();
|
||||||
|
GameContext ctx = new GameContext(null, p, io);
|
||||||
|
|
||||||
|
new LookCommand().execute(ctx, List.of());
|
||||||
|
assertThat(io.allOutput()).containsIgnoringCase("pitch black");
|
||||||
|
|
||||||
|
io.outputs().clear();
|
||||||
|
new TakeCommand().execute(ctx, List.of("anything"));
|
||||||
|
assertThat(io.allOutput()).containsIgnoringCase("too dark");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user