@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 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 ?? beatmap.difficulty.od,
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
- this.mods = options?.mods ?? [];
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?.customSpeedMultiplier,
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
- return this.hitObjects[this.index - backwardsIndex] ?? null;
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
- return (this.hitObjects[this.index + forwardsIndex + 2] ?? null);
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 ?? pos;
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)?.object instanceof osuBase.Spinner) {
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)?.travelDistance ?? 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
- * Strain peaks are stored here.
653
- */
654
- strainPeaks = [];
655
- sectionLength = 400;
656
- currentStrain = 0;
657
- currentSectionPeak = 0;
658
- currentSectionEnd = 0;
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)?.startTime ?? 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)?.startTime ?? 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)?.startTime ?? 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)?.startTime ?? 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)?.startTime ?? 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] ?? null, objects[i - 2] ?? null, difficultyObjects, this.difficultyStatistics.overallSpeedMultiplier, difficultyAdjustMod?.ar !== undefined);
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 ?? difficulty.od,
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?.customSpeedMultiplier,
1720
- oldStatistics: options?.oldStatistics,
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?.combo ?? maxCombo - miss;
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?.accPercent instanceof osuBase.Accuracy) {
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?.accPercent,
2040
+ percent: options === null || options === void 0 ? void 0 : options.accPercent,
2083
2041
  nobjects: this.totalHits,
2084
- nmiss: options?.miss || 0,
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
- * The aim performance value.
2163
- */
2164
- aim = 0;
2165
- /**
2166
- * The tap performance value.
2167
- */
2168
- tap = 0;
2169
- /**
2170
- * The accuracy performance value.
2171
- */
2172
- accuracy = 0;
2173
- /**
2174
- * The flashlight performance value.
2175
- */
2176
- flashlight = 0;
2177
- /**
2178
- * The visual performance value.
2179
- */
2180
- visual = 0;
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
- this._tapPenalty = options?.tapPenalty ?? 1;
2332
- this._aimSliderCheesePenalty = options?.aimSliderCheesePenalty ?? 1;
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?.flashlightSliderCheesePenalty ?? 1;
2296
+ (_c = options === null || options === void 0 ? void 0 : options.flashlightSliderCheesePenalty) !== null && _c !== void 0 ? _c : 1;
2335
2297
  this._visualSliderCheesePenalty =
2336
- options?.visualSliderCheesePenalty ?? 1;
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
- * The default multiplier applied to the final difficulty value after all other calculations.
2644
- *
2645
- * May be overridden via {@link difficultyMultiplier}.
2646
- */
2647
- static defaultDifficultyMultiplier = 1.06;
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?.object instanceof osuBase.Spinner) {
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)?.startTime ?? 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?.travelDistance ?? 0;
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)?.startTime ?? 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)?.startTime ?? 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] ?? null, objects[i - 2] ?? null, difficultyObjects, this.difficultyStatistics.overallSpeedMultiplier);
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 ?? difficulty.od,
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?.mods,
3343
- customSpeedMultiplier: options?.customSpeedMultiplier,
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
- * The aim performance value.
3418
- */
3419
- aim = 0;
3420
- /**
3421
- * The speed performance value.
3422
- */
3423
- speed = 0;
3424
- /**
3425
- * The accuracy performance value.
3426
- */
3427
- accuracy = 0;
3428
- /**
3429
- * The flashlight performance value.
3430
- */
3431
- flashlight = 0;
3432
- finalMultiplier = 1.14;
3433
- mode = osuBase.Modes.osu;
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) *