1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-15 00:02:54 +08:00

Add DoubleTime, HalfTime and Nightcore support.

This commit is contained in:
Dean Herbert 2017-04-21 17:33:20 +09:00
parent 6e3125e115
commit 3f832731c9
No known key found for this signature in database
GPG Key ID: 46D71BF4958ABB49
21 changed files with 313 additions and 134 deletions

View File

@ -8,6 +8,7 @@ using osu.Game.Database;
using osu.Game.Rulesets.Mods;
using System;
using System.Collections.Generic;
using System.Linq;
namespace osu.Game.Beatmaps
{
@ -26,6 +27,18 @@ namespace osu.Game.Beatmaps
BeatmapInfo = beatmapInfo;
BeatmapSetInfo = beatmapSetInfo;
WithStoryboard = withStoryboard;
Mods.ValueChanged += mods => applyRateAdjustments();
}
private void applyRateAdjustments()
{
var t = track;
if (t == null) return;
t.ResetRate();
foreach (var mod in Mods.Value.OfType<IApplicableToClock>())
mod.ApplyToClock(t);
}
protected abstract Beatmap GetBeatmap();
@ -66,7 +79,11 @@ namespace osu.Game.Beatmaps
{
lock (trackLock)
{
return track ?? (track = GetTrack());
if (track != null) return track;
track = GetTrack();
applyRateAdjustments();
return track;
}
}
}

View File

@ -17,6 +17,6 @@ namespace osu.Game.Rulesets.Mods
/// Applies the mod to a HitRenderer.
/// </summary>
/// <param name="hitRenderer">The HitRenderer to apply the mod to.</param>
void Apply(HitRenderer<TObject> hitRenderer);
void ApplyToHitRenderer(HitRenderer<TObject> hitRenderer);
}
}

View File

@ -0,0 +1,15 @@
// 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.Framework.Timing;
namespace osu.Game.Rulesets.Mods
{
/// <summary>
/// An interface for mods that make adjustments to the track.
/// </summary>
public interface IApplicableToClock
{
void ApplyToClock(IAdjustableClock clock);
}
}

View File

@ -1,12 +1,8 @@
// 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.Objects;
using osu.Game.Rulesets.UI;
using System;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mods
{
@ -45,131 +41,4 @@ namespace osu.Game.Rulesets.Mods
/// </summary>
public virtual Type[] IncompatibleMods => new Type[] { };
}
public class MultiMod : Mod
{
public override string Name => string.Empty;
public override string Description => string.Empty;
public override double ScoreMultiplier => 0.0;
public Mod[] Mods;
}
public abstract class ModNoFail : Mod
{
public override string Name => "NoFail";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nofail;
public override string Description => "You can't fail, no matter what.";
public override double ScoreMultiplier => 0.5;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModAutoplay) };
}
public abstract class ModEasy : Mod
{
public override string Name => "Easy";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_easy;
public override string Description => "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required.";
public override double ScoreMultiplier => 0.5;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModHardRock) };
}
public abstract class ModHidden : Mod
{
public override string Name => "Hidden";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
public override bool Ranked => true;
}
public abstract class ModHardRock : Mod
{
public override string Name => "Hard Rock";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hardrock;
public override string Description => "Everything just got a bit harder...";
public override Type[] IncompatibleMods => new[] { typeof(ModEasy) };
}
public abstract class ModSuddenDeath : Mod
{
public override string Name => "Sudden Death";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_suddendeath;
public override string Description => "Miss a note and fail.";
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModNoFail), typeof(ModRelax), typeof(ModAutoplay) };
}
public abstract class ModDoubleTime : Mod
{
public override string Name => "Double Time";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_doubletime;
public override string Description => "Zoooooooooom";
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModHalfTime) };
}
public abstract class ModRelax : Mod
{
public override string Name => "Relax";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_relax;
public override double ScoreMultiplier => 0;
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModNoFail), typeof(ModSuddenDeath) };
}
public abstract class ModHalfTime : Mod
{
public override string Name => "Half Time";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_halftime;
public override string Description => "Less zoom";
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModDoubleTime) };
}
public abstract class ModNightcore : ModDoubleTime
{
public override string Name => "Nightcore";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nightcore;
public override string Description => "uguuuuuuuu";
}
public abstract class ModFlashlight : Mod
{
public override string Name => "Flashlight";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_flashlight;
public override string Description => "Restricted view area.";
public override bool Ranked => true;
}
public class ModAutoplay : Mod
{
public override string Name => "Autoplay";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_auto;
public override string Description => "Watch a perfect automated play through the song";
public override double ScoreMultiplier => 0;
public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail) };
}
public abstract class ModAutoplay<T> : ModAutoplay, IApplicableMod<T>
where T : HitObject
{
protected abstract Score CreateReplayScore(Beatmap<T> beatmap);
public void Apply(HitRenderer<T> hitRenderer)
{
hitRenderer.SetReplay(CreateReplayScore(hitRenderer.Beatmap)?.Replay);
}
}
public abstract class ModPerfect : ModSuddenDeath
{
public override string Name => "Perfect";
public override string Description => "SS or quit.";
}
public class ModCinema : ModAutoplay
{
public override string Name => "Cinema";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_cinema;
}
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2007-2017 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.Graphics;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModAutoplay<T> : ModAutoplay, IApplicableMod<T>
where T : HitObject
{
protected abstract Score CreateReplayScore(Beatmap<T> beatmap);
public void ApplyToHitRenderer(HitRenderer<T> hitRenderer)
{
hitRenderer.SetReplay(CreateReplayScore(hitRenderer.Beatmap)?.Replay);
}
}
public class ModAutoplay : Mod
{
public override string Name => "Autoplay";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_auto;
public override string Description => "Watch a perfect automated play through the song";
public override double ScoreMultiplier => 0;
public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail) };
}
}

View File

@ -0,0 +1,13 @@
// 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.Graphics;
namespace osu.Game.Rulesets.Mods
{
public class ModCinema : ModAutoplay
{
public override string Name => "Cinema";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_cinema;
}
}

View File

@ -0,0 +1,25 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Timing;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
public class ModDoubleTime : Mod, IApplicableToClock
{
public override string Name => "Double Time";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_doubletime;
public override string Description => "Zoooooooooom";
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModHalfTime) };
public override double ScoreMultiplier => 1.12;
public virtual void ApplyToClock(IAdjustableClock clock)
{
clock.Rate = 1.5;
}
}
}

View File

@ -0,0 +1,18 @@
// Copyright (c) 2007-2017 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;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModEasy : Mod
{
public override string Name => "Easy";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_easy;
public override string Description => "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required.";
public override double ScoreMultiplier => 0.5;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModHardRock) };
}
}

View File

@ -0,0 +1,15 @@
// 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.Graphics;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModFlashlight : Mod
{
public override string Name => "Flashlight";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_flashlight;
public override string Description => "Restricted view area.";
public override bool Ranked => true;
}
}

View File

@ -0,0 +1,25 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Timing;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModHalfTime : Mod, IApplicableToClock
{
public override string Name => "Half Time";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_halftime;
public override string Description => "Less zoom";
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModDoubleTime) };
public override double ScoreMultiplier => 1.12;
public void ApplyToClock(IAdjustableClock clock)
{
clock.Rate = 0.75;
}
}
}

View File

@ -0,0 +1,16 @@
// Copyright (c) 2007-2017 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;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModHardRock : Mod
{
public override string Name => "Hard Rock";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hardrock;
public override string Description => "Everything just got a bit harder...";
public override Type[] IncompatibleMods => new[] { typeof(ModEasy) };
}
}

View File

@ -0,0 +1,14 @@
// 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.Graphics;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModHidden : Mod
{
public override string Name => "Hidden";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
public override bool Ranked => true;
}
}

View File

@ -0,0 +1,25 @@
// 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.Framework.Audio;
using osu.Framework.Timing;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModNightcore : ModDoubleTime
{
public override string Name => "Nightcore";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nightcore;
public override string Description => "uguuuuuuuu";
public override void ApplyToClock(IAdjustableClock clock)
{
var pitchAdjust = clock as IHasPitchAdjust;
if (pitchAdjust != null)
pitchAdjust.PitchAdjust = 1.5;
else
base.ApplyToClock(clock);
}
}
}

View File

@ -0,0 +1,18 @@
// Copyright (c) 2007-2017 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;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModNoFail : Mod
{
public override string Name => "NoFail";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nofail;
public override string Description => "You can't fail, no matter what.";
public override double ScoreMultiplier => 0.5;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModAutoplay) };
}
}

View File

@ -0,0 +1,11 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Mods
{
public abstract class ModPerfect : ModSuddenDeath
{
public override string Name => "Perfect";
public override string Description => "SS or quit.";
}
}

View File

@ -0,0 +1,16 @@
// Copyright (c) 2007-2017 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;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModRelax : Mod
{
public override string Name => "Relax";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_relax;
public override double ScoreMultiplier => 0;
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModNoFail), typeof(ModSuddenDeath) };
}
}

View File

@ -0,0 +1,18 @@
// Copyright (c) 2007-2017 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;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModSuddenDeath : Mod
{
public override string Name => "Sudden Death";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_suddendeath;
public override string Description => "Miss a note and fail.";
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModNoFail), typeof(ModRelax), typeof(ModAutoplay) };
}
}

View File

@ -0,0 +1,14 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Mods
{
public class MultiMod : Mod
{
public override string Name => string.Empty;
public override string Description => string.Empty;
public override double ScoreMultiplier => 0.0;
public Mod[] Mods;
}
}

View File

@ -157,7 +157,7 @@ namespace osu.Game.Rulesets.UI
return;
foreach (var mod in mods.OfType<IApplicableMod<TObject>>())
mod.Apply(this);
mod.ApplyToHitRenderer(this);
}
/// <summary>

View File

@ -20,6 +20,7 @@ using osu.Game.Screens.Backgrounds;
using System;
using System.Linq;
using osu.Framework.Threading;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Ranking;
@ -120,6 +121,8 @@ namespace osu.Game.Screens.Play
Schedule(() =>
{
sourceClock.Reset();
foreach (var mod in Beatmap.Mods.Value.OfType<IApplicableToClock>())
mod.ApplyToClock(sourceClock);
});
scoreProcessor = HitRenderer.CreateScoreProcessor();

View File

@ -109,6 +109,21 @@
<Compile Include="IO\Serialization\IJsonSerializable.cs" />
<Compile Include="IPC\ScoreIPCChannel.cs" />
<Compile Include="Rulesets\BeatmapStatistic.cs" />
<Compile Include="Rulesets\Mods\IApplicableToClock.cs" />
<Compile Include="Rulesets\Mods\ModAutoplay.cs" />
<Compile Include="Rulesets\Mods\ModCinema.cs" />
<Compile Include="Rulesets\Mods\ModDoubleTime.cs" />
<Compile Include="Rulesets\Mods\ModEasy.cs" />
<Compile Include="Rulesets\Mods\ModFlashlight.cs" />
<Compile Include="Rulesets\Mods\ModHalfTime.cs" />
<Compile Include="Rulesets\Mods\ModHardRock.cs" />
<Compile Include="Rulesets\Mods\ModHidden.cs" />
<Compile Include="Rulesets\Mods\ModNightcore.cs" />
<Compile Include="Rulesets\Mods\ModNoFail.cs" />
<Compile Include="Rulesets\Mods\ModPerfect.cs" />
<Compile Include="Rulesets\Mods\ModRelax.cs" />
<Compile Include="Rulesets\Mods\ModSuddenDeath.cs" />
<Compile Include="Rulesets\Mods\MultiMod.cs" />
<Compile Include="Rulesets\Objects\Legacy\Catch\Hit.cs" />
<Compile Include="Rulesets\Objects\Legacy\Catch\HitObjectParser.cs" />
<Compile Include="Rulesets\Objects\Legacy\Catch\Slider.cs" />