Credibility pass: one voice, no scars
A three-reviewer sweep for tells of piecemeal machine generation, every finding verified against the code before touching it. No behavior changes; the full suite passes unchanged (plus two strengthened pins). Engine: removed four void-silenced fossils (a parseEdgeKey call voided where it stood, stoneEffect's ignored cardId parameter, the actualTarget remnant in doCast, a voided loop variable in shadow upkeep); fixed the initialize-then-overwrite narration in spawnCreature; replaced a filter(() => false) no-op; waterwall now rides waveFromEdge instead of carrying its own verbatim copy (and the single-caller washBack wrapper went with it); blind wall-bumps and LOS blockers each collapsed to one implementation; the wand-id list and the "permanent" duration sentinel became named constants; the ambush number local no longer shadows the imported numberValue function; assorted reviewer-aimed phrasings rewritten as the constraints they guard. Server/deploy: the protocol header now documents all eleven message types; dropped an eslint pragma with no eslint, a test script with no tests, and an rsync exclude anchored at a path that never existed (the real data/ dir now excluded); the Caddy vhost has one source of truth; stale "pending DNS" note removed — the record resolves. Web: ~90 lines of CSS swallowed verbatim into a mobile media query deduplicated; the reduced-motion guard on the board now actually stops the marked-cell pulse; one shared color module replaces two drifted palettes; an orphaned doc comment rejoined its function. Tests: the ten-times-pasted helper block became test/helpers.ts; wave-numbered files renamed for the behaviors they pin; deliberation comments and void-ed corpses of unwritten assertions deleted; silent seed-dependent early-returns now fail loudly; one assertion that compared a value to itself now pins the home-translation it meant to; the stored-log single-number command form gained the explicit compatibility test it deserved. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
f62fcf2510
commit
695307daa8
@@ -1,50 +1,12 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
applyCommand,
|
||||
activePlayer,
|
||||
createGame,
|
||||
boardView,
|
||||
type Command,
|
||||
type GameState,
|
||||
type PlayerId,
|
||||
} from "../src/game";
|
||||
import { applyCommand, activePlayer, boardView } from "../src/game";
|
||||
import { cellKey, edgeKey, hasLineOfSight, neighbor, type Side } from "../src/board";
|
||||
import type { CardInstance } from "../src/cards";
|
||||
|
||||
function newGame(seed = 42) {
|
||||
return createGame({ playerIds: ["alice", "bob"], seed, sets: ["basic"] });
|
||||
}
|
||||
|
||||
function must(state: GameState, player: PlayerId, command: Command): GameState {
|
||||
const result = applyCommand(state, player, command);
|
||||
if (!result.ok) throw new Error(`command failed: ${result.error}`);
|
||||
return result.state;
|
||||
}
|
||||
import { newGame, must, giveCard, toRound2, faceOff } from "./helpers";
|
||||
|
||||
/** Test surgery: put a specific card into a player's hand (swapping one out). */
|
||||
function giveCard(state: GameState, playerId: PlayerId, cardId: string, tag = "T"): CardInstance {
|
||||
const p = state.players.find((p) => p.id === playerId)!;
|
||||
const instance = { instanceId: `${cardId}#${tag}`, cardId };
|
||||
p.hand[0] = instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Advance past round 1 (both players just end their turns). */
|
||||
function toRound2(state: GameState): GameState {
|
||||
state = must(state, activePlayer(state).id, { type: "endTurn", draw: 0 });
|
||||
state = must(state, activePlayer(state).id, { type: "endTurn", draw: 0 });
|
||||
expect(state.turn.round).toBe(2);
|
||||
return state;
|
||||
}
|
||||
|
||||
/** Put attacker and defender in mutual LOS (same square works for spells too). */
|
||||
function faceOff(state: GameState): { attacker: PlayerId; defender: PlayerId } {
|
||||
const attacker = activePlayer(state);
|
||||
const defender = state.players.find((p) => p.id !== attacker.id)!;
|
||||
defender.position = { ...attacker.position };
|
||||
return { attacker: attacker.id, defender: defender.id };
|
||||
}
|
||||
|
||||
describe("attack spells", () => {
|
||||
it("fireball does 5 flat damage when unopposed", () => {
|
||||
let { state } = newGame();
|
||||
@@ -174,9 +136,7 @@ describe("attack spells", () => {
|
||||
state = toRound2(state);
|
||||
const attacker = activePlayer(state);
|
||||
const defender = state.players.find((p) => p.id !== attacker.id)!;
|
||||
// Stand defender 1 east of attacker with open space behind (find a spot):
|
||||
// use same square then nudge — simplest robust arrangement: same square,
|
||||
// knockback direction defaults to none, so instead place east if open.
|
||||
// Same square: waterbolt needs a legal target; knockback is the engine's problem.
|
||||
defender.position = { ...attacker.position };
|
||||
const wb = giveCard(state, attacker.id, "waterbolt");
|
||||
const a = state.players.find((p) => p.id === attacker.id)!;
|
||||
@@ -338,3 +298,19 @@ describe("the post-game reveal", () => {
|
||||
expect(fallen.map((c) => c.cardId).sort()).toEqual(["fireball", "number-6"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("stored-log compatibility", () => {
|
||||
it("replays the single-number command form older logs contain", () => {
|
||||
let { state } = newGame();
|
||||
state = toRound2(state);
|
||||
const { attacker, defender } = faceOff(state);
|
||||
const fb = giveCard(state, attacker, "fireball");
|
||||
giveCard(state, attacker, "number-3", "N", 1);
|
||||
state = must(state, attacker, {
|
||||
type: "cast", instanceId: fb.instanceId, numberInstanceId: "number-3#N",
|
||||
target: { kind: "player", playerId: defender },
|
||||
});
|
||||
state = must(state, defender, { type: "pass" });
|
||||
expect(state.players.find((p) => p.id === defender)!.life).toBe(15 - 5); // fireball: 2 + the 3
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user