From 175cd13870285f9523683e0afa3772dec9651600 Mon Sep 17 00:00:00 2001 From: Taken Date: Wed, 24 Sep 2025 00:13:02 +0200 Subject: [PATCH] Updated tkr stats --- .../player/[ign]/_stats/classic/tkr.tsx | 3 + .../player/[ign]/_stats/classic/tkrkart.tsx | 64 +++++++++++++++++ src/data/hypixel/classic.ts | 33 +++++++++ src/lib/hypixel/classic/general.ts | 69 ++++++++++++++++++- src/lib/hypixel/general.ts | 16 +++++ src/lib/schema/stats/classic.ts | 5 +- 6 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 src/app/(stats)/player/[ign]/_stats/classic/tkrkart.tsx diff --git a/src/app/(stats)/player/[ign]/_stats/classic/tkr.tsx b/src/app/(stats)/player/[ign]/_stats/classic/tkr.tsx index d5da300..6365ca7 100644 --- a/src/app/(stats)/player/[ign]/_stats/classic/tkr.tsx +++ b/src/app/(stats)/player/[ign]/_stats/classic/tkr.tsx @@ -3,6 +3,7 @@ import { formatNumber } from "@/lib/formatters" import { NonNullStats } from "@/lib/schema/player" import { EmptyStats, GeneralStats } from "../stats-components" import { TkrGeneralStats } from "./stats" +import TkrKart from "./tkrkart" export default function TkrStats({ stats }: { stats: NonNullStats["TurboKartRacers"] }) { if (!stats) return @@ -29,6 +30,8 @@ export default function TkrStats({ stats }: { stats: NonNullStats["TurboKartRace + + ) } diff --git a/src/app/(stats)/player/[ign]/_stats/classic/tkrkart.tsx b/src/app/(stats)/player/[ign]/_stats/classic/tkrkart.tsx new file mode 100644 index 0000000..6883ef3 --- /dev/null +++ b/src/app/(stats)/player/[ign]/_stats/classic/tkrkart.tsx @@ -0,0 +1,64 @@ +import { getTkrKart } from "@/lib/hypixel/classic/general" +import { NonNullStats } from "@/lib/schema/player" +import { cn } from "@/lib/utils" + +export default function TkrKart({ stats }: { stats: NonNullable }) { + const { engine, frame, turbocharger } = getTkrKart(stats.engine_active, stats.frame_active, stats.booster_active) + + return ( +
+

Current Kart

+
+ {engine !== null ? + ( +
+

{`${engine.name} ${engine.rarity} Engine`}

+ {engine.attributes.map((e, i) => { + return ( +
+

{e.name}

+

+ {e.level} +

+
+ ) + })} +
+ ) : +

Error while getting engine

} + {frame !== null ? + ( +
+

{`${frame.name} ${frame.rarity} Frame`}

+ {frame.attributes.map((e, i) => { + return ( +
+

{e.name}

+

{e.level}

+
+ ) + })} +
+ ) : +

Error while getting frame

} + {turbocharger !== null ? + ( +
+

+ {`${turbocharger.name} ${turbocharger.rarity} Turbocharger`} +

+ {turbocharger.attributes.map((e, i) => { + return ( +
+

{e.name}

+

{e.level}

+
+ ) + })} +
+ ) : +

Error while getting turbocharger

} +
+
+ ) +} diff --git a/src/data/hypixel/classic.ts b/src/data/hypixel/classic.ts index f031c9a..e61eb1a 100644 --- a/src/data/hypixel/classic.ts +++ b/src/data/hypixel/classic.ts @@ -7,3 +7,36 @@ export const QUAKECRAFTMODES = [ { id: "", name: "Solo" }, { id: "teams", name: "Teams" } ] as const +export const TKRATTRIBUTES = [ + { id: "ACCELERATION", name: "Acceleration" }, + { id: "BOOSTER_SPEED", name: "Booster Speed" }, + { id: "BRAKES", name: "Brakes" }, + { id: "DRIFTING_EFFICIENCY", name: "Drifting Efficiency" }, + { id: "HANDLING", name: "Handling" }, + { id: "RECOVERY", name: "Recovery" }, + { id: "START_POSITION", name: "Start Position" }, + { id: "TOP_SPEED", name: "Top Speed" }, + { id: "TRACTION", name: "Traction" } +] as const +export const TKRQUALITY = [ + { name: "Starter", color: "gray" }, + { name: "Mini", color: "gray" }, + { name: "Auxiliary", color: "green" }, + { name: "Standard", color: "green" }, + { name: "Primary", color: "green" }, + { name: "Experimental", color: "green" }, + { name: "Dynamic", color: "blue" }, + { name: "Stellar", color: "blue" }, + { name: "Kinetic", color: "blue" }, + { name: "Multi-phase", color: "blue" }, + { name: "Turbocharged", color: "light-purple" }, + { name: "Quantum", color: "light-purple" }, + { name: "Superluminal", color: "light-purple" }, + { name: "Psi", color: "light-purple" }, + { name: "Eternal", color: "dark-purple" } +] as const +export const TKRRARITY = [ + { id: "BASIC", name: "Basic" }, + { id: "SUPER", name: "Super" }, + { id: "AWESOME", name: "Awesome" } +] as const diff --git a/src/lib/hypixel/classic/general.ts b/src/lib/hypixel/classic/general.ts index 7ed3c53..470af9d 100644 --- a/src/lib/hypixel/classic/general.ts +++ b/src/lib/hypixel/classic/general.ts @@ -1,6 +1,71 @@ -import { ARENABRAWLMODES, QUAKECRAFTMODES } from "@/data/hypixel/classic" +import { ARENABRAWLMODES, QUAKECRAFTMODES, TKRATTRIBUTES, TKRQUALITY, TKRRARITY } from "@/data/hypixel/classic" import { NonNullStats } from "@/lib/schema/player" -import { devide } from "../general" +import z from "zod" +import { addQuotes, devide } from "../general" + +const tkrSchema = z.object({ + GingerbreadPart: z.object({ + PartRarity: z.string().optional(), + Attributes: z.array(z.object({ + KartAttributeType: z.string().optional(), + Level: z.coerce.number().default(0) + })) + }) +}) + +export function getTkrKart(engine?: string, frame?: string, turbocharger?: string) { + return { + engine: getTkrPart(engine), + frame: getTkrPart(frame), + turbocharger: getTkrPart(turbocharger) + } +} + +function getTkrPart(val?: string) { + const unknown = JSON.parse(addQuotes(val)) + const { data, success } = tkrSchema.safeParse(unknown) + if (!success) return null + + let quality = 0 + const rarity = getTkrRarity(data.GingerbreadPart.PartRarity) + + const attributes: { name: typeof TKRATTRIBUTES[number]["name"], level: number }[] = [] + for (const attr of data.GingerbreadPart.Attributes) { + const val = getTkrAttribute(attr) + if (!val) continue + quality += val.level + attributes.push({ name: val.name, level: val.level }) + } + const { color, name } = getTkrQuality(quality) + + return { rarity, attributes, color, name } +} + +function getTkrRarity(rarity?: string) { + const val = TKRRARITY.find(r => r.id === rarity) + return val?.name || TKRRARITY.find(r => r.id === "BASIC")!.name +} + +function getTkrAttribute(attr: z.infer["GingerbreadPart"]["Attributes"][number]) { + const val = TKRATTRIBUTES.find(a => a.id === attr.KartAttributeType)?.name + + if (!val) return null + + return { name: val, level: attr.Level } +} + +function getTkrQuality(quality: number) { + if (quality < 1) { + const { color, name } = TKRQUALITY.at(0)! + return { name, color } + } + if (quality > TKRQUALITY.length) { + const { color, name } = TKRQUALITY.at(-1)! + return { name, color } + } + const { color, name } = TKRQUALITY.at(quality - 1)! + return { name, color } +} export function getQuakecraftModeName(modeId: Exclude | "solo") { if (modeId === "solo") return QUAKECRAFTMODES.find(m => m.id === "")!.name diff --git a/src/lib/hypixel/general.ts b/src/lib/hypixel/general.ts index 0d0ec43..5396f71 100644 --- a/src/lib/hypixel/general.ts +++ b/src/lib/hypixel/general.ts @@ -82,3 +82,19 @@ export function romanize(num: number) { export function head(val: string, size: number) { return `https://vzge.me/face/${size}/${val}?no-shadow,cape,ears,overlay` } + +export function addQuotes(str?: string) { + if (!str) return "{}" + const bank = ["{", "}", "[", "]", ",", ":"] + let newStr = str.charAt(0) + for (let i = 1; i < str.length; i++) { + if ( + (bank.includes(str[i - 1]) && !bank.includes(str[i])) || + (!bank.includes(str[i - 1]) && bank.includes(str[i])) + ) { + newStr += "\"" + } + newStr += str[i] + } + return newStr +} diff --git a/src/lib/schema/stats/classic.ts b/src/lib/schema/stats/classic.ts index 71b18f4..0173555 100644 --- a/src/lib/schema/stats/classic.ts +++ b/src/lib/schema/stats/classic.ts @@ -82,5 +82,8 @@ export const turboKartRacersStatsSchema = z.object({ laps_completed: z.number().default(0), blue_torpedo_hit: z.number().default(0), banana_hits_sent: z.number().default(0), - banana_hits_received: z.number().default(0) + banana_hits_received: z.number().default(0), + engine_active: z.string().optional(), + frame_active: z.string().optional(), + booster_active: z.string().optional() })