mirror of
https://github.com/zkldi/Tachi.git
synced 2026-09-28 01:48:11 +03:00
124 lines
3.7 KiB
TypeScript
124 lines
3.7 KiB
TypeScript
import { FormatGame, Game, integer, Playtype, WebhookEventClassUpdateV1 } from "tachi-common";
|
|
import { AllClassSets } from "tachi-common/js/game-classes";
|
|
import { BotConfig } from "../config";
|
|
import { client } from "../main";
|
|
import { GetUGPTStats, GetUserInfo } from "../utils/apiRequests";
|
|
import { POPN_CLASSES, SDVX_VF_CLASSES } from "../utils/constants";
|
|
import { CreateEmbed } from "../utils/embeds";
|
|
import { PrependTachiUrl } from "../utils/fetchTachi";
|
|
import logger from "../utils/logger";
|
|
import { FormatClass, GetGameChannel } from "../utils/misc";
|
|
|
|
export async function HandleClassUpdateV1(
|
|
event: WebhookEventClassUpdateV1["content"]
|
|
): Promise<integer> {
|
|
const { game, playtype } = event;
|
|
|
|
let channel;
|
|
try {
|
|
channel = GetGameChannel(client, game);
|
|
} catch (e) {
|
|
const err = e as Error;
|
|
logger.error(`ClassUpdate handler failed: ${err.message}`);
|
|
return 500;
|
|
}
|
|
|
|
if (!ShouldRenderUpdate(game, playtype, event.set, event.new)) {
|
|
return 204;
|
|
}
|
|
|
|
const userDoc = await GetUserInfo(event.userID);
|
|
|
|
// We don't want to render classes if the user is blitzing through them
|
|
// because they haven't played enough charts to "average out".
|
|
// For example, a new player playing their first 50 charts will blitz through
|
|
// atleast 10 of the volforce ranks, which will just result in channel spam.
|
|
const minimumNecessaryScores = GetMinimumScores(game, playtype, event.set);
|
|
|
|
if (minimumNecessaryScores) {
|
|
const { totalScores } = await GetUGPTStats(userDoc.id, game, playtype);
|
|
|
|
// Do not render if the user hasn't hit the score cap.
|
|
if (totalScores < minimumNecessaryScores) {
|
|
logger.info(`Not rendering class update ${event.set}: ${event.old} -> ${event.new}.`);
|
|
return 204;
|
|
}
|
|
}
|
|
|
|
const newClass = FormatClass(game, playtype, event.set, event.new);
|
|
|
|
const embed = CreateEmbed()
|
|
.setTitle(`${userDoc.username} just achieved ${newClass} in ${FormatGame(game, playtype)}!`)
|
|
.setURL(
|
|
`${BotConfig.TACHI_SERVER_LOCATION}/dashboard/users/${userDoc.username}/games/${game}/${playtype}`
|
|
)
|
|
.setThumbnail(PrependTachiUrl(`/users/${userDoc.id}/pfp`));
|
|
|
|
if (event.old !== null) {
|
|
embed.setDescription(
|
|
`(This was raised from ${FormatClass(game, playtype, event.set, event.old)}.)`
|
|
);
|
|
}
|
|
|
|
await channel.send({ embeds: [embed] });
|
|
|
|
return 200;
|
|
}
|
|
|
|
/**
|
|
* Returns Whether this class update is notable enough to be rendered or not.
|
|
*/
|
|
function ShouldRenderUpdate(
|
|
game: Game,
|
|
playtype: Playtype,
|
|
classSet: AllClassSets,
|
|
classValue: integer
|
|
) {
|
|
if (game === "sdvx" && classSet === "vfClass") {
|
|
return [
|
|
// Notifying about these vfClasses is pointless, since they're
|
|
// very easy to just blister through.
|
|
// SDVXVFClasses.SIENNA_I,
|
|
// SDVXVFClasses.COBALT_I,
|
|
// SDVXVFClasses.DANDELION_I,
|
|
// SDVXVFClasses.CYAN_I,
|
|
// SDVXVFClasses.SCARLET_I,
|
|
// SDVX_VF_CLASSES.CORAL_I,
|
|
// SDVX_VF_CLASSES.ARGENTO_I,
|
|
// SDVX_VF_CLASSES.ELDORA_I,
|
|
// SDVX_VF_CLASSES.CRIMSON_I,
|
|
SDVX_VF_CLASSES.IMPERIAL_I,
|
|
SDVX_VF_CLASSES.IMPERIAL_II,
|
|
SDVX_VF_CLASSES.IMPERIAL_III,
|
|
SDVX_VF_CLASSES.IMPERIAL_IV,
|
|
].includes(classValue);
|
|
} else if (game === "popn" && classSet === "class") {
|
|
return [
|
|
// All of the other classes in pop'n can be trivially blitzed through.
|
|
POPN_CLASSES.GOD,
|
|
];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function GetMinimumScores(game: Game, playtype: Playtype, classSet: AllClassSets): integer | null {
|
|
if (game === "chunithm") {
|
|
return 20;
|
|
} else if (game === "sdvx" && classSet === "vfClass") {
|
|
return 50;
|
|
} else if (game === "gitadora") {
|
|
return 50;
|
|
} else if (game === "jubeat") {
|
|
return 60;
|
|
} else if (game === "wacca") {
|
|
return 50;
|
|
} else if (game === "bms") {
|
|
return 20;
|
|
} else if (game === "iidx") {
|
|
return 20;
|
|
}
|
|
|
|
return null;
|
|
}
|