UNPKG

osumodcalculator

Version:

osu! calculator for converting values to DT & HT and other things

398 lines (397 loc) 11.8 kB
"use strict"; 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); }