import type { PartyMember } from '../game' import type { PvpMatchSnapshot, PvpMatchSide } from '../pvpRoguelike' export type PvpRoguelikeSetupSide = { party: PartyMember[] resource: number cooldowns: Record enemyHealth: number buffs: TBuff[] debuffs: TDebuff[] castsTowardFree: number freeCastReady: boolean } export type PvpRoguelikeLiveMatchSetup = { id: string side: PvpMatchSide opponentSide: PvpMatchSide opponentName: string opponentClassName: string } export function createPvpRoguelikeStarterSide( partyTemplate: readonly PartyMember[], maxResource: number, ): PvpRoguelikeSetupSide { return { party: partyTemplate.map((member) => ({ ...member })), resource: maxResource, cooldowns: {}, enemyHealth: 0, buffs: [], debuffs: [], castsTowardFree: 0, freeCastReady: false, } } export function createPvpRoguelikeMatchStart< TBuff extends string, TDebuff extends string, TEncounter extends { maxHealth: number }, >({ startStage, encounterPool, buildSegment, partyTemplate, opponentPartyTemplate, maxResource, upgradeChoiceSeconds, }: { startStage: number encounterPool: readonly TEncounter[] buildSegment: (pool: readonly TEncounter[], stage: number) => TEncounter[] partyTemplate: readonly PartyMember[] opponentPartyTemplate: readonly PartyMember[] maxResource: number upgradeChoiceSeconds: number }) { const firstSegment = buildSegment(encounterPool, startStage) const firstEncounter = firstSegment[0] const playerSide = createPvpRoguelikeStarterSide(partyTemplate, maxResource) const opponentSide = createPvpRoguelikeStarterSide(opponentPartyTemplate, maxResource) playerSide.enemyHealth = firstEncounter.maxHealth opponentSide.enemyHealth = firstEncounter.maxHealth return { startStage, firstSegment, firstEncounter, playerSide, opponentSide, defaults: { encounterIndex: 0, elapsedTicks: 0, encountersCleared: 0, paused: false, targetGroup: 0 as const, upgradeTimeLeft: upgradeChoiceSeconds, liveUpgradePending: false, rewardError: '', showEndLog: false, }, } } export function createPvpRoguelikeLiveMatchStart< TBuff extends string, TDebuff extends string, TEncounter extends { maxHealth: number }, >({ match, side, encounterPool, buildSegment, partyTemplate, opponentPartyTemplate, maxResource, upgradeChoiceSeconds, message, }: { match: PvpMatchSnapshot> side: PvpMatchSide encounterPool: readonly TEncounter[] buildSegment: (pool: readonly TEncounter[], stage: number) => TEncounter[] partyTemplate: readonly PartyMember[] opponentPartyTemplate: readonly PartyMember[] maxResource: number upgradeChoiceSeconds: number message?: string }) { const opponentSideId: PvpMatchSide = side === 'a' ? 'b' : 'a' const opponent = match.players[opponentSideId] const opponentTemplate = opponentPartyTemplate.map((member) => ({ ...member, name: member.id === 'mira' ? opponent.characterName : member.name, })) const setup = createPvpRoguelikeMatchStart({ startStage: match.startStage, encounterPool, buildSegment, partyTemplate, opponentPartyTemplate: opponentTemplate, maxResource, upgradeChoiceSeconds, }) const liveMatch: PvpRoguelikeLiveMatchSetup = { id: match.id, side, opponentSide: opponentSideId, opponentName: opponent.characterName, opponentClassName: opponent.className, } return { ...setup, liveMatch, logText: message ?? `${opponent.characterName} found. Stage ${match.startStage} begins.`, } }