// 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.Collections.Generic; using System.Linq; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModInvert : Mod, IApplicableAfterBeatmapConversion { public override string Name => "Invert"; public override string Acronym => "IN"; public override double ScoreMultiplier => 1; public override LocalisableString Description => "Hold the keys. To the beat."; public override IconUsage? Icon => FontAwesome.Solid.YinYang; public override ModType Type => ModType.Conversion; public override Type[] IncompatibleMods => new[] { typeof(ManiaModHoldOff) }; public void ApplyToBeatmap(IBeatmap beatmap) { var maniaBeatmap = (ManiaBeatmap)beatmap; var newObjects = new List(); foreach (var column in maniaBeatmap.HitObjects.GroupBy(h => h.Column)) { var newColumnObjects = new List(); var locations = column.OfType().Select(n => (startTime: n.StartTime, samples: n.Samples)) .Concat(column.OfType().SelectMany(h => new[] { (startTime: h.StartTime, samples: h.GetNodeSamples(0)), (startTime: h.EndTime, samples: h.GetNodeSamples(1)) })) .OrderBy(h => h.startTime).ToList(); for (int i = 0; i < locations.Count - 1; i++) { // Full duration of the hold note. double duration = locations[i + 1].startTime - locations[i].startTime; // Beat length at the end of the hold note. double beatLength = beatmap.ControlPointInfo.TimingPointAt(locations[i + 1].startTime).BeatLength; // Decrease the duration by at most a 1/4 beat to ensure there's no instantaneous notes. duration = Math.Max(duration / 2, duration - beatLength / 4); newColumnObjects.Add(new HoldNote { Column = column.Key, StartTime = locations[i].startTime, Duration = duration, NodeSamples = new List> { locations[i].samples, Array.Empty() } }); } newObjects.AddRange(newColumnObjects); } maniaBeatmap.HitObjects = newObjects.OrderBy(h => h.StartTime).ToList(); // No breaks maniaBeatmap.Breaks.Clear(); } } }