From ba4d924a2f5f47ddc2f7a549c57d3a768473110c Mon Sep 17 00:00:00 2001 From: Gyoo Date: Mon, 23 Sep 2024 15:24:35 +0200 Subject: [PATCH] feat: support exScore, fast, slow, maxCombo as optional metrics for DDR (#1163) * feat: support exScore, fast, slow, maxCombo as optional metrics for DDR * chore: lint-fix in common * fix: remove exScore from calculated metrics for DDR * fix: use clearer logic for number|null --------- Co-authored-by: zkldi <20380519+zkldi@users.noreply.github.com> --- .../components/tables/cells/DDRScoreCell.tsx | 8 +++++++ common/src/config/game-support/ddr.ts | 17 ++++++++++++-- server/src/game-implementations/games/ddr.ts | 22 +++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/client/src/components/tables/cells/DDRScoreCell.tsx b/client/src/components/tables/cells/DDRScoreCell.tsx index 39d4a931f..59954a748 100644 --- a/client/src/components/tables/cells/DDRScoreCell.tsx +++ b/client/src/components/tables/cells/DDRScoreCell.tsx @@ -6,12 +6,14 @@ export default function DDRScoreCell({ score, colour, grade, + exScore, scoreRenderFn, }: { score?: integer; grade: string; colour: string; showScore?: boolean; + exScore?: integer; scoreRenderFn?: (s: number) => string; }) { return ( @@ -23,6 +25,12 @@ export default function DDRScoreCell({ {grade}
{score !== undefined && <>{scoreRenderFn ? scoreRenderFn(score) : score}} + {typeof exScore === "number" && ( + <> +
+ [EX: {exScore}] + + )} ); } diff --git a/common/src/config/game-support/ddr.ts b/common/src/config/game-support/ddr.ts index 497ef1595..99b28b1f1 100644 --- a/common/src/config/game-support/ddr.ts +++ b/common/src/config/game-support/ddr.ts @@ -1,5 +1,5 @@ -import { IIDXDans } from "./iidx"; -import { FmtNum, FmtPercent, FmtScoreNoCommas } from "../../utils/util"; +import { FAST_SLOW_MAXCOMBO } from "./_common"; +import { FmtNum, FmtScoreNoCommas } from "../../utils/util"; import { ClassValue, zodNonNegativeInt } from "../config-utils"; import { p } from "prudence"; import { z } from "zod"; @@ -123,6 +123,19 @@ export const DDR_SP_CONF = { minimumRelevantValue: "0", description: "The Flare rank. If no Flare is provided, Flare 0 is chosen by default.", }, + exScore: { + type: "INTEGER", + formatter: FmtNum, + validate: p.isPositiveInteger, + + // We want to track the best EXScore a user gets, but it is an optional + // metric. + partOfScoreID: true, + + description: + "The EXScore value. Marvelous and O.K. judgements are worth 3 points, Perfect judgements are worth 2 points, Great judgements are worth 1 point, and Good and lower judgements are not worth any points.", + }, + ...FAST_SLOW_MAXCOMBO, }, defaultMetric: "score", diff --git a/server/src/game-implementations/games/ddr.ts b/server/src/game-implementations/games/ddr.ts index 5a14c1cad..174e9c90b 100644 --- a/server/src/game-implementations/games/ddr.ts +++ b/server/src/game-implementations/games/ddr.ts @@ -136,6 +136,25 @@ export const DDR_SCORE_VALIDATORS: Array> = default: } }, + (s) => { + const { MARVELOUS, PERFECT, GREAT, OK } = s.scoreData.judgements; + + if ( + IsNullish(MARVELOUS) || + IsNullish(PERFECT) || + IsNullish(GREAT) || + IsNullish(OK) || + IsNullish(s.scoreData.optional.exScore) + ) { + return; + } + + const calculatedExScore = MARVELOUS * 3 + OK * 3 + PERFECT * 2 + GREAT; + + if (calculatedExScore !== s.scoreData.optional.exScore) { + return `EXScore expected to be ${calculatedExScore} instead of ${s.scoreData.optional.exScore}`; + } + }, ]; export const DDR_IMPL: GPTServerImplementation<"ddr:DP" | "ddr:SP"> = { @@ -255,6 +274,9 @@ export const DDR_IMPL: GPTServerImplementation<"ddr:DP" | "ddr:SP"> = { base.scoreData.score = score.scoreData.score; base.scoreData.grade = score.scoreData.grade; }), + CreatePBMergeFor("largest", "optional.exScore", "Best EX Score", (base, score) => { + base.scoreData.optional.exScore = score.scoreData.optional.exScore; + }), ], profileCalcs: { flareSkill: async (game: Game, playtype: Playtype, userID: integer) => {