Skip to content

Commit 0cec412

Browse files
authored
feat: add disasters stats to /arcade (#813)
* feat: add disasters stats to /arcade * chore: update assets * fix: disasters leaderboard metadata * chore: fix fmt * feat: add overall survivals and deaths * fix: lint
1 parent 08063f7 commit 0cec412

File tree

10 files changed

+616
-26
lines changed

10 files changed

+616
-26
lines changed

apps/discord-bot/src/commands/arcade/arcade.profile.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
BlockingDeadTable,
1212
BountyHuntersTable,
1313
CreeperAttackTable,
14+
DisastersTable,
1415
DragonWarsTable,
1516
DropperTable,
1617
EnderSpleefTable,
@@ -72,6 +73,10 @@ export const ArcadeProfile = ({
7273
table = <CreeperAttackTable stats={arcade[api]} t={t} />;
7374
break;
7475

76+
case "disasters":
77+
table = <DisastersTable stats={arcade[api]} t={t} submode={mode.submode} />;
78+
break;
79+
7580
case "dragonWars":
7681
table = <DragonWarsTable stats={arcade[api]} t={t} />;
7782
break;
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/**
2+
* Copyright (c) Statsify
3+
*
4+
* This source code is licensed under the GNU GPL v3 license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
* https://github.com/Statsify/statsify/blob/main/LICENSE
7+
*/
8+
9+
import {
10+
ArcadeModes,
11+
DisasterSurvivals,
12+
Disasters,
13+
DisastersDeaths,
14+
SubModeForMode,
15+
} from "@statsify/schemas";
16+
import { LocalizeFunction } from "@statsify/discord";
17+
import { Table } from "#components";
18+
import { arrayGroup, formatTime } from "@statsify/util";
19+
20+
interface DisastersTableProps {
21+
stats: Disasters;
22+
submode: SubModeForMode<ArcadeModes, "disasters">;
23+
t: LocalizeFunction;
24+
}
25+
26+
export const DisastersTable = ({ stats, t, submode }: DisastersTableProps) => {
27+
if (submode.api === "survivals")
28+
return <DisastersSurvivalsTable stats={stats} t={t} />;
29+
if (submode.api === "deaths")
30+
return <DisastersDeathsTable stats={stats} t={t} />;
31+
32+
return (
33+
<Table.table>
34+
<Table.tr>
35+
<Table.td title={t("stats.wins")} value={t(stats.wins)} color="§a" />
36+
<Table.td
37+
title={t("stats.losses")}
38+
value={t(stats.losses)}
39+
color="§c"
40+
/>
41+
<Table.td title={t("stats.wlr")} value={t(stats.wlr)} color="§6" />
42+
</Table.tr>
43+
<Table.tr>
44+
<Table.td
45+
title={t("stats.gamesPlayed")}
46+
value={t(stats.gamesPlayed)}
47+
color="§e"
48+
/>
49+
<Table.td
50+
title={t("stats.playtime")}
51+
value={formatTime(stats.playtime)}
52+
color="§b"
53+
/>
54+
<Table.td
55+
title={t("stats.survivals")}
56+
value={t(stats.survivals.overall)}
57+
color="§d"
58+
/>
59+
</Table.tr>
60+
</Table.table>
61+
);
62+
};
63+
64+
const DisasterSurvivalsLabels: Record<keyof DisasterSurvivals, string> = {
65+
overall: "§l§fOVERALL",
66+
acidRain: "§l§aACID RAIN",
67+
anvilRain: "§l§7ANVIL RAIN §7[S]",
68+
batSwarm: "§l§8BAT SWARM §7[S]",
69+
blackout: "§l§5BLACKOUT §7[S]",
70+
disco: "§l§dDISCO §7[S]",
71+
dragons: "§l§5DRAGONS",
72+
flood: "§l§9FLOOD",
73+
fragileGround: "§l§7FRAGILE GROUND",
74+
grounded: "§l§2GROUNDED §7[S]",
75+
halfHealth: "§l§aHALF HEALTH §7[S]",
76+
hotPotato: "§l§6HOT POTATO §7[S]",
77+
hypixelSays: "§l§6HYPIXEL SAYS §7[S]",
78+
lightning: "§l§eLIGHTNING",
79+
meteorShower: "§l§cMETEOR SHOWER",
80+
nuke: "§l§cNUKE §7[S]",
81+
purge: "§l§aPURGE §7[S]",
82+
redLightGreenLight: "§l§cRED LIGHT§r§f, §l§aGREEN LIGHT §7[S]",
83+
sinkhole: "§l§6SINKHOLE",
84+
solarFlare: "§l§6SOLAR FLARE",
85+
stampede: "§l§6STAMPEDE",
86+
swappage: "§l§dSWAPPAGE §7[S]",
87+
theFloorIsLava: "§l§cTHE FLOOR IS LAVA",
88+
tntRain: "§l§4TNT RAIN",
89+
tornado: "§l§7TORNADO",
90+
werewolf: "§l§cWEREWOLF §7[S]",
91+
withers: "§l§3WITHERS",
92+
zombieApocalypse: "§l§2ZOMBIE APOCALYPSE",
93+
};
94+
95+
const DisastersSurvivalsTable = ({
96+
stats,
97+
t,
98+
}: Omit<DisastersTableProps, "submode">) => {
99+
const entries = Object.entries(DisasterSurvivalsLabels) as [
100+
keyof DisasterSurvivals,
101+
string
102+
][];
103+
104+
const rows = arrayGroup(
105+
entries
106+
.map(([key, label]) => ({ label, survivals: stats.survivals[key] }))
107+
.toSorted((a, b) => b.survivals - a.survivals),
108+
2
109+
);
110+
111+
return (
112+
<>
113+
{rows.map((row) => (
114+
<Table.tr>
115+
{row.map(({ label, survivals }) => (
116+
<Table.td
117+
title={label}
118+
value={t(survivals)}
119+
size="inline"
120+
color="§f"
121+
/>
122+
))}
123+
</Table.tr>
124+
))}
125+
</>
126+
);
127+
};
128+
129+
const DisastersDeathsLabels: Record<keyof DisastersDeaths, string> = {
130+
overall: "§l§fOVERALL",
131+
acidRain: "§l§aACID RAIN",
132+
anvilRain: "§l§7ANVIL RAIN §7[S]",
133+
batSwarm: "§l§8BAT SWARM §7[S]",
134+
disco: "§l§dDISCO §7[S]",
135+
dragons: "§l§5DRAGONS",
136+
fall: "§l§eFALL",
137+
flood: "§l§9FLOOD",
138+
hotPotato: "§l§6HOT POTATO §7[S]",
139+
hypixelSays: "§l§6HYPIXEL SAYS §7[S]",
140+
lightning: "§l§eLIGHTNING",
141+
nuke: "§l§cNUKE §7[S]",
142+
redLightGreenLight: "§l§cRED LIGHT§r§f, §l§aGREEN LIGHT §7[S]",
143+
sinkhole: "§l§6SINKHOLE",
144+
solarFlare: "§l§6SOLAR FLARE",
145+
stampede: "§l§6STAMPEDE",
146+
theFloorIsLava: "§l§cTHE FLOOR IS LAVA",
147+
tntRain: "§l§4TNT RAIN",
148+
tornado: "§l§7TORNADO",
149+
unknown: "§l§4UNKNOWN",
150+
void: "§l§5VOID",
151+
werewolf: "§l§cWEREWOLF §7[S]",
152+
withers: "§l§3WITHERS",
153+
zombieApocalypse: "§l§2ZOMBIE APOCALYPSE",
154+
};
155+
156+
const DisastersDeathsTable = ({
157+
stats,
158+
t,
159+
}: Omit<DisastersTableProps, "submode">) => {
160+
const entries = Object.entries(DisastersDeathsLabels) as [
161+
keyof DisastersDeaths,
162+
string
163+
][];
164+
165+
const rows = arrayGroup(
166+
entries
167+
.map(([key, label]) => ({ label, deaths: stats.deaths[key] }))
168+
.toSorted((a, b) => b.deaths - a.deaths),
169+
2
170+
);
171+
172+
return (
173+
<>
174+
{rows.map((row) => (
175+
<Table.tr>
176+
{row.map(({ label, deaths }) => (
177+
<Table.td
178+
title={label}
179+
value={t(deaths)}
180+
size="inline"
181+
color="§f"
182+
/>
183+
))}
184+
</Table.tr>
185+
))}
186+
</>
187+
);
188+
};

apps/discord-bot/src/commands/arcade/modes/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
export * from "./blocking-dead.js";
1010
export * from "./bounty-hunters.js";
1111
export * from "./creeper-attack.js";
12+
export * from "./disasters.js";
1213
export * from "./dragon-wars.js";
1314
export * from "./dropper.js";
1415
export * from "./ender-spleef.js";

apps/discord-bot/src/commands/arcade/modes/overall-arcade.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@ interface OverallArcadeTableProps {
1717
}
1818

1919
export const OverallArcadeTable = ({ stats, t }: OverallArcadeTableProps) => {
20-
const rowSize = 3;
21-
2220
const games: [string, number][] = [
2321
["Blocking Dead", stats.blockingDead.wins],
2422
["Bounty Hunters", stats.bountyHunters.wins],
23+
["Disasters", stats.disasters.wins],
2524
["Dragon Wars", stats.dragonWars.wins],
2625
["Dropper", stats.dropper.wins],
2726
["Ender Spleef", stats.enderSpleef.wins],
@@ -42,16 +41,20 @@ export const OverallArcadeTable = ({ stats, t }: OverallArcadeTableProps) => {
4241

4342
games.sort((a, b) => b[1] - a[1]);
4443

45-
const rows = arrayGroup(games, rowSize);
44+
const rows = arrayGroup(games, 4);
4645

47-
const colors = [d", b", "§a", "§e", "§6", "§c"];
46+
const colors = ["§b", "§a", "§e", "§6", "§c"];
4847

4948
return (
5049
<Table.table>
5150
{rows.map((row, index) => (
5251
<Table.tr>
53-
{row.map((game) => (
54-
<Table.td title={game[0]} value={t(game[1])} color={colors[index]} />
52+
{row.map(([game, wins]) => (
53+
<Table.td
54+
title={game}
55+
value={t(wins)}
56+
color={colors[index]}
57+
/>
5558
))}
5659
</Table.tr>
5760
))}

apps/site/app/(home)/previews/arcade.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export function ArcadePreview({ className }: { className?: string }) {
3535
const games: [string, number][] = [
3636
["Blocking Dead", arcade.blockingDead.wins],
3737
["Bounty Hunters", arcade.bountyHunters.wins],
38+
["Disasters", arcade.disasters.wins],
3839
["Dragon Wars", arcade.dragonWars.wins],
3940
["Dropper", arcade.dropper.wins],
4041
["Ender Spleef", arcade.enderSpleef.wins],
@@ -55,8 +56,8 @@ export function ArcadePreview({ className }: { className?: string }) {
5556

5657
games.sort((a, b) => b[1] - a[1]);
5758

58-
const rows = arrayGroup(games, 3);
59-
const colors = ["text-mc-pink", "text-mc-aqua", "text-mc-green", "text-mc-yellow", "text-mc-gold", "text-mc-red"];
59+
const rows = arrayGroup(games, 4);
60+
const colors = ["text-mc-aqua", "text-mc-green", "text-mc-yellow", "text-mc-gold", "text-mc-red"];
6061

6162
return (
6263
<div className={cn("grid grid-cols-3 gap-2 whitespace-nowrap", className)}>

assets/private

locales/en-US/default.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@
761761
"superVotes": "Super Votes",
762762
"superluck": "Superluck",
763763
"support": "Support",
764+
"survivals": "Survivals",
764765
"survivorWins": "Survivor Wins",
765766
"tags": "Tags",
766767
"tauntsUsed": "Taunts Used",
@@ -862,4 +863,4 @@
862863
"successfulUnverification": "Successfully unverified your account!",
863864
"successfulVerification": "You are now verified to **{{displayName}}**"
864865
}
865-
}
866+
}

locales/en-US/emojis.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@
163163
"blockingDead": "<:blockingDead:1336087005595041852>",
164164
"bountyHunters": "<:bountyHunters:1336087007038017546>",
165165
"creeperAttack": "<:creeperAttack:1336087008547700857>",
166+
"disasters": "<:disasters:1454506073317839119>",
166167
"dragonWars": "<:dragonWars:1336087010208780421>",
167168
"dropper": "<:dropper:1336087011920056444>",
168169
"enderSpleef": "<:enderSpleef:1336087013258039468>",
@@ -236,4 +237,4 @@
236237
"minecraft": "<:minecraft22:1144296782281584650>",
237238
"check": "<:check22:1144296280349212822>"
238239
}
239-
}
240+
}

packages/schemas/src/player/gamemodes/arcade/index.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
BlockingDead,
1111
BountyHunters,
1212
CreeperAttack,
13+
Disasters,
1314
DragonWars,
1415
Dropper,
1516
EnderSpleef,
@@ -37,6 +38,15 @@ export const ARCADE_MODES = new GameModes([
3738
{ api: "blockingDead", hypixel: "DAYONE" },
3839
{ api: "bountyHunters", hypixel: "ONEINTHEQUIVER" },
3940
{ api: "creeperAttack", hypixel: "DEFENDER" },
41+
{
42+
api: "disasters",
43+
hypixel: "DISASTERS",
44+
submodes: [
45+
{ api: "overall" },
46+
{ api: "survivals" },
47+
{ api: "deaths" },
48+
],
49+
},
4050
{ api: "dragonWars", hypixel: "DRAGONWARS2" },
4151
{
4252
api: "dropper",
@@ -103,6 +113,9 @@ export class Arcade {
103113
@Field()
104114
public creeperAttack: CreeperAttack;
105115

116+
@Field()
117+
public disasters: Disasters;
118+
106119
@Field()
107120
public dragonWars: DragonWars;
108121

@@ -158,6 +171,7 @@ export class Arcade {
158171
this.blockingDead = new BlockingDead(data);
159172
this.bountyHunters = new BountyHunters(data);
160173
this.creeperAttack = new CreeperAttack(data);
174+
this.disasters = new Disasters(data?.disasters?.stats);
161175
this.dragonWars = new DragonWars(data, ap);
162176
this.dropper = new Dropper(data?.dropper);
163177
this.enderSpleef = new EnderSpleef(data);
@@ -178,6 +192,7 @@ export class Arcade {
178192
this.wins = add(
179193
this.blockingDead.wins,
180194
this.bountyHunters.wins,
195+
this.disasters.wins,
181196
this.dragonWars.wins,
182197
this.dropper.wins,
183198
this.enderSpleef.wins,

0 commit comments

Comments
 (0)