diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 9e69bc1386..7fde14d6ca 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -1,14 +1,18 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Linq; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; namespace osu.Game.Rulesets.Mods { @@ -22,27 +26,79 @@ namespace osu.Game.Rulesets.Mods public override double ScoreMultiplier => 1; } - public abstract class ModMuted : ModMuted, IApplicableToDrawableRuleset, IApplicableToTrack + public abstract class ModMuted : ModMuted, IApplicableToDrawableRuleset, IApplicableToTrack, IApplicableToScoreProcessor where TObject : HitObject { - private readonly BindableNumber volumeAdjust = new BindableDouble(); + private readonly BindableNumber mainVolumeAdjust = new BindableDouble(0.5); + private readonly BindableNumber metronomeVolumeAdjust = new BindableDouble(0.5); - [SettingSource("Enable metronome", "Add a metronome to help you keep track of the rhythm.")] + private BindableNumber currentCombo; + + [SettingSource("Enable metronome", "Add a metronome beat to help you keep track of the rhythm.")] public BindableBool EnableMetronome { get; } = new BindableBool { Default = true, Value = true }; + [SettingSource("Final volume at combo", "The combo count at which point the track reaches its final volume.")] + public BindableInt MuteComboCount { get; } = new BindableInt + { + Default = 100, + Value = 100, + MinValue = 0, + MaxValue = 500, + }; + + [SettingSource("Start muted", "Increase volume as combo builds.")] + public BindableBool InverseMuting { get; } = new BindableBool + { + Default = false, + Value = false + }; + + [SettingSource("Mute hit sounds", "Hit sounds are also muted alongside the track.")] + public BindableBool AffectsHitSounds { get; } = new BindableBool + { + Default = true, + Value = true + }; + public void ApplyToTrack(ITrack track) { - track.AddAdjustment(AdjustableProperty.Volume, volumeAdjust); + track.AddAdjustment(AdjustableProperty.Volume, mainVolumeAdjust); } public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { if (EnableMetronome.Value) - drawableRuleset.Overlays.Add(new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime)); + { + Metronome metronome; + + drawableRuleset.Overlays.Add(metronome = new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime)); + + metronome.AddAdjustment(AdjustableProperty.Volume, metronomeVolumeAdjust); + } + + if (AffectsHitSounds.Value) + drawableRuleset.Audio.AddAdjustment(AdjustableProperty.Volume, mainVolumeAdjust); } + + public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + { + currentCombo = scoreProcessor.Combo.GetBoundCopy(); + currentCombo.BindValueChanged(combo => + { + double dimFactor = Math.Min(1, (double)combo.NewValue / MuteComboCount.Value); + + if (InverseMuting.Value) + dimFactor = 1 - dimFactor; + + scoreProcessor.TransformBindableTo(metronomeVolumeAdjust, dimFactor, 500, Easing.OutQuint); + scoreProcessor.TransformBindableTo(mainVolumeAdjust, 1 - dimFactor, 500, Easing.OutQuint); + }, true); + } + + public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; } } diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index daf46dcdcc..29559f5036 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -1,29 +1,30 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; -using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Drawables; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Input; using osu.Framework.Input.Events; +using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.Cursor; using osu.Game.Input.Handlers; using osu.Game.Overlays; using osu.Game.Replays; using osu.Game.Rulesets.Configuration; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -98,6 +99,14 @@ namespace osu.Game.Rulesets.UI private DrawableRulesetDependencies dependencies; + /// + /// Audio adjustments which are applied to the playfield. + /// + /// + /// Does not affect . + /// + public IAdjustableAudioComponent Audio { get; private set; } + /// /// Creates a ruleset visualisation for the provided ruleset and beatmap. /// @@ -155,23 +164,28 @@ namespace osu.Game.Rulesets.UI [BackgroundDependencyLoader] private void load(CancellationToken? cancellationToken) { - InternalChildren = new Drawable[] + AudioContainer audioContainer; + + InternalChild = frameStabilityContainer = new FrameStabilityContainer(GameplayStartTime) { - frameStabilityContainer = new FrameStabilityContainer(GameplayStartTime) + FrameStablePlayback = FrameStablePlayback, + Children = new Drawable[] { - FrameStablePlayback = FrameStablePlayback, - Children = new Drawable[] + FrameStableComponents, + audioContainer = new AudioContainer { - FrameStableComponents, - KeyBindingInputManager + RelativeSizeAxes = Axes.Both, + Child = KeyBindingInputManager .WithChild(CreatePlayfieldAdjustmentContainer() .WithChild(Playfield) ), - Overlays, - } - }, + }, + Overlays, + } }; + Audio = audioContainer; + if ((ResumeOverlay = CreateResumeOverlay()) != null) { AddInternal(CreateInputManager()