// Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; 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.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Configuration; using osu.Framework.Configuration; namespace osu.Game.Rulesets.Osu.Mods { public class OsuModHidden : ModHidden, IApplicableToDrawableHitObjects, IReadFromConfig { 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 Bindable increaseFirstObjectVisibility = new Bindable(false); public void ReadFromConfig(OsuConfigManager config) { increaseFirstObjectVisibility = config.GetBindable(OsuSetting.IncreaseFirstObjectVisibility); } public void ApplyToDrawableHitObjects(IEnumerable drawables) { foreach (var d in drawables.OfType()) { //Don't hide the first object ("drawables" are in a reverse order -> Last() ) if (d == drawables.Last() && increaseFirstObjectVisibility) continue; d.ApplyCustomUpdateState += ApplyHiddenState; d.HitObject.TimeFadein = d.HitObject.TimePreempt * fade_in_duration_multiplier; foreach (var h in d.HitObject.NestedHitObjects.OfType()) h.TimeFadein = h.TimePreempt * fade_in_duration_multiplier; } } protected void ApplyHiddenState(DrawableHitObject drawable, ArmedState state) { if (!(drawable is DrawableOsuHitObject d)) return; var h = d.HitObject; var fadeOutStartTime = h.StartTime - h.TimePreempt + h.TimeFadein; var fadeOutDuration = h.TimePreempt * fade_out_duration_multiplier; // new duration from completed fade in to end (before fading out) var longFadeDuration = ((h as IHasEndTime)?.EndTime ?? h.StartTime) - fadeOutStartTime; switch (drawable) { case DrawableHitCircle circle: // we don't want to see the approach circle using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) 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 DrawableSliderTick sliderTick: // slider ticks fade out over up to one second var tickFadeOutDuration = Math.Min(sliderTick.HitObject.TimePreempt - DrawableSliderTick.ANIM_DURATION, 1000); using (sliderTick.BeginAbsoluteSequence(sliderTick.HitObject.StartTime - tickFadeOutDuration, true)) sliderTick.FadeOut(tickFadeOutDuration); 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; } } } }