rg-stats
Version:
A library for calculating various rhythm game stats.
74 lines • 3.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculate = void 0;
const throw_if_1 = require("../util/throw-if");
const RATING_COEFFICIENTS = new Map([
[1005000, 224],
[1004999, 222],
[1000000, 216],
[999999, 214],
[995000, 211],
[990000, 208],
[989999, 206],
[980000, 203],
[970000, 200],
[969999, 176],
[940000, 168],
[900000, 152],
[800000, 136],
[799999, 128],
[750000, 120],
[700000, 112],
[600000, 96],
[500000, 80],
[400000, 64],
[300000, 48],
[200000, 32],
[100000, 16],
[0, 0],
]);
/**
* Calculate maimai DX Splash+ (and newer) rate for a score.
*
* @param score - The score to calculate the rate for.
* @param internalChartLevel - The internal decimal level of the chart the score was achieved on.
* @param lamp - The lamp for this score. Since maimai DX CiRCLE, there is a 1 rating bonus
* for ALL PERFECT/ALL PERFECT+ scores.
*/
function calculate(score, internalChartLevel, lamp) {
(0, throw_if_1.ThrowIf)(score > 101, "Score cannot be greater than 101%.", { score });
throw_if_1.ThrowIf.negative(score, "Score cannot be negative.", { score });
throw_if_1.ThrowIf.negative(internalChartLevel, "Internal chart level cannot be negative.", {
level: internalChartLevel,
});
(0, throw_if_1.ThrowIf)(lamp === "ALL PERFECT+" && score !== 101, "Cannot have an ALL PERFECT+ without 101%.",
// @ts-expect-error Lamp is "ALL PERFECT+" if the exception is thrown.
{ score, lamp });
(0, throw_if_1.ThrowIf)(score === 101 && lamp !== undefined && lamp !== "ALL PERFECT+", "A score of 101% should be an ALL PERFECT+.",
// @ts-expect-error Lamp is defined if the exception is thrown.
{ score, lamp });
(0, throw_if_1.ThrowIf)(lamp === "ALL PERFECT" && score < 100, "Cannot have an ALL PERFECT without at least 100%.",
// @ts-expect-error Lamp is "ALL PERFECT" if the exception is thrown.
{ score, lamp });
(0, throw_if_1.ThrowIf)(score >= 80 && lamp === "FAILED", "A score of >=80% should not be a FAILED.",
// @ts-expect-error Lamp is "FAILED" if the exception is thrown.
{ score, lamp });
(0, throw_if_1.ThrowIf)(score < 80 && lamp === "CLEAR", // check specifically CLEARs so that sub-80% FCs are still permitted
"A score of <80% should not be a CLEAR.",
// @ts-expect-error Lamp is "CLEAR" if the exception is thrown.
{ score, lamp });
// Scores above 100.5% are capped at 100.5% by the algorithm.
const scoreInt = Math.min(Math.round(score * 10000), 1005000);
const iclInt = Math.round(internalChartLevel * 10);
const bonus = lamp === "ALL PERFECT" || lamp === "ALL PERFECT+" ? 1 : 0;
for (const [scoreBoundary, coefficient] of RATING_COEFFICIENTS) {
if (scoreInt >= scoreBoundary) {
return Math.floor((scoreInt * coefficient * iclInt) / 100000000) + bonus;
}
}
// should be impossible as score cannot be negative and the lowest boundary is >= 0.
/* istanbul ignore next */
throw new Error(`Unresolvable score of ${score}.`);
}
exports.calculate = calculate;
//# sourceMappingURL=maimaidx-rate.js.map