Added tnt games stats
This commit is contained in:
@@ -18,7 +18,32 @@ type GenericProgressProps =
|
||||
rainbow: true
|
||||
})
|
||||
|
||||
export default function GenericProgress({ percent, tooltipId, tooltipContent, className, rainbow }: GenericProgressProps) {
|
||||
type GenericProgressNoTooltipProps = {
|
||||
text: string
|
||||
percent: number
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function GenericProgressNoTooltip({ text, percent, className }: GenericProgressNoTooltipProps) {
|
||||
return (
|
||||
<div className="flex flex-1">
|
||||
<div
|
||||
className={cn("h-5 rounded-l-md flex items-center justify-center", percent >= 100 ? "rounded-r-md" : undefined, className)}
|
||||
style={{ width: `${percent > 100 ? 100 : percent}%` }}
|
||||
>
|
||||
{text}
|
||||
</div>
|
||||
{percent < 100 && (
|
||||
<div
|
||||
className={cn("flex-1 h-5 rounded-r-md bg-background", percent === 0 ? "rounded-l-md" : undefined)}
|
||||
>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function GenericProgress({ percent, tooltipId, tooltipContent, className, rainbow }: GenericProgressProps) {
|
||||
const [pos, setPos] = useState({ x: 0, y: 0 })
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
39
src/app/(stats)/player/[ign]/_stats/tnt-games/stats.tsx
Normal file
39
src/app/(stats)/player/[ign]/_stats/tnt-games/stats.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { formatNumber, formatSecondsToTime } from "@/lib/formatters"
|
||||
import { devide } from "@/lib/hypixel/general"
|
||||
import { NonNullStats } from "@/lib/schema/player"
|
||||
import { BasicStat } from "../../_components/Stats"
|
||||
|
||||
export default function TNTGamesGeneralStats({ stats }: { stats: NonNullable<NonNullStats["TNTGames"]> }) {
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<div>
|
||||
<BasicStat title="Token: " value={formatNumber(stats.coins)} className="text-mc-dark-green" />
|
||||
<BasicStat title="Wins: " value={formatNumber(stats.wins)} />
|
||||
</div>
|
||||
<div className="grid grid-cols-2 grid-rows-2">
|
||||
<div>
|
||||
<h2 className="text-xl font-bold">TNT Tag</h2>
|
||||
<BasicStat title="Kills: " value={formatNumber(stats.kills_tntag)} />
|
||||
<BasicStat title="Wins: " value={formatNumber(stats.wins_tntag)} />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl font-bold">TNT Run</h2>
|
||||
<BasicStat title="Wins: " value={formatNumber(stats.wins_tntrun)} />
|
||||
<BasicStat title="Record Time: " value={formatSecondsToTime(stats.record_tntrun)} />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl font-bold">PvP Run</h2>
|
||||
<BasicStat title="Kills: " value={formatNumber(stats.kills_pvprun)} />
|
||||
<BasicStat title="Wins: " value={formatNumber(stats.wins_pvprun)} />
|
||||
<BasicStat title="Record Time: " value={formatSecondsToTime(stats.record_pvprun)} />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl font-bold">Bow Spleef</h2>
|
||||
<BasicStat title="Wins: " value={formatNumber(stats.wins_bowspleef)} />
|
||||
<BasicStat title="Losses: " value={formatNumber(stats.deaths_bowspleef)} />
|
||||
<BasicStat title="Win/Loss Ratio: " value={formatNumber(devide(stats.wins_bowspleef, stats.deaths_bowspleef))} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
37
src/app/(stats)/player/[ign]/_stats/tnt-games/tnt-games.tsx
Normal file
37
src/app/(stats)/player/[ign]/_stats/tnt-games/tnt-games.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { NonNullStats } from "@/lib/schema/player"
|
||||
import CollapsedStats from "../../_components/CollapsedStats"
|
||||
import TNTGamesGeneralStats from "./stats"
|
||||
import TNTWizardsStats from "./wizards"
|
||||
|
||||
export default function TNTGamesStats({ stats }: { stats: NonNullStats["TNTGames"] }) {
|
||||
if (!stats) return null
|
||||
|
||||
return (
|
||||
<AccordionItem value="tnt-games">
|
||||
<Card className="py-0">
|
||||
<CardContent>
|
||||
<AccordionTrigger className="items-center py-2 hover:no-underline hover:cursor-pointer">
|
||||
<h1 className="text-xl font-bold">TNT Games</h1>
|
||||
<div className="flex gap-4">
|
||||
<CollapsedStats
|
||||
stats={[{
|
||||
title: <p>Wins</p>,
|
||||
stat: <p className="text-muted-foreground">{stats.wins}</p>
|
||||
}]}
|
||||
/>
|
||||
</div>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<Separator className="my-4" />
|
||||
<TNTGamesGeneralStats stats={stats} />
|
||||
<Separator className="my-4" />
|
||||
<TNTWizardsStats stats={stats} />
|
||||
</AccordionContent>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</AccordionItem>
|
||||
)
|
||||
}
|
||||
102
src/app/(stats)/player/[ign]/_stats/tnt-games/wizards.tsx
Normal file
102
src/app/(stats)/player/[ign]/_stats/tnt-games/wizards.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||
import { formatNumber } from "@/lib/formatters"
|
||||
import { devide, romanize } from "@/lib/hypixel/general"
|
||||
import { getTNTGameMode, getTNTModeStats } from "@/lib/hypixel/tnt-games/general"
|
||||
import { NonNullStats } from "@/lib/schema/player"
|
||||
import { GenericProgressNoTooltip } from "../../_components/GenericProgress"
|
||||
import { BasicStat } from "../../_components/Stats"
|
||||
|
||||
export default function TNTWizardsStats({ stats }: { stats: NonNullable<NonNullStats["TNTGames"]> }) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<h2 className="text-xl font-bold">TNT Wizards</h2>
|
||||
<div>
|
||||
<BasicStat title="Wins: " value={formatNumber(stats.wins_capture)} />
|
||||
<BasicStat title="Kills: " value={formatNumber(stats.kills_capture)} />
|
||||
<BasicStat title="Deaths: " value={formatNumber(stats.deaths_capture)} />
|
||||
<BasicStat title="Kill/Death Ratio: " value={formatNumber(devide(stats.kills_capture, stats.deaths_capture))} />
|
||||
</div>
|
||||
<Table>
|
||||
<TNTWizardsTableHeader />
|
||||
<TableBody>
|
||||
<TableStats id="ancient" stats={stats} />
|
||||
<TableStats id="blood" stats={stats} />
|
||||
<TableStats id="fire" stats={stats} />
|
||||
<TableStats id="hydro" stats={stats} />
|
||||
<TableStats id="ice" stats={stats} />
|
||||
<TableStats id="kinetic" stats={stats} />
|
||||
<TableStats id="storm" stats={stats} />
|
||||
<TableStats id="toxic" stats={stats} />
|
||||
<TableStats id="wither" stats={stats} />
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function TableStats({ id, stats }: { id: Parameters<typeof getTNTGameMode>[0], stats: NonNullable<NonNullStats["TNTGames"]> }) {
|
||||
const gm = getTNTGameMode(id)
|
||||
const modeStats = getTNTModeStats(id, stats)
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell className={`text-mc-${gm.color}`}>{gm.name}</TableCell>
|
||||
{modeStats.map((m, i) => {
|
||||
if (i === modeStats.length - 2) {
|
||||
if (m === 0) {
|
||||
return <TableCell key={i}>?</TableCell>
|
||||
}
|
||||
return (
|
||||
<TableCell key={i}>
|
||||
{
|
||||
<GenericProgressNoTooltip
|
||||
text={romanize(m)}
|
||||
percent={m / 7 * 100}
|
||||
className={`bg-mc-${gm.color}`}
|
||||
/>
|
||||
}
|
||||
</TableCell>
|
||||
)
|
||||
}
|
||||
if (i === modeStats.length - 1) {
|
||||
if (m === 0) {
|
||||
return <TableCell key={i}>?</TableCell>
|
||||
}
|
||||
return (
|
||||
<TableCell key={i}>
|
||||
{
|
||||
<GenericProgressNoTooltip
|
||||
text={romanize(m)}
|
||||
percent={m / 7 * 100}
|
||||
className={`bg-mc-${gm.color}`}
|
||||
/>
|
||||
}
|
||||
</TableCell>
|
||||
)
|
||||
}
|
||||
return <TableCell key={i}>{formatNumber(m)}</TableCell>
|
||||
})}
|
||||
</TableRow>
|
||||
)
|
||||
}
|
||||
|
||||
function TNTWizardsTableHeader() {
|
||||
const headerElements = [
|
||||
"Wizard",
|
||||
"Kills",
|
||||
"Deaths",
|
||||
"Assists",
|
||||
"KD",
|
||||
"Power",
|
||||
"Regen"
|
||||
]
|
||||
|
||||
return (
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{headerElements.map((v, i) => {
|
||||
return <TableHead key={i} className="font-bold">{v}</TableHead>
|
||||
})}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
)
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import DuelsStats from "./_stats/duels/duels"
|
||||
import MurderMysteryStats from "./_stats/murder-mystery/murder-mystery"
|
||||
import PitStats from "./_stats/pit/pit"
|
||||
import SkyWarsStats from "./_stats/skywars/skywars"
|
||||
import TNTGamesStats from "./_stats/tnt-games/tnt-games"
|
||||
import UHCStats from "./_stats/uhc/uhc"
|
||||
|
||||
export async function generateMetadata({ params }: { params: Promise<{ ign: string }> }): Promise<Metadata> {
|
||||
@@ -116,6 +117,7 @@ async function SuspendedPage({ ign: pign }: { ign: string }) {
|
||||
<BuildBattleStats stats={player.stats.BuildBattle} />
|
||||
<UHCStats stats={player.stats.UHC} />
|
||||
<PitStats stats={player.stats.Pit} />
|
||||
<TNTGamesStats stats={player.stats.TNTGames} />
|
||||
</Accordion>
|
||||
</div>
|
||||
) :
|
||||
|
||||
11
src/data/hypixel/tnt-games.ts
Normal file
11
src/data/hypixel/tnt-games.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export const WIZARDS = [
|
||||
{ id: "ancient", name: "Ancient", color: "gold" },
|
||||
{ id: "blood", name: "Blood", color: "dark-red" },
|
||||
{ id: "fire", name: "Fire", color: "red" },
|
||||
{ id: "hydro", name: "Hydro", color: "dark-blue" },
|
||||
{ id: "ice", name: "Ice", color: "blue" },
|
||||
{ id: "kinetic", name: "Kinetic", color: "light-purple" },
|
||||
{ id: "storm", name: "Storm", color: "yellow" },
|
||||
{ id: "toxic", name: "Toxic", color: "green" },
|
||||
{ id: "wither", name: "Wither", color: "black" }
|
||||
] as const
|
||||
18
src/lib/hypixel/tnt-games/general.ts
Normal file
18
src/lib/hypixel/tnt-games/general.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { WIZARDS } from "@/data/hypixel/tnt-games"
|
||||
import { NonNullStats } from "@/lib/schema/player"
|
||||
import { devide } from "../general"
|
||||
|
||||
export function getTNTGameMode(id: typeof WIZARDS[number]["id"]) {
|
||||
return WIZARDS.find(w => w.id === id)!
|
||||
}
|
||||
|
||||
export function getTNTModeStats(id: typeof WIZARDS[number]["id"], stats: NonNullable<NonNullStats["TNTGames"]>) {
|
||||
return [
|
||||
stats[`new_${id}wizard_kills`],
|
||||
stats[`new_${id}wizard_deaths`],
|
||||
stats[`new_${id}wizard_assists`],
|
||||
devide(stats[`new_${id}wizard_kills`], stats[`new_${id}wizard_deaths`]),
|
||||
stats[`new_${id}wizard_explode`],
|
||||
stats[`new_${id}wizard_regen`]
|
||||
]
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
murderMysteryStatsSchema,
|
||||
pitStats,
|
||||
skywarsStatsSchema,
|
||||
tntGamesStatsSchema,
|
||||
uhcSchema
|
||||
} from "./stats"
|
||||
|
||||
@@ -28,7 +29,8 @@ export const playerSchema = z.looseObject({
|
||||
MurderMystery: murderMysteryStatsSchema.optional(),
|
||||
BuildBattle: buildBattleStatsSchema.optional(),
|
||||
UHC: uhcSchema.optional(),
|
||||
Pit: pitStats.optional()
|
||||
Pit: pitStats.optional(),
|
||||
TNTGames: tntGamesStatsSchema.optional()
|
||||
}).optional(),
|
||||
quests: z.record(
|
||||
z.string(),
|
||||
|
||||
@@ -503,3 +503,53 @@ export const pitStats = z.looseObject({
|
||||
...pit_stats_ptl,
|
||||
...rest
|
||||
}))
|
||||
|
||||
function tntGamesModeStats() {
|
||||
const ids = [
|
||||
"ancient",
|
||||
"blood",
|
||||
"fire",
|
||||
"hydro",
|
||||
"ice",
|
||||
"kinetic",
|
||||
"storm",
|
||||
"toxic",
|
||||
"wither"
|
||||
] as const
|
||||
|
||||
const stats = [
|
||||
"kills",
|
||||
"deaths",
|
||||
"assists",
|
||||
"explode",
|
||||
"regen"
|
||||
] as const
|
||||
|
||||
const entries = new Map<string, z.ZodDefault<z.ZodNumber>>()
|
||||
|
||||
for (const id of ids) {
|
||||
for (const stat of stats) {
|
||||
entries.set(`new_${id}wizard_${stat}`, z.number().default(0))
|
||||
}
|
||||
}
|
||||
|
||||
return Object.fromEntries(entries) as Record<`new_${typeof ids[number]}wizard_${typeof stats[number]}`, z.ZodDefault<z.ZodNumber>>
|
||||
}
|
||||
|
||||
export const tntGamesStatsSchema = z.looseObject({
|
||||
wins: z.number().default(0),
|
||||
coins: z.number().default(0),
|
||||
kills_tntag: z.number().default(0),
|
||||
wins_tntag: z.number().default(0),
|
||||
wins_tntrun: z.number().default(0),
|
||||
record_tntrun: z.number().default(0),
|
||||
kills_pvprun: z.number().default(0),
|
||||
wins_pvprun: z.number().default(0),
|
||||
record_pvprun: z.number().default(0),
|
||||
wins_bowspleef: z.number().default(0),
|
||||
deaths_bowspleef: z.number().default(0),
|
||||
wins_capture: z.number().default(0),
|
||||
kills_capture: z.number().default(0),
|
||||
deaths_capture: z.number().default(0),
|
||||
...tntGamesModeStats()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user