feat(engine): range-bonus modifier descriptor
Add RANGE_BONUS_DESCRIPTOR that seeds RangeBonus fact on piece entities, and update getSlidingMoves to respect it via a per-ray maxSteps cap. Clamped to [0,7] in apply(); standard boards are unaffected (RangeBonus=0 → maxSteps=7, identical to prior behaviour). Foundation for range-limit presets.
This commit is contained in:
parent
e58bb02605
commit
761adfb699
2 changed files with 92 additions and 0 deletions
67
packages/chess/src/modifiers/descriptors/range-bonus.test.ts
Normal file
67
packages/chess/src/modifiers/descriptors/range-bonus.test.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
import { Session, type EntityId } from "@paratype/rete";
|
||||
import { RANGE_BONUS_DESCRIPTOR } from "./range-bonus.js";
|
||||
import { MODIFIER_REGISTRY } from "../registry.js";
|
||||
|
||||
function setupSession(): Session {
|
||||
return new Session({ autoFire: false });
|
||||
}
|
||||
|
||||
describe("RANGE_BONUS_DESCRIPTOR", () => {
|
||||
it("registers in MODIFIER_REGISTRY with id 'range-bonus'", () => {
|
||||
expect(MODIFIER_REGISTRY.has("range-bonus")).toBe(true);
|
||||
expect(MODIFIER_REGISTRY.get("range-bonus")).toBe(RANGE_BONUS_DESCRIPTOR);
|
||||
});
|
||||
|
||||
it("has correct metadata", () => {
|
||||
expect(RANGE_BONUS_DESCRIPTOR.id).toBe("range-bonus");
|
||||
expect(RANGE_BONUS_DESCRIPTOR.attrName).toBe("RangeBonus");
|
||||
expect(RANGE_BONUS_DESCRIPTOR.stackingRule).toBe("additive");
|
||||
expect(RANGE_BONUS_DESCRIPTOR.uiForm).toBe("number");
|
||||
});
|
||||
|
||||
describe("describe()", () => {
|
||||
it("returns 'Range +N' for non-negative values", () => {
|
||||
expect(RANGE_BONUS_DESCRIPTOR.describe(2)).toBe("Range +2");
|
||||
expect(RANGE_BONUS_DESCRIPTOR.describe(0)).toBe("Range +0");
|
||||
expect(RANGE_BONUS_DESCRIPTOR.describe(7)).toBe("Range +7");
|
||||
});
|
||||
|
||||
it("returns 'Range -N' for negative values", () => {
|
||||
expect(RANGE_BONUS_DESCRIPTOR.describe(-1)).toBe("Range -1");
|
||||
expect(RANGE_BONUS_DESCRIPTOR.describe(-7)).toBe("Range -7");
|
||||
});
|
||||
});
|
||||
|
||||
describe("apply()", () => {
|
||||
it("inserts RangeBonus fact on the piece entity", () => {
|
||||
const session = setupSession();
|
||||
RANGE_BONUS_DESCRIPTOR.apply(session, 1 as EntityId, 3);
|
||||
expect(session.get(1 as EntityId, "RangeBonus")).toBe(3);
|
||||
});
|
||||
|
||||
it("clamps effectiveValue above RANGE_MAX (7) down to 7", () => {
|
||||
const session = setupSession();
|
||||
RANGE_BONUS_DESCRIPTOR.apply(session, 1 as EntityId, 10 as number);
|
||||
expect(session.get(1 as EntityId, "RangeBonus")).toBe(7);
|
||||
});
|
||||
|
||||
it("clamps negative effectiveValue to 0", () => {
|
||||
const session = setupSession();
|
||||
RANGE_BONUS_DESCRIPTOR.apply(session, 1 as EntityId, -5 as number);
|
||||
expect(session.get(1 as EntityId, "RangeBonus")).toBe(0);
|
||||
});
|
||||
|
||||
it("applies exactly RANGE_MAX (7) without clamping", () => {
|
||||
const session = setupSession();
|
||||
RANGE_BONUS_DESCRIPTOR.apply(session, 2 as EntityId, 7);
|
||||
expect(session.get(2 as EntityId, "RangeBonus")).toBe(7);
|
||||
});
|
||||
|
||||
it("applies zero without clamping", () => {
|
||||
const session = setupSession();
|
||||
RANGE_BONUS_DESCRIPTOR.apply(session, 3 as EntityId, 0);
|
||||
expect(session.get(3 as EntityId, "RangeBonus")).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
25
packages/chess/src/modifiers/descriptors/range-bonus.ts
Normal file
25
packages/chess/src/modifiers/descriptors/range-bonus.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { z } from "zod";
|
||||
import { MODIFIER_REGISTRY } from "../registry.js";
|
||||
import type { ModifierDescriptor } from "../types.js";
|
||||
|
||||
const RANGE_MAX = 7;
|
||||
const schema = z.number().int().min(-7).max(7);
|
||||
type Value = z.infer<typeof schema>;
|
||||
|
||||
export const RANGE_BONUS_DESCRIPTOR: ModifierDescriptor<Value> = {
|
||||
id: "range-bonus",
|
||||
attrName: "RangeBonus",
|
||||
label: "Range Bonus",
|
||||
valueSchema: schema,
|
||||
stackingRule: "additive",
|
||||
uiForm: "number",
|
||||
apply(session, pieceId, effectiveValue) {
|
||||
const clamped = Math.max(0, Math.min(RANGE_MAX, effectiveValue));
|
||||
session.insert(pieceId, "RangeBonus", clamped);
|
||||
},
|
||||
describe(value) {
|
||||
return `Range ${value >= 0 ? "+" : ""}${value}`;
|
||||
},
|
||||
};
|
||||
|
||||
MODIFIER_REGISTRY.register(RANGE_BONUS_DESCRIPTOR);
|
||||
Loading…
Add table
Add a link
Reference in a new issue