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

Allow unstacking mods

This commit is contained in:
smoogipoo 2021-02-01 13:24:56 +09:00
parent 230b347c1e
commit 797a810287
3 changed files with 45 additions and 7 deletions

View File

@ -22,6 +22,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens;
using osu.Game.Utils;
using osuTK;
using osuTK.Graphics;
using osuTK.Input;
@ -46,9 +47,27 @@ namespace osu.Game.Overlays.Mods
protected readonly ModSettingsContainer ModSettingsContainer;
private bool stacked = true;
/// <summary>
/// Whether mod icons should be stacked, or appear as individual buttons.
/// </summary>
public bool Stacked
{
get => stacked;
set
{
stacked = value;
updateAvailableMods();
}
}
[NotNull]
private Func<Mod, bool> isValidMod = m => true;
/// <summary>
/// A function that checks whether a given mod is valid.
/// </summary>
[NotNull]
public Func<Mod, bool> IsValidMod
{
@ -419,11 +438,18 @@ namespace osu.Game.Overlays.Mods
private void updateAvailableMods()
{
if (availableMods.Value == null)
if (availableMods?.Value == null)
return;
foreach (var section in ModSectionsContainer.Children)
section.Mods = availableMods.Value[section.ModType].Where(IsValidMod);
{
IEnumerable<Mod> modEnumeration = availableMods.Value[section.ModType];
if (!stacked)
modEnumeration = ModValidation.FlattenMods(modEnumeration);
section.Mods = modEnumeration.Where(IsValidMod);
}
}
private void selectedModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)

View File

@ -14,6 +14,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
{
public class FreeModSelectOverlay : ModSelectOverlay
{
public FreeModSelectOverlay()
{
Stacked = false;
}
protected override ModSection CreateModSection(ModType type) => new FreeModSection(type);
private class FreeModSection : ModSection

View File

@ -42,7 +42,7 @@ namespace osu.Game.Utils
var incompatibleTypes = new HashSet<Type>();
var incomingTypes = new HashSet<Type>();
foreach (var mod in combination.SelectMany(flattenMod))
foreach (var mod in combination.SelectMany(FlattenMod))
{
// Add the new mod incompatibilities, checking whether any match the existing mod types.
foreach (var t in mod.IncompatibleMods)
@ -79,7 +79,7 @@ namespace osu.Game.Utils
{
var allowedSet = new HashSet<Type>(allowedTypes);
return combination.SelectMany(flattenMod)
return combination.SelectMany(FlattenMod)
.All(m => allowedSet.Contains(m.GetType()));
}
@ -93,20 +93,27 @@ namespace osu.Game.Utils
/// <param name="incompatibleTypes">The set of incompatible <see cref="Mod"/> types.</param>
/// <returns>Whether the given <see cref="Mod"/> is incompatible.</returns>
private static bool isModIncompatible(Mod mod, ICollection<Type> incompatibleTypes)
=> flattenMod(mod)
=> FlattenMod(mod)
.SelectMany(m => m.GetType().EnumerateBaseTypes())
.Any(incompatibleTypes.Contains);
/// <summary>
/// Flattens a set of <see cref="Mod"/>s, returning a new set with all <see cref="MultiMod"/>s removed.
/// </summary>
/// <param name="mods">The set of <see cref="Mod"/>s to flatten.</param>
/// <returns>The new set, containing all <see cref="Mod"/>s in <paramref name="mods"/> recursively with all <see cref="MultiMod"/>s removed.</returns>
public static IEnumerable<Mod> FlattenMods(IEnumerable<Mod> mods) => mods.SelectMany(FlattenMod);
/// <summary>
/// Flattens a <see cref="Mod"/>, returning a set of <see cref="Mod"/>s in-place of any <see cref="MultiMod"/>s.
/// </summary>
/// <param name="mod">The <see cref="Mod"/> to flatten.</param>
/// <returns>A set of singular "flattened" <see cref="Mod"/>s</returns>
private static IEnumerable<Mod> flattenMod(Mod mod)
public static IEnumerable<Mod> FlattenMod(Mod mod)
{
if (mod is MultiMod multi)
{
foreach (var m in multi.Mods.SelectMany(flattenMod))
foreach (var m in multi.Mods.SelectMany(FlattenMod))
yield return m;
}
else