Merge branch 'master' into update-branch

This commit is contained in:
smoogipoo
2018-02-08 23:35:48 +09:00
990 changed files with 9243 additions and 4835 deletions

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;

View File

@ -1,11 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Beatmaps
{
@ -29,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
colourIndex = (colourIndex + 1) % beatmap.ComboColors.Count;
}
obj.ComboIndex = comboIndex++;
obj.IndexInCurrentCombo = comboIndex++;
obj.ComboColour = beatmap.ComboColors[colourIndex];
}
}
@ -37,7 +36,6 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
private void applyStacking(Beatmap<OsuHitObject> beatmap)
{
const int stack_distance = 3;
float stackThreshold = DrawableOsuHitObject.TIME_PREEMPT * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
// Reset stacking
for (int i = 0; i <= beatmap.HitObjects.Count - 1; i++)
@ -58,6 +56,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
continue;
double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
if (objectN.StartTime - endTime > stackThreshold)
//We are no longer within stacking range of the next object.
@ -100,6 +99,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
OsuHitObject objectI = beatmap.HitObjects[i];
if (objectI.StackHeight != 0 || objectI is Spinner) continue;
double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
/* If this object is a hitcircle, then we enter this "special" case.
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.
* Any other case is handled by the "is Slider" code below this.

View File

@ -1,15 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Cursor;
using osu.Game.Rulesets.Osu.UI;
namespace osu.Game.Rulesets.Osu.Edit
{
public class OsuEditPlayfield : OsuPlayfield
{
protected override CursorContainer CreateCursor() => null;
protected override bool ProxyApproachCircles => false;
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Cursor;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.UI;
@ -15,5 +16,7 @@ namespace osu.Game.Rulesets.Osu.Edit
}
protected override Playfield CreatePlayfield() => new OsuEditPlayfield();
protected override CursorContainer CreateCursor() => null;
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;

View File

@ -0,0 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Judgements
{
public class OsuSliderTailJudgement : OsuJudgement
{
public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result) => 0;
}
}

View File

@ -1,212 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Osu.Replays;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Scoring;
using OpenTK;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModNoFail : ModNoFail
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
}
public class OsuModEasy : ModEasy
{
}
public class OsuModHidden : ModHidden, IApplicableToDrawableHitObjects
{
public override string Description => @"Play with no approach circles and fading notes for a slight score advantage.";
public override double ScoreMultiplier => 1.06;
private const double fade_in_duration_multiplier = 0.4;
private const double fade_out_duration_multiplier = 0.3;
private float preEmpt => DrawableOsuHitObject.TIME_PREEMPT;
public void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
{
foreach (var d in drawables.OfType<DrawableOsuHitObject>())
{
d.ApplyCustomUpdateState += ApplyHiddenState;
d.FadeInDuration = preEmpt * fade_in_duration_multiplier;
}
}
protected void ApplyHiddenState(DrawableHitObject drawable, ArmedState state)
{
if (!(drawable is DrawableOsuHitObject d))
return;
var fadeOutStartTime = d.HitObject.StartTime - preEmpt + d.FadeInDuration;
var fadeOutDuration = preEmpt * fade_out_duration_multiplier;
// new duration from completed fade in to end (before fading out)
var longFadeDuration = ((d.HitObject as IHasEndTime)?.EndTime ?? d.HitObject.StartTime) - fadeOutStartTime;
switch (drawable)
{
case DrawableHitCircle circle:
// we don't want to see the approach circle
circle.ApproachCircle.Hide();
// fade out immediately after fade in.
using (drawable.BeginAbsoluteSequence(fadeOutStartTime, true))
circle.FadeOut(fadeOutDuration);
break;
case DrawableSlider slider:
using (slider.BeginAbsoluteSequence(fadeOutStartTime, true))
{
slider.Body.FadeOut(longFadeDuration, Easing.Out);
// delay a bit less to let the sliderball fade out peacefully instead of having a hard cut
using (slider.BeginDelayedSequence(longFadeDuration - fadeOutDuration, true))
slider.Ball.FadeOut(fadeOutDuration);
}
break;
case DrawableSpinner spinner:
// hide elements we don't care about.
spinner.Disc.Hide();
spinner.Ticks.Hide();
spinner.Background.Hide();
using (spinner.BeginAbsoluteSequence(fadeOutStartTime + longFadeDuration, true))
{
spinner.FadeOut(fadeOutDuration);
// speed up the end sequence accordingly
switch (state)
{
case ArmedState.Hit:
spinner.ScaleTo(spinner.Scale * 1.2f, fadeOutDuration * 2, Easing.Out);
break;
case ArmedState.Miss:
spinner.ScaleTo(spinner.Scale * 0.8f, fadeOutDuration * 2, Easing.In);
break;
}
spinner.Expire();
}
break;
}
}
}
public class OsuModHardRock : ModHardRock, IApplicableToHitObject<OsuHitObject>
{
public override double ScoreMultiplier => 1.06;
public override bool Ranked => true;
public void ApplyToHitObject(OsuHitObject hitObject)
{
hitObject.Position = new Vector2(hitObject.Position.X, OsuPlayfield.BASE_SIZE.Y - hitObject.Y);
var slider = hitObject as Slider;
if (slider == null)
return;
var newControlPoints = new List<Vector2>();
slider.ControlPoints.ForEach(c => newControlPoints.Add(new Vector2(c.X, OsuPlayfield.BASE_SIZE.Y - c.Y)));
slider.ControlPoints = newControlPoints;
slider.Curve?.Calculate(); // Recalculate the slider curve
}
}
public class OsuModSuddenDeath : ModSuddenDeath
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
}
public class OsuModDaycore : ModDaycore
{
public override double ScoreMultiplier => 0.5;
}
public class OsuModDoubleTime : ModDoubleTime
{
public override double ScoreMultiplier => 1.12;
}
public class OsuModRelax : ModRelax
{
public override string Description => "You don't need to click.\nGive your clicking/tapping finger a break from the heat of things.";
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
}
public class OsuModHalfTime : ModHalfTime
{
public override double ScoreMultiplier => 0.5;
}
public class OsuModNightcore : ModNightcore
{
public override double ScoreMultiplier => 1.12;
}
public class OsuModFlashlight : ModFlashlight
{
public override double ScoreMultiplier => 1.12;
}
public class OsuModPerfect : ModPerfect
{
}
public class OsuModSpunOut : Mod
{
public override string Name => "Spun Out";
public override string ShortenedName => "SO";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_spunout;
public override string Description => @"Spinners will be automatically completed";
public override double ScoreMultiplier => 0.9;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot) };
}
public class OsuModAutopilot : Mod
{
public override string Name => "Autopilot";
public override string ShortenedName => "AP";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
public override double ScoreMultiplier => 0;
public override bool Ranked => false;
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) };
}
public class OsuModAutoplay : ModAutoplay<OsuHitObject>
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot), typeof(OsuModSpunOut) }).ToArray();
protected override Score CreateReplayScore(Beatmap<OsuHitObject> beatmap) => new Score
{
Replay = new OsuAutoGenerator(beatmap).Generate()
};
}
public class OsuModTarget : Mod
{
public override string Name => "Target";
public override string ShortenedName => "TP";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_target;
public override string Description => @"";
public override double ScoreMultiplier => 1;
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModAutopilot : Mod
{
public override string Name => "Autopilot";
public override string ShortenedName => "AP";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
public override double ScoreMultiplier => 0;
public override bool Ranked => false;
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) };
}
}

View File

@ -0,0 +1,26 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Replays;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModAutoplay : ModAutoplay<OsuHitObject>
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot), typeof(OsuModSpunOut) }).ToArray();
protected override Score CreateReplayScore(Beatmap<OsuHitObject> beatmap)
{
return new Score
{
Replay = new OsuAutoGenerator(beatmap).Generate()
};
}
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModDaycore : ModDaycore
{
public override double ScoreMultiplier => 0.5;
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModDoubleTime : ModDoubleTime
{
public override double ScoreMultiplier => 1.12;
}
}

View File

@ -0,0 +1,11 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModEasy : ModEasy
{
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModFlashlight : ModFlashlight
{
public override double ScoreMultiplier => 1.12;
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModHalfTime : ModHalfTime
{
public override double ScoreMultiplier => 0.5;
}
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using OpenTK;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModHardRock : ModHardRock, IApplicableToHitObject<OsuHitObject>
{
public override double ScoreMultiplier => 1.06;
public override bool Ranked => true;
public void ApplyToHitObject(OsuHitObject hitObject)
{
hitObject.Position = new Vector2(hitObject.Position.X, OsuPlayfield.BASE_SIZE.Y - hitObject.Y);
var slider = hitObject as Slider;
if (slider == null)
return;
var newControlPoints = new List<Vector2>();
slider.ControlPoints.ForEach(c => newControlPoints.Add(new Vector2(c.X, OsuPlayfield.BASE_SIZE.Y - c.Y)));
slider.ControlPoints = newControlPoints;
slider.Curve?.Calculate(); // Recalculate the slider curve
}
}
}

View File

@ -0,0 +1,77 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModHidden : ModHidden, IApplicableToDrawableHitObjects
{
public override string Description => @"Play with no approach circles and fading notes for a slight score advantage.";
public override double ScoreMultiplier => 1.06;
private const double fade_in_duration_multiplier = 0.4;
private const double fade_out_duration_multiplier = 0.3;
public void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
{
foreach (var d in drawables.OfType<DrawableOsuHitObject>())
{
d.ApplyCustomUpdateState += ApplyHiddenState;
d.HitObject.TimeFadein = d.HitObject.TimePreempt * fade_in_duration_multiplier;
}
}
protected void ApplyHiddenState(DrawableHitObject drawable, ArmedState state)
{
if (!(drawable is DrawableOsuHitObject d))
return;
var fadeOutStartTime = d.HitObject.StartTime - d.HitObject.TimePreempt + d.HitObject.TimeFadein;
var fadeOutDuration = d.HitObject.TimePreempt * fade_out_duration_multiplier;
// new duration from completed fade in to end (before fading out)
var longFadeDuration = ((d.HitObject as IHasEndTime)?.EndTime ?? d.HitObject.StartTime) - fadeOutStartTime;
switch (drawable)
{
case DrawableHitCircle circle:
// we don't want to see the approach circle
circle.ApproachCircle.Hide();
// fade out immediately after fade in.
using (drawable.BeginAbsoluteSequence(fadeOutStartTime, true))
{
circle.FadeOut(fadeOutDuration);
}
break;
case DrawableSlider slider:
using (slider.BeginAbsoluteSequence(fadeOutStartTime, true))
{
slider.Body.FadeOut(longFadeDuration, Easing.Out);
}
break;
case DrawableSpinner spinner:
// hide elements we don't care about.
spinner.Disc.Hide();
spinner.Ticks.Hide();
spinner.Background.Hide();
using (spinner.BeginAbsoluteSequence(fadeOutStartTime + longFadeDuration, true))
{
spinner.FadeOut(fadeOutDuration);
}
break;
}
}
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModNightcore : ModNightcore
{
public override double ScoreMultiplier => 1.12;
}
}

View File

@ -0,0 +1,14 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModNoFail : ModNoFail
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
}
}

View File

@ -0,0 +1,11 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModPerfect : ModPerfect
{
}
}

View File

@ -0,0 +1,15 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModRelax : ModRelax
{
public override string Description => "You don't need to click.\nGive your clicking/tapping finger a break from the heat of things.";
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModSpunOut : Mod
{
public override string Name => "Spun Out";
public override string ShortenedName => "SO";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_spunout;
public override string Description => @"Spinners will be automatically completed";
public override double ScoreMultiplier => 0.9;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot) };
}
}

View File

@ -0,0 +1,14 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModSuddenDeath : ModSuddenDeath
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
}
}

View File

@ -0,0 +1,17 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModTarget : Mod
{
public override string Name => "Target";
public override string ShortenedName => "TP";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_target;
public override string Description => @"";
public override double ScoreMultiplier => 1;
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Containers;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
@ -96,12 +96,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
using (fp.BeginAbsoluteSequence(fadeInTime))
{
fp.FadeIn(DrawableOsuHitObject.TIME_FADEIN);
fp.ScaleTo(1, DrawableOsuHitObject.TIME_FADEIN, Easing.Out);
fp.FadeIn(currHitObject.TimeFadein);
fp.ScaleTo(1, currHitObject.TimeFadein, Easing.Out);
fp.MoveTo(pointEndPosition, DrawableOsuHitObject.TIME_FADEIN, Easing.Out);
fp.MoveTo(pointEndPosition, currHitObject.TimeFadein, Easing.Out);
fp.Delay(fadeOutTime - fadeInTime).FadeOut(DrawableOsuHitObject.TIME_FADEIN);
fp.Delay(fadeOutTime - fadeInTime).FadeOut(currHitObject.TimeFadein);
}
fp.Expire(true);

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
},
number = new NumberPiece
{
Text = (HitObject.ComboIndex + 1).ToString(),
Text = (HitObject.IndexInCurrentCombo + 1).ToString(),
},
ring = new RingPiece(),
flash = new FlashPiece(),
@ -72,14 +72,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
if (!userTriggered)
{
if (timeOffset > HitObject.HitWindowFor(HitResult.Meh))
if (!HitObject.HitWindows.CanBeHit(timeOffset))
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
return;
}
var result = HitObject.HitWindows.ResultFor(timeOffset);
if (result == HitResult.None)
return;
AddJudgement(new OsuJudgement
{
Result = HitObject.ScoreResultForOffset(Math.Abs(timeOffset)),
Result = result,
PositionOffset = Vector2.Zero //todo: set to correct value
});
}
@ -88,8 +92,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
base.UpdatePreemptState();
ApproachCircle.FadeIn(Math.Min(FadeInDuration * 2, TIME_PREEMPT));
ApproachCircle.ScaleTo(1.1f, TIME_PREEMPT);
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadein * 2, HitObject.TimePreempt));
ApproachCircle.ScaleTo(1.1f, HitObject.TimePreempt);
}
protected override void UpdateCurrentState(ArmedState state)
@ -99,12 +103,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
switch (state)
{
case ArmedState.Idle:
this.Delay(TIME_PREEMPT).FadeOut(500);
this.Delay(HitObject.TimePreempt).FadeOut(500);
Expire(true);
// override lifetime end as FadeIn may have been changed externally, causing out expiration to be too early.
LifetimeEnd = HitObject.StartTime + HitObject.HitWindowFor(HitResult.Miss);
LifetimeEnd = HitObject.StartTime + HitObject.HitWindows.HalfWindowFor(HitResult.Miss);
break;
case ArmedState.Miss:
ApproachCircle.FadeOut(50);

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
@ -10,15 +10,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
public class DrawableOsuHitObject : DrawableHitObject<OsuHitObject>
{
public const float TIME_PREEMPT = 600;
public const float TIME_FADEIN = 400;
/// <summary>
/// The number of milliseconds used to fade in.
/// </summary>
public virtual double FadeInDuration { get; set; } = TIME_FADEIN;
public override bool IsPresent => base.IsPresent || State.Value == ArmedState.Idle && Time.Current >= HitObject.StartTime - TIME_PREEMPT;
public override bool IsPresent => base.IsPresent || State.Value == ArmedState.Idle && Time.Current >= HitObject.StartTime - HitObject.TimePreempt;
protected DrawableOsuHitObject(OsuHitObject hitObject)
: base(hitObject)
@ -29,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected sealed override void UpdateState(ArmedState state)
{
double transformTime = HitObject.StartTime - TIME_PREEMPT;
double transformTime = HitObject.StartTime - HitObject.TimePreempt;
base.ApplyTransformsAt(transformTime, true);
base.ClearTransformsAfter(transformTime, true);
@ -38,12 +30,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
UpdatePreemptState();
using (BeginDelayedSequence(TIME_PREEMPT + (Judgements.FirstOrDefault()?.TimeOffset ?? 0), true))
using (BeginDelayedSequence(HitObject.TimePreempt + (Judgements.FirstOrDefault()?.TimeOffset ?? 0), true))
UpdateCurrentState(state);
}
}
protected virtual void UpdatePreemptState() => this.FadeIn(FadeInDuration);
protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadein);
protected virtual void UpdateCurrentState(ArmedState state)
{

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;

View File

@ -1,7 +1,8 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
@ -11,13 +12,12 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
public class DrawableRepeatPoint : DrawableOsuHitObject
public class DrawableRepeatPoint : DrawableOsuHitObject, ITrackSnaking
{
private readonly RepeatPoint repeatPoint;
private readonly DrawableSlider drawableSlider;
public double FadeInTime;
public double FadeOutTime;
private double animDuration;
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider)
: base(repeatPoint)
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
this.repeatPoint = repeatPoint;
this.drawableSlider = drawableSlider;
Size = new Vector2(32 * repeatPoint.Scale);
Size = new Vector2(45 * repeatPoint.Scale);
Blending = BlendingMode.Additive;
Origin = Anchor.Centre;
@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
new SpriteIcon
{
RelativeSizeAxes = Axes.Both,
Icon = FontAwesome.fa_eercast
Icon = FontAwesome.fa_chevron_right
}
};
}
@ -48,11 +48,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void UpdatePreemptState()
{
var animIn = Math.Min(150, repeatPoint.StartTime - FadeInTime);
animDuration = Math.Min(150, repeatPoint.SpanDuration / 2);
this.FadeIn(animIn).ScaleTo(1.2f, animIn)
.Then()
.ScaleTo(1, 150, Easing.Out);
this.Animate(
d => d.FadeIn(animDuration),
d => d.ScaleTo(0.5f).ScaleTo(1f, animDuration * 4, Easing.OutElasticHalf)
);
}
protected override void UpdateCurrentState(ArmedState state)
@ -60,16 +61,40 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
switch (state)
{
case ArmedState.Idle:
this.Delay(FadeOutTime - repeatPoint.StartTime).FadeOut();
this.Delay(HitObject.TimePreempt).FadeOut();
break;
case ArmedState.Miss:
this.FadeOut(160);
this.FadeOut(animDuration);
break;
case ArmedState.Hit:
this.FadeOut(120, Easing.OutQuint)
.ScaleTo(Scale * 1.5f, 120, Easing.OutQuint);
this.FadeOut(animDuration, Easing.OutQuint)
.ScaleTo(Scale * 1.5f, animDuration, Easing.Out);
break;
}
}
public void UpdateSnakingPosition(Vector2 start, Vector2 end)
{
bool isRepeatAtEnd = repeatPoint.RepeatIndex % 2 == 0;
List<Vector2> curve = drawableSlider.Body.CurrentCurve;
Position = isRepeatAtEnd ? end : start;
if (curve.Count < 2)
return;
int searchStart = isRepeatAtEnd ? curve.Count - 1 : 0;
int direction = isRepeatAtEnd ? -1 : 1;
// find the next vector2 in the curve which is not equal to our current position to infer a rotation.
for (int i = searchStart; i >= 0 && i < curve.Count; i += direction)
{
if (curve[i] == Position)
continue;
Rotation = MathHelper.RadiansToDegrees((float)Math.Atan2(curve[i].Y - Position.Y, curve[i].X - Position.X));
break;
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
@ -10,6 +10,7 @@ using System.Linq;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Framework.Graphics.Primitives;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
@ -17,14 +18,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public class DrawableSlider : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
{
private readonly Slider slider;
private readonly List<Drawable> components = new List<Drawable>();
public readonly DrawableHitCircle InitialCircle;
private readonly List<ISliderProgress> components = new List<ISliderProgress>();
private readonly Container<DrawableSliderTick> ticks;
private readonly Container<DrawableRepeatPoint> repeatPoints;
public readonly DrawableHitCircle HeadCircle;
public readonly SliderBody Body;
public readonly SliderBall Ball;
@ -33,6 +29,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
slider = s;
DrawableSliderTail tail;
Container<DrawableSliderTick> ticks;
Container<DrawableRepeatPoint> repeatPoints;
Children = new Drawable[]
{
Body = new SliderBody(s)
@ -50,68 +50,46 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AlwaysPresent = true,
Alpha = 0
},
InitialCircle = new DrawableHitCircle(new HitCircle
{
StartTime = s.StartTime,
Position = s.StackedPosition,
ComboIndex = s.ComboIndex,
Scale = s.Scale,
ComboColour = s.ComboColour,
Samples = s.Samples,
SampleControlPoint = s.SampleControlPoint
})
HeadCircle = new DrawableHitCircle(s.HeadCircle),
tail = new DrawableSliderTail(s.TailCircle)
};
components.Add(Body);
components.Add(Ball);
AddNested(InitialCircle);
AddNested(HeadCircle);
AddNested(tail);
components.Add(tail);
var repeatDuration = s.Curve.Distance / s.Velocity;
foreach (var tick in s.NestedHitObjects.OfType<SliderTick>())
{
var repeatStartTime = s.StartTime + tick.RepeatIndex * repeatDuration;
var fadeInTime = repeatStartTime + (tick.StartTime - repeatStartTime) / 2 - (tick.RepeatIndex == 0 ? FadeInDuration : FadeInDuration / 2);
var fadeOutTime = repeatStartTime + repeatDuration;
var drawableTick = new DrawableSliderTick(tick)
{
FadeInTime = fadeInTime,
FadeOutTime = fadeOutTime,
Position = tick.Position,
Position = tick.Position
};
ticks.Add(drawableTick);
components.Add(drawableTick);
AddNested(drawableTick);
}
foreach (var repeatPoint in s.NestedHitObjects.OfType<RepeatPoint>())
{
var repeatStartTime = s.StartTime + repeatPoint.RepeatIndex * repeatDuration;
var fadeInTime = repeatStartTime + (repeatPoint.StartTime - repeatStartTime) / 2 - (repeatPoint.RepeatIndex == 0 ? FadeInDuration : FadeInDuration / 2);
var fadeOutTime = repeatStartTime + repeatDuration;
var drawableRepeatPoint = new DrawableRepeatPoint(repeatPoint, this)
{
FadeInTime = fadeInTime,
FadeOutTime = fadeOutTime,
Position = repeatPoint.Position,
Position = repeatPoint.Position
};
repeatPoints.Add(drawableRepeatPoint);
components.Add(drawableRepeatPoint);
AddNested(drawableRepeatPoint);
}
}
private int currentRepeat;
private int currentSpan;
public bool Tracking;
public override double FadeInDuration
{
get { return base.FadeInDuration; }
set { InitialCircle.FadeInDuration = base.FadeInDuration = value; }
}
protected override void Update()
{
base.Update();
@ -120,33 +98,32 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
double progress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
int repeat = slider.RepeatAt(progress);
int span = slider.SpanAt(progress);
progress = slider.ProgressAt(progress);
if (repeat > currentRepeat)
currentRepeat = repeat;
if (span > currentSpan)
currentSpan = span;
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
if (!InitialCircle.Judgements.Any(j => j.IsHit))
InitialCircle.Position = slider.Curve.PositionAt(progress);
if (!HeadCircle.IsHit)
HeadCircle.Position = slider.Curve.PositionAt(progress);
foreach (var c in components) c.UpdateProgress(progress, repeat);
foreach (var t in ticks.Children) t.Tracking = Ball.Tracking;
foreach (var c in components.OfType<ISliderProgress>()) c.UpdateProgress(progress, span);
foreach (var c in components.OfType<ITrackSnaking>()) c.UpdateSnakingPosition(slider.Curve.PositionAt(Body.SnakedStart ?? 0), slider.Curve.PositionAt(Body.SnakedEnd ?? 0));
foreach (var t in components.OfType<IRequireTracking>()) t.Tracking = Ball.Tracking;
}
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (!userTriggered && Time.Current >= slider.EndTime)
{
var judgementsCount = ticks.Children.Count + repeatPoints.Children.Count + 1;
var judgementsHit = ticks.Children.Count(t => t.Judgements.Any(j => j.IsHit)) + repeatPoints.Children.Count(t => t.Judgements.Any(j => j.IsHit));
if (InitialCircle.Judgements.Any(j => j.IsHit))
judgementsHit++;
var judgementsCount = NestedHitObjects.Count;
var judgementsHit = NestedHitObjects.Count(h => h.IsHit);
var hitFraction = (double)judgementsHit / judgementsCount;
if (hitFraction == 1 && InitialCircle.Judgements.Any(j => j.Result == HitResult.Great))
if (hitFraction == 1 && HeadCircle.Judgements.Any(j => j.Result == HitResult.Great))
AddJudgement(new OsuJudgement { Result = HitResult.Great });
else if (hitFraction >= 0.5 && InitialCircle.Judgements.Any(j => j.Result >= HitResult.Good))
else if (hitFraction >= 0.5 && HeadCircle.Judgements.Any(j => j.Result >= HitResult.Good))
AddJudgement(new OsuJudgement { Result = HitResult.Good });
else if (hitFraction > 0)
AddJudgement(new OsuJudgement { Result = HitResult.Meh });
@ -178,7 +155,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}
}
public Drawable ProxiedLayer => InitialCircle.ApproachCircle;
public Drawable ProxiedLayer => HeadCircle.ApproachCircle;
public override Vector2 SelectionPoint => ToScreenSpace(Body.Position);
public override Quad SelectionQuad => Body.PathDrawQuad;

View File

@ -0,0 +1,32 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking
{
/// <summary>
/// The judgement text is provided by the <see cref="DrawableSlider"/>.
/// </summary>
public override bool DisplayJudgement => false;
public bool Tracking { get; set; }
public DrawableSliderTail(HitCircle hitCircle)
: base(hitCircle)
{
AlwaysPresent = true;
RelativeSizeAxes = Axes.Both;
}
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (!userTriggered && timeOffset >= 0)
AddJudgement(new OsuSliderTailJudgement { Result = Tracking ? HitResult.Great : HitResult.Miss });
}
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
@ -12,21 +11,16 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
public class DrawableSliderTick : DrawableOsuHitObject
public class DrawableSliderTick : DrawableOsuHitObject, IRequireTracking
{
private readonly SliderTick sliderTick;
private const double anim_duration = 150;
public double FadeInTime;
public double FadeOutTime;
public bool Tracking;
public bool Tracking { get; set; }
public override bool DisplayJudgement => false;
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
{
this.sliderTick = sliderTick;
Size = new Vector2(16) * sliderTick.Scale;
Masking = true;
@ -56,13 +50,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void UpdatePreemptState()
{
var animIn = Math.Min(150, sliderTick.StartTime - FadeInTime);
this.Animate(
d => d.FadeIn(animIn),
d => d.ScaleTo(0.5f).ScaleTo(1.2f, animIn)
).Then(
d => d.ScaleTo(1, 150, Easing.Out)
d => d.FadeIn(anim_duration),
d => d.ScaleTo(0.5f).ScaleTo(1f, anim_duration * 4, Easing.OutElasticHalf)
);
}
@ -71,15 +61,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
switch (state)
{
case ArmedState.Idle:
this.Delay(FadeOutTime - sliderTick.StartTime).FadeOut();
this.Delay(HitObject.TimePreempt).FadeOut();
break;
case ArmedState.Miss:
this.FadeOut(160)
.FadeColour(Color4.Red, 80);
this.FadeOut(anim_duration)
.FadeColour(Color4.Red, anim_duration / 2);
break;
case ArmedState.Hit:
this.FadeOut(120, Easing.OutQuint)
.ScaleTo(Scale * 1.5f, 120, Easing.OutQuint);
this.FadeOut(anim_duration, Easing.OutQuint)
.ScaleTo(Scale * 1.5f, anim_duration, Easing.Out);
break;
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
@ -167,7 +167,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
Disc.Tracking = OsuActionInputManager.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton);
if (!spmCounter.IsPresent && Disc.Tracking)
spmCounter.FadeIn(FadeInDuration);
spmCounter.FadeIn(HitObject.TimeFadein);
base.Update();
}
@ -191,14 +191,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
base.UpdatePreemptState();
circleContainer.ScaleTo(Spinner.Scale * 0.3f);
circleContainer.ScaleTo(Spinner.Scale, TIME_PREEMPT / 1.4f, Easing.OutQuint);
circleContainer.ScaleTo(Spinner.Scale, HitObject.TimePreempt / 1.4f, Easing.OutQuint);
Disc.RotateTo(-720);
symbol.RotateTo(-720);
mainContainer
.ScaleTo(0)
.ScaleTo(Spinner.Scale * circle.DrawHeight / DrawHeight * 1.4f, TIME_PREEMPT - 150, Easing.OutQuint)
.ScaleTo(Spinner.Scale * circle.DrawHeight / DrawHeight * 1.4f, HitObject.TimePreempt - 150, Easing.OutQuint)
.Then()
.ScaleTo(1, 500, Easing.OutQuint);
}

View File

@ -0,0 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
public interface IRequireTracking
{
/// <summary>
/// Whether the <see cref="DrawableSlider"/> is currently being tracked by the user.
/// </summary>
bool Tracking { get; set; }
}
}

View File

@ -0,0 +1,15 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
/// <summary>
/// A component which tracks the current end snaking position of a slider.
/// </summary>
public interface ITrackSnaking
{
void UpdateSnakingPosition(Vector2 start, Vector2 end);
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
@ -32,4 +32,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
approachCircle.Texture = textures.Get(@"Play/osu/approachcircle");
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
@ -63,4 +63,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
public bool OnReleased(OsuAction action) => false;
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
@ -30,4 +30,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
};
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
@ -32,4 +32,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
};
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
@ -36,4 +36,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
layer.Texture = textures.Get(@"Play/osu/ring-glow");
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Extensions.Color4Extensions;
@ -56,4 +56,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
};
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
@ -35,4 +35,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
};
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
@ -139,7 +139,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
}
}
public void UpdateProgress(double progress, int repeat)
public void UpdateProgress(double progress, int span)
{
Position = slider.Curve.PositionAt(progress);
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
@ -15,6 +15,7 @@ using OpenTK;
using OpenTK.Graphics.ES30;
using OpenTK.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
@ -88,7 +89,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
// We want the container to have the same size as the slider,
// and to be positioned such that the slider head is at (0,0).
container.Size = path.Size;
container.Position = -path.PositionInBoundingBox(slider.Curve.PositionAt(0) - currentCurve[0]);
container.Position = -path.PositionInBoundingBox(slider.Curve.PositionAt(0) - CurrentCurve[0]);
container.ForceRedraw();
}
@ -147,7 +148,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
path.Texture = texture;
}
private readonly List<Vector2> currentCurve = new List<Vector2>();
public readonly List<Vector2> CurrentCurve = new List<Vector2>();
private bool updateSnaking(double p0, double p1)
{
if (SnakedStart == p0 && SnakedEnd == p1) return false;
@ -155,23 +156,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
SnakedStart = p0;
SnakedEnd = p1;
slider.Curve.GetPathToProgress(currentCurve, p0, p1);
slider.Curve.GetPathToProgress(CurrentCurve, p0, p1);
path.ClearVertices();
foreach (Vector2 p in currentCurve)
path.AddVertex(p - currentCurve[0]);
foreach (Vector2 p in CurrentCurve)
path.AddVertex(p - CurrentCurve[0]);
return true;
}
public void UpdateProgress(double progress, int repeat)
public void UpdateProgress(double progress, int span)
{
double start = 0;
double end = snakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - DrawableOsuHitObject.TIME_PREEMPT)) / DrawableOsuHitObject.TIME_FADEIN, 0, 1) : 1;
double end = snakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadein, 0, 1) : 1;
if (repeat >= slider.RepeatCount - 1)
if (span >= slider.SpanCount() - 1)
{
if (Math.Min(repeat, slider.RepeatCount - 1) % 2 == 1)
if (Math.Min(span, slider.SpanCount() - 1) % 2 == 1)
{
start = 0;
end = snakingOut ? progress : 1;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
@ -11,7 +11,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public class SpinnerBackground : CircularContainer, IHasAccentColour
{
public override bool HandleInput => false;
public override bool HandleKeyboardInput => false;
public override bool HandleMouseInput => false;
protected Box Disc;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
@ -54,4 +54,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
}
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Graphics.Backgrounds;
@ -23,4 +23,4 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
base.Update();
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Osu.Objects

View File

@ -1,10 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Osu.Objects
{
public interface ISliderProgress
{
void UpdateProgress(double progress, int repeat);
void UpdateProgress(double progress, int span);
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
@ -7,7 +7,6 @@ using OpenTK;
using osu.Game.Rulesets.Objects.Types;
using OpenTK.Graphics;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects
{
@ -15,10 +14,8 @@ namespace osu.Game.Rulesets.Osu.Objects
{
public const double OBJECT_RADIUS = 64;
private const double hittable_range = 300;
private const double hit_window_50 = 150;
private const double hit_window_100 = 80;
private const double hit_window_300 = 30;
public double TimePreempt = 600;
public double TimeFadein = 400;
public Vector2 Position { get; set; }
public float X => Position.X;
@ -40,38 +37,15 @@ namespace osu.Game.Rulesets.Osu.Objects
public Color4 ComboColour { get; set; } = Color4.Gray;
public virtual bool NewCombo { get; set; }
public int ComboIndex { get; set; }
public double HitWindowFor(HitResult result)
{
switch (result)
{
default:
return 300;
case HitResult.Meh:
return 150;
case HitResult.Good:
return 80;
case HitResult.Great:
return 30;
}
}
public HitResult ScoreResultForOffset(double offset)
{
if (offset < HitWindowFor(HitResult.Great))
return HitResult.Great;
if (offset < HitWindowFor(HitResult.Good))
return HitResult.Good;
if (offset < HitWindowFor(HitResult.Meh))
return HitResult.Meh;
return HitResult.Miss;
}
public int IndexInCurrentCombo { get; set; }
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
TimeFadein = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300);
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
}
}

View File

@ -1,10 +1,25 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Rulesets.Osu.Objects
{
public class RepeatPoint : OsuHitObject
{
public int RepeatIndex { get; set; }
public double SpanDuration { get; set; }
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
// We want to show the first RepeatPoint as the TimePreempt dictates but on short (and possibly fast) sliders
// we may need to cut down this time on following RepeatPoints to only show up to two RepeatPoints at any given time.
if (RepeatIndex > 0)
TimePreempt = Math.Min(SpanDuration * 2, TimePreempt);
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
@ -20,12 +20,13 @@ namespace osu.Game.Rulesets.Osu.Objects
/// </summary>
private const float base_scoring_distance = 100;
public readonly SliderCurve Curve = new SliderCurve();
public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity;
public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;
public double Duration => EndTime - StartTime;
public override Vector2 EndPosition => PositionAt(1);
public Vector2 StackedPositionAt(double t) => this.PositionAt(t) + StackOffset;
public override Vector2 EndPosition => this.PositionAt(1);
public SliderCurve Curve { get; } = new SliderCurve();
public List<Vector2> ControlPoints
{
@ -58,9 +59,15 @@ namespace osu.Game.Rulesets.Osu.Objects
internal float LazyTravelDistance;
public List<List<SampleInfo>> RepeatSamples { get; set; } = new List<List<SampleInfo>>();
public int RepeatCount { get; set; } = 1;
public int RepeatCount { get; set; }
/// <summary>
/// The length of one span of this <see cref="Slider"/>.
/// </summary>
public double SpanDuration => Duration / this.SpanCount();
private int stackHeight;
public override int StackHeight
{
get { return stackHeight; }
@ -74,6 +81,9 @@ namespace osu.Game.Rulesets.Osu.Objects
public double Velocity;
public double TickDistance;
public HitCircle HeadCircle;
public HitCircle TailCircle;
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
@ -87,40 +97,52 @@ namespace osu.Game.Rulesets.Osu.Objects
TickDistance = scoringDistance / difficulty.SliderTickRate;
}
public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress));
public double ProgressAt(double progress)
{
double p = progress * RepeatCount % 1;
if (RepeatAt(progress) % 2 == 1)
p = 1 - p;
return p;
}
public int RepeatAt(double progress) => (int)(progress * RepeatCount);
protected override void CreateNestedHitObjects()
{
base.CreateNestedHitObjects();
createSliderEnds();
createTicks();
createRepeatPoints();
}
private void createSliderEnds()
{
HeadCircle = new HitCircle
{
StartTime = StartTime,
Position = StackedPosition,
IndexInCurrentCombo = IndexInCurrentCombo,
ComboColour = ComboColour,
Samples = Samples,
SampleControlPoint = SampleControlPoint
};
TailCircle = new HitCircle
{
StartTime = EndTime,
Position = StackedEndPosition,
IndexInCurrentCombo = IndexInCurrentCombo,
ComboColour = ComboColour
};
AddNested(HeadCircle);
AddNested(TailCircle);
}
private void createTicks()
{
if (TickDistance == 0) return;
var length = Curve.Distance;
var tickDistance = Math.Min(TickDistance, length);
var repeatDuration = length / Velocity;
var minDistanceFromEnd = Velocity * 0.01;
for (var repeat = 0; repeat < RepeatCount; repeat++)
for (var span = 0; span < this.SpanCount(); span++)
{
var repeatStartTime = StartTime + repeat * repeatDuration;
var reversed = repeat % 2 == 1;
var spanStartTime = StartTime + span * SpanDuration;
var reversed = span % 2 == 1;
for (var d = tickDistance; d <= length; d += tickDistance)
{
@ -130,20 +152,27 @@ namespace osu.Game.Rulesets.Osu.Objects
var distanceProgress = d / length;
var timeProgress = reversed ? 1 - distanceProgress : distanceProgress;
var firstSample = Samples.FirstOrDefault(s => s.Name == SampleInfo.HIT_NORMAL) ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
var sampleList = new List<SampleInfo>();
if (firstSample != null)
sampleList.Add(new SampleInfo
{
Bank = firstSample.Bank,
Volume = firstSample.Volume,
Name = @"slidertick",
});
AddNested(new SliderTick
{
RepeatIndex = repeat,
StartTime = repeatStartTime + timeProgress * repeatDuration,
SpanIndex = span,
SpanStartTime = spanStartTime,
StartTime = spanStartTime + timeProgress * SpanDuration,
Position = Curve.PositionAt(distanceProgress),
StackHeight = StackHeight,
Scale = Scale,
ComboColour = ComboColour,
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}))
Samples = sampleList
});
}
}
@ -151,21 +180,18 @@ namespace osu.Game.Rulesets.Osu.Objects
private void createRepeatPoints()
{
var repeatDuration = Distance / Velocity;
for (var repeat = 1; repeat < RepeatCount; repeat++)
for (int repeatIndex = 0, repeat = 1; repeatIndex < RepeatCount; repeatIndex++, repeat++)
{
var repeatStartTime = StartTime + repeat * repeatDuration;
AddNested(new RepeatPoint
{
RepeatIndex = repeat,
StartTime = repeatStartTime,
RepeatIndex = repeatIndex,
SpanDuration = SpanDuration,
StartTime = StartTime + repeat * SpanDuration,
Position = Curve.PositionAt(repeat % 2),
StackHeight = StackHeight,
Scale = Scale,
ComboColour = ComboColour,
Samples = new List<SampleInfo>(RepeatSamples[repeat])
Samples = new List<SampleInfo>(RepeatSamples[repeatIndex])
});
}
}

View File

@ -1,10 +1,30 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Rulesets.Osu.Objects
{
public class SliderTick : OsuHitObject
{
public int RepeatIndex { get; set; }
public int SpanIndex { get; set; }
public double SpanStartTime { get; set; }
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
double offset;
if (SpanIndex > 0)
// Adding 200 to include the offset stable used.
// This is so on repeats ticks don't appear too late to be visually processed by the player.
offset = 200;
else
offset = TimeFadein * 0.66f;
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
@ -29,8 +29,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty
protected override void PreprocessHitObjects()
{
foreach (OsuHitObject h in Beatmap.HitObjects)
(h as Slider)?.Curve?.Calculate();
new OsuBeatmapProcessor().PostProcess(Beatmap);
}
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
var computeVertex = new Action<double>(t =>
{
// ReSharper disable once PossibleInvalidOperationException (bugged in current r# version)
var diff = slider.PositionAt(t) - slider.LazyEndPosition.Value;
var diff = slider.StackedPositionAt(t) - slider.LazyEndPosition.Value;
float dist = diff.Length;
if (dist > approxFollowCircleRadius)

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
@ -145,7 +145,7 @@ namespace osu.Game.Rulesets.Osu
public override int LegacyID => 0;
public OsuRuleset(RulesetInfo rulesetInfo)
public OsuRuleset(RulesetInfo rulesetInfo = null)
: base(rulesetInfo)
{
}

View File

@ -1,11 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using System;
using System.Diagnostics;
using osu.Framework.Graphics;
@ -90,20 +89,20 @@ namespace osu.Game.Rulesets.Osu.Replays
double endTime = (prev as IHasEndTime)?.EndTime ?? prev.StartTime;
// Make the cursor stay at a hitObject as long as possible (mainly for autopilot).
if (h.StartTime - h.HitWindowFor(HitResult.Miss) > endTime + h.HitWindowFor(HitResult.Meh) + 50)
if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Miss) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50)
{
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Miss), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
}
else if (h.StartTime - h.HitWindowFor(HitResult.Meh) > endTime + h.HitWindowFor(HitResult.Meh) + 50)
else if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50)
{
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Meh), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
}
else if (h.StartTime - h.HitWindowFor(HitResult.Good) > endTime + h.HitWindowFor(HitResult.Good) + 50)
else if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50)
{
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(HitResult.Good), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(HitResult.Good), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new ReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), prev.StackedEndPosition.X, prev.StackedEndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) AddFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh), h.StackedPosition.X, h.StackedPosition.Y, ReplayButtonState.None));
}
}
@ -133,7 +132,7 @@ namespace osu.Game.Rulesets.Osu.Replays
// Do some nice easing for cursor movements
if (Frames.Count > 0)
{
moveToHitObject(h.StartTime, startPosition, h.Radius, easing);
moveToHitObject(h, startPosition, easing);
}
// Add frames to click the hitobject
@ -191,12 +190,12 @@ namespace osu.Game.Rulesets.Osu.Replays
}
}
private void moveToHitObject(double targetTime, Vector2 targetPos, double hitObjectRadius, Easing easing)
private void moveToHitObject(OsuHitObject h, Vector2 targetPos, Easing easing)
{
ReplayFrame lastFrame = Frames[Frames.Count - 1];
// Wait until Auto could "see and react" to the next note.
double waitTime = targetTime - Math.Max(0.0, DrawableOsuHitObject.TIME_PREEMPT - reactionTime);
double waitTime = h.StartTime - Math.Max(0.0, h.TimePreempt - reactionTime);
if (waitTime > lastFrame.Time)
{
lastFrame = new ReplayFrame(waitTime, lastFrame.MouseX, lastFrame.MouseY, lastFrame.ButtonState);
@ -205,17 +204,17 @@ namespace osu.Game.Rulesets.Osu.Replays
Vector2 lastPosition = lastFrame.Position;
double timeDifference = ApplyModsToTime(targetTime - lastFrame.Time);
double timeDifference = ApplyModsToTime(h.StartTime - lastFrame.Time);
// Only "snap" to hitcircles if they are far enough apart. As the time between hitcircles gets shorter the snapping threshold goes up.
if (timeDifference > 0 && // Sanity checks
((lastPosition - targetPos).Length > hitObjectRadius * (1.5 + 100.0 / timeDifference) || // Either the distance is big enough
((lastPosition - targetPos).Length > h.Radius * (1.5 + 100.0 / timeDifference) || // Either the distance is big enough
timeDifference >= 266)) // ... or the beats are slow enough to tap anyway.
{
// Perform eased movement
for (double time = lastFrame.Time + FrameDelay; time < targetTime; time += FrameDelay)
for (double time = lastFrame.Time + FrameDelay; time < h.StartTime; time += FrameDelay)
{
Vector2 currentPosition = Interpolation.ValueAt(time, lastPosition, targetPos, lastFrame.Time, targetTime, easing);
Vector2 currentPosition = Interpolation.ValueAt(time, lastPosition, targetPos, lastFrame.Time, h.StartTime, easing);
AddFrameToReplay(new ReplayFrame((int)time, currentPosition.X, currentPosition.Y, lastFrame.ButtonState));
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework;
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
{
public TestCasePerformancePoints()
: base(new OsuRuleset(new RulesetInfo()))
: base(new OsuRuleset())
{
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
@ -16,6 +16,10 @@ using OpenTK;
using OpenTK.Graphics;
using osu.Game.Rulesets.Mods;
using System.Linq;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Osu.Tests
@ -27,7 +31,9 @@ namespace osu.Game.Rulesets.Osu.Tests
{
typeof(SliderBall),
typeof(SliderBody),
typeof(SliderTick),
typeof(DrawableSlider),
typeof(DrawableSliderTick),
typeof(DrawableRepeatPoint),
typeof(DrawableOsuHitObject)
};
@ -63,9 +69,27 @@ namespace osu.Game.Rulesets.Osu.Tests
AddStep("Fast Short Slider", () => testShortHighSpeed());
AddStep("Fast Short Slider 1 Repeat", () => testShortHighSpeed(1));
AddStep("Fast Short Slider 2 Repeats", () => testShortHighSpeed(2));
AddStep("Fast Short Slider 6 Repeats", () => testShortHighSpeed(6));
AddStep("Perfect Curve", testCurve);
// TODO more curve types?
AddStep("Perfect Curve", () => testPerfect());
AddStep("Perfect Curve 1 Repeat", () => testPerfect(1));
AddStep("Perfect Curve 2 Repeats", () => testPerfect(2));
AddStep("Linear Slider", () => testLinear());
AddStep("Linear Slider 1 Repeat", () => testLinear(1));
AddStep("Linear Slider 2 Repeats", () => testLinear(2));
AddStep("Bezier Slider", () => testBezier());
AddStep("Bezier Slider 1 Repeat", () => testBezier(1));
AddStep("Bezier Slider 2 Repeats", () => testBezier(2));
AddStep("Linear Overlapping", () => testLinearOverlapping());
AddStep("Linear Overlapping 1 Repeat", () => testLinearOverlapping(1));
AddStep("Linear Overlapping 2 Repeats", () => testLinearOverlapping(2));
AddStep("Catmull Slider", () => testCatmull());
AddStep("Catmull Slider 1 Repeat", () => testCatmull(1));
AddStep("Catmull Slider 2 Repeats", () => testCatmull(2));
}
private void testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats);
@ -84,15 +108,6 @@ namespace osu.Game.Rulesets.Osu.Tests
private void createSlider(float circleSize = 2, float distance = 400, int repeats = 0, double speedMultiplier = 2)
{
repeats++; // The first run through the slider is considered a repeat
var repeatSamples = new List<List<SampleInfo>>();
if (repeats > 1)
{
for (int i = 0; i < repeats; i++)
repeatSamples.Add(new List<SampleInfo>());
}
var slider = new Slider
{
StartTime = Time.Current + 1000,
@ -105,13 +120,13 @@ namespace osu.Game.Rulesets.Osu.Tests
},
Distance = distance,
RepeatCount = repeats,
RepeatSamples = repeatSamples
RepeatSamples = createEmptySamples(repeats)
};
addSlider(slider, circleSize, speedMultiplier);
}
private void testCurve()
private void testPerfect(int repeats = 0)
{
var slider = new Slider
{
@ -124,18 +139,137 @@ namespace osu.Game.Rulesets.Osu.Tests
new Vector2(0, 200),
new Vector2(200, 0)
},
Distance = 600
Distance = 600,
RepeatCount = repeats,
RepeatSamples = createEmptySamples(repeats)
};
addSlider(slider, 2, 3);
}
private void testLinear(int repeats = 0) => createLinear(repeats);
private void createLinear(int repeats)
{
var slider = new Slider
{
CurveType = CurveType.Linear,
StartTime = Time.Current + 1000,
Position = new Vector2(-200, 0),
ComboColour = Color4.LightSeaGreen,
ControlPoints = new List<Vector2>
{
new Vector2(-200, 0),
new Vector2(-50, 75),
new Vector2(0, 100),
new Vector2(100, -200),
new Vector2(200, 0),
new Vector2(230, 0)
},
Distance = 793.4417,
RepeatCount = repeats,
RepeatSamples = createEmptySamples(repeats)
};
addSlider(slider, 2, 3);
}
private void testBezier(int repeats = 0) => createBezier(repeats);
private void createBezier(int repeats)
{
var slider = new Slider
{
CurveType = CurveType.Bezier,
StartTime = Time.Current + 1000,
Position = new Vector2(-200, 0),
ComboColour = Color4.LightSeaGreen,
ControlPoints = new List<Vector2>
{
new Vector2(-200, 0),
new Vector2(-50, 75),
new Vector2(0, 100),
new Vector2(100, -200),
new Vector2(230, 0)
},
Distance = 480,
RepeatCount = repeats,
RepeatSamples = createEmptySamples(repeats)
};
addSlider(slider, 2, 3);
}
private void testLinearOverlapping(int repeats = 0) => createOverlapping(repeats);
private void createOverlapping(int repeats)
{
var slider = new Slider
{
CurveType = CurveType.Linear,
StartTime = Time.Current + 1000,
Position = new Vector2(0, 0),
ComboColour = Color4.LightSeaGreen,
ControlPoints = new List<Vector2>
{
new Vector2(0, 0),
new Vector2(-200, 0),
new Vector2(0, 0),
new Vector2(0, -200),
new Vector2(-200, -200),
new Vector2(0, -200)
},
Distance = 1000,
RepeatCount = repeats,
RepeatSamples = createEmptySamples(repeats)
};
addSlider(slider, 2, 3);
}
private void testCatmull(int repeats = 0) => createCatmull(repeats);
private void createCatmull(int repeats = 0)
{
var repeatSamples = new List<List<SampleInfo>>();
for (int i = 0; i < repeats; i++)
repeatSamples.Add(new List<SampleInfo>());
var slider = new Slider
{
StartTime = Time.Current + 1000,
Position = new Vector2(-100, 0),
ComboColour = Color4.LightSeaGreen,
CurveType = CurveType.Catmull,
ControlPoints = new List<Vector2>
{
new Vector2(-100, 0),
new Vector2(-50, -50),
new Vector2(50, 50),
new Vector2(100, 0)
},
Distance = 300,
RepeatCount = repeats,
RepeatSamples = repeatSamples
};
addSlider(slider, 3, 1);
}
private List<List<SampleInfo>> createEmptySamples(int repeats)
{
var repeatSamples = new List<List<SampleInfo>>();
for (int i = 0; i < repeats; i++)
repeatSamples.Add(new List<SampleInfo>());
return repeatSamples;
}
private void addSlider(Slider slider, float circleSize, double speedMultiplier)
{
var cpi = new ControlPointInfo();
cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier });
slider.ApplyDefaults(cpi, new BeatmapDifficulty { CircleSize = circleSize });
slider.ApplyDefaults(cpi, new BeatmapDifficulty { CircleSize = circleSize, SliderTickRate = 3 });
var drawable = new DrawableSlider(slider)
{
@ -146,7 +280,34 @@ namespace osu.Game.Rulesets.Osu.Tests
foreach (var mod in Mods.OfType<IApplicableToDrawableHitObjects>())
mod.ApplyToDrawableHitObjects(new[] { drawable });
drawable.OnJudgement += onJudgement;
Add(drawable);
}
private float judgementOffsetDirection = 1;
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement)
{
var osuObject = judgedObject as DrawableOsuHitObject;
if (osuObject == null)
return;
OsuSpriteText text;
Add(text = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = judgement.IsHit ? "Hit!" : "Miss!",
Colour = judgement.IsHit ? Color4.Green : Color4.Red,
TextSize = 30,
Position = osuObject.HitObject.StackedEndPosition + judgementOffsetDirection * new Vector2(0, 45)
});
text.Delay(150)
.Then().FadeOut(200)
.Then().Expire();
judgementOffsetDirection *= -1;
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
@ -159,5 +159,17 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
return false;
}
protected override void PopIn()
{
ActiveCursor.FadeTo(1, 250, Easing.OutQuint);
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
}
protected override void PopOut()
{
ActiveCursor.FadeTo(0, 250, Easing.OutQuint);
ActiveCursor.ScaleTo(0.6f, 250, Easing.In);
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
@ -12,8 +12,6 @@ using osu.Game.Rulesets.UI;
using System.Linq;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.UI.Cursor;
using osu.Framework.Graphics.Cursor;
namespace osu.Game.Rulesets.Osu.UI
{
@ -23,8 +21,6 @@ namespace osu.Game.Rulesets.Osu.UI
private readonly Container judgementLayer;
private readonly ConnectionRenderer<OsuHitObject> connectionLayer;
public override bool ProvidingUserCursor => true;
// Todo: This should not be a thing, but is currently required for the editor
// https://github.com/ppy/osu-framework/issues/1283
protected virtual bool ProxyApproachCircles => true;
@ -70,19 +66,12 @@ namespace osu.Game.Rulesets.Osu.UI
});
}
protected override void LoadComplete()
{
base.LoadComplete();
var cursor = CreateCursor();
if (cursor != null)
AddInternal(cursor);
}
public override void Add(DrawableHitObject h)
{
h.Depth = (float)h.HitObject.StartTime;
h.OnJudgement += onJudgement;
var c = h as IDrawableHitObjectWithProxiedApproach;
if (c != null && ProxyApproachCircles)
approachCircles.Add(c.ProxiedLayer.CreateProxy());
@ -97,7 +86,7 @@ namespace osu.Game.Rulesets.Osu.UI
.OrderBy(h => h.StartTime).OfType<OsuHitObject>();
}
public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement)
{
var osuJudgement = (OsuJudgement)judgement;
var osuObject = (OsuHitObject)judgedObject.HitObject;
@ -113,7 +102,5 @@ namespace osu.Game.Rulesets.Osu.UI
judgementLayer.Add(explosion);
}
protected virtual CursorContainer CreateCursor() => new GameplayCursor();
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics.Cursor;
using osu.Framework.Input;
using OpenTK;
using osu.Game.Beatmaps;
@ -10,6 +11,7 @@ using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Replays;
using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Osu.UI.Cursor;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.Replays;
@ -49,5 +51,7 @@ namespace osu.Game.Rulesets.Osu.UI
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new OsuReplayInputHandler(replay);
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f);
protected override CursorContainer CreateCursor() => new GameplayCursor();
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;