feat(sts-viewer): implement combat state and fix inventory removal

- Add `createCombatState` to initialize combat using inventory and run
  state
- Implement `runContext` to bridge inventory data with combat logic
- Update inventory to use `removeItem` instead of `removeItemFromGrid`
This commit is contained in:
hypercross 2026-04-21 23:28:47 +08:00
parent 82c026628a
commit 9637312b7c
2 changed files with 65 additions and 3 deletions

View File

@ -0,0 +1,62 @@
import {
buildCombatState,
CombatState,
createRunState,
createStartWith,
data,
generateDeckFromInventory,
getAdjacentItems,
getItemEffects,
IRunContext,
} from "boardgame-core/samples/slay-the-spire-like";
import { createInventorySignal } from "./inventory";
import { GameModule } from "boardgame-core";
export function createCombatState() {
const inventory = createInventorySignal(true);
const deck = generateDeckFromInventory(inventory.value);
const run = createRunState();
const encounter = data.desert.getEncounters()[0];
const effects = getItemEffects(inventory.value);
const combat = buildCombatState(
{
hp: run.currentHp,
maxHp: run.maxHp,
itemEffects: effects,
},
deck,
encounter,
);
const runContext: IRunContext = {
getItemData(id: string) {
return inventory.value.items.get(id)?.meta?.itemData || null;
},
getAdjacentItems(id: string) {
return getAdjacentItems(inventory.value, id).keys();
},
getConsumedUses(id: string) {
return inventory.value.items.get(id)?.meta?.consumedUses || 0;
},
async setConsumedUsesAsync(id: string, uses: number) {
await inventory.produceAsync((draft) => {
const item = draft.items.get(id);
if (!item?.meta) return;
item.meta.consumedUses = uses;
});
},
};
const start = createStartWith((triggers, ctx) => {
data.desert.addTriggers(triggers, runContext);
}, runContext);
return {
start,
createInitialState: () => combat,
} as GameModule<CombatState>;
}

View File

@ -6,7 +6,7 @@ import {
data, data,
GameItemMeta, GameItemMeta,
placeItem, placeItem,
removeItemFromGrid, removeItem,
Transform2D, Transform2D,
validatePlacement, validatePlacement,
} from "boardgame-core/samples/slay-the-spire-like"; } from "boardgame-core/samples/slay-the-spire-like";
@ -58,14 +58,14 @@ export function moveItem(
}; };
const removed = create(to.value, (inv) => { const removed = create(to.value, (inv) => {
removeItemFromGrid(inv, itemId); removeItem(inv, itemId);
}); });
const validation = validatePlacement(removed, item.shape, newTransform); const validation = validatePlacement(removed, item.shape, newTransform);
if (!validation.valid) return false; if (!validation.valid) return false;
batch(() => { batch(() => {
from.produce((inv) => { from.produce((inv) => {
removeItemFromGrid(inv, itemId); removeItem(inv, itemId);
}); });
to.produce((inv) => { to.produce((inv) => {
placeItem(inv, { placeItem(inv, {