Files
i-want-to-heal/src/pvpRoguelike.ts
T
Warren H 3a8d5ad8c5 changes
2026-06-18 22:28:04 -04:00

69 lines
2.3 KiB
TypeScript

export type PvpContentType = 'dungeon' | 'raid'
export type CpuDifficulty = 1 | 2 | 3 | 4 | 5
export type CpuPvpLeaderboardEntry = {
characterName: string
className: string
contentType: PvpContentType
encountersCleared: number
cpuDifficulty: CpuDifficulty
result: 'victory' | 'defeat'
completedAt: string
}
const cpuLeaderboardKey = 'chronicle.pvpCpuLeaderboard.v1'
const checkpointKey = 'chronicle.pvpRoguelikeCheckpoint.v1'
export function randomCpuDifficulty(): CpuDifficulty {
return (Math.floor(Math.random() * 5) + 1) as CpuDifficulty
}
export function loadCpuPvpLeaderboard(contentType?: PvpContentType): CpuPvpLeaderboardEntry[] {
try {
const raw = JSON.parse(localStorage.getItem(cpuLeaderboardKey) ?? '[]') as CpuPvpLeaderboardEntry[]
return raw
.filter((entry) => !contentType || entry.contentType === contentType)
.sort((left, right) =>
right.encountersCleared - left.encountersCleared
|| right.cpuDifficulty - left.cpuDifficulty
|| right.completedAt.localeCompare(left.completedAt),
)
.slice(0, 12)
} catch {
return []
}
}
export function recordCpuPvpLeaderboard(entry: CpuPvpLeaderboardEntry) {
const current = loadCpuPvpLeaderboard()
const next = [...current, entry]
.sort((left, right) =>
right.encountersCleared - left.encountersCleared
|| right.cpuDifficulty - left.cpuDifficulty
|| right.completedAt.localeCompare(left.completedAt),
)
.slice(0, 30)
localStorage.setItem(cpuLeaderboardKey, JSON.stringify(next))
}
function checkpointStorageKey(characterId: number, contentType: PvpContentType) {
return `${checkpointKey}:${characterId}:${contentType}`
}
export function loadPvpRoguelikeCheckpoint(characterId: number, contentType: PvpContentType) {
const value = Number(localStorage.getItem(checkpointStorageKey(characterId, contentType)) ?? 1)
return Number.isInteger(value) && value >= 5 ? value : 1
}
export function recordPvpRoguelikeCheckpoint(
characterId: number,
contentType: PvpContentType,
stage: number,
) {
if (stage < 5 || stage % 5 !== 0) return loadPvpRoguelikeCheckpoint(characterId, contentType)
const current = loadPvpRoguelikeCheckpoint(characterId, contentType)
const next = Math.max(current, stage)
localStorage.setItem(checkpointStorageKey(characterId, contentType), String(next))
return next
}