@rian8337/osu-difficulty-calculator 4.0.0-beta.16 → 4.0.0-beta.18
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 +413 -445
- package/package.json +5 -5
- package/typings/index.d.ts +0 -1105
- package/dist/index.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -8,10 +8,6 @@ var osuBase = require('@rian8337/osu-base');
|
|
|
8
8
|
* This class should be considered an "evaluating" class and not persisted.
|
|
9
9
|
*/
|
|
10
10
|
class AimEvaluator {
|
|
11
|
-
static wideAngleMultiplier = 1.5;
|
|
12
|
-
static acuteAngleMultiplier = 1.95;
|
|
13
|
-
static sliderMultiplier = 1.35;
|
|
14
|
-
static velocityChangeMultiplier = 0.75;
|
|
15
11
|
/**
|
|
16
12
|
* Calculates the bonus of wide angles.
|
|
17
13
|
*/
|
|
@@ -27,52 +23,49 @@ class AimEvaluator {
|
|
|
27
23
|
return 1 - this.calculateWideAngleBonus(angle);
|
|
28
24
|
}
|
|
29
25
|
}
|
|
26
|
+
AimEvaluator.wideAngleMultiplier = 1.5;
|
|
27
|
+
AimEvaluator.acuteAngleMultiplier = 1.95;
|
|
28
|
+
AimEvaluator.sliderMultiplier = 1.35;
|
|
29
|
+
AimEvaluator.velocityChangeMultiplier = 0.75;
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* The base of a difficulty calculator.
|
|
33
33
|
*/
|
|
34
34
|
class DifficultyCalculator {
|
|
35
|
-
/**
|
|
36
|
-
* The calculated beatmap.
|
|
37
|
-
*/
|
|
38
|
-
beatmap;
|
|
39
|
-
/**
|
|
40
|
-
* The difficulty objects of the beatmap.
|
|
41
|
-
*/
|
|
42
|
-
objects = [];
|
|
43
|
-
/**
|
|
44
|
-
* The modifications applied.
|
|
45
|
-
*/
|
|
46
|
-
mods = [];
|
|
47
35
|
/**
|
|
48
36
|
* The total star rating of the beatmap.
|
|
49
37
|
*/
|
|
50
38
|
get total() {
|
|
51
39
|
return this.attributes.starRating;
|
|
52
40
|
}
|
|
53
|
-
/**
|
|
54
|
-
* The difficulty statistics of the beatmap after modifications are applied.
|
|
55
|
-
*/
|
|
56
|
-
difficultyStatistics;
|
|
57
|
-
/**
|
|
58
|
-
* The strain peaks of various calculated difficulties.
|
|
59
|
-
*/
|
|
60
|
-
strainPeaks = {
|
|
61
|
-
aimWithSliders: [],
|
|
62
|
-
aimWithoutSliders: [],
|
|
63
|
-
speed: [],
|
|
64
|
-
flashlight: [],
|
|
65
|
-
};
|
|
66
41
|
/**
|
|
67
42
|
* Constructs a new instance of the calculator.
|
|
68
43
|
*
|
|
69
44
|
* @param beatmap The beatmap to calculate. This beatmap will be deep-cloned to prevent reference changes.
|
|
70
45
|
*/
|
|
71
46
|
constructor(beatmap) {
|
|
47
|
+
var _a;
|
|
48
|
+
/**
|
|
49
|
+
* The difficulty objects of the beatmap.
|
|
50
|
+
*/
|
|
51
|
+
this.objects = [];
|
|
52
|
+
/**
|
|
53
|
+
* The modifications applied.
|
|
54
|
+
*/
|
|
55
|
+
this.mods = [];
|
|
56
|
+
/**
|
|
57
|
+
* The strain peaks of various calculated difficulties.
|
|
58
|
+
*/
|
|
59
|
+
this.strainPeaks = {
|
|
60
|
+
aimWithSliders: [],
|
|
61
|
+
aimWithoutSliders: [],
|
|
62
|
+
speed: [],
|
|
63
|
+
flashlight: [],
|
|
64
|
+
};
|
|
72
65
|
this.beatmap = beatmap;
|
|
73
66
|
this.difficultyStatistics = {
|
|
74
67
|
circleSize: beatmap.difficulty.cs,
|
|
75
|
-
approachRate: beatmap.difficulty.ar
|
|
68
|
+
approachRate: (_a = beatmap.difficulty.ar) !== null && _a !== void 0 ? _a : beatmap.difficulty.od,
|
|
76
69
|
overallDifficulty: beatmap.difficulty.od,
|
|
77
70
|
healthDrain: beatmap.difficulty.hp,
|
|
78
71
|
overallSpeedMultiplier: 1,
|
|
@@ -94,11 +87,12 @@ class DifficultyCalculator {
|
|
|
94
87
|
* @returns The current instance.
|
|
95
88
|
*/
|
|
96
89
|
calculate(options) {
|
|
97
|
-
|
|
90
|
+
var _a;
|
|
91
|
+
this.mods = (_a = options === null || options === void 0 ? void 0 : options.mods) !== null && _a !== void 0 ? _a : [];
|
|
98
92
|
const converted = new osuBase.BeatmapConverter(this.beatmap).convert({
|
|
99
93
|
mode: this.mode,
|
|
100
94
|
mods: this.mods,
|
|
101
|
-
customSpeedMultiplier: options
|
|
95
|
+
customSpeedMultiplier: options === null || options === void 0 ? void 0 : options.customSpeedMultiplier,
|
|
102
96
|
});
|
|
103
97
|
this.difficultyStatistics = Object.seal(this.computeDifficultyStatistics(options));
|
|
104
98
|
this.populateDifficultyAttributes();
|
|
@@ -156,91 +150,6 @@ class DifficultyCalculator {
|
|
|
156
150
|
* Represents a hit object with difficulty calculation values.
|
|
157
151
|
*/
|
|
158
152
|
class DifficultyHitObject {
|
|
159
|
-
/**
|
|
160
|
-
* The underlying hitobject.
|
|
161
|
-
*/
|
|
162
|
-
object;
|
|
163
|
-
/**
|
|
164
|
-
* The index of this hitobject in the list of all hitobjects.
|
|
165
|
-
*
|
|
166
|
-
* This is one less than the actual index of the hitobject in the beatmap.
|
|
167
|
-
*/
|
|
168
|
-
index;
|
|
169
|
-
/**
|
|
170
|
-
* The aim strain generated by the hitobject if sliders are considered.
|
|
171
|
-
*/
|
|
172
|
-
aimStrainWithSliders = 0;
|
|
173
|
-
/**
|
|
174
|
-
* The aim strain generated by the hitobject if sliders are not considered.
|
|
175
|
-
*/
|
|
176
|
-
aimStrainWithoutSliders = 0;
|
|
177
|
-
/**
|
|
178
|
-
* The rhythm multiplier generated by the hitobject. This is used to alter tap strain.
|
|
179
|
-
*/
|
|
180
|
-
rhythmMultiplier = 0;
|
|
181
|
-
/**
|
|
182
|
-
* The normalized distance from the "lazy" end position of the previous hitobject to the start position of this hitobject.
|
|
183
|
-
*
|
|
184
|
-
* The "lazy" end position is the position at which the cursor ends up if the previous hitobject is followed with as minimal movement as possible (i.e. on the edge of slider follow circles).
|
|
185
|
-
*/
|
|
186
|
-
lazyJumpDistance = 0;
|
|
187
|
-
/**
|
|
188
|
-
* The normalized shortest distance to consider for a jump between the previous hitobject and this hitobject.
|
|
189
|
-
*
|
|
190
|
-
* This is bounded from above by `lazyJumpDistance`, and is smaller than the former if a more natural path is able to be taken through the previous hitobject.
|
|
191
|
-
*
|
|
192
|
-
* Suppose a linear slider - circle pattern. Following the slider lazily (see: `lazyJumpDistance`) will result in underestimating the true end position of the slider as being closer towards the start position.
|
|
193
|
-
* As a result, `lazyJumpDistance` overestimates the jump distance because the player is able to take a more natural path by following through the slider to its end,
|
|
194
|
-
* such that the jump is felt as only starting from the slider's true end position.
|
|
195
|
-
*
|
|
196
|
-
* Now consider a slider - circle pattern where the circle is stacked along the path inside the slider.
|
|
197
|
-
* In this case, the lazy end position correctly estimates the true end position of the slider and provides the more natural movement path.
|
|
198
|
-
*/
|
|
199
|
-
minimumJumpDistance = 0;
|
|
200
|
-
/**
|
|
201
|
-
* The time taken to travel through `minimumJumpDistance`, with a minimum value of 25ms.
|
|
202
|
-
*/
|
|
203
|
-
minimumJumpTime = 0;
|
|
204
|
-
/**
|
|
205
|
-
* The normalized distance between the start and end position of this hitobject.
|
|
206
|
-
*/
|
|
207
|
-
travelDistance = 0;
|
|
208
|
-
/**
|
|
209
|
-
* The time taken to travel through `travelDistance`, with a minimum value of 25ms for sliders.
|
|
210
|
-
*/
|
|
211
|
-
travelTime = 0;
|
|
212
|
-
/**
|
|
213
|
-
* Angle the player has to take to hit this hitobject.
|
|
214
|
-
*
|
|
215
|
-
* Calculated as the angle between the circles (current-2, current-1, current).
|
|
216
|
-
*/
|
|
217
|
-
angle = null;
|
|
218
|
-
/**
|
|
219
|
-
* The amount of milliseconds elapsed between this hitobject and the last hitobject.
|
|
220
|
-
*/
|
|
221
|
-
deltaTime;
|
|
222
|
-
/**
|
|
223
|
-
* The amount of milliseconds elapsed since the start time of the previous hitobject, with a minimum of 25ms.
|
|
224
|
-
*/
|
|
225
|
-
strainTime;
|
|
226
|
-
/**
|
|
227
|
-
* Adjusted start time of the hitobject, taking speed multiplier into account.
|
|
228
|
-
*/
|
|
229
|
-
startTime;
|
|
230
|
-
/**
|
|
231
|
-
* Adjusted end time of the hitobject, taking speed multiplier into account.
|
|
232
|
-
*/
|
|
233
|
-
endTime;
|
|
234
|
-
/**
|
|
235
|
-
* Other hitobjects in the beatmap, including this hitobject.
|
|
236
|
-
*/
|
|
237
|
-
hitObjects;
|
|
238
|
-
normalizedRadius = 50;
|
|
239
|
-
maximumSliderRadius = this.normalizedRadius * 2.4;
|
|
240
|
-
assumedSliderRadius = this.normalizedRadius * 1.8;
|
|
241
|
-
minDeltaTime = 25;
|
|
242
|
-
lastObject;
|
|
243
|
-
lastLastObject;
|
|
244
153
|
/**
|
|
245
154
|
* Note: You **must** call `computeProperties` at some point due to how TypeScript handles
|
|
246
155
|
* overridden properties (see [this](https://github.com/microsoft/TypeScript/issues/1617) GitHub issue.).
|
|
@@ -255,6 +164,59 @@ class DifficultyHitObject {
|
|
|
255
164
|
* @param mode The gamemode to compute properties for.
|
|
256
165
|
*/
|
|
257
166
|
constructor(object, lastObject, lastLastObject, difficultyHitObjects, clockRate) {
|
|
167
|
+
/**
|
|
168
|
+
* The aim strain generated by the hitobject if sliders are considered.
|
|
169
|
+
*/
|
|
170
|
+
this.aimStrainWithSliders = 0;
|
|
171
|
+
/**
|
|
172
|
+
* The aim strain generated by the hitobject if sliders are not considered.
|
|
173
|
+
*/
|
|
174
|
+
this.aimStrainWithoutSliders = 0;
|
|
175
|
+
/**
|
|
176
|
+
* The rhythm multiplier generated by the hitobject. This is used to alter tap strain.
|
|
177
|
+
*/
|
|
178
|
+
this.rhythmMultiplier = 0;
|
|
179
|
+
/**
|
|
180
|
+
* The normalized distance from the "lazy" end position of the previous hitobject to the start position of this hitobject.
|
|
181
|
+
*
|
|
182
|
+
* The "lazy" end position is the position at which the cursor ends up if the previous hitobject is followed with as minimal movement as possible (i.e. on the edge of slider follow circles).
|
|
183
|
+
*/
|
|
184
|
+
this.lazyJumpDistance = 0;
|
|
185
|
+
/**
|
|
186
|
+
* The normalized shortest distance to consider for a jump between the previous hitobject and this hitobject.
|
|
187
|
+
*
|
|
188
|
+
* This is bounded from above by `lazyJumpDistance`, and is smaller than the former if a more natural path is able to be taken through the previous hitobject.
|
|
189
|
+
*
|
|
190
|
+
* Suppose a linear slider - circle pattern. Following the slider lazily (see: `lazyJumpDistance`) will result in underestimating the true end position of the slider as being closer towards the start position.
|
|
191
|
+
* As a result, `lazyJumpDistance` overestimates the jump distance because the player is able to take a more natural path by following through the slider to its end,
|
|
192
|
+
* such that the jump is felt as only starting from the slider's true end position.
|
|
193
|
+
*
|
|
194
|
+
* Now consider a slider - circle pattern where the circle is stacked along the path inside the slider.
|
|
195
|
+
* In this case, the lazy end position correctly estimates the true end position of the slider and provides the more natural movement path.
|
|
196
|
+
*/
|
|
197
|
+
this.minimumJumpDistance = 0;
|
|
198
|
+
/**
|
|
199
|
+
* The time taken to travel through `minimumJumpDistance`, with a minimum value of 25ms.
|
|
200
|
+
*/
|
|
201
|
+
this.minimumJumpTime = 0;
|
|
202
|
+
/**
|
|
203
|
+
* The normalized distance between the start and end position of this hitobject.
|
|
204
|
+
*/
|
|
205
|
+
this.travelDistance = 0;
|
|
206
|
+
/**
|
|
207
|
+
* The time taken to travel through `travelDistance`, with a minimum value of 25ms for sliders.
|
|
208
|
+
*/
|
|
209
|
+
this.travelTime = 0;
|
|
210
|
+
/**
|
|
211
|
+
* Angle the player has to take to hit this hitobject.
|
|
212
|
+
*
|
|
213
|
+
* Calculated as the angle between the circles (current-2, current-1, current).
|
|
214
|
+
*/
|
|
215
|
+
this.angle = null;
|
|
216
|
+
this.normalizedRadius = 50;
|
|
217
|
+
this.maximumSliderRadius = this.normalizedRadius * 2.4;
|
|
218
|
+
this.assumedSliderRadius = this.normalizedRadius * 1.8;
|
|
219
|
+
this.minDeltaTime = 25;
|
|
258
220
|
this.object = object;
|
|
259
221
|
this.lastObject = lastObject;
|
|
260
222
|
this.lastLastObject = lastLastObject;
|
|
@@ -295,7 +257,8 @@ class DifficultyHitObject {
|
|
|
295
257
|
* difficulty hitobject's index, `null` if the index is out of range.
|
|
296
258
|
*/
|
|
297
259
|
previous(backwardsIndex) {
|
|
298
|
-
|
|
260
|
+
var _a;
|
|
261
|
+
return (_a = this.hitObjects[this.index - backwardsIndex]) !== null && _a !== void 0 ? _a : null;
|
|
299
262
|
}
|
|
300
263
|
/**
|
|
301
264
|
* Gets the difficulty hitobject at a specific index with respect to the current
|
|
@@ -308,7 +271,8 @@ class DifficultyHitObject {
|
|
|
308
271
|
* difficulty hitobject's index, `null` if the index is out of range.
|
|
309
272
|
*/
|
|
310
273
|
next(forwardsIndex) {
|
|
311
|
-
|
|
274
|
+
var _a;
|
|
275
|
+
return ((_a = this.hitObjects[this.index + forwardsIndex + 2]) !== null && _a !== void 0 ? _a : null);
|
|
312
276
|
}
|
|
313
277
|
/**
|
|
314
278
|
* Calculates the opacity of the hitobject at a given time.
|
|
@@ -461,10 +425,11 @@ class DifficultyHitObject {
|
|
|
461
425
|
}
|
|
462
426
|
}
|
|
463
427
|
getEndCursorPosition(object) {
|
|
428
|
+
var _a;
|
|
464
429
|
let pos = object.getStackedPosition(this.mode);
|
|
465
430
|
if (object instanceof osuBase.Slider) {
|
|
466
431
|
this.calculateSliderCursorPosition(object);
|
|
467
|
-
pos = object.lazyEndPosition
|
|
432
|
+
pos = (_a = object.lazyEndPosition) !== null && _a !== void 0 ? _a : pos;
|
|
468
433
|
}
|
|
469
434
|
return pos;
|
|
470
435
|
}
|
|
@@ -474,12 +439,6 @@ class DifficultyHitObject {
|
|
|
474
439
|
* An evaluator for calculating osu!droid Aim skill.
|
|
475
440
|
*/
|
|
476
441
|
class DroidAimEvaluator extends AimEvaluator {
|
|
477
|
-
static wideAngleMultiplier = 1.65;
|
|
478
|
-
static sliderMultiplier = 1.5;
|
|
479
|
-
static velocityChangeMultiplier = 0.85;
|
|
480
|
-
static singleSpacingThreshold = 100;
|
|
481
|
-
// 200 1/4 BPM delta time
|
|
482
|
-
static minSpeedBonus = 75;
|
|
483
442
|
/**
|
|
484
443
|
* Evaluates the difficulty of aiming the current object, based on:
|
|
485
444
|
*
|
|
@@ -504,8 +463,9 @@ class DroidAimEvaluator extends AimEvaluator {
|
|
|
504
463
|
* Calculates the snap aim strain of a hitobject.
|
|
505
464
|
*/
|
|
506
465
|
static snapAimStrainOf(current, withSliders) {
|
|
466
|
+
var _a;
|
|
507
467
|
if (current.index <= 1 ||
|
|
508
|
-
current.previous(0)
|
|
468
|
+
((_a = current.previous(0)) === null || _a === void 0 ? void 0 : _a.object) instanceof osuBase.Spinner) {
|
|
509
469
|
return 0;
|
|
510
470
|
}
|
|
511
471
|
const last = current.previous(0);
|
|
@@ -616,17 +576,24 @@ class DroidAimEvaluator extends AimEvaluator {
|
|
|
616
576
|
* Calculates the flow aim strain of a hitobject.
|
|
617
577
|
*/
|
|
618
578
|
static flowAimStrainOf(current) {
|
|
579
|
+
var _a, _b;
|
|
619
580
|
let speedBonus = 1;
|
|
620
581
|
if (current.strainTime < this.minSpeedBonus) {
|
|
621
582
|
speedBonus +=
|
|
622
583
|
0.75 *
|
|
623
584
|
Math.pow((this.minSpeedBonus - current.strainTime) / 40, 2);
|
|
624
585
|
}
|
|
625
|
-
const travelDistance = current.previous(0)
|
|
586
|
+
const travelDistance = (_b = (_a = current.previous(0)) === null || _a === void 0 ? void 0 : _a.travelDistance) !== null && _b !== void 0 ? _b : 0;
|
|
626
587
|
const shortDistancePenalty = Math.pow(Math.min(this.singleSpacingThreshold, travelDistance + current.minimumJumpDistance) / this.singleSpacingThreshold, 3.5);
|
|
627
588
|
return (200 * speedBonus * shortDistancePenalty) / current.strainTime;
|
|
628
589
|
}
|
|
629
590
|
}
|
|
591
|
+
DroidAimEvaluator.wideAngleMultiplier = 1.65;
|
|
592
|
+
DroidAimEvaluator.sliderMultiplier = 1.5;
|
|
593
|
+
DroidAimEvaluator.velocityChangeMultiplier = 0.85;
|
|
594
|
+
DroidAimEvaluator.singleSpacingThreshold = 100;
|
|
595
|
+
// 200 1/4 BPM delta time
|
|
596
|
+
DroidAimEvaluator.minSpeedBonus = 75;
|
|
630
597
|
|
|
631
598
|
/**
|
|
632
599
|
* A bare minimal abstract skill for fully custom skill implementations.
|
|
@@ -634,10 +601,6 @@ class DroidAimEvaluator extends AimEvaluator {
|
|
|
634
601
|
* This class should be considered a "processing" class and not persisted.
|
|
635
602
|
*/
|
|
636
603
|
class Skill {
|
|
637
|
-
/**
|
|
638
|
-
* The mods that this skill processes.
|
|
639
|
-
*/
|
|
640
|
-
mods;
|
|
641
604
|
constructor(mods) {
|
|
642
605
|
this.mods = mods;
|
|
643
606
|
}
|
|
@@ -648,14 +611,17 @@ class Skill {
|
|
|
648
611
|
* and to calculate a final difficulty value representing the difficulty of hitting all the processed objects.
|
|
649
612
|
*/
|
|
650
613
|
class StrainSkill extends Skill {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
614
|
+
constructor() {
|
|
615
|
+
super(...arguments);
|
|
616
|
+
/**
|
|
617
|
+
* Strain peaks are stored here.
|
|
618
|
+
*/
|
|
619
|
+
this.strainPeaks = [];
|
|
620
|
+
this.sectionLength = 400;
|
|
621
|
+
this.currentStrain = 0;
|
|
622
|
+
this.currentSectionPeak = 0;
|
|
623
|
+
this.currentSectionEnd = 0;
|
|
624
|
+
}
|
|
659
625
|
process(current) {
|
|
660
626
|
// The first object doesn't generate a strain, so we begin with an incremented section end
|
|
661
627
|
if (current.index === 0) {
|
|
@@ -734,15 +700,14 @@ class DroidSkill extends StrainSkill {
|
|
|
734
700
|
* Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
|
|
735
701
|
*/
|
|
736
702
|
class DroidAim extends DroidSkill {
|
|
737
|
-
strainDecayBase = 0.15;
|
|
738
|
-
reducedSectionCount = 10;
|
|
739
|
-
reducedSectionBaseline = 0.75;
|
|
740
|
-
starsPerDouble = 1.05;
|
|
741
|
-
skillMultiplier = 24.55;
|
|
742
|
-
withSliders;
|
|
743
|
-
currentAimStrain = 0;
|
|
744
703
|
constructor(mods, withSliders) {
|
|
745
704
|
super(mods);
|
|
705
|
+
this.strainDecayBase = 0.15;
|
|
706
|
+
this.reducedSectionCount = 10;
|
|
707
|
+
this.reducedSectionBaseline = 0.75;
|
|
708
|
+
this.starsPerDouble = 1.05;
|
|
709
|
+
this.skillMultiplier = 24.55;
|
|
710
|
+
this.currentAimStrain = 0;
|
|
746
711
|
this.withSliders = withSliders;
|
|
747
712
|
}
|
|
748
713
|
strainValueAt(current) {
|
|
@@ -753,8 +718,9 @@ class DroidAim extends DroidSkill {
|
|
|
753
718
|
return this.currentAimStrain;
|
|
754
719
|
}
|
|
755
720
|
calculateInitialStrain(time, current) {
|
|
721
|
+
var _a, _b;
|
|
756
722
|
return (this.currentAimStrain *
|
|
757
|
-
this.strainDecay(time - (current.previous(0)
|
|
723
|
+
this.strainDecay(time - ((_b = (_a = current.previous(0)) === null || _a === void 0 ? void 0 : _a.startTime) !== null && _b !== void 0 ? _b : 0)));
|
|
758
724
|
}
|
|
759
725
|
/**
|
|
760
726
|
* @param current The hitobject to save to.
|
|
@@ -775,9 +741,9 @@ class DroidAim extends DroidSkill {
|
|
|
775
741
|
* This class should be considered an "evaluating" class and not persisted.
|
|
776
742
|
*/
|
|
777
743
|
class SpeedEvaluator {
|
|
778
|
-
// ~200 1/4 BPM streams
|
|
779
|
-
static minSpeedBonus = 75;
|
|
780
744
|
}
|
|
745
|
+
// ~200 1/4 BPM streams
|
|
746
|
+
SpeedEvaluator.minSpeedBonus = 75;
|
|
781
747
|
|
|
782
748
|
/**
|
|
783
749
|
* An evaluator for calculating osu!droid tap skill.
|
|
@@ -829,17 +795,15 @@ class DroidTapEvaluator extends SpeedEvaluator {
|
|
|
829
795
|
* Represents the skill required to press keys or tap with regards to keeping up with the speed at which objects need to be hit.
|
|
830
796
|
*/
|
|
831
797
|
class DroidTap extends DroidSkill {
|
|
832
|
-
reducedSectionCount = 10;
|
|
833
|
-
reducedSectionBaseline = 0.75;
|
|
834
|
-
strainDecayBase = 0.3;
|
|
835
|
-
starsPerDouble = 1.1;
|
|
836
|
-
currentTapStrain = 0;
|
|
837
|
-
currentRhythmMultiplier = 0;
|
|
838
|
-
skillMultiplier = 1375;
|
|
839
|
-
greatWindow;
|
|
840
|
-
considerCheesability;
|
|
841
798
|
constructor(mods, overallDifficulty, considerCheesability) {
|
|
842
799
|
super(mods);
|
|
800
|
+
this.reducedSectionCount = 10;
|
|
801
|
+
this.reducedSectionBaseline = 0.75;
|
|
802
|
+
this.strainDecayBase = 0.3;
|
|
803
|
+
this.starsPerDouble = 1.1;
|
|
804
|
+
this.currentTapStrain = 0;
|
|
805
|
+
this.currentRhythmMultiplier = 0;
|
|
806
|
+
this.skillMultiplier = 1375;
|
|
843
807
|
this.greatWindow = new osuBase.OsuHitWindow(overallDifficulty).hitWindowFor300();
|
|
844
808
|
this.considerCheesability = considerCheesability;
|
|
845
809
|
}
|
|
@@ -852,9 +816,10 @@ class DroidTap extends DroidSkill {
|
|
|
852
816
|
return this.currentTapStrain * current.rhythmMultiplier;
|
|
853
817
|
}
|
|
854
818
|
calculateInitialStrain(time, current) {
|
|
819
|
+
var _a, _b;
|
|
855
820
|
return (this.currentTapStrain *
|
|
856
821
|
this.currentRhythmMultiplier *
|
|
857
|
-
this.strainDecay(time - (current.previous(0)
|
|
822
|
+
this.strainDecay(time - ((_b = (_a = current.previous(0)) === null || _a === void 0 ? void 0 : _a.startTime) !== null && _b !== void 0 ? _b : 0)));
|
|
858
823
|
}
|
|
859
824
|
/**
|
|
860
825
|
* @param current The hitobject to save to.
|
|
@@ -876,12 +841,12 @@ class DroidTap extends DroidSkill {
|
|
|
876
841
|
* This class should be considered an "evaluating" class and not persisted.
|
|
877
842
|
*/
|
|
878
843
|
class FlashlightEvaluator {
|
|
879
|
-
static maxOpacityBonus = 0.4;
|
|
880
|
-
static hiddenBonus = 0.2;
|
|
881
|
-
static minVelocity = 0.5;
|
|
882
|
-
static sliderMultiplier = 1.3;
|
|
883
|
-
static minAngleMultiplier = 0.2;
|
|
884
844
|
}
|
|
845
|
+
FlashlightEvaluator.maxOpacityBonus = 0.4;
|
|
846
|
+
FlashlightEvaluator.hiddenBonus = 0.2;
|
|
847
|
+
FlashlightEvaluator.minVelocity = 0.5;
|
|
848
|
+
FlashlightEvaluator.sliderMultiplier = 1.3;
|
|
849
|
+
FlashlightEvaluator.minAngleMultiplier = 0.2;
|
|
885
850
|
|
|
886
851
|
/**
|
|
887
852
|
* An evaluator for calculating osu!droid Flashlight skill.
|
|
@@ -974,16 +939,14 @@ class DroidFlashlightEvaluator extends FlashlightEvaluator {
|
|
|
974
939
|
* Represents the skill required to memorize and hit every object in a beatmap with the Flashlight mod enabled.
|
|
975
940
|
*/
|
|
976
941
|
class DroidFlashlight extends DroidSkill {
|
|
977
|
-
strainDecayBase = 0.15;
|
|
978
|
-
reducedSectionCount = 0;
|
|
979
|
-
reducedSectionBaseline = 1;
|
|
980
|
-
starsPerDouble = 1.06;
|
|
981
|
-
skillMultiplier = 0.052;
|
|
982
|
-
isHidden;
|
|
983
|
-
withSliders;
|
|
984
|
-
currentFlashlightStrain = 0;
|
|
985
942
|
constructor(mods, withSliders) {
|
|
986
943
|
super(mods);
|
|
944
|
+
this.strainDecayBase = 0.15;
|
|
945
|
+
this.reducedSectionCount = 0;
|
|
946
|
+
this.reducedSectionBaseline = 1;
|
|
947
|
+
this.starsPerDouble = 1.06;
|
|
948
|
+
this.skillMultiplier = 0.052;
|
|
949
|
+
this.currentFlashlightStrain = 0;
|
|
987
950
|
this.isHidden = mods.some((m) => m instanceof osuBase.ModHidden);
|
|
988
951
|
this.withSliders = withSliders;
|
|
989
952
|
}
|
|
@@ -994,8 +957,9 @@ class DroidFlashlight extends DroidSkill {
|
|
|
994
957
|
return this.currentFlashlightStrain;
|
|
995
958
|
}
|
|
996
959
|
calculateInitialStrain(time, current) {
|
|
960
|
+
var _a, _b;
|
|
997
961
|
return (this.currentFlashlightStrain *
|
|
998
|
-
this.strainDecay(time - (current.previous(0)
|
|
962
|
+
this.strainDecay(time - ((_b = (_a = current.previous(0)) === null || _a === void 0 ? void 0 : _a.startTime) !== null && _b !== void 0 ? _b : 0)));
|
|
999
963
|
}
|
|
1000
964
|
saveToHitObject(current) {
|
|
1001
965
|
if (this.withSliders) {
|
|
@@ -1017,9 +981,9 @@ class DroidFlashlight extends DroidSkill {
|
|
|
1017
981
|
* This class should be considered an "evaluating" class and not persisted.
|
|
1018
982
|
*/
|
|
1019
983
|
class RhythmEvaluator {
|
|
1020
|
-
static rhythmMultiplier = 0.75;
|
|
1021
|
-
static historyTimeMax = 5000; // 5 seconds of calculateRhythmBonus max.
|
|
1022
984
|
}
|
|
985
|
+
RhythmEvaluator.rhythmMultiplier = 0.75;
|
|
986
|
+
RhythmEvaluator.historyTimeMax = 5000; // 5 seconds of calculateRhythmBonus max.
|
|
1023
987
|
|
|
1024
988
|
/**
|
|
1025
989
|
* An evaluator for calculating osu!droid Rhythm skill.
|
|
@@ -1155,15 +1119,14 @@ class DroidRhythmEvaluator extends RhythmEvaluator {
|
|
|
1155
1119
|
* Represents the skill required to properly follow a beatmap's rhythm.
|
|
1156
1120
|
*/
|
|
1157
1121
|
class DroidRhythm extends DroidSkill {
|
|
1158
|
-
reducedSectionCount = 5;
|
|
1159
|
-
reducedSectionBaseline = 0.75;
|
|
1160
|
-
strainDecayBase = 0.3;
|
|
1161
|
-
starsPerDouble = 1.75;
|
|
1162
|
-
currentRhythmStrain = 0;
|
|
1163
|
-
currentRhythmMultiplier = 1;
|
|
1164
|
-
hitWindow;
|
|
1165
1122
|
constructor(mods, overallDifficulty) {
|
|
1166
1123
|
super(mods);
|
|
1124
|
+
this.reducedSectionCount = 5;
|
|
1125
|
+
this.reducedSectionBaseline = 0.75;
|
|
1126
|
+
this.strainDecayBase = 0.3;
|
|
1127
|
+
this.starsPerDouble = 1.75;
|
|
1128
|
+
this.currentRhythmStrain = 0;
|
|
1129
|
+
this.currentRhythmMultiplier = 1;
|
|
1167
1130
|
this.hitWindow = new osuBase.OsuHitWindow(overallDifficulty);
|
|
1168
1131
|
}
|
|
1169
1132
|
strainValueAt(current) {
|
|
@@ -1174,8 +1137,9 @@ class DroidRhythm extends DroidSkill {
|
|
|
1174
1137
|
return this.currentRhythmStrain;
|
|
1175
1138
|
}
|
|
1176
1139
|
calculateInitialStrain(time, current) {
|
|
1140
|
+
var _a, _b;
|
|
1177
1141
|
return (this.currentRhythmStrain *
|
|
1178
|
-
this.strainDecay(time - (current.previous(0)
|
|
1142
|
+
this.strainDecay(time - ((_b = (_a = current.previous(0)) === null || _a === void 0 ? void 0 : _a.startTime) !== null && _b !== void 0 ? _b : 0)));
|
|
1179
1143
|
}
|
|
1180
1144
|
saveToHitObject(current) {
|
|
1181
1145
|
current.rhythmStrain = this.currentRhythmStrain;
|
|
@@ -1283,17 +1247,15 @@ class DroidVisualEvaluator {
|
|
|
1283
1247
|
* Represents the skill required to read every object in the map.
|
|
1284
1248
|
*/
|
|
1285
1249
|
class DroidVisual extends DroidSkill {
|
|
1286
|
-
starsPerDouble = 1.025;
|
|
1287
|
-
reducedSectionCount = 10;
|
|
1288
|
-
reducedSectionBaseline = 0.75;
|
|
1289
|
-
strainDecayBase = 0.1;
|
|
1290
|
-
isHidden;
|
|
1291
|
-
withSliders;
|
|
1292
|
-
currentVisualStrain = 0;
|
|
1293
|
-
currentRhythmMultiplier = 1;
|
|
1294
|
-
skillMultiplier = 10;
|
|
1295
1250
|
constructor(mods, withSliders) {
|
|
1296
1251
|
super(mods);
|
|
1252
|
+
this.starsPerDouble = 1.025;
|
|
1253
|
+
this.reducedSectionCount = 10;
|
|
1254
|
+
this.reducedSectionBaseline = 0.75;
|
|
1255
|
+
this.strainDecayBase = 0.1;
|
|
1256
|
+
this.currentVisualStrain = 0;
|
|
1257
|
+
this.currentRhythmMultiplier = 1;
|
|
1258
|
+
this.skillMultiplier = 10;
|
|
1297
1259
|
this.isHidden = mods.some((m) => m instanceof osuBase.ModHidden);
|
|
1298
1260
|
this.withSliders = withSliders;
|
|
1299
1261
|
}
|
|
@@ -1305,9 +1267,10 @@ class DroidVisual extends DroidSkill {
|
|
|
1305
1267
|
return this.currentVisualStrain * this.currentRhythmMultiplier;
|
|
1306
1268
|
}
|
|
1307
1269
|
calculateInitialStrain(time, current) {
|
|
1270
|
+
var _a, _b;
|
|
1308
1271
|
return (this.currentVisualStrain *
|
|
1309
1272
|
this.currentRhythmMultiplier *
|
|
1310
|
-
this.strainDecay(time - (current.previous(0)
|
|
1273
|
+
this.strainDecay(time - ((_b = (_a = current.previous(0)) === null || _a === void 0 ? void 0 : _a.startTime) !== null && _b !== void 0 ? _b : 0)));
|
|
1311
1274
|
}
|
|
1312
1275
|
saveToHitObject(current) {
|
|
1313
1276
|
const strain = this.currentVisualStrain * this.currentRhythmMultiplier;
|
|
@@ -1324,52 +1287,6 @@ class DroidVisual extends DroidSkill {
|
|
|
1324
1287
|
* Represents an osu!droid hit object with difficulty calculation values.
|
|
1325
1288
|
*/
|
|
1326
1289
|
class DroidDifficultyHitObject extends DifficultyHitObject {
|
|
1327
|
-
/**
|
|
1328
|
-
* The tap strain generated by the hitobject.
|
|
1329
|
-
*/
|
|
1330
|
-
tapStrain = 0;
|
|
1331
|
-
/**
|
|
1332
|
-
* The tap strain generated by the hitobject if `strainTime` isn't modified by
|
|
1333
|
-
* OD. This is used in three-finger detection.
|
|
1334
|
-
*/
|
|
1335
|
-
originalTapStrain = 0;
|
|
1336
|
-
/**
|
|
1337
|
-
* The rhythm strain generated by the hitobject.
|
|
1338
|
-
*/
|
|
1339
|
-
rhythmStrain = 0;
|
|
1340
|
-
/**
|
|
1341
|
-
* The flashlight strain generated by the hitobject if sliders are considered.
|
|
1342
|
-
*/
|
|
1343
|
-
flashlightStrainWithSliders = 0;
|
|
1344
|
-
/**
|
|
1345
|
-
* The flashlight strain generated by the hitobject if sliders are not considered.
|
|
1346
|
-
*/
|
|
1347
|
-
flashlightStrainWithoutSliders = 0;
|
|
1348
|
-
/**
|
|
1349
|
-
* The visual strain generated by the hitobject if sliders are considered.
|
|
1350
|
-
*/
|
|
1351
|
-
visualStrainWithSliders = 0;
|
|
1352
|
-
/**
|
|
1353
|
-
* The visual strain generated by the hitobject if sliders are not considered.
|
|
1354
|
-
*/
|
|
1355
|
-
visualStrainWithoutSliders = 0;
|
|
1356
|
-
/**
|
|
1357
|
-
* The note density of the hitobject.
|
|
1358
|
-
*/
|
|
1359
|
-
noteDensity = 1;
|
|
1360
|
-
/**
|
|
1361
|
-
* The overlapping factor of the hitobject.
|
|
1362
|
-
*
|
|
1363
|
-
* This is used to scale visual skill.
|
|
1364
|
-
*/
|
|
1365
|
-
overlappingFactor = 0;
|
|
1366
|
-
/**
|
|
1367
|
-
* Adjusted preempt time of the hitobject, taking speed multiplier into account.
|
|
1368
|
-
*/
|
|
1369
|
-
timePreempt;
|
|
1370
|
-
radiusBuffThreshold = 70;
|
|
1371
|
-
mode = osuBase.Modes.droid;
|
|
1372
|
-
maximumSliderRadius = this.normalizedRadius * 2;
|
|
1373
1290
|
get scalingFactor() {
|
|
1374
1291
|
const radius = this.object.radius;
|
|
1375
1292
|
// We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps.
|
|
@@ -1394,6 +1311,48 @@ class DroidDifficultyHitObject extends DifficultyHitObject {
|
|
|
1394
1311
|
*/
|
|
1395
1312
|
constructor(object, lastObject, lastLastObject, difficultyHitObjects, clockRate, isForceAR) {
|
|
1396
1313
|
super(object, lastObject, lastLastObject, difficultyHitObjects, clockRate);
|
|
1314
|
+
/**
|
|
1315
|
+
* The tap strain generated by the hitobject.
|
|
1316
|
+
*/
|
|
1317
|
+
this.tapStrain = 0;
|
|
1318
|
+
/**
|
|
1319
|
+
* The tap strain generated by the hitobject if `strainTime` isn't modified by
|
|
1320
|
+
* OD. This is used in three-finger detection.
|
|
1321
|
+
*/
|
|
1322
|
+
this.originalTapStrain = 0;
|
|
1323
|
+
/**
|
|
1324
|
+
* The rhythm strain generated by the hitobject.
|
|
1325
|
+
*/
|
|
1326
|
+
this.rhythmStrain = 0;
|
|
1327
|
+
/**
|
|
1328
|
+
* The flashlight strain generated by the hitobject if sliders are considered.
|
|
1329
|
+
*/
|
|
1330
|
+
this.flashlightStrainWithSliders = 0;
|
|
1331
|
+
/**
|
|
1332
|
+
* The flashlight strain generated by the hitobject if sliders are not considered.
|
|
1333
|
+
*/
|
|
1334
|
+
this.flashlightStrainWithoutSliders = 0;
|
|
1335
|
+
/**
|
|
1336
|
+
* The visual strain generated by the hitobject if sliders are considered.
|
|
1337
|
+
*/
|
|
1338
|
+
this.visualStrainWithSliders = 0;
|
|
1339
|
+
/**
|
|
1340
|
+
* The visual strain generated by the hitobject if sliders are not considered.
|
|
1341
|
+
*/
|
|
1342
|
+
this.visualStrainWithoutSliders = 0;
|
|
1343
|
+
/**
|
|
1344
|
+
* The note density of the hitobject.
|
|
1345
|
+
*/
|
|
1346
|
+
this.noteDensity = 1;
|
|
1347
|
+
/**
|
|
1348
|
+
* The overlapping factor of the hitobject.
|
|
1349
|
+
*
|
|
1350
|
+
* This is used to scale visual skill.
|
|
1351
|
+
*/
|
|
1352
|
+
this.overlappingFactor = 0;
|
|
1353
|
+
this.radiusBuffThreshold = 70;
|
|
1354
|
+
this.mode = osuBase.Modes.droid;
|
|
1355
|
+
this.maximumSliderRadius = this.normalizedRadius * 2;
|
|
1397
1356
|
this.timePreempt = object.timePreempt;
|
|
1398
1357
|
if (!isForceAR) {
|
|
1399
1358
|
this.timePreempt /= clockRate;
|
|
@@ -1498,6 +1457,40 @@ class DroidDifficultyHitObject extends DifficultyHitObject {
|
|
|
1498
1457
|
* A difficulty calculator for osu!droid gamemode.
|
|
1499
1458
|
*/
|
|
1500
1459
|
class DroidDifficultyCalculator extends DifficultyCalculator {
|
|
1460
|
+
constructor() {
|
|
1461
|
+
super(...arguments);
|
|
1462
|
+
this.attributes = {
|
|
1463
|
+
mode: "live",
|
|
1464
|
+
tapDifficulty: 0,
|
|
1465
|
+
rhythmDifficulty: 0,
|
|
1466
|
+
visualDifficulty: 0,
|
|
1467
|
+
aimNoteCount: 0,
|
|
1468
|
+
mods: [],
|
|
1469
|
+
starRating: 0,
|
|
1470
|
+
maxCombo: 0,
|
|
1471
|
+
aimDifficulty: 0,
|
|
1472
|
+
flashlightDifficulty: 0,
|
|
1473
|
+
speedNoteCount: 0,
|
|
1474
|
+
sliderFactor: 0,
|
|
1475
|
+
clockRate: 1,
|
|
1476
|
+
approachRate: 0,
|
|
1477
|
+
overallDifficulty: 0,
|
|
1478
|
+
hitCircleCount: 0,
|
|
1479
|
+
sliderCount: 0,
|
|
1480
|
+
spinnerCount: 0,
|
|
1481
|
+
aimDifficultStrainCount: 0,
|
|
1482
|
+
tapDifficultStrainCount: 0,
|
|
1483
|
+
flashlightDifficultStrainCount: 0,
|
|
1484
|
+
visualDifficultStrainCount: 0,
|
|
1485
|
+
flashlightSliderFactor: 0,
|
|
1486
|
+
visualSliderFactor: 0,
|
|
1487
|
+
possibleThreeFingeredSections: [],
|
|
1488
|
+
difficultSliders: [],
|
|
1489
|
+
averageSpeedDeltaTime: 0,
|
|
1490
|
+
};
|
|
1491
|
+
this.difficultyMultiplier = 0.18;
|
|
1492
|
+
this.mode = osuBase.Modes.droid;
|
|
1493
|
+
}
|
|
1501
1494
|
/**
|
|
1502
1495
|
* The aim star rating of the beatmap.
|
|
1503
1496
|
*/
|
|
@@ -1528,41 +1521,6 @@ class DroidDifficultyCalculator extends DifficultyCalculator {
|
|
|
1528
1521
|
get visual() {
|
|
1529
1522
|
return this.attributes.visualDifficulty;
|
|
1530
1523
|
}
|
|
1531
|
-
/**
|
|
1532
|
-
* The strain threshold to start detecting for possible three-fingered section.
|
|
1533
|
-
*
|
|
1534
|
-
* Increasing this number will result in less sections being flagged.
|
|
1535
|
-
*/
|
|
1536
|
-
static threeFingerStrainThreshold = 175;
|
|
1537
|
-
attributes = {
|
|
1538
|
-
mode: "live",
|
|
1539
|
-
tapDifficulty: 0,
|
|
1540
|
-
rhythmDifficulty: 0,
|
|
1541
|
-
visualDifficulty: 0,
|
|
1542
|
-
aimNoteCount: 0,
|
|
1543
|
-
mods: [],
|
|
1544
|
-
starRating: 0,
|
|
1545
|
-
maxCombo: 0,
|
|
1546
|
-
aimDifficulty: 0,
|
|
1547
|
-
flashlightDifficulty: 0,
|
|
1548
|
-
speedNoteCount: 0,
|
|
1549
|
-
sliderFactor: 0,
|
|
1550
|
-
clockRate: 1,
|
|
1551
|
-
approachRate: 0,
|
|
1552
|
-
overallDifficulty: 0,
|
|
1553
|
-
hitCircleCount: 0,
|
|
1554
|
-
sliderCount: 0,
|
|
1555
|
-
spinnerCount: 0,
|
|
1556
|
-
aimDifficultStrainCount: 0,
|
|
1557
|
-
tapDifficultStrainCount: 0,
|
|
1558
|
-
flashlightDifficultStrainCount: 0,
|
|
1559
|
-
visualDifficultStrainCount: 0,
|
|
1560
|
-
flashlightSliderFactor: 0,
|
|
1561
|
-
visualSliderFactor: 0,
|
|
1562
|
-
possibleThreeFingeredSections: [],
|
|
1563
|
-
difficultSliders: [],
|
|
1564
|
-
averageSpeedDeltaTime: 0,
|
|
1565
|
-
};
|
|
1566
1524
|
get cacheableAttributes() {
|
|
1567
1525
|
return {
|
|
1568
1526
|
tapDifficulty: this.tap,
|
|
@@ -1588,8 +1546,6 @@ class DroidDifficultyCalculator extends DifficultyCalculator {
|
|
|
1588
1546
|
averageSpeedDeltaTime: this.attributes.averageSpeedDeltaTime,
|
|
1589
1547
|
};
|
|
1590
1548
|
}
|
|
1591
|
-
difficultyMultiplier = 0.18;
|
|
1592
|
-
mode = osuBase.Modes.droid;
|
|
1593
1549
|
calculate(options) {
|
|
1594
1550
|
return super.calculate(options);
|
|
1595
1551
|
}
|
|
@@ -1698,26 +1654,28 @@ class DroidDifficultyCalculator extends DifficultyCalculator {
|
|
|
1698
1654
|
" visual)");
|
|
1699
1655
|
}
|
|
1700
1656
|
generateDifficultyHitObjects(beatmap) {
|
|
1657
|
+
var _a, _b;
|
|
1701
1658
|
const difficultyObjects = [];
|
|
1702
1659
|
const { objects } = beatmap.hitObjects;
|
|
1703
1660
|
const difficultyAdjustMod = this.mods.find((m) => m instanceof osuBase.ModDifficultyAdjust);
|
|
1704
1661
|
for (let i = 0; i < objects.length; ++i) {
|
|
1705
|
-
const difficultyObject = new DroidDifficultyHitObject(objects[i], objects[i - 1]
|
|
1662
|
+
const difficultyObject = new DroidDifficultyHitObject(objects[i], (_a = objects[i - 1]) !== null && _a !== void 0 ? _a : null, (_b = objects[i - 2]) !== null && _b !== void 0 ? _b : null, difficultyObjects, this.difficultyStatistics.overallSpeedMultiplier, (difficultyAdjustMod === null || difficultyAdjustMod === void 0 ? void 0 : difficultyAdjustMod.ar) !== undefined);
|
|
1706
1663
|
difficultyObject.computeProperties(this.difficultyStatistics.overallSpeedMultiplier, objects);
|
|
1707
1664
|
difficultyObjects.push(difficultyObject);
|
|
1708
1665
|
}
|
|
1709
1666
|
return difficultyObjects;
|
|
1710
1667
|
}
|
|
1711
1668
|
computeDifficultyStatistics(options) {
|
|
1669
|
+
var _a;
|
|
1712
1670
|
const { difficulty } = this.beatmap;
|
|
1713
1671
|
return osuBase.calculateDroidDifficultyStatistics({
|
|
1714
1672
|
circleSize: difficulty.cs,
|
|
1715
|
-
approachRate: difficulty.ar
|
|
1673
|
+
approachRate: (_a = difficulty.ar) !== null && _a !== void 0 ? _a : difficulty.od,
|
|
1716
1674
|
overallDifficulty: difficulty.od,
|
|
1717
1675
|
healthDrain: difficulty.hp,
|
|
1718
1676
|
mods: this.mods,
|
|
1719
|
-
customSpeedMultiplier: options
|
|
1720
|
-
oldStatistics: options
|
|
1677
|
+
customSpeedMultiplier: options === null || options === void 0 ? void 0 : options.customSpeedMultiplier,
|
|
1678
|
+
oldStatistics: options === null || options === void 0 ? void 0 : options.oldStatistics,
|
|
1721
1679
|
});
|
|
1722
1680
|
}
|
|
1723
1681
|
createSkills() {
|
|
@@ -1977,44 +1935,43 @@ class DroidDifficultyCalculator extends DifficultyCalculator {
|
|
|
1977
1935
|
}
|
|
1978
1936
|
}
|
|
1979
1937
|
}
|
|
1938
|
+
/**
|
|
1939
|
+
* The strain threshold to start detecting for possible three-fingered section.
|
|
1940
|
+
*
|
|
1941
|
+
* Increasing this number will result in less sections being flagged.
|
|
1942
|
+
*/
|
|
1943
|
+
DroidDifficultyCalculator.threeFingerStrainThreshold = 175;
|
|
1980
1944
|
|
|
1981
1945
|
/**
|
|
1982
1946
|
* The base class of performance calculators.
|
|
1983
1947
|
*/
|
|
1984
1948
|
class PerformanceCalculator {
|
|
1985
|
-
/**
|
|
1986
|
-
* The overall performance value.
|
|
1987
|
-
*/
|
|
1988
|
-
total = 0;
|
|
1989
|
-
/**
|
|
1990
|
-
* The calculated accuracy.
|
|
1991
|
-
*/
|
|
1992
|
-
computedAccuracy = new osuBase.Accuracy({});
|
|
1993
|
-
/**
|
|
1994
|
-
* The difficulty attributes that is being calculated.
|
|
1995
|
-
*/
|
|
1996
|
-
difficultyAttributes;
|
|
1997
|
-
/**
|
|
1998
|
-
* Penalty for combo breaks.
|
|
1999
|
-
*/
|
|
2000
|
-
comboPenalty = 0;
|
|
2001
|
-
/**
|
|
2002
|
-
* The amount of misses that are filtered out from sliderbreaks.
|
|
2003
|
-
*/
|
|
2004
|
-
effectiveMissCount = 0;
|
|
2005
|
-
/**
|
|
2006
|
-
* Nerf factor used for nerfing beatmaps with very likely dropped sliderends.
|
|
2007
|
-
*/
|
|
2008
|
-
sliderNerfFactor = 1;
|
|
2009
1949
|
/**
|
|
2010
1950
|
* @param difficultyAttributes The difficulty attributes to calculate.
|
|
2011
1951
|
*/
|
|
2012
1952
|
constructor(difficultyAttributes) {
|
|
1953
|
+
/**
|
|
1954
|
+
* The overall performance value.
|
|
1955
|
+
*/
|
|
1956
|
+
this.total = 0;
|
|
1957
|
+
/**
|
|
1958
|
+
* The calculated accuracy.
|
|
1959
|
+
*/
|
|
1960
|
+
this.computedAccuracy = new osuBase.Accuracy({});
|
|
1961
|
+
/**
|
|
1962
|
+
* Penalty for combo breaks.
|
|
1963
|
+
*/
|
|
1964
|
+
this.comboPenalty = 0;
|
|
1965
|
+
/**
|
|
1966
|
+
* The amount of misses that are filtered out from sliderbreaks.
|
|
1967
|
+
*/
|
|
1968
|
+
this.effectiveMissCount = 0;
|
|
1969
|
+
/**
|
|
1970
|
+
* Nerf factor used for nerfing beatmaps with very likely dropped sliderends.
|
|
1971
|
+
*/
|
|
1972
|
+
this.sliderNerfFactor = 1;
|
|
2013
1973
|
if (this.isCacheableAttribute(difficultyAttributes)) {
|
|
2014
|
-
this.difficultyAttributes = {
|
|
2015
|
-
...difficultyAttributes,
|
|
2016
|
-
mods: osuBase.ModUtil.pcStringToMods(difficultyAttributes.mods),
|
|
2017
|
-
};
|
|
1974
|
+
this.difficultyAttributes = Object.assign(Object.assign({}, difficultyAttributes), { mods: osuBase.ModUtil.pcStringToMods(difficultyAttributes.mods) });
|
|
2018
1975
|
}
|
|
2019
1976
|
else {
|
|
2020
1977
|
this.difficultyAttributes = osuBase.Utils.deepCopy(difficultyAttributes);
|
|
@@ -2060,11 +2017,12 @@ class PerformanceCalculator {
|
|
|
2060
2017
|
* @param options Options for performance calculation.
|
|
2061
2018
|
*/
|
|
2062
2019
|
handleOptions(options) {
|
|
2020
|
+
var _a;
|
|
2063
2021
|
const maxCombo = this.difficultyAttributes.maxCombo;
|
|
2064
2022
|
const miss = this.computedAccuracy.nmiss;
|
|
2065
|
-
const combo = options
|
|
2023
|
+
const combo = (_a = options === null || options === void 0 ? void 0 : options.combo) !== null && _a !== void 0 ? _a : maxCombo - miss;
|
|
2066
2024
|
this.comboPenalty = Math.min(Math.pow(combo / maxCombo, 0.8), 1);
|
|
2067
|
-
if (options
|
|
2025
|
+
if ((options === null || options === void 0 ? void 0 : options.accPercent) instanceof osuBase.Accuracy) {
|
|
2068
2026
|
// Copy into new instance to not modify the original
|
|
2069
2027
|
this.computedAccuracy = new osuBase.Accuracy(options.accPercent);
|
|
2070
2028
|
if (this.computedAccuracy.n300 <= 0) {
|
|
@@ -2079,9 +2037,9 @@ class PerformanceCalculator {
|
|
|
2079
2037
|
}
|
|
2080
2038
|
else {
|
|
2081
2039
|
this.computedAccuracy = new osuBase.Accuracy({
|
|
2082
|
-
percent: options
|
|
2040
|
+
percent: options === null || options === void 0 ? void 0 : options.accPercent,
|
|
2083
2041
|
nobjects: this.totalHits,
|
|
2084
|
-
nmiss: options
|
|
2042
|
+
nmiss: (options === null || options === void 0 ? void 0 : options.miss) || 0,
|
|
2085
2043
|
});
|
|
2086
2044
|
}
|
|
2087
2045
|
this.effectiveMissCount = this.calculateEffectiveMissCount(combo, maxCombo);
|
|
@@ -2158,26 +2116,37 @@ class PerformanceCalculator {
|
|
|
2158
2116
|
* A performance points calculator that calculates performance points for osu!droid gamemode.
|
|
2159
2117
|
*/
|
|
2160
2118
|
class DroidPerformanceCalculator extends PerformanceCalculator {
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2119
|
+
constructor() {
|
|
2120
|
+
super(...arguments);
|
|
2121
|
+
/**
|
|
2122
|
+
* The aim performance value.
|
|
2123
|
+
*/
|
|
2124
|
+
this.aim = 0;
|
|
2125
|
+
/**
|
|
2126
|
+
* The tap performance value.
|
|
2127
|
+
*/
|
|
2128
|
+
this.tap = 0;
|
|
2129
|
+
/**
|
|
2130
|
+
* The accuracy performance value.
|
|
2131
|
+
*/
|
|
2132
|
+
this.accuracy = 0;
|
|
2133
|
+
/**
|
|
2134
|
+
* The flashlight performance value.
|
|
2135
|
+
*/
|
|
2136
|
+
this.flashlight = 0;
|
|
2137
|
+
/**
|
|
2138
|
+
* The visual performance value.
|
|
2139
|
+
*/
|
|
2140
|
+
this.visual = 0;
|
|
2141
|
+
this.finalMultiplier = 1.24;
|
|
2142
|
+
this.mode = osuBase.Modes.droid;
|
|
2143
|
+
this._aimSliderCheesePenalty = 1;
|
|
2144
|
+
this._flashlightSliderCheesePenalty = 1;
|
|
2145
|
+
this._visualSliderCheesePenalty = 1;
|
|
2146
|
+
this._tapPenalty = 1;
|
|
2147
|
+
this._deviation = 0;
|
|
2148
|
+
this._tapDeviation = 0;
|
|
2149
|
+
}
|
|
2181
2150
|
/**
|
|
2182
2151
|
* The penalty used to penalize the tap performance value.
|
|
2183
2152
|
*
|
|
@@ -2222,14 +2191,6 @@ class DroidPerformanceCalculator extends PerformanceCalculator {
|
|
|
2222
2191
|
get visualSliderCheesePenalty() {
|
|
2223
2192
|
return this._visualSliderCheesePenalty;
|
|
2224
2193
|
}
|
|
2225
|
-
finalMultiplier = 1.24;
|
|
2226
|
-
mode = osuBase.Modes.droid;
|
|
2227
|
-
_aimSliderCheesePenalty = 1;
|
|
2228
|
-
_flashlightSliderCheesePenalty = 1;
|
|
2229
|
-
_visualSliderCheesePenalty = 1;
|
|
2230
|
-
_tapPenalty = 1;
|
|
2231
|
-
_deviation = 0;
|
|
2232
|
-
_tapDeviation = 0;
|
|
2233
2194
|
/**
|
|
2234
2195
|
* Applies a tap penalty value to this calculator.
|
|
2235
2196
|
*
|
|
@@ -2328,12 +2289,13 @@ class DroidPerformanceCalculator extends PerformanceCalculator {
|
|
|
2328
2289
|
Math.pow(this.visual, 1.1), 1 / 1.1) * this.finalMultiplier);
|
|
2329
2290
|
}
|
|
2330
2291
|
handleOptions(options) {
|
|
2331
|
-
|
|
2332
|
-
this.
|
|
2292
|
+
var _a, _b, _c, _d;
|
|
2293
|
+
this._tapPenalty = (_a = options === null || options === void 0 ? void 0 : options.tapPenalty) !== null && _a !== void 0 ? _a : 1;
|
|
2294
|
+
this._aimSliderCheesePenalty = (_b = options === null || options === void 0 ? void 0 : options.aimSliderCheesePenalty) !== null && _b !== void 0 ? _b : 1;
|
|
2333
2295
|
this._flashlightSliderCheesePenalty =
|
|
2334
|
-
options
|
|
2296
|
+
(_c = options === null || options === void 0 ? void 0 : options.flashlightSliderCheesePenalty) !== null && _c !== void 0 ? _c : 1;
|
|
2335
2297
|
this._visualSliderCheesePenalty =
|
|
2336
|
-
options
|
|
2298
|
+
(_d = options === null || options === void 0 ? void 0 : options.visualSliderCheesePenalty) !== null && _d !== void 0 ? _d : 1;
|
|
2337
2299
|
super.handleOptions(options);
|
|
2338
2300
|
}
|
|
2339
2301
|
/**
|
|
@@ -2639,16 +2601,13 @@ class DroidPerformanceCalculator extends PerformanceCalculator {
|
|
|
2639
2601
|
* and to calculate a final difficulty value representing the difficulty of hitting all the processed objects.
|
|
2640
2602
|
*/
|
|
2641
2603
|
class OsuSkill extends StrainSkill {
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
* The final multiplier to be applied to the final difficulty value after all other calculations.
|
|
2650
|
-
*/
|
|
2651
|
-
difficultyMultiplier = OsuSkill.defaultDifficultyMultiplier;
|
|
2604
|
+
constructor() {
|
|
2605
|
+
super(...arguments);
|
|
2606
|
+
/**
|
|
2607
|
+
* The final multiplier to be applied to the final difficulty value after all other calculations.
|
|
2608
|
+
*/
|
|
2609
|
+
this.difficultyMultiplier = OsuSkill.defaultDifficultyMultiplier;
|
|
2610
|
+
}
|
|
2652
2611
|
difficultyValue() {
|
|
2653
2612
|
const strains = this.strainPeaks
|
|
2654
2613
|
.slice()
|
|
@@ -2676,6 +2635,12 @@ class OsuSkill extends StrainSkill {
|
|
|
2676
2635
|
return difficulty * this.difficultyMultiplier;
|
|
2677
2636
|
}
|
|
2678
2637
|
}
|
|
2638
|
+
/**
|
|
2639
|
+
* The default multiplier applied to the final difficulty value after all other calculations.
|
|
2640
|
+
*
|
|
2641
|
+
* May be overridden via {@link difficultyMultiplier}.
|
|
2642
|
+
*/
|
|
2643
|
+
OsuSkill.defaultDifficultyMultiplier = 1.06;
|
|
2679
2644
|
|
|
2680
2645
|
/**
|
|
2681
2646
|
* An evaluator for calculating osu!standard Aim skill.
|
|
@@ -2696,7 +2661,7 @@ class OsuAimEvaluator extends AimEvaluator {
|
|
|
2696
2661
|
const last = current.previous(0);
|
|
2697
2662
|
if (current.object instanceof osuBase.Spinner ||
|
|
2698
2663
|
current.index <= 1 ||
|
|
2699
|
-
last
|
|
2664
|
+
(last === null || last === void 0 ? void 0 : last.object) instanceof osuBase.Spinner) {
|
|
2700
2665
|
return 0;
|
|
2701
2666
|
}
|
|
2702
2667
|
const lastLast = current.previous(1);
|
|
@@ -2803,15 +2768,14 @@ class OsuAimEvaluator extends AimEvaluator {
|
|
|
2803
2768
|
* Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
|
|
2804
2769
|
*/
|
|
2805
2770
|
class OsuAim extends OsuSkill {
|
|
2806
|
-
strainDecayBase = 0.15;
|
|
2807
|
-
reducedSectionCount = 10;
|
|
2808
|
-
reducedSectionBaseline = 0.75;
|
|
2809
|
-
decayWeight = 0.9;
|
|
2810
|
-
currentAimStrain = 0;
|
|
2811
|
-
skillMultiplier = 23.55;
|
|
2812
|
-
withSliders;
|
|
2813
2771
|
constructor(mods, withSliders) {
|
|
2814
2772
|
super(mods);
|
|
2773
|
+
this.strainDecayBase = 0.15;
|
|
2774
|
+
this.reducedSectionCount = 10;
|
|
2775
|
+
this.reducedSectionBaseline = 0.75;
|
|
2776
|
+
this.decayWeight = 0.9;
|
|
2777
|
+
this.currentAimStrain = 0;
|
|
2778
|
+
this.skillMultiplier = 23.55;
|
|
2815
2779
|
this.withSliders = withSliders;
|
|
2816
2780
|
}
|
|
2817
2781
|
strainValueAt(current) {
|
|
@@ -2822,8 +2786,9 @@ class OsuAim extends OsuSkill {
|
|
|
2822
2786
|
return this.currentAimStrain;
|
|
2823
2787
|
}
|
|
2824
2788
|
calculateInitialStrain(time, current) {
|
|
2789
|
+
var _a, _b;
|
|
2825
2790
|
return (this.currentAimStrain *
|
|
2826
|
-
this.strainDecay(time - (current.previous(0)
|
|
2791
|
+
this.strainDecay(time - ((_b = (_a = current.previous(0)) === null || _a === void 0 ? void 0 : _a.startTime) !== null && _b !== void 0 ? _b : 0)));
|
|
2827
2792
|
}
|
|
2828
2793
|
/**
|
|
2829
2794
|
* @param current The hitobject to save to.
|
|
@@ -2842,10 +2807,6 @@ class OsuAim extends OsuSkill {
|
|
|
2842
2807
|
* An evaluator for calculating osu!standard speed skill.
|
|
2843
2808
|
*/
|
|
2844
2809
|
class OsuSpeedEvaluator extends SpeedEvaluator {
|
|
2845
|
-
/**
|
|
2846
|
-
* Spacing threshold for a single hitobject spacing.
|
|
2847
|
-
*/
|
|
2848
|
-
static SINGLE_SPACING_THRESHOLD = 125;
|
|
2849
2810
|
/**
|
|
2850
2811
|
* Evaluates the difficulty of tapping the current object, based on:
|
|
2851
2812
|
*
|
|
@@ -2857,6 +2818,7 @@ class OsuSpeedEvaluator extends SpeedEvaluator {
|
|
|
2857
2818
|
* @param greatWindow The great hit window of the current object.
|
|
2858
2819
|
*/
|
|
2859
2820
|
static evaluateDifficultyOf(current, greatWindow) {
|
|
2821
|
+
var _a;
|
|
2860
2822
|
if (current.object instanceof osuBase.Spinner) {
|
|
2861
2823
|
return 0;
|
|
2862
2824
|
}
|
|
@@ -2882,7 +2844,7 @@ class OsuSpeedEvaluator extends SpeedEvaluator {
|
|
|
2882
2844
|
speedBonus +=
|
|
2883
2845
|
0.75 * Math.pow((this.minSpeedBonus - strainTime) / 40, 2);
|
|
2884
2846
|
}
|
|
2885
|
-
const travelDistance = prev
|
|
2847
|
+
const travelDistance = (_a = prev === null || prev === void 0 ? void 0 : prev.travelDistance) !== null && _a !== void 0 ? _a : 0;
|
|
2886
2848
|
const distance = Math.min(this.SINGLE_SPACING_THRESHOLD, travelDistance + current.minimumJumpDistance);
|
|
2887
2849
|
return (((speedBonus +
|
|
2888
2850
|
speedBonus *
|
|
@@ -2891,6 +2853,10 @@ class OsuSpeedEvaluator extends SpeedEvaluator {
|
|
|
2891
2853
|
strainTime);
|
|
2892
2854
|
}
|
|
2893
2855
|
}
|
|
2856
|
+
/**
|
|
2857
|
+
* Spacing threshold for a single hitobject spacing.
|
|
2858
|
+
*/
|
|
2859
|
+
OsuSpeedEvaluator.SINGLE_SPACING_THRESHOLD = 125;
|
|
2894
2860
|
|
|
2895
2861
|
/**
|
|
2896
2862
|
* An evaluator for calculating osu!standard Rhythm skill.
|
|
@@ -3005,17 +2971,16 @@ class OsuRhythmEvaluator extends RhythmEvaluator {
|
|
|
3005
2971
|
* Represents the skill required to press keys or tap with regards to keeping up with the speed at which objects need to be hit.
|
|
3006
2972
|
*/
|
|
3007
2973
|
class OsuSpeed extends OsuSkill {
|
|
3008
|
-
strainDecayBase = 0.3;
|
|
3009
|
-
reducedSectionCount = 5;
|
|
3010
|
-
reducedSectionBaseline = 0.75;
|
|
3011
|
-
difficultyMultiplier = 1.04;
|
|
3012
|
-
decayWeight = 0.9;
|
|
3013
|
-
currentSpeedStrain = 0;
|
|
3014
|
-
currentRhythm = 0;
|
|
3015
|
-
skillMultiplier = 1375;
|
|
3016
|
-
greatWindow;
|
|
3017
2974
|
constructor(mods, overallDifficulty) {
|
|
3018
2975
|
super(mods);
|
|
2976
|
+
this.strainDecayBase = 0.3;
|
|
2977
|
+
this.reducedSectionCount = 5;
|
|
2978
|
+
this.reducedSectionBaseline = 0.75;
|
|
2979
|
+
this.difficultyMultiplier = 1.04;
|
|
2980
|
+
this.decayWeight = 0.9;
|
|
2981
|
+
this.currentSpeedStrain = 0;
|
|
2982
|
+
this.currentRhythm = 0;
|
|
2983
|
+
this.skillMultiplier = 1375;
|
|
3019
2984
|
this.greatWindow = new osuBase.OsuHitWindow(overallDifficulty).hitWindowFor300();
|
|
3020
2985
|
}
|
|
3021
2986
|
/**
|
|
@@ -3030,9 +2995,10 @@ class OsuSpeed extends OsuSkill {
|
|
|
3030
2995
|
return this.currentSpeedStrain * this.currentRhythm;
|
|
3031
2996
|
}
|
|
3032
2997
|
calculateInitialStrain(time, current) {
|
|
2998
|
+
var _a, _b;
|
|
3033
2999
|
return (this.currentSpeedStrain *
|
|
3034
3000
|
this.currentRhythm *
|
|
3035
|
-
this.strainDecay(time - (current.previous(0)
|
|
3001
|
+
this.strainDecay(time - ((_b = (_a = current.previous(0)) === null || _a === void 0 ? void 0 : _a.startTime) !== null && _b !== void 0 ? _b : 0)));
|
|
3036
3002
|
}
|
|
3037
3003
|
/**
|
|
3038
3004
|
* @param current The hitobject to save to.
|
|
@@ -3129,15 +3095,14 @@ class OsuFlashlightEvaluator extends FlashlightEvaluator {
|
|
|
3129
3095
|
* Represents the skill required to memorize and hit every object in a beatmap with the Flashlight mod enabled.
|
|
3130
3096
|
*/
|
|
3131
3097
|
class OsuFlashlight extends OsuSkill {
|
|
3132
|
-
strainDecayBase = 0.15;
|
|
3133
|
-
reducedSectionCount = 0;
|
|
3134
|
-
reducedSectionBaseline = 1;
|
|
3135
|
-
decayWeight = 1;
|
|
3136
|
-
currentFlashlightStrain = 0;
|
|
3137
|
-
skillMultiplier = 0.052;
|
|
3138
|
-
isHidden;
|
|
3139
3098
|
constructor(mods) {
|
|
3140
3099
|
super(mods);
|
|
3100
|
+
this.strainDecayBase = 0.15;
|
|
3101
|
+
this.reducedSectionCount = 0;
|
|
3102
|
+
this.reducedSectionBaseline = 1;
|
|
3103
|
+
this.decayWeight = 1;
|
|
3104
|
+
this.currentFlashlightStrain = 0;
|
|
3105
|
+
this.skillMultiplier = 0.052;
|
|
3141
3106
|
this.isHidden = mods.some((m) => m instanceof osuBase.ModHidden);
|
|
3142
3107
|
}
|
|
3143
3108
|
strainValueAt(current) {
|
|
@@ -3147,8 +3112,9 @@ class OsuFlashlight extends OsuSkill {
|
|
|
3147
3112
|
return this.currentFlashlightStrain;
|
|
3148
3113
|
}
|
|
3149
3114
|
calculateInitialStrain(time, current) {
|
|
3115
|
+
var _a, _b;
|
|
3150
3116
|
return (this.currentFlashlightStrain *
|
|
3151
|
-
this.strainDecay(time - (current.previous(0)
|
|
3117
|
+
this.strainDecay(time - ((_b = (_a = current.previous(0)) === null || _a === void 0 ? void 0 : _a.startTime) !== null && _b !== void 0 ? _b : 0)));
|
|
3152
3118
|
}
|
|
3153
3119
|
saveToHitObject(current) {
|
|
3154
3120
|
current.flashlightStrain = this.currentFlashlightStrain;
|
|
@@ -3159,16 +3125,6 @@ class OsuFlashlight extends OsuSkill {
|
|
|
3159
3125
|
* Represents an osu!standard hit object with difficulty calculation values.
|
|
3160
3126
|
*/
|
|
3161
3127
|
class OsuDifficultyHitObject extends DifficultyHitObject {
|
|
3162
|
-
/**
|
|
3163
|
-
* The speed strain generated by the hitobject.
|
|
3164
|
-
*/
|
|
3165
|
-
speedStrain = 0;
|
|
3166
|
-
/**
|
|
3167
|
-
* The flashlight strain generated by this hitobject.
|
|
3168
|
-
*/
|
|
3169
|
-
flashlightStrain = 0;
|
|
3170
|
-
radiusBuffThreshold = 30;
|
|
3171
|
-
mode = osuBase.Modes.osu;
|
|
3172
3128
|
get scalingFactor() {
|
|
3173
3129
|
const radius = this.object.radius;
|
|
3174
3130
|
// We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps.
|
|
@@ -3192,6 +3148,16 @@ class OsuDifficultyHitObject extends DifficultyHitObject {
|
|
|
3192
3148
|
*/
|
|
3193
3149
|
constructor(object, lastObject, lastLastObject, difficultyHitObjects, clockRate) {
|
|
3194
3150
|
super(object, lastObject, lastLastObject, difficultyHitObjects, clockRate);
|
|
3151
|
+
/**
|
|
3152
|
+
* The speed strain generated by the hitobject.
|
|
3153
|
+
*/
|
|
3154
|
+
this.speedStrain = 0;
|
|
3155
|
+
/**
|
|
3156
|
+
* The flashlight strain generated by this hitobject.
|
|
3157
|
+
*/
|
|
3158
|
+
this.flashlightStrain = 0;
|
|
3159
|
+
this.radiusBuffThreshold = 30;
|
|
3160
|
+
this.mode = osuBase.Modes.osu;
|
|
3195
3161
|
}
|
|
3196
3162
|
}
|
|
3197
3163
|
|
|
@@ -3199,6 +3165,27 @@ class OsuDifficultyHitObject extends DifficultyHitObject {
|
|
|
3199
3165
|
* A difficulty calculator for osu!standard gamemode.
|
|
3200
3166
|
*/
|
|
3201
3167
|
class OsuDifficultyCalculator extends DifficultyCalculator {
|
|
3168
|
+
constructor() {
|
|
3169
|
+
super(...arguments);
|
|
3170
|
+
this.attributes = {
|
|
3171
|
+
speedDifficulty: 0,
|
|
3172
|
+
mods: [],
|
|
3173
|
+
starRating: 0,
|
|
3174
|
+
maxCombo: 0,
|
|
3175
|
+
aimDifficulty: 0,
|
|
3176
|
+
flashlightDifficulty: 0,
|
|
3177
|
+
speedNoteCount: 0,
|
|
3178
|
+
sliderFactor: 0,
|
|
3179
|
+
clockRate: 1,
|
|
3180
|
+
approachRate: 0,
|
|
3181
|
+
overallDifficulty: 0,
|
|
3182
|
+
hitCircleCount: 0,
|
|
3183
|
+
sliderCount: 0,
|
|
3184
|
+
spinnerCount: 0,
|
|
3185
|
+
};
|
|
3186
|
+
this.difficultyMultiplier = 0.0675;
|
|
3187
|
+
this.mode = osuBase.Modes.osu;
|
|
3188
|
+
}
|
|
3202
3189
|
/**
|
|
3203
3190
|
* The aim star rating of the beatmap.
|
|
3204
3191
|
*/
|
|
@@ -3217,30 +3204,9 @@ class OsuDifficultyCalculator extends DifficultyCalculator {
|
|
|
3217
3204
|
get flashlight() {
|
|
3218
3205
|
return this.attributes.flashlightDifficulty;
|
|
3219
3206
|
}
|
|
3220
|
-
attributes = {
|
|
3221
|
-
speedDifficulty: 0,
|
|
3222
|
-
mods: [],
|
|
3223
|
-
starRating: 0,
|
|
3224
|
-
maxCombo: 0,
|
|
3225
|
-
aimDifficulty: 0,
|
|
3226
|
-
flashlightDifficulty: 0,
|
|
3227
|
-
speedNoteCount: 0,
|
|
3228
|
-
sliderFactor: 0,
|
|
3229
|
-
clockRate: 1,
|
|
3230
|
-
approachRate: 0,
|
|
3231
|
-
overallDifficulty: 0,
|
|
3232
|
-
hitCircleCount: 0,
|
|
3233
|
-
sliderCount: 0,
|
|
3234
|
-
spinnerCount: 0,
|
|
3235
|
-
};
|
|
3236
3207
|
get cacheableAttributes() {
|
|
3237
|
-
return {
|
|
3238
|
-
...this.attributes,
|
|
3239
|
-
mods: osuBase.ModUtil.modsToOsuString(this.attributes.mods),
|
|
3240
|
-
};
|
|
3208
|
+
return Object.assign(Object.assign({}, this.attributes), { mods: osuBase.ModUtil.modsToOsuString(this.attributes.mods) });
|
|
3241
3209
|
}
|
|
3242
|
-
difficultyMultiplier = 0.0675;
|
|
3243
|
-
mode = osuBase.Modes.osu;
|
|
3244
3210
|
/**
|
|
3245
3211
|
* Calculates the aim star rating of the beatmap and stores it in this instance.
|
|
3246
3212
|
*/
|
|
@@ -3323,24 +3289,26 @@ class OsuDifficultyCalculator extends DifficultyCalculator {
|
|
|
3323
3289
|
" flashlight)");
|
|
3324
3290
|
}
|
|
3325
3291
|
generateDifficultyHitObjects() {
|
|
3292
|
+
var _a, _b;
|
|
3326
3293
|
const difficultyObjects = [];
|
|
3327
3294
|
const { objects } = this.beatmap.hitObjects;
|
|
3328
3295
|
for (let i = 0; i < objects.length; ++i) {
|
|
3329
|
-
const difficultyObject = new OsuDifficultyHitObject(objects[i], objects[i - 1]
|
|
3296
|
+
const difficultyObject = new OsuDifficultyHitObject(objects[i], (_a = objects[i - 1]) !== null && _a !== void 0 ? _a : null, (_b = objects[i - 2]) !== null && _b !== void 0 ? _b : null, difficultyObjects, this.difficultyStatistics.overallSpeedMultiplier);
|
|
3330
3297
|
difficultyObject.computeProperties(this.difficultyStatistics.overallSpeedMultiplier, objects);
|
|
3331
3298
|
difficultyObjects.push(difficultyObject);
|
|
3332
3299
|
}
|
|
3333
3300
|
return difficultyObjects;
|
|
3334
3301
|
}
|
|
3335
3302
|
computeDifficultyStatistics(options) {
|
|
3303
|
+
var _a;
|
|
3336
3304
|
const { difficulty } = this.beatmap;
|
|
3337
3305
|
return osuBase.calculateOsuDifficultyStatistics({
|
|
3338
3306
|
circleSize: difficulty.cs,
|
|
3339
|
-
approachRate: difficulty.ar
|
|
3307
|
+
approachRate: (_a = difficulty.ar) !== null && _a !== void 0 ? _a : difficulty.od,
|
|
3340
3308
|
overallDifficulty: difficulty.od,
|
|
3341
3309
|
healthDrain: difficulty.hp,
|
|
3342
|
-
mods: options
|
|
3343
|
-
customSpeedMultiplier: options
|
|
3310
|
+
mods: options === null || options === void 0 ? void 0 : options.mods,
|
|
3311
|
+
customSpeedMultiplier: options === null || options === void 0 ? void 0 : options.customSpeedMultiplier,
|
|
3344
3312
|
});
|
|
3345
3313
|
}
|
|
3346
3314
|
createSkills() {
|
|
@@ -3413,24 +3381,27 @@ class OsuDifficultyCalculator extends DifficultyCalculator {
|
|
|
3413
3381
|
* A performance points calculator that calculates performance points for osu!standard gamemode.
|
|
3414
3382
|
*/
|
|
3415
3383
|
class OsuPerformanceCalculator extends PerformanceCalculator {
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3384
|
+
constructor() {
|
|
3385
|
+
super(...arguments);
|
|
3386
|
+
/**
|
|
3387
|
+
* The aim performance value.
|
|
3388
|
+
*/
|
|
3389
|
+
this.aim = 0;
|
|
3390
|
+
/**
|
|
3391
|
+
* The speed performance value.
|
|
3392
|
+
*/
|
|
3393
|
+
this.speed = 0;
|
|
3394
|
+
/**
|
|
3395
|
+
* The accuracy performance value.
|
|
3396
|
+
*/
|
|
3397
|
+
this.accuracy = 0;
|
|
3398
|
+
/**
|
|
3399
|
+
* The flashlight performance value.
|
|
3400
|
+
*/
|
|
3401
|
+
this.flashlight = 0;
|
|
3402
|
+
this.finalMultiplier = 1.14;
|
|
3403
|
+
this.mode = osuBase.Modes.osu;
|
|
3404
|
+
}
|
|
3434
3405
|
calculateValues() {
|
|
3435
3406
|
this.aim = this.calculateAimValue();
|
|
3436
3407
|
this.speed = this.calculateSpeedValue();
|
|
@@ -3564,10 +3535,7 @@ class OsuPerformanceCalculator extends PerformanceCalculator {
|
|
|
3564
3535
|
if (ncircles === 0) {
|
|
3565
3536
|
return 0;
|
|
3566
3537
|
}
|
|
3567
|
-
const realAccuracy = new osuBase.Accuracy({
|
|
3568
|
-
...this.computedAccuracy,
|
|
3569
|
-
n300: this.computedAccuracy.n300 - (this.totalHits - ncircles),
|
|
3570
|
-
});
|
|
3538
|
+
const realAccuracy = new osuBase.Accuracy(Object.assign(Object.assign({}, this.computedAccuracy), { n300: this.computedAccuracy.n300 - (this.totalHits - ncircles) }));
|
|
3571
3539
|
// Lots of arbitrary values from testing.
|
|
3572
3540
|
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
|
|
3573
3541
|
let accuracyValue = Math.pow(1.52163, this.difficultyAttributes.overallDifficulty) *
|