checkpoint: insanity ascends (35)

127 errors to go
This commit is contained in:
zkldi
2023-01-19 16:39:42 +00:00
parent 2b0e65f0c8
commit 5cbb2d5f8a
131 changed files with 2106 additions and 1886 deletions
+4 -3
View File
@@ -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>;
+16 -15
View File
@@ -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: {
+2 -1
View File
@@ -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"],
+2 -1
View File
@@ -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"],
+6 -4
View File
@@ -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.
+14 -3
View File
@@ -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: {
+3 -2
View File
@@ -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"],
+2 -1
View File
@@ -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+"],
+2 -1
View File
@@ -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"],
+15 -14
View File
@@ -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: {
+3 -2
View File
@@ -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: {
+4 -3
View File
@@ -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: {
+3 -2
View File
@@ -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: {
+2 -1
View File
@@ -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"],
+1 -1
View File
@@ -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),
},
+1 -1
View File
@@ -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];
+1 -1
View File
@@ -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 = {
+5 -1
View File
@@ -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
View File
@@ -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}.`);
}