refactor(slay-the-spire-like): use IRunContext for combat logic

Decouple combat systems from the inventory and progress state by
introducing `IRunContext`. This replaces direct access to
`GridInventory` and `GameItemMeta` with abstract methods for
retrieving item data, neighbors, and managing consumed uses.
This commit is contained in:
2026-04-20 11:03:44 +08:00
parent 9bed2ca13e
commit 5019bc6324
6 changed files with 95 additions and 80 deletions
@@ -3,6 +3,7 @@ import {
CombatGameContext,
CombatState,
EffectTable,
IRunContext,
PlayerEntity,
} from "./types";
import {
@@ -12,8 +13,6 @@ import {
EffectData,
EffectTarget,
} from "@/samples/slay-the-spire-like/system/types";
import { GameItemMeta } from "@/samples/slay-the-spire-like/system/progress/types";
import { GridInventory } from "@/samples/slay-the-spire-like/system/grid-inventory/types";
export function addEffect(
effects: EffectTable,
@@ -138,33 +137,32 @@ export function canPlayCard(
costType: CardData["costType"],
costCount: number,
itemId: string,
inventory: GridInventory<GameItemMeta>,
run: IRunContext,
): boolean {
if (costType === "energy") {
return player.energy >= costCount;
}
if (costType === "uses") {
const item = inventory.items.get(itemId);
if (!item || !item.meta) return false;
const depletion = item.meta.consumedUses ?? 0;
return depletion < costCount;
const item = run.getItemData(itemId);
if (!item) return false;
const maxUses = item?.card.costType === "energy" ? item.card.costCount : 0;
const consumed = run.getConsumedUses(itemId);
return consumed + costCount <= maxUses;
}
return true;
}
export function payCardCost(
export async function payCardCost(
player: PlayerEntity,
costType: CardData["costType"],
costCount: number,
itemId: string,
inventory: GridInventory<GameItemMeta>,
): void {
run: IRunContext,
): Promise<void> {
if (costType === "energy") {
player.energy -= costCount;
} else if (costType === "uses") {
const item = inventory.items.get(itemId);
if (item && item.meta) {
item.meta.consumedUses = (item.meta.consumedUses ?? 0) + costCount;
}
const consumed = run.getConsumedUses(itemId);
await run.setConsumedUsesAsync(itemId, consumed + costCount);
}
}