mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-06 13:58:05 +03:00
* [chunithm] Update to CHUNITHM VERSE * fix: change naiveRating to 50 songs * fix: unfuck duplicate charts caused by later options modifying earlier options * feat: new rating classes for verse * fix(bot): chunithm min scores is 50 * add charts to VERSE Omnimix * add search aliases for new songs * disable verse intl for now
128 lines
3.4 KiB
TypeScript
128 lines
3.4 KiB
TypeScript
import { BotConfig } from "../config";
|
|
import { client } from "../main";
|
|
import { GetUGPTStats, GetUserInfo } from "../utils/apiRequests";
|
|
import { CreateEmbed } from "../utils/embeds";
|
|
import { PrependTachiUrl } from "../utils/fetchTachi";
|
|
import logger from "../utils/logger";
|
|
import { FormatClass, GetGameChannel } from "../utils/misc";
|
|
import { FormatGame } from "tachi-common";
|
|
import type {
|
|
Classes,
|
|
GPTString,
|
|
Game,
|
|
Playtype,
|
|
WebhookEventClassUpdateV1,
|
|
integer,
|
|
} from "tachi-common";
|
|
|
|
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 !== null) {
|
|
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}/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: Classes[GPTString],
|
|
classValue: string
|
|
) {
|
|
if (game === "sdvx" && classSet === "vfClass") {
|
|
return ["IMPERIAL_I", "IMPERIAL_II", "IMPERIAL_III", "IMPERIAL_IV"].includes(classValue);
|
|
} else if (game === "popn" && classSet === "class") {
|
|
return [
|
|
// All of the other classes in pop'n can be trivially blitzed through.
|
|
"GOD",
|
|
].includes(classValue);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function GetMinimumScores(
|
|
game: Game,
|
|
playtype: Playtype,
|
|
classSet: Classes[GPTString]
|
|
): integer | null {
|
|
if (game === "chunithm" && classSet === "colour") {
|
|
return 50;
|
|
} 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;
|
|
} else if (game === "pms") {
|
|
return 20;
|
|
} else if (game === "ddr") {
|
|
return 90;
|
|
} else if (game === "maimai" && classSet === "colour") {
|
|
return 30;
|
|
} else if (game === "maimaidx" && classSet === "colour") {
|
|
return 50;
|
|
}
|
|
|
|
return null;
|
|
}
|