Added wool games mode stats

This commit is contained in:
2025-09-11 11:42:42 +02:00
parent 11fb9b75cd
commit c686be44e6
5 changed files with 180 additions and 10 deletions

View File

@@ -0,0 +1,130 @@
import { formatNumber, formatSecondsToTime } from "@/lib/formatters"
import { devide } from "@/lib/hypixel/general"
import { getWoolGamesWoolWarsClass, getWoolGamesWoolWarsClassColor } from "@/lib/hypixel/woolgames/general"
import { NonNullStats } from "@/lib/schema/player"
import { cn } from "@/lib/utils"
import { BasicStat } from "../../_components/Stats"
export function WoolGamesCaptureTheWool({ ctw }: { ctw: NonNullable<NonNullStats["WoolGames"]>["capture_the_wool"] }) {
if (!ctw) {
return (
<>
<h2 className="text-xl font-bold">Capture The Wool</h2>
<p>This person has no Capture The Wool stats.</p>
</>
)
}
const kd = formatNumber(devide(ctw.stats?.kills || 0, ctw.stats?.deaths || 0))
const wl = formatNumber(devide(ctw.stats?.participated_wins || 0, ctw.stats?.participated_losses || 0))
return (
<>
<h2 className="pb-6 text-xl font-bold">Capture The Wool</h2>
<div className="flex">
<div className="flex-1">
<BasicStat title="Kills: " value={formatNumber(ctw.stats?.kills || 0)} />
<BasicStat title="Assists: " value={formatNumber(ctw.stats?.assits || 0)} />
<BasicStat title="Deaths: " value={formatNumber(ctw.stats?.deaths || 0)} />
<BasicStat title="Kill/Death Ratio: " value={kd} />
</div>
<div className="flex-1">
<BasicStat title="Wins: " value={formatNumber(ctw.stats?.participated_wins || 0)} />
<BasicStat title="Losses: " value={formatNumber(ctw.stats?.participated_losses || 0)} />
<BasicStat title="Win/Loss Ratio: " value={wl} />
<BasicStat title="Fastest Win: " value={formatSecondsToTime(ctw.stats?.fastest_win || 0)} />
<BasicStat title="Longest Game: " value={formatSecondsToTime(ctw.stats?.longest_game || 0)} />
</div>
<div className="flex-1">
<BasicStat title="Wools Stolen: " value={formatNumber(ctw.stats?.wools_stolen || 0)} />
<BasicStat title="Wools Captured: " value={formatNumber(ctw.stats?.wools_captured || 0)} />
<BasicStat title="Fastest Wool Capture: " value={formatSecondsToTime(ctw.stats?.fastest_wool_capture || 0)} />
<BasicStat title="Total Gold Earned: " value={formatNumber(ctw.stats?.gold_earned || 0)} className="text-mc-gold" />
<BasicStat title="Total Gold Spent: " value={formatNumber(Math.abs(ctw.stats?.gold_spent || 0))} className="text-mc-gold" />
</div>
</div>
</>
)
}
export function WoolGamesSheepWars({ sw }: { sw: NonNullable<NonNullStats["WoolGames"]>["sheep_wars"] }) {
if (!sw) {
return (
<>
<h2 className="text-xl font-bold">Sheep Wars</h2>
<p>This person has no Sheep Wars stats.</p>
</>
)
}
const kd = formatNumber(devide(sw.stats?.kills || 0, sw.stats?.deaths || 0))
const wl = formatNumber(devide(sw.stats?.wins || 0, sw.stats?.losses || 0))
return (
<>
<h2 className="pb-6 text-xl font-bold">Sheep Wars</h2>
<div className="flex">
<div className="flex-1">
<BasicStat title="Kills: " value={formatNumber(sw.stats?.kills || 0)} />
<BasicStat title="Deaths: " value={formatNumber(sw.stats?.deaths || 0)} />
<BasicStat title="Kill/Death Ratio: " value={kd} />
</div>
<div className="flex-1">
<BasicStat title="Wins: " value={formatNumber(sw.stats?.wins || 0)} />
<BasicStat title="Losses: " value={formatNumber(sw.stats?.losses || 0)} />
<BasicStat title="Win/Loss Ratio: " value={wl} />
</div>
<div className="flex-1">
<BasicStat title="Sheep Thrown: " value={formatNumber(sw.stats?.sheep_thrown || 0)} />
<BasicStat title="Damage Dealt: " value={formatNumber(sw.stats?.damage_dealt || 0)} />
</div>
</div>
</>
)
}
export function WoolGamesWoolWars({ ww }: { ww: NonNullable<NonNullStats["WoolGames"]>["wool_wars"] }) {
if (!ww) {
return (
<>
<h2 className="text-xl font-bold">Wool Wars</h2>
<p>This person has no Wool Wars stats.</p>
</>
)
}
const klass = getWoolGamesWoolWarsClass(ww.selected_class)
const klassName = klass?.name || "Unknown"
const klassColor = getWoolGamesWoolWarsClassColor(klass?.difficulty)
const kd = formatNumber(devide(ww.stats?.kills || 0, ww.stats?.deaths || 0))
const wl = formatNumber(devide(ww.stats?.wins || 0, ww.stats?.losses || 0))
return (
<>
<h2 className="pb-6 text-lg font-bold">Wool Wars</h2>
<div className="flex">
<div className="flex-1">
<BasicStat
className={cn(klassColor && `text-mc-${klassColor}`)}
title="Selected Class: "
value={klassName}
/>
<BasicStat title="Kills: " value={formatNumber(ww.stats?.kills || 0)} />
<BasicStat title="Assists: " value={formatNumber(ww.stats?.assits || 0)} />
<BasicStat title="Deaths: " value={formatNumber(ww.stats?.deaths || 0)} />
<BasicStat title="Kill/Death Ratio: " value={kd} />
</div>
<div className="flex-1">
<BasicStat title="Wins: " value={formatNumber(ww.stats?.wins || 0)} />
<BasicStat title="Losses: " value={formatNumber(ww.stats?.losses || 0)} />
<BasicStat title="Win/Loss Ratio: " value={wl} />
</div>
<div className="flex-1">
<BasicStat title="Wool Placed: " value={formatNumber(ww.stats?.wool_placed || 0)} />
<BasicStat title="Wool Broken: " value={formatNumber(ww.stats?.blocks_broken || 0)} />
<BasicStat title="Poweups: " value={formatNumber(ww.stats?.powerups_gotten || 0)} />
</div>
</div>
</>
)
}

View File

@@ -4,6 +4,7 @@ import { getWoolGamesLevel, getWoolGamesPrestige, getWoolGamesPretigeIcon } from
import { NonNullStats } from "@/lib/schema/player" import { NonNullStats } from "@/lib/schema/player"
import Multicolored from "../../_components/Multicolored" import Multicolored from "../../_components/Multicolored"
import GeneralStats from "../GeneralStats" import GeneralStats from "../GeneralStats"
import { WoolGamesCaptureTheWool, WoolGamesSheepWars, WoolGamesWoolWars } from "./modes"
import WoolGamesProgress from "./progress" import WoolGamesProgress from "./progress"
import WoolGamesGeneralStats from "./stats" import WoolGamesGeneralStats from "./stats"
@@ -40,6 +41,12 @@ export default function WoolGamesStats({ stats }: { stats: NonNullStats["WoolGam
<Separator className="my-4" /> <Separator className="my-4" />
<WoolGamesGeneralStats stats={stats} level={level} kills={kills} wins={wins} /> <WoolGamesGeneralStats stats={stats} level={level} kills={kills} wins={wins} />
<Separator className="my-4" /> <Separator className="my-4" />
<WoolGamesCaptureTheWool ctw={stats.capture_the_wool} />
<Separator className="my-4" />
<WoolGamesSheepWars sw={stats.sheep_wars} />
<Separator className="my-4" />
<WoolGamesWoolWars ww={stats.wool_wars} />
<Separator className="my-4" />
</GeneralStats> </GeneralStats>
) )
} }

View File

@@ -26,12 +26,12 @@ export const ICONS = {
YIN_YANG: "\u262f" // ☯ YIN_YANG: "\u262f" // ☯
} as const } as const
export const CLASSES = [ export const CLASSES = [
{ id: "tank", name: "Tank", difficulty: 1 }, { id: "TANK", name: "Tank", difficulty: 1 },
{ id: "archer", name: "Archer", difficulty: 2 }, { id: "ARCHER", name: "Archer", difficulty: 2 },
{ id: "swordsman", name: "Swordsman", difficulty: 1 }, { id: "SWORDSMAN", name: "Swordsman", difficulty: 1 },
{ id: "engineer", name: "Engineer", difficulty: 1 }, { id: "ENGINEER", name: "Engineer", difficulty: 1 },
{ id: "golem", name: "Golem", difficulty: 2 }, { id: "GOLEM", name: "Golem", difficulty: 2 },
{ id: "assault", name: "Assault", difficulty: 3 } { id: "ASSAULT", name: "Assault", difficulty: 3 }
] as const ] as const
export const DIFFICULTIES = { export const DIFFICULTIES = {
"1": "green", "1": "green",

View File

@@ -1,7 +1,19 @@
import { EASY_XP, ICONS, NORMAL_XP, PRESTIGES } from "@/data/hypixel/woolgames" import { CLASSES, DIFFICULTIES, EASY_XP, ICONS, NORMAL_XP, PRESTIGES } from "@/data/hypixel/woolgames"
import { getColorFromCode } from "@/lib/colors" import { getColorFromCode } from "@/lib/colors"
import { floorLevel } from "../general" import { floorLevel } from "../general"
export function getWoolGamesWoolWarsClass(val?: string) {
const klass = CLASSES.find(c => c.id === val)
return klass || null
}
export function getWoolGamesWoolWarsClassColor(id?: 1 | 2 | 3 | 4) {
if (!id) {
return null
}
return DIFFICULTIES[id]
}
export function getWoolGamesPrestige(level: number) { export function getWoolGamesPrestige(level: number) {
const floored = floorLevel(Math.floor(level), 100) const floored = floorLevel(Math.floor(level), 100)

View File

@@ -735,19 +735,40 @@ export const woolGamesStatsSchema = z.looseObject({
capture_the_wool: z.looseObject({ capture_the_wool: z.looseObject({
stats: z.looseObject({ stats: z.looseObject({
kills: z.number().default(0), kills: z.number().default(0),
participated_wins: z.number().default(0) assits: z.number().default(0),
deaths: z.number().default(0),
participated_wins: z.number().default(0),
participated_losses: z.number().default(0),
fastest_win: z.number().default(0),
longest_game: z.number().default(0),
wools_stolen: z.number().default(0),
wools_captured: z.number().default(0),
fastest_wool_capture: z.number().default(0),
gold_earned: z.number().default(0),
gold_spent: z.number().default(0)
}).optional() }).optional()
}).optional(), }).optional(),
sheep_wars: z.looseObject({ sheep_wars: z.looseObject({
stats: z.looseObject({ stats: z.looseObject({
kills: z.number().default(0), kills: z.number().default(0),
wins: z.number().default(0) deaths: z.number().default(0),
wins: z.number().default(0),
losses: z.number().default(0),
sheep_thrown: z.number().default(0),
damage_dealt: z.number().default(0)
}).optional() }).optional()
}).optional(), }).optional(),
wool_wars: z.looseObject({ wool_wars: z.looseObject({
selected_class: z.string().optional(),
stats: z.looseObject({ stats: z.looseObject({
kills: z.number().default(0), kills: z.number().default(0),
wins: z.number().default(0) assits: z.number().default(0),
deaths: z.number().default(0),
wins: z.number().default(0),
losses: z.number().default(0),
wool_placed: z.number().default(0),
blocks_broken: z.number().default(0),
powerups_gotten: z.number().default(0)
}).optional() }).optional()
}).optional() }).optional()
}) })