diff --git a/src/app/(stats)/player/[ign]/_components/GenericProgress.tsx b/src/app/(stats)/player/[ign]/_components/GenericProgress.tsx
index 3f493e1..a8a9296 100644
--- a/src/app/(stats)/player/[ign]/_components/GenericProgress.tsx
+++ b/src/app/(stats)/player/[ign]/_components/GenericProgress.tsx
@@ -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 (
+
+
= 100 ? "rounded-r-md" : undefined, className)}
+ style={{ width: `${percent > 100 ? 100 : percent}%` }}
+ >
+ {text}
+
+ {percent < 100 && (
+
+
+ )}
+
+ )
+}
+
+export function GenericProgress({ percent, tooltipId, tooltipContent, className, rainbow }: GenericProgressProps) {
const [pos, setPos] = useState({ x: 0, y: 0 })
useEffect(() => {
diff --git a/src/app/(stats)/player/[ign]/_stats/tnt-games/stats.tsx b/src/app/(stats)/player/[ign]/_stats/tnt-games/stats.tsx
new file mode 100644
index 0000000..79a1435
--- /dev/null
+++ b/src/app/(stats)/player/[ign]/_stats/tnt-games/stats.tsx
@@ -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 }) {
+ return (
+
+
+
+
+
+
+
+
TNT Tag
+
+
+
+
+
TNT Run
+
+
+
+
+
PvP Run
+
+
+
+
+
+
Bow Spleef
+
+
+
+
+
+
+ )
+}
diff --git a/src/app/(stats)/player/[ign]/_stats/tnt-games/tnt-games.tsx b/src/app/(stats)/player/[ign]/_stats/tnt-games/tnt-games.tsx
new file mode 100644
index 0000000..4eca443
--- /dev/null
+++ b/src/app/(stats)/player/[ign]/_stats/tnt-games/tnt-games.tsx
@@ -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 (
+
+
+
+
+ TNT Games
+
+
Wins,
+ stat: {stats.wins}
+ }]}
+ />
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/app/(stats)/player/[ign]/_stats/tnt-games/wizards.tsx b/src/app/(stats)/player/[ign]/_stats/tnt-games/wizards.tsx
new file mode 100644
index 0000000..52206ae
--- /dev/null
+++ b/src/app/(stats)/player/[ign]/_stats/tnt-games/wizards.tsx
@@ -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 }) {
+ return (
+
+
TNT Wizards
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+function TableStats({ id, stats }: { id: Parameters[0], stats: NonNullable }) {
+ const gm = getTNTGameMode(id)
+ const modeStats = getTNTModeStats(id, stats)
+ return (
+
+ {gm.name}
+ {modeStats.map((m, i) => {
+ if (i === modeStats.length - 2) {
+ if (m === 0) {
+ return ?
+ }
+ return (
+
+ {
+
+ }
+
+ )
+ }
+ if (i === modeStats.length - 1) {
+ if (m === 0) {
+ return ?
+ }
+ return (
+
+ {
+
+ }
+
+ )
+ }
+ return {formatNumber(m)}
+ })}
+
+ )
+}
+
+function TNTWizardsTableHeader() {
+ const headerElements = [
+ "Wizard",
+ "Kills",
+ "Deaths",
+ "Assists",
+ "KD",
+ "Power",
+ "Regen"
+ ]
+
+ return (
+
+
+ {headerElements.map((v, i) => {
+ return {v}
+ })}
+
+
+ )
+}
diff --git a/src/app/(stats)/player/[ign]/page.tsx b/src/app/(stats)/player/[ign]/page.tsx
index de836e7..f3e0e51 100644
--- a/src/app/(stats)/player/[ign]/page.tsx
+++ b/src/app/(stats)/player/[ign]/page.tsx
@@ -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 {
@@ -116,6 +117,7 @@ async function SuspendedPage({ ign: pign }: { ign: string }) {
+
) :
diff --git a/src/data/hypixel/tnt-games.ts b/src/data/hypixel/tnt-games.ts
new file mode 100644
index 0000000..23c07b5
--- /dev/null
+++ b/src/data/hypixel/tnt-games.ts
@@ -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
diff --git a/src/lib/hypixel/tnt-games/general.ts b/src/lib/hypixel/tnt-games/general.ts
new file mode 100644
index 0000000..1f5c856
--- /dev/null
+++ b/src/lib/hypixel/tnt-games/general.ts
@@ -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) {
+ 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`]
+ ]
+}
diff --git a/src/lib/schema/player.ts b/src/lib/schema/player.ts
index 6209a61..f646f65 100644
--- a/src/lib/schema/player.ts
+++ b/src/lib/schema/player.ts
@@ -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(),
diff --git a/src/lib/schema/stats.ts b/src/lib/schema/stats.ts
index 05a7d14..064b975 100644
--- a/src/lib/schema/stats.ts
+++ b/src/lib/schema/stats.ts
@@ -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>()
+
+ 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>
+}
+
+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()
+})