diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs
index 8bcd66292a..3e387f8405 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Components/RankedPlayStageDisplay.cs
@@ -14,6 +14,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Multiplayer;
+using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay;
using osu.Game.Online.RankedPlay;
using osuTK;
using osuTK.Graphics;
@@ -37,6 +38,40 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components
private DateTimeOffset countdownStartTime;
private DateTimeOffset countdownEndTime;
+ private RankedPlayStage? activeStage;
+
+ private LocalisableString heading;
+
+ ///
+ /// Heading text to be displayed indicating the purpose of the current stage.
+ ///
+ public LocalisableString Heading
+ {
+ get => heading;
+ set
+ {
+ heading = value;
+ if (headingText != null)
+ headingText.Text = value;
+ }
+ }
+
+ private LocalisableString caption;
+
+ ///
+ /// Subtitle text to be displayed indicating the action a user should take in the current stage.
+ ///
+ public LocalisableString Caption
+ {
+ get => caption;
+ set
+ {
+ caption = value;
+ if (captionText != null)
+ captionText.Text = value;
+ }
+ }
+
public RankedPlayStageDisplay(RankedPlayColourScheme colourScheme)
{
this.colourScheme = colourScheme;
@@ -152,7 +187,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components
Left = 10
},
UseFullGlyphHeight = false,
- Text = "00:27:123",
Font = OsuFont.TorusAlternate.With(size: 16, fixedWidth: true, weight: FontWeight.SemiBold)
}
]
@@ -164,61 +198,12 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components
Top = 80,
Left = 20
},
- Colour = CaptionColour ?? colourScheme.Primary,
Text = Caption,
Font = OsuFont.TorusAlternate.With(size: 24, weight: FontWeight.SemiBold)
}
};
}
- private LocalisableString heading;
-
- ///
- /// Heading text to be displayed indicating the purpose of the current stage.
- ///
- public LocalisableString Heading
- {
- get => heading;
- set
- {
- heading = value;
- if (headingText != null)
- headingText.Text = value;
- }
- }
-
- private LocalisableString caption;
-
- ///
- /// Subtitle text to be displayed indicating the action a user should take in the current stage.
- ///
- public LocalisableString Caption
- {
- get => caption;
- set
- {
- caption = value;
- if (captionText != null)
- captionText.Text = value;
- }
- }
-
- private Color4? captionColour;
-
- ///
- /// Overrides the default caption colour from the colour scheme with a custom one.
- ///
- public Color4? CaptionColour
- {
- get => captionColour;
- set
- {
- captionColour = value;
- if (captionText != null)
- captionText.Colour = value ?? colourScheme.Primary;
- }
- }
-
protected override void LoadComplete()
{
base.LoadComplete();
@@ -254,18 +239,37 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components
private void onCountdownStarted(MultiplayerCountdown countdown) => Scheduler.Add(() =>
{
- if (countdown is not RankedPlayStageCountdown)
+ if (countdown is not RankedPlayStageCountdown stageCountdown)
return;
+ switch (stageCountdown.Stage)
+ {
+ case RankedPlayStage.CardDiscard:
+ // Discard stage ends when both players have discarded, but adds a 3 second delay before completing.
+ // Showing this in the countdown just creates visual noise, so let's handle internally.
+ if (activeStage == stageCountdown.Stage)
+ return;
+
+ break;
+ }
+
+ activeStage = stageCountdown.Stage;
countdownStartTime = DateTimeOffset.Now;
countdownEndTime = DateTimeOffset.Now + countdown.TimeRemaining;
});
private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add(() =>
{
- if (countdown is not RankedPlayStageCountdown)
+ if (countdown is not RankedPlayStageCountdown stageCountdown)
return;
+ switch (stageCountdown.Stage)
+ {
+ // See above special case handling.
+ case RankedPlayStage.CardDiscard:
+ return;
+ }
+
countdownEndTime = DateTimeOffset.Now;
});
diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs
index 42f1dd94fb..bc6a725fc8 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/DiscardScreen.cs
@@ -12,6 +12,7 @@ using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Localisation;
+using osu.Framework.Threading;
using osu.Game.Audio;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
@@ -23,7 +24,6 @@ using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Card;
using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components;
using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Hand;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
{
@@ -36,7 +36,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
public override bool ShowStageOverlay => true;
public override LocalisableString StageHeading => "Discard Phase";
- protected override LocalisableString StageCaption => "Replace cards from your hand";
private PlayerHandOfCards playerHand = null!;
private ShearedButton discardButton = null!;
@@ -62,9 +61,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
private DateTimeOffset stageEndTime;
private TimeSpan stageDuration;
+ private ScheduledDelegate? waitingOpponentTextUpdate;
+
public DiscardScreen()
{
- StageDisplay.CaptionColour = Color4.White;
+ StageCaption = "Replace cards from your hand";
}
[BackgroundDependencyLoader]
@@ -233,6 +234,12 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
playerHand.SelectionMode = HandSelectionMode.Disabled;
hasDiscardedCards = true;
+
+ StageCaption = string.Empty;
+
+ // A bit awkward, but we're delaying this until we're mostly sure the opponent is still discarding.
+ // See the countdown reset logic for DiscardStage which gives 3 seconds for animation.
+ waitingOpponentTextUpdate = Scheduler.AddDelayed(() => StageCaption = "Waiting for your opponent...", 3200);
}
private readonly List discardedCards = new List();
@@ -313,6 +320,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
double presentationTime = Math.Max(earliestPresentationTime, Time.Current);
Scheduler.AddDelayed(presentRemainingCards, presentationTime - Time.Current);
+
+ waitingOpponentTextUpdate?.Cancel();
+ StageCaption = string.Empty;
}
private void presentRemainingCards()
diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs
index 8dfc8ebb60..46798343c6 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/EndedScreen.cs
@@ -28,7 +28,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
public Action? ExitRequested { get; init; }
public override LocalisableString StageHeading => "Results";
- protected override LocalisableString StageCaption => string.Empty;
[Resolved]
private RankedPlayMatchInfo matchInfo { get; set; } = null!;
diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs
index a1ef73d965..71fbaeacbd 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayScreen.cs
@@ -14,7 +14,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
public partial class GameplayScreen : RankedPlaySubScreen
{
public override LocalisableString StageHeading => "Gameplay";
- protected override LocalisableString StageCaption => string.Empty;
[BackgroundDependencyLoader]
private void load()
diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs
index 854dcc0a6b..2ea154eeae 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/GameplayWarmupScreen.cs
@@ -33,7 +33,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
public override bool ShowBeatmapBackground => true;
public override LocalisableString StageHeading => "Gameplay";
- protected override LocalisableString StageCaption => string.Empty;
[Cached(typeof(IBindable))]
private readonly Bindable lastLookupResult = new Bindable();
diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs
index 2ec5621c23..017dc30f59 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/Intro/IntroScreen.cs
@@ -20,7 +20,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Intro
public partial class IntroScreen : RankedPlaySubScreen
{
public override LocalisableString StageHeading => string.Empty;
- protected override LocalisableString StageCaption => string.Empty;
public IntroScreen()
{
diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs
index a9e743e8f9..cd5d2406a7 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/OpponentPickScreen.cs
@@ -25,7 +25,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
public override bool ShowStageOverlay => true;
public override LocalisableString StageHeading => "Pick Phase";
- protected override LocalisableString StageCaption => "Waiting for your opponent...";
protected override RankedPlayColourScheme ColourScheme => RankedPlayColourScheme.RED;
@@ -40,6 +39,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
private const int card_play_samples = 2;
private Sample?[]? cardPlaySamples;
+ public OpponentPickScreen()
+ {
+ StageCaption = "Waiting for your opponent...";
+ }
+
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs
index e0e83b6624..bc96fd5877 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/PickScreen.cs
@@ -31,7 +31,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
public override bool ShowStageOverlay => true;
public override LocalisableString StageHeading => "Pick Phase";
- protected override LocalisableString StageCaption => "It's your turn to play a card!";
private PlayerHandOfCards playerHand = null!;
private OpponentHandOfCards opponentHand = null!;
@@ -46,7 +45,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
private Sample? timeRunningOutSample;
private SampleChannel? timeRunningOutSampleChannel;
- private Sample? timeUpBuzzerSample;
private DateTimeOffset stageEndTime;
private TimeSpan stageDuration;
@@ -56,6 +54,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
///
private bool hasPlayedCard;
+ public PickScreen()
+ {
+ StageCaption = "It's your turn to play a card!";
+ }
+
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
@@ -103,7 +106,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
cardPlaySamples[i] = audio.Samples.Get($@"Multiplayer/Matchmaking/Ranked/card-play-{1 + i}");
timeRunningOutSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/time-running-out");
- timeUpBuzzerSample = audio.Samples.Get(@"Multiplayer/Matchmaking/Ranked/time-up");
}
protected override void LoadComplete()
@@ -209,14 +211,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add(() =>
{
- if (countdown is not RankedPlayStageCountdown stageCountdown)
+ if (countdown is not RankedPlayStageCountdown)
return;
stageEndTime = DateTimeOffset.Now;
stageDuration = TimeSpan.Zero;
-
- if (stageCountdown.Stage == RankedPlayStage.CardPlay && !hasPlayedCard)
- timeUpBuzzerSample?.Play();
});
private void onPlayButtonClicked()
diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs
index 3d49aaac4d..464e99d1b6 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/RankedPlaySubScreen.cs
@@ -37,7 +37,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
///
/// Subtitle text to be displayed indicating the action a user should take in the current stage.
///
- protected abstract LocalisableString StageCaption { get; }
+ protected LocalisableString StageCaption
+ {
+ get => StageDisplay.Caption;
+ set => StageDisplay.Caption = value;
+ }
///
/// The colour scheme commonly used for components of this screen.
@@ -79,7 +83,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
StageDisplay = new RankedPlayStageDisplay(ColourScheme)
{
Heading = StageHeading,
- Caption = StageCaption,
Margin = new MarginPadding { Top = 60 },
State = { BindTarget = CountdownVisibility }
},
diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs
index 2a16040268..70c501943e 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/RankedPlay/ResultsScreen.cs
@@ -40,7 +40,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay
public partial class ResultsScreen : RankedPlaySubScreen
{
public override LocalisableString StageHeading => "Results";
- protected override LocalisableString StageCaption => string.Empty;
public override bool ShowBeatmapBackground => true;