diff --git a/apps/discord-bot/src/commands/duels/duels.profile.tsx b/apps/discord-bot/src/commands/duels/duels.profile.tsx index d45cfdd5a..ec8f31f80 100644 --- a/apps/discord-bot/src/commands/duels/duels.profile.tsx +++ b/apps/discord-bot/src/commands/duels/duels.profile.tsx @@ -131,7 +131,7 @@ export const DuelsProfile = ({ duels[mode.api].titleFormatted }\n${formatProgression({ t, - label: t("stats.progression.win"), + label: t(mode.api === "arena" ? "stats.progression.kill" : "stats.progression.win"), progression: duels[mode.api].progression, currentLevel: duels[mode.api].titleLevelFormatted, nextLevel: duels[mode.api].nextTitleLevelFormatted, diff --git a/apps/discord-bot/src/commands/duels/tables/titles.table.tsx b/apps/discord-bot/src/commands/duels/tables/titles.table.tsx index 25319fcd7..07dcf82c5 100644 --- a/apps/discord-bot/src/commands/duels/tables/titles.table.tsx +++ b/apps/discord-bot/src/commands/duels/tables/titles.table.tsx @@ -6,8 +6,7 @@ * https://github.com/Statsify/statsify/blob/main/LICENSE */ -import { arrayGroup } from "@statsify/util"; -import type { Duels } from "@statsify/schemas"; +import { type Duels, type TitleRequirement, getTitleAndProgression } from "@statsify/schemas"; import type { DuelsModeIcons } from "../duels.command.js"; import type { Image } from "skia-canvas"; import type { LocalizeFunction } from "@statsify/discord"; @@ -18,64 +17,116 @@ interface TitlesTableProps { modeIcons: DuelsModeIcons; } -function ModeTitle({ icon, title, wins, t }: { icon: Image; title: string; wins: number; t: LocalizeFunction }) { +interface TitleMode { + icon: Image; + mode: string; + score: number; + titleRequirement: TitleRequirement; +} + +function ModeTitle({ + icon, + title, + score, + t, +}: { + icon: Image; + title: string; + score: number; + t: LocalizeFunction; +}) { return ( - - {title} - + {title}
- {t(wins)} + {t(score)} ); } export const TitlesTable = ({ duels, t, modeIcons }: TitlesTableProps) => { + const getBaseTitle = ( + score: number, + mode: string, + titleRequirement: TitleRequirement + ) => + getTitleAndProgression({ + score, + mode, + data: {}, + titleRequirement, + }).titleFormatted; + + const titleSortScore = (score: number, titleRequirement: TitleRequirement) => { + if (titleRequirement === "half") return score * 2; + if (titleRequirement === "overall") return score / 2; + + return score; + }; + const games = [ - { icon: modeIcons.bedwars, title: duels.bedwars.titleFormatted, wins: duels.bedwars.overall.wins }, - { icon: modeIcons.blitzsg, title: duels.blitzsg.titleFormatted, wins: duels.blitzsg.wins }, - { icon: modeIcons.bow, title: duels.bow.titleFormatted, wins: duels.bow.wins }, - { icon: modeIcons.spleef, title: duels.spleef.titleFormatted, wins: duels.spleef.overallWins }, - { icon: modeIcons.boxing, title: duels.boxing.titleFormatted, wins: duels.boxing.wins }, - { icon: modeIcons.bridge, title: duels.bridge.titleFormatted, wins: duels.bridge.overall.wins }, - { icon: modeIcons.classic, title: duels.classic.titleFormatted, wins: duels.classic.overall.wins }, - { icon: modeIcons.combo, title: duels.combo.titleFormatted, wins: duels.combo.wins }, - { icon: modeIcons.megawalls, title: duels.megawalls.titleFormatted, wins: duels.megawalls.wins }, - { icon: modeIcons.nodebuff, title: duels.nodebuff.titleFormatted, wins: duels.nodebuff.wins }, - { icon: modeIcons.op, title: duels.op.titleFormatted, wins: duels.op.overall.wins }, - { icon: modeIcons.quake, title: duels.quake.titleFormatted, wins: duels.quake.wins }, - { icon: modeIcons.parkour, title: duels.parkour.titleFormatted, wins: duels.parkour.wins }, - { icon: modeIcons.skywars, title: duels.skywars.titleFormatted, wins: duels.skywars.overall.wins }, - { icon: modeIcons.sumo, title: duels.sumo.titleFormatted, wins: duels.sumo.wins }, - { icon: modeIcons.uhc, title: duels.uhc.titleFormatted, wins: duels.uhc.overall.wins }, - ]; + { icon: modeIcons.arena, mode: "Duel Arena", score: duels.arena.kills, titleRequirement: "default" }, + { icon: modeIcons.bedwars, mode: "Bed Wars", score: duels.bedwars.overall.wins, titleRequirement: "default" }, + { icon: modeIcons.blitzsg, mode: "Blitz", score: duels.blitzsg.wins, titleRequirement: "default" }, + { icon: modeIcons.bow, mode: "Bow", score: duels.bow.wins, titleRequirement: "default" }, + { icon: modeIcons.spleef, mode: "Spleef", score: duels.spleef.overallWins, titleRequirement: "default" }, + { icon: modeIcons.boxing, mode: "Boxing", score: duels.boxing.wins, titleRequirement: "half" }, + { icon: modeIcons.bridge, mode: "Bridge", score: duels.bridge.overall.wins, titleRequirement: "half" }, + { icon: modeIcons.classic, mode: "Classic", score: duels.classic.overall.wins, titleRequirement: "default" }, + { icon: modeIcons.combo, mode: "Combo", score: duels.combo.wins, titleRequirement: "default" }, + { icon: modeIcons.megawalls, mode: "Mega Walls", score: duels.megawalls.wins, titleRequirement: "half" }, + { icon: modeIcons.nodebuff, mode: "NoDebuff", score: duels.nodebuff.wins, titleRequirement: "half" }, + { icon: modeIcons.op, mode: "OP", score: duels.op.overall.wins, titleRequirement: "default" }, + { icon: modeIcons.quake, mode: "Quakecraft", score: duels.quake.wins, titleRequirement: "default" }, + { icon: modeIcons.parkour, mode: "Parkour", score: duels.parkour.wins, titleRequirement: "half" }, + { icon: modeIcons.skywars, mode: "SkyWars", score: duels.skywars.overall.wins, titleRequirement: "default" }, + { icon: modeIcons.sumo, mode: "Sumo", score: duels.sumo.wins, titleRequirement: "default" }, + { icon: modeIcons.uhc, mode: "UHC", score: duels.uhc.overall.wins, titleRequirement: "default" }, + ] satisfies TitleMode[]; - games.sort((a, b) => b.wins - a.wins); - const groups = arrayGroup(games, games.length / 2); + games.sort( + (a, b) => + titleSortScore(b.score, b.titleRequirement) - + titleSortScore(a.score, a.titleRequirement) + ); + + const rows = games.reduce((acc, game, index) => { + const rowIndex = Math.floor(index / 2); + + acc[rowIndex] ??= []; + acc[rowIndex].push(game); + + return acc; + }, []); + + const overallTitle = getBaseTitle(duels.overall.wins, "", "overall"); return (
-
- {groups.map((group) => ( -
- {group.map(({ icon, title, wins }) => ( - + +
+ {rows.map((row) => ( +
+ {[...row].reverse().map(({ icon, mode, score, titleRequirement }) => ( +
+ +
))}
))}
); -}; +}; \ No newline at end of file diff --git a/packages/schemas/src/player/gamemodes/duels/index.ts b/packages/schemas/src/player/gamemodes/duels/index.ts index 7a2d60cc7..90e7f3276 100644 --- a/packages/schemas/src/player/gamemodes/duels/index.ts +++ b/packages/schemas/src/player/gamemodes/duels/index.ts @@ -33,7 +33,7 @@ export const DUELS_MODES = new GameModes([ { api: "titles" }, ], }, - { api: "arena", hypixel: "DUELS_DUEL_ARENA" }, + { api: "arena", hypixel: "DUELS_DUEL_ARENA", formatted: "Duel Arena" }, { api: "bedwars", formatted: "BedWars", @@ -122,7 +122,7 @@ export class Duels { @Field({ leaderboard: { extraDisplay: "this.overall.titleFormatted" } }) public overall: SingleBowPVPDuelsGameMode; - @Field({ leaderboard: { extraDisplay: "this.arena.titleFormatted" } }) + @Field({ leaderboard: { name: "Duel Arena", extraDisplay: "this.arena.titleFormatted" } }) public arena: ArenaDuels; @Field({ @@ -236,3 +236,4 @@ export class Duels { } export * from "./mode.js"; +export * from "./util.js"; diff --git a/packages/schemas/src/player/gamemodes/duels/mode.ts b/packages/schemas/src/player/gamemodes/duels/mode.ts index 57cd014a0..d56807dc5 100644 --- a/packages/schemas/src/player/gamemodes/duels/mode.ts +++ b/packages/schemas/src/player/gamemodes/duels/mode.ts @@ -237,11 +237,17 @@ export class SinglePVPDuelsGameMode extends PVPBaseDuelsGameMode { @Field() public progression: Progression; - public constructor(data: APIData, title: string, mode: string, titleRequirement: TitleRequirement) { + public constructor( + data: APIData, + title: string, + mode: string, + titleRequirement: TitleRequirement, + titleScore?: number + ) { super(data, mode); const { titleFormatted, titleLevelFormatted, nextTitleLevelFormatted, progression } = getTitleAndProgression({ - score: this.wins, + score: titleScore ?? this.wins, mode: title, data, titleRequirement, @@ -295,12 +301,12 @@ export class SingleDuelsGameMode extends BaseDuelsGameMode { } } -export class ArenaDuels extends SingleDuelsGameMode { +export class ArenaDuels extends SinglePVPDuelsGameMode { @Field() public shotsFired: number; public constructor(data: APIData) { - super(data, "Arena", "duel_arena", "default"); + super(data, "Duel Arena", "duel_arena", "default", data.duel_arena_kills); this.shotsFired = data[`duel_arena_bow_shots`]; } } diff --git a/packages/schemas/src/player/gamemodes/duels/util.ts b/packages/schemas/src/player/gamemodes/duels/util.ts index 1910a5600..76376e011 100644 --- a/packages/schemas/src/player/gamemodes/duels/util.ts +++ b/packages/schemas/src/player/gamemodes/duels/util.ts @@ -269,4 +269,3 @@ const SCHEME_MAP: Record = { variety_values: gradientColorScheme(["§b", "§f", "§f", "§f", "§b"]), og_fade: gradientColorScheme(["§6", "§e", "§f", "§7", "§8"]), }; -