diff --git a/osu.Game.Tournament.Tests/TestCaseMatchPairings.cs b/osu.Game.Tournament.Tests/TestCaseMatchPairings.cs index a1ab2c7a48..553e48a822 100644 --- a/osu.Game.Tournament.Tests/TestCaseMatchPairings.cs +++ b/osu.Game.Tournament.Tests/TestCaseMatchPairings.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Tests.Visual; @@ -21,6 +23,9 @@ namespace osu.Game.Tournament.Tests typeof(DrawableTournamentTeam), }; + [Cached] + private Bindable conditions = new Bindable(new TournamentConditions { BestOf = 9 }); + public TestCaseMatchPairings() { FillFlowContainer level1; @@ -30,8 +35,8 @@ namespace osu.Game.Tournament.Tests new TournamentTeam { FlagName = "AU", FullName = "Australia", }, new TournamentTeam { FlagName = "JP", FullName = "Japan", Acronym = "JPN" }) { - Team1Score = { Value = 8 }, - Team2Score = { Value = 6 }, + Team1Score = { Value = 4 }, + Team2Score = { Value = 1 }, }; var pairing2 = new MatchPairing( @@ -76,21 +81,19 @@ namespace osu.Game.Tournament.Tests level1.Children[0].Progression = level2.Children[0]; level1.Children[1].Progression = level2.Children[0]; - AddStep("mark complete", () => pairing1.Completed.Value = true); - AddRepeatStep("change scores", () => pairing1.Team2Score.Value++, 5); - AddStep("mark complete", () => pairing1.Completed.Value = true); + AddRepeatStep("change scores", () => pairing1.Team2Score.Value++, 4); AddStep("add new team", () => pairing2.Team2.Value = new TournamentTeam { FlagName = "PT", FullName = "Portugal" }); AddStep("Add progression", () => level1.Children[2].Progression = level2.Children[1]); - AddStep("start match", () => pairing2.ResetScores()); + AddStep("start match", () => pairing2.StartMatch()); - AddRepeatStep("change scores", () => pairing2.Team1Score.Value++, 5); - AddStep("mark complete", () => pairing2.Completed.Value = true); + AddRepeatStep("change scores", () => pairing2.Team1Score.Value++, 10); - AddStep("start submatch", () => level2.Children[0].Pairing.ResetScores()); + AddStep("start submatch", () => level2.Children[0].Pairing.StartMatch()); AddRepeatStep("change scores", () => level2.Children[0].Pairing.Team1Score.Value++, 5); - AddStep("mark complete", () => level2.Children[0].Pairing.Completed.Value = true); + + AddRepeatStep("change scores", () => level2.Children[0].Pairing.Team2Score.Value++, 4); } } } diff --git a/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchPairing.cs b/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchPairing.cs index 461199327e..7be302be73 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchPairing.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchPairing.cs @@ -2,6 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Lines; @@ -14,9 +16,10 @@ namespace osu.Game.Tournament.Screens.Ladder.Components { public readonly MatchPairing Pairing; private readonly FillFlowContainer flow; - private DrawableMatchPairing progression; + private readonly Bindable conditions = new Bindable(); + private readonly Path path; public DrawableMatchPairing Progression @@ -39,6 +42,51 @@ namespace osu.Game.Tournament.Screens.Ladder.Components private const float line_width = 2; + public DrawableMatchPairing(MatchPairing pairing) + { + Pairing = pairing; + + AutoSizeAxes = Axes.Both; + + Margin = new MarginPadding(5); + + InternalChildren = new Drawable[] + { + flow = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(2) + }, + path = new Path + { + Alpha = 0, + BypassAutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreRight, + PathWidth = line_width, + }, + }; + + pairing.Team1.BindValueChanged(_ => updateTeams()); + pairing.Team2.BindValueChanged(_ => updateTeams()); + + pairing.Team1Score.BindValueChanged(_ => updateWinConditions()); + pairing.Team2Score.BindValueChanged(_ => updateWinConditions()); + + pairing.Completed.BindValueChanged(_ => updateProgression()); + + updateTeams(); + } + + [BackgroundDependencyLoader(true)] + private void load(Bindable conditions) + { + this.conditions.BindValueChanged(_ => updateWinConditions()); + + if (conditions != null) + this.conditions.BindTo(conditions); + } + private void updateProgression() { if (progression == null) @@ -83,37 +131,11 @@ namespace osu.Game.Tournament.Screens.Ladder.Components destinationForWinner.Value = Pairing.Winner; } - public DrawableMatchPairing(MatchPairing pairing) + private void updateWinConditions() { - Pairing = pairing; + if (conditions.Value == null) return; - AutoSizeAxes = Axes.Both; - - Margin = new MarginPadding(5); - - InternalChildren = new Drawable[] - { - flow = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(2) - }, - path = new Path - { - Alpha = 0, - BypassAutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreRight, - PathWidth = line_width, - }, - }; - - pairing.Team1.BindValueChanged(_ => updateTeams()); - pairing.Team2.BindValueChanged(_ => updateTeams()); - - pairing.Completed.BindValueChanged(_ => updateProgression()); - - updateTeams(); + Pairing.Completed.Value = Pairing.Team1Score.Value + Pairing.Team2Score.Value >= conditions.Value.BestOf; } protected override void LoadComplete() @@ -136,6 +158,9 @@ namespace osu.Game.Tournament.Screens.Ladder.Components // todo: teams may need to be bindable for transitions at a later point. + if (Pairing.Team1.Value == null || Pairing.Team2.Value == null) + Pairing.CancelMatchStart(); + flow.Children = new[] { new DrawableMatchTeam(Pairing.Team1, Pairing), @@ -143,6 +168,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components }; updateProgression(); + updateWinConditions(); } } } diff --git a/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs b/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs index 1f2447ef06..06b400976c 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs @@ -7,16 +7,20 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.EventArgs; +using osu.Framework.Input.States; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Tournament.Components; using OpenTK; using OpenTK.Graphics; +using OpenTK.Input; namespace osu.Game.Tournament.Screens.Ladder.Components { public class DrawableMatchTeam : DrawableTournamentTeam { + private readonly MatchPairing pairing; private OsuSpriteText scoreText; private Box background; @@ -31,6 +35,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components public DrawableMatchTeam(TournamentTeam team, MatchPairing pairing) : base(team) { + this.pairing = pairing; Size = new Vector2(150, 40); Masking = true; @@ -48,7 +53,8 @@ namespace osu.Game.Tournament.Screens.Ladder.Components isWinner = () => pairing.Winner == Team; completed.BindTo(pairing.Completed); - score.BindTo(team == pairing.Team1.Value ? pairing.Team1Score : pairing.Team2Score); + if (team != null) + score.BindTo(team == pairing.Team1.Value ? pairing.Team1Score : pairing.Team2Score); } } @@ -109,6 +115,30 @@ namespace osu.Game.Tournament.Screens.Ladder.Components }, true); } + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + if (Team == null) return true; + + if (args.Button == MouseButton.Left) + { + if (score.Value == null) + { + pairing.StartMatch(); + } + else if (!pairing.Completed) + score.Value++; + } + else + { + if (score.Value > 0) + score.Value--; + else + pairing.CancelMatchStart(); + } + + return true; + } + private void updateWinStyle() { bool winner = completed && isWinner?.Invoke() == true; diff --git a/osu.Game.Tournament/Screens/Ladder/Components/MatchPairing.cs b/osu.Game.Tournament/Screens/Ladder/Components/MatchPairing.cs index b19b551a04..b615330cc2 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/MatchPairing.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/MatchPairing.cs @@ -23,15 +23,27 @@ namespace osu.Game.Tournament.Screens.Ladder.Components { Team1.Value = team1; Team2.Value = team2; - - Team1Score.ValueChanged += _ => Completed.Value = false; - Team2Score.ValueChanged += _ => Completed.Value = false; } public TournamentTeam Winner => !Completed.Value ? null : (Team1Score.Value > Team2Score.Value ? Team1.Value : Team2.Value); - public void ResetScores() + /// + /// Remove scores from the match, in case of a false click or false start. + /// + public void CancelMatchStart() { + Team1Score.Value = null; + Team2Score.Value = null; + } + + /// + /// Initialise this match with zeroed scores. Will be a noop if either team is not present. + /// + public void StartMatch() + { + if (Team1.Value == null || Team2.Value == null) + return; + Team1Score.Value = 0; Team2Score.Value = 0; } diff --git a/osu.Game.Tournament/Screens/Ladder/Components/TournamentConditions.cs b/osu.Game.Tournament/Screens/Ladder/Components/TournamentConditions.cs new file mode 100644 index 0000000000..fd0e8cea87 --- /dev/null +++ b/osu.Game.Tournament/Screens/Ladder/Components/TournamentConditions.cs @@ -0,0 +1,13 @@ +namespace osu.Game.Tournament.Screens.Ladder.Components +{ + /// + /// Conditions governing a tournament. + /// + public class TournamentConditions + { + /// + /// How many matches before a winner is decided. + /// + public int BestOf; + } +}