mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 11:39:50 +02:00
fix: more imports
This commit is contained in:
1 parent
25cfb7db74
commit
4f24db0956
182 files changed
+456
-452
No files matched your search
@@ -0,0 +1,88 @@
|
||||
import { assertSecret, EventManager, Region } from '@blitzkit/core';
|
||||
import { patientFetch } from '../../../website/src/core/blitzkit/patientFetch';
|
||||
|
||||
const RETRY_ERRORS = ['REQUEST_LIMIT_EXCEEDED', 'SOURCE_NOT_AVAILABLE'];
|
||||
|
||||
export const retryAbleBlitzFetchEvent = new EventManager();
|
||||
export const blitzFetchQueueAvailableEvent = new EventManager();
|
||||
|
||||
type BlitzResponse<Data extends object> =
|
||||
| {
|
||||
status: 'error';
|
||||
error: { field: string; message: string; code: 402; value: null };
|
||||
}
|
||||
| {
|
||||
status: 'ok';
|
||||
data: Data;
|
||||
};
|
||||
|
||||
const MAX_CALLS_PER_SECOND = 10;
|
||||
|
||||
const queue: { url: string; resolve: (data: object) => void }[] = [];
|
||||
let inProgress = 0;
|
||||
|
||||
function decrement() {
|
||||
inProgress--;
|
||||
blitzFetchQueueAvailableEvent.emit(undefined);
|
||||
manageQueue();
|
||||
}
|
||||
|
||||
async function manageQueue() {
|
||||
if (queue.length > 0 && inProgress < MAX_CALLS_PER_SECOND) {
|
||||
inProgress++;
|
||||
|
||||
const timeout = setTimeout(decrement, 1000);
|
||||
const request = queue.shift()!;
|
||||
const data = (await patientFetch(request.url)
|
||||
.then((response) => response.json())
|
||||
.catch((error) => ({ status: 'error', error }))) as BlitzResponse<
|
||||
typeof request.resolve
|
||||
>;
|
||||
|
||||
if (data.status === 'ok') {
|
||||
request.resolve(data.data);
|
||||
} else {
|
||||
if (RETRY_ERRORS.includes(data.error.message)) {
|
||||
retryAbleBlitzFetchEvent.emit(undefined);
|
||||
clearTimeout(timeout);
|
||||
setTimeout(() => {
|
||||
queue.push(request);
|
||||
decrement();
|
||||
}, 1000 / MAX_CALLS_PER_SECOND);
|
||||
} else {
|
||||
clearTimeout(timeout);
|
||||
decrement();
|
||||
|
||||
throw new Error(`Wargaming response error status: "${data.status}"`, {
|
||||
cause: `Message: "${data.error.message}"\nURL: "${request.url}"`,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type FetchBlitzParams = Record<string, string | number | undefined>;
|
||||
|
||||
export function fetchBlitz<Data extends object>(
|
||||
region: Region,
|
||||
path: string,
|
||||
params: FetchBlitzParams = {},
|
||||
) {
|
||||
return new Promise<Data>((resolve) => {
|
||||
queue.push({
|
||||
url: `https://api.wotblitz.${region}/wotb/${path}/?${Object.entries({
|
||||
application_id: assertSecret(
|
||||
process.env.NEXT_PUBLIC_WARGAMING_APPLICATION_ID,
|
||||
),
|
||||
...params,
|
||||
})
|
||||
.filter(([_, value]) => value !== undefined)
|
||||
.map(([key, value]) => `${key}=${encodeURIComponent(value!)}`)
|
||||
.join('&')}`,
|
||||
resolve(data) {
|
||||
resolve(data as Data);
|
||||
},
|
||||
});
|
||||
manageQueue();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { LEAGUES } from '@blitzkit/core';
|
||||
|
||||
export function getLeagueFromScore(score: number) {
|
||||
return LEAGUES.find(({ minScore }) => score >= minScore)!;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { RatingInfo, Region } from '@blitzkit/core';
|
||||
import { regionToRegionSubdomain } from '../../../website/src/core/blitz/regionToRegionSubdomain';
|
||||
import { context } from '../../../website/src/core/blitzkit/context';
|
||||
import { patientFetch } from '../../../website/src/core/blitzkit/patientFetch';
|
||||
|
||||
const cache: Partial<Record<Region, RatingInfo>> = {};
|
||||
|
||||
export async function getRatingInfo(region: Region) {
|
||||
if (cache[region]) return cache[region]!;
|
||||
|
||||
const response = await patientFetch(
|
||||
context === 'website'
|
||||
? `/api/${region}/rating/current/info`
|
||||
: `https://${regionToRegionSubdomain(
|
||||
region,
|
||||
)}.wotblitz.com/en/api/rating-leaderboards/season/`,
|
||||
undefined,
|
||||
);
|
||||
const data = (await response.json()) as RatingInfo;
|
||||
|
||||
cache[region] = data;
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
export * from './clans';
|
||||
export * from './constants';
|
||||
export * from './equipmentPrice';
|
||||
export * from './fetchBlitz';
|
||||
export * from './getLeagueFromScore';
|
||||
export * from './getRatingInfo';
|
||||
export * from './idToRegion';
|
||||
export * from './nations';
|
||||
export * from './permanentSkills';
|
||||
export * from './rating';
|
||||
export * from './regions';
|
||||
export * from './regionSubdomainToRegion';
|
||||
export * from './resolveNearPenetration';
|
||||
export * from './searchClansAcrossRegions';
|
||||
export * from './searchPlayersAcrossRegions';
|
||||
@@ -0,0 +1,5 @@
|
||||
import { Region, RegionSubdomain } from '@blitzkit/core';
|
||||
|
||||
export function regionSubdomainToRegion(regionDomain: RegionSubdomain): Region {
|
||||
return regionDomain === 'na' ? 'com' : regionDomain;
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
import { Region } from '@blitzkit/core';
|
||||
import fetchBlitz from '../../../website/src/core/blitz/fetchBlitz';
|
||||
import { fetchBlitz, Region } from '@blitzkit/core';
|
||||
import { ClanList } from './clans';
|
||||
|
||||
export default async function searchClansAcrossRegions(
|
||||
search: string,
|
||||
limit = 25,
|
||||
) {
|
||||
export async function searchClansAcrossRegions(search: string, limit = 25) {
|
||||
const trimmed = search.trim();
|
||||
if (trimmed.length < 3 && trimmed.length > 100) return [];
|
||||
const normalizedLimit = Math.floor(limit / 3);
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export const usernamePattern = /^[a-zA-Z0-9_]{3,24}$/;
|
||||
export const usernamePatternWithoutPosition = /[a-zA-Z0-9_]{3,24}/;
|
||||
@@ -0,0 +1,61 @@
|
||||
import { Region } from '@blitzkit/core';
|
||||
import { fetchBlitz } from '@blitzkit/core/src/blitz/fetchBlitz';
|
||||
import { usernamePattern } from './constants';
|
||||
|
||||
export interface AccountListItem {
|
||||
nickname: string;
|
||||
account_id: number;
|
||||
}
|
||||
export type AccountList = AccountListItem[];
|
||||
export type AccountListWithServer = (AccountListItem & {
|
||||
region: Region;
|
||||
})[];
|
||||
|
||||
export async function searchPlayersAcrossRegions(search: string, limit = 25) {
|
||||
const trimmedSearch = search.trim();
|
||||
const normalizedLimit = Math.floor(limit / 3);
|
||||
|
||||
if (usernamePattern.test(trimmedSearch)) {
|
||||
return (
|
||||
await Promise.all([
|
||||
fetchBlitz<AccountList>('com', 'account/list', {
|
||||
search,
|
||||
limit: normalizedLimit,
|
||||
}).then(
|
||||
(value) =>
|
||||
value &&
|
||||
value.map((account) => ({
|
||||
...account,
|
||||
region: 'com' as Region,
|
||||
})),
|
||||
),
|
||||
fetchBlitz<AccountList>('eu', 'account/list', {
|
||||
search,
|
||||
limit: normalizedLimit,
|
||||
}).then(
|
||||
(value) =>
|
||||
value &&
|
||||
value.map((account) => ({
|
||||
...account,
|
||||
region: 'eu' as Region,
|
||||
})),
|
||||
),
|
||||
fetchBlitz<AccountList>('asia', 'account/list', {
|
||||
search,
|
||||
limit: normalizedLimit,
|
||||
}).then(
|
||||
(value) =>
|
||||
value &&
|
||||
value.map((account) => ({
|
||||
...account,
|
||||
region: 'asia' as Region,
|
||||
})),
|
||||
),
|
||||
])
|
||||
)
|
||||
.filter(Boolean)
|
||||
.flat() as AccountListWithServer;
|
||||
} else {
|
||||
return [] as AccountListWithServer;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ProvisionDefinitions } from '@blitzkit/core/src/blitzkit/provisionDefinitions';
|
||||
import { ProvisionDefinitions } from '@blitzkit/core';
|
||||
import { checkConsumableProvisionInclusivity } from './checkConsumableProvisionInclusivity';
|
||||
import { GunDefinition, TankDefinition } from './tankDefinitions';
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { asset } from '@blitzkit/core/src/blitzkit/asset';
|
||||
import { fetchCdonLz4 } from '@blitzkit/core/src/blitzkit/fetchCdonLz4';
|
||||
import { asset, fetchCdonLz4 } from '@blitzkit/core';
|
||||
|
||||
export type CamouflageDefinitions = Record<
|
||||
number,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ConsumableEntry } from '@blitzkit/core/src/blitzkit/consumableDefinitions';
|
||||
import { ProvisionEntry } from '@blitzkit/core/src/blitzkit/provisionDefinitions';
|
||||
import { ConsumableEntry, ProvisionEntry } from '@blitzkit/core';
|
||||
import { GunDefinition, TankDefinition } from './tankDefinitions';
|
||||
|
||||
export function checkConsumableProvisionInclusivity(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SkillDefinitions } from '@blitzkit/core/src/blitzkit/skillDefinitions';
|
||||
import { SkillDefinitions } from '@blitzkit/core';
|
||||
import { permanentSkills } from '../blitz/permanentSkills';
|
||||
|
||||
export function createDefaultSkills(skillDefinitions: SkillDefinitions) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { superDecompress } from '@blitzkit/core/src/blitzkit/superDecompress';
|
||||
import { superDecompress } from '@blitzkit/core';
|
||||
|
||||
export async function fetchCdonLz4<Type>(url: string) {
|
||||
return await fetch(url, { cache: 'no-store' })
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { assertSecret } from '@blitzkit/core';
|
||||
import { getRatingInfo } from '@blitzkit/core/src/blitz/getRatingInfo';
|
||||
|
||||
interface GitHubTrees {
|
||||
tree: { path: string; url: string }[];
|
||||
}
|
||||
|
||||
let cachedLatestArchivedSeasonNumber: number | null = null;
|
||||
|
||||
export async function getArchivedLatestSeasonNumber() {
|
||||
if (cachedLatestArchivedSeasonNumber !== null) {
|
||||
return cachedLatestArchivedSeasonNumber;
|
||||
}
|
||||
|
||||
const ratingInfo = await getRatingInfo('com');
|
||||
|
||||
if (ratingInfo.detail) {
|
||||
const regionsURL = (
|
||||
(await fetch(
|
||||
`https://api.github.com/repos/tresabhi/${assertSecret(
|
||||
process.env.NEXT_PUBLIC_ASSET_REPO,
|
||||
)}/git/trees/main`,
|
||||
).then((response) => response.json())) as GitHubTrees
|
||||
).tree.find(({ path }) => path === 'regions')!.url;
|
||||
const comURL = (
|
||||
(await fetch(regionsURL).then((response) =>
|
||||
response.json(),
|
||||
)) as GitHubTrees
|
||||
).tree.find(({ path }) => path === 'com')!.url;
|
||||
const ratingURL = (
|
||||
(await fetch(comURL).then((response) => response.json())) as {
|
||||
tree: [{ url: string }];
|
||||
}
|
||||
).tree[0].url;
|
||||
const latestSeason = Math.max(
|
||||
...(
|
||||
(await fetch(ratingURL).then((response) => response.json())) as {
|
||||
tree: { path: string }[];
|
||||
}
|
||||
).tree.map(({ path }) => Number(path)),
|
||||
);
|
||||
|
||||
cachedLatestArchivedSeasonNumber = latestSeason;
|
||||
} else {
|
||||
cachedLatestArchivedSeasonNumber = ratingInfo.current_season - 1;
|
||||
}
|
||||
|
||||
return cachedLatestArchivedSeasonNumber;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { RatingInfo, Region, asset, superDecompress } from '@blitzkit/core';
|
||||
|
||||
const cache: Record<
|
||||
Region,
|
||||
Record<
|
||||
number,
|
||||
RatingInfo & {
|
||||
detail: undefined;
|
||||
}
|
||||
>
|
||||
> = {
|
||||
com: {},
|
||||
eu: {},
|
||||
asia: {},
|
||||
};
|
||||
|
||||
export async function getArchivedRatingInfo(region: Region, season: number) {
|
||||
if (!cache[region][season]) {
|
||||
const info = await fetch(
|
||||
asset(`regions/${region}/rating/${season}/info.cdon.lz4`),
|
||||
)
|
||||
.then((response) => response.arrayBuffer())
|
||||
.then((buffer) =>
|
||||
superDecompress<RatingInfo & { detail: undefined }>(buffer),
|
||||
);
|
||||
cache[region][season] = info;
|
||||
}
|
||||
|
||||
return cache[region][season];
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import {
|
||||
asset,
|
||||
BkrlDiscriminatedEntries,
|
||||
BkrlReadStream,
|
||||
Region,
|
||||
} from '@blitzkit/core';
|
||||
|
||||
const cache: Record<Region, Record<number, BkrlDiscriminatedEntries>> = {
|
||||
asia: {},
|
||||
eu: {},
|
||||
com: {},
|
||||
};
|
||||
|
||||
export async function getArchivedRatingLeaderboard(
|
||||
region: Region,
|
||||
season: number,
|
||||
) {
|
||||
if (!cache[region][season]) {
|
||||
const info = await fetch(
|
||||
asset(`regions/${region}/rating/${season}/latest.bkrl`),
|
||||
)
|
||||
.then((response) => response.arrayBuffer())
|
||||
.then((buffer) => new BkrlReadStream(buffer).bkrl());
|
||||
cache[region][season] = info;
|
||||
}
|
||||
|
||||
return cache[region][season];
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
asset,
|
||||
BkrlDiscriminatedEntries,
|
||||
BkrlReadStream,
|
||||
Region,
|
||||
} from '@blitzkit/core';
|
||||
|
||||
const cache: Record<Region, Record<number, BkrlDiscriminatedEntries | null>> = {
|
||||
com: {},
|
||||
eu: {},
|
||||
asia: {},
|
||||
};
|
||||
|
||||
export async function getArchivedRatingMidnightLeaderboard(
|
||||
region: Region,
|
||||
season: number,
|
||||
) {
|
||||
if (!cache[region][season]) {
|
||||
const info = await fetch(
|
||||
asset(`regions/${region}/rating/${season}/midnight.bkrl`),
|
||||
)
|
||||
.then((response) =>
|
||||
response.status === 404 ? null : response.arrayBuffer(),
|
||||
)
|
||||
.then((buffer) =>
|
||||
buffer === null ? null : new BkrlReadStream(buffer).bkrl(),
|
||||
);
|
||||
cache[region][season] = info;
|
||||
}
|
||||
|
||||
return cache[region][season];
|
||||
}
|
||||
@@ -13,6 +13,10 @@ export * from './eventManager';
|
||||
export * from './fetchCdonLz4';
|
||||
export * from './filterTank';
|
||||
export * from './gameDefinitions';
|
||||
export * from './getArchivedLatestSeasonNumber';
|
||||
export * from './getArchivedRatingInfo';
|
||||
export * from './getArchivedRatingLeaderboard';
|
||||
export * from './getArchivedRatingMidnightLeaderboard';
|
||||
export * from './isExplosive';
|
||||
export * from './modelDefinitions';
|
||||
export * from './normalizeBoundingBox';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TankFilterDefinition } from '@blitzkit/core/src/blitzkit/consumableDefinitions';
|
||||
import { TankFilterDefinition } from '@blitzkit/core';
|
||||
import { asset } from './asset';
|
||||
import { fetchCdonLz4 } from './fetchCdonLz4';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { asset } from '@blitzkit/core/src/blitzkit/asset';
|
||||
import { asset } from '@blitzkit/core';
|
||||
import { decodeProtobuf } from '../protobuf';
|
||||
|
||||
export interface Reviews {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { asset } from '@blitzkit/core/src/blitzkit/asset';
|
||||
import { fetchCdonLz4 } from '@blitzkit/core/src/blitzkit/fetchCdonLz4';
|
||||
import { asset, fetchCdonLz4 } from '@blitzkit/core';
|
||||
import { TankClass } from './tankDefinitions';
|
||||
|
||||
export interface SkillDefinitions {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { EquipmentDefinitions } from '@blitzkit/core/src/blitzkit/equipmentDefinitions';
|
||||
import { ModelDefinition } from '@blitzkit/core/src/blitzkit/modelDefinitions';
|
||||
import { ProvisionDefinitions } from '@blitzkit/core/src/blitzkit/provisionDefinitions';
|
||||
import {
|
||||
EquipmentDefinitions,
|
||||
ModelDefinition,
|
||||
ProvisionDefinitions,
|
||||
} from '@blitzkit/core';
|
||||
import { EquipmentMatrix } from '../../../website/src/stores/duel';
|
||||
import { resolveNearPenetration } from '../blitz/resolveNearPenetration';
|
||||
import { coefficient } from './coefficient';
|
||||
@@ -238,10 +240,10 @@ export function tankCharacteristics(
|
||||
tank.class === 'heavyTank'
|
||||
? 0.06
|
||||
: tank.class === 'mediumTank'
|
||||
? 0.08
|
||||
: tank.class === 'lightTank'
|
||||
? 0.11
|
||||
: 0.04,
|
||||
? 0.08
|
||||
: tank.class === 'lightTank'
|
||||
? 0.11
|
||||
: 0.04,
|
||||
]) * coefficient([true, progressiveStat(commanderMastery)]);
|
||||
const fireChanceCoefficient = coefficient([hasProtectiveKit, -0.2]);
|
||||
|
||||
@@ -263,8 +265,8 @@ export function tankCharacteristics(
|
||||
tank.class === 'AT-SPG'
|
||||
? 0.04
|
||||
: tank.class === 'heavyTank'
|
||||
? 0.03
|
||||
: 0.02,
|
||||
? 0.03
|
||||
: 0.02,
|
||||
]),
|
||||
],
|
||||
[
|
||||
@@ -272,10 +274,10 @@ export function tankCharacteristics(
|
||||
tank.class === 'heavyTank'
|
||||
? 0.02
|
||||
: tank.class === 'mediumTank'
|
||||
? 0.04
|
||||
: tank.class === 'lightTank'
|
||||
? 0.07
|
||||
: 0.1,
|
||||
? 0.04
|
||||
: tank.class === 'lightTank'
|
||||
? 0.07
|
||||
: 0.1,
|
||||
],
|
||||
);
|
||||
const camouflageCoefficientStill = sum(
|
||||
@@ -287,8 +289,8 @@ export function tankCharacteristics(
|
||||
tank.class === 'AT-SPG'
|
||||
? 0.04
|
||||
: tank.class === 'heavyTank'
|
||||
? 0.03
|
||||
: 0.02,
|
||||
? 0.03
|
||||
: 0.02,
|
||||
],
|
||||
[true, crewSkills.camouflage * (3 / 100)],
|
||||
),
|
||||
@@ -298,10 +300,10 @@ export function tankCharacteristics(
|
||||
tank.class === 'heavyTank'
|
||||
? 0.04
|
||||
: tank.class === 'mediumTank'
|
||||
? 0.08
|
||||
: tank.class === 'lightTank'
|
||||
? 0.14
|
||||
: 0.2,
|
||||
? 0.08
|
||||
: tank.class === 'lightTank'
|
||||
? 0.14
|
||||
: 0.2,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { asset } from '@blitzkit/core/src/blitzkit/asset';
|
||||
import { asset } from '@blitzkit/core';
|
||||
|
||||
export function tankIcon(id: number, size: 'big' | 'small' = 'big') {
|
||||
return asset(`icons/tanks/${size}/${id}.webp`);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BoundingBox } from '@blitzkit/core/src/blitzkit/modelDefinitions';
|
||||
import { BoundingBox } from '@blitzkit/core';
|
||||
import { Vector3Tuple } from 'three';
|
||||
|
||||
export function unionBoundingBox(a: BoundingBox, b: BoundingBox) {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export default function isNumber(value: any) {
|
||||
export function isNumber(value: any) {
|
||||
return typeof value === 'number' && isFinite(value);
|
||||
}
|
||||
@@ -19,7 +19,7 @@ const ROMAN = {
|
||||
};
|
||||
const ROMAN_KEYS = Object.keys(ROMAN) as (keyof typeof ROMAN)[];
|
||||
|
||||
export default function numberToRomanNumeral(value: number) {
|
||||
export function numberToRomanNumeral(value: number) {
|
||||
let string = '';
|
||||
|
||||
ROMAN_KEYS.forEach((index) => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { BlitzStats } from './compositeStats/constants';
|
||||
* @param expected what all players on average perform like
|
||||
* @param average what the player in question performs like
|
||||
*/
|
||||
export default function calculateWN8(
|
||||
export function calculateWN8(
|
||||
expected: BlitzStats,
|
||||
average: {
|
||||
damage_dealt: number;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import calculateWN8 from '../calculateWN8';
|
||||
import { calculateWN8 } from '../calculateWN8';
|
||||
import {
|
||||
BlitzkitStats,
|
||||
CompositeStats,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { SupplementaryStats } from '../../../website/src/core/blitz/getAccountInfo';
|
||||
import { tankDefinitions, TreeType } from '../blitzkit/tankDefinitions';
|
||||
import { blitzStarsTankAverages } from '../blitzstars/tankAverages';
|
||||
import calculateWN8 from './calculateWN8';
|
||||
import { calculateWN8 } from './calculateWN8';
|
||||
import { BlitzStats } from './compositeStats';
|
||||
import sumStats from './sumStats';
|
||||
import { sumStats } from './sumStats';
|
||||
|
||||
export interface StatFilters {
|
||||
nation?: string;
|
||||
|
||||
@@ -40,7 +40,7 @@ export const BKNI_COLORS = {
|
||||
[BkniPercentile.SuperUnicum]: 'purple',
|
||||
} as const;
|
||||
|
||||
export default function getBkniPercentile(wn8: number) {
|
||||
export function getBkniPercentile(wn8: number) {
|
||||
const lastIndex = BKNI_PERCENTILES.findLastIndex(({ min }) => min <= wn8);
|
||||
return BKNI_PERCENTILES[lastIndex === -1 ? 0 : lastIndex].percentile;
|
||||
}
|
||||
@@ -13,7 +13,7 @@ const WN8_PERCENTILES: [number, Percentile][] = [
|
||||
[2900, Percentile.SuperUnicum],
|
||||
];
|
||||
|
||||
export default function getWN8Percentile(WN8: number) {
|
||||
export function getWN8Percentile(WN8: number) {
|
||||
const lastIndex = WN8_PERCENTILES.findLastIndex(
|
||||
([WN8Listing]) => WN8Listing <= WN8,
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { emptyAllStats } from '..';
|
||||
import { BlitzStats } from './compositeStats/constants';
|
||||
|
||||
export default function sumStats(allStatsCollection: BlitzStats[]) {
|
||||
export function sumStats(allStatsCollection: BlitzStats[]) {
|
||||
return allStatsCollection.reduce((accumulated, current) => {
|
||||
function sum(value: (allStats: BlitzStats) => number) {
|
||||
return value(accumulated) + value(current);
|
||||
|
||||
Reference in new issue
Block a user