feat: added WN8 to /today

This commit is contained in:
TresAbhi committed 2023-06-02 01:31:14 +00:00
1 parent c5d14758d5
commit f801783358
14 files changed
+163 -51

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
import { SlashCommandBuilder } from 'discord.js';
import packageJSON from '../../package.json' assert { type: 'json' };
import { tankopedia } from '../core/blitz/tankopedia.js';
import { tankAverages } from '../core/blitzstars/tankaverages.js';
import { tankAverages } from '../core/blitzstars/tankAverages.js';
import cleanTable from '../core/interaction/cleanTable.js';
import cmdName from '../core/interaction/cmdName.js';
import infoEmbed from '../core/interaction/infoEmbed.js';
+1 -1
View File
@@ -18,7 +18,7 @@ import { tankopedia } from '../core/blitz/tankopedia.js';
import getPeriodNow from '../core/blitzstars/getPeriodNow.js';
import getPeriodicStart from '../core/blitzstars/getPeriodStart.js';
import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js';
import { tankAverages } from '../core/blitzstars/tankaverages.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';
+1 -1
View File
@@ -22,7 +22,7 @@ import getPeriodicStart from '../core/blitzstars/getPeriodStart.js';
import getTankStatsOverTime, {
emptyAllStats,
} from '../core/blitzstars/getTankStatsOverTime.js';
import { tankAverages } from '../core/blitzstars/tankaverages.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';
+91 -26
View File
@@ -7,18 +7,21 @@ import * as Breakdown from '../components/Breakdown/index.js';
import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js';
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
import TitleBar from '../components/TitleBar.js';
import Wrapper from '../components/Wrapper.js';
import Wrapper, { WrapperSize } from '../components/Wrapper.js';
import { BLITZ_SERVERS } from '../constants/servers.js';
import usernameAutocomplete from '../core/autocomplete/username.js';
import getBlitzAccount from '../core/blitz/getBlitzAccount.js';
import getWN8 from '../core/blitz/getWN8.js';
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
import resolveTankName from '../core/blitz/resolveTankName.js';
import sumStats from '../core/blitz/sumStats.js';
import { tankopedia } from '../core/blitz/tankopedia.js';
import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js';
import last5AM from '../core/blitzstars/last5AM.js';
import { tankAverages } from '../core/blitzstars/tankAverages.js';
import cmdName from '../core/interaction/cmdName.js';
import fullBlitzStarsStats from '../core/interaction/fullBlitzStarsStats.js';
import infoEmbed from '../core/interaction/infoEmbed.js';
import { supportBlitzStars } from '../core/interaction/supportBlitzStars.js';
import addUsernameOption from '../core/options/addUsernameOption.js';
import { args } from '../core/process/args.js';
@@ -75,36 +78,88 @@ export default {
tankStatsOverTime[0] = accumulatedStats;
}
const rows = Object.entries(tankStatsOverTime).map(
([tankId, tankStats]) => {
const career = careerStats[tankId as unknown as number];
const tankStatsOverTimeEntries = Object.entries(tankStatsOverTime);
const todayWN8s = tankStatsOverTimeEntries.reduce<Record<number, number>>(
(accumulator, [tankIdString, tankStats]) => {
const tankId = Number(tankIdString);
return (
<Breakdown.Row
key={tankId}
name={tankId === '0' ? 'Today' : resolveTankName(Number(tankId))}
winrate={tankStats.wins / tankStats.battles}
careerWinrate={career.wins / career.battles}
WN8={-Infinity}
careerWN8={-Infinity}
damage={tankStats.damage_dealt / tankStats.battles}
careerDamage={career.damage_dealt / career.battles}
survival={tankStats.survived_battles / tankStats.battles}
careerSurvival={career.survived_battles / career.battles}
battles={tankStats.battles}
careerBattles={career.battles}
icon={
tankId === '0'
? undefined
: tankopedia[tankId as unknown as number].images.normal
}
/>
);
return tankId === 0
? accumulator
: {
...accumulator,
[tankId]: getWN8(tankAverages[tankId].all, tankStats),
};
},
{},
);
const careerWN8s = tankStatsOverTimeEntries.reduce<Record<number, number>>(
(accumulator, [tankIdString, tankStats]) => {
const tankId = Number(tankIdString);
return tankId === 0
? accumulator
: {
...accumulator,
[tankId]: getWN8(tankAverages[tankId].all, careerStats[tankId]),
};
},
{},
);
const todayWN8sEntries = Object.entries(todayWN8s);
const careerWN8sEntries = Object.entries(careerWN8s);
todayWN8s[0] =
todayWN8sEntries.reduce(
(accumulator, [tankIdString, wn8]) =>
accumulator + wn8 * tankStatsOverTime[Number(tankIdString)].battles,
0,
) /
todayWN8sEntries.reduce(
(accumulator, [tankIdString]) =>
accumulator + tankStatsOverTime[Number(tankIdString)].battles,
0,
);
careerWN8s[0] =
careerWN8sEntries.reduce(
(accumulator, [tankIdString, wn8]) =>
accumulator + wn8 * careerStats[Number(tankIdString)].battles,
0,
) /
careerWN8sEntries.reduce(
(accumulator, [tankIdString]) =>
accumulator + careerStats[Number(tankIdString)].battles,
0,
);
const rows = tankStatsOverTimeEntries.map(([tankIdString, tankStats]) => {
const tankId = Number(tankIdString);
const career = careerStats[tankId];
return (
<Breakdown.Row
key={tankId}
name={tankId === 0 ? 'Total' : resolveTankName(Number(tankIdString))}
winrate={tankStats.wins / tankStats.battles}
careerWinrate={career.wins / career.battles}
WN8={todayWN8s[tankId]}
careerWN8={careerWN8s[tankId]}
damage={tankStats.damage_dealt / tankStats.battles}
careerDamage={career.damage_dealt / career.battles}
survival={tankStats.survived_battles / tankStats.battles}
careerSurvival={career.survived_battles / career.battles}
battles={tankStats.battles}
careerBattles={career.battles}
icon={
tankId === 0
? undefined
: tankopedia[tankIdString as unknown as number].images.normal
}
/>
);
});
const image = await render(
<Wrapper>
<Wrapper size={WrapperSize.Roomy}>
<TitleBar
name={accountInfo[id].nickname}
nameDiscriminator={
@@ -125,6 +180,7 @@ export default {
<PoweredByBlitzStars />
</Wrapper>,
WrapperSize.Roomy,
);
const actionRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
@@ -133,6 +189,15 @@ export default {
);
await interaction.editReply({
embeds:
rows.length >= 6
? [
infoEmbed(
'Very large image!',
'Zoom in or click "Open in Browser."',
),
]
: undefined,
files: [image],
components: [actionRow],
});
+12 -5
View File
@@ -1,3 +1,4 @@
import getWN8Percentile from '../../../core/blitz/getWN8Percentile.js';
import { RowDiscriminator } from './RowDiscriminator.js';
import { RowStat } from './RowStat.js';
@@ -22,8 +23,8 @@ export function Row({
careerWinrate,
WN8,
careerWN8,
damage: averageDamage,
careerDamage: careerAverageDamage,
damage,
careerDamage,
survival,
careerSurvival,
battles,
@@ -39,11 +40,17 @@ export function Row({
career={`${(careerWinrate * 100).toFixed(2)}%`}
delta={winrate - careerWinrate}
/>
<RowStat
name="WN8"
value={WN8.toFixed(0)}
career={careerWN8.toFixed(0)}
percentile={getWN8Percentile(WN8)}
/>
<RowStat
name="Damage"
value={averageDamage.toFixed(2)}
career={careerAverageDamage.toFixed(2)}
delta={averageDamage - careerAverageDamage}
value={damage.toFixed(2)}
career={careerDamage.toFixed(2)}
delta={damage - careerDamage}
/>
<RowStat
name="Survival"
@@ -1,13 +1,22 @@
import { Percentile } from '../../../constants/percentiles.js';
import { theme } from '../../../stitches.config.js';
import PercentileIndicator from '../../PercentileIndicator.js';
export interface RowStatProps {
name: string;
value: string;
career: string;
delta?: number;
percentile?: Percentile;
}
export function RowStat({ name, value, career, delta }: RowStatProps) {
export function RowStat({
name,
value,
career,
delta,
percentile,
}: RowStatProps) {
return (
<div
style={{
@@ -31,7 +40,7 @@ export function RowStat({ name, value, career, delta }: RowStatProps) {
justifyContent: 'center',
}}
>
{delta !== undefined && delta !== 0 && (
{percentile === undefined && delta !== undefined && delta !== 0 && (
<img
src={
(delta ?? 0) > 0
@@ -41,6 +50,9 @@ export function RowStat({ name, value, career, delta }: RowStatProps) {
style={{ width: 12, height: 12 }}
/>
)}
{percentile !== undefined && (
<PercentileIndicator percentile={percentile} />
)}
<span
style={{
+2 -2
View File
@@ -17,7 +17,7 @@ export default function GenericAllStats({
['Winrate', `${(100 * (stats.wins / stats.battles)).toFixed(2)}%`],
[
'WN8',
supplementaryStats?.WN8.toFixed(0) ?? -Infinity,
supplementaryStats?.WN8.toFixed(0),
supplementaryStats
? getWN8Percentile(supplementaryStats.WN8)
: undefined,
@@ -31,7 +31,7 @@ export default function GenericAllStats({
['Wins', stats.wins],
['Losses', stats.losses],
['Average damage', (stats.damage_dealt / stats.battles).toFixed(0)],
['Average tier', supplementaryStats?.tier.toFixed(2) ?? -Infinity],
['Average tier', supplementaryStats?.tier.toFixed(2)],
['Average XP', (stats.xp / stats.battles).toFixed(0)],
['Average shots', (stats.shots / stats.battles).toFixed(2)],
['Average hits', (stats.hits / stats.battles).toFixed(2)],
@@ -31,7 +31,7 @@ export default function GenericStatsRow({ stat }: GenericStatsRowProps) {
gap: 4,
}}
>
{stat[2] && <PercentileIndicator percentile={stat[2]} />}
{stat[2] !== undefined && <PercentileIndicator percentile={stat[2]} />}
{stat[1]}
</span>
</div>
+3 -5
View File
@@ -2,8 +2,8 @@ import { Percentile } from '../../constants/percentiles.js';
import GenericStatsColumn from './components/GenericStatsColumn.js';
export type Stat =
| [string, string | number]
| [string, string | number, Percentile | undefined];
| [string, string | number | undefined]
| [string, string | number | undefined, Percentile | undefined];
export interface GenericStatsProps {
stats: Stat[];
@@ -14,9 +14,7 @@ export default function GenericStats({
stats,
columnCount = 2,
}: GenericStatsProps) {
const filteredStats = stats.filter(
([, value]) => `${value}` !== `${-Infinity}`,
);
const filteredStats = stats.filter(([, value]) => value !== undefined);
const itemsPerRow = Math.ceil(filteredStats.length / columnCount);
const columns: Stat[][] = [];
+18 -4
View File
@@ -1,11 +1,25 @@
import { ReactNode } from 'react';
import { theme } from '../stitches.config.js';
export interface WrapperProps {
children: ReactNode;
export enum WrapperSize {
Regular,
Roomy,
}
export default function Wrapper({ children }: WrapperProps) {
export interface WrapperProps {
children: ReactNode;
size?: WrapperSize;
}
export const WRAPPER_SIZE_WIDTHS: Record<WrapperSize, number> = {
[WrapperSize.Regular]: 640,
[WrapperSize.Roomy]: 800,
};
export default function Wrapper({
children,
size = WrapperSize.Regular,
}: WrapperProps) {
return (
<div
style={{
@@ -13,7 +27,7 @@ export default function Wrapper({ children }: WrapperProps) {
flexDirection: 'column',
padding: 16,
gap: 32,
width: 640,
width: WRAPPER_SIZE_WIDTHS[size],
background: 'url(https://i.imgur.com/PhS06NJ.png)',
color: theme.colors.textHighContrast,
}}
+12
View File
@@ -0,0 +1,12 @@
import sumStats from '../blitz/sumStats.js';
import { emptyAllStats } from './getTankStatsOverTime.js';
import { tankAverages } from './tankAverages.js';
console.log('Calculating player average...');
export const playerAverage = Object.entries(tankAverages).reduce(
(accumulator, [, tankAverage]) => {
return sumStats([accumulator, tankAverage.all]);
},
emptyAllStats,
);
console.log('Calculated player average');
File renamed without changes.
+1 -1
View File
@@ -3,7 +3,7 @@ export type TableInput = TableInputEntry[];
export default function cleanTable(input: TableInput) {
return input
.filter((array) => array[1] !== `${-Infinity}`)
.filter((array) => array[1] !== undefined)
.map((array) => (array.length === 0 ? '' : `**${array[0]}**: ${array[1]}`))
.join('\n');
}
+6 -2
View File
@@ -2,6 +2,7 @@ import { Resvg } from '@resvg/resvg-js';
import { readFile } from 'fs';
import { ReactNode } from 'react';
import satori from 'satori';
import { WRAPPER_SIZE_WIDTHS, WrapperSize } from '../../components/Wrapper.js';
const FONT_NAME = 'Roboto';
const FONT_FILES = ['Roboto', 'Roboto-Bold', 'Roboto-Black'];
@@ -20,9 +21,12 @@ const [robotoFlex, robotoFlexBold, robotoFlexBlack] = await Promise.all(
);
console.log('Fonts imported');
export default async function render(element: ReactNode) {
export default async function render(
element: ReactNode,
size: WrapperSize = WrapperSize.Regular,
) {
const svg = await satori(element, {
width: 640,
width: WRAPPER_SIZE_WIDTHS[size],
fonts: [
{ data: robotoFlex, name: FONT_NAME, weight: 400 },
{ data: robotoFlexBold, name: FONT_NAME, weight: 700 },