feat: wm8 and average tier calculation

This commit is contained in:
TresAbhi committed 2023-06-01 18:36:39 +00:00
1 parent c2fca42a86
commit a12f969251
15 files changed
+306 -319

No files matched your search

+21 -17
View File
@@ -1,8 +1,10 @@
import { EmbedBuilder, SlashCommandBuilder } from 'discord.js'; import { SlashCommandBuilder } from 'discord.js';
import packageJSON from '../../package.json' assert { type: 'json' }; import packageJSON from '../../package.json' assert { type: 'json' };
import { ACCENT_COLOR } from '../constants/colors.js';
import { tankopedia } from '../core/blitz/tankopedia.js'; import { tankopedia } from '../core/blitz/tankopedia.js';
import { tankAverages } from '../core/blitzstars/tankaverages.js';
import cleanTable from '../core/interaction/cleanTable.js';
import cmdName from '../core/interaction/cmdName.js'; import cmdName from '../core/interaction/cmdName.js';
import infoEmbed from '../core/interaction/infoEmbed.js';
import getClientId from '../core/process/getClientId.js'; import getClientId from '../core/process/getClientId.js';
import { CommandRegistry } from '../events/interactionCreate.js'; import { CommandRegistry } from '../events/interactionCreate.js';
import { client } from '../index.js'; import { client } from '../index.js';
@@ -24,21 +26,23 @@ export default {
await interaction.editReply({ await interaction.editReply({
embeds: [ embeds: [
new EmbedBuilder() infoEmbed(
.setTitle(`${client.user?.username} debug information`) `${client.user?.username} debug information`,
.setColor(ACCENT_COLOR) cleanTable([
.setDescription( ['Version', packageJSON.version],
`**Version**: ${packageJSON.version}\n**Uptime**: ${Math.floor( ['Client ID', getClientId()],
uptime / 1000 / 60 / 60 / 24, ['Tag', interaction.client.user.tag],
)}d ${Math.floor((uptime / 1000 / 60 / 60) % 24)}h ${Math.floor( [
(uptime / 1000 / 60) % 60, 'Uptime',
)}m ${Math.floor((uptime / 1000) % 60)}s ${Math.floor( `${Math.floor(uptime / 1000 / 60 / 60 / 24)}d ${Math.floor(
uptime % 1000, (uptime / 1000 / 60 / 60) % 24,
)}ms\n**Tankopedia**: ${ )}h ${Math.floor((uptime / 1000 / 60) % 60)}m ${Math.floor(
tankopedia ? 'cached' : 'not cached' (uptime / 1000) % 60,
}\n**Client ID**: ${getClientId()}\n**Tag**: ${ )}s ${Math.floor(uptime % 1000)}ms`,
interaction.client.user.tag ],
}`, ['Tankopedia cached', `${tankopedia !== undefined}`],
['Tank averages cached', `${tankAverages !== undefined}`],
]),
), ),
], ],
}); });
+39 -45
View File
@@ -3,7 +3,7 @@ import {
ButtonBuilder, ButtonBuilder,
SlashCommandBuilder, SlashCommandBuilder,
} from 'discord.js'; } from 'discord.js';
import GenericStats from '../components/GenericStats/index.js'; import GenericAllStats from '../components/GenericAllStats.js';
import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js'; import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js';
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js'; import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
import TitleBar from '../components/TitleBar.js'; import TitleBar from '../components/TitleBar.js';
@@ -11,11 +11,14 @@ import Wrapper from '../components/Wrapper.js';
import { BLITZ_SERVERS } from '../constants/servers.js'; import { BLITZ_SERVERS } from '../constants/servers.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 getWN8 from '../core/blitz/getWN8.js';
import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; 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 getPeriodNow from '../core/blitzstars/getPeriodNow.js'; import getPeriodNow from '../core/blitzstars/getPeriodNow.js';
import getPeriodicStart from '../core/blitzstars/getPeriodStart.js'; import getPeriodicStart 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 cmdName from '../core/interaction/cmdName.js'; import cmdName from '../core/interaction/cmdName.js';
import fullBlitzStarsStats from '../core/interaction/fullBlitzStarsStats.js'; import fullBlitzStarsStats from '../core/interaction/fullBlitzStarsStats.js';
import { supportBlitzStars } from '../core/interaction/supportBlitzStars.js'; import { supportBlitzStars } from '../core/interaction/supportBlitzStars.js';
@@ -27,12 +30,16 @@ import addUsernameOption from '../core/options/addUsernameOption.js';
import { args } from '../core/process/args.js'; import { args } from '../core/process/args.js';
import render from '../core/ui/render.js'; import render from '../core/ui/render.js';
import { CommandRegistry } from '../events/interactionCreate.js'; import { CommandRegistry } from '../events/interactionCreate.js';
import { AccountInfo, AllStats } from '../types/accountInfo.js'; import {
AccountInfo,
AllStats,
SupplementaryStats,
} from '../types/accountInfo.js';
import { PlayerClanData } from '../types/playerClanData.js'; import { PlayerClanData } from '../types/playerClanData.js';
export default { export default {
inProduction: true, inProduction: true,
inDevelopment: false, inDevelopment: true,
inPublic: true, inPublic: true,
command: new SlashCommandBuilder() command: new SlashCommandBuilder()
@@ -53,20 +60,41 @@ export default {
`https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${args['wargaming-application-id']}&account_id=${id}&extra=clan`, `https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${args['wargaming-application-id']}&account_id=${id}&extra=clan`,
); );
let stats: AllStats; let stats: AllStats;
let supplementaryStats: SupplementaryStats | undefined;
if (period === 'career') { if (period === 'career') {
stats = accountInfo[id].statistics.all; stats = accountInfo[id].statistics.all;
} else { } else {
stats = sumStats( const tankStatsOverTime = await getTankStatsOverTime(
Object.entries(
await getTankStatsOverTime(
server, server,
id, id,
getPeriodicStart(period), getPeriodicStart(period),
getPeriodNow(), getPeriodNow(),
),
).map(([, stats]) => stats),
); );
const entries = Object.entries(tankStatsOverTime);
const totalBattles = entries.reduce(
(accumulator, [, stats]) => accumulator + stats.battles,
0,
);
supplementaryStats = {
tier:
entries.reduce((accumulator, [tankIdString, stats]) => {
const tankId = Number(tankIdString);
const tankTier = tankopedia[tankId].tier;
return accumulator + tankTier * stats.battles;
}, 0) / totalBattles,
wn8:
entries.reduce((accumulator, [tankIdString, stats]) => {
const tankId = Number(tankIdString);
const tankWn8 = getWN8(tankAverages[tankId].all, stats);
return accumulator + tankWn8 * stats.battles;
}, 0) / totalBattles,
};
stats = sumStats(entries.map(([, stats]) => stats));
} }
const image = await render( const image = await render(
@@ -88,43 +116,9 @@ export default {
{stats.battles === 0 && <NoBattlesInPeriod />} {stats.battles === 0 && <NoBattlesInPeriod />}
{stats.battles > 0 && ( {stats.battles > 0 && (
<GenericStats <GenericAllStats
stats={[ stats={stats}
[ supplementaryStats={supplementaryStats}
'Winrate',
`${(100 * (stats.wins / stats.battles)).toFixed(2)}%`,
],
[
'Survival',
`${(100 * (stats.survived_battles / stats.battles)).toFixed(
2,
)}%`,
],
['Accuracy', `${((stats.hits / stats.shots) * 100).toFixed(2)}%`],
['Battles', stats.battles],
['Wins', stats.wins],
['Losses', stats.losses],
[
'Average damage',
(stats.damage_dealt / stats.battles).toFixed(0),
],
['Average XP', (stats.xp / stats.battles).toFixed(0)],
['Average shots', (stats.shots / stats.battles).toFixed(2)],
['Average hits', (stats.hits / stats.battles).toFixed(2)],
['Average kills', (stats.frags / stats.battles).toFixed(2)],
['Average spots', (stats.spotted / stats.battles).toFixed(2)],
[
'Damage ratio',
(stats.damage_dealt / stats.damage_received).toFixed(2),
],
[
'Kills to death ratio',
(
stats.frags /
(stats.battles - stats.survived_battles)
).toFixed(2),
],
]}
/> />
)} )}
+18 -47
View File
@@ -3,7 +3,7 @@ import {
ButtonBuilder, ButtonBuilder,
SlashCommandBuilder, SlashCommandBuilder,
} from 'discord.js'; } from 'discord.js';
import GenericStats from '../components/GenericStats/index.js'; import GenericAllStats from '../components/GenericAllStats.js';
import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js'; import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js';
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js'; import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
import TitleBar from '../components/TitleBar.js'; import TitleBar from '../components/TitleBar.js';
@@ -12,6 +12,7 @@ import { BLITZ_SERVERS } from '../constants/servers.js';
import tanksAutocomplete from '../core/autocomplete/tanks.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 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 resolveTankId from '../core/blitz/resolveTankId.js';
import resolveTankName from '../core/blitz/resolveTankName.js'; import resolveTankName from '../core/blitz/resolveTankName.js';
@@ -21,6 +22,7 @@ import getPeriodicStart from '../core/blitzstars/getPeriodStart.js';
import getTankStatsOverTime, { import getTankStatsOverTime, {
emptyAllStats, emptyAllStats,
} from '../core/blitzstars/getTankStatsOverTime.js'; } from '../core/blitzstars/getTankStatsOverTime.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 fullBlitzStarsStats from '../core/interaction/fullBlitzStarsStats.js';
import { supportBlitzStars } from '../core/interaction/supportBlitzStars.js'; import { supportBlitzStars } from '../core/interaction/supportBlitzStars.js';
@@ -38,7 +40,7 @@ import { TanksStats } from '../types/tanksStats.js';
export default { export default {
inProduction: true, inProduction: true,
inDevelopment: false, inDevelopment: true,
inPublic: true, inPublic: true,
command: new SlashCommandBuilder() command: new SlashCommandBuilder()
@@ -64,28 +66,29 @@ export default {
`https://api.wotblitz.${server}/wotb/tanks/stats/?application_id=${args['wargaming-application-id']}&account_id=${id}`, `https://api.wotblitz.${server}/wotb/tanks/stats/?application_id=${args['wargaming-application-id']}&account_id=${id}`,
); );
let stats: AllStats; let stats: AllStats;
const tankId = Number(tank);
if (period === 'career') { if (period === 'career') {
stats = stats =
tankStats[id].find((stats) => stats.tank_id === Number(tank))?.all ?? tankStats[id].find((stats) => stats.tank_id === tankId)?.all ??
emptyAllStats; emptyAllStats;
} else { } else {
stats = ( const tankStatsOverTime = await getTankStatsOverTime(
await getTankStatsOverTime(
server, server,
id, id,
getPeriodicStart(period), getPeriodicStart(period),
getPeriodNow(), getPeriodNow(),
) );
)[Number(tank)];
stats = tankStatsOverTime[tankId] ?? emptyAllStats;
} }
const image = await render( const image = await render(
<Wrapper> <Wrapper>
<TitleBar <TitleBar
name={accountInfo[id].nickname} name={accountInfo[id].nickname}
nameDiscriminator={`(${resolveTankName(Number(tank))})`} nameDiscriminator={`(${resolveTankName(tankId)})`}
image={tankopedia[Number(tank)].images.normal} image={tankopedia[tankId].images.normal}
description={`${ description={`${
statPeriodNames[period] statPeriodNames[period]
} • ${new Date().toDateString()} • ${BLITZ_SERVERS[server]}`} } • ${new Date().toDateString()} • ${BLITZ_SERVERS[server]}`}
@@ -93,44 +96,12 @@ export default {
{stats.battles === 0 && <NoBattlesInPeriod />} {stats.battles === 0 && <NoBattlesInPeriod />}
{stats.battles > 0 && ( {stats.battles > 0 && (
// TODO: GenericStats generator for AllStats <GenericAllStats
<GenericStats stats={stats}
stats={[ supplementaryStats={{
[ tier: tankopedia[tankId].tier,
'Winrate', wn8: getWN8(tankAverages[tankId].all, stats),
`${(100 * (stats.wins / stats.battles)).toFixed(2)}%`, }}
],
[
'Survival',
`${(100 * (stats.survived_battles / stats.battles)).toFixed(
2,
)}%`,
],
['Accuracy', `${((stats.hits / stats.shots) * 100).toFixed(2)}%`],
['Battles', stats.battles],
['Wins', stats.wins],
['Losses', stats.losses],
[
'Average damage',
(stats.damage_dealt / stats.battles).toFixed(0),
],
['Average XP', (stats.xp / stats.battles).toFixed(0)],
['Average shots', (stats.shots / stats.battles).toFixed(2)],
['Average hits', (stats.hits / stats.battles).toFixed(2)],
['Average kills', (stats.frags / stats.battles).toFixed(2)],
['Average spots', (stats.spotted / stats.battles).toFixed(2)],
[
'Damage ratio',
(stats.damage_dealt / stats.damage_received).toFixed(2),
],
[
'Kills to death ratio',
(
stats.frags /
(stats.battles - stats.survived_battles)
).toFixed(2),
],
]}
/> />
)} )}
+1 -1
View File
@@ -30,7 +30,7 @@ import { TanksStats } from '../types/tanksStats.js';
export default { export default {
inProduction: true, inProduction: true,
inDevelopment: false, inDevelopment: true,
inPublic: true, inPublic: true,
command: new SlashCommandBuilder() command: new SlashCommandBuilder()
+44
View File
@@ -0,0 +1,44 @@
import { AllStats, SupplementaryStats } from '../types/accountInfo.js';
import GenericStats from './GenericStats/index.js';
export interface GenericAllStatsProps {
stats: AllStats;
supplementaryStats?: SupplementaryStats;
}
export default function GenericAllStats({
stats,
supplementaryStats,
}: GenericAllStatsProps) {
return (
<GenericStats
stats={[
['Winrate', `${(100 * (stats.wins / stats.battles)).toFixed(2)}%`],
['WN8', supplementaryStats?.wn8.toFixed(0) ?? -Infinity],
[
'Survival',
`${(100 * (stats.survived_battles / stats.battles)).toFixed(2)}%`,
],
['Accuracy', `${((stats.hits / stats.shots) * 100).toFixed(2)}%`],
['Battles', stats.battles],
['Wins', stats.wins],
['Losses', stats.losses],
['Average damage', (stats.damage_dealt / stats.battles).toFixed(0)],
['Average tier', supplementaryStats?.tier.toFixed(2) ?? -Infinity],
['Average XP', (stats.xp / stats.battles).toFixed(0)],
['Average shots', (stats.shots / stats.battles).toFixed(2)],
['Average hits', (stats.hits / stats.battles).toFixed(2)],
['Average kills', (stats.frags / stats.battles).toFixed(2)],
['Average spots', (stats.spotted / stats.battles).toFixed(2)],
[
'Damage ratio',
(stats.damage_dealt / stats.damage_received).toFixed(2),
],
[
'Kills to death ratio',
(stats.frags / (stats.battles - stats.survived_battles)).toFixed(2),
],
]}
/>
);
}
+3 -1
View File
@@ -11,7 +11,9 @@ export default function GenericStats({
stats, stats,
columnCount = 2, columnCount = 2,
}: GenericStatsProps) { }: GenericStatsProps) {
const filteredStats = stats.filter(([, value]) => value !== `${-Infinity}`); const filteredStats = stats.filter(
([, value]) => `${value}` !== `${-Infinity}`,
);
const itemsPerRow = Math.ceil(filteredStats.length / columnCount); const itemsPerRow = Math.ceil(filteredStats.length / columnCount);
const columns: Stat[][] = []; const columns: Stat[][] = [];
+45
View File
@@ -0,0 +1,45 @@
import { AllStats } from '../../types/accountInfo.js';
/**
* Formula from https://web.archive.org/web/20190105064817/http://wiki.wnefficiency.net/pages/WN8
*/
export default function getWN8(expected: AllStats, average: AllStats) {
const avgDmg = average.damage_dealt / average.battles;
const avgSpot = average.spotted / average.battles;
const avgFrag = average.frags / average.battles;
const avgDef = average.dropped_capture_points / average.battles;
const avgWinRate = average.wins / average.battles;
const expDmg = expected.damage_dealt / expected.battles;
const expSpot = expected.spotted / expected.battles;
const expFrag = expected.frags / expected.battles;
const expDef = expected.dropped_capture_points / expected.battles;
const expWinRate = expected.wins / expected.battles;
const rDAMAGE = avgDmg / expDmg;
const rSPOT = avgSpot / expSpot;
const rFRAG = avgFrag / expFrag;
const rDEF = avgDef / expDef;
const rWIN = avgWinRate / expWinRate;
const rWINc = Math.max(0, (rWIN - 0.71) / (1 - 0.71));
const rDAMAGEc = Math.max(0, (rDAMAGE - 0.22) / (1 - 0.22));
const rFRAGc = Math.max(
0,
Math.min(rDAMAGEc + 0.2, (rFRAG - 0.12) / (1 - 0.12)),
);
const rSPOTc = Math.max(
0,
Math.min(rDAMAGEc + 0.1, (rSPOT - 0.38) / (1 - 0.38)),
);
const rDEFc = Math.max(0, Math.min(rDAMAGEc + 0.1, (rDEF - 0.1) / (1 - 0.1)));
const WN8 =
980 * rDAMAGEc +
210 * rDAMAGEc * rFRAGc +
155 * rFRAGc * rSPOTc +
75 * rDEFc * rFRAGc +
145 * Math.min(1.8, rWINc);
return WN8;
}
+31 -127
View File
@@ -1,145 +1,49 @@
import { args } from '../process/args.js'; import { WargamingResponse } from '../../types/wargamingResponse.js';
import isDev from '../process/isDev.js'; import isDev from '../process/isDev.js';
import URLToBase64 from '../ui/URLToBase64.js'; import URLToBase64 from '../ui/URLToBase64.js';
import getWargamingResponse from './getWargamingResponse.js';
/*
"1": {
"name": "T-34",
"nation": "ussr",
"is_premium": false,
"tier": 5,
"cost": {
"price_credit": 400000,
"price_gold": 0
},
"images": {
"preview": "/api/bs-cache/tank-icons/https%3A%2F%2Fglossary-eu-static.gcdn.co%2Ficons%2Fwotb%2Fcurrent%2Fuploaded%2Fvehicles%2Fhd_thumbnail%2FT-34.png",
"normal": "http://glossary-eu-static.gcdn.co/icons/wotb/current/uploaded/vehicles/hd/T-34.png"
},
"tank_id": 1,
"type": "mediumTank",
"description": "The legend of the Soviet armored forces and the most widely-produced Soviet tank of World War II, with a total of 33,805 vehicles manufactured. Three variants of this model were produced at several Soviet factories from 1940 through 1944."
},
*/
export interface Tankopedia { export interface Tankopedia {
[id: number]: { [id: number]: {
description: string;
engines: number[];
guns: number[];
is_premium: boolean;
name: string; name: string;
nation: string; nation: string;
next_tanks: { [id: number]: number }; is_premium: boolean;
prices_xp: { [id: number]: number }; tier: number;
suspensions: number[]; cost: { price_credit: number; price_gold: number };
images: { preview: string; normal: string };
tank_id: number; tank_id: number;
tier: number;
turrets: number[] | null;
type: string; type: string;
cost: { description: string;
price_credit: number;
price_gold: number;
}; };
default_profile: {
battle_level_range_max: number;
battle_level_range_min: number;
engine_id: number;
firepower: number;
gun_id: number;
hp: number;
hull_hp: number;
hull_weight: number;
is_default: boolean;
maneuverability: number;
max_ammo: number;
max_weight: number;
profile_id: string;
protection: number;
shot_efficiency: number;
signal_range: number;
speed_backward: number;
suspension_id: number;
turret_id: number;
weight: number;
armor: {
hull: {
front: number;
rear: number;
sides: number;
};
turret: {
front: number;
rear: number;
sides: number;
};
};
engine: {
fire_chance: number;
name: string;
power: number;
tier: number;
weight: number;
};
gun: {
aim_time: number;
caliber: number;
clip_capacity: number;
clip_reload_time: number;
dispersion: number;
fire_rate: number;
move_down_arc: number;
move_up_arc: number;
name: string;
reload_time: number;
tier: number;
traverse_speed: number;
weight: number;
};
shells: {
damage: number;
penetration: number;
type: string;
};
suspension: {
load_limit: number;
name: string;
tier: number;
traverse_speed: number;
weight: number;
};
turret: {
hp: number;
name: string;
tier: number;
traverse_left_arc: number;
traverse_right_arc: number;
traverse_speed: number;
view_range: number;
weight: number;
};
};
images: {
normal: string;
preview: string;
};
modules_tree: {
[id: number]: {
is_default: boolean;
module_id: number;
name: string;
next_modules: number[] | null;
next_tanks: number[] | null;
price_credit: number;
price_xp: number;
type: string;
};
};
};
}
export interface TankopediaInfo {
achievement_sections: { [name: string]: { name: string; order: number } };
tanks_updated_at: number;
languages: { [name: string]: string };
vehicle_types: { [name: string]: string };
vehicle_nations: { [name: string]: string };
game_version: string;
} }
console.log('Caching tankopedia...'); console.log('Caching tankopedia...');
export const tankopedia = await getWargamingResponse<Tankopedia>( export const tankopedia = (
`https://api.wotblitz.com/wotb/encyclopedia/vehicles/?application_id=${args['wargaming-application-id']}`, (await (
); await fetch('https://www.blitzstars.com/bs-tankopedia.json')
).json()) as WargamingResponse<Tankopedia> & { status: 'ok' }
).data;
console.log('Cached tankopedia'); console.log('Cached tankopedia');
console.log('Caching tankopedia info...');
export const tankopediaInfo = await getWargamingResponse<TankopediaInfo>(
`https://api.wotblitz.com/wotb/encyclopedia/info/?application_id=${args['wargaming-application-id']}`,
);
console.log('Cached tankopedia info');
/** /**
* @deprecated * @deprecated
*/ */
+9 -1
View File
@@ -3,8 +3,16 @@ import { StatPeriod } from '../options/addStatPeriodChoices.js';
export default function getPeriodicStart(period: StatPeriod) { export default function getPeriodicStart(period: StatPeriod) {
if (period === 'career') { if (period === 'career') {
return -Infinity; return -Infinity;
} else if (period === 'today') {
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);
return now.getTime() / 1000;
} else { } else {
const daysAgo = period === 'today' ? 0 : Number(period) - 1; const daysAgo = Number(period) - 1;
const periodStart = new Date(); const periodStart = new Date();
periodStart.setDate(periodStart.getDate() - daysAgo); periodStart.setDate(periodStart.getDate() - daysAgo);
-15
View File
@@ -1,15 +0,0 @@
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
import { PlayerStats } from '../../types/playerStats.js';
export default async function getPlayerStats(
interaction: ChatInputCommandInteraction<CacheType>,
command: string,
id: number,
callback: (playerStats: PlayerStats) => void,
) {
fetch(`https://www.blitzstars.com/api/playerstats/${id}`).then(
async (response) => {
callback((await response.json()) as PlayerStats);
},
);
}
+2 -2
View File
@@ -47,8 +47,8 @@ export type TankHistory = TankHistoryNode[];
export default async function getTankStatsOverTime( export default async function getTankStatsOverTime(
server: BlitzServer, server: BlitzServer,
id: number, id: number,
start = -Infinity, start: number,
end = Infinity, end: number,
) { ) {
const latestTankStatsRaw = await getWargamingResponse<TanksStats>( const latestTankStatsRaw = await getWargamingResponse<TanksStats>(
`https://api.wotblitz.${server}/wotb/tanks/stats/?application_id=${args['wargaming-application-id']}&account_id=${id}`, `https://api.wotblitz.${server}/wotb/tanks/stats/?application_id=${args['wargaming-application-id']}&account_id=${id}`,
+90
View File
@@ -0,0 +1,90 @@
import { AllStats } from '../../types/accountInfo.js';
export interface SpecialStats {
winrate: number;
damageRatio: number;
kdr: number;
damagePerBattle: number;
killsPerBattle: number;
hitsPerBattle: number;
spotsPerBattle: number;
wpm: number;
dpm: number;
kpm: number;
hitRate: number;
survivalRate: number;
}
export type Percentiles = [
number,
number,
number,
number,
number,
number,
number,
number,
number,
];
export interface SpecialPercentiles {
winRate: Percentiles;
damageRatio: Percentiles;
kdr: Percentiles;
damagePerBattle: Percentiles;
killsPerBattle: Percentiles;
hitsPerBattle: Percentiles;
spotsPerBattle: Percentiles;
wpm: Percentiles;
dpm: Percentiles;
kpm: Percentiles;
hitRate: Percentiles;
survivalRate: Percentiles;
}
export interface MeanSd {
winrateMean: number;
winrateSd: number;
hitRateMean: number;
hitRateSd: number;
survivalRateMean: number;
survivalRateSd: number;
damageRatioMean: number;
damageRatioSd: number;
kdrMean: number;
kdrSd: number;
dpbMean: number;
dpbSd: number;
kpbMean: number;
kpbSd: number;
hpbMean: number;
hpbSd: number;
spbMean: number;
spbSd: number;
}
export interface IndividualTankAverages {
_id: number;
battle_life_time: number;
total_battle_life_time: number;
number_of_players: number;
tank_id: number;
all: AllStats;
special: SpecialStats;
percentiles: SpecialPercentiles;
percentiles_player_count: number;
meanSd: MeanSd;
shotEff: number;
last_update: number;
}
console.log('Caching tank averages...');
const tankAveragesRaw = (await (
await fetch('https://www.blitzstars.com/api/tankaverages.json')
).json()) as IndividualTankAverages[];
export const tankAverages: Record<number, IndividualTankAverages> = {};
Object.entries(tankAveragesRaw).forEach(([, tank]) => {
tankAverages[tank.tank_id] = tank;
});
console.log('Tank averages cached');
+3 -10
View File
@@ -18,16 +18,9 @@ export interface AllStats {
dropped_capture_points: number; dropped_capture_points: number;
} }
export interface SpecialStats { export interface SupplementaryStats {
winrate: number; wn8: number;
damageRatio: number; tier: number;
kdr: number;
dpb: number;
kpb: number;
hpb: number;
spb: number;
hitRate: number;
survivalRate: number;
} }
export interface ClanStats { export interface ClanStats {
-23
View File
@@ -1,23 +0,0 @@
import { BlitzStartsComputedPeriodicStatistics } from './statistics.js';
export type PlayerStats = {
clan: {
clan_id: number;
name: string;
tag: string;
};
statistics: BlitzStartsComputedPeriodicStatistics;
_id: string;
last_battle_time: number;
nickname: string;
account_id: number;
achievements: {
account_id: string;
medalLafayettePool: number;
medalRadleyWalters: number;
warrior: number;
jointVictoryCount: number;
};
region: string;
__v: number;
}[];
-30
View File
@@ -1,30 +0,0 @@
import { AllStats, SpecialStats } from './accountInfo.js';
export interface BlitzStartsComputedPeriodicStatistics {
all: AllStats;
wn7: number;
wn8: number;
avg_tier: number;
}
export interface PeriodStatistics
extends BlitzStartsComputedPeriodicStatistics {
special: SpecialStats;
pwp: number;
}
export interface PlayerPeriodicStatsCollection {
statistics: PeriodStatistics;
period30d: PeriodStatistics;
period90d: PeriodStatistics;
_id: string;
nickname: string;
nickname_lowercase: string;
region: string;
last_battle_time: number;
__v: number;
updatedAt: string;
createdAt: string;
}