// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osuTK; using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { internal partial class TeamDisplay : CompositeDrawable { private readonly MultiplayerRoomUser user; [Resolved] private OsuColour colours { get; set; } = null!; [Resolved] private MultiplayerClient client { get; set; } = null!; private OsuClickableContainer clickableContent = null!; private Drawable box = null!; private Sample? sampleTeamSwap; public TeamDisplay(MultiplayerRoomUser user) { this.user = user; RelativeSizeAxes = Axes.Y; AutoSizeAxes = Axes.X; Margin = new MarginPadding { Horizontal = 3 }; } [BackgroundDependencyLoader] private void load(AudioManager audio) { InternalChild = clickableContent = new OsuClickableContainer { Width = 15, Alpha = 0, Scale = new Vector2(0, 1), RelativeSizeAxes = Axes.Y, Child = box = new Container { RelativeSizeAxes = Axes.Both, CornerRadius = 5, Masking = true, Scale = new Vector2(0, 1), Anchor = Anchor.Centre, Origin = Anchor.Centre, Child = new Box { Colour = Color4.White, RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, } } }; if (client.LocalUser?.Equals(user) == true) { clickableContent.Action = changeTeam; clickableContent.TooltipText = "Change team"; } sampleTeamSwap = audio.Samples.Get(@"Multiplayer/team-swap"); } protected override void LoadComplete() { base.LoadComplete(); client.RoomUpdated += onRoomUpdated; updateState(); } private void changeTeam() { client.SendMatchRequest(new ChangeTeamRequest { TeamID = ((client.LocalUser?.MatchState as TeamVersusUserState)?.TeamID + 1) % 2 ?? 0, }).FireAndForget(); } public int? DisplayedTeam { get; private set; } private void onRoomUpdated() => Scheduler.AddOnce(updateState); private void updateState() { // we don't have a way of knowing when an individual user's state has updated, so just handle on RoomUpdated for now. var userRoomState = client.Room?.Users.FirstOrDefault(u => u.Equals(user))?.MatchState; const double duration = 400; int? newTeam = (userRoomState as TeamVersusUserState)?.TeamID; if (newTeam == DisplayedTeam) return; // only play the sample if an already valid team changes to another valid team. // this avoids playing a sound for each user if the match type is changed to/from a team mode. if (newTeam != null && DisplayedTeam != null) sampleTeamSwap?.Play(); DisplayedTeam = newTeam; if (DisplayedTeam != null) { box.FadeColour(getColourForTeam(DisplayedTeam.Value), duration, Easing.OutQuint); box.ScaleTo(new Vector2(box.Scale.X < 0 ? 1 : -1, 1), duration, Easing.OutQuint); clickableContent.ScaleTo(Vector2.One, duration, Easing.OutQuint); clickableContent.FadeIn(duration); } else { clickableContent.ScaleTo(new Vector2(0, 1), duration, Easing.OutQuint); clickableContent.FadeOut(duration); } } private ColourInfo getColourForTeam(int id) { switch (id) { default: return colours.Red; case 1: return colours.Blue; } } protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); if (client.IsNotNull()) client.RoomUpdated -= onRoomUpdated; } } }