mirror of
https://github.com/ppy/osu.git
synced 2025-02-15 07:32:58 +08:00
Merge pull request #14441 from Henry-YSLin/mod-incompatibility-ui
Show mods that are incompatible with the current selection
This commit is contained in:
commit
6a916a264f
64
osu.Game/Overlays/Mods/IncompatibleIcon.cs
Normal file
64
osu.Game/Overlays/Mods/IncompatibleIcon.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Mods
|
||||||
|
{
|
||||||
|
public class IncompatibleIcon : VisibilityContainer, IHasTooltip
|
||||||
|
{
|
||||||
|
private Circle circle;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
Size = new Vector2(20);
|
||||||
|
|
||||||
|
State.Value = Visibility.Hidden;
|
||||||
|
Alpha = 0;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
circle = new Circle
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.Gray4,
|
||||||
|
},
|
||||||
|
new SpriteIcon
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Size = new Vector2(0.6f),
|
||||||
|
Icon = FontAwesome.Solid.Slash,
|
||||||
|
Colour = Color4.White,
|
||||||
|
Shadow = true,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn()
|
||||||
|
{
|
||||||
|
this.FadeIn(200, Easing.OutQuint);
|
||||||
|
circle.FlashColour(Color4.Red, 500, Easing.OutQuint);
|
||||||
|
this.ScaleTo(1.8f).Then().ScaleTo(1, 500, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopOut()
|
||||||
|
{
|
||||||
|
this.FadeOut(200, Easing.OutQuint);
|
||||||
|
this.ScaleTo(0.8f, 200, Easing.In);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalisableString TooltipText => "Incompatible with current selected mods";
|
||||||
|
}
|
||||||
|
}
|
@ -11,24 +11,29 @@ using osu.Game.Graphics.Sprites;
|
|||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Utils;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Mods
|
namespace osu.Game.Overlays.Mods
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a clickable button which can cycle through one of more mods.
|
/// Represents a clickable button which can cycle through one of more mods.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ModButton : ModButtonEmpty, IHasTooltip
|
public class ModButton : ModButtonEmpty, IHasCustomTooltip
|
||||||
{
|
{
|
||||||
private ModIcon foregroundIcon;
|
private ModIcon foregroundIcon;
|
||||||
private ModIcon backgroundIcon;
|
private ModIcon backgroundIcon;
|
||||||
private readonly SpriteText text;
|
private readonly SpriteText text;
|
||||||
private readonly Container<ModIcon> iconsContainer;
|
private readonly Container<ModIcon> iconsContainer;
|
||||||
|
private readonly CompositeDrawable incompatibleIcon;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when the selection changes.
|
/// Fired when the selection changes.
|
||||||
@ -43,6 +48,9 @@ namespace osu.Game.Overlays.Mods
|
|||||||
// A selected index of -1 means not selected.
|
// A selected index of -1 means not selected.
|
||||||
private int selectedIndex = -1;
|
private int selectedIndex = -1;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private Bindable<IReadOnlyList<Mod>> selectedMods { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change the selected mod index of this button.
|
/// Change the selected mod index of this button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -237,6 +245,23 @@ namespace osu.Game.Overlays.Mods
|
|||||||
foregroundIcon.Mod = mod;
|
foregroundIcon.Mod = mod;
|
||||||
text.Text = mod.Name;
|
text.Text = mod.Name;
|
||||||
Colour = mod.HasImplementation ? Color4.White : Color4.Gray;
|
Colour = mod.HasImplementation ? Color4.White : Color4.Gray;
|
||||||
|
|
||||||
|
Scheduler.AddOnce(updateCompatibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCompatibility()
|
||||||
|
{
|
||||||
|
var m = SelectedMod ?? Mods.First();
|
||||||
|
|
||||||
|
bool isIncompatible = false;
|
||||||
|
|
||||||
|
if (selectedMods.Value.Count > 0 && !selectedMods.Value.Contains(m))
|
||||||
|
isIncompatible = !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(m));
|
||||||
|
|
||||||
|
if (isIncompatible)
|
||||||
|
incompatibleIcon.Show();
|
||||||
|
else
|
||||||
|
incompatibleIcon.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createIcons()
|
private void createIcons()
|
||||||
@ -284,11 +309,20 @@ namespace osu.Game.Overlays.Mods
|
|||||||
{
|
{
|
||||||
scaleContainer = new Container
|
scaleContainer = new Container
|
||||||
{
|
{
|
||||||
Child = iconsContainer = new Container<ModIcon>
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
iconsContainer = new Container<ModIcon>
|
||||||
Origin = Anchor.Centre,
|
{
|
||||||
Anchor = Anchor.Centre,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
},
|
||||||
|
incompatibleIcon = new IncompatibleIcon
|
||||||
|
{
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.BottomRight,
|
||||||
|
Position = new Vector2(-13),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
@ -305,8 +339,18 @@ namespace osu.Game.Overlays.Mods
|
|||||||
},
|
},
|
||||||
new HoverSounds()
|
new HoverSounds()
|
||||||
};
|
};
|
||||||
|
|
||||||
Mod = mod;
|
Mod = mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
selectedMods.BindValueChanged(_ => Scheduler.AddOnce(updateCompatibility), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITooltip GetCustomTooltip() => new ModButtonTooltip();
|
||||||
|
|
||||||
|
public object TooltipContent => SelectedMod ?? Mods.FirstOrDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
115
osu.Game/Overlays/Mods/ModButtonTooltip.cs
Normal file
115
osu.Game/Overlays/Mods/ModButtonTooltip.cs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Screens.Play.HUD;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Mods
|
||||||
|
{
|
||||||
|
public class ModButtonTooltip : VisibilityContainer, ITooltip
|
||||||
|
{
|
||||||
|
private readonly OsuSpriteText descriptionText;
|
||||||
|
private readonly Box background;
|
||||||
|
private readonly OsuSpriteText incompatibleText;
|
||||||
|
|
||||||
|
private readonly Bindable<IReadOnlyList<Mod>> incompatibleMods = new Bindable<IReadOnlyList<Mod>>();
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private Bindable<RulesetInfo> ruleset { get; set; }
|
||||||
|
|
||||||
|
public ModButtonTooltip()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
Masking = true;
|
||||||
|
CornerRadius = 5;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Padding = new MarginPadding { Left = 10, Right = 10, Top = 5, Bottom = 5 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
descriptionText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(weight: FontWeight.Regular),
|
||||||
|
Margin = new MarginPadding { Bottom = 5 }
|
||||||
|
},
|
||||||
|
incompatibleText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(weight: FontWeight.Regular),
|
||||||
|
Text = "Incompatible with:"
|
||||||
|
},
|
||||||
|
new ModDisplay
|
||||||
|
{
|
||||||
|
Current = incompatibleMods,
|
||||||
|
ExpansionMode = ExpansionMode.AlwaysExpanded,
|
||||||
|
Scale = new Vector2(0.7f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
background.Colour = colours.Gray3;
|
||||||
|
descriptionText.Colour = colours.BlueLighter;
|
||||||
|
incompatibleText.Colour = colours.BlueLight;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn() => this.FadeIn(200, Easing.OutQuint);
|
||||||
|
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
|
||||||
|
|
||||||
|
private Mod lastMod;
|
||||||
|
|
||||||
|
public bool SetContent(object content)
|
||||||
|
{
|
||||||
|
if (!(content is Mod mod))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mod.Equals(lastMod)) return true;
|
||||||
|
|
||||||
|
lastMod = mod;
|
||||||
|
|
||||||
|
descriptionText.Text = mod.Description;
|
||||||
|
|
||||||
|
var incompatibleTypes = mod.IncompatibleMods;
|
||||||
|
|
||||||
|
var allMods = ruleset.Value.CreateInstance().GetAllMods();
|
||||||
|
|
||||||
|
incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList();
|
||||||
|
|
||||||
|
if (!incompatibleMods.Value.Any())
|
||||||
|
{
|
||||||
|
incompatibleText.Text = "Compatible with all mods";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
incompatibleText.Text = "Incompatible with:";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Move(Vector2 pos) => Position = pos;
|
||||||
|
}
|
||||||
|
}
|
@ -74,6 +74,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
protected readonly ModSettingsContainer ModSettingsContainer;
|
protected readonly ModSettingsContainer ModSettingsContainer;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
public readonly Bindable<IReadOnlyList<Mod>> SelectedMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
public readonly Bindable<IReadOnlyList<Mod>> SelectedMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||||
|
|
||||||
private Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods;
|
private Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods;
|
||||||
|
Loading…
Reference in New Issue
Block a user