diff --git a/Output/PartyModes/Tournament.xml b/Output/PartyModes/Tournament.xml new file mode 100644 index 00000000..490aceaf --- /dev/null +++ b/Output/PartyModes/Tournament.xml @@ -0,0 +1,20 @@ + + + 2 + + TR_PARTYMODE_NAME + McSchneidar + TR_PARTYMODE_DESCRIPTION + Tournament + CPartyModeTournament + 1 + 0 + TR_PARTYMODE_AUDIENCE + + + CPartyScreenTournamentMain + CPartyScreenTournamentConfig + CPartyScreenTournamentNames + CPartyScreenTournamentSongs + + diff --git a/Output/PartyModes/Tournament/Languages/de.xml b/Output/PartyModes/Tournament/Languages/de.xml new file mode 100644 index 00000000..dda4780b --- /dev/null +++ b/Output/PartyModes/Tournament/Languages/de.xml @@ -0,0 +1,31 @@ + + + Deutsch + K.O.-Turnier + Singt Duelle im K.O.-System, bis nur noch ein Sieger übrig ist. + Für 3 bis 16 Spieler, die einen echten Wettkampf mögen. + Weiter + Zurück + Start + Beenden + Ja + Nein + Duell starten + Songs + K.O.-Turnier: Konfiguration + Anzahl der Spieler + Joker pro Spieler + K.O.-Turnier: Spieler auswählen + Zufällig wählen + K.O.-Turnier + Willst du das Turnier wirklich beenden? + Achtelfinale + Viertelfinale + Halbfinale + Finale + Freilos + Sieger + Nächstes Duell: + gegen + Gleichstand! Das Duell wird nachgesungen. + diff --git a/Output/PartyModes/Tournament/Languages/en.xml b/Output/PartyModes/Tournament/Languages/en.xml new file mode 100644 index 00000000..a622bd06 --- /dev/null +++ b/Output/PartyModes/Tournament/Languages/en.xml @@ -0,0 +1,31 @@ + + + English + Knockout Tournament + Sing duels in a knockout bracket until only one champion is left. + For 3 to 16 players who like a real competition. + Next + Back + Start + Exit + Yes + No + Start duel + Songs + Knockout Tournament: Configuration + Number of players + Jokers per player + Knockout Tournament: Choose Players + Select random + Knockout Tournament + Do you really want to exit the tournament? + Round of 16 + Quarterfinal + Semifinal + Final + Bye + Champion + Next duel: + vs. + Tie! The duel is sung again. + diff --git a/Output/PartyModes/Tournament/Themes/Default.xml b/Output/PartyModes/Tournament/Themes/Default.xml new file mode 100644 index 00000000..97392ded --- /dev/null +++ b/Output/PartyModes/Tournament/Themes/Default.xml @@ -0,0 +1,10 @@ + + + 9 + + Default + McSchneidar + 0 + 1 + + diff --git a/Output/PartyModes/Tournament/Themes/Default/Default.xml b/Output/PartyModes/Tournament/Themes/Default/Default.xml new file mode 100644 index 00000000..d88d34b4 --- /dev/null +++ b/Output/PartyModes/Tournament/Themes/Default/Default.xml @@ -0,0 +1,15 @@ + + + 4 + + Default + McSchneidar + 0 + 1 + + + + PartyModeIcon.png + + + diff --git a/Output/PartyModes/Tournament/Themes/Default/PartyModeIcon.png b/Output/PartyModes/Tournament/Themes/Default/PartyModeIcon.png new file mode 100644 index 00000000..a8a9b3bc Binary files /dev/null and b/Output/PartyModes/Tournament/Themes/Default/PartyModeIcon.png differ diff --git a/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentConfig.xml b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentConfig.xml new file mode 100644 index 00000000..3c14c60e --- /dev/null +++ b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentConfig.xml @@ -0,0 +1,239 @@ + + + + PartyScreenTournamentConfig + 1 + + + + Video + + + BG_Default + + + + + + + + + 0 + 60 + 1920 + 67.5 + 1 + + + + + + 960 + 75 + 0 + 40.5 + 0 + + + Center + Center + + Outline + TR_SCREENCONFIG_TITLE + + + 112.5 + 157.5 + 0 + 40.5 + 0 + + + Left + Center + + Outline + TR_SCREENCONFIG_NUMPLAYERS + + + 112.5 + 247.5 + 0 + 40.5 + 0 + + + Left + Center + + Outline + TR_SCREENCONFIG_NUMJOKERS + + + + + + + + + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 150 + 1050 + 75 + 0 + + + 757.5 + 157.5 + 60 + 60 + 0 + + + 1732.5 + 157.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 300 + Outline + Bold + 9 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 240 + 1050 + 75 + 0 + + + 757.5 + 247.5 + 60 + 60 + 0 + + + 1732.5 + 247.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 300 + Outline + Bold + 10 + + + + + + + + + diff --git a/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentMain.xml b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentMain.xml new file mode 100644 index 00000000..e2cef273 --- /dev/null +++ b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentMain.xml @@ -0,0 +1,491 @@ + + + + PartyScreenTournamentMain + 1 + + + + Video + + + BG_Default + + + + + + + + + 0 + 60 + 1920 + 67.5 + 1 + + + + PopupBG + + + 0 + 0 + 1920 + 1080 + -1 + + + + + + 0.1 + 0.09 + 0.25 + 0.92 + + + 0 + 0 + 380 + 100 + 0.5 + + + + + + 1 + 0.8 + 0 + 1 + + + 0 + 0 + 388 + 108 + 0.6 + + + + + + + 0 + 0 + 38 + 38 + 0.4 + + + + + + 1 + 1 + 1 + 0.5 + + + 0 + 0 + 3 + 3 + 0.7 + + + + + + 960 + 75 + 0 + 40.5 + 0 + + + Center + Center + + Outline + TR_SCREENMAIN_TITLE + + + 960 + 405 + -11 + 40.5 + 570 + + + Center + Center + + Outline + TR_SCREENMAIN_POPUP_REALLYEXIT + + + 0 + 150 + 0 + 34 + 0 + + 0.75 + 0.78 + 0.85 + 1 + + + Center + Center + + Outline + + + + 0 + 0 + 0 + 30 + 0 + + + Left + Center + + Outline + + + + 0 + 0 + 0 + 30 + 0 + + 0.31 + 0.82 + 0.91 + 1 + + + Left + Center + + Outline + + + + 0 + 0 + 0 + 30 + 0 + + 0.6 + 0.62 + 0.68 + 1 + + + Left + Center + + Outline + + + + 0 + 0 + 0 + 30 + 0 + + + Right + Center + + Outline + + + + 960 + 320 + 0 + 36 + 0 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + TR_SCREENMAIN_CHAMPION + + + 960 + 365 + 0 + 54 + 500 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + + + + 960 + 860 + 0 + 40.5 + 1500 + + + Center + Center + + Outline + + + + 960 + 908 + 0 + 34 + 1500 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + TR_SCREENMAIN_REMATCH + + + + + + + + + + + + + + + + + + + Star + + 700 + 290 + 520 + 170 + -1 + + + 1 + 0.8 + 0 + 0.6 + + Star + 18 + 40 + + + + diff --git a/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentNames.xml b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentNames.xml new file mode 100644 index 00000000..2550c469 --- /dev/null +++ b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentNames.xml @@ -0,0 +1,382 @@ + + + + PartyScreenTournamentNames + 1 + + + + Video + + + BG_Default + + + + + + + + + 0 + 60 + 1920 + 67.5 + 1 + + + + + + 960 + 75 + 0 + 40.5 + 0 + + + Center + Center + + Outline + TR_SCREENNAMES_TITLE + + + + + + + + + + + + + + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 60 + 150 + 1800 + 75 + 0 + + + 67.5 + 157.5 + 60 + 60 + 0 + + + 1792.5 + 157.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 300 + Outline + Bold + 2 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlidePlayer + SelectSlideArrowLeft + SelectSlideArrowRight + + 60 + 240 + 1800 + 225 + 0 + + + 67.5 + 315 + 60 + 60 + 0 + + + 1792.5 + 315 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 5 + 300 + Outline + Bold + 8 + + + + + + + 142.5 + 525 + 1800 + 589.5 + 0 + + CoverTile + + PlayerSelector + + 150 + 150 + 10 + 2 + 15 + 15 + + -20 + 25.5 + Outline + + + + + + + + + + + diff --git a/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentSongs.xml b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentSongs.xml new file mode 100644 index 00000000..8819866f --- /dev/null +++ b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentSongs.xml @@ -0,0 +1,407 @@ + + + + PartyScreenTournamentSongs + 1 + + + + Video + + + BG_Default + + + + + + + + + 0 + 60 + 1920 + 67.5 + 1 + + + + + + 960 + 75 + 0 + 40.5 + 0 + + + Center + Center + + Outline + TR_SCREENCONFIG_TITLE + + + 112.5 + 157.5 + 0 + 40.5 + 0 + + + Left + Center + + Outline + TR_SONGSOURCE + + + 112.5 + 435 + 0 + 40.5 + 0 + + + Left + Center + + Outline + TR_GAMEMODE + + + + + + + + + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 150 + 1050 + 75 + 0 + + + 757.5 + 157.5 + 60 + 60 + 0 + + + 1732.5 + 157.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 308 + Outline + Bold + 3 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 240 + 1050 + 75 + 0 + + + 757.5 + 247.5 + 60 + 60 + 0 + + + 1732.5 + 247.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 900 + Outline + Bold + 3 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 240 + 1050 + 75 + 0 + + + 757.5 + 247.5 + 60 + 60 + 0 + + + 1732.5 + 247.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 900 + Outline + Bold + 3 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 330 + 1050 + 75 + 0 + + + 757.5 + 337.5 + 60 + 60 + 0 + + + 1732.5 + 337.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 900 + Outline + Bold + 1 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 435 + 1050 + 75 + 0 + + + 757.5 + 442.5 + 60 + 60 + 0 + + + 1732.5 + 442.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 308 + Outline + Bold + 2 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 540 + 1050 + 75 + 0 + + + 757.5 + 547.5 + 60 + 60 + 0 + + + 1732.5 + 547.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 308 + Outline + Bold + 5 + + + + + + + + + diff --git a/PartyModes/PartyModeTournament/CPartyModeTournament.cs b/PartyModes/PartyModeTournament/CPartyModeTournament.cs new file mode 100644 index 00000000..f21093c5 --- /dev/null +++ b/PartyModes/PartyModeTournament/CPartyModeTournament.cs @@ -0,0 +1,711 @@ +#region license +// This file is part of Vocaluxe. +// +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using VocaluxeLib.Menu; +using VocaluxeLib.Utils; + +[assembly: ComVisible(false)] + +namespace VocaluxeLib.PartyModes.Tournament +{ + public class CTournamentMatch + { + public int Round; + public int Index; + public int Player1 = -1; + public int Player2 = -1; + public int Score1; + public int Score2; + public int Winner = -1; + public bool Bye; + + public bool Played + { + get { return Winner >= 0; } + } + + public bool Ready + { + get { return !Played && Player1 >= 0 && Player2 >= 0; } + } + + public int WinnerPlayer + { + get + { + if (Winner == 0) + { + return Player1; + } + + return Winner == 1 ? Player2 : -1; + } + } + + public int LoserPlayer + { + get + { + if (Winner == 0) + { + return Player2; + } + + return Winner == 1 ? Player1 : -1; + } + } + } + + public abstract class CPartyScreenTournament : CMenuParty + { + protected new CPartyModeTournament _PartyMode; + + public override void Init() + { + base.Init(); + _PartyMode = (CPartyModeTournament)base._PartyMode; + } + } + + public sealed class CPartyModeTournament : CPartyMode + { + public const int NumPlayerAtOnce = 2; + public const int MaxJokers = 3; + + public override int MinMics + { + get { return NumPlayerAtOnce; } + } + public override int MaxMics + { + get { return CBase.Config.GetMaxNumMics(); } + } + public override int MinPlayers + { + get { return 3; } + } + public override int MaxPlayers + { + get { return 16; } + } + public override int MinTeams + { + get { return 1; } + } + public override int MaxTeams + { + get { return 1; } + } + public override int MinPlayersPerTeam + { + get { return MinPlayers; } + } + public override int MaxPlayersPerTeam + { + get { return MaxPlayers; } + } + + private enum EStage + { + Config, + Songs, + Names, + Main, + SongSelection, + Singing, + MedleySinging + } + + public struct SData + { + public int NumPlayer; + public int NumJokers; + public int[] Jokers; + public List ProfileIds; + + public ESongSource SongSource; + public ESongSorting Sorting; + public int CategoryIndex; + public int PlaylistId; + + public EGameMode GameMode; + public int NumMedleySongs; + + public List Rounds; + public bool IsRematch; + public int NumMatchesPlayed; + public CTournamentMatch LastDecidedMatch; + + public List Songs; + } + + public SData GameData; + private EStage _Stage; + + public CPartyModeTournament(int id) : base(id) + { + _ScreenSongOptions.Selection.RandomOnly = false; + _ScreenSongOptions.Selection.PartyMode = true; + _ScreenSongOptions.Selection.CategoryChangeAllowed = true; + _ScreenSongOptions.Selection.NumJokers = new int[] { 1, 1 }; + _ScreenSongOptions.Selection.TeamNames = new string[] { "foo", "bar" }; + + _ScreenSongOptions.Sorting.SearchString = string.Empty; + _ScreenSongOptions.Sorting.SearchActive = false; + _ScreenSongOptions.Sorting.DuetOptions = EDuetOptions.NoDuets; + _ScreenSongOptions.Sorting.FilterPlaylistId = -1; + + GameData = new SData + { + NumPlayer = 8, + NumJokers = 1, + ProfileIds = new List(), + Sorting = CBase.Config.GetSongSorting(), + SongSource = ESongSource.TR_SONGSOURCE_ALLSONGS, + PlaylistId = 0, + CategoryIndex = 0, + GameMode = EGameMode.TR_GAMEMODE_NORMAL, + NumMedleySongs = 5, + Rounds = new List(), + Songs = new List() + }; + } + + public override void SetDefaults() + { + _Stage = EStage.Config; + + _ScreenSongOptions.Sorting.IgnoreArticles = CBase.Config.GetIgnoreArticles(); + _ScreenSongOptions.Sorting.SongSorting = CBase.Config.GetSongSorting(); + _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_OFF; + _ScreenSongOptions.Selection.SongIndex = -1; + _ScreenSongOptions.Selection.CategoryIndex = -1; + + if (CBase.Config.GetTabs() == EOffOn.TR_CONFIG_ON && _ScreenSongOptions.Sorting.SongSorting != ESongSorting.TR_CONFIG_NONE) + { + _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_ON; + } + + GameData.Rounds = new List(); + } + + public override bool Init() + { + if (!base.Init()) + { + return false; + } + + SetDefaults(); + return true; + } + + public override void UpdateGame() { } + + public int NumRounds + { + get { return GameData.Rounds.Count; } + } + + public CTournamentMatch FinalMatch + { + get { return GameData.Rounds.Count > 0 ? GameData.Rounds[GameData.Rounds.Count - 1][0] : null; } + } + + public bool IsFinished + { + get { return FinalMatch != null && FinalMatch.Played; } + } + + public CTournamentMatch CurrentMatch + { + get + { + foreach (var round in GameData.Rounds) + { + foreach (var match in round) + { + if (match.Ready) + { + return match; + } + } + } + + return null; + } + } + + private IMenu _GetNextScreen() + { + switch (_Stage) + { + case EStage.Config: + return _Screens["CPartyScreenTournamentConfig"]; + case EStage.Songs: + return _Screens["CPartyScreenTournamentSongs"]; + case EStage.Names: + return _Screens["CPartyScreenTournamentNames"]; + case EStage.Main: + return _Screens["CPartyScreenTournamentMain"]; + case EStage.SongSelection: + return CBase.Graphics.GetScreen(EScreen.Song); + case EStage.Singing: + case EStage.MedleySinging: + return CBase.Graphics.GetScreen(EScreen.Sing); + default: + throw new ArgumentException("Invalid stage: " + _Stage); + } + } + + private void _FadeToScreen() + { + CBase.Graphics.FadeTo(_GetNextScreen()); + } + + public void Next() + { + switch (_Stage) + { + case EStage.Config: + _Stage = EStage.Songs; + break; + case EStage.Songs: + _Stage = EStage.Names; + break; + case EStage.Names: + _Stage = EStage.Main; + CBase.Songs.ResetSongSung(); + _CreateBracket(); + break; + case EStage.Main: + if (CurrentMatch == null) + { + return; + } + + if (GameData.GameMode == EGameMode.TR_GAMEMODE_MEDLEY) + { + _Stage = EStage.MedleySinging; + _PrepareMedleyRound(); + } + else + { + _Stage = EStage.SongSelection; + _PrepareSongSelection(); + } + + break; + case EStage.SongSelection: + _Stage = EStage.Singing; + break; + case EStage.MedleySinging: + case EStage.Singing: + _Stage = EStage.Main; + _UpdateScores(); + break; + default: + throw new ArgumentException("Invalid stage: " + _Stage); + } + + _FadeToScreen(); + } + + public void Back() + { + switch (_Stage) + { + case EStage.Config: + CBase.Graphics.FadeTo(EScreen.Party); + return; + case EStage.Songs: + _Stage = EStage.Config; + break; + case EStage.Names: + _Stage = EStage.Songs; + break; + case EStage.Main: + _Stage = EStage.Names; + break; + default: + throw new ArgumentException("Invalid stage: " + _Stage); + } + + _FadeToScreen(); + } + + public override IMenu GetStartScreen() + { + return _Screens["CPartyScreenTournamentConfig"]; + } + + public override SScreenSongOptions GetScreenSongOptions() + { + return _ScreenSongOptions; + } + + public override void OnSongChange(int songIndex, ref SScreenSongOptions screenSongOptions) + { + if (_ScreenSongOptions.Selection.SelectNextRandomSong && songIndex != -1) + { + _ScreenSongOptions.Selection.SelectNextRandomSong = false; + } + + _ScreenSongOptions.Selection.SongIndex = songIndex; + + screenSongOptions = _ScreenSongOptions; + } + + public override void OnCategoryChange(int categoryIndex, ref SScreenSongOptions screenSongOptions) + { + if (categoryIndex != -1 || CBase.Config.GetTabs() == EOffOn.TR_CONFIG_OFF) + { + _ScreenSongOptions.Selection.SelectNextRandomSong = true; + _ScreenSongOptions.Selection.RandomOnly = true; + } + else + { + _ScreenSongOptions.Selection.SongIndex = -1; + _ScreenSongOptions.Selection.RandomOnly = false; + } + + _ScreenSongOptions.Selection.CategoryIndex = categoryIndex; + + screenSongOptions = _ScreenSongOptions; + } + + public override void SetSearchString(string searchString, bool visible) + { + _ScreenSongOptions.Sorting.SearchString = searchString; + _ScreenSongOptions.Sorting.SearchActive = visible; + } + + public override void JokerUsed(int teamNr) + { + if (_ScreenSongOptions.Selection.NumJokers == null || teamNr >= _ScreenSongOptions.Selection.NumJokers.Length) + { + return; + } + + var match = CurrentMatch; + if (match != null && GameData.Jokers != null) + { + var player = teamNr == 0 ? match.Player1 : match.Player2; + if (GameData.Jokers[player] > 0) + { + GameData.Jokers[player]--; + } + } + + _ScreenSongOptions.Selection.NumJokers[teamNr]--; + _ScreenSongOptions.Selection.RandomOnly = true; + _ScreenSongOptions.Selection.CategoryChangeAllowed = false; + } + + public override void SongSelected(int songId) + { + _PrepareRound(new int[] { songId }); + + Next(); + } + + public override void LeavingHighscore() + { + for (var i = 0; i < CBase.Game.GetNumSongs(); i++) + { + CBase.Songs.AddPartySongSung(CBase.Game.GetSong(i).Id); + } + + Next(); + } + + private void _CreateBracket() + { + var size = 4; + while (size < GameData.NumPlayer) + { + size *= 2; + } + + GameData.Rounds = new List(); + for (var count = size / 2; count >= 1; count /= 2) + { + var round = new CTournamentMatch[count]; + for (var i = 0; i < count; i++) + { + round[i] = new CTournamentMatch { Round = GameData.Rounds.Count, Index = i }; + } + + GameData.Rounds.Add(round); + } + + var firstRound = GameData.Rounds[0]; + var half = firstRound.Length / 2; + var byeOrder = new List(); + for (var i = 0; i < half; i++) + { + byeOrder.Add(i); + byeOrder.Add(half + i); + } + + var numByes = size - GameData.NumPlayer; + for (var i = 0; i < numByes; i++) + { + firstRound[byeOrder[i]].Bye = true; + } + + var players = Enumerable.Range(0, GameData.NumPlayer).ToList(); + players.Shuffle(); + var next = 0; + foreach (var match in firstRound) + { + match.Player1 = players[next++]; + if (!match.Bye) + { + match.Player2 = players[next++]; + } + } + + foreach (var match in firstRound) + { + if (match.Bye) + { + match.Winner = 0; + _Advance(match); + } + } + + GameData.Jokers = new int[GameData.NumPlayer]; + for (var i = 0; i < GameData.NumPlayer; i++) + { + GameData.Jokers[i] = GameData.NumJokers; + } + + GameData.IsRematch = false; + GameData.NumMatchesPlayed = 0; + GameData.LastDecidedMatch = null; + GameData.Songs = new List(); + } + + private void _Advance(CTournamentMatch match) + { + if (match.Round + 1 >= GameData.Rounds.Count) + { + return; + } + + var nextMatch = GameData.Rounds[match.Round + 1][match.Index / 2]; + if (match.Index % 2 == 0) + { + nextMatch.Player1 = match.WinnerPlayer; + } + else + { + nextMatch.Player2 = match.WinnerPlayer; + } + } + + private void _PrepareMedleyRound() + { + var songIds = new List(); + for (var i = 0; i < GameData.NumMedleySongs; i++) + { + if (GameData.Songs.Count == 0) + { + _UpdateSongList(); + } + + if (GameData.Songs.Count == 0) + { + break; + } + + songIds.Add(GameData.Songs[0]); + GameData.Songs.RemoveAt(0); + } + + _PrepareRound(songIds.ToArray()); + } + + private void _PrepareSongSelection() + { + _ScreenSongOptions.Selection.RandomOnly = true; + _ScreenSongOptions.Selection.SelectNextRandomSong = true; + + _ScreenSongOptions.Sorting.IgnoreArticles = CBase.Config.GetIgnoreArticles(); + + switch (GameData.SongSource) + { + case ESongSource.TR_SONGSOURCE_ALLSONGS: + _ScreenSongOptions.Sorting.SongSorting = CBase.Config.GetSongSorting(); + _ScreenSongOptions.Sorting.Tabs = CBase.Config.GetTabs(); + _ScreenSongOptions.Sorting.FilterPlaylistId = -1; + + _ScreenSongOptions.Selection.SongIndex = -1; + _ScreenSongOptions.Selection.CategoryIndex = -1; + _ScreenSongOptions.Selection.CategoryChangeAllowed = true; + break; + + case ESongSource.TR_SONGSOURCE_CATEGORY: + _ScreenSongOptions.Sorting.SongSorting = GameData.Sorting; + _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_ON; + _ScreenSongOptions.Sorting.FilterPlaylistId = -1; + + _ScreenSongOptions.Selection.CategoryIndex = GameData.CategoryIndex; + _ScreenSongOptions.Selection.CategoryChangeAllowed = false; + break; + + case ESongSource.TR_SONGSOURCE_PLAYLIST: + _ScreenSongOptions.Sorting.SongSorting = CBase.Config.GetSongSorting(); + _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_OFF; + _ScreenSongOptions.Sorting.FilterPlaylistId = GameData.PlaylistId; + + _ScreenSongOptions.Selection.CategoryChangeAllowed = false; + break; + } + + var match = CurrentMatch; + _ScreenSongOptions.Selection.NumJokers = new int[] { GameData.Jokers[match.Player1], GameData.Jokers[match.Player2] }; + _ScreenSongOptions.Selection.TeamNames = new string[] + { + CBase.Profiles.GetPlayerName(GameData.ProfileIds[match.Player1]), + CBase.Profiles.GetPlayerName(GameData.ProfileIds[match.Player2]) + }; + } + + private bool _PrepareRound(int[] songIds) + { + CBase.Game.Reset(); + CBase.Game.ClearSongs(); + + CBase.Game.SetNumPlayer(NumPlayerAtOnce); + var players = CBase.Game.GetPlayers(); + var match = CurrentMatch; + if (players == null || players.Length < NumPlayerAtOnce || match == null) + { + return false; + } + + players[0].ProfileId = GameData.ProfileIds[match.Player1]; + players[1].ProfileId = GameData.ProfileIds[match.Player2]; + + foreach (var songId in songIds) + { + var gameMode = GameData.GameMode; + if (GameData.IsRematch && gameMode != EGameMode.TR_GAMEMODE_MEDLEY && CBase.Songs.GetSongById(songId).IsGameModeAvailable(EGameMode.TR_GAMEMODE_SHORTSONG)) + { + gameMode = EGameMode.TR_GAMEMODE_SHORTSONG; + } + + CBase.Game.AddSong(songId, gameMode); + } + + return true; + } + + private void _UpdateSongList() + { + if (GameData.Songs.Count > 0) + { + return; + } + + switch (GameData.SongSource) + { + case ESongSource.TR_SONGSOURCE_PLAYLIST: + for (var i = 0; i < CBase.Playlist.GetSongCount(GameData.PlaylistId); i++) + { + var id = CBase.Playlist.GetSong(GameData.PlaylistId, i).SongId; + if (CBase.Songs.GetSongById(id).IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY)) + { + GameData.Songs.Add(id); + } + } + + break; + + case ESongSource.TR_SONGSOURCE_ALLSONGS: + var avSongs = CBase.Songs.GetSongs(); + GameData.Songs.AddRange(avSongs.Where(song => song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY)).Select(song => song.Id)); + break; + + case ESongSource.TR_SONGSOURCE_CATEGORY: + var oldSorting = CBase.Config.GetSongSorting(); + CBase.Songs.SortSongs(GameData.Sorting, EOffOn.TR_CONFIG_ON, CBase.Config.GetIgnoreArticles(), string.Empty, EDuetOptions.NoDuets, -1); + + CBase.Songs.SetCategory(GameData.CategoryIndex); + avSongs = CBase.Songs.GetVisibleSongs(); + GameData.Songs.AddRange(avSongs.Where(song => song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY)).Select(song => song.Id)); + + CBase.Songs.SetCategory(-1); + CBase.Songs.SortSongs(oldSorting, CBase.Config.GetTabs(), CBase.Config.GetIgnoreArticles(), string.Empty, EDuetOptions.NoDuets, -1); + break; + } + + GameData.Songs.Shuffle(); + } + + private void _UpdateScores() + { + var match = CurrentMatch; + if (match == null) + { + return; + } + + var points = CBase.Game.GetPoints(); + if (points == null || points.NumRounds == 0) + { + return; + } + + var scores = new double[NumPlayerAtOnce]; + for (var round = 0; round < points.NumRounds; round++) + { + var res = points.GetPlayer(round, NumPlayerAtOnce); + if (res == null || res.Length < NumPlayerAtOnce) + { + return; + } + + for (var p = 0; p < NumPlayerAtOnce; p++) + { + scores[p] += res[p].Points; + } + } + + match.Score1 = (int)Math.Round(scores[0] / points.NumRounds); + match.Score2 = (int)Math.Round(scores[1] / points.NumRounds); + GameData.NumMatchesPlayed++; + + if (match.Score1 == match.Score2) + { + GameData.IsRematch = true; + return; + } + + GameData.IsRematch = false; + GameData.LastDecidedMatch = match; + match.Winner = match.Score1 > match.Score2 ? 0 : 1; + _Advance(match); + } + } +} diff --git a/PartyModes/PartyModeTournament/CPartyScreenTournamentConfig.cs b/PartyModes/PartyModeTournament/CPartyScreenTournamentConfig.cs new file mode 100644 index 00000000..48a5230b --- /dev/null +++ b/PartyModes/PartyModeTournament/CPartyScreenTournamentConfig.cs @@ -0,0 +1,138 @@ +#region license +// This file is part of Vocaluxe. +// +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . +#endregion + +using System.Windows.Forms; + +namespace VocaluxeLib.PartyModes.Tournament +{ + public class CPartyScreenTournamentConfig : CPartyScreenTournament + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private const string _SelectSlideNumPlayers = "SelectSlideNumPlayers"; + private const string _SelectSlideNumJokers = "SelectSlideNumJokers"; + private const string _ButtonNext = "ButtonNext"; + private const string _ButtonBack = "ButtonBack"; + + public override void Init() + { + base.Init(); + + _ThemeSelectSlides = new string[] { _SelectSlideNumPlayers, _SelectSlideNumJokers }; + _ThemeButtons = new string[] { _ButtonNext, _ButtonBack }; + } + + public override bool HandleInput(SKeyEvent keyEvent) + { + base.HandleInput(keyEvent); + + if (!keyEvent.KeyPressed) + { + switch (keyEvent.Key) + { + case Keys.Back: + case Keys.Escape: + _PartyMode.Back(); + break; + + case Keys.Enter: + _UpdateSlides(); + + if (_Buttons[_ButtonBack].Selected) + { + _PartyMode.Back(); + } + + if (_Buttons[_ButtonNext].Selected) + { + _PartyMode.Next(); + } + + break; + + case Keys.Left: + case Keys.Right: + _UpdateSlides(); + break; + } + } + + return true; + } + + public override bool HandleMouse(SMouseEvent mouseEvent) + { + base.HandleMouse(mouseEvent); + + if (mouseEvent.LB && _IsMouseOverCurSelection(mouseEvent)) + { + _UpdateSlides(); + if (_Buttons[_ButtonBack].Selected) + { + _PartyMode.Back(); + } + + if (_Buttons[_ButtonNext].Selected) + { + _PartyMode.Next(); + } + } + + if (mouseEvent.RB) + { + _PartyMode.Back(); + } + + return true; + } + + public override void OnShow() + { + base.OnShow(); + + _SelectSlides[_SelectSlideNumPlayers].Clear(); + for (var i = _PartyMode.MinPlayers; i <= _PartyMode.MaxPlayers; i++) + { + _SelectSlides[_SelectSlideNumPlayers].AddValue(i.ToString()); + } + + _SelectSlides[_SelectSlideNumPlayers].SelectedValue = _PartyMode.GameData.NumPlayer.ToString(); + + _SelectSlides[_SelectSlideNumJokers].Clear(); + for (var i = 0; i <= CPartyModeTournament.MaxJokers; i++) + { + _SelectSlides[_SelectSlideNumJokers].AddValue(i.ToString()); + } + + _SelectSlides[_SelectSlideNumJokers].SelectedValue = _PartyMode.GameData.NumJokers.ToString(); + } + + public override bool UpdateGame() + { + return true; + } + + private void _UpdateSlides() + { + _PartyMode.GameData.NumPlayer = _SelectSlides[_SelectSlideNumPlayers].Selection + _PartyMode.MinPlayers; + _PartyMode.GameData.NumJokers = _SelectSlides[_SelectSlideNumJokers].Selection; + } + } +} diff --git a/PartyModes/PartyModeTournament/CPartyScreenTournamentMain.cs b/PartyModes/PartyModeTournament/CPartyScreenTournamentMain.cs new file mode 100644 index 00000000..59e2dbb6 --- /dev/null +++ b/PartyModes/PartyModeTournament/CPartyScreenTournamentMain.cs @@ -0,0 +1,716 @@ +#region license +// This file is part of Vocaluxe. +// +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Windows.Forms; +using VocaluxeLib.Menu; + +namespace VocaluxeLib.PartyModes.Tournament +{ + class CMatchBox + { + public CStatic Box; + public CStatic Active; + public CStatic[] Avatars; + public CText[] Names; + public CText[] Scores; + } + + public class CPartyScreenTournamentMain : CPartyScreenTournament + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private const string _TextPopupReallyExit = "TextPopupReallyExit"; + private const string _TextRoundLabel = "TextRoundLabel"; + private const string _TextMatchName = "TextMatchName"; + private const string _TextMatchNameWinner = "TextMatchNameWinner"; + private const string _TextMatchNameLoser = "TextMatchNameLoser"; + private const string _TextMatchScore = "TextMatchScore"; + private const string _TextChampionLabel = "TextChampionLabel"; + private const string _TextChampion = "TextChampion"; + private const string _TextNextMatch = "TextNextMatch"; + private const string _TextRematch = "TextRematch"; + + private const string _ButtonNextRound = "ButtonNextRound"; + private const string _ButtonBack = "ButtonBack"; + private const string _ButtonExit = "ButtonExit"; + private const string _ButtonPopupYes = "ButtonPopupYes"; + private const string _ButtonPopupNo = "ButtonPopupNo"; + + private const string _StaticPopupBG = "StaticPopupBG"; + private const string _StaticMatchBox = "StaticMatchBox"; + private const string _StaticMatchActive = "StaticMatchActive"; + private const string _StaticMatchAvatar = "StaticMatchAvatar"; + private const string _StaticBracketLine = "StaticBracketLine"; + + private const string _ParticleEffectChampion = "ParticleEffectChampion"; + + private const int _MaxMatches = 15; + private const int _MaxColumns = 7; + private const int _MaxLines = 32; + private const float _Margin = 40f; + private const float _AreaTop = 210f; + private const float _AreaBottom = 830f; + private const float _MaxBoxW = 380f; + private const float _ColumnGap = 24f; + private const float _ScoreW = 70f; + private const float _RowH = 46f; + private const float _BoxPadding = 4f; + private const float _ActiveBorder = 4f; + private const float _LineThickness = 3f; + private const float _AdvanceDelay = 600f; + private const float _AdvanceDuration = 900f; + private const float _ChampionPopDuration = 700f; + private const float _FlyZ = -0.5f; + + private bool _ExitPopupVisible; + + private List _MatchBoxes; + private List _RoundLabels; + private List _Lines; + private int _NumLinesUsed; + + private readonly Stopwatch _AnimTimer = new Stopwatch(); + private CTournamentMatch _AdvanceMatch; + private CTournamentMatch _AdvanceTarget; + private int _AdvanceSlot; + private bool _ChampionShown; + private float _ChampionHeight; + + private CStatic _FlyBorder; + private CStatic _FlyBox; + private CStatic _FlyAvatar; + private CText _FlyName; + + public override void Init() + { + base.Init(); + + _ThemeTexts = new string[] + { + _TextPopupReallyExit, _TextRoundLabel, _TextMatchName, _TextMatchNameWinner, _TextMatchNameLoser, _TextMatchScore, _TextChampionLabel, _TextChampion, + _TextNextMatch, _TextRematch + }; + _ThemeButtons = new string[] { _ButtonNextRound, _ButtonBack, _ButtonExit, _ButtonPopupYes, _ButtonPopupNo }; + _ThemeStatics = new string[] { _StaticPopupBG, _StaticMatchBox, _StaticMatchActive, _StaticMatchAvatar, _StaticBracketLine }; + _ThemeParticleEffects = new string[] { _ParticleEffectChampion }; + } + + public override void LoadTheme(string xmlPath) + { + base.LoadTheme(xmlPath); + + _Lines = new List(); + for (var i = 0; i < _MaxLines; i++) + { + var line = GetNewStatic(_Statics[_StaticBracketLine]); + _AddStatic(line); + _Lines.Add(line); + } + + _MatchBoxes = new List(); + for (var i = 0; i < _MaxMatches; i++) + { + var matchBox = new CMatchBox + { + Active = GetNewStatic(_Statics[_StaticMatchActive]), + Box = GetNewStatic(_Statics[_StaticMatchBox]), + Avatars = new CStatic[CPartyModeTournament.NumPlayerAtOnce], + Names = new CText[CPartyModeTournament.NumPlayerAtOnce], + Scores = new CText[CPartyModeTournament.NumPlayerAtOnce] + }; + _AddStatic(matchBox.Active); + _AddStatic(matchBox.Box); + + for (var p = 0; p < CPartyModeTournament.NumPlayerAtOnce; p++) + { + matchBox.Avatars[p] = GetNewStatic(_Statics[_StaticMatchAvatar]); + matchBox.Avatars[p].Aspect = EAspect.Crop; + _AddStatic(matchBox.Avatars[p]); + matchBox.Names[p] = GetNewText(_Texts[_TextMatchName]); + _AddText(matchBox.Names[p]); + matchBox.Scores[p] = GetNewText(_Texts[_TextMatchScore]); + _AddText(matchBox.Scores[p]); + } + + _MatchBoxes.Add(matchBox); + } + + _RoundLabels = new List(); + for (var i = 0; i < _MaxColumns; i++) + { + var label = GetNewText(_Texts[_TextRoundLabel]); + _AddText(label); + _RoundLabels.Add(label); + } + + _Statics[_StaticMatchBox].Visible = false; + _Statics[_StaticMatchActive].Visible = false; + _Statics[_StaticMatchAvatar].Visible = false; + _Statics[_StaticBracketLine].Visible = false; + _Texts[_TextRoundLabel].Visible = false; + _Texts[_TextMatchName].Visible = false; + _Texts[_TextMatchNameWinner].Visible = false; + _Texts[_TextMatchNameLoser].Visible = false; + _Texts[_TextMatchScore].Visible = false; + + _FlyBorder = GetNewStatic(_Statics[_StaticMatchActive]); + _FlyBox = GetNewStatic(_Statics[_StaticMatchBox]); + _FlyAvatar = GetNewStatic(_Statics[_StaticMatchAvatar]); + _FlyAvatar.Aspect = EAspect.Crop; + _FlyName = GetNewText(_Texts[_TextMatchNameWinner]); + _FlyName.Z = _FlyZ - 0.15f; + _AddStatic(_FlyBorder); + _AddStatic(_FlyBox); + _AddStatic(_FlyAvatar); + _AddText(_FlyName); + _SetFlyVisible(false); + + _ChampionHeight = _Texts[_TextChampion].Font.Height; + } + + public override bool HandleInput(SKeyEvent keyEvent) + { + base.HandleInput(keyEvent); + + if (!keyEvent.KeyPressed) + { + switch (keyEvent.Key) + { + case Keys.Back: + case Keys.Escape: + _OnBack(); + break; + + case Keys.Enter: + _OnSelect(); + break; + } + } + + return true; + } + + public override bool HandleMouse(SMouseEvent mouseEvent) + { + base.HandleMouse(mouseEvent); + + if (mouseEvent.LB && _IsMouseOverCurSelection(mouseEvent)) + { + _OnSelect(); + } + + if (mouseEvent.RB) + { + _OnBack(); + } + + return true; + } + + public override void OnShow() + { + base.OnShow(); + + _AdvanceMatch = _PartyMode.GameData.LastDecidedMatch; + _PartyMode.GameData.LastDecidedMatch = null; + _AdvanceTarget = null; + if (_AdvanceMatch != null && _AdvanceMatch.Round + 1 < _PartyMode.NumRounds) + { + _AdvanceTarget = _PartyMode.GameData.Rounds[_AdvanceMatch.Round + 1][_AdvanceMatch.Index / 2]; + _AdvanceSlot = _AdvanceMatch.Index % 2; + } + + _ChampionShown = _PartyMode.IsFinished && _AdvanceMatch == null; + _AnimTimer.Reset(); + _AnimTimer.Start(); + _SetFlyVisible(false); + + _UpdateBracket(); + _UpdateInfo(); + + var started = _PartyMode.GameData.NumMatchesPlayed > 0; + _Buttons[_ButtonBack].Visible = !started; + _Buttons[_ButtonExit].Visible = started; + _Buttons[_ButtonNextRound].Visible = !_PartyMode.IsFinished; + + _ShowPopup(false); + + if (_PartyMode.IsFinished) + { + _SelectElement(_Buttons[_ButtonExit]); + } + else + { + _SelectElement(_Buttons[_ButtonNextRound]); + } + } + + public override bool UpdateGame() + { + if (_AdvanceMatch != null) + { + _UpdateAdvance(); + } + + if (_ChampionShown) + { + _UpdateChampion(); + } + + return true; + } + + private static float _EaseInOut(float t) + { + return t < 0.5f ? 4f * t * t * t : 1f - (float)Math.Pow(-2f * t + 2f, 3) / 2f; + } + + private static float _EaseOutBack(float t) + { + const float c1 = 1.70158f; + const float c3 = c1 + 1f; + return 1f + c3 * (float)Math.Pow(t - 1f, 3) + c1 * (float)Math.Pow(t - 1f, 2); + } + + private void _SetFlyVisible(bool visible) + { + _FlyBorder.Visible = visible; + _FlyBox.Visible = visible; + _FlyAvatar.Visible = visible; + _FlyName.Visible = visible; + } + + private SRectF _GetRowRect(int round, int index, int slot) + { + var box = _GetBoxRect(round, index); + return new SRectF(box.X, box.Y + _BoxPadding + slot * _RowH, box.W, _RowH, 0f); + } + + private void _UpdateAdvance() + { + var time = _AnimTimer.ElapsedMilliseconds - _AdvanceDelay; + if (time < 0) + { + return; + } + + if (_AdvanceTarget == null) + { + _AdvanceMatch = null; + _ChampionShown = true; + _AnimTimer.Reset(); + _AnimTimer.Start(); + _UpdateInfo(); + return; + } + + var progress = Math.Min(1f, time / _AdvanceDuration); + if (progress >= 1f) + { + _AdvanceMatch = null; + _AdvanceTarget = null; + _SetFlyVisible(false); + _UpdateBracket(); + return; + } + + var from = _GetRowRect(_AdvanceMatch.Round, _AdvanceMatch.Index, _AdvanceMatch.Winner); + var to = _GetRowRect(_AdvanceTarget.Round, _AdvanceTarget.Index, _AdvanceSlot); + var eased = _EaseInOut(progress); + var row = new SRectF(from.X + (to.X - from.X) * eased, from.Y + (to.Y - from.Y) * eased, from.W + (to.W - from.W) * eased, _RowH, 0f); + + var avatarSize = _RowH - 8f; + _FlyBox.MaxRect = new SRectF(row.X, row.Y, row.W, row.H, _FlyZ - 0.05f); + _FlyBorder.MaxRect = new SRectF(row.X - _ActiveBorder, row.Y - _ActiveBorder, row.W + 2 * _ActiveBorder, row.H + 2 * _ActiveBorder, _FlyZ); + _FlyAvatar.MaxRect = new SRectF(row.X + 8f, row.Y + 4f, avatarSize, avatarSize, _FlyZ - 0.1f); + _FlyAvatar.Texture = CBase.Profiles.GetAvatar(_PartyMode.GameData.ProfileIds[_AdvanceMatch.WinnerPlayer]); + _FlyName.Text = _GetName(_AdvanceMatch.WinnerPlayer); + _FlyName.X = row.X + 16f + avatarSize; + _FlyName.Y = row.Y + (_RowH - _FlyName.Rect.H) / 2; + _FlyName.W = row.W - avatarSize - 24f; + _SetFlyVisible(true); + } + + private void _UpdateChampion() + { + var time = _AnimTimer.ElapsedMilliseconds; + float scale; + if (time < _ChampionPopDuration) + { + scale = 0.3f + 0.7f * _EaseOutBack(time / _ChampionPopDuration); + } + else + { + scale = 1f + 0.03f * (float)Math.Sin((time - _ChampionPopDuration) / 1000.0 * Math.PI * 1.4); + } + + _Texts[_TextChampion].Font.Height = _ChampionHeight * scale; + } + + private void _OnBack() + { + if (_ExitPopupVisible) + { + _ShowPopup(false); + } + else if (_PartyMode.GameData.NumMatchesPlayed == 0) + { + _PartyMode.Back(); + } + else if (_PartyMode.IsFinished) + { + _EndParty(); + } + else + { + _ShowPopup(true); + } + } + + private void _OnSelect() + { + if (_ExitPopupVisible) + { + if (_Buttons[_ButtonPopupYes].Selected) + { + _EndParty(); + } + + if (_Buttons[_ButtonPopupNo].Selected) + { + _ShowPopup(false); + } + + return; + } + + if (_Buttons[_ButtonNextRound].Selected && _Buttons[_ButtonNextRound].Visible) + { + _PartyMode.Next(); + } + + if (_Buttons[_ButtonBack].Selected && _Buttons[_ButtonBack].Visible) + { + _PartyMode.Back(); + } + + if (_Buttons[_ButtonExit].Selected && _Buttons[_ButtonExit].Visible) + { + if (_PartyMode.IsFinished) + { + _EndParty(); + } + else + { + _ShowPopup(true); + } + } + } + + private void _EndParty() + { + CBase.Graphics.FadeTo(EScreen.Party); + } + + private void _ShowPopup(bool visible) + { + _ExitPopupVisible = visible; + + _Statics[_StaticPopupBG].Visible = _ExitPopupVisible; + _Texts[_TextPopupReallyExit].Visible = _ExitPopupVisible; + _Buttons[_ButtonPopupYes].Visible = _ExitPopupVisible; + _Buttons[_ButtonPopupNo].Visible = _ExitPopupVisible; + + if (_ExitPopupVisible) + { + _SelectElement(_Buttons[_ButtonPopupNo]); + } + } + + private string _GetName(int player) + { + return CBase.Profiles.GetPlayerName(_PartyMode.GameData.ProfileIds[player]); + } + + private string _GetRoundName(int round) + { + var fromEnd = _PartyMode.NumRounds - 1 - round; + switch (fromEnd) + { + case 0: + return "TR_SCREENMAIN_ROUND_FINAL"; + case 1: + return "TR_SCREENMAIN_ROUND_SEMIFINAL"; + case 2: + return "TR_SCREENMAIN_ROUND_QUARTERFINAL"; + default: + return "TR_SCREENMAIN_ROUND_EIGHTHFINAL"; + } + } + + private int _GetColumn(int round, int index) + { + var numRounds = _PartyMode.NumRounds; + if (round == numRounds - 1) + { + return round; + } + + var count = _PartyMode.GameData.Rounds[round].Length; + return index < count / 2 ? round : 2 * numRounds - 2 - round; + } + + private float _GetColumnWidth() + { + var numColumns = 2 * _PartyMode.NumRounds - 1; + return (CBase.Settings.GetRenderW() - 2 * _Margin) / numColumns; + } + + private float _GetBoxWidth() + { + return Math.Min(_GetColumnWidth() - _ColumnGap, _MaxBoxW); + } + + private float _GetBoxHeight() + { + return CPartyModeTournament.NumPlayerAtOnce * _RowH + 2 * _BoxPadding; + } + + private SRectF _GetBoxRect(int round, int index) + { + var columnW = _GetColumnWidth(); + var boxW = _GetBoxWidth(); + var boxH = _GetBoxHeight(); + var x = _Margin + _GetColumn(round, index) * columnW + (columnW - boxW) / 2; + + var areaH = _AreaBottom - _AreaTop; + float centerY; + if (round == _PartyMode.NumRounds - 1) + { + centerY = _AreaTop + areaH / 2; + } + else + { + var perSide = _PartyMode.GameData.Rounds[round].Length / 2; + var position = index % perSide; + centerY = _AreaTop + areaH * (position + 0.5f) / perSide; + } + + return new SRectF(x, centerY - boxH / 2, boxW, boxH, _Statics[_StaticMatchBox].Rect.Z); + } + + private void _UpdateBracket() + { + var current = _PartyMode.CurrentMatch; + var boxNr = 0; + _NumLinesUsed = 0; + + foreach (var round in _PartyMode.GameData.Rounds) + { + foreach (var match in round) + { + _UpdateMatchBox(_MatchBoxes[boxNr], match, match == current); + boxNr++; + + if (match.Round < _PartyMode.NumRounds - 1) + { + _AddConnector(match); + } + } + } + + for (var i = boxNr; i < _MatchBoxes.Count; i++) + { + _SetMatchBoxVisible(_MatchBoxes[i], false); + } + + for (var i = _NumLinesUsed; i < _Lines.Count; i++) + { + _Lines[i].Visible = false; + } + + var numColumns = 2 * _PartyMode.NumRounds - 1; + var columnW = _GetColumnWidth(); + for (var c = 0; c < _RoundLabels.Count; c++) + { + _RoundLabels[c].Visible = c < numColumns; + if (c >= numColumns) + { + continue; + } + + var round = c < _PartyMode.NumRounds ? c : numColumns - 1 - c; + _RoundLabels[c].X = _Margin + c * columnW + columnW / 2; + _RoundLabels[c].Text = _GetRoundName(round); + } + + var final = _GetBoxRect(_PartyMode.NumRounds - 1, 0); + _Texts[_TextChampionLabel].X = final.X + final.W / 2; + _Texts[_TextChampion].X = final.X + final.W / 2; + } + + private void _SetMatchBoxVisible(CMatchBox matchBox, bool visible) + { + matchBox.Box.Visible = visible; + matchBox.Active.Visible = false; + for (var p = 0; p < CPartyModeTournament.NumPlayerAtOnce; p++) + { + matchBox.Avatars[p].Visible = visible; + matchBox.Names[p].Visible = visible; + matchBox.Scores[p].Visible = visible; + } + } + + private void _UpdateMatchBox(CMatchBox matchBox, CTournamentMatch match, bool isCurrent) + { + var rect = _GetBoxRect(match.Round, match.Index); + _SetMatchBoxVisible(matchBox, true); + + matchBox.Box.MaxRect = rect; + matchBox.Active.MaxRect = new SRectF(rect.X - _ActiveBorder, rect.Y - _ActiveBorder, rect.W + 2 * _ActiveBorder, rect.H + 2 * _ActiveBorder, _Statics[_StaticMatchActive].Rect.Z); + matchBox.Active.Visible = isCurrent; + + var avatarSize = _RowH - 8f; + var showScore = (match.Played && !match.Bye) || (_PartyMode.GameData.IsRematch && isCurrent); + for (var p = 0; p < CPartyModeTournament.NumPlayerAtOnce; p++) + { + var player = p == 0 ? match.Player1 : match.Player2; + if (match == _AdvanceTarget && p == _AdvanceSlot) + { + player = -1; + } + + var rowY = rect.Y + _BoxPadding + p * _RowH; + + var avatar = matchBox.Avatars[p]; + avatar.MaxRect = new SRectF(rect.X + 8f, rowY + 4f, avatarSize, avatarSize, _Statics[_StaticMatchAvatar].Rect.Z); + avatar.Texture = player >= 0 ? CBase.Profiles.GetAvatar(_PartyMode.GameData.ProfileIds[player]) : null; + avatar.Visible = player >= 0; + + var name = matchBox.Names[p]; + name.X = rect.X + 16f + avatarSize; + name.Y = rowY + (_RowH - name.Rect.H) / 2; + name.W = rect.W - avatarSize - 24f - (showScore ? _ScoreW : 0f); + + var score = matchBox.Scores[p]; + score.X = rect.X + rect.W - 10f; + score.Y = name.Y; + + if (player >= 0) + { + name.Text = _GetName(player); + } + else if (match.Bye) + { + name.Text = "TR_SCREENMAIN_BYE"; + } + else + { + name.Text = "?"; + } + + score.Text = showScore ? (p == 0 ? match.Score1 : match.Score2).ToString() : string.Empty; + + if (match.Played) + { + name.Color = match.Winner == p ? _Texts[_TextMatchNameWinner].Color : _Texts[_TextMatchNameLoser].Color; + } + else + { + name.Color = player >= 0 ? _Texts[_TextMatchName].Color : _Texts[_TextMatchNameLoser].Color; + } + + score.Color = name.Color; + } + } + + private void _AddLine(float x1, float y1, float x2, float y2) + { + if (_NumLinesUsed >= _Lines.Count) + { + return; + } + + var line = _Lines[_NumLinesUsed++]; + var z = _Statics[_StaticBracketLine].Rect.Z; + if (Math.Abs(y1 - y2) < 0.5f) + { + line.MaxRect = new SRectF(Math.Min(x1, x2), y1 - _LineThickness / 2, Math.Abs(x2 - x1), _LineThickness, z); + } + else + { + line.MaxRect = new SRectF(x1 - _LineThickness / 2, Math.Min(y1, y2), _LineThickness, Math.Abs(y2 - y1), z); + } + + line.Visible = true; + } + + private void _AddConnector(CTournamentMatch match) + { + var box = _GetBoxRect(match.Round, match.Index); + var target = _GetBoxRect(match.Round + 1, match.Index / 2); + var leftSide = _GetColumn(match.Round, match.Index) < _PartyMode.NumRounds - 1; + var boxEdge = leftSide ? box.X + box.W : box.X; + var targetEdge = leftSide ? target.X : target.X + target.W; + var boxCenterY = box.Y + box.H / 2; + var targetCenterY = target.Y + target.H / 2; + + if (match.Round + 1 == _PartyMode.NumRounds - 1) + { + _AddLine(boxEdge, boxCenterY, targetEdge, boxCenterY); + return; + } + + var middleX = (boxEdge + targetEdge) / 2; + _AddLine(boxEdge, boxCenterY, middleX, boxCenterY); + + if (match.Index % 2 == 0) + { + var sibling = _GetBoxRect(match.Round, match.Index + 1); + _AddLine(middleX, boxCenterY, middleX, sibling.Y + sibling.H / 2); + _AddLine(middleX, targetCenterY, targetEdge, targetCenterY); + } + } + + private void _UpdateInfo() + { + var current = _PartyMode.CurrentMatch; + var finished = _PartyMode.IsFinished; + + _Texts[_TextChampion].Visible = finished && _ChampionShown; + _ParticleEffects[_ParticleEffectChampion].Visible = finished && _ChampionShown; + _Texts[_TextNextMatch].Visible = !finished && current != null; + _Texts[_TextRematch].Visible = !finished && _PartyMode.GameData.IsRematch; + + if (finished) + { + _Texts[_TextChampion].Text = _GetName(_PartyMode.FinalMatch.WinnerPlayer); + } + else if (current != null) + { + _Texts[_TextNextMatch].Text = CBase.Language.Translate("TR_SCREENMAIN_NEXT_MATCH", PartyModeId) + " " + _GetName(current.Player1) + " " + + CBase.Language.Translate("TR_SCREENMAIN_VERSUS", PartyModeId) + " " + _GetName(current.Player2); + } + } + } +} diff --git a/PartyModes/PartyModeTournament/CPartyScreenTournamentNames.cs b/PartyModes/PartyModeTournament/CPartyScreenTournamentNames.cs new file mode 100644 index 00000000..fa4de4b2 --- /dev/null +++ b/PartyModes/PartyModeTournament/CPartyScreenTournamentNames.cs @@ -0,0 +1,74 @@ +#region license +// This file is part of Vocaluxe. +// +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . +#endregion + +using System; +using System.Collections.Generic; +using VocaluxeLib.Menu; + +namespace VocaluxeLib.PartyModes.Tournament +{ + public class CPartyScreenTournamentNames : CMenuPartyNameSelection + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private new CPartyModeTournament _PartyMode; + + public override void Init() + { + base.Init(); + _PartyMode = (CPartyModeTournament)base._PartyMode; + _AllowChangePlayerNum = false; + _Teams = false; + } + + public override void OnShow() + { + base.OnShow(); + SetPartyModeData(_PartyMode.GameData.NumPlayer); + while (_PartyMode.GameData.ProfileIds.Count > _NumPlayer) + { + _PartyMode.GameData.ProfileIds.RemoveAt(_PartyMode.GameData.ProfileIds.Count - 1); + } + + var ids = new List[] { _PartyMode.GameData.ProfileIds }; + SetPartyModeProfiles(ids); + } + + public override void Back() + { + if (_TeamList.Length == 1) + { + _PartyMode.GameData.ProfileIds = _TeamList[0]; + } + + _PartyMode.Back(); + } + + public override void Next() + { + if (_TeamList.Length == 1) + { + _PartyMode.GameData.ProfileIds = _TeamList[0]; + } + + _PartyMode.Next(); + } + } +} \ No newline at end of file diff --git a/PartyModes/PartyModeTournament/CPartyScreenTournamentSongs.cs b/PartyModes/PartyModeTournament/CPartyScreenTournamentSongs.cs new file mode 100644 index 00000000..842f305f --- /dev/null +++ b/PartyModes/PartyModeTournament/CPartyScreenTournamentSongs.cs @@ -0,0 +1,66 @@ +using VocaluxeLib.Menu; + +namespace VocaluxeLib.PartyModes.Tournament +{ + class CPartyScreenTournamentSongs : CMenuPartySongSelection + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private new CPartyModeTournament _PartyMode; + + public override void Init() + { + base.Init(); + _PartyMode = (CPartyModeTournament)base._PartyMode; + } + + public override void OnShow() + { + Source = _PartyMode.GameData.SongSource; + Sorting = _PartyMode.GameData.Sorting; + Category = _PartyMode.GameData.CategoryIndex; + Playlist = _PartyMode.GameData.PlaylistId; + SongMode = _PartyMode.GameData.GameMode; + NumMedleySongs = _PartyMode.GameData.NumMedleySongs; + + base.OnShow(); + } + + public override void Back() + { + _SaveConfig(); + _PartyMode.Back(); + } + + public override void Next() + { + _SaveConfig(); + _PartyMode.Next(); + } + + public override bool UpdateGame() + { + return true; + } + + protected override void _SetAllowedOptions() + { + base._SetAllowedOptions(); + + AllowedSongModes = new EGameMode[] { EGameMode.TR_GAMEMODE_NORMAL, EGameMode.TR_GAMEMODE_SHORTSONG, EGameMode.TR_GAMEMODE_MEDLEY }; + } + + private void _SaveConfig() + { + _PartyMode.GameData.SongSource = Source; + _PartyMode.GameData.Sorting = Sorting; + _PartyMode.GameData.CategoryIndex = Category; + _PartyMode.GameData.PlaylistId = Playlist; + _PartyMode.GameData.GameMode = SongMode; + _PartyMode.GameData.NumMedleySongs = NumMedleySongs; + } + } +} \ No newline at end of file diff --git a/PartyModes/PartyModeTournament/GlobalSuppressions.cs b/PartyModes/PartyModeTournament/GlobalSuppressions.cs new file mode 100644 index 00000000..e661ff03 Binary files /dev/null and b/PartyModes/PartyModeTournament/GlobalSuppressions.cs differ diff --git a/PartyModes/PartyModeTournament/PartyModeTournament.csproj b/PartyModes/PartyModeTournament/PartyModeTournament.csproj new file mode 100644 index 00000000..6404e834 --- /dev/null +++ b/PartyModes/PartyModeTournament/PartyModeTournament.csproj @@ -0,0 +1,118 @@ + + + + DebugWin + AnyCPU + 8.0.30703 + 2.0 + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20} + Library + Properties + VocaluxeLib.PartyModes.Tournament + Tournament + v4.8.1 + + + 512 + + + AnyCPU + true + full + false + bin + TRACE;DEBUG;WIN + prompt + 4 + Off + ..\..\CheckingRules.ruleset + false + 9.0 + + + AnyCPU + pdbonly + true + bin + prompt + 4 + false + WIN + Off + false + true + 9.0 + + + AnyCPU + true + full + false + bin + TRACE;DEBUG;LINUX + prompt + 4 + Off + false + 9.0 + + + AnyCPU + pdbonly + true + bin + prompt + 4 + false + LINUX + Off + false + true + 9.0 + + + bin + WIN + true + AnyCPU + false + Off + prompt + ManagedMinimumRules.ruleset + false + pdbonly + true + 9.0 + + + + + + + + + + + + {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} + VocaluxeLib + False + + + + + + + + + + if exist "$(SolutionDir)Output\PartyModes\$(TargetName)\Code" rd "$(SolutionDir)Output\PartyModes\$(TargetName)\Code" /S /Q +cd $(SolutionDir)Partymodes\ +xcopy "$(ProjectDir)*.cs" "$(SolutionDir)Output\PartyModes\$(TargetName)\Code\" /EXCLUDE:Excludes.txt /I /Y + rm -rf "$(SolutionDir)Output\PartyModes\$(TargetName)\Code" +mkdir -p "$(SolutionDir)Output\PartyModes\$(TargetName)\Code\" +cp -R $(ProjectDir)*.cs "$(SolutionDir)Output\PartyModes\$(TargetName)\Code\" +rm -f "$(SolutionDir)Output\PartyModes\$(TargetName)\Code\GlobalSuppressions.cs" + + + \ No newline at end of file diff --git a/PartyModes/PartyModeTournament/Settings.StyleCop b/PartyModes/PartyModeTournament/Settings.StyleCop new file mode 100644 index 00000000..f4a4ea2a --- /dev/null +++ b/PartyModes/PartyModeTournament/Settings.StyleCop @@ -0,0 +1,809 @@ + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + \ No newline at end of file diff --git a/Vocaluxe.sln b/Vocaluxe.sln index 21d9d0f9..b1556cb0 100644 --- a/Vocaluxe.sln +++ b/Vocaluxe.sln @@ -10,6 +10,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocalu {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53} = {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53} {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} = {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} {5A4053F1-5AD5-441F-B254-D97A088127B6} = {5A4053F1-5AD5-441F-B254-D97A088127B6} + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20} = {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20} {54A48AF7-515C-4EDD-B395-2BFFA096050A} = {54A48AF7-515C-4EDD-B395-2BFFA096050A} {2E6A9B48-71C3-4D05-8F2B-C4A7D19E6E3F} = {2E6A9B48-71C3-4D05-8F2B-C4A7D19E6E3F} EndProjectSection @@ -22,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeTicTacToe", "Party EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeChallenge", "PartyModes\PartyModeChallenge\PartyModeChallenge.csproj", "{5A4053F1-5AD5-441F-B254-D97A088127B6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeTournament", "PartyModes\PartyModeTournament\PartyModeTournament.csproj", "{3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebserverInitalConfig", "WebserverInitalConfig\WebserverInitalConfig.csproj", "{55F89808-4E79-4FFE-BC13-48258913F5C9}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeRuleRoulette", "PartyModes\PartyModeRuleRoulette\PartyModeRuleRoulette.csproj", "{2E6A9B48-71C3-4D05-8F2B-C4A7D19E6E3F}" @@ -146,6 +149,26 @@ Global {5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU {5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU {5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugLinux|x64.ActiveCfg = DebugLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugLinux|x64.Build.0 = DebugLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugLinux|x86.ActiveCfg = DebugLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugLinux|x86.Build.0 = DebugLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugWin|x64.ActiveCfg = DebugWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugWin|x64.Build.0 = DebugWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugWin|x86.ActiveCfg = DebugWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugWin|x86.Build.0 = DebugWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.InstallerWin|x64.ActiveCfg = InstallerWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.InstallerWin|x64.Build.0 = InstallerWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.InstallerWin|x86.ActiveCfg = InstallerWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.InstallerWin|x86.Build.0 = InstallerWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseLinux|x64.Build.0 = ReleaseLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseLinux|x86.ActiveCfg = ReleaseLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseLinux|x86.Build.0 = ReleaseLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseWin|x64.ActiveCfg = ReleaseWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU {55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugLinux|x64.ActiveCfg = Debug|Any CPU {55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugLinux|x86.ActiveCfg = Debug|Any CPU {55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugWin|x64.ActiveCfg = Debug|Any CPU diff --git a/VocaluxeLib/Menu/CNameSelection.cs b/VocaluxeLib/Menu/CNameSelection.cs index 971745c3..4e66c6d2 100644 --- a/VocaluxeLib/Menu/CNameSelection.cs +++ b/VocaluxeLib/Menu/CNameSelection.cs @@ -479,30 +479,13 @@ namespace VocaluxeLib.Menu public Guid GetRandomUnusedProfile() { - var id = Guid.Empty; - - if (_VisibleProfiles.Count == 0) + var unusedProfiles = _VisibleProfiles.Where(profileId => !_UsedProfiles.Contains(profileId)).ToList(); + if (unusedProfiles.Count == 0) { - return id; + return Guid.Empty; } - if (_VisibleProfiles.Count == _UsedProfiles.Count) - { - return id; - } - - while (id == Guid.Empty) - { - var rand = CBase.Game.GetRandom(_VisibleProfiles.Count); - if (_UsedProfiles.Contains(_VisibleProfiles[rand])) - { - continue; - } - - id = _VisibleProfiles.ElementAt(rand); - } - - return id; + return unusedProfiles[CBase.Game.GetRandom(unusedProfiles.Count)]; } private void _PrepareTiles()