Updated tkr stats

This commit is contained in:
2025-09-24 00:13:02 +02:00
parent c3351e8268
commit 175cd13870
6 changed files with 187 additions and 3 deletions

View File

@@ -3,6 +3,7 @@ import { formatNumber } from "@/lib/formatters"
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 { TkrGeneralStats } from "./stats" import { TkrGeneralStats } from "./stats"
import TkrKart from "./tkrkart"
export default function TkrStats({ stats }: { stats: NonNullStats["TurboKartRacers"] }) { export default function TkrStats({ stats }: { stats: NonNullStats["TurboKartRacers"] }) {
if (!stats) return <EmptyStats title="Turbo Kart Racers" /> if (!stats) return <EmptyStats title="Turbo Kart Racers" />
@@ -29,6 +30,8 @@ export default function TkrStats({ stats }: { stats: NonNullStats["TurboKartRace
<Separator className="my-4" /> <Separator className="my-4" />
<TkrGeneralStats stats={stats} /> <TkrGeneralStats stats={stats} />
<Separator className="my-4" /> <Separator className="my-4" />
<TkrKart stats={stats} />
<Separator className="my-4" />
</GeneralStats> </GeneralStats>
) )
} }

View File

@@ -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<NonNullStats["TurboKartRacers"]> }) {
const { engine, frame, turbocharger } = getTkrKart(stats.engine_active, stats.frame_active, stats.booster_active)
return (
<div>
<h2 className="text-xl font-bold">Current Kart</h2>
<div className="flex gap-4 mt-4">
{engine !== null ?
(
<div className="flex-1">
<p className={cn("mb-2 font-bold", `text-mc-${engine.color}`)}>{`${engine.name} ${engine.rarity} Engine`}</p>
{engine.attributes.map((e, i) => {
return (
<div key={i} className="flex justify-between">
<p>{e.name}</p>
<p className="text-mc-green">
{e.level}
</p>
</div>
)
})}
</div>
) :
<p>Error while getting engine</p>}
{frame !== null ?
(
<div className="flex-1">
<p className={cn("mb-2 font-bold", `text-mc-${frame.color}`)}>{`${frame.name} ${frame.rarity} Frame`}</p>
{frame.attributes.map((e, i) => {
return (
<div key={i} className="flex justify-between">
<p>{e.name}</p>
<p className="text-mc-green">{e.level}</p>
</div>
)
})}
</div>
) :
<p>Error while getting frame</p>}
{turbocharger !== null ?
(
<div className="flex-1">
<p className={cn("mb-2 font-bold", `text-mc-${turbocharger.color}`)}>
{`${turbocharger.name} ${turbocharger.rarity} Turbocharger`}
</p>
{turbocharger.attributes.map((e, i) => {
return (
<div key={i} className="flex justify-between">
<p>{e.name}</p>
<p className="text-mc-green">{e.level}</p>
</div>
)
})}
</div>
) :
<p>Error while getting turbocharger</p>}
</div>
</div>
)
}

View File

@@ -7,3 +7,36 @@ export const QUAKECRAFTMODES = [
{ id: "", name: "Solo" }, { id: "", name: "Solo" },
{ id: "teams", name: "Teams" } { id: "teams", name: "Teams" }
] as const ] 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

View File

@@ -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 { 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<typeof tkrSchema>["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<typeof QUAKECRAFTMODES[number]["id"], ""> | "solo") { export function getQuakecraftModeName(modeId: Exclude<typeof QUAKECRAFTMODES[number]["id"], ""> | "solo") {
if (modeId === "solo") return QUAKECRAFTMODES.find(m => m.id === "")!.name if (modeId === "solo") return QUAKECRAFTMODES.find(m => m.id === "")!.name

View File

@@ -82,3 +82,19 @@ export function romanize(num: number) {
export function head(val: string, size: number) { export function head(val: string, size: number) {
return `https://vzge.me/face/${size}/${val}?no-shadow,cape,ears,overlay` 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
}

View File

@@ -82,5 +82,8 @@ export const turboKartRacersStatsSchema = z.object({
laps_completed: z.number().default(0), laps_completed: z.number().default(0),
blue_torpedo_hit: z.number().default(0), blue_torpedo_hit: z.number().default(0),
banana_hits_sent: 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()
}) })