From c0fa0e91b29bfb67eb6d8ad697a7eb48f5a444b4 Mon Sep 17 00:00:00 2001 From: hypercross Date: Fri, 17 Apr 2026 00:28:25 +0800 Subject: [PATCH] refactor: avoid using types from the csv --- .../slay-the-spire-like/combat/effects.ts | 7 ++-- .../slay-the-spire-like/combat/index.ts | 3 ++ .../slay-the-spire-like/combat/state.ts | 34 +++++++++---------- .../slay-the-spire-like/combat/triggers.ts | 1 - .../slay-the-spire-like/combat/types.ts | 34 +++++++++++++++---- 5 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/samples/slay-the-spire-like/combat/effects.ts b/src/samples/slay-the-spire-like/combat/effects.ts index 3b0b64e..5809fbd 100644 --- a/src/samples/slay-the-spire-like/combat/effects.ts +++ b/src/samples/slay-the-spire-like/combat/effects.ts @@ -1,5 +1,3 @@ -import type { EffectDesert } from "../data/effectDesert.csv"; -import type { CardDesert } from "../data/cardDesert.csv"; import { effectDesertData, cardDesertData } from "../data"; import { createStatusCard } from "../deck/factory"; import type { PlayerDeck, GameCard } from "../deck/types"; @@ -7,6 +5,7 @@ import type { BuffTable, CombatEffectEntry, CombatState, + EffectData, EffectTarget, EffectTiming, EnemyState, @@ -176,7 +175,7 @@ export type ResolveEffectContext = { export function resolveEffect( ctx: ResolveEffectContext, target: EffectTarget, - effect: EffectDesert, + effect: EffectData, stacks: number, sourceKey?: "player" | string, sourceCardId?: string, @@ -235,7 +234,7 @@ function applyBuffToTarget( function resolveInstantEffect( ctx: ResolveEffectContext, target: EffectTarget, - effect: EffectDesert, + effect: EffectData, stacks: number, sourceKey?: "player" | string, sourceCardId?: string, diff --git a/src/samples/slay-the-spire-like/combat/index.ts b/src/samples/slay-the-spire-like/combat/index.ts index cfdb10e..137db0a 100644 --- a/src/samples/slay-the-spire-like/combat/index.ts +++ b/src/samples/slay-the-spire-like/combat/index.ts @@ -6,8 +6,11 @@ export type { CombatPhase, CombatResult, CombatState, + EffectData, EffectTarget, EffectTiming, + EncounterData, + EnemyIntentData, EnemyState, ItemBuff, LootEntry, diff --git a/src/samples/slay-the-spire-like/combat/state.ts b/src/samples/slay-the-spire-like/combat/state.ts index 017603c..2051347 100644 --- a/src/samples/slay-the-spire-like/combat/state.ts +++ b/src/samples/slay-the-spire-like/combat/state.ts @@ -1,9 +1,6 @@ import type { GridInventory } from "../grid-inventory/types"; import type { GameItemMeta, PlayerState } from "../progress/types"; import type { PlayerDeck } from "../deck/types"; -import type { EnemyDesert } from "../data/enemyDesert.csv"; -import type { EffectDesert } from "../data/effectDesert.csv"; -import type { EncounterDesert } from "../data/encounterDesert.csv"; import { generateDeckFromInventory, createStatusCard } from "../deck/factory"; import { enemyDesertData, effectDesertData, cardDesertData } from "../data"; import { createRNG } from "@/utils/rng"; @@ -11,7 +8,11 @@ import type { BuffTable, CombatState, CombatPhase, + EffectData, + EffectTiming, + EnemyIntentData, EnemyState, + EncounterData, PlayerCombatState, ItemBuff, LootEntry, @@ -24,7 +25,7 @@ const FATIGUE_CARDS_PER_SHUFFLE = 2; export function createEnemyInstance( templateId: string, hp: number, - initBuffs: [EffectDesert, number][], + initBuffs: [EffectData, number][], idCounter: { value: number }, ): EnemyState { idCounter.value++; @@ -62,11 +63,11 @@ function findInitialIntent(enemyTemplateId: string): string | undefined { return undefined; } -function buildIntentLookup(enemyTemplateId: string): Record { - const lookup: Record = {}; +function buildIntentLookup(enemyTemplateId: string): Record { + const lookup: Record = {}; for (const row of enemyDesertData) { if (row.enemy === enemyTemplateId) { - lookup[row.intentId] = row; + lookup[row.intentId] = row as unknown as EnemyIntentData; } } return lookup; @@ -95,22 +96,21 @@ export function createPlayerCombatState( export function createCombatState( playerState: PlayerState, inventory: GridInventory, - encounter: EncounterDesert, + encounter: EncounterData, ): CombatState { const idCounter = { value: 0 }; const player = createPlayerCombatState(playerState, inventory); const enemies: Record = {}; const enemyOrder: string[] = []; - const enemyTemplateData: Record = {}; + const enemyTemplateData: Record = {}; for (const enemyEntry of encounter.enemies as unknown as [string, number, number][]) { const [enemyId, hp, bonusHp] = enemyEntry; - // Find initBuffs from enemyDesert (first row for this enemy type) const enemyRow = enemyDesertData.find((e) => e.enemy === enemyId); - const initBuffs: [EffectDesert, number][] = []; + const initBuffs: [EffectData, number][] = []; if (enemyRow) { - for (const [effect, stacks] of enemyRow.initBuffs) { + for (const [effect, stacks] of enemyRow.initBuffs as unknown as [EffectData, number][]) { initBuffs.push([effect, stacks]); } } @@ -124,7 +124,7 @@ export function createCombatState( ); enemies[enemyInstance.id] = enemyInstance; enemyOrder.push(enemyInstance.id); - enemyTemplateData[enemyInstance.templateId] = enemyRow!; + enemyTemplateData[enemyInstance.templateId] = enemyRow as unknown as EnemyIntentData; } shuffleDeck(player.deck.drawPile, createRNG(0)); @@ -211,7 +211,7 @@ export function exhaustCard(deck: PlayerDeck, cardId: string): void { } } -export function getEnemyCurrentIntent(enemy: EnemyState): EnemyDesert | undefined { +export function getEnemyCurrentIntent(enemy: EnemyState): EnemyIntentData | undefined { return enemy.intentData[enemy.currentIntentId]; } @@ -242,13 +242,13 @@ function shuffleDeck(drawPile: string[], rng: { nextInt: (n: number) => number } } } -export function getEffectTiming(effectId: string): EffectDesert["timing"] | undefined { +export function getEffectTiming(effectId: string): EffectTiming | undefined { const effect = effectDesertData.find(e => e.id === effectId); return effect?.timing; } -export function getEffectData(effectId: string): EffectDesert | undefined { - return effectDesertData.find(e => e.id === effectId); +export function getEffectData(effectId: string): EffectData | undefined { + return effectDesertData.find(e => e.id === effectId) as EffectData | undefined; } export { INITIAL_HAND_SIZE, DEFAULT_MAX_ENERGY, FATIGUE_CARDS_PER_SHUFFLE }; diff --git a/src/samples/slay-the-spire-like/combat/triggers.ts b/src/samples/slay-the-spire-like/combat/triggers.ts index c654c09..683c4a0 100644 --- a/src/samples/slay-the-spire-like/combat/triggers.ts +++ b/src/samples/slay-the-spire-like/combat/triggers.ts @@ -1,4 +1,3 @@ -import type { EffectDesert } from "../data/effectDesert.csv"; import { cardDesertData } from "../data"; import { createStatusCard } from "../deck/factory"; import type { BuffTable, CombatEffectEntry, CombatState } from "./types"; diff --git a/src/samples/slay-the-spire-like/combat/types.ts b/src/samples/slay-the-spire-like/combat/types.ts index 00d0ad4..d1fc064 100644 --- a/src/samples/slay-the-spire-like/combat/types.ts +++ b/src/samples/slay-the-spire-like/combat/types.ts @@ -1,15 +1,35 @@ -import type { EnemyDesert } from "../data/enemyDesert.csv"; -import type { EffectDesert } from "../data/effectDesert.csv"; import type { PlayerDeck, GameCard } from "../deck/types"; import type { PlayerState } from "../progress/types"; export type BuffTable = Record; -/** Lifecycle timing for effects - matches CSV timing column */ -export type EffectTiming = EffectDesert["timing"]; +export type EffectTiming = "instant" | "temporary" | "lingering" | "permanent" | "posture" | "card" | "cardDraw" | "cardHand" | "item" | "itemUntilPlayed"; + +export type EffectData = { + readonly id: string; + readonly timing: EffectTiming; +}; export type EffectTarget = "self" | "target" | "all" | "random" | "player" | "team"; +export type EnemyIntentData = { + readonly enemy: string; + readonly intentId: string; + readonly initialIntent: boolean; + readonly nextIntents: readonly string[]; + readonly brokenIntent: readonly string[]; + readonly initBuffs: readonly [EffectData, number]; + readonly effects: readonly ["self" | "player" | "team", EffectData, number]; +}; + +export type EncounterData = { + readonly type: "minion" | "elite" | "event" | "shop" | "camp" | "curio"; + readonly name: string; + readonly description: string; + readonly enemies: readonly [string, number, number]; + readonly dialogue: string; +}; + export type ItemBuff = { effectId: string; stacks: number; @@ -25,7 +45,7 @@ export type EnemyState = { maxHp: number; buffs: BuffTable; currentIntentId: string; - intentData: Record; + intentData: Record; isAlive: boolean; hadDefendBroken: boolean; }; @@ -62,10 +82,10 @@ export type CombatState = { turnNumber: number; result: CombatResult | null; loot: LootEntry[]; - enemyTemplateData: Record; + enemyTemplateData: Record; }; -export type CombatEffectEntry = [EffectTarget, EffectDesert, number]; +export type CombatEffectEntry = [EffectTarget, EffectData, number]; export type CombatEntity = { buffs: BuffTable;