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()