@rian8337/osu-base 4.0.0-beta.25 → 4.0.0-beta.27
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 +446 -506
- package/package.json +2 -2
- package/typings/index.d.ts +162 -174
package/dist/index.js
CHANGED
|
@@ -390,6 +390,42 @@ class BeatmapDifficulty {
|
|
|
390
390
|
set ar(value) {
|
|
391
391
|
this._ar = value;
|
|
392
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* Maps a difficulty value [0, 10] to a two-piece linear range of values.
|
|
395
|
+
*
|
|
396
|
+
* @param difficulty The difficulty value to be mapped.
|
|
397
|
+
* @param min Minimum of the resulting range which will be achieved by a difficulty value of 0.
|
|
398
|
+
* @param mid Midpoint of the resulting range which will be achieved by a difficulty value of 5.
|
|
399
|
+
* @param max Maximum of the resulting range which will be achieved by a difficulty value of 10.
|
|
400
|
+
*/
|
|
401
|
+
static difficultyRange(difficulty, min, mid, max) {
|
|
402
|
+
switch (true) {
|
|
403
|
+
case difficulty > 5:
|
|
404
|
+
return mid + ((max - mid) * (difficulty - 5)) / 5;
|
|
405
|
+
case difficulty < 5:
|
|
406
|
+
return mid + ((mid - min) * (difficulty - 5)) / 5;
|
|
407
|
+
default:
|
|
408
|
+
return mid;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Inverse function to `difficultyRange`. Maps a value returned by the function back to the
|
|
413
|
+
* difficulty that produced it.
|
|
414
|
+
*
|
|
415
|
+
* @param difficultyValue The difficulty-dependent value to be unmapped.
|
|
416
|
+
* @param diff0 Minimum of the resulting range which will be achieved by a difficulty value of 0.
|
|
417
|
+
* @param diff5 Midpoint of the resulting range which will be achieved by a difficulty value of 5.
|
|
418
|
+
* @param diff10 Maximum of the resulting range which will be achieved by a difficulty value of 10.
|
|
419
|
+
* @return The value to which the difficulty value maps in the specified range.
|
|
420
|
+
*/
|
|
421
|
+
static inverseDifficultyRange(difficultyValue, diff0, diff5, diff10) {
|
|
422
|
+
if (Math.sign(difficultyValue - diff5) == Math.sign(diff10 - diff0)) {
|
|
423
|
+
return ((difficultyValue - diff5) / (diff10 - diff5)) * 5 + 5;
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
return ((difficultyValue - diff5) / (diff5 - diff0)) * 5 + 5;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
393
429
|
constructor(shallowCopy) {
|
|
394
430
|
/**
|
|
395
431
|
* The circle size of the beatmap.
|
|
@@ -568,477 +604,6 @@ CircleSizeCalculator.brokenGamefieldRoundingAllowance = 1.00041;
|
|
|
568
604
|
*/
|
|
569
605
|
CircleSizeCalculator.assumedDroidHeight = 681;
|
|
570
606
|
|
|
571
|
-
/**
|
|
572
|
-
* Represents a mod.
|
|
573
|
-
*/
|
|
574
|
-
class Mod {
|
|
575
|
-
/**
|
|
576
|
-
* Whether this mod can be applied to osu!droid.
|
|
577
|
-
*/
|
|
578
|
-
isApplicableToDroid() {
|
|
579
|
-
return "droidRanked" in this;
|
|
580
|
-
}
|
|
581
|
-
/**
|
|
582
|
-
* Whether this mod can be applied to osu!standard.
|
|
583
|
-
*/
|
|
584
|
-
isApplicableToOsu() {
|
|
585
|
-
return "pcRanked" in this;
|
|
586
|
-
}
|
|
587
|
-
/**
|
|
588
|
-
* Whether this mod can be applied to a beatmap.
|
|
589
|
-
*/
|
|
590
|
-
isApplicableToBeatmap() {
|
|
591
|
-
return "applyToBeatmap" in this;
|
|
592
|
-
}
|
|
593
|
-
/**
|
|
594
|
-
* Whether this mod can be applied to a beatmap difficulty.
|
|
595
|
-
*/
|
|
596
|
-
isApplicableToDifficulty() {
|
|
597
|
-
return "applyToDifficulty" in this;
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* Whether this mod can be applied to a beatmap difficulty relative to other mods and settings.
|
|
601
|
-
*/
|
|
602
|
-
isApplicableToDifficultyWithSettings() {
|
|
603
|
-
return "applyToDifficultyWithSettings" in this;
|
|
604
|
-
}
|
|
605
|
-
/**
|
|
606
|
-
* Whether this mod can be applied to a hitobject.
|
|
607
|
-
*/
|
|
608
|
-
isApplicableToHitObject() {
|
|
609
|
-
return "applyToHitObject" in this;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
/**
|
|
614
|
-
* Represents the difficulty adjust (DA) mod.
|
|
615
|
-
*
|
|
616
|
-
* This is not a real mod in osu! but is used to force difficulty values in the game.
|
|
617
|
-
*/
|
|
618
|
-
class ModDifficultyAdjust extends Mod {
|
|
619
|
-
constructor(values) {
|
|
620
|
-
super();
|
|
621
|
-
this.acronym = "DA";
|
|
622
|
-
this.name = "Difficulty Adjust";
|
|
623
|
-
this.droidRanked = false;
|
|
624
|
-
this.droidScoreMultiplier = 1;
|
|
625
|
-
this.droidString = "";
|
|
626
|
-
this.isDroidLegacyMod = false;
|
|
627
|
-
this.pcRanked = false;
|
|
628
|
-
this.pcScoreMultiplier = 1;
|
|
629
|
-
this.bitwise = 0;
|
|
630
|
-
this.cs = values === null || values === void 0 ? void 0 : values.cs;
|
|
631
|
-
this.ar = values === null || values === void 0 ? void 0 : values.ar;
|
|
632
|
-
this.od = values === null || values === void 0 ? void 0 : values.od;
|
|
633
|
-
this.hp = values === null || values === void 0 ? void 0 : values.hp;
|
|
634
|
-
}
|
|
635
|
-
applyToDifficulty(mode, difficulty) {
|
|
636
|
-
if (this.cs !== undefined) {
|
|
637
|
-
difficulty.cs = this.cs;
|
|
638
|
-
}
|
|
639
|
-
if (this.ar !== undefined) {
|
|
640
|
-
difficulty.ar = this.ar;
|
|
641
|
-
}
|
|
642
|
-
if (this.od !== undefined) {
|
|
643
|
-
difficulty.od = this.od;
|
|
644
|
-
}
|
|
645
|
-
if (this.hp !== undefined) {
|
|
646
|
-
difficulty.hp = this.hp;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
/**
|
|
652
|
-
* Represents the DoubleTime mod.
|
|
653
|
-
*/
|
|
654
|
-
class ModDoubleTime extends Mod {
|
|
655
|
-
constructor() {
|
|
656
|
-
super(...arguments);
|
|
657
|
-
this.acronym = "DT";
|
|
658
|
-
this.name = "DoubleTime";
|
|
659
|
-
this.droidRanked = true;
|
|
660
|
-
this.droidScoreMultiplier = 1.12;
|
|
661
|
-
this.droidString = "d";
|
|
662
|
-
this.isDroidLegacyMod = false;
|
|
663
|
-
this.pcRanked = true;
|
|
664
|
-
this.pcScoreMultiplier = 1.12;
|
|
665
|
-
this.bitwise = 1 << 6;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
/**
|
|
670
|
-
* Represents the HalfTime mod.
|
|
671
|
-
*/
|
|
672
|
-
class ModHalfTime extends Mod {
|
|
673
|
-
constructor() {
|
|
674
|
-
super(...arguments);
|
|
675
|
-
this.acronym = "HT";
|
|
676
|
-
this.name = "HalfTime";
|
|
677
|
-
this.droidRanked = true;
|
|
678
|
-
this.droidScoreMultiplier = 0.3;
|
|
679
|
-
this.droidString = "t";
|
|
680
|
-
this.isDroidLegacyMod = false;
|
|
681
|
-
this.pcRanked = true;
|
|
682
|
-
this.pcScoreMultiplier = 0.3;
|
|
683
|
-
this.bitwise = 1 << 8;
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
/**
|
|
688
|
-
* Represents the NightCore mod.
|
|
689
|
-
*/
|
|
690
|
-
class ModNightCore extends Mod {
|
|
691
|
-
constructor() {
|
|
692
|
-
super(...arguments);
|
|
693
|
-
this.acronym = "NC";
|
|
694
|
-
this.name = "NightCore";
|
|
695
|
-
this.droidRanked = true;
|
|
696
|
-
this.droidString = "c";
|
|
697
|
-
this.isDroidLegacyMod = false;
|
|
698
|
-
this.droidScoreMultiplier = 1.12;
|
|
699
|
-
this.pcRanked = true;
|
|
700
|
-
this.pcScoreMultiplier = 1.12;
|
|
701
|
-
this.bitwise = 1 << 9;
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
/**
|
|
706
|
-
* Represents the Precise mod.
|
|
707
|
-
*/
|
|
708
|
-
class ModPrecise extends Mod {
|
|
709
|
-
constructor() {
|
|
710
|
-
super(...arguments);
|
|
711
|
-
this.acronym = "PR";
|
|
712
|
-
this.name = "Precise";
|
|
713
|
-
this.droidRanked = true;
|
|
714
|
-
this.droidScoreMultiplier = 1.06;
|
|
715
|
-
this.droidString = "s";
|
|
716
|
-
this.isDroidLegacyMod = false;
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
/**
|
|
721
|
-
* Represents the SpeedUp mod.
|
|
722
|
-
*/
|
|
723
|
-
class ModSpeedUp extends Mod {
|
|
724
|
-
constructor() {
|
|
725
|
-
super(...arguments);
|
|
726
|
-
this.acronym = "SU";
|
|
727
|
-
this.name = "Speed Up";
|
|
728
|
-
this.droidRanked = false;
|
|
729
|
-
this.droidScoreMultiplier = 1.06;
|
|
730
|
-
this.droidString = "b";
|
|
731
|
-
this.isDroidLegacyMod = true;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
class HitWindow {
|
|
736
|
-
/**
|
|
737
|
-
* @param overallDifficulty The overall difficulty of this hit window.
|
|
738
|
-
*/
|
|
739
|
-
constructor(overallDifficulty) {
|
|
740
|
-
this.overallDifficulty = overallDifficulty;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
/**
|
|
744
|
-
* Represents the hit window of osu!droid.
|
|
745
|
-
*/
|
|
746
|
-
class DroidHitWindow extends HitWindow {
|
|
747
|
-
/**
|
|
748
|
-
* Calculates the overall difficulty value of a great hit window.
|
|
749
|
-
*
|
|
750
|
-
* @param value The value of the hit window, in milliseconds.
|
|
751
|
-
* @param isPrecise Whether to calculate for Precise mod.
|
|
752
|
-
* @returns The overall difficulty value.
|
|
753
|
-
*/
|
|
754
|
-
static hitWindow300ToOD(value, isPrecise) {
|
|
755
|
-
if (isPrecise) {
|
|
756
|
-
return 5 - (value - 55) / 6;
|
|
757
|
-
}
|
|
758
|
-
else {
|
|
759
|
-
return 5 - (value - 75) / 5;
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
/**
|
|
763
|
-
* Calculates the overall difficulty value of a good hit window.
|
|
764
|
-
*
|
|
765
|
-
* @param value The value of the hit window, in milliseconds.
|
|
766
|
-
* @param isPrecise Whether to calculate for Precise mod.
|
|
767
|
-
* @returns The overall difficulty value.
|
|
768
|
-
*/
|
|
769
|
-
static hitWindow100ToOD(value, isPrecise) {
|
|
770
|
-
if (isPrecise) {
|
|
771
|
-
return 5 - (value - 120) / 8;
|
|
772
|
-
}
|
|
773
|
-
else {
|
|
774
|
-
return 5 - (value - 150) / 10;
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
/**
|
|
778
|
-
* Calculates the overall difficulty value of a meh hit window.
|
|
779
|
-
*
|
|
780
|
-
* @param value The value of the hit window, in milliseconds.
|
|
781
|
-
* @param isPrecise Whether to calculate for Precise mod.
|
|
782
|
-
* @returns The overall difficulty value.
|
|
783
|
-
*/
|
|
784
|
-
static hitWindow50ToOD(value, isPrecise) {
|
|
785
|
-
if (isPrecise) {
|
|
786
|
-
return 5 - (value - 180) / 10;
|
|
787
|
-
}
|
|
788
|
-
else {
|
|
789
|
-
return 5 - (value - 250) / 10;
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
hitWindowFor300(isPrecise) {
|
|
793
|
-
if (isPrecise) {
|
|
794
|
-
return 55 + 6 * (5 - this.overallDifficulty);
|
|
795
|
-
}
|
|
796
|
-
else {
|
|
797
|
-
return 75 + 5 * (5 - this.overallDifficulty);
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
hitWindowFor100(isPrecise) {
|
|
801
|
-
if (isPrecise) {
|
|
802
|
-
return 120 + 8 * (5 - this.overallDifficulty);
|
|
803
|
-
}
|
|
804
|
-
else {
|
|
805
|
-
return 150 + 10 * (5 - this.overallDifficulty);
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
hitWindowFor50(isPrecise) {
|
|
809
|
-
if (isPrecise) {
|
|
810
|
-
return 180 + 10 * (5 - this.overallDifficulty);
|
|
811
|
-
}
|
|
812
|
-
else {
|
|
813
|
-
return 250 + 10 * (5 - this.overallDifficulty);
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
/**
|
|
818
|
-
* Represents the hit window of osu!standard.
|
|
819
|
-
*/
|
|
820
|
-
class OsuHitWindow extends HitWindow {
|
|
821
|
-
/**
|
|
822
|
-
* Calculates the overall difficulty value of a great hit window.
|
|
823
|
-
*
|
|
824
|
-
* @param value The value of the hit window, in milliseconds.
|
|
825
|
-
* @returns The overall difficulty value.
|
|
826
|
-
*/
|
|
827
|
-
static hitWindow300ToOD(value) {
|
|
828
|
-
return (80 - value) / 6;
|
|
829
|
-
}
|
|
830
|
-
/**
|
|
831
|
-
* Calculates the overall difficulty value of a good hit window.
|
|
832
|
-
*
|
|
833
|
-
* @param value The value of the hit window, in milliseconds.
|
|
834
|
-
* @returns The overall difficulty value.
|
|
835
|
-
*/
|
|
836
|
-
static hitWindow100ToOD(value) {
|
|
837
|
-
return (140 - value) / 8;
|
|
838
|
-
}
|
|
839
|
-
/**
|
|
840
|
-
* Calculates the overall difficulty value of a meh hit window.
|
|
841
|
-
*
|
|
842
|
-
* @param value The value of the hit window, in milliseconds.
|
|
843
|
-
* @returns The overall difficulty value.
|
|
844
|
-
*/
|
|
845
|
-
static hitWindow50ToOD(value) {
|
|
846
|
-
return (200 - value) / 10;
|
|
847
|
-
}
|
|
848
|
-
hitWindowFor300() {
|
|
849
|
-
return 80 - 6 * this.overallDifficulty;
|
|
850
|
-
}
|
|
851
|
-
hitWindowFor100() {
|
|
852
|
-
return 140 - 8 * this.overallDifficulty;
|
|
853
|
-
}
|
|
854
|
-
hitWindowFor50() {
|
|
855
|
-
return 200 - 10 * this.overallDifficulty;
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
/**
|
|
860
|
-
* Calculates the osu!droid difficulty statistics of a beatmap.
|
|
861
|
-
*
|
|
862
|
-
* This provides functionality to apply speed-changing mods to the difficulty statistics.
|
|
863
|
-
*
|
|
864
|
-
* @param options The options for the difficulty statistics calculator.
|
|
865
|
-
* @returns The difficulty statistics of the beatmap.
|
|
866
|
-
*/
|
|
867
|
-
function calculateDroidDifficultyStatistics(options) {
|
|
868
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
869
|
-
const overallSpeedMultiplier = calculateSpeedMultiplierFromMods((_a = options.mods) !== null && _a !== void 0 ? _a : [], options.oldStatistics) * ((_b = options.customSpeedMultiplier) !== null && _b !== void 0 ? _b : 1);
|
|
870
|
-
const difficulty = new BeatmapDifficulty();
|
|
871
|
-
difficulty.cs = (_c = options.circleSize) !== null && _c !== void 0 ? _c : difficulty.cs;
|
|
872
|
-
difficulty.ar = (_d = options.approachRate) !== null && _d !== void 0 ? _d : difficulty.ar;
|
|
873
|
-
difficulty.od = (_e = options.overallDifficulty) !== null && _e !== void 0 ? _e : difficulty.od;
|
|
874
|
-
difficulty.hp = (_f = options.healthDrain) !== null && _f !== void 0 ? _f : difficulty.hp;
|
|
875
|
-
const difficultyAdjustMod = (_g = options.mods) === null || _g === void 0 ? void 0 : _g.find((mod) => mod instanceof ModDifficultyAdjust);
|
|
876
|
-
(_h = options.mods) === null || _h === void 0 ? void 0 : _h.forEach((mod) => {
|
|
877
|
-
if (mod.isApplicableToDifficulty()) {
|
|
878
|
-
mod.applyToDifficulty(exports.Modes.droid, difficulty);
|
|
879
|
-
}
|
|
880
|
-
});
|
|
881
|
-
// Special handling for difficulty adjust mod where difficulty statistics are forced.
|
|
882
|
-
difficultyAdjustMod === null || difficultyAdjustMod === void 0 ? void 0 : difficultyAdjustMod.applyToDifficulty(exports.Modes.droid, difficulty);
|
|
883
|
-
(_j = options.mods) === null || _j === void 0 ? void 0 : _j.forEach((mod, _, arr) => {
|
|
884
|
-
var _a;
|
|
885
|
-
if (mod.isApplicableToDifficultyWithSettings()) {
|
|
886
|
-
mod.applyToDifficultyWithSettings(exports.Modes.droid, difficulty, arr, (_a = options.customSpeedMultiplier) !== null && _a !== void 0 ? _a : 1);
|
|
887
|
-
}
|
|
888
|
-
});
|
|
889
|
-
if (options.circleSize !== undefined &&
|
|
890
|
-
options.convertCircleSize !== false) {
|
|
891
|
-
const scale = CircleSizeCalculator.droidCSToDroidScale(difficulty.cs);
|
|
892
|
-
const radius = CircleSizeCalculator.droidScaleToStandardRadius(scale);
|
|
893
|
-
difficulty.cs = CircleSizeCalculator.standardRadiusToStandardCS(radius, true);
|
|
894
|
-
}
|
|
895
|
-
// Apply speed-changing mods
|
|
896
|
-
if (options.approachRate !== undefined &&
|
|
897
|
-
(difficultyAdjustMod === null || difficultyAdjustMod === void 0 ? void 0 : difficultyAdjustMod.ar) === undefined) {
|
|
898
|
-
const approachRateMilliseconds = convertApproachRateToMilliseconds(difficulty.ar) /
|
|
899
|
-
overallSpeedMultiplier;
|
|
900
|
-
difficulty.ar = convertApproachRateMilliseconds(approachRateMilliseconds);
|
|
901
|
-
}
|
|
902
|
-
if (options.overallDifficulty !== undefined) {
|
|
903
|
-
const isPrecise = (_l = (_k = options.mods) === null || _k === void 0 ? void 0 : _k.some((mod) => mod instanceof ModPrecise)) !== null && _l !== void 0 ? _l : false;
|
|
904
|
-
let hitWindowGreat = new DroidHitWindow(difficulty.od).hitWindowFor300(isPrecise);
|
|
905
|
-
if ((difficultyAdjustMod === null || difficultyAdjustMod === void 0 ? void 0 : difficultyAdjustMod.od) === undefined) {
|
|
906
|
-
hitWindowGreat /= overallSpeedMultiplier;
|
|
907
|
-
}
|
|
908
|
-
difficulty.od =
|
|
909
|
-
options.convertOverallDifficulty !== false
|
|
910
|
-
? OsuHitWindow.hitWindow300ToOD(hitWindowGreat)
|
|
911
|
-
: DroidHitWindow.hitWindow300ToOD(hitWindowGreat, isPrecise);
|
|
912
|
-
}
|
|
913
|
-
return {
|
|
914
|
-
circleSize: (options.circleSize !== undefined
|
|
915
|
-
? difficulty.cs
|
|
916
|
-
: undefined),
|
|
917
|
-
approachRate: (options.approachRate !== undefined
|
|
918
|
-
? difficulty.ar
|
|
919
|
-
: undefined),
|
|
920
|
-
overallDifficulty: (options.overallDifficulty !== undefined
|
|
921
|
-
? difficulty.od
|
|
922
|
-
: undefined),
|
|
923
|
-
healthDrain: (options.healthDrain !== undefined
|
|
924
|
-
? difficulty.hp
|
|
925
|
-
: undefined),
|
|
926
|
-
overallSpeedMultiplier: overallSpeedMultiplier,
|
|
927
|
-
};
|
|
928
|
-
}
|
|
929
|
-
/**
|
|
930
|
-
* Calculates the osu!standard difficulty statistics of a beatmap.
|
|
931
|
-
*
|
|
932
|
-
* This provides functionality to apply speed-changing mods to the difficulty statistics.
|
|
933
|
-
*
|
|
934
|
-
* @param options The options for the difficulty statistics calculator.
|
|
935
|
-
* @returns The difficulty statistics of the beatmap.
|
|
936
|
-
*/
|
|
937
|
-
function calculateOsuDifficultyStatistics(options) {
|
|
938
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
939
|
-
const overallSpeedMultiplier = calculateSpeedMultiplierFromMods((_a = options.mods) !== null && _a !== void 0 ? _a : []) *
|
|
940
|
-
((_b = options.customSpeedMultiplier) !== null && _b !== void 0 ? _b : 1);
|
|
941
|
-
const difficulty = new BeatmapDifficulty();
|
|
942
|
-
difficulty.cs = (_c = options.circleSize) !== null && _c !== void 0 ? _c : difficulty.cs;
|
|
943
|
-
difficulty.ar = (_d = options.approachRate) !== null && _d !== void 0 ? _d : difficulty.ar;
|
|
944
|
-
difficulty.od = (_e = options.overallDifficulty) !== null && _e !== void 0 ? _e : difficulty.od;
|
|
945
|
-
difficulty.hp = (_f = options.healthDrain) !== null && _f !== void 0 ? _f : difficulty.hp;
|
|
946
|
-
const difficultyAdjustMod = (_g = options.mods) === null || _g === void 0 ? void 0 : _g.find((mod) => mod instanceof ModDifficultyAdjust);
|
|
947
|
-
(_h = options.mods) === null || _h === void 0 ? void 0 : _h.forEach((mod) => {
|
|
948
|
-
if (mod.isApplicableToDifficulty()) {
|
|
949
|
-
mod.applyToDifficulty(exports.Modes.osu, difficulty);
|
|
950
|
-
}
|
|
951
|
-
});
|
|
952
|
-
// Special handling for difficulty adjust mod where difficulty statistics are forced.
|
|
953
|
-
difficultyAdjustMod === null || difficultyAdjustMod === void 0 ? void 0 : difficultyAdjustMod.applyToDifficulty(exports.Modes.osu, difficulty);
|
|
954
|
-
(_j = options.mods) === null || _j === void 0 ? void 0 : _j.forEach((mod, _, arr) => {
|
|
955
|
-
var _a;
|
|
956
|
-
if (mod.isApplicableToDifficultyWithSettings()) {
|
|
957
|
-
mod.applyToDifficultyWithSettings(exports.Modes.osu, difficulty, arr, (_a = options.customSpeedMultiplier) !== null && _a !== void 0 ? _a : 1);
|
|
958
|
-
}
|
|
959
|
-
});
|
|
960
|
-
// Apply speed-changing mods
|
|
961
|
-
if (options.approachRate !== undefined &&
|
|
962
|
-
(difficultyAdjustMod === null || difficultyAdjustMod === void 0 ? void 0 : difficultyAdjustMod.ar) === undefined) {
|
|
963
|
-
const approachRateMilliseconds = convertApproachRateToMilliseconds(difficulty.ar) /
|
|
964
|
-
overallSpeedMultiplier;
|
|
965
|
-
difficulty.ar = convertApproachRateMilliseconds(approachRateMilliseconds);
|
|
966
|
-
}
|
|
967
|
-
if (options.overallDifficulty !== undefined &&
|
|
968
|
-
(difficultyAdjustMod === null || difficultyAdjustMod === void 0 ? void 0 : difficultyAdjustMod.od) === undefined) {
|
|
969
|
-
const hitWindowGreat = new OsuHitWindow(difficulty.od).hitWindowFor300() /
|
|
970
|
-
overallSpeedMultiplier;
|
|
971
|
-
difficulty.od = OsuHitWindow.hitWindow300ToOD(hitWindowGreat);
|
|
972
|
-
}
|
|
973
|
-
return {
|
|
974
|
-
circleSize: (options.circleSize !== undefined
|
|
975
|
-
? difficulty.cs
|
|
976
|
-
: undefined),
|
|
977
|
-
approachRate: (options.approachRate !== undefined
|
|
978
|
-
? difficulty.ar
|
|
979
|
-
: undefined),
|
|
980
|
-
overallDifficulty: (options.overallDifficulty !== undefined
|
|
981
|
-
? difficulty.od
|
|
982
|
-
: undefined),
|
|
983
|
-
healthDrain: (options.healthDrain !== undefined
|
|
984
|
-
? difficulty.hp
|
|
985
|
-
: undefined),
|
|
986
|
-
overallSpeedMultiplier: overallSpeedMultiplier,
|
|
987
|
-
};
|
|
988
|
-
}
|
|
989
|
-
/**
|
|
990
|
-
* Calculates the speed multiplier obtained from mods.
|
|
991
|
-
*
|
|
992
|
-
* @param mods The mods to calculate the speed multiplier from.
|
|
993
|
-
* @param oldStatistics Whether to calculate for old statistics for osu!droid (1.6.7 and older). Defaults to `false`.
|
|
994
|
-
* @returns The speed multiplier obtained from the mods.
|
|
995
|
-
*/
|
|
996
|
-
function calculateSpeedMultiplierFromMods(mods, oldStatistics) {
|
|
997
|
-
let speedMultiplier = 1;
|
|
998
|
-
for (const mod of mods) {
|
|
999
|
-
switch (true) {
|
|
1000
|
-
case mod instanceof ModDoubleTime:
|
|
1001
|
-
speedMultiplier *= 1.5;
|
|
1002
|
-
break;
|
|
1003
|
-
case mod instanceof ModHalfTime:
|
|
1004
|
-
speedMultiplier *= 0.75;
|
|
1005
|
-
break;
|
|
1006
|
-
case mod instanceof ModNightCore:
|
|
1007
|
-
speedMultiplier *= oldStatistics ? 1.39 : 1.5;
|
|
1008
|
-
break;
|
|
1009
|
-
case mod instanceof ModSpeedUp:
|
|
1010
|
-
speedMultiplier *= 1.25;
|
|
1011
|
-
break;
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
return speedMultiplier;
|
|
1015
|
-
}
|
|
1016
|
-
const AR0_MS = 1800;
|
|
1017
|
-
const AR5_MS = 1200;
|
|
1018
|
-
const AR10_MS = 450;
|
|
1019
|
-
const AR_MS_STEP1 = (AR0_MS - AR5_MS) / 5;
|
|
1020
|
-
const AR_MS_STEP2 = (AR5_MS - AR10_MS) / 5;
|
|
1021
|
-
/**
|
|
1022
|
-
* Converts an approach rate value to its milliseconds counterpart.
|
|
1023
|
-
*
|
|
1024
|
-
* @param ar The approach rate to convert.
|
|
1025
|
-
* @returns The converted approach rate in milliseconds.
|
|
1026
|
-
*/
|
|
1027
|
-
function convertApproachRateToMilliseconds(ar) {
|
|
1028
|
-
return ar < 5 ? AR0_MS - AR_MS_STEP1 * ar : AR5_MS - AR_MS_STEP2 * (ar - 5);
|
|
1029
|
-
}
|
|
1030
|
-
/**
|
|
1031
|
-
* Converts an approach rate value in milliseconds to its approach rate value counterpart.
|
|
1032
|
-
*
|
|
1033
|
-
* @param ms The approach rate in milliseconds to convert.
|
|
1034
|
-
* @returns The converted approach rate value.
|
|
1035
|
-
*/
|
|
1036
|
-
function convertApproachRateMilliseconds(ms) {
|
|
1037
|
-
return ms > AR5_MS
|
|
1038
|
-
? (AR0_MS - ms) / AR_MS_STEP1
|
|
1039
|
-
: 5 + (AR5_MS - ms) / AR_MS_STEP2;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
607
|
/**
|
|
1043
608
|
* Represents a hitobject in a beatmap.
|
|
1044
609
|
*/
|
|
@@ -1162,17 +727,18 @@ class HitObject {
|
|
|
1162
727
|
* @param mode The gamemode to apply defaults for.
|
|
1163
728
|
*/
|
|
1164
729
|
applyDefaults(controlPoints, difficulty, mode) {
|
|
1165
|
-
this.timePreempt =
|
|
730
|
+
this.timePreempt = BeatmapDifficulty.difficultyRange(difficulty.ar, HitObject.preemptMax, HitObject.preemptMid, HitObject.preemptMin);
|
|
1166
731
|
// Preempt time can go below 450ms. Normally, this is achieved via the DT mod which uniformly speeds up all animations game wide regardless of AR.
|
|
1167
732
|
// This uniform speedup is hard to match 1:1, however we can at least make AR>10 (via mods) feel good by extending the upper linear function above.
|
|
1168
733
|
// Note that this doesn't exactly match the AR>10 visuals as they're classically known, but it feels good.
|
|
1169
734
|
// This adjustment is necessary for AR>10, otherwise timePreempt can become smaller leading to hit circles not fully fading in.
|
|
1170
|
-
this.timeFadeIn =
|
|
735
|
+
this.timeFadeIn =
|
|
736
|
+
400 * Math.min(1, this.timePreempt / HitObject.preemptMin);
|
|
1171
737
|
switch (mode) {
|
|
1172
738
|
case exports.Modes.droid: {
|
|
1173
|
-
const
|
|
1174
|
-
|
|
1175
|
-
|
|
739
|
+
const droidScale = CircleSizeCalculator.droidCSToDroidScale(difficulty.cs);
|
|
740
|
+
const radius = CircleSizeCalculator.droidScaleToStandardRadius(droidScale);
|
|
741
|
+
const cs = CircleSizeCalculator.standardRadiusToStandardCS(radius, true);
|
|
1176
742
|
this.scale = CircleSizeCalculator.standardCSToStandardScale(cs, true);
|
|
1177
743
|
break;
|
|
1178
744
|
}
|
|
@@ -1261,6 +827,18 @@ class HitObject {
|
|
|
1261
827
|
* The base radius of all hitobjects.
|
|
1262
828
|
*/
|
|
1263
829
|
HitObject.baseRadius = 64;
|
|
830
|
+
/**
|
|
831
|
+
* Maximum preempt time at AR=0.
|
|
832
|
+
*/
|
|
833
|
+
HitObject.preemptMax = 1800;
|
|
834
|
+
/**
|
|
835
|
+
* Median preempt time at AR=5.
|
|
836
|
+
*/
|
|
837
|
+
HitObject.preemptMid = 1200;
|
|
838
|
+
/**
|
|
839
|
+
* Minimum preempt time at AR=10.
|
|
840
|
+
*/
|
|
841
|
+
HitObject.preemptMin = 450;
|
|
1264
842
|
/**
|
|
1265
843
|
* A small adjustment to the start time of control points to account for rounding/precision errors.
|
|
1266
844
|
*/
|
|
@@ -2588,8 +2166,9 @@ class BeatmapProcessor {
|
|
|
2588
2166
|
for (let i = 0; i < objects.length - 1; ++i) {
|
|
2589
2167
|
const current = objects[i];
|
|
2590
2168
|
const next = objects[i + 1];
|
|
2591
|
-
if (
|
|
2592
|
-
|
|
2169
|
+
if (current instanceof Circle &&
|
|
2170
|
+
next.startTime - current.startTime <
|
|
2171
|
+
2000 * this.beatmap.general.stackLeniency &&
|
|
2593
2172
|
next.position.getDistance(current.position) <
|
|
2594
2173
|
Math.sqrt(convertedScale)) {
|
|
2595
2174
|
next.stackHeight = current.stackHeight + 1;
|
|
@@ -3037,9 +2616,6 @@ class Beatmap {
|
|
|
3037
2616
|
mod.applyToDifficulty(mode, converted.difficulty);
|
|
3038
2617
|
}
|
|
3039
2618
|
});
|
|
3040
|
-
// Special handling for difficulty adjust mod where difficulty statistics are forced.
|
|
3041
|
-
const difficultyAdjustMod = mods.find((m) => m instanceof ModDifficultyAdjust);
|
|
3042
|
-
difficultyAdjustMod === null || difficultyAdjustMod === void 0 ? void 0 : difficultyAdjustMod.applyToDifficulty(mode, converted.difficulty);
|
|
3043
2619
|
mods.forEach((mod) => {
|
|
3044
2620
|
if (mod.isApplicableToDifficultyWithSettings()) {
|
|
3045
2621
|
mod.applyToDifficultyWithSettings(mode, converted.difficulty, mods, customSpeedMultiplier);
|
|
@@ -3054,6 +2630,13 @@ class Beatmap {
|
|
|
3054
2630
|
}
|
|
3055
2631
|
}
|
|
3056
2632
|
});
|
|
2633
|
+
mods.forEach((mod) => {
|
|
2634
|
+
if (mod.isApplicableToHitObjectWithSettings()) {
|
|
2635
|
+
for (const hitObject of converted.hitObjects.objects) {
|
|
2636
|
+
mod.applyToHitObjectWithSettings(mode, hitObject, mods, customSpeedMultiplier);
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
});
|
|
3057
2640
|
new BeatmapProcessor(converted).postProcess(mode);
|
|
3058
2641
|
mods.forEach((mod) => {
|
|
3059
2642
|
if (mod.isApplicableToBeatmap()) {
|
|
@@ -5658,7 +5241,7 @@ class BeatmapBaseEncoder extends BaseEncoder {
|
|
|
5658
5241
|
*/
|
|
5659
5242
|
class BeatmapColorEncoder extends BeatmapBaseEncoder {
|
|
5660
5243
|
encodeInternal() {
|
|
5661
|
-
const colors = this.map
|
|
5244
|
+
const { colors } = this.map;
|
|
5662
5245
|
if (colors.combo.length === 0 &&
|
|
5663
5246
|
!colors.sliderBorder &&
|
|
5664
5247
|
!colors.sliderTrackOverride) {
|
|
@@ -5778,7 +5361,7 @@ class BeatmapDifficultyEncoder extends BeatmapBaseEncoder {
|
|
|
5778
5361
|
if (this.encodeSections) {
|
|
5779
5362
|
this.writeLine("[Difficulty]");
|
|
5780
5363
|
}
|
|
5781
|
-
const difficulty = this.map
|
|
5364
|
+
const { difficulty } = this.map;
|
|
5782
5365
|
this.writeLine(`HPDrainRate: ${difficulty.hp}`);
|
|
5783
5366
|
this.writeLine(`CircleSize: ${difficulty.cs}`);
|
|
5784
5367
|
this.writeLine(`OverallDifficulty: ${difficulty.od}`);
|
|
@@ -5796,7 +5379,7 @@ class BeatmapEditorEncoder extends BeatmapBaseEncoder {
|
|
|
5796
5379
|
if (this.encodeSections) {
|
|
5797
5380
|
this.writeLine("[Editor]");
|
|
5798
5381
|
}
|
|
5799
|
-
const editor = this.map
|
|
5382
|
+
const { editor } = this.map;
|
|
5800
5383
|
if (editor.bookmarks.length > 0) {
|
|
5801
5384
|
this.writeLine(editor.bookmarks.join());
|
|
5802
5385
|
}
|
|
@@ -6010,7 +5593,7 @@ class StoryboardEncoder extends Encoder {
|
|
|
6010
5593
|
reset() {
|
|
6011
5594
|
this.finalResult = "";
|
|
6012
5595
|
this.encoders = [
|
|
6013
|
-
// The variable decoder is put first as
|
|
5596
|
+
// The variable decoder is put first as variables need to be on top of a .osb file.
|
|
6014
5597
|
new StoryboardVariablesEncoder(this.target, this.encodeSections),
|
|
6015
5598
|
new StoryboardEventsEncoder(this.target, this.encodeSections),
|
|
6016
5599
|
];
|
|
@@ -6026,7 +5609,7 @@ class BeatmapEventsEncoder extends BeatmapBaseEncoder {
|
|
|
6026
5609
|
this.writeLine("[Events]");
|
|
6027
5610
|
}
|
|
6028
5611
|
this.writeLine("//Background and Video Events");
|
|
6029
|
-
const events = this.map
|
|
5612
|
+
const { events } = this.map;
|
|
6030
5613
|
if (events.background) {
|
|
6031
5614
|
this.writeLine(`0,0,"${events.background.filename}",${events.background.offset.x},${events.background.offset.y}`);
|
|
6032
5615
|
}
|
|
@@ -6059,7 +5642,7 @@ class BeatmapGeneralEncoder extends BeatmapBaseEncoder {
|
|
|
6059
5642
|
if (this.encodeSections) {
|
|
6060
5643
|
this.writeLine("[General]");
|
|
6061
5644
|
}
|
|
6062
|
-
const general = this.map
|
|
5645
|
+
const { general } = this.map;
|
|
6063
5646
|
if (general.audioFilename) {
|
|
6064
5647
|
this.writeLine(`AudioFilename: ${general.audioFilename}`);
|
|
6065
5648
|
}
|
|
@@ -6196,7 +5779,7 @@ class BeatmapMetadataEncoder extends BeatmapBaseEncoder {
|
|
|
6196
5779
|
if (this.encodeSections) {
|
|
6197
5780
|
this.writeLine("[Metadata]");
|
|
6198
5781
|
}
|
|
6199
|
-
const metadata = this.map
|
|
5782
|
+
const { metadata } = this.map;
|
|
6200
5783
|
this.writeLine(`Title: ${metadata.title}`);
|
|
6201
5784
|
if (metadata.titleUnicode) {
|
|
6202
5785
|
this.writeLine(`TitleUnicode: ${metadata.titleUnicode}`);
|
|
@@ -6659,7 +6242,7 @@ class APIRequestBuilder {
|
|
|
6659
6242
|
* @param value The value to add for the parameter.
|
|
6660
6243
|
*/
|
|
6661
6244
|
addParameter(param, value) {
|
|
6662
|
-
this.params.set(param, value);
|
|
6245
|
+
this.params.set(param, value.toString());
|
|
6663
6246
|
return this;
|
|
6664
6247
|
}
|
|
6665
6248
|
/**
|
|
@@ -7509,13 +7092,137 @@ ErrorFunction.ervInvImpGn = [
|
|
|
7509
7092
|
0.13588013010892486e-14, -0.3488903933999489e-21,
|
|
7510
7093
|
];
|
|
7511
7094
|
/**
|
|
7512
|
-
* Polynomial coefficients for a denominator of erfInvImp
|
|
7513
|
-
* calculation for erf^-1(z) in the interval [0.75, 1] with x greater than 44.
|
|
7095
|
+
* Polynomial coefficients for a denominator of erfInvImp
|
|
7096
|
+
* calculation for erf^-1(z) in the interval [0.75, 1] with x greater than 44.
|
|
7097
|
+
*/
|
|
7098
|
+
ErrorFunction.ervInvImpGd = [
|
|
7099
|
+
1, 0.08457462340018994, 0.002820929847262647, 0.4682929219408942e-4,
|
|
7100
|
+
0.3999688121938621e-6, 0.1618092908879045e-8, 0.2315586083102596e-11,
|
|
7101
|
+
];
|
|
7102
|
+
|
|
7103
|
+
class HitWindow {
|
|
7104
|
+
/**
|
|
7105
|
+
* @param overallDifficulty The overall difficulty of this hit window.
|
|
7106
|
+
*/
|
|
7107
|
+
constructor(overallDifficulty) {
|
|
7108
|
+
this.overallDifficulty = overallDifficulty;
|
|
7109
|
+
}
|
|
7110
|
+
}
|
|
7111
|
+
/**
|
|
7112
|
+
* Represents the hit window of osu!droid.
|
|
7113
|
+
*/
|
|
7114
|
+
class DroidHitWindow extends HitWindow {
|
|
7115
|
+
/**
|
|
7116
|
+
* Calculates the overall difficulty value of a great hit window.
|
|
7117
|
+
*
|
|
7118
|
+
* @param value The value of the hit window, in milliseconds.
|
|
7119
|
+
* @param isPrecise Whether to calculate for Precise mod.
|
|
7120
|
+
* @returns The overall difficulty value.
|
|
7121
|
+
*/
|
|
7122
|
+
static hitWindow300ToOD(value, isPrecise) {
|
|
7123
|
+
if (isPrecise) {
|
|
7124
|
+
return 5 - (value - 55) / 6;
|
|
7125
|
+
}
|
|
7126
|
+
else {
|
|
7127
|
+
return 5 - (value - 75) / 5;
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
7130
|
+
/**
|
|
7131
|
+
* Calculates the overall difficulty value of a good hit window.
|
|
7132
|
+
*
|
|
7133
|
+
* @param value The value of the hit window, in milliseconds.
|
|
7134
|
+
* @param isPrecise Whether to calculate for Precise mod.
|
|
7135
|
+
* @returns The overall difficulty value.
|
|
7136
|
+
*/
|
|
7137
|
+
static hitWindow100ToOD(value, isPrecise) {
|
|
7138
|
+
if (isPrecise) {
|
|
7139
|
+
return 5 - (value - 120) / 8;
|
|
7140
|
+
}
|
|
7141
|
+
else {
|
|
7142
|
+
return 5 - (value - 150) / 10;
|
|
7143
|
+
}
|
|
7144
|
+
}
|
|
7145
|
+
/**
|
|
7146
|
+
* Calculates the overall difficulty value of a meh hit window.
|
|
7147
|
+
*
|
|
7148
|
+
* @param value The value of the hit window, in milliseconds.
|
|
7149
|
+
* @param isPrecise Whether to calculate for Precise mod.
|
|
7150
|
+
* @returns The overall difficulty value.
|
|
7151
|
+
*/
|
|
7152
|
+
static hitWindow50ToOD(value, isPrecise) {
|
|
7153
|
+
if (isPrecise) {
|
|
7154
|
+
return 5 - (value - 180) / 10;
|
|
7155
|
+
}
|
|
7156
|
+
else {
|
|
7157
|
+
return 5 - (value - 250) / 10;
|
|
7158
|
+
}
|
|
7159
|
+
}
|
|
7160
|
+
hitWindowFor300(isPrecise) {
|
|
7161
|
+
if (isPrecise) {
|
|
7162
|
+
return 55 + 6 * (5 - this.overallDifficulty);
|
|
7163
|
+
}
|
|
7164
|
+
else {
|
|
7165
|
+
return 75 + 5 * (5 - this.overallDifficulty);
|
|
7166
|
+
}
|
|
7167
|
+
}
|
|
7168
|
+
hitWindowFor100(isPrecise) {
|
|
7169
|
+
if (isPrecise) {
|
|
7170
|
+
return 120 + 8 * (5 - this.overallDifficulty);
|
|
7171
|
+
}
|
|
7172
|
+
else {
|
|
7173
|
+
return 150 + 10 * (5 - this.overallDifficulty);
|
|
7174
|
+
}
|
|
7175
|
+
}
|
|
7176
|
+
hitWindowFor50(isPrecise) {
|
|
7177
|
+
if (isPrecise) {
|
|
7178
|
+
return 180 + 10 * (5 - this.overallDifficulty);
|
|
7179
|
+
}
|
|
7180
|
+
else {
|
|
7181
|
+
return 250 + 10 * (5 - this.overallDifficulty);
|
|
7182
|
+
}
|
|
7183
|
+
}
|
|
7184
|
+
}
|
|
7185
|
+
/**
|
|
7186
|
+
* Represents the hit window of osu!standard.
|
|
7514
7187
|
*/
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7188
|
+
class OsuHitWindow extends HitWindow {
|
|
7189
|
+
/**
|
|
7190
|
+
* Calculates the overall difficulty value of a great hit window.
|
|
7191
|
+
*
|
|
7192
|
+
* @param value The value of the hit window, in milliseconds.
|
|
7193
|
+
* @returns The overall difficulty value.
|
|
7194
|
+
*/
|
|
7195
|
+
static hitWindow300ToOD(value) {
|
|
7196
|
+
return (80 - value) / 6;
|
|
7197
|
+
}
|
|
7198
|
+
/**
|
|
7199
|
+
* Calculates the overall difficulty value of a good hit window.
|
|
7200
|
+
*
|
|
7201
|
+
* @param value The value of the hit window, in milliseconds.
|
|
7202
|
+
* @returns The overall difficulty value.
|
|
7203
|
+
*/
|
|
7204
|
+
static hitWindow100ToOD(value) {
|
|
7205
|
+
return (140 - value) / 8;
|
|
7206
|
+
}
|
|
7207
|
+
/**
|
|
7208
|
+
* Calculates the overall difficulty value of a meh hit window.
|
|
7209
|
+
*
|
|
7210
|
+
* @param value The value of the hit window, in milliseconds.
|
|
7211
|
+
* @returns The overall difficulty value.
|
|
7212
|
+
*/
|
|
7213
|
+
static hitWindow50ToOD(value) {
|
|
7214
|
+
return (200 - value) / 10;
|
|
7215
|
+
}
|
|
7216
|
+
hitWindowFor300() {
|
|
7217
|
+
return 80 - 6 * this.overallDifficulty;
|
|
7218
|
+
}
|
|
7219
|
+
hitWindowFor100() {
|
|
7220
|
+
return 140 - 8 * this.overallDifficulty;
|
|
7221
|
+
}
|
|
7222
|
+
hitWindowFor50() {
|
|
7223
|
+
return 200 - 10 * this.overallDifficulty;
|
|
7224
|
+
}
|
|
7225
|
+
}
|
|
7519
7226
|
|
|
7520
7227
|
/**
|
|
7521
7228
|
* Holds interpolation methods for numbers and vectors.
|
|
@@ -7779,12 +7486,13 @@ class MapInfo {
|
|
|
7779
7486
|
});
|
|
7780
7487
|
}
|
|
7781
7488
|
/**
|
|
7782
|
-
* Constructs a `MapInfo` from an osu! API response
|
|
7489
|
+
* Constructs a `MapInfo` from an osu! API response and (optionally) a parsed `Beatmap`.
|
|
7783
7490
|
*
|
|
7784
7491
|
* @param mapinfo The osu! API response.
|
|
7785
|
-
* @
|
|
7492
|
+
* @param parsedBeatmap The parsed `Beatmap`.
|
|
7493
|
+
* @returns A `MapInfo` instance representing the osu! API response and parsed `Beatmap`.
|
|
7786
7494
|
*/
|
|
7787
|
-
static from(mapinfo) {
|
|
7495
|
+
static from(mapinfo, parsedBeatmap) {
|
|
7788
7496
|
const map = new MapInfo();
|
|
7789
7497
|
const parseDate = (str) => {
|
|
7790
7498
|
const t = str.split(/[- :]/).map((e) => parseInt(e));
|
|
@@ -7842,6 +7550,9 @@ class MapInfo {
|
|
|
7842
7550
|
map.videoAvailable = !!parseInt(mapinfo.video);
|
|
7843
7551
|
map.downloadAvailable = !parseInt(mapinfo.download_unavailable);
|
|
7844
7552
|
map.audioAvailable = !parseInt(mapinfo.audio_unavailable);
|
|
7553
|
+
if (parsedBeatmap) {
|
|
7554
|
+
map.cachedBeatmap = parsedBeatmap;
|
|
7555
|
+
}
|
|
7845
7556
|
return map;
|
|
7846
7557
|
}
|
|
7847
7558
|
/**
|
|
@@ -7939,6 +7650,60 @@ class MapInfo {
|
|
|
7939
7650
|
}
|
|
7940
7651
|
}
|
|
7941
7652
|
|
|
7653
|
+
/**
|
|
7654
|
+
* Represents a mod.
|
|
7655
|
+
*/
|
|
7656
|
+
class Mod {
|
|
7657
|
+
/**
|
|
7658
|
+
* Whether this `Mod` can be applied to osu!droid.
|
|
7659
|
+
*/
|
|
7660
|
+
isApplicableToDroid() {
|
|
7661
|
+
return "droidRanked" in this;
|
|
7662
|
+
}
|
|
7663
|
+
/**
|
|
7664
|
+
* Whether this `Mod` can be applied to osu!standard.
|
|
7665
|
+
*/
|
|
7666
|
+
isApplicableToOsu() {
|
|
7667
|
+
return "pcRanked" in this;
|
|
7668
|
+
}
|
|
7669
|
+
/**
|
|
7670
|
+
* Whether this `Mod` can be applied to a `Beatmap`.
|
|
7671
|
+
*/
|
|
7672
|
+
isApplicableToBeatmap() {
|
|
7673
|
+
return "applyToBeatmap" in this;
|
|
7674
|
+
}
|
|
7675
|
+
/**
|
|
7676
|
+
* Whether this `Mod` can be applied to a `BeatmapDifficulty`.
|
|
7677
|
+
*/
|
|
7678
|
+
isApplicableToDifficulty() {
|
|
7679
|
+
return "applyToDifficulty" in this;
|
|
7680
|
+
}
|
|
7681
|
+
/**
|
|
7682
|
+
* Whether this `Mod` can be applied to a `BeatmapDifficulty` relative to other `Mod`s and settings.
|
|
7683
|
+
*/
|
|
7684
|
+
isApplicableToDifficultyWithSettings() {
|
|
7685
|
+
return "applyToDifficultyWithSettings" in this;
|
|
7686
|
+
}
|
|
7687
|
+
/**
|
|
7688
|
+
* Whether this `Mod` can be applied to a `HitObject`.
|
|
7689
|
+
*/
|
|
7690
|
+
isApplicableToHitObject() {
|
|
7691
|
+
return "applyToHitObject" in this;
|
|
7692
|
+
}
|
|
7693
|
+
/**
|
|
7694
|
+
* Whether this `Mod` can be applied to a `HitObject` relative to other `Mod`s and settings.
|
|
7695
|
+
*/
|
|
7696
|
+
isApplicableToHitObjectWithSettings() {
|
|
7697
|
+
return "applyToHitObjectWithSettings" in this;
|
|
7698
|
+
}
|
|
7699
|
+
/**
|
|
7700
|
+
* Whether this `Mod`s can be applied to a track's playback rate.
|
|
7701
|
+
*/
|
|
7702
|
+
isApplicableToTrackRate() {
|
|
7703
|
+
return "applyToRate" in this;
|
|
7704
|
+
}
|
|
7705
|
+
}
|
|
7706
|
+
|
|
7942
7707
|
/**
|
|
7943
7708
|
* Represents the Auto mod.
|
|
7944
7709
|
*/
|
|
@@ -7975,6 +7740,27 @@ class ModAutopilot extends Mod {
|
|
|
7975
7740
|
}
|
|
7976
7741
|
}
|
|
7977
7742
|
|
|
7743
|
+
/**
|
|
7744
|
+
* Represents the DoubleTime mod.
|
|
7745
|
+
*/
|
|
7746
|
+
class ModDoubleTime extends Mod {
|
|
7747
|
+
constructor() {
|
|
7748
|
+
super(...arguments);
|
|
7749
|
+
this.acronym = "DT";
|
|
7750
|
+
this.name = "DoubleTime";
|
|
7751
|
+
this.droidRanked = true;
|
|
7752
|
+
this.droidScoreMultiplier = 1.12;
|
|
7753
|
+
this.droidString = "d";
|
|
7754
|
+
this.isDroidLegacyMod = false;
|
|
7755
|
+
this.pcRanked = true;
|
|
7756
|
+
this.pcScoreMultiplier = 1.12;
|
|
7757
|
+
this.bitwise = 1 << 6;
|
|
7758
|
+
}
|
|
7759
|
+
applyToRate(rate) {
|
|
7760
|
+
return rate * 1.5;
|
|
7761
|
+
}
|
|
7762
|
+
}
|
|
7763
|
+
|
|
7978
7764
|
/**
|
|
7979
7765
|
* Represents the Easy mod.
|
|
7980
7766
|
*/
|
|
@@ -8025,6 +7811,27 @@ class ModFlashlight extends Mod {
|
|
|
8025
7811
|
}
|
|
8026
7812
|
}
|
|
8027
7813
|
|
|
7814
|
+
/**
|
|
7815
|
+
* Represents the HalfTime mod.
|
|
7816
|
+
*/
|
|
7817
|
+
class ModHalfTime extends Mod {
|
|
7818
|
+
constructor() {
|
|
7819
|
+
super(...arguments);
|
|
7820
|
+
this.acronym = "HT";
|
|
7821
|
+
this.name = "HalfTime";
|
|
7822
|
+
this.droidRanked = true;
|
|
7823
|
+
this.droidScoreMultiplier = 0.3;
|
|
7824
|
+
this.droidString = "t";
|
|
7825
|
+
this.isDroidLegacyMod = false;
|
|
7826
|
+
this.pcRanked = true;
|
|
7827
|
+
this.pcScoreMultiplier = 0.3;
|
|
7828
|
+
this.bitwise = 1 << 8;
|
|
7829
|
+
}
|
|
7830
|
+
applyToRate(rate) {
|
|
7831
|
+
return rate * 0.75;
|
|
7832
|
+
}
|
|
7833
|
+
}
|
|
7834
|
+
|
|
8028
7835
|
/**
|
|
8029
7836
|
* Represents the osu! playfield.
|
|
8030
7837
|
*/
|
|
@@ -8125,6 +7932,27 @@ class ModHidden extends Mod {
|
|
|
8125
7932
|
ModHidden.fadeInDurationMultiplier = 0.4;
|
|
8126
7933
|
ModHidden.fadeOutDurationMultiplier = 0.3;
|
|
8127
7934
|
|
|
7935
|
+
/**
|
|
7936
|
+
* Represents the NightCore mod.
|
|
7937
|
+
*/
|
|
7938
|
+
class ModNightCore extends Mod {
|
|
7939
|
+
constructor() {
|
|
7940
|
+
super(...arguments);
|
|
7941
|
+
this.acronym = "NC";
|
|
7942
|
+
this.name = "NightCore";
|
|
7943
|
+
this.droidRanked = true;
|
|
7944
|
+
this.droidString = "c";
|
|
7945
|
+
this.isDroidLegacyMod = false;
|
|
7946
|
+
this.droidScoreMultiplier = 1.12;
|
|
7947
|
+
this.pcRanked = true;
|
|
7948
|
+
this.pcScoreMultiplier = 1.12;
|
|
7949
|
+
this.bitwise = 1 << 9;
|
|
7950
|
+
}
|
|
7951
|
+
applyToRate(rate, oldStatistics) {
|
|
7952
|
+
return rate * (oldStatistics ? 1.39 : 1.5);
|
|
7953
|
+
}
|
|
7954
|
+
}
|
|
7955
|
+
|
|
8128
7956
|
/**
|
|
8129
7957
|
* Represents the NoFail mod.
|
|
8130
7958
|
*/
|
|
@@ -8161,6 +7989,21 @@ class ModPerfect extends Mod {
|
|
|
8161
7989
|
}
|
|
8162
7990
|
}
|
|
8163
7991
|
|
|
7992
|
+
/**
|
|
7993
|
+
* Represents the Precise mod.
|
|
7994
|
+
*/
|
|
7995
|
+
class ModPrecise extends Mod {
|
|
7996
|
+
constructor() {
|
|
7997
|
+
super(...arguments);
|
|
7998
|
+
this.acronym = "PR";
|
|
7999
|
+
this.name = "Precise";
|
|
8000
|
+
this.droidRanked = true;
|
|
8001
|
+
this.droidScoreMultiplier = 1.06;
|
|
8002
|
+
this.droidString = "s";
|
|
8003
|
+
this.isDroidLegacyMod = false;
|
|
8004
|
+
}
|
|
8005
|
+
}
|
|
8006
|
+
|
|
8164
8007
|
/**
|
|
8165
8008
|
* Represents the ReallyEasy mod.
|
|
8166
8009
|
*/
|
|
@@ -8268,6 +8111,25 @@ class ModSmallCircle extends Mod {
|
|
|
8268
8111
|
}
|
|
8269
8112
|
}
|
|
8270
8113
|
|
|
8114
|
+
/**
|
|
8115
|
+
* Represents the SpeedUp mod.
|
|
8116
|
+
*/
|
|
8117
|
+
class ModSpeedUp extends Mod {
|
|
8118
|
+
constructor() {
|
|
8119
|
+
super(...arguments);
|
|
8120
|
+
this.acronym = "SU";
|
|
8121
|
+
this.name = "Speed Up";
|
|
8122
|
+
this.droidRanked = false;
|
|
8123
|
+
this.droidScoreMultiplier = 1.06;
|
|
8124
|
+
this.droidString = "b";
|
|
8125
|
+
this.isDroidLegacyMod = true;
|
|
8126
|
+
this.trackRateMultiplier = 1.25;
|
|
8127
|
+
}
|
|
8128
|
+
applyToRate(rate) {
|
|
8129
|
+
return rate * 1.25;
|
|
8130
|
+
}
|
|
8131
|
+
}
|
|
8132
|
+
|
|
8271
8133
|
/**
|
|
8272
8134
|
* Represents the SpunOut mod.
|
|
8273
8135
|
*/
|
|
@@ -8420,6 +8282,42 @@ class ModUtil {
|
|
|
8420
8282
|
.slice()
|
|
8421
8283
|
.filter((m) => !this.speedChangingMods.some((v) => m.acronym === v.acronym));
|
|
8422
8284
|
}
|
|
8285
|
+
/**
|
|
8286
|
+
* Applies the selected `Mod`s to a `BeatmapDifficulty`.
|
|
8287
|
+
*
|
|
8288
|
+
* @param difficulty The `BeatmapDifficulty` to apply the `Mod`s to.
|
|
8289
|
+
* @param mode The game mode to apply the `Mod`s for.
|
|
8290
|
+
* @param mods The selected `Mod`s.
|
|
8291
|
+
* @param customSpeedMultiplier The custom speed multiplier to apply.
|
|
8292
|
+
*/
|
|
8293
|
+
static applyModsToBeatmapDifficulty(difficulty, mode, mods, customSpeedMultiplier = 1) {
|
|
8294
|
+
for (const mod of mods) {
|
|
8295
|
+
if (mod.isApplicableToDifficulty()) {
|
|
8296
|
+
mod.applyToDifficulty(mode, difficulty);
|
|
8297
|
+
}
|
|
8298
|
+
}
|
|
8299
|
+
for (const mod of mods) {
|
|
8300
|
+
if (mod.isApplicableToDifficultyWithSettings()) {
|
|
8301
|
+
mod.applyToDifficultyWithSettings(mode, difficulty, mods, customSpeedMultiplier);
|
|
8302
|
+
}
|
|
8303
|
+
}
|
|
8304
|
+
}
|
|
8305
|
+
/**
|
|
8306
|
+
* Calculates the rate for the track with the selected `Mod`s.
|
|
8307
|
+
*
|
|
8308
|
+
* @param mods The list of selected `Mod`s.
|
|
8309
|
+
* @param oldStatistics Whether to enforce old statistics. Some `Mod`s behave differently with this flag.
|
|
8310
|
+
* @returns The rate with `Mod`s.
|
|
8311
|
+
*/
|
|
8312
|
+
static calculateRateWithMods(mods, oldStatistics) {
|
|
8313
|
+
let rate = 1;
|
|
8314
|
+
for (const mod of mods) {
|
|
8315
|
+
if (mod.isApplicableToTrackRate()) {
|
|
8316
|
+
rate = mod.applyToRate(rate, oldStatistics);
|
|
8317
|
+
}
|
|
8318
|
+
}
|
|
8319
|
+
return rate;
|
|
8320
|
+
}
|
|
8423
8321
|
/**
|
|
8424
8322
|
* Processes parsing options.
|
|
8425
8323
|
*
|
|
@@ -8492,6 +8390,56 @@ ModUtil.speedChangingMods = [
|
|
|
8492
8390
|
*/
|
|
8493
8391
|
ModUtil.mapChangingMods = _a.speedChangingMods.concat(new ModEasy(), new ModHardRock(), new ModReallyEasy(), new ModSmallCircle());
|
|
8494
8392
|
|
|
8393
|
+
/**
|
|
8394
|
+
* Represents the difficulty adjust (DA) mod.
|
|
8395
|
+
*
|
|
8396
|
+
* This is not a real mod in osu! but is used to force difficulty values in the game.
|
|
8397
|
+
*/
|
|
8398
|
+
class ModDifficultyAdjust extends Mod {
|
|
8399
|
+
constructor(values) {
|
|
8400
|
+
super();
|
|
8401
|
+
this.acronym = "DA";
|
|
8402
|
+
this.name = "Difficulty Adjust";
|
|
8403
|
+
this.droidRanked = false;
|
|
8404
|
+
this.droidScoreMultiplier = 1;
|
|
8405
|
+
this.droidString = "";
|
|
8406
|
+
this.isDroidLegacyMod = false;
|
|
8407
|
+
this.pcRanked = false;
|
|
8408
|
+
this.pcScoreMultiplier = 1;
|
|
8409
|
+
this.bitwise = 0;
|
|
8410
|
+
this.cs = values === null || values === void 0 ? void 0 : values.cs;
|
|
8411
|
+
this.ar = values === null || values === void 0 ? void 0 : values.ar;
|
|
8412
|
+
this.od = values === null || values === void 0 ? void 0 : values.od;
|
|
8413
|
+
this.hp = values === null || values === void 0 ? void 0 : values.hp;
|
|
8414
|
+
}
|
|
8415
|
+
applyToDifficultyWithSettings(mode, difficulty, mods, customSpeedMultiplier) {
|
|
8416
|
+
var _a, _b, _c, _d;
|
|
8417
|
+
difficulty.cs = (_a = this.cs) !== null && _a !== void 0 ? _a : difficulty.cs;
|
|
8418
|
+
difficulty.ar = (_b = this.ar) !== null && _b !== void 0 ? _b : difficulty.ar;
|
|
8419
|
+
difficulty.od = (_c = this.od) !== null && _c !== void 0 ? _c : difficulty.od;
|
|
8420
|
+
difficulty.hp = (_d = this.hp) !== null && _d !== void 0 ? _d : difficulty.hp;
|
|
8421
|
+
// Special case for force AR, where the AR value is kept constant with respect to game time.
|
|
8422
|
+
// This makes the player perceive the AR as is under all speed multipliers.
|
|
8423
|
+
if (this.ar !== undefined) {
|
|
8424
|
+
const preempt = BeatmapDifficulty.difficultyRange(this.ar, HitObject.preemptMax, HitObject.preemptMid, HitObject.preemptMin);
|
|
8425
|
+
const trackRate = this.calculateTrackRate(mods, customSpeedMultiplier);
|
|
8426
|
+
difficulty.ar = BeatmapDifficulty.inverseDifficultyRange(preempt * trackRate, HitObject.preemptMax, HitObject.preemptMid, HitObject.preemptMin);
|
|
8427
|
+
}
|
|
8428
|
+
}
|
|
8429
|
+
applyToHitObjectWithSettings(mode, hitObject, mods, customSpeedMultiplier) {
|
|
8430
|
+
// Special case for force AR, where the AR value is kept constant with respect to game time.
|
|
8431
|
+
// This makes the player perceive the fade in animation as is under all speed multipliers.
|
|
8432
|
+
if (this.ar === undefined) {
|
|
8433
|
+
return;
|
|
8434
|
+
}
|
|
8435
|
+
const trackRate = this.calculateTrackRate(mods, customSpeedMultiplier);
|
|
8436
|
+
hitObject.timeFadeIn *= trackRate;
|
|
8437
|
+
}
|
|
8438
|
+
calculateTrackRate(mods, customSpeedMultiplier) {
|
|
8439
|
+
return ModUtil.calculateRateWithMods(mods) * customSpeedMultiplier;
|
|
8440
|
+
}
|
|
8441
|
+
}
|
|
8442
|
+
|
|
8495
8443
|
/**
|
|
8496
8444
|
* Continuous Univariate Normal distribution, also known as Gaussian distribution.
|
|
8497
8445
|
*
|
|
@@ -8519,9 +8467,6 @@ class NormalDistribution {
|
|
|
8519
8467
|
|
|
8520
8468
|
dotenv.config();
|
|
8521
8469
|
|
|
8522
|
-
exports.AR0_MS = AR0_MS;
|
|
8523
|
-
exports.AR10_MS = AR10_MS;
|
|
8524
|
-
exports.AR5_MS = AR5_MS;
|
|
8525
8470
|
exports.Accuracy = Accuracy;
|
|
8526
8471
|
exports.BankHitSampleInfo = BankHitSampleInfo;
|
|
8527
8472
|
exports.Beatmap = Beatmap;
|
|
@@ -8618,9 +8563,4 @@ exports.TimingControlPointManager = TimingControlPointManager;
|
|
|
8618
8563
|
exports.Utils = Utils;
|
|
8619
8564
|
exports.Vector2 = Vector2;
|
|
8620
8565
|
exports.ZeroCrossingBracketing = ZeroCrossingBracketing;
|
|
8621
|
-
exports.calculateDroidDifficultyStatistics = calculateDroidDifficultyStatistics;
|
|
8622
|
-
exports.calculateOsuDifficultyStatistics = calculateOsuDifficultyStatistics;
|
|
8623
|
-
exports.calculateSpeedMultiplierFromMods = calculateSpeedMultiplierFromMods;
|
|
8624
|
-
exports.convertApproachRateMilliseconds = convertApproachRateMilliseconds;
|
|
8625
|
-
exports.convertApproachRateToMilliseconds = convertApproachRateToMilliseconds;
|
|
8626
8566
|
//# sourceMappingURL=index.js.map
|