@rian8337/osu-base 1.0.0
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/LICENSE +21 -0
- package/README.md +11 -0
- package/dist/beatmap/Beatmap.js +223 -0
- package/dist/beatmap/Parser.js +620 -0
- package/dist/beatmap/hitobjects/Circle.js +20 -0
- package/dist/beatmap/hitobjects/HitObject.js +74 -0
- package/dist/beatmap/hitobjects/Slider.js +143 -0
- package/dist/beatmap/hitobjects/Spinner.js +26 -0
- package/dist/beatmap/hitobjects/sliderObjects/HeadCircle.js +10 -0
- package/dist/beatmap/hitobjects/sliderObjects/RepeatPoint.js +21 -0
- package/dist/beatmap/hitobjects/sliderObjects/SliderTick.js +21 -0
- package/dist/beatmap/hitobjects/sliderObjects/TailCircle.js +10 -0
- package/dist/beatmap/timings/BreakPoint.js +34 -0
- package/dist/beatmap/timings/DifficultyControlPoint.js +22 -0
- package/dist/beatmap/timings/TimingControlPoint.js +22 -0
- package/dist/beatmap/timings/TimingPoint.js +12 -0
- package/dist/constants/ParserConstants.js +19 -0
- package/dist/constants/PathType.js +13 -0
- package/dist/constants/modes.js +11 -0
- package/dist/constants/objectTypes.js +12 -0
- package/dist/constants/rankedStatus.js +16 -0
- package/dist/index.js +64 -0
- package/dist/mathutil/Interpolation.js +9 -0
- package/dist/mathutil/MathUtils.js +41 -0
- package/dist/mathutil/Vector2.js +79 -0
- package/dist/mods/Mod.js +9 -0
- package/dist/mods/ModAuto.js +21 -0
- package/dist/mods/ModAutopilot.js +21 -0
- package/dist/mods/ModDoubleTime.js +21 -0
- package/dist/mods/ModEasy.js +21 -0
- package/dist/mods/ModFlashlight.js +21 -0
- package/dist/mods/ModHalfTime.js +21 -0
- package/dist/mods/ModHardRock.js +21 -0
- package/dist/mods/ModHidden.js +21 -0
- package/dist/mods/ModNightCore.js +21 -0
- package/dist/mods/ModNoFail.js +21 -0
- package/dist/mods/ModPerfect.js +21 -0
- package/dist/mods/ModPrecise.js +21 -0
- package/dist/mods/ModReallyEasy.js +21 -0
- package/dist/mods/ModRelax.js +21 -0
- package/dist/mods/ModScoreV2.js +21 -0
- package/dist/mods/ModSmallCircle.js +21 -0
- package/dist/mods/ModSpunOut.js +21 -0
- package/dist/mods/ModSuddenDeath.js +21 -0
- package/dist/mods/ModTouchDevice.js +21 -0
- package/dist/tools/MapInfo.js +559 -0
- package/dist/utils/APIRequestBuilder.js +144 -0
- package/dist/utils/Accuracy.js +96 -0
- package/dist/utils/HitWindow.js +56 -0
- package/dist/utils/MapStats.js +212 -0
- package/dist/utils/ModUtil.js +137 -0
- package/dist/utils/PathApproximator.js +269 -0
- package/dist/utils/Precision.js +31 -0
- package/dist/utils/SliderPath.js +187 -0
- package/dist/utils/Utils.js +53 -0
- package/package.json +43 -0
- package/typings/index.d.ts +1951 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Accuracy = void 0;
|
|
4
|
+
const MathUtils_1 = require("../mathutil/MathUtils");
|
|
5
|
+
/**
|
|
6
|
+
* An accuracy calculator that calculates accuracy based on given parameters.
|
|
7
|
+
*/
|
|
8
|
+
class Accuracy {
|
|
9
|
+
/**
|
|
10
|
+
* Calculates accuracy based on given parameters.
|
|
11
|
+
*
|
|
12
|
+
* If `percent` and `nobjects` are specified, `n300`, `n100`, and `n50` will
|
|
13
|
+
* be automatically calculated to be the closest to the given
|
|
14
|
+
* acc percent.
|
|
15
|
+
*
|
|
16
|
+
* @param values Function parameters.
|
|
17
|
+
*/
|
|
18
|
+
constructor(values) {
|
|
19
|
+
this.nmiss = values.nmiss ?? 0;
|
|
20
|
+
this.n300 = values.n300 ?? -1;
|
|
21
|
+
this.n100 = values.n100 ?? 0;
|
|
22
|
+
this.n50 = values.n50 ?? 0;
|
|
23
|
+
let nobjects;
|
|
24
|
+
if (values.nobjects) {
|
|
25
|
+
let n300 = this.n300;
|
|
26
|
+
nobjects = values.nobjects;
|
|
27
|
+
let hitcount;
|
|
28
|
+
if (n300 < 0) {
|
|
29
|
+
n300 = Math.max(0, nobjects - this.n100 - this.n50 - this.nmiss);
|
|
30
|
+
}
|
|
31
|
+
hitcount = n300 + this.n100 + this.n50 + this.nmiss;
|
|
32
|
+
if (hitcount > nobjects) {
|
|
33
|
+
n300 -= Math.min(n300, hitcount - nobjects);
|
|
34
|
+
}
|
|
35
|
+
hitcount = n300 + this.n100 + this.n50 + this.nmiss;
|
|
36
|
+
if (hitcount > nobjects) {
|
|
37
|
+
this.n100 -= Math.min(this.n100, hitcount - nobjects);
|
|
38
|
+
}
|
|
39
|
+
hitcount = n300 + this.n100 + this.n50 + this.nmiss;
|
|
40
|
+
if (hitcount > nobjects) {
|
|
41
|
+
this.n50 -= Math.min(this.n50, hitcount - nobjects);
|
|
42
|
+
}
|
|
43
|
+
hitcount = n300 + this.n100 + this.n50 + this.nmiss;
|
|
44
|
+
if (hitcount > nobjects) {
|
|
45
|
+
this.nmiss -= Math.min(this.nmiss, hitcount - nobjects);
|
|
46
|
+
}
|
|
47
|
+
this.n300 = nobjects - this.n100 - this.n50 - this.nmiss;
|
|
48
|
+
}
|
|
49
|
+
if (values.percent) {
|
|
50
|
+
if (!values.nobjects) {
|
|
51
|
+
throw new TypeError("nobjects is required when specifying percent");
|
|
52
|
+
}
|
|
53
|
+
nobjects = values.nobjects;
|
|
54
|
+
const max300 = nobjects - this.nmiss;
|
|
55
|
+
const maxacc = new Accuracy({
|
|
56
|
+
n300: max300,
|
|
57
|
+
n100: 0,
|
|
58
|
+
n50: 0,
|
|
59
|
+
nmiss: this.nmiss,
|
|
60
|
+
}).value() * 100;
|
|
61
|
+
let acc_percent = values.percent;
|
|
62
|
+
acc_percent = Math.max(0, Math.min(maxacc, acc_percent));
|
|
63
|
+
// just some black magic maths from wolfram alpha
|
|
64
|
+
this.n100 = Math.round(-3 * ((acc_percent * 0.01 - 1) * nobjects + this.nmiss) * 0.5);
|
|
65
|
+
if (this.n100 > max300) {
|
|
66
|
+
// acc lower than all 100s, use 50s
|
|
67
|
+
this.n100 = 0;
|
|
68
|
+
this.n50 = Math.round(-6 *
|
|
69
|
+
((acc_percent * 0.01 - 1) * nobjects + this.nmiss) *
|
|
70
|
+
0.5);
|
|
71
|
+
this.n50 = Math.min(max300, this.n50);
|
|
72
|
+
}
|
|
73
|
+
this.n300 = nobjects - this.n100 - this.n50 - this.nmiss;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Calculates the accuracy value (0.0 - 1.0).
|
|
78
|
+
*
|
|
79
|
+
* @param nobjects The amount of objects in the beatmap. If `n300` was not specified in the constructor, this is required.
|
|
80
|
+
*/
|
|
81
|
+
value(nobjects) {
|
|
82
|
+
let n300 = this.n300;
|
|
83
|
+
if (n300 < 0) {
|
|
84
|
+
if (!nobjects) {
|
|
85
|
+
throw new TypeError("Either n300 or nobjects must be specified");
|
|
86
|
+
}
|
|
87
|
+
n300 = nobjects - this.n100 - this.n50 - this.nmiss;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
nobjects ??= n300 + this.n100 + this.n50 + this.nmiss;
|
|
91
|
+
}
|
|
92
|
+
const res = (n300 * 6 + this.n100 * 2 + this.n50) / (nobjects * 6);
|
|
93
|
+
return MathUtils_1.MathUtils.clamp(res, 0, 1);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.Accuracy = Accuracy;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OsuHitWindow = exports.DroidHitWindow = void 0;
|
|
4
|
+
class HitWindow {
|
|
5
|
+
/**
|
|
6
|
+
* @param overallDifficulty The overall difficulty of this hit window.
|
|
7
|
+
*/
|
|
8
|
+
constructor(overallDifficulty) {
|
|
9
|
+
this.overallDifficulty = overallDifficulty;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Represents the hit window of osu!droid.
|
|
14
|
+
*/
|
|
15
|
+
class DroidHitWindow extends HitWindow {
|
|
16
|
+
hitWindowFor300(isPrecise) {
|
|
17
|
+
if (isPrecise) {
|
|
18
|
+
return 55 + 6 * (5 - this.overallDifficulty);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
return 75 + 5 * (5 - this.overallDifficulty);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
hitWindowFor100(isPrecise) {
|
|
25
|
+
if (isPrecise) {
|
|
26
|
+
return 120 + 8 * (5 - this.overallDifficulty);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
return 150 + 10 * (5 - this.overallDifficulty);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
hitWindowFor50(isPrecise) {
|
|
33
|
+
if (isPrecise) {
|
|
34
|
+
return 180 + 10 * (5 - this.overallDifficulty);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
return 250 + 10 * (5 - this.overallDifficulty);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.DroidHitWindow = DroidHitWindow;
|
|
42
|
+
/**
|
|
43
|
+
* Represents the hit window of osu!standard.
|
|
44
|
+
*/
|
|
45
|
+
class OsuHitWindow extends HitWindow {
|
|
46
|
+
hitWindowFor300() {
|
|
47
|
+
return 80 - 6 * this.overallDifficulty;
|
|
48
|
+
}
|
|
49
|
+
hitWindowFor100() {
|
|
50
|
+
return 140 - 8 * this.overallDifficulty;
|
|
51
|
+
}
|
|
52
|
+
hitWindowFor50() {
|
|
53
|
+
return 200 - 10 * this.overallDifficulty;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.OsuHitWindow = OsuHitWindow;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MapStats = void 0;
|
|
4
|
+
const modes_1 = require("../constants/modes");
|
|
5
|
+
const HitWindow_1 = require("../utils/HitWindow");
|
|
6
|
+
const ModDoubleTime_1 = require("../mods/ModDoubleTime");
|
|
7
|
+
const ModHalfTime_1 = require("../mods/ModHalfTime");
|
|
8
|
+
const ModNightCore_1 = require("../mods/ModNightCore");
|
|
9
|
+
const ModHardRock_1 = require("../mods/ModHardRock");
|
|
10
|
+
const ModEasy_1 = require("../mods/ModEasy");
|
|
11
|
+
const ModPrecise_1 = require("../mods/ModPrecise");
|
|
12
|
+
const ModSmallCircle_1 = require("../mods/ModSmallCircle");
|
|
13
|
+
const ModReallyEasy_1 = require("../mods/ModReallyEasy");
|
|
14
|
+
const ModUtil_1 = require("./ModUtil");
|
|
15
|
+
/**
|
|
16
|
+
* Holds general beatmap statistics for further modifications.
|
|
17
|
+
*/
|
|
18
|
+
class MapStats {
|
|
19
|
+
constructor(values = {}) {
|
|
20
|
+
/**
|
|
21
|
+
* Whether this map statistics have been calculated.
|
|
22
|
+
*/
|
|
23
|
+
this.calculated = false;
|
|
24
|
+
this.cs = values.cs;
|
|
25
|
+
this.ar = values.ar;
|
|
26
|
+
this.od = values.od;
|
|
27
|
+
this.hp = values.hp;
|
|
28
|
+
this.mods = values.mods ?? [];
|
|
29
|
+
this.speedMultiplier = values.speedMultiplier ?? 1;
|
|
30
|
+
this.isForceAR = values.isForceAR ?? false;
|
|
31
|
+
this.oldStatistics = values.oldStatistics ?? false;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Calculates map statistics.
|
|
35
|
+
*
|
|
36
|
+
* This can only be called once for an instance.
|
|
37
|
+
*/
|
|
38
|
+
calculate(params) {
|
|
39
|
+
if (this.calculated) {
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
this.calculated = true;
|
|
43
|
+
if (params?.mods) {
|
|
44
|
+
this.mods = ModUtil_1.ModUtil.pcStringToMods(params.mods);
|
|
45
|
+
}
|
|
46
|
+
if (params?.speedMultiplier) {
|
|
47
|
+
this.speedMultiplier = params.speedMultiplier;
|
|
48
|
+
}
|
|
49
|
+
if (params?.isForceAR) {
|
|
50
|
+
this.isForceAR = params.isForceAR;
|
|
51
|
+
}
|
|
52
|
+
let statisticsMultiplier = 1;
|
|
53
|
+
if (this.mods.some((m) => m instanceof ModDoubleTime_1.ModDoubleTime)) {
|
|
54
|
+
this.speedMultiplier *= 1.5;
|
|
55
|
+
}
|
|
56
|
+
if (this.mods.some((m) => m instanceof ModHalfTime_1.ModHalfTime)) {
|
|
57
|
+
this.speedMultiplier *= 0.75;
|
|
58
|
+
}
|
|
59
|
+
if (this.mods.some((m) => m instanceof ModNightCore_1.ModNightCore)) {
|
|
60
|
+
this.speedMultiplier *= 1.5;
|
|
61
|
+
}
|
|
62
|
+
if (this.mods.some((m) => m instanceof ModHardRock_1.ModHardRock)) {
|
|
63
|
+
statisticsMultiplier *= 1.4;
|
|
64
|
+
}
|
|
65
|
+
if (this.mods.some((m) => m instanceof ModEasy_1.ModEasy)) {
|
|
66
|
+
statisticsMultiplier *= 0.5;
|
|
67
|
+
}
|
|
68
|
+
switch (params?.mode ?? modes_1.modes.osu) {
|
|
69
|
+
case modes_1.modes.droid:
|
|
70
|
+
// In droid pre-1.6.8, NC speed multiplier is assumed bugged (1.39)
|
|
71
|
+
if (this.mods.some((m) => m instanceof ModNightCore_1.ModNightCore) &&
|
|
72
|
+
this.oldStatistics) {
|
|
73
|
+
this.speedMultiplier *= 1.39 / 1.5;
|
|
74
|
+
}
|
|
75
|
+
// CS and OD work differently in droid, therefore it
|
|
76
|
+
// needs to be computed regardless of map-changing mods
|
|
77
|
+
// and statistics multiplier
|
|
78
|
+
if (this.od !== undefined) {
|
|
79
|
+
// apply EZ or HR to OD
|
|
80
|
+
this.od = Math.min(this.od * statisticsMultiplier, 10);
|
|
81
|
+
// convert original OD to droid OD
|
|
82
|
+
const droidToMS = new HitWindow_1.DroidHitWindow(this.od).hitWindowFor300(this.mods.some((m) => m instanceof ModPrecise_1.ModPrecise)) / this.speedMultiplier;
|
|
83
|
+
this.od = 5 - (droidToMS - 50) / 6;
|
|
84
|
+
}
|
|
85
|
+
// HR and EZ works differently in droid in terms of
|
|
86
|
+
// CS modification (even CS in itself as well)
|
|
87
|
+
//
|
|
88
|
+
// If present mods are found, they need to be removed
|
|
89
|
+
// from the bitwise enum of mods to prevent double
|
|
90
|
+
// calculation
|
|
91
|
+
if (this.cs !== undefined) {
|
|
92
|
+
// Assume 681 is height
|
|
93
|
+
const assumedHeight = 681;
|
|
94
|
+
let scale = ((assumedHeight / 480) * (54.42 - this.cs * 4.48) * 2) /
|
|
95
|
+
128 +
|
|
96
|
+
(0.5 * (11 - 5.2450170716245195)) / 5;
|
|
97
|
+
if (this.mods.some((m) => m instanceof ModHardRock_1.ModHardRock)) {
|
|
98
|
+
scale -= 0.125;
|
|
99
|
+
}
|
|
100
|
+
if (this.mods.some((m) => m instanceof ModEasy_1.ModEasy)) {
|
|
101
|
+
scale += 0.125;
|
|
102
|
+
}
|
|
103
|
+
if (this.mods.some((m) => m instanceof ModReallyEasy_1.ModReallyEasy)) {
|
|
104
|
+
scale += 0.125;
|
|
105
|
+
}
|
|
106
|
+
if (this.mods.some((m) => m instanceof ModSmallCircle_1.ModSmallCircle)) {
|
|
107
|
+
scale -= ((assumedHeight / 480) * (4 * 4.48) * 2) / 128;
|
|
108
|
+
}
|
|
109
|
+
const radius = (64 * scale) / ((assumedHeight * 0.85) / 384);
|
|
110
|
+
this.cs = Math.min(5 + ((1 - radius / 32) * 5) / 0.7, 10);
|
|
111
|
+
}
|
|
112
|
+
if (this.hp !== undefined) {
|
|
113
|
+
if (this.mods.some((m) => m instanceof ModReallyEasy_1.ModReallyEasy)) {
|
|
114
|
+
this.hp /= 2;
|
|
115
|
+
}
|
|
116
|
+
this.hp = Math.min(this.hp * statisticsMultiplier, 10);
|
|
117
|
+
}
|
|
118
|
+
if (this.ar !== undefined && !this.isForceAR) {
|
|
119
|
+
this.ar *= statisticsMultiplier;
|
|
120
|
+
if (this.mods.some((m) => m instanceof ModReallyEasy_1.ModReallyEasy)) {
|
|
121
|
+
if (this.mods.some((m) => m instanceof ModEasy_1.ModEasy)) {
|
|
122
|
+
this.ar *= 2;
|
|
123
|
+
this.ar -= 0.5;
|
|
124
|
+
}
|
|
125
|
+
this.ar -= 0.5;
|
|
126
|
+
this.ar -= this.speedMultiplier - 1;
|
|
127
|
+
}
|
|
128
|
+
this.ar = MapStats.modifyAR(this.ar, this.speedMultiplier, 1);
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
case modes_1.modes.osu:
|
|
132
|
+
if (!this.mods.some((m) => ModUtil_1.ModUtil.mapChangingMods.find((mod) => mod.acronym === m.acronym)) &&
|
|
133
|
+
this.speedMultiplier === 1) {
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
if (this.cs !== undefined) {
|
|
137
|
+
if (this.mods.some((m) => m instanceof ModHardRock_1.ModHardRock)) {
|
|
138
|
+
this.cs *= 1.3;
|
|
139
|
+
}
|
|
140
|
+
if (this.mods.some((m) => m instanceof ModEasy_1.ModEasy)) {
|
|
141
|
+
this.cs *= 0.5;
|
|
142
|
+
}
|
|
143
|
+
this.cs = Math.min(this.cs, 10);
|
|
144
|
+
}
|
|
145
|
+
if (this.hp !== undefined) {
|
|
146
|
+
this.hp = Math.min(this.hp * statisticsMultiplier, 10);
|
|
147
|
+
}
|
|
148
|
+
if (this.ar !== undefined && !this.isForceAR) {
|
|
149
|
+
this.ar = MapStats.modifyAR(this.ar, this.speedMultiplier, statisticsMultiplier);
|
|
150
|
+
}
|
|
151
|
+
if (this.od !== undefined) {
|
|
152
|
+
this.od = MapStats.modifyOD(this.od, this.speedMultiplier, statisticsMultiplier);
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
default:
|
|
156
|
+
throw new TypeError("Mode not supported");
|
|
157
|
+
}
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Returns a string representative of the class.
|
|
162
|
+
*/
|
|
163
|
+
toString() {
|
|
164
|
+
return `CS: ${this.cs?.toFixed(2)}, AR: ${this.ar?.toFixed(2)}, OD: ${this.od?.toFixed(2)}, HP: ${this.hp?.toFixed(2)}`;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Utility function to apply speed and flat multipliers to stats where speed changes apply for AR.
|
|
168
|
+
*
|
|
169
|
+
* @param baseAR The base AR value.
|
|
170
|
+
* @param speedMultiplier The speed multiplier to calculate.
|
|
171
|
+
* @param statisticsMultiplier The statistics multiplier to calculate from map-changing nonspeed-changing mods.
|
|
172
|
+
*/
|
|
173
|
+
static modifyAR(baseAR, speedMultiplier, statisticsMultiplier) {
|
|
174
|
+
let ar = baseAR;
|
|
175
|
+
ar *= statisticsMultiplier;
|
|
176
|
+
let arMS = ar < 5.0
|
|
177
|
+
? this.AR0_MS - this.AR_MS_STEP1 * ar
|
|
178
|
+
: this.AR5_MS - this.AR_MS_STEP2 * (ar - 5);
|
|
179
|
+
arMS = Math.min(this.AR0_MS, Math.max(this.AR10_MS, arMS));
|
|
180
|
+
arMS /= speedMultiplier;
|
|
181
|
+
ar =
|
|
182
|
+
arMS > this.AR5_MS
|
|
183
|
+
? (this.AR0_MS - arMS) / this.AR_MS_STEP1
|
|
184
|
+
: 5 + (this.AR5_MS - arMS) / this.AR_MS_STEP2;
|
|
185
|
+
return ar;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Utility function to apply speed and flat multipliers to stats where speed changes apply for OD.
|
|
189
|
+
*
|
|
190
|
+
* @param baseOD The base OD value.
|
|
191
|
+
* @param speedMultiplier The speed multiplier to calculate.
|
|
192
|
+
* @param statisticsMultiplier The statistics multiplier to calculate from map-changing nonspeed-changing mods.
|
|
193
|
+
*/
|
|
194
|
+
static modifyOD(baseOD, speedMultiplier, statisticsMultiplier) {
|
|
195
|
+
let od = baseOD;
|
|
196
|
+
od *= statisticsMultiplier;
|
|
197
|
+
let odMS = this.OD0_MS - Math.ceil(this.OD_MS_STEP * od);
|
|
198
|
+
odMS = Math.min(this.OD0_MS, Math.max(this.OD10_MS, odMS));
|
|
199
|
+
odMS /= speedMultiplier;
|
|
200
|
+
od = (this.OD0_MS - odMS) / this.OD_MS_STEP;
|
|
201
|
+
return od;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
exports.MapStats = MapStats;
|
|
205
|
+
MapStats.OD0_MS = 80;
|
|
206
|
+
MapStats.OD10_MS = 20;
|
|
207
|
+
MapStats.AR0_MS = 1800;
|
|
208
|
+
MapStats.AR5_MS = 1200;
|
|
209
|
+
MapStats.AR10_MS = 450;
|
|
210
|
+
MapStats.OD_MS_STEP = (MapStats.OD0_MS - MapStats.OD10_MS) / 10;
|
|
211
|
+
MapStats.AR_MS_STEP1 = (MapStats.AR0_MS - MapStats.AR5_MS) / 5;
|
|
212
|
+
MapStats.AR_MS_STEP2 = (MapStats.AR5_MS - MapStats.AR10_MS) / 5;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ModUtil = void 0;
|
|
4
|
+
const ModAuto_1 = require("../mods/ModAuto");
|
|
5
|
+
const ModAutopilot_1 = require("../mods/ModAutopilot");
|
|
6
|
+
const ModDoubleTime_1 = require("../mods/ModDoubleTime");
|
|
7
|
+
const ModEasy_1 = require("../mods/ModEasy");
|
|
8
|
+
const ModFlashlight_1 = require("../mods/ModFlashlight");
|
|
9
|
+
const ModHalfTime_1 = require("../mods/ModHalfTime");
|
|
10
|
+
const ModHardRock_1 = require("../mods/ModHardRock");
|
|
11
|
+
const ModHidden_1 = require("../mods/ModHidden");
|
|
12
|
+
const ModNightCore_1 = require("../mods/ModNightCore");
|
|
13
|
+
const ModNoFail_1 = require("../mods/ModNoFail");
|
|
14
|
+
const ModPerfect_1 = require("../mods/ModPerfect");
|
|
15
|
+
const ModPrecise_1 = require("../mods/ModPrecise");
|
|
16
|
+
const ModReallyEasy_1 = require("../mods/ModReallyEasy");
|
|
17
|
+
const ModRelax_1 = require("../mods/ModRelax");
|
|
18
|
+
const ModScoreV2_1 = require("../mods/ModScoreV2");
|
|
19
|
+
const ModSmallCircle_1 = require("../mods/ModSmallCircle");
|
|
20
|
+
const ModSpunOut_1 = require("../mods/ModSpunOut");
|
|
21
|
+
const ModSuddenDeath_1 = require("../mods/ModSuddenDeath");
|
|
22
|
+
const ModTouchDevice_1 = require("../mods/ModTouchDevice");
|
|
23
|
+
/**
|
|
24
|
+
* Utilities for mods.
|
|
25
|
+
*/
|
|
26
|
+
class ModUtil {
|
|
27
|
+
/**
|
|
28
|
+
* Gets a list of mods from a droid mod string, such as "hd".
|
|
29
|
+
*
|
|
30
|
+
* @param str The string.
|
|
31
|
+
*/
|
|
32
|
+
static droidStringToMods(str) {
|
|
33
|
+
return this.checkDuplicateMods(this.allMods.filter((m) => m.droidString && str.toLowerCase().includes(m.droidString)));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Gets a list of mods from a PC modbits.
|
|
37
|
+
*
|
|
38
|
+
* @param modbits The modbits.
|
|
39
|
+
*/
|
|
40
|
+
static pcModbitsToMods(modbits) {
|
|
41
|
+
return this.checkDuplicateMods(this.allMods.filter((m) => m.bitwise & modbits));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Gets a list of mods from a PC mod string, such as "HDHR".
|
|
45
|
+
*
|
|
46
|
+
* @param str The string.
|
|
47
|
+
*/
|
|
48
|
+
static pcStringToMods(str) {
|
|
49
|
+
const finalMods = [];
|
|
50
|
+
str = str.toLowerCase();
|
|
51
|
+
while (str) {
|
|
52
|
+
let nchars = 1;
|
|
53
|
+
for (const mod of this.allMods) {
|
|
54
|
+
if (str.startsWith(mod.acronym.toLowerCase())) {
|
|
55
|
+
finalMods.push(mod);
|
|
56
|
+
nchars = 2;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
str = str.slice(nchars);
|
|
61
|
+
}
|
|
62
|
+
return this.checkDuplicateMods(finalMods);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Checks for mods that are duplicate and incompatible with each other.
|
|
66
|
+
*
|
|
67
|
+
* @param mods The mods to check for.
|
|
68
|
+
*/
|
|
69
|
+
static checkDuplicateMods(mods) {
|
|
70
|
+
for (const incompatibleMod of this.incompatibleMods) {
|
|
71
|
+
const fulfilledMods = mods.filter((m) => incompatibleMod.map((v) => v.acronym).includes(m.acronym));
|
|
72
|
+
if (fulfilledMods.length > 1) {
|
|
73
|
+
mods = mods.filter((m) => !incompatibleMod
|
|
74
|
+
.map((v) => v.acronym)
|
|
75
|
+
.includes(m.acronym));
|
|
76
|
+
// Keep the first selected mod
|
|
77
|
+
mods.push(fulfilledMods[0]);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Check for duplicate mod entries
|
|
81
|
+
return Array.from(new Set(mods));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.ModUtil = ModUtil;
|
|
85
|
+
/**
|
|
86
|
+
* Mods that are incompatible with each other.
|
|
87
|
+
*/
|
|
88
|
+
ModUtil.incompatibleMods = [
|
|
89
|
+
[new ModDoubleTime_1.ModDoubleTime(), new ModNightCore_1.ModNightCore(), new ModHalfTime_1.ModHalfTime()],
|
|
90
|
+
[new ModNoFail_1.ModNoFail(), new ModSuddenDeath_1.ModSuddenDeath(), new ModPerfect_1.ModPerfect()],
|
|
91
|
+
[new ModHardRock_1.ModHardRock(), new ModEasy_1.ModEasy()],
|
|
92
|
+
[new ModAuto_1.ModAuto(), new ModRelax_1.ModRelax(), new ModAutopilot_1.ModAutopilot()],
|
|
93
|
+
];
|
|
94
|
+
/**
|
|
95
|
+
* All mods that exists.
|
|
96
|
+
*/
|
|
97
|
+
ModUtil.allMods = [
|
|
98
|
+
// Janky order to keep the order on what players are used to
|
|
99
|
+
new ModAuto_1.ModAuto(),
|
|
100
|
+
new ModRelax_1.ModRelax(),
|
|
101
|
+
new ModAutopilot_1.ModAutopilot(),
|
|
102
|
+
new ModEasy_1.ModEasy(),
|
|
103
|
+
new ModNoFail_1.ModNoFail(),
|
|
104
|
+
new ModHidden_1.ModHidden(),
|
|
105
|
+
new ModHardRock_1.ModHardRock(),
|
|
106
|
+
new ModDoubleTime_1.ModDoubleTime(),
|
|
107
|
+
new ModNightCore_1.ModNightCore(),
|
|
108
|
+
new ModHalfTime_1.ModHalfTime(),
|
|
109
|
+
new ModFlashlight_1.ModFlashlight(),
|
|
110
|
+
new ModSuddenDeath_1.ModSuddenDeath(),
|
|
111
|
+
new ModPerfect_1.ModPerfect(),
|
|
112
|
+
new ModPrecise_1.ModPrecise(),
|
|
113
|
+
new ModReallyEasy_1.ModReallyEasy(),
|
|
114
|
+
new ModScoreV2_1.ModScoreV2(),
|
|
115
|
+
new ModSmallCircle_1.ModSmallCircle(),
|
|
116
|
+
new ModSpunOut_1.ModSpunOut(),
|
|
117
|
+
new ModTouchDevice_1.ModTouchDevice(),
|
|
118
|
+
];
|
|
119
|
+
/**
|
|
120
|
+
* Mods that change the playback speed of a beatmap.
|
|
121
|
+
*/
|
|
122
|
+
ModUtil.speedChangingMods = [
|
|
123
|
+
new ModDoubleTime_1.ModDoubleTime(),
|
|
124
|
+
new ModNightCore_1.ModNightCore(),
|
|
125
|
+
new ModHalfTime_1.ModHalfTime(),
|
|
126
|
+
];
|
|
127
|
+
/**
|
|
128
|
+
* Mods that change the way the map looks.
|
|
129
|
+
*/
|
|
130
|
+
ModUtil.mapChangingMods = [
|
|
131
|
+
new ModDoubleTime_1.ModDoubleTime(),
|
|
132
|
+
new ModNightCore_1.ModNightCore(),
|
|
133
|
+
new ModHalfTime_1.ModHalfTime(),
|
|
134
|
+
new ModEasy_1.ModEasy(),
|
|
135
|
+
new ModHardRock_1.ModHardRock(),
|
|
136
|
+
new ModSmallCircle_1.ModSmallCircle(),
|
|
137
|
+
];
|