refactor: avoid using types from the csv

This commit is contained in:
hypercross 2026-04-17 00:28:25 +08:00
parent e3014e47a8
commit c0fa0e91b2
5 changed files with 50 additions and 29 deletions

View File

@ -1,5 +1,3 @@
import type { EffectDesert } from "../data/effectDesert.csv";
import type { CardDesert } from "../data/cardDesert.csv";
import { effectDesertData, cardDesertData } from "../data"; import { effectDesertData, cardDesertData } from "../data";
import { createStatusCard } from "../deck/factory"; import { createStatusCard } from "../deck/factory";
import type { PlayerDeck, GameCard } from "../deck/types"; import type { PlayerDeck, GameCard } from "../deck/types";
@ -7,6 +5,7 @@ import type {
BuffTable, BuffTable,
CombatEffectEntry, CombatEffectEntry,
CombatState, CombatState,
EffectData,
EffectTarget, EffectTarget,
EffectTiming, EffectTiming,
EnemyState, EnemyState,
@ -176,7 +175,7 @@ export type ResolveEffectContext = {
export function resolveEffect( export function resolveEffect(
ctx: ResolveEffectContext, ctx: ResolveEffectContext,
target: EffectTarget, target: EffectTarget,
effect: EffectDesert, effect: EffectData,
stacks: number, stacks: number,
sourceKey?: "player" | string, sourceKey?: "player" | string,
sourceCardId?: string, sourceCardId?: string,
@ -235,7 +234,7 @@ function applyBuffToTarget(
function resolveInstantEffect( function resolveInstantEffect(
ctx: ResolveEffectContext, ctx: ResolveEffectContext,
target: EffectTarget, target: EffectTarget,
effect: EffectDesert, effect: EffectData,
stacks: number, stacks: number,
sourceKey?: "player" | string, sourceKey?: "player" | string,
sourceCardId?: string, sourceCardId?: string,

View File

@ -6,8 +6,11 @@ export type {
CombatPhase, CombatPhase,
CombatResult, CombatResult,
CombatState, CombatState,
EffectData,
EffectTarget, EffectTarget,
EffectTiming, EffectTiming,
EncounterData,
EnemyIntentData,
EnemyState, EnemyState,
ItemBuff, ItemBuff,
LootEntry, LootEntry,

View File

@ -1,9 +1,6 @@
import type { GridInventory } from "../grid-inventory/types"; import type { GridInventory } from "../grid-inventory/types";
import type { GameItemMeta, PlayerState } from "../progress/types"; import type { GameItemMeta, PlayerState } from "../progress/types";
import type { PlayerDeck } from "../deck/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 { generateDeckFromInventory, createStatusCard } from "../deck/factory";
import { enemyDesertData, effectDesertData, cardDesertData } from "../data"; import { enemyDesertData, effectDesertData, cardDesertData } from "../data";
import { createRNG } from "@/utils/rng"; import { createRNG } from "@/utils/rng";
@ -11,7 +8,11 @@ import type {
BuffTable, BuffTable,
CombatState, CombatState,
CombatPhase, CombatPhase,
EffectData,
EffectTiming,
EnemyIntentData,
EnemyState, EnemyState,
EncounterData,
PlayerCombatState, PlayerCombatState,
ItemBuff, ItemBuff,
LootEntry, LootEntry,
@ -24,7 +25,7 @@ const FATIGUE_CARDS_PER_SHUFFLE = 2;
export function createEnemyInstance( export function createEnemyInstance(
templateId: string, templateId: string,
hp: number, hp: number,
initBuffs: [EffectDesert, number][], initBuffs: [EffectData, number][],
idCounter: { value: number }, idCounter: { value: number },
): EnemyState { ): EnemyState {
idCounter.value++; idCounter.value++;
@ -62,11 +63,11 @@ function findInitialIntent(enemyTemplateId: string): string | undefined {
return undefined; return undefined;
} }
function buildIntentLookup(enemyTemplateId: string): Record<string, EnemyDesert> { function buildIntentLookup(enemyTemplateId: string): Record<string, EnemyIntentData> {
const lookup: Record<string, EnemyDesert> = {}; const lookup: Record<string, EnemyIntentData> = {};
for (const row of enemyDesertData) { for (const row of enemyDesertData) {
if (row.enemy === enemyTemplateId) { if (row.enemy === enemyTemplateId) {
lookup[row.intentId] = row; lookup[row.intentId] = row as unknown as EnemyIntentData;
} }
} }
return lookup; return lookup;
@ -95,22 +96,21 @@ export function createPlayerCombatState(
export function createCombatState( export function createCombatState(
playerState: PlayerState, playerState: PlayerState,
inventory: GridInventory<GameItemMeta>, inventory: GridInventory<GameItemMeta>,
encounter: EncounterDesert, encounter: EncounterData,
): CombatState { ): CombatState {
const idCounter = { value: 0 }; const idCounter = { value: 0 };
const player = createPlayerCombatState(playerState, inventory); const player = createPlayerCombatState(playerState, inventory);
const enemies: Record<string, EnemyState> = {}; const enemies: Record<string, EnemyState> = {};
const enemyOrder: string[] = []; const enemyOrder: string[] = [];
const enemyTemplateData: Record<string, EnemyDesert> = {}; const enemyTemplateData: Record<string, EnemyIntentData> = {};
for (const enemyEntry of encounter.enemies as unknown as [string, number, number][]) { for (const enemyEntry of encounter.enemies as unknown as [string, number, number][]) {
const [enemyId, hp, bonusHp] = enemyEntry; const [enemyId, hp, bonusHp] = enemyEntry;
// Find initBuffs from enemyDesert (first row for this enemy type)
const enemyRow = enemyDesertData.find((e) => e.enemy === enemyId); const enemyRow = enemyDesertData.find((e) => e.enemy === enemyId);
const initBuffs: [EffectDesert, number][] = []; const initBuffs: [EffectData, number][] = [];
if (enemyRow) { 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]); initBuffs.push([effect, stacks]);
} }
} }
@ -124,7 +124,7 @@ export function createCombatState(
); );
enemies[enemyInstance.id] = enemyInstance; enemies[enemyInstance.id] = enemyInstance;
enemyOrder.push(enemyInstance.id); enemyOrder.push(enemyInstance.id);
enemyTemplateData[enemyInstance.templateId] = enemyRow!; enemyTemplateData[enemyInstance.templateId] = enemyRow as unknown as EnemyIntentData;
} }
shuffleDeck(player.deck.drawPile, createRNG(0)); 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]; 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); const effect = effectDesertData.find(e => e.id === effectId);
return effect?.timing; return effect?.timing;
} }
export function getEffectData(effectId: string): EffectDesert | undefined { export function getEffectData(effectId: string): EffectData | undefined {
return effectDesertData.find(e => e.id === effectId); return effectDesertData.find(e => e.id === effectId) as EffectData | undefined;
} }
export { INITIAL_HAND_SIZE, DEFAULT_MAX_ENERGY, FATIGUE_CARDS_PER_SHUFFLE }; export { INITIAL_HAND_SIZE, DEFAULT_MAX_ENERGY, FATIGUE_CARDS_PER_SHUFFLE };

View File

@ -1,4 +1,3 @@
import type { EffectDesert } from "../data/effectDesert.csv";
import { cardDesertData } from "../data"; import { cardDesertData } from "../data";
import { createStatusCard } from "../deck/factory"; import { createStatusCard } from "../deck/factory";
import type { BuffTable, CombatEffectEntry, CombatState } from "./types"; import type { BuffTable, CombatEffectEntry, CombatState } from "./types";

View File

@ -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 { PlayerDeck, GameCard } from "../deck/types";
import type { PlayerState } from "../progress/types"; import type { PlayerState } from "../progress/types";
export type BuffTable = Record<string, number>; export type BuffTable = Record<string, number>;
/** Lifecycle timing for effects - matches CSV timing column */ export type EffectTiming = "instant" | "temporary" | "lingering" | "permanent" | "posture" | "card" | "cardDraw" | "cardHand" | "item" | "itemUntilPlayed";
export type EffectTiming = EffectDesert["timing"];
export type EffectData = {
readonly id: string;
readonly timing: EffectTiming;
};
export type EffectTarget = "self" | "target" | "all" | "random" | "player" | "team"; 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 = { export type ItemBuff = {
effectId: string; effectId: string;
stacks: number; stacks: number;
@ -25,7 +45,7 @@ export type EnemyState = {
maxHp: number; maxHp: number;
buffs: BuffTable; buffs: BuffTable;
currentIntentId: string; currentIntentId: string;
intentData: Record<string, EnemyDesert>; intentData: Record<string, EnemyIntentData>;
isAlive: boolean; isAlive: boolean;
hadDefendBroken: boolean; hadDefendBroken: boolean;
}; };
@ -62,10 +82,10 @@ export type CombatState = {
turnNumber: number; turnNumber: number;
result: CombatResult | null; result: CombatResult | null;
loot: LootEntry[]; loot: LootEntry[];
enemyTemplateData: Record<string, EnemyDesert>; enemyTemplateData: Record<string, EnemyIntentData>;
}; };
export type CombatEffectEntry = [EffectTarget, EffectDesert, number]; export type CombatEffectEntry = [EffectTarget, EffectData, number];
export type CombatEntity = { export type CombatEntity = {
buffs: BuffTable; buffs: BuffTable;