nonebot-plugin-osubot 6.24.0__py3-none-any.whl → 6.24.1__py3-none-any.whl

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.

Potentially problematic release.


This version of nonebot-plugin-osubot might be problematic. Click here for more details.

Files changed (46) hide show
  1. nonebot_plugin_osubot/draw/osu_preview.py +64 -0
  2. nonebot_plugin_osubot/draw/osu_preview_templates/css/style.css +258 -0
  3. nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/README.md +109 -0
  4. nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.js +3 -0
  5. nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.js.map +1 -0
  6. nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.worker.js +3 -0
  7. nonebot_plugin_osubot/draw/osu_preview_templates/gif.js/gif.worker.js.map +1 -0
  8. nonebot_plugin_osubot/draw/osu_preview_templates/index.html +437 -0
  9. nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/beatmap.js +211 -0
  10. nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/hitobject.js +29 -0
  11. nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/point.js +55 -0
  12. nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/scroll.js +45 -0
  13. nonebot_plugin_osubot/draw/osu_preview_templates/js/beatmap/timingpoint.js +35 -0
  14. nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/LegacyRandom.js +81 -0
  15. nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/PalpableCatchHitObject.js +53 -0
  16. nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/bananashower.js +33 -0
  17. nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/catch.js +211 -0
  18. nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/fruit.js +21 -0
  19. nonebot_plugin_osubot/draw/osu_preview_templates/js/catch/juicestream.js +176 -0
  20. nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/hitnote.js +21 -0
  21. nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/holdnote.js +37 -0
  22. nonebot_plugin_osubot/draw/osu_preview_templates/js/mania/mania.js +164 -0
  23. nonebot_plugin_osubot/draw/osu_preview_templates/js/preview.js +61 -0
  24. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/bezier2.js +33 -0
  25. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/catmullcurve.js +34 -0
  26. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/centripetalcatmullrom.js +30 -0
  27. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/circumstancedcircle.js +47 -0
  28. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/curve.js +25 -0
  29. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/curvetype.js +17 -0
  30. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/equaldistancemulticurve.js +70 -0
  31. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/curve/linearbezier.js +40 -0
  32. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/hitcircle.js +85 -0
  33. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/slider.js +120 -0
  34. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/spinner.js +56 -0
  35. nonebot_plugin_osubot/draw/osu_preview_templates/js/standard/standard.js +170 -0
  36. nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/donkat.js +40 -0
  37. nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/drumroll.js +34 -0
  38. nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/shaker.js +58 -0
  39. nonebot_plugin_osubot/draw/osu_preview_templates/js/taiko/taiko.js +120 -0
  40. nonebot_plugin_osubot/draw/osu_preview_templates/js/util.js +61 -0
  41. nonebot_plugin_osubot/draw/osu_preview_templates/pic.html +115 -0
  42. nonebot_plugin_osubot/matcher/preview.py +7 -0
  43. nonebot_plugin_osubot/pp.py +7 -0
  44. {nonebot_plugin_osubot-6.24.0.dist-info → nonebot_plugin_osubot-6.24.1.dist-info}/METADATA +2 -2
  45. {nonebot_plugin_osubot-6.24.0.dist-info → nonebot_plugin_osubot-6.24.1.dist-info}/RECORD +46 -5
  46. {nonebot_plugin_osubot-6.24.0.dist-info → nonebot_plugin_osubot-6.24.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,33 @@
1
+ function Bezier2(points)
2
+ {
3
+ // https://github.com/itdelatrisu/opsu/blob/master/src/itdelatrisu/opsu/objects/curves/Bezier2.java
4
+ if (points.length < 2)
5
+ {
6
+ throw 'invalid data';
7
+ }
8
+
9
+ this.points = points;
10
+ var approxLength = 0;
11
+ for (var i = 1; i < this.points.length; i++)
12
+ {
13
+ approxLength += this.points[i].distanceTo(this.points[i - 1]);
14
+ }
15
+
16
+ CurveType.call(this, approxLength);
17
+ }
18
+ Bezier2.prototype = Object.create(CurveType.prototype);
19
+ Bezier2.prototype.constructor = Bezier2;
20
+ Bezier2.prototype.pointAt = function(t)
21
+ {
22
+ var n = this.points.length - 1,
23
+ point = new Point(),
24
+ combination = 1;
25
+ for (var i = 0; i <= n; i++)
26
+ {
27
+ var bernstein = combination * Math.pow(t, i) * Math.pow(1 - t, n - i);
28
+ point.x += this.points[i].x * bernstein;
29
+ point.y += this.points[i].y * bernstein;
30
+ combination = combination * (n - i) / (i + 1);
31
+ }
32
+ return point;
33
+ };
@@ -0,0 +1,34 @@
1
+ function CatmullCurve(points, pixelLength)
2
+ {
3
+ // https://github.com/itdelatrisu/opsu/blob/master/src/itdelatrisu/opsu/objects/curves/CatmullCurve.java
4
+ var catmulls = [],
5
+ controls = [];
6
+ if (!points[0].equalTo(points[1]))
7
+ {
8
+ controls.push(points[0]);
9
+ }
10
+ for (var i = 0; i < points.length; i++)
11
+ {
12
+ controls.push(points[i]);
13
+ try
14
+ {
15
+ catmulls.push(new CentripetalCatmullRom(controls));
16
+ controls.shift();
17
+ }
18
+ catch (e) {}
19
+ }
20
+ var point2 = points.slice(-2);
21
+ if (!point2[1].equalTo(point2[0]))
22
+ {
23
+ controls.push(point2[1]);
24
+ }
25
+ try
26
+ {
27
+ catmulls.push(new CentripetalCatmullRom(controls));
28
+ }
29
+ catch (e) {}
30
+
31
+ EqualDistanceMultiCurve.call(this, catmulls, pixelLength);
32
+ };
33
+ CatmullCurve.prototype = Object.create(EqualDistanceMultiCurve.prototype);
34
+ CatmullCurve.prototype.constructor = CatmullCurve;
@@ -0,0 +1,30 @@
1
+ function CentripetalCatmullRom(points)
2
+ {
3
+ // https://github.com/itdelatrisu/opsu/blob/master/src/itdelatrisu/opsu/objects/curves/CentripetalCatmullRom.java
4
+ // needs 4 points
5
+ if (points.length != 4)
6
+ {
7
+ throw 'invalid data';
8
+ }
9
+
10
+ this.points = points;
11
+ var approxLength = 0;
12
+ for (var i = 1; i < 4; i++)
13
+ {
14
+ approxLength += this.points[i].distanceTo(this.points[i - 1]);
15
+ }
16
+
17
+ CurveType.call(this, approxLength / 2);
18
+ }
19
+ CentripetalCatmullRom.prototype = Object.create(CurveType.prototype);
20
+ CentripetalCatmullRom.prototype.constructor = CentripetalCatmullRom;
21
+ CentripetalCatmullRom.prototype.pointAt = function(t)
22
+ {
23
+ t = Math.lerp(1, 2, t);
24
+ var A1 = this.points[0].clone().scale(1 - t).translate(this.points[1].clone().scale(t));
25
+ var A2 = this.points[1].clone().scale(2 - t).translate(this.points[2].clone().scale(t - 1));
26
+ var A3 = this.points[2].clone().scale(3 - t).translate(this.points[3].clone().scale(t - 2));
27
+ var B1 = A1.clone().scale(2 - t).translate(A2.clone().scale(t));
28
+ var B2 = A2.clone().scale(3 - t).translate(A3.clone().scale(t - 1));
29
+ return B1.clone().scale(2 - t).translate(B2.clone().scale(t - 1)).scale(0.5);
30
+ };
@@ -0,0 +1,47 @@
1
+ function CircumscribedCircle(points, pixelLength)
2
+ {
3
+ var a = points[0].x - points[1].x, b = points[0].y - points[1].y,
4
+ c = points[1].x - points[2].x, d = points[1].y - points[2].y,
5
+ q = (a * d - b * c) * 2,
6
+ l0 = points[0].x * points[0].x + points[0].y * points[0].y,
7
+ l1 = points[1].x * points[1].x + points[1].y * points[1].y,
8
+ l2 = points[2].x * points[2].x + points[2].y * points[2].y,
9
+ x = ((l0 - l1) * d + (l1 - l2) * -b) / q,
10
+ y = ((l0 - l1) * -c + (l1 - l2) * a) / q,
11
+ dx = points[0].x - x,
12
+ dy = points[0].y - y,
13
+ r = Math.hypot(dx, dy),
14
+ base = Math.atan2(dy, dx),
15
+ t = pixelLength / r * Math.ccw(points[0], points[1], points[2]);
16
+ if (!t)
17
+ {
18
+ // when points[2] is missing or vectors are parallel
19
+ throw 'invalid data';
20
+ }
21
+ this.circle = {
22
+ x: x,
23
+ y: y,
24
+ radius: r
25
+ };
26
+ this.angle = {
27
+ base: base,
28
+ delta: t
29
+ };
30
+
31
+ var nCurve = pixelLength / Curve.PRECISION | 0;
32
+ this.path = [];
33
+ for (var i = 0; i <= nCurve; i++)
34
+ {
35
+ this.path[i] = this.pointAt(i / nCurve);
36
+ }
37
+
38
+ Curve.call(this);
39
+ };
40
+ CircumscribedCircle.prototype = Object.create(Curve.prototype);
41
+ CircumscribedCircle.prototype.constructor = CircumscribedCircle;
42
+ CircumscribedCircle.prototype.pointAt = function(t)
43
+ {
44
+ var angle = this.angle.base + this.angle.delta * t;
45
+ return new Point(this.circle.x + Math.cos(angle) * this.circle.radius,
46
+ this.circle.y + Math.sin(angle) * this.circle.radius);
47
+ };
@@ -0,0 +1,25 @@
1
+ function Curve()
2
+ {
3
+ this.startAngle = this.path[0].angleTo(this.path[1]);
4
+ var path2 = this.path.slice(-2);
5
+ this.endAngle = path2[1].angleTo(path2[0]);
6
+ }
7
+ Curve.prototype.path = undefined;
8
+ Curve.prototype.pointAt = undefined;
9
+ Curve.PRECISION = 5;
10
+ Curve.parse = function(sliderType, points, pixelLength)
11
+ {
12
+ try
13
+ {
14
+ if (sliderType == 'P')
15
+ {
16
+ return new CircumscribedCircle(points, pixelLength);
17
+ }
18
+ if (sliderType == 'C')
19
+ {
20
+ return new CatmullCurve(points, pixelLength);
21
+ }
22
+ }
23
+ catch(e) {}
24
+ return new LinearBezier(points, pixelLength, sliderType == 'L');
25
+ }
@@ -0,0 +1,17 @@
1
+ function CurveType(approxLength)
2
+ {
3
+ // https://github.com/itdelatrisu/opsu/blob/master/src/itdelatrisu/opsu/objects/curves/CurveType.java
4
+ var points = (approxLength / 4 | 0) + 1;
5
+ this.path = [];
6
+ for (var i = 0; i <= points; i++)
7
+ {
8
+ this.path[i] = this.pointAt(i / points);
9
+ }
10
+
11
+ this.distance = [ 0 ];
12
+ for (var i = 1; i <= points; i++)
13
+ {
14
+ this.distance[i] = this.path[i].distanceTo(this.path[i - 1]);
15
+ }
16
+ }
17
+ CurveType.prototype.pointAt = undefined;
@@ -0,0 +1,70 @@
1
+ function EqualDistanceMultiCurve(curves, pixelLength)
2
+ {
3
+ // https://github.com/itdelatrisu/opsu/blob/master/src/itdelatrisu/opsu/objects/curves/EqualDistanceMultiCurve.java
4
+ var nCurve = pixelLength / Curve.PRECISION | 0;
5
+ this.path = [];
6
+
7
+ var distanceAt = 0,
8
+ curveIndex = 0,
9
+ curve = curves[curveIndex],
10
+ pointIndex = 0,
11
+ startPoint = curve.path[0],
12
+ lastDistanceAt = 0;
13
+ // for each distance, try to get in between the two points that are between it
14
+ for (var i = 0; i <= nCurve; i++)
15
+ {
16
+ var prefDistance = i * pixelLength / nCurve | 0;
17
+ while (distanceAt < prefDistance)
18
+ {
19
+ lastDistanceAt = distanceAt;
20
+ startPoint = curve.path[pointIndex];
21
+
22
+ if (++pointIndex >= curve.path.length)
23
+ {
24
+ if (curveIndex + 1 < curves.length)
25
+ {
26
+ curve = curves[++curveIndex];
27
+ pointIndex = 0;
28
+ }
29
+ else
30
+ {
31
+ pointIndex = curve.path.length - 1;
32
+ if (lastDistanceAt == distanceAt)
33
+ {
34
+ // out of points even though the preferred distance hasn't been reached
35
+ break;
36
+ }
37
+ }
38
+ }
39
+ distanceAt += curve.distance[pointIndex];
40
+ }
41
+ var endPoint = curve.path[pointIndex];
42
+
43
+ // interpolate the point between the two closest distances
44
+ if (distanceAt - lastDistanceAt > 1)
45
+ {
46
+ this.path[i] = Math.lerp(startPoint, endPoint, (prefDistance - lastDistanceAt) / (distanceAt - lastDistanceAt));
47
+ }
48
+ else
49
+ {
50
+ this.path[i] = endPoint;
51
+ }
52
+ }
53
+
54
+ Curve.call(this);
55
+ };
56
+ EqualDistanceMultiCurve.prototype = Object.create(Curve.prototype);
57
+ EqualDistanceMultiCurve.prototype.constructor = EqualDistanceMultiCurve;
58
+ EqualDistanceMultiCurve.prototype.pointAt = function(t)
59
+ {
60
+ var indexF = this.path.length * t,
61
+ index = indexF | 0;
62
+ if (index + 1 < this.path.length)
63
+ {
64
+ return Math.lerp(this.path[index], this.path[index + 1], indexF - index);
65
+ }
66
+ else
67
+ {
68
+ return this.path[this.path.length - 1];
69
+ }
70
+ };
@@ -0,0 +1,40 @@
1
+ function LinearBezier(points, pixelLength, linear)
2
+ {
3
+ // https://github.com/itdelatrisu/opsu/blob/master/src/itdelatrisu/opsu/objects/curves/LinearBezier.java
4
+ var beziers = [],
5
+ controls = [],
6
+ last;
7
+ for (var i = 0; i < points.length; i++)
8
+ {
9
+ var point = points[i];
10
+ if (linear)
11
+ {
12
+ if (typeof last != 'undefined')
13
+ {
14
+ controls.push(point);
15
+ beziers.push(new Bezier2(controls));
16
+ controls = [];
17
+ }
18
+ }
19
+ else if (point.equalTo(last))
20
+ {
21
+ try
22
+ {
23
+ beziers.push(new Bezier2(controls));
24
+ }
25
+ catch (e) {}
26
+ controls = [];
27
+ }
28
+ controls.push(point);
29
+ last = point;
30
+ }
31
+ try
32
+ {
33
+ beziers.push(new Bezier2(controls));
34
+ }
35
+ catch (e) {}
36
+
37
+ EqualDistanceMultiCurve.call(this, beziers, pixelLength);
38
+ };
39
+ LinearBezier.prototype = Object.create(EqualDistanceMultiCurve.prototype);
40
+ LinearBezier.prototype.constructor = LinearBezier;
@@ -0,0 +1,85 @@
1
+ function HitCircle(data, beatmap)
2
+ {
3
+ HitObject.call(this, data, beatmap);
4
+
5
+ this.stack = 0;
6
+ }
7
+ HitCircle.prototype = Object.create(HitObject.prototype, {
8
+ newCombo: {
9
+ get: function()
10
+ {
11
+ return this.flag & 4;
12
+ }
13
+ },
14
+ comboSkip: {
15
+ get: function()
16
+ {
17
+ return this.flag >> 4;
18
+ }
19
+ }
20
+ });
21
+ HitCircle.prototype.constructor = HitCircle;
22
+ HitCircle.ID = 1;
23
+ Standard.prototype.hitObjectTypes[HitCircle.ID] = HitCircle;
24
+ HitCircle.FADE_IN_TIME = 375;
25
+ HitCircle.FADE_OUT_TIME = 200;
26
+ HitCircle.prototype.draw = function(time, ctx)
27
+ {
28
+ var dt = this.time - time,
29
+ opacity = 1;
30
+ if (dt >= 0)
31
+ {
32
+ opacity = (this.beatmap.approachTime - dt) / HitCircle.FADE_IN_TIME;
33
+ }
34
+ else
35
+ {
36
+ opacity = 1 + dt / HitCircle.FADE_OUT_TIME;
37
+ }
38
+ ctx.globalAlpha = Math.max(0, Math.min(opacity, 1));
39
+
40
+ this.drawCircle(this.position, ctx);
41
+ this.drawText(this.position, this.combo, 0, ctx);
42
+ if (dt >= 0)
43
+ {
44
+ this.drawApproach(dt, ctx);
45
+ }
46
+ };
47
+ HitCircle.prototype.drawCircle = function(position, ctx)
48
+ {
49
+ // HitCircle
50
+ ctx.beginPath();
51
+ ctx.arc(position.x - this.stack * this.beatmap.stackOffset,
52
+ position.y - this.stack * this.beatmap.stackOffset,
53
+ this.beatmap.circleRadius - this.beatmap.circleBorder / 2, -Math.PI, Math.PI);
54
+ ctx.shadowBlur = 0;
55
+ ctx.fillStyle = this.color;
56
+ ctx.fill();
57
+ // Overlay
58
+ ctx.shadowBlur = this.beatmap.shadowBlur;
59
+ ctx.strokeStyle = '#fff';
60
+ ctx.lineWidth = this.beatmap.circleBorder;
61
+ ctx.stroke();
62
+ };
63
+ HitCircle.prototype.drawText = function(position, text, deg, ctx)
64
+ {
65
+ ctx.shadowBlur = this.beatmap.shadowBlur;
66
+ ctx.fillStyle = '#fff';
67
+ ctx.save();
68
+ ctx.translate(position.x - this.stack * this.beatmap.stackOffset,
69
+ position.y - this.stack * this.beatmap.stackOffset);
70
+ ctx.rotate(deg);
71
+ ctx.fillText(text, 0, 0);
72
+ ctx.restore();
73
+ };
74
+ HitCircle.prototype.drawApproach = function(dt, ctx)
75
+ {
76
+ var scale = 1 + dt / this.beatmap.approachTime * 3;
77
+ ctx.beginPath();
78
+ ctx.arc(this.position.x - this.stack * this.beatmap.stackOffset,
79
+ this.position.y - this.stack * this.beatmap.stackOffset,
80
+ this.beatmap.circleRadius * scale - this.beatmap.circleBorder / 2, -Math.PI, Math.PI);
81
+ ctx.shadowBlur = 0;
82
+ ctx.strokeStyle = this.color;
83
+ ctx.lineWidth = this.beatmap.circleBorder / 2 * scale;
84
+ ctx.stroke();
85
+ };
@@ -0,0 +1,120 @@
1
+ function Slider(data, beatmap)
2
+ {
3
+ HitCircle.call(this, data, beatmap);
4
+
5
+ var points = data[5].split('|');
6
+ var sliderType = points[0];
7
+ points[0] = this.position;
8
+ for (var i = 1; i < points.length; i++)
9
+ {
10
+ points[i] = new Point(points[i].split(':'));
11
+ }
12
+ this.repeat = data[6] | 0;
13
+ this.pixelLength = +data[7];
14
+
15
+ var sliderTime = this.beatmap.timingPointAt(this.time).beatLength * (
16
+ this.pixelLength / this.beatmap.SliderMultiplier
17
+ ) / 100;
18
+ this.endTime += sliderTime * this.repeat;
19
+ this.duration = this.endTime - this.time;
20
+
21
+ this.curve = Curve.parse(sliderType, points, this.pixelLength);
22
+
23
+ this.endPosition = this.curve.pointAt(1);
24
+ }
25
+ Slider.prototype = Object.create(HitCircle.prototype);
26
+ Slider.prototype.constructor = Slider;
27
+ Slider.ID = 2;
28
+ Standard.prototype.hitObjectTypes[Slider.ID] = Slider;
29
+ Slider.FADE_IN_TIME = 375;
30
+ Slider.FADE_OUT_TIME = 200;
31
+ Slider.REVERSE_ARROW = String.fromCharCode(10132);
32
+ Slider.OPACITY = 0.66;
33
+ Slider.prototype.draw = function(time, ctx)
34
+ {
35
+ var dt = this.time - time,
36
+ opacity = 1;
37
+ if (dt >= 0)
38
+ {
39
+ opacity = (this.beatmap.approachTime - dt) / Slider.FADE_IN_TIME;
40
+ }
41
+ else if (time > this.endTime)
42
+ {
43
+ opacity = 1 - (time - this.endTime) / Slider.FADE_OUT_TIME;
44
+ }
45
+ ctx.globalAlpha = Math.max(0, Math.min(opacity, 1));
46
+
47
+ this.drawPath(ctx);
48
+ // this.drawCircle(this.endPosition, ctx);
49
+ // this.drawCircle(this.position, ctx);
50
+
51
+ var repeat = -dt * this.repeat / this.duration;
52
+ // this.repeat - this.repeat % 2: 홀수면 짝수로 내리기
53
+ if (this.repeat > 1 && repeat + 1 <= (this.repeat & ~1))
54
+ {
55
+ this.drawCircle(this.endPosition, ctx);
56
+ this.drawText(this.endPosition, Slider.REVERSE_ARROW, this.curve.endAngle, ctx);
57
+ }
58
+ // this.repeat - (this.repeat + 1) % 2: 짝수면 홀수로 내리기
59
+ if (repeat > 0 && repeat + 1 <= this.repeat - !(this.repeat & 1))
60
+ {
61
+ this.drawCircle(this.position, ctx);
62
+ this.drawText(this.position, Slider.REVERSE_ARROW, this.curve.startAngle, ctx);
63
+ }
64
+ else if (dt >= 0)
65
+ {
66
+ this.drawCircle(this.position, ctx);
67
+ this.drawText(this.position, this.combo, 0, ctx);
68
+ }
69
+
70
+ if (dt >= 0)
71
+ {
72
+ this.drawApproach(dt, ctx);
73
+ }
74
+ else if (time < this.endTime)
75
+ {
76
+ this.drawFollowCircle(repeat, ctx);
77
+ }
78
+ };
79
+ Slider.prototype.drawPath = function(ctx)
80
+ {
81
+ ctx.save();
82
+ // Slider
83
+ ctx.globalAlpha *= Slider.OPACITY;
84
+ ctx.beginPath();
85
+ ctx.moveTo(this.position.x - this.stack * this.beatmap.stackOffset,
86
+ this.position.y - this.stack * this.beatmap.stackOffset);
87
+ for (var i = 1; i < this.curve.path.length; i++)
88
+ {
89
+ ctx.lineTo(this.curve.path[i].x - this.stack * this.beatmap.stackOffset,
90
+ this.curve.path[i].y - this.stack * this.beatmap.stackOffset);
91
+ }
92
+ ctx.shadowBlur = 0;
93
+ ctx.strokeStyle = this.color;
94
+ ctx.lineWidth = (this.beatmap.circleRadius - this.beatmap.circleBorder) * 2;
95
+ ctx.stroke();
96
+ // Border
97
+ ctx.globalCompositeOperation = 'destination-over';
98
+ ctx.shadowBlur = 0;
99
+ ctx.strokeStyle = '#fff';
100
+ ctx.lineWidth = this.beatmap.circleRadius * 2;
101
+ ctx.stroke();
102
+ ctx.restore();
103
+ };
104
+ Slider.prototype.drawFollowCircle = function(repeat, ctx)
105
+ {
106
+ repeat %= 2;
107
+ if (repeat > 1)
108
+ {
109
+ repeat = 2 - repeat;
110
+ }
111
+ var point = this.curve.pointAt(repeat);
112
+ ctx.beginPath();
113
+ ctx.arc(point.x - this.stack * this.beatmap.stackOffset,
114
+ point.y - this.stack * this.beatmap.stackOffset,
115
+ this.beatmap.circleRadius - this.beatmap.circleBorder / 2, -Math.PI, Math.PI);
116
+ ctx.shadowBlur = this.beatmap.shadowBlur;
117
+ ctx.strokeStyle = '#fff';
118
+ ctx.lineWidth = this.beatmap.circleBorder;
119
+ ctx.stroke();
120
+ }
@@ -0,0 +1,56 @@
1
+ function Spinner(data, beatmap)
2
+ {
3
+ HitCircle.call(this, data, beatmap);
4
+
5
+ this.endTime = data[5] | 0;
6
+ this.duration = this.endTime - this.time;
7
+ }
8
+ Spinner.prototype = Object.create(HitCircle.prototype);
9
+ Spinner.prototype.constructor = Spinner;
10
+ Spinner.ID = 8;
11
+ Standard.prototype.hitObjectTypes[Spinner.ID] = Spinner;
12
+ Spinner.FADE_IN_TIME = 500;
13
+ Spinner.FADE_OUT_TIME = 200;
14
+ Spinner.RADIUS = Beatmap.MAX_Y / 2;
15
+ Spinner.BORDER_WIDTH = Spinner.RADIUS / 20;
16
+ Spinner.prototype.draw = function(time, ctx)
17
+ {
18
+ var dt = this.time - time,
19
+ opacity = 1;
20
+ if (dt >= 0)
21
+ {
22
+ opacity = (this.beatmap.approachTime - dt) / Spinner.FADE_IN_TIME;
23
+ }
24
+ else if (time > this.endTime)
25
+ {
26
+ opacity = 1 - (time - this.endTime) / Spinner.FADE_OUT_TIME;
27
+ }
28
+ ctx.globalAlpha = Math.max(0, Math.min(opacity, 1));
29
+ ctx.save();
30
+ // Spinner
31
+ ctx.beginPath();
32
+ ctx.arc(this.position.x, this.position.y,
33
+ Spinner.RADIUS - Spinner.BORDER_WIDTH / 2, -Math.PI, Math.PI);
34
+ ctx.globalCompositeOperation = 'destination-over';
35
+ ctx.shadowBlur = 0;
36
+ ctx.fillStyle = 'rgba(0,0,0,.4)';
37
+ ctx.fill();
38
+ // Border
39
+ ctx.shadowBlur = Spinner.BORDER_WIDTH;
40
+ ctx.strokeStyle = '#fff';
41
+ ctx.lineWidth = Spinner.BORDER_WIDTH;
42
+ ctx.stroke();
43
+ ctx.restore();
44
+ // Approach
45
+ if (dt < 0 && time <= this.endTime)
46
+ {
47
+ var scale = 1 + dt / this.duration;
48
+ ctx.beginPath();
49
+ ctx.arc(this.position.x, this.position.y,
50
+ (Spinner.RADIUS - Spinner.BORDER_WIDTH / 2) * scale, -Math.PI, Math.PI);
51
+ ctx.shadowBlur = 3;
52
+ ctx.strokeStyle = '#fff';
53
+ ctx.lineWidth = (Spinner.BORDER_WIDTH / 2) * scale;
54
+ ctx.stroke();
55
+ }
56
+ };