mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
feat: merged stats and tankstats
This commit is contained in:
1 parent
0cf0e63fda
commit
d9690460d5
14 files changed
+195
-338
No files matched your search
+1
-1
@@ -20,7 +20,7 @@ build({
|
|||||||
},
|
},
|
||||||
|
|
||||||
bundle: true,
|
bundle: true,
|
||||||
sourcemap: isProd,
|
sourcemap: true,
|
||||||
minifyIdentifiers: false, // causes errors
|
minifyIdentifiers: false, // causes errors
|
||||||
minifySyntax: isProd,
|
minifySyntax: isProd,
|
||||||
minifyWhitespace: isProd,
|
minifyWhitespace: isProd,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
|
|||||||
import sumStats from '../core/blitz/sumStats.js';
|
import sumStats from '../core/blitz/sumStats.js';
|
||||||
import { tankopedia } from '../core/blitz/tankopedia.js';
|
import { tankopedia } from '../core/blitz/tankopedia.js';
|
||||||
import getPeriodNow from '../core/blitzstars/getPeriodNow.js';
|
import getPeriodNow from '../core/blitzstars/getPeriodNow.js';
|
||||||
import getPeriodicStart from '../core/blitzstars/getPeriodStart.js';
|
import getPeriodStart from '../core/blitzstars/getPeriodStart.js';
|
||||||
import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js';
|
import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js';
|
||||||
import { tankAverages } from '../core/blitzstars/tankAverages.js';
|
import { tankAverages } from '../core/blitzstars/tankAverages.js';
|
||||||
import cleanTable, { TableInput } from '../core/interaction/cleanTable.js';
|
import cleanTable, { TableInput } from '../core/interaction/cleanTable.js';
|
||||||
@@ -62,7 +62,7 @@ export default {
|
|||||||
const tankStatsOverTime = await getTankStatsOverTime(
|
const tankStatsOverTime = await getTankStatsOverTime(
|
||||||
server,
|
server,
|
||||||
id,
|
id,
|
||||||
getPeriodicStart('30'),
|
getPeriodStart('30'),
|
||||||
getPeriodNow(),
|
getPeriodNow(),
|
||||||
);
|
);
|
||||||
const entries = Object.entries(tankStatsOverTime);
|
const entries = Object.entries(tankStatsOverTime);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { CommandRegistry } from '../events/interactionCreate.js';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
inProduction: true,
|
inProduction: true,
|
||||||
inDevelopment: true,
|
inDevelopment: false,
|
||||||
inPublic: true,
|
inPublic: true,
|
||||||
handlesInteraction: true,
|
handlesInteraction: true,
|
||||||
|
|
||||||
|
|||||||
+112
-122
@@ -5,26 +5,26 @@ import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
|||||||
import TitleBar from '../components/TitleBar.js';
|
import TitleBar from '../components/TitleBar.js';
|
||||||
import Wrapper from '../components/Wrapper.js';
|
import Wrapper from '../components/Wrapper.js';
|
||||||
import { BLITZ_SERVERS } from '../constants/servers.js';
|
import { BLITZ_SERVERS } from '../constants/servers.js';
|
||||||
|
import tanksAutocomplete from '../core/autocomplete/tanks.js';
|
||||||
import usernameAutocomplete from '../core/autocomplete/username.js';
|
import usernameAutocomplete from '../core/autocomplete/username.js';
|
||||||
import getBlitzAccount from '../core/blitz/getBlitzAccount.js';
|
import getBlitzAccount from '../core/blitz/getBlitzAccount.js';
|
||||||
import getTankStats from '../core/blitz/getTankStats.js';
|
|
||||||
import getWN8 from '../core/blitz/getWN8.js';
|
import getWN8 from '../core/blitz/getWN8.js';
|
||||||
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
|
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
|
||||||
|
import resolveTankId from '../core/blitz/resolveTankId.js';
|
||||||
|
import resolveTankName from '../core/blitz/resolveTankName.js';
|
||||||
import sumStats from '../core/blitz/sumStats.js';
|
import sumStats from '../core/blitz/sumStats.js';
|
||||||
import { tankopedia } from '../core/blitz/tankopedia.js';
|
import { tankopedia } from '../core/blitz/tankopedia.js';
|
||||||
import getPeriodNow from '../core/blitzstars/getPeriodNow.js';
|
import getPeriodNow from '../core/blitzstars/getPeriodNow.js';
|
||||||
import getPeriodicStart from '../core/blitzstars/getPeriodStart.js';
|
import getPeriodStart from '../core/blitzstars/getPeriodStart.js';
|
||||||
import getPeriodStartFromDaysAgo from '../core/blitzstars/getPeriodStartFromDaysAgo.js';
|
|
||||||
import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js';
|
import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js';
|
||||||
|
import getTimeDaysAgo from '../core/blitzstars/getTimeDaysAgo.js';
|
||||||
import { tankAverages } from '../core/blitzstars/tankAverages.js';
|
import { tankAverages } from '../core/blitzstars/tankAverages.js';
|
||||||
import cmdName from '../core/interaction/cmdName.js';
|
import cmdName from '../core/interaction/cmdName.js';
|
||||||
import fullBlitzStarsStats from '../core/interaction/fullBlitzStarsStats.js';
|
import addPeriodSubCommands, {
|
||||||
import { supportBlitzStars } from '../core/interaction/supportBlitzStars.js';
|
PERIOD_NAMES,
|
||||||
import addCustomPeriodOption from '../core/options/addCustomPeriodOption.js';
|
Period,
|
||||||
import addPeriodChoices, {
|
} from '../core/options/addPeriodSubCommands.js';
|
||||||
StatPeriod,
|
import addTankChoices from '../core/options/addTankChoices.js';
|
||||||
statPeriodNames,
|
|
||||||
} from '../core/options/addPeriodChoices.js';
|
|
||||||
import addUsernameOption from '../core/options/addUsernameOption.js';
|
import addUsernameOption from '../core/options/addUsernameOption.js';
|
||||||
import { WARGAMING_APPLICATION_ID } from '../core/process/args.js';
|
import { WARGAMING_APPLICATION_ID } from '../core/process/args.js';
|
||||||
import { CommandRegistry } from '../events/interactionCreate.js';
|
import { CommandRegistry } from '../events/interactionCreate.js';
|
||||||
@@ -41,152 +41,142 @@ export default {
|
|||||||
inPublic: true,
|
inPublic: true,
|
||||||
|
|
||||||
command: new SlashCommandBuilder()
|
command: new SlashCommandBuilder()
|
||||||
|
// TODO: embed cmdName into interaction create
|
||||||
.setName(cmdName('stats'))
|
.setName(cmdName('stats'))
|
||||||
.setDescription("Gets the user's in-game statistics")
|
.setDescription('In-game statistics')
|
||||||
.addSubcommand((option) =>
|
.addSubcommandGroup((option) =>
|
||||||
option
|
addPeriodSubCommands(option, (option) =>
|
||||||
.setName('period')
|
option.addStringOption(addUsernameOption),
|
||||||
.setDescription('Pick from a predetermined periods')
|
)
|
||||||
.addStringOption(addPeriodChoices)
|
.setName('player')
|
||||||
.addStringOption(addUsernameOption),
|
.setDescription("Player's statistics"),
|
||||||
)
|
)
|
||||||
.addSubcommand((option) =>
|
.addSubcommandGroup((option) =>
|
||||||
addCustomPeriodOption(option)
|
addPeriodSubCommands(option, (option) =>
|
||||||
.setName('customperiod')
|
option
|
||||||
.setDescription('Custom periods')
|
.addStringOption(addTankChoices)
|
||||||
.addStringOption(addUsernameOption),
|
.addStringOption(addUsernameOption),
|
||||||
|
)
|
||||||
|
.setName('tank')
|
||||||
|
.setDescription("Tank's statistics"),
|
||||||
),
|
),
|
||||||
|
|
||||||
async execute(interaction) {
|
async execute(interaction) {
|
||||||
const period = interaction.options.getString('period') as StatPeriod;
|
const commandGroup = interaction.options.getSubcommandGroup()!;
|
||||||
const { id, server } = await getBlitzAccount(interaction);
|
const { id, server } = await getBlitzAccount(interaction);
|
||||||
const accountInfo = await getWargamingResponse<AccountInfo>(
|
let nameDiscriminator: string | undefined;
|
||||||
`https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`,
|
let image: string | undefined;
|
||||||
);
|
const tankIdRaw = interaction.options.getString('tank')!;
|
||||||
const clanData = await getWargamingResponse<PlayerClanData>(
|
|
||||||
`https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}&extra=clan`,
|
|
||||||
);
|
|
||||||
let stats: AllStats;
|
|
||||||
let supplementaryStats: SupplementaryStats | undefined;
|
|
||||||
let hasWN8AccumulatedAtAll = false;
|
|
||||||
const isCustomPeriod =
|
|
||||||
interaction.options.getSubcommand() === 'customperiod';
|
|
||||||
let periodName: string;
|
|
||||||
const startRaw = interaction.options.getInteger('start')!;
|
|
||||||
const endRaw = interaction.options.getInteger('end')!;
|
|
||||||
const start = Math.max(startRaw, endRaw);
|
|
||||||
const end = Math.min(startRaw, endRaw);
|
|
||||||
|
|
||||||
if (isCustomPeriod) {
|
if (commandGroup === 'player') {
|
||||||
periodName = `${start} to ${end} days ago`;
|
const clan = (
|
||||||
} else {
|
await getWargamingResponse<PlayerClanData>(
|
||||||
periodName = statPeriodNames[period];
|
`https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}&extra=clan`,
|
||||||
|
)
|
||||||
|
)[id]?.clan;
|
||||||
|
|
||||||
|
if (clan) nameDiscriminator = `[${clan.tag}]`;
|
||||||
|
image = clan
|
||||||
|
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
|
||||||
|
: undefined;
|
||||||
|
} else if (commandGroup === 'tank') {
|
||||||
|
const tankId = await resolveTankId(tankIdRaw);
|
||||||
|
nameDiscriminator = `(${resolveTankName(tankId)})`;
|
||||||
|
image = tankopedia[tankId].images.normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (period === 'career') {
|
const period = interaction.options.getSubcommand(true) as Period;
|
||||||
const tankStats = await getTankStats(server, id);
|
let periodName: string;
|
||||||
stats = accountInfo[id].statistics.all;
|
let periodStart: number;
|
||||||
const totalBattles = tankStats.reduce(
|
let periodEnd: number;
|
||||||
(accumulator, { all }) => accumulator + all.battles,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
|
|
||||||
supplementaryStats = {
|
if (period === 'custom') {
|
||||||
tier:
|
const startRaw = interaction.options.getInteger('start')!;
|
||||||
tankStats.reduce(
|
const endRaw = interaction.options.getInteger('end')!;
|
||||||
(accumulator, { tank_id, all }) =>
|
const start = Math.max(startRaw, endRaw);
|
||||||
accumulator + tankopedia[tank_id].tier * all.battles,
|
const end = Math.min(startRaw, endRaw);
|
||||||
0,
|
|
||||||
) / totalBattles,
|
|
||||||
WN8:
|
|
||||||
tankStats.reduce((accumulator, { tank_id, all }) => {
|
|
||||||
if (tankAverages[tank_id]) {
|
|
||||||
const tankWN8 = getWN8(tankAverages[tank_id].all, all);
|
|
||||||
|
|
||||||
if (isNaN(tankWN8)) return accumulator;
|
periodName = `${start} to ${end} days ago`;
|
||||||
|
periodStart = getTimeDaysAgo(start);
|
||||||
hasWN8AccumulatedAtAll = true;
|
periodEnd = getTimeDaysAgo(end);
|
||||||
|
|
||||||
return accumulator + tankWN8 * all.battles;
|
|
||||||
} else return accumulator;
|
|
||||||
}, 0) / totalBattles,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
const tankStatsOverTime = await getTankStatsOverTime(
|
periodName = PERIOD_NAMES[period];
|
||||||
server,
|
periodStart = getPeriodStart(period);
|
||||||
id,
|
periodEnd = getPeriodNow();
|
||||||
isCustomPeriod
|
}
|
||||||
? getPeriodStartFromDaysAgo(start)
|
|
||||||
: getPeriodicStart(period),
|
const tankStats = await getTankStatsOverTime(
|
||||||
isCustomPeriod ? getPeriodStartFromDaysAgo(end) : getPeriodNow(),
|
server,
|
||||||
);
|
id,
|
||||||
const entries = Object.entries(tankStatsOverTime);
|
periodStart,
|
||||||
const totalBattles = entries.reduce(
|
periodEnd,
|
||||||
|
);
|
||||||
|
let stats: AllStats;
|
||||||
|
let supplementaryStats: SupplementaryStats;
|
||||||
|
|
||||||
|
if (commandGroup === 'player') {
|
||||||
|
const entries = Object.entries(tankStats);
|
||||||
|
stats = sumStats(entries.map(([, stats]) => stats));
|
||||||
|
const battles = entries.reduce(
|
||||||
(accumulator, [, stats]) => accumulator + stats.battles,
|
(accumulator, [, stats]) => accumulator + stats.battles,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
supplementaryStats = {
|
supplementaryStats = {
|
||||||
tier:
|
|
||||||
entries.reduce((accumulator, [tankIdString, stats]) => {
|
|
||||||
const tankId = parseInt(tankIdString);
|
|
||||||
const tankTier = tankopedia[tankId].tier;
|
|
||||||
|
|
||||||
return accumulator + tankTier * stats.battles;
|
|
||||||
}, 0) / totalBattles,
|
|
||||||
WN8:
|
WN8:
|
||||||
entries.reduce((accumulator, [tankIdString, stats]) => {
|
entries.reduce(
|
||||||
const tankId = parseInt(tankIdString);
|
(accumulator, [tankIdString, stats]) =>
|
||||||
|
accumulator +
|
||||||
// edge case where new tanks don't have averages
|
getWN8(tankAverages[parseInt(tankIdString)].all, stats) *
|
||||||
if (tankAverages[tankId]) {
|
stats.battles,
|
||||||
const tankWN8 = getWN8(tankAverages[tankId].all, stats);
|
0,
|
||||||
|
) / battles,
|
||||||
if (isNaN(tankWN8)) return accumulator;
|
tier:
|
||||||
|
entries.reduce(
|
||||||
hasWN8AccumulatedAtAll = true;
|
(accumulator, [tankIdString, stats]) =>
|
||||||
|
accumulator +
|
||||||
return accumulator + tankWN8 * stats.battles;
|
tankopedia[parseInt(tankIdString)].tier * stats.battles,
|
||||||
} else return accumulator;
|
0,
|
||||||
}, 0) / totalBattles,
|
) / battles,
|
||||||
|
};
|
||||||
|
} else if (commandGroup === 'tank') {
|
||||||
|
const tankId = await resolveTankId(tankIdRaw);
|
||||||
|
stats = tankStats[tankId];
|
||||||
|
supplementaryStats = {
|
||||||
|
WN8: getWN8(tankAverages[tankId].all, tankStats[tankId]),
|
||||||
|
tier: tankopedia[tankId].tier,
|
||||||
};
|
};
|
||||||
|
|
||||||
stats = sumStats(entries.map(([, stats]) => stats));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasWN8AccumulatedAtAll) supplementaryStats.WN8 = undefined;
|
const accountInfo = await getWargamingResponse<AccountInfo>(
|
||||||
|
`https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`,
|
||||||
|
);
|
||||||
|
|
||||||
return [
|
return (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<TitleBar
|
<TitleBar
|
||||||
name={accountInfo[id].nickname}
|
name={accountInfo[id].nickname}
|
||||||
nameDiscriminator={
|
nameDiscriminator={nameDiscriminator}
|
||||||
clanData[id]?.clan ? `[${clanData[id]?.clan?.tag}]` : undefined
|
image={image}
|
||||||
}
|
|
||||||
image={
|
|
||||||
clanData[id]?.clan
|
|
||||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData[id]?.clan?.emblem_set_id}.png`
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
description={`${periodName} • ${new Date().toDateString()} • ${
|
description={`${periodName} • ${new Date().toDateString()} • ${
|
||||||
BLITZ_SERVERS[server]
|
BLITZ_SERVERS[server]
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{stats.battles === 0 && <NoData type={NoDataType.BattlesInPeriod} />}
|
{stats!.battles === 0 && <NoData type={NoDataType.BattlesInPeriod} />}
|
||||||
{stats.battles > 0 && (
|
{stats!.battles > 0 && (
|
||||||
<GenericAllStats
|
<GenericAllStats
|
||||||
stats={stats}
|
stats={stats!}
|
||||||
supplementaryStats={supplementaryStats}
|
supplementaryStats={supplementaryStats!}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<PoweredByBlitzStars />
|
<PoweredByBlitzStars />
|
||||||
</Wrapper>,
|
</Wrapper>
|
||||||
fullBlitzStarsStats(server, accountInfo[id].nickname),
|
);
|
||||||
supportBlitzStars,
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
|
|
||||||
autocomplete: usernameAutocomplete,
|
autocomplete: (interaction) => {
|
||||||
|
usernameAutocomplete(interaction);
|
||||||
|
tanksAutocomplete(interaction);
|
||||||
|
},
|
||||||
} satisfies CommandRegistry;
|
} satisfies CommandRegistry;
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
import { SlashCommandBuilder } from 'discord.js';
|
|
||||||
import GenericAllStats from '../components/GenericAllStats.js';
|
|
||||||
import NoData, { NoDataType } from '../components/NoData.js';
|
|
||||||
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
|
||||||
import TitleBar from '../components/TitleBar.js';
|
|
||||||
import Wrapper from '../components/Wrapper.js';
|
|
||||||
import { BLITZ_SERVERS } from '../constants/servers.js';
|
|
||||||
import tanksAutocomplete from '../core/autocomplete/tanks.js';
|
|
||||||
import usernameAutocomplete from '../core/autocomplete/username.js';
|
|
||||||
import getBlitzAccount from '../core/blitz/getBlitzAccount.js';
|
|
||||||
import getTankStats from '../core/blitz/getTankStats.js';
|
|
||||||
import getWN8 from '../core/blitz/getWN8.js';
|
|
||||||
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
|
|
||||||
import resolveTankId from '../core/blitz/resolveTankId.js';
|
|
||||||
import resolveTankName from '../core/blitz/resolveTankName.js';
|
|
||||||
import { tankopedia } from '../core/blitz/tankopedia.js';
|
|
||||||
import getPeriodNow from '../core/blitzstars/getPeriodNow.js';
|
|
||||||
import getPeriodicStart from '../core/blitzstars/getPeriodStart.js';
|
|
||||||
import getPeriodStartFromDaysAgo from '../core/blitzstars/getPeriodStartFromDaysAgo.js';
|
|
||||||
import getTankStatsOverTime, {
|
|
||||||
emptyAllStats,
|
|
||||||
} from '../core/blitzstars/getTankStatsOverTime.js';
|
|
||||||
import { tankAverages } from '../core/blitzstars/tankAverages.js';
|
|
||||||
import cmdName from '../core/interaction/cmdName.js';
|
|
||||||
import fullBlitzStarsStats from '../core/interaction/fullBlitzStarsStats.js';
|
|
||||||
import { supportBlitzStars } from '../core/interaction/supportBlitzStars.js';
|
|
||||||
import addCustomPeriodOption from '../core/options/addCustomPeriodOption.js';
|
|
||||||
import addPeriodChoices, {
|
|
||||||
StatPeriod,
|
|
||||||
statPeriodNames,
|
|
||||||
} from '../core/options/addPeriodChoices.js';
|
|
||||||
import addTankChoices from '../core/options/addTankChoices.js';
|
|
||||||
import addUsernameOption from '../core/options/addUsernameOption.js';
|
|
||||||
import { WARGAMING_APPLICATION_ID } from '../core/process/args.js';
|
|
||||||
import { CommandRegistry } from '../events/interactionCreate.js';
|
|
||||||
import { AccountInfo, AllStats } from '../types/accountInfo.js';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
inProduction: true,
|
|
||||||
inDevelopment: true,
|
|
||||||
inPublic: true,
|
|
||||||
|
|
||||||
command: new SlashCommandBuilder()
|
|
||||||
.setName(cmdName('tankstats'))
|
|
||||||
.setDescription('Stats for a tank over a period')
|
|
||||||
.addSubcommand((option) =>
|
|
||||||
option
|
|
||||||
.setName('period')
|
|
||||||
.setDescription('Pick from a predetermined periods')
|
|
||||||
.addStringOption(addTankChoices)
|
|
||||||
.addStringOption(addPeriodChoices)
|
|
||||||
.addStringOption(addUsernameOption),
|
|
||||||
)
|
|
||||||
.addSubcommand((option) =>
|
|
||||||
addCustomPeriodOption(option)
|
|
||||||
.setName('customperiod')
|
|
||||||
.addStringOption(addTankChoices)
|
|
||||||
.setDescription('Custom periods')
|
|
||||||
.addStringOption(addUsernameOption),
|
|
||||||
),
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
const tank = await resolveTankId(
|
|
||||||
interaction,
|
|
||||||
interaction.options.getString('tank')!,
|
|
||||||
);
|
|
||||||
const period = interaction.options.getString('period') as StatPeriod;
|
|
||||||
const blitzAccount = await getBlitzAccount(interaction);
|
|
||||||
const { id, server } = blitzAccount;
|
|
||||||
const accountInfo = await getWargamingResponse<AccountInfo>(
|
|
||||||
`https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`,
|
|
||||||
);
|
|
||||||
const tankStats = await getTankStats(server, id);
|
|
||||||
let stats: AllStats;
|
|
||||||
const tankId = Number(tank);
|
|
||||||
const isCustomPeriod =
|
|
||||||
interaction.options.getSubcommand() === 'customperiod';
|
|
||||||
let periodName: string;
|
|
||||||
const startRaw = interaction.options.getInteger('start')!;
|
|
||||||
const endRaw = interaction.options.getInteger('end')!;
|
|
||||||
const start = Math.max(startRaw, endRaw);
|
|
||||||
const end = Math.min(startRaw, endRaw);
|
|
||||||
|
|
||||||
if (isCustomPeriod) {
|
|
||||||
periodName = `${start} to ${end} days ago`;
|
|
||||||
} else {
|
|
||||||
periodName = statPeriodNames[period];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (period === 'career') {
|
|
||||||
stats =
|
|
||||||
tankStats.find((stats) => stats.tank_id === tankId)?.all ??
|
|
||||||
emptyAllStats;
|
|
||||||
} else {
|
|
||||||
const tankStatsOverTime = await getTankStatsOverTime(
|
|
||||||
server,
|
|
||||||
id,
|
|
||||||
isCustomPeriod
|
|
||||||
? getPeriodStartFromDaysAgo(start)
|
|
||||||
: getPeriodicStart(period),
|
|
||||||
isCustomPeriod ? getPeriodStartFromDaysAgo(end) : getPeriodNow(),
|
|
||||||
);
|
|
||||||
|
|
||||||
stats = tankStatsOverTime[tankId] ?? emptyAllStats;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
<Wrapper>
|
|
||||||
<TitleBar
|
|
||||||
name={accountInfo[id].nickname}
|
|
||||||
nameDiscriminator={`(${resolveTankName(tankId)})`}
|
|
||||||
image={tankopedia[tankId].images.normal}
|
|
||||||
description={`${periodName} • ${new Date().toDateString()} • ${
|
|
||||||
BLITZ_SERVERS[server]
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{stats.battles === 0 && <NoData type={NoDataType.BattlesInPeriod} />}
|
|
||||||
{stats.battles > 0 && (
|
|
||||||
<GenericAllStats
|
|
||||||
stats={stats}
|
|
||||||
supplementaryStats={{
|
|
||||||
tier: tankopedia[tankId].tier,
|
|
||||||
WN8: getWN8(tankAverages[tankId].all, stats),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<PoweredByBlitzStars />
|
|
||||||
</Wrapper>,
|
|
||||||
fullBlitzStarsStats(server, accountInfo[id].nickname),
|
|
||||||
supportBlitzStars,
|
|
||||||
];
|
|
||||||
},
|
|
||||||
|
|
||||||
autocomplete: (interaction) => {
|
|
||||||
tanksAutocomplete(interaction);
|
|
||||||
usernameAutocomplete(interaction);
|
|
||||||
},
|
|
||||||
} satisfies CommandRegistry;
|
|
||||||
@@ -27,7 +27,7 @@ import { PlayerClanData } from '../types/playerClanData.js';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
inProduction: true,
|
inProduction: true,
|
||||||
inDevelopment: true,
|
inDevelopment: false,
|
||||||
inPublic: true,
|
inPublic: true,
|
||||||
|
|
||||||
command: new SlashCommandBuilder()
|
command: new SlashCommandBuilder()
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
|
||||||
import { go } from 'fuzzysort';
|
import { go } from 'fuzzysort';
|
||||||
import errorWithCause from '../process/errorWithCause.js';
|
import errorWithCause from '../process/errorWithCause.js';
|
||||||
import { TANKS, tankopedia } from './tankopedia.js';
|
import { TANKS, tankopedia } from './tankopedia.js';
|
||||||
|
|
||||||
export default async function resolveTankId(
|
export default async function resolveTankId(tank: string) {
|
||||||
interaction: ChatInputCommandInteraction<CacheType>,
|
|
||||||
tank: string,
|
|
||||||
) {
|
|
||||||
const number = Number(tank);
|
const number = Number(tank);
|
||||||
|
|
||||||
if (Number.isNaN(number)) {
|
if (Number.isNaN(number)) {
|
||||||
|
|||||||
@@ -1,18 +1,12 @@
|
|||||||
import { StatPeriod } from '../options/addPeriodChoices.js';
|
import { Period } from '../options/addPeriodSubCommands.js';
|
||||||
import getPeriodStartFromDaysAgo from './getPeriodStartFromDaysAgo.js';
|
import getTimeDaysAgo from './getTimeDaysAgo.js';
|
||||||
|
|
||||||
export default function getPeriodicStart(period: StatPeriod) {
|
export default function getPeriodStart(period: Exclude<Period, 'custom'>) {
|
||||||
if (period === 'career') {
|
if (period === 'career') {
|
||||||
return -Infinity;
|
return -Infinity;
|
||||||
} else if (period === 'today') {
|
} else if (period === 'today') {
|
||||||
const now = new Date();
|
return getTimeDaysAgo(0);
|
||||||
now.setHours(5, 0, 0, 0);
|
|
||||||
|
|
||||||
// If it's after 5:00 AM today, subtract one day
|
|
||||||
if (now.getTime() > Date.now()) now.setDate(now.getDate() - 1);
|
|
||||||
|
|
||||||
return now.getTime() / 1000;
|
|
||||||
} else {
|
} else {
|
||||||
return getPeriodStartFromDaysAgo(Number(period));
|
return getTimeDaysAgo(Number(period));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
export default function getPeriodStartFromDaysAgo(period: number) {
|
|
||||||
const daysAgo = Number(period) - 1;
|
|
||||||
const periodStart = new Date();
|
|
||||||
|
|
||||||
periodStart.setDate(periodStart.getDate() - daysAgo);
|
|
||||||
periodStart.setHours(5, 0, 0, 0);
|
|
||||||
|
|
||||||
return periodStart.getTime() / 1000;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
export default function getTimeDaysAgo(period: number) {
|
||||||
|
const now = new Date();
|
||||||
|
now.setHours(5, 0, 0, 0);
|
||||||
|
|
||||||
|
// if it's after 5:00 AM today, subtract one day
|
||||||
|
if (now.getTime() > Date.now()) now.setDate(now.getDate() - 1);
|
||||||
|
|
||||||
|
// subtract the period number of days from now
|
||||||
|
now.setDate(now.getDate() - period);
|
||||||
|
|
||||||
|
return now.getTime() / 1000;
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import { SlashCommandSubcommandBuilder } from 'discord.js';
|
|
||||||
|
|
||||||
export default function addCustomPeriodOption(
|
|
||||||
option: SlashCommandSubcommandBuilder,
|
|
||||||
) {
|
|
||||||
return option
|
|
||||||
.addIntegerOption((option) =>
|
|
||||||
option
|
|
||||||
.setName('start')
|
|
||||||
.setDescription('Start of period in days ago from today')
|
|
||||||
.setMinValue(0)
|
|
||||||
.setRequired(true),
|
|
||||||
)
|
|
||||||
.addIntegerOption((option) =>
|
|
||||||
option
|
|
||||||
.setName('end')
|
|
||||||
.setDescription('End of period in days ago from today')
|
|
||||||
.setMinValue(0)
|
|
||||||
.setRequired(true),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { SlashCommandStringOption } from 'discord.js';
|
|
||||||
|
|
||||||
export type StatPeriod = 'today' | '30' | '60' | '90' | 'career';
|
|
||||||
export const statPeriodNames: Record<StatPeriod, string> = {
|
|
||||||
today: "Today's statistics",
|
|
||||||
30: '30-day statistics',
|
|
||||||
60: '60-day statistics',
|
|
||||||
90: '90-day statistics',
|
|
||||||
career: 'Career statistics',
|
|
||||||
};
|
|
||||||
export default function addPeriodChoices(option: SlashCommandStringOption) {
|
|
||||||
return option
|
|
||||||
.setName('period')
|
|
||||||
.setDescription('The period to get stats for')
|
|
||||||
.setChoices(
|
|
||||||
{ name: 'Today', value: 'today' satisfies StatPeriod },
|
|
||||||
{ name: '30 Days', value: '30' satisfies StatPeriod },
|
|
||||||
{ name: '60 Days', value: '60' satisfies StatPeriod },
|
|
||||||
{ name: '90 Days', value: '90' satisfies StatPeriod },
|
|
||||||
{ name: 'Career', value: 'career' satisfies StatPeriod },
|
|
||||||
)
|
|
||||||
.setRequired(true);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import {
|
||||||
|
SlashCommandSubcommandBuilder,
|
||||||
|
SlashCommandSubcommandGroupBuilder,
|
||||||
|
} from 'discord.js';
|
||||||
|
|
||||||
|
export type Period = 'today' | '30' | '60' | '90' | 'career' | 'custom';
|
||||||
|
|
||||||
|
export const PERIOD_NAMES: Record<Period, string> = {
|
||||||
|
today: "Today's statistics",
|
||||||
|
'30': "30 days' statistics",
|
||||||
|
'60': "60 days' statistics",
|
||||||
|
'90': "90 days' statistics",
|
||||||
|
career: 'Career statistics',
|
||||||
|
custom: 'Custom period',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function addPeriodSubCommands(
|
||||||
|
option: SlashCommandSubcommandGroupBuilder,
|
||||||
|
extra: (
|
||||||
|
option: SlashCommandSubcommandBuilder,
|
||||||
|
) => SlashCommandSubcommandBuilder = (option) => option,
|
||||||
|
) {
|
||||||
|
return option
|
||||||
|
.addSubcommand((option) =>
|
||||||
|
extra(option.setName('today').setDescription(PERIOD_NAMES.today)),
|
||||||
|
)
|
||||||
|
.addSubcommand((option) =>
|
||||||
|
extra(option.setName('30').setDescription(PERIOD_NAMES['30'])),
|
||||||
|
)
|
||||||
|
.addSubcommand((option) =>
|
||||||
|
extra(option.setName('60').setDescription(PERIOD_NAMES['60'])),
|
||||||
|
)
|
||||||
|
.addSubcommand((option) =>
|
||||||
|
extra(option.setName('90').setDescription(PERIOD_NAMES['90'])),
|
||||||
|
)
|
||||||
|
.addSubcommand((option) =>
|
||||||
|
extra(option.setName('career').setDescription(PERIOD_NAMES.career)),
|
||||||
|
)
|
||||||
|
.addSubcommand((option) =>
|
||||||
|
extra(
|
||||||
|
option
|
||||||
|
.setName('custom')
|
||||||
|
.setDescription(PERIOD_NAMES.custom)
|
||||||
|
.addIntegerOption((option) =>
|
||||||
|
option
|
||||||
|
.setName('start')
|
||||||
|
.setDescription('Start of period in days ago from today')
|
||||||
|
.setMinValue(0)
|
||||||
|
.setRequired(true),
|
||||||
|
)
|
||||||
|
.addIntegerOption((option) =>
|
||||||
|
option
|
||||||
|
.setName('end')
|
||||||
|
.setDescription('End of period in days ago from today')
|
||||||
|
.setMinValue(0)
|
||||||
|
.setRequired(true),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -27,7 +27,6 @@ import searchclans from '../commands/searchclans.js';
|
|||||||
import searchplayers from '../commands/searchplayers.js';
|
import searchplayers from '../commands/searchplayers.js';
|
||||||
import searchtanks from '../commands/searchtanks.js';
|
import searchtanks from '../commands/searchtanks.js';
|
||||||
import stats from '../commands/stats.js';
|
import stats from '../commands/stats.js';
|
||||||
import tankstats from '../commands/tankstats.js';
|
|
||||||
import today from '../commands/today.js';
|
import today from '../commands/today.js';
|
||||||
import verify from '../commands/verify.js';
|
import verify from '../commands/verify.js';
|
||||||
import negativeEmbed from '../core/interaction/negativeEmbed.js';
|
import negativeEmbed from '../core/interaction/negativeEmbed.js';
|
||||||
@@ -77,7 +76,6 @@ const commands = (
|
|||||||
searchplayers,
|
searchplayers,
|
||||||
searchtanks,
|
searchtanks,
|
||||||
stats,
|
stats,
|
||||||
tankstats,
|
|
||||||
today,
|
today,
|
||||||
verify,
|
verify,
|
||||||
ping,
|
ping,
|
||||||
|
|||||||
Reference in new issue
Block a user