var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; define("Objects/osu!/HitType", ["require", "exports"], function (require, exports) { "use strict"; exports.__esModule = true; var HitType; (function (HitType) { HitType[HitType["Normal"] = 1] = "Normal"; HitType[HitType["Slider"] = 2] = "Slider"; HitType[HitType["NewCombo"] = 4] = "NewCombo"; HitType[HitType["Spinner"] = 8] = "Spinner"; HitType[HitType["ComboSkip1"] = 16] = "ComboSkip1"; HitType[HitType["ComboSkip2"] = 32] = "ComboSkip2"; HitType[HitType["ComboSkip3"] = 64] = "ComboSkip3"; HitType[HitType["Hold"] = 128] = "Hold"; })(HitType = exports.HitType || (exports.HitType = {})); }); define("Objects/osu!/PathType", ["require", "exports"], function (require, exports) { "use strict"; exports.__esModule = true; var PathType; (function (PathType) { PathType[PathType["Catmull"] = 0] = "Catmull"; PathType[PathType["Bezier"] = 1] = "Bezier"; PathType[PathType["Linear"] = 2] = "Linear"; PathType[PathType["PerfectCurve"] = 3] = "PerfectCurve"; })(PathType = exports.PathType || (exports.PathType = {})); ; }); define("Objects/Vector2", ["require", "exports"], function (require, exports) { "use strict"; exports.__esModule = true; var Vector2 = /** @class */ (function () { function Vector2(x, y) { this.x = x; this.y = y; } ; Vector2.prototype.add = function (vector) { return new Vector2(this.x + vector.x, this.y + vector.y); }; ; Vector2.prototype.subtract = function (vector) { return new Vector2(this.x - vector.x, this.y - vector.y); }; ; Vector2.prototype.scale = function (scaleFactor) { return new Vector2(this.x * scaleFactor, this.y * scaleFactor); }; ; Vector2.prototype.divide = function (divideFactor) { if (divideFactor === 0) throw new Error("Attempt to divide vector by 0"); return new Vector2(this.x / divideFactor, this.y / divideFactor); }; ; Vector2.prototype.dot = function (vector) { return this.x * vector.x + this.y * vector.y; }; ; Vector2.prototype.length = function () { return Math.sqrt((this.x * this.x) + (this.y * this.y)); }; ; Vector2.prototype.lengthSquared = function () { return Math.pow(this.length(), 2); }; ; Vector2.prototype.distance = function (vector) { var x = this.x - vector.x; var y = this.y - vector.y; var dist = x * x + y * y; return Math.sqrt(dist); }; ; Vector2.prototype.clone = function () { return new Vector2(this.x, this.y); }; ; Vector2.prototype.normalize = function () { var length = this.length(); this.x /= length; this.y /= length; }; ; Vector2.prototype.almostEquals = function (vec2, acceptableDifference) { function checkNumbers(value1, value2) { return Math.abs(value1 - value2) <= acceptableDifference; } ; return checkNumbers(this.x, vec2.x) && checkNumbers(this.y, vec2.y); }; ; return Vector2; }()); exports.Vector2 = Vector2; ; }); define("Objects/osu!/HitObjects/HitObject", ["require", "exports", "Objects/Vector2"], function (require, exports, Vector2_1) { "use strict"; exports.__esModule = true; /** * Base class for all osu! hit objects */ var HitObject = /** @class */ (function () { function HitObject(pos, startTime, radius) { this.Position = pos; this.StartTime = startTime; this.Radius = radius; } ; HitObject.prototype.calculateStackedPosition = function (scale) { var coordinate = this.StackHeight * scale * -6.4; var stackOffset = new Vector2_1.Vector2(coordinate, coordinate); if (this.Position !== undefined) this.StackedPosition = this.Position.add(stackOffset); }; ; return HitObject; }()); exports.HitObject = HitObject; ; }); define("Objects/osu!/Beatmap", ["require", "exports"], function (require, exports) { "use strict"; exports.__esModule = true; /** * Class for beatmaps */ var Beatmap = /** @class */ (function () { function Beatmap() { /** * .osu file version */ /** * Stack leniency used in the beatmap */ this.Version = 0; this.StackLeniency = 0; this.Difficulty = { HPDrainRate: 0, CircleSize: 0, OverallDifficulty: 0, ApproachRate: 0, SliderMultiplier: 0, SliderTickRate: 0 }; this.HitObjects = []; this.TimingPoints = []; this.DifficultyTimingPoints = []; } ; return Beatmap; }()); exports.Beatmap = Beatmap; ; }); define("Objects/osu!/HitObjects/HitCircle", ["require", "exports", "Objects/osu!/HitObjects/HitObject"], function (require, exports, HitObject_1) { "use strict"; exports.__esModule = true; /** * Class for hit circles */ var HitCircle = /** @class */ (function (_super) { __extends(HitCircle, _super); /** * * @param pos The raw position of the hit circle (as listed in the .osu file) * @param startTime The hit time of the hit circle in ms from start * @param radius The radius of the hit circle */ function HitCircle(pos, startTime, radius) { return _super.call(this, pos, startTime, radius) || this; } ; return HitCircle; }(HitObject_1.HitObject)); exports.HitCircle = HitCircle; ; }); define("Precision", ["require", "exports"], function (require, exports) { "use strict"; exports.__esModule = true; var Precision = /** @class */ (function () { function Precision() { } Precision.almostEqualsNumber = function (value1, value2, acceptableDifference) { if (acceptableDifference === void 0) { acceptableDifference = this.FLOAT_EPSILON; } return Math.abs(value1 - value2) <= acceptableDifference; }; ; Precision.almostEqualsVector = function (vec1, vec2, acceptableDifference) { if (acceptableDifference === void 0) { acceptableDifference = this.FLOAT_EPSILON; } return this.almostEqualsNumber(vec1.x, vec2.x, acceptableDifference) && this.almostEqualsNumber(vec1.y, vec2.y, acceptableDifference); }; ; Precision.FLOAT_EPSILON = 1e-3; return Precision; }()); exports.Precision = Precision; ; }); define("PathApproximator", ["require", "exports", "Objects/Vector2", "Precision"], function (require, exports, Vector2_2, Precision_1) { "use strict"; exports.__esModule = true; var PathApproximator = /** @class */ (function () { function PathApproximator() { this.bezier_tolerance = 0.25; this.catmull_detail = 50; this.circular_arc_tolerance = 0.1; } PathApproximator.prototype.approximateBezier = function (controlPoints) { var output = []; var count = controlPoints.length; if (count === 0) return output; var subdivisionBuffer1 = []; var subdivisionBuffer2 = []; for (var i = 0; i < count; i++) { subdivisionBuffer1.push(new Vector2_2.Vector2(0, 0)); } for (var i = 0; i < count * 2 - 1; i++) { subdivisionBuffer2.push(new Vector2_2.Vector2(0, 0)); } var toFlatten = []; var freeBuffers = []; var deepCopy = []; controlPoints.forEach(function (c) { deepCopy.push(new Vector2_2.Vector2(c.x, c.y)); }); toFlatten.push(deepCopy); var leftChild = subdivisionBuffer2; while (toFlatten.length > 0) { var parent_1 = toFlatten.pop(); if (this.bezierIsFlatEnough(parent_1)) { this.bezierApproximate(parent_1, output, subdivisionBuffer1, subdivisionBuffer2, count); freeBuffers.push(parent_1); continue; } var rightChild = []; if (freeBuffers.length > 0) rightChild = freeBuffers.pop(); else { for (var i = 0; i < count; i++) { rightChild.push(new Vector2_2.Vector2(0, 0)); } } this.bezierSubdivide(parent_1, leftChild, rightChild, subdivisionBuffer1, count); for (var i = 0; i < count; i++) { parent_1[i] = leftChild[i]; } toFlatten.push(rightChild); toFlatten.push(parent_1); } output.push(controlPoints[count - 1]); return output; }; ; PathApproximator.prototype.approximateCatmull = function (controlPoints) { var result = []; for (var i = 0; i < controlPoints.length - 1; i++) { var v1 = i > 0 ? controlPoints[i - 1] : controlPoints[i]; var v2 = controlPoints[i]; var v3 = i < controlPoints.length - 1 ? controlPoints[i + 1] : v2.add(v2).subtract(v1); var v4 = i < controlPoints.length - 2 ? controlPoints[i + 2] : v3.add(v3).subtract(v2); for (var c = 0; c < this.catmull_detail; c++) { result.push(this.catmullFindPoint(v1, v2, v3, v4, c / this.catmull_detail)); result.push(this.catmullFindPoint(v1, v2, v3, v4, (c + 1) / this.catmull_detail)); } } return result; }; ; PathApproximator.prototype.approximateCircularArc = function (controlPoints) { var a = controlPoints[0]; var b = controlPoints[1]; var c = controlPoints[2]; var aSq = (b.subtract(c)).lengthSquared(); var bSq = (a.subtract(c)).lengthSquared(); var cSq = (a.subtract(b)).lengthSquared(); if (Precision_1.Precision.almostEqualsNumber(aSq, 0) || Precision_1.Precision.almostEqualsNumber(bSq, 0) || Precision_1.Precision.almostEqualsNumber(cSq, 0)) return []; var s = aSq * (bSq + cSq - aSq); var t = bSq * (aSq + cSq - bSq); var u = cSq * (aSq + bSq - cSq); var sum = s + t + u; if (Precision_1.Precision.almostEqualsNumber(sum, 0)) return []; var centre = (a.scale(s).add(b.scale(t)).add(c.scale(u))).divide(sum); var dA = a.subtract(centre); var dC = c.subtract(centre); var r = dA.length(); var thetaStart = Math.atan2(dA.y, dA.x); var thetaEnd = Math.atan2(dC.y, dC.x); while (thetaEnd < thetaStart) { thetaEnd += 2 * Math.PI; } var dir = 1; var thetaRange = thetaEnd - thetaStart; var orthoAtoC = c.subtract(a); orthoAtoC = new Vector2_2.Vector2(orthoAtoC.y, -orthoAtoC.x); if (orthoAtoC.dot(b.subtract(a)) < 0) { dir = -dir; thetaRange = 2 * Math.PI - thetaRange; } var amountPoints = 2 * r <= this.circular_arc_tolerance ? 2 : Math.max(2, Math.ceil(thetaRange / (2 * Math.acos(1 - this.circular_arc_tolerance / r)))); var output = []; for (var i = 0; i < amountPoints; i++) { var fract = i / (amountPoints - 1); var theta = thetaStart + dir * fract * thetaRange; var o = new Vector2_2.Vector2(Math.cos(theta), Math.sin(theta)).scale(r); output.push(centre.add(o)); } return output; }; ; PathApproximator.prototype.approximateLinear = function (controlPoints) { return controlPoints; }; ; PathApproximator.prototype.bezierIsFlatEnough = function (controlPoints) { for (var i = 1; i < controlPoints.length - 1; i++) { if ((controlPoints[i - 1].subtract(controlPoints[i].scale(2)).add(controlPoints[i + 1])).lengthSquared() > this.bezier_tolerance * this.bezier_tolerance * 4) { return false; } } return true; }; ; PathApproximator.prototype.bezierApproximate = function (controlPoints, output, subdivisionBuffer1, subdivisionBuffer2, count) { var l = subdivisionBuffer2; var r = subdivisionBuffer1; this.bezierSubdivide(controlPoints, l, r, subdivisionBuffer1, count); for (var i = 0; i < count - 1; i++) { l[count + i] = r[i + 1]; } output.push(controlPoints[0]); for (var i = 1; i < count - 1; i++) { var index = 2 * i; var p = (l[index - 1].add(l[index].scale(2)).add(l[index + 1])).scale(0.25); output.push(p); } }; ; PathApproximator.prototype.bezierSubdivide = function (controlPoints, l, r, subdivisionBuffer, count) { var midpoints = subdivisionBuffer; for (var i = 0; i < count; i++) { midpoints[i] = controlPoints[i]; } for (var i = 0; i < count; i++) { l[i] = midpoints[0]; r[count - i - 1] = midpoints[count - i - 1]; for (var j = 0; j < count - i - 1; j++) { midpoints[j] = (midpoints[j].add(midpoints[j + 1])).divide(2); } } }; ; PathApproximator.prototype.catmullFindPoint = function (vec1, vec2, vec3, vec4, t) { var t2 = t * t; var t3 = t * t2; var result = new Vector2_2.Vector2(0.5 * (2 * vec2.x + (-vec1.x + vec3.x) * t + (2 * vec1.x - 5 * vec2.x + 4 * vec3.x - vec4.x) * t2 + (-vec1.x + 3 * vec2.x - 3 * vec3.x + vec4.x) * t3), 0.5 * (2 * vec2.y + (-vec1.y + vec3.y) * t + (2 * vec1.y - 5 * vec2.y + 4 * vec3.y - vec4.y) * t2 + (-vec1.y + 3 * vec2.y - 3 * vec3.y + vec4.y) * t3)); return result; }; ; return PathApproximator; }()); ; exports["default"] = PathApproximator; }); define("SliderPath", ["require", "exports", "Objects/osu!/PathType", "PathApproximator", "Objects/Vector2", "Precision"], function (require, exports, PathType_1, PathApproximator_1, Vector2_3, Precision_2) { "use strict"; var SliderPath = /** @class */ (function () { function SliderPath(pathType, controlPoints, expectedDistance) { this.isInitialised = false; this.pathApproximator = new PathApproximator_1["default"](); this.pathType = pathType; this.controlPoints = controlPoints; this.expectedDistance = expectedDistance; this.ensureInitialised(); } ; SliderPath.prototype.ensureInitialised = function () { if (this.isInitialised) return; this.isInitialised = true; this.controlPoints = this.controlPoints !== null ? this.controlPoints : []; this.calculatedPath = []; this.cumulativeLength = []; this.calculatePath(); this.calculateCumulativeLength(); }; ; SliderPath.prototype.calculatePath = function () { var _this = this; this.calculatedPath = []; var start = 0; var end = 0; for (var i = 0; i < this.controlPoints.length; i++) { end++; //Different class instances are always different, so check the x and y values for equality instead if (i === this.controlPoints.length - 1 || (this.controlPoints[i].x === this.controlPoints[i + 1].x && this.controlPoints[i].y === this.controlPoints[i + 1].y)) { var cpSpan = this.controlPoints.slice(start, end); this.calculateSubPath(cpSpan).forEach(function (t) { if (_this.calculatedPath.length === 0 || _this.calculatedPath[_this.calculatedPath.length - 1].x !== t.x || _this.calculatedPath[_this.calculatedPath.length - 1].y !== t.y) { _this.calculatedPath.push(new Vector2_3.Vector2(t.x, t.y)); } }); start = end; } } }; ; SliderPath.prototype.calculateSubPath = function (subControlPoints) { switch (this.pathType) { case PathType_1.PathType.Linear: return this.pathApproximator.approximateLinear(subControlPoints); case PathType_1.PathType.PerfectCurve: if (this.controlPoints.length !== 3 || subControlPoints.length !== 3) break; var subPath = this.pathApproximator.approximateCircularArc(subControlPoints); if (subPath.length === 0) break; return subPath; case PathType_1.PathType.Catmull: return this.pathApproximator.approximateCatmull(subControlPoints); } return this.pathApproximator.approximateBezier(subControlPoints); }; ; SliderPath.prototype.calculateCumulativeLength = function () { var l = 0; this.cumulativeLength = []; this.cumulativeLength.push(l); for (var i = 0; i < this.calculatedPath.length - 1; i++) { var diff = this.calculatedPath[i + 1].subtract(this.calculatedPath[i]); var d = diff.length(); if (this.expectedDistance !== null && this.expectedDistance !== undefined && this.expectedDistance - l < d) { this.calculatedPath[i + 1] = this.calculatedPath[i].add(diff.scale((this.expectedDistance - l) / d)); this.calculatedPath.splice(i + 2, this.calculatedPath.length - 2 - i); l = this.expectedDistance; this.cumulativeLength.push(l); break; } l += d; this.cumulativeLength.push(l); } if (this.expectedDistance !== undefined && this.expectedDistance !== null && l < this.expectedDistance && this.calculatedPath.length > 1) { var diff = this.calculatedPath[this.calculatedPath.length - 1].subtract(this.calculatedPath[this.calculatedPath.length - 2]); var d = diff.length(); if (d <= 0) return; this.calculatedPath[this.calculatedPath.length - 1].add(diff.scale((this.expectedDistance - l) / d)); this.cumulativeLength[this.calculatedPath.length - 1] = this.expectedDistance; } }; ; SliderPath.prototype.PositionAt = function (progress) { this.ensureInitialised(); var d = this.progressToDistance(progress); return this.interpolateVertices(this.indexOfDistance(d), d); }; ; SliderPath.prototype.progressToDistance = function (progress) { return Math.min(Math.max(progress, 0), 1) * this.expectedDistance; }; ; SliderPath.prototype.interpolateVertices = function (i, d) { if (this.calculatedPath.length === 0) return new Vector2_3.Vector2(0, 0); if (i <= 0) return this.calculatedPath[0]; if (i >= this.calculatedPath.length) return this.calculatedPath[this.calculatedPath.length - 1]; var p0 = this.calculatedPath[i - 1]; var p1 = this.calculatedPath[i]; var d0 = this.cumulativeLength[i - 1]; var d1 = this.cumulativeLength[i]; if (Precision_2.Precision.almostEqualsNumber(d0, d1)) return p0; var w = (d - d0) / (d1 - d0); var result = p0.add(p1.subtract(p0).scale(w)); return result; }; ; SliderPath.prototype.indexOfDistance = function (d) { var index = this.cumulativeLength.indexOf(d); if (index < 0) { for (var i = 0; i < this.cumulativeLength.length; i++) { if (this.cumulativeLength[i] > d) { return i; } } return this.cumulativeLength.length; } return index; }; ; return SliderPath; }()); return SliderPath; }); define("Objects/osu!/HitObjects/SliderObjects/HeadCircle", ["require", "exports", "Objects/osu!/HitObjects/HitCircle"], function (require, exports, HitCircle_1) { "use strict"; exports.__esModule = true; var HeadCircle = /** @class */ (function (_super) { __extends(HeadCircle, _super); function HeadCircle() { return _super !== null && _super.apply(this, arguments) || this; } return HeadCircle; }(HitCircle_1.HitCircle)); exports.HeadCircle = HeadCircle; ; }); define("Objects/osu!/HitObjects/SliderObjects/TailCircle", ["require", "exports", "Objects/osu!/HitObjects/HitCircle"], function (require, exports, HitCircle_2) { "use strict"; exports.__esModule = true; var TailCircle = /** @class */ (function (_super) { __extends(TailCircle, _super); function TailCircle() { return _super !== null && _super.apply(this, arguments) || this; } return TailCircle; }(HitCircle_2.HitCircle)); exports.TailCircle = TailCircle; ; }); define("Objects/osu!/HitObjects/SliderObjects/SliderTick", ["require", "exports", "Objects/osu!/HitObjects/HitObject"], function (require, exports, HitObject_2) { "use strict"; exports.__esModule = true; var SliderTick = /** @class */ (function (_super) { __extends(SliderTick, _super); function SliderTick(pos, startTime, spanIndex, spanStartTime, radius) { var _this = _super.call(this, pos, startTime, radius) || this; _this.SpanIndex = spanIndex; _this.SpanStartTime = spanStartTime; return _this; } ; return SliderTick; }(HitObject_2.HitObject)); exports.SliderTick = SliderTick; ; }); define("Objects/osu!/HitObjects/SliderObjects/RepeatPoint", ["require", "exports", "Objects/osu!/HitObjects/HitObject"], function (require, exports, HitObject_3) { "use strict"; exports.__esModule = true; var RepeatPoint = /** @class */ (function (_super) { __extends(RepeatPoint, _super); function RepeatPoint(pos, startTime, repeatIndex, spanDuration, radius) { var _this = _super.call(this, pos, startTime, radius) || this; _this.RepeatIndex = repeatIndex; _this.SpanDuration = spanDuration; return _this; } ; return RepeatPoint; }(HitObject_3.HitObject)); exports.RepeatPoint = RepeatPoint; ; }); define("Objects/osu!/HitObjects/Slider", ["require", "exports", "Objects/osu!/HitObjects/HitObject", "Objects/osu!/HitObjects/SliderObjects/HeadCircle", "Objects/osu!/HitObjects/SliderObjects/TailCircle", "Objects/osu!/HitObjects/SliderObjects/SliderTick", "Objects/osu!/HitObjects/SliderObjects/RepeatPoint"], function (require, exports, HitObject_4, HeadCircle_1, TailCircle_1, SliderTick_1, RepeatPoint_1) { "use strict"; exports.__esModule = true; /** * Class for sliders */ var Slider = /** @class */ (function (_super) { __extends(Slider, _super); /** * * @param pos The raw position of the slider (as listed in the .osu file) * @param startTime The start time of the slider * @param path The calculated slider path of the slider * @param repeatCount The number of repeats this slider has * @param speedMultiplier The speed multiplier of this slider compared to the base bpm * @param beatLength The length of one beat in ms at this point in the map * @param mapDifficulty The difficulty settings of the beatmap * @param radius The radius of the slider head circle */ function Slider(pos, startTime, path, repeatCount, speedMultiplier, beatLength, mapDifficulty, radius) { var _this = _super.call(this, pos, startTime, radius) || this; _this.LegacyLastTickOffset = 36; _this.Path = path; _this.EndPosition = _this.Position.add(_this.Path.PositionAt(1)); _this.calculateEndTimeAndTickDistance(speedMultiplier, beatLength, mapDifficulty, repeatCount, startTime, path.expectedDistance); _this.Duration = _this.EndTime - startTime; _this.RepeatCount = repeatCount; _this.createNestedHitObjects(); return _this; } ; Slider.prototype.calculateEndTimeAndTickDistance = function (speedMultiplier, beatLength, mapDifficulty, repeatCount, startTime, expectedDistance) { var scoringDistance = 100 * mapDifficulty.SliderMultiplier * speedMultiplier; this.Velocity = scoringDistance / beatLength; this.SpanCount = repeatCount + 1; this.TickDistance = scoringDistance / mapDifficulty.SliderTickRate * 1; this.EndTime = startTime + this.SpanCount * expectedDistance / this.Velocity; }; ; /** * Creates the nested hit objects (head and tail circle, slider ticks and repeat points) for this slider */ Slider.prototype.createNestedHitObjects = function () { this.NestedHitObjects = []; this.createSliderEnds(); this.createSliderTicks(); this.createRepeatPoints(); this.NestedHitObjects.sort(function (a, b) { return a.StartTime - b.StartTime; }); this.TailCircle.StartTime = Math.max(this.StartTime + this.Duration / 2, this.TailCircle.StartTime - this.LegacyLastTickOffset); }; ; Slider.prototype.createSliderEnds = function () { this.HeadCircle = new HeadCircle_1.HeadCircle(this.Position, this.StartTime, this.Radius); this.TailCircle = new TailCircle_1.TailCircle(this.EndPosition, this.EndTime, this.Radius); this.NestedHitObjects.push(this.HeadCircle); this.NestedHitObjects.push(this.TailCircle); }; ; Slider.prototype.createSliderTicks = function () { var max_length = 100000; var length = Math.min(max_length, this.Path.expectedDistance); var tickDistance = Math.min(Math.max(this.TickDistance, 0), length); if (tickDistance === 0) return; var minDistanceFromEnd = this.Velocity * 10; this.SpanDuration = this.Duration / this.SpanCount; for (var span = 0; span < this.SpanCount; span++) { var spanStartTime = this.StartTime + span * this.SpanDuration; var reversed = span % 2 === 1; for (var d = tickDistance; d <= length; d += tickDistance) { if (d > length - minDistanceFromEnd) break; var distanceProgress = d / length; var timeProgress = reversed ? 1 - distanceProgress : distanceProgress; var sliderTickPosition = this.Position.add(this.Path.PositionAt(distanceProgress)); var sliderTick = new SliderTick_1.SliderTick(sliderTickPosition, spanStartTime + timeProgress * this.SpanDuration, span, spanStartTime, this.Radius); this.NestedHitObjects.push(sliderTick); } } }; ; Slider.prototype.createRepeatPoints = function () { for (var repeatIndex = 0, repeat = 1; repeatIndex < this.RepeatCount; repeatIndex++, repeat++) { var repeatPosition = this.Position.add(this.Path.PositionAt(repeat % 2)); var repeatPoint = new RepeatPoint_1.RepeatPoint(repeatPosition, this.StartTime + repeat * this.SpanDuration, repeatIndex, this.SpanDuration, this.Radius); this.NestedHitObjects.push(repeatPoint); } }; ; return Slider; }(HitObject_4.HitObject)); exports.Slider = Slider; ; }); define("Objects/osu!/HitObjects/Spinner", ["require", "exports", "Objects/osu!/HitObjects/HitObject"], function (require, exports, HitObject_5) { "use strict"; exports.__esModule = true; /** * Class for spinners */ var Spinner = /** @class */ (function (_super) { __extends(Spinner, _super); /** * * @param startTime The start time of the spinner * @param endTime The end time of the spinner */ function Spinner(pos, startTime, endTime) { var _this = _super.call(this, pos, startTime) || this; _this.EndTime = endTime; return _this; } ; return Spinner; }(HitObject_5.HitObject)); exports.Spinner = Spinner; ; }); define("BeatmapParser", ["require", "exports", "Objects/osu!/HitType", "Objects/osu!/PathType", "Objects/Vector2", "Objects/osu!/Beatmap", "Objects/osu!/HitObjects/HitCircle", "Objects/osu!/HitObjects/Slider", "Objects/osu!/HitObjects/Spinner", "SliderPath", "Precision"], function (require, exports, HitType_1, PathType_2, Vector2_4, Beatmap_1, HitCircle_3, Slider_1, Spinner_1, SliderPath, Precision_3) { "use strict"; exports.__esModule = true; var BeatmapParser = /** @class */ (function () { function BeatmapParser() { } BeatmapParser.prototype.parseBeatmap = function (data, mods) { function isLinear(p) { return Precision_3.Precision.almostEqualsNumber(0, (p[1].y - p[0].y) * (p[2].x - p[0].x) - (p[1].x - p[0].x) * (p[2].y - p[0].y)); } if (!data) throw new Error('No beatmap found'); this.beatmap = new Beatmap_1.Beatmap(); var section = null; var lines = data.split('\n').map(function (line) { return line.trim(); }); var _loop_1 = function (line) { if (line.startsWith('//')) return "continue"; if (!line) return "continue"; if (!section && line.includes('osu file format v')) { this_1.beatmap.Version = parseInt(line.split('osu file format v')[1], 10); return "continue"; } if (/^\s*\[(.+?)\]\s*$/.test(line)) { section = /^\s*\[(.+?)\]\s*$/.exec(line)[1]; return "continue"; } switch (section) { case 'General': { var _a = line.split(':').map(function (v) { return v.trim(); }), key = _a[0], value = _a[1]; if (key === 'StackLeniency') this_1.beatmap.StackLeniency = parseFloat(value); break; } case 'Difficulty': { var _b = line.split(':').map(function (v) { return v.trim(); }), key = _b[0], value = _b[1]; this_1.beatmap[section][key] = parseFloat(value); break; } case 'TimingPoints': { var split = line.split(','); var time = +split[0] + (this_1.beatmap.Version < 5 ? 24 : 0); var beatLength = +split[1]; var speedMultiplier = beatLength < 0 ? 100 / -beatLength : 1; var timeSignature = 4; if (split.length >= 3) timeSignature = split[2][0] === '0' ? 4 : +split[2]; var timingChange = true; if (split.length >= 7) timingChange = split[6][0] === '1'; if (timingChange) { this_1.beatmap.TimingPoints.push({ Time: time, BeatLength: beatLength, TimeSignature: timeSignature }); } this_1.beatmap.DifficultyTimingPoints.push({ Time: time, SpeedMultiplier: speedMultiplier }); break; } case 'HitObjects': { var split = line.split(','); var pos_1 = new Vector2_4.Vector2(+split[0], +split[1]); var startTime = +split[2]; var hitType = +split[3]; var result = null; var scale_1 = (1 - 0.7 * (this_1.getCircleSize(mods) - 5) / 5) / 2; var radius = 64 * scale_1; if (hitType & HitType_1.HitType.Normal) { result = this_1.createCircle(pos_1, startTime, radius); } if (hitType & HitType_1.HitType.Slider) { var pathType_1; var length_1 = 0; var pointSplit = split[5].split('|'); var points_1 = [new Vector2_4.Vector2(0, 0)]; pointSplit.forEach(function (point) { if (point.length === 1) { switch (point) { case 'C': pathType_1 = PathType_2.PathType.Catmull; break; case 'B': pathType_1 = PathType_2.PathType.Bezier; break; case 'L': pathType_1 = PathType_2.PathType.Linear; break; case 'P': pathType_1 = PathType_2.PathType.PerfectCurve; break; default: pathType_1 = PathType_2.PathType.Catmull; break; } return; } var temp = point.split(':'); points_1.push(new Vector2_4.Vector2(+temp[0], +temp[1]).subtract(pos_1)); }); if (points_1.length === 3 && pathType_1 === PathType_2.PathType.PerfectCurve && isLinear(points_1)) pathType_1 = PathType_2.PathType.Linear; var repeatCount = +split[6]; repeatCount = Math.max(0, repeatCount - 1); if (split.length > 7) length_1 = +split[7]; var slider = this_1.createSlider(pos_1, points_1, length_1, pathType_1, repeatCount, startTime, radius); result = slider; } if (hitType & HitType_1.HitType.Spinner) { var endTime = +split[5]; result = this_1.createSpinner(pos_1, startTime, endTime); } this_1.beatmap.HitObjects.push(result); } } }; var this_1 = this; for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) { var line = lines_1[_i]; _loop_1(line); } this.beatmap.HitObjects.forEach(function (h) { h.StackHeight = 0; }); this.applyStacking(0, this.beatmap.HitObjects.length - 1); var scale = (1 - 0.7 * (this.getCircleSize(mods) - 5) / 5) / 2; this.beatmap.HitObjects.forEach(function (hitObject) { hitObject.calculateStackedPosition(scale); }); return this.beatmap; }; ; BeatmapParser.prototype.createCircle = function (pos, startTime, radius) { return new HitCircle_3.HitCircle(pos, startTime, radius); }; ; BeatmapParser.prototype.createSlider = function (pos, points, length, pathType, repeatCount, startTime, radius) { var path = new SliderPath(pathType, points, Math.max(0, length)); var speedMultiplier = this.getSpeedMultiplier(startTime); var beatLength = this.getBeatLength(startTime); return new Slider_1.Slider(pos, startTime, path, repeatCount, speedMultiplier, beatLength, this.beatmap.Difficulty, radius); }; ; BeatmapParser.prototype.createSpinner = function (pos, startTime, endTime) { return new Spinner_1.Spinner(pos, startTime, endTime); }; ; BeatmapParser.prototype.getSpeedMultiplier = function (startTime) { var currentTimingPoint = this.getTimingPoints(startTime, this.beatmap.DifficultyTimingPoints); return currentTimingPoint.SpeedMultiplier; }; ; BeatmapParser.prototype.getBeatLength = function (startTime) { var currentTimingPoint = this.getTimingPoints(startTime, this.beatmap.TimingPoints); return currentTimingPoint.BeatLength; }; ; BeatmapParser.prototype.getTimingPoints = function (startTime, timingPoints) { timingPoints.sort(function (a, b) { return a.Time - b.Time; }); var currentTimingPoint; for (var i = 0; i < timingPoints.length; i++) { if (timingPoints[i].Time > startTime) { currentTimingPoint = i - 1; break; } } if (currentTimingPoint < 0) { console.warn("Warning: first timing point after current hit object (", startTime, "). Defaulting to first timing point of the map"); currentTimingPoint = 0; } if (currentTimingPoint === undefined) currentTimingPoint = timingPoints.length - 1; return timingPoints[currentTimingPoint]; }; ; BeatmapParser.prototype.applyStacking = function (startIndex, endIndex) { var stack_distance = 3; var TimePreempt = 600; if (this.beatmap.Difficulty.ApproachRate > 5) TimePreempt = 1200 + (450 - 1200) * (this.beatmap.Difficulty.ApproachRate - 5) / 5; else if (this.beatmap.Difficulty.ApproachRate < 5) TimePreempt = 1200 - (1200 - 1800) * (5 - this.beatmap.Difficulty.ApproachRate) / 5; else TimePreempt = 1200; var extendedEndIndex = endIndex; if (endIndex < this.beatmap.HitObjects.length - 1) { for (var i = endIndex; i >= startIndex; i--) { var stackBaseIndex = i; for (var n = stackBaseIndex + 1; n < this.beatmap.HitObjects.length; n++) { var stackBaseObject = this.beatmap.HitObjects[stackBaseIndex]; if (stackBaseObject instanceof Spinner_1.Spinner) break; var objectN = this.beatmap.HitObjects[n]; if (objectN instanceof Spinner_1.Spinner) continue; var endTime = stackBaseObject instanceof HitCircle_3.HitCircle ? stackBaseObject.StartTime : stackBaseObject.EndTime; var stackThresHold = TimePreempt * this.beatmap.StackLeniency; if (objectN.StartTime - endTime > stackThresHold) break; var endPositionDistanceCheck = stackBaseObject instanceof Slider_1.Slider ? stackBaseObject.EndPosition.distance(objectN.Position) < stack_distance : false; if (stackBaseObject.Position.distance(objectN.Position) < stack_distance || endPositionDistanceCheck) { stackBaseIndex = n; objectN.StackHeight = 0; } } if (stackBaseIndex > extendedEndIndex) { extendedEndIndex = stackBaseIndex; if (extendedEndIndex === this.beatmap.HitObjects.length - 1) break; } } } var extendedStartIndex = startIndex; for (var i = extendedEndIndex; i > startIndex; i--) { var n = i; var objectI = this.beatmap.HitObjects[i]; if (objectI.StackHeight !== 0 || objectI instanceof Spinner_1.Spinner) continue; var stackThresHold = TimePreempt * this.beatmap.StackLeniency; if (objectI instanceof HitCircle_3.HitCircle) { while (--n >= 0) { var objectN = this.beatmap.HitObjects[n]; if (objectN instanceof Spinner_1.Spinner) continue; var endTime = objectN instanceof HitCircle_3.HitCircle ? objectN.StartTime : objectN.EndTime; if (objectI.StartTime - endTime > stackThresHold) break; if (n < extendedStartIndex) { objectN.StackHeight = 0; extendedStartIndex = n; } var endPositionDistanceCheck = objectN instanceof Slider_1.Slider ? objectN.EndPosition.distance(objectI.Position) < stack_distance : false; if (endPositionDistanceCheck) { var offset = objectI.StackHeight - objectN.StackHeight + 1; for (var j = n + 1; j <= i; j++) { var objectJ = this.beatmap.HitObjects[j]; if (objectN.EndPosition.distance(objectJ.Position) < stack_distance) { objectJ.StackHeight -= offset; } } break; } if (objectN.Position.distance(objectI.Position) < stack_distance) { objectN.StackHeight = objectI.StackHeight + 1; objectI = objectN; } } } else if (objectI instanceof Slider_1.Slider) { while (--n >= startIndex) { var objectN = this.beatmap.HitObjects[n]; if (objectN instanceof Spinner_1.Spinner) continue; if (objectI.StartTime - objectN.StartTime > stackThresHold) break; var objectNEndPosition = objectN instanceof HitCircle_3.HitCircle ? objectN.Position : objectN.EndPosition; if (objectNEndPosition.distance(objectI.Position) < stack_distance) { objectN.StackHeight = objectI.StackHeight + 1; objectI = objectN; } } } } }; ; BeatmapParser.prototype.getCircleSize = function (mods) { if (mods.includes("HR")) return Math.min(this.beatmap.Difficulty.CircleSize * 1.3, 10); if (mods.includes("EZ")) return this.beatmap.Difficulty.CircleSize * 0.5; return this.beatmap.Difficulty.CircleSize; }; ; return BeatmapParser; }()); ; exports["default"] = BeatmapParser; }); define("Objects/osu!/HitObjects/DifficultyHitObject", ["require", "exports", "Objects/osu!/HitObjects/HitObject"], function (require, exports, HitObject_6) { "use strict"; exports.__esModule = true; /** * HitObject with additional difficulty properties required to calculate the star rating */ var DifficultyHitObject = /** @class */ (function (_super) { __extends(DifficultyHitObject, _super); /** * * @param currentObject HitObject to create a DifficultyHitObject from * @param lastObject HitObject before the current HitObject * @param lastLastObject HitObject before the lastObject * @param travelDistance The calculated Travel Distance for this HitObject * @param jumpDistance The calculated Jump Distance for this HitObject * @param angle The calculated Angle for this HitObject * @param deltaTime The calculated Deltatime for this HitObject * @param strainTime The calculated Straintime for this hitObject */ function DifficultyHitObject(currentObject, lastObject, lastLastObject, travelDistance, jumpDistance, angle, deltaTime, strainTime) { var _this = _super.call(this, currentObject.Position, currentObject.StartTime, currentObject.Radius) || this; _this.TravelDistance = travelDistance; _this.JumpDistance = jumpDistance; _this.Angle = angle; _this.DeltaTime = deltaTime; _this.StrainTime = strainTime; _this.CurrentObject = currentObject; _this.LastObject = lastObject; _this.LastLastObject = lastLastObject; return _this; } ; return DifficultyHitObject; }(HitObject_6.HitObject)); exports.DifficultyHitObject = DifficultyHitObject; ; }); define("DifficultyHitObjectCreator", ["require", "exports", "Objects/osu!/HitObjects/DifficultyHitObject", "Objects/osu!/HitObjects/Slider", "Objects/osu!/HitObjects/Spinner"], function (require, exports, DifficultyHitObject_1, Slider_2, Spinner_2) { "use strict"; exports.__esModule = true; var DifficultyHitObjectCreator = /** @class */ (function () { function DifficultyHitObjectCreator() { this.normalized_radius = 52; this.TravelDistance = 0; this.JumpDistance = 0; this.Angle = 0; this.DeltaTime = 0; this.StrainTime = 0; } DifficultyHitObjectCreator.prototype.convertToDifficultyHitObjects = function (hitObjects, timeRate) { this.difficultyHitObjects = []; for (var i = 1; i < hitObjects.length; i++) { var lastLast = i > 1 ? hitObjects[i - 2] : null; var last = hitObjects[i - 1]; var current = hitObjects[i]; var difficultyHitObject = this.createDifficultyHitObject(lastLast, last, current, timeRate); this.difficultyHitObjects.push(difficultyHitObject); } return this.difficultyHitObjects; }; ; DifficultyHitObjectCreator.prototype.createDifficultyHitObject = function (lastLast, last, current, timeRate) { this.lastLastObject = lastLast; this.lastObject = last; this.currentObject = current; this.timeRate = timeRate; this.setDistances(); this.setTimingValues(); return new DifficultyHitObject_1.DifficultyHitObject(this.currentObject, this.lastObject, this.lastLastObject, this.TravelDistance, this.JumpDistance, this.Angle, this.DeltaTime, this.StrainTime); }; ; DifficultyHitObjectCreator.prototype.setDistances = function () { this.TravelDistance = 0; this.JumpDistance = 0; this.Angle = 0; this.DeltaTime = 0; this.StrainTime = 0; var scalingFactor = this.normalized_radius / this.currentObject.Radius; if (this.currentObject.Radius < 30) { var smallCircleBonus = Math.min(30 - this.currentObject.Radius, 5) / 50; scalingFactor *= 1 + smallCircleBonus; } if (this.lastObject instanceof Slider_2.Slider) { var lastSlider = this.lastObject; this.computeSliderCursorPosition(lastSlider); this.TravelDistance = lastSlider.LazyTravelDistance * scalingFactor; } var lastCursorPosition = this.getEndCursorPosition(this.lastObject); if (!(this.currentObject instanceof Spinner_2.Spinner)) this.JumpDistance = this.currentObject.StackedPosition.scale(scalingFactor).subtract(lastCursorPosition.scale(scalingFactor)).length(); if (this.lastLastObject !== null) { var lastLastCursorPosition = this.getEndCursorPosition(this.lastLastObject); var v1 = lastLastCursorPosition.subtract(this.lastObject.StackedPosition); var v2 = this.currentObject.StackedPosition.subtract(lastCursorPosition); var dot = v1.dot(v2); var det = v1.x * v2.y - v1.y * v2.x; this.Angle = Math.abs(Math.atan2(det, dot)); } }; ; DifficultyHitObjectCreator.prototype.setTimingValues = function () { this.DeltaTime = (this.currentObject.StartTime - this.lastObject.StartTime) / this.timeRate; this.StrainTime = Math.max(50, this.DeltaTime); }; ; DifficultyHitObjectCreator.prototype.computeSliderCursorPosition = function (slider) { if (slider.LazyEndPosition !== null && slider.LazyEndPosition !== undefined) return; slider.LazyEndPosition = slider.StackedPosition; slider.LazyTravelDistance = 0; var approxFollowCircleRadius = slider.Radius * 3; function computeVertex(t) { var progress = (t - slider.StartTime) / slider.SpanDuration; if (progress % 2 >= 1) progress = 1 - progress % 1; else progress = progress % 1; var diff = slider.StackedPosition.add(slider.Path.PositionAt(progress)).subtract(slider.LazyEndPosition); var dist = diff.length(); if (dist > approxFollowCircleRadius) { diff.normalize(); dist -= approxFollowCircleRadius; slider.LazyEndPosition = slider.LazyEndPosition.add(diff.scale(dist)); slider.LazyTravelDistance = slider.LazyTravelDistance === undefined ? dist : slider.LazyTravelDistance += dist; } } ; var scoringTimes = slider.NestedHitObjects.slice(1, slider.NestedHitObjects.length).map(function (t) { return t.StartTime; }); scoringTimes.forEach(function (time) { computeVertex(time); }); }; ; DifficultyHitObjectCreator.prototype.getEndCursorPosition = function (object) { var pos = object.StackedPosition; if (object instanceof Slider_2.Slider) { this.computeSliderCursorPosition(object); pos = object.LazyEndPosition !== null && object.LazyEndPosition !== undefined ? object.LazyEndPosition : pos; } return pos; }; ; return DifficultyHitObjectCreator; }()); ; exports["default"] = DifficultyHitObjectCreator; }); define("Skills/Skill", ["require", "exports", "Objects/osu!/HitObjects/Spinner"], function (require, exports, Spinner_3) { "use strict"; exports.__esModule = true; var Skill = /** @class */ (function () { function Skill() { this.SINGLE_SPACING_THRESHOLD = 125; this.STREAM_SPACING_THRESHOLD = 110; this.Previous = []; this.currentStrain = 1; this.currentSectionPeak = 1; this.strainPeaks = []; } Skill.prototype.saveCurrentPeak = function () { if (this.Previous.length > 0) this.strainPeaks.push(this.currentSectionPeak); }; ; Skill.prototype.startNewSectionFrom = function (offset) { if (this.Previous.length > 0) this.currentSectionPeak = this.currentStrain * this.strainDecay(offset - this.Previous[0].CurrentObject.StartTime); }; ; Skill.prototype.process = function (currentObject) { this.currentStrain *= this.strainDecay(currentObject.DeltaTime); if (!(currentObject.CurrentObject instanceof Spinner_3.Spinner)) this.currentStrain += this.strainValueOf(currentObject) * this.SkillMultiplier; this.currentSectionPeak = Math.max(this.currentStrain, this.currentSectionPeak); this.addToHistory(currentObject); }; ; Skill.prototype.difficultyValue = function () { this.strainPeaks.sort(function (a, b) { return b - a; }); var difficulty = 0; var weight = 1; this.strainPeaks.forEach(function (strain) { difficulty += strain * weight; weight *= 0.9; }); return difficulty; }; ; Skill.prototype.strainDecay = function (ms) { return Math.pow(this.StrainDecayBase, ms / 1000); }; ; Skill.prototype.addToHistory = function (currentObject) { this.Previous.unshift(currentObject); if (this.Previous.length > 2) this.Previous.pop(); }; ; return Skill; }()); exports.Skill = Skill; ; }); define("Skills/Aim", ["require", "exports", "Skills/Skill"], function (require, exports, Skill_1) { "use strict"; exports.__esModule = true; var Aim = /** @class */ (function (_super) { __extends(Aim, _super); function Aim() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.angle_bonus_begin = Math.PI / 3; _this.timing_threshold = 107; _this.SkillMultiplier = 26.25; _this.StrainDecayBase = 0.15; return _this; } Aim.prototype.strainValueOf = function (currentObject) { var result = 0; var scale = 90; function applyDiminishingExp(val) { return Math.pow(val, 0.99); } ; if (this.Previous.length > 0) { if (currentObject.Angle !== null && currentObject.Angle !== undefined && currentObject.Angle > 0 && currentObject.Angle > this.angle_bonus_begin) { var angleBonus = Math.sqrt(Math.max(this.Previous[0].JumpDistance - scale, 0) * Math.pow(Math.sin(currentObject.Angle - this.angle_bonus_begin), 2) * Math.max(currentObject.JumpDistance - scale, 0)); result = 1.5 * applyDiminishingExp(Math.max(0, angleBonus)) / Math.max(this.timing_threshold, this.Previous[0].StrainTime); } } var jumpDistanceExp = applyDiminishingExp(currentObject.JumpDistance); var travelDistanceExp = applyDiminishingExp(currentObject.TravelDistance); var returnValue = Math.max(result + (jumpDistanceExp + travelDistanceExp + Math.sqrt(travelDistanceExp * jumpDistanceExp)) / Math.max(currentObject.StrainTime, this.timing_threshold), (Math.sqrt(travelDistanceExp * jumpDistanceExp) + jumpDistanceExp + travelDistanceExp) / currentObject.StrainTime); return returnValue; }; ; return Aim; }(Skill_1.Skill)); exports.Aim = Aim; ; }); define("Skills/Speed", ["require", "exports", "Skills/Skill"], function (require, exports, Skill_2) { "use strict"; exports.__esModule = true; var Speed = /** @class */ (function (_super) { __extends(Speed, _super); function Speed() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.angle_bonus_begin = 5 * Math.PI / 6; _this.pi_over_4 = Math.PI / 4; _this.pi_over_2 = Math.PI / 2; _this.SkillMultiplier = 1400; _this.StrainDecayBase = 0.3; _this.min_speed_bonus = 75; _this.max_speed_bonus = 45; _this.speed_balancing_factor = 40; return _this; } Speed.prototype.strainValueOf = function (currentObject) { var distance = Math.min(this.SINGLE_SPACING_THRESHOLD, currentObject.TravelDistance + currentObject.JumpDistance); var deltaTime = Math.max(this.max_speed_bonus, currentObject.DeltaTime); var speedBonus = 1.0; if (deltaTime < this.min_speed_bonus) speedBonus = 1 + Math.pow((this.min_speed_bonus - deltaTime) / this.speed_balancing_factor, 2); var angleBonus = 1.0; if (currentObject.Angle !== null && currentObject.Angle !== undefined && currentObject.Angle > 0 && currentObject.Angle < this.angle_bonus_begin) { angleBonus = 1 + Math.pow(Math.sin(1.5 * (this.angle_bonus_begin - currentObject.Angle)), 2) / 3.57; if (currentObject.Angle < this.pi_over_2) { angleBonus = 1.28; if (distance < 90 && currentObject.Angle < this.pi_over_4) angleBonus += (1 - angleBonus) * Math.min((90 - distance) / 10, 1); else if (distance < 90) angleBonus += (1 - angleBonus) * Math.min((90 - distance) / 10, 1) * Math.sin((this.pi_over_2 - currentObject.Angle) / this.pi_over_4); } } var returnValue = (1 + (speedBonus - 1) * 0.75) * angleBonus * (0.95 + speedBonus * Math.pow(distance / this.SINGLE_SPACING_THRESHOLD, 3.5)) / currentObject.StrainTime; return returnValue; }; ; return Speed; }(Skill_2.Skill)); exports.Speed = Speed; ; }); define("StarRatingCalculator", ["require", "exports", "Skills/Aim", "Skills/Speed"], function (require, exports, Aim_1, Speed_1) { "use strict"; exports.__esModule = true; ; var StarRatingCalculator = /** @class */ (function () { function StarRatingCalculator() { this.section_length = 400; this.difficulty_multiplier = 0.0675; } StarRatingCalculator.prototype.calculate = function (hitObjects, timeRate) { var _a; this.hitObjects = hitObjects; var aimSkill = new Aim_1.Aim(); var speedSkill = new Speed_1.Speed(); var sectionLength = this.section_length * timeRate; var currentSectionEnd = Math.ceil((((_a = this.hitObjects[0]) === null || _a === void 0 ? void 0 : _a.StartTime) || 0) / sectionLength) * sectionLength; this.hitObjects.forEach(function (h) { // console.log("JumpDistance:", h.JumpDistance, "- TravelDistance:", h.TravelDistance, "- DeltaTime:", h.DeltaTime, "- StrainTime:", h.StrainTime, "- Angle:", h.Angle); while (h.CurrentObject.StartTime > currentSectionEnd) { aimSkill.saveCurrentPeak(); aimSkill.startNewSectionFrom(currentSectionEnd); speedSkill.saveCurrentPeak(); speedSkill.startNewSectionFrom(currentSectionEnd); currentSectionEnd += sectionLength; } aimSkill.process(h); speedSkill.process(h); }); aimSkill.saveCurrentPeak(); speedSkill.saveCurrentPeak(); var aimRating = Math.sqrt(aimSkill.difficultyValue()) * this.difficulty_multiplier; var speedRating = Math.sqrt(speedSkill.difficultyValue()) * this.difficulty_multiplier; var starRating = aimRating + speedRating + Math.abs(aimRating - speedRating) / 2; return { aim: aimRating, speed: speedRating, total: starRating }; }; return StarRatingCalculator; }()); ; exports["default"] = StarRatingCalculator; }); define("osu-service", ["require", "exports"], function (require, exports) { "use strict"; exports.__esModule = true; var OsuService = /** @class */ (function () { function OsuService() { } OsuService.prototype.getOsuBeatmap = function (map_id) { var request = require('request'); return new Promise(function (resolve, reject) { var url = "https://osu.ppy.sh/osu/" + map_id; request(url, function (error, response, body) { if (!error && response.statusCode === 200) resolve(body); else reject(error); }); }); }; ; return OsuService; }()); exports.OsuService = OsuService; ; }); define("index", ["require", "exports", "osu-service", "BeatmapParser", "DifficultyHitObjectCreator", "StarRatingCalculator"], function (require, exports, osu_service_1, BeatmapParser_1, DifficultyHitObjectCreator_1, StarRatingCalculator_1) { "use strict"; exports.__esModule = true; var osuService = new osu_service_1.OsuService(); var beatmapParser = new BeatmapParser_1["default"](); var difficultyHitObjectCreator = new DifficultyHitObjectCreator_1["default"](); var starRatingCalculator = new StarRatingCalculator_1["default"](); var Beatmap = null; function calculateStarRating(map_id, mods, allCombinations, returnAllDifficultyValues) { if (returnAllDifficultyValues === void 0) { returnAllDifficultyValues = false; } return __awaiter(this, void 0, void 0, function () { var map, output, label, response, allModCombinations; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, getOsuBeatmap(map_id)]; case 1: map = _a.sent(); if (map === null) throw new Error("No map found for specified map id"); mods = parseMods(mods); output = {}; if (!allCombinations) { label = mods.length > 0 ? mods.join('') : "nomod"; response = calculateNextModCombination(map, mods, true); output[label] = returnAllDifficultyValues ? response : response.total; return [2 /*return*/, output]; } else { allModCombinations = getAllModCombinations(); allModCombinations.forEach(function (combi) { var label = combi.mods.length > 0 ? combi.mods.join('') : "nomod"; var response = calculateNextModCombination(map, combi.mods, combi.reParse); output[label] = returnAllDifficultyValues ? response : response.total; }); return [2 /*return*/, output]; } return [2 /*return*/]; } }); }); } exports.calculateStarRating = calculateStarRating; function calculateNextModCombination(map, mods, reParse) { if (reParse) Beatmap = beatmapParser.parseBeatmap(map, mods); var timeRate = getTimeRate(mods); var difficultyHitObjects = difficultyHitObjectCreator.convertToDifficultyHitObjects(Beatmap.HitObjects, timeRate); return starRatingCalculator.calculate(difficultyHitObjects, timeRate); } ; function getOsuBeatmap(map_id) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, osuService.getOsuBeatmap(map_id)]; case 1: return [2 /*return*/, _a.sent()]; } }); }); } ; function parseMods(mods) { if (mods === undefined) return []; return mods; } ; function getTimeRate(mods) { if (mods.includes("DT")) return 1.5; if (mods.includes("HT")) return 0.75; return 1; } ; function getAllModCombinations() { return [ { mods: [], reParse: true }, { mods: ["DT"], reParse: false }, { mods: ["HT"], reParse: false }, { mods: ["HR"], reParse: true }, { mods: ["HR", "DT"], reParse: false }, { mods: ["HR", "HT"], reParse: false }, { mods: ["EZ"], reParse: true }, { mods: ["EZ", "DT"], reParse: false }, { mods: ["EZ", "HT"], reParse: false } ]; } ; });