Added smash heros hero stat table

This commit is contained in:
2025-09-18 12:47:18 +02:00
parent 7e1e64d254
commit 405bc4370c
5 changed files with 161 additions and 5 deletions

View File

@@ -5,7 +5,7 @@ import { getSmashHerosDifficultyColor, getSmashHerosMostPlayedHero } from "@/lib
import { NonNullStats } from "@/lib/schema/player" import { NonNullStats } from "@/lib/schema/player"
import GeneralStats from "../GeneralStats" import GeneralStats from "../GeneralStats"
import SmashHerosGeneralStats from "./stats" import SmashHerosGeneralStats from "./stats"
import { SmashHerosModeTable } from "./table" import { SmashHerosHeroTable, SmashHerosModeTable } from "./table"
export default function SmashHerosStats({ stats }: { stats: NonNullStats["SmashHeros"] }) { export default function SmashHerosStats({ stats }: { stats: NonNullStats["SmashHeros"] }) {
if (!stats) return null if (!stats) return null
@@ -52,6 +52,8 @@ export default function SmashHerosStats({ stats }: { stats: NonNullStats["SmashH
<Separator className="my-4" /> <Separator className="my-4" />
<SmashHerosModeTable stats={stats} /> <SmashHerosModeTable stats={stats} />
<Separator className="my-4" /> <Separator className="my-4" />
<SmashHerosHeroTable stats={stats} />
<Separator className="my-4" />
</GeneralStats> </GeneralStats>
) )
} }

View File

@@ -1,9 +1,83 @@
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 { getSmashHerosModeName, getSmashHerosModeStats, getSmashHerosMostPlayedMode } from "@/lib/hypixel/smashhero/general" import {
getSmashHerosAllHerosStats,
getSmashHerosDifficultyColor,
getSmashHerosHero,
getSmashHerosHeroLvlPres,
getSmashHerosHeroPrestigeColor,
getSmashHerosModeName,
getSmashHerosModeStats,
getSmashHerosMostPlayedHero,
getSmashHerosMostPlayedMode
} from "@/lib/hypixel/smashhero/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 SmashHerosHeroTable({ stats }: { stats: NonNullable<NonNullStats["SmashHeros"]> }) {
return (
<Table>
<SmashHerosHeroTableHeader />
<SmashHerosHeroTableStats stats={stats} />
</Table>
)
}
function SmashHerosHeroTableStats({ stats }: { stats: NonNullable<NonNullStats["SmashHeros"]> }) {
const heroStats = getSmashHerosAllHerosStats(stats)
return (
<TableBody>
{heroStats.map((v, i) => {
const { id, nums } = v
const hero = getSmashHerosHero(id)
const difficultyColor = getSmashHerosDifficultyColor(hero.difficulty)
const mostPlayed = getSmashHerosMostPlayedHero(stats)?.id === id
const { lvl, pg: pres } = getSmashHerosHeroLvlPres(id, stats)
const presColor = getSmashHerosHeroPrestigeColor(pres)
return (
<TableRow key={i} className={cn(mostPlayed && "text-mc-light-purple")}>
<TableCell>
<span className={`text-mc-${difficultyColor}`}>{hero.name}</span>
<span className="text-mc-gray">{" Lv"}</span>
<span className="text-mc-aqua">{lvl}</span>
{pres > 0 && (
<span className={`text-mc-${presColor}`}>
{`${pres}`}
</span>
)}
</TableCell>
{nums.map((n, j) => {
return <TableCell key={j}>{formatNumber(n)}</TableCell>
})}
</TableRow>
)
})}
</TableBody>
)
}
function SmashHerosHeroTableHeader() {
const headerElements = [
"Hero",
"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 SmashHerosModeTable({ stats }: { stats: NonNullable<NonNullStats["SmashHeros"]> }) { export function SmashHerosModeTable({ stats }: { stats: NonNullable<NonNullStats["SmashHeros"]> }) {
return ( return (
<Table> <Table>

View File

@@ -1,7 +1,8 @@
export const MODES = [ export const MODES = [
{ id: "normal", name: "1v1v1v1" }, { id: "normal", name: "1v1v1v1" },
{ id: "2v2", name: "2v2" }, { id: "teams", name: "2v2v2v2" },
{ id: "teams", name: "2v2v2" }, { id: "teams", name: "2v2v2" },
{ id: "2v2", name: "2v2" },
{ id: "", name: "Overall" } { id: "", name: "Overall" }
] as const ] as const
export const HEROES = [ export const HEROES = [

View File

@@ -1,7 +1,50 @@
import { DIFFICULTY, HEROES, MODES } from "@/data/hypixel/smashheros" import { DIFFICULTY, HEROES, MODES, PRESTIGECOLORS } from "@/data/hypixel/smashheros"
import { NonNullStats } from "@/lib/schema/player" import { NonNullStats } from "@/lib/schema/player"
import { devide } from "../general" import { devide } from "../general"
export function getSmashHerosHeroPrestigeColor(pres: number) {
if (pres < 1) return PRESTIGECOLORS.at(0)!
if (pres > PRESTIGECOLORS.length) return PRESTIGECOLORS.at(0)!
return PRESTIGECOLORS.at(pres - 1)!
}
export function getSmashHerosHeroLvlPres(heroId: typeof HEROES[number]["id"], stats: NonNullable<NonNullStats["SmashHeros"]>) {
return {
lvl: stats[`lastLevel_${heroId}`],
pg: stats[`pg_${heroId}`]
}
}
export function getSmashHerosHero(heroId: typeof HEROES[number]["id"]) {
return HEROES.find(h => h.id === heroId)!
}
export function getSmashHerosAllHerosStats(stats: NonNullable<NonNullStats["SmashHeros"]>) {
const vals: { id: typeof HEROES[number]["id"], nums: number[] }[] = []
for (const hero of HEROES) {
vals.push({ id: hero.id, nums: getSmashHerosHeroStats(hero.id, stats) })
}
return vals
}
export function getSmashHerosHeroStats(heroId: typeof HEROES[number]["id"], stats: NonNullable<NonNullStats["SmashHeros"]>) {
if (!stats.class_stats) return [0, 0, 0, 0, 0, 0]
const cStats = stats.class_stats[heroId]
return [
cStats?.kills || 0,
cStats?.deaths || 0,
devide(cStats?.kills || 0, cStats?.deaths || 0),
cStats?.wins || 0,
cStats?.losses || 0,
devide(cStats?.wins || 0, cStats?.losses || 0)
]
}
export function getSmashHerosModeName(modeId: Exclude<typeof MODES[number]["id"], ""> | "all") { export function getSmashHerosModeName(modeId: Exclude<typeof MODES[number]["id"], ""> | "all") {
if (modeId === "all") return MODES.find(m => m.id === "")!.name if (modeId === "all") return MODES.find(m => m.id === "")!.name
return MODES.find(m => m.id === modeId)!.name return MODES.find(m => m.id === modeId)!.name

View File

@@ -1,7 +1,11 @@
import z from "zod" import z from "zod"
const classStats = z.object({ const classStats = z.object({
games: z.number().default(0) games: z.number().default(0),
kills: z.number().default(0),
deaths: z.number().default(0),
wins: z.number().default(0),
losses: z.number().default(0)
}).optional() }).optional()
export const smashHerosStats = z.object({ export const smashHerosStats = z.object({
@@ -30,6 +34,38 @@ export const smashHerosStats = z.object({
TINMAN: classStats, TINMAN: classStats,
DUSK_CRAWLER: classStats DUSK_CRAWLER: classStats
}).optional(), }).optional(),
lastLevel_BOTMUN: z.number().default(0),
lastLevel_THE_BULK: z.number().default(0),
lastLevel_CAKE_MONSTER: z.number().default(0),
lastLevel_FROSTY: z.number().default(0),
lastLevel_GENERAL_CLUCK: z.number().default(0),
lastLevel_GREEN_HOOD: z.number().default(0),
lastLevel_GOKU: z.number().default(0),
lastLevel_MARAUDER: z.number().default(0),
lastLevel_PUG: z.number().default(0),
lastLevel_SANIC: z.number().default(0),
lastLevel_SERGEANT_SHIELD: z.number().default(0),
lastLevel_SHOOP_DA_WHOOP: z.number().default(0),
lastLevel_SKULLFIRE: z.number().default(0),
lastLevel_SPODERMAN: z.number().default(0),
lastLevel_TINMAN: z.number().default(0),
lastLevel_DUSK_CRAWLER: z.number().default(0),
pg_BOTMUN: z.number().default(0),
pg_THE_BULK: z.number().default(0),
pg_CAKE_MONSTER: z.number().default(0),
pg_FROSTY: z.number().default(0),
pg_GENERAL_CLUCK: z.number().default(0),
pg_GREEN_HOOD: z.number().default(0),
pg_GOKU: z.number().default(0),
pg_MARAUDER: z.number().default(0),
pg_PUG: z.number().default(0),
pg_SANIC: z.number().default(0),
pg_SERGEANT_SHIELD: z.number().default(0),
pg_SHOOP_DA_WHOOP: z.number().default(0),
pg_SKULLFIRE: z.number().default(0),
pg_SPODERMAN: z.number().default(0),
pg_TINMAN: z.number().default(0),
pg_DUSK_CRAWLER: z.number().default(0),
kills_normal: z.number().default(0), kills_normal: z.number().default(0),
deaths_normal: z.number().default(0), deaths_normal: z.number().default(0),
wins_normal: z.number().default(0), wins_normal: z.number().default(0),