114 lines
2.8 KiB
TypeScript
114 lines
2.8 KiB
TypeScript
import {
|
|
CombatState,
|
|
EffectTable,
|
|
EnemyEntity,
|
|
PlayerEntity,
|
|
} from "../combat/types";
|
|
import { generateDeckFromInventory } from "../deck";
|
|
import { GridInventory } from "../grid-inventory";
|
|
import { GameItemMeta } from "../grid-inventory/types";
|
|
import { EffectData, EncounterData, EnemyData, IntentData } from "../types";
|
|
import { CombatEncounterState, RunState } from "./types";
|
|
|
|
export function buildCombatState(
|
|
runState: RunState,
|
|
inventory: GridInventory<GameItemMeta>,
|
|
encounter: CombatEncounterState,
|
|
): CombatState {
|
|
const deck = generateDeckFromInventory(inventory);
|
|
const player = createPlayerEntity(runState, deck);
|
|
const enemies = createEnemyEntities(encounter.data);
|
|
|
|
return {
|
|
enemies,
|
|
player,
|
|
phase: "playerTurn",
|
|
turnNumber: 1,
|
|
result: null,
|
|
loot: [],
|
|
};
|
|
}
|
|
|
|
export function buildCombatEncounterState(
|
|
data: EncounterData<"minion" | "elite">,
|
|
): CombatEncounterState {
|
|
return { data, blocked: false };
|
|
}
|
|
|
|
function createEnemyEntities(encounter: EncounterData): EnemyEntity[] {
|
|
const enemies: EnemyEntity[] = [];
|
|
let instanceCounter = 0;
|
|
|
|
for (const [enemyData, hp, encounterBuffs] of encounter.enemies) {
|
|
const instanceId = `${enemyData.id}-${instanceCounter++}`;
|
|
const intents = buildIntentMap(enemyData);
|
|
const initialIntent = findInitialIntent(enemyData);
|
|
const effects = buildEffectTable(encounterBuffs);
|
|
|
|
const entity: EnemyEntity = {
|
|
id: instanceId,
|
|
enemy: enemyData,
|
|
hp,
|
|
maxHp: hp,
|
|
isAlive: true,
|
|
effects,
|
|
intents,
|
|
currentIntent: initialIntent,
|
|
};
|
|
enemies.push(entity);
|
|
}
|
|
|
|
return enemies;
|
|
}
|
|
|
|
/**
|
|
* Builds a map of intent ID -> IntentData for an enemy.
|
|
*/
|
|
function buildIntentMap(enemy: EnemyData): Record<string, IntentData> {
|
|
const intents: Record<string, IntentData> = {};
|
|
for (const intent of enemy.intents) {
|
|
intents[intent.id] = intent;
|
|
}
|
|
return intents;
|
|
}
|
|
|
|
/**
|
|
* Finds the initial intent ID for an enemy.
|
|
*/
|
|
function findInitialIntent(enemy: EnemyData): IntentData {
|
|
for (const intent of enemy.intents) {
|
|
if (intent.initialIntent) {
|
|
return intent;
|
|
}
|
|
}
|
|
if (enemy.intents.length === 0) {
|
|
throw new Error(`Enemy "${enemy.id}" has no intents`);
|
|
}
|
|
return enemy.intents[0];
|
|
}
|
|
|
|
function buildEffectTable(buffs: readonly [EffectData, number][]): EffectTable {
|
|
const table: EffectTable = {};
|
|
for (const [effect, stacks] of buffs) {
|
|
table[effect.id] = { data: effect, stacks };
|
|
}
|
|
return table;
|
|
}
|
|
|
|
function createPlayerEntity(
|
|
runState: RunState,
|
|
deck: ReturnType<typeof generateDeckFromInventory>,
|
|
): PlayerEntity {
|
|
return {
|
|
id: "player",
|
|
hp: runState.currentHp,
|
|
maxHp: runState.maxHp,
|
|
isAlive: runState.currentHp > 0,
|
|
energy: 3,
|
|
maxEnergy: 3,
|
|
deck,
|
|
itemEffects: {},
|
|
effects: {},
|
|
};
|
|
}
|