Files
blitzkit/src/commands/eligible.ts
T

198 lines
6.6 KiB
TypeScript
Raw Normal View History

2023-06-04 00:01:10 +00:00
import { SlashCommandBuilder } from 'discord.js';
2023-10-14 11:06:03 -05:00
import { getAccountInfo } from '../core/blitz/getAccountInfo';
2023-12-05 17:36:18 -06:00
import { tankDefinitions } from '../core/blitzkrieg/definitions/tanks';
2023-10-14 11:25:42 -05:00
import getPeriodNow from '../core/blitzkrieg/getPeriodNow';
import getTimeDaysAgo from '../core/blitzkrieg/getTimeDaysAgo';
import getStatsInPeriod from '../core/blitzstars/getStatsInPeriod';
import { tankAverages } from '../core/blitzstars/tankAverages';
2023-10-14 11:32:02 -05:00
import addUsernameChoices from '../core/discord/addUsernameChoices';
import embedNegative from '../core/discord/embedNegative';
import embedPositive from '../core/discord/embedPositive';
2023-10-14 11:36:10 -05:00
import markdownTable, { TableInput } from '../core/discord/markdownTable';
import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand';
2023-10-14 11:06:03 -05:00
import calculateWN8 from '../core/statistics/calculateWN8';
2023-10-14 11:25:42 -05:00
import sumStats from '../core/statistics/sumStats';
2023-07-11 19:54:57 +00:00
import { CommandRegistry } from '../events/interactionCreate';
import { PossiblyPromise } from '../types/possiblyPromise';
2023-06-04 00:01:10 +00:00
export type SkilledClan = 'SKLLD' | 'SMRI';
export const SKILLED_CLANS: Record<SkilledClan, string> = {
SKLLD: 'Skilled',
SMRI: 'Samurai',
};
2023-07-05 01:15:18 +00:00
export const eligibleCommand: CommandRegistry = {
2023-06-04 00:01:10 +00:00
inProduction: true,
inPublic: false,
command: new SlashCommandBuilder()
.setName('eligible')
2023-06-04 00:01:10 +00:00
.setDescription('Checks eligibility for any Skilled clan')
.addStringOption((option) =>
option
.setName('clan')
.setDescription('The clan to check')
.setChoices(
{
name: SKILLED_CLANS.SKLLD,
value: 'SKLLD' satisfies SkilledClan,
},
{ name: SKILLED_CLANS.SMRI, value: 'SMRI' satisfies SkilledClan },
)
.setRequired(true),
)
2023-06-27 02:22:28 +00:00
.addStringOption(addUsernameChoices),
2023-06-04 00:01:10 +00:00
2023-06-27 01:43:30 +00:00
async handler(interaction) {
2023-06-04 00:01:10 +00:00
const clan = interaction.options.getString('clan') as SkilledClan;
2023-10-12 13:00:33 -05:00
const { id, region: region } = await resolvePlayerFromCommand(interaction);
const accountInfo = await getAccountInfo(region, id);
2023-06-04 00:01:10 +00:00
const problems: TableInput = [];
2023-10-12 13:00:33 -05:00
const title = `${accountInfo.nickname}'s eligibility for ${SKILLED_CLANS[clan]}`;
2023-06-04 00:01:10 +00:00
let isEligible = false;
let body = '';
if (clan === 'SKLLD') {
2023-10-14 11:25:42 -05:00
const { diff: diffed } = await getStatsInPeriod(
2023-10-12 13:00:33 -05:00
region,
2023-06-04 00:01:10 +00:00
id,
2023-10-12 13:00:33 -05:00
getTimeDaysAgo(region, 30),
2023-06-04 00:01:10 +00:00
getPeriodNow(),
);
2023-07-09 17:49:11 +00:00
const entries = Object.entries(diffed);
2023-06-04 00:01:10 +00:00
const stats = sumStats(entries.map(([, stats]) => stats));
const averageTier =
(await entries.reduce<PossiblyPromise<number>>(
async (accumulator, [tankIdString, stats]) => {
const tankId = parseInt(tankIdString);
2023-12-05 17:36:18 -06:00
const tankDefinition = (await tankDefinitions)[tankId];
2023-12-05 17:36:18 -06:00
if (!tankDefinition) return accumulator;
2023-12-05 17:36:18 -06:00
const tankTier = tankDefinition.tier;
2023-06-04 00:01:10 +00:00
return (await accumulator) + tankTier * stats.battles;
},
0,
)) /
(await entries.reduce<PossiblyPromise<number>>(
async (accumulator, [tankIdString, stats]) => {
const tankId = parseInt(tankIdString);
2023-12-05 17:36:18 -06:00
const tankDefinition = (await tankDefinitions)[tankId];
2023-12-05 17:36:18 -06:00
if (!tankDefinition) return accumulator;
return stats.battles;
},
0,
));
2023-06-04 00:01:10 +00:00
const WN8 =
(await entries.reduce<PossiblyPromise<number>>(
async (accumulator, [tankIdString, stats]) => {
const tankId = parseInt(tankIdString);
2023-06-04 00:01:10 +00:00
// edge case where new tanks don't have averages
if ((await tankAverages)[tankId]) {
const tankWN8 = calculateWN8(
(await tankAverages)[tankId].all,
stats,
);
2023-06-04 00:01:10 +00:00
if (isNaN(tankWN8)) return accumulator;
return (await accumulator) + tankWN8 * stats.battles;
} else return accumulator;
},
0,
)) / stats.battles;
2023-06-04 00:01:10 +00:00
const tier10Damage =
(await entries.reduce<PossiblyPromise<number>>(
async (accumulator, [tankIdString, stats]) => {
const tankId = parseInt(tankIdString);
2023-06-04 00:01:10 +00:00
2023-12-05 17:36:18 -06:00
if ((await tankDefinitions)[tankId]?.tier === 10) {
2023-07-09 17:49:11 +00:00
const tankStats = diffed[tankId];
return (await accumulator) + tankStats.damage_dealt;
} else return accumulator;
},
0,
)) /
(await entries.reduce<PossiblyPromise<number>>(
async (accumulator, [tankIdString, stats]) => {
const tankId = parseInt(tankIdString);
2023-06-04 00:01:10 +00:00
2023-12-05 17:36:18 -06:00
if ((await tankDefinitions)[tankId]?.tier === 10) {
2023-07-09 17:49:11 +00:00
const tankStats = diffed[tankId];
return (await accumulator) + tankStats.battles;
} else return accumulator;
},
0,
));
2023-06-04 00:01:10 +00:00
if (stats.battles < 126) {
problems.push(['Battles', `${stats.battles} (${stats.battles - 126})`]);
}
if (averageTier < 8) {
problems.push([
'Average tier',
`${averageTier.toFixed(2)} (${(averageTier - 8).toFixed(2)})`,
]);
}
if (stats.wins / stats.battles < 0.6) {
problems.push([
'Winrate',
`${(100 * (stats.wins / stats.battles)).toFixed(2)}% (${(
100 *
(stats.wins / stats.battles - 0.6)
).toFixed(2)}%)`,
]);
}
if (WN8 < 2450) {
2023-06-22 18:28:10 +00:00
problems.push([
'WN8',
`${WN8.toFixed(0)} (${(WN8 - 2450).toFixed(0)})`,
]);
2023-06-04 00:01:10 +00:00
}
if (tier10Damage < 1250) {
problems.push([
'Tier 10 damage',
`${tier10Damage.toFixed(0)} (${tier10Damage - 1250})`,
]);
}
isEligible = problems.length === 0;
body = isEligible
? 'Player is fully eligible.'
2023-06-27 02:22:28 +00:00
: `Player is not eligible. Shortcomings in 30-day statistics:\n\n${markdownTable(
2023-06-04 00:01:10 +00:00
problems,
)}`;
} else if (clan === 'SMRI') {
2023-10-12 13:00:33 -05:00
const stats = accountInfo.statistics.all;
2023-06-04 00:01:10 +00:00
if (stats.battles < 1500) {
problems.push([
'Battles',
`${stats.battles} (${stats.battles - 1500})`,
]);
}
if (stats.wins / stats.battles <= 0.53) {
problems.push([
'Winrate',
`${(100 * (stats.wins / stats.battles)).toFixed(2)}% (${(
100 *
(stats.wins / stats.battles - 0.53)
).toFixed(2)}%)`,
]);
}
isEligible = problems.length === 0;
body = isEligible
? 'Player is fully eligible.'
2023-06-27 02:22:28 +00:00
: `Player is not eligible. Shortcomings in career statistics:\n\n${markdownTable(
2023-06-04 00:01:10 +00:00
problems,
)}`;
}
2023-06-27 02:22:28 +00:00
return (isEligible ? embedPositive : embedNegative)(title, body);
2023-06-04 00:01:10 +00:00
},
2023-07-05 01:15:18 +00:00
};