import type { DungeonEncounter } from '../profile' import { chooseRandom } from './rules' export function encounterThreat(encounter: DungeonEncounter) { return ( encounter.maxHealth + encounter.damage * 18 + encounter.tankDamage * 10 + encounter.partyDamage * 18 ) } export function buildRoguelikeSegment({ pool, stage, mechanics, trashCandidateCount, bossCandidateCount, healthScale, damageScale, partyDamageScale, idBase, bossDescription, bossName, fallbackBossFirst = false, extraFields, }: { pool: DungeonEncounter[] stage: number mechanics: TMechanic[] trashCandidateCount: (trashCount: number) => number bossCandidateCount: (bossCount: number) => number healthScale: number damageScale: number partyDamageScale: number idBase: number bossDescription: (mechanics: TMechanic[]) => string bossName?: (encounter: DungeonEncounter) => string fallbackBossFirst?: boolean extraFields?: (encounter: DungeonEncounter, isBoss: boolean, mechanics: TMechanic[]) => TExtra }) { const trashPool = [...pool.filter((encounter) => !encounter.isBoss)] .sort((left, right) => encounterThreat(left) - encounterThreat(right)) const bossPool = [...pool.filter((encounter) => encounter.isBoss)] .sort((left, right) => encounterThreat(left) - encounterThreat(right)) const selectedTrash = chooseRandom(trashPool.slice(0, trashCandidateCount(trashPool.length)), 2) const selectedBoss = chooseRandom(bossPool.slice(0, bossCandidateCount(bossPool.length)), 1)[0] ?? (fallbackBossFirst ? bossPool[0] : trashPool[0]) ?? trashPool[0] ?? pool[0] const selectedMechanics = mechanics return [...selectedTrash, selectedBoss].map((encounter, index) => { const isBoss = index === 2 return { ...encounter, id: idBase + stage * 10 + index, sequence: (stage - 1) * 3 + index + 1, isBoss, encounterType: isBoss ? 'boss' : 'trash', enemyName: isBoss ? (bossName?.(encounter) ?? `${encounter.enemyName} ${stage}`) : encounter.enemyName, description: isBoss ? bossDescription(selectedMechanics) : encounter.description, maxHealth: Math.round(encounter.maxHealth * healthScale), damage: Math.round(encounter.damage * damageScale), tankDamage: Math.round(encounter.tankDamage * damageScale), partyDamage: Math.round(encounter.partyDamage * partyDamageScale), lootTables: [], ...(extraFields?.(encounter, isBoss, selectedMechanics) ?? {} as TExtra), } }) }