Added zombie type stats

This commit is contained in:
2025-09-14 22:43:12 +02:00
parent 060e277c37
commit a6b4b6efad
5 changed files with 242 additions and 28 deletions

View File

@@ -3,7 +3,7 @@ import { devide } from "@/lib/hypixel/general"
import { NonNullStats } from "@/lib/schema/player" import { NonNullStats } from "@/lib/schema/player"
import { capitalizeFirstLetter } from "@/lib/utils" import { capitalizeFirstLetter } from "@/lib/utils"
import { BasicStat } from "../../_components/Stats" import { BasicStat } from "../../_components/Stats"
import { PixelPartyStatsTable } from "./table" import { ArcadePixelPartyStatsTable, ArcadeZombieStatsTable, ArcadeZombieTypesTable } from "./table"
export function ArcadeZombieStats({ stats }: { stats: NonNullable<NonNullStats["Arcade"]> }) { export function ArcadeZombieStats({ stats }: { stats: NonNullable<NonNullStats["Arcade"]> }) {
const bha = devide(stats.bullets_hit_zombies, stats.bullets_shot_zombies) * 100 const bha = devide(stats.bullets_hit_zombies, stats.bullets_shot_zombies) * 100
@@ -38,6 +38,8 @@ export function ArcadeZombieStats({ stats }: { stats: NonNullable<NonNullStats["
<BasicStat title="Windows Repaired: " value={formatNumber(stats.windows_repaired_zombies)} /> <BasicStat title="Windows Repaired: " value={formatNumber(stats.windows_repaired_zombies)} />
</div> </div>
</div> </div>
<ArcadeZombieStatsTable stats={stats} />
<ArcadeZombieTypesTable stats={stats} />
</> </>
) )
} }
@@ -63,7 +65,7 @@ export function ArcadePixelPartyStats({ stats }: { stats: NonNullable<NonNullSta
<BasicStat title="Power-ups Collected: " value={formatNumber(stats.pixel_party?.power_ups_collected || 0)} /> <BasicStat title="Power-ups Collected: " value={formatNumber(stats.pixel_party?.power_ups_collected || 0)} />
</div> </div>
</div> </div>
<PixelPartyStatsTable stats={stats.pixel_party} /> <ArcadePixelPartyStatsTable stats={stats.pixel_party} />
</> </>
) )
} }

View File

@@ -1,23 +1,128 @@
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { formatNumber } from "@/lib/formatters" import { formatNumber } from "@/lib/formatters"
import { getArcadeMostPlayedPixelPartyMode, getArcadePixelPartyModeName, getArcadePixelPartyModeStats } from "@/lib/hypixel/arcade/general" import {
getArcadeMostPlayedPixelPartyMode,
getArcadePixelPartyModeName,
getArcadePixelPartyModeStats,
getArcadeZombiesBestMode,
getArcadeZombiesMode,
getArcadeZombiesModeStats,
getArcadeZombiesType,
getArcadeZombiesTypeStats
} from "@/lib/hypixel/arcade/general"
import { NonNullStats } from "@/lib/schema/player" import { NonNullStats } from "@/lib/schema/player"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
export function PixelPartyStatsTable({ stats }: { stats: NonNullable<NonNullStats["Arcade"]>["pixel_party"] }) { export function ArcadeZombieTypesTable({ stats }: { stats: NonNullable<NonNullStats["Arcade"]> }) {
return ( return (
<Table> <Table>
<PixelPartyStatsTableHeader /> <ArcadeZombieTypesTableHeader />
<ArcadeZombieTypes stats={stats} />
</Table>
)
}
function ArcadeZombieTypes({ stats }: { stats: NonNullable<NonNullStats["Arcade"]> }) {
const wins = getArcadeZombiesTypeStats(stats)
return (
<TableBody> <TableBody>
<PixelPartyTableStat modeId="normal" stats={stats} /> {wins.map((w, i) => {
<PixelPartyTableStat modeId="hyper" stats={stats} /> const { id, wins } = w
<PixelPartyTableStat modeId="all_modes" stats={stats} /> const type = getArcadeZombiesType(id)
return (
<TableRow key={i}>
<TableCell className={cn(type.color && `text-mc-${type.color}`)}>{type.name}</TableCell>
<TableCell>{formatNumber(wins)}</TableCell>
</TableRow>
)
})}
</TableBody>
)
}
function ArcadeZombieTypesTableHeader() {
const headerElements = [
"Zombies",
"Kills"
]
return (
<TableHeader>
<TableRow>
{headerElements.map((v, i) => <TableHead key={i} className="font-bold">{v}</TableHead>)}
</TableRow>
</TableHeader>
)
}
export function ArcadeZombieStatsTable({ stats }: { stats: NonNullable<NonNullStats["Arcade"]> }) {
return (
<Table>
<ArcadeZombiesTableHeader />
<TableBody>
<ArcadeZombiesTableStat modeId="deadend" stats={stats} />
<ArcadeZombiesTableStat modeId="badblood" stats={stats} />
<ArcadeZombiesTableStat modeId="alienarcadium" stats={stats} />
</TableBody> </TableBody>
</Table> </Table>
) )
} }
function PixelPartyTableStat( function ArcadeZombiesTableStat(
{ modeId, stats }: { modeId: Parameters<typeof getArcadeZombiesModeStats>[0], stats: NonNullable<NonNullStats["Arcade"]> }
) {
const mode = getArcadeZombiesMode(modeId)
const modeStats = getArcadeZombiesModeStats(modeId, stats)
const isMostPlayed = getArcadeZombiesBestMode(stats) === modeId
return (
<TableRow className={cn(isMostPlayed && "text-mc-light-purple")}>
<TableCell className={cn(`text-mc-${mode.color}`)}>{mode.name}</TableCell>
{modeStats.map((v, i) => {
return <TableCell key={i}>{formatNumber(v)}</TableCell>
})}
</TableRow>
)
}
function ArcadeZombiesTableHeader() {
const headerElements = [
"Map",
"Downs",
"Revives",
"Doors Opened",
"Windows Repaired",
"Zombies Killed",
"Deaths",
"Best Round",
"Wins"
]
return (
<TableHeader>
<TableRow>
{headerElements.map((v, i) => <TableHead key={i} className="font-bold">{v}</TableHead>)}
</TableRow>
</TableHeader>
)
}
export function ArcadePixelPartyStatsTable({ stats }: { stats: NonNullable<NonNullStats["Arcade"]>["pixel_party"] }) {
return (
<Table>
<ArcadePixelPartyStatsTableHeader />
<TableBody>
<ArcadePixelPartyTableStat modeId="normal" stats={stats} />
<ArcadePixelPartyTableStat modeId="hyper" stats={stats} />
<ArcadePixelPartyTableStat modeId="all_modes" stats={stats} />
</TableBody>
</Table>
)
}
function ArcadePixelPartyTableStat(
{ modeId, stats }: { modeId: Parameters<typeof getArcadePixelPartyModeStats>[0], stats: NonNullable<NonNullStats["Arcade"]>["pixel_party"] } { modeId, stats }: { modeId: Parameters<typeof getArcadePixelPartyModeStats>[0], stats: NonNullable<NonNullStats["Arcade"]>["pixel_party"] }
) { ) {
const modeName = getArcadePixelPartyModeName(modeId) const modeName = getArcadePixelPartyModeName(modeId)
@@ -35,7 +140,7 @@ function PixelPartyTableStat(
) )
} }
function PixelPartyStatsTableHeader() { function ArcadePixelPartyStatsTableHeader() {
const headerElements = [ const headerElements = [
"Mode", "Mode",
"Wins", "Wins",

View File

@@ -26,30 +26,30 @@ export const WINS = [
export const ZOMBIESMODES = [ export const ZOMBIESMODES = [
{ id: "deadend", name: "Dead End", color: "gold" }, { id: "deadend", name: "Dead End", color: "gold" },
{ id: "badblood", name: "Bad Blood", color: "red" }, { id: "badblood", name: "Bad Blood", color: "red" },
{ id: "alienarcadium", name: "Alien Arcadium", color: "pink" } { id: "alienarcadium", name: "Alien Arcadium", color: "light-purple" }
] as const ] as const
export const ZOMBIESTYPES = [ export const ZOMBIESTYPES = [
{ id: "basic", name: "Basic" }, { id: "basic", name: "Basic", color: null },
{ id: "blaze", name: "Blaze" }, { id: "blaze", name: "Blaze", color: null },
{ id: "empowered", name: "Empowered" }, { id: "empowered", name: "Empowered", color: null },
{ id: "ender", name: "Ender" }, { id: "ender", name: "Ender", color: null },
{ id: "endermite", name: "Endermite" }, { id: "endermite", name: "Endermite", color: null },
{ id: "fire", name: "Fire" }, { id: "fire", name: "Fire", color: null },
{ id: "guardian", name: "Guardian" }, { id: "guardian", name: "Guardian", color: null },
{ id: "magma", name: "Magma" }, { id: "magma", name: "Magma", color: null },
{ id: "magma_cube", name: "Magma Cube" }, { id: "magma_cube", name: "Magma Cube", color: null },
{ id: "pig_zombie", name: "Pig Zombie" }, { id: "pig_zombie", name: "Pig Zombie", color: null },
{ id: "skelefish", name: "Skelefish" }, { id: "skelefish", name: "Skelefish", color: null },
{ id: "tnt_baby", name: "TNT Baby" }, { id: "tnt_baby", name: "TNT Baby", color: null },
{ id: "tnt", name: "Bombie", color: "gold" }, { id: "tnt", name: "Bombie", color: "gold" },
{ id: "inferno", name: "Inferno", color: "gold" }, { id: "inferno", name: "Inferno", color: "gold" },
{ id: "broodmother", name: "Broodmother", color: "gold" }, { id: "broodmother", name: "Broodmother", color: "gold" },
{ id: "king_slime", name: "King Slime", color: "red" }, { id: "king_slime", name: "King Slime", color: "red" },
{ id: "wither", name: "Wither", color: "red" }, { id: "wither", name: "Wither", color: "red" },
{ id: "herobrine", name: "Herobrine", color: "red" }, { id: "herobrine", name: "Herobrine", color: "red" },
{ id: "mega_blob", name: "Mega Blob", color: "pink" }, { id: "mega_blob", name: "Mega Blob", color: "light-purple" },
{ id: "mega_magma", name: "Mega Magma", color: "pink" }, { id: "mega_magma", name: "Mega Magma", color: "light-purple" },
{ id: "world_ender", name: "World Ender", color: "pink" } { id: "world_ender", name: "World Ender", color: "light-purple" }
] as const ] as const
export const PIXELPARTYMODES = [ export const PIXELPARTYMODES = [
{ id: "normal", name: "Normal" }, { id: "normal", name: "Normal" },

View File

@@ -1,7 +1,51 @@
import { PIXELPARTYMODES, WINS } from "@/data/hypixel/arcade" import { PIXELPARTYMODES, WINS, ZOMBIESMODES, ZOMBIESTYPES } from "@/data/hypixel/arcade"
import { NonNullStats } from "@/lib/schema/player" import { NonNullStats } from "@/lib/schema/player"
import { devide } from "../general" import { devide } from "../general"
export function getArcadeZombiesType(typeId: typeof ZOMBIESTYPES[number]["id"]) {
return ZOMBIESTYPES.find(t => t.id === typeId)!
}
export function getArcadeZombiesTypeStats(stats: NonNullable<NonNullStats["Arcade"]>) {
const nums: { id: typeof ZOMBIESTYPES[number]["id"], wins: number }[] = []
for (const type of ZOMBIESTYPES) {
nums.push({ id: type.id, wins: stats[`${type.id}_zombie_kills_zombies`] })
}
return nums
}
export function getArcadeZombiesMode(modeId: typeof ZOMBIESMODES[number]["id"]) {
return ZOMBIESMODES.find(m => m.id === modeId)!
}
export function getArcadeZombiesBestMode(stats: NonNullable<NonNullStats["Arcade"]>) {
const modes = ZOMBIESMODES.map(mode => ({
modeId: mode.id,
bestRound: stats[`best_round_zombies_${mode.id}`]
}))
if (modes.map(m => m.bestRound).reduce((a, b) => a + b) === 0) return null
const bestMode = modes.reduce((max, current) => current.bestRound > max.bestRound ? current : max)
return bestMode.modeId
}
export function getArcadeZombiesModeStats(modeId: typeof ZOMBIESMODES[number]["id"], stats: NonNullable<NonNullStats["Arcade"]>) {
return [
stats[`times_knocked_down_zombies_${modeId}`],
stats[`players_revived_zombies_${modeId}`],
stats[`doors_opened_zombies_${modeId}`],
stats[`windows_repaired_zombies_${modeId}`],
stats[`zombie_kills_zombies_${modeId}`],
stats[`deaths_zombies_${modeId}`],
stats[`best_round_zombies_${modeId}`],
stats[`wins_zombies_${modeId}`]
]
}
export function getArcadeMostPlayedPixelPartyMode(stats: NonNullable<NonNullStats["Arcade"]>["pixel_party"]) { export function getArcadeMostPlayedPixelPartyMode(stats: NonNullable<NonNullStats["Arcade"]>["pixel_party"]) {
if (!stats) return null if (!stats) return null
const played = [ const played = [

View File

@@ -912,6 +912,67 @@ function arcadeModeWins() {
return Object.fromEntries(entries) as Record<`${typeof ids[number]}`, z.ZodDefault<z.ZodNumber>> return Object.fromEntries(entries) as Record<`${typeof ids[number]}`, z.ZodDefault<z.ZodNumber>>
} }
function arcadeZombiesModeStats() {
const ids = [
"deadend",
"badblood",
"alienarcadium"
] as const
const stats = [
"times_knocked_down_zombies",
"players_revived_zombies",
"doors_opened_zombies",
"windows_repaired_zombies",
"zombie_kills_zombies",
"deaths_zombies",
"best_round_zombies",
"wins_zombies"
] as const
const entries = new Map<string, z.ZodDefault<z.ZodNumber>>()
for (const id of ids) {
for (const stat of stats) {
entries.set(`${stat}_${id}`, z.number().default(0))
}
}
return Object.fromEntries(entries) as Record<`${typeof stats[number]}_${typeof ids[number]}`, z.ZodDefault<z.ZodNumber>>
}
function arcadeZombiesTypeStats() {
const ids = [
"basic",
"blaze",
"empowered",
"ender",
"endermite",
"fire",
"guardian",
"magma",
"magma_cube",
"pig_zombie",
"skelefish",
"tnt_baby",
"tnt",
"inferno",
"broodmother",
"king_slime",
"wither",
"herobrine",
"mega_blob",
"mega_magma",
"world_ender"
] as const
const entries = new Map<string, z.ZodDefault<z.ZodNumber>>()
for (const id of ids) {
entries.set(`${id}_zombie_kills_zombies`, z.number().default(0))
}
return Object.fromEntries(entries) as Record<`${typeof ids[number]}_zombie_kills_zombies`, z.ZodDefault<z.ZodNumber>>
}
export const arcadeStatsSchema = z.object({ export const arcadeStatsSchema = z.object({
miniwalls_activeKit: z.string().optional(), miniwalls_activeKit: z.string().optional(),
wither_kills_mini_walls: z.number().default(0), wither_kills_mini_walls: z.number().default(0),
@@ -949,5 +1010,7 @@ export const arcadeStatsSchema = z.object({
dropper: z.object({ dropper: z.object({
wins: z.number().default(0) wins: z.number().default(0)
}).optional(), }).optional(),
...arcadeModeWins() ...arcadeModeWins(),
...arcadeZombiesModeStats(),
...arcadeZombiesTypeStats()
}) })