mirror of
https://github.com/zkldi/Tachi.git
synced 2026-09-30 19:07:58 +03:00
checkpoint: insanity ascends (35)
127 errors to go
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
* Common stuff for that all games might want to inherit.
|
||||
*/
|
||||
|
||||
import { FmtNum } from "../../utils/util";
|
||||
import { p } from "prudence";
|
||||
import type { ConfScoreMetric } from "../../types/metrics";
|
||||
|
||||
@@ -20,7 +21,7 @@ import type { ConfScoreMetric } from "../../types/metrics";
|
||||
* as that necessitates that you either can't miss, or can't hit.
|
||||
*/
|
||||
export const FAST_SLOW_MAXCOMBO = {
|
||||
fast: { type: "INTEGER", validate: p.isPositiveInteger },
|
||||
slow: { type: "INTEGER", validate: p.isPositiveInteger },
|
||||
maxCombo: { type: "INTEGER", validate: p.isPositiveInteger },
|
||||
fast: { type: "INTEGER", validate: p.isPositiveInteger, formatter: FmtNum },
|
||||
slow: { type: "INTEGER", validate: p.isPositiveInteger, formatter: FmtNum },
|
||||
maxCombo: { type: "INTEGER", validate: p.isPositiveInteger, formatter: FmtNum },
|
||||
} as const satisfies Record<string, ConfScoreMetric>;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { FmtPercent, FmtScoreNoCommas } from "../../utils/util";
|
||||
import { ClassValue, zodNonNegativeInt } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -16,7 +17,7 @@ export const BMS_CONF = {
|
||||
}),
|
||||
} as const satisfies INTERNAL_GAME_CONFIG;
|
||||
|
||||
function FormatSieglindeBMS(sgl: number): string {
|
||||
export function FormatSieglindeBMS(sgl: number): string {
|
||||
if (sgl < 13) {
|
||||
return `☆${sgl.toFixed(2)}`;
|
||||
}
|
||||
@@ -135,7 +136,7 @@ const RANDOM_SCHEMA = z.enum(["MIRROR", "NONRAN", "R-RANDOM", "RANDOM", "S-RANDO
|
||||
|
||||
export const BMS_7K_CONF = {
|
||||
providedMetrics: {
|
||||
score: { type: "INTEGER", chartDependentMax: true },
|
||||
score: { type: "INTEGER", chartDependentMax: true, formatter: FmtScoreNoCommas },
|
||||
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
@@ -163,7 +164,7 @@ export const BMS_7K_CONF = {
|
||||
// if #RANDOM is to ever be supported, the user's percent would become
|
||||
// a *mandatory* metric, as a chart's notecount can be completely unknown.
|
||||
// However, supporting #RANDOM is an awful pain, so I don't really care.
|
||||
percent: { type: "DECIMAL", validate: p.isBetween(0, 100) },
|
||||
percent: { type: "DECIMAL", validate: p.isBetween(0, 100), formatter: FmtPercent },
|
||||
},
|
||||
|
||||
defaultMetric: "percent",
|
||||
@@ -171,19 +172,19 @@ export const BMS_7K_CONF = {
|
||||
|
||||
optionalMetrics: {
|
||||
...FAST_SLOW_MAXCOMBO,
|
||||
bp: { type: "INTEGER", validate: p.isPositive },
|
||||
gauge: { type: "DECIMAL", validate: p.isBetween(0, 100) },
|
||||
bp: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
gauge: { type: "DECIMAL", validate: p.isBetween(0, 100), formatter: FmtPercent },
|
||||
gaugeHistory: { type: "GRAPH", validate: p.isBetween(0, 100) },
|
||||
epg: { type: "INTEGER", validate: p.isPositive },
|
||||
egr: { type: "INTEGER", validate: p.isPositive },
|
||||
egd: { type: "INTEGER", validate: p.isPositive },
|
||||
ebd: { type: "INTEGER", validate: p.isPositive },
|
||||
epr: { type: "INTEGER", validate: p.isPositive },
|
||||
lpg: { type: "INTEGER", validate: p.isPositive },
|
||||
lgr: { type: "INTEGER", validate: p.isPositive },
|
||||
lgd: { type: "INTEGER", validate: p.isPositive },
|
||||
lbd: { type: "INTEGER", validate: p.isPositive },
|
||||
lpr: { type: "INTEGER", validate: p.isPositive },
|
||||
epg: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
egr: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
egd: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
ebd: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
epr: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
lpg: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
lgr: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
lgd: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
lbd: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
lpr: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
},
|
||||
|
||||
scoreRatingAlgs: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { FmtNum } from "../../utils/util";
|
||||
import { ClassValue, zodNonNegativeInt } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -29,7 +30,7 @@ export const CHUNITHMColours = [
|
||||
|
||||
export const CHUNITHM_SINGLE_CONF = {
|
||||
providedMetrics: {
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 1_010_000) },
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 1_010_000), formatter: FmtNum },
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
values: ["FAILED", "CLEAR", "FULL COMBO", "ALL JUSTICE", "ALL JUSTICE CRITICAL"],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { FmtPercent } from "../../utils/util";
|
||||
import { ClassValue, zodNonNegativeInt } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -36,7 +37,7 @@ const GitadoraColours = [
|
||||
|
||||
export const GITADORA_GITA_CONF = {
|
||||
providedMetrics: {
|
||||
percent: { type: "DECIMAL", validate: p.isBetween(0, 100) },
|
||||
percent: { type: "DECIMAL", validate: p.isBetween(0, 100), formatter: FmtPercent },
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
values: ["FAILED", "CLEAR", "FULL COMBO", "EXCELLENT"],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { FmtNum, FmtPercent, FmtScoreNoCommas } from "../../utils/util";
|
||||
import { ClassValue, zodNonNegativeInt, zodTierlistData } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -50,7 +51,7 @@ const RANDOM_SCHEMA = z.enum(["NONRAN", "MIRROR", "R-RANDOM", "RANDOM", "S-RANDO
|
||||
|
||||
export const IIDX_SP_CONF = {
|
||||
providedMetrics: {
|
||||
score: { type: "INTEGER", chartDependentMax: true },
|
||||
score: { type: "INTEGER", chartDependentMax: true, formatter: FmtScoreNoCommas },
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
values: [
|
||||
@@ -71,6 +72,7 @@ export const IIDX_SP_CONF = {
|
||||
percent: {
|
||||
type: "DECIMAL",
|
||||
validate: p.isBetween(0, 100),
|
||||
formatter: FmtPercent,
|
||||
},
|
||||
grade: {
|
||||
type: "ENUM",
|
||||
@@ -85,9 +87,9 @@ export const IIDX_SP_CONF = {
|
||||
optionalMetrics: {
|
||||
...FAST_SLOW_MAXCOMBO,
|
||||
|
||||
bp: { type: "INTEGER", validate: p.isPositive },
|
||||
gauge: { type: "DECIMAL", validate: p.isBetween(0, 100) },
|
||||
comboBreak: { type: "INTEGER", validate: p.isPositive },
|
||||
bp: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
gauge: { type: "DECIMAL", validate: p.isBetween(0, 100), formatter: FmtPercent },
|
||||
comboBreak: { type: "INTEGER", validate: p.isPositive, formatter: FmtNum },
|
||||
|
||||
// The players history for the gauge type they were playing on.
|
||||
// this may fall into "NULL" if the user fails.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { FmtPercent } from "../../utils/util";
|
||||
import { NoDecimalPlace, zodNonNegativeInt } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -15,13 +16,13 @@ export const ITG_CONF = {
|
||||
|
||||
export const ITG_STAMINA_CONF = {
|
||||
providedMetrics: {
|
||||
scorePercent: { type: "DECIMAL", validate: p.isBetween(0, 100) },
|
||||
scorePercent: { type: "DECIMAL", validate: p.isBetween(0, 100), formatter: FmtPercent },
|
||||
|
||||
// How far through the chart did they get?
|
||||
// 100 means they cleared.
|
||||
// 50 means they got halfway through.
|
||||
// 0 means they died instantly etc.
|
||||
survivedPercent: { type: "DECIMAL", validate: p.isBetween(0, 100) },
|
||||
survivedPercent: { type: "DECIMAL", validate: p.isBetween(0, 100), formatter: FmtPercent },
|
||||
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
@@ -50,7 +51,17 @@ export const ITG_STAMINA_CONF = {
|
||||
//
|
||||
// NOTE that in our ITG implementation we don't allow for negative percents
|
||||
// as it breaks this silly metric. Also negative percents are stupid.
|
||||
finalPercent: { type: "DECIMAL", validate: p.isBetween(0, 200) },
|
||||
finalPercent: {
|
||||
type: "DECIMAL",
|
||||
validate: p.isBetween(0, 200),
|
||||
formatter: (v) => {
|
||||
if (v < 100) {
|
||||
return `Died ${v.toFixed(2)}% in`;
|
||||
}
|
||||
|
||||
return `Cleared with ${(v - 100).toFixed(2)}%`;
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
optionalMetrics: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { FmtNum, FmtPercent } from "../../utils/util";
|
||||
import { ClassValue, zodNonNegativeInt } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -28,8 +29,8 @@ const JubeatColours = [
|
||||
|
||||
export const JUBEAT_SINGLE_CONF = {
|
||||
providedMetrics: {
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 1_000_000) },
|
||||
musicRate: { type: "DECIMAL", chartDependentMax: true },
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 1_000_000), formatter: FmtNum },
|
||||
musicRate: { type: "DECIMAL", chartDependentMax: true, formatter: FmtPercent },
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
values: ["FAILED", "CLEAR", "FULL COMBO", "EXCELLENT"],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { FmtPercent } from "../../utils/util";
|
||||
import { ClassValue, NoDecimalPlace } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -57,7 +58,7 @@ const MaimaiDXColours = [
|
||||
|
||||
export const MAIMAI_DX_SINGLE_CONF = {
|
||||
providedMetrics: {
|
||||
percent: { type: "DECIMAL", validate: p.isBetween(0, 101) },
|
||||
percent: { type: "DECIMAL", validate: p.isBetween(0, 101), formatter: FmtPercent },
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
values: ["FAILED", "CLEAR", "FULL COMBO", "FULL COMBO+", "ALL PERFECT", "ALL PERFECT+"],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { FmtNum } from "../../utils/util";
|
||||
import { NoDecimalPlace, zodNonNegativeInt } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -17,7 +18,7 @@ export const MUSECA_CONF = {
|
||||
|
||||
export const MUSECA_SINGLE_CONF = {
|
||||
providedMetrics: {
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 1_000_000) },
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 1_000_000), formatter: FmtNum },
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
values: ["FAILED", "CLEAR", "CONNECT ALL", "PERFECT CONNECT ALL"],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { FmtScoreNoCommas, FmtPercent } from "../../utils/util";
|
||||
import { ClassValue, zodNonNegativeInt } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -42,7 +43,7 @@ function FormatSieglindePMS(sgl: number): string {
|
||||
|
||||
export const PMS_CONTROLLER_CONF = {
|
||||
providedMetrics: {
|
||||
score: { type: "INTEGER", chartDependentMax: true },
|
||||
score: { type: "INTEGER", chartDependentMax: true, formatter: FmtScoreNoCommas },
|
||||
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
@@ -70,7 +71,7 @@ export const PMS_CONTROLLER_CONF = {
|
||||
// if #RANDOM is to ever be supported, the user's percent would become
|
||||
// a *mandatory* metric, as a chart's notecount can be completely unknown.
|
||||
// However, supporting #RANDOM is an awful pain, so I don't really care.
|
||||
percent: { type: "DECIMAL", validate: p.isBetween(0, 100) },
|
||||
percent: { type: "DECIMAL", validate: p.isBetween(0, 100), formatter: FmtPercent },
|
||||
},
|
||||
|
||||
defaultMetric: "percent",
|
||||
@@ -78,19 +79,19 @@ export const PMS_CONTROLLER_CONF = {
|
||||
|
||||
optionalMetrics: {
|
||||
...FAST_SLOW_MAXCOMBO,
|
||||
bp: { type: "INTEGER", validate: p.isPositive },
|
||||
gauge: { type: "DECIMAL", validate: p.isBetween(0, 100) },
|
||||
bp: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
gauge: { type: "DECIMAL", validate: p.isBetween(0, 100), formatter: FmtPercent },
|
||||
gaugeHistory: { type: "GRAPH", validate: p.isBetween(0, 100) },
|
||||
epg: { type: "INTEGER", validate: p.isPositive },
|
||||
egr: { type: "INTEGER", validate: p.isPositive },
|
||||
egd: { type: "INTEGER", validate: p.isPositive },
|
||||
ebd: { type: "INTEGER", validate: p.isPositive },
|
||||
epr: { type: "INTEGER", validate: p.isPositive },
|
||||
lpg: { type: "INTEGER", validate: p.isPositive },
|
||||
lgr: { type: "INTEGER", validate: p.isPositive },
|
||||
lgd: { type: "INTEGER", validate: p.isPositive },
|
||||
lbd: { type: "INTEGER", validate: p.isPositive },
|
||||
lpr: { type: "INTEGER", validate: p.isPositive },
|
||||
epg: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
egr: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
egd: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
ebd: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
epr: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
lpg: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
lgr: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
lgd: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
lbd: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
lpr: { type: "INTEGER", validate: p.isPositive, formatter: FmtScoreNoCommas },
|
||||
},
|
||||
|
||||
scoreRatingAlgs: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { FmtNum, FmtPercent } from "../../utils/util";
|
||||
import { ClassValue, zodNonNegativeInt } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -28,7 +29,7 @@ const PopnClasses = [
|
||||
|
||||
export const POPN_9B_CONF = {
|
||||
providedMetrics: {
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 100_000) },
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 100_000), formatter: FmtNum },
|
||||
clearMedal: {
|
||||
type: "ENUM",
|
||||
values: [
|
||||
@@ -70,7 +71,7 @@ export const POPN_9B_CONF = {
|
||||
|
||||
optionalMetrics: {
|
||||
...FAST_SLOW_MAXCOMBO,
|
||||
gauge: { type: "INTEGER", validate: p.isBetween(0, 100) },
|
||||
gauge: { type: "DECIMAL", validate: p.isBetween(0, 100), formatter: FmtPercent },
|
||||
},
|
||||
|
||||
scoreRatingAlgs: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { FmtNum, FmtPercent } from "../../utils/util";
|
||||
import { ClassValue, ToDecimalPlaces, zodNonNegativeInt, zodTierlistData } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -73,7 +74,7 @@ export const SDVXVFClasses = [
|
||||
|
||||
export const SDVX_SINGLE_CONF = {
|
||||
providedMetrics: {
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 10_000_000) },
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 10_000_000), formatter: FmtNum },
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
values: [
|
||||
@@ -100,8 +101,8 @@ export const SDVX_SINGLE_CONF = {
|
||||
|
||||
optionalMetrics: {
|
||||
...FAST_SLOW_MAXCOMBO,
|
||||
exScore: { type: "INTEGER", chartDependentMax: true },
|
||||
gauge: { type: "DECIMAL", validate: p.isBetween(0, 100) },
|
||||
exScore: { type: "INTEGER", chartDependentMax: true, formatter: FmtNum },
|
||||
gauge: { type: "DECIMAL", validate: p.isBetween(0, 100), formatter: FmtPercent },
|
||||
},
|
||||
|
||||
scoreRatingAlgs: {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { SDVXVFClasses } from "./sdvx";
|
||||
import { FmtNum, FmtPercent } from "../../utils/util";
|
||||
import { ToDecimalPlaces } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -14,7 +15,7 @@ export const USC_CONF = {
|
||||
|
||||
export const USC_CONTROLLER_CONF = {
|
||||
providedMetrics: {
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 10_000_000) },
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 10_000_000), formatter: FmtNum },
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
values: [
|
||||
@@ -41,7 +42,7 @@ export const USC_CONTROLLER_CONF = {
|
||||
|
||||
optionalMetrics: {
|
||||
...FAST_SLOW_MAXCOMBO,
|
||||
gauge: { type: "DECIMAL", validate: p.isBetween(0, 100) },
|
||||
gauge: { type: "DECIMAL", validate: p.isBetween(0, 100), formatter: FmtPercent },
|
||||
},
|
||||
|
||||
scoreRatingAlgs: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FAST_SLOW_MAXCOMBO } from "./_common";
|
||||
import { FmtNum } from "../../utils/util";
|
||||
import { ClassValue } from "../config-utils";
|
||||
import { p } from "prudence";
|
||||
import { z } from "zod";
|
||||
@@ -47,7 +48,7 @@ export const WaccaColours = [
|
||||
|
||||
export const WACCA_SINGLE_CONF = {
|
||||
providedMetrics: {
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 1_000_000) },
|
||||
score: { type: "INTEGER", validate: p.isBetween(0, 1_000_000), formatter: FmtNum },
|
||||
lamp: {
|
||||
type: "ENUM",
|
||||
values: ["FAILED", "CLEAR", "MISSLESS", "FULL COMBO", "ALL MARVELOUS"],
|
||||
|
||||
@@ -581,7 +581,7 @@ const PRE_SCHEMAS = {
|
||||
],
|
||||
(self) => Array.isArray(self) && self.length <= 6
|
||||
),
|
||||
scoreBucket: p.isIn(null, "grade", "lamp"),
|
||||
preferredDefaultEnum: p.isIn(null, "grade", "lamp"),
|
||||
|
||||
gameSpecific: PrudenceZodShim(gptConfig.preferences),
|
||||
},
|
||||
|
||||
@@ -638,7 +638,7 @@ export interface UGPTSettingsDocument<GPT extends GPTString = GPTString> {
|
||||
preferredSessionAlg: SessionRatingAlgorithms[GPT] | null;
|
||||
preferredProfileAlg: ProfileRatingAlgorithms[GPT] | null;
|
||||
stats: Array<ShowcaseStatDetails>;
|
||||
scoreBucket: "grade" | "lamp" | null;
|
||||
preferredDefaultEnum: string | null;
|
||||
defaultTable: string | null;
|
||||
preferredRanking: "global" | "rival" | null;
|
||||
gameSpecific: Preferences[GPT];
|
||||
|
||||
@@ -158,7 +158,7 @@ export type AnyClasses = {
|
||||
};
|
||||
|
||||
export type Classes = {
|
||||
[G in GPTString]: keyof typeof GAME_PT_CONFIGS[G]["classes"];
|
||||
[G in GPTString]: string & keyof typeof GAME_PT_CONFIGS[G]["classes"];
|
||||
};
|
||||
|
||||
export type ClassConfigs = {
|
||||
|
||||
@@ -22,6 +22,7 @@ import type {
|
||||
|
||||
interface ConfDecimalScoreMetricNormal {
|
||||
type: "DECIMAL";
|
||||
formatter: (v: number) => string;
|
||||
|
||||
validate: (v: number) => string | true;
|
||||
|
||||
@@ -31,6 +32,7 @@ interface ConfDecimalScoreMetricNormal {
|
||||
|
||||
interface ConfIntegerScoreMetricNormal {
|
||||
type: "INTEGER";
|
||||
formatter: (v: number) => string;
|
||||
|
||||
validate: (v: number) => string | true;
|
||||
|
||||
@@ -40,6 +42,7 @@ interface ConfIntegerScoreMetricNormal {
|
||||
|
||||
interface ConfDecimalScoreMetricChartDependent {
|
||||
type: "DECIMAL";
|
||||
formatter: (v: number) => string;
|
||||
|
||||
/**
|
||||
* Is the maximum/minimum value of this metric chart dependent?
|
||||
@@ -51,6 +54,7 @@ interface ConfDecimalScoreMetricChartDependent {
|
||||
|
||||
interface ConfIntegerScoreMetricChartDependent {
|
||||
type: "INTEGER";
|
||||
formatter: (v: number) => string;
|
||||
|
||||
/**
|
||||
* Is the maximum/minimum value of this metric chart dependent?
|
||||
@@ -143,7 +147,7 @@ export type ExtractMetricValue<M extends ConfScoreMetric> = M extends ConfDecima
|
||||
* would return a type of "grade" | "lamp"
|
||||
*/
|
||||
export type ExtractEnumMetricNames<R extends Record<string, ConfScoreMetric>> = {
|
||||
[K in keyof R]: R[K] extends ConfEnumScoreMetric<infer _> ? K : never;
|
||||
[K in keyof R]: R[K] extends ConfEnumScoreMetric<infer _> ? K & string : never;
|
||||
}[keyof R];
|
||||
|
||||
/**
|
||||
|
||||
+42
-12
@@ -6,6 +6,7 @@ import {
|
||||
} from "../config/config";
|
||||
import type { GradeBoundary } from "../constants/grade-boundaries";
|
||||
import type {
|
||||
BMSCourseDocument,
|
||||
ChartDocument,
|
||||
GPTString,
|
||||
GPTStrings,
|
||||
@@ -228,6 +229,17 @@ export function FmtNum(num: number) {
|
||||
return num.toLocaleString();
|
||||
}
|
||||
|
||||
export function FmtPercent(v: number, dp = 2) {
|
||||
return `${v.toFixed(dp)}%`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a number of 12834 into "12834" instead of "12,834".
|
||||
*/
|
||||
export function FmtScoreNoCommas(v: number) {
|
||||
return v.toString();
|
||||
}
|
||||
|
||||
function WrapGrade(grade: string) {
|
||||
if (grade.endsWith("-") || grade.endsWith("+")) {
|
||||
return `(${grade})`;
|
||||
@@ -236,18 +248,6 @@ function WrapGrade(grade: string) {
|
||||
return grade;
|
||||
}
|
||||
|
||||
type FormatGradeDeltaReturns =
|
||||
| {
|
||||
lower: string;
|
||||
upper: string;
|
||||
closer: "upper";
|
||||
}
|
||||
| {
|
||||
lower: string;
|
||||
upper?: string;
|
||||
closer: "lower";
|
||||
};
|
||||
|
||||
function RelativeGradeDelta<G extends string>(
|
||||
gradeBoundaries: Array<GradeBoundary<G>>,
|
||||
scoreGrade: G,
|
||||
@@ -378,3 +378,33 @@ export function FormatPrError(err: PrudenceError, foreword = "Error"): string {
|
||||
|
||||
return `${foreword}: ${err.keychain} | ${err.message}${receivedText}.`;
|
||||
}
|
||||
|
||||
export function GetBMSCourseIndex(course: BMSCourseDocument) {
|
||||
const gptConf = GetGamePTConfig("bms", course.playtype);
|
||||
|
||||
const cls = gptConf.classes[course.set];
|
||||
|
||||
if (!cls) {
|
||||
throw new Error(
|
||||
`Invalid BMSCourse set of ${course.set}. No classes are defined for this set.`
|
||||
);
|
||||
}
|
||||
|
||||
return cls.values.findIndex((e) => e.id === course.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Util for getting a games' grade for a given score.
|
||||
*/
|
||||
export function GetGrade<G extends string>(grades: Array<GradeBoundary<G>>, score: number): G {
|
||||
// sort grades going downwards in their boundaries.
|
||||
const descendingGrades = grades.slice(0).sort((a, b) => b.lowerBound - a.lowerBound);
|
||||
|
||||
for (const { name, lowerBound } of descendingGrades) {
|
||||
if (score >= lowerBound) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Could not resolve grade for score ${score}.`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user