├── osu.Game.Rulesets.PumpTrainer ├── Resources │ └── Textures │ │ ├── C.png │ │ ├── DL.png │ │ ├── UL.png │ │ ├── C-gray.png │ │ ├── DL-gray.png │ │ └── UL-gray.png ├── Mods │ ├── PumpTrainerModHalfTime.cs │ ├── PumpTrainerModDoubleTime.cs │ ├── ExcludeColumns │ │ ├── PumpTrainerModExcludeP1C.cs │ │ ├── PumpTrainerModExcludeP2C.cs │ │ ├── PumpTrainerModExcludeP1DL.cs │ │ ├── PumpTrainerModExcludeP1DR.cs │ │ ├── PumpTrainerModExcludeP1UL.cs │ │ ├── PumpTrainerModExcludeP1UR.cs │ │ ├── PumpTrainerModExcludeP2DL.cs │ │ ├── PumpTrainerModExcludeP2DR.cs │ │ ├── PumpTrainerModExcludeP2UL.cs │ │ ├── PumpTrainerModExcludeP2UR.cs │ │ └── PumpTrainerModExcludeColumn.cs │ ├── PumpTrainerModAutoplay.cs │ ├── PumpTrainerModSeeded.cs │ ├── PumpTrainerModDiagonalSkips.cs │ ├── PumpTrainerModNoFarColumns.cs │ ├── PumpTrainerModCornersOnSixteenths.cs │ ├── PumpTrainerModHorizontalTriplesOnSixteenths.cs │ └── PumpTrainerModHorizontalTwists.cs ├── osu.Game.Rulesets.PumpTrainer.csproj ├── Replays │ ├── PumpTrainerReplayFrame.cs │ ├── PumpTrainerFramedReplayInputHandler.cs │ └── PumpTrainerAutoGenerator.cs ├── PumpTrainerInputManager.cs ├── Objects │ ├── Drawables │ │ ├── DrawableTopRowHitObject.cs │ │ └── DrawablePumpTrainerHitObject.cs │ └── PumpTrainerHitObject.cs ├── PumpTrainerDifficultyCalculator.cs ├── PumpTrainerKeybindConversions.cs ├── UI │ ├── DrawablePumpTrainerRuleset.cs │ └── PumpTrainerPlayfield.cs ├── Beatmaps │ ├── PumpTrainerHitObjectGeneratorSettingsPerHitObject.cs │ ├── PumpTrainerHitObjectGeneratorSettings.cs │ ├── PumpTrainerBeatmapConverter.cs │ └── PumpTrainerHitObjectGenerator.cs └── PumpTrainerRuleset.cs ├── Directory.Build.props ├── osu.Game.Rulesets.PumpTrainer.Tests ├── TestSceneOsuPlayer.cs ├── VisualTestRunner.cs ├── TestSceneOsuGame.cs ├── .vscode │ ├── launch.json │ └── tasks.json └── osu.Game.Rulesets.PumpTrainer.Tests.csproj ├── README.md ├── app.manifest ├── .gitattributes ├── osu.Game.Rulesets.PumpTrainer.sln ├── .gitignore ├── .editorconfig └── osu.Game.Rulesets.PumpTrainer.sln.DotSettings /osu.Game.Rulesets.PumpTrainer/Resources/Textures/C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwabis/pump-trainer/HEAD/osu.Game.Rulesets.PumpTrainer/Resources/Textures/C.png -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Resources/Textures/DL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwabis/pump-trainer/HEAD/osu.Game.Rulesets.PumpTrainer/Resources/Textures/DL.png -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Resources/Textures/UL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwabis/pump-trainer/HEAD/osu.Game.Rulesets.PumpTrainer/Resources/Textures/UL.png -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Resources/Textures/C-gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwabis/pump-trainer/HEAD/osu.Game.Rulesets.PumpTrainer/Resources/Textures/C-gray.png -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Resources/Textures/DL-gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwabis/pump-trainer/HEAD/osu.Game.Rulesets.PumpTrainer/Resources/Textures/DL-gray.png -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Resources/Textures/UL-gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwabis/pump-trainer/HEAD/osu.Game.Rulesets.PumpTrainer/Resources/Textures/UL-gray.png -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/PumpTrainerModHalfTime.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods 4 | { 5 | public class PumpTrainerModHalfTime : ModHalfTime 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/PumpTrainerModDoubleTime.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods 4 | { 5 | public class PumpTrainerModDoubleTime : ModDoubleTime 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/ExcludeColumns/PumpTrainerModExcludeP1C.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.PumpTrainer.Objects; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns 4 | { 5 | public class PumpTrainerModExcludeP1C : PumpTrainerModExcludeColumn 6 | { 7 | public override Column ExcludedColumn => Column.P1C; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/ExcludeColumns/PumpTrainerModExcludeP2C.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.PumpTrainer.Objects; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns 4 | { 5 | public class PumpTrainerModExcludeP2C : PumpTrainerModExcludeColumn 6 | { 7 | public override Column ExcludedColumn => Column.P2C; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/ExcludeColumns/PumpTrainerModExcludeP1DL.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.PumpTrainer.Objects; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns 4 | { 5 | public class PumpTrainerModExcludeP1DL : PumpTrainerModExcludeColumn 6 | { 7 | public override Column ExcludedColumn => Column.P1DL; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/ExcludeColumns/PumpTrainerModExcludeP1DR.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.PumpTrainer.Objects; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns 4 | { 5 | public class PumpTrainerModExcludeP1DR : PumpTrainerModExcludeColumn 6 | { 7 | public override Column ExcludedColumn => Column.P1DR; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/ExcludeColumns/PumpTrainerModExcludeP1UL.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.PumpTrainer.Objects; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns 4 | { 5 | public class PumpTrainerModExcludeP1UL : PumpTrainerModExcludeColumn 6 | { 7 | public override Column ExcludedColumn => Column.P1UL; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/ExcludeColumns/PumpTrainerModExcludeP1UR.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.PumpTrainer.Objects; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns 4 | { 5 | public class PumpTrainerModExcludeP1UR : PumpTrainerModExcludeColumn 6 | { 7 | public override Column ExcludedColumn => Column.P1UR; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/ExcludeColumns/PumpTrainerModExcludeP2DL.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.PumpTrainer.Objects; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns 4 | { 5 | public class PumpTrainerModExcludeP2DL : PumpTrainerModExcludeColumn 6 | { 7 | public override Column ExcludedColumn => Column.P2DL; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/ExcludeColumns/PumpTrainerModExcludeP2DR.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.PumpTrainer.Objects; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns 4 | { 5 | public class PumpTrainerModExcludeP2DR : PumpTrainerModExcludeColumn 6 | { 7 | public override Column ExcludedColumn => Column.P2DR; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/ExcludeColumns/PumpTrainerModExcludeP2UL.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.PumpTrainer.Objects; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns 4 | { 5 | public class PumpTrainerModExcludeP2UL : PumpTrainerModExcludeColumn 6 | { 7 | public override Column ExcludedColumn => Column.P2UL; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/ExcludeColumns/PumpTrainerModExcludeP2UR.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.PumpTrainer.Objects; 2 | 3 | namespace osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns 4 | { 5 | public class PumpTrainerModExcludeP2UR : PumpTrainerModExcludeColumn 6 | { 7 | public override Column ExcludedColumn => Column.P2UR; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildThisFileDirectory)app.manifest 5 | 6 | 7 | true 8 | $(NoWarn);CS1591 9 | 10 | 11 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer.Tests/TestSceneOsuPlayer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using NUnit.Framework; 5 | using osu.Game.Tests.Visual; 6 | 7 | namespace osu.Game.Rulesets.PumpTrainer.Tests 8 | { 9 | [TestFixture] 10 | public partial class TestSceneOsuPlayer : PlayerTestScene 11 | { 12 | protected override Ruleset CreatePlayerRuleset() => new PumpTrainerRuleset(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/osu.Game.Rulesets.PumpTrainer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | osu.Game.Rulesets.PumpTrainer 5 | Library 6 | AnyCPU 7 | osu.Game.Rulesets.PumpTrainer 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Replays/PumpTrainerReplayFrame.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System.Collections.Generic; 5 | using osu.Game.Rulesets.Replays; 6 | 7 | namespace osu.Game.Rulesets.PumpTrainer.Replays 8 | { 9 | public class PumpTrainerReplayFrame : ReplayFrame 10 | { 11 | public List Actions = new List(); 12 | 13 | public PumpTrainerReplayFrame(PumpTrainerAction? button = null) 14 | { 15 | if (button.HasValue) 16 | Actions.Add(button.Value); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/PumpTrainerModAutoplay.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System.Collections.Generic; 5 | using osu.Game.Beatmaps; 6 | using osu.Game.Rulesets.PumpTrainer.Replays; 7 | using osu.Game.Rulesets.Mods; 8 | 9 | namespace osu.Game.Rulesets.PumpTrainer.Mods 10 | { 11 | public class PumpTrainerModAutoplay : ModAutoplay 12 | { 13 | public override ModReplayData CreateReplayData(IBeatmap beatmap, IReadOnlyList mods) 14 | => new ModReplayData(new PumpTrainerAutoGenerator(beatmap).Generate(), new ModCreatedUser { Username = "sample" }); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer.Tests/VisualTestRunner.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System; 5 | using osu.Framework; 6 | using osu.Framework.Platform; 7 | using osu.Game.Tests; 8 | 9 | namespace osu.Game.Rulesets.PumpTrainer.Tests 10 | { 11 | public static class VisualTestRunner 12 | { 13 | [STAThread] 14 | public static int Main(string[] args) 15 | { 16 | using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu")) 17 | { 18 | host.Run(new OsuTestBrowser()); 19 | return 0; 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/PumpTrainerInputManager.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using osu.Framework.Input.Bindings; 5 | using osu.Game.Rulesets.UI; 6 | 7 | namespace osu.Game.Rulesets.PumpTrainer 8 | { 9 | public partial class PumpTrainerInputManager : RulesetInputManager 10 | { 11 | public PumpTrainerInputManager(RulesetInfo ruleset) 12 | : base(ruleset, 0, SimultaneousBindingMode.Unique) 13 | { 14 | } 15 | } 16 | 17 | public enum PumpTrainerAction 18 | { 19 | P1DL, 20 | P1UL, 21 | P1C, 22 | P1UR, 23 | P1DR, 24 | P2DL, 25 | P2UL, 26 | P2C, 27 | P2UR, 28 | P2DR, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer.Tests/TestSceneOsuGame.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using osu.Framework.Allocation; 5 | using osu.Framework.Graphics; 6 | using osu.Framework.Graphics.Shapes; 7 | using osu.Game.Tests.Visual; 8 | using osuTK.Graphics; 9 | 10 | namespace osu.Game.Rulesets.PumpTrainer.Tests 11 | { 12 | public partial class TestSceneOsuGame : OsuTestScene 13 | { 14 | [BackgroundDependencyLoader] 15 | private void load() 16 | { 17 | Children = new Drawable[] 18 | { 19 | new Box 20 | { 21 | RelativeSizeAxes = Axes.Both, 22 | Colour = Color4.Black, 23 | }, 24 | }; 25 | 26 | AddGame(new OsuGame()); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer.Tests/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "VisualTests (Debug)", 6 | "type": "coreclr", 7 | "request": "launch", 8 | "program": "dotnet", 9 | "args": [ 10 | "${workspaceRoot}/bin/Debug/net8.0/osu.Game.Rulesets.PumpTrainer.Tests.dll" 11 | ], 12 | "cwd": "${workspaceRoot}", 13 | "preLaunchTask": "Build (Debug)", 14 | "env": {}, 15 | "console": "internalConsole" 16 | }, 17 | { 18 | "name": "VisualTests (Release)", 19 | "type": "coreclr", 20 | "request": "launch", 21 | "program": "dotnet", 22 | "args": [ 23 | "${workspaceRoot}/bin/Release/net8.0/osu.Game.Rulesets.PumpTrainer.Tests.dll" 24 | ], 25 | "cwd": "${workspaceRoot}", 26 | "preLaunchTask": "Build (Release)", 27 | "env": {}, 28 | "console": "internalConsole" 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Objects/Drawables/DrawableTopRowHitObject.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Allocation; 2 | using osu.Framework.Graphics; 3 | using osu.Framework.Graphics.Containers; 4 | using osu.Framework.Graphics.Textures; 5 | using osuTK; 6 | using osuTK.Graphics; 7 | 8 | namespace osu.Game.Rulesets.PumpTrainer.Objects.Drawables 9 | { 10 | public partial class DrawableTopRowHitObject : CompositeDrawable 11 | { 12 | private PumpTrainerHitObject hitObject; 13 | 14 | public DrawableTopRowHitObject(PumpTrainerHitObject hitObject) 15 | : base() 16 | { 17 | this.hitObject = hitObject; 18 | Size = new Vector2(DrawablePumpTrainerHitObject.WIDTH); 19 | 20 | Colour = Color4.Gray; 21 | } 22 | 23 | [BackgroundDependencyLoader] 24 | private void load(TextureStore textures) 25 | { 26 | AddInternal(hitObject.GetAssociatedSprite(textures, true)); 27 | } 28 | 29 | public void FlashOnHit() 30 | { 31 | this.FlashColour(Color4.White, 250, Easing.In); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer.Tests/osu.Game.Rulesets.PumpTrainer.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | osu.Game.Rulesets.PumpTrainer.Tests.VisualTestRunner 4 | 5 | 6 | 7 | 8 | 9 | false 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | WinExe 21 | net8.0 22 | osu.Game.Rulesets.PumpTrainer.Tests 23 | 24 | 25 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Replays/PumpTrainerFramedReplayInputHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using osu.Framework.Input.StateChanges; 7 | using osu.Game.Replays; 8 | using osu.Game.Rulesets.Replays; 9 | 10 | namespace osu.Game.Rulesets.PumpTrainer.Replays 11 | { 12 | public class PumpTrainerFramedReplayInputHandler : FramedReplayInputHandler 13 | { 14 | public PumpTrainerFramedReplayInputHandler(Replay replay) 15 | : base(replay) 16 | { 17 | } 18 | 19 | protected override bool IsImportant(PumpTrainerReplayFrame frame) => frame.Actions.Any(); 20 | 21 | protected override void CollectReplayInputs(List inputs) 22 | { 23 | inputs.Add(new ReplayState 24 | { 25 | PressedActions = CurrentFrame?.Actions ?? new List(), 26 | }); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/ExcludeColumns/PumpTrainerModExcludeColumn.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Localisation; 2 | using osu.Game.Beatmaps; 3 | using osu.Game.Rulesets.Mods; 4 | using osu.Game.Rulesets.PumpTrainer.Beatmaps; 5 | using osu.Game.Rulesets.PumpTrainer.Objects; 6 | 7 | namespace osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns 8 | { 9 | public abstract class PumpTrainerModExcludeColumn : Mod, IApplicableToBeatmapConverter 10 | { 11 | public override string Name => "Exclude " + ExcludedColumn.ToString(); 12 | public override string Acronym => ExcludedColumn.ToString().Substring(1); 13 | public override LocalisableString Description => "Excludes the column " + ExcludedColumn + "."; 14 | public override double ScoreMultiplier => 1; 15 | public override ModType Type => ModType.Conversion; 16 | 17 | public abstract Column ExcludedColumn { get; } 18 | 19 | public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter) 20 | { 21 | var pumpBeatmapConverter = (PumpTrainerBeatmapConverter)beatmapConverter; 22 | 23 | pumpBeatmapConverter.HitObjectGenerator.Settings.AllowedColumns.Remove(ExcludedColumn); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/PumpTrainerModSeeded.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Bindables; 2 | using osu.Framework.Localisation; 3 | using osu.Game.Beatmaps; 4 | using osu.Game.Configuration; 5 | using osu.Game.Rulesets.Mods; 6 | using osu.Game.Rulesets.PumpTrainer.Beatmaps; 7 | 8 | namespace osu.Game.Rulesets.PumpTrainer.Mods 9 | { 10 | public class PumpTrainerModSeeded : Mod, IApplicableToBeatmapConverter 11 | { 12 | [SettingSource("Seed")] 13 | public Bindable Seed { get; } = new BindableInt(0) 14 | { 15 | MinValue = 0, 16 | MaxValue = 100, 17 | }; 18 | 19 | public override string Name => "Seeded"; 20 | public override string Acronym => "SD"; 21 | public override LocalisableString Description => "Play consistently generated charts."; 22 | public override double ScoreMultiplier => 1; 23 | public override ModType Type => ModType.Automation; 24 | 25 | public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter) 26 | { 27 | var pumpBeatmapConverter = (PumpTrainerBeatmapConverter)beatmapConverter; 28 | 29 | pumpBeatmapConverter.HitObjectGenerator.Seed = Seed.Value; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Replays/PumpTrainerAutoGenerator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Rulesets.PumpTrainer.Objects; 6 | using osu.Game.Rulesets.Replays; 7 | 8 | namespace osu.Game.Rulesets.PumpTrainer.Replays 9 | { 10 | public class PumpTrainerAutoGenerator : AutoGenerator 11 | { 12 | public new Beatmap Beatmap => (Beatmap)base.Beatmap; 13 | 14 | public PumpTrainerAutoGenerator(IBeatmap beatmap) 15 | : base(beatmap) 16 | { 17 | } 18 | 19 | protected override void GenerateFrames() 20 | { 21 | Frames.Add(new PumpTrainerReplayFrame()); 22 | 23 | foreach (PumpTrainerHitObject hitObject in Beatmap.HitObjects) 24 | { 25 | Frames.Add(new PumpTrainerReplayFrame 26 | { 27 | Time = hitObject.StartTime, 28 | Actions = [PumpTrainerKeybindConversions.COLUMN_TO_ACTION[hitObject.Column]], 29 | }); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/PumpTrainerDifficultyCalculator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using osu.Game.Beatmaps; 8 | using osu.Game.Rulesets.Difficulty; 9 | using osu.Game.Rulesets.Difficulty.Preprocessing; 10 | using osu.Game.Rulesets.Difficulty.Skills; 11 | using osu.Game.Rulesets.Mods; 12 | 13 | namespace osu.Game.Rulesets.PumpTrainer 14 | { 15 | public class PumpTrainerDifficultyCalculator : DifficultyCalculator 16 | { 17 | public PumpTrainerDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) 18 | : base(ruleset, beatmap) 19 | { 20 | } 21 | 22 | protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) 23 | { 24 | return new DifficultyAttributes(mods, 0); 25 | } 26 | 27 | protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty(); 28 | 29 | protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) => Array.Empty(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/PumpTrainerKeybindConversions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.Immutable; 3 | using osu.Game.Rulesets.PumpTrainer.Objects; 4 | 5 | namespace osu.Game.Rulesets.PumpTrainer 6 | { 7 | public static class PumpTrainerKeybindConversions 8 | { 9 | public static readonly ImmutableDictionary ACTION_TO_COLUMN = new Dictionary() 10 | { 11 | { PumpTrainerAction.P1DL, Column.P1DL }, 12 | { PumpTrainerAction.P1UL, Column.P1UL }, 13 | { PumpTrainerAction.P1C, Column.P1C }, 14 | { PumpTrainerAction.P1UR, Column.P1UR }, 15 | { PumpTrainerAction.P1DR, Column.P1DR }, 16 | { PumpTrainerAction.P2DL, Column.P2DL }, 17 | { PumpTrainerAction.P2UL, Column.P2UL }, 18 | { PumpTrainerAction.P2C, Column.P2C }, 19 | { PumpTrainerAction.P2UR, Column.P2UR }, 20 | { PumpTrainerAction.P2DR, Column.P2DR }, 21 | }.ToImmutableDictionary(); 22 | 23 | public static readonly ImmutableDictionary COLUMN_TO_ACTION; 24 | 25 | static PumpTrainerKeybindConversions() 26 | { 27 | COLUMN_TO_ACTION = ACTION_TO_COLUMN.ToImmutableDictionary(i => i.Value, i => i.Key); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer.Tests/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Build (Debug)", 8 | "type": "shell", 9 | "command": "dotnet", 10 | "args": [ 11 | "build", 12 | "--no-restore", 13 | "osu.Game.Rulesets.PumpTrainer.Tests.csproj", 14 | "-p:GenerateFullPaths=true", 15 | "-m", 16 | "-verbosity:m" 17 | ], 18 | "group": "build", 19 | "problemMatcher": "$msCompile" 20 | }, 21 | { 22 | "label": "Build (Release)", 23 | "type": "shell", 24 | "command": "dotnet", 25 | "args": [ 26 | "build", 27 | "--no-restore", 28 | "osu.Game.Rulesets.PumpTrainer.Tests.csproj", 29 | "-p:Configuration=Release", 30 | "-p:GenerateFullPaths=true", 31 | "-m", 32 | "-verbosity:m" 33 | ], 34 | "group": "build", 35 | "problemMatcher": "$msCompile" 36 | }, 37 | { 38 | "label": "Restore", 39 | "type": "shell", 40 | "command": "dotnet", 41 | "args": [ 42 | "restore" 43 | ], 44 | "problemMatcher": [] 45 | } 46 | ] 47 | } -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/PumpTrainerModDiagonalSkips.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using osu.Framework.Bindables; 3 | using osu.Framework.Localisation; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Configuration; 6 | using osu.Game.Rulesets.Mods; 7 | using osu.Game.Rulesets.PumpTrainer.Beatmaps; 8 | using osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns; 9 | 10 | namespace osu.Game.Rulesets.PumpTrainer.Mods 11 | { 12 | public class PumpTrainerModDiagonalSkips : Mod, IApplicableToBeatmapConverter 13 | { 14 | [SettingSource("Frequency")] 15 | public Bindable DiagonalSkipFrequency { get; } = new BindableDouble(0.8) 16 | { 17 | MinValue = 0.1, 18 | MaxValue = 1.0, 19 | Default = 0.8, 20 | Precision = 0.1, 21 | }; 22 | 23 | public override string Name => "[P1Single+] Diagonal Skips"; 24 | public override string Acronym => "DD"; 25 | public override LocalisableString Description => "Twists across a single pad that skip over the center panel.\n"; 26 | public override double ScoreMultiplier => 1; 27 | public override ModType Type => ModType.DifficultyIncrease; 28 | public override Type[] IncompatibleMods => new Type[] 29 | { 30 | typeof(PumpTrainerModExcludeP1DL), 31 | typeof(PumpTrainerModExcludeP1UL), 32 | typeof(PumpTrainerModExcludeP1C), 33 | typeof(PumpTrainerModExcludeP1UR), 34 | typeof(PumpTrainerModExcludeP1DR), 35 | }; 36 | 37 | public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter) 38 | { 39 | var pumpBeatmapConverter = (PumpTrainerBeatmapConverter)beatmapConverter; 40 | 41 | pumpBeatmapConverter.HitObjectGenerator.Settings.DiagonalSkipFrequency = DiagonalSkipFrequency.Value; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/UI/DrawablePumpTrainerRuleset.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System.Collections.Generic; 5 | using osu.Framework.Allocation; 6 | using osu.Framework.Input; 7 | using osu.Game.Beatmaps; 8 | using osu.Game.Input.Handlers; 9 | using osu.Game.Replays; 10 | using osu.Game.Rulesets.Mods; 11 | using osu.Game.Rulesets.Objects.Drawables; 12 | using osu.Game.Rulesets.PumpTrainer.Objects; 13 | using osu.Game.Rulesets.PumpTrainer.Objects.Drawables; 14 | using osu.Game.Rulesets.PumpTrainer.Replays; 15 | using osu.Game.Rulesets.UI; 16 | using osu.Game.Rulesets.UI.Scrolling; 17 | 18 | namespace osu.Game.Rulesets.PumpTrainer.UI 19 | { 20 | [Cached] 21 | public partial class DrawablePumpTrainerRuleset : DrawableScrollingRuleset 22 | { 23 | public DrawablePumpTrainerRuleset(PumpTrainerRuleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) 24 | : base(ruleset, beatmap, mods) 25 | { 26 | Direction.Value = ScrollingDirection.Up; 27 | TimeRange.Value = 5000; 28 | // still have no idea what this number means. but apparently you can use F3 and F4 to adjust scroll speed 29 | } 30 | 31 | protected override Playfield CreatePlayfield() => new PumpTrainerPlayfield(); 32 | 33 | protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new PumpTrainerFramedReplayInputHandler(replay); 34 | 35 | public override DrawableHitObject CreateDrawableRepresentation(PumpTrainerHitObject h) => 36 | new DrawablePumpTrainerHitObject(h, (PumpTrainerPlayfield)Playfield); 37 | 38 | protected override PassThroughInputManager CreateInputManager() => new PumpTrainerInputManager(Ruleset?.RulesetInfo); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Beatmaps/PumpTrainerHitObjectGeneratorSettingsPerHitObject.cs: -------------------------------------------------------------------------------- 1 | namespace osu.Game.Rulesets.PumpTrainer.Beatmaps 2 | { 3 | /// 4 | /// By default, all the fields in this class are set to maximize the frequency of each pattern. 5 | /// 6 | public class PumpTrainerHitObjectGeneratorSettingsPerHitObject 7 | { 8 | /// 9 | /// 0 to 1 determining how frequently to generate a corner pattern. Higher means more likely. 10 | /// Corner patterns include 90 degree patterns and V shape patterns (see examples below). 11 | /// (Corner patterns are usually banned on sixteenth rhythms.) 12 | /// Examples: 13 | /// Starting left: UL, UR, DR (and 7 other variations per singles panel) - 90 degrees across a single panel. 14 | /// Starting left: UL, DR, UR (and 7 other variations per singles panel) - V shape across a single panel. 15 | /// 16 | public double CornersFrequency = 1; 17 | 18 | /// 19 | /// 0 to 1 determining how frequently to generate 3 horizontally adjacent notes that go in one direction (i.e. only left, or only right), 20 | /// and are not all on the same single pad. Higher means more likely. 21 | /// Example: P1C --> P1DR --> P2UL 22 | /// NON-example: P1C --> P2UL --> P2DL (because the notes do not go in one direction) 23 | /// NON-example: P1C --> P2UL --> P1DR (because the notes do not go in one direction) 24 | /// NON-example: P1UL --> P1C --> P1UR (because the notes only span a single pad) 25 | /// NON-example: P1C --> P1UR --> P2C (because the notes are not horizontally adjacent. This case is actually always banned, no matter what mods are on.) 26 | /// 27 | public double HorizontalTripleFrequency = 1; 28 | 29 | public PumpTrainerHitObjectGeneratorSettingsPerHitObject() 30 | { 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/PumpTrainerModNoFarColumns.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Bindables; 2 | using osu.Framework.Localisation; 3 | using osu.Game.Beatmaps; 4 | using osu.Game.Configuration; 5 | using osu.Game.Rulesets.Mods; 6 | using osu.Game.Rulesets.PumpTrainer.Beatmaps; 7 | using osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns; 8 | using System; 9 | 10 | namespace osu.Game.Rulesets.PumpTrainer.Mods 11 | { 12 | public class PumpTrainerModNoFarColumns : Mod, IApplicableToBeatmapConverter 13 | { 14 | [SettingSource("Frequency")] 15 | public Bindable FarColumnsFrequency { get; } = new BindableDouble(0.5) 16 | { 17 | MinValue = 0, 18 | MaxValue = 0.9, 19 | Default = 0.5, 20 | Precision = 0.1, 21 | }; 22 | 23 | public override string Name => "[Half-Dbl+] No Far Columns"; 24 | public override string Acronym => "D"; 25 | public override LocalisableString Description => 26 | "Reduces the frequency of two physically non-adjacent consecutive notes in the half-doubles region."; 27 | public override double ScoreMultiplier => 1; 28 | public override ModType Type => ModType.DifficultyReduction; 29 | public override Type[] IncompatibleMods => new Type[] 30 | { 31 | typeof(PumpTrainerModExcludeP1C), 32 | typeof(PumpTrainerModExcludeP1UR), 33 | typeof(PumpTrainerModExcludeP1DR), 34 | typeof(PumpTrainerModExcludeP2DL), 35 | typeof(PumpTrainerModExcludeP2UL), 36 | typeof(PumpTrainerModExcludeP2C), 37 | }; 38 | 39 | public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter) 40 | { 41 | var pumpBeatmapConverter = (PumpTrainerBeatmapConverter)beatmapConverter; 42 | 43 | pumpBeatmapConverter.HitObjectGenerator.Settings.FarColumnsFrequency = FarColumnsFrequency.Value; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/PumpTrainerModCornersOnSixteenths.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Bindables; 2 | using osu.Framework.Localisation; 3 | using System; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Configuration; 6 | using osu.Game.Rulesets.Mods; 7 | using osu.Game.Rulesets.PumpTrainer.Beatmaps; 8 | using osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns; 9 | 10 | namespace osu.Game.Rulesets.PumpTrainer.Mods 11 | { 12 | public class PumpTrainerModCornersOnSixteenths : Mod, IApplicableToBeatmapConverter 13 | { 14 | [SettingSource("Frequency")] 15 | public Bindable CornersOnSixteenthsFrequency { get; } = new BindableDouble(0.8) 16 | { 17 | MinValue = 0.1, 18 | MaxValue = 1.0, 19 | Default = 0.8, 20 | Precision = 0.1, 21 | }; 22 | 23 | public override string Name => "[P1Single+] Corners on 1/4s"; 24 | public override string Acronym => "CO"; 25 | public override LocalisableString Description => 26 | "90-degree and V-twists across a single pad.\n" + 27 | "These are normally banned for rhythms 1/4 and faster."; 28 | public override double ScoreMultiplier => 1; 29 | public override ModType Type => ModType.DifficultyIncrease; 30 | public override Type[] IncompatibleMods => new Type[] 31 | { 32 | typeof(PumpTrainerModExcludeP1DL), 33 | typeof(PumpTrainerModExcludeP1UL), 34 | typeof(PumpTrainerModExcludeP1C), 35 | typeof(PumpTrainerModExcludeP1UR), 36 | typeof(PumpTrainerModExcludeP1DR), 37 | }; 38 | 39 | public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter) 40 | { 41 | var pumpBeatmapConverter = (PumpTrainerBeatmapConverter)beatmapConverter; 42 | 43 | pumpBeatmapConverter.GeneratorSettingsForSixteenthRhythms.CornersFrequency = CornersOnSixteenthsFrequency.Value; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/PumpTrainerModHorizontalTriplesOnSixteenths.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using osu.Framework.Bindables; 3 | using osu.Framework.Localisation; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Configuration; 6 | using osu.Game.Rulesets.Mods; 7 | using osu.Game.Rulesets.PumpTrainer.Beatmaps; 8 | using osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns; 9 | 10 | namespace osu.Game.Rulesets.PumpTrainer.Mods 11 | { 12 | public class PumpTrainerModHorizontalTriplesOnSixteenths : Mod, IApplicableToBeatmapConverter 13 | { 14 | [SettingSource("Frequency")] 15 | public Bindable HorizontalTripleFrequency { get; } = new BindableDouble(0.8) 16 | { 17 | MinValue = 0.1, 18 | MaxValue = 1.0, 19 | Default = 0.8, 20 | Precision = 0.1, 21 | }; 22 | 23 | public override string Name => "[Half-Dbl+] Horiz-3's on 1/4s"; 24 | public override string Acronym => "3H"; 25 | public override LocalisableString Description => 26 | "Three consecutive notes in horizontally adjacent columns in a single direction.\n" + 27 | "These are normally banned for rhythms 1/4 and faster."; 28 | public override double ScoreMultiplier => 1; 29 | public override ModType Type => ModType.DifficultyIncrease; 30 | public override Type[] IncompatibleMods => new Type[] 31 | { 32 | typeof(PumpTrainerModExcludeP1C), 33 | typeof(PumpTrainerModExcludeP1UR), 34 | typeof(PumpTrainerModExcludeP1DR), 35 | typeof(PumpTrainerModExcludeP2DL), 36 | typeof(PumpTrainerModExcludeP2UL), 37 | typeof(PumpTrainerModExcludeP2C), 38 | }; 39 | 40 | public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter) 41 | { 42 | var pumpBeatmapConverter = (PumpTrainerBeatmapConverter)beatmapConverter; 43 | 44 | pumpBeatmapConverter.GeneratorSettingsForSixteenthRhythms.HorizontalTripleFrequency = HorizontalTripleFrequency.Value; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## What is this? 2 | 3 | This is a ruleset for [osu!](https://github.com/ppy/osu). It generates Pump It Up charts that are playable with two feet, from osu! beatmaps. 4 | 5 | The current the formula generates charts with: 6 | - No double-steps 7 | - No spins 8 | - No splits (consecutive notes have at most 1 panel horizontally between them) 9 | - No large horizontal travels (e.g. P2DL --> P1UR --> P1UL) 10 | - osu! slider rhythm simplification: 1/6 and 1/8 buzz sliders are treated as 1/4's, and long sliders are rounded down to the nearest 1/2 (e.g. 3/4 sliders are treated as 1/2) 11 | - For rhythms 1/4 and faster (overridable through mods): 12 | - No 90 degree twists (e.g. DL --> DR --> UR) 13 | - No horizontal travels (e.g. P1C --> P1UR --> P2DL) 14 | - Adjustable through mods: 15 | - Regular twists (e.g. C --> UL) 16 | - Large twists (e.g. P2DL --> P1C) 17 | - Diagonal twists (e.g. DL --> C --> UR) 18 | - Diagonal skips (e.g. UR --> DL) 19 | 20 | All examples above start with the left foot. See [this page](https://www.piucenter.com/skill) for more background. 21 | (The terminology I'm using here and in the code don't match exactly to that page.) 22 | 23 | ## How to install 24 | 25 | https://rulesets.info/install/rulesets 26 | 27 | The ruleset file is provided here: https://github.com/hwabis/pump-trainer/releases 28 | 29 | ## Tips 30 | 31 | - Keybinds: 32 | ``` 33 | Q E R Y 34 | S G 35 | Z C V N 36 | ``` 37 | - However, I believe playing with your feet with Autoplay mod is more fun. 38 | - f3 and f4 in-game to change scroll speed. This is a keybind in osu! itself, not a ruleset keybind. 39 | 40 | ## Example converted beatmaps 41 | 42 | Converted map: https://osu.ppy.sh/beatmapsets/2010589#osu/4183614 43 | 44 | ### Single 45 | 46 | https://github.com/user-attachments/assets/443fd2df-9c3f-4c19-bf72-c9ba25ae3e57 47 | 48 | ### Half-double 49 | 50 | https://github.com/user-attachments/assets/87712408-7cc8-42e1-b919-8e6acae75598 51 | 52 | ### Double with regular twists 53 | 54 | Converted map: https://osu.ppy.sh/beatmapsets/600303#osu/1310291 55 | 56 | https://github.com/user-attachments/assets/30c1f1d2-d591-476f-acda-669ef21f94d8 57 | -------------------------------------------------------------------------------- /app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | true 32 | 33 | 34 | 35 | 36 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/UI/PumpTrainerPlayfield.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System.Collections.Generic; 5 | using osu.Framework.Allocation; 6 | using osu.Framework.Graphics; 7 | using osu.Framework.Graphics.Containers; 8 | using osu.Framework.Graphics.Textures; 9 | using osu.Game.Rulesets.PumpTrainer.Objects; 10 | using osu.Game.Rulesets.PumpTrainer.Objects.Drawables; 11 | using osu.Game.Rulesets.UI.Scrolling; 12 | 13 | namespace osu.Game.Rulesets.PumpTrainer.UI 14 | { 15 | [Cached] 16 | public partial class PumpTrainerPlayfield : ScrollingPlayfield 17 | { 18 | public IReadOnlyList TopRowHitObjects; 19 | 20 | [BackgroundDependencyLoader] 21 | private void load(TextureStore textures) 22 | { 23 | Margin = new() 24 | { 25 | Top = 50, 26 | }; 27 | 28 | AddRangeInternal(new Drawable[] 29 | { 30 | new FillFlowContainer() 31 | { 32 | Direction = FillDirection.Horizontal, 33 | Anchor = Anchor.TopCentre, 34 | Origin = Anchor.TopCentre, 35 | AutoSizeAxes = Axes.Both, 36 | Children = TopRowHitObjects = 37 | [ 38 | new DrawableTopRowHitObject(new(Column.P1DL)), 39 | new DrawableTopRowHitObject(new(Column.P1UL)), 40 | new DrawableTopRowHitObject(new(Column.P1C)), 41 | new DrawableTopRowHitObject(new(Column.P1UR)), 42 | new DrawableTopRowHitObject(new(Column.P1DR)), 43 | new DrawableTopRowHitObject(new(Column.P2DL)), 44 | new DrawableTopRowHitObject(new(Column.P2UL)), 45 | new DrawableTopRowHitObject(new(Column.P2C)), 46 | new DrawableTopRowHitObject(new(Column.P2UR)), 47 | new DrawableTopRowHitObject(new(Column.P2DR)), 48 | ] 49 | }, 50 | HitObjectContainer, 51 | }); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Mods/PumpTrainerModHorizontalTwists.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Bindables; 2 | using osu.Framework.Localisation; 3 | using osu.Game.Beatmaps; 4 | using osu.Game.Configuration; 5 | using osu.Game.Rulesets.Mods; 6 | using osu.Game.Rulesets.PumpTrainer.Beatmaps; 7 | 8 | namespace osu.Game.Rulesets.PumpTrainer.Mods 9 | { 10 | public class PumpTrainerModHorizontalTwists : Mod, IApplicableToBeatmapConverter 11 | { 12 | [SettingSource("Twist Frequency")] 13 | public Bindable HorizontalTwistFrequency { get; } = new BindableDouble(0.8) 14 | { 15 | MinValue = 0.1, 16 | MaxValue = 1.0, 17 | Default = 0.8, 18 | Precision = 0.1, 19 | }; 20 | 21 | [SettingSource("[Half-Dbl+] Large Twists")] 22 | public Bindable IncludeLargeTwists { get; } = new BindableBool(false) 23 | { 24 | Default = false, 25 | }; 26 | 27 | [SettingSource("[P1Single+] Diagonal Twists")] 28 | public Bindable AllowDiagonalTwists { get; } = new BindableBool(false) 29 | { 30 | Default = false, 31 | }; 32 | 33 | public override string Name => "Horizontal Twists"; 34 | public override string Acronym => "TW"; 35 | public override LocalisableString Description => 36 | "Twists involving a center panel. Also enables other types of twists in mod customization."; 37 | public override double ScoreMultiplier => 1; 38 | public override ModType Type => ModType.DifficultyIncrease; 39 | 40 | public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter) 41 | { 42 | var pumpBeatmapConverter = (PumpTrainerBeatmapConverter)beatmapConverter; 43 | 44 | pumpBeatmapConverter.HitObjectGenerator.Settings.HorizontalTwistFrequency = HorizontalTwistFrequency.Value; 45 | 46 | if (IncludeLargeTwists.Value) 47 | { 48 | pumpBeatmapConverter.HitObjectGenerator.Settings.LargeTwistFrequency = HorizontalTwistFrequency.Value; 49 | } 50 | 51 | if (AllowDiagonalTwists.Value) 52 | { 53 | pumpBeatmapConverter.HitObjectGenerator.Settings.AllowDiagonalTwists = true; 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Beatmaps/PumpTrainerHitObjectGeneratorSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using osu.Game.Rulesets.PumpTrainer.Objects; 3 | 4 | namespace osu.Game.Rulesets.PumpTrainer.Beatmaps 5 | { 6 | public class PumpTrainerHitObjectGeneratorSettings 7 | { 8 | public List AllowedColumns = 9 | [Column.P1DL, Column.P1UL, Column.P1C, Column.P1UR, Column.P1DR, Column.P2DL, Column.P2UL, Column.P2C, Column.P2UR, Column.P2DR]; 10 | 11 | /// 12 | /// 0 to 1 determining how frequently to generate two notes that are in adjacent columns on the physical dance pad. 13 | /// One of the notes must be a center panel (aka they do not span across a center panel, aka they must be in the half-doubles region). 14 | /// Higher means more likely. 15 | /// Example starting left foot: P1C --> P2UL 16 | /// Example starting right foot: P2DL --> P1C 17 | /// NON-example starting left foot: P1DL --> P1DR 18 | /// 19 | public double FarColumnsFrequency = 1; 20 | 21 | /// 22 | /// 0 to 1 determining how frequently to generate a horizontal twist. Higher means more likely. 23 | /// Example starting left foot: UL --> C --> UR 24 | /// 25 | public double HorizontalTwistFrequency = 0; 26 | 27 | /// 28 | /// Determines whether to allow generating diagonal twists. 29 | /// This requires horizontal twists to be on (greater than 0) to have any effect. 30 | /// Example starting left foot: DL --> C --> UR 31 | /// 32 | public bool AllowDiagonalTwists = false; 33 | 34 | /// 35 | /// 0 to 1 determining how frequently to generate a diagonal skip. Higher means more likely. 36 | /// Example starting left foot: DR --> UL 37 | /// 38 | public double DiagonalSkipFrequency = 0; 39 | 40 | /// 41 | /// 0 to 1 determining how frequently to generate a large horizontal twist. Higher means more likely. 42 | /// This kind of twist is very rare. Example charts are Uranium D24 and See D20 (those are actually the only charts I know of that have this pattern lol). 43 | /// Example starting right foot: P1C --> P2UL 44 | /// 45 | public double LargeTwistFrequency = 0; 46 | 47 | public PumpTrainerHitObjectGeneratorSettings() 48 | { 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Objects/Drawables/DrawablePumpTrainerHitObject.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using osu.Framework.Allocation; 5 | using osu.Framework.Graphics; 6 | using osu.Framework.Graphics.Textures; 7 | using osu.Framework.Input.Bindings; 8 | using osu.Framework.Input.Events; 9 | using osu.Game.Rulesets.Objects.Drawables; 10 | using osu.Game.Rulesets.PumpTrainer.UI; 11 | using osu.Game.Rulesets.Scoring; 12 | using osuTK; 13 | 14 | namespace osu.Game.Rulesets.PumpTrainer.Objects.Drawables 15 | { 16 | public partial class DrawablePumpTrainerHitObject : DrawableHitObject, IKeyBindingHandler 17 | { 18 | public const int WIDTH = 80; 19 | 20 | private DrawableTopRowHitObject correspondingTopRowHitObject; 21 | 22 | public DrawablePumpTrainerHitObject(PumpTrainerHitObject hitObject, PumpTrainerPlayfield playfield) 23 | : base(hitObject) 24 | { 25 | Size = new Vector2(WIDTH); 26 | Origin = Anchor.TopCentre; 27 | Anchor = Anchor.TopCentre; 28 | 29 | // Indexes 0 to 9 so midpoint is 4.5 30 | X = (float)((int)HitObject.Column - 4.5) * WIDTH; 31 | 32 | correspondingTopRowHitObject = playfield.TopRowHitObjects[(int)HitObject.Column]; 33 | } 34 | 35 | [BackgroundDependencyLoader] 36 | private void load(TextureStore textures) 37 | { 38 | AddInternal(HitObject.GetAssociatedSprite(textures, false)); 39 | } 40 | 41 | protected override void CheckForResult(bool userTriggered, double timeOffset) 42 | { 43 | if (!userTriggered) 44 | { 45 | if (!HitObject.HitWindows.CanBeHit(timeOffset)) 46 | { 47 | ApplyMinResult(); 48 | } 49 | 50 | return; 51 | } 52 | 53 | var result = HitObject.HitWindows.ResultFor(timeOffset); 54 | 55 | if (result == HitResult.None) 56 | return; 57 | 58 | ApplyResult(result); 59 | correspondingTopRowHitObject.FlashOnHit(); 60 | } 61 | 62 | protected override void UpdateHitStateTransforms(ArmedState state) 63 | { 64 | switch (state) 65 | { 66 | case ArmedState.Hit: 67 | this.FadeOut().Expire(); 68 | break; 69 | 70 | case ArmedState.Miss: 71 | // todo ? 72 | break; 73 | } 74 | } 75 | 76 | public bool OnPressed(KeyBindingPressEvent e) 77 | { 78 | if (PumpTrainerKeybindConversions.ACTION_TO_COLUMN[e.Action] == HitObject.Column) 79 | { 80 | return UpdateResult(true); 81 | } 82 | 83 | return false; 84 | } 85 | 86 | public void OnReleased(KeyBindingReleaseEvent e) 87 | { 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Objects/PumpTrainerHitObject.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System.Text; 5 | using osu.Framework.Graphics; 6 | using osu.Framework.Graphics.Sprites; 7 | using osu.Framework.Graphics.Textures; 8 | using osu.Game.Rulesets.Judgements; 9 | using osu.Game.Rulesets.Objects; 10 | 11 | namespace osu.Game.Rulesets.PumpTrainer.Objects 12 | { 13 | public class PumpTrainerHitObject : HitObject 14 | { 15 | public override Judgement CreateJudgement() => new Judgement(); 16 | 17 | public Foot IntendedFoot; 18 | public Column Column; 19 | 20 | public PumpTrainerHitObject(Column column) 21 | : base() 22 | { 23 | Column = column; 24 | } 25 | 26 | // does this belong here? 27 | public Sprite GetAssociatedSprite(TextureStore textures, bool gray) 28 | { 29 | StringBuilder textureString = new(); 30 | 31 | switch (Column) 32 | { 33 | case Column.P1DL: 34 | case Column.P1DR: 35 | case Column.P2DL: 36 | case Column.P2DR: 37 | textureString.Append("DL"); 38 | break; 39 | case Column.P1UL: 40 | case Column.P1UR: 41 | case Column.P2UL: 42 | case Column.P2UR: 43 | textureString.Append("UL"); 44 | break; 45 | default: 46 | textureString.Append("C"); 47 | break; 48 | } 49 | 50 | if (gray) 51 | { 52 | textureString.Append("-gray"); 53 | } 54 | 55 | Sprite sprite = new() 56 | { 57 | RelativeSizeAxes = Axes.Both, 58 | Origin = Anchor.TopCentre, 59 | Anchor = Anchor.TopCentre, 60 | Texture = textures.Get(textureString.ToString()), 61 | // In PIU, there is a slight overlap between hitobjects that are directly next to each other 62 | // so bloat the sprite by a little 63 | Scale = new(1.08f), 64 | }; 65 | 66 | 67 | switch (Column) 68 | { 69 | case Column.P1UR: 70 | case Column.P1DR: 71 | case Column.P2UR: 72 | case Column.P2DR: 73 | sprite.Scale = new(-sprite.Scale.X, sprite.Scale.Y); 74 | break; 75 | } 76 | 77 | return sprite; 78 | } 79 | } 80 | 81 | public enum Column 82 | { 83 | P1DL, 84 | P1UL, 85 | P1C, 86 | P1UR, 87 | P1DR, 88 | P2DL, 89 | P2UL, 90 | P2C, 91 | P2UR, 92 | P2DR, 93 | } 94 | 95 | public enum Foot 96 | { 97 | Left, 98 | Right, 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29123.88 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.PumpTrainer", "osu.Game.Rulesets.PumpTrainer\osu.Game.Rulesets.PumpTrainer.csproj", "{5AE1F0F1-DAFA-46E7-959C-DA233B7C87E9}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.PumpTrainer.Tests", "osu.Game.Rulesets.PumpTrainer.Tests\osu.Game.Rulesets.PumpTrainer.Tests.csproj", "{B4577C85-CB83-462A-BCE3-22FFEB16311D}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | VisualTests|Any CPU = VisualTests|Any CPU 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {5AE1F0F1-DAFA-46E7-959C-DA233B7C87E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {5AE1F0F1-DAFA-46E7-959C-DA233B7C87E9}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {5AE1F0F1-DAFA-46E7-959C-DA233B7C87E9}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {5AE1F0F1-DAFA-46E7-959C-DA233B7C87E9}.Release|Any CPU.Build.0 = Release|Any CPU 21 | {5AE1F0F1-DAFA-46E7-959C-DA233B7C87E9}.VisualTests|Any CPU.ActiveCfg = Release|Any CPU 22 | {5AE1F0F1-DAFA-46E7-959C-DA233B7C87E9}.VisualTests|Any CPU.Build.0 = Release|Any CPU 23 | {B4577C85-CB83-462A-BCE3-22FFEB16311D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {B4577C85-CB83-462A-BCE3-22FFEB16311D}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {B4577C85-CB83-462A-BCE3-22FFEB16311D}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {B4577C85-CB83-462A-BCE3-22FFEB16311D}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {B4577C85-CB83-462A-BCE3-22FFEB16311D}.VisualTests|Any CPU.ActiveCfg = Debug|Any CPU 28 | {B4577C85-CB83-462A-BCE3-22FFEB16311D}.VisualTests|Any CPU.Build.0 = Debug|Any CPU 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | GlobalSection(NestedProjects) = preSolution 34 | EndGlobalSection 35 | GlobalSection(ExtensibilityGlobals) = postSolution 36 | SolutionGuid = {671B0BEC-2403-45B0-9357-2C97CC517668} 37 | EndGlobalSection 38 | GlobalSection(MonoDevelopProperties) = preSolution 39 | Policies = $0 40 | $0.TextStylePolicy = $1 41 | $1.EolMarker = Windows 42 | $1.inheritsSet = VisualStudio 43 | $1.inheritsScope = text/plain 44 | $1.scope = text/x-csharp 45 | $0.CSharpFormattingPolicy = $2 46 | $2.IndentSwitchSection = True 47 | $2.NewLinesForBracesInProperties = True 48 | $2.NewLinesForBracesInAccessors = True 49 | $2.NewLinesForBracesInAnonymousMethods = True 50 | $2.NewLinesForBracesInControlBlocks = True 51 | $2.NewLinesForBracesInAnonymousTypes = True 52 | $2.NewLinesForBracesInObjectCollectionArrayInitializers = True 53 | $2.NewLinesForBracesInLambdaExpressionBody = True 54 | $2.NewLineForElse = True 55 | $2.NewLineForCatch = True 56 | $2.NewLineForFinally = True 57 | $2.NewLineForMembersInObjectInit = True 58 | $2.NewLineForMembersInAnonymousTypes = True 59 | $2.NewLineForClausesInQuery = True 60 | $2.SpacingAfterMethodDeclarationName = False 61 | $2.SpaceAfterMethodCallName = False 62 | $2.SpaceBeforeOpenSquareBracket = False 63 | $2.inheritsSet = Mono 64 | $2.inheritsScope = text/x-csharp 65 | $2.scope = text/x-csharp 66 | EndGlobalSection 67 | GlobalSection(MonoDevelopProperties) = preSolution 68 | Policies = $0 69 | $0.TextStylePolicy = $1 70 | $1.EolMarker = Windows 71 | $1.inheritsSet = VisualStudio 72 | $1.inheritsScope = text/plain 73 | $1.scope = text/x-csharp 74 | $0.CSharpFormattingPolicy = $2 75 | $2.IndentSwitchSection = True 76 | $2.NewLinesForBracesInProperties = True 77 | $2.NewLinesForBracesInAccessors = True 78 | $2.NewLinesForBracesInAnonymousMethods = True 79 | $2.NewLinesForBracesInControlBlocks = True 80 | $2.NewLinesForBracesInAnonymousTypes = True 81 | $2.NewLinesForBracesInObjectCollectionArrayInitializers = True 82 | $2.NewLinesForBracesInLambdaExpressionBody = True 83 | $2.NewLineForElse = True 84 | $2.NewLineForCatch = True 85 | $2.NewLineForFinally = True 86 | $2.NewLineForMembersInObjectInit = True 87 | $2.NewLineForMembersInAnonymousTypes = True 88 | $2.NewLineForClausesInQuery = True 89 | $2.SpacingAfterMethodDeclarationName = False 90 | $2.SpaceAfterMethodCallName = False 91 | $2.SpaceBeforeOpenSquareBracket = False 92 | $2.inheritsSet = Mono 93 | $2.inheritsScope = text/x-csharp 94 | $2.scope = text/x-csharp 95 | EndGlobalSection 96 | EndGlobal 97 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/PumpTrainerRuleset.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using osu.Framework.Graphics; 7 | using osu.Framework.Graphics.Sprites; 8 | using osu.Framework.Input.Bindings; 9 | using osu.Game.Beatmaps; 10 | using osu.Game.Graphics; 11 | using osu.Game.Rulesets.Difficulty; 12 | using osu.Game.Rulesets.Mods; 13 | using osu.Game.Rulesets.PumpTrainer.Beatmaps; 14 | using osu.Game.Rulesets.PumpTrainer.Mods; 15 | using osu.Game.Rulesets.PumpTrainer.Mods.ExcludeColumns; 16 | using osu.Game.Rulesets.PumpTrainer.UI; 17 | using osu.Game.Rulesets.UI; 18 | 19 | namespace osu.Game.Rulesets.PumpTrainer 20 | { 21 | public class PumpTrainerRuleset : Ruleset 22 | { 23 | public override string Description => "Pump It Up!"; 24 | 25 | public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => new DrawablePumpTrainerRuleset(this, beatmap, mods); 26 | 27 | public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new PumpTrainerBeatmapConverter(beatmap, this); 28 | 29 | // todo yeah no this is impossible 30 | public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new PumpTrainerDifficultyCalculator(RulesetInfo, beatmap); 31 | 32 | public override IEnumerable GetModsFor(ModType type) 33 | { 34 | switch (type) 35 | { 36 | case ModType.DifficultyReduction: 37 | return new Mod[] 38 | { 39 | new PumpTrainerModNoFarColumns(), 40 | new PumpTrainerModHalfTime(), 41 | }; 42 | 43 | case ModType.DifficultyIncrease: 44 | return new Mod[] 45 | { 46 | new PumpTrainerModHorizontalTwists(), 47 | new PumpTrainerModDiagonalSkips(), 48 | new PumpTrainerModCornersOnSixteenths(), 49 | new PumpTrainerModHorizontalTriplesOnSixteenths(), 50 | new PumpTrainerModDoubleTime(), 51 | }; 52 | 53 | case ModType.Conversion: 54 | return new Mod[] 55 | { 56 | new PumpTrainerModExcludeP1DL(), 57 | new PumpTrainerModExcludeP1UL(), 58 | new PumpTrainerModExcludeP1C(), 59 | new PumpTrainerModExcludeP1UR(), 60 | new PumpTrainerModExcludeP1DR(), 61 | new PumpTrainerModExcludeP2DL(), 62 | new PumpTrainerModExcludeP2UL(), 63 | new PumpTrainerModExcludeP2C(), 64 | new PumpTrainerModExcludeP2UR(), 65 | new PumpTrainerModExcludeP2DR(), 66 | }; 67 | 68 | case ModType.Automation: 69 | return new Mod[] 70 | { 71 | new PumpTrainerModAutoplay(), 72 | new PumpTrainerModSeeded(), 73 | }; 74 | 75 | default: 76 | return Array.Empty(); 77 | } 78 | } 79 | 80 | public override string ShortName => "pumptrainer"; 81 | 82 | public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] 83 | { 84 | new KeyBinding(InputKey.Z, PumpTrainerAction.P1DL), 85 | new KeyBinding(InputKey.Q, PumpTrainerAction.P1UL), 86 | new KeyBinding(InputKey.S, PumpTrainerAction.P1C), 87 | new KeyBinding(InputKey.E, PumpTrainerAction.P1UR), 88 | new KeyBinding(InputKey.C, PumpTrainerAction.P1DR), 89 | new KeyBinding(InputKey.V, PumpTrainerAction.P2DL), 90 | new KeyBinding(InputKey.R, PumpTrainerAction.P2UL), 91 | new KeyBinding(InputKey.G, PumpTrainerAction.P2C), 92 | new KeyBinding(InputKey.Y, PumpTrainerAction.P2UR), 93 | new KeyBinding(InputKey.N, PumpTrainerAction.P2DR), 94 | }; 95 | 96 | // TODO make an actual icon like an arrow or something. 97 | // Apparently according to the tau developers, there's no good way to do the resource texture store stuff (???) 98 | // so that's my excuse for putting this off 99 | public override Drawable CreateIcon() => new SpriteText 100 | { 101 | Anchor = Anchor.Centre, 102 | Origin = Anchor.Centre, 103 | Text = ShortName[0].ToString(), 104 | Font = OsuFont.Default.With(size: 18), 105 | }; 106 | 107 | // Leave this line intact. It will bake the correct version into the ruleset on each build/release. 108 | public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Beatmaps/PumpTrainerBeatmapConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System.Collections.Generic; 5 | using System.Threading; 6 | using osu.Game.Beatmaps; 7 | using osu.Game.Beatmaps.ControlPoints; 8 | using osu.Game.Rulesets.Objects; 9 | using osu.Game.Rulesets.Objects.Types; 10 | using osu.Game.Rulesets.PumpTrainer.Objects; 11 | 12 | namespace osu.Game.Rulesets.PumpTrainer.Beatmaps 13 | { 14 | public class PumpTrainerBeatmapConverter : BeatmapConverter 15 | { 16 | public PumpTrainerHitObjectGenerator HitObjectGenerator = new(); 17 | 18 | // Initialized with values that minimize the per-(hit object) patterns 19 | public PumpTrainerHitObjectGeneratorSettingsPerHitObject GeneratorSettingsForSixteenthRhythms = new() 20 | { 21 | CornersFrequency = 0, 22 | HorizontalTripleFrequency = 0, 23 | }; 24 | 25 | private double timeOfPreviousPumpHitObject = 0; 26 | private const double rounding_error = 5; // Use this rounding error "generously" for '<=' and '>=', and "not generously" for '<' and '>' 27 | 28 | public PumpTrainerBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) 29 | : base(beatmap, ruleset) 30 | { 31 | } 32 | 33 | public override bool CanConvert() => true; 34 | 35 | protected override IEnumerable ConvertHitObject(HitObject original, IBeatmap beatmap, CancellationToken cancellationToken) 36 | { 37 | if (HitObjectGenerator.Settings.AllowedColumns.Count <= 1) 38 | { 39 | yield break; 40 | } 41 | 42 | yield return getNextHitObject(original.StartTime, beatmap); 43 | 44 | if (original is IHasRepeats hasRepeats) 45 | { 46 | // This is a slider. (Even a slider with no repeats is IHasRepeats) 47 | 48 | int hitObjectsToReturnAfterFirst = hasRepeats.RepeatCount + 1; // +1 for the last hit object 49 | 50 | double durationBetweenHitObjects = (hasRepeats.EndTime - original.StartTime) / hitObjectsToReturnAfterFirst; 51 | 52 | TimingControlPoint currentTimingPoint = beatmap.ControlPointInfo.TimingPointAt(original.StartTime); 53 | 54 | if (hitObjectsToReturnAfterFirst > 1) 55 | { 56 | // This is a slider with at least one repeat. Apply buzz slider protection: 57 | // If the duration between the points is shorter than 1/4 of a beat, 58 | // fill the duration with notes 1/4 apart instead of with the original rhythm. 59 | 60 | if (durationBetweenHitObjects < currentTimingPoint.BeatLength / 4) 61 | { 62 | durationBetweenHitObjects = currentTimingPoint.BeatLength / 4; 63 | } 64 | 65 | for (double newHitObjectTime = original.StartTime + durationBetweenHitObjects; 66 | newHitObjectTime <= hasRepeats.EndTime + rounding_error; 67 | newHitObjectTime += durationBetweenHitObjects) 68 | { 69 | yield return getNextHitObject(newHitObjectTime, beatmap); 70 | } 71 | } 72 | else if (durationBetweenHitObjects >= currentTimingPoint.BeatLength / 4 - rounding_error) 73 | { 74 | // This is a slider with no repeats, and lasts at least a 1/4 beat (same as buzz slider protection). 75 | 76 | double hitObjectTimeForSliderEnd = hasRepeats.EndTime; 77 | 78 | if (durationBetweenHitObjects > currentTimingPoint.BeatLength / 2 + rounding_error) 79 | { 80 | // The slider is longer than 1/2 a beat. 81 | // Round down to the nearest 1/4. 82 | 83 | double newEndTime = original.StartTime; 84 | 85 | while (newEndTime < hitObjectTimeForSliderEnd) 86 | { 87 | newEndTime += currentTimingPoint.BeatLength / 2; 88 | } 89 | 90 | hitObjectTimeForSliderEnd = newEndTime - currentTimingPoint.BeatLength / 2; 91 | } 92 | else if (durationBetweenHitObjects > currentTimingPoint.BeatLength / 4 + rounding_error 93 | && durationBetweenHitObjects < currentTimingPoint.BeatLength / 2 - rounding_error) 94 | { 95 | // The slider length is longer than 1/4 but shorter than 1/2, so it has to be 3/8 or something. 96 | // Round down to the nearest 1/4. 97 | // Good test map: https://osu.ppy.sh/beatmapsets/929924#osu/2073258 98 | 99 | double newEndTime = original.StartTime; 100 | 101 | while (newEndTime < hitObjectTimeForSliderEnd) 102 | { 103 | newEndTime += currentTimingPoint.BeatLength / 4; 104 | } 105 | 106 | hitObjectTimeForSliderEnd = newEndTime - currentTimingPoint.BeatLength / 4; 107 | } 108 | 109 | yield return getNextHitObject(hitObjectTimeForSliderEnd, beatmap); 110 | } 111 | } 112 | } 113 | 114 | private PumpTrainerHitObject getNextHitObject(double pumpHitObjectTime, IBeatmap beatmap) 115 | { 116 | double lengthOfSixteenthRhythm = beatmap.ControlPointInfo.TimingPointAt(pumpHitObjectTime).BeatLength / 4; 117 | 118 | PumpTrainerHitObjectGeneratorSettingsPerHitObject perHitObjectSettingsToUse = 119 | pumpHitObjectTime - timeOfPreviousPumpHitObject <= lengthOfSixteenthRhythm + rounding_error ? 120 | GeneratorSettingsForSixteenthRhythms : new(); 121 | 122 | timeOfPreviousPumpHitObject = pumpHitObjectTime; 123 | 124 | return HitObjectGenerator.GetNextHitObject(pumpHitObjectTime, beatmap, perHitObjectSettingsToUse); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | bld/ 19 | [Bb]in/ 20 | [Oo]bj/ 21 | [Ll]og/ 22 | 23 | # Visual Studio 2015 cache/options directory 24 | .vs/ 25 | # Uncomment if you have tasks that create the project's static files in wwwroot 26 | #wwwroot/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | project.fragment.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | *.VC.db 83 | *.VC.VC.opendb 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | # TODO: Comment the next line if you want to checkin your web deploy settings 143 | # but database connection strings (with potential passwords) will be unencrypted 144 | *.pubxml 145 | *.publishproj 146 | 147 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 148 | # checkin your Azure Web App publish settings, but sensitive information contained 149 | # in these scripts will be unencrypted 150 | PublishScripts/ 151 | 152 | # NuGet Packages 153 | *.nupkg 154 | # The packages folder can be ignored because of Package Restore 155 | **/packages/* 156 | # except build/, which is used as an MSBuild target. 157 | !**/packages/build/ 158 | # Uncomment if necessary however generally it will be regenerated when needed 159 | #!**/packages/repositories.config 160 | # NuGet v3's project.json files produces more ignoreable files 161 | *.nuget.props 162 | *.nuget.targets 163 | 164 | # Microsoft Azure Build Output 165 | csx/ 166 | *.build.csdef 167 | 168 | # Microsoft Azure Emulator 169 | ecf/ 170 | rcf/ 171 | 172 | # Windows Store app package directories and files 173 | AppPackages/ 174 | BundleArtifacts/ 175 | Package.StoreAssociation.xml 176 | _pkginfo.txt 177 | 178 | # Visual Studio cache files 179 | # files ending in .cache can be ignored 180 | *.[Cc]ache 181 | # but keep track of directories ending in .cache 182 | !*.[Cc]ache/ 183 | 184 | # Others 185 | ClientBin/ 186 | ~$* 187 | *~ 188 | *.dbmdl 189 | *.dbproj.schemaview 190 | *.pfx 191 | *.publishsettings 192 | node_modules/ 193 | orleans.codegen.cs 194 | Resource.designer.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # Python Tools for Visual Studio (PTVS) 251 | __pycache__/ 252 | *.pyc 253 | 254 | # Cake # 255 | /tools/** 256 | /build/tools/** 257 | /build/temp/** 258 | 259 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 260 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 261 | 262 | # User-specific stuff 263 | .idea/**/workspace.xml 264 | .idea/**/tasks.xml 265 | .idea/**/usage.statistics.xml 266 | .idea/**/dictionaries 267 | .idea/**/shelf 268 | 269 | # Generated files 270 | .idea/**/contentModel.xml 271 | 272 | # Sensitive or high-churn files 273 | .idea/**/dataSources/ 274 | .idea/**/dataSources.ids 275 | .idea/**/dataSources.local.xml 276 | .idea/**/sqlDataSources.xml 277 | .idea/**/dynamic.xml 278 | .idea/**/uiDesigner.xml 279 | .idea/**/dbnavigator.xml 280 | 281 | # Gradle 282 | .idea/**/gradle.xml 283 | .idea/**/libraries 284 | 285 | # Gradle and Maven with auto-import 286 | # When using Gradle or Maven with auto-import, you should exclude module files, 287 | # since they will be recreated, and may cause churn. Uncomment if using 288 | # auto-import. 289 | .idea/modules.xml 290 | .idea/*.iml 291 | .idea/modules 292 | *.iml 293 | *.ipr 294 | 295 | # CMake 296 | cmake-build-*/ 297 | 298 | # Mongo Explorer plugin 299 | .idea/**/mongoSettings.xml 300 | 301 | # File-based project format 302 | *.iws 303 | 304 | # IntelliJ 305 | out/ 306 | 307 | # mpeltonen/sbt-idea plugin 308 | .idea_modules/ 309 | 310 | # JIRA plugin 311 | atlassian-ide-plugin.xml 312 | 313 | # Cursive Clojure plugin 314 | .idea/replstate.xml 315 | 316 | # Crashlytics plugin (for Android Studio and IntelliJ) 317 | com_crashlytics_export_strings.xml 318 | crashlytics.properties 319 | crashlytics-build.properties 320 | fabric.properties 321 | 322 | # Editor-based Rest Client 323 | .idea/httpRequests 324 | 325 | # Android studio 3.1+ serialized cache file 326 | .idea/caches/build_file_checksums.ser 327 | 328 | # fastlane 329 | fastlane/report.xml 330 | 331 | # inspectcode 332 | inspectcodereport.xml 333 | inspectcode 334 | 335 | # BenchmarkDotNet 336 | /BenchmarkDotNet.Artifacts 337 | 338 | *.GeneratedMSBuildEditorConfig.editorconfig 339 | 340 | # Fody (pulled in by Realm) - schema file 341 | FodyWeavers.xsd 342 | **/FodyWeavers.xml 343 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://editorconfig.org 2 | root = true 3 | 4 | [*.cs] 5 | end_of_line = crlf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | #Roslyn naming styles 12 | 13 | #camelCase for private members 14 | dotnet_naming_style.camelcase.capitalization = camel_case 15 | 16 | dotnet_naming_symbols.private_members.applicable_accessibilities = private 17 | dotnet_naming_symbols.private_members.applicable_kinds = property,method,field,event 18 | dotnet_naming_rule.private_members_camelcase.severity = warning 19 | dotnet_naming_rule.private_members_camelcase.symbols = private_members 20 | dotnet_naming_rule.private_members_camelcase.style = camelcase 21 | 22 | dotnet_naming_symbols.local_function.applicable_kinds = local_function 23 | dotnet_naming_rule.local_function_camelcase.severity = warning 24 | dotnet_naming_rule.local_function_camelcase.symbols = local_function 25 | dotnet_naming_rule.local_function_camelcase.style = camelcase 26 | 27 | #all_lower for private and local constants/static readonlys 28 | dotnet_naming_style.all_lower.capitalization = all_lower 29 | dotnet_naming_style.all_lower.word_separator = _ 30 | 31 | dotnet_naming_symbols.private_constants.applicable_accessibilities = private 32 | dotnet_naming_symbols.private_constants.required_modifiers = const 33 | dotnet_naming_symbols.private_constants.applicable_kinds = field 34 | dotnet_naming_rule.private_const_all_lower.severity = warning 35 | dotnet_naming_rule.private_const_all_lower.symbols = private_constants 36 | dotnet_naming_rule.private_const_all_lower.style = all_lower 37 | 38 | dotnet_naming_symbols.private_static_readonly.applicable_accessibilities = private 39 | dotnet_naming_symbols.private_static_readonly.required_modifiers = static,readonly 40 | dotnet_naming_symbols.private_static_readonly.applicable_kinds = field 41 | dotnet_naming_rule.private_static_readonly_all_lower.severity = warning 42 | dotnet_naming_rule.private_static_readonly_all_lower.symbols = private_static_readonly 43 | dotnet_naming_rule.private_static_readonly_all_lower.style = all_lower 44 | 45 | dotnet_naming_symbols.local_constants.applicable_kinds = local 46 | dotnet_naming_symbols.local_constants.required_modifiers = const 47 | dotnet_naming_rule.local_const_all_lower.severity = warning 48 | dotnet_naming_rule.local_const_all_lower.symbols = local_constants 49 | dotnet_naming_rule.local_const_all_lower.style = all_lower 50 | 51 | #ALL_UPPER for non private constants/static readonlys 52 | dotnet_naming_style.all_upper.capitalization = all_upper 53 | dotnet_naming_style.all_upper.word_separator = _ 54 | 55 | dotnet_naming_symbols.public_constants.applicable_accessibilities = public,internal,protected,protected_internal,private_protected 56 | dotnet_naming_symbols.public_constants.required_modifiers = const 57 | dotnet_naming_symbols.public_constants.applicable_kinds = field 58 | dotnet_naming_rule.public_const_all_upper.severity = warning 59 | dotnet_naming_rule.public_const_all_upper.symbols = public_constants 60 | dotnet_naming_rule.public_const_all_upper.style = all_upper 61 | 62 | dotnet_naming_symbols.public_static_readonly.applicable_accessibilities = public,internal,protected,protected_internal,private_protected 63 | dotnet_naming_symbols.public_static_readonly.required_modifiers = static,readonly 64 | dotnet_naming_symbols.public_static_readonly.applicable_kinds = field 65 | dotnet_naming_rule.public_static_readonly_all_upper.severity = warning 66 | dotnet_naming_rule.public_static_readonly_all_upper.symbols = public_static_readonly 67 | dotnet_naming_rule.public_static_readonly_all_upper.style = all_upper 68 | 69 | #Roslyn formating options 70 | 71 | #Formatting - indentation options 72 | csharp_indent_case_contents = true 73 | csharp_indent_case_contents_when_block = false 74 | csharp_indent_labels = one_less_than_current 75 | csharp_indent_switch_labels = true 76 | 77 | #Formatting - new line options 78 | csharp_new_line_before_catch = true 79 | csharp_new_line_before_else = true 80 | csharp_new_line_before_finally = true 81 | csharp_new_line_before_open_brace = all 82 | #csharp_new_line_before_members_in_anonymous_types = true 83 | #csharp_new_line_before_members_in_object_initializers = true # Currently no effect in VS/dotnet format (16.4), and makes Rider confusing 84 | csharp_new_line_between_query_expression_clauses = true 85 | 86 | #Formatting - organize using options 87 | dotnet_sort_system_directives_first = true 88 | 89 | #Formatting - spacing options 90 | csharp_space_after_cast = false 91 | csharp_space_after_colon_in_inheritance_clause = true 92 | csharp_space_after_keywords_in_control_flow_statements = true 93 | csharp_space_before_colon_in_inheritance_clause = true 94 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 95 | csharp_space_between_method_call_name_and_opening_parenthesis = false 96 | csharp_space_between_method_call_parameter_list_parentheses = false 97 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 98 | csharp_space_between_method_declaration_parameter_list_parentheses = false 99 | 100 | #Formatting - wrapping options 101 | csharp_preserve_single_line_blocks = true 102 | csharp_preserve_single_line_statements = true 103 | 104 | #Roslyn language styles 105 | 106 | #Style - this. qualification 107 | dotnet_style_qualification_for_field = false:warning 108 | dotnet_style_qualification_for_property = false:warning 109 | dotnet_style_qualification_for_method = false:warning 110 | dotnet_style_qualification_for_event = false:warning 111 | 112 | #Style - type names 113 | dotnet_style_predefined_type_for_locals_parameters_members = true:warning 114 | dotnet_style_predefined_type_for_member_access = true:warning 115 | csharp_style_var_when_type_is_apparent = true:none 116 | csharp_style_var_for_built_in_types = false:warning 117 | csharp_style_var_elsewhere = true:silent 118 | 119 | #Style - modifiers 120 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning 121 | csharp_preferred_modifier_order = public,private,protected,internal,new,abstract,virtual,sealed,override,static,readonly,extern,unsafe,volatile,async:warning 122 | 123 | #Style - parentheses 124 | # Skipped because roslyn cannot separate +-*/ with << >> 125 | 126 | #Style - expression bodies 127 | csharp_style_expression_bodied_accessors = true:warning 128 | csharp_style_expression_bodied_constructors = false:none 129 | csharp_style_expression_bodied_indexers = true:warning 130 | csharp_style_expression_bodied_methods = false:silent 131 | csharp_style_expression_bodied_operators = true:warning 132 | csharp_style_expression_bodied_properties = true:warning 133 | csharp_style_expression_bodied_local_functions = true:silent 134 | 135 | #Style - expression preferences 136 | dotnet_style_object_initializer = true:warning 137 | dotnet_style_collection_initializer = true:warning 138 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning 139 | dotnet_style_prefer_auto_properties = true:warning 140 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 141 | dotnet_style_prefer_conditional_expression_over_return = true:silent 142 | dotnet_style_prefer_compound_assignment = true:warning 143 | 144 | #Style - null/type checks 145 | dotnet_style_coalesce_expression = true:warning 146 | dotnet_style_null_propagation = true:warning 147 | csharp_style_pattern_matching_over_is_with_cast_check = true:warning 148 | csharp_style_pattern_matching_over_as_with_null_check = true:warning 149 | csharp_style_throw_expression = true:silent 150 | csharp_style_conditional_delegate_call = true:warning 151 | 152 | #Style - unused 153 | dotnet_style_readonly_field = true:silent 154 | dotnet_code_quality_unused_parameters = non_public:silent 155 | csharp_style_unused_value_expression_statement_preference = discard_variable:silent 156 | csharp_style_unused_value_assignment_preference = discard_variable:warning 157 | 158 | #Style - variable declaration 159 | csharp_style_inlined_variable_declaration = true:warning 160 | csharp_style_deconstructed_variable_declaration = false:silent 161 | 162 | #Style - other C# 7.x features 163 | dotnet_style_prefer_inferred_tuple_names = true:warning 164 | csharp_prefer_simple_default_expression = true:warning 165 | csharp_style_pattern_local_over_anonymous_function = true:warning 166 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent 167 | 168 | #Style - C# 8 features 169 | csharp_prefer_static_local_function = true:warning 170 | csharp_prefer_simple_using_statement = true:silent 171 | csharp_style_prefer_index_operator = false:silent 172 | csharp_style_prefer_range_operator = false:silent 173 | csharp_style_prefer_switch_expression = false:none 174 | 175 | #Supressing roslyn built-in analyzers 176 | # Suppress: EC112 177 | 178 | #Private method is unused 179 | dotnet_diagnostic.IDE0051.severity = silent 180 | #Private member is unused 181 | dotnet_diagnostic.IDE0052.severity = silent 182 | 183 | #Rules for disposable 184 | dotnet_diagnostic.IDE0067.severity = none 185 | dotnet_diagnostic.IDE0068.severity = none 186 | dotnet_diagnostic.IDE0069.severity = none 187 | 188 | #Disable operator overloads requiring alternate named methods 189 | dotnet_diagnostic.CA2225.severity = none 190 | 191 | # Banned APIs 192 | dotnet_diagnostic.RS0030.severity = error 193 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer/Beatmaps/PumpTrainerHitObjectGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.Immutable; 4 | using System.Linq; 5 | using osu.Game.Beatmaps; 6 | using osu.Game.Rulesets.PumpTrainer.Objects; 7 | 8 | namespace osu.Game.Rulesets.PumpTrainer.Beatmaps 9 | { 10 | public class PumpTrainerHitObjectGenerator 11 | { 12 | private Dictionary> nextColumnsPreviousFootLeft = new() 13 | { 14 | { Column.P1DL, [Column.P1UL, Column.P1C, Column.P1UR, Column.P1DR] }, 15 | { Column.P1UL, [Column.P1DL, Column.P1C, Column.P1UR, Column.P1DR] }, 16 | { Column.P1C, [Column.P1UR, Column.P1DR, Column.P2DL, Column.P2UL] }, 17 | { Column.P1UR, [Column.P1DR, Column.P2DL, Column.P2UL, Column.P2C] }, 18 | { Column.P1DR, [Column.P1UR, Column.P2DL, Column.P2UL, Column.P2C] }, 19 | { Column.P2DL, [Column.P1UR, Column.P2UL, Column.P2C, Column.P2UR, Column.P2DR] }, 20 | { Column.P2UL, [Column.P1DR, Column.P2DL, Column.P2C, Column.P2UR, Column.P2DR] }, 21 | { Column.P2C, [Column.P2UR, Column.P2DR] }, 22 | { Column.P2UR, [Column.P2DR] }, 23 | { Column.P2DR, [Column.P2UR] }, 24 | }; 25 | 26 | private Dictionary> nextColumnsPreviousFootRight = []; 27 | 28 | private Dictionary> nextColumnsPreviousFootLeftHorizontalTwist = new() 29 | { 30 | { Column.P1C, [Column.P1DL, Column.P1UL] }, 31 | { Column.P1UR, [Column.P1C] }, 32 | { Column.P1DR, [Column.P1C] }, 33 | { Column.P2C, [Column.P2DL, Column.P2UL] }, 34 | { Column.P2UR, [Column.P2C] }, 35 | { Column.P2DR, [Column.P2C] }, 36 | }; 37 | 38 | private Dictionary> nextColumnsPreviousFootRightHorizontalTwist = []; 39 | 40 | private Dictionary> nextColumnsPreviousFootLeftDiagonalSkip = new() 41 | { 42 | { Column.P1UR, [Column.P1DL] }, 43 | { Column.P1DR, [Column.P1UL] }, 44 | { Column.P2UR, [Column.P2DL] }, 45 | { Column.P2DR, [Column.P2UL] }, 46 | }; 47 | 48 | private Dictionary> nextColumnsPreviousFootRightDiagonalSkip = []; 49 | 50 | private Dictionary> nextColumnsPreviousFootLeftLargeTwist = new() 51 | { 52 | { Column.P2DL, [Column.P1C] }, 53 | { Column.P2UL, [Column.P1C] }, 54 | { Column.P2C, [Column.P1UR, Column.P1DR] }, 55 | }; 56 | 57 | private Dictionary> nextColumnsPreviousFootRightLargeTwist = []; 58 | 59 | private Dictionary horizontalFlips = new() 60 | { 61 | { Column.P1DL, Column.P2DR }, 62 | { Column.P1UL, Column.P2UR }, 63 | { Column.P1C, Column.P2C }, 64 | { Column.P1UR, Column.P2UL }, 65 | { Column.P1DR, Column.P2DL }, 66 | { Column.P2DL, Column.P1DR }, 67 | { Column.P2UL, Column.P1UR }, 68 | { Column.P2C, Column.P1C }, 69 | { Column.P2UR, Column.P1UL }, 70 | { Column.P2DR, Column.P1DL }, 71 | }; 72 | 73 | private ImmutableDictionary columnToPhysicalColumn = new Dictionary() 74 | { 75 | { Column.P1DL, 0 }, 76 | { Column.P1UL, 0 }, 77 | { Column.P1C, 1 }, 78 | { Column.P1UR, 2 }, 79 | { Column.P1DR, 2 }, 80 | { Column.P2DL, 3 }, 81 | { Column.P2UL, 3 }, 82 | { Column.P2C, 4 }, 83 | { Column.P2UR, 5 }, 84 | { Column.P2DR, 5 }, 85 | }.ToImmutableDictionary(); 86 | 87 | public int Seed 88 | { 89 | set => random = new(value); 90 | } 91 | private Random random = new(); 92 | 93 | private List hitObjectsSoFar = []; 94 | 95 | private Foot? previousFoot = null; 96 | private Column? previousColumn = null; 97 | 98 | public PumpTrainerHitObjectGeneratorSettings Settings = new(); 99 | 100 | // Updated for every newly generated note 101 | private PumpTrainerHitObjectGeneratorSettingsPerHitObject perHitObjectsettings; 102 | 103 | private int fullDoublesEdgeStreak = 0; 104 | private int p1SinglesEdgeStreak = 0; 105 | 106 | public PumpTrainerHitObjectGenerator() 107 | { 108 | initializeFootRightDictionaries(); 109 | } 110 | 111 | /// 112 | /// Generates a hitobject solely based off the settings of this class and previously generated hitobjects. 113 | /// Does NOT take into account any rhythms between the hitobject being generated and previously generated hitobjects. 114 | /// 115 | /// The start time of the next hitobject to generate. 116 | /// The source beatmap we're generating objects based off. Typically an osu! beatmap. 117 | /// The settings to apply for the generated hit object. 118 | /// 119 | public PumpTrainerHitObject GetNextHitObject(double startTime, IBeatmap beatmap, PumpTrainerHitObjectGeneratorSettingsPerHitObject perHitObjectsettings) 120 | { 121 | this.perHitObjectsettings = perHitObjectsettings; 122 | 123 | // Always start on the left foot as the first note (for now?) 124 | Foot nextFoot = previousFoot == null || previousFoot == Foot.Right ? Foot.Left : Foot.Right; 125 | 126 | Column nextColumn = previousColumn == null ? Settings.AllowedColumns[random.Next(Settings.AllowedColumns.Count())] 127 | : getNextColumn(nextFoot, (Column)previousColumn); 128 | 129 | PumpTrainerHitObject nextHitObject = new(nextColumn) 130 | { 131 | IntendedFoot = nextFoot, 132 | StartTime = startTime, 133 | }; 134 | 135 | hitObjectsSoFar.Add(nextHitObject); 136 | 137 | previousFoot = nextFoot; 138 | previousColumn = nextColumn; 139 | 140 | return nextHitObject; 141 | } 142 | 143 | private Column getNextColumn(Foot nextFoot, Column previousColumn) 144 | { 145 | List candidateColumns = getCandidateColumns(nextFoot, previousColumn, false); 146 | includeOnlyAllowedColumns(candidateColumns); 147 | banColumnsCausingBannedPatterns(candidateColumns, nextFoot == Foot.Left ? Foot.Right : Foot.Left); 148 | 149 | if (candidateColumns.Count == 0) 150 | { 151 | // We messed up. Do the whole thing again but this time, allow all twists. 152 | // todo There are many combination of mods that can break beatmap generation 153 | // particularly when you have an "island" of included columns 154 | 155 | candidateColumns = getCandidateColumns(nextFoot, previousColumn, true); 156 | includeOnlyAllowedColumns(candidateColumns); 157 | banColumnsCausingBannedPatterns(candidateColumns, nextFoot == Foot.Left ? Foot.Right : Foot.Left); 158 | } 159 | 160 | return getRandomCandidateColumnWeighted(candidateColumns); 161 | } 162 | 163 | private List getCandidateColumns(Foot nextFoot, Column previousColumn, bool guaranteeTwistCandidates) 164 | { 165 | List candidateColumns = (nextFoot == Foot.Left ? 166 | nextColumnsPreviousFootRight[previousColumn] : nextColumnsPreviousFootLeft[previousColumn]).ToList(); 167 | 168 | possiblyAddHorizontalTwistsToCandidates(candidateColumns, previousColumn, guaranteeTwistCandidates); 169 | possiblyAddDiagonalSkipsToCandidates(candidateColumns, previousColumn); 170 | possiblyAddLargeHorizontalTwistsToCandidates(candidateColumns, previousColumn); 171 | 172 | // Easy mod bans 173 | possiblyBanFarColumns(candidateColumns, previousColumn, guaranteeTwistCandidates); 174 | 175 | return candidateColumns; 176 | } 177 | 178 | private void possiblyAddHorizontalTwistsToCandidates(List candidates, Column previousColumn, bool alwaysAdd) 179 | { 180 | if (random.NextDouble() < Settings.HorizontalTwistFrequency || alwaysAdd) 181 | { 182 | List twistColumnsToAdd; 183 | 184 | if (previousFoot == Foot.Left) 185 | { 186 | if (nextColumnsPreviousFootLeftHorizontalTwist.ContainsKey(previousColumn)) 187 | { 188 | twistColumnsToAdd = nextColumnsPreviousFootLeftHorizontalTwist[previousColumn]; 189 | } 190 | else 191 | { 192 | return; 193 | } 194 | } 195 | else 196 | { 197 | if (nextColumnsPreviousFootRightHorizontalTwist.ContainsKey(previousColumn)) 198 | { 199 | twistColumnsToAdd = nextColumnsPreviousFootRightHorizontalTwist[previousColumn]; 200 | } 201 | else 202 | { 203 | return; 204 | } 205 | } 206 | 207 | candidates.AddRange(twistColumnsToAdd); 208 | } 209 | } 210 | 211 | private void possiblyAddDiagonalSkipsToCandidates(List candidates, Column previousColumn) 212 | { 213 | if (random.NextDouble() < Settings.DiagonalSkipFrequency) 214 | { 215 | List twistColumnsToAdd; 216 | 217 | if (previousFoot == Foot.Left) 218 | { 219 | if (nextColumnsPreviousFootLeftDiagonalSkip.ContainsKey(previousColumn)) 220 | { 221 | twistColumnsToAdd = nextColumnsPreviousFootLeftDiagonalSkip[previousColumn]; 222 | } 223 | else 224 | { 225 | return; 226 | } 227 | } 228 | else 229 | { 230 | if (nextColumnsPreviousFootRightDiagonalSkip.ContainsKey(previousColumn)) 231 | { 232 | twistColumnsToAdd = nextColumnsPreviousFootRightDiagonalSkip[previousColumn]; 233 | } 234 | else 235 | { 236 | return; 237 | } 238 | } 239 | 240 | candidates.AddRange(twistColumnsToAdd); 241 | } 242 | } 243 | 244 | private void possiblyAddLargeHorizontalTwistsToCandidates(List candidates, Column previousColumn) 245 | { 246 | if (random.NextDouble() < Settings.LargeTwistFrequency) 247 | { 248 | List twistColumnsToAdd; 249 | 250 | if (previousFoot == Foot.Left) 251 | { 252 | if (nextColumnsPreviousFootLeftLargeTwist.ContainsKey(previousColumn)) 253 | { 254 | twistColumnsToAdd = nextColumnsPreviousFootLeftLargeTwist[previousColumn]; 255 | } 256 | else 257 | { 258 | return; 259 | } 260 | } 261 | else 262 | { 263 | if (nextColumnsPreviousFootRightLargeTwist.ContainsKey(previousColumn)) 264 | { 265 | twistColumnsToAdd = nextColumnsPreviousFootRightLargeTwist[previousColumn]; 266 | } 267 | else 268 | { 269 | return; 270 | } 271 | } 272 | 273 | candidates.AddRange(twistColumnsToAdd); 274 | } 275 | } 276 | 277 | private void possiblyBanFarColumns(List candidates, Column previousColumn, bool neverBan) 278 | { 279 | if (neverBan) 280 | { 281 | return; 282 | } 283 | 284 | if (random.NextDouble() > Settings.FarColumnsFrequency) 285 | { 286 | List columnsToBan; 287 | int previousPhysicalColumn = columnToPhysicalColumn[previousColumn]; 288 | 289 | if (previousColumn == Column.P1C || previousColumn == Column.P2C) 290 | { 291 | // Just ban everything that's two columns away 292 | columnsToBan = 293 | columnToPhysicalColumn 294 | .Where(entry => entry.Value == previousPhysicalColumn + 2 || entry.Value == previousPhysicalColumn - 2) 295 | .Select(entry => entry.Key) 296 | .ToList(); 297 | } 298 | else 299 | { 300 | // Ban everything that's two columns away and that's also a center panel 301 | columnsToBan = 302 | columnToPhysicalColumn 303 | .Where(entry => 304 | (entry.Value == previousPhysicalColumn + 2 || entry.Value == previousPhysicalColumn - 2) 305 | && (entry.Key == Column.P1C || entry.Key == Column.P2C)) 306 | .Select(entry => entry.Key) 307 | .ToList(); 308 | } 309 | 310 | candidates.RemoveAll(columnsToBan.Contains); 311 | } 312 | } 313 | 314 | private void includeOnlyAllowedColumns(List candidateColumns) 315 | { 316 | foreach (Column column in candidateColumns.ToList()) 317 | { 318 | if (!Settings.AllowedColumns.Contains(column)) 319 | { 320 | candidateColumns.Remove(column); 321 | } 322 | } 323 | } 324 | 325 | /// 326 | /// Bans columns the given list of candidates based on the columns two most recent hit objects in the generated beatmap. 327 | /// A pattern is a group of 3 notes (not 2). 328 | /// 329 | /// Candidate columns to ban from. 330 | /// Associated foot of the most recent hit object in the beatmap. 331 | private void banColumnsCausingBannedPatterns(List candidateColumns, Foot previousFoot) 332 | { 333 | // todo this function and maybe this whole class can be broken down into ban types and stuff 334 | // so we can just add the types of bans we want to a list instead of this hugh mungus method 335 | 336 | if (hitObjectsSoFar.Count <= 1) 337 | { 338 | // No possible bans if we're only on the first or second note 339 | return; 340 | } 341 | 342 | Column previousColumn = hitObjectsSoFar[^1].Column; 343 | Column previousPreviousColumn = hitObjectsSoFar[^2].Column; 344 | 345 | // Ban spins no matter what (this covers large twist spins as well) 346 | if (previousFoot == Foot.Left) 347 | { 348 | if (previousColumn == Column.P1C) 349 | { 350 | if (previousPreviousColumn == Column.P1DL) 351 | { 352 | candidateColumns.Remove(Column.P1UL); 353 | } 354 | else if (previousPreviousColumn == Column.P1UL) 355 | { 356 | candidateColumns.Remove(Column.P1DL); 357 | } 358 | } 359 | else if (previousColumn == Column.P2C) 360 | { 361 | if (previousPreviousColumn == Column.P2DL || previousPreviousColumn == Column.P1DR) 362 | { 363 | candidateColumns.Remove(Column.P2UL); 364 | candidateColumns.Remove(Column.P1UR); 365 | } 366 | else if (previousPreviousColumn == Column.P2UL || previousPreviousColumn == Column.P1UR) 367 | { 368 | candidateColumns.Remove(Column.P2DL); 369 | candidateColumns.Remove(Column.P1DR); 370 | } 371 | } 372 | } 373 | else if (previousFoot == Foot.Right) 374 | { 375 | if (previousColumn == Column.P1C) 376 | { 377 | if (previousPreviousColumn == Column.P1DR || previousPreviousColumn == Column.P2DL) 378 | { 379 | candidateColumns.Remove(Column.P1UR); 380 | candidateColumns.Remove(Column.P2UL); 381 | } 382 | else if (previousPreviousColumn == Column.P1UR || previousPreviousColumn == Column.P2UL) 383 | { 384 | candidateColumns.Remove(Column.P1DR); 385 | candidateColumns.Remove(Column.P2DL); 386 | } 387 | } 388 | else if (previousColumn == Column.P2C) 389 | { 390 | if (previousPreviousColumn == Column.P2DR) 391 | { 392 | candidateColumns.Remove(Column.P2UR); 393 | } 394 | else if (previousPreviousColumn == Column.P2UR) 395 | { 396 | candidateColumns.Remove(Column.P2DR); 397 | } 398 | } 399 | } 400 | 401 | // Ban large horizontal triples no matter what. This is where all three columns go in one direction, and they are not adjacent to each other. 402 | { 403 | int previousPhysicalColumn = columnToPhysicalColumn[previousColumn]; 404 | int previousPreviousPhysicalColumn = columnToPhysicalColumn[previousPreviousColumn]; 405 | 406 | List columnsToBan = []; 407 | 408 | // If the two previous columns are adjacent, then we have an extra column of leniency for the column of the next hit object 409 | // (so that we don't mistakenly ban a regular horizontal triple, where all the columns are adjacent). 410 | // If the two previous columns already have a gap between them, then we can't be lenient and we must ban everything going in that direction. 411 | int banColumnLeniency = Math.Abs(previousPhysicalColumn - previousPreviousPhysicalColumn) >= 2 ? 0 : 1; 412 | 413 | if (previousPhysicalColumn > previousPreviousPhysicalColumn) 414 | { 415 | // Going right! Ban everything to the right 416 | columnsToBan = columnToPhysicalColumn.Where(entry => entry.Value > previousPhysicalColumn + banColumnLeniency).Select(entry => entry.Key).ToList(); 417 | } 418 | else if (previousPhysicalColumn < previousPreviousPhysicalColumn) 419 | { 420 | // Going left! Ban everything to the left 421 | columnsToBan = columnToPhysicalColumn.Where(entry => entry.Value < previousPhysicalColumn - banColumnLeniency).Select(entry => entry.Key).ToList(); 422 | } 423 | 424 | candidateColumns.RemoveAll(columnsToBan.Contains); 425 | } 426 | 427 | // Ban diagonal twists (single pad) 428 | if (!Settings.AllowDiagonalTwists) 429 | { 430 | if (previousColumn == Column.P1C) 431 | { 432 | if (previousPreviousColumn == Column.P1DL) 433 | { 434 | candidateColumns.Remove(Column.P1UR); 435 | } 436 | else if (previousPreviousColumn == Column.P1UL) 437 | { 438 | candidateColumns.Remove(Column.P1DR); 439 | } 440 | else if (previousPreviousColumn == Column.P1DR) 441 | { 442 | candidateColumns.Remove(Column.P1UL); 443 | } 444 | else if (previousPreviousColumn == Column.P1UR) 445 | { 446 | candidateColumns.Remove(Column.P1DL); 447 | } 448 | } 449 | else if (previousColumn == Column.P2C) 450 | { 451 | if (previousPreviousColumn == Column.P2DR) 452 | { 453 | candidateColumns.Remove(Column.P2UL); 454 | } 455 | else if (previousPreviousColumn == Column.P2UR) 456 | { 457 | candidateColumns.Remove(Column.P2DL); 458 | } 459 | else if (previousPreviousColumn == Column.P2DL) 460 | { 461 | candidateColumns.Remove(Column.P2UR); 462 | } 463 | else if (previousPreviousColumn == Column.P2UL) 464 | { 465 | candidateColumns.Remove(Column.P2DR); 466 | } 467 | } 468 | } 469 | 470 | // Ban horizontal triples (horizontally adjacent to each other) 471 | if (random.NextDouble() > perHitObjectsettings.HorizontalTripleFrequency) 472 | { 473 | int previousPhysicalColumn = columnToPhysicalColumn[previousColumn]; 474 | int previousPreviousPhysicalColumn = columnToPhysicalColumn[previousPreviousColumn]; 475 | 476 | List columnsToBan = []; 477 | 478 | if (previousPhysicalColumn > previousPreviousPhysicalColumn) 479 | { 480 | // Going right! Ban everything to the right 481 | columnsToBan = columnToPhysicalColumn.Where(entry => entry.Value > previousPhysicalColumn).Select(entry => entry.Key).ToList(); 482 | } 483 | else if (previousPhysicalColumn < previousPreviousPhysicalColumn) 484 | { 485 | // Going left! Ban everything to the left 486 | columnsToBan = columnToPhysicalColumn.Where(entry => entry.Value < previousPhysicalColumn).Select(entry => entry.Key).ToList(); 487 | } 488 | 489 | // Don't ban columns where all three notes are on the same singles pad. This would interfere with horizontal twists. 490 | // Just manually check all four possibilities. 491 | if (previousPhysicalColumn == 1 && previousPreviousPhysicalColumn == 0) 492 | { 493 | columnsToBan.RemoveAll(column => columnToPhysicalColumn[column] == 2); 494 | } 495 | if (previousPhysicalColumn == 1 && previousPreviousPhysicalColumn == 2) 496 | { 497 | columnsToBan.RemoveAll(column => columnToPhysicalColumn[column] == 0); 498 | } 499 | if (previousPhysicalColumn == 4 && previousPreviousPhysicalColumn == 3) 500 | { 501 | columnsToBan.RemoveAll(column => columnToPhysicalColumn[column] == 5); 502 | } 503 | if (previousPhysicalColumn == 4 && previousPreviousPhysicalColumn == 5) 504 | { 505 | columnsToBan.RemoveAll(column => columnToPhysicalColumn[column] == 3); 506 | } 507 | 508 | candidateColumns.RemoveAll(columnsToBan.Contains); 509 | } 510 | 511 | // Ban corner patterns 512 | if (random.NextDouble() > perHitObjectsettings.CornersFrequency) 513 | { 514 | // Ban 90 degree patterns 515 | if (previousPreviousColumn == Column.P1UL && (previousColumn == Column.P1UR || previousColumn == Column.P1DL)) 516 | { 517 | candidateColumns.Remove(Column.P1DR); 518 | } 519 | else if (previousPreviousColumn == Column.P1DL && (previousColumn == Column.P1DR || previousColumn == Column.P1UL)) 520 | { 521 | candidateColumns.Remove(Column.P1UR); 522 | } 523 | else if (previousPreviousColumn == Column.P1UR && (previousColumn == Column.P1UL || previousColumn == Column.P1DR)) 524 | { 525 | candidateColumns.Remove(Column.P1DL); 526 | } 527 | else if (previousPreviousColumn == Column.P1DR && (previousColumn == Column.P1DL || previousColumn == Column.P1UR)) 528 | { 529 | candidateColumns.Remove(Column.P1UL); 530 | } 531 | else if (previousPreviousColumn == Column.P2UL && (previousColumn == Column.P2UR || previousColumn == Column.P2DL)) 532 | { 533 | candidateColumns.Remove(Column.P2DR); 534 | } 535 | else if (previousPreviousColumn == Column.P2DL && (previousColumn == Column.P2DR || previousColumn == Column.P2UL)) 536 | { 537 | candidateColumns.Remove(Column.P2UR); 538 | } 539 | else if (previousPreviousColumn == Column.P2UR && (previousColumn == Column.P2UL || previousColumn == Column.P2DR)) 540 | { 541 | candidateColumns.Remove(Column.P2DL); 542 | } 543 | else if (previousPreviousColumn == Column.P2DR && (previousColumn == Column.P2DL || previousColumn == Column.P2UR)) 544 | { 545 | candidateColumns.Remove(Column.P2UL); 546 | } 547 | 548 | // Ban V patterns 549 | if (previousPreviousColumn == Column.P1UL && (previousColumn == Column.P1DR || previousColumn == Column.P1DL)) 550 | { 551 | candidateColumns.Remove(Column.P1UR); 552 | } 553 | else if (previousPreviousColumn == Column.P1DL && (previousColumn == Column.P1UR || previousColumn == Column.P1UL)) 554 | { 555 | candidateColumns.Remove(Column.P1DR); 556 | } 557 | else if (previousPreviousColumn == Column.P1UR && (previousColumn == Column.P1DL || previousColumn == Column.P1DR)) 558 | { 559 | candidateColumns.Remove(Column.P1UL); 560 | } 561 | else if (previousPreviousColumn == Column.P1DR && (previousColumn == Column.P1UL || previousColumn == Column.P1UR)) 562 | { 563 | candidateColumns.Remove(Column.P1DL); 564 | } 565 | else if (previousPreviousColumn == Column.P2UL && (previousColumn == Column.P2DR || previousColumn == Column.P2DL)) 566 | { 567 | candidateColumns.Remove(Column.P2UR); 568 | } 569 | else if (previousPreviousColumn == Column.P2DL && (previousColumn == Column.P2UR || previousColumn == Column.P2UL)) 570 | { 571 | candidateColumns.Remove(Column.P2DR); 572 | } 573 | else if (previousPreviousColumn == Column.P2UR && (previousColumn == Column.P2DL || previousColumn == Column.P2DR)) 574 | { 575 | candidateColumns.Remove(Column.P2UL); 576 | } 577 | else if (previousPreviousColumn == Column.P2DR && (previousColumn == Column.P2UL || previousColumn == Column.P2UR)) 578 | { 579 | candidateColumns.Remove(Column.P2DL); 580 | } 581 | } 582 | } 583 | 584 | private Column getRandomCandidateColumnWeighted(List candidateColumns) 585 | { 586 | if (candidateColumns.Count == 0) 587 | { 588 | throw new Exception("There were no candidate columns :("); 589 | } 590 | 591 | if (hitObjectsSoFar.Count < 2) 592 | { 593 | return candidateColumns[random.Next(candidateColumns.Count)]; 594 | } 595 | 596 | Column previousPreviousColumn = hitObjectsSoFar[^2].Column; 597 | List candidateColumnsWeighted = []; 598 | 599 | foreach (Column candidateColumn in candidateColumns) 600 | { 601 | candidateColumnsWeighted.Add(candidateColumn); 602 | 603 | // Reduce the likelihood of trills 604 | if (candidateColumn != previousPreviousColumn) 605 | { 606 | for (int i = 0; i < 4; i++) 607 | { 608 | candidateColumnsWeighted.Add(candidateColumn); 609 | } 610 | } 611 | 612 | // If full-doubles, decrease the likelihood of a panel on the same column as the previous if on the edge 613 | if (Settings.AllowedColumns.Count == 10 && 614 | fullDoublesEdgeStreak > 0 && 615 | previousColumn != null && 616 | columnToPhysicalColumn[candidateColumn] != columnToPhysicalColumn[previousColumn.Value]) 617 | { 618 | for (int i = 0; i < 4 * fullDoublesEdgeStreak; i++) 619 | { 620 | candidateColumnsWeighted.Add(candidateColumn); 621 | } 622 | } 623 | 624 | // Also apply for singles 625 | if (Settings.AllowedColumns.SequenceEqual([Column.P1DL, Column.P1UL, Column.P1C, Column.P1UR, Column.P1DR]) && 626 | p1SinglesEdgeStreak > 0 && 627 | previousColumn != null && 628 | columnToPhysicalColumn[candidateColumn] != columnToPhysicalColumn[previousColumn.Value]) 629 | { 630 | for (int i = 0; i < 4 * p1SinglesEdgeStreak; i++) 631 | { 632 | candidateColumnsWeighted.Add(candidateColumn); 633 | } 634 | } 635 | } 636 | 637 | Column selectedColumn = candidateColumnsWeighted[random.Next(candidateColumnsWeighted.Count)]; 638 | 639 | fullDoublesEdgeStreak = 640 | columnToPhysicalColumn[selectedColumn] == 0 || columnToPhysicalColumn[selectedColumn] == 5 ? 641 | fullDoublesEdgeStreak + 1 : 0; 642 | 643 | p1SinglesEdgeStreak = 644 | columnToPhysicalColumn[selectedColumn] == 0 || columnToPhysicalColumn[selectedColumn] == 2 ? 645 | p1SinglesEdgeStreak + 1 : 0; 646 | 647 | return selectedColumn; 648 | } 649 | 650 | private void initializeFootRightDictionaries() 651 | { 652 | foreach (Column column in Enum.GetValues(typeof(Column))) 653 | { 654 | Column flippedColumn = horizontalFlips[column]; 655 | 656 | if (nextColumnsPreviousFootLeft.ContainsKey(flippedColumn)) 657 | { 658 | nextColumnsPreviousFootRight[column] = nextColumnsPreviousFootLeft[flippedColumn].Select(n => horizontalFlips[n]).ToList(); 659 | } 660 | 661 | if (nextColumnsPreviousFootLeftHorizontalTwist.ContainsKey(flippedColumn)) 662 | { 663 | nextColumnsPreviousFootRightHorizontalTwist[column] = nextColumnsPreviousFootLeftHorizontalTwist[flippedColumn].Select(n => horizontalFlips[n]).ToList(); 664 | } 665 | 666 | if (nextColumnsPreviousFootLeftDiagonalSkip.ContainsKey(flippedColumn)) 667 | { 668 | nextColumnsPreviousFootRightDiagonalSkip[column] = nextColumnsPreviousFootLeftDiagonalSkip[flippedColumn].Select(n => horizontalFlips[n]).ToList(); 669 | } 670 | 671 | if (nextColumnsPreviousFootLeftLargeTwist.ContainsKey(flippedColumn)) 672 | { 673 | nextColumnsPreviousFootRightLargeTwist[column] = nextColumnsPreviousFootLeftLargeTwist[flippedColumn].Select(n => horizontalFlips[n]).ToList(); 674 | } 675 | } 676 | } 677 | } 678 | } 679 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.PumpTrainer.sln.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | True 3 | True 4 | True 5 | True 6 | ExplicitlyExcluded 7 | ExplicitlyExcluded 8 | SOLUTION 9 | WARNING 10 | WARNING 11 | WARNING 12 | HINT 13 | HINT 14 | WARNING 15 | WARNING 16 | True 17 | WARNING 18 | WARNING 19 | HINT 20 | DO_NOT_SHOW 21 | WARNING 22 | WARNING 23 | HINT 24 | HINT 25 | WARNING 26 | WARNING 27 | WARNING 28 | WARNING 29 | WARNING 30 | WARNING 31 | WARNING 32 | WARNING 33 | WARNING 34 | WARNING 35 | WARNING 36 | WARNING 37 | WARNING 38 | WARNING 39 | WARNING 40 | WARNING 41 | WARNING 42 | WARNING 43 | WARNING 44 | WARNING 45 | WARNING 46 | WARNING 47 | WARNING 48 | WARNING 49 | WARNING 50 | WARNING 51 | WARNING 52 | WARNING 53 | WARNING 54 | HINT 55 | WARNING 56 | HINT 57 | SUGGESTION 58 | HINT 59 | HINT 60 | HINT 61 | WARNING 62 | WARNING 63 | WARNING 64 | WARNING 65 | WARNING 66 | WARNING 67 | WARNING 68 | WARNING 69 | WARNING 70 | WARNING 71 | WARNING 72 | WARNING 73 | WARNING 74 | HINT 75 | WARNING 76 | HINT 77 | DO_NOT_SHOW 78 | WARNING 79 | DO_NOT_SHOW 80 | WARNING 81 | WARNING 82 | WARNING 83 | WARNING 84 | WARNING 85 | WARNING 86 | WARNING 87 | WARNING 88 | HINT 89 | WARNING 90 | DO_NOT_SHOW 91 | WARNING 92 | HINT 93 | DO_NOT_SHOW 94 | HINT 95 | HINT 96 | ERROR 97 | WARNING 98 | HINT 99 | HINT 100 | HINT 101 | WARNING 102 | WARNING 103 | HINT 104 | DO_NOT_SHOW 105 | HINT 106 | HINT 107 | HINT 108 | HINT 109 | WARNING 110 | DO_NOT_SHOW 111 | DO_NOT_SHOW 112 | WARNING 113 | WARNING 114 | WARNING 115 | WARNING 116 | WARNING 117 | WARNING 118 | WARNING 119 | WARNING 120 | WARNING 121 | WARNING 122 | WARNING 123 | WARNING 124 | WARNING 125 | HINT 126 | HINT 127 | WARNING 128 | HINT 129 | HINT 130 | HINT 131 | DO_NOT_SHOW 132 | HINT 133 | HINT 134 | WARNING 135 | WARNING 136 | WARNING 137 | WARNING 138 | WARNING 139 | WARNING 140 | WARNING 141 | HINT 142 | DO_NOT_SHOW 143 | DO_NOT_SHOW 144 | DO_NOT_SHOW 145 | WARNING 146 | WARNING 147 | WARNING 148 | WARNING 149 | WARNING 150 | WARNING 151 | WARNING 152 | WARNING 153 | ERROR 154 | WARNING 155 | WARNING 156 | HINT 157 | WARNING 158 | WARNING 159 | WARNING 160 | WARNING 161 | WARNING 162 | WARNING 163 | WARNING 164 | WARNING 165 | WARNING 166 | WARNING 167 | WARNING 168 | WARNING 169 | WARNING 170 | WARNING 171 | WARNING 172 | WARNING 173 | WARNING 174 | WARNING 175 | WARNING 176 | WARNING 177 | WARNING 178 | WARNING 179 | WARNING 180 | WARNING 181 | WARNING 182 | WARNING 183 | WARNING 184 | WARNING 185 | WARNING 186 | WARNING 187 | WARNING 188 | WARNING 189 | WARNING 190 | WARNING 191 | WARNING 192 | WARNING 193 | WARNING 194 | WARNING 195 | WARNING 196 | WARNING 197 | WARNING 198 | WARNING 199 | WARNING 200 | WARNING 201 | WARNING 202 | WARNING 203 | WARNING 204 | WARNING 205 | WARNING 206 | WARNING 207 | WARNING 208 | HINT 209 | WARNING 210 | WARNING 211 | SUGGESTION 212 | DO_NOT_SHOW 213 | 214 | True 215 | DO_NOT_SHOW 216 | WARNING 217 | WARNING 218 | WARNING 219 | WARNING 220 | WARNING 221 | HINT 222 | WARNING 223 | HINT 224 | HINT 225 | HINT 226 | HINT 227 | HINT 228 | HINT 229 | HINT 230 | HINT 231 | HINT 232 | HINT 233 | DO_NOT_SHOW 234 | WARNING 235 | WARNING 236 | WARNING 237 | WARNING 238 | WARNING 239 | WARNING 240 | WARNING 241 | 242 | True 243 | WARNING 244 | WARNING 245 | WARNING 246 | WARNING 247 | WARNING 248 | HINT 249 | HINT 250 | WARNING 251 | WARNING 252 | <?xml version="1.0" encoding="utf-16"?><Profile name="Code Cleanup (peppy)"><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSUseVar><BehavourStyle>CAN_CHANGE_TO_EXPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_EXPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_EXPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSUpdateFileHeader>True</CSUpdateFileHeader><CSCodeStyleAttributes ArrangeTypeAccessModifier="False" ArrangeTypeMemberAccessModifier="False" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="False" ArrangeBraces="False" ArrangeAttributes="False" ArrangeArgumentsStyle="False" /><XAMLCollapseEmptyTags>False</XAMLCollapseEmptyTags><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CSArrangeQualifiers>True</CSArrangeQualifiers></Profile> 253 | Code Cleanup (peppy) 254 | RequiredForMultiline 255 | RequiredForMultiline 256 | RequiredForMultiline 257 | RequiredForMultiline 258 | RequiredForMultiline 259 | RequiredForMultiline 260 | RequiredForMultiline 261 | RequiredForMultiline 262 | Explicit 263 | ExpressionBody 264 | BlockBody 265 | True 266 | NEXT_LINE 267 | True 268 | True 269 | True 270 | True 271 | True 272 | True 273 | True 274 | True 275 | NEXT_LINE 276 | 1 277 | 1 278 | NEXT_LINE 279 | MULTILINE 280 | True 281 | True 282 | True 283 | True 284 | NEXT_LINE 285 | 1 286 | 1 287 | True 288 | NEXT_LINE 289 | NEVER 290 | NEVER 291 | True 292 | False 293 | True 294 | NEVER 295 | False 296 | False 297 | True 298 | False 299 | False 300 | True 301 | True 302 | False 303 | False 304 | CHOP_IF_LONG 305 | True 306 | 200 307 | CHOP_IF_LONG 308 | UseExplicitType 309 | UseVarWhenEvident 310 | UseVarWhenEvident 311 | False 312 | False 313 | AABB 314 | API 315 | BPM 316 | EF 317 | FPS 318 | GC 319 | GL 320 | GLSL 321 | HID 322 | HSV 323 | HTML 324 | HUD 325 | ID 326 | IL 327 | IOS 328 | IP 329 | IPC 330 | JIT 331 | LTRB 332 | MD5 333 | NS 334 | OS 335 | PM 336 | RGB 337 | RNG 338 | SHA 339 | SRGB 340 | TK 341 | SS 342 | PP 343 | GMT 344 | QAT 345 | BNG 346 | UI 347 | False 348 | HINT 349 | <?xml version="1.0" encoding="utf-16"?> 350 | <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> 351 | <TypePattern DisplayName="COM interfaces or structs"> 352 | <TypePattern.Match> 353 | <Or> 354 | <And> 355 | <Kind Is="Interface" /> 356 | <Or> 357 | <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /> 358 | <HasAttribute Name="System.Runtime.InteropServices.ComImport" /> 359 | </Or> 360 | </And> 361 | <Kind Is="Struct" /> 362 | </Or> 363 | </TypePattern.Match> 364 | </TypePattern> 365 | <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"> 366 | <TypePattern.Match> 367 | <And> 368 | <Kind Is="Class" /> 369 | <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" /> 370 | </And> 371 | </TypePattern.Match> 372 | <Entry DisplayName="Setup/Teardown Methods"> 373 | <Entry.Match> 374 | <And> 375 | <Kind Is="Method" /> 376 | <Or> 377 | <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" /> 378 | <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" /> 379 | <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" /> 380 | <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" /> 381 | </Or> 382 | </And> 383 | </Entry.Match> 384 | </Entry> 385 | <Entry DisplayName="All other members" /> 386 | <Entry Priority="100" DisplayName="Test Methods"> 387 | <Entry.Match> 388 | <And> 389 | <Kind Is="Method" /> 390 | <HasAttribute Name="NUnit.Framework.TestAttribute" /> 391 | </And> 392 | </Entry.Match> 393 | <Entry.SortBy> 394 | <Name /> 395 | </Entry.SortBy> 396 | </Entry> 397 | </TypePattern> 398 | <TypePattern DisplayName="Default Pattern"> 399 | <Group DisplayName="Fields/Properties"> 400 | <Group DisplayName="Public Fields"> 401 | <Entry DisplayName="Constant Fields"> 402 | <Entry.Match> 403 | <And> 404 | <Access Is="Public" /> 405 | <Or> 406 | <Kind Is="Constant" /> 407 | <Readonly /> 408 | <And> 409 | <Static /> 410 | <Readonly /> 411 | </And> 412 | </Or> 413 | </And> 414 | </Entry.Match> 415 | </Entry> 416 | <Entry DisplayName="Static Fields"> 417 | <Entry.Match> 418 | <And> 419 | <Access Is="Public" /> 420 | <Static /> 421 | <Not> 422 | <Readonly /> 423 | </Not> 424 | <Kind Is="Field" /> 425 | </And> 426 | </Entry.Match> 427 | </Entry> 428 | <Entry DisplayName="Normal Fields"> 429 | <Entry.Match> 430 | <And> 431 | <Access Is="Public" /> 432 | <Not> 433 | <Or> 434 | <Static /> 435 | <Readonly /> 436 | </Or> 437 | </Not> 438 | <Kind Is="Field" /> 439 | </And> 440 | </Entry.Match> 441 | </Entry> 442 | </Group> 443 | <Entry DisplayName="Public Properties"> 444 | <Entry.Match> 445 | <And> 446 | <Access Is="Public" /> 447 | <Kind Is="Property" /> 448 | </And> 449 | </Entry.Match> 450 | </Entry> 451 | <Group DisplayName="Internal Fields"> 452 | <Entry DisplayName="Constant Fields"> 453 | <Entry.Match> 454 | <And> 455 | <Access Is="Internal" /> 456 | <Or> 457 | <Kind Is="Constant" /> 458 | <Readonly /> 459 | <And> 460 | <Static /> 461 | <Readonly /> 462 | </And> 463 | </Or> 464 | </And> 465 | </Entry.Match> 466 | </Entry> 467 | <Entry DisplayName="Static Fields"> 468 | <Entry.Match> 469 | <And> 470 | <Access Is="Internal" /> 471 | <Static /> 472 | <Not> 473 | <Readonly /> 474 | </Not> 475 | <Kind Is="Field" /> 476 | </And> 477 | </Entry.Match> 478 | </Entry> 479 | <Entry DisplayName="Normal Fields"> 480 | <Entry.Match> 481 | <And> 482 | <Access Is="Internal" /> 483 | <Not> 484 | <Or> 485 | <Static /> 486 | <Readonly /> 487 | </Or> 488 | </Not> 489 | <Kind Is="Field" /> 490 | </And> 491 | </Entry.Match> 492 | </Entry> 493 | </Group> 494 | <Entry DisplayName="Internal Properties"> 495 | <Entry.Match> 496 | <And> 497 | <Access Is="Internal" /> 498 | <Kind Is="Property" /> 499 | </And> 500 | </Entry.Match> 501 | </Entry> 502 | <Group DisplayName="Protected Fields"> 503 | <Entry DisplayName="Constant Fields"> 504 | <Entry.Match> 505 | <And> 506 | <Access Is="Protected" /> 507 | <Or> 508 | <Kind Is="Constant" /> 509 | <Readonly /> 510 | <And> 511 | <Static /> 512 | <Readonly /> 513 | </And> 514 | </Or> 515 | </And> 516 | </Entry.Match> 517 | </Entry> 518 | <Entry DisplayName="Static Fields"> 519 | <Entry.Match> 520 | <And> 521 | <Access Is="Protected" /> 522 | <Static /> 523 | <Not> 524 | <Readonly /> 525 | </Not> 526 | <Kind Is="Field" /> 527 | </And> 528 | </Entry.Match> 529 | </Entry> 530 | <Entry DisplayName="Normal Fields"> 531 | <Entry.Match> 532 | <And> 533 | <Access Is="Protected" /> 534 | <Not> 535 | <Or> 536 | <Static /> 537 | <Readonly /> 538 | </Or> 539 | </Not> 540 | <Kind Is="Field" /> 541 | </And> 542 | </Entry.Match> 543 | </Entry> 544 | </Group> 545 | <Entry DisplayName="Protected Properties"> 546 | <Entry.Match> 547 | <And> 548 | <Access Is="Protected" /> 549 | <Kind Is="Property" /> 550 | </And> 551 | </Entry.Match> 552 | </Entry> 553 | <Group DisplayName="Private Fields"> 554 | <Entry DisplayName="Constant Fields"> 555 | <Entry.Match> 556 | <And> 557 | <Access Is="Private" /> 558 | <Or> 559 | <Kind Is="Constant" /> 560 | <Readonly /> 561 | <And> 562 | <Static /> 563 | <Readonly /> 564 | </And> 565 | </Or> 566 | </And> 567 | </Entry.Match> 568 | </Entry> 569 | <Entry DisplayName="Static Fields"> 570 | <Entry.Match> 571 | <And> 572 | <Access Is="Private" /> 573 | <Static /> 574 | <Not> 575 | <Readonly /> 576 | </Not> 577 | <Kind Is="Field" /> 578 | </And> 579 | </Entry.Match> 580 | </Entry> 581 | <Entry DisplayName="Normal Fields"> 582 | <Entry.Match> 583 | <And> 584 | <Access Is="Private" /> 585 | <Not> 586 | <Or> 587 | <Static /> 588 | <Readonly /> 589 | </Or> 590 | </Not> 591 | <Kind Is="Field" /> 592 | </And> 593 | </Entry.Match> 594 | </Entry> 595 | </Group> 596 | <Entry DisplayName="Private Properties"> 597 | <Entry.Match> 598 | <And> 599 | <Access Is="Private" /> 600 | <Kind Is="Property" /> 601 | </And> 602 | </Entry.Match> 603 | </Entry> 604 | </Group> 605 | <Group DisplayName="Constructor/Destructor"> 606 | <Entry DisplayName="Ctor"> 607 | <Entry.Match> 608 | <Kind Is="Constructor" /> 609 | </Entry.Match> 610 | </Entry> 611 | <Region Name="Disposal"> 612 | <Entry DisplayName="Dtor"> 613 | <Entry.Match> 614 | <Kind Is="Destructor" /> 615 | </Entry.Match> 616 | </Entry> 617 | <Entry DisplayName="Dispose()"> 618 | <Entry.Match> 619 | <And> 620 | <Access Is="Public" /> 621 | <Kind Is="Method" /> 622 | <Name Is="Dispose" /> 623 | </And> 624 | </Entry.Match> 625 | </Entry> 626 | <Entry DisplayName="Dispose(true)"> 627 | <Entry.Match> 628 | <And> 629 | <Access Is="Protected" /> 630 | <Or> 631 | <Virtual /> 632 | <Override /> 633 | </Or> 634 | <Kind Is="Method" /> 635 | <Name Is="Dispose" /> 636 | </And> 637 | </Entry.Match> 638 | </Entry> 639 | </Region> 640 | </Group> 641 | <Group DisplayName="Methods"> 642 | <Group DisplayName="Public"> 643 | <Entry DisplayName="Static Methods"> 644 | <Entry.Match> 645 | <And> 646 | <Access Is="Public" /> 647 | <Static /> 648 | <Kind Is="Method" /> 649 | </And> 650 | </Entry.Match> 651 | </Entry> 652 | <Entry DisplayName="Methods"> 653 | <Entry.Match> 654 | <And> 655 | <Access Is="Public" /> 656 | <Not> 657 | <Static /> 658 | </Not> 659 | <Kind Is="Method" /> 660 | </And> 661 | </Entry.Match> 662 | </Entry> 663 | </Group> 664 | <Group DisplayName="Internal"> 665 | <Entry DisplayName="Static Methods"> 666 | <Entry.Match> 667 | <And> 668 | <Access Is="Internal" /> 669 | <Static /> 670 | <Kind Is="Method" /> 671 | </And> 672 | </Entry.Match> 673 | </Entry> 674 | <Entry DisplayName="Methods"> 675 | <Entry.Match> 676 | <And> 677 | <Access Is="Internal" /> 678 | <Not> 679 | <Static /> 680 | </Not> 681 | <Kind Is="Method" /> 682 | </And> 683 | </Entry.Match> 684 | </Entry> 685 | </Group> 686 | <Group DisplayName="Protected"> 687 | <Entry DisplayName="Static Methods"> 688 | <Entry.Match> 689 | <And> 690 | <Access Is="Protected" /> 691 | <Static /> 692 | <Kind Is="Method" /> 693 | </And> 694 | </Entry.Match> 695 | </Entry> 696 | <Entry DisplayName="Methods"> 697 | <Entry.Match> 698 | <And> 699 | <Access Is="Protected" /> 700 | <Not> 701 | <Static /> 702 | </Not> 703 | <Kind Is="Method" /> 704 | </And> 705 | </Entry.Match> 706 | </Entry> 707 | </Group> 708 | <Group DisplayName="Private"> 709 | <Entry DisplayName="Static Methods"> 710 | <Entry.Match> 711 | <And> 712 | <Access Is="Private" /> 713 | <Static /> 714 | <Kind Is="Method" /> 715 | </And> 716 | </Entry.Match> 717 | </Entry> 718 | <Entry DisplayName="Methods"> 719 | <Entry.Match> 720 | <And> 721 | <Access Is="Private" /> 722 | <Not> 723 | <Static /> 724 | </Not> 725 | <Kind Is="Method" /> 726 | </And> 727 | </Entry.Match> 728 | </Entry> 729 | </Group> 730 | </Group> 731 | </TypePattern> 732 | </Patterns> 733 | <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> 734 | <Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /> 735 | <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /> 736 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 737 | <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /> 738 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"><ExtraRule Prefix="_" Suffix="" Style="aaBb" /></Policy> 739 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 740 | <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /> 741 | <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> 742 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 743 | <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private methods"><ElementKinds><Kind Name="ASYNC_METHOD" /><Kind Name="METHOD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> 744 | <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public methods"><ElementKinds><Kind Name="ASYNC_METHOD" /><Kind Name="METHOD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy> 745 | <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private properties"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> 746 | <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public properties"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy> 747 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 748 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 749 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 750 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 751 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 752 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 753 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 754 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 755 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 756 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 757 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 758 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 759 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 760 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 761 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 762 | <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> 763 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 764 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 765 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 766 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 767 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 768 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 769 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 770 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 771 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 772 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 773 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 774 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 775 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 776 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 777 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 778 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 779 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 780 | <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> 781 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 782 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 783 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 784 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 785 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> 786 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 787 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> 788 | 789 | True 790 | True 791 | True 792 | True 793 | True 794 | True 795 | True 796 | True 797 | True 798 | True 799 | True 800 | TestFolder 801 | True 802 | True 803 | o!f – Object Initializer: Anchor&Origin 804 | True 805 | constant("Centre") 806 | 0 807 | True 808 | True 809 | 2.0 810 | InCSharpFile 811 | ofao 812 | True 813 | Anchor = Anchor.$anchor$, 814 | Origin = Anchor.$anchor$, 815 | True 816 | True 817 | o!f – InternalChildren = [] 818 | True 819 | True 820 | 2.0 821 | InCSharpFile 822 | ofic 823 | True 824 | InternalChildren = new Drawable[] 825 | { 826 | $END$ 827 | }; 828 | True 829 | True 830 | o!f – new GridContainer { .. } 831 | True 832 | True 833 | 2.0 834 | InCSharpFile 835 | ofgc 836 | True 837 | new GridContainer 838 | { 839 | RelativeSizeAxes = Axes.Both, 840 | Content = new[] 841 | { 842 | new Drawable[] { $END$ }, 843 | new Drawable[] { } 844 | } 845 | }; 846 | True 847 | True 848 | o!f – new FillFlowContainer { .. } 849 | True 850 | True 851 | 2.0 852 | InCSharpFile 853 | offf 854 | True 855 | new FillFlowContainer 856 | { 857 | RelativeSizeAxes = Axes.Both, 858 | Direction = FillDirection.Vertical, 859 | Children = new Drawable[] 860 | { 861 | $END$ 862 | } 863 | }, 864 | True 865 | True 866 | o!f – new Container { .. } 867 | True 868 | True 869 | 2.0 870 | InCSharpFile 871 | ofcont 872 | True 873 | new Container 874 | { 875 | RelativeSizeAxes = Axes.Both, 876 | Children = new Drawable[] 877 | { 878 | $END$ 879 | } 880 | }, 881 | True 882 | True 883 | o!f – BackgroundDependencyLoader load() 884 | True 885 | True 886 | 2.0 887 | InCSharpFile 888 | ofbdl 889 | True 890 | [BackgroundDependencyLoader] 891 | private void load() 892 | { 893 | $END$ 894 | } 895 | True 896 | True 897 | o!f – new Box { .. } 898 | True 899 | True 900 | 2.0 901 | InCSharpFile 902 | ofbox 903 | True 904 | new Box 905 | { 906 | Colour = Color4.Black, 907 | RelativeSizeAxes = Axes.Both, 908 | }, 909 | True 910 | True 911 | o!f – Children = [] 912 | True 913 | True 914 | 2.0 915 | InCSharpFile 916 | ofc 917 | True 918 | Children = new Drawable[] 919 | { 920 | $END$ 921 | }; 922 | True 923 | True 924 | True 925 | True 926 | True 927 | True 928 | True 929 | True 930 | True 931 | True 932 | True 933 | True 934 | True 935 | True 936 | True 937 | True 938 | True 939 | True 940 | True 941 | True 942 | True 943 | True 944 | True 945 | True 946 | True 947 | True 948 | True 949 | True 950 | True 951 | True 952 | True 953 | True 954 | True 955 | True 956 | True 957 | True 958 | True 959 | True 960 | True 961 | True 962 | True 963 | True 964 | True 965 | True 966 | True 967 | True 968 | True 969 | True 970 | True 971 | True 972 | True 973 | True 974 | True 975 | True 976 | True 977 | True 978 | True 979 | True 980 | True 981 | True 982 | True 983 | True 984 | True 985 | True 986 | True 987 | True 988 | True 989 | True 990 | True 991 | True 992 | True 993 | True 994 | True 995 | True 996 | True 997 | True 998 | True 999 | True 1000 | True 1001 | --------------------------------------------------------------------------------