fix: encounter generation
This commit is contained in:
parent
af0906561c
commit
a80852bc59
|
|
@ -1,11 +1,9 @@
|
||||||
import type { PointCrawlMap, MapNode } from '../map/types';
|
import type { PointCrawlMap } from '../map/types';
|
||||||
import type { CombatState, EnemyEntity, PlayerEntity, EffectTable } from '../combat/types';
|
import type { CombatState, EnemyEntity, PlayerEntity, EffectTable } from '../combat/types';
|
||||||
import type { EncounterData, EnemyData, EffectData, IntentData } from '../types';
|
import type { EncounterData, EnemyData, EffectData, IntentData } from '../types';
|
||||||
import type { RunState, GameItemMeta } from './types';
|
import type { RunState } from './types';
|
||||||
import type { GridInventory } from '../grid-inventory/types';
|
|
||||||
import { generateDeckFromInventory } from '../deck/factory';
|
import { generateDeckFromInventory } from '../deck/factory';
|
||||||
import { ReadonlyRNG } from '@/utils/rng';
|
import { ReadonlyRNG } from '@/utils/rng';
|
||||||
import { createRegion } from '@/core/region';
|
|
||||||
|
|
||||||
// -- Encounter assignment to nodes --
|
// -- Encounter assignment to nodes --
|
||||||
|
|
||||||
|
|
@ -77,10 +75,8 @@ export function assignAllEncounters(
|
||||||
export function buildCombatState(
|
export function buildCombatState(
|
||||||
encounter: EncounterData,
|
encounter: EncounterData,
|
||||||
runState: RunState,
|
runState: RunState,
|
||||||
intentPool: IntentData[] = []
|
|
||||||
): CombatState {
|
): CombatState {
|
||||||
const intentIndex = buildIntentIndex(intentPool);
|
const enemies = createEnemyEntities(encounter);
|
||||||
const enemies = createEnemyEntities(encounter, intentIndex);
|
|
||||||
const deck = generateDeckFromInventory(runState.inventory);
|
const deck = generateDeckFromInventory(runState.inventory);
|
||||||
const player = createPlayerEntity(runState, deck);
|
const player = createPlayerEntity(runState, deck);
|
||||||
|
|
||||||
|
|
@ -95,47 +91,33 @@ export function buildCombatState(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds an index of intents by their ID for fast lookup.
|
|
||||||
*/
|
|
||||||
function buildIntentIndex(intentPool: IntentData[]): Map<string, IntentData> {
|
|
||||||
const index = new Map<string, IntentData>();
|
|
||||||
for (const intent of intentPool) {
|
|
||||||
index.set(intent.id, intent);
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates EnemyEntity instances from encounter enemy definitions.
|
* Creates EnemyEntity instances from encounter enemy definitions.
|
||||||
* Each enemy gets: initial HP from enemy data, initial buffs from encounter, intents from enemy definition.
|
* Each enemy gets: HP from encounter tuple, initial buffs from encounter, intents from enemy definition.
|
||||||
*/
|
*/
|
||||||
export function createEnemyEntities(
|
export function createEnemyEntities(
|
||||||
encounter: EncounterData,
|
encounter: EncounterData,
|
||||||
intentIndex: Map<string, IntentData>
|
|
||||||
): EnemyEntity[] {
|
): EnemyEntity[] {
|
||||||
const enemies: EnemyEntity[] = [];
|
const enemies: EnemyEntity[] = [];
|
||||||
let instanceCounter = 0;
|
let instanceCounter = 0;
|
||||||
|
|
||||||
for (const [enemyData, count, encounterBuffs] of encounter.enemies) {
|
for (const [enemyData, hp, encounterBuffs] of encounter.enemies) {
|
||||||
for (let i = 0; i < count; i++) {
|
const instanceId = `${enemyData.id}-${instanceCounter++}`;
|
||||||
const instanceId = `${enemyData.id}-${instanceCounter++}`;
|
const intents = buildIntentMap(enemyData);
|
||||||
const intents = buildIntentMap(enemyData, intentIndex);
|
const initialIntent = findInitialIntent(enemyData);
|
||||||
const initialIntentId = findInitialIntent(enemyData, intentIndex);
|
const effects = buildEffectTable(encounterBuffs);
|
||||||
const effects = buildEffectTable(encounterBuffs);
|
|
||||||
|
|
||||||
const entity: EnemyEntity = {
|
const entity: EnemyEntity = {
|
||||||
id: instanceId,
|
id: instanceId,
|
||||||
enemy: enemyData,
|
enemy: enemyData,
|
||||||
hp: enemyData.hp,
|
hp,
|
||||||
maxHp: enemyData.hp,
|
maxHp: hp,
|
||||||
isAlive: true,
|
isAlive: true,
|
||||||
effects,
|
effects,
|
||||||
intents,
|
intents,
|
||||||
currentIntentId: initialIntentId,
|
currentIntent: initialIntent,
|
||||||
};
|
};
|
||||||
enemies.push(entity);
|
enemies.push(entity);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return enemies;
|
return enemies;
|
||||||
|
|
@ -146,14 +128,10 @@ export function createEnemyEntities(
|
||||||
*/
|
*/
|
||||||
function buildIntentMap(
|
function buildIntentMap(
|
||||||
enemy: EnemyData,
|
enemy: EnemyData,
|
||||||
intentIndex: Map<string, IntentData>
|
|
||||||
): Record<string, IntentData> {
|
): Record<string, IntentData> {
|
||||||
const intents: Record<string, IntentData> = {};
|
const intents: Record<string, IntentData> = {};
|
||||||
for (const intentId of enemy.intentIds) {
|
for (const intent of enemy.intents) {
|
||||||
const intent = intentIndex.get(intentId);
|
intents[intent.id] = intent;
|
||||||
if (intent) {
|
|
||||||
intents[intentId] = intent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return intents;
|
return intents;
|
||||||
}
|
}
|
||||||
|
|
@ -161,18 +139,16 @@ function buildIntentMap(
|
||||||
/**
|
/**
|
||||||
* Finds the initial intent ID for an enemy.
|
* Finds the initial intent ID for an enemy.
|
||||||
*/
|
*/
|
||||||
function findInitialIntent(
|
function findInitialIntent(enemy: EnemyData): IntentData {
|
||||||
enemy: EnemyData,
|
for (const intent of enemy.intents) {
|
||||||
intentIndex: Map<string, IntentData>
|
if (intent.initialIntent) {
|
||||||
): string {
|
return intent;
|
||||||
for (const intentId of enemy.intentIds) {
|
|
||||||
const intent = intentIndex.get(intentId);
|
|
||||||
if (intent?.initialIntent) {
|
|
||||||
return intentId;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Fallback: first intent
|
if (enemy.intents.length === 0) {
|
||||||
return enemy.intentIds[0] ?? '';
|
throw new Error(`Enemy "${enemy.id}" has no intents`);
|
||||||
|
}
|
||||||
|
return enemy.intents[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -191,6 +167,7 @@ function buildEffectTable(buffs: readonly [EffectData, number][]): EffectTable {
|
||||||
*/
|
*/
|
||||||
function createPlayerEntity(runState: RunState, deck: ReturnType<typeof generateDeckFromInventory>): PlayerEntity {
|
function createPlayerEntity(runState: RunState, deck: ReturnType<typeof generateDeckFromInventory>): PlayerEntity {
|
||||||
return {
|
return {
|
||||||
|
id: "player",
|
||||||
hp: runState.player.currentHp,
|
hp: runState.player.currentHp,
|
||||||
maxHp: runState.player.maxHp,
|
maxHp: runState.player.maxHp,
|
||||||
isAlive: runState.player.currentHp > 0,
|
isAlive: runState.player.currentHp > 0,
|
||||||
|
|
@ -224,13 +201,13 @@ export function isCombatEncounter(runState: RunState): boolean {
|
||||||
* Starts the encounter at the current node.
|
* Starts the encounter at the current node.
|
||||||
* Returns the constructed CombatState, or null if no combat encounter.
|
* Returns the constructed CombatState, or null if no combat encounter.
|
||||||
*/
|
*/
|
||||||
export function startEncounter(runState: RunState, intentPool: IntentData[] = []): CombatState | null {
|
export function startEncounter(runState: RunState): CombatState | null {
|
||||||
const encounter = getCurrentEncounterData(runState);
|
const encounter = getCurrentEncounterData(runState);
|
||||||
if (!encounter || encounter.enemies.length === 0) {
|
if (!encounter || encounter.enemies.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildCombatState(encounter, runState, intentPool);
|
return buildCombatState(encounter, runState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue