mirror of
https://github.com/ppy/osu.git
synced 2025-01-15 06:42:56 +08:00
Merge branch 'master' into on-drawable-hitobject-added
This commit is contained in:
commit
87ce8a53ff
@ -5,7 +5,7 @@ using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModEasy : ModEasy
|
||||
public class CatchModEasy : ModEasyWithExtraLives
|
||||
{
|
||||
public override string Description => @"Larger fruits, more forgiving HP drain, less accuracy required, and three lives!";
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModEasy : ModEasy
|
||||
public class ManiaModEasy : ModEasyWithExtraLives
|
||||
{
|
||||
public override string Description => @"More forgiving HP drain, less accuracy required, and three lives!";
|
||||
}
|
||||
|
@ -44,6 +44,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IEditorChangeHandler changeHandler { get; set; }
|
||||
|
||||
private readonly BindableList<PathControlPoint> controlPoints = new BindableList<PathControlPoint>();
|
||||
private readonly IBindable<int> pathVersion = new Bindable<int>();
|
||||
|
||||
public SliderSelectionBlueprint(DrawableSlider slider)
|
||||
: base(slider)
|
||||
{
|
||||
@ -61,13 +64,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
};
|
||||
}
|
||||
|
||||
private IBindable<int> pathVersion;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
pathVersion = HitObject.Path.Version.GetBoundCopy();
|
||||
controlPoints.BindTo(HitObject.Path.ControlPoints);
|
||||
|
||||
pathVersion.BindTo(HitObject.Path.Version);
|
||||
pathVersion.BindValueChanged(_ => updatePath());
|
||||
|
||||
BodyPiece.UpdateFrom(HitObject);
|
||||
@ -164,8 +167,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
}
|
||||
}
|
||||
|
||||
private BindableList<PathControlPoint> controlPoints => HitObject.Path.ControlPoints;
|
||||
|
||||
private int addControlPoint(Vector2 position)
|
||||
{
|
||||
position -= HitObject.Position;
|
||||
|
@ -5,7 +5,7 @@ using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public class OsuModEasy : ModEasy
|
||||
public class OsuModEasy : ModEasyWithExtraLives
|
||||
{
|
||||
public override string Description => @"Larger circles, more forgiving HP drain, less accuracy required, and three lives!";
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Bindables;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
@ -47,6 +48,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
});
|
||||
}
|
||||
|
||||
public double AnimationStartTime { get; set; }
|
||||
public Bindable<double> AnimationStartTime { get; } = new BindableDouble();
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
fp.Alpha = 0;
|
||||
fp.Scale = new Vector2(1.5f * end.Scale);
|
||||
|
||||
fp.AnimationStartTime = fadeInTime;
|
||||
fp.AnimationStartTime.Value = fadeInTime;
|
||||
|
||||
using (fp.BeginAbsoluteSequence(fadeInTime))
|
||||
{
|
||||
|
@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
{
|
||||
public class TaikoModEasy : ModEasy
|
||||
{
|
||||
public override string Description => @"Beats move slower, less accuracy required, and three lives!";
|
||||
public override string Description => @"Beats move slower, and less accuracy required!";
|
||||
}
|
||||
}
|
||||
|
79
osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs
Normal file
79
osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs
Normal file
@ -0,0 +1,79 @@
|
||||
// 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;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Tests.NonVisual.Skinning
|
||||
{
|
||||
[HeadlessTest]
|
||||
public class LegacySkinAnimationTest : OsuTestScene
|
||||
{
|
||||
private const string animation_name = "animation";
|
||||
private const int frame_count = 6;
|
||||
|
||||
[Cached(typeof(IAnimationTimeReference))]
|
||||
private TestAnimationTimeReference animationTimeReference = new TestAnimationTimeReference();
|
||||
|
||||
private TextureAnimation animation;
|
||||
|
||||
[Test]
|
||||
public void TestAnimationTimeReferenceChange()
|
||||
{
|
||||
ISkin skin = new TestSkin();
|
||||
|
||||
AddStep("get animation", () => Add(animation = (TextureAnimation)skin.GetAnimation(animation_name, true, false)));
|
||||
AddAssert("frame count correct", () => animation.FrameCount == frame_count);
|
||||
assertPlaybackPosition(0);
|
||||
|
||||
AddStep("set start time to 1000", () => animationTimeReference.AnimationStartTime.Value = 1000);
|
||||
assertPlaybackPosition(-1000);
|
||||
|
||||
AddStep("set current time to 500", () => animationTimeReference.ManualClock.CurrentTime = 500);
|
||||
assertPlaybackPosition(-500);
|
||||
}
|
||||
|
||||
private void assertPlaybackPosition(double expectedPosition)
|
||||
=> AddAssert($"playback position is {expectedPosition}", () => animation.PlaybackPosition == expectedPosition);
|
||||
|
||||
private class TestSkin : ISkin
|
||||
{
|
||||
private static readonly string[] lookup_names = Enumerable.Range(0, frame_count).Select(frame => $"{animation_name}-{frame}").ToArray();
|
||||
|
||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
|
||||
{
|
||||
return lookup_names.Contains(componentName) ? Texture.WhitePixel : null;
|
||||
}
|
||||
|
||||
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException();
|
||||
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException();
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
private class TestAnimationTimeReference : IAnimationTimeReference
|
||||
{
|
||||
public ManualClock ManualClock { get; }
|
||||
public IFrameBasedClock Clock { get; }
|
||||
public Bindable<double> AnimationStartTime { get; } = new BindableDouble();
|
||||
|
||||
public TestAnimationTimeReference()
|
||||
{
|
||||
ManualClock = new ManualClock();
|
||||
Clock = new FramedClock(ManualClock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -318,7 +318,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
private class FadeAccessibleResults : ResultsScreen
|
||||
{
|
||||
public FadeAccessibleResults(ScoreInfo score)
|
||||
: base(score)
|
||||
: base(score, true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -256,7 +256,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
public HotkeyRetryOverlay RetryOverlay;
|
||||
|
||||
public TestResultsScreen(ScoreInfo score)
|
||||
: base(score)
|
||||
: base(score, true)
|
||||
{
|
||||
}
|
||||
|
||||
@ -326,7 +326,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
public HotkeyRetryOverlay RetryOverlay;
|
||||
|
||||
public UnrankedSoloResultsScreen(ScoreInfo score)
|
||||
: base(score)
|
||||
: base(score, true)
|
||||
{
|
||||
Score.Beatmap.OnlineBeatmapID = 0;
|
||||
Score.Beatmap.Status = BeatmapSetOnlineStatus.Pending;
|
||||
|
@ -11,12 +11,12 @@ using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestScenePaginatedContainerHeader : OsuTestScene
|
||||
public class TestSceneProfileSubsectionHeader : OsuTestScene
|
||||
{
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
|
||||
|
||||
private PaginatedContainerHeader header;
|
||||
private ProfileSubsectionHeader header;
|
||||
|
||||
[Test]
|
||||
public void TestHiddenCounter()
|
||||
@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
private void createHeader(string text, CounterVisibilityState state, int initialValue = 0)
|
||||
{
|
||||
Clear();
|
||||
Add(header = new PaginatedContainerHeader(text, state)
|
||||
Add(header = new ProfileSubsectionHeader(text, state)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
@ -196,7 +196,7 @@ namespace osu.Game.Configuration
|
||||
|
||||
public Func<int, string> LookupSkinName { private get; set; }
|
||||
|
||||
public Func<GlobalAction, string> LookupKeyBindings { private get; set; }
|
||||
public Func<GlobalAction, string> LookupKeyBindings { get; set; }
|
||||
}
|
||||
|
||||
public enum OsuSetting
|
||||
|
@ -420,7 +420,7 @@ namespace osu.Game
|
||||
break;
|
||||
|
||||
case ScorePresentType.Results:
|
||||
screen.Push(new SoloResultsScreen(databasedScore.ScoreInfo));
|
||||
screen.Push(new SoloResultsScreen(databasedScore.ScoreInfo, false));
|
||||
break;
|
||||
}
|
||||
}, validScreens: new[] { typeof(PlaySongSelect) });
|
||||
|
@ -6,6 +6,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Overlays.OSD;
|
||||
|
||||
@ -37,11 +38,11 @@ namespace osu.Game.Overlays.Music
|
||||
bool wasPlaying = musicController.IsPlaying;
|
||||
|
||||
if (musicController.TogglePause())
|
||||
onScreenDisplay?.Display(new MusicActionToast(wasPlaying ? "Pause track" : "Play track"));
|
||||
onScreenDisplay?.Display(new MusicActionToast(wasPlaying ? "Pause track" : "Play track", action));
|
||||
return true;
|
||||
|
||||
case GlobalAction.MusicNext:
|
||||
musicController.NextTrack(() => onScreenDisplay?.Display(new MusicActionToast("Next track")));
|
||||
musicController.NextTrack(() => onScreenDisplay?.Display(new MusicActionToast("Next track", action)));
|
||||
|
||||
return true;
|
||||
|
||||
@ -51,11 +52,11 @@ namespace osu.Game.Overlays.Music
|
||||
switch (res)
|
||||
{
|
||||
case PreviousTrackResult.Restart:
|
||||
onScreenDisplay?.Display(new MusicActionToast("Restart track"));
|
||||
onScreenDisplay?.Display(new MusicActionToast("Restart track", action));
|
||||
break;
|
||||
|
||||
case PreviousTrackResult.Previous:
|
||||
onScreenDisplay?.Display(new MusicActionToast("Previous track"));
|
||||
onScreenDisplay?.Display(new MusicActionToast("Previous track", action));
|
||||
break;
|
||||
}
|
||||
});
|
||||
@ -72,9 +73,18 @@ namespace osu.Game.Overlays.Music
|
||||
|
||||
private class MusicActionToast : Toast
|
||||
{
|
||||
public MusicActionToast(string action)
|
||||
: base("Music Playback", action, string.Empty)
|
||||
private readonly GlobalAction action;
|
||||
|
||||
public MusicActionToast(string value, GlobalAction action)
|
||||
: base("Music Playback", value, string.Empty)
|
||||
{
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
ShortcutText.Text = config.LookupKeyBindings(action).ToUpperInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,13 @@ namespace osu.Game.Overlays.OSD
|
||||
private const int toast_minimum_width = 240;
|
||||
|
||||
private readonly Container content;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
protected readonly OsuSpriteText ValueText;
|
||||
|
||||
protected readonly OsuSpriteText ShortcutText;
|
||||
|
||||
protected Toast(string description, string value, string shortcut)
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
@ -68,7 +71,7 @@ namespace osu.Game.Overlays.OSD
|
||||
Origin = Anchor.Centre,
|
||||
Text = value
|
||||
},
|
||||
new OsuSpriteText
|
||||
ShortcutText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
|
@ -14,7 +14,7 @@ using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Beatmaps
|
||||
{
|
||||
public class PaginatedBeatmapContainer : PaginatedContainer<APIBeatmapSet>
|
||||
public class PaginatedBeatmapContainer : PaginatedProfileSubsection<APIBeatmapSet>
|
||||
{
|
||||
private const float panel_padding = 10f;
|
||||
private readonly BeatmapSetType type;
|
||||
|
@ -13,7 +13,7 @@ using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Historical
|
||||
{
|
||||
public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer<APIUserMostPlayedBeatmap>
|
||||
public class PaginatedMostPlayedBeatmapContainer : PaginatedProfileSubsection<APIUserMostPlayedBeatmap>
|
||||
{
|
||||
public PaginatedMostPlayedBeatmapContainer(Bindable<User> user)
|
||||
: base(user, "Most Played Beatmaps", "No records. :(", CounterVisibilityState.AlwaysVisible)
|
||||
|
@ -11,7 +11,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Kudosu
|
||||
{
|
||||
public class PaginatedKudosuHistoryContainer : PaginatedContainer<APIKudosuHistory>
|
||||
public class PaginatedKudosuHistoryContainer : PaginatedProfileSubsection<APIKudosuHistory>
|
||||
{
|
||||
public PaginatedKudosuHistoryContainer(Bindable<User> user)
|
||||
: base(user, missingText: "This user hasn't received any kudosu!")
|
||||
|
@ -6,62 +6,51 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections
|
||||
{
|
||||
public abstract class PaginatedContainer<TModel> : FillFlowContainer
|
||||
public abstract class PaginatedProfileSubsection<TModel> : ProfileSubsection
|
||||
{
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
[Resolved]
|
||||
protected RulesetStore Rulesets { get; private set; }
|
||||
|
||||
protected int VisiblePages;
|
||||
protected int ItemsPerPage;
|
||||
|
||||
protected readonly Bindable<User> User = new Bindable<User>();
|
||||
protected FillFlowContainer ItemsContainer;
|
||||
protected RulesetStore Rulesets;
|
||||
protected FillFlowContainer ItemsContainer { get; private set; }
|
||||
|
||||
private APIRequest<List<TModel>> retrievalRequest;
|
||||
private CancellationTokenSource loadCancellation;
|
||||
|
||||
private readonly string missingText;
|
||||
private ShowMoreButton moreButton;
|
||||
private OsuSpriteText missing;
|
||||
private PaginatedContainerHeader header;
|
||||
private readonly string missingText;
|
||||
|
||||
private readonly string headerText;
|
||||
private readonly CounterVisibilityState counterVisibilityState;
|
||||
|
||||
protected PaginatedContainer(Bindable<User> user, string headerText = "", string missingText = "", CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden)
|
||||
protected PaginatedProfileSubsection(Bindable<User> user, string headerText = "", string missingText = "", CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden)
|
||||
: base(user, headerText, counterVisibilityState)
|
||||
{
|
||||
this.headerText = headerText;
|
||||
this.missingText = missingText;
|
||||
this.counterVisibilityState = counterVisibilityState;
|
||||
User.BindTo(user);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
protected override Drawable CreateContent() => new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Direction = FillDirection.Vertical;
|
||||
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
header = new PaginatedContainerHeader(headerText, counterVisibilityState)
|
||||
{
|
||||
Alpha = string.IsNullOrEmpty(headerText) ? 0 : 1
|
||||
},
|
||||
ItemsContainer = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
@ -81,13 +70,14 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
Font = OsuFont.GetFont(size: 15),
|
||||
Text = missingText,
|
||||
Alpha = 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Rulesets = rulesets;
|
||||
|
||||
User.ValueChanged += onUserChanged;
|
||||
User.TriggerChange();
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
User.BindValueChanged(onUserChanged, true);
|
||||
}
|
||||
|
||||
private void onUserChanged(ValueChangedEvent<User> e)
|
||||
@ -124,7 +114,7 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
moreButton.Hide();
|
||||
moreButton.IsLoading = false;
|
||||
|
||||
if (!string.IsNullOrEmpty(missing.Text))
|
||||
if (!string.IsNullOrEmpty(missingText))
|
||||
missing.Show();
|
||||
|
||||
return;
|
||||
@ -142,8 +132,6 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
|
||||
protected virtual int GetCount(User user) => 0;
|
||||
|
||||
protected void SetCount(int value) => header.Current.Value = value;
|
||||
|
||||
protected virtual void OnItemsReceived(List<TModel> items)
|
||||
{
|
||||
}
|
||||
@ -154,8 +142,9 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
retrievalRequest?.Cancel();
|
||||
loadCancellation?.Cancel();
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
}
|
51
osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
Normal file
51
osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs
Normal file
@ -0,0 +1,51 @@
|
||||
// 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.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Users;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections
|
||||
{
|
||||
public abstract class ProfileSubsection : FillFlowContainer
|
||||
{
|
||||
protected readonly Bindable<User> User = new Bindable<User>();
|
||||
|
||||
private readonly string headerText;
|
||||
private readonly CounterVisibilityState counterVisibilityState;
|
||||
|
||||
private ProfileSubsectionHeader header;
|
||||
|
||||
protected ProfileSubsection(Bindable<User> user, string headerText = "", CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden)
|
||||
{
|
||||
this.headerText = headerText;
|
||||
this.counterVisibilityState = counterVisibilityState;
|
||||
User.BindTo(user);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Direction = FillDirection.Vertical;
|
||||
|
||||
Children = new[]
|
||||
{
|
||||
header = new ProfileSubsectionHeader(headerText, counterVisibilityState)
|
||||
{
|
||||
Alpha = string.IsNullOrEmpty(headerText) ? 0 : 1
|
||||
},
|
||||
CreateContent()
|
||||
};
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
protected abstract Drawable CreateContent();
|
||||
|
||||
protected void SetCount(int value) => header.Current.Value = value;
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections
|
||||
{
|
||||
public class PaginatedContainerHeader : CompositeDrawable, IHasCurrentValue<int>
|
||||
public class ProfileSubsectionHeader : CompositeDrawable, IHasCurrentValue<int>
|
||||
{
|
||||
private readonly BindableWithCurrent<int> current = new BindableWithCurrent<int>();
|
||||
|
||||
@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
|
||||
private CounterPill counterPill;
|
||||
|
||||
public PaginatedContainerHeader(string text, CounterVisibilityState counterState)
|
||||
public ProfileSubsectionHeader(string text, CounterVisibilityState counterState)
|
||||
{
|
||||
this.text = text;
|
||||
this.counterState = counterState;
|
@ -14,7 +14,7 @@ using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
public class PaginatedScoreContainer : PaginatedContainer<APILegacyScoreInfo>
|
||||
public class PaginatedScoreContainer : PaginatedProfileSubsection<APILegacyScoreInfo>
|
||||
{
|
||||
private readonly ScoreType type;
|
||||
|
||||
|
@ -13,7 +13,7 @@ using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Recent
|
||||
{
|
||||
public class PaginatedRecentActivityContainer : PaginatedContainer<APIRecentActivity>
|
||||
public class PaginatedRecentActivityContainer : PaginatedProfileSubsection<APIRecentActivity>
|
||||
{
|
||||
public PaginatedRecentActivityContainer(Bindable<User> user)
|
||||
: base(user, missingText: "This user hasn't done anything notable recently!")
|
||||
|
@ -149,7 +149,10 @@ namespace osu.Game.Rulesets.Judgements
|
||||
|
||||
private void runAnimation()
|
||||
{
|
||||
// undo any transforms applies in ApplyMissAnimations/ApplyHitAnimations to get a sane initial state.
|
||||
ApplyTransformsAt(double.MinValue, true);
|
||||
ClearTransforms(true);
|
||||
|
||||
LifetimeStart = Result.TimeAbsolute;
|
||||
|
||||
using (BeginAbsoluteSequence(Result.TimeAbsolute, true))
|
||||
|
@ -2,17 +2,13 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using Humanizer;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public abstract class ModEasy : Mod, IApplicableToDifficulty, IApplicableFailOverride, IApplicableToHealthProcessor
|
||||
public abstract class ModEasy : Mod, IApplicableToDifficulty
|
||||
{
|
||||
public override string Name => "Easy";
|
||||
public override string Acronym => "EZ";
|
||||
@ -22,49 +18,17 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override bool Ranked => true;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModHardRock), typeof(ModDifficultyAdjust) };
|
||||
|
||||
[SettingSource("Extra Lives", "Number of extra lives")]
|
||||
public Bindable<int> Retries { get; } = new BindableInt(2)
|
||||
{
|
||||
MinValue = 0,
|
||||
MaxValue = 10
|
||||
};
|
||||
|
||||
public override string SettingDescription => Retries.IsDefault ? string.Empty : $"{"lives".ToQuantity(Retries.Value)}";
|
||||
|
||||
private int retries;
|
||||
|
||||
private BindableNumber<double> health;
|
||||
|
||||
public void ReadFromDifficulty(BeatmapDifficulty difficulty)
|
||||
public virtual void ReadFromDifficulty(BeatmapDifficulty difficulty)
|
||||
{
|
||||
}
|
||||
|
||||
public void ApplyToDifficulty(BeatmapDifficulty difficulty)
|
||||
public virtual void ApplyToDifficulty(BeatmapDifficulty difficulty)
|
||||
{
|
||||
const float ratio = 0.5f;
|
||||
difficulty.CircleSize *= ratio;
|
||||
difficulty.ApproachRate *= ratio;
|
||||
difficulty.DrainRate *= ratio;
|
||||
difficulty.OverallDifficulty *= ratio;
|
||||
|
||||
retries = Retries.Value;
|
||||
}
|
||||
|
||||
public bool PerformFail()
|
||||
{
|
||||
if (retries == 0) return true;
|
||||
|
||||
health.Value = health.MaxValue;
|
||||
retries--;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool RestartOnFail => false;
|
||||
|
||||
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
|
||||
{
|
||||
health = healthProcessor.Health.GetBoundCopy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
50
osu.Game/Rulesets/Mods/ModEasyWithExtraLives.cs
Normal file
50
osu.Game/Rulesets/Mods/ModEasyWithExtraLives.cs
Normal file
@ -0,0 +1,50 @@
|
||||
// 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 Humanizer;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public abstract class ModEasyWithExtraLives : ModEasy, IApplicableFailOverride, IApplicableToHealthProcessor
|
||||
{
|
||||
[SettingSource("Extra Lives", "Number of extra lives")]
|
||||
public Bindable<int> Retries { get; } = new BindableInt(2)
|
||||
{
|
||||
MinValue = 0,
|
||||
MaxValue = 10
|
||||
};
|
||||
|
||||
public override string SettingDescription => Retries.IsDefault ? string.Empty : $"{"lives".ToQuantity(Retries.Value)}";
|
||||
|
||||
private int retries;
|
||||
|
||||
private BindableNumber<double> health;
|
||||
|
||||
public override void ApplyToDifficulty(BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyToDifficulty(difficulty);
|
||||
retries = Retries.Value;
|
||||
}
|
||||
|
||||
public bool PerformFail()
|
||||
{
|
||||
if (retries == 0) return true;
|
||||
|
||||
health.Value = health.MaxValue;
|
||||
retries--;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool RestartOnFail => false;
|
||||
|
||||
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
|
||||
{
|
||||
health = healthProcessor.Health.GetBoundCopy();
|
||||
}
|
||||
}
|
||||
}
|
@ -454,6 +454,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
private void clearExistingStateTransforms()
|
||||
{
|
||||
base.ApplyTransformsAt(double.MinValue, true);
|
||||
|
||||
// has to call this method directly (not ClearTransforms) to bypass the local ClearTransformsAfter override.
|
||||
base.ClearTransformsAfter(double.MinValue, true);
|
||||
}
|
||||
|
||||
|
@ -113,8 +113,7 @@ namespace osu.Game.Screens.Menu
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Alpha = 0.5f,
|
||||
AccentColour = Color4.DarkBlue,
|
||||
Colour = Color4.DarkBlue,
|
||||
Size = new Vector2(0.96f)
|
||||
},
|
||||
new Circle
|
||||
|
@ -11,7 +11,6 @@ using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
@ -20,13 +19,14 @@ using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
|
||||
namespace osu.Game.Screens.Menu
|
||||
{
|
||||
/// <summary>
|
||||
/// A visualiser that reacts to music coming from beatmaps.
|
||||
/// </summary>
|
||||
public class LogoVisualisation : Drawable, IHasAccentColour
|
||||
public class LogoVisualisation : Drawable
|
||||
{
|
||||
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
||||
|
||||
@ -67,8 +67,6 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
private int indexOffset;
|
||||
|
||||
public Color4 AccentColour { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The relative movement of bars based on input amplification. Defaults to 1.
|
||||
/// </summary>
|
||||
@ -176,7 +174,8 @@ namespace osu.Game.Screens.Menu
|
||||
// Assuming the logo is a circle, we don't need a second dimension.
|
||||
private float size;
|
||||
|
||||
private Color4 colour;
|
||||
private static readonly Color4 transparent_white = Color4.White.Opacity(0.2f);
|
||||
|
||||
private float[] audioData;
|
||||
|
||||
private readonly QuadBatch<TexturedVertex2D> vertexBatch = new QuadBatch<TexturedVertex2D>(100, 10);
|
||||
@ -193,7 +192,6 @@ namespace osu.Game.Screens.Menu
|
||||
shader = Source.shader;
|
||||
texture = Source.texture;
|
||||
size = Source.DrawSize.X;
|
||||
colour = Source.AccentColour;
|
||||
audioData = Source.frequencyAmplitudes;
|
||||
}
|
||||
|
||||
@ -206,7 +204,7 @@ namespace osu.Game.Screens.Menu
|
||||
Vector2 inflation = DrawInfo.MatrixInverse.ExtractScale().Xy;
|
||||
|
||||
ColourInfo colourInfo = DrawColourInfo.Colour;
|
||||
colourInfo.ApplyChild(colour);
|
||||
colourInfo.ApplyChild(transparent_white);
|
||||
|
||||
if (audioData != null)
|
||||
{
|
||||
|
@ -7,7 +7,6 @@ using osu.Game.Online.API;
|
||||
using osu.Game.Users;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
|
||||
namespace osu.Game.Screens.Menu
|
||||
{
|
||||
@ -28,12 +27,10 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
private void updateColour()
|
||||
{
|
||||
Color4 defaultColour = Color4.White.Opacity(0.2f);
|
||||
|
||||
if (user.Value?.IsSupporter ?? false)
|
||||
AccentColour = skin.Value.GetConfig<GlobalSkinColours, Color4>(GlobalSkinColours.MenuGlow)?.Value ?? defaultColour;
|
||||
Colour = skin.Value.GetConfig<GlobalSkinColours, Color4>(GlobalSkinColours.MenuGlow)?.Value ?? Color4.White;
|
||||
else
|
||||
AccentColour = defaultColour;
|
||||
Colour = Color4.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +81,8 @@ namespace osu.Game.Screens.Menu
|
||||
set => rippleContainer.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private const float visualizer_default_alpha = 0.5f;
|
||||
|
||||
private readonly Box flashLayer;
|
||||
|
||||
private readonly Container impactContainer;
|
||||
@ -144,7 +146,7 @@ namespace osu.Game.Screens.Menu
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Alpha = 0.5f,
|
||||
Alpha = visualizer_default_alpha,
|
||||
Size = new Vector2(0.96f)
|
||||
},
|
||||
new Container
|
||||
@ -282,8 +284,7 @@ namespace osu.Game.Screens.Menu
|
||||
this.Delay(early_activation).Schedule(() => sampleBeat.Play());
|
||||
|
||||
logoBeatContainer
|
||||
.ScaleTo(1 - 0.02f * amplitudeAdjust, early_activation, Easing.Out)
|
||||
.Then()
|
||||
.ScaleTo(1 - 0.02f * amplitudeAdjust, early_activation, Easing.Out).Then()
|
||||
.ScaleTo(1, beatLength * 2, Easing.OutQuint);
|
||||
|
||||
ripple.ClearTransforms();
|
||||
@ -296,15 +297,13 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
flashLayer.ClearTransforms();
|
||||
flashLayer
|
||||
.FadeTo(0.2f * amplitudeAdjust, early_activation, Easing.Out)
|
||||
.Then()
|
||||
.FadeTo(0.2f * amplitudeAdjust, early_activation, Easing.Out).Then()
|
||||
.FadeOut(beatLength);
|
||||
|
||||
visualizer.ClearTransforms();
|
||||
visualizer
|
||||
.FadeTo(0.9f * amplitudeAdjust, early_activation, Easing.Out)
|
||||
.Then()
|
||||
.FadeTo(0.5f, beatLength);
|
||||
.FadeTo(visualizer_default_alpha * 1.8f * amplitudeAdjust, early_activation, Easing.Out).Then()
|
||||
.FadeTo(visualizer_default_alpha, beatLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ namespace osu.Game.Screens.Multi.Play
|
||||
protected override ResultsScreen CreateResults(ScoreInfo score)
|
||||
{
|
||||
Debug.Assert(roomId.Value != null);
|
||||
return new TimeshiftResultsScreen(score, roomId.Value.Value, playlistItem);
|
||||
return new TimeshiftResultsScreen(score, roomId.Value.Value, playlistItem, true);
|
||||
}
|
||||
|
||||
protected override ScoreInfo CreateScore()
|
||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.Ranking
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
public TimeshiftResultsScreen(ScoreInfo score, int roomId, PlaylistItem playlistItem, bool allowRetry = true)
|
||||
public TimeshiftResultsScreen(ScoreInfo score, int roomId, PlaylistItem playlistItem, bool allowRetry)
|
||||
: base(score, allowRetry)
|
||||
{
|
||||
this.roomId = roomId;
|
||||
|
@ -545,7 +545,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
protected override bool OnScroll(ScrollEvent e) => mouseWheelDisabled.Value && !GameplayClockContainer.IsPaused.Value;
|
||||
|
||||
protected virtual ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score);
|
||||
protected virtual ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, true);
|
||||
|
||||
#region Fail Logic
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Screens.Play
|
||||
public class SpectatorResultsScreen : SoloResultsScreen
|
||||
{
|
||||
public SpectatorResultsScreen(ScoreInfo score)
|
||||
: base(score)
|
||||
: base(score, false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ namespace osu.Game.Screens.Ranking
|
||||
|
||||
private readonly bool allowRetry;
|
||||
|
||||
protected ResultsScreen(ScoreInfo score, bool allowRetry = true)
|
||||
protected ResultsScreen(ScoreInfo score, bool allowRetry)
|
||||
{
|
||||
Score = score;
|
||||
this.allowRetry = allowRetry;
|
||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Screens.Ranking
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
public SoloResultsScreen(ScoreInfo score, bool allowRetry = true)
|
||||
public SoloResultsScreen(ScoreInfo score, bool allowRetry)
|
||||
: base(score, allowRetry)
|
||||
{
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
|
||||
protected void PresentScore(ScoreInfo score) =>
|
||||
FinaliseSelection(score.Beatmap, score.Ruleset, () => this.Push(new SoloResultsScreen(score)));
|
||||
FinaliseSelection(score.Beatmap, score.Ruleset, () => this.Push(new SoloResultsScreen(score, false)));
|
||||
|
||||
protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea();
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Timing;
|
||||
|
||||
@ -25,6 +26,6 @@ namespace osu.Game.Skinning
|
||||
/// <summary>
|
||||
/// The time which animations should be started from, relative to <see cref="Clock"/>.
|
||||
/// </summary>
|
||||
double AnimationStartTime { get; }
|
||||
Bindable<double> AnimationStartTime { get; }
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.OpenGL.Textures;
|
||||
@ -70,6 +71,8 @@ namespace osu.Game.Skinning
|
||||
[Resolved(canBeNull: true)]
|
||||
private IAnimationTimeReference timeReference { get; set; }
|
||||
|
||||
private readonly Bindable<double> animationStartTime = new BindableDouble();
|
||||
|
||||
public SkinnableTextureAnimation(bool startAtCurrentTime = true)
|
||||
: base(startAtCurrentTime)
|
||||
{
|
||||
@ -82,8 +85,18 @@ namespace osu.Game.Skinning
|
||||
if (timeReference != null)
|
||||
{
|
||||
Clock = timeReference.Clock;
|
||||
PlaybackPosition = timeReference.Clock.CurrentTime - timeReference.AnimationStartTime;
|
||||
animationStartTime.BindTo(timeReference.AnimationStartTime);
|
||||
}
|
||||
|
||||
animationStartTime.BindValueChanged(_ => updatePlaybackPosition(), true);
|
||||
}
|
||||
|
||||
private void updatePlaybackPosition()
|
||||
{
|
||||
if (timeReference == null)
|
||||
return;
|
||||
|
||||
PlaybackPosition = timeReference.Clock.CurrentTime - timeReference.AnimationStartTime.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user