@rian8337/osu-difficulty-calculator 4.0.0-beta.44 → 4.0.0-beta.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +38 -36
- package/package.json +3 -3
- package/typings/index.d.ts +9 -2
package/dist/index.js
CHANGED
|
@@ -1158,8 +1158,9 @@ class DroidRhythmEvaluator {
|
|
|
1158
1158
|
* with historic data of the current object.
|
|
1159
1159
|
*
|
|
1160
1160
|
* @param current The current object.
|
|
1161
|
+
* @param useSliderAccuracy Whether to use slider accuracy.
|
|
1161
1162
|
*/
|
|
1162
|
-
static evaluateDifficultyOf(current) {
|
|
1163
|
+
static evaluateDifficultyOf(current, useSliderAccuracy) {
|
|
1163
1164
|
if (current.object instanceof osuBase.Spinner) {
|
|
1164
1165
|
return 1;
|
|
1165
1166
|
}
|
|
@@ -1221,15 +1222,17 @@ class DroidRhythmEvaluator {
|
|
|
1221
1222
|
island.addDelta(currentDelta);
|
|
1222
1223
|
}
|
|
1223
1224
|
else {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1225
|
+
if (!useSliderAccuracy) {
|
|
1226
|
+
// BPM change is into slider, this is easy acc window.
|
|
1227
|
+
if (currentObject.object instanceof osuBase.Slider) {
|
|
1228
|
+
effectiveRatio /= 8;
|
|
1229
|
+
}
|
|
1230
|
+
// BPM change was from a slider, this is easier typically than circle -> circle.
|
|
1231
|
+
// Unintentional side effect is that bursts with kicksliders at the ends might have lower difficulty
|
|
1232
|
+
// than bursts without sliders.
|
|
1233
|
+
if (prevObject.object instanceof osuBase.Slider) {
|
|
1234
|
+
effectiveRatio *= 0.3;
|
|
1235
|
+
}
|
|
1233
1236
|
}
|
|
1234
1237
|
// Repeated island polarity (2 -> 4, 3 -> 5).
|
|
1235
1238
|
if (island.isSimilarPolarity(previousIsland)) {
|
|
@@ -1312,18 +1315,19 @@ DroidRhythmEvaluator.rhythmRatioMultiplier = 12;
|
|
|
1312
1315
|
* Represents the skill required to properly follow a beatmap's rhythm.
|
|
1313
1316
|
*/
|
|
1314
1317
|
class DroidRhythm extends DroidSkill {
|
|
1315
|
-
constructor() {
|
|
1316
|
-
super(
|
|
1318
|
+
constructor(mods) {
|
|
1319
|
+
super(mods);
|
|
1317
1320
|
this.reducedSectionCount = 5;
|
|
1318
1321
|
this.reducedSectionBaseline = 0.75;
|
|
1319
1322
|
this.strainDecayBase = 0.3;
|
|
1320
1323
|
this.starsPerDouble = 1.75;
|
|
1321
1324
|
this.currentRhythmStrain = 0;
|
|
1322
1325
|
this.currentRhythmMultiplier = 1;
|
|
1326
|
+
this.useSliderAccuracy = mods.some((m) => m instanceof osuBase.ModScoreV2);
|
|
1323
1327
|
}
|
|
1324
1328
|
strainValueAt(current) {
|
|
1325
1329
|
this.currentRhythmMultiplier =
|
|
1326
|
-
DroidRhythmEvaluator.evaluateDifficultyOf(current);
|
|
1330
|
+
DroidRhythmEvaluator.evaluateDifficultyOf(current, this.useSliderAccuracy);
|
|
1327
1331
|
this.currentRhythmStrain *= this.strainDecay(current.deltaTime);
|
|
1328
1332
|
this.currentRhythmStrain += this.currentRhythmMultiplier - 1;
|
|
1329
1333
|
return this.currentRhythmStrain;
|
|
@@ -2103,12 +2107,10 @@ class PerformanceCalculator {
|
|
|
2103
2107
|
* Nerf factor used for nerfing beatmaps with very likely dropped sliderends.
|
|
2104
2108
|
*/
|
|
2105
2109
|
this.sliderNerfFactor = 1;
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
this.difficultyAttributes = osuBase.Utils.deepCopy(difficultyAttributes);
|
|
2111
|
-
}
|
|
2110
|
+
this.difficultyAttributes = difficultyAttributes;
|
|
2111
|
+
this.mods = this.isCacheableAttribute(difficultyAttributes)
|
|
2112
|
+
? osuBase.ModUtil.pcStringToMods(difficultyAttributes.mods)
|
|
2113
|
+
: difficultyAttributes.mods;
|
|
2112
2114
|
}
|
|
2113
2115
|
/**
|
|
2114
2116
|
* Calculates the performance points of the beatmap.
|
|
@@ -2175,15 +2177,15 @@ class PerformanceCalculator {
|
|
|
2175
2177
|
});
|
|
2176
2178
|
}
|
|
2177
2179
|
this.effectiveMissCount = this.calculateEffectiveMissCount(combo, maxCombo);
|
|
2178
|
-
if (this.
|
|
2180
|
+
if (this.mods.some((m) => m instanceof osuBase.ModNoFail)) {
|
|
2179
2181
|
this.finalMultiplier *= Math.max(0.9, 1 - 0.02 * this.effectiveMissCount);
|
|
2180
2182
|
}
|
|
2181
|
-
if (this.
|
|
2183
|
+
if (this.mods.some((m) => m instanceof osuBase.ModSpunOut)) {
|
|
2182
2184
|
this.finalMultiplier *=
|
|
2183
2185
|
1 -
|
|
2184
2186
|
Math.pow(this.difficultyAttributes.spinnerCount / this.totalHits, 0.85);
|
|
2185
2187
|
}
|
|
2186
|
-
if (this.
|
|
2188
|
+
if (this.mods.some((m) => m instanceof osuBase.ModRelax)) {
|
|
2187
2189
|
// Graph: https://www.desmos.com/calculator/bc9eybdthb
|
|
2188
2190
|
// We use OD13.3 as maximum since it's the value at which great hit window becomes 0.
|
|
2189
2191
|
const n100Multiplier = Math.max(0, this.difficultyAttributes.overallDifficulty > 0
|
|
@@ -2512,12 +2514,12 @@ class DroidPerformanceCalculator extends PerformanceCalculator {
|
|
|
2512
2514
|
* Calculates the accuracy performance value of the beatmap.
|
|
2513
2515
|
*/
|
|
2514
2516
|
calculateAccuracyValue() {
|
|
2515
|
-
if (this.
|
|
2517
|
+
if (this.mods.some((m) => m instanceof osuBase.ModRelax) ||
|
|
2516
2518
|
this.totalSuccessfulHits === 0) {
|
|
2517
2519
|
return 0;
|
|
2518
2520
|
}
|
|
2519
2521
|
let accuracyValue = 650 * Math.exp(-0.1 * this._deviation);
|
|
2520
|
-
const ncircles = this.
|
|
2522
|
+
const ncircles = this.mods.some((m) => m instanceof osuBase.ModScoreV2)
|
|
2521
2523
|
? this.totalHits - this.difficultyAttributes.spinnerCount
|
|
2522
2524
|
: this.difficultyAttributes.hitCircleCount;
|
|
2523
2525
|
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer.
|
|
@@ -2529,7 +2531,7 @@ class DroidPerformanceCalculator extends PerformanceCalculator {
|
|
|
2529
2531
|
Math.exp(-(this.difficultyAttributes.rhythmDifficulty - 1) / 2));
|
|
2530
2532
|
// Penalize accuracy pp after the first miss.
|
|
2531
2533
|
accuracyValue *= Math.pow(0.97, Math.max(0, this.effectiveMissCount - 1));
|
|
2532
|
-
if (this.
|
|
2534
|
+
if (this.mods.some((m) => m instanceof osuBase.ModFlashlight)) {
|
|
2533
2535
|
accuracyValue *= 1.02;
|
|
2534
2536
|
}
|
|
2535
2537
|
return accuracyValue;
|
|
@@ -2538,7 +2540,7 @@ class DroidPerformanceCalculator extends PerformanceCalculator {
|
|
|
2538
2540
|
* Calculates the flashlight performance value of the beatmap.
|
|
2539
2541
|
*/
|
|
2540
2542
|
calculateFlashlightValue() {
|
|
2541
|
-
if (!this.
|
|
2543
|
+
if (!this.mods.some((m) => m instanceof osuBase.ModFlashlight)) {
|
|
2542
2544
|
return 0;
|
|
2543
2545
|
}
|
|
2544
2546
|
let flashlightValue = Math.pow(this.difficultyAttributes.flashlightDifficulty, 1.6) * 25;
|
|
@@ -2761,7 +2763,7 @@ class DroidPerformanceCalculator extends PerformanceCalculator {
|
|
|
2761
2763
|
}
|
|
2762
2764
|
getConvertedHitWindow() {
|
|
2763
2765
|
const hitWindow300 = new osuBase.OsuHitWindow(this.difficultyAttributes.overallDifficulty).greatWindow;
|
|
2764
|
-
if (this.
|
|
2766
|
+
if (this.mods.some((m) => m instanceof osuBase.ModPrecise)) {
|
|
2765
2767
|
return new osuBase.PreciseDroidHitWindow(osuBase.PreciseDroidHitWindow.greatWindowToOD(hitWindow300 * this.difficultyAttributes.clockRate));
|
|
2766
2768
|
}
|
|
2767
2769
|
else {
|
|
@@ -3638,7 +3640,7 @@ class OsuPerformanceCalculator extends PerformanceCalculator {
|
|
|
3638
3640
|
aimValue *= lengthBonus;
|
|
3639
3641
|
aimValue *= this.calculateStrainBasedMissPenalty(this.difficultyAttributes.aimDifficultStrainCount);
|
|
3640
3642
|
const calculatedAR = this.difficultyAttributes.approachRate;
|
|
3641
|
-
if (!this.
|
|
3643
|
+
if (!this.mods.some((m) => m instanceof osuBase.ModRelax)) {
|
|
3642
3644
|
// AR scaling
|
|
3643
3645
|
let arFactor = 0;
|
|
3644
3646
|
if (calculatedAR > 10.33) {
|
|
@@ -3651,7 +3653,7 @@ class OsuPerformanceCalculator extends PerformanceCalculator {
|
|
|
3651
3653
|
aimValue *= 1 + arFactor * lengthBonus;
|
|
3652
3654
|
}
|
|
3653
3655
|
// We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR.
|
|
3654
|
-
if (this.
|
|
3656
|
+
if (this.mods.some((m) => m instanceof osuBase.ModHidden)) {
|
|
3655
3657
|
aimValue *= 1 + 0.04 * (12 - calculatedAR);
|
|
3656
3658
|
}
|
|
3657
3659
|
// Scale the aim value with slider factor to nerf very likely dropped sliderends.
|
|
@@ -3667,7 +3669,7 @@ class OsuPerformanceCalculator extends PerformanceCalculator {
|
|
|
3667
3669
|
* Calculates the speed performance value of the beatmap.
|
|
3668
3670
|
*/
|
|
3669
3671
|
calculateSpeedValue() {
|
|
3670
|
-
if (this.
|
|
3672
|
+
if (this.mods.some((m) => m instanceof osuBase.ModRelax)) {
|
|
3671
3673
|
return 0;
|
|
3672
3674
|
}
|
|
3673
3675
|
let speedValue = this.baseValue(this.difficultyAttributes.speedDifficulty);
|
|
@@ -3684,7 +3686,7 @@ class OsuPerformanceCalculator extends PerformanceCalculator {
|
|
|
3684
3686
|
// Buff for longer maps with high AR.
|
|
3685
3687
|
speedValue *= 1 + 0.3 * (calculatedAR - 10.33) * lengthBonus;
|
|
3686
3688
|
}
|
|
3687
|
-
if (this.
|
|
3689
|
+
if (this.mods.some((m) => m instanceof osuBase.ModHidden)) {
|
|
3688
3690
|
speedValue *= 1 + 0.04 * (12 - calculatedAR);
|
|
3689
3691
|
}
|
|
3690
3692
|
// Calculate accuracy assuming the worst case scenario.
|
|
@@ -3717,10 +3719,10 @@ class OsuPerformanceCalculator extends PerformanceCalculator {
|
|
|
3717
3719
|
* Calculates the accuracy performance value of the beatmap.
|
|
3718
3720
|
*/
|
|
3719
3721
|
calculateAccuracyValue() {
|
|
3720
|
-
if (this.
|
|
3722
|
+
if (this.mods.some((m) => m instanceof osuBase.ModRelax)) {
|
|
3721
3723
|
return 0;
|
|
3722
3724
|
}
|
|
3723
|
-
const ncircles = this.
|
|
3725
|
+
const ncircles = this.mods.some((m) => m instanceof osuBase.ModScoreV2)
|
|
3724
3726
|
? this.totalHits - this.difficultyAttributes.spinnerCount
|
|
3725
3727
|
: this.difficultyAttributes.hitCircleCount;
|
|
3726
3728
|
if (ncircles === 0) {
|
|
@@ -3735,10 +3737,10 @@ class OsuPerformanceCalculator extends PerformanceCalculator {
|
|
|
3735
3737
|
2.83;
|
|
3736
3738
|
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
|
|
3737
3739
|
accuracyValue *= Math.min(1.15, Math.pow(ncircles / 1000, 0.3));
|
|
3738
|
-
if (this.
|
|
3740
|
+
if (this.mods.some((m) => m instanceof osuBase.ModHidden)) {
|
|
3739
3741
|
accuracyValue *= 1.08;
|
|
3740
3742
|
}
|
|
3741
|
-
if (this.
|
|
3743
|
+
if (this.mods.some((m) => m instanceof osuBase.ModFlashlight)) {
|
|
3742
3744
|
accuracyValue *= 1.02;
|
|
3743
3745
|
}
|
|
3744
3746
|
return accuracyValue;
|
|
@@ -3747,7 +3749,7 @@ class OsuPerformanceCalculator extends PerformanceCalculator {
|
|
|
3747
3749
|
* Calculates the flashlight performance value of the beatmap.
|
|
3748
3750
|
*/
|
|
3749
3751
|
calculateFlashlightValue() {
|
|
3750
|
-
if (!this.
|
|
3752
|
+
if (!this.mods.some((m) => m instanceof osuBase.ModFlashlight)) {
|
|
3751
3753
|
return 0;
|
|
3752
3754
|
}
|
|
3753
3755
|
let flashlightValue = Math.pow(this.difficultyAttributes.flashlightDifficulty, 2) * 25;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rian8337/osu-difficulty-calculator",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.48",
|
|
4
4
|
"description": "A module for calculating osu!standard beatmap difficulty and performance value with respect to the current difficulty and performance algorithm.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"osu",
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"url": "https://github.com/Rian8337/osu-droid-module/issues"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@rian8337/osu-base": "^4.0.0-beta.
|
|
36
|
+
"@rian8337/osu-base": "^4.0.0-beta.48"
|
|
37
37
|
},
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "da34d3703153595c0314e3a6bb62a0b989bae53a"
|
|
42
42
|
}
|
package/typings/index.d.ts
CHANGED
|
@@ -1006,7 +1006,11 @@ declare abstract class PerformanceCalculator<T extends DifficultyAttributes> {
|
|
|
1006
1006
|
/**
|
|
1007
1007
|
* The difficulty attributes that is being calculated.
|
|
1008
1008
|
*/
|
|
1009
|
-
readonly difficultyAttributes: T
|
|
1009
|
+
readonly difficultyAttributes: T | CacheableDifficultyAttributes<T>;
|
|
1010
|
+
/**
|
|
1011
|
+
* The mods that were used.
|
|
1012
|
+
*/
|
|
1013
|
+
protected readonly mods: Mod[];
|
|
1010
1014
|
/**
|
|
1011
1015
|
* The global multiplier to be applied to the final performance value.
|
|
1012
1016
|
*
|
|
@@ -1254,8 +1258,10 @@ declare class DroidRhythm extends DroidSkill {
|
|
|
1254
1258
|
protected readonly reducedSectionBaseline = 0.75;
|
|
1255
1259
|
protected readonly strainDecayBase = 0.3;
|
|
1256
1260
|
protected readonly starsPerDouble = 1.75;
|
|
1261
|
+
private readonly useSliderAccuracy;
|
|
1257
1262
|
private currentRhythmStrain;
|
|
1258
1263
|
private currentRhythmMultiplier;
|
|
1264
|
+
constructor(mods: Mod[]);
|
|
1259
1265
|
protected strainValueAt(current: DroidDifficultyHitObject): number;
|
|
1260
1266
|
protected calculateInitialStrain(time: number, current: DroidDifficultyHitObject): number;
|
|
1261
1267
|
protected getObjectStrain(): number;
|
|
@@ -1275,8 +1281,9 @@ declare abstract class DroidRhythmEvaluator {
|
|
|
1275
1281
|
* with historic data of the current object.
|
|
1276
1282
|
*
|
|
1277
1283
|
* @param current The current object.
|
|
1284
|
+
* @param useSliderAccuracy Whether to use slider accuracy.
|
|
1278
1285
|
*/
|
|
1279
|
-
static evaluateDifficultyOf(current: DroidDifficultyHitObject): number;
|
|
1286
|
+
static evaluateDifficultyOf(current: DroidDifficultyHitObject, useSliderAccuracy: boolean): number;
|
|
1280
1287
|
}
|
|
1281
1288
|
|
|
1282
1289
|
/**
|