From 31077824c573a2d4bfbf2bdaf4d99512bdd5ab12 Mon Sep 17 00:00:00 2001 From: zkldi Date: Sun, 20 Jun 2021 03:00:07 +0100 Subject: [PATCH] Complete overhaul --- common/.eslintrc | 3 +- common/.gitignore | 3 +- common/package.json | 66 +- common/src/config/config.test.ts | 22 +- common/src/config/config.ts | 1866 +++++++++++++-------------- common/src/config/static-config.ts | 122 +- common/src/game-classes.ts | 310 ++--- common/src/index.test.ts | 13 + common/src/legacy/legacy-config.ts | 958 +++++++------- common/src/lib/esd.test.ts | 36 + common/src/lib/esd.ts | 203 ++- common/src/lib/util.test.ts | 8 +- common/src/lib/util.ts | 26 +- common/src/types.ts | 1904 ++++++++++++++-------------- 14 files changed, 2801 insertions(+), 2739 deletions(-) create mode 100644 common/src/index.test.ts create mode 100644 common/src/lib/esd.test.ts diff --git a/common/.eslintrc b/common/.eslintrc index 0b81b7811..ca03c0dec 100644 --- a/common/.eslintrc +++ b/common/.eslintrc @@ -20,7 +20,8 @@ "singleQuote": false, "trailingComma": "es5", "bracketSpacing": true, - "endOfLine": "auto" + "endOfLine": "auto", + "useTabs": true }], "@typescript-eslint/no-unused-vars": "error", "@typescript-eslint/no-unused-expressions": "error", diff --git a/common/.gitignore b/common/.gitignore index 4bc2f9ce7..15aae8d54 100644 --- a/common/.gitignore +++ b/common/.gitignore @@ -1,4 +1,5 @@ /node_modules /.vscode -.nyc_output \ No newline at end of file +.nyc_output +coverage \ No newline at end of file diff --git a/common/package.json b/common/package.json index 9b09f377f..96af75d1d 100644 --- a/common/package.json +++ b/common/package.json @@ -1,27 +1,41 @@ { - "name": "tachi-common", - "version": "0.1.0", - "description": "Common Types & Stuff for Tachi", - "main": "js/index.js", - "scripts": { - "test": "tap", - "build": "tsc" - }, - "author": "zkldi", - "license": "ISC", - "devDependencies": { - "@types/tap": "^15.0.3", - "@typescript-eslint/eslint-plugin": "^4.19.0", - "@typescript-eslint/parser": "^4.19.0", - "eslint": "^7.22.0", - "eslint-config-prettier": "^8.1.0", - "eslint-plugin-prettier": "^3.3.1", - "prettier": "^2.2.1", - "ts-node": "^10.0.0", - "typescript": "^4.3.4" - }, - "dependencies": { - "monk": "^7.3.3", - "tap": "^15.0.9" - } -} + "name": "tachi-common", + "version": "0.1.0", + "description": "Common Types & Stuff for Tachi", + "main": "js/index.js", + "scripts": { + "test": "tap", + "build": "tsc" + }, + "author": "zkldi", + "license": "ISC", + "devDependencies": { + "@types/tap": "^15.0.3", + "@typescript-eslint/eslint-plugin": "^4.19.0", + "@typescript-eslint/parser": "^4.19.0", + "eslint": "^7.22.0", + "eslint-config-prettier": "^8.1.0", + "eslint-plugin-prettier": "^3.3.1", + "prettier": "^2.2.1", + "ts-node": "^10.0.0", + "typescript": "^4.3.4" + }, + "dependencies": { + "monk": "^7.3.3", + "tap": "^15.0.9" + }, + "nyc": { + "reporter": [ + "html", + "lcov" + ], + "all": true, + "include": [ + "src/*/!(test-utils)/**/*.ts" + ], + "exclude": [ + "src/**/*.test.ts", + "src/external/mongo/schemas.ts" + ] + } +} \ No newline at end of file diff --git a/common/src/config/config.test.ts b/common/src/config/config.test.ts index b9e8ec637..7d374e3fa 100644 --- a/common/src/config/config.test.ts +++ b/common/src/config/config.test.ts @@ -3,23 +3,23 @@ import { GetGameConfig, GetGamePTConfig } from "./config"; import { allSupportedGames } from "./static-config"; t.test("#GetGameConfig", (t) => { - t.plan(allSupportedGames.length); + t.plan(allSupportedGames.length); - for (const game of allSupportedGames) { - t.equal(GetGameConfig(game).internalName, game); - } + for (const game of allSupportedGames) { + t.equal(GetGameConfig(game).internalName, game); + } }); // i have no idea why this one doesn't need t.end() // and this one does t.test("#GetGamePTConfig", (t) => { - for (const game of allSupportedGames) { - const gameConfig = GetGameConfig(game); + for (const game of allSupportedGames) { + const gameConfig = GetGameConfig(game); - for (const playtype of gameConfig.validPlaytypes) { - t.equal(GetGamePTConfig(game, playtype).idString, `${game}:${playtype}`); - } - } + for (const playtype of gameConfig.validPlaytypes) { + t.equal(GetGamePTConfig(game, playtype).idString, `${game}:${playtype}`); + } + } - t.end(); + t.end(); }); diff --git a/common/src/config/config.ts b/common/src/config/config.ts index c38b969d0..7ad2d85ed 100644 --- a/common/src/config/config.ts +++ b/common/src/config/config.ts @@ -1,980 +1,980 @@ import { ESDJudgementFormat } from "../lib/esd"; import { - Playtypes, - Game, - Difficulties, - IDStrings, - ScoreCalculatedDataLookup, - SessionCalculatedDataLookup, - UGSRatingsLookup, - Grades, - Lamps, + Playtypes, + Game, + Difficulties, + IDStrings, + ScoreCalculatedDataLookup, + SessionCalculatedDataLookup, + UGSRatingsLookup, + Grades, + Lamps, } from "../types"; export interface GameConfig { - internalName: string; - name: string; - defaultPlaytype: Playtypes[G]; - validPlaytypes: Playtypes[G][]; + internalName: string; + name: string; + defaultPlaytype: Playtypes[G]; + validPlaytypes: Playtypes[G][]; } interface BaseGamePTConfig { - idString: I; + idString: I; - percentMax: number; + percentMax: number; - defaultScoreRatingAlg: ScoreCalculatedDataLookup[I]; - defaultSessionRatingAlg: SessionCalculatedDataLookup[I]; - defaultProfileRatingAlg: UGSRatingsLookup[I]; + defaultScoreRatingAlg: ScoreCalculatedDataLookup[I]; + defaultSessionRatingAlg: SessionCalculatedDataLookup[I]; + defaultProfileRatingAlg: UGSRatingsLookup[I]; - difficulties: Difficulties[I][]; - defaultDifficulty: Difficulties[I]; - difficultyColours: Record; + difficulties: Difficulties[I][]; + defaultDifficulty: Difficulties[I]; + difficultyColours: Record; - grades: Grades[I][]; - gradeColours: Record; - clearGrade: Grades[I]; - gradeBoundaries: number[]; + grades: Grades[I][]; + gradeColours: Record; + clearGrade: Grades[I]; + gradeBoundaries: number[]; - lamps: Lamps[I][]; - lampColours: Record; - clearLamp: Lamps[I]; + lamps: Lamps[I][]; + lampColours: Record; + clearLamp: Lamps[I]; - supportsESD: boolean; - judgementWindows?: ESDJudgementFormat[]; + supportsESD: boolean; + judgementWindows?: ESDJudgementFormat[]; - defaultTable: string; + defaultTable: string; - scoreBucket: "grade" | "lamp"; + scoreBucket: "grade" | "lamp"; } interface GamePTConfigWithESD extends BaseGamePTConfig { - supportsESD: true; - judgementWindows: ESDJudgementFormat[]; + supportsESD: true; + judgementWindows: ESDJudgementFormat[]; } interface GamePTConfigWithoutESD extends BaseGamePTConfig { - supportsESD: false; + supportsESD: false; } export type GamePTConfig = - | GamePTConfigWithESD - | GamePTConfigWithoutESD; + | GamePTConfigWithESD + | GamePTConfigWithoutESD; /** * A collection of CSS colours we want to work with. */ export const COLOUR_SET = { - gray: "rgba(105, 105, 105, 1)", - maroon: "rgba(85, 17, 17, 1)", - red: "rgba(170, 85, 85, 1)", - paleGreen: "rgba(142,174,79, 1)", - paleBlue: "rgba(92, 97, 153, 1)", - green: "rgba(50, 205, 50, 1)", - blue: "rgba(70, 130, 180, 1)", - gold: "rgba(255, 215, 0, 1)", - vibrantYellow: "rgba(245, 229, 27, 1)", - teal: "rgba(127, 255, 212, 1)", - white: "rgba(192, 192, 192, 1)", - purple: "rgba(153, 50, 204, 1)", - vibrantPurple: "rgba(161, 23, 230, 1)", - paleOrange: "rgba(235, 151, 78, 1)", - orange: "rgba(248, 148, 6, 1)", - vibrantOrange: "rgba(248, 175, 6, 1)", - vibrantBlue: "rgba(43, 149, 237, 1)", - vibrantGreen: "rgba(26, 232, 26, 1)", + gray: "rgba(105, 105, 105, 1)", + maroon: "rgba(85, 17, 17, 1)", + red: "rgba(170, 85, 85, 1)", + paleGreen: "rgba(142,174,79, 1)", + paleBlue: "rgba(92, 97, 153, 1)", + green: "rgba(50, 205, 50, 1)", + blue: "rgba(70, 130, 180, 1)", + gold: "rgba(255, 215, 0, 1)", + vibrantYellow: "rgba(245, 229, 27, 1)", + teal: "rgba(127, 255, 212, 1)", + white: "rgba(192, 192, 192, 1)", + purple: "rgba(153, 50, 204, 1)", + vibrantPurple: "rgba(161, 23, 230, 1)", + paleOrange: "rgba(235, 151, 78, 1)", + orange: "rgba(248, 148, 6, 1)", + vibrantOrange: "rgba(248, 175, 6, 1)", + vibrantBlue: "rgba(43, 149, 237, 1)", + vibrantGreen: "rgba(26, 232, 26, 1)", }; type GameConfigs = { - [G in Game]: GameConfig; + [G in Game]: GameConfig; }; const GAME_CONFIGS: GameConfigs = { - iidx: { - defaultPlaytype: "SP", - name: "beatmania IIDX", - internalName: "iidx", - validPlaytypes: ["SP", "DP"], - }, - museca: { - defaultPlaytype: "Single", - name: "MÚSECA", - internalName: "museca", - validPlaytypes: ["Single"], - }, - chunithm: { - defaultPlaytype: "Single", - name: "CHUNITHM", - internalName: "chunithm", - validPlaytypes: ["Single"], - }, - ddr: { - defaultPlaytype: "SP", - name: "DDR", // used to be 'Dance Dance Revolution', is now DDR for space reasons. - internalName: "ddr", - validPlaytypes: ["SP", "DP"], - }, - bms: { - defaultPlaytype: "7K", - name: "BMS", - internalName: "bms", - validPlaytypes: ["7K", "14K"], - }, - gitadora: { - defaultPlaytype: "Dora", - name: "GITADORA", - internalName: "gitadora", - validPlaytypes: ["Gita", "Dora"], - }, - // jubeat: { - // defaultPlaytype: "Single", - // name: "jubeat", - // internalName: "jubeat", - // validPlaytypes: ["Single"], - // }, - maimai: { - defaultPlaytype: "Single", - name: "maimai", - internalName: "maimai", - validPlaytypes: ["Single"], - }, - // popn: { - // defaultPlaytype: "9B", - // name: "pop'n music", - // internalName: "popn", // note: KAI servers use pnm as a name. - // validPlaytypes: ["9B"], - // }, - sdvx: { - defaultPlaytype: "Single", - name: "SOUND VOLTEX", - internalName: "sdvx", - validPlaytypes: ["Single"], - }, - usc: { - defaultPlaytype: "Single", - name: "unnamed_sdvx_clone", - internalName: "usc", - validPlaytypes: ["Single"], - }, + iidx: { + defaultPlaytype: "SP", + name: "beatmania IIDX", + internalName: "iidx", + validPlaytypes: ["SP", "DP"], + }, + museca: { + defaultPlaytype: "Single", + name: "MÚSECA", + internalName: "museca", + validPlaytypes: ["Single"], + }, + chunithm: { + defaultPlaytype: "Single", + name: "CHUNITHM", + internalName: "chunithm", + validPlaytypes: ["Single"], + }, + ddr: { + defaultPlaytype: "SP", + name: "DDR", // used to be 'Dance Dance Revolution', is now DDR for space reasons. + internalName: "ddr", + validPlaytypes: ["SP", "DP"], + }, + bms: { + defaultPlaytype: "7K", + name: "BMS", + internalName: "bms", + validPlaytypes: ["7K", "14K"], + }, + gitadora: { + defaultPlaytype: "Dora", + name: "GITADORA", + internalName: "gitadora", + validPlaytypes: ["Gita", "Dora"], + }, + // jubeat: { + // defaultPlaytype: "Single", + // name: "jubeat", + // internalName: "jubeat", + // validPlaytypes: ["Single"], + // }, + maimai: { + defaultPlaytype: "Single", + name: "maimai", + internalName: "maimai", + validPlaytypes: ["Single"], + }, + // popn: { + // defaultPlaytype: "9B", + // name: "pop'n music", + // internalName: "popn", // note: KAI servers use pnm as a name. + // validPlaytypes: ["9B"], + // }, + sdvx: { + defaultPlaytype: "Single", + name: "SOUND VOLTEX", + internalName: "sdvx", + validPlaytypes: ["Single"], + }, + usc: { + defaultPlaytype: "Single", + name: "unnamed_sdvx_clone", + internalName: "usc", + validPlaytypes: ["Single"], + }, }; type GamePTConfigs = { - [I in IDStrings]: GamePTConfig; + [I in IDStrings]: GamePTConfig; }; const GAME_PT_CONFIGS: GamePTConfigs = { - "iidx:SP": { - idString: "iidx:SP", - - percentMax: 100, - - defaultScoreRatingAlg: "ktRating", - defaultSessionRatingAlg: "ktRating", - defaultProfileRatingAlg: "ktRating", - - difficulties: ["BEGINNER", "NORMAL", "HYPER", "ANOTHER", "LEGGENDARIA"], - defaultDifficulty: "ANOTHER", - difficultyColours: { - BEGINNER: COLOUR_SET.paleGreen, - NORMAL: COLOUR_SET.blue, - HYPER: COLOUR_SET.orange, - ANOTHER: COLOUR_SET.red, - LEGGENDARIA: COLOUR_SET.purple, - }, - - grades: ["F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX"], - gradeColours: { - F: COLOUR_SET.gray, - E: COLOUR_SET.red, - D: COLOUR_SET.maroon, - C: COLOUR_SET.purple, - B: COLOUR_SET.paleBlue, - A: COLOUR_SET.green, - AA: COLOUR_SET.blue, - AAA: COLOUR_SET.gold, - "MAX-": COLOUR_SET.teal, - MAX: COLOUR_SET.white, - }, - clearGrade: "A", - gradeBoundaries: [0, 22.22, 33.33, 44.44, 55.55, 66.66, 77.77, 88.88, 94.44, 100.0], - - lamps: [ - "NO PLAY", - "FAILED", - "ASSIST CLEAR", - "EASY CLEAR", - "CLEAR", - "HARD CLEAR", - "EX HARD CLEAR", - "FULL COMBO", - ], - lampColours: { - "NO PLAY": COLOUR_SET.gray, - FAILED: COLOUR_SET.red, - "ASSIST CLEAR": COLOUR_SET.purple, - "EASY CLEAR": COLOUR_SET.green, - CLEAR: COLOUR_SET.blue, - "HARD CLEAR": COLOUR_SET.orange, - "EX HARD CLEAR": COLOUR_SET.gold, - "FULL COMBO": COLOUR_SET.teal, - }, - clearLamp: "CLEAR", - - supportsESD: true, - judgementWindows: [ - { name: "PGREAT", msBorder: 16.667, value: 2 }, - { name: "GREAT", msBorder: 33.333, value: 1 }, - { name: "GOOD", msBorder: 116.667, value: 0 }, - ], - - defaultTable: "Levels (N-1)", - - scoreBucket: "lamp", - }, - "iidx:DP": { - idString: "iidx:DP", - - percentMax: 100, - - defaultScoreRatingAlg: "ktRating", - defaultSessionRatingAlg: "ktRating", - defaultProfileRatingAlg: "ktRating", - - difficulties: ["NORMAL", "HYPER", "ANOTHER", "LEGGENDARIA"], - defaultDifficulty: "ANOTHER", - difficultyColours: { - NORMAL: COLOUR_SET.blue, - HYPER: COLOUR_SET.orange, - ANOTHER: COLOUR_SET.red, - LEGGENDARIA: COLOUR_SET.purple, - }, - - grades: ["F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX"], - gradeColours: { - F: COLOUR_SET.gray, - E: COLOUR_SET.red, - D: COLOUR_SET.maroon, - C: COLOUR_SET.purple, - B: COLOUR_SET.paleBlue, - A: COLOUR_SET.green, - AA: COLOUR_SET.blue, - AAA: COLOUR_SET.gold, - "MAX-": COLOUR_SET.teal, - MAX: COLOUR_SET.white, - }, - clearGrade: "A", - gradeBoundaries: [0, 22.22, 33.33, 44.44, 55.55, 66.66, 77.77, 88.88, 94.44, 100.0], - - lamps: [ - "NO PLAY", - "FAILED", - "ASSIST CLEAR", - "EASY CLEAR", - "CLEAR", - "HARD CLEAR", - "EX HARD CLEAR", - "FULL COMBO", - ], - lampColours: { - "NO PLAY": COLOUR_SET.gray, - FAILED: COLOUR_SET.red, - "ASSIST CLEAR": COLOUR_SET.purple, - "EASY CLEAR": COLOUR_SET.green, - CLEAR: COLOUR_SET.blue, - "HARD CLEAR": COLOUR_SET.orange, - "EX HARD CLEAR": COLOUR_SET.gold, - "FULL COMBO": COLOUR_SET.teal, - }, - clearLamp: "CLEAR", - - supportsESD: true, - judgementWindows: [ - { name: "PGREAT", msBorder: 16.667, value: 2 }, - { name: "GREAT", msBorder: 33.333, value: 1 }, - { name: "GOOD", msBorder: 116.667, value: 0 }, - ], - - defaultTable: "Levels (N-1)", - - scoreBucket: "lamp", - }, - "chunithm:Single": { - idString: "chunithm:Single", - percentMax: 101, - - defaultScoreRatingAlg: "rating", - defaultSessionRatingAlg: "rating", - defaultProfileRatingAlg: "naiveRating", - - difficulties: ["BASIC", "ADVANCED", "EXPERT", "MASTER", "WORLD'S END"], - defaultDifficulty: "MASTER", - difficultyColours: { - BASIC: COLOUR_SET.blue, - ADVANCED: COLOUR_SET.orange, - EXPERT: COLOUR_SET.red, - MASTER: COLOUR_SET.purple, - "WORLD'S END": COLOUR_SET.vibrantYellow, - }, - - grades: ["D", "C", "B", "BB", "BBB", "A", "AA", "AAA", "S", "SS", "SSS"], - gradeColours: { - D: COLOUR_SET.red, - C: COLOUR_SET.purple, - B: COLOUR_SET.paleBlue, - BB: COLOUR_SET.blue, - BBB: COLOUR_SET.vibrantBlue, - A: COLOUR_SET.paleGreen, - AA: COLOUR_SET.green, - AAA: COLOUR_SET.vibrantGreen, - S: COLOUR_SET.vibrantOrange, - SS: COLOUR_SET.vibrantYellow, - SSS: COLOUR_SET.teal, - }, - clearGrade: "A", - gradeBoundaries: [0, 50, 60, 70, 80, 90, 92.5, 95.0, 97.5, 100, 107.5, 101], - - lamps: ["FAILED", "CLEAR", "FULL COMBO", "ALL JUSTICE", "ALL JUSTICE CRITICAL"], - lampColours: { - FAILED: COLOUR_SET.red, - CLEAR: COLOUR_SET.paleGreen, - "FULL COMBO": COLOUR_SET.paleBlue, - "ALL JUSTICE": COLOUR_SET.gold, - "ALL JUSTICE CRITICAL": COLOUR_SET.white, - }, - clearLamp: "CLEAR", - - supportsESD: false, - - defaultTable: "Levels (N-1)", - - scoreBucket: "grade", - }, - "sdvx:Single": { - idString: "sdvx:Single", - percentMax: 100, - - defaultScoreRatingAlg: "VF6", - defaultSessionRatingAlg: "ProfileVF6", - defaultProfileRatingAlg: "VF6", - - difficulties: ["NOV", "ADV", "EXH", "INF", "GRV", "HVN", "VVD", "MXM"], - defaultDifficulty: "EXH", - difficultyColours: { - NOV: COLOUR_SET.purple, // colour set dark purple - ADV: COLOUR_SET.vibrantYellow, - EXH: COLOUR_SET.red, - INF: "TODO", // colour set light pink - GRV: COLOUR_SET.orange, - HVN: COLOUR_SET.teal, - VVD: "TODO", // colour set pink - MXM: COLOUR_SET.white, - }, - - grades: ["D", "C", "B", "A", "A+", "AA", "AA+", "AAA", "AAA+", "S"], - gradeColours: { - D: COLOUR_SET.gray, - C: COLOUR_SET.red, - B: COLOUR_SET.maroon, - A: COLOUR_SET.paleBlue, - "A+": COLOUR_SET.blue, - AA: COLOUR_SET.paleGreen, - "AA+": COLOUR_SET.green, - AAA: COLOUR_SET.gold, - "AAA+": COLOUR_SET.vibrantYellow, - S: COLOUR_SET.teal, - }, - clearGrade: "A", - gradeBoundaries: [0, 70, 80, 87, 90, 93, 95, 97, 98, 99], - - lamps: ["FAILED", "CLEAR", "EXCESSIVE CLEAR", "ULTIMATE CHAIN", "PERFECT ULTIMATE CHAIN"], - lampColours: { - FAILED: COLOUR_SET.red, - CLEAR: COLOUR_SET.green, - "EXCESSIVE CLEAR": COLOUR_SET.orange, - "ULTIMATE CHAIN": COLOUR_SET.teal, - "PERFECT ULTIMATE CHAIN": COLOUR_SET.gold, - }, - clearLamp: "CLEAR", - - supportsESD: false, - - defaultTable: "Levels (N-1)", - - scoreBucket: "grade", - }, - "usc:Single": { - idString: "usc:Single", - percentMax: 100, - - defaultScoreRatingAlg: "VF6", - defaultSessionRatingAlg: "ProfileVF6", - defaultProfileRatingAlg: "VF6", - - difficulties: ["NOV", "ADV", "EXH", "INF"], - defaultDifficulty: "EXH", - difficultyColours: { - NOV: COLOUR_SET.purple, // colour set dark purple - ADV: COLOUR_SET.vibrantYellow, - EXH: COLOUR_SET.red, - INF: "TODO", // colour set light pink - }, - - grades: ["D", "C", "B", "A", "A+", "AA", "AA+", "AAA", "AAA+", "S"], - gradeColours: { - D: COLOUR_SET.gray, - C: COLOUR_SET.red, - B: COLOUR_SET.maroon, - A: COLOUR_SET.paleBlue, - "A+": COLOUR_SET.blue, - AA: COLOUR_SET.paleGreen, - "AA+": COLOUR_SET.green, - AAA: COLOUR_SET.gold, - "AAA+": COLOUR_SET.vibrantYellow, - S: COLOUR_SET.teal, - }, - clearGrade: "A", - gradeBoundaries: [0, 70, 80, 87, 90, 93, 95, 97, 98, 99], - - lamps: ["FAILED", "CLEAR", "EXCESSIVE CLEAR", "ULTIMATE CHAIN", "PERFECT ULTIMATE CHAIN"], - lampColours: { - FAILED: COLOUR_SET.red, - CLEAR: COLOUR_SET.green, - "EXCESSIVE CLEAR": COLOUR_SET.orange, - "ULTIMATE CHAIN": COLOUR_SET.teal, - "PERFECT ULTIMATE CHAIN": COLOUR_SET.gold, - }, - clearLamp: "CLEAR", - - supportsESD: false, - - defaultTable: "Levels (N-1)", - - scoreBucket: "grade", - }, - "museca:Single": { - idString: "museca:Single", - percentMax: 100, - - defaultScoreRatingAlg: "ktRating", - defaultSessionRatingAlg: "ktRating", - defaultProfileRatingAlg: "ktRating", - - difficulties: ["Green", "Yellow", "Red"], - defaultDifficulty: "Red", - difficultyColours: { - Green: COLOUR_SET.green, - Yellow: COLOUR_SET.vibrantYellow, - Red: COLOUR_SET.red, - }, - - grades: ["没", "拙", "凡", "佳", "良", "優", "秀", "傑", "傑G"], - gradeColours: { - 没: COLOUR_SET.gray, - 拙: COLOUR_SET.maroon, - 凡: COLOUR_SET.red, - 佳: COLOUR_SET.paleGreen, - 良: COLOUR_SET.paleBlue, - 優: COLOUR_SET.green, - 秀: COLOUR_SET.blue, - 傑: COLOUR_SET.teal, - 傑G: COLOUR_SET.gold, - }, - clearGrade: "良", - gradeBoundaries: [0, 60, 70, 80, 85, 90, 95, 97.5, 100], - - lamps: ["FAILED", "CLEAR", "CONNECT ALL", "PERFECT CONNECT ALL"], - lampColours: { - FAILED: COLOUR_SET.red, - CLEAR: COLOUR_SET.green, - "CONNECT ALL": COLOUR_SET.teal, - "PERFECT CONNECT ALL": COLOUR_SET.gold, - }, - clearLamp: "CLEAR", - - supportsESD: true, - judgementWindows: [ - { name: "CRITICAL", msBorder: 33.333, value: 2 }, - { name: "NEAR", msBorder: 66.667, value: 1 }, - ], - - defaultTable: "Levels (N-1)", - - scoreBucket: "grade", - }, - "bms:7K": { - idString: "bms:7K", - percentMax: 100, - - defaultScoreRatingAlg: "ktLampRating", - defaultSessionRatingAlg: "ktLampRating", - defaultProfileRatingAlg: "ktLampRating", - - difficulties: ["CHART"], - defaultDifficulty: "CHART", - difficultyColours: { - CHART: null, - }, - - grades: ["F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX"], - gradeColours: { - F: COLOUR_SET.gray, - E: COLOUR_SET.red, - D: COLOUR_SET.maroon, - C: COLOUR_SET.purple, - B: COLOUR_SET.paleBlue, - A: COLOUR_SET.green, - AA: COLOUR_SET.blue, - AAA: COLOUR_SET.gold, - "MAX-": COLOUR_SET.teal, - MAX: COLOUR_SET.white, - }, - clearGrade: "A", - gradeBoundaries: [0, 22.22, 33.33, 44.44, 55.55, 66.66, 77.77, 88.88, 94.44, 100.0], - - lamps: [ - "NO PLAY", - "FAILED", - "ASSIST CLEAR", - "EASY CLEAR", - "CLEAR", - "HARD CLEAR", - "EX HARD CLEAR", - "FULL COMBO", - ], - lampColours: { - "NO PLAY": COLOUR_SET.gray, - FAILED: COLOUR_SET.red, - "ASSIST CLEAR": COLOUR_SET.purple, - "EASY CLEAR": COLOUR_SET.green, - CLEAR: COLOUR_SET.blue, - "HARD CLEAR": COLOUR_SET.orange, - "EX HARD CLEAR": COLOUR_SET.gold, - "FULL COMBO": COLOUR_SET.teal, - }, - clearLamp: "CLEAR", - - supportsESD: false, - - defaultTable: "Insane", - - scoreBucket: "lamp", - }, - "bms:14K": { - idString: "bms:14K", - - percentMax: 100, - - defaultScoreRatingAlg: "ktLampRating", - defaultSessionRatingAlg: "ktLampRating", - defaultProfileRatingAlg: "ktLampRating", - - difficulties: ["CHART"], - defaultDifficulty: "CHART", - difficultyColours: { - CHART: null, - }, - - grades: ["F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX"], - gradeColours: { - F: COLOUR_SET.gray, - E: COLOUR_SET.red, - D: COLOUR_SET.maroon, - C: COLOUR_SET.purple, - B: COLOUR_SET.paleBlue, - A: COLOUR_SET.green, - AA: COLOUR_SET.blue, - AAA: COLOUR_SET.gold, - "MAX-": COLOUR_SET.teal, - MAX: COLOUR_SET.white, - }, - clearGrade: "A", - gradeBoundaries: [0, 22.22, 33.33, 44.44, 55.55, 66.66, 77.77, 88.88, 94.44, 100.0], - - lamps: [ - "NO PLAY", - "FAILED", - "ASSIST CLEAR", - "EASY CLEAR", - "CLEAR", - "HARD CLEAR", - "EX HARD CLEAR", - "FULL COMBO", - ], - lampColours: { - "NO PLAY": COLOUR_SET.gray, - FAILED: COLOUR_SET.red, - "ASSIST CLEAR": COLOUR_SET.purple, - "EASY CLEAR": COLOUR_SET.green, - CLEAR: COLOUR_SET.blue, - "HARD CLEAR": COLOUR_SET.orange, - "EX HARD CLEAR": COLOUR_SET.gold, - "FULL COMBO": COLOUR_SET.teal, - }, - clearLamp: "CLEAR", - - supportsESD: false, - - defaultTable: "Insane", - - scoreBucket: "lamp", - }, - "ddr:SP": { - idString: "ddr:SP", - - percentMax: 100, - - defaultScoreRatingAlg: "ktRating", - defaultSessionRatingAlg: "ktRating", - defaultProfileRatingAlg: "ktRating", - - difficulties: ["BEGINNER", "BASIC", "DIFFICULT", "EXPERT", "CHALLENGE"], - defaultDifficulty: "EXPERT", - difficultyColours: { - BEGINNER: COLOUR_SET.paleBlue, - BASIC: COLOUR_SET.orange, - DIFFICULT: COLOUR_SET.red, - EXPERT: COLOUR_SET.green, - CHALLENGE: COLOUR_SET.purple, - }, - - grades: [ - "D", - "D+", - "C-", - "C", - "C+", - "B-", - "B", - "B+", - "A-", - "A", - "A+", - "AA-", - "AA", - "AA+", - "AAA", - ], - gradeColours: { - D: COLOUR_SET.gray, - "D+": COLOUR_SET.maroon, - "C-": COLOUR_SET.red, - C: COLOUR_SET.purple, - "C+": COLOUR_SET.vibrantPurple, - "B-": COLOUR_SET.paleBlue, - B: COLOUR_SET.blue, - "B+": COLOUR_SET.vibrantBlue, - "A-": COLOUR_SET.paleGreen, - A: COLOUR_SET.green, - "A+": COLOUR_SET.vibrantGreen, - "AA-": COLOUR_SET.paleOrange, - AA: COLOUR_SET.orange, - "AA+": COLOUR_SET.vibrantOrange, - AAA: COLOUR_SET.gold, - }, - clearGrade: "A", - gradeBoundaries: [0, 55, 59, 60, 65, 69, 70, 75, 79, 80, 85, 89, 90, 95, 99], - - lamps: [ - "FAILED", - "CLEAR", - "LIFE4", - "FULL COMBO", - "GREAT FULL COMBO", - "PERFECT FULL COMBO", - "MARVELOUS FULL COMBO", - ], - lampColours: { - FAILED: COLOUR_SET.red, - CLEAR: COLOUR_SET.paleGreen, - LIFE4: COLOUR_SET.orange, - "FULL COMBO": COLOUR_SET.paleBlue, - "GREAT FULL COMBO": COLOUR_SET.green, - "PERFECT FULL COMBO": COLOUR_SET.gold, - "MARVELOUS FULL COMBO": COLOUR_SET.teal, - }, - clearLamp: "CLEAR", - - supportsESD: true, - judgementWindows: [ - { name: "MARVELOUS", msBorder: 15, value: 3 }, - { name: "PERFECT", msBorder: 30, value: 2 }, - { name: "GREAT", msBorder: 59, value: 1 }, - { name: "GOOD", msBorder: 89, value: 0 }, - { name: "BAD", msBorder: 119, value: 0 }, - ], - - defaultTable: "Levels (N-1)", - - scoreBucket: "lamp", - }, - "ddr:DP": { - idString: "ddr:DP", - - percentMax: 100, - - defaultScoreRatingAlg: "ktRating", - defaultSessionRatingAlg: "ktRating", - defaultProfileRatingAlg: "ktRating", - - difficulties: ["BASIC", "DIFFICULT", "EXPERT", "CHALLENGE"], - defaultDifficulty: "EXPERT", - difficultyColours: { - BASIC: COLOUR_SET.orange, - DIFFICULT: COLOUR_SET.red, - EXPERT: COLOUR_SET.green, - CHALLENGE: COLOUR_SET.purple, - }, - - grades: [ - "D", - "D+", - "C-", - "C", - "C+", - "B-", - "B", - "B+", - "A-", - "A", - "A+", - "AA-", - "AA", - "AA+", - "AAA", - ], - gradeColours: { - D: COLOUR_SET.gray, - "D+": COLOUR_SET.maroon, - "C-": COLOUR_SET.red, - C: COLOUR_SET.purple, - "C+": COLOUR_SET.vibrantPurple, - "B-": COLOUR_SET.paleBlue, - B: COLOUR_SET.blue, - "B+": COLOUR_SET.vibrantBlue, - "A-": COLOUR_SET.paleGreen, - A: COLOUR_SET.green, - "A+": COLOUR_SET.vibrantGreen, - "AA-": COLOUR_SET.paleOrange, - AA: COLOUR_SET.orange, - "AA+": COLOUR_SET.vibrantOrange, - AAA: COLOUR_SET.gold, - }, - clearGrade: "A", - gradeBoundaries: [0, 55, 59, 60, 65, 69, 70, 75, 79, 80, 85, 89, 90, 95, 99], - - lamps: [ - "FAILED", - "CLEAR", - "LIFE4", - "FULL COMBO", - "GREAT FULL COMBO", - "PERFECT FULL COMBO", - "MARVELOUS FULL COMBO", - ], - lampColours: { - FAILED: COLOUR_SET.red, - CLEAR: COLOUR_SET.paleGreen, - LIFE4: COLOUR_SET.orange, - "FULL COMBO": COLOUR_SET.paleBlue, - "GREAT FULL COMBO": COLOUR_SET.green, - "PERFECT FULL COMBO": COLOUR_SET.gold, - "MARVELOUS FULL COMBO": COLOUR_SET.teal, - }, - clearLamp: "CLEAR", - - supportsESD: true, - judgementWindows: [ - { name: "MARVELOUS", msBorder: 15, value: 3 }, - { name: "PERFECT", msBorder: 30, value: 2 }, - { name: "GREAT", msBorder: 59, value: 1 }, - { name: "GOOD", msBorder: 89, value: 0 }, - { name: "BAD", msBorder: 119, value: 0 }, - ], - - defaultTable: "Levels (N-1)", - - scoreBucket: "lamp", - }, - "maimai:Single": { - idString: "maimai:Single", - - percentMax: 120, // a safe estimate? - - defaultScoreRatingAlg: "ktRating", - defaultSessionRatingAlg: "ktRating", - defaultProfileRatingAlg: "ktRating", - - difficulties: ["Easy", "Basic", "Advanced", "Expert", "Master", "Re:Master"], - defaultDifficulty: "Master", - difficultyColours: { - Easy: COLOUR_SET.blue, - Basic: COLOUR_SET.green, - Advanced: COLOUR_SET.orange, - Expert: COLOUR_SET.red, - Master: COLOUR_SET.purple, - "Re:Master": COLOUR_SET.white, - }, - - grades: ["F", "E", "D", "C", "B", "A", "AA", "AAA", "S", "S+", "SS", "SS+", "SSS", "SSS+"], - gradeColours: { - F: COLOUR_SET.gray, - E: COLOUR_SET.red, - D: COLOUR_SET.maroon, - C: COLOUR_SET.purple, - B: COLOUR_SET.paleGreen, - A: COLOUR_SET.green, - AA: COLOUR_SET.paleBlue, - AAA: COLOUR_SET.blue, - S: COLOUR_SET.gold, - "S+": COLOUR_SET.vibrantYellow, - SS: COLOUR_SET.paleOrange, - "SS+": COLOUR_SET.orange, - SSS: COLOUR_SET.teal, - "SSS+": COLOUR_SET.white, - }, - clearGrade: "A", - // @hack Maimai's top grade depends on the chart's maximum percent - // we just set it at percentMax, but it's not technically correct - gradeBoundaries: [0, 10, 20, 40, 60, 80, 90, 94, 97, 98, 99, 99.5, 100, 120], - - lamps: ["FAILED", "CLEAR", "FULL COMBO", "ALL PERFECT", "ALL PERFECT+"], - lampColours: { - FAILED: COLOUR_SET.red, - CLEAR: COLOUR_SET.green, - "FULL COMBO": COLOUR_SET.blue, - "ALL PERFECT": COLOUR_SET.gold, - "ALL PERFECT+": COLOUR_SET.teal, - }, - clearLamp: "CLEAR", - - supportsESD: false, - - defaultTable: "Levels", - - scoreBucket: "grade", - }, - "gitadora:Gita": { - idString: "gitadora:Gita", - - percentMax: 100, - - defaultScoreRatingAlg: "skill", - defaultSessionRatingAlg: "skill", - defaultProfileRatingAlg: "skill", - - difficulties: [ - "BASIC", - "ADVANCED", - "EXTREME", - "MASTER", - "BASS BASIC", - "BASS ADVANCED", - "BASS EXTREME", - "BASS MASTER", - ], - defaultDifficulty: "EXTREME", - difficultyColours: { - BASIC: COLOUR_SET.blue, - ADVANCED: COLOUR_SET.orange, - EXTREME: COLOUR_SET.red, - MASTER: COLOUR_SET.purple, - "BASS BASIC": COLOUR_SET.vibrantBlue, - "BASS ADVANCED": COLOUR_SET.vibrantOrange, - "BASS EXTREME": "todo", // colourset vibrant red - "BASS MASTER": COLOUR_SET.vibrantPurple, - }, - - grades: ["C", "B", "A", "S", "SS", "MAX"], - gradeColours: { - C: COLOUR_SET.purple, - B: COLOUR_SET.blue, - A: COLOUR_SET.green, - S: COLOUR_SET.orange, - SS: COLOUR_SET.gold, - MAX: COLOUR_SET.white, - }, - clearGrade: "A", - gradeBoundaries: [0, 63, 73, 80, 95, 100], - - lamps: ["FAILED", "CLEAR", "FULL COMBO", "EXCELLENT"], - lampColours: { - FAILED: COLOUR_SET.red, - CLEAR: COLOUR_SET.blue, - "FULL COMBO": COLOUR_SET.teal, - EXCELLENT: COLOUR_SET.gold, - }, - clearLamp: "CLEAR", - - supportsESD: true, - judgementWindows: [ - { name: "PERFECT", msBorder: 33, value: 1 }, - { name: "GREAT", msBorder: 57, value: 0.5 }, - { name: "GOOD", msBorder: 81, value: 0.2 }, - { name: "OK", msBorder: 116.667 /* not really, but yknow */, value: 0 }, - ], - - defaultTable: "Levels (N-1)", - - scoreBucket: "grade", - }, - "gitadora:Dora": { - idString: "gitadora:Dora", - - percentMax: 100, - - defaultScoreRatingAlg: "skill", - defaultSessionRatingAlg: "skill", - defaultProfileRatingAlg: "skill", - - difficulties: ["BASIC", "ADVANCED", "EXTREME", "MASTER"], - defaultDifficulty: "EXTREME", - difficultyColours: { - BASIC: COLOUR_SET.blue, - ADVANCED: COLOUR_SET.orange, - EXTREME: COLOUR_SET.red, - MASTER: COLOUR_SET.purple, - }, - - grades: ["C", "B", "A", "S", "SS", "MAX"], - gradeColours: { - C: COLOUR_SET.purple, - B: COLOUR_SET.blue, - A: COLOUR_SET.green, - S: COLOUR_SET.orange, - SS: COLOUR_SET.gold, - MAX: COLOUR_SET.white, - }, - clearGrade: "A", - gradeBoundaries: [0, 63, 73, 80, 95, 100], - - lamps: ["FAILED", "CLEAR", "FULL COMBO", "EXCELLENT"], - lampColours: { - FAILED: COLOUR_SET.red, - CLEAR: COLOUR_SET.blue, - "FULL COMBO": COLOUR_SET.teal, - EXCELLENT: COLOUR_SET.gold, - }, - clearLamp: "CLEAR", - - supportsESD: true, - judgementWindows: [ - { name: "PERFECT", msBorder: 27, value: 1 }, - { name: "GREAT", msBorder: 48, value: 0.5 }, - { name: "GOOD", msBorder: 72, value: 0.2 }, - { name: "OK", msBorder: 116.667 /* not really, but yknow */, value: 0 }, - ], - - defaultTable: "Levels (N-1)", - - scoreBucket: "grade", - }, + "iidx:SP": { + idString: "iidx:SP", + + percentMax: 100, + + defaultScoreRatingAlg: "ktRating", + defaultSessionRatingAlg: "ktRating", + defaultProfileRatingAlg: "ktRating", + + difficulties: ["BEGINNER", "NORMAL", "HYPER", "ANOTHER", "LEGGENDARIA"], + defaultDifficulty: "ANOTHER", + difficultyColours: { + BEGINNER: COLOUR_SET.paleGreen, + NORMAL: COLOUR_SET.blue, + HYPER: COLOUR_SET.orange, + ANOTHER: COLOUR_SET.red, + LEGGENDARIA: COLOUR_SET.purple, + }, + + grades: ["F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX"], + gradeColours: { + F: COLOUR_SET.gray, + E: COLOUR_SET.red, + D: COLOUR_SET.maroon, + C: COLOUR_SET.purple, + B: COLOUR_SET.paleBlue, + A: COLOUR_SET.green, + AA: COLOUR_SET.blue, + AAA: COLOUR_SET.gold, + "MAX-": COLOUR_SET.teal, + MAX: COLOUR_SET.white, + }, + clearGrade: "A", + gradeBoundaries: [0, 22.22, 33.33, 44.44, 55.55, 66.66, 77.77, 88.88, 94.44, 100.0], + + lamps: [ + "NO PLAY", + "FAILED", + "ASSIST CLEAR", + "EASY CLEAR", + "CLEAR", + "HARD CLEAR", + "EX HARD CLEAR", + "FULL COMBO", + ], + lampColours: { + "NO PLAY": COLOUR_SET.gray, + FAILED: COLOUR_SET.red, + "ASSIST CLEAR": COLOUR_SET.purple, + "EASY CLEAR": COLOUR_SET.green, + CLEAR: COLOUR_SET.blue, + "HARD CLEAR": COLOUR_SET.orange, + "EX HARD CLEAR": COLOUR_SET.gold, + "FULL COMBO": COLOUR_SET.teal, + }, + clearLamp: "CLEAR", + + supportsESD: true, + judgementWindows: [ + { name: "PGREAT", msBorder: 16.667, value: 2 }, + { name: "GREAT", msBorder: 33.333, value: 1 }, + { name: "GOOD", msBorder: 116.667, value: 0 }, + ], + + defaultTable: "Levels (N-1)", + + scoreBucket: "lamp", + }, + "iidx:DP": { + idString: "iidx:DP", + + percentMax: 100, + + defaultScoreRatingAlg: "ktRating", + defaultSessionRatingAlg: "ktRating", + defaultProfileRatingAlg: "ktRating", + + difficulties: ["NORMAL", "HYPER", "ANOTHER", "LEGGENDARIA"], + defaultDifficulty: "ANOTHER", + difficultyColours: { + NORMAL: COLOUR_SET.blue, + HYPER: COLOUR_SET.orange, + ANOTHER: COLOUR_SET.red, + LEGGENDARIA: COLOUR_SET.purple, + }, + + grades: ["F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX"], + gradeColours: { + F: COLOUR_SET.gray, + E: COLOUR_SET.red, + D: COLOUR_SET.maroon, + C: COLOUR_SET.purple, + B: COLOUR_SET.paleBlue, + A: COLOUR_SET.green, + AA: COLOUR_SET.blue, + AAA: COLOUR_SET.gold, + "MAX-": COLOUR_SET.teal, + MAX: COLOUR_SET.white, + }, + clearGrade: "A", + gradeBoundaries: [0, 22.22, 33.33, 44.44, 55.55, 66.66, 77.77, 88.88, 94.44, 100.0], + + lamps: [ + "NO PLAY", + "FAILED", + "ASSIST CLEAR", + "EASY CLEAR", + "CLEAR", + "HARD CLEAR", + "EX HARD CLEAR", + "FULL COMBO", + ], + lampColours: { + "NO PLAY": COLOUR_SET.gray, + FAILED: COLOUR_SET.red, + "ASSIST CLEAR": COLOUR_SET.purple, + "EASY CLEAR": COLOUR_SET.green, + CLEAR: COLOUR_SET.blue, + "HARD CLEAR": COLOUR_SET.orange, + "EX HARD CLEAR": COLOUR_SET.gold, + "FULL COMBO": COLOUR_SET.teal, + }, + clearLamp: "CLEAR", + + supportsESD: true, + judgementWindows: [ + { name: "PGREAT", msBorder: 16.667, value: 2 }, + { name: "GREAT", msBorder: 33.333, value: 1 }, + { name: "GOOD", msBorder: 116.667, value: 0 }, + ], + + defaultTable: "Levels (N-1)", + + scoreBucket: "lamp", + }, + "chunithm:Single": { + idString: "chunithm:Single", + percentMax: 101, + + defaultScoreRatingAlg: "rating", + defaultSessionRatingAlg: "rating", + defaultProfileRatingAlg: "naiveRating", + + difficulties: ["BASIC", "ADVANCED", "EXPERT", "MASTER", "WORLD'S END"], + defaultDifficulty: "MASTER", + difficultyColours: { + BASIC: COLOUR_SET.blue, + ADVANCED: COLOUR_SET.orange, + EXPERT: COLOUR_SET.red, + MASTER: COLOUR_SET.purple, + "WORLD'S END": COLOUR_SET.vibrantYellow, + }, + + grades: ["D", "C", "B", "BB", "BBB", "A", "AA", "AAA", "S", "SS", "SSS"], + gradeColours: { + D: COLOUR_SET.red, + C: COLOUR_SET.purple, + B: COLOUR_SET.paleBlue, + BB: COLOUR_SET.blue, + BBB: COLOUR_SET.vibrantBlue, + A: COLOUR_SET.paleGreen, + AA: COLOUR_SET.green, + AAA: COLOUR_SET.vibrantGreen, + S: COLOUR_SET.vibrantOrange, + SS: COLOUR_SET.vibrantYellow, + SSS: COLOUR_SET.teal, + }, + clearGrade: "A", + gradeBoundaries: [0, 50, 60, 70, 80, 90, 92.5, 95.0, 97.5, 100, 107.5, 101], + + lamps: ["FAILED", "CLEAR", "FULL COMBO", "ALL JUSTICE", "ALL JUSTICE CRITICAL"], + lampColours: { + FAILED: COLOUR_SET.red, + CLEAR: COLOUR_SET.paleGreen, + "FULL COMBO": COLOUR_SET.paleBlue, + "ALL JUSTICE": COLOUR_SET.gold, + "ALL JUSTICE CRITICAL": COLOUR_SET.white, + }, + clearLamp: "CLEAR", + + supportsESD: false, + + defaultTable: "Levels (N-1)", + + scoreBucket: "grade", + }, + "sdvx:Single": { + idString: "sdvx:Single", + percentMax: 100, + + defaultScoreRatingAlg: "VF6", + defaultSessionRatingAlg: "ProfileVF6", + defaultProfileRatingAlg: "VF6", + + difficulties: ["NOV", "ADV", "EXH", "INF", "GRV", "HVN", "VVD", "MXM"], + defaultDifficulty: "EXH", + difficultyColours: { + NOV: COLOUR_SET.purple, // colour set dark purple + ADV: COLOUR_SET.vibrantYellow, + EXH: COLOUR_SET.red, + INF: "TODO", // colour set light pink + GRV: COLOUR_SET.orange, + HVN: COLOUR_SET.teal, + VVD: "TODO", // colour set pink + MXM: COLOUR_SET.white, + }, + + grades: ["D", "C", "B", "A", "A+", "AA", "AA+", "AAA", "AAA+", "S"], + gradeColours: { + D: COLOUR_SET.gray, + C: COLOUR_SET.red, + B: COLOUR_SET.maroon, + A: COLOUR_SET.paleBlue, + "A+": COLOUR_SET.blue, + AA: COLOUR_SET.paleGreen, + "AA+": COLOUR_SET.green, + AAA: COLOUR_SET.gold, + "AAA+": COLOUR_SET.vibrantYellow, + S: COLOUR_SET.teal, + }, + clearGrade: "A", + gradeBoundaries: [0, 70, 80, 87, 90, 93, 95, 97, 98, 99], + + lamps: ["FAILED", "CLEAR", "EXCESSIVE CLEAR", "ULTIMATE CHAIN", "PERFECT ULTIMATE CHAIN"], + lampColours: { + FAILED: COLOUR_SET.red, + CLEAR: COLOUR_SET.green, + "EXCESSIVE CLEAR": COLOUR_SET.orange, + "ULTIMATE CHAIN": COLOUR_SET.teal, + "PERFECT ULTIMATE CHAIN": COLOUR_SET.gold, + }, + clearLamp: "CLEAR", + + supportsESD: false, + + defaultTable: "Levels (N-1)", + + scoreBucket: "grade", + }, + "usc:Single": { + idString: "usc:Single", + percentMax: 100, + + defaultScoreRatingAlg: "VF6", + defaultSessionRatingAlg: "ProfileVF6", + defaultProfileRatingAlg: "VF6", + + difficulties: ["NOV", "ADV", "EXH", "INF"], + defaultDifficulty: "EXH", + difficultyColours: { + NOV: COLOUR_SET.purple, // colour set dark purple + ADV: COLOUR_SET.vibrantYellow, + EXH: COLOUR_SET.red, + INF: "TODO", // colour set light pink + }, + + grades: ["D", "C", "B", "A", "A+", "AA", "AA+", "AAA", "AAA+", "S"], + gradeColours: { + D: COLOUR_SET.gray, + C: COLOUR_SET.red, + B: COLOUR_SET.maroon, + A: COLOUR_SET.paleBlue, + "A+": COLOUR_SET.blue, + AA: COLOUR_SET.paleGreen, + "AA+": COLOUR_SET.green, + AAA: COLOUR_SET.gold, + "AAA+": COLOUR_SET.vibrantYellow, + S: COLOUR_SET.teal, + }, + clearGrade: "A", + gradeBoundaries: [0, 70, 80, 87, 90, 93, 95, 97, 98, 99], + + lamps: ["FAILED", "CLEAR", "EXCESSIVE CLEAR", "ULTIMATE CHAIN", "PERFECT ULTIMATE CHAIN"], + lampColours: { + FAILED: COLOUR_SET.red, + CLEAR: COLOUR_SET.green, + "EXCESSIVE CLEAR": COLOUR_SET.orange, + "ULTIMATE CHAIN": COLOUR_SET.teal, + "PERFECT ULTIMATE CHAIN": COLOUR_SET.gold, + }, + clearLamp: "CLEAR", + + supportsESD: false, + + defaultTable: "Levels (N-1)", + + scoreBucket: "grade", + }, + "museca:Single": { + idString: "museca:Single", + percentMax: 100, + + defaultScoreRatingAlg: "ktRating", + defaultSessionRatingAlg: "ktRating", + defaultProfileRatingAlg: "ktRating", + + difficulties: ["Green", "Yellow", "Red"], + defaultDifficulty: "Red", + difficultyColours: { + Green: COLOUR_SET.green, + Yellow: COLOUR_SET.vibrantYellow, + Red: COLOUR_SET.red, + }, + + grades: ["没", "拙", "凡", "佳", "良", "優", "秀", "傑", "傑G"], + gradeColours: { + 没: COLOUR_SET.gray, + 拙: COLOUR_SET.maroon, + 凡: COLOUR_SET.red, + 佳: COLOUR_SET.paleGreen, + 良: COLOUR_SET.paleBlue, + 優: COLOUR_SET.green, + 秀: COLOUR_SET.blue, + 傑: COLOUR_SET.teal, + 傑G: COLOUR_SET.gold, + }, + clearGrade: "良", + gradeBoundaries: [0, 60, 70, 80, 85, 90, 95, 97.5, 100], + + lamps: ["FAILED", "CLEAR", "CONNECT ALL", "PERFECT CONNECT ALL"], + lampColours: { + FAILED: COLOUR_SET.red, + CLEAR: COLOUR_SET.green, + "CONNECT ALL": COLOUR_SET.teal, + "PERFECT CONNECT ALL": COLOUR_SET.gold, + }, + clearLamp: "CLEAR", + + supportsESD: true, + judgementWindows: [ + { name: "CRITICAL", msBorder: 33.333, value: 2 }, + { name: "NEAR", msBorder: 66.667, value: 1 }, + ], + + defaultTable: "Levels (N-1)", + + scoreBucket: "grade", + }, + "bms:7K": { + idString: "bms:7K", + percentMax: 100, + + defaultScoreRatingAlg: "ktLampRating", + defaultSessionRatingAlg: "ktLampRating", + defaultProfileRatingAlg: "ktLampRating", + + difficulties: ["CHART"], + defaultDifficulty: "CHART", + difficultyColours: { + CHART: null, + }, + + grades: ["F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX"], + gradeColours: { + F: COLOUR_SET.gray, + E: COLOUR_SET.red, + D: COLOUR_SET.maroon, + C: COLOUR_SET.purple, + B: COLOUR_SET.paleBlue, + A: COLOUR_SET.green, + AA: COLOUR_SET.blue, + AAA: COLOUR_SET.gold, + "MAX-": COLOUR_SET.teal, + MAX: COLOUR_SET.white, + }, + clearGrade: "A", + gradeBoundaries: [0, 22.22, 33.33, 44.44, 55.55, 66.66, 77.77, 88.88, 94.44, 100.0], + + lamps: [ + "NO PLAY", + "FAILED", + "ASSIST CLEAR", + "EASY CLEAR", + "CLEAR", + "HARD CLEAR", + "EX HARD CLEAR", + "FULL COMBO", + ], + lampColours: { + "NO PLAY": COLOUR_SET.gray, + FAILED: COLOUR_SET.red, + "ASSIST CLEAR": COLOUR_SET.purple, + "EASY CLEAR": COLOUR_SET.green, + CLEAR: COLOUR_SET.blue, + "HARD CLEAR": COLOUR_SET.orange, + "EX HARD CLEAR": COLOUR_SET.gold, + "FULL COMBO": COLOUR_SET.teal, + }, + clearLamp: "CLEAR", + + supportsESD: false, + + defaultTable: "Insane", + + scoreBucket: "lamp", + }, + "bms:14K": { + idString: "bms:14K", + + percentMax: 100, + + defaultScoreRatingAlg: "ktLampRating", + defaultSessionRatingAlg: "ktLampRating", + defaultProfileRatingAlg: "ktLampRating", + + difficulties: ["CHART"], + defaultDifficulty: "CHART", + difficultyColours: { + CHART: null, + }, + + grades: ["F", "E", "D", "C", "B", "A", "AA", "AAA", "MAX-", "MAX"], + gradeColours: { + F: COLOUR_SET.gray, + E: COLOUR_SET.red, + D: COLOUR_SET.maroon, + C: COLOUR_SET.purple, + B: COLOUR_SET.paleBlue, + A: COLOUR_SET.green, + AA: COLOUR_SET.blue, + AAA: COLOUR_SET.gold, + "MAX-": COLOUR_SET.teal, + MAX: COLOUR_SET.white, + }, + clearGrade: "A", + gradeBoundaries: [0, 22.22, 33.33, 44.44, 55.55, 66.66, 77.77, 88.88, 94.44, 100.0], + + lamps: [ + "NO PLAY", + "FAILED", + "ASSIST CLEAR", + "EASY CLEAR", + "CLEAR", + "HARD CLEAR", + "EX HARD CLEAR", + "FULL COMBO", + ], + lampColours: { + "NO PLAY": COLOUR_SET.gray, + FAILED: COLOUR_SET.red, + "ASSIST CLEAR": COLOUR_SET.purple, + "EASY CLEAR": COLOUR_SET.green, + CLEAR: COLOUR_SET.blue, + "HARD CLEAR": COLOUR_SET.orange, + "EX HARD CLEAR": COLOUR_SET.gold, + "FULL COMBO": COLOUR_SET.teal, + }, + clearLamp: "CLEAR", + + supportsESD: false, + + defaultTable: "Insane", + + scoreBucket: "lamp", + }, + "ddr:SP": { + idString: "ddr:SP", + + percentMax: 100, + + defaultScoreRatingAlg: "ktRating", + defaultSessionRatingAlg: "ktRating", + defaultProfileRatingAlg: "ktRating", + + difficulties: ["BEGINNER", "BASIC", "DIFFICULT", "EXPERT", "CHALLENGE"], + defaultDifficulty: "EXPERT", + difficultyColours: { + BEGINNER: COLOUR_SET.paleBlue, + BASIC: COLOUR_SET.orange, + DIFFICULT: COLOUR_SET.red, + EXPERT: COLOUR_SET.green, + CHALLENGE: COLOUR_SET.purple, + }, + + grades: [ + "D", + "D+", + "C-", + "C", + "C+", + "B-", + "B", + "B+", + "A-", + "A", + "A+", + "AA-", + "AA", + "AA+", + "AAA", + ], + gradeColours: { + D: COLOUR_SET.gray, + "D+": COLOUR_SET.maroon, + "C-": COLOUR_SET.red, + C: COLOUR_SET.purple, + "C+": COLOUR_SET.vibrantPurple, + "B-": COLOUR_SET.paleBlue, + B: COLOUR_SET.blue, + "B+": COLOUR_SET.vibrantBlue, + "A-": COLOUR_SET.paleGreen, + A: COLOUR_SET.green, + "A+": COLOUR_SET.vibrantGreen, + "AA-": COLOUR_SET.paleOrange, + AA: COLOUR_SET.orange, + "AA+": COLOUR_SET.vibrantOrange, + AAA: COLOUR_SET.gold, + }, + clearGrade: "A", + gradeBoundaries: [0, 55, 59, 60, 65, 69, 70, 75, 79, 80, 85, 89, 90, 95, 99], + + lamps: [ + "FAILED", + "CLEAR", + "LIFE4", + "FULL COMBO", + "GREAT FULL COMBO", + "PERFECT FULL COMBO", + "MARVELOUS FULL COMBO", + ], + lampColours: { + FAILED: COLOUR_SET.red, + CLEAR: COLOUR_SET.paleGreen, + LIFE4: COLOUR_SET.orange, + "FULL COMBO": COLOUR_SET.paleBlue, + "GREAT FULL COMBO": COLOUR_SET.green, + "PERFECT FULL COMBO": COLOUR_SET.gold, + "MARVELOUS FULL COMBO": COLOUR_SET.teal, + }, + clearLamp: "CLEAR", + + supportsESD: true, + judgementWindows: [ + { name: "MARVELOUS", msBorder: 15, value: 3 }, + { name: "PERFECT", msBorder: 30, value: 2 }, + { name: "GREAT", msBorder: 59, value: 1 }, + { name: "GOOD", msBorder: 89, value: 0 }, + { name: "BAD", msBorder: 119, value: 0 }, + ], + + defaultTable: "Levels (N-1)", + + scoreBucket: "lamp", + }, + "ddr:DP": { + idString: "ddr:DP", + + percentMax: 100, + + defaultScoreRatingAlg: "ktRating", + defaultSessionRatingAlg: "ktRating", + defaultProfileRatingAlg: "ktRating", + + difficulties: ["BASIC", "DIFFICULT", "EXPERT", "CHALLENGE"], + defaultDifficulty: "EXPERT", + difficultyColours: { + BASIC: COLOUR_SET.orange, + DIFFICULT: COLOUR_SET.red, + EXPERT: COLOUR_SET.green, + CHALLENGE: COLOUR_SET.purple, + }, + + grades: [ + "D", + "D+", + "C-", + "C", + "C+", + "B-", + "B", + "B+", + "A-", + "A", + "A+", + "AA-", + "AA", + "AA+", + "AAA", + ], + gradeColours: { + D: COLOUR_SET.gray, + "D+": COLOUR_SET.maroon, + "C-": COLOUR_SET.red, + C: COLOUR_SET.purple, + "C+": COLOUR_SET.vibrantPurple, + "B-": COLOUR_SET.paleBlue, + B: COLOUR_SET.blue, + "B+": COLOUR_SET.vibrantBlue, + "A-": COLOUR_SET.paleGreen, + A: COLOUR_SET.green, + "A+": COLOUR_SET.vibrantGreen, + "AA-": COLOUR_SET.paleOrange, + AA: COLOUR_SET.orange, + "AA+": COLOUR_SET.vibrantOrange, + AAA: COLOUR_SET.gold, + }, + clearGrade: "A", + gradeBoundaries: [0, 55, 59, 60, 65, 69, 70, 75, 79, 80, 85, 89, 90, 95, 99], + + lamps: [ + "FAILED", + "CLEAR", + "LIFE4", + "FULL COMBO", + "GREAT FULL COMBO", + "PERFECT FULL COMBO", + "MARVELOUS FULL COMBO", + ], + lampColours: { + FAILED: COLOUR_SET.red, + CLEAR: COLOUR_SET.paleGreen, + LIFE4: COLOUR_SET.orange, + "FULL COMBO": COLOUR_SET.paleBlue, + "GREAT FULL COMBO": COLOUR_SET.green, + "PERFECT FULL COMBO": COLOUR_SET.gold, + "MARVELOUS FULL COMBO": COLOUR_SET.teal, + }, + clearLamp: "CLEAR", + + supportsESD: true, + judgementWindows: [ + { name: "MARVELOUS", msBorder: 15, value: 3 }, + { name: "PERFECT", msBorder: 30, value: 2 }, + { name: "GREAT", msBorder: 59, value: 1 }, + { name: "GOOD", msBorder: 89, value: 0 }, + { name: "BAD", msBorder: 119, value: 0 }, + ], + + defaultTable: "Levels (N-1)", + + scoreBucket: "lamp", + }, + "maimai:Single": { + idString: "maimai:Single", + + percentMax: 120, // a safe estimate? + + defaultScoreRatingAlg: "ktRating", + defaultSessionRatingAlg: "ktRating", + defaultProfileRatingAlg: "ktRating", + + difficulties: ["Easy", "Basic", "Advanced", "Expert", "Master", "Re:Master"], + defaultDifficulty: "Master", + difficultyColours: { + Easy: COLOUR_SET.blue, + Basic: COLOUR_SET.green, + Advanced: COLOUR_SET.orange, + Expert: COLOUR_SET.red, + Master: COLOUR_SET.purple, + "Re:Master": COLOUR_SET.white, + }, + + grades: ["F", "E", "D", "C", "B", "A", "AA", "AAA", "S", "S+", "SS", "SS+", "SSS", "SSS+"], + gradeColours: { + F: COLOUR_SET.gray, + E: COLOUR_SET.red, + D: COLOUR_SET.maroon, + C: COLOUR_SET.purple, + B: COLOUR_SET.paleGreen, + A: COLOUR_SET.green, + AA: COLOUR_SET.paleBlue, + AAA: COLOUR_SET.blue, + S: COLOUR_SET.gold, + "S+": COLOUR_SET.vibrantYellow, + SS: COLOUR_SET.paleOrange, + "SS+": COLOUR_SET.orange, + SSS: COLOUR_SET.teal, + "SSS+": COLOUR_SET.white, + }, + clearGrade: "A", + // @hack Maimai's top grade depends on the chart's maximum percent + // we just set it at percentMax, but it's not technically correct + gradeBoundaries: [0, 10, 20, 40, 60, 80, 90, 94, 97, 98, 99, 99.5, 100, 120], + + lamps: ["FAILED", "CLEAR", "FULL COMBO", "ALL PERFECT", "ALL PERFECT+"], + lampColours: { + FAILED: COLOUR_SET.red, + CLEAR: COLOUR_SET.green, + "FULL COMBO": COLOUR_SET.blue, + "ALL PERFECT": COLOUR_SET.gold, + "ALL PERFECT+": COLOUR_SET.teal, + }, + clearLamp: "CLEAR", + + supportsESD: false, + + defaultTable: "Levels", + + scoreBucket: "grade", + }, + "gitadora:Gita": { + idString: "gitadora:Gita", + + percentMax: 100, + + defaultScoreRatingAlg: "skill", + defaultSessionRatingAlg: "skill", + defaultProfileRatingAlg: "skill", + + difficulties: [ + "BASIC", + "ADVANCED", + "EXTREME", + "MASTER", + "BASS BASIC", + "BASS ADVANCED", + "BASS EXTREME", + "BASS MASTER", + ], + defaultDifficulty: "EXTREME", + difficultyColours: { + BASIC: COLOUR_SET.blue, + ADVANCED: COLOUR_SET.orange, + EXTREME: COLOUR_SET.red, + MASTER: COLOUR_SET.purple, + "BASS BASIC": COLOUR_SET.vibrantBlue, + "BASS ADVANCED": COLOUR_SET.vibrantOrange, + "BASS EXTREME": "todo", // colourset vibrant red + "BASS MASTER": COLOUR_SET.vibrantPurple, + }, + + grades: ["C", "B", "A", "S", "SS", "MAX"], + gradeColours: { + C: COLOUR_SET.purple, + B: COLOUR_SET.blue, + A: COLOUR_SET.green, + S: COLOUR_SET.orange, + SS: COLOUR_SET.gold, + MAX: COLOUR_SET.white, + }, + clearGrade: "A", + gradeBoundaries: [0, 63, 73, 80, 95, 100], + + lamps: ["FAILED", "CLEAR", "FULL COMBO", "EXCELLENT"], + lampColours: { + FAILED: COLOUR_SET.red, + CLEAR: COLOUR_SET.blue, + "FULL COMBO": COLOUR_SET.teal, + EXCELLENT: COLOUR_SET.gold, + }, + clearLamp: "CLEAR", + + supportsESD: true, + judgementWindows: [ + { name: "PERFECT", msBorder: 33, value: 1 }, + { name: "GREAT", msBorder: 57, value: 0.5 }, + { name: "GOOD", msBorder: 81, value: 0.2 }, + { name: "OK", msBorder: 116.667 /* not really, but yknow */, value: 0 }, + ], + + defaultTable: "Levels (N-1)", + + scoreBucket: "grade", + }, + "gitadora:Dora": { + idString: "gitadora:Dora", + + percentMax: 100, + + defaultScoreRatingAlg: "skill", + defaultSessionRatingAlg: "skill", + defaultProfileRatingAlg: "skill", + + difficulties: ["BASIC", "ADVANCED", "EXTREME", "MASTER"], + defaultDifficulty: "EXTREME", + difficultyColours: { + BASIC: COLOUR_SET.blue, + ADVANCED: COLOUR_SET.orange, + EXTREME: COLOUR_SET.red, + MASTER: COLOUR_SET.purple, + }, + + grades: ["C", "B", "A", "S", "SS", "MAX"], + gradeColours: { + C: COLOUR_SET.purple, + B: COLOUR_SET.blue, + A: COLOUR_SET.green, + S: COLOUR_SET.orange, + SS: COLOUR_SET.gold, + MAX: COLOUR_SET.white, + }, + clearGrade: "A", + gradeBoundaries: [0, 63, 73, 80, 95, 100], + + lamps: ["FAILED", "CLEAR", "FULL COMBO", "EXCELLENT"], + lampColours: { + FAILED: COLOUR_SET.red, + CLEAR: COLOUR_SET.blue, + "FULL COMBO": COLOUR_SET.teal, + EXCELLENT: COLOUR_SET.gold, + }, + clearLamp: "CLEAR", + + supportsESD: true, + judgementWindows: [ + { name: "PERFECT", msBorder: 27, value: 1 }, + { name: "GREAT", msBorder: 48, value: 0.5 }, + { name: "GOOD", msBorder: 72, value: 0.2 }, + { name: "OK", msBorder: 116.667 /* not really, but yknow */, value: 0 }, + ], + + defaultTable: "Levels (N-1)", + + scoreBucket: "grade", + }, }; /** * Returns the configuration for this game. */ export function GetGameConfig(game: G): GameConfig { - return GAME_CONFIGS[game] as GameConfig; + return GAME_CONFIGS[game] as GameConfig; } /** @@ -983,9 +983,9 @@ export function GetGameConfig(game: G): GameConfig { * to indicate what IDString this configuration is for. */ export function GetGamePTConfig( - game: Game, - playtype: Playtypes[Game] + game: Game, + playtype: Playtypes[Game] ): GamePTConfig { - const idString = `${game}:${playtype}` as IDStrings; - return (GAME_PT_CONFIGS[idString] as unknown) as GamePTConfig; + const idString = `${game}:${playtype}` as IDStrings; + return (GAME_PT_CONFIGS[idString] as unknown) as GamePTConfig; } diff --git a/common/src/config/static-config.ts b/common/src/config/static-config.ts index 039131005..dc0f8542d 100644 --- a/common/src/config/static-config.ts +++ b/common/src/config/static-config.ts @@ -1,89 +1,89 @@ import { FileUploadImportTypes, IRImportTypes, APIImportTypes, ImportTypes, Game } from ".."; export const fileImportTypes: FileUploadImportTypes[] = [ - "file/eamusement-iidx-csv", - "file/batch-manual", - "file/solid-state-squad", - "file/mer-iidx", - "file/pli-iidx-csv", + "file/eamusement-iidx-csv", + "file/batch-manual", + "file/solid-state-squad", + "file/mer-iidx", + "file/pli-iidx-csv", ]; export const irImportTypes: IRImportTypes[] = [ - "ir/direct-manual", - "ir/barbatos", - "ir/fervidex", - "ir/fervidex-static", - "ir/beatoraja", - "ir/chunitachi", - "ir/usc", + "ir/direct-manual", + "ir/barbatos", + "ir/fervidex", + "ir/fervidex-static", + "ir/beatoraja", + "ir/chunitachi", + "ir/usc", ]; export const apiImportTypes: APIImportTypes[] = [ - "api/arc-iidx", - "api/arc-sdvx", - "api/arc-ddr", - "api/eag-iidx", - "api/eag-sdvx", - "api/flo-iidx", - "api/flo-sdvx", + "api/arc-iidx", + "api/arc-sdvx", + "api/arc-ddr", + "api/eag-iidx", + "api/eag-sdvx", + "api/flo-iidx", + "api/flo-sdvx", ]; export const allImportTypes: ImportTypes[] = [ - ...fileImportTypes, - ...irImportTypes, - ...apiImportTypes, + ...fileImportTypes, + ...irImportTypes, + ...apiImportTypes, ]; export const allSupportedGames: Game[] = [ - "iidx", - "museca", - "maimai", - // "jubeat", - // "popn", - "sdvx", - "ddr", - "bms", - "chunithm", - "gitadora", - "usc", + "iidx", + "museca", + "maimai", + // "jubeat", + // "popn", + "sdvx", + "ddr", + "bms", + "chunithm", + "gitadora", + "usc", ]; export interface ServerConfig { - name: string; - supportedGames: Game[]; - supportedImportTypes: ImportTypes[]; + name: string; + supportedGames: Game[]; + supportedImportTypes: ImportTypes[]; } export const KTCHI_CONFIG: ServerConfig = { - name: "Kamaitachi", - supportedGames: ["iidx", "gitadora", "chunithm", "maimai", "museca", "sdvx"], - supportedImportTypes: [ - "api/arc-iidx", - "api/arc-sdvx", - "api/arc-ddr", - "api/eag-iidx", - "api/eag-sdvx", - "api/flo-iidx", - "api/flo-sdvx", - "ir/direct-manual", - "ir/fervidex", - "ir/fervidex-static", - "ir/chunitachi", - "file/eamusement-iidx-csv", - "file/solid-state-squad", - "file/mer-iidx", - "file/pli-iidx-csv", - ], + name: "Kamaitachi", + supportedGames: ["iidx", "gitadora", "chunithm", "maimai", "museca", "sdvx"], + supportedImportTypes: [ + "api/arc-iidx", + "api/arc-sdvx", + "api/arc-ddr", + "api/eag-iidx", + "api/eag-sdvx", + "api/flo-iidx", + "api/flo-sdvx", + "ir/direct-manual", + "ir/fervidex", + "ir/fervidex-static", + "ir/chunitachi", + "file/eamusement-iidx-csv", + "file/solid-state-squad", + "file/mer-iidx", + "file/pli-iidx-csv", + ], }; export const BTCHI_CONFIG: ServerConfig = { - name: "Bokutachi", - supportedGames: ["usc", "bms"], - supportedImportTypes: ["ir/beatoraja", "ir/usc", "ir/direct-manual", "file/batch-manual"], + name: "Bokutachi", + supportedGames: ["usc", "bms"], + supportedImportTypes: ["ir/beatoraja", "ir/usc", "ir/direct-manual", "file/batch-manual"], }; export const OMNI_CONFIG: ServerConfig = { - name: "Omnitachi", - supportedGames: allSupportedGames, - supportedImportTypes: allImportTypes, + name: "Omnitachi", + supportedGames: allSupportedGames, + supportedImportTypes: allImportTypes, }; diff --git a/common/src/game-classes.ts b/common/src/game-classes.ts index 2f3dfc908..051b0716b 100644 --- a/common/src/game-classes.ts +++ b/common/src/game-classes.ts @@ -4,191 +4,191 @@ import { IDStrings, integer } from "./types"; export interface ClassInfo { - display: string; - mouseover: string | null; + display: string; + mouseover: string | null; } function c(d: string, m: string) { - return { display: d, mouseover: m }; + return { display: d, mouseover: m }; } function n(d: string) { - return { display: d, mouseover: null }; + return { display: d, mouseover: null }; } export const IIDXDans: ClassInfo[] = [ - c("七級", "7th Kyu"), - c("六級", "6th Kyu"), - c("五級", "5th Kyu"), - c("四級", "4th Kyu"), - c("三級", "3rd Kyu"), - c("二級", "2nd Kyu"), - c("一級", "1st Kyu"), - c("初段", "1st Dan"), - c("二段", "2nd Dan"), - c("三段", "3rd Dan"), - c("四段", "4th Dan"), - c("五段", "5th Dan"), - c("六段", "6th Dan"), - c("七段", "7th Dan"), - c("八段", "8th Dan"), - c("九段", "9th Dan"), - c("十段", "10th Dan"), - c("中伝", "Chuuden"), - c("皆伝", "Kaiden"), + c("七級", "7th Kyu"), + c("六級", "6th Kyu"), + c("五級", "5th Kyu"), + c("四級", "4th Kyu"), + c("三級", "3rd Kyu"), + c("二級", "2nd Kyu"), + c("一級", "1st Kyu"), + c("初段", "1st Dan"), + c("二段", "2nd Dan"), + c("三段", "3rd Dan"), + c("四段", "4th Dan"), + c("五段", "5th Dan"), + c("六段", "6th Dan"), + c("七段", "7th Dan"), + c("八段", "8th Dan"), + c("九段", "9th Dan"), + c("十段", "10th Dan"), + c("中伝", "Chuuden"), + c("皆伝", "Kaiden"), ]; export const GitadoraColours: ClassInfo[] = [ - c("白", "White"), - c("橙", "Orange"), - c("橙グラ", "Orange Gradient"), - c("黄", "Yellow"), - c("黄グラ", "Yellow Gradient"), - c("緑", "Green"), - c("緑グラ", "Green Gradient"), - c("青", "Blue"), - c("青グラ", "Blue Gradient"), - c("紫", "Purple"), - c("紫グラ", "Purple Gradient"), - c("赤", "Red"), - c("赤グラ", "Red Gradient"), - c("銅", "Bronze"), - c("銀", "Silver"), - c("金", "Gold"), - c("虹", "Rainbow"), + c("白", "White"), + c("橙", "Orange"), + c("橙グラ", "Orange Gradient"), + c("黄", "Yellow"), + c("黄グラ", "Yellow Gradient"), + c("緑", "Green"), + c("緑グラ", "Green Gradient"), + c("青", "Blue"), + c("青グラ", "Blue Gradient"), + c("紫", "Purple"), + c("紫グラ", "Purple Gradient"), + c("赤", "Red"), + c("赤グラ", "Red Gradient"), + c("銅", "Bronze"), + c("銀", "Silver"), + c("金", "Gold"), + c("虹", "Rainbow"), ]; export const BMSGenocideDans: ClassInfo[] = [ - c("☆1", "Normal 1st Dan"), - c("☆2", "Normal 2nd Dan"), - c("☆3", "Normal 3rd Dan"), - c("☆4", "Normal 4th Dan"), - c("☆5", "Normal 5th Dan"), - c("☆6", "Normal 6th Dan"), - c("☆7", "Normal 7th Dan"), - c("☆8", "Normal 8th Dan"), - c("☆9", "Normal 9th Dan"), - c("☆10", "Normal 10th Dan"), - c("★1", "Insane 1st Dan"), - c("★2", "Insane 2nd Dan"), - c("★3", "Insane 3rd Dan"), - c("★4", "Insane 4th Dan"), - c("★5", "Insane 5th Dan"), - c("★6", "Insane 6th Dan"), - c("★7", "Insane 7th Dan"), - c("★8", "Insane 8th Dan"), - c("★9", "Insane 9th Dan"), - c("★10", "Insane 10th Dan"), - c("★★", "Insane Kaiden"), - c("(^^)", "Overjoy"), + c("☆1", "Normal 1st Dan"), + c("☆2", "Normal 2nd Dan"), + c("☆3", "Normal 3rd Dan"), + c("☆4", "Normal 4th Dan"), + c("☆5", "Normal 5th Dan"), + c("☆6", "Normal 6th Dan"), + c("☆7", "Normal 7th Dan"), + c("☆8", "Normal 8th Dan"), + c("☆9", "Normal 9th Dan"), + c("☆10", "Normal 10th Dan"), + c("★1", "Insane 1st Dan"), + c("★2", "Insane 2nd Dan"), + c("★3", "Insane 3rd Dan"), + c("★4", "Insane 4th Dan"), + c("★5", "Insane 5th Dan"), + c("★6", "Insane 6th Dan"), + c("★7", "Insane 7th Dan"), + c("★8", "Insane 8th Dan"), + c("★9", "Insane 9th Dan"), + c("★10", "Insane 10th Dan"), + c("★★", "Insane Kaiden"), + c("(^^)", "Overjoy"), ]; export const BMSStSlDans: ClassInfo[] = [ - c("sl0", "Satellite 0"), - c("sl1", "Satellite 1"), - c("sl2", "Satellite 2"), - c("sl3", "Satellite 3"), - c("sl4", "Satellite 4"), - c("sl5", "Satellite 5"), - c("sl6", "Satellite 6"), - c("sl7", "Satellite 7"), - c("sl8", "Satellite 8"), - c("sl9", "Satellite 9"), - c("sl10", "Satellite 10"), - c("sl11", "Satellite 11"), - c("sl12", "Satellite 12"), - c("st0", "Stella 0"), - c("st1", "Stella 1"), - c("st2", "Stella 2"), - c("st3", "Stella 3"), - c("st4", "Stella 4"), - c("st5", "Stella 5"), - c("st6", "Stella 6"), - c("st7", "Stella 7"), - c("st8", "Stella 8"), - c("st9", "Stella 9"), - c("st10", "Stella 10"), - c("st11", "Stella 11"), + c("sl0", "Satellite 0"), + c("sl1", "Satellite 1"), + c("sl2", "Satellite 2"), + c("sl3", "Satellite 3"), + c("sl4", "Satellite 4"), + c("sl5", "Satellite 5"), + c("sl6", "Satellite 6"), + c("sl7", "Satellite 7"), + c("sl8", "Satellite 8"), + c("sl9", "Satellite 9"), + c("sl10", "Satellite 10"), + c("sl11", "Satellite 11"), + c("sl12", "Satellite 12"), + c("st0", "Stella 0"), + c("st1", "Stella 1"), + c("st2", "Stella 2"), + c("st3", "Stella 3"), + c("st4", "Stella 4"), + c("st5", "Stella 5"), + c("st6", "Stella 6"), + c("st7", "Stella 7"), + c("st8", "Stella 8"), + c("st9", "Stella 9"), + c("st10", "Stella 10"), + c("st11", "Stella 11"), ]; export const SDVXDans: ClassInfo[] = [ - c("LV.01", "1st Dan"), - c("LV.02", "2nd Dan"), - c("LV.03", "3rd Dan"), - c("LV.04", "4th Dan"), - c("LV.05", "5th Dan"), - c("LV.06", "6th Dan"), - c("LV.07", "7th Dan"), - c("LV.08", "8th Dan"), - c("LV.09", "9th Dan"), - c("LV.10", "10th Dan"), - c("LV.11", "11th Dan"), - c("LV.INF", "Inf. Dan"), + c("LV.01", "1st Dan"), + c("LV.02", "2nd Dan"), + c("LV.03", "3rd Dan"), + c("LV.04", "4th Dan"), + c("LV.05", "5th Dan"), + c("LV.06", "6th Dan"), + c("LV.07", "7th Dan"), + c("LV.08", "8th Dan"), + c("LV.09", "9th Dan"), + c("LV.10", "10th Dan"), + c("LV.11", "11th Dan"), + c("LV.INF", "Inf. Dan"), ]; export const SDVXVFClasses: ClassInfo[] = [ - n("Sienna I"), - n("Sienna II"), - n("Sienna III"), - n("Sienna IV"), - n("Cobalt I"), - n("Cobalt II"), - n("Cobalt III"), - n("Cobalt IV"), - n("Dandelion I"), - n("Dandelion II"), - n("Dandelion III"), - n("Dandelion IV"), - n("Cyan I"), - n("Cyan II"), - n("Cyan III"), - n("Cyan IV"), - n("Scarlet I"), - n("Scarlet II"), - n("Scarlet III"), - n("Scarlet IV"), - n("Coral I"), - n("Coral II"), - n("Coral III"), - n("Coral IV"), - n("Argento I"), - n("Argento II"), - n("Argento III"), - n("Argento IV"), - n("Eldora I"), - n("Eldora II"), - n("Eldora III"), - n("Eldora IV"), - n("Crimson I"), - n("Crimson II"), - n("Crimson III"), - n("Crimson IV"), - n("Imperial I"), - n("Imperial II"), - n("Imperial III"), - n("Imperial IV"), + n("Sienna I"), + n("Sienna II"), + n("Sienna III"), + n("Sienna IV"), + n("Cobalt I"), + n("Cobalt II"), + n("Cobalt III"), + n("Cobalt IV"), + n("Dandelion I"), + n("Dandelion II"), + n("Dandelion III"), + n("Dandelion IV"), + n("Cyan I"), + n("Cyan II"), + n("Cyan III"), + n("Cyan IV"), + n("Scarlet I"), + n("Scarlet II"), + n("Scarlet III"), + n("Scarlet IV"), + n("Coral I"), + n("Coral II"), + n("Coral III"), + n("Coral IV"), + n("Argento I"), + n("Argento II"), + n("Argento III"), + n("Argento IV"), + n("Eldora I"), + n("Eldora II"), + n("Eldora III"), + n("Eldora IV"), + n("Crimson I"), + n("Crimson II"), + n("Crimson III"), + n("Crimson IV"), + n("Imperial I"), + n("Imperial II"), + n("Imperial III"), + n("Imperial IV"), ]; export interface GameClassSets { - "iidx:SP": "dan"; - "iidx:DP": "dan"; - "popn:9B": never; - "sdvx:Single": "dan" | "vfClass"; - "usc:Single": never; - "ddr:SP": "dan"; - "ddr:DP": "dan"; - "maimai:Single": never; - "jubeat:Single": "colour"; - "museca:Single": never; - "bms:7K": "genocideDan" | "stslDan"; - "bms:14K": "genocideDan"; - "chunithm:Single": never; - "gitadora:Gita": "colour"; - "gitadora:Dora": "colour"; + "iidx:SP": "dan"; + "iidx:DP": "dan"; + "popn:9B": never; + "sdvx:Single": "dan" | "vfClass"; + "usc:Single": never; + "ddr:SP": "dan"; + "ddr:DP": "dan"; + "maimai:Single": never; + "jubeat:Single": "colour"; + "museca:Single": never; + "bms:7K": "genocideDan" | "stslDan"; + "bms:14K": "genocideDan"; + "chunithm:Single": never; + "gitadora:Gita": "colour"; + "gitadora:Dora": "colour"; } export type AllClassSets = GameClassSets[IDStrings]; export type GameClasses = { - [K in GameClassSets[I]]: integer; + [K in GameClassSets[I]]: integer; }; diff --git a/common/src/index.test.ts b/common/src/index.test.ts new file mode 100644 index 000000000..562cdb4df --- /dev/null +++ b/common/src/index.test.ts @@ -0,0 +1,13 @@ +import t from "tap"; + +import * as tachiCommon from "./index"; + +// we just check that we're exporting stuff properly +t.test("Property Checks", (t) => { + t.type(tachiCommon.GetGameConfig, "function"); + t.type(tachiCommon.GetGamePTConfig, "function"); + t.type(tachiCommon.gameClasses, "object"); + t.type(tachiCommon.COLOUR_SET, "object"); + + t.end(); +}); diff --git a/common/src/legacy/legacy-config.ts b/common/src/legacy/legacy-config.ts index 8de9b4093..39c903b40 100644 --- a/common/src/legacy/legacy-config.ts +++ b/common/src/legacy/legacy-config.ts @@ -9,538 +9,538 @@ import { Game, Playtypes, ChartDocument, AnyChartDocument } from "../types"; // human readable stuff for versions const versionHuman: Record> = { - iidx: { - 0: "1st Style", - 1: "substream", - 2: "2nd Style", - 3: "3rd Style", - 4: "4th Style", - 5: "5th Style", - 6: "6th Style", - 7: "7th Style", - 8: "8th Style", - 9: "9th Style", - 10: "10th Style", - 11: "IIDX RED", - 12: "HAPPY SKY", - 13: "DISTORTED", - 14: "GOLD", - 15: "DJ TROOPERS", - 16: "EMPRESS", - 17: "SIRIUS", - 18: "Resort Anthem", - 19: "Lincle", - 20: "tricoro", - 21: "SPADA", - 22: "PENDUAL", - 23: "copula", - 24: "SINOBUZ", - 25: "CANNON BALLERS", - 26: "ROOTAGE", - 27: "HEROIC VERSE", - 28: "BISTROVER", - }, - museca: { - 1: "", - 1.5: "1+1/2", - }, - maimai: { - maimai: "", - maimaiplus: "PLUS", - green: "GReeN", - greenplus: "GReeN PLUS", - orange: "ORANGE", - orangeplus: "ORANGE PLUS", - pink: "PiNK", - pinkplus: "PiNK PLUS", - murasaki: "MURASAKi", - murasakiplus: "MURASAKi PLUS", - milk: "MiLK", - milkplus: "MiLK PLUS", - finale: "FiNALE", - }, - // jubeat: { - // jubeat: "", - // ripples: "ripples", - // knit: "knit", - // copious: "copious", - // saucer: "saucer", - // saucerfulfill: "saucer fulfill", - // prop: "prop", - // qubell: "Qubell", - // clan: "clan", - // festo: "festo", - // }, - // popn: { - // 1: "1", - // 2: "2", - // 3: "3", - // 4: "4", - // 5: "5", - // 6: "6", - // 7: "7", - // 8: "8", - // 9: "9", - // 10: "10", - // 11: "11", - // 12: "12 Iroha", - // 13: "13 CARNIVAL", - // 14: "14 FEVER!", - // 15: "15 ADVENTURE", - // 16: "16 PARTY♪", - // 17: "17 THE MOVIE", - // 18: "18 Sengoku", - // 19: "19 TUNE STREET", - // 20: "20 fantasia", - // park: "Sunny Park", - // lapis: "Lapistoria", - // eclale: "éclale", - // usaneko: "Usaneko", - // peace: "peace", - // }, - sdvx: { - booth: "BOOTH", - inf: "II -infinite infection-", - gw: "III GRAVITY WARS", - heaven: "IV HEAVENLY HAVEN", - vivid: "V VIVID WAVE", - }, - ddr: { - 1: "1st Mix", - 2: "2nd Mix", - 3: "3rd Mix", - 4: "4th Mix", - 5: "5th Mix", - max: "MAX", - max2: "MAX2", - extreme: "EXTREME", - snova: "SuperNOVA", - snova2: "SuperNOVA 2", - x: "X", - x2: "X2", - x3: "X3 vs. 2nd Mix", - 2013: "(2013)", - 2014: "(2014)", - a: "Ace", - a20: "A20", - }, - chunithm: { - chuni: "", - chuniplus: "PLUS", - air: "AIR", - airplus: "AIR PLUS", - star: "STAR", - starplus: "STAR PLUS", - amazon: "AMAZON", - amazonplus: "AMAZON PLUS", - crystal: "CRYSTAL", - crystalplus: "CRYSTAL PLUS", - }, - gitadora: { - xg: "XG", - xg2: "XG2", - xg3: "XG3", - gitadora: "", - overdrive: "OverDrive", - triboost: "Tri-Boost", - triboostplus: "Tri-Boost (Re:EVOLVE)", - matixx: "Matixx", - exchain: "EXCHAIN", - nextage: "NEX+AGE", - }, - bms: { - 0: "BMS", - }, - usc: { - 0: "USC", - }, + iidx: { + 0: "1st Style", + 1: "substream", + 2: "2nd Style", + 3: "3rd Style", + 4: "4th Style", + 5: "5th Style", + 6: "6th Style", + 7: "7th Style", + 8: "8th Style", + 9: "9th Style", + 10: "10th Style", + 11: "IIDX RED", + 12: "HAPPY SKY", + 13: "DISTORTED", + 14: "GOLD", + 15: "DJ TROOPERS", + 16: "EMPRESS", + 17: "SIRIUS", + 18: "Resort Anthem", + 19: "Lincle", + 20: "tricoro", + 21: "SPADA", + 22: "PENDUAL", + 23: "copula", + 24: "SINOBUZ", + 25: "CANNON BALLERS", + 26: "ROOTAGE", + 27: "HEROIC VERSE", + 28: "BISTROVER", + }, + museca: { + 1: "", + 1.5: "1+1/2", + }, + maimai: { + maimai: "", + maimaiplus: "PLUS", + green: "GReeN", + greenplus: "GReeN PLUS", + orange: "ORANGE", + orangeplus: "ORANGE PLUS", + pink: "PiNK", + pinkplus: "PiNK PLUS", + murasaki: "MURASAKi", + murasakiplus: "MURASAKi PLUS", + milk: "MiLK", + milkplus: "MiLK PLUS", + finale: "FiNALE", + }, + // jubeat: { + // jubeat: "", + // ripples: "ripples", + // knit: "knit", + // copious: "copious", + // saucer: "saucer", + // saucerfulfill: "saucer fulfill", + // prop: "prop", + // qubell: "Qubell", + // clan: "clan", + // festo: "festo", + // }, + // popn: { + // 1: "1", + // 2: "2", + // 3: "3", + // 4: "4", + // 5: "5", + // 6: "6", + // 7: "7", + // 8: "8", + // 9: "9", + // 10: "10", + // 11: "11", + // 12: "12 Iroha", + // 13: "13 CARNIVAL", + // 14: "14 FEVER!", + // 15: "15 ADVENTURE", + // 16: "16 PARTY♪", + // 17: "17 THE MOVIE", + // 18: "18 Sengoku", + // 19: "19 TUNE STREET", + // 20: "20 fantasia", + // park: "Sunny Park", + // lapis: "Lapistoria", + // eclale: "éclale", + // usaneko: "Usaneko", + // peace: "peace", + // }, + sdvx: { + booth: "BOOTH", + inf: "II -infinite infection-", + gw: "III GRAVITY WARS", + heaven: "IV HEAVENLY HAVEN", + vivid: "V VIVID WAVE", + }, + ddr: { + 1: "1st Mix", + 2: "2nd Mix", + 3: "3rd Mix", + 4: "4th Mix", + 5: "5th Mix", + max: "MAX", + max2: "MAX2", + extreme: "EXTREME", + snova: "SuperNOVA", + snova2: "SuperNOVA 2", + x: "X", + x2: "X2", + x3: "X3 vs. 2nd Mix", + 2013: "(2013)", + 2014: "(2014)", + a: "Ace", + a20: "A20", + }, + chunithm: { + chuni: "", + chuniplus: "PLUS", + air: "AIR", + airplus: "AIR PLUS", + star: "STAR", + starplus: "STAR PLUS", + amazon: "AMAZON", + amazonplus: "AMAZON PLUS", + crystal: "CRYSTAL", + crystalplus: "CRYSTAL PLUS", + }, + gitadora: { + xg: "XG", + xg2: "XG2", + xg3: "XG3", + gitadora: "", + overdrive: "OverDrive", + triboost: "Tri-Boost", + triboostplus: "Tri-Boost (Re:EVOLVE)", + matixx: "Matixx", + exchain: "EXCHAIN", + nextage: "NEX+AGE", + }, + bms: { + 0: "BMS", + }, + usc: { + 0: "USC", + }, }; // release orders of the games. const gameOrders = { - iidx: [ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - "17", - "18", - "19", - "20", - "21", - "22", - "23", - "24", - "25", - "26", - "27", - "28", - ], - museca: ["1", "1.5"], - maimai: [ - "maimai", - "maimaiplus", - "green", - "greenplus", - "orange", - "orangeplus", - "pink", - "pinkplus", - "murasaki", - "murasakiplus", - "milk", - "milkplus", - "finale", - ], - jubeat: [ - "jubeat", - "ripples", - "knit", - "copious", - "saucer", - "saucerfulfill", - "prop", - "qubell", - "clan", - "festo", - ], - popn: [ - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", - "16", - "17", - "18", - "19", - "20", - "park", - "lapis", - "eclale", - "usaneko", - "peace", - ], - sdvx: ["booth", "inf", "gw", "heaven", "vivid"], - ddr: [ - "1", - "2", - "3", - "4", - "5", - "max", - "max2", - "extreme", - "snova", - "snova2", - "x", - "x2", - "x3", - "2013", - "2014", - "a", - "a20", - ], - bms: ["0"], - chunithm: [ - "chuni", - "chuniplus", - "air", - "airplus", - "star", - "starplus", - "amazon", - "amazonplus", - "crystal", - "crystalplus", - ], - gitadora: [ - "gf1", - "gf2dm1", - "gf3dm2", - "gf4dm3", - "gf5dm4", - "gf6dm5", - "gf7dm6", - "gf8dm7", - "gf8dm7plus", - "gf9dm8", - "gf10dm9", - "gf11dm10", - "v", - "v2", - "v3", - "v4", - "v5", - "v6", - "v7", - "v8", - "xg", - "xg2", - "xg3", - "gitadora", - "overdrive", - "triboost", - "triboostplus", - "matixx", - "exchain", - "nextage", - ], - usc: ["0"], + iidx: [ + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + ], + museca: ["1", "1.5"], + maimai: [ + "maimai", + "maimaiplus", + "green", + "greenplus", + "orange", + "orangeplus", + "pink", + "pinkplus", + "murasaki", + "murasakiplus", + "milk", + "milkplus", + "finale", + ], + jubeat: [ + "jubeat", + "ripples", + "knit", + "copious", + "saucer", + "saucerfulfill", + "prop", + "qubell", + "clan", + "festo", + ], + popn: [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "park", + "lapis", + "eclale", + "usaneko", + "peace", + ], + sdvx: ["booth", "inf", "gw", "heaven", "vivid"], + ddr: [ + "1", + "2", + "3", + "4", + "5", + "max", + "max2", + "extreme", + "snova", + "snova2", + "x", + "x2", + "x3", + "2013", + "2014", + "a", + "a20", + ], + bms: ["0"], + chunithm: [ + "chuni", + "chuniplus", + "air", + "airplus", + "star", + "starplus", + "amazon", + "amazonplus", + "crystal", + "crystalplus", + ], + gitadora: [ + "gf1", + "gf2dm1", + "gf3dm2", + "gf4dm3", + "gf5dm4", + "gf6dm5", + "gf7dm6", + "gf8dm7", + "gf8dm7plus", + "gf9dm8", + "gf10dm9", + "gf11dm10", + "v", + "v2", + "v3", + "v4", + "v5", + "v6", + "v7", + "v8", + "xg", + "xg2", + "xg3", + "gitadora", + "overdrive", + "triboost", + "triboostplus", + "matixx", + "exchain", + "nextage", + ], + usc: ["0"], }; function humaniseGame(game: T, pt?: Playtypes[T]): string { - if (!pt) { - return gameHuman[game]; - } + if (!pt) { + return gameHuman[game]; + } - if (validPlaytypes[game].length === 1) { - return gameHuman[game]; - } + if (validPlaytypes[game].length === 1) { + return gameHuman[game]; + } - return `${gameHuman[game]} (${pt})`; + return `${gameHuman[game]} (${pt})`; } const ratingParameters = { - iidx: { - failHarshnessMultiplier: 0.3, - pivotPercent: 0.7777, // Grade: AA - clearExpMultiplier: 1, - }, - bms: { - failHarshnessMultiplier: 0.5, - pivotPercent: 0.7777, // Grade: AA - clearExpMultiplier: 0.75, - }, - museca: { - failHarshnessMultiplier: 1, - pivotPercent: 0.8, // grade: not fail - clearExpMultiplier: 1, // no real reason - }, - popn: { - failHarshnessMultiplier: 1, - pivotPercent: 0.8, // grade: A - clearExpMultiplier: 0.4, // no real reason - }, - maimai: { - failHarshnessMultiplier: 1, - pivotPercent: 0.8, - clearExpMultiplier: 1, - }, - jubeat: { - failHarshnessMultiplier: 0.9, - pivotPercent: 0.7, // grade: A (clear) - clearExpMultiplier: 1, - }, - sdvx: { - failHarshnessMultiplier: 1, - pivotPercent: 0.92, - clearExpMultiplier: 1.45, // testing - }, - usc: { - failHarshnessMultiplier: 1, - pivotPercent: 0.92, - clearExpMultiplier: 1.45, // testing - }, - ddr: { - failHarshnessMultiplier: 0.9, - pivotPercent: 0.9, - clearExpMultiplier: 1, - }, - chunithm: { - failHarshnessMultiplier: 1, - pivotPercent: 0.975, - clearExpMultiplier: 1.1, - }, - gitadora: { - // GENERIC PARAMS. THIS IS **NOT** THE USED CALC. - failHarshnessMultiplier: 1, - pivotPercent: 0.8, - clearExpMultiplier: 1.1, - }, + iidx: { + failHarshnessMultiplier: 0.3, + pivotPercent: 0.7777, // Grade: AA + clearExpMultiplier: 1, + }, + bms: { + failHarshnessMultiplier: 0.5, + pivotPercent: 0.7777, // Grade: AA + clearExpMultiplier: 0.75, + }, + museca: { + failHarshnessMultiplier: 1, + pivotPercent: 0.8, // grade: not fail + clearExpMultiplier: 1, // no real reason + }, + popn: { + failHarshnessMultiplier: 1, + pivotPercent: 0.8, // grade: A + clearExpMultiplier: 0.4, // no real reason + }, + maimai: { + failHarshnessMultiplier: 1, + pivotPercent: 0.8, + clearExpMultiplier: 1, + }, + jubeat: { + failHarshnessMultiplier: 0.9, + pivotPercent: 0.7, // grade: A (clear) + clearExpMultiplier: 1, + }, + sdvx: { + failHarshnessMultiplier: 1, + pivotPercent: 0.92, + clearExpMultiplier: 1.45, // testing + }, + usc: { + failHarshnessMultiplier: 1, + pivotPercent: 0.92, + clearExpMultiplier: 1.45, // testing + }, + ddr: { + failHarshnessMultiplier: 0.9, + pivotPercent: 0.9, + clearExpMultiplier: 1, + }, + chunithm: { + failHarshnessMultiplier: 1, + pivotPercent: 0.975, + clearExpMultiplier: 1.1, + }, + gitadora: { + // GENERIC PARAMS. THIS IS **NOT** THE USED CALC. + failHarshnessMultiplier: 1, + pivotPercent: 0.8, + clearExpMultiplier: 1.1, + }, }; function ChangeAlpha(string: string, alpha: string): string { - const spl = string.split(","); - spl[spl.length - 1] = `${alpha})`; - return spl.join(","); + const spl = string.split(","); + spl[spl.length - 1] = `${alpha})`; + return spl.join(","); } function DirectScoreGradeDelta( - game: Game, - score: number, - percent: number, - chart: AnyChartDocument, - delta: number + game: Game, + score: number, + percent: number, + chart: AnyChartDocument, + delta: number ): SGDReturn | null { - const grade = GetGrade(game, percent); + const grade = GetGrade(game, percent); - if (!grade) { - throw new Error(`Invalid grade created from ${game}, ${percent}`); - } + if (!grade) { + throw new Error(`Invalid grade created from ${game}, ${percent}`); + } - const scoreObj: PartialScore = { - scoreData: { - score, - grade, - }, - }; + const scoreObj: PartialScore = { + scoreData: { + score, + grade, + }, + }; - return ScoreGradeDelta(game, scoreObj, chart, delta); + return ScoreGradeDelta(game, scoreObj, chart, delta); } interface SGDReturn { - grade: string; - delta: number; - formattedString: string; + grade: string; + delta: number; + formattedString: string; } interface PartialScore { - scoreData: { - score: number; - grade: string; - }; + scoreData: { + score: number; + grade: string; + }; } function ScoreGradeDelta( - game: Game, - score: PartialScore, - chart: AnyChartDocument, - delta: number + game: Game, + score: PartialScore, + chart: AnyChartDocument, + delta: number ): SGDReturn | null { - const nextGrade = grades[game][grades[game].indexOf(score.scoreData.grade) + delta]; + const nextGrade = grades[game][grades[game].indexOf(score.scoreData.grade) + delta]; - if (nextGrade) { - const nextGradePercent = gradeBoundaries[game][grades[game].indexOf(nextGrade)]; + if (nextGrade) { + const nextGradePercent = gradeBoundaries[game][grades[game].indexOf(nextGrade)]; - const nGScore = CalculateScore(game, nextGradePercent, chart); + const nGScore = CalculateScore(game, nextGradePercent, chart); - if (nGScore) { - const delta = score.scoreData.score - nGScore; - let formattedString = `(${nextGrade})`; + if (nGScore) { + const delta = score.scoreData.score - nGScore; + let formattedString = `(${nextGrade})`; - if (Number.isInteger(delta)) { - formattedString += delta >= 0 ? `+${delta}` : `${delta}`; - } else { - formattedString += delta >= 0 ? `+${delta.toFixed(2)}` : `${delta.toFixed(2)}`; - } + if (Number.isInteger(delta)) { + formattedString += delta >= 0 ? `+${delta}` : `${delta}`; + } else { + formattedString += delta >= 0 ? `+${delta.toFixed(2)}` : `${delta.toFixed(2)}`; + } - return { - grade: nextGrade, - delta: delta, - formattedString: formattedString, - }; - } else { - return null; - } - } else { - return null; - } + return { + grade: nextGrade, + delta: delta, + formattedString: formattedString, + }; + } else { + return null; + } + } else { + return null; + } } function AbsoluteScoreGradeDelta( - game: Game, - score: number, - percent: number, - absDelta: number + game: Game, + score: number, + percent: number, + absDelta: number ): SGDReturn | null { - const grade = grades[game][absDelta]; - if (grade) { - let chart = null; - if (game === "iidx" || game === "bms") { - const reversedNC = Math.floor((score / percent) * 100) / 2; - chart = { - data: { - notecount: reversedNC, - }, - } as unknown; // heheh - } + const grade = grades[game][absDelta]; + if (grade) { + let chart = null; + if (game === "iidx" || game === "bms") { + const reversedNC = Math.floor((score / percent) * 100) / 2; + chart = { + data: { + notecount: reversedNC, + }, + } as unknown; // heheh + } - const sc = CalculateScore(game, gradeBoundaries[game][absDelta], chart as AnyChartDocument); - if (sc) { - const delta = score - sc; - let formattedString = `(${grade})`; - formattedString += delta >= 0 ? `+${delta}` : `${delta}`; - return { - grade: grade, - delta: delta, - formattedString: formattedString, - }; - } else { - return null; - } - } else { - return null; - } + const sc = CalculateScore(game, gradeBoundaries[game][absDelta], chart as AnyChartDocument); + if (sc) { + const delta = score - sc; + let formattedString = `(${grade})`; + formattedString += delta >= 0 ? `+${delta}` : `${delta}`; + return { + grade: grade, + delta: delta, + formattedString: formattedString, + }; + } else { + return null; + } + } else { + return null; + } } function CalculateScore(game: Game, percent: number, chart: AnyChartDocument): number | null { - let score = percent; + let score = percent; - if (game === "iidx" || game === "bms") { - score = (chart as ChartDocument<"iidx:SP">).data.notecount * 2 * (percent / 100); - } else if (game === "ddr" || game === "museca" || game === "jubeat" || game === "chunithm") { - score = 1_000_000 * (percent / 100); - } else if (game === "popn") { - score = 100_000 * (percent / 100); - } else if (game === "sdvx" || game === "usc") { - score = 10_000_000 * (percent / 100); - } + if (game === "iidx" || game === "bms") { + score = (chart as ChartDocument<"iidx:SP">).data.notecount * 2 * (percent / 100); + } else if (game === "ddr" || game === "museca" || game === "jubeat" || game === "chunithm") { + score = 1_000_000 * (percent / 100); + } else if (game === "popn") { + score = 100_000 * (percent / 100); + } else if (game === "sdvx" || game === "usc") { + score = 10_000_000 * (percent / 100); + } - if (score) { - return score; - } - return null; + if (score) { + return score; + } + return null; } function PercentToScore(percent: number, game: Game, chartData: AnyChartDocument): number { - let eScore = 0; + let eScore = 0; - if (game === "iidx" || game === "bms") { - eScore = percent * (chartData as ChartDocument<"iidx:SP">).data.notecount * 2; - } else if (game === "museca" || game === "jubeat") { - eScore = percent * 1000000; - } else if (game === "popn") { - eScore = percent * 100000; - } else if (game === "sdvx" || game === "usc") { - eScore = percent * 10000000; - } else if (game === "ddr") { - // todo - } else if (game === "chunithm") { - eScore = percent * 1000000; - } else if (game === "gitadora") { - eScore = percent; - } + if (game === "iidx" || game === "bms") { + eScore = percent * (chartData as ChartDocument<"iidx:SP">).data.notecount * 2; + } else if (game === "museca" || game === "jubeat") { + eScore = percent * 1000000; + } else if (game === "popn") { + eScore = percent * 100000; + } else if (game === "sdvx" || game === "usc") { + eScore = percent * 10000000; + } else if (game === "ddr") { + // todo + } else if (game === "chunithm") { + eScore = percent * 1000000; + } else if (game === "gitadora") { + eScore = percent; + } - return eScore; + return eScore; } function FormatDifficulty(chart: AnyChartDocument, game: Game): string { - if (validPlaytypes[game].length > 1) { - return `${chart.playtype} ${chart.difficulty} ${chart.level}`; - } - return `${chart.difficulty}`; + if (validPlaytypes[game].length > 1) { + return `${chart.playtype} ${chart.difficulty} ${chart.level}`; + } + return `${chart.difficulty}`; } diff --git a/common/src/lib/esd.test.ts b/common/src/lib/esd.test.ts new file mode 100644 index 000000000..4dfc0f8be --- /dev/null +++ b/common/src/lib/esd.test.ts @@ -0,0 +1,36 @@ +import t from "tap"; +import { GetGamePTConfig } from "../config/config"; +import { CalculateESD, ESDCompare, PercentCompare } from "./esd"; + +function approx(t: Tap.Test, given: number, recieved: number, acc = 0.01) { + if (Math.abs(given - recieved) < acc) { + return t.pass(); + } else { + return t.fail(`Expected ${given} to be within ${acc} of ${recieved}.`); + } +} + +t.test("#CalculateESD", (t) => { + const jdg = GetGamePTConfig("iidx", "SP").judgementWindows!; + approx(t, CalculateESD(jdg, 0.8), 17.58); + approx(t, CalculateESD(jdg, 0), 200); + t.throws(() => CalculateESD(jdg, 0, true)); + + t.end(); +}); + +t.test("#ESDCompare", (t) => { + approx(t, ESDCompare(16, 14), 6.42); + approx(t, ESDCompare(16, 14, 1), ESDCompare(16, 14)); + approx(t, ESDCompare(0, 200, 1), -68.27); + + t.end(); +}); + +t.test("#PercentCompare", (t) => { + const jdg = GetGamePTConfig("iidx", "SP").judgementWindows!; + approx(t, PercentCompare(jdg, 0.99, 0.98), -5.53); + approx(t, PercentCompare(jdg, 0.99, 0.98), PercentCompare(jdg, 0.99, 0.98, 1)); + + t.end(); +}); diff --git a/common/src/lib/esd.ts b/common/src/lib/esd.ts index 0f556971f..3db5476aa 100644 --- a/common/src/lib/esd.ts +++ b/common/src/lib/esd.ts @@ -3,7 +3,7 @@ * https://en.wikipedia.org/wiki/Cumulative_distribution_function */ function cdf(x: number, mean: number, variance: number) { - return 0.5 * (1 + erf((x - mean) / Math.sqrt(2 * variance))); + return 0.5 * (1 + erf((x - mean) / Math.sqrt(2 * variance))); } /** @@ -11,27 +11,27 @@ function cdf(x: number, mean: number, variance: number) { * https://en.wikipedia.org/wiki/Error_function */ function erf(x: number) { - // save the sign of x - const sign = x >= 0 ? 1 : -1; - x = Math.abs(x); + // save the sign of x + const sign = x >= 0 ? 1 : -1; + x = Math.abs(x); - // constants - const a1 = 0.254829592; - const a2 = -0.284496736; - const a3 = 1.421413741; - const a4 = -1.453152027; - const a5 = 1.061405429; - const p = 0.3275911; + // constants + const a1 = 0.254829592; + const a2 = -0.284496736; + const a3 = 1.421413741; + const a4 = -1.453152027; + const a5 = 1.061405429; + const p = 0.3275911; - // A&S formula 7.1.26 - const t = 1.0 / (1.0 + p * x); - const y = 1.0 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-x * x); - return sign * y; // erf(-x) = -erf(x); + // A&S formula 7.1.26 + const t = 1.0 / (1.0 + p * x); + const y = 1.0 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-x * x); + return sign * y; // erf(-x) = -erf(x); } function CDFBetween(lowBound: number, highBound: number, mean: number, variance: number) { - // Since the normal distribution is symmetrical, we want to double this, as the cut will only get one tail. - return 2 * (cdf(highBound, mean, variance) - cdf(lowBound, mean, variance)); + // Since the normal distribution is symmetrical, we want to double this, as the cut will only get one tail. + return 2 * (cdf(highBound, mean, variance) - cdf(lowBound, mean, variance)); } // This is a direct port of ESD-JS to typescript. Maybe this should be released as its own module some day. @@ -46,32 +46,32 @@ const MEAN = 0; * @returns The percent this std. deviation would produce. */ function StdDeviationToPercent( - judgements: ESDJudgementFormat[], - stddev: number, - largestValue: number + judgements: ESDJudgementFormat[], + stddev: number, + largestValue: number ) { - let lastJudgeMSBorder = 0; - let prbSum = 0; + let lastJudgeMSBorder = 0; + let prbSum = 0; - for (let i = 0; i < judgements.length; i++) { - const judge = judgements[i]; - const nVal = CDFBetween(lastJudgeMSBorder, judge.msBorder, MEAN, stddev ** 2) * judge.value; - lastJudgeMSBorder = judge.msBorder; - prbSum += nVal; - } + for (let i = 0; i < judgements.length; i++) { + const judge = judgements[i]; + const nVal = CDFBetween(lastJudgeMSBorder, judge.msBorder, MEAN, stddev ** 2) * judge.value; + lastJudgeMSBorder = judge.msBorder; + prbSum += nVal; + } - prbSum /= largestValue; + prbSum /= largestValue; - return prbSum; + return prbSum; } const ACCEPTABLE_ERROR = 0.001; const MAX_ITERATIONS = 50; export interface ESDJudgementFormat { - name: string; - msBorder: number; - value: number; + name: string; + msBorder: number; + value: number; } /** @@ -83,58 +83,55 @@ export interface ESDJudgementFormat { * @returns */ export function CalculateESD( - judgements: ESDJudgementFormat[], - percent: number, - errOnInaccuracy = false + judgements: ESDJudgementFormat[], + percent: number, + errOnInaccuracy = false ): number { - if (percent > 1 || percent < 0 || Number.isNaN(percent)) { - throw new Error( - "(ESD) Invalid percent. Percent must be between 0 and 1, and also a number." - ); - } - const largestValue = judgements.slice(0).sort((a, b) => b.value - a.value)[0].value; + if (percent > 1 || percent < 0 || Number.isNaN(percent)) { + throw new Error( + "(ESD) Invalid percent. Percent must be between 0 and 1, and also a number." + ); + } + const largestValue = judgements.slice(0).sort((a, b) => b.value - a.value)[0].value; - // massive optimisation possible here by using better initial estimates with precalc'd table of values. - // until then, it's just kinda slow. - let minSD = 0; - let maxSD = 200; - let estSD = (minSD + maxSD) / 2; + // massive optimisation possible here by using better initial estimates with precalc'd table of values. + // until then, it's just kinda slow. + let minSD = 0; + let maxSD = 200; + let estSD = (minSD + maxSD) / 2; - // So, fundamentally the function that takes SD and returns estimated percent is NOT invertible. - // as in, it is very literally not invertible. - // if you figure it out, let me know. - // until then; we make MAX_ITERATIONS attempts at finding a value within the acceptable range of error. - // the defaults for these are 100 for iterations, and 0.001 for error. - // for most of what i've tested, this has been fine. - for (let i = 0; i < MAX_ITERATIONS; i++) { - const estimatedPercent = StdDeviationToPercent(judgements, estSD, largestValue); + // So, fundamentally the function that takes SD and returns estimated percent is NOT invertible. + // as in, it is very literally not invertible. + // if you figure it out, let me know. + // until then; we make MAX_ITERATIONS attempts at finding a value within the acceptable range of error. + // the defaults for these are 100 for iterations, and 0.001 for error. + // for most of what i've tested, this has been fine. + for (let i = 0; i < MAX_ITERATIONS; i++) { + const estimatedPercent = StdDeviationToPercent(judgements, estSD, largestValue); - if (Math.abs(estimatedPercent - percent) < ACCEPTABLE_ERROR) { - return estSD; - } + if (Math.abs(estimatedPercent - percent) < ACCEPTABLE_ERROR) { + return estSD; + } - if (estimatedPercent < percent) { - maxSD = estSD; - } else { - minSD = estSD; - } + if (estimatedPercent < percent) { + maxSD = estSD; + } else { + minSD = estSD; + } - if (estSD === (minSD + maxSD) / 2) { - // if it isn't moving, just terminate - break; - } + if (estSD === (minSD + maxSD) / 2) { + // if it isn't moving, just terminate + break; + } - estSD = (minSD + maxSD) / 2; - } + estSD = (minSD + maxSD) / 2; + } - if (errOnInaccuracy) { - throw `(ESD-JS) Did not reach value within MAX_ITERATIONS (${MAX_ITERATIONS})`; - } else { - console.warn( - `(ESD-JS) Did not reach value within MAX_ITERATIONS (${MAX_ITERATIONS}), returning last estimate (${estSD}), which was generated from ${percent}.` - ); - return estSD; - } + if (errOnInaccuracy) { + throw `(ESD-JS) Did not reach value within MAX_ITERATIONS (${MAX_ITERATIONS})`; + } + + return estSD; } /** @@ -145,42 +142,42 @@ export function CalculateESD( * @returns A number between -100 and 100. */ export function ESDCompare(baseESD: number, compareESD: number, cdeg = 1): number { - const CONFIDENCE_DEGREE = cdeg; - const BASE_CASE = CDFBetween(-1 * CONFIDENCE_DEGREE, CONFIDENCE_DEGREE, 0, 1) / 2; + const CONFIDENCE_DEGREE = cdeg; + const BASE_CASE = CDFBetween(-1 * CONFIDENCE_DEGREE, CONFIDENCE_DEGREE, 0, 1) / 2; - let inv = false; - let variance; - let bound; - if (compareESD > baseESD) { - inv = true; - variance = compareESD ** 2; - bound = CONFIDENCE_DEGREE * baseESD; - } else { - variance = baseESD ** 2; - bound = CONFIDENCE_DEGREE * compareESD; - } + let inv = false; + let variance; + let bound; + if (compareESD > baseESD) { + inv = true; + variance = compareESD ** 2; + bound = CONFIDENCE_DEGREE * baseESD; + } else { + variance = baseESD ** 2; + bound = CONFIDENCE_DEGREE * compareESD; + } - const esdc = CDFBetween(-1 * bound, bound, 0, variance) / 2; + const esdc = CDFBetween(-1 * bound, bound, 0, variance) / 2; - let besdc = BASE_CASE - esdc; + let besdc = BASE_CASE - esdc; - if (inv) { - besdc *= -1; - } + if (inv) { + besdc *= -1; + } - return besdc * 100; + return besdc * 100; } /** * Converts two percents to ESD, then runs ESDCompare. */ export function PercentCompare( - judgements: ESDJudgementFormat[], - baseP: number, - compareP: number, - cdeg = 1 + judgements: ESDJudgementFormat[], + baseP: number, + compareP: number, + cdeg = 1 ): number { - const e1 = CalculateESD(judgements, baseP); - const e2 = CalculateESD(judgements, compareP); - return ESDCompare(e1, e2, cdeg); + const e1 = CalculateESD(judgements, baseP); + const e2 = CalculateESD(judgements, compareP); + return ESDCompare(e1, e2, cdeg); } diff --git a/common/src/lib/util.test.ts b/common/src/lib/util.test.ts index 3f1038bb0..d36c2383d 100644 --- a/common/src/lib/util.test.ts +++ b/common/src/lib/util.test.ts @@ -2,9 +2,9 @@ import t from "tap"; import { CalculateGradeDeltaIIDX } from "./util"; t.test("#CalculateGradeDeltaIIDX", (t) => { - t.equal(CalculateGradeDeltaIIDX("A", 1000, 2000), "A-334"); - t.equal(CalculateGradeDeltaIIDX("AAA", 1778, 2000), "AAA+0"); - t.equal(CalculateGradeDeltaIIDX("MAX", 1900, 2000), "MAX-100"); + t.equal(CalculateGradeDeltaIIDX("A", 1000, 2000), "A-334"); + t.equal(CalculateGradeDeltaIIDX("AAA", 1778, 2000), "AAA+0"); + t.equal(CalculateGradeDeltaIIDX("MAX", 1900, 2000), "MAX-100"); - t.end(); + t.end(); }); diff --git a/common/src/lib/util.ts b/common/src/lib/util.ts index 9647a4793..585243ac8 100644 --- a/common/src/lib/util.ts +++ b/common/src/lib/util.ts @@ -4,22 +4,22 @@ import { Grades, integer } from "../types"; const IIDXConfig = GetGamePTConfig("iidx", "SP"); export function CalculateGradeDeltaIIDX( - cmpGrade: Grades["iidx:SP" | "iidx:DP"], - score: integer, - notecount: integer + cmpGrade: Grades["iidx:SP" | "iidx:DP"], + score: integer, + notecount: integer ): string { - const cmpGradeIDX = IIDXConfig.grades.indexOf(cmpGrade); + const cmpGradeIDX = IIDXConfig.grades.indexOf(cmpGrade); - const cmpGradePercent = IIDXConfig.gradeBoundaries[cmpGradeIDX]; + const cmpGradePercent = IIDXConfig.gradeBoundaries[cmpGradeIDX]; - const cmpScore = Math.ceil(notecount * (cmpGradePercent / 100)); + const cmpScore = Math.ceil(notecount * (cmpGradePercent / 100)); - const delta = score - cmpScore; + const delta = score - cmpScore; - if (delta >= 0) { - return `${cmpGrade}+${delta}`; - } else { - // negative numbers implicitly stringify with the - prefix - return `${cmpGrade}${delta}`; - } + if (delta >= 0) { + return `${cmpGrade}+${delta}`; + } else { + // negative numbers implicitly stringify with the - prefix + return `${cmpGrade}${delta}`; + } } diff --git a/common/src/types.ts b/common/src/types.ts index e8d956dc9..5f0427507 100644 --- a/common/src/types.ts +++ b/common/src/types.ts @@ -3,8 +3,8 @@ import { FilterQuery } from "mongodb"; import { AllClassSets, GameClasses, GameClassSets } from "./game-classes"; export interface CounterDocument { - counterName: string; - value: integer; + counterName: string; + value: integer; } /** @@ -14,70 +14,70 @@ export interface CounterDocument { * like the ScoreDocument (Especially the ScoreDocument) *very* hard! */ export type IDStrings = - | "iidx:SP" - | "iidx:DP" - // | "popn:9B" - | "sdvx:Single" - | "usc:Single" - | "ddr:SP" - | "ddr:DP" - | "maimai:Single" - | "museca:Single" - // | "jubeat:Single" - | "bms:7K" - | "bms:14K" - | "chunithm:Single" - | "gitadora:Gita" - | "gitadora:Dora"; + | "iidx:SP" + | "iidx:DP" + // | "popn:9B" + | "sdvx:Single" + | "usc:Single" + | "ddr:SP" + | "ddr:DP" + | "maimai:Single" + | "museca:Single" + // | "jubeat:Single" + | "bms:7K" + | "bms:14K" + | "chunithm:Single" + | "gitadora:Gita" + | "gitadora:Dora"; export interface IDStringToPlaytype { - "iidx:SP": "SP"; - "iidx:DP": "DP"; - "popn:9B": "9B"; - "sdvx:Single": "Single"; - "usc:Single": "Single"; - "ddr:SP": "SP"; - "ddr:DP": "DP"; - "maimai:Single": "Single"; - "jubeat:Single": "Single"; - "museca:Single": "Single"; - "bms:7K": "7K"; - "bms:14K": "14K"; - "chunithm:Single": "Single"; - "gitadora:Gita": "Gita"; - "gitadora:Dora": "Dora"; + "iidx:SP": "SP"; + "iidx:DP": "DP"; + "popn:9B": "9B"; + "sdvx:Single": "Single"; + "usc:Single": "Single"; + "ddr:SP": "SP"; + "ddr:DP": "DP"; + "maimai:Single": "Single"; + "jubeat:Single": "Single"; + "museca:Single": "Single"; + "bms:7K": "7K"; + "bms:14K": "14K"; + "chunithm:Single": "Single"; + "gitadora:Gita": "Gita"; + "gitadora:Dora": "Dora"; } export interface IDStringToGame { - "iidx:SP": "iidx"; - "iidx:DP": "iidx"; - "popn:9B": "popn"; - "sdvx:Single": "sdvx"; - "usc:Single": "usc"; - "ddr:SP": "ddr"; - "ddr:DP": "ddr"; - "maimai:Single": "maimai"; - "jubeat:Single": "jubeat"; - "museca:Single": "museca"; - "bms:7K": "bms"; - "bms:14K": "bms"; - "chunithm:Single": "chunithm"; - "gitadora:Gita": "gitadora"; - "gitadora:Dora": "gitadora"; + "iidx:SP": "iidx"; + "iidx:DP": "iidx"; + "popn:9B": "popn"; + "sdvx:Single": "sdvx"; + "usc:Single": "usc"; + "ddr:SP": "ddr"; + "ddr:DP": "ddr"; + "maimai:Single": "maimai"; + "jubeat:Single": "jubeat"; + "museca:Single": "museca"; + "bms:7K": "bms"; + "bms:14K": "bms"; + "chunithm:Single": "chunithm"; + "gitadora:Gita": "gitadora"; + "gitadora:Dora": "gitadora"; } export interface GameToIDStrings { - iidx: "iidx:SP" | "iidx:DP"; - sdvx: "sdvx:Single"; - usc: "usc:Single"; - ddr: "ddr:SP" | "ddr:DP"; - maimai: "maimai:Single"; - jubeat: "jubeat:Single"; - museca: "museca:Single"; - bms: "bms:7K" | "bms:14K"; - chunithm: "chunithm:Single"; - gitadora: "gitadora:Gita" | "gitadora:Dora"; - popn: "popn:9B"; + iidx: "iidx:SP" | "iidx:DP"; + sdvx: "sdvx:Single"; + usc: "usc:Single"; + ddr: "ddr:SP" | "ddr:DP"; + maimai: "maimai:Single"; + jubeat: "jubeat:Single"; + museca: "museca:Single"; + bms: "bms:7K" | "bms:14K"; + chunithm: "chunithm:Single"; + gitadora: "gitadora:Gita" | "gitadora:Dora"; + popn: "popn:9B"; } /** @@ -92,33 +92,33 @@ export interface GameToIDStrings { * All MongoDB Documents require this field, or atleast they all have them in ktchi's DB. */ export interface MongoDBDocument { - _id?: IObjectID; + _id?: IObjectID; } export type Databases = - | "sessions" - | "session-views" - | "folders" - | "folder-chart-lookup" - | "scores" - | "personal-bests" - | "notifications" - | "imports" - | "import-timings" - | "tierlist-data" - | "tierlists" - | "goals" - | "user-goals" - | "user-milestones" - | "milestones" - | "game-stats" - | "users" - | "kai-auth-tokens" - | "usc-auth-tokens" - | "beatoraja-auth-tokens" - | "bms-course-lookup" - | "api-tokens" - | "import-locks"; + | "sessions" + | "session-views" + | "folders" + | "folder-chart-lookup" + | "scores" + | "personal-bests" + | "notifications" + | "imports" + | "import-timings" + | "tierlist-data" + | "tierlists" + | "goals" + | "user-goals" + | "user-milestones" + | "milestones" + | "game-stats" + | "users" + | "kai-auth-tokens" + | "usc-auth-tokens" + | "beatoraja-auth-tokens" + | "bms-course-lookup" + | "api-tokens" + | "import-locks"; export type ValidDatabases = Databases | `songs-${Game}` | `charts-${Game}`; @@ -126,24 +126,24 @@ export type ValidDatabases = Databases | `songs-${Game}` | `charts-${Game}`; * Supported games by Kamaitachi. */ export type Game = - | "iidx" - | "museca" - | "maimai" - // | "jubeat" - // | "popn" - | "sdvx" - | "ddr" - | "bms" - | "chunithm" - | "gitadora" - | "usc"; + | "iidx" + | "museca" + | "maimai" + // | "jubeat" + // | "popn" + | "sdvx" + | "ddr" + | "bms" + | "chunithm" + | "gitadora" + | "usc"; /** * This is the generic response from the Kamaitachi API in event of a failure. */ export interface UnsuccessfulAPIResponse { - success: false; - description: string; + success: false; + description: string; } /** @@ -151,215 +151,215 @@ export interface UnsuccessfulAPIResponse { * endpoint-defined information about the response, such as database data. */ export interface SuccessfulAPIResponse { - success: true; - description: string; - // This isn't ideal, but we need to restrict - // this to only objects - Record - // mandates indexability of the type, which makes - // it unusable for known objects. - // eslint-disable-next-line @typescript-eslint/ban-types - body: T; + success: true; + description: string; + // This isn't ideal, but we need to restrict + // this to only objects - Record + // mandates indexability of the type, which makes + // it unusable for known objects. + // eslint-disable-next-line @typescript-eslint/ban-types + body: T; } export interface ChartFolderLookupDocument extends MongoDBDocument { - chartID: string; - folderID: string; + chartID: string; + folderID: string; } export interface Playtypes { - iidx: "SP" | "DP"; - popn: "9B"; - sdvx: "Single"; - usc: "Single"; - ddr: "SP" | "DP"; - maimai: "Single"; - jubeat: "Single"; - museca: "Single"; - chunithm: "Single"; - bms: "7K" | "14K"; - gitadora: "Gita" | "Dora"; + iidx: "SP" | "DP"; + popn: "9B"; + sdvx: "Single"; + usc: "Single"; + ddr: "SP" | "DP"; + maimai: "Single"; + jubeat: "Single"; + museca: "Single"; + chunithm: "Single"; + bms: "7K" | "14K"; + gitadora: "Gita" | "Dora"; } type IIDXGrades = "F" | "E" | "D" | "C" | "B" | "A" | "AA" | "AAA" | "MAX-" | "MAX"; type SDVXGrades = "D" | "C" | "B" | "A" | "A+" | "AA" | "AA+" | "AAA" | "AAA+" | "S"; type DDRGrades = - | "D" - | "D+" - | "C-" - | "C" - | "C+" - | "B-" - | "B" - | "B+" - | "A-" - | "A" - | "A+" - | "AA-" - | "AA" - | "AA+" - | "AAA"; + | "D" + | "D+" + | "C-" + | "C" + | "C+" + | "B-" + | "B" + | "B+" + | "A-" + | "A" + | "A+" + | "AA-" + | "AA" + | "AA+" + | "AAA"; type GitadoraGrades = "C" | "B" | "A" | "S" | "SS" | "MAX"; export interface Grades { - "iidx:SP": IIDXGrades; - "iidx:DP": IIDXGrades; - "popn:9B": "E" | "D" | "C" | "B" | "A" | "AA" | "AAA" | "S"; - "sdvx:Single": SDVXGrades; - "usc:Single": SDVXGrades; - "ddr:SP": DDRGrades; - "ddr:DP": DDRGrades; - "maimai:Single": - | "F" - | "E" - | "D" - | "C" - | "B" - | "A" - | "AA" - | "AAA" - | "S" - | "S+" - | "SS" - | "SS+" - | "SSS" - | "SSS+"; - "jubeat:Single": "E" | "D" | "C" | "B" | "A" | "S" | "SS" | "SSS" | "EXC"; - "museca:Single": "没" | "拙" | "凡" | "佳" | "良" | "優" | "秀" | "傑" | "傑G"; - "bms:7K": IIDXGrades; - "bms:14K": IIDXGrades; - "chunithm:Single": "D" | "C" | "B" | "BB" | "BBB" | "A" | "AA" | "AAA" | "S" | "SS" | "SSS"; - "gitadora:Gita": GitadoraGrades; - "gitadora:Dora": GitadoraGrades; + "iidx:SP": IIDXGrades; + "iidx:DP": IIDXGrades; + "popn:9B": "E" | "D" | "C" | "B" | "A" | "AA" | "AAA" | "S"; + "sdvx:Single": SDVXGrades; + "usc:Single": SDVXGrades; + "ddr:SP": DDRGrades; + "ddr:DP": DDRGrades; + "maimai:Single": + | "F" + | "E" + | "D" + | "C" + | "B" + | "A" + | "AA" + | "AAA" + | "S" + | "S+" + | "SS" + | "SS+" + | "SSS" + | "SSS+"; + "jubeat:Single": "E" | "D" | "C" | "B" | "A" | "S" | "SS" | "SSS" | "EXC"; + "museca:Single": "没" | "拙" | "凡" | "佳" | "良" | "優" | "秀" | "傑" | "傑G"; + "bms:7K": IIDXGrades; + "bms:14K": IIDXGrades; + "chunithm:Single": "D" | "C" | "B" | "BB" | "BBB" | "A" | "AA" | "AAA" | "S" | "SS" | "SSS"; + "gitadora:Gita": GitadoraGrades; + "gitadora:Dora": GitadoraGrades; } type IIDXLamps = - | "NO PLAY" - | "FAILED" - | "ASSIST CLEAR" - | "EASY CLEAR" - | "CLEAR" - | "HARD CLEAR" - | "EX HARD CLEAR" - | "FULL COMBO"; + | "NO PLAY" + | "FAILED" + | "ASSIST CLEAR" + | "EASY CLEAR" + | "CLEAR" + | "HARD CLEAR" + | "EX HARD CLEAR" + | "FULL COMBO"; type GitadoraLamps = "FAILED" | "CLEAR" | "FULL COMBO" | "EXCELLENT"; type SDVXLamps = - | "FAILED" - | "CLEAR" - | "EXCESSIVE CLEAR" - | "ULTIMATE CHAIN" - | "PERFECT ULTIMATE CHAIN"; + | "FAILED" + | "CLEAR" + | "EXCESSIVE CLEAR" + | "ULTIMATE CHAIN" + | "PERFECT ULTIMATE CHAIN"; type DDRLamps = - | "FAILED" - | "CLEAR" - | "LIFE4" - | "FULL COMBO" - | "GREAT FULL COMBO" - | "PERFECT FULL COMBO" - | "MARVELOUS FULL COMBO"; + | "FAILED" + | "CLEAR" + | "LIFE4" + | "FULL COMBO" + | "GREAT FULL COMBO" + | "PERFECT FULL COMBO" + | "MARVELOUS FULL COMBO"; export interface Lamps { - "iidx:SP": IIDXLamps; - "iidx:DP": IIDXLamps; - // THIS ONE IS WRONG! - "popn:9B": "FAILED" | "CLEAR" | "FULL COMBO" | "PERFECT"; - "sdvx:Single": SDVXLamps; - "usc:Single": SDVXLamps; - "ddr:SP": DDRLamps; - "ddr:DP": DDRLamps; - "maimai:Single": "FAILED" | "CLEAR" | "FULL COMBO" | "ALL PERFECT" | "ALL PERFECT+"; - "jubeat:Single": "FAILED" | "CLEAR" | "FULL COMBO" | "EXCELLENT"; - "museca:Single": "FAILED" | "CLEAR" | "CONNECT ALL" | "PERFECT CONNECT ALL"; - "bms:7K": IIDXLamps; - "bms:14K": IIDXLamps; - "chunithm:Single": "FAILED" | "CLEAR" | "FULL COMBO" | "ALL JUSTICE" | "ALL JUSTICE CRITICAL"; - "gitadora:Gita": GitadoraLamps; - "gitadora:Dora": GitadoraLamps; + "iidx:SP": IIDXLamps; + "iidx:DP": IIDXLamps; + // THIS ONE IS WRONG! + "popn:9B": "FAILED" | "CLEAR" | "FULL COMBO" | "PERFECT"; + "sdvx:Single": SDVXLamps; + "usc:Single": SDVXLamps; + "ddr:SP": DDRLamps; + "ddr:DP": DDRLamps; + "maimai:Single": "FAILED" | "CLEAR" | "FULL COMBO" | "ALL PERFECT" | "ALL PERFECT+"; + "jubeat:Single": "FAILED" | "CLEAR" | "FULL COMBO" | "EXCELLENT"; + "museca:Single": "FAILED" | "CLEAR" | "CONNECT ALL" | "PERFECT CONNECT ALL"; + "bms:7K": IIDXLamps; + "bms:14K": IIDXLamps; + "chunithm:Single": "FAILED" | "CLEAR" | "FULL COMBO" | "ALL JUSTICE" | "ALL JUSTICE CRITICAL"; + "gitadora:Gita": GitadoraLamps; + "gitadora:Dora": GitadoraLamps; } export interface Difficulties { - "iidx:SP": "BEGINNER" | "NORMAL" | "HYPER" | "ANOTHER" | "LEGGENDARIA"; - "iidx:DP": "NORMAL" | "HYPER" | "ANOTHER" | "LEGGENDARIA"; - "popn:9B": "Easy" | "Normal" | "Hyper" | "EX"; - "sdvx:Single": "NOV" | "ADV" | "EXH" | "MXM" | "INF" | "GRV" | "HVN" | "VVD"; - "usc:Single": "NOV" | "ADV" | "EXH" | "INF"; - "ddr:SP": "BEGINNER" | "BASIC" | "DIFFICULT" | "EXPERT" | "CHALLENGE"; - "ddr:DP": "BASIC" | "DIFFICULT" | "EXPERT" | "CHALLENGE"; - "maimai:Single": "Easy" | "Basic" | "Advanced" | "Expert" | "Master" | "Re:Master"; - "jubeat:Single": "BSC" | "ADV" | "EXT"; - "museca:Single": "Green" | "Yellow" | "Red"; - "bms:7K": "CHART"; - "bms:14K": "CHART"; - "chunithm:Single": "BASIC" | "ADVANCED" | "EXPERT" | "MASTER" | "WORLD'S END"; - "gitadora:Gita": - | "BASIC" - | "ADVANCED" - | "EXTREME" - | "MASTER" - | "BASS BASIC" - | "BASS ADVANCED" - | "BASS EXTREME" - | "BASS MASTER"; - "gitadora:Dora": "BASIC" | "ADVANCED" | "EXTREME" | "MASTER"; + "iidx:SP": "BEGINNER" | "NORMAL" | "HYPER" | "ANOTHER" | "LEGGENDARIA"; + "iidx:DP": "NORMAL" | "HYPER" | "ANOTHER" | "LEGGENDARIA"; + "popn:9B": "Easy" | "Normal" | "Hyper" | "EX"; + "sdvx:Single": "NOV" | "ADV" | "EXH" | "MXM" | "INF" | "GRV" | "HVN" | "VVD"; + "usc:Single": "NOV" | "ADV" | "EXH" | "INF"; + "ddr:SP": "BEGINNER" | "BASIC" | "DIFFICULT" | "EXPERT" | "CHALLENGE"; + "ddr:DP": "BASIC" | "DIFFICULT" | "EXPERT" | "CHALLENGE"; + "maimai:Single": "Easy" | "Basic" | "Advanced" | "Expert" | "Master" | "Re:Master"; + "jubeat:Single": "BSC" | "ADV" | "EXT"; + "museca:Single": "Green" | "Yellow" | "Red"; + "bms:7K": "CHART"; + "bms:14K": "CHART"; + "chunithm:Single": "BASIC" | "ADVANCED" | "EXPERT" | "MASTER" | "WORLD'S END"; + "gitadora:Gita": + | "BASIC" + | "ADVANCED" + | "EXTREME" + | "MASTER" + | "BASS BASIC" + | "BASS ADVANCED" + | "BASS EXTREME" + | "BASS MASTER"; + "gitadora:Dora": "BASIC" | "ADVANCED" | "EXTREME" | "MASTER"; } export interface CustomRatings { - iidx: { - SP: { - BPI: number; - "K%": number; - }; - DP: { - BPI: number; - }; - }; - popn: { - "9B": Record; - }; - sdvx: { - Single: { - VF4: number; - VF5: number; - }; - }; - usc: { - Single: { - VF4: number; - VF5: number; - }; - }; - ddr: { - SP: { - MFCP: integer; - }; - DP: { - MFCP: integer; - }; - }; - maimai: { - Single: Record; - }; - jubeat: { - Single: { - jubility: number; - }; - }; - museca: { - Single: Record; - }; - bms: { - "7K": Record; - "14K": Record; - }; - chunithm: { - Single: Record; - }; - gitadora: { - Single: Record; - }; + iidx: { + SP: { + BPI: number; + "K%": number; + }; + DP: { + BPI: number; + }; + }; + popn: { + "9B": Record; + }; + sdvx: { + Single: { + VF4: number; + VF5: number; + }; + }; + usc: { + Single: { + VF4: number; + VF5: number; + }; + }; + ddr: { + SP: { + MFCP: integer; + }; + DP: { + MFCP: integer; + }; + }; + maimai: { + Single: Record; + }; + jubeat: { + Single: { + jubility: number; + }; + }; + museca: { + Single: Record; + }; + bms: { + "7K": Record; + "14K": Record; + }; + chunithm: { + Single: Record; + }; + gitadora: { + Single: Record; + }; } /** @@ -372,22 +372,22 @@ export type integer = number; export type Ratings = Record>; export interface BaseGoalDocument extends MongoDBDocument { - game: Game; - playtype: Playtypes[Game]; - timeAdded: integer; - createdBy: integer; - title: string; - goalID: string; - criteria: GoalSingleCriteria | GoalCountCriteria; + game: Game; + playtype: Playtypes[Game]; + timeAdded: integer; + createdBy: integer; + title: string; + goalID: string; + criteria: GoalSingleCriteria | GoalCountCriteria; } interface GoalCriteria { - key: "scoreData.percent" | "scoreData.lampIndex" | "scoreData.gradeIndex" | "scoreData.score"; - value: number; + key: "scoreData.percent" | "scoreData.lampIndex" | "scoreData.gradeIndex" | "scoreData.score"; + value: number; } export interface GoalSingleCriteria extends GoalCriteria { - mode: "single"; + mode: "single"; } /** @@ -395,18 +395,18 @@ export interface GoalSingleCriteria extends GoalCriteria { * atleast N scores have to match this criteria. This is for things like folders. */ export interface GoalCountCriteria extends GoalCriteria { - mode: "abs" | "proportion"; - countNum: number; + mode: "abs" | "proportion"; + countNum: number; } /** * Goal Document - Single. A goal document that is only for one specific chart. */ export interface GoalDocumentSingle extends BaseGoalDocument { - charts: { - type: "single"; - data: string; - }; + charts: { + type: "single"; + data: string; + }; } /** @@ -414,10 +414,10 @@ export interface GoalDocumentSingle extends BaseGoalDocument { * chartIDs inside "charts". */ export interface GoalDocumentMulti extends BaseGoalDocument { - charts: { - type: "multi"; - data: string[]; - }; + charts: { + type: "multi"; + data: string[]; + }; } /** @@ -425,328 +425,328 @@ export interface GoalDocumentMulti extends BaseGoalDocument { * the folderID inside "charts". */ export interface GoalDocumentFolder extends BaseGoalDocument { - charts: { - type: "folder"; - data: string; - }; + charts: { + type: "folder"; + data: string; + }; } /** * Goal Document - Any. A goal document who's set of charts is not bound. */ export interface GoalDocumentAny extends BaseGoalDocument { - charts: { - type: "any"; - }; + charts: { + type: "any"; + }; } export type GoalDocument = - | GoalDocumentFolder - | GoalDocumentMulti - | GoalDocumentSingle - | GoalDocumentAny; + | GoalDocumentFolder + | GoalDocumentMulti + | GoalDocumentSingle + | GoalDocumentAny; export interface RivalGroupDocument extends MongoDBDocument { - name: string; - desc: string; - founderID: integer; - members: integer[]; - mutualGroup: boolean; - isDefault: boolean; - game: Game; - playtype: Playtypes[Game]; - settings: { - scoreCompareMode: "relevant" | "folder"; - strictness: number; - boundary: number; - scoreCompareFolderID: string | null; - cellShading: "grade" | "lamp"; - }; - rivalGroupID: string; + name: string; + desc: string; + founderID: integer; + members: integer[]; + mutualGroup: boolean; + isDefault: boolean; + game: Game; + playtype: Playtypes[Game]; + settings: { + scoreCompareMode: "relevant" | "folder"; + strictness: number; + boundary: number; + scoreCompareFolderID: string | null; + cellShading: "grade" | "lamp"; + }; + rivalGroupID: string; } export type MRGChallengeModes = "goal" | "lamp" | "score"; export interface MutualRivalGroupChallenge extends MongoDBDocument { - challengeID: string; - derivedScoreID: string | null; - mode: MRGChallengeModes; - name: string; - postedBy: integer; - goalID: string; - mrgID: string; - postedAt: integer; + challengeID: string; + derivedScoreID: string | null; + mode: MRGChallengeModes; + name: string; + postedBy: integer; + goalID: string; + mrgID: string; + postedAt: integer; } export type MRGFolderTargetFieldNames = - | "scoreData.percent" - | "scoreData.gradeIndex" - | "scoreData.lampIndex" - | "calculatedData.gameSpecific.BPI"; + | "scoreData.percent" + | "scoreData.gradeIndex" + | "scoreData.lampIndex" + | "calculatedData.gameSpecific.BPI"; export interface MRGFolderTarget { - field: MRGFolderTargetFieldNames; - target: number; + field: MRGFolderTargetFieldNames; + target: number; } export interface MRGFolderInformation { - folderID: string; - difficulty: Difficulties[I][] | null; - datapoints: MRGFolderTarget[]; + folderID: string; + difficulty: Difficulties[I][] | null; + datapoints: MRGFolderTarget[]; } export interface MutualRivalGroupDocument extends MongoDBDocument { - name: string; - about: string; - founderID: integer; - members: integer[]; - outgoingInvites: integer[]; - game: Game; - playtype: Playtypes[Game]; - folders: MRGFolderInformation[]; - settings: Record; - mrgID: string; + name: string; + about: string; + founderID: integer; + members: integer[]; + outgoingInvites: integer[]; + game: Game; + playtype: Playtypes[Game]; + folders: MRGFolderInformation[]; + settings: Record; + mrgID: string; } export interface InviteCodeDocument extends MongoDBDocument { - createdBy: integer; - code: string; - createdOn: number; - consumed: boolean; + createdBy: integer; + code: string; + createdOn: number; + consumed: boolean; } export interface SessionInfoReturn { - sessionID: string; - type: "Created" | "Appended"; + sessionID: string; + type: "Created" | "Appended"; } interface SessionScorePBInfo { - scoreID: string; - isNewScore: false; - scoreDelta: number; - gradeDelta: integer; - lampDelta: integer; - percentDelta: integer; + scoreID: string; + isNewScore: false; + scoreDelta: number; + gradeDelta: integer; + lampDelta: integer; + percentDelta: integer; } interface SessionScoreNewInfo { - scoreID: string; - isNewScore: true; + scoreID: string; + isNewScore: true; } export type SessionScoreInfo = SessionScorePBInfo | SessionScoreNewInfo; export interface SessionCalculatedDataLookup { - "iidx:SP": "BPI" | "ktRating" | "ktLampRating"; - "iidx:DP": "BPI" | "ktRating" | "ktLampRating"; - "popn:9B": never; // @todo - "sdvx:Single": "VF6" | "ProfileVF6"; - "usc:Single": "VF6" | "ProfileVF6"; - "ddr:SP": "MFCP" | "ktRating"; - "ddr:DP": "MFCP" | "ktRating"; - "maimai:Single": "ktRating"; - "jubeat:Single": "jubility"; - "museca:Single": "ktRating"; - "bms:7K": "ktLampRating"; - "bms:14K": "ktLampRating"; - "chunithm:Single": "rating"; - "gitadora:Gita": "skill"; - "gitadora:Dora": "skill"; + "iidx:SP": "BPI" | "ktRating" | "ktLampRating"; + "iidx:DP": "BPI" | "ktRating" | "ktLampRating"; + "popn:9B": never; // @todo + "sdvx:Single": "VF6" | "ProfileVF6"; + "usc:Single": "VF6" | "ProfileVF6"; + "ddr:SP": "MFCP" | "ktRating"; + "ddr:DP": "MFCP" | "ktRating"; + "maimai:Single": "ktRating"; + "jubeat:Single": "jubility"; + "museca:Single": "ktRating"; + "bms:7K": "ktLampRating"; + "bms:14K": "ktLampRating"; + "chunithm:Single": "rating"; + "gitadora:Gita": "skill"; + "gitadora:Dora": "skill"; } export interface SessionDocument extends MongoDBDocument { - userID: integer; - sessionID: string; - scoreInfo: SessionScoreInfo[]; - name: string; - desc: string | null; - game: Game; - playtype: Playtypes[Game]; - importType: ImportTypes; - timeInserted: integer; - timeEnded: integer; - timeStarted: integer; - calculatedData: Partial>; - highlight: boolean; + userID: integer; + sessionID: string; + scoreInfo: SessionScoreInfo[]; + name: string; + desc: string | null; + game: Game; + playtype: Playtypes[Game]; + importType: ImportTypes; + timeInserted: integer; + timeEnded: integer; + timeStarted: integer; + calculatedData: Partial>; + highlight: boolean; } export interface SessionViewDocument extends MongoDBDocument { - sessionID: string; - ip: string; - timestamp: number; + sessionID: string; + ip: string; + timestamp: number; } interface ImportErrContent { - type: string; - message: string | null; + type: string; + message: string | null; } export interface ClassDelta { - set: AllClassSets; - playtype: Playtypes[Game]; - old: integer | null; - new: integer; + set: AllClassSets; + playtype: Playtypes[Game]; + old: integer | null; + new: integer; } export interface ImportDocument extends MongoDBDocument { - userID: integer; - timeStarted: number; - timeFinished: number; - // Contains an array of IDStrings, which dictates what (game:playtype)s were involved in this import. - idStrings: IDStrings[]; - importID: string; - scoreIDs: string[]; - errors: ImportErrContent[]; - // For performance reasons, imports only show what sessions they created, rather than what sessions they didn't. - // This is just an array of sessionIDs, to keep things normalised. May be empty. - createdSessions: SessionInfoReturn[]; - importType: ImportTypes; - classDeltas: ClassDelta[]; - goalInfo: GoalImportInfo[]; - milestoneInfo: MilestoneImportInfo[]; - /** - * Whether the user deliberately imported this through an action (i.e. uploaded a file personally) [true] - * or was imported on their behalf through a service (i.e. fervidex) - */ - userIntent: boolean; + userID: integer; + timeStarted: number; + timeFinished: number; + // Contains an array of IDStrings, which dictates what (game:playtype)s were involved in this import. + idStrings: IDStrings[]; + importID: string; + scoreIDs: string[]; + errors: ImportErrContent[]; + // For performance reasons, imports only show what sessions they created, rather than what sessions they didn't. + // This is just an array of sessionIDs, to keep things normalised. May be empty. + createdSessions: SessionInfoReturn[]; + importType: ImportTypes; + classDeltas: ClassDelta[]; + goalInfo: GoalImportInfo[]; + milestoneInfo: MilestoneImportInfo[]; + /** + * Whether the user deliberately imported this through an action (i.e. uploaded a file personally) [true] + * or was imported on their behalf through a service (i.e. fervidex) + */ + userIntent: boolean; } export interface ImportTimingsDocument { - importID: string; - timestamp: number; - total: number; - /** - * Relative times - these are the times for each section - * divided by how much data they had to process. - */ - rel: Omit; - /** - * Absolute times - these are the times for each section. - */ - abs: ImportTimingSections; + importID: string; + timestamp: number; + total: number; + /** + * Relative times - these are the times for each section + * divided by how much data they had to process. + */ + rel: Omit; + /** + * Absolute times - these are the times for each section. + */ + abs: ImportTimingSections; } interface ImportTimingSections { - parse: number; - import: number; - importParse: number; - session: number; - pb: number; - ugs: number; - goal: number; - milestone: number; + parse: number; + import: number; + importParse: number; + session: number; + pb: number; + ugs: number; + goal: number; + milestone: number; } export type GoalImportStat = Pick< - UserGoalDocument, - "progress" | "progressHuman" | "outOf" | "outOfHuman" | "achieved" + UserGoalDocument, + "progress" | "progressHuman" | "outOf" | "outOfHuman" | "achieved" >; export interface GoalImportInfo { - goalID: string; - old: GoalImportStat; - new: GoalImportStat; + goalID: string; + old: GoalImportStat; + new: GoalImportStat; } export type MilestoneImportStat = Pick; export interface MilestoneImportInfo { - milestoneID: string; - old: MilestoneImportStat; - new: MilestoneImportStat; + milestoneID: string; + old: MilestoneImportStat; + new: MilestoneImportStat; } export interface UserGoalDocument extends MongoDBDocument { - goalID: string; - userID: integer; - game: Game; - playtype: Playtypes[Game]; - achieved: boolean; - timeSet: integer; - timeAchieved: integer | null; - lastInteraction: integer | null; - progress: number | null; - progressHuman: string; - outOf: number; - outOfHuman: string; + goalID: string; + userID: integer; + game: Game; + playtype: Playtypes[Game]; + achieved: boolean; + timeSet: integer; + timeAchieved: integer | null; + lastInteraction: integer | null; + progress: number | null; + progressHuman: string; + outOf: number; + outOfHuman: string; } interface MilestoneGoalReference { - goalID: string; - note?: string; + goalID: string; + note?: string; } interface MilestoneSection { - title: string; - desc: string; - goals: MilestoneGoalReference[]; + title: string; + desc: string; + goals: MilestoneGoalReference[]; } export interface MilestoneDocument extends MongoDBDocument { - game: Game; - playtype: Playtypes[Game]; - /** - * all: All goals must be achieved in order for the milestone to be complete - * abs: Goals achieved must be greater than or equal to criteria.value. - * proportion: Goals achieved must be greater than or equal to criteria.value * total_goals. - */ - criteria: MilestoneAllCriteria | MilestoneAbsPropCriteria; - createdBy: integer; - name: string; - desc: string; - milestoneData: MilestoneSection[]; - milestoneID: string; - group: string | null; - groupIndex: number | null; + game: Game; + playtype: Playtypes[Game]; + /** + * all: All goals must be achieved in order for the milestone to be complete + * abs: Goals achieved must be greater than or equal to criteria.value. + * proportion: Goals achieved must be greater than or equal to criteria.value * total_goals. + */ + criteria: MilestoneAllCriteria | MilestoneAbsPropCriteria; + createdBy: integer; + name: string; + desc: string; + milestoneData: MilestoneSection[]; + milestoneID: string; + group: string | null; + groupIndex: number | null; } interface MilestoneAllCriteria { - type: "all"; + type: "all"; } interface MilestoneAbsPropCriteria { - type: "abs" | "proportion"; - value: number; + type: "abs" | "proportion"; + value: number; } export interface MilestoneGroupDocument extends MongoDBDocument { - game: Game; - playtype: Playtypes[Game]; - isDefault: boolean; - createdBy: integer; - groupName: string; - name: string; - desc: string; + game: Game; + playtype: Playtypes[Game]; + isDefault: boolean; + createdBy: integer; + groupName: string; + name: string; + desc: string; } export type NotificationType = - | "clandisband" - | "claninvite" - | "goals" - | "import" - | "milestone" - | "mrginvite" - | "mrgkicked" - | "mrgdisband" - | "mrginviterejected"; + | "clandisband" + | "claninvite" + | "goals" + | "import" + | "milestone" + | "mrginvite" + | "mrgkicked" + | "mrgdisband" + | "mrginviterejected"; export interface NotificationDocument extends MongoDBDocument { - notifID: string; - title: string; - read: boolean; - body: string; - toUserID: integer; - fromUserID: integer; - type: NotificationType; - data: Record; + notifID: string; + title: string; + read: boolean; + body: string; + toUserID: integer; + fromUserID: integer; + type: NotificationType; + data: Record; } export interface FunFactDocument extends MongoDBDocument { - text: string; - nsfw: boolean; - anonymous: boolean; - userID: integer; - funfactID: string; - timestamp: integer; + text: string; + nsfw: boolean; + anonymous: boolean; + userID: integer; + funfactID: string; + timestamp: integer; } /** @@ -754,53 +754,53 @@ export interface FunFactDocument extends MongoDBDocument { * Note that the private fields: password, email and integrations, are not present in this document. */ export interface PublicUserDocument extends MongoDBDocument { - username: string; - usernameLowercase: string; - id: integer; - settings: { - nsfwSplashes: boolean; - invisible: boolean; - }; - friends: integer[]; - socialMedia: { - discord?: string | null; - twitter?: string | null; - github?: string | null; - steam?: string | null; - youtube?: string | null; - twitch?: string | null; - }; - lastSeen: integer; - about: string; - customPfp: boolean; - customBanner: boolean; - clan: string | null; // todo + username: string; + usernameLowercase: string; + id: integer; + settings: { + nsfwSplashes: boolean; + invisible: boolean; + }; + friends: integer[]; + socialMedia: { + discord?: string | null; + twitter?: string | null; + github?: string | null; + steam?: string | null; + youtube?: string | null; + twitch?: string | null; + }; + lastSeen: integer; + about: string; + customPfp: boolean; + customBanner: boolean; + clan: string | null; // todo } export interface UGSRatingsLookup { - "iidx:SP": "BPI" | "K%" | "ktRating" | "ktLampRating"; - "iidx:DP": "BPI" | "ktRating" | "ktLampRating"; - "popn:9B": never; // @todo - "sdvx:Single": "VF6"; - "usc:Single": "VF6"; - "ddr:SP": "MFCP" | "ktRating"; - "ddr:DP": "MFCP" | "ktRating"; - "maimai:Single": "ktRating"; - "jubeat:Single": "jubility"; - "museca:Single": "ktRating"; - "bms:7K": "ktLampRating"; - "bms:14K": "ktLampRating"; - "chunithm:Single": "naiveRating"; - "gitadora:Gita": "skill"; - "gitadora:Dora": "skill"; + "iidx:SP": "BPI" | "K%" | "ktRating" | "ktLampRating"; + "iidx:DP": "BPI" | "ktRating" | "ktLampRating"; + "popn:9B": never; // @todo + "sdvx:Single": "VF6"; + "usc:Single": "VF6"; + "ddr:SP": "MFCP" | "ktRating"; + "ddr:DP": "MFCP" | "ktRating"; + "maimai:Single": "ktRating"; + "jubeat:Single": "jubility"; + "museca:Single": "ktRating"; + "bms:7K": "ktLampRating"; + "bms:14K": "ktLampRating"; + "chunithm:Single": "naiveRating"; + "gitadora:Gita": "skill"; + "gitadora:Dora": "skill"; } export interface UserGameStats extends MongoDBDocument { - userID: integer; - game: IDStringToGame[I]; - playtype: IDStringToPlaytype[I]; - ratings: Partial>; - classes: Partial>; + userID: integer; + game: IDStringToGame[I]; + playtype: IDStringToPlaytype[I]; + ratings: Partial>; + classes: Partial>; } /** @@ -808,311 +808,311 @@ export interface UserGameStats extends MongoDBD * from the DB - including their private information. */ export interface PrivateUserDocument extends PublicUserDocument { - password: string; - email: string; + password: string; + email: string; } export interface IIDXEamusementScoreDocument extends MongoDBDocument { - chartID: string; - lamp: Lamps["iidx:SP" | "iidx:DP"]; - score: integer; - ranking: integer; + chartID: string; + lamp: Lamps["iidx:SP" | "iidx:DP"]; + score: integer; + ranking: integer; } interface ChartDocumentFlags { - "iidx:SP": "IN BASE GAME" | "OMNIMIX" | "N-1" | "2dxtra"; - "iidx:DP": "IN BASE GAME" | "OMNIMIX" | "N-1" | "2dxtra"; - "popn:9B": "IN BASE GAME" | "OMNIMIX"; - "sdvx:Single": "IN BASE GAME" | "OMNIMIX" | "N-1"; - "usc:Single": "CUSTOM"; - "ddr:SP": "IN BASE GAME" | "N-1"; - "ddr:DP": "IN BASE GAME" | "N-1"; - "maimai:Single": "IN BASE GAME"; - "jubeat:Single": "IN BASE GAME"; - "museca:Single": "IN BASE GAME" | "OMNIMIX"; - "bms:7K": never; - "bms:14K": never; - "chunithm:Single": "IN BASE GAME" | "OMNIMIX"; - "gitadora:Gita": "IN BASE GAME" | "OMNIMIX" | "HOT" | "HOT N-1"; - "gitadora:Dora": "IN BASE GAME" | "OMNIMIX" | "HOT" | "HOT N-1"; + "iidx:SP": "IN BASE GAME" | "OMNIMIX" | "N-1" | "2dxtra"; + "iidx:DP": "IN BASE GAME" | "OMNIMIX" | "N-1" | "2dxtra"; + "popn:9B": "IN BASE GAME" | "OMNIMIX"; + "sdvx:Single": "IN BASE GAME" | "OMNIMIX" | "N-1"; + "usc:Single": "CUSTOM"; + "ddr:SP": "IN BASE GAME" | "N-1"; + "ddr:DP": "IN BASE GAME" | "N-1"; + "maimai:Single": "IN BASE GAME"; + "jubeat:Single": "IN BASE GAME"; + "museca:Single": "IN BASE GAME" | "OMNIMIX"; + "bms:7K": never; + "bms:14K": never; + "chunithm:Single": "IN BASE GAME" | "OMNIMIX"; + "gitadora:Gita": "IN BASE GAME" | "OMNIMIX" | "HOT" | "HOT N-1"; + "gitadora:Dora": "IN BASE GAME" | "OMNIMIX" | "HOT" | "HOT N-1"; } interface CDDataIIDXSP { - notecount: integer; - inGameID: integer; - arcChartID: string | null; - hashSHA256: string | null; - "2dxtraSet": string | null; + notecount: integer; + inGameID: integer; + arcChartID: string | null; + hashSHA256: string | null; + "2dxtraSet": string | null; } interface CDDataDDRSP { - songHash: string; - inGameID: string; - arcChartID: string | null; + songHash: string; + inGameID: string; + arcChartID: string | null; } interface CDDataBMS { - notecount: integer; - hashMD5: string; - hashSHA256: string; + notecount: integer; + hashMD5: string; + hashSHA256: string; } interface ChartDocumentData { - "iidx:SP": CDDataIIDXSP; - "iidx:DP": CDDataIIDXSP; - "popn:9B": Record; - "sdvx:Single": { inGameID: integer; arcChartID: string | null }; - "usc:Single": { hashSHA1: string | string[] }; - "ddr:SP": CDDataDDRSP; - "ddr:DP": CDDataDDRSP; - "maimai:Single": { maxPercent: number; inGameID: string }; - "jubeat:Single": { arcChartID: string | null }; - "museca:Single": Record; - "bms:7K": CDDataBMS; - "bms:14K": CDDataBMS; - "chunithm:Single": { inGameID: integer }; - "gitadora:Gita": { inGameID: integer }; - "gitadora:Dora": { inGameID: integer }; + "iidx:SP": CDDataIIDXSP; + "iidx:DP": CDDataIIDXSP; + "popn:9B": Record; + "sdvx:Single": { inGameID: integer; arcChartID: string | null }; + "usc:Single": { hashSHA1: string | string[] }; + "ddr:SP": CDDataDDRSP; + "ddr:DP": CDDataDDRSP; + "maimai:Single": { maxPercent: number; inGameID: string }; + "jubeat:Single": { arcChartID: string | null }; + "museca:Single": Record; + "bms:7K": CDDataBMS; + "bms:14K": CDDataBMS; + "chunithm:Single": { inGameID: integer }; + "gitadora:Gita": { inGameID: integer }; + "gitadora:Dora": { inGameID: integer }; } export interface AnyChartDocument extends MongoDBDocument { - chartID: string; - rgcID: string | null; // ID to perform backbeat lookup in future. - songID: integer; - level: string; - levelNum: number; - difficulty: Difficulties[IDStrings]; - playtype: Playtypes[Game]; - isPrimary: boolean; - versions: string[]; + chartID: string; + rgcID: string | null; // ID to perform backbeat lookup in future. + songID: integer; + level: string; + levelNum: number; + difficulty: Difficulties[IDStrings]; + playtype: Playtypes[Game]; + isPrimary: boolean; + versions: string[]; } export interface ChartDocument extends AnyChartDocument { - difficulty: Difficulties[I]; - playtype: IDStringToPlaytype[I]; - flags: Record; - data: ChartDocumentData[I]; + difficulty: Difficulties[I]; + playtype: IDStringToPlaytype[I]; + flags: Record; + data: ChartDocumentData[I]; } interface TierlistPermissions { - // all permission values are as follows: - // 0 -> cannot do this - // 1 -> can do this, but can be overrode by requireState - // 2 -> can do this, and cannot be overrode. - edit: integer; - submit: integer; - vote: integer; + // all permission values are as follows: + // 0 -> cannot do this + // 1 -> can do this, but can be overrode by requireState + // 2 -> can do this, and cannot be overrode. + edit: integer; + submit: integer; + vote: integer; } export interface TierlistParent extends MongoDBDocument { - game: G; - playtype: Playtypes[G]; - name: string; - isDefault: boolean; - tierlistID: string; - createdBy: integer; - createdAt: number; - permissions: Record & { anyPlayer: TierlistPermissions }; - description: string; - lastUpdated: number; - config: { - // Automatically update TierlistDataDocuments with humanised strings. idk how this will work yet. - autoHumanise: boolean; - // No matter what, users have a permission of 000 if they have not cleared/played the chart - requireState: null | "clear" | "play"; - // the list of flags that can appear in TierlistDataDocuments - flags: string[]; - }; + game: G; + playtype: Playtypes[G]; + name: string; + isDefault: boolean; + tierlistID: string; + createdBy: integer; + createdAt: number; + permissions: Record & { anyPlayer: TierlistPermissions }; + description: string; + lastUpdated: number; + config: { + // Automatically update TierlistDataDocuments with humanised strings. idk how this will work yet. + autoHumanise: boolean; + // No matter what, users have a permission of 000 if they have not cleared/played the chart + requireState: null | "clear" | "play"; + // the list of flags that can appear in TierlistDataDocuments + flags: string[]; + }; } export interface TierlistDataDocument extends MongoDBDocument { - chartID: string; - tierlistID: string; - // grade -> the approximate "difficulty" to achieve this grade on this song. - // lamp -> same, but for the lamp - // score -> A generic, single value that determines how hard it is to "score" on this song. This is not - // useful, to be honest, but is still used in generic rating calculations. - type: "grade" | "lamp" | "score"; - // null if type is "score", else, the grade or lamp this corresponds to. - key: string | null; - // used as primary key - is a hash of this data. - tierlistDataID: string; - data: { - value: number; - humanised: string; - flags: { - [flag in F]: boolean; - }; - }; + chartID: string; + tierlistID: string; + // grade -> the approximate "difficulty" to achieve this grade on this song. + // lamp -> same, but for the lamp + // score -> A generic, single value that determines how hard it is to "score" on this song. This is not + // useful, to be honest, but is still used in generic rating calculations. + type: "grade" | "lamp" | "score"; + // null if type is "score", else, the grade or lamp this corresponds to. + key: string | null; + // used as primary key - is a hash of this data. + tierlistDataID: string; + data: { + value: number; + humanised: string; + flags: { + [flag in F]: boolean; + }; + }; } interface SongDocumentData { - iidx: { genre: string }; - museca: { titleJP: string; artistJP: string }; - maimai: { titleJP: string; artistJP: string; genre: string }; - jubeat: Record; - popn: Record; - sdvx: { uscEquiv: integer | null }; - usc: { sdvxEquiv: integer | null }; - ddr: Record; - bms: { genre: string | null; subtitle: string | null; subartist: string | null }; - chunithm: { genre: string }; - gitadora: Record; + iidx: { genre: string }; + museca: { titleJP: string; artistJP: string }; + maimai: { titleJP: string; artistJP: string; genre: string }; + jubeat: Record; + popn: Record; + sdvx: { uscEquiv: integer | null }; + usc: { sdvxEquiv: integer | null }; + ddr: Record; + bms: { genre: string | null; subtitle: string | null; subartist: string | null }; + chunithm: { genre: string }; + gitadora: Record; } export interface AnySongDocument extends MongoDBDocument { - id: integer; - title: string; - artist: string; - firstVersion: string | null; - /** - * Alternative names for this song, to be used while searching. - */ - "search-titles": string[]; - /** - * Alternative titles for this song, to be used whenever the song is - * requested. - */ - "alt-titles": string[]; + id: integer; + title: string; + artist: string; + firstVersion: string | null; + /** + * Alternative names for this song, to be used while searching. + */ + "search-titles": string[]; + /** + * Alternative titles for this song, to be used whenever the song is + * requested. + */ + "alt-titles": string[]; } export interface SongDocument extends AnySongDocument { - data: SongDocumentData[G]; + data: SongDocumentData[G]; } export interface BaseFolderDocument extends MongoDBDocument { - title: string; - game: Game; - playtype: Playtypes[Game]; - folderID: string; - table: string; - tableIndex: number; + title: string; + game: Game; + playtype: Playtypes[Game]; + folderID: string; + table: string; + tableIndex: number; } export interface FolderSongsDocument extends BaseFolderDocument { - type: "songs"; - data: FilterQuery; + type: "songs"; + data: FilterQuery; } export interface FolderChartsDocument extends BaseFolderDocument { - type: "charts"; - data: FilterQuery; + type: "charts"; + data: FilterQuery; } export interface FolderStaticDocument extends BaseFolderDocument { - type: "static"; - data: string[]; + type: "static"; + data: string[]; } export type FolderDocument = FolderStaticDocument | FolderChartsDocument | FolderSongsDocument; export interface FolderChartLookup extends MongoDBDocument { - chartID: string; - folderID: string; + chartID: string; + folderID: string; } export interface UserMilestoneDocument extends MongoDBDocument { - milestoneID: string; - userID: integer; - game: Game; - playtype: Playtypes[Game]; - timeSet: integer; - achieved: boolean; - timeAchieved: integer | null; - progress: integer; + milestoneID: string; + userID: integer; + game: Game; + playtype: Playtypes[Game]; + timeSet: integer; + achieved: boolean; + timeAchieved: integer | null; + progress: integer; } type RanOptions = "NONRAN" | "RANDOM" | "R-RANDOM" | "S-RANDOM" | "MIRROR"; interface IIDXSPScoreMeta { - random: RanOptions | null; - assist: "NO ASSIST" | "AUTO SCRATCH" | "LEGACY NOTE" | "FULL ASSIST" | null; - range: "NONE" | "SUDDEN+" | "HIDDEN+" | "SUD+ HID+" | "LIFT" | "LIFT SUD+" | null; - gauge: "ASSISTED EASY" | "EASY" | "NORMAL" | "HARD" | "EX HARD" | null; + random: RanOptions | null; + assist: "NO ASSIST" | "AUTO SCRATCH" | "LEGACY NOTE" | "FULL ASSIST" | null; + range: "NONE" | "SUDDEN+" | "HIDDEN+" | "SUD+ HID+" | "LIFT" | "LIFT SUD+" | null; + gauge: "ASSISTED EASY" | "EASY" | "NORMAL" | "HARD" | "EX HARD" | null; } interface BMS7KScoreMeta { - random: RanOptions | null; - inputDevice: "KEYBOARD" | "BM_CONTROLLER" | "MIDI" | null; - client: "LR2" | "beatoraja" | "lr2oraja"; - lntype: null | "LN" | "CN"; + random: RanOptions | null; + inputDevice: "KEYBOARD" | "BM_CONTROLLER" | "MIDI" | null; + client: "LR2" | "beatoraja" | "lr2oraja"; + lntype: null | "LN" | "CN"; } interface ScoreMetaLookup { - "iidx:SP": IIDXSPScoreMeta; - "iidx:DP": IIDXSPScoreMeta & { random: [RanOptions, RanOptions] | null }; - "popn:9B": Record; - "sdvx:Single": { inSkillAnalyser: boolean | null }; - "usc:Single": { - noteMod: "NORMAL" | "MIRROR" | "RANDOM" | "MIR-RAN"; - gaugeMod: "NORMAL" | "HARD"; - }; - "ddr:SP": Record; - "ddr:DP": Record; - "maimai:Single": Record; - "jubeat:Single": Record; - "museca:Single": Record; - "bms:7K": BMS7KScoreMeta; - "bms:14K": BMS7KScoreMeta & { random: [RanOptions, RanOptions] | null }; - "chunithm:Single": Record; - "gitadora:Gita": Record; - "gitadora:Dora": Record; + "iidx:SP": IIDXSPScoreMeta; + "iidx:DP": IIDXSPScoreMeta & { random: [RanOptions, RanOptions] | null }; + "popn:9B": Record; + "sdvx:Single": { inSkillAnalyser: boolean | null }; + "usc:Single": { + noteMod: "NORMAL" | "MIRROR" | "RANDOM" | "MIR-RAN"; + gaugeMod: "NORMAL" | "HARD"; + }; + "ddr:SP": Record; + "ddr:DP": Record; + "maimai:Single": Record; + "jubeat:Single": Record; + "museca:Single": Record; + "bms:7K": BMS7KScoreMeta; + "bms:14K": BMS7KScoreMeta & { random: [RanOptions, RanOptions] | null }; + "chunithm:Single": Record; + "gitadora:Gita": Record; + "gitadora:Dora": Record; } interface BASE_VALID_HIT_META { - fast: integer | null; - slow: integer | null; - maxCombo: integer | null; + fast: integer | null; + slow: integer | null; + maxCombo: integer | null; } type IIDXHitMeta = BASE_VALID_HIT_META & { - bp: integer | null; - gauge: number | null; - gaugeHistory: (number | null)[] | null; - scoreHistory: number[] | null; - comboBreak: integer | null; - gsm: { - EASY: (number | null)[]; - NORMAL: (number | null)[]; - HARD: (number | null)[]; - EX_HARD: (number | null)[]; - } | null; + bp: integer | null; + gauge: number | null; + gaugeHistory: (number | null)[] | null; + scoreHistory: number[] | null; + comboBreak: integer | null; + gsm: { + EASY: (number | null)[]; + NORMAL: (number | null)[]; + HARD: (number | null)[]; + EX_HARD: (number | null)[]; + } | null; }; type BMSJudgePermutations = `${"e" | "l"}${"bd" | "pr" | "gd" | "gr" | "pg"}`; type BMSHitMeta = BASE_VALID_HIT_META & - { - [K in BMSJudgePermutations]: integer; - } & { - bp: integer | null; - gauge: number | null; - diedAt: integer | null; - }; + { + [K in BMSJudgePermutations]: integer; + } & { + bp: integer | null; + gauge: number | null; + diedAt: integer | null; + }; type SDVXHitMeta = BASE_VALID_HIT_META & { - gauge: number | null; - btnRate: number | null; - holdRate: number | null; - laserRate: number | null; + gauge: number | null; + btnRate: number | null; + holdRate: number | null; + laserRate: number | null; }; export interface HitMetaLookup { - "iidx:SP": IIDXHitMeta; - "iidx:DP": IIDXHitMeta; - "popn:9B": BASE_VALID_HIT_META & { gauge: number }; - "sdvx:Single": SDVXHitMeta; - "usc:Single": SDVXHitMeta; - "ddr:SP": BASE_VALID_HIT_META & { exScore: integer }; - "ddr:DP": BASE_VALID_HIT_META & { exScore: integer }; - "maimai:Single": BASE_VALID_HIT_META; - "jubeat:Single": BASE_VALID_HIT_META; - "museca:Single": BASE_VALID_HIT_META; - "bms:7K": BMSHitMeta; - "bms:14K": BMSHitMeta; - "chunithm:Single": BASE_VALID_HIT_META; - "gitadora:Gita": BASE_VALID_HIT_META; - "gitadora:Dora": BASE_VALID_HIT_META; + "iidx:SP": IIDXHitMeta; + "iidx:DP": IIDXHitMeta; + "popn:9B": BASE_VALID_HIT_META & { gauge: number }; + "sdvx:Single": SDVXHitMeta; + "usc:Single": SDVXHitMeta; + "ddr:SP": BASE_VALID_HIT_META & { exScore: integer }; + "ddr:DP": BASE_VALID_HIT_META & { exScore: integer }; + "maimai:Single": BASE_VALID_HIT_META; + "jubeat:Single": BASE_VALID_HIT_META; + "museca:Single": BASE_VALID_HIT_META; + "bms:7K": BMSHitMeta; + "bms:14K": BMSHitMeta; + "chunithm:Single": BASE_VALID_HIT_META; + "gitadora:Gita": BASE_VALID_HIT_META; + "gitadora:Dora": BASE_VALID_HIT_META; } type IIDXJudges = "pgreat" | "great" | "good" | "bad" | "poor"; @@ -1123,243 +1123,243 @@ type GitadoraJudges = "perfect" | "great" | "good" | "ok" | "miss"; type SDVXJudges = "critical" | "near" | "miss"; export interface JudgementLookup { - "iidx:SP": IIDXJudges; - "iidx:DP": IIDXJudges; - "popn:9B": "cool" | "great" | "good" | "miss"; - "sdvx:Single": SDVXJudges; - "usc:Single": SDVXJudges; - "ddr:SP": DDRJudges; - "ddr:DP": DDRJudges; - "maimai:Single": "perfect" | "great" | "good" | "miss"; - "jubeat:Single": "perfect" | "great" | "good" | "bad" | "miss"; - "museca:Single": "critical" | "near" | "miss"; - "bms:7K": IIDXJudges; - "bms:14K": IIDXJudges; - "chunithm:Single": "jcrit" | "justice" | "attack" | "miss"; - "gitadora:Gita": GitadoraJudges; - "gitadora:Dora": GitadoraJudges; + "iidx:SP": IIDXJudges; + "iidx:DP": IIDXJudges; + "popn:9B": "cool" | "great" | "good" | "miss"; + "sdvx:Single": SDVXJudges; + "usc:Single": SDVXJudges; + "ddr:SP": DDRJudges; + "ddr:DP": DDRJudges; + "maimai:Single": "perfect" | "great" | "good" | "miss"; + "jubeat:Single": "perfect" | "great" | "good" | "bad" | "miss"; + "museca:Single": "critical" | "near" | "miss"; + "bms:7K": IIDXJudges; + "bms:14K": IIDXJudges; + "chunithm:Single": "jcrit" | "justice" | "attack" | "miss"; + "gitadora:Gita": GitadoraJudges; + "gitadora:Dora": GitadoraJudges; } export interface ScoreCalculatedDataLookup { - "iidx:SP": "BPI" | "K%" | "ktRating" | "ktLampRating"; - "iidx:DP": "BPI" | "ktRating" | "ktLampRating"; - // "popn:9B": never; // @todo - "sdvx:Single": "VF6"; - "usc:Single": "VF6"; - "ddr:SP": "MFCP" | "ktRating"; - "ddr:DP": "MFCP" | "ktRating"; - "maimai:Single": "ktRating"; - // "jubeat:Single": "jubility"; - "museca:Single": "ktRating"; - "bms:7K": "ktLampRating"; - "bms:14K": "ktLampRating"; - "chunithm:Single": "rating"; - "gitadora:Gita": "skill"; - "gitadora:Dora": "skill"; + "iidx:SP": "BPI" | "K%" | "ktRating" | "ktLampRating"; + "iidx:DP": "BPI" | "ktRating" | "ktLampRating"; + // "popn:9B": never; // @todo + "sdvx:Single": "VF6"; + "usc:Single": "VF6"; + "ddr:SP": "MFCP" | "ktRating"; + "ddr:DP": "MFCP" | "ktRating"; + "maimai:Single": "ktRating"; + // "jubeat:Single": "jubility"; + "museca:Single": "ktRating"; + "bms:7K": "ktLampRating"; + "bms:14K": "ktLampRating"; + "chunithm:Single": "rating"; + "gitadora:Gita": "skill"; + "gitadora:Dora": "skill"; } export interface ScoreDocument extends MongoDBDocument { - service: string; - game: IDStringToGame[I]; - playtype: IDStringToPlaytype[I]; - userID: integer; - scoreData: { - score: number; - lamp: Lamps[I]; - percent: number; - grade: Grades[I]; - lampIndex: integer; - gradeIndex: integer; - esd: number | null; - hitData: Partial>; - hitMeta: Partial; - }; - scoreMeta: Partial; - calculatedData: Partial>; - timeAchieved: integer | null; - songID: integer; - chartID: string; - isPrimary: boolean; - highlight: boolean; - comment: string | null; - timeAdded: integer; - scoreID: string; - importType: ImportTypes | null; + service: string; + game: IDStringToGame[I]; + playtype: IDStringToPlaytype[I]; + userID: integer; + scoreData: { + score: number; + lamp: Lamps[I]; + percent: number; + grade: Grades[I]; + lampIndex: integer; + gradeIndex: integer; + esd: number | null; + hitData: Partial>; + hitMeta: Partial; + }; + scoreMeta: Partial; + calculatedData: Partial>; + timeAchieved: integer | null; + songID: integer; + chartID: string; + isPrimary: boolean; + highlight: boolean; + comment: string | null; + timeAdded: integer; + scoreID: string; + importType: ImportTypes | null; } export interface PBScoreComposedReference { - name: string; - scoreID: string; + name: string; + scoreID: string; } export interface PBScoreDocument extends MongoDBDocument { - composedFrom: { - scorePB: string; - lampPB: string; - other?: PBScoreComposedReference[]; - }; - rankingData: { - rank: integer; - outOf: integer; - }; - userID: integer; - chartID: string; - game: Game; - playtype: Playtypes[Game]; - songID: integer; - comments: string[]; - highlight: boolean; - isPrimary: boolean; - timeAchieved: number | null; - scoreData: { - score: number; - lamp: Lamps[I]; - percent: number; - grade: Grades[I]; - lampIndex: integer; - gradeIndex: integer; - esd: number | null; - hitData: Partial>; - hitMeta: Partial; - }; - calculatedData: Partial>; + composedFrom: { + scorePB: string; + lampPB: string; + other?: PBScoreComposedReference[]; + }; + rankingData: { + rank: integer; + outOf: integer; + }; + userID: integer; + chartID: string; + game: Game; + playtype: Playtypes[Game]; + songID: integer; + comments: string[]; + highlight: boolean; + isPrimary: boolean; + timeAchieved: number | null; + scoreData: { + score: number; + lamp: Lamps[I]; + percent: number; + grade: Grades[I]; + lampIndex: integer; + gradeIndex: integer; + esd: number | null; + hitData: Partial>; + hitMeta: Partial; + }; + calculatedData: Partial>; } export type FileUploadImportTypes = - | "file/eamusement-iidx-csv" - | "file/batch-manual" - | "file/solid-state-squad" - | "file/mer-iidx" - | "file/pli-iidx-csv"; + | "file/eamusement-iidx-csv" + | "file/batch-manual" + | "file/solid-state-squad" + | "file/mer-iidx" + | "file/pli-iidx-csv"; export type APIImportTypes = - | "api/flo-iidx" - | "api/flo-sdvx" - | "api/eag-iidx" - | "api/eag-sdvx" - | "api/arc-iidx" - | "api/arc-sdvx" - | "api/arc-ddr"; + | "api/flo-iidx" + | "api/flo-sdvx" + | "api/eag-iidx" + | "api/eag-sdvx" + | "api/arc-iidx" + | "api/arc-sdvx" + | "api/arc-ddr"; export type IRImportTypes = - | "ir/direct-manual" - | "ir/barbatos" - | "ir/fervidex" - | "ir/usc" - | "ir/chunitachi" - | "ir/beatoraja" - | "ir/fervidex-static"; + | "ir/direct-manual" + | "ir/barbatos" + | "ir/fervidex" + | "ir/usc" + | "ir/chunitachi" + | "ir/beatoraja" + | "ir/fervidex-static"; export type ImportTypes = FileUploadImportTypes | IRImportTypes | APIImportTypes; export interface ImportProcessInfoKTDataNotFound { - success: false; - type: "KTDataNotFound"; - message: string | null; - content: { - data: unknown; - context: unknown; // TEMP - orphanID: string; - }; + success: false; + type: "KTDataNotFound"; + message: string | null; + content: { + data: unknown; + context: unknown; // TEMP + orphanID: string; + }; } export interface ImportProcessInfoOrphanExists { - success: false; - type: "OrphanExists"; - message: string | null; - content: { - orphanID: string; - }; + success: false; + type: "OrphanExists"; + message: string | null; + content: { + orphanID: string; + }; } export interface ImportProcessInfoInvalidDatapoint { - success: false; - type: "InvalidDatapoint"; - message: string | null; - content: { - field?: string; // optional, and probably temp - }; + success: false; + type: "InvalidDatapoint"; + message: string | null; + content: { + field?: string; // optional, and probably temp + }; } export interface ImportProcessInfoScoreImported { - success: true; - type: "ScoreImported"; - message: string | null; - content: { - score: ScoreDocument; - }; + success: true; + type: "ScoreImported"; + message: string | null; + content: { + score: ScoreDocument; + }; } export interface ImportProcessInfoInternalError { - success: false; - type: "InternalError"; - message: string | null; - content: Record; + success: false; + type: "InternalError"; + message: string | null; + content: Record; } export type ImportProcessingInfo = - | ImportProcessInfoKTDataNotFound - | ImportProcessInfoOrphanExists - | ImportProcessInfoScoreImported - | ImportProcessInfoInvalidDatapoint - | ImportProcessInfoInternalError; + | ImportProcessInfoKTDataNotFound + | ImportProcessInfoOrphanExists + | ImportProcessInfoScoreImported + | ImportProcessInfoInvalidDatapoint + | ImportProcessInfoInternalError; export interface IIDXBPIData { - chartID: string; - kavg: integer; - wr: integer; - kesd: number; - coef: number | null; + chartID: string; + kavg: integer; + wr: integer; + kesd: number; + coef: number | null; } export interface ImportStatistics { - scoreCount: integer; - msPerScore: number; - sessionCount: integer; - msPerSession: number; - ratingTime: number; - importID: string; + scoreCount: integer; + msPerScore: number; + sessionCount: integer; + msPerSession: number; + ratingTime: number; + importID: string; } export interface KaiAuthDocument { - userID: integer; - token: string; - refreshToken: string; - service: "FLO" | "EAG"; // MIN might exist at some point. + userID: integer; + token: string; + refreshToken: string; + service: "FLO" | "EAG"; // MIN might exist at some point. } /** * Used to resolve beatoraja IR courses. */ export interface BMSCourseDocument { - title: string; - md5sums: string; - set: "genocideDan" | "stslDan"; - playtype: "7K" | "14K"; - value: integer; + title: string; + md5sums: string; + set: "genocideDan" | "stslDan"; + playtype: "7K" | "14K"; + value: integer; } export type RedisIPCChannels = "class-update" | "goal-achieved" | "milestone-achieved"; export type RedisIPCData = { - "class-update": { - userID: integer; - set: GameClassSets[IDStrings]; - old: integer | null; - new: integer | null; - }; - "goal-achieved": { - userID: integer; - goalID: string; - old: GoalImportStat; - new: GoalImportStat; - }; - "milestone-achieved": { - userID: integer; - milestoneID: string; - old: MilestoneImportStat; - new: MilestoneImportStat; - }; + "class-update": { + userID: integer; + set: GameClassSets[IDStrings]; + old: integer | null; + new: integer | null; + }; + "goal-achieved": { + userID: integer; + goalID: string; + old: GoalImportStat; + new: GoalImportStat; + }; + "milestone-achieved": { + userID: integer; + milestoneID: string; + old: MilestoneImportStat; + new: MilestoneImportStat; + }; }; /** @@ -1371,12 +1371,12 @@ export type APIPermissions = "create:goal" | "manage:goal" | "submit:score"; * Information about the API Token used to make this request. */ export interface APITokenDocument extends MongoDBDocument { - userID: integer | null; - token: string | null; - identifier: string; - permissions: Partial>; + userID: integer | null; + token: string | null; + identifier: string; + permissions: Partial>; } export interface ImportLockDocument extends MongoDBDocument { - userID: integer; + userID: integer; }