Adde speed uhc mastery stats

This commit is contained in:
2025-09-17 20:22:40 +02:00
parent 9c3e0edd90
commit 0eb410dff7
4 changed files with 161 additions and 37 deletions

View File

@@ -6,7 +6,7 @@ import { NonNullStats } from "@/lib/schema/player"
import GeneralStats from "../GeneralStats" import GeneralStats from "../GeneralStats"
import SpeedUHCProgress from "./progress" import SpeedUHCProgress from "./progress"
import SpeedUHCGeneralStats from "./stats" import SpeedUHCGeneralStats from "./stats"
import { SpeedUHCModeStatsTable } from "./table" import { SpeedUHCMasteryStatsTable, SpeedUHCModeStatsTable } from "./table"
export default function SpeedUHCStats({ stats, uhcCoins }: { stats: NonNullStats["SpeedUHC"], uhcCoins: number | undefined }) { export default function SpeedUHCStats({ stats, uhcCoins }: { stats: NonNullStats["SpeedUHC"], uhcCoins: number | undefined }) {
if (!stats) return null if (!stats) return null
@@ -45,6 +45,8 @@ export default function SpeedUHCStats({ stats, uhcCoins }: { stats: NonNullStats
<Separator className="my-4" /> <Separator className="my-4" />
<SpeedUHCModeStatsTable stats={stats} /> <SpeedUHCModeStatsTable stats={stats} />
<Separator className="my-4" /> <Separator className="my-4" />
<SpeedUHCMasteryStatsTable stats={stats} />
<Separator className="my-4" />
</GeneralStats> </GeneralStats>
) )
} }

View File

@@ -1,9 +1,74 @@
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { formatNumber } from "@/lib/formatters" import { formatNumber } from "@/lib/formatters"
import { getSpeedUHCBestMode, getSpeedUHCModeName, getSpeedUHCModeStats } from "@/lib/hypixel/speeduhc/general" import {
getSpeedUHCBestMastery,
getSpeedUHCBestMode,
getSpeedUHCMasteryName,
getSpeedUHCMasteryStats,
getSpeedUHCModeName,
getSpeedUHCModeStats
} from "@/lib/hypixel/speeduhc/general"
import { NonNullStats } from "@/lib/schema/player" import { NonNullStats } from "@/lib/schema/player"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
export function SpeedUHCMasteryStatsTable({ stats }: { stats: NonNullable<NonNullStats["SpeedUHC"]> }) {
return (
<Table>
<SpeedUHCMasteryStatsTableHeader />
<TableBody>
<SpeedUHCMasteryStatRow id="mastery_wild_specialist" stats={stats} />
<SpeedUHCMasteryStatRow id="mastery_sniper" stats={stats} />
<SpeedUHCMasteryStatRow id="mastery_berserk" stats={stats} />
<SpeedUHCMasteryStatRow id="mastery_fortune" stats={stats} />
<SpeedUHCMasteryStatRow id="mastery_invigorate" stats={stats} />
<SpeedUHCMasteryStatRow id="mastery_huntsman" stats={stats} />
<SpeedUHCMasteryStatRow id="mastery_vampirism" stats={stats} />
<SpeedUHCMasteryStatRow id="mastery_guardian" stats={stats} />
<SpeedUHCMasteryStatRow id="all" stats={stats} />
</TableBody>
</Table>
)
}
function SpeedUHCMasteryStatRow(
{ id, stats }: { id: Parameters<typeof getSpeedUHCMasteryStats>[0], stats: NonNullable<NonNullStats["SpeedUHC"]> }
) {
const modeStats = getSpeedUHCMasteryStats(id, stats)
const modeName = getSpeedUHCMasteryName(id)
const isBest = getSpeedUHCBestMastery(stats) === id
return (
<TableRow className={cn(isBest && "text-mc-light-purple")}>
<TableCell>{modeName}</TableCell>
{modeStats.map((v, i) => {
return <TableCell key={i}>{formatNumber(v)}</TableCell>
})}
</TableRow>
)
}
function SpeedUHCMasteryStatsTableHeader() {
const headerElements = [
"Mastery",
"Kills",
"Deaths",
"KD",
"Wins",
"Losses",
"WL"
]
return (
<TableHeader>
<TableRow>
{headerElements.map((v, i) => {
return <TableHead key={i} className="font-bold">{v}</TableHead>
})}
</TableRow>
</TableHeader>
)
}
export function SpeedUHCModeStatsTable({ stats }: { stats: NonNullable<NonNullStats["SpeedUHC"]> }) { export function SpeedUHCModeStatsTable({ stats }: { stats: NonNullable<NonNullStats["SpeedUHC"]> }) {
return ( return (
<Table> <Table>

View File

@@ -1,7 +1,57 @@
import { MODES, TITLES } from "@/data/hypixel/speeduhc" import { MASTERIES, MODES, TITLES } from "@/data/hypixel/speeduhc"
import { NonNullStats } from "@/lib/schema/player" import { NonNullStats } from "@/lib/schema/player"
import { devide } from "../general" import { devide } from "../general"
export function getSpeedUHCMasteryName(modeId: Exclude<typeof MASTERIES[number]["id"], ""> | "all") {
if (modeId === "all") {
return MASTERIES.find(m => m.id === "")!.name
}
return MASTERIES.find(m => m.id === modeId)!.name
}
export function getSpeedUHCBestMastery(stats: NonNullable<NonNullStats["SpeedUHC"]>) {
let bestMastery: typeof MASTERIES[number]["id"] | null = null
let maxGames = 0
for (const mode of MASTERIES) {
if (mode.id === "") continue
const wins = stats[`wins_${mode.id}`]
const losses = stats[`losses_${mode.id}`]
const totalGames = wins + losses
if (totalGames > maxGames) {
maxGames = totalGames
bestMastery = mode.id
}
}
return bestMastery
}
export function getSpeedUHCMasteryStats(id: Exclude<typeof MASTERIES[number]["id"], ""> | "all", stats: NonNullable<NonNullStats["SpeedUHC"]>) {
if (id === "all") {
return [
stats.kills,
stats.deaths,
devide(stats.kills, stats.deaths),
stats.wins,
stats.losses,
devide(stats.wins, stats.losses)
]
}
return [
stats[`kills_${id}`],
stats[`deaths_${id}`],
devide(stats[`kills_${id}`], stats[`deaths_${id}`]),
stats[`wins_${id}`],
stats[`losses_${id}`],
devide(stats[`wins_${id}`], stats[`losses_${id}`])
]
}
export function getSpeedUHCModeName(modeId: Exclude<typeof MODES[number]["id"], ""> | "all_modes") { export function getSpeedUHCModeName(modeId: Exclude<typeof MODES[number]["id"], ""> | "all_modes") {
if (modeId === "all_modes") { if (modeId === "all_modes") {
return MODES.find(m => m.id === "")!.name return MODES.find(m => m.id === "")!.name
@@ -32,25 +82,13 @@ export function getSpeedUHCBestMode(stats: NonNullable<NonNullStats["SpeedUHC"]>
export function getSpeedUHCModeStats(modeId: Exclude<typeof MODES[number]["id"], ""> | "all_modes", stats: NonNullable<NonNullStats["SpeedUHC"]>) { export function getSpeedUHCModeStats(modeId: Exclude<typeof MODES[number]["id"], ""> | "all_modes", stats: NonNullable<NonNullStats["SpeedUHC"]>) {
if (modeId === "all_modes") { if (modeId === "all_modes") {
const bestMode = getSpeedUHCBestMode(stats)
if (!bestMode) {
return [
stats.kills,
stats.deaths,
devide(stats.kills, stats.deaths),
stats.wins,
stats.losses,
devide(stats.wins, stats.losses)
]
}
return [ return [
stats[`kills_${bestMode}`], stats.kills,
stats[`deaths_${bestMode}`], stats.deaths,
devide(stats[`kills_${bestMode}`], stats[`deaths_${bestMode}`]), devide(stats.kills, stats.deaths),
stats[`wins_${bestMode}`], stats.wins,
stats[`losses_${bestMode}`], stats.losses,
devide(stats[`wins_${bestMode}`], stats[`losses_${bestMode}`]) devide(stats.wins, stats.losses)
] ]
} }

View File

@@ -1048,6 +1048,40 @@ export const arcadeStatsSchema = z.object({
...arcadeZombiesTypeStats() ...arcadeZombiesTypeStats()
}) })
function speedUhcModeModeMasteryStats() {
const ids = [
"mastery_wild_specialist",
"mastery_sniper",
"mastery_berserk",
"mastery_fortune",
"mastery_master_baker",
"mastery_invigorate",
"mastery_huntsman",
"mastery_vampirism",
"mastery_guardian",
"solo_normal",
"solo_insane",
"team_normal",
"team_insane"
] as const
const stats = [
"kills",
"deaths",
"wins",
"losses"
] as const
const entries = new Map<string, z.ZodDefault<z.ZodNumber>>()
for (const id of ids) {
for (const stat of stats) {
entries.set(`${stat}_${id}`, z.number().default(0))
}
}
return Object.fromEntries(entries) as Record<`${typeof stats[number]}_${typeof ids[number]}`, z.ZodDefault<z.ZodNumber>>
}
export const speedUhcStatsSchema = z.object({ export const speedUhcStatsSchema = z.object({
kills: z.number().default(0), kills: z.number().default(0),
deaths: z.number().default(0), deaths: z.number().default(0),
@@ -1055,20 +1089,5 @@ export const speedUhcStatsSchema = z.object({
losses: z.number().default(0), losses: z.number().default(0),
score: z.number().default(0), score: z.number().default(0),
coins: z.number().default(0), coins: z.number().default(0),
kills_solo_normal: z.number().default(0), ...speedUhcModeModeMasteryStats()
deaths_solo_normal: z.number().default(0),
wins_solo_normal: z.number().default(0),
losses_solo_normal: z.number().default(0),
kills_solo_insane: z.number().default(0),
deaths_solo_insane: z.number().default(0),
wins_solo_insane: z.number().default(0),
losses_solo_insane: z.number().default(0),
kills_team_normal: z.number().default(0),
deaths_team_normal: z.number().default(0),
wins_team_normal: z.number().default(0),
losses_team_normal: z.number().default(0),
kills_team_insane: z.number().default(0),
deaths_team_insane: z.number().default(0),
wins_team_insane: z.number().default(0),
losses_team_insane: z.number().default(0)
}) })