Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/discord-bot/src/commands/duels/duels.profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export const DuelsProfile = <T extends ProfileTime>({
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,
Expand Down
129 changes: 90 additions & 39 deletions apps/discord-bot/src/commands/duels/tables/titles.table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -18,64 +17,116 @@
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 (
<box width="100%" padding={{ left: 8, right: 8, top: 4, bottom: 4 }}>
<img image={icon} width={32} height={32} />
<text margin={{ left: 8 }}>
{title}
</text>
<text margin={{ left: 8 }}>{title}</text>
<div width="remaining" margin={{ left: 4, right: 4 }} />
<text>{t(wins)}</text>
<text>{t(score)}</text>
</box>
);
}

export const TitlesTable = ({ duels, t, modeIcons }: TitlesTableProps) => {
const getBaseTitle = (
score: number,
mode: string,
titleRequirement: TitleRequirement
) =>

Check failure on line 53 in apps/discord-bot/src/commands/duels/tables/titles.table.tsx

View workflow job for this annotation

GitHub Actions / CI

Move arrow function 'getBaseTitle' to the outer scope
getTitleAndProgression({
score,
mode,
data: {},
titleRequirement,
}).titleFormatted;

const titleSortScore = (score: number, titleRequirement: TitleRequirement) => {

Check failure on line 61 in apps/discord-bot/src/commands/duels/tables/titles.table.tsx

View workflow job for this annotation

GitHub Actions / CI

Move arrow function 'titleSortScore' to the outer scope
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<TitleMode[][]>((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 (
<div width="100%" direction="column">
<ModeTitle
icon={modeIcons.overall}
title={duels.overall.titleFormatted}
wins={duels.overall.wins}
title={overallTitle}
score={duels.overall.wins}
t={t}
/>
<div width="100%">
{groups.map((group) => (
<div width={`1/${groups.length}`} direction="column">
{group.map(({ icon, title, wins }) => (
<ModeTitle
icon={icon}
title={title}
wins={wins}
t={t}
/>

<div width="100%" direction="column">
{rows.map((row) => (
<div width="100%">
{[...row].reverse().map(({ icon, mode, score, titleRequirement }) => (

Check failure on line 117 in apps/discord-bot/src/commands/duels/tables/titles.table.tsx

View workflow job for this annotation

GitHub Actions / CI

Use `Array#toReversed()` instead of `Array#reverse()`
<div width={row.length === 1 ? "100%" : "1/2"}>
<ModeTitle
icon={icon}
title={getBaseTitle(score, mode, titleRequirement)}
score={score}
t={t}
/>
</div>
))}
</div>
))}
</div>
</div>
);
};
};

Check failure on line 132 in apps/discord-bot/src/commands/duels/tables/titles.table.tsx

View workflow job for this annotation

GitHub Actions / CI

Newline required at end of file but not found
5 changes: 3 additions & 2 deletions packages/schemas/src/player/gamemodes/duels/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -236,3 +236,4 @@ export class Duels {
}

export * from "./mode.js";
export * from "./util.js";
14 changes: 10 additions & 4 deletions packages/schemas/src/player/gamemodes/duels/mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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`];
}
}
Expand Down
1 change: 0 additions & 1 deletion packages/schemas/src/player/gamemodes/duels/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,4 +269,3 @@ const SCHEME_MAP: Record<string, Scheme> = {
variety_values: gradientColorScheme(["§b", "§f", "§f", "§f", "§b"]),
og_fade: gradientColorScheme(["§6", "§e", "§f", "§7", "§8"]),
};

Loading