Add poison effect to enemies

This commit is contained in:
Jared Miller 2026-02-25 09:24:13 -05:00
parent 62a1ef051c
commit 02f9e1ec2c
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
3 changed files with 83 additions and 0 deletions

View file

@ -1,6 +1,7 @@
import { beforeAll, describe, expect, test } from "bun:test";
import { initCards } from "./cards.js";
import { checkCombatEnd, resolveEnemyTurn, startTurn } from "./combat.js";
import { resolveEffects } from "./effects.js";
import { initEnemies } from "./enemies.js";
import { createCombatState } from "./state.js";
@ -144,3 +145,80 @@ describe("checkCombatEnd - multiplayer", () => {
expect(checkCombatEnd(state)).toBe("defeat");
});
});
describe("poison effect", () => {
test("applying poison adds poison to target enemy", () => {
let state = createCombatState("ironclad", "jaw_worm");
state = {
...state,
enemies: [{ ...state.enemies[0], poison: 0 }],
enemy: { ...state.enemy, poison: 0 },
};
const next = resolveEffects(
state,
[{ type: "poison", value: 3 }],
{ type: "player", index: 0 },
{ type: "enemy", index: 0 },
);
expect(next.enemies[0].poison).toBe(3);
});
test("poison stacks additively up to 30", () => {
let state = createCombatState("ironclad", "jaw_worm");
state = {
...state,
enemies: [{ ...state.enemies[0], poison: 0 }],
enemy: { ...state.enemy, poison: 0 },
};
let next = resolveEffects(
state,
[{ type: "poison", value: 20 }],
{ type: "player", index: 0 },
{ type: "enemy", index: 0 },
);
next = resolveEffects(
next,
[{ type: "poison", value: 15 }],
{ type: "player", index: 0 },
{ type: "enemy", index: 0 },
);
expect(next.enemies[0].poison).toBe(30);
});
});
describe("poison tick", () => {
test("poison damages enemy and decrements at start of enemy turn", () => {
let state = createCombatState("ironclad", "jaw_worm");
const poisonedEnemy = { ...state.enemies[0], poison: 5, hp: 10 };
state = {
...state,
enemies: [poisonedEnemy],
enemy: poisonedEnemy,
combat: { ...state.combat, dieResult: 1 },
};
const next = resolveEnemyTurn(state);
expect(next.enemies[0].hp).toBe(5);
expect(next.enemies[0].poison).toBe(4);
});
test("enemy dies from poison", () => {
let state = createCombatState("ironclad", "jaw_worm");
const poisonedEnemy = { ...state.enemies[0], poison: 10, hp: 3 };
state = {
...state,
enemies: [poisonedEnemy],
enemy: poisonedEnemy,
combat: { ...state.combat, dieResult: 1 },
};
const next = resolveEnemyTurn(state);
expect(next.enemies[0].hp).toBe(0);
expect(next.enemies[0].poison).toBe(9);
});
test("zero poison does not tick", () => {
let state = createCombatState("ironclad", "jaw_worm");
state = { ...state, combat: { ...state.combat, dieResult: 1 } };
const next = resolveEnemyTurn(state);
expect(next.enemies[0].poison).toBe(0);
});
});

2
src/effects.js vendored
View file

@ -71,6 +71,8 @@ function resolveSingleEffect(state, effect, source, target) {
return applyStatus(state, target, "vulnerable", effect.value, 3);
case "weak":
return applyStatus(state, target, "weak", effect.value, 3);
case "poison":
return applyStatus(state, target, "poison", effect.value, 30);
case "strength":
return applyStatus(state, source, "strength", effect.value, 8);
case "draw": {

View file

@ -14,6 +14,7 @@ function makePlayer(character, index) {
strength: 0,
vulnerable: 0,
weak: 0,
poison: 0,
drawPile: shuffle([...getStarterDeck(character)]),
hand: [],
discardPile: [],
@ -34,6 +35,7 @@ function makeEnemy(enemyId, index) {
strength: 0,
vulnerable: 0,
weak: 0,
poison: 0,
actionType: enemy.actionType,
actions: enemy.actions,
actionTrack: enemy.actionTrack || null,
@ -88,6 +90,7 @@ export function createCombatFromRun(run, enemyIdOrIds) {
strength: 0,
vulnerable: 0,
weak: 0,
poison: 0,
drawPile: shuffle([...run.deck]),
hand: [],
discardPile: [],