Added first

This commit is contained in:
2025-09-05 19:31:06 +02:00
parent 306ad1f146
commit 5bf00d513a
7 changed files with 238 additions and 2 deletions

View File

@@ -0,0 +1,59 @@
import { AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
import { Card, CardContent } from "@/components/ui/card"
import { Separator } from "@/components/ui/separator"
import { formatNumber } from "@/lib/formatters"
import { devide, romanize } from "@/lib/hypixel/general"
import { getLevelColor, getPrestige, getPrestigeColor } from "@/lib/hypixel/pit/general"
import { getPitLevel } from "@/lib/hypixel/pit/level"
import { NonNullStats } from "@/lib/schema/player"
import CollapsedStats from "../../_components/CollapsedStats"
export default function PitStats({ stats }: { stats: NonNullStats["Pit"] }) {
if (!stats) return null
const kd = formatNumber(devide(stats.kills, stats.deaths))
const prestige = getPrestige(stats)
const level = getPitLevel(stats.profile.xp, prestige)
const prestigeColor = getPrestigeColor(prestige)
const levelColor = getLevelColor(level)
return (
<AccordionItem value="pit">
<Card className="py-0">
<CardContent>
<AccordionTrigger className="items-center py-2 hover:no-underline hover:cursor-pointer">
<h1 className="text-xl font-bold">Pit</h1>
<div className="flex gap-4">
<CollapsedStats
stats={[
{
title: <p>Level</p>,
stat: (
<p className="font-bold">
<span className={`text-mc-${prestigeColor}`}>[</span>
<span className="text-mc-yellow">{romanize(prestige)}</span>
<span className={`text-mc-${levelColor}`}>{`-${level}`}</span>
<span className={`text-mc-${prestigeColor}`}>]</span>
</p>
)
},
{
title: <p>Kills</p>,
stat: <p className="text-muted-foreground">{formatNumber(stats.kills)}</p>
},
{
title: <p>KD</p>,
stat: <p className="text-muted-foreground">{kd}</p>
}
]}
/>
</div>
</AccordionTrigger>
<AccordionContent>
<Separator className="my-4" />
</AccordionContent>
</CardContent>
</Card>
</AccordionItem>
)
}

View File

@@ -14,6 +14,7 @@ import BedwarsStats from "./_stats/bedwars/bedwars"
import BuildBattleStats from "./_stats/build-battle/build-battle"
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 UHCStats from "./_stats/uhc/uhc"
@@ -114,6 +115,7 @@ async function SuspendedPage({ ign: pign }: { ign: string }) {
<MurderMysteryStats stats={player.stats.MurderMystery} />
<BuildBattleStats stats={player.stats.BuildBattle} />
<UHCStats stats={player.stats.UHC} />
<PitStats stats={player.stats.Pit} />
</Accordion>
</div>
) :

98
src/data/hypixel/pit.ts Normal file
View File

@@ -0,0 +1,98 @@
export const TITLE = "Pit" as const
export const MAXPRESTIGE = 40 as const
export const MAXLEVEL = 120 as const
export const PRESTIGE_MULTIPLIERS = [
{ "Multiplier": 1, "SumXp": 65950 },
{ "Multiplier": 1.1, "SumXp": 138510 },
{ "Multiplier": 1.2, "SumXp": 217680 },
{ "Multiplier": 1.3, "SumXp": 303430 },
{ "Multiplier": 1.4, "SumXp": 395760 },
{ "Multiplier": 1.5, "SumXp": 494700 },
{ "Multiplier": 1.75, "SumXp": 610140 },
{ "Multiplier": 2, "SumXp": 742040 },
{ "Multiplier": 2.5, "SumXp": 906930 },
{ "Multiplier": 3, "SumXp": 1104780 },
{ "Multiplier": 4, "SumXp": 1368580 },
{ "Multiplier": 5, "SumXp": 1698330 },
{ "Multiplier": 6, "SumXp": 2094030 },
{ "Multiplier": 7, "SumXp": 2555680 },
{ "Multiplier": 8, "SumXp": 3083280 },
{ "Multiplier": 9, "SumXp": 3676830 },
{ "Multiplier": 10, "SumXp": 4336330 },
{ "Multiplier": 12, "SumXp": 5127730 },
{ "Multiplier": 14, "SumXp": 6051030 },
{ "Multiplier": 16, "SumXp": 7106230 },
{ "Multiplier": 18, "SumXp": 8293330 },
{ "Multiplier": 20, "SumXp": 9612330 },
{ "Multiplier": 24, "SumXp": 11195130 },
{ "Multiplier": 28, "SumXp": 13041730 },
{ "Multiplier": 32, "SumXp": 15152130 },
{ "Multiplier": 36, "SumXp": 17526330 },
{ "Multiplier": 40, "SumXp": 20164330 },
{ "Multiplier": 45, "SumXp": 23132080 },
{ "Multiplier": 50, "SumXp": 26429580 },
{ "Multiplier": 75, "SumXp": 31375830 },
{ "Multiplier": 100, "SumXp": 37970830 },
{ "Multiplier": 101, "SumXp": 44631780 },
{ "Multiplier": 101, "SumXp": 51292730 },
{ "Multiplier": 101, "SumXp": 57953680 },
{ "Multiplier": 101, "SumXp": 64614630 },
{ "Multiplier": 101, "SumXp": 71275580 },
{ "Multiplier": 200, "SumXp": 84465580 },
{ "Multiplier": 300, "SumXp": 104250580 },
{ "Multiplier": 400, "SumXp": 130630580 },
{ "Multiplier": 500, "SumXp": 163605580 },
{ "Multiplier": 750, "SumXp": 213068080 },
{ "Multiplier": 1000, "SumXp": 279018080 },
{ "Multiplier": 1250, "SumXp": 361455580 },
{ "Multiplier": 1500, "SumXp": 460380580 },
{ "Multiplier": 1750, "SumXp": 575793080 },
{ "Multiplier": 2000, "SumXp": 707693080 },
{ "Multiplier": 3000, "SumXp": 905543080 },
{ "Multiplier": 5000, "SumXp": 1235293080 },
{ "Multiplier": 10000, "SumXp": 1894793080 },
{ "Multiplier": 50000, "SumXp": 5192293080 },
{ "Multiplier": 100000, "SumXp": 11787293080 }
] as const
export const LEVEL_REQUIREMENTS = [
15,
30,
50,
75,
125,
300,
600,
800,
900,
1000,
1200,
1500,
0
] as const
export const LEVELCOLORS = [
{ level: 0, color: "gray" },
{ level: 10, color: "blue" },
{ level: 20, color: "dark-aqua" },
{ level: 30, color: "dark-green" },
{ level: 40, color: "green" },
{ level: 50, color: "yellow" },
{ level: 60, color: "gold" },
{ level: 70, color: "red" },
{ level: 80, color: "dark-red" },
{ level: 90, color: "dark-purple" },
{ level: 100, color: "light-purple" },
{ level: 110, color: "white" },
{ level: 120, color: "aqua" }
] as const
export const PRESTIGECOLORS = [
{ prestige: 0, color: "gray" },
{ prestige: 1, color: "blue" },
{ prestige: 5, color: "yellow" },
{ prestige: 10, color: "gold" },
{ prestige: 15, color: "red" },
{ prestige: 20, color: "dark-purple" },
{ prestige: 25, color: "light-purple" },
{ prestige: 30, color: "white" },
{ prestige: 35, color: "aqua" },
{ prestige: 40, color: "dark-blue" }
] as const

View File

@@ -0,0 +1,22 @@
import { LEVELCOLORS, PRESTIGECOLORS } from "@/data/hypixel/pit"
import { NonNullStats } from "@/lib/schema/player"
export function getLevelColor(level: number) {
for (const lvl of LEVELCOLORS.slice().reverse()) {
if (lvl.level <= level) return lvl.color
}
return LEVELCOLORS.at(0)!.color
}
export function getPrestigeColor(prestige: number) {
for (const pres of PRESTIGECOLORS.slice().reverse()) {
if (pres.prestige <= prestige) return pres.color
}
return PRESTIGECOLORS.at(0)!.color
}
export function getPrestige(stats: NonNullable<NonNullStats["Pit"]>) {
return stats.profile.prestiges.length
}

View File

@@ -0,0 +1,27 @@
import { LEVEL_REQUIREMENTS, PRESTIGE_MULTIPLIERS } from "@/data/hypixel/pit"
export function getPitLevel(xp: number, prestige: number) {
let xps = xp
if (prestige > 0) {
xps = xps - PRESTIGE_MULTIPLIERS[prestige - 1]["SumXp"]
}
const multiplier = PRESTIGE_MULTIPLIERS[prestige]["Multiplier"]
let level = 0
while (xps > 0 && level < 120) {
const levelXp = LEVEL_REQUIREMENTS[Math.floor(level / 10)] * multiplier
if (xps >= levelXp * 10) {
xps -= levelXp * 10
level += 10
} else {
const gain = Math.floor(xps / levelXp)
level += gain
xps -= gain * levelXp
xps = 0
}
}
return level
}

View File

@@ -1,5 +1,13 @@
import z from "zod"
import { bedwarsStatsSchema, buildBattleStatsSchema, duelsStatsSchema, murderMysteryStatsSchema, skywarsStatsSchema, uhcSchema } from "./stats"
import {
bedwarsStatsSchema,
buildBattleStatsSchema,
duelsStatsSchema,
murderMysteryStatsSchema,
pitStats,
skywarsStatsSchema,
uhcSchema
} from "./stats"
export const playerSchema = z.looseObject({
player: z.looseObject({
@@ -19,7 +27,8 @@ export const playerSchema = z.looseObject({
Duels: duelsStatsSchema.optional(),
MurderMystery: murderMysteryStatsSchema.optional(),
BuildBattle: buildBattleStatsSchema.optional(),
UHC: uhcSchema.optional()
UHC: uhcSchema.optional(),
Pit: pitStats.optional()
}).optional(),
quests: z.record(
z.string(),

View File

@@ -445,3 +445,22 @@ export const uhcSchema = z.looseObject({
ultimates_crafted_solo: z.number().default(0),
...uhcModesStats()
})
export const pitStats = z.looseObject({
pit_stats_ptl: z.looseObject({
kills: z.number().default(0),
deaths: z.number().default(0)
}),
profile: z.looseObject({
prestiges: z.array(z.looseObject({
index: z.number(),
xp_on_prestige: z.number(),
timestamp: z.number()
})),
xp: z.number().default(0)
})
}).transform(({ profile, pit_stats_ptl, ...rest }) => ({
profile,
...pit_stats_ptl,
...rest
}))