feat: switchable items apply effects when turned on

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 21:59:46 +02:00
parent 258ab4f63b
commit 00bad46661
4 changed files with 49 additions and 1 deletions

View File

@@ -44,6 +44,7 @@ public final class ItemFactory {
.state(Boolean.TRUE.equals(dto.initialState())) .state(Boolean.TRUE.equals(dto.initialState()))
.onText(dto.onText()) .onText(dto.onText())
.offText(dto.offText()) .offText(dto.offText())
.effects(thb.jeanluc.adventure.loader.dto.EffectDto.toModelList(dto.effects()))
.build(); .build();
default -> throw new WorldLoadException( default -> throw new WorldLoadException(
"Unknown item type '" + dto.type() + "' on item '" + dto.id() + "'"); "Unknown item type '" + dto.type() + "' on item '" + dto.id() + "'");

View File

@@ -1,5 +1,7 @@
package thb.jeanluc.adventure.loader.dto; package thb.jeanluc.adventure.loader.dto;
import java.util.List;
/** /**
* YAML representation of a single item. Fields outside of the type's * YAML representation of a single item. Fields outside of the type's
* scope (e.g. {@code readText} on a switchable) are simply ignored. * scope (e.g. {@code readText} on a switchable) are simply ignored.
@@ -12,6 +14,7 @@ package thb.jeanluc.adventure.loader.dto;
* @param initialState initial on/off state of a switchable item * @param initialState initial on/off state of a switchable item
* @param onText message printed when a switchable transitions to on * @param onText message printed when a switchable transitions to on
* @param offText message printed when a switchable transitions to off * @param offText message printed when a switchable transitions to off
* @param effects effects applied when a switchable transitions to on; nullable
*/ */
public record ItemDto( public record ItemDto(
String type, String type,
@@ -21,6 +24,12 @@ public record ItemDto(
String readText, String readText,
Boolean initialState, Boolean initialState,
String onText, String onText,
String offText String offText,
List<EffectDto> effects
) { ) {
/** Backward-compatible constructor without effects. */
public ItemDto(String type, String id, String name, String description,
String readText, Boolean initialState, String onText, String offText) {
this(type, id, name, description, readText, initialState, onText, offText, null);
}
} }

View File

@@ -2,7 +2,11 @@ package thb.jeanluc.adventure.model.item;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;
import thb.jeanluc.adventure.game.Effects;
import thb.jeanluc.adventure.game.GameContext; import thb.jeanluc.adventure.game.GameContext;
import thb.jeanluc.adventure.model.Effect;
import java.util.List;
/** /**
* Item with two boolean states (on / off). Each {@code use} toggles the * Item with two boolean states (on / off). Each {@code use} toggles the
@@ -24,6 +28,9 @@ public class SwitchableItem extends Item {
*/ */
private boolean state; private boolean state;
/** Effects applied when this item transitions to on; null = none. */
private final List<Effect> effects;
/** /**
* Toggles the state and writes the corresponding transition text. * Toggles the state and writes the corresponding transition text.
* *
@@ -33,6 +40,9 @@ public class SwitchableItem extends Item {
public void use(GameContext ctx) { public void use(GameContext ctx) {
state = !state; state = !state;
ctx.getIo().write(state ? onText : offText); ctx.getIo().write(state ? onText : offText);
if (state) {
Effects.applyAll(effects, ctx);
}
} }
/** /**

View File

@@ -0,0 +1,28 @@
package thb.jeanluc.adventure.model.item;
import org.junit.jupiter.api.Test;
import thb.jeanluc.adventure.game.GameContext;
import thb.jeanluc.adventure.io.TestIO;
import thb.jeanluc.adventure.model.Effect;
import thb.jeanluc.adventure.model.Player;
import thb.jeanluc.adventure.model.Room;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
class SwitchEffectsTest {
@Test
void switchingOnAppliesEffects() {
SwitchableItem breaker = SwitchableItem.builder()
.id("breaker").name("Breaker").description("d")
.state(false).onText("hums to life").offText("off")
.effects(List.of(new Effect(Effect.Type.SET_FLAG, "power_on")))
.build();
Player player = new Player(new Room("k", "K", "d"), 0);
GameContext ctx = new GameContext(null, player, new TestIO());
breaker.use(ctx);
assertThat(ctx.getState().isSet("power_on")).isTrue();
}
}