osumodcalculator
Version:
osu! calculator for converting values to DT & HT and other things
398 lines (397 loc) • 11.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ToMsOd = ToMsOd;
exports.ToMsAr = ToMsAr;
exports.FromMsOd = FromMsOd;
exports.FromMsAr = FromMsAr;
exports.ToDtAr = ToDtAr;
exports.ToHtAr = ToHtAr;
exports.ToDtOd = ToDtOd;
exports.ToHtOd = ToHtOd;
exports.toHR = toHR;
exports.toEZ = toEZ;
exports.csToRadius = csToRadius;
exports.csFromRadius = csFromRadius;
exports.speed = speed;
exports.modded = modded;
/**
* Get hit windows for an Overall Difficulty (accuracy) value (standard)
*
* @includeExample src/examples/stats.ts:17-22
*/
function ToMsOd(od) {
const rangeobj = {
hitwindow_300: 79 - (od * 6) + 0.5,
hitwindow_100: 139 - (od * 8) + 0.5,
hitwindow_50: 199 - (od * 10) + 0.5,
};
return rangeobj;
}
/**
* convert approach rate to milliseconds
*
* @includeExample src/examples/stats.ts:25
*/
function ToMsAr(ar) {
const ogtoms = ar > 5 ? 1200 - (((ar - 5) * 10) * 15) : 1800 - (((ar) * 10) * 12);
return ogtoms;
}
/**
* convert hit window timings into an Overall Difficulty (accuracy) value
*
* if a hitwindow is missing, either replace it with NaN, null or undefined
*
* @includeExample src/examples/stats.ts:28-34
*/
function FromMsOd(hitwindow300, hitwindow100, hitwindow50) {
let od = 'NaN';
if (!isNaN(hitwindow300)) {
od = ((79.5 - hitwindow300) / 6).toFixed(2);
}
else if (hitwindow100 && !isNaN(hitwindow100)) {
od = ((139.5 - hitwindow100) / 8).toFixed(2);
}
else if (hitwindow50 && !isNaN(hitwindow50)) {
od = ((199.5 - hitwindow50) / 10).toFixed(2);
}
if (+od > 11) {
od = '11';
}
return +od;
}
/**
* calculate approach rate from milliseconds
*
* @includeExample src/examples/stats.ts:37
*/
function FromMsAr(ms) {
let ar;
if (ms < 300) {
ar = 11;
}
else if (ms < 1200) {
ar = Math.round((11 - (ms - 300) / 150) * 100) / 100;
}
else {
ar = Math.round((5 - (ms - 1200) / 120) * 100) / 100;
}
return ar;
}
/**
* calculate approach rate with Double Time applied
*
* @includeExample src/examples/stats.ts:30-34
*/
function ToDtAr(ar) {
/* if (ar > 5) {
ms = 200 + (11 - ar) * 100;
}
else {
ms = 800 + (5 - ar) * 80;
} */
const ogtoms = ar > 5 ? 1200 - ((ar - 5) * 10 * 15) : 1800 - ((ar * 10) * 12);
const ms = ogtoms * (2 / 3);
let newAR;
if (ms < 300) {
newAR = 11;
}
else if (ms < 1200) {
newAR = Math.round((11 - (ms - 300) / 150) * 100) / 100;
}
else {
newAR = Math.round((5 - (ms - 1200) / 120) * 100) / 100;
}
const arobj = {
ar: newAR,
ms: ms,
};
return arobj;
}
/**
* calculate approach rate with Half Time applied
*
* @includeExample src/examples/stats.ts:48-53
*/
function ToHtAr(ar) {
let newAR;
const ogtoms = ar > 5 ? 1200 - ((ar - 5) * 10 * 15) : 1800 - ((ar * 10) * 12);
const ms = ogtoms * (4 / 3);
if (ms < 300) {
newAR = 11;
}
else if (ms < 1200) {
newAR = Math.round((11 - (ms - 300) / 150) * 100) / 100;
}
else {
newAR = Math.round((5 - (ms - 1200) / 120) * 100) / 100;
}
const arobj = {
ar: newAR,
ms: ms,
};
return arobj;
}
/**
* calculate Overall Difficulty (accuracy) with Double Time applied
*
* @includeExample src/examples/stats.ts:56-63
*/
function ToDtOd(od) {
const range300 = ((79 - (od * 6) + 0.5) * 2 / 3) + 0.33;
const odobj = {
hitwindow_300: range300,
hitwindow_100: ((139 - (od * 8) + 0.5) * 2 / 3) + 0.33,
hitwindow_50: ((199 - (od * 10) + 0.5) * 2 / 3) + 0.33,
od: +((79.5 - range300) / 6).toFixed(2) > 11 ? 11 : +((79.5 - range300) / 6)
};
return odobj;
}
/**
* calculate Overall Difficulty (accuracy) with Half Time applied
*
* @includeExample src/examples/stats.ts:66-73
*/
function ToHtOd(od) {
const range300 = ((79 - (od * 6) + 0.5) * 4 / 3) + 0.66;
const odobj = {
hitwindow_300: range300,
hitwindow_100: ((139 - (od * 8) + 0.5) * 4 / 3) + 0.66,
hitwindow_50: ((199 - (od * 10) + 0.5) * 4 / 3) + 0.66,
od: +((79.5 - range300) / 6).toFixed(2) > 11 ? 11 : +((79.5 - range300) / 6)
};
return odobj;
}
/**
* calculate values with hard rock applied
*
* @includeExample src/examples/stats.ts:76-87
*/
function toHR(cs, ar, od, hp) {
const hrobj = {
cs: cs * 1.3 > 10 ? 10 : cs * 1.3,
ar: ar * 1.4 > 10 ? 10 : ar * 1.4,
od: od * 1.4 > 10 ? 10 : od * 1.4,
hp: hp * 1.4 > 10 ? 10 : hp * 1.4,
};
return hrobj;
}
/**
* calculate values with hard rock applied
*
* @includeExample src/examples/stats.ts:90-101
*/
function toEZ(cs, ar, od, hp) {
const ezobj = {
cs: cs / 2 > 10 ? 10 : cs / 2,
ar: ar / 2 > 10 ? 10 : ar / 2,
od: od / 2 > 10 ? 10 : od / 2,
hp: hp / 2 > 10 ? 10 : hp / 2,
};
return ezobj;
}
/**
* get the radius of the circle (in pixels)
*
* @includeExample src/examples/stats.ts:104
*/
function csToRadius(cs) {
return (0.00005556 * cs ** 2 - 4.483 * cs + 54.42);
}
/**
* radius to circle size
*
* @includeExample src/examples/stats.ts:108-109
*/
function csFromRadius(radius) {
return +((5000 / 8104533921) * radius ** 2 - (1808448550 / 8104533921) * radius + (8582285633270972 / 706821088118109)).toFixed(2);
}
/**
* calculate stats with speed applied
*
* @param i - the level of speed to apply.
* Using DT or HT will apply 1.5 and 0.75 speed, respectively.
*
* @includeExample src/examples/stats.ts:112-133
*/
function speed(i, stats) {
if (!i) {
i = 1.0;
}
if (typeof i == 'string') {
switch (i) {
case "DT":
i = 1.5;
break;
case "HT":
i = 0.75;
break;
}
}
const modAr = ToMsAr(stats.ar) / i;
const modOd = ToMsOd(stats.od);
modOd.hitwindow_300 /= i;
modOd.hitwindow_100 /= i;
modOd.hitwindow_50 /= i;
const modBpm = stats.bpm * i;
const modSl = stats.songLength / i;
return {
ar: FromMsAr(modAr),
od: FromMsOd(modOd.hitwindow_300),
bpm: modBpm,
songLength: modSl,
extra: {
arMs: modAr,
odMs: modOd,
lengthReadable: secondsToReadable(modSl),
}
};
}
/**
* calculate values with mods applied
*
* if custom speed is unused then the speed from any given mods will be used (DT, HT etc.)
*
* @includeExample src/examples/stats.ts:136-177
*/
function modded(stats, mods, customSpeed) {
var _a, _b, _c, _d, _e, _f;
if (mods.length == 0) {
if (!customSpeed || customSpeed == 1) {
return {
cs: stats.cs,
ar: stats.ar,
od: stats.od,
hp: stats.hp,
bpm: stats.bpm,
songLength: stats.songLength,
extra: {
csRadius: csToRadius(stats.cs),
arMs: ToMsAr(stats.ar),
odMs: ToMsOd(stats.od),
lengthReadable: secondsToReadable(stats.songLength),
}
};
}
const modAr = ToMsAr(stats.ar) / customSpeed;
const modOd = ToMsOd(stats.od);
modOd.hitwindow_300 /= customSpeed;
modOd.hitwindow_100 /= customSpeed;
modOd.hitwindow_50 /= customSpeed;
const modBpm = stats.bpm * customSpeed;
const modSl = stats.songLength / customSpeed;
return {
cs: stats.cs,
ar: FromMsAr(modAr),
od: FromMsOd(modOd.hitwindow_300),
hp: stats.hp,
bpm: modBpm,
songLength: modSl,
extra: {
csRadius: csToRadius(stats.cs),
arMs: modAr,
odMs: modOd,
lengthReadable: secondsToReadable(modSl),
}
};
}
let modCs = stats.cs;
let modArMs = ToMsAr(stats.ar);
let modOdMs = ToMsOd(stats.od);
let modHp = stats.hp;
let modBpm = stats.bpm;
let modSl = stats.songLength;
if (typeof mods[0] == 'string') {
mods = mods;
if (mods.includes('HR')) {
modCs *= 1.3;
modArMs = ToMsAr(stats.ar * 1.4);
modOdMs = ToMsOd(stats.od * 1.4);
modHp *= 1.4;
}
else if (mods.includes('EZ')) {
modCs /= 2;
modArMs = ToMsAr(stats.ar / 2);
modOdMs = ToMsOd(stats.od / 2);
modHp /= 2;
}
if (!customSpeed) {
if (mods.includes('DT') || mods.includes('NC'))
customSpeed = 1.5;
if (mods.includes('HT') || mods.includes('DC'))
customSpeed = 0.75;
}
}
else {
mods = mods;
const modacrs = mods.map(x => x.acronym);
if (modacrs.includes('HR')) {
modCs *= 1.3;
modArMs = ToMsAr(stats.ar * 1.4);
modOdMs = ToMsOd(stats.od * 1.4);
modHp *= 1.4;
}
else if (modacrs.includes('EZ')) {
modCs /= 2;
modArMs = ToMsAr(stats.ar / 2);
modOdMs = ToMsOd(stats.od / 2);
modHp /= 2;
}
for (const mod of mods) {
if (mod === null || mod === void 0 ? void 0 : mod.settings) {
if ((_a = mod.settings) === null || _a === void 0 ? void 0 : _a.circle_size) {
modCs = mod.settings.circle_size;
}
if ((_b = mod.settings) === null || _b === void 0 ? void 0 : _b.approach_rate) {
modArMs = ToMsAr(mod.settings.approach_rate);
}
if ((_c = mod.settings) === null || _c === void 0 ? void 0 : _c.overall_difficulty) {
modOdMs = ToMsOd(mod.settings.overall_difficulty);
}
if ((_d = mod.settings) === null || _d === void 0 ? void 0 : _d.drain_rate) {
modHp = mod.settings.drain_rate;
}
if ((_e = mod === null || mod === void 0 ? void 0 : mod.settings) === null || _e === void 0 ? void 0 : _e.speed_change) {
customSpeed = (_f = mod === null || mod === void 0 ? void 0 : mod.settings) === null || _f === void 0 ? void 0 : _f.speed_change;
}
}
}
if (!customSpeed) {
if (modacrs.includes('DT') || modacrs.includes('NC'))
customSpeed = 1.5;
if (modacrs.includes('HT') || modacrs.includes('DC'))
customSpeed = 0.75;
}
}
if (customSpeed) {
modArMs /= customSpeed;
modOdMs.hitwindow_300 /= customSpeed;
modOdMs.hitwindow_100 /= customSpeed;
modOdMs.hitwindow_50 /= customSpeed;
modBpm *= customSpeed;
modSl /= customSpeed;
}
return {
cs: modCs,
ar: FromMsAr(modArMs),
od: FromMsOd(modOdMs.hitwindow_300),
hp: modHp,
bpm: modBpm,
songLength: modSl,
extra: {
csRadius: csToRadius(modCs),
arMs: modArMs,
odMs: modOdMs,
lengthReadable: secondsToReadable(modSl),
}
};
}
function secondsToReadable(inpt) {
return inpt > 60 ?
inpt % 60 < 10 ?
Math.floor(inpt / 60) + ':0' + Math.floor(inpt % 60) :
Math.floor(inpt / 60) + ':' + Math.floor(inpt % 60)
:
inpt % 60 < 10 ?
Math.floor(inpt / 60) + ':0' + Math.floor(inpt % 60) :
Math.floor(inpt / 60) + ':' + Math.floor(inpt % 60);
}