Finished quake craft stats

This commit is contained in:
2025-09-22 14:11:12 +02:00
parent acf5f3b36d
commit f2a7987bc9
6 changed files with 173 additions and 5 deletions

View File

@@ -109,7 +109,7 @@ export function PlayerStats(
"paintball": <PaintballStats stats={stats.Paintball} />, "paintball": <PaintballStats stats={stats.Paintball} />,
"walls": <WallsStats stats={stats.Walls} />, "walls": <WallsStats stats={stats.Walls} />,
"vampirez": <VampireZStats stats={stats.VampireZ} />, "vampirez": <VampireZStats stats={stats.VampireZ} />,
"quakecraft": <QuakecraftStats stats={stats.Quakecraft} /> "quakecraft": <QuakecraftStats stats={stats.Quakecraft} godlikes={achievements?.["quake_godlikes"] ?? 0} />
} as const } as const
const defaultOrder = Object.keys(statsComponents) const defaultOrder = Object.keys(statsComponents)

View File

@@ -3,8 +3,10 @@ import { formatNumber } from "@/lib/formatters"
import { devide } from "@/lib/hypixel/general" import { devide } from "@/lib/hypixel/general"
import { NonNullStats } from "@/lib/schema/player" import { NonNullStats } from "@/lib/schema/player"
import { EmptyStats, GeneralStats } from "../stats-components" import { EmptyStats, GeneralStats } from "../stats-components"
import { QuakeCraftGeneralStats } from "./stats"
import { QuakecraftModeStatsTable } from "./table"
export default function QuakecraftStats({ stats }: { stats: NonNullStats["Quakecraft"] }) { export default function QuakecraftStats({ stats, godlikes }: { stats: NonNullStats["Quakecraft"], godlikes: number }) {
if (!stats) return <EmptyStats title="Quakecraft" /> if (!stats) return <EmptyStats title="Quakecraft" />
const kd = formatNumber(devide(stats.kills + stats.kills_teams, stats.deaths + stats.deaths_teams)) const kd = formatNumber(devide(stats.kills + stats.kills_teams, stats.deaths + stats.deaths_teams))
@@ -29,6 +31,10 @@ export default function QuakecraftStats({ stats }: { stats: NonNullStats["Quakec
]} ]}
> >
<Separator className="my-4" /> <Separator className="my-4" />
<QuakeCraftGeneralStats stats={stats} godlikes={godlikes} />
<Separator className="my-4" />
<QuakecraftModeStatsTable stats={stats} />
<Separator className="my-4" />
</GeneralStats> </GeneralStats>
) )
} }

View File

@@ -87,3 +87,32 @@ export function VampireZGeneralStats({ stats }: { stats: NonNullable<NonNullStat
</> </>
) )
} }
export function QuakeCraftGeneralStats({ stats, godlikes }: { stats: NonNullable<NonNullStats["Quakecraft"]>, godlikes: number }) {
return (
<div className="flex mt-4">
<div className="flex-1">
<BasicStat title="Coins: " value={formatNumber(stats.coins)} className="text-mc-gold" />
<p>
<br />
</p>
<BasicStat title="Kills: " value={formatNumber(stats.kills + stats.kills_teams)} />
<BasicStat title="Deaths: " value={formatNumber(stats.deaths + stats.deaths_teams)} />
<BasicStat
title="Kill/Death Ratio: "
value={formatNumber(devide(stats.kills + stats.kills_teams, stats.deaths + stats.deaths_teams))}
/>
</div>
<div className="flex-1">
<BasicStat title="Wins: " value={formatNumber(stats.wins + stats.wins_teams)} />
<p>
<br />
</p>
<BasicStat title="Godlikes: " value={formatNumber(godlikes)} />
<BasicStat title="Highest Killstreak: " value={formatNumber(stats.highest_killstreak)} />
<BasicStat title="Dash Cooldown: " value={stats.dash_cooldown + 1} />
<BasicStat title="Dash Power: " value={stats.dash_power + 1} />
</div>
</div>
)
}

View File

@@ -1,9 +1,82 @@
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 { getArenaBrawlModeName, getArenaBrawlModeStats, getArenaBrawlMostPlayedMode, getArenaBrawlOverallStats } from "@/lib/hypixel/classic/general" import {
getArenaBrawlModeName,
getArenaBrawlModeStats,
getArenaBrawlMostPlayedMode,
getArenaBrawlOverallStats,
getQuakecraftModeName,
getQuakecraftModeStats,
getQuakecraftMostPlayedMode
} from "@/lib/hypixel/classic/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 QuakecraftModeStatsTable({ stats }: { stats: NonNullable<NonNullStats["Quakecraft"]> }) {
return (
<Table>
<QuakecraftModeStatsTableHeader />
<TableBody>
<QuakecraftModeStat modeId="solo" stats={stats} />
<QuakecraftModeStat modeId="teams" stats={stats} />
<QuakecraftModeStat modeId="all" stats={stats} />
</TableBody>
</Table>
)
}
function QuakecraftModeStat(
{ modeId, stats }: { modeId: Parameters<typeof getQuakecraftModeStats>[0], stats: NonNullable<NonNullStats["Quakecraft"]> }
) {
if (modeId === "all") {
const modeStats = getQuakecraftModeStats(modeId, stats)
return (
<TableRow className="font-bold">
<TableCell>Overall</TableCell>
{modeStats.map((v, i) => {
return <TableCell key={i}>{formatNumber(v)}</TableCell>
})}
</TableRow>
)
}
const modeStats = getQuakecraftModeStats(modeId, stats)
const modeName = getQuakecraftModeName(modeId)
const mostPlayed = getQuakecraftMostPlayedMode(stats) === modeId
return (
<TableRow className={cn(mostPlayed && "text-mc-light-purple")}>
<TableCell>{modeName}</TableCell>
{modeStats.map((v, i) => {
return <TableCell key={i}>{formatNumber(v)}</TableCell>
})}
</TableRow>
)
}
function QuakecraftModeStatsTableHeader() {
const headerElements = [
"Mode",
"Kills",
"Deaths",
"KD",
"Wins",
"Killstreaks",
"Headshots",
"Shots Fired",
"HK",
"KS"
]
return (
<TableHeader>
<TableRow>
{headerElements.map((v, i) => <TableHead key={i} className="font-bold">{v}</TableHead>)}
</TableRow>
</TableHeader>
)
}
export function ArenaBrawlModeStatsTable({ stats }: { stats: NonNullable<NonNullStats["ArenaBrawl"]> }) { export function ArenaBrawlModeStatsTable({ stats }: { stats: NonNullable<NonNullStats["ArenaBrawl"]> }) {
return ( return (
<Table> <Table>

View File

@@ -1,7 +1,61 @@
import { ARENABRAWLMODES } from "@/data/hypixel/classic" import { ARENABRAWLMODES, QUAKECRAFTMODES } from "@/data/hypixel/classic"
import { NonNullStats } from "@/lib/schema/player" import { NonNullStats } from "@/lib/schema/player"
import { devide } from "../general" import { devide } from "../general"
export function getQuakecraftModeName(modeId: Exclude<typeof QUAKECRAFTMODES[number]["id"], ""> | "solo") {
if (modeId === "solo") return QUAKECRAFTMODES.find(m => m.id === "")!.name
return QUAKECRAFTMODES.find(m => m.id === modeId)!.name
}
export function getQuakecraftMostPlayedMode(stats: NonNullable<NonNullStats["Quakecraft"]>) {
if (stats.wins + stats.wins_teams === 0) return null
return stats.wins > stats.wins_teams ? "solo" : "teams"
}
export function getQuakecraftModeStats(
modeId: Exclude<typeof QUAKECRAFTMODES[number]["id"], ""> | "solo" | "all",
stats: NonNullable<NonNullStats["Quakecraft"]>
) {
if (modeId === "all") {
return [
stats.kills + stats.kills_teams,
stats.deaths + stats.deaths_teams,
devide(stats.kills + stats.kills_teams, stats.deaths + stats.deaths_teams),
stats.wins + stats.wins_teams,
stats.killstreaks + stats.killstreaks_teams,
stats.headshots + stats.headshots_teams,
stats.shots_fired + stats.shots_fired_teams,
devide(stats.headshots + stats.headshots_teams, stats.kills_since_update_feb_2017 + stats.kills_since_update_feb_2017_teams),
devide(stats.kills_since_update_feb_2017 + stats.kills_since_update_feb_2017_teams, stats.shots_fired + stats.shots_fired_teams)
]
} else if (modeId === "solo") {
return [
stats.kills,
stats.deaths,
devide(stats.kills, stats.deaths),
stats.wins,
stats.killstreaks,
stats.headshots,
stats.shots_fired,
devide(stats.headshots, stats.kills_since_update_feb_2017),
devide(stats.kills_since_update_feb_2017, stats.shots_fired)
]
} else {
return [
stats[`kills_${modeId}`],
stats[`deaths_${modeId}`],
devide(stats[`kills_${modeId}`], stats[`deaths_${modeId}`]),
stats[`wins_${modeId}`],
stats[`killstreaks_${modeId}`],
stats[`headshots_${modeId}`],
stats[`shots_fired_${modeId}`],
devide(stats[`headshots_${modeId}`], stats[`kills_since_update_feb_2017_${modeId}`]),
devide(stats[`kills_since_update_feb_2017_${modeId}`], stats[`shots_fired_${modeId}`])
]
}
}
export function getArenaBrawlModeName(modeId: typeof ARENABRAWLMODES[number]["id"]) { export function getArenaBrawlModeName(modeId: typeof ARENABRAWLMODES[number]["id"]) {
return ARENABRAWLMODES.find(m => m.id === modeId)!.name return ARENABRAWLMODES.find(m => m.id === modeId)!.name
} }

View File

@@ -50,16 +50,22 @@ export const vampireZStatsSchema = z.object({
}) })
export const quakecraftStatsSchema = z.object({ export const quakecraftStatsSchema = z.object({
coins: z.number().default(0),
kills: z.number().default(0), kills: z.number().default(0),
deaths: z.number().default(0), deaths: z.number().default(0),
killstreaks: z.number().default(0),
wins: z.number().default(0), wins: z.number().default(0),
headshots: z.number().default(0), headshots: z.number().default(0),
kills_since_update_feb_2017: z.number().default(0), kills_since_update_feb_2017: z.number().default(0),
shots_fired: z.number().default(0), shots_fired: z.number().default(0),
kills_teams: z.number().default(0), kills_teams: z.number().default(0),
deaths_teams: z.number().default(0), deaths_teams: z.number().default(0),
killstreaks_teams: z.number().default(0),
wins_teams: z.number().default(0), wins_teams: z.number().default(0),
headshots_teams: z.number().default(0), headshots_teams: z.number().default(0),
kills_since_update_feb_2017_teams: z.number().default(0), kills_since_update_feb_2017_teams: z.number().default(0),
shots_fired_teams: z.number().default(0) shots_fired_teams: z.number().default(0),
highest_killstreak: z.number().default(0),
dash_cooldown: z.coerce.number().default(0),
dash_power: z.coerce.number().default(0)
}) })