diff --git a/src/commands/fullStats.tsx b/src/commands/fullStats.tsx index e0b87937e..a622487b9 100644 --- a/src/commands/fullStats.tsx +++ b/src/commands/fullStats.tsx @@ -1,4 +1,5 @@ import { SlashCommandBuilder } from 'discord.js'; +import { TreeTypeString } from '../components/Tanks'; import { CYCLIC_API } from '../constants/cyclic'; import getWargamingResponse from '../core/blitz/getWargamingResponse'; import resolveTankId from '../core/blitz/resolveTankId'; @@ -15,7 +16,7 @@ import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand'; import { secrets } from '../core/node/secrets'; import { CommandRegistryRaw } from '../events/interactionCreate'; import fullStats from '../renderers/fullStats'; -import { StatType } from '../renderers/stats'; +import { MultiTankFilters, StatType } from '../renderers/stats'; import { AccountInfo } from '../types/accountInfo'; export const fullStatsCommand = new Promise( @@ -38,7 +39,11 @@ export const fullStatsCommand = new Promise( true, ) as StatType; const player = await resolvePlayerFromCommand(interaction); - const period = resolvePeriodFromCommand(player.region, interaction); + const resolvedPeriod = resolvePeriodFromCommand( + player.region, + interaction, + ); + const period = interaction.options.getString('period'); const tankIdRaw = interaction.options.getString('tank')!; const tankId = commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null; @@ -49,6 +54,7 @@ export const fullStatsCommand = new Promise( tankId, start, end, + period, }); const { nickname } = ( await getWargamingResponse( @@ -57,7 +63,23 @@ export const fullStatsCommand = new Promise( )[player.id]; return [ - await fullStats(commandGroup, period, player, tankId), + await fullStats( + commandGroup, + resolvedPeriod, + player, + commandGroup === 'tank' + ? tankId + : commandGroup === 'multi-tank' + ? ({ + 'tank-type': + interaction.options.getString('tank-type') ?? undefined, + nation: interaction.options.getString('nation') ?? undefined, + tier: interaction.options.getInteger('tier') ?? undefined, + 'tree-type': (interaction.options.getString('tree-type') ?? + undefined) as TreeTypeString | undefined, + } satisfies Partial) + : null, + ), primaryButton(path, 'Refresh'), // linkButton(`${CYCLIC_API}/${path}`, 'Embed'), linkButton( diff --git a/src/renderers/fullStats.tsx b/src/renderers/fullStats.tsx index 9b6041152..6196b0c89 100644 --- a/src/renderers/fullStats.tsx +++ b/src/renderers/fullStats.tsx @@ -20,14 +20,17 @@ import { SupplementaryStats, } from '../types/accountInfo'; import { PlayerClanData } from '../types/playerClanData'; -import { PossiblyPromise } from '../types/possiblyPromise'; -import { StatType } from './stats'; +import { MultiTankFilters, StatType } from './stats'; export default async function fullStats( type: Type, { start, end, statsName }: ResolvedPeriod, { region: server, id }: ResolvedPlayer, - tankId: Type extends 'tank' ? number : null, + filters: Type extends 'tank' + ? number + : Type extends 'multi-tank' + ? Partial + : null, ) { let nameDiscriminator: string | undefined; let image: string | undefined; @@ -44,89 +47,98 @@ export default async function fullStats( ? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png` : undefined; } else if (type === 'tank') { - nameDiscriminator = `(${await resolveTankName(tankId!)})`; - image = (await tankopedia)[tankId!]?.images.normal; + nameDiscriminator = `(${await resolveTankName(filters as number)})`; + image = (await tankopedia)[filters as number]?.images.normal; + } else { } - const { diffed } = await getDiffedTankStats(server, id, start, end); - let stats: AllStats; + const { diffed, order } = await getDiffedTankStats(server, id, start, end); + const awaitedTankopedia = await tankopedia; + let stats: AllStats | undefined; let supplementaryStats: SupplementaryStats; let tierWeights: TierWeightsRecord; - if (type === 'player') { - const entries = Object.entries(diffed); - stats = sumStats(entries.map(([, stats]) => stats)); - const battlesOfTanksWithAverages = await entries.reduce< - PossiblyPromise - >(async (accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankAverage = (await tankAverages)[tankId]; - - return tankAverage ? (await accumulator) + stats.battles : accumulator; - }, 0); - const battlesOfTanksWithTankopediaEntry = await entries.reduce< - PossiblyPromise - >(async (accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankopediaEntry = (await tankopedia)[tankId]; - - return tankopediaEntry - ? (await accumulator) + stats.battles - : accumulator; - }, 0); + if (type === 'player' || type === 'multi-tank') { + const typedFilters = filters as Partial | null; + const filteredOrder = order.filter( + (id) => + typedFilters === null || + ((typedFilters.nation === undefined || + awaitedTankopedia[id]?.nation === typedFilters.nation) && + (typedFilters['tank-type'] === undefined || + awaitedTankopedia[id]?.type === typedFilters['tank-type']) && + (typedFilters.tier === undefined || + awaitedTankopedia[id]?.tier === typedFilters.tier) && + (typedFilters['tree-type'] === undefined || + (typedFilters['tree-type'] === 'collector' && + awaitedTankopedia[id]?.is_collectible) || + (typedFilters['tree-type'] === 'premium' && + awaitedTankopedia[id]?.is_premium) || + (typedFilters['tree-type'] === 'techtree' && + !awaitedTankopedia[id]?.is_collectible && + !awaitedTankopedia[id]?.is_premium))), + ); + const awaitedTankAverages = await tankAverages; + stats = sumStats(filteredOrder.map((id) => diffed[id])); + const battlesOfTanksWithAverages = filteredOrder.reduce( + (accumulator, id) => + awaitedTankAverages[id] + ? accumulator + diffed[id].battles + : accumulator, + 0, + ); + const battlesOfTanksWithTankopediaEntry = filteredOrder.reduce( + (accumulator, id) => + awaitedTankopedia[id] ? accumulator + diffed[id].battles : accumulator, + 0, + ); supplementaryStats = { WN8: - (await entries.reduce>( - async (accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankAverage = (await tankAverages)[tankId]; - - return tankAverage - ? (await accumulator) + - calculateWN8(tankAverage.all, stats) * stats.battles - : accumulator; - }, + filteredOrder.reduce( + (accumulator, id) => + awaitedTankAverages[id] + ? accumulator + + calculateWN8(awaitedTankAverages[id].all, diffed[id]) * + diffed[id].battles + : accumulator, 0, - )) / battlesOfTanksWithAverages, + ) / battlesOfTanksWithAverages, tier: - (await entries.reduce>( - async (accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankopediaEntry = (await tankopedia)[tankId]; - - return tankopediaEntry - ? (await accumulator) + tankopediaEntry.tier * stats.battles - : accumulator; - }, + filteredOrder.reduce( + (accumulator, id) => + awaitedTankopedia[id] + ? accumulator + awaitedTankopedia[id]!.tier * diffed[id].battles + : accumulator, 0, - )) / battlesOfTanksWithTankopediaEntry, + ) / battlesOfTanksWithTankopediaEntry, }; - tierWeights = await entries.reduce>( - async (accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankopediaEntry = (await tankopedia)[tankId]; + tierWeights = filteredOrder.reduce((accumulator, id) => { + const tankopediaEntry = awaitedTankopedia[id]; - if (!tankopediaEntry) return accumulator; + if (!tankopediaEntry) return accumulator; - const tier = tankopediaEntry.tier as Tier; + const tier = tankopediaEntry.tier as Tier; - if ((await accumulator)[tier]) { - (await accumulator)[tier]! += stats.battles; - } else { - (await accumulator)[tier] = stats.battles; - } + if (accumulator[tier]) { + accumulator[tier]! += diffed[id].battles; + } else { + accumulator[tier] = diffed[id].battles; + } - return accumulator; - }, - {}, - ); + return accumulator; + }, {}); } else { - stats = diffed[tankId!]; + stats = diffed[(filters as number)!]; supplementaryStats = { - WN8: calculateWN8((await tankAverages)[tankId!].all, diffed[tankId!]), - tier: (await tankopedia)[tankId!]?.tier, + WN8: stats + ? calculateWN8( + (await tankAverages)[(filters as number)!].all, + diffed[(filters as number)!], + ) + : undefined, + tier: (await tankopedia)[(filters as number)!]?.tier, }; }