diff --git a/Output/Languages/English.xml b/Output/Languages/English.xml index a847b5d2..2ad11503 100644 --- a/Output/Languages/English.xml +++ b/Output/Languages/English.xml @@ -101,6 +101,7 @@ Version Can\'t load this party-mode. There are no mics configured! + %d mics are required for this party-mode! Target audience No teams Number of teams diff --git a/Output/Languages/German.xml b/Output/Languages/German.xml index 968b2f79..82924766 100644 --- a/Output/Languages/German.xml +++ b/Output/Languages/German.xml @@ -101,6 +101,7 @@ Version Dieser Party-Modus konnte nicht geladen werden. Es sind keine Mikros konfiguriert! + Für diesen Party-Modus werden %d Mikros benötigt! Zielgruppe Keine Teams Anzahl der Teams diff --git a/Output/Languages/Spanish.xml b/Output/Languages/Spanish.xml index 06ce81a0..9d725abc 100644 --- a/Output/Languages/Spanish.xml +++ b/Output/Languages/Spanish.xml @@ -210,8 +210,6 @@ Cámaras web Resolución cámara web Ajustes de pantalla - Pulsa CTRL + ALT + SHIFT + Flechas para ajustar la pantalla - CTRL + ALT + SHIFT + 0 para reiniciar Arriba izquierda Abajo derecha Abajo izquierda diff --git a/Output/Languages/Swedish.xml b/Output/Languages/Swedish.xml index 92c72192..8d400dac 100644 --- a/Output/Languages/Swedish.xml +++ b/Output/Languages/Swedish.xml @@ -93,6 +93,7 @@ Party Alternativ Profiler + Inga profiler funna! Party Läge Väljare Party Läge Beskrivning @@ -100,6 +101,7 @@ Version kan ej ladda detta party läge Det finns inga mikrofoner konfigurerade! + %d mikrofoner krävs för denna party-mode! Mål publik Inga lag Antal lag @@ -211,8 +213,8 @@ Webkameror Webkamera Upplösning Skärmjusteringar - Tryck CTRL + ALT +SHIFT + Pilar för att justera skärmen - CTRL + ALT + SHIFT + 0 för att återställa + Tryck CTR + ALT (+ SHIFT) + Pilar"+" för att justera skärmen + CTR + ALT + 0 för att återställa Överst till vänster Överst till höger Nederst till vänster diff --git a/Output/PartyModes/Challenge/Themes/Default/Screens/PartyScreenChallengeConfig.xml b/Output/PartyModes/Challenge/Themes/Default/Screens/PartyScreenChallengeConfig.xml index da365e48..5dfbf453 100644 --- a/Output/PartyModes/Challenge/Themes/Default/Screens/PartyScreenChallengeConfig.xml +++ b/Output/PartyModes/Challenge/Themes/Default/Screens/PartyScreenChallengeConfig.xml @@ -194,7 +194,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -236,7 +236,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -278,7 +278,7 @@ 27 - 0 + 50 0 205.33 Outline diff --git a/Output/PartyModes/Challenge/Themes/Default/Screens/PartyScreenChallengeNames.xml b/Output/PartyModes/Challenge/Themes/Default/Screens/PartyScreenChallengeNames.xml index a3bd1919..5980e6d3 100644 --- a/Output/PartyModes/Challenge/Themes/Default/Screens/PartyScreenChallengeNames.xml +++ b/Output/PartyModes/Challenge/Themes/Default/Screens/PartyScreenChallengeNames.xml @@ -295,7 +295,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -337,8 +337,8 @@ 27 - 0 - -5 + 50 + 5 205.33 Outline Bold diff --git a/Output/PartyModes/ChallengeMedley/Themes/Default/Screens/PartyScreenChallengeMedleyConfig.xml b/Output/PartyModes/ChallengeMedley/Themes/Default/Screens/PartyScreenChallengeMedleyConfig.xml index 02620808..dbc62be5 100644 --- a/Output/PartyModes/ChallengeMedley/Themes/Default/Screens/PartyScreenChallengeMedleyConfig.xml +++ b/Output/PartyModes/ChallengeMedley/Themes/Default/Screens/PartyScreenChallengeMedleyConfig.xml @@ -194,7 +194,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -236,7 +236,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -278,7 +278,7 @@ 27 - 0 + 50 0 205.33 Outline diff --git a/Output/PartyModes/ChallengeMedley/Themes/Default/Screens/PartyScreenChallengeMedleyNames.xml b/Output/PartyModes/ChallengeMedley/Themes/Default/Screens/PartyScreenChallengeMedleyNames.xml index 72512c94..2292a076 100644 --- a/Output/PartyModes/ChallengeMedley/Themes/Default/Screens/PartyScreenChallengeMedleyNames.xml +++ b/Output/PartyModes/ChallengeMedley/Themes/Default/Screens/PartyScreenChallengeMedleyNames.xml @@ -295,7 +295,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -337,8 +337,8 @@ 27 - 0 - -5 + 50 + 5 205.33 Outline Bold diff --git a/Output/PartyModes/TicTacToe/Themes/Default/Screens/PartyScreenTicTacToeConfig.xml b/Output/PartyModes/TicTacToe/Themes/Default/Screens/PartyScreenTicTacToeConfig.xml index 1d02431f..bf570d8d 100644 --- a/Output/PartyModes/TicTacToe/Themes/Default/Screens/PartyScreenTicTacToeConfig.xml +++ b/Output/PartyModes/TicTacToe/Themes/Default/Screens/PartyScreenTicTacToeConfig.xml @@ -194,7 +194,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -236,7 +236,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -278,7 +278,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -320,7 +320,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -362,7 +362,7 @@ 27 - 0 + 50 0 205.33 Outline diff --git a/Output/PartyModes/TicTacToe/Themes/Default/Screens/PartyScreenTicTacToeNames.xml b/Output/PartyModes/TicTacToe/Themes/Default/Screens/PartyScreenTicTacToeNames.xml index df5bc5db..583ea0bc 100644 --- a/Output/PartyModes/TicTacToe/Themes/Default/Screens/PartyScreenTicTacToeNames.xml +++ b/Output/PartyModes/TicTacToe/Themes/Default/Screens/PartyScreenTicTacToeNames.xml @@ -295,7 +295,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -337,8 +337,8 @@ 27 - 0 - -5 + 50 + 5 205.33 Outline Bold diff --git a/Output/Themes/Ambient/Screens/PopupScreenVolumeControl.xml b/Output/Themes/Ambient/Screens/PopupScreenVolumeControl.xml index 1bb2bfdd..1ec17015 100644 --- a/Output/Themes/Ambient/Screens/PopupScreenVolumeControl.xml +++ b/Output/Themes/Ambient/Screens/PopupScreenVolumeControl.xml @@ -46,22 +46,22 @@ Minus Plus - 1090 + 1070 680 200 - 50 + 30 -2 1195 - 682 + 680 30 30 -2 - 1240 - 682 + 1235 + 680 30 30 -2 @@ -73,9 +73,9 @@ 27 - -15 - -8 - 500 + 0 + 0 + 25 Outline Bold 1 diff --git a/Output/Themes/Ambient/Screens/ScreenNames.xml b/Output/Themes/Ambient/Screens/ScreenNames.xml index fe44cdc6..24cac2dd 100644 --- a/Output/Themes/Ambient/Screens/ScreenNames.xml +++ b/Output/Themes/Ambient/Screens/ScreenNames.xml @@ -418,7 +418,7 @@ 27 - 0 + 50 0 186 Outline @@ -460,7 +460,7 @@ 20 - 0 + 50 0 86 Outline @@ -502,7 +502,7 @@ 20 - 0 + 50 0 86 Outline @@ -544,7 +544,7 @@ 20 - 0 + 50 0 86 Outline @@ -586,7 +586,7 @@ 20 - 0 + 50 0 86 Outline @@ -628,7 +628,7 @@ 20 - 0 + 50 0 86 Outline @@ -670,7 +670,7 @@ 20 - 0 + 50 0 86 Outline diff --git a/Output/Themes/Ambient/Screens/ScreenOptionsGame.xml b/Output/Themes/Ambient/Screens/ScreenOptionsGame.xml index cd75ed75..5b3b6ec4 100644 --- a/Output/Themes/Ambient/Screens/ScreenOptionsGame.xml +++ b/Output/Themes/Ambient/Screens/ScreenOptionsGame.xml @@ -302,7 +302,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -344,7 +344,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -386,7 +386,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -428,7 +428,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -470,7 +470,7 @@ 27 - 0 + 50 0 308 Outline @@ -512,7 +512,7 @@ 27 - 0 + 50 0 205.33 Outline diff --git a/Output/Themes/Ambient/Screens/ScreenOptionsLyrics.xml b/Output/Themes/Ambient/Screens/ScreenOptionsLyrics.xml index 4ad2bbf6..ea8f4344 100644 --- a/Output/Themes/Ambient/Screens/ScreenOptionsLyrics.xml +++ b/Output/Themes/Ambient/Screens/ScreenOptionsLyrics.xml @@ -145,7 +145,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -187,7 +187,7 @@ 27 - 0 + 50 0 205.33 Outline diff --git a/Output/Themes/Ambient/Screens/ScreenOptionsRecord.xml b/Output/Themes/Ambient/Screens/ScreenOptionsRecord.xml index f5696725..95b8464d 100644 --- a/Output/Themes/Ambient/Screens/ScreenOptionsRecord.xml +++ b/Output/Themes/Ambient/Screens/ScreenOptionsRecord.xml @@ -338,7 +338,7 @@ 27 - 0 + 50 0 616 Outline @@ -380,7 +380,7 @@ 27 - 0 + 50 0 154 Outline @@ -422,7 +422,7 @@ 27 - 0 + 50 0 154 Outline @@ -464,7 +464,7 @@ 27 - 0 + 50 0 123.2 Outline diff --git a/Output/Themes/Ambient/Screens/ScreenOptionsSound.xml b/Output/Themes/Ambient/Screens/ScreenOptionsSound.xml index ae35c3bc..9b7e88c6 100644 --- a/Output/Themes/Ambient/Screens/ScreenOptionsSound.xml +++ b/Output/Themes/Ambient/Screens/ScreenOptionsSound.xml @@ -187,7 +187,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -229,7 +229,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -271,7 +271,7 @@ 27 - 0 + 50 0 500 Outline @@ -313,7 +313,7 @@ 27 - 0 + 50 0 500 Outline @@ -355,7 +355,7 @@ 27 - 0 + 50 0 500 Outline diff --git a/Output/Themes/Ambient/Screens/ScreenOptionsTheme.xml b/Output/Themes/Ambient/Screens/ScreenOptionsTheme.xml index 3f0e890c..61ed39bb 100644 --- a/Output/Themes/Ambient/Screens/ScreenOptionsTheme.xml +++ b/Output/Themes/Ambient/Screens/ScreenOptionsTheme.xml @@ -317,7 +317,7 @@ 27 - 0 + 50 0 616 Outline @@ -359,7 +359,7 @@ 27 - 0 + 50 0 616 Outline @@ -401,7 +401,7 @@ 27 - 0 + 50 0 308 Outline @@ -443,7 +443,7 @@ 27 - 0 + 50 0 308 Outline @@ -485,7 +485,7 @@ 27 - 0 + 50 0 308 Outline @@ -527,7 +527,7 @@ 27 - 0 + 50 0 308 Outline @@ -569,7 +569,7 @@ 27 - 0 + 50 0 616 Outline @@ -611,7 +611,7 @@ 27 - 0 + 50 0 616 Outline diff --git a/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml b/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml index b5740cc5..06a05c7b 100644 --- a/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml +++ b/Output/Themes/Ambient/Screens/ScreenOptionsVideo.xml @@ -280,7 +280,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -322,7 +322,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -364,7 +364,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -406,7 +406,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -448,7 +448,7 @@ 27 - 0 + 50 0 205.33 Outline @@ -490,7 +490,7 @@ 27 - 0 + 50 0 150 Outline diff --git a/Output/Themes/Ambient/Screens/ScreenParty.xml b/Output/Themes/Ambient/Screens/ScreenParty.xml index de8283d4..3dec51bd 100644 --- a/Output/Themes/Ambient/Screens/ScreenParty.xml +++ b/Output/Themes/Ambient/Screens/ScreenParty.xml @@ -348,7 +348,7 @@ 27 - 0 + 50 0 600 Outline diff --git a/Output/Themes/Ambient/Screens/ScreenProfiles.xml b/Output/Themes/Ambient/Screens/ScreenProfiles.xml index ca84426b..c612e90e 100644 --- a/Output/Themes/Ambient/Screens/ScreenProfiles.xml +++ b/Output/Themes/Ambient/Screens/ScreenProfiles.xml @@ -509,7 +509,7 @@ 27 - 0 + 50 0 219.2 Outline @@ -551,7 +551,7 @@ 27 - 0 + 50 0 208.67 Outline @@ -593,7 +593,7 @@ 27 - 0 + 50 0 208.67 Outline @@ -635,7 +635,7 @@ 27 - 0 + 50 0 313 Outline @@ -677,7 +677,7 @@ 27 - 0 + 50 0 313 Outline diff --git a/Output/Themes/Ambient/Screens/ScreenSong.xml b/Output/Themes/Ambient/Screens/ScreenSong.xml index d9f45cd2..62dba236 100644 --- a/Output/Themes/Ambient/Screens/ScreenSong.xml +++ b/Output/Themes/Ambient/Screens/ScreenSong.xml @@ -899,7 +899,7 @@ 25 - 0 + 50 0 280 Outline @@ -941,7 +941,7 @@ 25 - 0 + 50 0 280 Outline @@ -983,7 +983,7 @@ 25 - 0 + 50 0 280 Outline @@ -1025,7 +1025,7 @@ 25 - 0 + 50 0 280 Outline @@ -1232,7 +1232,7 @@ - + Button SelectSlideArrowLeft SelectSlideArrowRight diff --git a/PartyModes/PartyModeChallenge/CChallengeRounds.cs b/PartyModes/PartyModeChallenge/CChallengeRounds.cs index 6b45ea1f..37d46362 100644 --- a/PartyModes/PartyModeChallenge/CChallengeRounds.cs +++ b/PartyModes/PartyModeChallenge/CChallengeRounds.cs @@ -17,218 +17,136 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using VocaluxeLib.Utils.Combinatorics; namespace VocaluxeLib.PartyModes.Challenge { public class CChallengeRounds { - private readonly Random _Rand; - private readonly int _NumPlayer; - - public readonly List Rounds; + private readonly List _Rounds = new List(); public int Count { - get { return Rounds.Count; } + get { return _Rounds.Count; } } - public CCombination this[int index] + public CRound this[int index] { - get { return Rounds[index]; } + get { return _Rounds[index]; } } - public CChallengeRounds(int numRounds, int numPlayer, int numPlayerAtOnce) + public CChallengeRounds(int numRounds, int numPlayer, int playersPerRound) { - Rounds = new List(); - _Rand = new Random(DateTime.Now.Millisecond); + if (numRounds < 1 || numPlayer < 1 || playersPerRound < 1) + throw new ArgumentException("Invalid paramters for the rounds"); - if (numPlayerAtOnce < 1 || numRounds < 1 || numPlayer == 0) - _NumPlayer = 0; - else + if (playersPerRound > numPlayer) + playersPerRound = numPlayer; + + _BuildRounds(numRounds, numPlayer, playersPerRound); + if (Count > numRounds) { - _NumPlayer = numPlayer; - _BuildRounds(numRounds, numPlayerAtOnce, _Rand); - } - } - - public CCombination GetRound(int roundNr) - { - if (roundNr >= Rounds.Count || _NumPlayer == 0 || Rounds.Count == 0) - return null; - - return Rounds[roundNr]; - } - - private void _BuildRounds(int numRounds, int numPlayerAtOnce, Random rand) - { - CCombinations combinations = new CCombinations(_NumPlayer, numPlayerAtOnce, rand); - Rounds.Add(combinations.GetNextCombination(null)); - - for (int i = 1; i < numRounds; i++) - Rounds.Add(combinations.GetNextCombination(_GetPlayerDemand(i))); - } - - private IEnumerable _GetPlayerDemand(int roundIndex) - { - List numPlayed = new List(_NumPlayer); - for (int i = 0; i < _NumPlayer; i++) - numPlayed.Add(0); - - for (int i = 0; i < roundIndex; i++) - { - foreach (int playerIndex in Rounds[i].Player) - numPlayed[playerIndex]++; - } - - int max = numPlayed.Max(); - - int num = Rounds[0].Player.Count; - List result = new List(); - List other = new List(); - List last = new List(); - - for (int i = 0; i < numPlayed.Count; i++) - { - if (roundIndex == 0 || numPlayed[i] < max) + //Try again and take the better one + List old = new List(_Rounds); + _Rounds.Clear(); + _BuildRounds(numRounds, numPlayer, playersPerRound); + if (Count > old.Count) { - if (roundIndex == 0 || roundIndex > 0 && numPlayed[i] < max && !Rounds[roundIndex - 1].IsAvailable(i)) - result.Add(i); - else if (numPlayed[i] < max) - other.Add(i); - } - else - { - if (roundIndex > 0) - { - if (!Rounds[roundIndex - 1].IsAvailable(i)) - other.Add(i); - else - last.Add(i); - } - else - last.Add(i); + _Rounds.Clear(); + _Rounds.AddRange(old); } } + } - while (result.Count < num && other.Count > 0) + /// + /// Divides players in 2 categories: Those how sung the most and the others + /// + /// List matching the playerIndex to the number of songs sung + private static List _GetPlayersForRound(IList numSung) + { + List mustSing = new List(); + int max = numSung.Max(); + for (int i = 0; i < numSung.Count; i++) { - int n = other.Count; - int r = _Rand.Next(n); - result.Add(other[r]); - other.RemoveAt(r); + if (numSung[i] < max) + mustSing.Add(i); } + return mustSing; + } - while (result.Count < num) + private static void _AddCombinations(int numPlayer, int playersPerRound, List combinations) + { + List input = new List(numPlayer); + for (int i = 0; i < numPlayer; i++) + input.Add(i); + CCombinations combs = new CCombinations(input, playersPerRound); + combinations.AddRange(combs.Select(combination => new CRound(combination))); + combinations.Shuffle(); + } + + private static CRound _GetMatchingCombination(List playersInRound, List numSung, List combinations) + { + foreach (CRound round in combinations) { - int n = last.Count; - int r = _Rand.Next(n); - result.Add(last[r]); - last.RemoveAt(r); + int matching = round.Players.Count(playersInRound.Contains); + // A valid round contains only players from playersInRound or all players from playersInRound (and some others) + if (matching == round.Players.Count || matching == playersInRound.Count) + return round; } - - while (result.Count > num) + // It may happen, that there are only players that already sung against each other. So create a 2nd best option with the most number of players that should sing in it + int maxMatching = combinations.Max(c => c.Players.Count(playersInRound.Contains)); + List nextOptions = combinations.Where(c => c.Players.Count(playersInRound.Contains) == maxMatching).ToList(); + // And select the combination that minimizes the sum of the number of songs sung (--> favor rounds with players that sung less than others) + CRound result = null; + int minSung = int.MaxValue; + foreach (CRound round in nextOptions) { - int n = result.Count; - int r = _Rand.Next(n); - result.RemoveAt(r); + int curNumSung = round.Players.Sum(pl => numSung[pl]); + if (curNumSung < minSung) + { + minSung = curNumSung; + result = round; + } } - - result.Sort(); + Debug.Assert(result != null); return result; } - } - class CCombinations - { - private readonly List _Combs; - private readonly Random _Rand; - private readonly int _NumPlayer; - private readonly int _NumMics; - - public CCombinations(int numPlayer, int numMics, Random rand) + private void _BuildRounds(int numRounds, int numPlayer, int playersPerRound) { - _Combs = new List(); - _NumMics = numMics; - _NumPlayer = numPlayer; - _Rand = rand; - } - - public CCombination GetNextCombination(IEnumerable playerNrDemand) - { - if (_Combs.Count == 0) - _Create(); - - if (_NumPlayer == _NumMics) - return _Combs[0]; - - //filter against PlayerNrDemand - List combsFiltered = new List(); - if (playerNrDemand != null) - combsFiltered.AddRange(_Combs.Where(t => t.IsAvailableAll(playerNrDemand))); - - //1st fallback - if (playerNrDemand != null && combsFiltered.Count == 0) - combsFiltered.AddRange(_Combs.Where(t => t.IsAvailableSomeone(playerNrDemand))); - - //2nd fallback - if (combsFiltered.Count == 0) - combsFiltered.AddRange(_Combs); - - int num = combsFiltered.Count; - int rand = _Rand.Next(num); - CCombination c = new CCombination(); - for (int i = 0; i < combsFiltered[rand].Player.Count; i++) - c.Player.Add(combsFiltered[rand].Player[i]); - _Combs.Remove(combsFiltered[rand]); - - return combsFiltered[rand]; - } - - private void _Create() - { - _Combs.Clear(); - - int num = (int)Math.Pow(2, _NumPlayer); - - for (int i = 1; i <= num; i++) + // What we want is that every player sung the same amount of songs + // So we keep track how many songs each palyer sung + List numSung = new List(numPlayer); + for (int i = 0; i < numPlayer; i++) + numSung.Add(0); + List combinations = new List(); + // Posibly add more rounds than requested if the song count per player is unequal + for (int i = 0; i < numRounds * 10; i++) { - CCombination c = new CCombination(); - - for (int j = 0; j < _NumPlayer; j++) - { - if ((i & (1 << j)) > 0) - c.Player.Add(j); - } - - if (c.Player.Count == _NumMics) - _Combs.Add(c); + if (combinations.Count == 0) + _AddCombinations(numPlayer, playersPerRound, combinations); + List playersInRound = _GetPlayersForRound(numSung); + CRound curRound = _GetMatchingCombination(playersInRound, numSung, combinations); + foreach (int player in curRound.Players) + numSung[player]++; + _Rounds.Add(curRound); + combinations.Remove(curRound); + //Stop if we have enough rounds and all players sung the same amount of songs + if (_Rounds.Count >= numRounds && numSung.All(ct => ct == numSung[0])) + break; } } } - public class CCombination + public class CRound { - public readonly List Player; + public readonly List Players; - public CCombination() + public CRound(List players) { - Player = new List(); - } - - public bool IsAvailable(int playerIndex) - { - return Player.Any(p => p == playerIndex); - } - - public bool IsAvailableAll(IEnumerable playerIndices) - { - return playerIndices.All(IsAvailable); - } - - public bool IsAvailableSomeone(IEnumerable playerIndices) - { - return playerIndices.Any(IsAvailable); + Players = players.Shuffle(); } } } \ No newline at end of file diff --git a/PartyModes/PartyModeChallenge/CPartyModeChallenge.cs b/PartyModes/PartyModeChallenge/CPartyModeChallenge.cs index db882cd4..d00a1f5b 100644 --- a/PartyModes/PartyModeChallenge/CPartyModeChallenge.cs +++ b/PartyModes/PartyModeChallenge/CPartyModeChallenge.cs @@ -67,11 +67,38 @@ namespace VocaluxeLib.PartyModes.Challenge public sealed class CPartyModeChallenge : CPartyMode // ReSharper restore ClassNeverInstantiated.Global { - private const int _MaxPlayer = 12; - private const int _MinPlayer = 1; - private const int _MaxTeams = 0; - private const int _MinTeams = 0; - private const int _MaxNumRounds = 100; + public override int MinMics + { + get { return 1; } + } + public override int MaxMics + { + get { return CBase.Config.GetMaxNumMics(); } + } + public override int MinPlayers + { + get { return 1; } + } + public override int MaxPlayers + { + get { return 12; } + } + 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 { @@ -108,7 +135,7 @@ namespace VocaluxeLib.PartyModes.Challenge public SData GameData; private EStage _Stage; - public CPartyModeChallenge(int id, string folder) : base(id, folder) + public CPartyModeChallenge(int id) : base(id) { _ScreenSongOptions.Selection.RandomOnly = false; _ScreenSongOptions.Selection.PartyMode = true; @@ -125,6 +152,8 @@ namespace VocaluxeLib.PartyModes.Challenge public override bool Init() { + if (!base.Init()) + return false; _Stage = EStage.Config; _ScreenSongOptions.Sorting.IgnoreArticles = CBase.Config.GetIgnoreArticles(); @@ -283,31 +312,6 @@ namespace VocaluxeLib.PartyModes.Challenge _ScreenSongOptions.Sorting.SearchActive = visible; } - public override int GetMaxPlayer() - { - return _MaxPlayer; - } - - public override int GetMinPlayer() - { - return _MinPlayer; - } - - public override int GetMaxTeams() - { - return _MaxTeams; - } - - public override int GetMinTeams() - { - return _MinTeams; - } - - public override int GetMaxNumRounds() - { - return _MaxNumRounds; - } - public override void JokerUsed(int teamNr) { if (_ScreenSongOptions.Selection.NumJokers == null) @@ -337,13 +341,13 @@ namespace VocaluxeLib.PartyModes.Challenge if (players.Length < GameData.NumPlayerAtOnce) return; - CCombination c = GameData.Rounds.GetRound(GameData.CurrentRoundNr - 1); + CRound c = GameData.Rounds[GameData.CurrentRoundNr - 1]; for (int i = 0; i < GameData.NumPlayerAtOnce; i++) { //try to fill with the right data if (c != null) - players[i].ProfileID = GameData.ProfileIDs[c.Player[i]]; + players[i].ProfileID = GameData.ProfileIDs[c.Players[i]]; else players[i].ProfileID = -1; } @@ -409,15 +413,10 @@ namespace VocaluxeLib.PartyModes.Challenge } _ScreenSongOptions.Selection.TeamNames = new string[GameData.NumPlayerAtOnce]; - CCombination c = GameData.Rounds.GetRound(GameData.CurrentRoundNr - 1); + CRound c = GameData.Rounds[GameData.CurrentRoundNr - 1]; for (int i = 0; i < GameData.NumPlayerAtOnce; i++) - { - if (c != null) - _ScreenSongOptions.Selection.TeamNames[i] = CBase.Profiles.GetPlayerName(GameData.ProfileIDs[c.Player[i]]); - else - _ScreenSongOptions.Selection.TeamNames[i] = "foobar"; - } + _ScreenSongOptions.Selection.TeamNames[i] = CBase.Profiles.GetPlayerName(GameData.ProfileIDs[c.Players[i]]); } private void _UpdateScores() @@ -437,44 +436,42 @@ namespace VocaluxeLib.PartyModes.Challenge GameData.Results[i, j] = 0; } } - else + SPlayer[] results = CBase.Game.GetPlayers(); + if (results == null) + return; + + if (results.Length < GameData.NumPlayerAtOnce) + return; + + for (int j = 0; j < GameData.NumPlayerAtOnce; j++) + GameData.Results[GameData.CurrentRoundNr - 2, j] = (int)Math.Round(results[j].Points); + + List points = _GetPointsForPlayer(results); + + for (int i = 0; i < GameData.NumPlayerAtOnce; i++) { - SPlayer[] results = CBase.Game.GetPlayers(); - if (results == null) - return; - - if (results.Length < GameData.NumPlayerAtOnce) - return; - - for (int j = 0; j < GameData.NumPlayerAtOnce; j++) - GameData.Results[GameData.CurrentRoundNr - 2, j] = (int)Math.Round(results[j].Points); - - List points = _GetPointsForPlayer(results); - - for (int i = 0; i < GameData.NumPlayerAtOnce; i++) + int index = -1; + for (int j = 0; j < GameData.ResultTable.Count; j++) { - int index = -1; - for (int j = 0; j < GameData.ResultTable.Count; j++) + if (points[i].ProfileID == GameData.ResultTable[j].PlayerID) { - if (points[i].ProfileID == GameData.ResultTable[j].PlayerID) - { - index = j; - break; - } + index = j; + break; } - - if (index == -1) - continue; - CResultTableRow row = GameData.ResultTable[index]; - - row.NumPlayed++; - row.NumWon += points[i].Won; - row.NumSingPoints += points[i].SingPoints; - row.NumGamePoints += points[i].GamePoints; - - GameData.ResultTable[index] = row; } + + if (index == -1) + continue; + CResultTableRow row = GameData.ResultTable[index]; + + row.NumPlayed++; + row.NumWon += points[i].Won; + row.NumSingPoints += points[i].SingPoints; + row.NumGamePoints += points[i].GamePoints; + + GameData.ResultTable[index] = row; } + GameData.ResultTable.Sort(); diff --git a/PartyModes/PartyModeChallenge/CPartyScreenChallengeConfig.cs b/PartyModes/PartyModeChallenge/CPartyScreenChallengeConfig.cs index e1ef8456..d1a4747b 100644 --- a/PartyModes/PartyModeChallenge/CPartyScreenChallengeConfig.cs +++ b/PartyModes/PartyModeChallenge/CPartyScreenChallengeConfig.cs @@ -15,6 +15,7 @@ // along with Vocaluxe. If not, see . #endregion +using System; using System.Windows.Forms; namespace VocaluxeLib.PartyModes.Challenge @@ -35,8 +36,7 @@ namespace VocaluxeLib.PartyModes.Challenge private const string _ButtonNext = "ButtonNext"; private const string _ButtonBack = "ButtonBack"; - private int _MaxNumMics = 2; - private int _MaxNumRounds = 100; + private const int _MaxNumRounds = 100; private int _RoundSteps = 1; public override void Init() @@ -107,12 +107,6 @@ namespace VocaluxeLib.PartyModes.Challenge { base.OnShow(); - _MaxNumMics = CBase.Config.GetMaxNumMics(); - if (_MaxNumMics > 6) - _MaxNumMics = 6; - - _MaxNumRounds = _PartyMode.GetMaxNumRounds(); - _RebuildSlides(); } @@ -125,9 +119,9 @@ namespace VocaluxeLib.PartyModes.Challenge { // build num player slide (min player ... max player); _SelectSlides[_SelectSlideNumPlayers].Clear(); - for (int i = _PartyMode.GetMinPlayer(); i <= _PartyMode.GetMaxPlayer(); i++) + for (int i = _PartyMode.MinPlayers; i <= _PartyMode.MaxPlayers; i++) _SelectSlides[_SelectSlideNumPlayers].AddValue(i.ToString()); - _SelectSlides[_SelectSlideNumPlayers].Selection = _PartyMode.GameData.NumPlayer - _PartyMode.GetMinPlayer(); + _SelectSlides[_SelectSlideNumPlayers].SelectedValue = _PartyMode.GameData.NumPlayer.ToString(); _UpdateMicsAtOnce(); _SetRoundSteps(); @@ -138,8 +132,8 @@ namespace VocaluxeLib.PartyModes.Challenge { int player = _PartyMode.GameData.NumPlayer; int mics = _PartyMode.GameData.NumPlayerAtOnce; - _PartyMode.GameData.NumPlayer = _SelectSlides[_SelectSlideNumPlayers].Selection + _PartyMode.GetMinPlayer(); - _PartyMode.GameData.NumPlayerAtOnce = _SelectSlides[_SelectSlideNumMics].Selection + _PartyMode.GetMinPlayer(); + _PartyMode.GameData.NumPlayer = _SelectSlides[_SelectSlideNumPlayers].Selection + _PartyMode.MinPlayers; + _PartyMode.GameData.NumPlayerAtOnce = _SelectSlides[_SelectSlideNumMics].Selection + _PartyMode.MinPlayers; _PartyMode.GameData.NumRounds = (_SelectSlides[_SelectSlideNumRounds].Selection + 1) * _RoundSteps; _UpdateMicsAtOnce(); @@ -158,9 +152,7 @@ namespace VocaluxeLib.PartyModes.Challenge private void _UpdateMicsAtOnce() { - int maxNum = _MaxNumMics; - if (_PartyMode.GameData.NumPlayer < _MaxNumMics) - maxNum = _PartyMode.GameData.NumPlayer; + int maxNum = Math.Min(_PartyMode.MaxMics, _PartyMode.GameData.NumPlayer); if (_PartyMode.GameData.NumPlayerAtOnce > maxNum) _PartyMode.GameData.NumPlayerAtOnce = maxNum; @@ -169,7 +161,7 @@ namespace VocaluxeLib.PartyModes.Challenge _SelectSlides[_SelectSlideNumMics].Clear(); for (int i = 1; i <= maxNum; i++) _SelectSlides[_SelectSlideNumMics].AddValue(i.ToString()); - _SelectSlides[_SelectSlideNumMics].Selection = _PartyMode.GameData.NumPlayerAtOnce - _PartyMode.GetMinPlayer(); + _SelectSlides[_SelectSlideNumMics].Selection = _PartyMode.GameData.NumPlayerAtOnce - _PartyMode.MinPlayers; } private void _UpdateSlideRounds() diff --git a/PartyModes/PartyModeChallenge/CPartyScreenChallengeMain.cs b/PartyModes/PartyModeChallenge/CPartyScreenChallengeMain.cs index 41805118..5e10bcff 100644 --- a/PartyModes/PartyModeChallenge/CPartyScreenChallengeMain.cs +++ b/PartyModes/PartyModeChallenge/CPartyScreenChallengeMain.cs @@ -119,7 +119,7 @@ namespace VocaluxeLib.PartyModes.Challenge _NextPlayerTexts = new List(); _NextPlayerStatics = new List(); - for (int i = 0; i < _PartyMode.GetMaxPlayer(); i++) + for (int i = 0; i < _PartyMode.MaxPlayers; i++) { _NextPlayerTexts.Add(GetNewText(_Texts[_TextNextPlayer])); _AddText(_NextPlayerTexts[_NextPlayerTexts.Count - 1]); @@ -326,7 +326,7 @@ namespace VocaluxeLib.PartyModes.Challenge x += _Statics[_StaticNextPlayer].Rect.W + 15; } - for (int i = _PartyMode.GameData.NumPlayerAtOnce; i < _PartyMode.GetMaxPlayer(); i++) + for (int i = _PartyMode.GameData.NumPlayerAtOnce; i < _PartyMode.MaxPlayers; i++) { _NextPlayerStatics[i].Visible = false; _NextPlayerTexts[i].Visible = false; @@ -340,7 +340,7 @@ namespace VocaluxeLib.PartyModes.Challenge _Texts[_TextNextPlayerMessage].Visible = true; for (int i = 0; i < _PartyMode.GameData.NumPlayerAtOnce; i++) { - int id = _PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[_PartyMode.GameData.CurrentRoundNr - 1].Player[i]]; + int id = _PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[_PartyMode.GameData.CurrentRoundNr - 1].Players[i]]; _NextPlayerStatics[i].Texture = CBase.Profiles.GetAvatar(id); _NextPlayerTexts[i].Text = CBase.Profiles.GetPlayerName(id); _NextPlayerTexts[i].Color = CBase.Themes.GetPlayerColor(i + 1); @@ -452,14 +452,14 @@ namespace VocaluxeLib.PartyModes.Challenge { for (int p = 0; p < _RoundsTable[i].TextPlayer.Count; p++) { - if (_PartyMode.GameData.Rounds.Count > i + _RoundsTableOffset && _PartyMode.GameData.Rounds[i + _RoundsTableOffset].Player.Count > p) + if (_PartyMode.GameData.Rounds.Count > i + _RoundsTableOffset && _PartyMode.GameData.Rounds[i + _RoundsTableOffset].Players.Count > p) { _RoundsTable[i].Number.Visible = true; _RoundsTable[i].TextPlayer[p].Visible = true; _RoundsTable[i].TextScores[p].Visible = true; _RoundsTable[i].Number.Text = (i + 1 + _RoundsTableOffset) + ")"; _RoundsTable[i].TextPlayer[p].Text = - CBase.Profiles.GetPlayerName(_PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[i + _RoundsTableOffset].Player[p]]); + CBase.Profiles.GetPlayerName(_PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[i + _RoundsTableOffset].Players[p]]); // ReSharper disable ConvertIfStatementToConditionalTernaryExpression if ((_PartyMode.GameData.CurrentRoundNr - 1) > i + _RoundsTableOffset) // ReSharper restore ConvertIfStatementToConditionalTernaryExpression diff --git a/PartyModes/PartyModeChallengeMedley/CChallengeRounds.cs b/PartyModes/PartyModeChallengeMedley/CChallengeRounds.cs index 01b6068e..92e5438f 100644 --- a/PartyModes/PartyModeChallengeMedley/CChallengeRounds.cs +++ b/PartyModes/PartyModeChallengeMedley/CChallengeRounds.cs @@ -17,218 +17,136 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using VocaluxeLib.Utils.Combinatorics; namespace VocaluxeLib.PartyModes.ChallengeMedley { public class CChallengeRounds { - private readonly Random _Rand; - private readonly int _NumPlayer; - - public readonly List Rounds; + private readonly List _Rounds = new List(); public int Count { - get { return Rounds.Count; } + get { return _Rounds.Count; } } - public CCombination this[int index] + public CRound this[int index] { - get { return Rounds[index]; } + get { return _Rounds[index]; } } - public CChallengeRounds(int numRounds, int numPlayer, int numPlayerAtOnce) + public CChallengeRounds(int numRounds, int numPlayer, int playersPerRound) { - Rounds = new List(); - _Rand = new Random(DateTime.Now.Millisecond); + if (numRounds < 1 || numPlayer < 1 || playersPerRound < 1) + throw new ArgumentException("Invalid paramters for the rounds"); - if (numPlayerAtOnce < 1 || numRounds < 1 || numPlayer == 0) - _NumPlayer = 0; - else + if (playersPerRound > numPlayer) + playersPerRound = numPlayer; + + _BuildRounds(numRounds, numPlayer, playersPerRound); + if (Count > numRounds) { - _NumPlayer = numPlayer; - _BuildRounds(numRounds, numPlayerAtOnce, _Rand); - } - } - - public CCombination GetRound(int roundNr) - { - if (roundNr >= Rounds.Count || _NumPlayer == 0 || Rounds.Count == 0) - return null; - - return Rounds[roundNr]; - } - - private void _BuildRounds(int numRounds, int numPlayerAtOnce, Random rand) - { - CCombinations combinations = new CCombinations(_NumPlayer, numPlayerAtOnce, rand); - Rounds.Add(combinations.GetNextCombination(null)); - - for (int i = 1; i < numRounds; i++) - Rounds.Add(combinations.GetNextCombination(_GetPlayerDemand(i))); - } - - private IEnumerable _GetPlayerDemand(int roundIndex) - { - List numPlayed = new List(_NumPlayer); - for (int i = 0; i < _NumPlayer; i++) - numPlayed.Add(0); - - for (int i = 0; i < roundIndex; i++) - { - foreach (int playerIndex in Rounds[i].Player) - numPlayed[playerIndex]++; - } - - int max = numPlayed.Max(); - - int num = Rounds[0].Player.Count; - List result = new List(); - List other = new List(); - List last = new List(); - - for (int i = 0; i < numPlayed.Count; i++) - { - if (roundIndex == 0 || numPlayed[i] < max) + //Try again and take the better one + List old = new List(_Rounds); + _Rounds.Clear(); + _BuildRounds(numRounds, numPlayer, playersPerRound); + if (Count > old.Count) { - if (roundIndex == 0 || roundIndex > 0 && numPlayed[i] < max && !Rounds[roundIndex - 1].IsAvailable(i)) - result.Add(i); - else if (numPlayed[i] < max) - other.Add(i); - } - else - { - if (roundIndex > 0) - { - if (!Rounds[roundIndex - 1].IsAvailable(i)) - other.Add(i); - else - last.Add(i); - } - else - last.Add(i); + _Rounds.Clear(); + _Rounds.AddRange(old); } } + } - while (result.Count < num && other.Count > 0) + /// + /// Divides players in 2 categories: Those how sung the most and the others + /// + /// List matching the playerIndex to the number of songs sung + private static List _GetPlayersForRound(IList numSung) + { + List mustSing = new List(); + int max = numSung.Max(); + for (int i = 0; i < numSung.Count; i++) { - int n = other.Count; - int r = _Rand.Next(n); - result.Add(other[r]); - other.RemoveAt(r); + if (numSung[i] < max) + mustSing.Add(i); } + return mustSing; + } - while (result.Count < num) + private static void _AddCombinations(int numPlayer, int playersPerRound, List combinations) + { + List input = new List(numPlayer); + for (int i = 0; i < numPlayer; i++) + input.Add(i); + CCombinations combs = new CCombinations(input, playersPerRound); + combinations.AddRange(combs.Select(combination => new CRound(combination))); + combinations.Shuffle(); + } + + private static CRound _GetMatchingCombination(List playersInRound, List numSung, List combinations) + { + foreach (CRound round in combinations) { - int n = last.Count; - int r = _Rand.Next(n); - result.Add(last[r]); - last.RemoveAt(r); + int matching = round.Players.Count(playersInRound.Contains); + // A valid round contains only players from playersInRound or all players from playersInRound (and some others) + if (matching == round.Players.Count || matching == playersInRound.Count) + return round; } - - while (result.Count > num) + // It may happen, that there are only players that already sung against each other. So create a 2nd best option with the most number of players that should sing in it + int maxMatching = combinations.Max(c => c.Players.Count(playersInRound.Contains)); + List nextOptions = combinations.Where(c => c.Players.Count(playersInRound.Contains) == maxMatching).ToList(); + // And select the combination that minimizes the sum of the number of songs sung (--> favor rounds with players that sung less than others) + CRound result = null; + int minSung = int.MaxValue; + foreach (CRound round in nextOptions) { - int n = result.Count; - int r = _Rand.Next(n); - result.RemoveAt(r); + int curNumSung = round.Players.Sum(pl => numSung[pl]); + if (curNumSung < minSung) + { + minSung = curNumSung; + result = round; + } } - - result.Sort(); + Debug.Assert(result != null); return result; } - } - class CCombinations - { - private readonly List _Combs; - private readonly Random _Rand; - private readonly int _NumPlayer; - private readonly int _NumMics; - - public CCombinations(int numPlayer, int numMics, Random rand) + private void _BuildRounds(int numRounds, int numPlayer, int playersPerRound) { - _Combs = new List(); - _NumMics = numMics; - _NumPlayer = numPlayer; - _Rand = rand; - } - - public CCombination GetNextCombination(IEnumerable playerNrDemand) - { - if (_Combs.Count == 0) - _Create(); - - if (_NumPlayer == _NumMics) - return _Combs[0]; - - //filter against PlayerNrDemand - List combsFiltered = new List(); - if (playerNrDemand != null) - combsFiltered.AddRange(_Combs.Where(t => t.IsAvailableAll(playerNrDemand))); - - //1st fallback - if (playerNrDemand != null && combsFiltered.Count == 0) - combsFiltered.AddRange(_Combs.Where(t => t.IsAvailableSomeone(playerNrDemand))); - - //2nd fallback - if (combsFiltered.Count == 0) - combsFiltered.AddRange(_Combs); - - int num = combsFiltered.Count; - int rand = _Rand.Next(num); - CCombination c = new CCombination(); - for (int i = 0; i < combsFiltered[rand].Player.Count; i++) - c.Player.Add(combsFiltered[rand].Player[i]); - _Combs.Remove(combsFiltered[rand]); - - return combsFiltered[rand]; - } - - private void _Create() - { - _Combs.Clear(); - - int num = (int)Math.Pow(2, _NumPlayer); - - for (int i = 1; i <= num; i++) + // What we want is that every player sung the same amount of songs + // So we keep track how many songs each palyer sung + List numSung = new List(numPlayer); + for (int i = 0; i < numPlayer; i++) + numSung.Add(0); + List combinations = new List(); + // Posibly add more rounds than requested if the song count per player is unequal + for (int i = 0; i < numRounds * 10; i++) { - CCombination c = new CCombination(); - - for (int j = 0; j < _NumPlayer; j++) - { - if ((i & (1 << j)) > 0) - c.Player.Add(j); - } - - if (c.Player.Count == _NumMics) - _Combs.Add(c); + if (combinations.Count == 0) + _AddCombinations(numPlayer, playersPerRound, combinations); + List playersInRound = _GetPlayersForRound(numSung); + CRound curRound = _GetMatchingCombination(playersInRound, numSung, combinations); + foreach (int player in curRound.Players) + numSung[player]++; + _Rounds.Add(curRound); + combinations.Remove(curRound); + //Stop if we have enough rounds and all players sung the same amount of songs + if (_Rounds.Count >= numRounds && numSung.All(ct => ct == numSung[0])) + break; } } } - public class CCombination + public class CRound { - public readonly List Player; + public readonly List Players; - public CCombination() + public CRound(List players) { - Player = new List(); - } - - public bool IsAvailable(int playerIndex) - { - return Player.Any(p => p == playerIndex); - } - - public bool IsAvailableAll(IEnumerable playerIndices) - { - return playerIndices.All(IsAvailable); - } - - public bool IsAvailableSomeone(IEnumerable playerIndices) - { - return playerIndices.Any(IsAvailable); + Players = players.Shuffle(); } } } \ No newline at end of file diff --git a/PartyModes/PartyModeChallengeMedley/CPartyModeChallengeMedley.cs b/PartyModes/PartyModeChallengeMedley/CPartyModeChallengeMedley.cs index ec9429f9..5f2d6a1b 100644 --- a/PartyModes/PartyModeChallengeMedley/CPartyModeChallengeMedley.cs +++ b/PartyModes/PartyModeChallengeMedley/CPartyModeChallengeMedley.cs @@ -72,13 +72,41 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley public sealed class CPartyModeChallengeMedley : CPartyMode // ReSharper restore ClassNeverInstantiated.Global { - private const int _MaxPlayer = 12; - private const int _MinPlayer = 1; - private const int _MaxTeams = 0; - private const int _MinTeams = 0; - private const int _MaxNumRounds = 100; private const int _NumSongs = 5; + public override int MinMics + { + get { return 1; } + } + public override int MaxMics + { + get { return CBase.Config.GetMaxNumMics(); } + } + public override int MinPlayers + { + get { return 1; } + } + public override int MaxPlayers + { + get { return 12; } + } + 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, @@ -114,7 +142,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley public SData GameData; private EStage _Stage; - public CPartyModeChallengeMedley(int id, string folder) : base(id, folder) + public CPartyModeChallengeMedley(int id) : base(id) { _ScreenSongOptions.Selection.RandomOnly = false; _ScreenSongOptions.Selection.PartyMode = true; @@ -131,6 +159,8 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley public override bool Init() { + if (!base.Init()) + return false; _Stage = EStage.Config; _ScreenSongOptions.Sorting.IgnoreArticles = EOffOn.TR_CONFIG_OFF; @@ -166,7 +196,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley case EStage.Main: return _Screens["CPartyScreenChallengeMedleyMain"]; case EStage.Singing: - return CBase.Graphics.GetScreen(EScreen.Song); + return CBase.Graphics.GetScreen(EScreen.Sing); default: throw new ArgumentException("Invalid stage: " + _Stage); } @@ -290,31 +320,6 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley _ScreenSongOptions.Sorting.SearchActive = visible; } - public override int GetMaxPlayer() - { - return _MaxPlayer; - } - - public override int GetMinPlayer() - { - return _MinPlayer; - } - - public override int GetMaxTeams() - { - return _MaxTeams; - } - - public override int GetMinTeams() - { - return _MinTeams; - } - - public override int GetMaxNumRounds() - { - return _MaxNumRounds; - } - public override void JokerUsed(int teamNr) { if (_ScreenSongOptions.Selection.NumJokers == null) @@ -361,13 +366,13 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley if (players.Length < GameData.NumPlayerAtOnce) return false; - CCombination c = GameData.Rounds.GetRound(GameData.CurrentRoundNr - 1); + CRound c = GameData.Rounds[GameData.CurrentRoundNr - 1]; for (int i = 0; i < GameData.NumPlayerAtOnce; i++) { //try to fill with the right data if (c != null) - players[i].ProfileID = GameData.ProfileIDs[c.Player[i]]; + players[i].ProfileID = GameData.ProfileIDs[c.Players[i]]; else players[i].ProfileID = -1; } @@ -470,14 +475,14 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley } _ScreenSongOptions.Selection.TeamNames = new string[GameData.NumPlayerAtOnce]; - CCombination c = GameData.Rounds.GetRound(GameData.CurrentRoundNr - 1); + CRound c = GameData.Rounds[GameData.CurrentRoundNr - 1]; for (int i = 0; i < GameData.NumPlayerAtOnce; i++) { if (c != null) { - if (GameData.ProfileIDs[c.Player[i]] < profiles.Length) - _ScreenSongOptions.Selection.TeamNames[i] = profiles[GameData.ProfileIDs[c.Player[i]]].PlayerName; + if (GameData.ProfileIDs[c.Players[i]] < profiles.Length) + _ScreenSongOptions.Selection.TeamNames[i] = profiles[GameData.ProfileIDs[c.Players[i]]].PlayerName; else _ScreenSongOptions.Selection.TeamNames[i] = "foobar"; } @@ -503,60 +508,58 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley GameData.Results[i, j] = 0; } } - else + + CPoints gamePoints = CBase.Game.GetPoints(); + if (gamePoints == null || gamePoints.NumPlayer < GameData.NumPlayerAtOnce) + return; + + SPlayer[] results = gamePoints.GetPlayer(0, GameData.NumPlayerAtOnce); + if (results == null) + return; + + if (results.Length < GameData.NumPlayerAtOnce) + return; + + if (gamePoints.NumRounds == 0) + return; + + for (int i = 1; i < gamePoints.NumRounds; i++) { - CPoints gamePoints = CBase.Game.GetPoints(); - if (gamePoints == null || gamePoints.NumPlayer < GameData.NumPlayerAtOnce) - return; + SPlayer[] temp = gamePoints.GetPlayer(i, GameData.NumPlayerAtOnce); + for (int p = 0; p < GameData.NumPlayerAtOnce; p++) + results[p].Points += temp[p].Points; + } - SPlayer[] results = gamePoints.GetPlayer(0, GameData.NumPlayerAtOnce); - if (results == null) - return; + for (int j = 0; j < GameData.NumPlayerAtOnce; j++) + { + results[j].Points = results[j].Points / gamePoints.NumRounds; + GameData.Results[GameData.CurrentRoundNr - 2, j] = (int)Math.Round(results[j].Points); + } - if (results.Length < GameData.NumPlayerAtOnce) - return; + List points = _GetPointsForPlayer(results); - if (gamePoints.NumRounds == 0) - return; - - for (int i = 1; i < gamePoints.NumRounds; i++) + for (int i = 0; i < GameData.NumPlayerAtOnce; i++) + { + int index = -1; + for (int j = 0; j < GameData.ResultTable.Count; j++) { - SPlayer[] temp = gamePoints.GetPlayer(i, GameData.NumPlayerAtOnce); - for (int p = 0; p < GameData.NumPlayerAtOnce; p++) - results[p].Points += temp[p].Points; + if (points[i].ProfileID == GameData.ResultTable[j].PlayerID) + { + index = j; + break; + } } - for (int j = 0; j < GameData.NumPlayerAtOnce; j++) + if (index != -1) { - results[j].Points = results[j].Points / gamePoints.NumRounds; - GameData.Results[GameData.CurrentRoundNr - 2, j] = (int)Math.Round(results[j].Points); - } + CResultTableRow row = GameData.ResultTable[index]; - List points = _GetPointsForPlayer(results); + row.NumPlayed++; + row.NumWon += points[i].Won; + row.NumSingPoints += points[i].SingPoints; + row.NumGamePoints += points[i].GamePoints; - for (int i = 0; i < GameData.NumPlayerAtOnce; i++) - { - int index = -1; - for (int j = 0; j < GameData.ResultTable.Count; j++) - { - if (points[i].ProfileID == GameData.ResultTable[j].PlayerID) - { - index = j; - break; - } - } - - if (index != -1) - { - CResultTableRow row = GameData.ResultTable[index]; - - row.NumPlayed++; - row.NumWon += points[i].Won; - row.NumSingPoints += points[i].SingPoints; - row.NumGamePoints += points[i].GamePoints; - - GameData.ResultTable[index] = row; - } + GameData.ResultTable[index] = row; } } diff --git a/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyConfig.cs b/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyConfig.cs index 2174939b..dbb80bb6 100644 --- a/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyConfig.cs +++ b/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyConfig.cs @@ -15,6 +15,7 @@ // along with Vocaluxe. If not, see . #endregion +using System; using System.Windows.Forms; namespace VocaluxeLib.PartyModes.ChallengeMedley @@ -35,8 +36,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley private const string _ButtonNext = "ButtonNext"; private const string _ButtonBack = "ButtonBack"; - private int _MaxNumMics = 2; - private int _MaxNumRounds = 100; + private const int _MaxNumRounds = 100; private int _RoundSteps = 1; public override void Init() @@ -107,12 +107,6 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley { base.OnShow(); - _MaxNumMics = CBase.Config.GetMaxNumMics(); - if (_MaxNumMics > 6) - _MaxNumMics = 6; - - _MaxNumRounds = _PartyMode.GetMaxNumRounds(); - _RebuildSlides(); } @@ -125,9 +119,9 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley { // build num player slide (min player ... max player); _SelectSlides[_SelectSlideNumPlayers].Clear(); - for (int i = _PartyMode.GetMinPlayer(); i <= _PartyMode.GetMaxPlayer(); i++) + for (int i = _PartyMode.MinPlayers; i <= _PartyMode.MaxPlayers; i++) _SelectSlides[_SelectSlideNumPlayers].AddValue(i.ToString()); - _SelectSlides[_SelectSlideNumPlayers].Selection = _PartyMode.GameData.NumPlayer - _PartyMode.GetMinPlayer(); + _SelectSlides[_SelectSlideNumPlayers].Selection = _PartyMode.GameData.NumPlayer - _PartyMode.MinPlayers; _UpdateMicsAtOnce(); _SetRoundSteps(); @@ -138,8 +132,8 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley { int player = _PartyMode.GameData.NumPlayer; int mics = _PartyMode.GameData.NumPlayerAtOnce; - _PartyMode.GameData.NumPlayer = _SelectSlides[_SelectSlideNumPlayers].Selection + _PartyMode.GetMinPlayer(); - _PartyMode.GameData.NumPlayerAtOnce = _SelectSlides[_SelectSlideNumMics].Selection + _PartyMode.GetMinPlayer(); + _PartyMode.GameData.NumPlayer = _SelectSlides[_SelectSlideNumPlayers].Selection + _PartyMode.MinPlayers; + _PartyMode.GameData.NumPlayerAtOnce = _SelectSlides[_SelectSlideNumMics].Selection + _PartyMode.MinPlayers; _PartyMode.GameData.NumRounds = (_SelectSlides[_SelectSlideNumRounds].Selection + 1) * _RoundSteps; _UpdateMicsAtOnce(); @@ -158,9 +152,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley private void _UpdateMicsAtOnce() { - int maxNum = _MaxNumMics; - if (_PartyMode.GameData.NumPlayer < _MaxNumMics) - maxNum = _PartyMode.GameData.NumPlayer; + int maxNum = Math.Min(_PartyMode.MaxMics, _PartyMode.GameData.NumPlayer); if (_PartyMode.GameData.NumPlayerAtOnce > maxNum) _PartyMode.GameData.NumPlayerAtOnce = maxNum; @@ -169,7 +161,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley _SelectSlides[_SelectSlideNumMics].Clear(); for (int i = 1; i <= maxNum; i++) _SelectSlides[_SelectSlideNumMics].AddValue(i.ToString()); - _SelectSlides[_SelectSlideNumMics].Selection = _PartyMode.GameData.NumPlayerAtOnce - _PartyMode.GetMinPlayer(); + _SelectSlides[_SelectSlideNumMics].Selection = _PartyMode.GameData.NumPlayerAtOnce - _PartyMode.MinPlayers; } private void _UpdateSlideRounds() diff --git a/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyMain.cs b/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyMain.cs index 84831c23..8e2841b1 100644 --- a/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyMain.cs +++ b/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyMain.cs @@ -119,7 +119,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley _NextPlayerTexts = new List(); _NextPlayerStatics = new List(); - for (int i = 0; i < _PartyMode.GetMaxPlayer(); i++) + for (int i = 0; i < _PartyMode.MaxPlayers; i++) { _NextPlayerTexts.Add(GetNewText(_Texts[_TextNextPlayer])); _AddText(_NextPlayerTexts[_NextPlayerTexts.Count - 1]); @@ -326,7 +326,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley x += _Statics[_StaticNextPlayer].Rect.W + 15; } - for (int i = _PartyMode.GameData.NumPlayerAtOnce; i < _PartyMode.GetMaxPlayer(); i++) + for (int i = _PartyMode.GameData.NumPlayerAtOnce; i < _PartyMode.MaxPlayers; i++) { _NextPlayerStatics[i].Visible = false; _NextPlayerTexts[i].Visible = false; @@ -340,7 +340,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley _Texts[_TextNextPlayerMessage].Visible = true; for (int i = 0; i < _PartyMode.GameData.NumPlayerAtOnce; i++) { - int id = _PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[_PartyMode.GameData.CurrentRoundNr - 1].Player[i]]; + int id = _PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[_PartyMode.GameData.CurrentRoundNr - 1].Players[i]]; _NextPlayerStatics[i].Texture = CBase.Profiles.GetAvatar(id); _NextPlayerTexts[i].Text = CBase.Profiles.GetPlayerName(id); _NextPlayerTexts[i].Color = CBase.Themes.GetPlayerColor(i + 1); @@ -452,14 +452,14 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley { for (int p = 0; p < _RoundsTable[i].TextPlayer.Count; p++) { - if (_PartyMode.GameData.Rounds.Count > i + _RoundsTableOffset && _PartyMode.GameData.Rounds[i + _RoundsTableOffset].Player.Count > p) + if (_PartyMode.GameData.Rounds.Count > i + _RoundsTableOffset && _PartyMode.GameData.Rounds[i + _RoundsTableOffset].Players.Count > p) { _RoundsTable[i].Number.Visible = true; _RoundsTable[i].TextPlayer[p].Visible = true; _RoundsTable[i].TextScores[p].Visible = true; _RoundsTable[i].Number.Text = (i + 1 + _RoundsTableOffset) + ")"; _RoundsTable[i].TextPlayer[p].Text = - CBase.Profiles.GetPlayerName(_PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[i + _RoundsTableOffset].Player[p]]); + CBase.Profiles.GetPlayerName(_PartyMode.GameData.ProfileIDs[_PartyMode.GameData.Rounds[i + _RoundsTableOffset].Players[p]]); // ReSharper disable ConvertIfStatementToConditionalTernaryExpression if ((_PartyMode.GameData.CurrentRoundNr - 1) > i + _RoundsTableOffset) // ReSharper restore ConvertIfStatementToConditionalTernaryExpression diff --git a/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs b/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs index 1dadbaea..81d3c308 100644 --- a/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs +++ b/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs @@ -36,15 +36,6 @@ namespace VocaluxeLib.PartyModes.TicTacToe // ReSharper restore InconsistentNaming } - public enum EPartyGameMode - { - // ReSharper disable InconsistentNaming - TR_GAMEMODE_NORMAL, - TR_GAMEMODE_SHORTSONG, - TR_GAMEMODE_DUET - // ReSharper restore InconsistentNaming - } - public class CRound { public int SongID; @@ -71,13 +62,39 @@ namespace VocaluxeLib.PartyModes.TicTacToe public sealed class CPartyModeTicTacToe : CPartyMode // ReSharper restore ClassNeverInstantiated.Global { - private const int _MaxPlayer = 20; - private const int _MinPlayer = 2; - private const int _MaxTeams = 2; - private const int _MinTeams = 2; - private const int _MinPlayerPerTeam = 1; - private const int _MaxPlayerPerTeam = 10; - private const int _NumFields = 9; + public override int MinMics + { + get { return 2; } + } + public override int MaxMics + { + get { return 2; } + } + public override int MinPlayers + { + get { return 2; } + } + public override int MaxPlayers + { + get { return 20; } + } + public override int MinTeams + { + get { return 2; } + } + public override int MaxTeams + { + get { return 2; } + } + + public override int MinPlayersPerTeam + { + get { return 1; } + } + public override int MaxPlayersPerTeam + { + get { return 10; } + } private enum EStage { @@ -99,10 +116,10 @@ namespace VocaluxeLib.PartyModes.TicTacToe public List PlayerTeam2; public ESongSource SongSource; - public int CategoryID; + public int CategoryIndex; public int PlaylistID; - public EPartyGameMode GameMode; + public EGameMode GameMode; public List Rounds; public List Songs; @@ -117,7 +134,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe public SData GameData; private EStage _Stage; - public CPartyModeTicTacToe(int id, string folder) : base(id, folder) + public CPartyModeTicTacToe(int id) : base(id) { _ScreenSongOptions.Selection.RandomOnly = false; _ScreenSongOptions.Selection.PartyMode = true; @@ -142,8 +159,8 @@ namespace VocaluxeLib.PartyModes.TicTacToe FieldNr = 0, SongSource = ESongSource.TR_ALLSONGS, PlaylistID = 0, - CategoryID = 0, - GameMode = EPartyGameMode.TR_GAMEMODE_NORMAL, + CategoryIndex = 0, + GameMode = EGameMode.TR_GAMEMODE_NORMAL, Rounds = new List(), Songs = new List(), NumJokerRandom = new int[2], @@ -153,6 +170,8 @@ namespace VocaluxeLib.PartyModes.TicTacToe public override bool Init() { + if (!base.Init()) + return false; _Stage = EStage.Config; _ScreenSongOptions.Sorting.IgnoreArticles = CBase.Config.GetIgnoreArticles(); @@ -277,41 +296,6 @@ namespace VocaluxeLib.PartyModes.TicTacToe throw new ArgumentException("Not required!"); } - public override int GetMaxPlayer() - { - return _MaxPlayer; - } - - public override int GetMinPlayer() - { - return _MinPlayer; - } - - public override int GetMaxTeams() - { - return _MaxTeams; - } - - public override int GetMinTeams() - { - return _MinTeams; - } - - public override int GetMinPlayerPerTeam() - { - return _MinPlayerPerTeam; - } - - public override int GetMaxPlayerPerTeam() - { - return _MaxPlayerPerTeam; - } - - public override int GetMaxNumRounds() - { - return _NumFields; - } - public override void JokerUsed(int teamNr) {} public override void SongSelected(int songID) @@ -431,67 +415,36 @@ namespace VocaluxeLib.PartyModes.TicTacToe } } - private static void _Shuffle(IList list) - { - for (int n = list.Count - 1; n >= 1; n--) - { - int k = CBase.Game.GetRandom(n); - T value = list[k]; - list[k] = list[n]; - list[n] = value; - } - } - public void UpdateSongList() { if (GameData.Songs.Count > 0) return; - EGameMode gm; - switch (GameData.GameMode) - { - case EPartyGameMode.TR_GAMEMODE_NORMAL: - gm = EGameMode.TR_GAMEMODE_NORMAL; - break; - - case EPartyGameMode.TR_GAMEMODE_DUET: - gm = EGameMode.TR_GAMEMODE_DUET; - break; - - case EPartyGameMode.TR_GAMEMODE_SHORTSONG: - gm = EGameMode.TR_GAMEMODE_SHORTSONG; - break; - - default: - gm = EGameMode.TR_GAMEMODE_NORMAL; - break; - } - switch (GameData.SongSource) { case ESongSource.TR_PLAYLIST: for (int i = 0; i < CBase.Playlist.GetSongCount(GameData.PlaylistID); i++) { int id = CBase.Playlist.GetSong(GameData.PlaylistID, i).SongID; - if (CBase.Songs.GetSongByID(id).AvailableGameModes.Contains(gm)) + if (CBase.Songs.GetSongByID(id).AvailableGameModes.Contains(GameData.GameMode)) GameData.Songs.Add(id); } break; case ESongSource.TR_ALLSONGS: ReadOnlyCollection avSongs = CBase.Songs.GetSongs(); - GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(gm)).Select(song => song.ID)); + GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(GameData.GameMode)).Select(song => song.ID)); break; case ESongSource.TR_CATEGORY: - CBase.Songs.SetCategory(GameData.CategoryID); + CBase.Songs.SetCategory(GameData.CategoryIndex); avSongs = CBase.Songs.GetVisibleSongs(); - GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(gm)).Select(song => song.ID)); + GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(GameData.GameMode)).Select(song => song.ID)); CBase.Songs.SetCategory(-1); break; } - _Shuffle(GameData.Songs); + GameData.Songs.Shuffle(); } private void _UpdatePlayerList() @@ -534,23 +487,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe if (isDuet) players[1].VoiceNr = 1; - var gm = EGameMode.TR_GAMEMODE_NORMAL; - - switch (GameData.GameMode) - { - case EPartyGameMode.TR_GAMEMODE_NORMAL: - gm = EGameMode.TR_GAMEMODE_NORMAL; - break; - - case EPartyGameMode.TR_GAMEMODE_DUET: - gm = EGameMode.TR_GAMEMODE_DUET; - break; - - case EPartyGameMode.TR_GAMEMODE_SHORTSONG: - gm = EGameMode.TR_GAMEMODE_SHORTSONG; - break; - } - CBase.Game.AddSong(round.SongID, gm); + CBase.Game.AddSong(round.SongID, GameData.GameMode); } private void _SetNumJokers() diff --git a/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs b/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs index 2986c303..c75cd880 100644 --- a/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs +++ b/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs @@ -16,6 +16,7 @@ #endregion using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Windows.Forms; using VocaluxeLib.Songs; @@ -113,8 +114,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe { base.OnShow(); - if (CBase.Config.GetMaxNumMics() >= 2) - _ConfigOk = true; + Debug.Assert(CBase.Config.GetMaxNumMics() >= 2); _FillSlides(); _UpdateSlides(); @@ -129,15 +129,11 @@ namespace VocaluxeLib.PartyModes.TicTacToe private void _FillSlides() { _SelectSlides[_SelectSlideNumFields].Clear(); - _SelectSlides[_SelectSlideNumFields].AddValue("9"); - _SelectSlides[_SelectSlideNumFields].AddValue("16"); - _SelectSlides[_SelectSlideNumFields].AddValue("25"); - if (_PartyMode.GameData.NumFields == 9) - _SelectSlides[_SelectSlideNumFields].Selection = 0; - else if (_PartyMode.GameData.NumFields == 16) - _SelectSlides[_SelectSlideNumFields].Selection = 1; - else if (_PartyMode.GameData.NumFields == 25) - _SelectSlides[_SelectSlideNumFields].Selection = 2; + _SelectSlides[_SelectSlideNumFields].AddValue(9); + _SelectSlides[_SelectSlideNumFields].AddValue(16); + _SelectSlides[_SelectSlideNumFields].AddValue(25); + + _SelectSlides[_SelectSlideNumFields].SelectedTag = _PartyMode.GameData.NumFields; _SelectSlides[_SelectSlideSongSource].Clear(); _SelectSlides[_SelectSlideSongSource].SetValues((int)_PartyMode.GameData.SongSource); @@ -152,52 +148,32 @@ namespace VocaluxeLib.PartyModes.TicTacToe _SelectSlides[_SelectSlidePlaylist].Selection = _PartyMode.GameData.PlaylistID; _SelectSlides[_SelectSlidePlaylist].Visible = _PartyMode.GameData.SongSource == ESongSource.TR_PLAYLIST; - var categories = new string[CBase.Songs.GetNumCategories()]; - for (int i = 0; i < CBase.Songs.GetNumCategories(); i++) - categories[i] = CBase.Songs.GetCategory(i).Name; _SelectSlides[_SelectSlideCategory].Clear(); - for (int i = 0; i < categories.Length; i++) + for (int i = 0; i < CBase.Songs.GetNumCategories(); i++) { - string value = categories[i] + " (" + CBase.Songs.GetNumSongsNotSungInCategory(i) + " " + CBase.Language.Translate("TR_SONGS", PartyModeID) + ")"; + CCategory cat = CBase.Songs.GetCategory(i); + string value = cat.Name + " (" + cat.GetNumSongsNotSung() + " " + CBase.Language.Translate("TR_SONGS", PartyModeID) + ")"; _SelectSlides[_SelectSlideCategory].AddValue(value); } - _SelectSlides[_SelectSlideCategory].Selection = _PartyMode.GameData.CategoryID; + _SelectSlides[_SelectSlideCategory].Selection = _PartyMode.GameData.CategoryIndex; _SelectSlides[_SelectSlideCategory].Visible = _PartyMode.GameData.SongSource == ESongSource.TR_CATEGORY; _SelectSlides[_SelectSlideGameMode].Visible = true; - _SelectSlides[_SelectSlideGameMode].SetValues((int)_PartyMode.GameData.GameMode); + _SelectSlides[_SelectSlideGameMode].Clear(); + _SelectSlides[_SelectSlideGameMode].SetValues((int)_PartyMode.GameData.GameMode); + _SelectSlides[_SelectSlideGameMode].RemoveValue(EGameMode.TR_GAMEMODE_MEDLEY.ToString()); } private void _UpdateSlides() { - if (_SelectSlides[_SelectSlideNumFields].Selection == 0) - _PartyMode.GameData.NumFields = 9; - else if (_SelectSlides[_SelectSlideNumFields].Selection == 1) - _PartyMode.GameData.NumFields = 16; - else if (_SelectSlides[_SelectSlideNumFields].Selection == 2) - _PartyMode.GameData.NumFields = 25; + _PartyMode.GameData.NumFields = _SelectSlides[_SelectSlideNumFields].SelectedTag; _PartyMode.GameData.SongSource = (ESongSource)_SelectSlides[_SelectSlideSongSource].Selection; _PartyMode.GameData.PlaylistID = _SelectSlides[_SelectSlidePlaylist].Selection; - _PartyMode.GameData.CategoryID = _SelectSlides[_SelectSlideCategory].Selection; - _PartyMode.GameData.GameMode = (EPartyGameMode)_SelectSlides[_SelectSlideGameMode].Selection; + _PartyMode.GameData.CategoryIndex = _SelectSlides[_SelectSlideCategory].Selection; + _PartyMode.GameData.GameMode = (EGameMode)_SelectSlides[_SelectSlideGameMode].Selection; - var gm = EGameMode.TR_GAMEMODE_NORMAL; - - switch (_PartyMode.GameData.GameMode) - { - case EPartyGameMode.TR_GAMEMODE_NORMAL: - gm = EGameMode.TR_GAMEMODE_NORMAL; - break; - - case EPartyGameMode.TR_GAMEMODE_DUET: - gm = EGameMode.TR_GAMEMODE_DUET; - break; - - case EPartyGameMode.TR_GAMEMODE_SHORTSONG: - gm = EGameMode.TR_GAMEMODE_SHORTSONG; - break; - } + EGameMode gm = _PartyMode.GameData.GameMode; if (_PartyMode.GameData.SongSource == ESongSource.TR_PLAYLIST) { @@ -224,11 +200,11 @@ namespace VocaluxeLib.PartyModes.TicTacToe { if (CBase.Songs.GetNumCategories() == 0) _ConfigOk = false; - else if (CBase.Songs.GetNumSongsNotSungInCategory(_PartyMode.GameData.CategoryID) <= 0) + else if (CBase.Songs.GetNumSongsNotSungInCategory(_PartyMode.GameData.CategoryIndex) <= 0) _ConfigOk = false; else { - CBase.Songs.SetCategory(_PartyMode.GameData.CategoryID); + CBase.Songs.SetCategory(_PartyMode.GameData.CategoryIndex); _ConfigOk = false; foreach (CSong song in CBase.Songs.GetVisibleSongs()) { diff --git a/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeMain.cs b/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeMain.cs index 1ffe157b..35f45351 100644 --- a/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeMain.cs +++ b/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeMain.cs @@ -73,7 +73,6 @@ namespace VocaluxeLib.PartyModes.TicTacToe private const int _FieldSpace = 10; private float _FieldSize = 100; - private int _PreviewStream = -1; private int _OldSelectedField = -1; private int[,] _Possibilities; @@ -267,8 +266,6 @@ namespace VocaluxeLib.PartyModes.TicTacToe { base.OnShow(); - _PreviewStream = -1; - if (_PartyMode.GameData.CurrentRoundNr == 1) { _BuildWinnerPossibilities(); @@ -334,13 +331,6 @@ namespace VocaluxeLib.PartyModes.TicTacToe return true; } - public override void OnClose() - { - base.OnClose(); - CBase.BackgroundMusic.SetDisabled(false); - CBase.Sound.Fade(_PreviewStream, 0, 0.5f, EStreamAction.Close); - } - private void _CreateFields() { for (int i = 0; i < 25; i++) @@ -490,14 +480,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe private void _StartPreview(int songID) { CSong song = CBase.Songs.GetSongByID(songID); - CBase.BackgroundMusic.SetDisabled(true); - - _PreviewStream = CBase.Sound.Load(song.GetMP3()); - CBase.Sound.SetGlobalVolume(CBase.Config.GetMusicVolume(EMusicType.Preview)); - CBase.Sound.SetPosition(_PreviewStream, song.Preview.StartTime); - CBase.Sound.SetStreamVolume(_PreviewStream, 0); - CBase.Sound.Play(_PreviewStream); - CBase.Sound.Fade(_PreviewStream, 100, 1f); + CBase.BackgroundMusic.LoadPreview(song); } private void _UpdatePlayerInformation() @@ -525,8 +508,6 @@ namespace VocaluxeLib.PartyModes.TicTacToe if (_PartyMode.GameData.NumJokerRandom[teamNr] > 0) { _PartyMode.GameData.NumJokerRandom[teamNr]--; - if (!CBase.Sound.IsFinished(_PreviewStream)) - CBase.Sound.Fade(_PreviewStream, 0, 1, EStreamAction.Close); _FieldSelected(true); } break; @@ -537,8 +518,6 @@ namespace VocaluxeLib.PartyModes.TicTacToe { _PartyMode.GameData.NumJokerRetry[teamNr]--; _PartyMode.GameData.Team = teamNr; - if (!CBase.Sound.IsFinished(_PreviewStream)) - CBase.Sound.Fade(_PreviewStream, 0, 1, EStreamAction.Close); _Status = EStatus.JokerRetry; _OldSelectedField = _PartyMode.GameData.FieldNr; _PartyMode.GameData.FieldNr = -1; @@ -579,13 +558,11 @@ namespace VocaluxeLib.PartyModes.TicTacToe private void _NextRound() { - CBase.Sound.Fade(_PreviewStream, 0, 0.5f, EStreamAction.Close); _PartyMode.Next(); } private void _EndParty() { - CBase.Sound.Fade(_PreviewStream, 0, 0.5f, EStreamAction.Close); CBase.Graphics.FadeTo(EScreen.Party); } @@ -604,7 +581,6 @@ namespace VocaluxeLib.PartyModes.TicTacToe private void _Back() { - CBase.Sound.Fade(_PreviewStream, 0, 0.5f, EStreamAction.Close); _PartyMode.Back(); } diff --git a/Vocaluxe/Base/CBackgroundMusic.cs b/Vocaluxe/Base/CBackgroundMusic.cs index 1e38e42b..c01a334d 100644 --- a/Vocaluxe/Base/CBackgroundMusic.cs +++ b/Vocaluxe/Base/CBackgroundMusic.cs @@ -18,7 +18,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using VocaluxeLib; using VocaluxeLib.Songs; using VocaluxeLib.Draw; @@ -30,12 +29,12 @@ namespace Vocaluxe.Base { private static bool _Initialized; - private static CSongPlayer _SongPlayer; - private static CSongPlayer _PreviewPlayer; + private static readonly CSongPlayer _BGPlayer = new CSongPlayer(); + private static readonly CSongPlayer _PreviewPlayer = new CSongPlayer(true); + private static CSongPlayer _CurPlayer; private static bool _OwnSongsAvailable; private static EBackgroundMusicSource _MusicSource; - private static bool _VideoEnabled; private static CPlaylistElement _CurrentPlaylistElement; //Currently played music private static int _PreviousMusicIndex = -1; @@ -47,29 +46,20 @@ namespace Vocaluxe.Base private static bool _OwnMusicAdded; private static bool _BackgroundMusicAdded; private static bool _Disabled; - private static bool _PlaysPreview; public static bool VideoEnabled { - get { return _PlaysPreview ? _PreviewPlayer.VideoEnabled : _SongPlayer.VideoEnabled; } - set - { - if (_PlaysPreview) - _PreviewPlayer.VideoEnabled = value; - else - _SongPlayer.VideoEnabled = value; - } + get { return _CurPlayer.VideoEnabled; } + set { _CurPlayer.VideoEnabled = value; } } public static bool CanSing { get { - if (_PlaysPreview) + if (IsPlayingPreview) return false; - if (_BGMusicFiles.Contains(_CurrentPlaylistElement)) - return false; - return true; + return !_BGMusicFiles.Contains(_CurrentPlaylistElement); } } @@ -81,54 +71,63 @@ namespace Vocaluxe.Base if (Disabled == value) return; _Disabled = value; - Pause(); + if (_Disabled) + Pause(); + else + Play(); } } + /// + /// Repeat the background song (preview songs are always repeating!) + /// public static bool RepeatSong { - get { return _SongPlayer.RepeatSong; } - set { _SongPlayer.RepeatSong = value; } + get { return _BGPlayer.Loop; } + set { _BGPlayer.Loop = value; } } public static int SongID { - get { return _SongPlayer.SongID; } + get { return _CurPlayer.SongID; } } public static bool SongHasVideo { - get { return _SongPlayer.SongHasVideo; } + get { return _CurPlayer.SongHasVideo; } } public static bool IsPlaying { - get { return _PlaysPreview ? _PreviewPlayer.IsPlaying : _SongPlayer.IsPlaying; } + get { return _CurPlayer.IsPlaying; } } public static bool IsPlayingPreview { - get { return _PlaysPreview; } + get { return _CurPlayer == _PreviewPlayer; } + set + { + if (IsPlayingPreview == value) + return; + Pause(); + _CurPlayer = value ? _PreviewPlayer : _BGPlayer; + Play(); + } } public static string ArtistAndTitle { - get - { - if (_PlaysPreview) - return _PreviewPlayer.ArtistAndTitle; - return _BGMusicFiles.Contains(_CurrentPlaylistElement) ? Path.GetFileNameWithoutExtension(_CurrentPlaylistElement.MusicFilePath) : _SongPlayer.ArtistAndTitle; - } + get { return _CurPlayer.ArtistAndTitle; } } public static float Length { - get { return _PlaysPreview ? _PreviewPlayer.Length : _SongPlayer.Length; } + get { return _CurPlayer.Length; } } public static CTextureRef Cover { - get { return _PlaysPreview ? _PreviewPlayer.Cover : _SongPlayer.Cover; } + get { return _CurPlayer.Cover; } } //Use this to set whether own songs are available for access @@ -160,21 +159,15 @@ namespace Vocaluxe.Base _MusicSource = EBackgroundMusicSource.TR_CONFIG_NO_OWN_MUSIC; _AddBackgroundMusic(); - _SongPlayer = new CSongPlayer(); - - _PreviewPlayer = new CSongPlayer {RepeatSong = true}; - - _VideoEnabled = (CConfig.Config.Video.VideoBackgrounds == EOffOn.TR_CONFIG_ON && CConfig.Config.Video.VideosToBackground == EOffOn.TR_CONFIG_ON); SetMusicSource(CConfig.Config.Sound.BackgroundMusicSource); + _CurPlayer = _BGPlayer; _Initialized = true; } public static void Close() { - if (_SongPlayer != null) - _SongPlayer.Stop(); - if (_PreviewPlayer != null) - _PreviewPlayer.Stop(); + _BGPlayer.Close(); + _PreviewPlayer.Close(); _BGMusicFiles.Clear(); _NotPlayedFiles.Clear(); @@ -185,124 +178,88 @@ namespace Vocaluxe.Base public static void Play() { - if (IsPlaying || (CConfig.Config.Sound.BackgroundMusic != EBackgroundMusicOffOn.TR_CONFIG_ON && !_PlaysPreview)) + if (!IsPlayingPreview && CConfig.Config.Sound.BackgroundMusic == EBackgroundMusicOffOn.TR_CONFIG_OFF) return; - if (_PlaysPreview) - _PreviewPlayer.Play(); - else if (CConfig.Config.Sound.BackgroundMusic == EBackgroundMusicOffOn.TR_CONFIG_ON) - { - if (_SongPlayer.SongLoaded) - //Resume - _SongPlayer.TogglePause(); - else - Next(); - } + if (IsPlayingPreview || _BGPlayer.SoundLoaded) + _CurPlayer.Play(); + else + Next(); } public static void Stop() { - if (!IsPlaying) - return; - - if (_PlaysPreview) - { - _PreviewPlayer.Stop(); - _PlaysPreview = false; - Pause(); - CSound.SetGlobalVolume(CConfig.BackgroundMusicVolume); - } - else - { - _SongPlayer.Stop(); + _CurPlayer.Stop(); + if (!IsPlayingPreview) _CurrentPlaylistElement = null; - } } public static void Pause() { - if (_PlaysPreview) - { - if (!_PreviewPlayer.SongLoaded) - return; - _PreviewPlayer.TogglePause(); - } - else if (CConfig.Config.Sound.BackgroundMusic == EBackgroundMusicOffOn.TR_CONFIG_ON) - { - if (!_SongPlayer.SongLoaded) - Next(); - else - _SongPlayer.TogglePause(); - } + _CurPlayer.Pause(); } public static void Next() { - if (!_PlaysPreview) + if (IsPlayingPreview) + return; + + Stop(); //stop last song if any + if (_PreviousMusicIndex < _PreviousFiles.Count - 2) { - Stop(); //stop last song if any - if (_PreviousMusicIndex < _PreviousFiles.Count - 2) - { - //We are in the previous list and next element exists - _PreviousMusicIndex++; - _CurrentPlaylistElement = _PreviousFiles[_PreviousMusicIndex]; - } - else - { - //We are not in the previous list (anymore) - if (_NotPlayedFiles.Count == 0) - { - if (_PreviousFiles.Count == 0) - return; //No songs to play - _NotPlayedFiles.AddRange(_PreviousFiles); - } - - _CurrentPlaylistElement = _NotPlayedFiles[CGame.Rand.Next(_NotPlayedFiles.Count)]; - _NotPlayedFiles.Remove(_CurrentPlaylistElement); - - _PreviousFiles.Add(_CurrentPlaylistElement); - _PreviousMusicIndex = _PreviousFiles.Count - 1; - } - _StartSong(); + //We are in the previous list and next element exists + _PreviousMusicIndex++; + _CurrentPlaylistElement = _PreviousFiles[_PreviousMusicIndex]; } + else + { + //We are not in the previous list (anymore) + if (_NotPlayedFiles.Count == 0) + { + if (_PreviousFiles.Count == 0) + return; //No songs to play + _NotPlayedFiles.AddRange(_PreviousFiles); + } + + _CurrentPlaylistElement = _NotPlayedFiles[CGame.Rand.Next(_NotPlayedFiles.Count)]; + _NotPlayedFiles.Remove(_CurrentPlaylistElement); + + _PreviousFiles.Add(_CurrentPlaylistElement); + _PreviousMusicIndex = _PreviousFiles.Count - 1; + } + _StartSong(); } public static void Previous() { - if (!_PlaysPreview) - { - if (_PreviousMusicIndex < 0) - return; - Debug.Assert(_CurrentPlaylistElement != null); - if (_SongPlayer.Position <= 1.5f && _PreviousMusicIndex > 0) - { - Stop(); //stop last song - _PreviousMusicIndex--; + if (IsPlayingPreview) + return; + if (_PreviousMusicIndex < 0) + return; - _CurrentPlaylistElement = _PreviousFiles[_PreviousMusicIndex]; - } - _StartSong(); + if (_CurrentPlaylistElement == null || (_BGPlayer.Position <= 1.5f && _PreviousMusicIndex > 0)) + { + Stop(); //stop last song + _PreviousMusicIndex--; + + _CurrentPlaylistElement = _PreviousFiles[_PreviousMusicIndex]; } + _StartSong(); } public static void Update() { - if (!IsPlaying && (!_SongPlayer.SongLoaded || !_PreviewPlayer.SongLoaded)) + if (!IsPlaying) return; - if (_PlaysPreview) - _PreviewPlayer.Update(); - else - { - _SongPlayer.Update(); - if (_SongPlayer.IsFinished) - Next(); - } + _CurPlayer.Update(); + if (!IsPlayingPreview && _BGPlayer.IsFinished) + Next(); } public static CTextureRef GetVideoTexture() { - return _PlaysPreview ? _PreviewPlayer.GetVideoTexture() : _SongPlayer.GetVideoTexture(); + return _CurPlayer.GetVideoTexture(); } public static void SetMusicSource(EBackgroundMusicSource source) @@ -328,54 +285,42 @@ namespace Vocaluxe.Base } } - public static void LoadPreview(CSong song, float start = 0f) + public static void LoadPreview(CSong song, float start = -1f) { - if (!_PlaysPreview) - Pause(); - else - StopPreview(); - if (song == null) - return; + throw new ArgumentNullException("song"); - // ReSharper disable CompareOfFloatsByEqualityOperator - if (start == 0f) - start = song.Preview.StartTime; - // ReSharper restore CompareOfFloatsByEqualityOperator + if (!IsPlayingPreview) + { + Pause(); + _CurPlayer = _PreviewPlayer; + CSound.SetGlobalVolume(CConfig.PreviewMusicVolume); + } - _PlaysPreview = true; - CSound.SetGlobalVolume(CConfig.PreviewMusicVolume); - _PreviewPlayer.Load(song, start); - - float startposition = song.Preview.StartTime; + _PreviewPlayer.Load(song); float length = _PreviewPlayer.Length; + if (length < 1) + length = 30; // If length is unknow or invalid assume a length of 30s - if (song.Preview.Source == EDataSource.None) - startposition = length / 4f; - else if (startposition > length - 5f) - startposition = Math.Max(0f, Math.Min(length / 4f, length - 5f)); + if (start < 0) + start = (song.Preview.Source == EDataSource.None) ? length / 4f : song.Preview.StartTime; + if (start > length - 5f) + start = Math.Max(0f, Math.Min(length / 4f, length - 5f)); + if (start >= 0.5f) + start -= 0.5f; - if (startposition >= 0.5f) - startposition -= 0.5f; - - _PreviewPlayer.Position = startposition; - - Play(); - } - - public static void PlayPreview(float start = -1f) - { - if (start > -1f) - _PreviewPlayer.Position = start; + _PreviewPlayer.Position = start; Play(); } public static void StopPreview() { - _PreviewPlayer.Stop(); - _PlaysPreview = false; + if (!IsPlayingPreview) + return; + Stop(); + _CurPlayer = _BGPlayer; CSound.SetGlobalVolume(CConfig.BackgroundMusicVolume); } @@ -387,19 +332,23 @@ namespace Vocaluxe.Base Debug.Assert(_CurrentPlaylistElement != null); //If current song same as loaded restart only - if (_CurrentPlaylistElement.SongID == _SongPlayer.SongID && _SongPlayer.SongLoaded) - _SongPlayer.Play(); + if (_BGPlayer.SoundLoaded && _CurrentPlaylistElement.MusicFilePath == _BGPlayer.FilePath) + { + _BGPlayer.Stop(); + _BGPlayer.Play(); + return; + } //otherwhise load - if (_BGMusicFiles.Contains(_CurrentPlaylistElement)) - _SongPlayer.LoadFile(_CurrentPlaylistElement.MusicFilePath, 0f, true); + if (!_CurrentPlaylistElement.HasMetaData) + _BGPlayer.Load(_CurrentPlaylistElement.MusicFilePath, 0f, true); else { //Seek to #Start-Tag, if found float start = 0f; if (_CurrentPlaylistElement.Start > 0.001 && CConfig.Config.Sound.BackgroundMusicUseStart == EOffOn.TR_CONFIG_ON) start = _CurrentPlaylistElement.Start; - _SongPlayer.Load(CBase.Songs.GetSongByID(_CurrentPlaylistElement.SongID), start, true); + _BGPlayer.Load(_CurrentPlaylistElement.Song, start, true); } } diff --git a/Vocaluxe/Base/CConfig.cs b/Vocaluxe/Base/CConfig.cs index 2c8cbd51..575002c3 100644 --- a/Vocaluxe/Base/CConfig.cs +++ b/Vocaluxe/Base/CConfig.cs @@ -145,7 +145,7 @@ namespace Vocaluxe.Base [DefaultValue(EOffOn.TR_CONFIG_ON)] public EOffOn VideoPreview; [DefaultValue(EOffOn.TR_CONFIG_ON)] public EOffOn VideosInSongs; [DefaultValue(EOffOn.TR_CONFIG_OFF)] public EOffOn VideosToBackground; - [DefaultValue(EWebcamLib.OpenCV)] public EWebcamLib WebcamLib; + [DefaultValue(EWebcamLib.AForgeNet)] public EWebcamLib WebcamLib; public SWebcamConfig? WebcamConfig; } @@ -348,8 +348,14 @@ namespace Vocaluxe.Base }; } + private static readonly List _CommentsGot = new List(); + private static string _GetComment(string elName) { + // Avoid multiple comments (e.g. for array entries) + if (_CommentsGot.Contains(elName)) + return null; + _CommentsGot.Add(elName); switch (elName) { case "DebugLevel": @@ -419,7 +425,7 @@ namespace Vocaluxe.Base case "Language": return "Game-Language"; case "SongFolder": - return "SongFolder: SongFolder1, SongFolder2, SongFolder3, ..."; + return "SongFolder: Add each song folder in a seperate SongFolder entry"; case "SongMenu": return "SongMenu: " + CHelper.ListStrings(Enum.GetNames(typeof(ESongMenu))); case "SongSorting": @@ -467,6 +473,7 @@ namespace Vocaluxe.Base public static void SaveConfig() { + _CommentsGot.Clear(); var xml = new CXmlSerializer(true, _GetComment); xml.Serialize(_FileConfig, Config); } diff --git a/Vocaluxe/Base/CCover.cs b/Vocaluxe/Base/CCover.cs index fb621f16..0a155740 100644 --- a/Vocaluxe/Base/CCover.cs +++ b/Vocaluxe/Base/CCover.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.IO; using System.Threading; @@ -40,10 +41,10 @@ namespace Vocaluxe.Base public static CTextureRef NoCover { get; private set; } - public static void Init() + public static bool Init() { _LoadCoverThemes(); - _LoadCovers(CConfig.Config.Theme.CoverTheme); + return _CoverThemes.Count != 0 && _LoadCovers(); } public static void Close() @@ -91,7 +92,10 @@ namespace Vocaluxe.Base public static CTextureRef GenerateCover(string text, ECoverGeneratorType type, CSong firstSong) { - CTextureRef texture = CDraw.CopyTexture(NoCover); + CTextureRef texture = Cover(text); + if (texture != NoCover) + return texture; + texture = CDraw.CopyTexture(NoCover); Task.Factory.StartNew(() => { _CancelToken.Token.ThrowIfCancellationRequested(); @@ -127,7 +131,7 @@ namespace Vocaluxe.Base public static void ReloadCovers() { _UnloadCovers(); - _LoadCovers(CConfig.Config.Theme.CoverTheme); + _LoadCovers(); } private static void _UnloadCovers() @@ -150,14 +154,15 @@ namespace Vocaluxe.Base /// /// Returns a SCoverTheme by cover-theme-name /// - private static SThemeCover _CoverTheme(string coverThemeName) + private static SThemeCover _GetCoverTheme() { - for (int i = 0; i < _CoverThemes.Count; i++) + int index = GetCoverThemeIndex(); + if (index < 0) { - if (_CoverThemes[i].Info.Name == coverThemeName) - return _CoverThemes[i]; + index = 0; + CConfig.Config.Theme.CoverTheme = _CoverThemes[0].Info.Name; } - return new SThemeCover(); + return _CoverThemes[index]; } /// @@ -184,7 +189,7 @@ namespace Vocaluxe.Base continue; } - if (theme.Info.Folder != "" && theme.Info.Name != "") + if (!String.IsNullOrEmpty(theme.Info.Folder) && !String.IsNullOrEmpty(theme.Info.Name)) { theme.FolderPath = Path.Combine(folderPath, theme.Info.Folder); _CoverThemes.Add(theme); @@ -195,12 +200,11 @@ namespace Vocaluxe.Base /// /// Loads all covers from the theme /// - private static void _LoadCovers(string coverThemeName) + private static bool _LoadCovers() { - SThemeCover coverTheme = _CoverTheme(coverThemeName); + SThemeCover coverTheme = _GetCoverTheme(); - if (String.IsNullOrEmpty(coverTheme.Info.Name)) - return; + Debug.Assert(!String.IsNullOrEmpty(coverTheme.Info.Name)); List files = CHelper.ListImageFiles(coverTheme.FolderPath, true, true); @@ -213,9 +217,16 @@ namespace Vocaluxe.Base else if (_CoverExists(_NoCoverNameAlt)) NoCover = _Covers[_NoCoverNameAlt]; else - CBase.Log.LogError("Covertheme \"" + coverThemeName + "\" does not include a cover file named \"" + _NoCoverName + "\" and cannot be used!", true, true); + { + CBase.Log.LogError("Covertheme \"" + coverTheme.Info.Name + "\" does not include a cover file named \"" + _NoCoverName + "\" and cannot be used!", true, true); + _UnloadCovers(); + // Remove current theme and recursively try the other themes + _CoverThemes.Remove(coverTheme); + return _CoverThemes.Count > 0 && _LoadCovers(); + } } _LoadCoverGenerators(coverTheme); + return true; } public static ECoverGeneratorType _SongSortingToType(ESongSorting sorting) diff --git a/Vocaluxe/Base/CDataBase.cs b/Vocaluxe/Base/CDataBase.cs index a3e6397d..fad913e8 100644 --- a/Vocaluxe/Base/CDataBase.cs +++ b/Vocaluxe/Base/CDataBase.cs @@ -75,37 +75,46 @@ namespace Vocaluxe.Base public static bool GetDataBaseSongInfos(string artist, string title, out int numPlayed, out DateTime dateAdded, out int highscoreID) { + if (_HighscoreDB == null) + { + numPlayed = 0; + dateAdded = new DateTime(); + highscoreID = 0; + return false; + } return _HighscoreDB.GetDataBaseSongInfos(artist, title, out numPlayed, out dateAdded, out highscoreID); } public static List LoadScore(int songID, EGameMode gameMode) { - return _HighscoreDB.LoadScore(songID, gameMode); + return _HighscoreDB == null ? null : _HighscoreDB.LoadScore(songID, gameMode); } public static int AddScore(SPlayer player) { - return _HighscoreDB.AddScore(player); + return _HighscoreDB == null ? -1 : _HighscoreDB.AddScore(player); } public static void IncreaseSongCounter(int dataBaseSongID) { - _HighscoreDB.IncreaseSongCounter(dataBaseSongID); + if (_HighscoreDB != null) + _HighscoreDB.IncreaseSongCounter(dataBaseSongID); } public static bool GetCover(string fileName, ref CTextureRef tex, int maxSize) { - return _CoverDB.GetCover(fileName, ref tex, maxSize); + return _CoverDB != null && _CoverDB.GetCover(fileName, ref tex, maxSize); } public static void CommitCovers() { - _CoverDB.CommitCovers(); + if (_CoverDB != null) + _CoverDB.CommitCovers(); } public static bool GetCreditsRessource(string fileName, ref CTextureRef tex) { - return _ResourceDB.GetCreditsRessource(fileName, ref tex); + return _ResourceDB != null && _ResourceDB.GetCreditsRessource(fileName, ref tex); } } } \ No newline at end of file diff --git a/Vocaluxe/Base/CGraphics.cs b/Vocaluxe/Base/CGraphics.cs index 5d4ea1c6..d5967687 100644 --- a/Vocaluxe/Base/CGraphics.cs +++ b/Vocaluxe/Base/CGraphics.cs @@ -224,16 +224,18 @@ namespace Vocaluxe.Base NextScreen.ProcessMouseMove(_Cursor.X, _Cursor.Y); HidePopup(EPopupScreens.PopupPlayerControl); + if (NextScreen.CurrentMusicType != EMusicType.Background && NextScreen.CurrentMusicType != EMusicType.Preview) + CBackgroundMusic.Disabled = true; } if (_Fading != null) { + Debug.Assert(NextScreen != null); bool finished; float newAlpha = _Fading.GetValue(out finished); if (!finished) { - GlobalAlpha = 1f; ZOffset = CSettings.ZFar / 2; _DrawScreen(CurrentScreen); @@ -242,6 +244,9 @@ namespace Vocaluxe.Base _DrawScreen(NextScreen); GlobalAlpha = 1f; + int oldVol = CConfig.GetVolumeByType(CurrentScreen.CurrentMusicType); + int newVol = CConfig.GetVolumeByType(NextScreen.CurrentMusicType); + CSound.SetGlobalVolume((int)((newVol - oldVol) * newAlpha + oldVol)); } else { @@ -274,6 +279,11 @@ namespace Vocaluxe.Base NextScreen = null; CurrentScreen.OnShowFinish(); CSound.SetGlobalVolume(CConfig.GetVolumeByType(CurrentScreen.CurrentMusicType)); + if (CurrentScreen.CurrentMusicType == EMusicType.Background || CurrentScreen.CurrentMusicType == EMusicType.Preview) + { + CBackgroundMusic.Disabled = false; + CBackgroundMusic.IsPlayingPreview = CurrentScreen.CurrentMusicType == EMusicType.Preview; + } _Fading = null; } @@ -305,8 +315,8 @@ namespace Vocaluxe.Base { if (screen == null) throw new ArgumentNullException("screen"); - Debug.Assert(NextScreen==null || NextScreen!=screen, "Don't fade to currently fading screen!"); - if(screen==NextScreen) + Debug.Assert(NextScreen == null || NextScreen != screen, "Don't fade to currently fading screen!"); + if (screen == NextScreen) return; // Make sure the last screen change is done _FinishScreenFading(); @@ -348,7 +358,7 @@ namespace Vocaluxe.Base SKeyEvent inputKeyEvent = new SKeyEvent(); SMouseEvent inputMouseEvent = new SMouseEvent(); - bool popupPlayerControlAllowed = CurrentScreen.CurrentMusicType == EMusicType.Background && !CBackgroundMusic.Disabled; + bool popupPlayerControlAllowed = CurrentScreen.CurrentMusicType == EMusicType.Background; bool popupVolumeControlAllowed = CurrentScreen.CurrentMusicType != EMusicType.None; //Hide volume control for bg-music if bg-music is disabled if (popupVolumeControlAllowed && CurrentScreen.CurrentMusicType == EMusicType.Background && CConfig.Config.Sound.BackgroundMusic == EBackgroundMusicOffOn.TR_CONFIG_OFF) diff --git a/Vocaluxe/Base/CMain.cs b/Vocaluxe/Base/CMain.cs index 320b8697..1224a1c0 100644 --- a/Vocaluxe/Base/CMain.cs +++ b/Vocaluxe/Base/CMain.cs @@ -355,21 +355,21 @@ namespace Vocaluxe.Base CBackgroundMusic.Stop(); } - public void LoadPreview(CSong song, float start = 0f) + public void LoadPreview(CSong song, float start = -1f) { CBackgroundMusic.LoadPreview(song, start); } - public void PlayPreview(float start = -1f) - { - CBackgroundMusic.PlayPreview(start); - } - public void StopPreview() { CBackgroundMusic.StopPreview(); } + public void SetPlayingPreview(bool playPreview) + { + CBackgroundMusic.IsPlayingPreview = playPreview; + } + public CTextureRef GetVideoTexture() { return CBackgroundMusic.GetVideoTexture(); @@ -877,6 +877,11 @@ namespace Vocaluxe.Base { CSound.SetGlobalVolume(volume); } + + public bool IsPaused(int streamID) + { + return CSound.IsPaused(streamID); + } } class CBcover : ICover diff --git a/Vocaluxe/Base/CParty.cs b/Vocaluxe/Base/CParty.cs index 6408281b..28847a28 100644 --- a/Vocaluxe/Base/CParty.cs +++ b/Vocaluxe/Base/CParty.cs @@ -18,6 +18,7 @@ using System; using System.CodeDom.Compiler; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Reflection; using Vocaluxe.Base.ThemeSystem; @@ -32,40 +33,52 @@ namespace Vocaluxe.Base { private const int _PartyModeSystemVersion = 1; - private static Dictionary _PartyModes; + private static readonly Dictionary _PartyModes = new Dictionary(); private static int _NextID; - - private static int _NormalGameModeID; - private static SPartyMode _CurrentPartyMode; + private static IPartyMode _CurrentPartyMode; #region public stuff - public static void Init() + public static bool Init() { - _PartyModes = new Dictionary(); - _NextID = 0; - - //add dummy normal game mode and set it as default - var pm = new SPartyMode {ScreenFiles = new List(), PartyMode = new CPartyModeNone(_NextID++, null)}; - _NormalGameModeID = pm.PartyMode.ID; - _PartyModes.Add(pm.PartyMode.ID, pm); - _CurrentPartyMode = pm; + if (_PartyModes.Count > 0) + return false; //Already initialized + SPartyMode pm = new SPartyMode + { + Info = new SPartyModeInfos {Author = "Vocaluxe Team", Description = "Normal game", Name = "Normal", TargetAudience = "Just a normal game for everyone"}, + PartyMode = new CPartyModeNormal(-1), + PartyModeSystemVersion = _PartyModeSystemVersion, + ScreenFiles = new List() + }; + _PartyModes.Add(-1, pm); + _CurrentPartyMode = pm.PartyMode; + Debug.Assert(_CurrentPartyMode != null && _CurrentPartyMode.ID == -1); //load other party modes _LoadPartyModes(); + return _CurrentPartyMode.Init(); } public static int CurrentPartyModeID { - get + get { return _CurrentPartyMode.ID; } + set { - if (_CurrentPartyMode.PartyMode.ID != _NormalGameModeID) - return _CurrentPartyMode.PartyMode.ID; - - return -1; + if (_CurrentPartyMode.ID == value) + return; + if (value != -1 && !_PartyModes.ContainsKey(value)) + throw new ArgumentException("Partymode with ID=" + value + " does not exist!"); + IPartyMode pm = _PartyModes[value].PartyMode; + if (pm.Init()) + _CurrentPartyMode = pm; + else + { + CLog.LogError("Could not init PartyMode \"" + _PartyModes[value].Info.Name + "\"! Removing...", true); + _PartyModes.Remove(value); + } } } - public static int NumModes + public static int Count { get { return _PartyModes.Count; } } @@ -90,85 +103,81 @@ namespace Vocaluxe.Base public static List GetPartyModeInfos() { - var infos = new List(); - - foreach (KeyValuePair kvp in _PartyModes) + List list = new List(); + foreach (SPartyMode pm in _PartyModes.Values) { - if (kvp.Key != _NormalGameModeID) - infos.Add(kvp.Value.Info); + if (pm.PartyMode.ID >= 0) + list.Add(pm.Info); } - return infos; + return list; } public static void SetNormalGameMode() { CSongs.ResetPartySongSung(); - SetPartyMode(_NormalGameModeID); + CurrentPartyModeID = -1; } public static void SetPartyMode(int partyModeID) { - if (!_PartyModes.TryGetValue(partyModeID, out _CurrentPartyMode)) - CLog.LogError("CParty: Can't find party mode ID: " + partyModeID); - - _CurrentPartyMode.PartyMode.Init(); + CurrentPartyModeID = partyModeID; } #endregion public stuff #region Interface public static void UpdateGame() { - _CurrentPartyMode.PartyMode.UpdateGame(); + _CurrentPartyMode.UpdateGame(); } public static IMenu GetStartScreen() { - return _CurrentPartyMode.PartyMode.GetStartScreen(); + return _CurrentPartyMode.GetStartScreen(); } public static SScreenSongOptions GetSongSelectionOptions() { - return _CurrentPartyMode.PartyMode.GetScreenSongOptions(); + return _CurrentPartyMode.GetScreenSongOptions(); } public static void OnSongChange(int songIndex, ref SScreenSongOptions screenSongOptions) { - _CurrentPartyMode.PartyMode.OnSongChange(songIndex, ref screenSongOptions); + _CurrentPartyMode.OnSongChange(songIndex, ref screenSongOptions); } public static void OnCategoryChange(int categoryIndex, ref SScreenSongOptions screenSongOptions) { - _CurrentPartyMode.PartyMode.OnCategoryChange(categoryIndex, ref screenSongOptions); + _CurrentPartyMode.OnCategoryChange(categoryIndex, ref screenSongOptions); } public static void SetSearchString(string searchString, bool visible) { - _CurrentPartyMode.PartyMode.SetSearchString(searchString, visible); + _CurrentPartyMode.SetSearchString(searchString, visible); } public static void JokerUsed(int teamNr) { - _CurrentPartyMode.PartyMode.JokerUsed(teamNr); + _CurrentPartyMode.JokerUsed(teamNr); } public static void SongSelected(int songID) { - _CurrentPartyMode.PartyMode.SongSelected(songID); + _CurrentPartyMode.SongSelected(songID); } public static void FinishedSinging() { - _CurrentPartyMode.PartyMode.FinishedSinging(); + _CurrentPartyMode.FinishedSinging(); } public static void LeavingScore() { - _CurrentPartyMode.PartyMode.LeavingScore(); + _CurrentPartyMode.LeavingScore(); } public static void LeavingHighscore() { - _CurrentPartyMode.PartyMode.LeavingHighscore(); + _CurrentPartyMode.LeavingHighscore(); } #endregion Interface @@ -216,7 +225,7 @@ namespace Vocaluxe.Base return false; object instance = output.CreateInstance(typeof(IPartyMode).Namespace + "." + pm.Info.Folder + "." + pm.Info.PartyModeFile, false, - BindingFlags.Public | BindingFlags.Instance, null, new object[] {_NextID++, pathToPm}, null, null); + BindingFlags.Public | BindingFlags.Instance, null, new object[] {_NextID++}, null, null); if (instance == null) { CLog.LogError("Error creating Instance of PartyMode file: " + filePath); @@ -258,7 +267,7 @@ namespace Vocaluxe.Base return false; } pm.PartyMode.LoadTheme(); - pm.Info.LoadData(pm.PartyMode); + pm.Info.ExtInfo = pm.PartyMode; return true; } @@ -269,6 +278,7 @@ namespace Vocaluxe.Base var compilerParams = new CompilerParameters(); compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll"); + compilerParams.ReferencedAssemblies.Add("System.dll"); compilerParams.ReferencedAssemblies.Add("System.Core.dll"); compilerParams.ReferencedAssemblies.Add("VocaluxeLib.dll"); compilerParams.GenerateInMemory = true; diff --git a/Vocaluxe/Base/CPlaylistElement.cs b/Vocaluxe/Base/CPlaylistElement.cs index eec209c1..4e82592a 100644 --- a/Vocaluxe/Base/CPlaylistElement.cs +++ b/Vocaluxe/Base/CPlaylistElement.cs @@ -23,61 +23,70 @@ namespace Vocaluxe.Base { class CPlaylistElement { - private readonly CSong _Song; + public readonly CSong Song; private readonly string _MusicFilePath = String.Empty; + public bool HasMetaData + { + get { return Song != null; } + } + public int SongID { - get { return (_Song == null) ? -1 : _Song.ID; } + get { return HasMetaData ? Song.ID : -1; } } public string MusicFilePath { - get { return _Song != null ? _Song.GetMP3() : _MusicFilePath; } + get { return HasMetaData ? Song.GetMP3() : _MusicFilePath; } } public string VideoFilePath { - get { return _Song != null ? _Song.GetVideo() : string.Empty; } + get { return HasMetaData ? Song.GetVideo() : string.Empty; } } public string Title { - get { return _Song != null ? _Song.Title : ""; } + get { return HasMetaData ? Song.Title : ""; } } public string Artist { - get { return _Song != null ? _Song.Artist : ""; } + get { return HasMetaData ? Song.Artist : ""; } } public float Start { - get { return _Song != null ? _Song.Start : 0f; } + get { return HasMetaData ? Song.Start : 0f; } } public float Finish { - get { return _Song != null ? _Song.Finish : 0f; } + get { return HasMetaData ? Song.Finish : 0f; } } public CTextureRef Cover { - get { return _Song != null ? _Song.CoverTextureSmall : CCover.NoCover; } + get { return HasMetaData ? Song.CoverTextureSmall : CCover.NoCover; } } public float VideoGap { - get { return _Song != null ? _Song.VideoGap : 0; } + get { return HasMetaData ? Song.VideoGap : 0; } } public CPlaylistElement(CSong song) { - _Song = song; + if (song == null) + throw new ArgumentNullException("song"); + Song = song; } public CPlaylistElement(string filePath) { + if (String.IsNullOrEmpty(filePath)) + throw new ArgumentNullException("filePath"); _MusicFilePath = filePath; } } diff --git a/Vocaluxe/Base/XmlStructs.cs b/Vocaluxe/Base/XmlStructs.cs index e9ee97d2..12046975 100644 --- a/Vocaluxe/Base/XmlStructs.cs +++ b/Vocaluxe/Base/XmlStructs.cs @@ -17,6 +17,7 @@ using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.Xml.Serialization; using Vocaluxe.Base.Fonts; using VocaluxeLib; @@ -121,17 +122,7 @@ namespace Vocaluxe.Base [XmlAltName("PartyModeVersionMajor")] public int VersionMajor; [XmlAltName("PartyModeVersionMinor")] public int VersionMinor; public string TargetAudience; - [XmlIgnore] public int MaxPlayers, MinPlayers, MaxTeams, MinTeams; - [XmlIgnore] public int PartyModeID; - - public void LoadData(IPartyMode pm) - { - MaxPlayers = pm.GetMaxPlayer(); - MinPlayers = pm.GetMinPlayer(); - MaxTeams = pm.GetMaxTeams(); - MinTeams = pm.GetMinTeams(); - PartyModeID = pm.ID; - } + [XmlIgnore] public IPartyModeInfo ExtInfo; } struct SPartyMode diff --git a/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudioStream.cs b/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudioStream.cs index ca0d602d..7a6fc6a4 100644 --- a/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudioStream.cs +++ b/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudioStream.cs @@ -237,7 +237,7 @@ namespace Vocaluxe.Lib.Sound.Playback.GstreamerSharp private bool _OnMessage(Message msg) { - if (msg.Handle == IntPtr.Zero) + if (msg == null || msg.Handle == IntPtr.Zero) return true; switch (msg.Type) { diff --git a/Vocaluxe/Lib/Sound/Playback/IPlayback.cs b/Vocaluxe/Lib/Sound/Playback/IPlayback.cs index 1dd10288..7bb4a9ad 100644 --- a/Vocaluxe/Lib/Sound/Playback/IPlayback.cs +++ b/Vocaluxe/Lib/Sound/Playback/IPlayback.cs @@ -45,9 +45,9 @@ namespace Vocaluxe.Lib.Sound.Playback void Fade(int streamID, int targetVolume, float seconds, EStreamAction afterFadeAction = EStreamAction.Nothing); /// - /// Set the streams current volume. Cancels fading + /// Set the stream's current volume. Cancels fading /// - /// Id of the stream (optained by Load) + /// Id of the stream (obtained by Load) /// Volume in percent void SetStreamVolume(int streamID, int volume); @@ -62,4 +62,4 @@ namespace Vocaluxe.Lib.Sound.Playback void Update(); #endregion stream Handling } -} \ No newline at end of file +} diff --git a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPt1.cs b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPt1.cs index ea854457..a4a7d561 100644 --- a/Vocaluxe/Lib/Sound/Playback/PortAudio/CPt1.cs +++ b/Vocaluxe/Lib/Sound/Playback/PortAudio/CPt1.cs @@ -49,8 +49,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio _CurrentTime = value; _OldTime = value; - _Timer.Reset(); - _Timer.Start(); + _Timer.Restart(); } } diff --git a/Vocaluxe/Lib/Sound/Playback/PortAudio/CSyncTimer.cs b/Vocaluxe/Lib/Sound/Playback/PortAudio/CSyncTimer.cs index 887c37cf..7a924663 100644 --- a/Vocaluxe/Lib/Sound/Playback/PortAudio/CSyncTimer.cs +++ b/Vocaluxe/Lib/Sound/Playback/PortAudio/CSyncTimer.cs @@ -44,8 +44,7 @@ namespace Vocaluxe.Lib.Sound.Playback.PortAudio { _ExternTime.Time = value; _SetValue = value; - _Timer.Reset(); - _Timer.Start(); + _Timer.Restart(); } } diff --git a/Vocaluxe/Lib/Video/IVideoDecoder.cs b/Vocaluxe/Lib/Video/IVideoDecoder.cs index 205b157c..c4484f9e 100644 --- a/Vocaluxe/Lib/Video/IVideoDecoder.cs +++ b/Vocaluxe/Lib/Video/IVideoDecoder.cs @@ -36,7 +36,7 @@ namespace Vocaluxe.Lib.Video /// Loads the file with the given file path. /// /// Absolute file path of the video file - /// stream >=0 on success or -1 on failure + /// Loaded video stream or null on failure CVideoStream Load(string videoFileName); /// diff --git a/Vocaluxe/Program.cs b/Vocaluxe/Program.cs index 5e1fb26c..73b5a737 100644 --- a/Vocaluxe/Program.cs +++ b/Vocaluxe/Program.cs @@ -199,7 +199,8 @@ namespace Vocaluxe // Load Cover CLog.StartBenchmark("Init Cover"); - CCover.Init(); + if (!CCover.Init()) + throw new CLoadingException("covertheme"); CLog.StopBenchmark("Init Cover"); Application.DoEvents(); @@ -237,7 +238,8 @@ namespace Vocaluxe // Init Party Modes; CLog.StartBenchmark("Init Party Modes"); - CParty.Init(); + if (!CParty.Init()) + throw new CLoadingException("Party Modes"); CLog.StopBenchmark("Init Party Modes"); Application.DoEvents(); diff --git a/Vocaluxe/Screens/CPopupScreenPlayerControl.cs b/Vocaluxe/Screens/CPopupScreenPlayerControl.cs index 0ed15bc7..0ce70b67 100644 --- a/Vocaluxe/Screens/CPopupScreenPlayerControl.cs +++ b/Vocaluxe/Screens/CPopupScreenPlayerControl.cs @@ -112,7 +112,7 @@ namespace Vocaluxe.Screens if (_Buttons[_ButtonPrevious].Selected) CBackgroundMusic.Previous(); if (_Buttons[_ButtonPlay].Selected) - CBackgroundMusic.Pause(); + CBackgroundMusic.Play(); if (_Buttons[_ButtonPause].Selected) CBackgroundMusic.Pause(); if (_Buttons[_ButtonRepeat].Selected) @@ -140,7 +140,7 @@ namespace Vocaluxe.Screens if (_Buttons[_ButtonPrevious].Selected) CBackgroundMusic.Previous(); if (_Buttons[_ButtonPlay].Selected) - CBackgroundMusic.Pause(); + CBackgroundMusic.Play(); if (_Buttons[_ButtonPause].Selected) CBackgroundMusic.Pause(); if (_Buttons[_ButtonRepeat].Selected) diff --git a/Vocaluxe/Screens/CScreenCredits.cs b/Vocaluxe/Screens/CScreenCredits.cs index e65d33c8..f75a13af 100644 --- a/Vocaluxe/Screens/CScreenCredits.cs +++ b/Vocaluxe/Screens/CScreenCredits.cs @@ -34,6 +34,72 @@ namespace Vocaluxe.Screens Up } + class CCreditTranslation + { + private readonly string _Language; + private readonly List _Texts; + public float StartTime; + + public float Y + { + get { return _Texts[0].Y; } + set + { + float diff = value - _Texts[0].Y; + foreach (CText t in _Texts) + t.Y += diff; + } + } + + public float Alpha + { + get { return _Texts[0].Alpha; } + set + { + foreach (CText t in _Texts) + t.Alpha = value; + } + } + + public bool Visible + { + set + { + foreach (CText t in _Texts) + t.Visible = value; + } + } + + public float LastY + { + get + { + int lastText = _Texts.Count - 1; + return _Texts[lastText].Y + _Texts[lastText].H; + } + } + + public CCreditTranslation(string language, List texts) + { + _Language = language; + _Texts = texts; + } + + public void Reset() + { + StartTime = -1; + Alpha = 1f; + Visible = true; + _Texts[0].Y = CSettings.RenderH + 1; + float y = CSettings.RenderH + 1; + foreach (CText t in _Texts) + { + y += 25; + t.Y = y; + } + } + } + class CCreditName { private readonly CStatic _Image; @@ -120,8 +186,12 @@ namespace Vocaluxe.Screens private CParticleEffect _StarsBlue; private List _CreditNames; + private List _Translations; + private int _NumTranslationTexts; + private Stopwatch _LogoTimer; private Stopwatch _CreditsTimer; + private Stopwatch _TranslationsTimer; private Stopwatch _TextTimer; private List _Paragraphs; @@ -155,6 +225,7 @@ namespace Vocaluxe.Screens _LogoTimer = new Stopwatch(); _CreditsTimer = new Stopwatch(); + _TranslationsTimer = new Stopwatch(); _TextTimer = new Stopwatch(); //Text for last part of credits. @@ -278,6 +349,8 @@ namespace Vocaluxe.Screens _AddNewCreditName(_TexNameBohning, 383, 54, false); _AddNewCreditName(_TexNameMesand, 525, 13, false); _AddNewCreditName(_TexNameBabene03, 33, 26, false); + + _AddTranslations(); } public override void ReloadTheme(string xmlPath) {} @@ -349,6 +422,42 @@ namespace Vocaluxe.Screens _AddParticleEffect(particle); } + private void _AddTranslations() + { + CCreditTranslation intro = _AddNewTranslation("A special thanks to all our translators", new List { }); + CCreditTranslation asturian = _AddNewTranslation("Asturian", new List { "Puxarra" }); + CCreditTranslation czech = _AddNewTranslation("Czech", new List { "fri" }); + CCreditTranslation dutch = _AddNewTranslation("Dutch", new List { "thijsblaauw" }); + CCreditTranslation french = _AddNewTranslation("French", new List { "pinky007" }); + CCreditTranslation hungarian = _AddNewTranslation("Hungarian", new List { "warez" }); + CCreditTranslation italian = _AddNewTranslation("Italian", new List { "giuseppep", "LFactory" }); + CCreditTranslation spanish = _AddNewTranslation("Spanish", new List { "Pantero03", "RubenDjOn", "TeLiX", "karv" }); + CCreditTranslation swedish = _AddNewTranslation("Swedish", new List { "u28151" }); + CCreditTranslation turkish = _AddNewTranslation("Turkish", new List { "spirax", "Swertyy" }); + + _Translations = new List { intro, asturian, czech, dutch, french, hungarian, italian, spanish, swedish, turkish }; + } + + private CCreditTranslation _AddNewTranslation(string language, List translators) + { + List texts = new List(); + CText text = GetNewText(new CText(CSettings.RenderW / 2, CSettings.RenderH + 1, -4f, 30, -1, EAlignment.Center, EStyle.Bold, "Outline", new SColorF(1, 1, 1, 1), language)); + _AddText(text); + texts.Add(text); + _NumTranslationTexts++; + float y = texts[0].Y; + foreach (string t in translators) + { + y += 30; + text = GetNewText(new CText(CSettings.RenderW / 2, y, -4f, 27, -1, EAlignment.Center, EStyle.Normal, "Outline", new SColorF(1, 1, 1, 1), t)); + _AddText(text); + texts.Add(text); + _NumTranslationTexts++; + } + CCreditTranslation cct = new CCreditTranslation(language, texts); + return cct; + } + public override void OnShow() { base.OnShow(); @@ -368,10 +477,13 @@ namespace Vocaluxe.Screens _Logo.Y = -270; _StarsRed.Y = _Logo.Y; _StarsBlue.Y = _Logo.Y; + foreach (CCreditTranslation translation in _Translations) + translation.Reset(); _TextTimer.Reset(); _LogoTimer.Reset(); _CreditsTimer.Reset(); + _TranslationsTimer.Reset(); } public override void OnShowFinish() @@ -447,9 +559,7 @@ namespace Vocaluxe.Screens if (i == _CreditNames.Count - 1) { _CreditsTimer.Stop(); - _TextTimer.Start(); - foreach (CText text in _ParagraphTexts) - text.Visible = true; + _TranslationsTimer.Start(); } } else if (_CreditNames[i].Y <= 360f) @@ -463,9 +573,43 @@ namespace Vocaluxe.Screens } } } + if (_TranslationsTimer.IsRunning) + { + active = true; + for (int i = 0; i < _Translations.Count; i++) + { + if (i * 1500f < _TranslationsTimer.ElapsedMilliseconds) + { + if (_Translations[i].StartTime == -1) + _Translations[i].StartTime = _TranslationsTimer.ElapsedMilliseconds; + float newY = 720f - (520f / 5000f) * (_TranslationsTimer.ElapsedMilliseconds - _Translations[i].StartTime); + _Translations[i].Y = newY; + } + + if (_Translations[i].Y <= 160f) + { + _Translations[i].Visible = false; + if (i == _Translations.Count - 1) + { + _TranslationsTimer.Stop(); + _TextTimer.Start(); + foreach (CText text in _ParagraphTexts) + text.Visible = true; + } + } + if (_Translations[i].Y <= 360f) + { + //Fade out + float alpha = ((360 - _Translations[i].Y) / 200).Clamp(0,1); + _Translations[i].Alpha = 1 - alpha; + } + } + + + } if (_TextTimer.IsRunning) - active = _TextTimer.ElapsedMilliseconds <= 500; + active = _TextTimer.ElapsedMilliseconds <= 10000; return active; } diff --git a/Vocaluxe/Screens/CScreenNames.cs b/Vocaluxe/Screens/CScreenNames.cs index bd04a3ab..f6d59be9 100644 --- a/Vocaluxe/Screens/CScreenNames.cs +++ b/Vocaluxe/Screens/CScreenNames.cs @@ -65,6 +65,11 @@ namespace Vocaluxe.Screens private bool _AvatarsChanged; private bool _ProfilesChanged; + public override EMusicType CurrentMusicType + { + get { return EMusicType.Preview; } + } + #region public methods public override void Init() { diff --git a/Vocaluxe/Screens/CScreenOptionsGame.cs b/Vocaluxe/Screens/CScreenOptionsGame.cs index ce71f532..71794199 100644 --- a/Vocaluxe/Screens/CScreenOptionsGame.cs +++ b/Vocaluxe/Screens/CScreenOptionsGame.cs @@ -134,7 +134,7 @@ namespace Vocaluxe.Screens private void _SaveConfig() { CLanguage.LanguageId = _SelectSlides[_SelectSlideLanguage].Selection; - CConfig.Config.Game.Language = _SelectSlides[_SelectSlideLanguage].Value; + CConfig.Config.Game.Language = _SelectSlides[_SelectSlideLanguage].SelectedValue; CConfig.Config.Debug.DebugLevel = (EDebugLevel)_SelectSlides[_SelectSlideDebugLevel].Selection; CConfig.Config.Game.SongMenu = (ESongMenu)_SelectSlides[_SelectSlideSongMenu].Selection; CConfig.Config.Game.SongSorting = (ESongSorting)_SelectSlides[_SelectSlideSongSorting].Selection; diff --git a/Vocaluxe/Screens/CScreenOptionsRecord.cs b/Vocaluxe/Screens/CScreenOptionsRecord.cs index bcf3e902..dca9586b 100644 --- a/Vocaluxe/Screens/CScreenOptionsRecord.cs +++ b/Vocaluxe/Screens/CScreenOptionsRecord.cs @@ -65,7 +65,7 @@ namespace Vocaluxe.Screens public override EMusicType CurrentMusicType { - get { return EMusicType.None; } + get { return EMusicType.Game; } } public override void Init() @@ -303,7 +303,6 @@ namespace Vocaluxe.Screens public override void OnShowFinish() { base.OnShowFinish(); - CBackgroundMusic.Disabled = true; } public override void Draw() @@ -332,7 +331,6 @@ namespace Vocaluxe.Screens CRecord.Stop(); _DelayTest.Reset(); - CBackgroundMusic.Disabled = false; } private void _OnDeviceEvent() diff --git a/Vocaluxe/Screens/CScreenOptionsTheme.cs b/Vocaluxe/Screens/CScreenOptionsTheme.cs index e21f5087..6723a305 100644 --- a/Vocaluxe/Screens/CScreenOptionsTheme.cs +++ b/Vocaluxe/Screens/CScreenOptionsTheme.cs @@ -171,15 +171,15 @@ namespace Vocaluxe.Screens CConfig.SaveConfig(); - if (_OldCoverTheme != _SelectSlides[_SelectSlideCover].Value) + if (_OldCoverTheme != _SelectSlides[_SelectSlideCover].SelectedValue) CCover.ReloadCovers(); } private void _OnChange() { - if (CConfig.Config.Theme.Theme != _SelectSlides[_SelectSlideTheme].Value) + if (CConfig.Config.Theme.Theme != _SelectSlides[_SelectSlideTheme].SelectedValue) { - CConfig.Config.Theme.Theme = _SelectSlides[_SelectSlideTheme].Value; + CConfig.Config.Theme.Theme = _SelectSlides[_SelectSlideTheme].SelectedValue; CThemes.Reload(); CGraphics.ReloadTheme(); @@ -188,9 +188,9 @@ namespace Vocaluxe.Screens return; } - if (CConfig.Config.Theme.Skin != _SelectSlides[_SelectSlideSkin].Value) + if (CConfig.Config.Theme.Skin != _SelectSlides[_SelectSlideSkin].SelectedValue) { - CConfig.Config.Theme.Skin = _SelectSlides[_SelectSlideSkin].Value; + CConfig.Config.Theme.Skin = _SelectSlides[_SelectSlideSkin].SelectedValue; CThemes.ReloadSkin(); CGraphics.ReloadSkin(); diff --git a/Vocaluxe/Screens/CScreenParty.cs b/Vocaluxe/Screens/CScreenParty.cs index 3f6d801f..7b11c376 100644 --- a/Vocaluxe/Screens/CScreenParty.cs +++ b/Vocaluxe/Screens/CScreenParty.cs @@ -20,6 +20,7 @@ using System.Windows.Forms; using Vocaluxe.Base; using VocaluxeLib; using VocaluxeLib.Menu; +using VocaluxeLib.PartyModes; namespace Vocaluxe.Screens { @@ -115,7 +116,7 @@ namespace Vocaluxe.Screens _SelectSlides[_SelectSlideModes].Clear(); foreach (SPartyModeInfos info in _PartyModeInfos) - _SelectSlides[_SelectSlideModes].AddValue(info.Name, info.PartyModeID); + _SelectSlides[_SelectSlideModes].AddValue(info.Name, info.ExtInfo.ID); _SelectSlides[_SelectSlideModes].Selection = 0; _UpdateSelection(); @@ -134,42 +135,48 @@ namespace Vocaluxe.Screens int index = _SelectSlides[_SelectSlideModes].Selection; if (index >= _PartyModeInfos.Count) - return; + { + index = 0; + _SelectSlides[_SelectSlideModes].Selection = 0; + } //Description - _Texts[_TextDescription].Text = _PartyModeInfos[index].Description; - _Texts[_TextDescription].TranslationID = _PartyModeInfos[index].PartyModeID; + SPartyModeInfos infos = _PartyModeInfos[index]; + IPartyModeInfo extInfo = infos.ExtInfo; + _Texts[_TextDescription].Text = infos.Description; + _Texts[_TextDescription].TranslationID = extInfo.ID; //TargetAudience - _Texts[_TextTargetAudience].TranslationID = _PartyModeInfos[index].PartyModeID; - _Texts[_TextTargetAudience].Text = _PartyModeInfos[index].TargetAudience; + _Texts[_TextTargetAudience].TranslationID = extInfo.ID; + _Texts[_TextTargetAudience].Text = infos.TargetAudience; //NumTeams - if (_PartyModeInfos[index].MaxTeams == 0) + if (extInfo.MaxTeams == 1) _Texts[_TextNumTeams].Text = "TR_SCREENPARTY_NOTEAMS"; - else if (_PartyModeInfos[index].MaxTeams == _PartyModeInfos[index].MinTeams) - _Texts[_TextNumTeams].Text = _PartyModeInfos[index].MaxTeams.ToString(); - else if (_PartyModeInfos[index].MaxTeams > _PartyModeInfos[index].MinTeams) - _Texts[_TextNumTeams].Text = _PartyModeInfos[index].MinTeams + " - " + _PartyModeInfos[index].MaxTeams; + else if (extInfo.MaxTeams == extInfo.MinTeams) + _Texts[_TextNumTeams].Text = extInfo.MaxTeams.ToString(); + else + _Texts[_TextNumTeams].Text = extInfo.MinTeams + " - " + extInfo.MaxTeams; //NumPlayers - if (_PartyModeInfos[index].MaxPlayers == _PartyModeInfos[index].MinPlayers) - _Texts[_TextNumPlayers].Text = _PartyModeInfos[index].MaxTeams.ToString(); - else if (_PartyModeInfos[index].MaxPlayers > _PartyModeInfos[index].MinPlayers) - _Texts[_TextNumPlayers].Text = _PartyModeInfos[index].MinPlayers + " - " + _PartyModeInfos[index].MaxPlayers; + if (extInfo.MaxPlayers == extInfo.MinPlayers) + _Texts[_TextNumPlayers].Text = extInfo.MaxTeams.ToString(); + else + _Texts[_TextNumPlayers].Text = extInfo.MinPlayers + " - " + extInfo.MaxPlayers; //Author - _Texts[_TextAuthor].Text = _PartyModeInfos[index].Author; - _Texts[_TextAuthor].TranslationID = _PartyModeInfos[index].PartyModeID; + _Texts[_TextAuthor].Text = infos.Author; + _Texts[_TextAuthor].TranslationID = extInfo.ID; //Version - _Texts[_TextVersion].Text = _PartyModeInfos[index].VersionMajor + "." + _PartyModeInfos[index].VersionMinor; - _Texts[_TextVersion].TranslationID = _PartyModeInfos[index].PartyModeID; + _Texts[_TextVersion].Text = infos.VersionMajor + "." + infos.VersionMinor; + _Texts[_TextVersion].TranslationID = extInfo.ID; - if (CConfig.GetMaxNumMics() == 0) + if (CConfig.GetMaxNumMics() < extInfo.MinMics) { _Buttons[_ButtonStart].Visible = false; - _Texts[_TextError].Text = "TR_SCREENPARTY_ERROR_MICS"; + _Texts[_TextError].Text = CConfig.GetMaxNumMics() == 0 + ? "TR_SCREENPARTY_ERROR_MICS" : CLanguage.Translate("TR_SCREENPARTY_ERROR_MIC_NUM").Replace("%d", extInfo.MinMics.ToString()); _Texts[_TextError].Visible = true; } else @@ -193,7 +200,7 @@ namespace Vocaluxe.Screens return; } - CParty.SetPartyMode(_PartyModeInfos[index].PartyModeID); + CParty.SetPartyMode(_PartyModeInfos[index].ExtInfo.ID); CGraphics.FadeTo(CParty.GetStartScreen()); } } diff --git a/Vocaluxe/Screens/CScreenProfiles.cs b/Vocaluxe/Screens/CScreenProfiles.cs index 383ff57b..44196e34 100644 --- a/Vocaluxe/Screens/CScreenProfiles.cs +++ b/Vocaluxe/Screens/CScreenProfiles.cs @@ -109,7 +109,7 @@ namespace Vocaluxe.Screens break; case EEditMode.PlayerName: _SelectSlides[_SelectSlideProfiles].RenameValue( - CProfiles.AddGetPlayerName(_SelectSlides[_SelectSlideProfiles].ValueIndex, keyEvent.Unicode)); + CProfiles.AddGetPlayerName(_SelectSlides[_SelectSlideProfiles].SelectedTag, keyEvent.Unicode)); _ProfilesChanged = true; break; } @@ -155,7 +155,7 @@ namespace Vocaluxe.Screens if (_EditMode == EEditMode.PlayerName) { _SelectSlides[_SelectSlideProfiles].RenameValue( - CProfiles.GetDeleteCharInPlayerName(_SelectSlides[_SelectSlideProfiles].ValueIndex)); + CProfiles.GetDeleteCharInPlayerName(_SelectSlides[_SelectSlideProfiles].SelectedTag)); _ProfilesChanged = true; } else @@ -168,22 +168,22 @@ namespace Vocaluxe.Screens } if (_SelectSlides[_SelectSlideDifficulty].Selected) { - CProfiles.SetDifficulty(_SelectSlides[_SelectSlideProfiles].ValueIndex, + CProfiles.SetDifficulty(_SelectSlides[_SelectSlideProfiles].SelectedTag, (EGameDifficulty)_SelectSlides[_SelectSlideDifficulty].Selection); } else if (_SelectSlides[_SelectSlideAvatars].Selected) { - CProfiles.SetAvatar(_SelectSlides[_SelectSlideProfiles].ValueIndex, - _SelectSlides[_SelectSlideAvatars].ValueIndex); + CProfiles.SetAvatar(_SelectSlides[_SelectSlideProfiles].SelectedTag, + _SelectSlides[_SelectSlideAvatars].SelectedTag); } else if (_SelectSlides[_SelectSlideUserRole].Selected) { - CProfiles.SetUserRoleProfile(_SelectSlides[_SelectSlideProfiles].ValueIndex, + CProfiles.SetUserRoleProfile(_SelectSlides[_SelectSlideProfiles].SelectedTag, (EUserRole)_SelectSlides[_SelectSlideUserRole].Selection); } else if (_SelectSlides[_SelectSlideActive].Selected) { - CProfiles.SetActive(_SelectSlides[_SelectSlideProfiles].ValueIndex, + CProfiles.SetActive(_SelectSlides[_SelectSlideProfiles].SelectedTag, (EOffOn)_SelectSlides[_SelectSlideActive].Selection); } } @@ -215,24 +215,24 @@ namespace Vocaluxe.Screens } else if (_SelectSlides[_SelectSlideDifficulty].Selected) { - CProfiles.SetDifficulty(_SelectSlides[_SelectSlideProfiles].ValueIndex, + CProfiles.SetDifficulty(_SelectSlides[_SelectSlideProfiles].SelectedTag, (EGameDifficulty)_SelectSlides[_SelectSlideDifficulty].Selection); } else if (_SelectSlides[_SelectSlideAvatars].Selected) { - CProfiles.SetAvatar(_SelectSlides[_SelectSlideProfiles].ValueIndex, - _SelectSlides[_SelectSlideAvatars].ValueIndex); + CProfiles.SetAvatar(_SelectSlides[_SelectSlideProfiles].SelectedTag, + _SelectSlides[_SelectSlideAvatars].SelectedTag); if (CWebcam.IsDeviceAvailable() && _WebcamTexture != null) _OnDiscardSnapshot(); } else if (_SelectSlides[_SelectSlideUserRole].Selected) { - CProfiles.SetUserRoleProfile(_SelectSlides[_SelectSlideProfiles].ValueIndex, + CProfiles.SetUserRoleProfile(_SelectSlides[_SelectSlideProfiles].SelectedTag, (EUserRole)_SelectSlides[_SelectSlideUserRole].Selection); } else if (_SelectSlides[_SelectSlideActive].Selected) { - CProfiles.SetActive(_SelectSlides[_SelectSlideProfiles].ValueIndex, + CProfiles.SetActive(_SelectSlides[_SelectSlideProfiles].SelectedTag, (EOffOn)_SelectSlides[_SelectSlideActive].Selection); } else if (_Buttons[_ButtonWebcam].Selected) @@ -260,16 +260,16 @@ namespace Vocaluxe.Screens if (_SelectSlides[_SelectSlideProfiles].Selection > -1) { - _Buttons[_ButtonPlayerName].Text.Text = CProfiles.GetPlayerName(_SelectSlides[_SelectSlideProfiles].ValueIndex); + _Buttons[_ButtonPlayerName].Text.Text = CProfiles.GetPlayerName(_SelectSlides[_SelectSlideProfiles].SelectedTag); if (_EditMode == EEditMode.PlayerName) _Buttons[_ButtonPlayerName].Text.Text += "|"; - _SelectSlides[_SelectSlideDifficulty].Selection = (int)CProfiles.GetDifficulty(_SelectSlides[_SelectSlideProfiles].ValueIndex); - _SelectSlides[_SelectSlideUserRole].Selection = (int)CProfiles.GetUserRoleProfile(_SelectSlides[_SelectSlideProfiles].ValueIndex); - _SelectSlides[_SelectSlideActive].Selection = (int)CProfiles.GetActive(_SelectSlides[_SelectSlideProfiles].ValueIndex); + _SelectSlides[_SelectSlideDifficulty].Selection = (int)CProfiles.GetDifficulty(_SelectSlides[_SelectSlideProfiles].SelectedTag); + _SelectSlides[_SelectSlideUserRole].Selection = (int)CProfiles.GetUserRoleProfile(_SelectSlides[_SelectSlideProfiles].SelectedTag); + _SelectSlides[_SelectSlideActive].Selection = (int)CProfiles.GetActive(_SelectSlides[_SelectSlideProfiles].SelectedTag); - int avatarID = CProfiles.GetAvatarID(_SelectSlides[_SelectSlideProfiles].ValueIndex); - _SelectSlides[_SelectSlideAvatars].SetSelectionByValueIndex(avatarID); + int avatarID = CProfiles.GetAvatarID(_SelectSlides[_SelectSlideProfiles].SelectedTag); + _SelectSlides[_SelectSlideAvatars].SelectedTag = avatarID; if (_Snapshot == null) { if (CWebcam.IsCapturing()) @@ -357,7 +357,7 @@ namespace Vocaluxe.Screens _Buttons[_ButtonWebcam].Visible = CWebcam.IsDeviceAvailable(); int id = CProfiles.NewAvatar(file); - CProfiles.SetAvatar(_SelectSlides[_SelectSlideProfiles].ValueIndex, id); + CProfiles.SetAvatar(_SelectSlides[_SelectSlideProfiles].SelectedTag, id); _LoadAvatars(false); } @@ -381,10 +381,9 @@ namespace Vocaluxe.Screens _EditMode = EEditMode.None; int id = CProfiles.NewProfile(); _LoadProfiles(false); - _SelectSlides[_SelectSlideProfiles].SetSelectionByValueIndex(id); + _SelectSlides[_SelectSlideProfiles].SelectedTag = id; - CProfiles.SetAvatar(_SelectSlides[_SelectSlideProfiles].ValueIndex, - _SelectSlides[_SelectSlideAvatars].ValueIndex); + CProfiles.SetAvatar(_SelectSlides[_SelectSlideProfiles].SelectedTag, _SelectSlides[_SelectSlideAvatars].SelectedTag); _SelectElement(_Buttons[_ButtonPlayerName]); _EditMode = EEditMode.PlayerName; @@ -400,7 +399,7 @@ namespace Vocaluxe.Screens { _EditMode = EEditMode.None; - CProfiles.DeleteProfile(_SelectSlides[_SelectSlideProfiles].ValueIndex); + CProfiles.DeleteProfile(_SelectSlides[_SelectSlideProfiles].SelectedTag); int selection = _SelectSlides[_SelectSlideProfiles].Selection; if (_SelectSlides[_SelectSlideProfiles].NumValues - 1 > selection) @@ -413,29 +412,23 @@ namespace Vocaluxe.Screens { string name = String.Empty; if (_EditMode == EEditMode.PlayerName) - name = CProfiles.GetPlayerName(_SelectSlides[_SelectSlideProfiles].ValueIndex); + name = CProfiles.GetPlayerName(_SelectSlides[_SelectSlideProfiles].SelectedTag); - int selectedProfileID = _SelectSlides[_SelectSlideProfiles].ValueIndex; + int selectedProfileID = _SelectSlides[_SelectSlideProfiles].SelectedTag; _SelectSlides[_SelectSlideProfiles].Clear(); CProfile[] profiles = CProfiles.GetProfiles(); foreach (CProfile profile in profiles) - { - _SelectSlides[_SelectSlideProfiles].AddValue( - profile.PlayerName, - null, - profile.ID, - -1); - } + _SelectSlides[_SelectSlideProfiles].AddValue(profile.PlayerName, null, profile.ID); if (CProfiles.NumProfiles > 0 && CProfiles.NumAvatars > 0) { if (selectedProfileID != -1) - _SelectSlides[_SelectSlideProfiles].SetSelectionByValueIndex(selectedProfileID); + _SelectSlides[_SelectSlideProfiles].SelectedTag = selectedProfileID; else { _SelectSlides[_SelectSlideProfiles].Selection = 0; - selectedProfileID = _SelectSlides[_SelectSlideProfiles].ValueIndex; + selectedProfileID = _SelectSlides[_SelectSlideProfiles].SelectedTag; } if (!keep) @@ -443,39 +436,33 @@ namespace Vocaluxe.Screens _SelectSlides[_SelectSlideDifficulty].Selection = (int)CProfiles.GetDifficulty(selectedProfileID); _SelectSlides[_SelectSlideUserRole].Selection = (int)CProfiles.GetUserRoleProfile(selectedProfileID); _SelectSlides[_SelectSlideActive].Selection = (int)CProfiles.GetActive(selectedProfileID); - _SelectSlides[_SelectSlideAvatars].SetSelectionByValueIndex(CProfiles.GetAvatarID(selectedProfileID)); + _SelectSlides[_SelectSlideAvatars].SelectedTag = CProfiles.GetAvatarID(selectedProfileID); } if (_EditMode == EEditMode.PlayerName) - CProfiles.SetPlayerName(_SelectSlides[_SelectSlideProfiles].ValueIndex, name); + CProfiles.SetPlayerName(_SelectSlides[_SelectSlideProfiles].SelectedTag, name); } _ProfilesChanged = false; } private void _LoadAvatars(bool keep) { - int selectedAvatarID = _SelectSlides[_SelectSlideAvatars].ValueIndex; + int selectedAvatarID = _SelectSlides[_SelectSlideAvatars].SelectedTag; _SelectSlides[_SelectSlideAvatars].Clear(); IEnumerable avatars = CProfiles.GetAvatars(); if (avatars != null) { foreach (CAvatar avatar in avatars) - { - _SelectSlides[_SelectSlideAvatars].AddValue( - avatar.GetDisplayName(), - null, - avatar.ID, - -1); - } + _SelectSlides[_SelectSlideAvatars].AddValue(avatar.GetDisplayName(), null, avatar.ID); } if (keep) { - _SelectSlides[_SelectSlideAvatars].SetSelectionByValueIndex(selectedAvatarID); - CProfiles.SetAvatar(_SelectSlides[_SelectSlideProfiles].ValueIndex, selectedAvatarID); + _SelectSlides[_SelectSlideAvatars].SelectedTag = selectedAvatarID; + CProfiles.SetAvatar(_SelectSlides[_SelectSlideProfiles].SelectedTag, selectedAvatarID); } else - _SelectSlides[_SelectSlideAvatars].SetSelectionByValueIndex(CProfiles.GetAvatarID(_SelectSlides[_SelectSlideProfiles].ValueIndex)); + _SelectSlides[_SelectSlideAvatars].SelectedTag = CProfiles.GetAvatarID(_SelectSlides[_SelectSlideProfiles].SelectedTag); _AvatarsChanged = false; } diff --git a/Vocaluxe/Screens/CScreenScore.cs b/Vocaluxe/Screens/CScreenScore.cs index 4f8a7aff..ffb5cc86 100644 --- a/Vocaluxe/Screens/CScreenScore.cs +++ b/Vocaluxe/Screens/CScreenScore.cs @@ -124,8 +124,6 @@ namespace Vocaluxe.Screens public override void OnShow() { - CBackgroundMusic.Disabled = false; - base.OnShow(); //-1 --> Show average _Round = CGame.NumRounds > 1 ? -1 : 0; @@ -187,26 +185,23 @@ namespace Vocaluxe.Screens private static string _GetRating(double points) { - string rating = String.Empty; + string rating; if (points >= 9800) - { - //in case of the game names so: rating = "TR_RATING_VOCAL_HERO"; - } - else if (points < 9800 && points >= 8400) + else if (points >= 8400) rating = "TR_RATING_SUPERSTAR"; - else if (points < 8400 && points >= 7000) + else if (points >= 7000) rating = "TR_RATING_LEAD_SINGER"; - else if (points < 7000 && points >= 5600) + else if (points >= 5600) rating = "TR_RATING_RISING_STAR"; - else if (points < 5600 && points >= 4200) + else if (points >= 4200) rating = "TR_RATING_HOPEFUL"; - else if (points < 4200 && points >= 2800) + else if (points >= 2800) rating = "TR_RATING_WANNABE"; - else if (points < 2800 && points >= 1400) + else if (points >= 1400) rating = "TR_RATING_AMATEUR"; - else if (points < 1400) + else rating = "TR_RATING_TONE_DEAF"; return rating; diff --git a/Vocaluxe/Screens/CScreenSing.cs b/Vocaluxe/Screens/CScreenSing.cs index 24584cd1..febdde72 100644 --- a/Vocaluxe/Screens/CScreenSing.cs +++ b/Vocaluxe/Screens/CScreenSing.cs @@ -96,8 +96,7 @@ namespace Vocaluxe.Screens private int _CurrentBeat; private int _CurrentStream = -1; private float _Length = -1f; - //private int _NextStream = -1; - private const int _Volume = 100; + private CVideoStream _CurrentVideo; private EAspect _VideoAspect = EAspect.Crop; private CTextureRef _CurrentWebcamFrameTexture; @@ -414,7 +413,6 @@ namespace Vocaluxe.Screens public override void OnShowFinish() { base.OnShowFinish(); - CBackgroundMusic.Disabled = true; CGame.Start(); _LoadNextSong(); @@ -528,7 +526,7 @@ namespace Vocaluxe.Screens _Texts[_TextSongName].Text = songname; _CurrentStream = CSound.Load(song.GetMP3(), false, true); - CSound.SetStreamVolume(_CurrentStream, _Volume); + CSound.SetStreamVolume(_CurrentStream, 100); CSound.SetPosition(_CurrentStream, song.Start); _CurrentTime = song.Start; _FinishTime = song.Finish; diff --git a/Vocaluxe/Screens/CScreenSong.cs b/Vocaluxe/Screens/CScreenSong.cs index 75dea6b9..8a4d5ff1 100644 --- a/Vocaluxe/Screens/CScreenSong.cs +++ b/Vocaluxe/Screens/CScreenSong.cs @@ -80,7 +80,6 @@ namespace Vocaluxe.Screens private readonly List _ButtonsJoker = new List(); private readonly List _TextsPlayer = new List(); private ESongOptionsView _CurSongOptionsView; - private bool _PlaylistActive; private readonly List _AvailableGameModes; private SScreenSongOptions _Sso; @@ -163,16 +162,26 @@ namespace Vocaluxe.Screens public override bool HandleInput(SKeyEvent keyEvent) { + if (_Playlist.Visible) + { + keyEvent.Handled = _Playlist.HandleInput(keyEvent); + if (keyEvent.Handled) + return true; + if (!keyEvent.KeyPressed && keyEvent.Key == Keys.Escape) + { + _ClosePlaylist(); + keyEvent.Handled = true; + return true; + } + } + + // Playlist selection is handled below not in base! + _Playlist.Selectable = false; base.HandleInput(keyEvent); + _Playlist.Selectable = true; if (keyEvent.Handled) return true; - if (_PlaylistActive) - { - _Playlist.HandleInput(keyEvent); - return true; - } - if (_CurSongOptionsView == ESongOptionsView.None) { if (keyEvent.KeyPressed && !Char.IsControl(keyEvent.Unicode) && keyEvent.Mod != EModifier.Ctrl) @@ -233,9 +242,8 @@ namespace Vocaluxe.Screens case Keys.Tab: if (_Playlist.Visible) { - _PlaylistActive = !_PlaylistActive; - _Playlist.Selected = _PlaylistActive; - _SongMenu.Selected = !_PlaylistActive; + _Playlist.Selected = !_Playlist.Selected; + _SongMenu.Selected = !_Playlist.Selected; } break; @@ -392,27 +400,18 @@ namespace Vocaluxe.Screens _OldMousePosX = mouseEvent.X; _OldMousePosY = mouseEvent.Y; - if (_Playlist.Visible && _Playlist.IsMouseOver(mouseEvent)) + if (_Playlist.Visible && _Playlist.Selected) { - _PlaylistActive = true; - _Playlist.Selected = _PlaylistActive; - _SongMenu.Selected = !_PlaylistActive; + _SongMenu.Selected = false; _ToggleSongOptions(ESongOptionsView.None); - } - else if (CHelper.IsInBounds(_SongMenu.Rect, mouseEvent)) - { - _PlaylistActive = false; - _Playlist.Selected = _PlaylistActive; - _SongMenu.Selected = !_PlaylistActive; - } - - - if (_Playlist.Visible && _PlaylistActive) - { if (_Playlist.HandleMouse(mouseEvent)) return true; } - + else if (CHelper.IsInBounds(_SongMenu.Rect, mouseEvent)) + { + _Playlist.Selected = false; + _SongMenu.Selected = true; + } if (mouseEvent.RB) { @@ -522,12 +521,12 @@ namespace Vocaluxe.Screens _HandleSelectButton(); return true; } - else if (_SelectSlides[_SelectSlideOptionsPlaylistOpen].ValueSelected) + else if (_SelectSlides[_SelectSlideOptionsPlaylistOpen].IsValueSelected) { _OpenPlaylist(_SelectSlides[_SelectSlideOptionsPlaylistOpen].Selection); return true; } - else if (_SelectSlides[_SelectSlideOptionsPlaylistAdd].ValueSelected) + else if (_SelectSlides[_SelectSlideOptionsPlaylistAdd].IsValueSelected) { _OpenPlaylist(_SelectSlides[_SelectSlideOptionsPlaylistAdd].Selection - 1); return true; @@ -629,12 +628,13 @@ namespace Vocaluxe.Screens _SongMenu.OnShow(); if (_Sso.Selection.PartyMode) - _PlaylistActive = false; - - if (_Sso.Selection.PartyMode) + { + _ClosePlaylist(); _ToggleSongOptions(ESongOptionsView.None); + _SelectElement(_Buttons[_ButtonStart]); + } - _SongMenu.Selected = !_PlaylistActive; + _SongMenu.Selected = !_Playlist.Visible; _SongMenu.SmallView = _Playlist.Visible; if (_Playlist.ActivePlaylistID != -1) @@ -659,7 +659,7 @@ namespace Vocaluxe.Screens public override bool UpdateGame() { - if (_PlaylistActive) + if (_Playlist.Visible) { if (_Playlist.ActivePlaylistID == -1) _ClosePlaylist(); @@ -1171,7 +1171,7 @@ namespace Vocaluxe.Screens { if (CSongs.VisibleSongs[_SongMenu.GetPreviewSongNr()].IsGameModeAvailable(gameMode)) { - _SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), gameMode)); + _SelectSlides[_SelectSlideOptionsMode].AddValue(Enum.GetName(typeof(EGameMode), gameMode), null, (int)gameMode); _AvailableGameModes.Add(gameMode); } } @@ -1189,11 +1189,7 @@ namespace Vocaluxe.Screens _CheckAndAddGameMode(EGameMode.TR_GAMEMODE_MEDLEY); //Set SelectSlide-Selection to last selected game-mode if possible - for (int i = 0; i < _AvailableGameModes.Count; i++) - { - if (_AvailableGameModes[i] == lastMode) - _SelectSlides[_SelectSlideOptionsMode].SetSelectionByValueIndex(i); - } + _SelectSlides[_SelectSlideOptionsMode].SelectedTag = (int)lastMode; _SelectSlides[_SelectSlideOptionsMode].Visible = true; _SelectSlides[_SelectSlideOptionsPlaylistAdd].Visible = true; _Buttons[_ButtonOptionsSing].Visible = true; @@ -1242,9 +1238,9 @@ namespace Vocaluxe.Screens _SelectSlides[_SelectSlideOptionsNumMedleySongs].AddValue(i.ToString()); } if (_SelectSlides[_SelectSlideOptionsNumMedleySongs].NumValues >= 5) - _SelectSlides[_SelectSlideOptionsNumMedleySongs].SetSelectionByValueIndex(4); + _SelectSlides[_SelectSlideOptionsNumMedleySongs].SelectedValue = "5"; else - _SelectSlides[_SelectSlideOptionsNumMedleySongs].SetSelectionByValueIndex(_SelectSlides[_SelectSlideOptionsNumMedleySongs].NumValues - 1); + _SelectSlides[_SelectSlideOptionsNumMedleySongs].SelectLastValue(); _SelectElement(_Buttons[_ButtonOptionsStartMedley]); } @@ -1260,12 +1256,12 @@ namespace Vocaluxe.Screens private void _ClosePlaylist() { - if (_Playlist.Visible || _PlaylistActive) + if (_Playlist.Visible) { _SongMenu.SmallView = false; - _PlaylistActive = false; - _Playlist.Selected = _PlaylistActive; - _SongMenu.Selected = !_PlaylistActive; + _Playlist.Visible = false; + _Playlist.Selected = false; + _SongMenu.Selected = false; _Playlist.ClosePlaylist(); } } diff --git a/Vocaluxe/Website/locales/sv.json b/Vocaluxe/Website/locales/sv.json index dafc5bcc..81d607bb 100644 --- a/Vocaluxe/Website/locales/sv.json +++ b/Vocaluxe/Website/locales/sv.json @@ -80,7 +80,7 @@ "keyboardButtonShift": "Shift", "keyboardButtonAlt": "Alt", "keyboardButtonCtrl": "Control", - "keyboardButtonBackspace": "Backspace", - "keyboardAutoSend": "Auto send keys", - "keyboardButtonSend": "Send" + "keyboardButtonBackspace": "Backsteg", + "keyboardAutoSend": "Auto skicka knappar", + "keyboardButtonSend": "Skicka" } \ No newline at end of file diff --git a/VocaluxeLib/Enums.cs b/VocaluxeLib/Enums.cs index cf22c332..436c81aa 100644 --- a/VocaluxeLib/Enums.cs +++ b/VocaluxeLib/Enums.cs @@ -180,7 +180,6 @@ namespace VocaluxeLib public enum EWebcamLib { - OpenCV, AForgeNet } diff --git a/VocaluxeLib/Extensions.cs b/VocaluxeLib/Extensions.cs index 12f06137..5e36958d 100644 --- a/VocaluxeLib/Extensions.cs +++ b/VocaluxeLib/Extensions.cs @@ -178,6 +178,18 @@ namespace VocaluxeLib rect.Z); } + public static List Shuffle(this List list) + { + for (int n = list.Count - 1; n >= 1; n--) + { + int k = CBase.Game.GetRandom(n); + T value = list[k]; + list[k] = list[n]; + list[n] = value; + } + return list; + } + public static Size GetSize(this Bitmap bmp) { return new Size(bmp.Width, bmp.Height); diff --git a/VocaluxeLib/IBasic.cs b/VocaluxeLib/IBasic.cs index 5262668b..6c18ddde 100644 --- a/VocaluxeLib/IBasic.cs +++ b/VocaluxeLib/IBasic.cs @@ -121,9 +121,9 @@ namespace VocaluxeLib CTextureRef GetVideoTexture(); - void LoadPreview(CSong song, float start = 0f); - void PlayPreview(float start = -1f); + void LoadPreview(CSong song, float start = -1f); void StopPreview(); + void SetPlayingPreview(bool playPreview); } public interface IDrawing @@ -266,17 +266,18 @@ namespace VocaluxeLib public interface ISound { int Load(string soundFile, bool loop = false, bool prescan = false); - void SetPosition(int soundStream, float newPosition); - void Play(int soundStream); - void Fade(int soundStream, int targetVolume, float duration, EStreamAction afterFadeAction = EStreamAction.Nothing); - void Close(int soundStream); + void SetPosition(int streamID, float newPosition); + void Play(int streamID); + void Fade(int streamID, int targetVolume, float duration, EStreamAction afterFadeAction = EStreamAction.Nothing); + void Close(int streamID); - bool IsFinished(int soundStream); - float GetPosition(int soundStream); - float GetLength(int soundStream); + bool IsFinished(int streamID); + float GetPosition(int streamID); + float GetLength(int streamID); - void SetStreamVolume(int soundStream, int volume); + void SetStreamVolume(int streamID, int volume); void SetGlobalVolume(int volume); + bool IsPaused(int streamID); } public interface ICover diff --git a/VocaluxeLib/Menu/CButton.cs b/VocaluxeLib/Menu/CButton.cs index fad72b20..b0ca4a48 100644 --- a/VocaluxeLib/Menu/CButton.cs +++ b/VocaluxeLib/Menu/CButton.cs @@ -300,11 +300,6 @@ namespace VocaluxeLib.Menu } } - public void ProcessMouseMove(int x, int y) - { - Selected = CHelper.IsInBounds(Rect, x, y); - } - public void UnloadSkin() { if (!ThemeLoaded) @@ -318,6 +313,7 @@ namespace VocaluxeLib.Menu return; Text = new CText(_Theme.Text, _PartyModeID); Text.LoadSkin(); + Text.Selected = Selected; if (_Theme.SelText.HasValue) { diff --git a/VocaluxeLib/Menu/CLyric.cs b/VocaluxeLib/Menu/CLyric.cs index 7ada94b3..7b17d0c0 100644 --- a/VocaluxeLib/Menu/CLyric.cs +++ b/VocaluxeLib/Menu/CLyric.cs @@ -188,14 +188,12 @@ namespace VocaluxeLib.Menu case ELyricStyle.Fill: _DrawFill(); break; - case ELyricStyle.Jump: - _DrawJump(); - break; case ELyricStyle.Slide: _DrawSlide(); break; case ELyricStyle.Zoom: - _DrawZoom(); + case ELyricStyle.Jump: + _DrawZoomOrJump(); break; default: _DrawSlide(); @@ -219,14 +217,15 @@ namespace VocaluxeLib.Menu { _Text.Color = _ColorProcessed; - int diff = note.EndBeat - note.StartBeat; + int diff = note.Duration; if (diff <= 0) _Text.Draw(0f, 1f); else { - _Text.Draw(0f, (_CurrentBeat - note.StartBeat) / diff); + float p = (_CurrentBeat - note.StartBeat) / diff; + _Text.Draw(0f, p); _Text.Color = _Color; - _Text.Draw((_CurrentBeat - note.StartBeat) / diff, 1f); + _Text.Draw(p, 1f); } } else @@ -245,87 +244,6 @@ namespace VocaluxeLib.Menu } } - private void _DrawZoom() - { - float x = X - _Width / 2; // most left position - - //find last active note - int lastNote = _Line.FindPreviousNote((int)_CurrentBeat); - - int zoomNote = -1; - int endBeat = -1; - float zoomx = 0f; - - for (int note = 0; note < _Line.Notes.Length; note++) - { - _Text.X = x; - _SetText(_Line.Notes[note]); - - if (_CurrentBeat >= _Line.Notes[note].StartBeat) - { - int curEndBeat = _Line.Notes[note].EndBeat; - if (note < _Line.Notes.Length - 1) - curEndBeat = _Line.Notes[note + 1].StartBeat - 1; - - if (_CurrentBeat <= curEndBeat) - { - zoomNote = note; - endBeat = curEndBeat; - zoomx = _Text.X; - } - else - { - // already passed - _Text.Color = note == lastNote ? _ColorProcessed : _Color; - - _Text.Draw(); - } - } - else - { - // not passed - _Text.Color = _Color; - _Text.Draw(); - } - - x += _Text.Rect.W; - } - - if (zoomNote > -1) - { - _Text.X = zoomx; - _SetText(_Line.Notes[zoomNote]); - - float diff = endBeat - _Line.Notes[zoomNote].StartBeat; - if (diff <= 0f) - diff = 1f; - - float p = (_CurrentBeat - _Line.Notes[zoomNote].StartBeat) / diff; - if (p > 1f) - p = 1f; - - p = 1f - p; - - float ty = _Text.Y; - float th = _Text.Font.Height; - float tz = _Text.Z; - - SRectF normalRect = _Text.Rect; - _Text.Font.Height *= 1f + p * 0.4f; - _Text.X -= (_Text.Rect.W - normalRect.W) / 2f; - _Text.Y -= (_Text.Rect.H - normalRect.H) / 2f; - _Text.Z -= 0.1f; - _Text.Color = _ColorProcessed; - - - _Text.Draw(); - - _Text.Y = ty; - _Text.Font.Height = th; - _Text.Z = tz; - } - } - private void _DrawFill() { float x = X - _Width / 2; // most left position @@ -351,37 +269,87 @@ namespace VocaluxeLib.Menu } } - private void _DrawJump() + private void _DrawZoomedNote(CBaseNote zoomNote, int endBeat) + { + float diff = endBeat - zoomNote.StartBeat; + if (diff <= 0f) + diff = 1f; + + float p = 1f - (_CurrentBeat - zoomNote.StartBeat) / diff; + if (p < 0) + p = 0; + + float ty = _Text.Y; + float th = _Text.Font.Height; + float tz = _Text.Z; + + SRectF normalRect = _Text.Rect; + _Text.Font.Height *= 1f + p * 0.4f; + _Text.X -= (_Text.Rect.W - normalRect.W) / 2f; + _Text.Y -= (_Text.Rect.H - normalRect.H) / 2f; + _Text.Z -= 0.1f; + _Text.Color = _ColorProcessed; + + + _Text.Draw(); + + _Text.Y = ty; + _Text.Font.Height = th; + _Text.Z = tz; + } + + private void _DrawJumpingNode(CBaseNote jumpNote) + { + _Text.Color = _ColorProcessed; + + int diff = jumpNote.Duration; + if (diff <= 0) + diff = 1; + + float p = 1f - (_CurrentBeat - jumpNote.StartBeat) / diff; + + if (p < 0.001) + _Text.Draw(); + else + { + float y = _Text.Y; + _Text.Y -= _Text.Font.Height * 0.1f * p; + _Text.Draw(); + _Text.Y = y; + } + } + + private void _DrawZoomOrJump() { float x = X - _Width / 2; // most left position - //find last active note int lastNote = _Line.FindPreviousNote((int)_CurrentBeat); - - int jumpNote = -1; - float jumpx = 0f; + CSongNote highlightNote = null; + int hEndBeat = 0; + float hX = 0; for (int note = 0; note < _Line.Notes.Length; note++) { _Text.X = x; - _SetText(_Line.Notes[note]); + CSongNote curNote = _Line.Notes[note]; + _SetText(curNote); - if (_CurrentBeat >= _Line.Notes[note].StartBeat) + if (_CurrentBeat >= curNote.StartBeat) { - int curEndBeat = _Line.Notes[note].EndBeat; + int curEndBeat = curNote.EndBeat; if (note < _Line.Notes.Length - 1) curEndBeat = _Line.Notes[note + 1].StartBeat - 1; if (_CurrentBeat <= curEndBeat) { - jumpNote = note; - jumpx = _Text.X; + highlightNote = curNote; + hEndBeat = curEndBeat; + hX = x; } else { // already passed - _Text.Color = note == lastNote ? _ColorProcessed : _Color; - + _Text.Color = lastNote == note ? _ColorProcessed : _Color; _Text.Draw(); } } @@ -395,28 +363,15 @@ namespace VocaluxeLib.Menu x += _Text.Rect.W; } - if (jumpNote < 0) + // Draw the highlighted note after all others because we want it to be above those! (transparency won't work well otherwhise) + if (highlightNote == null) return; - - _Text.X = jumpx; - _Text.Color = _ColorProcessed; - _SetText(_Line.Notes[jumpNote]); - - int diff = _Line.Notes[jumpNote].EndBeat - _Line.Notes[jumpNote].StartBeat; - if (diff <= 0) - diff = 1; - - float p = 1f - (_CurrentBeat - _Line.Notes[jumpNote].StartBeat) / diff; - - if (Math.Abs(p) < float.Epsilon) - _Text.Draw(); + _SetText(highlightNote); + _Text.X = hX; + if (LyricStyle == ELyricStyle.Jump) + _DrawJumpingNode(highlightNote); else - { - float y = _Text.Y; - _Text.Y -= _Text.Font.Height * 0.1f * p; - _Text.Draw(); - _Text.Y = y; - } + _DrawZoomedNote(highlightNote, hEndBeat); } #endregion draw diff --git a/VocaluxeLib/Menu/CMenu.cs b/VocaluxeLib/Menu/CMenu.cs index dfc66cce..7bb87d13 100644 --- a/VocaluxeLib/Menu/CMenu.cs +++ b/VocaluxeLib/Menu/CMenu.cs @@ -137,6 +137,26 @@ namespace VocaluxeLib.Menu } } + private class CLoadThemeErrorHandler : CXmlDeserializer.CXmlDefaultErrorHandler + { + private static readonly string[] _AllowedMissing = new string[] + { + "Backgrounds", "Statics", "Texts", "Buttons", "SongMenus", "Lyrics", "SelectSlides", "SingNotes", + "NameSelections", "Equalizers", "Playlists", "ParticleEffects", "ScreenSettings" + }; + + public override void HandleError(CXmlException e) + { + CXmlMissingElementException missingEx = e as CXmlMissingElementException; + if (missingEx != null) + { + if (_AllowedMissing.Contains(missingEx.Field.Name)) + return; + } + base.HandleError(e); + } + } + public virtual void LoadTheme(string xmlPath) { if (CBase.Config.GetLoadOldThemeFiles()) @@ -149,26 +169,10 @@ namespace VocaluxeLib.Menu string file = Path.Combine(xmlPath, ThemeName + ".xml"); - Theme.Informations = new SScreenInformation(); - Theme.Backgrounds = new List(); - Theme.Statics = new List(); - Theme.Texts = new List(); - Theme.Buttons = new List(); - Theme.SongMenus = new List(); - Theme.Lyrics = new List(); - Theme.SelectSlides = new List(); - Theme.SingNotes = new List(); - Theme.NameSelections = new List(); - Theme.Equalizers = new List(); - Theme.Playlists = new List(); - Theme.ParticleEffects = new List(); - Theme.ScreenSettings = new List(); - try { - TextReader textReader = new StreamReader(file); - XmlSerializer deserializer = new XmlSerializer(typeof(SThemeScreen)); - Theme = (SThemeScreen)deserializer.Deserialize(textReader); + CXmlDeserializer deserializer = new CXmlDeserializer(new CLoadThemeErrorHandler()); + Theme = deserializer.Deserialize(file); foreach (SThemeBackground bg in Theme.Backgrounds) _AddBackground(new CBackground(bg, PartyModeID), bg.Name); @@ -227,6 +231,10 @@ namespace VocaluxeLib.Menu { CBase.Log.LogError("Error while reading " + ThemeName + ".xml", true, true); } + catch (CXmlException e) + { + CBase.Log.LogError("Error while reading " + ThemeName + ".xml: " + e, true, true); + } catch (Exception e) { CBase.Log.LogError(e.Message + e.StackTrace, true, true); @@ -308,12 +316,8 @@ namespace VocaluxeLib.Menu try { - TextWriter textWriter = new StreamWriter(Path.Combine(ThemePath, ThemeName + ".xml")); - - XmlSerializer serializer = new XmlSerializer(typeof(SThemeScreen)); - serializer.Serialize(textWriter, Theme); - - textWriter.Close(); + CXmlSerializer serializer = new CXmlSerializer(); + serializer.Serialize(Path.Combine(ThemePath, ThemeName + ".xml"), Theme); } catch (Exception e) { diff --git a/VocaluxeLib/Menu/CMenuPartyNameSelection.cs b/VocaluxeLib/Menu/CMenuPartyNameSelection.cs index 6e3d1090..423d89e8 100644 --- a/VocaluxeLib/Menu/CMenuPartyNameSelection.cs +++ b/VocaluxeLib/Menu/CMenuPartyNameSelection.cs @@ -29,8 +29,10 @@ namespace VocaluxeLib.Menu get { for (int team = 0; team < _NumTeams; team++) + { if (_TeamList[team].Count < _NumPlayerTeams[team]) return false; + } return true; } } @@ -147,7 +149,7 @@ namespace VocaluxeLib.Menu { if (!_ChangePlayerNumDynamic && _TeamList[_CurrentTeam].Count == _NumPlayerTeams[_CurrentTeam]) resetSelection = true; - else if (_TeamList[_CurrentTeam].Count == _PartyMode.GetMaxPlayerPerTeam()) + else if (_TeamList[_CurrentTeam].Count == _PartyMode.MaxPlayersPerTeam) resetSelection = true; } else if (!_SelectingFast) @@ -344,13 +346,13 @@ namespace VocaluxeLib.Menu if (numPressed > 0) { - if (_ChangeTeamNumDynamic && numPressed < _PartyMode.GetMaxTeams() && numPressed > _SelectSlides[_SelectSlideTeams].NumValues) + if (_ChangeTeamNumDynamic && numPressed < _PartyMode.MaxTeams && numPressed > _SelectSlides[_SelectSlideTeams].NumValues) { - while (numPressed < _PartyMode.GetMaxTeams()) + while (numPressed < _PartyMode.MaxTeams) IncreaseTeamNum(); } if (numPressed <= _SelectSlides[_SelectSlideTeams].NumValues) - _SelectSlides[_SelectSlideTeams].SetSelectionByValueIndex(numPressed - 1); + _SelectSlides[_SelectSlideTeams].SelectedTag = numPressed; } } if (_SelectingFastPlayerNr > 0 && _SelectingFastPlayerNr <= _NumPlayerTeams[_CurrentTeam]) @@ -433,7 +435,7 @@ namespace VocaluxeLib.Menu if (!_ChangePlayerNumDynamic && _TeamList[_CurrentTeam].Count == _NumPlayerTeams[_CurrentTeam]) stopSelectingFast = true; - else if (_TeamList[_CurrentTeam].Count == _PartyMode.GetMaxPlayerPerTeam()) + else if (_TeamList[_CurrentTeam].Count == _PartyMode.MaxPlayersPerTeam) stopSelectingFast = true; } else @@ -488,7 +490,7 @@ namespace VocaluxeLib.Menu else if (mouseEvent.RB) { bool exit = true; - if (_SelectSlides[_SelectSlidePlayer].Selected && _TeamList[_CurrentTeam].Count > 0) + if (_SelectSlides[_SelectSlidePlayer].Selected && _TeamList[_CurrentTeam].Count > _SelectSlides[_SelectSlidePlayer].Selection) { int currentSelection = _SelectSlides[_SelectSlidePlayer].Selection; int id = _TeamList[_CurrentTeam][currentSelection]; @@ -505,7 +507,7 @@ namespace VocaluxeLib.Menu { if (!_ChangePlayerNumDynamic && _TeamList[_CurrentTeam].Count == _NumPlayerTeams[_CurrentTeam]) stopSelectingFast = true; - else if (_TeamList[_CurrentTeam].Count == _PartyMode.GetMaxPlayerPerTeam()) + else if (_TeamList[_CurrentTeam].Count == _PartyMode.MaxPlayersPerTeam) stopSelectingFast = true; } else if (mouseEvent.MB) @@ -539,8 +541,8 @@ namespace VocaluxeLib.Menu public override void LoadTheme(string xmlPath) { base.LoadTheme(xmlPath); - _SelectSlides[_SelectSlidePlayer].WithTextures = true; - _SelectSlides[_SelectSlidePlayer].SelectionByHover = true; + _SelectSlides[_SelectSlidePlayer].DrawTextures = true; + _SelectSlides[_SelectSlidePlayer].SelectByHovering = true; _AddStatic(_ChooseAvatarStatic); } @@ -571,7 +573,7 @@ namespace VocaluxeLib.Menu if (!_AllowChangeTeamNum) return; - if (_NumTeams + 1 <= _PartyMode.GetMaxTeams()) + if (_NumTeams + 1 <= _PartyMode.MaxTeams) { _NumTeams++; int[] numPlayerTeams = _NumPlayerTeams; @@ -600,7 +602,7 @@ namespace VocaluxeLib.Menu if (!_AllowChangeTeamNum) return; - if (_NumTeams - 1 >= _PartyMode.GetMinTeams()) + if (_NumTeams - 1 >= _PartyMode.MinTeams) _NumTeams--; _UpdateButtonState(); } @@ -611,7 +613,7 @@ namespace VocaluxeLib.Menu return; if (_NumPlayerTeams.Length > team) { - if (_NumPlayerTeams[team] + 1 <= _PartyMode.GetMaxPlayerPerTeam()) + if (_NumPlayerTeams[team] + 1 <= _PartyMode.MaxPlayersPerTeam) _NumPlayerTeams[team]++; _UpdatePlayerSlide(); } @@ -624,7 +626,7 @@ namespace VocaluxeLib.Menu return; if (_NumPlayerTeams.Length > team) { - if (_NumPlayerTeams[team] - 1 >= _PartyMode.GetMinPlayerPerTeam()) + if (_NumPlayerTeams[team] - 1 >= _PartyMode.MinPlayersPerTeam) _NumPlayerTeams[team]--; if (_TeamList[team].Count > _NumPlayerTeams[team]) _RemovePlayerByIndex(team, _NumPlayerTeams[team] - 1); @@ -684,7 +686,7 @@ namespace VocaluxeLib.Menu _SelectSlides[_SelectSlidePlayer].AddValue("", _NameSelections[_NameSelection].TextureEmptyTile); if (selection >= _TeamList[_CurrentTeam].Count) selection = _TeamList[_CurrentTeam].Count - 1; - _SelectSlides[_SelectSlidePlayer].SetSelectionByValueIndex(selection); + _SelectSlides[_SelectSlidePlayer].Selection = selection; } private void _UpdateTeamSlide() @@ -692,25 +694,25 @@ namespace VocaluxeLib.Menu _SelectSlides[_SelectSlideTeams].Visible = _Teams; _SelectSlides[_SelectSlideTeams].Clear(); for (int i = 1; i <= _NumTeams; i++) - _SelectSlides[_SelectSlideTeams].AddValue("Team " + i); + _SelectSlides[_SelectSlideTeams].AddValue("Team " + i, null, i); } private void _UpdateButtonVisibility() { - _Buttons[_ButtonIncreaseTeams].Visible = _AllowChangePlayerNum && _Teams && _PartyMode.GetMinTeams() != _PartyMode.GetMaxTeams(); - _Buttons[_ButtonDecreaseTeams].Visible = _AllowChangePlayerNum && _Teams && _PartyMode.GetMinTeams() != _PartyMode.GetMaxTeams(); + _Buttons[_ButtonIncreaseTeams].Visible = _AllowChangePlayerNum && _Teams && _PartyMode.MinTeams != _PartyMode.MaxTeams; + _Buttons[_ButtonDecreaseTeams].Visible = _AllowChangePlayerNum && _Teams && _PartyMode.MinTeams != _PartyMode.MaxTeams; _Buttons[_ButtonIncreasePlayer].Visible = _AllowChangePlayerNum; _Buttons[_ButtonDecreasePlayer].Visible = _AllowChangePlayerNum; } private void _UpdateButtonState() { - _Buttons[_ButtonIncreaseTeams].Selectable = _NumTeams < _PartyMode.GetMaxTeams(); - _Buttons[_ButtonDecreaseTeams].Selectable = _NumTeams > _PartyMode.GetMinTeams(); + _Buttons[_ButtonIncreaseTeams].Selectable = _NumTeams < _PartyMode.MaxTeams; + _Buttons[_ButtonDecreaseTeams].Selectable = _NumTeams > _PartyMode.MinTeams; if (_NumPlayerTeams != null && _NumPlayerTeams.Length > _CurrentTeam) { - _Buttons[_ButtonIncreasePlayer].Selectable = _NumPlayerTeams[_CurrentTeam] < _PartyMode.GetMaxPlayerPerTeam(); - _Buttons[_ButtonDecreasePlayer].Selectable = _NumPlayerTeams[_CurrentTeam] > _PartyMode.GetMinPlayerPerTeam(); + _Buttons[_ButtonIncreasePlayer].Selectable = _NumPlayerTeams[_CurrentTeam] < _PartyMode.MaxPlayersPerTeam; + _Buttons[_ButtonDecreasePlayer].Selectable = _NumPlayerTeams[_CurrentTeam] > _PartyMode.MinPlayersPerTeam; } else { @@ -723,7 +725,7 @@ namespace VocaluxeLib.Menu { if (_NumPlayerTeams[team] == _TeamList[team].Count && !_ChangePlayerNumDynamic) return; - if (_NumPlayerTeams[team] == _PartyMode.GetMaxPlayerPerTeam()) + if (_NumPlayerTeams[team] == _PartyMode.MaxPlayersPerTeam) return; _NameSelections[_NameSelection].UseProfile(profileID); diff --git a/VocaluxeLib/Menu/CObjectInteractions.cs b/VocaluxeLib/Menu/CObjectInteractions.cs index 0520e451..e7623787 100644 --- a/VocaluxeLib/Menu/CObjectInteractions.cs +++ b/VocaluxeLib/Menu/CObjectInteractions.cs @@ -91,6 +91,15 @@ namespace VocaluxeLib.Menu private void _SetSelected(int newSelection) { IMenuElement el = _GetElement(_Selection); + if (newSelection == _Selection) + { + // Don't change current selection + if (el == null) + _Selection = -1; + else if (!el.Selected) + el.Selected = true; + return; + } if (el != null) el.Selected = false; _Selection = newSelection; diff --git a/VocaluxeLib/Menu/CPlaylist.cs b/VocaluxeLib/Menu/CPlaylist.cs index 1280c513..0b39d443 100644 --- a/VocaluxeLib/Menu/CPlaylist.cs +++ b/VocaluxeLib/Menu/CPlaylist.cs @@ -169,15 +169,16 @@ namespace VocaluxeLib.Menu private readonly CStatic _StaticPlaylistHeader; private readonly CStatic _StaticPlaylistFooter; - private bool _Selected; public SRectF Rect { get { return MaxRect; } } public SRectF MaxRect { get; set; } + private bool _Selectable = true; public bool Selectable { - get { return Visible; } + get { return Visible && _Selectable; } + set { _Selectable = value; } } public bool Visible { @@ -185,6 +186,7 @@ namespace VocaluxeLib.Menu set { _Active = value; } } public bool Highlighted { get; set; } + private bool _Selected; public bool Selected { get { return _Selected; } @@ -204,6 +206,8 @@ namespace VocaluxeLib.Menu _ChangeOrderElement = null; _EditMode = EEditMode.None; } + else if (_CurrentPlaylistElement == -1 && _PlaylistElements.Count > 0) + _SelectElement(_PlaylistElements[0].SelectSlide); } } @@ -420,7 +424,7 @@ namespace VocaluxeLib.Menu public override bool HandleInput(SKeyEvent keyEvent) { if (!Selected) - return true; + return false; //Active EditMode ignores other input! if (_EditMode == EEditMode.PlaylistName) { @@ -446,6 +450,8 @@ namespace VocaluxeLib.Menu if (!String.IsNullOrEmpty(_ButtonPlaylistName.Text.Text)) _ButtonPlaylistName.Text.Text = _ButtonPlaylistName.Text.Text.Remove(_ButtonPlaylistName.Text.Text.Length - 1); break; + default: + return false; } } return true; @@ -453,10 +459,10 @@ namespace VocaluxeLib.Menu if (_CurrentPlaylistElement == -1 || _PlaylistElementContents.Count == 0) { //no song is selected - base.HandleInput(keyEvent); + bool handled = base.HandleInput(keyEvent); _CurrentPlaylistElement = _GetSelectedElementNr(); - if (_CurrentPlaylistElement != -1) + if (_CurrentPlaylistElement != -1 || handled) return true; } else if (_CurrentPlaylistElement != -1) @@ -669,6 +675,8 @@ namespace VocaluxeLib.Menu UpdatePlaylist(); } break; + default: + return false; } return true; } @@ -720,6 +728,8 @@ namespace VocaluxeLib.Menu case Keys.PageUp: _SetSelectionToFirstEntry(); break; + default: + return false; } return true; } @@ -1037,6 +1047,7 @@ namespace VocaluxeLib.Menu Cover = new CStatic(_Theme.StaticCover, _PartyModeID) }; + en.Cover.LoadSkin(); en.Cover.Y += Rect.Y + (i * _Theme.EntryHeight); en.Cover.X += Rect.X; @@ -1045,6 +1056,7 @@ namespace VocaluxeLib.Menu en.Text1.Y += Rect.Y + (i * _Theme.EntryHeight); en.SelectSlide = new CSelectSlide(_SelectSlideGameMode); + en.SelectSlide.LoadSkin(); en.SelectSlide.X += Rect.X; en.SelectSlide.Y += Rect.Y + (i * _Theme.EntryHeight); @@ -1145,12 +1157,9 @@ namespace VocaluxeLib.Menu string t1 = CBase.Language.Translate(_Text1.Text).Replace("%a", song.Artist).Replace("%t", song.Title); _PlaylistElements[i].Text1.Text = /*(Offset + i + 1) + ") " + */ t1; //TODO: Add text field for the number _PlaylistElements[i].SelectSlide.Clear(); - for (int g = 0; g < pec.Modes.Count; g++) - { - _PlaylistElements[i].SelectSlide.AddValue(Enum.GetName(typeof(EGameMode), pec.Modes[g])); - if (pec.Modes[g] == pec.Mode) - _PlaylistElements[i].SelectSlide.SetSelectionByValueIndex(g); - } + foreach (EGameMode gm in pec.Modes) + _PlaylistElements[i].SelectSlide.AddValue(Enum.GetName(typeof(EGameMode), gm), null, (int)gm); + _PlaylistElements[i].SelectSlide.SelectedTag = (int)pec.Mode; } else { diff --git a/VocaluxeLib/Menu/CSelectSlide.cs b/VocaluxeLib/Menu/CSelectSlide.cs index f5a876b0..64f39b08 100644 --- a/VocaluxeLib/Menu/CSelectSlide.cs +++ b/VocaluxeLib/Menu/CSelectSlide.cs @@ -17,6 +17,8 @@ using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; using System.Drawing; using System.Xml.Serialization; using VocaluxeLib.Draw; @@ -51,8 +53,8 @@ namespace VocaluxeLib.Menu public SThemeColor TextSelColor; public float TextH; - public float TextRelativeX; - public float TextRelativeY; + [DefaultValue(0.0f)] public float TextRelativeX; + [DefaultValue(0.0f)] public float TextRelativeY; public float TextMaxW; public string TextFont; @@ -61,8 +63,23 @@ namespace VocaluxeLib.Menu public int NumVisible; } - public sealed class CSelectSlide : CMenuElementBase, IMenuElement, ICloneable, IThemeable + public sealed class CSelectSlide : CMenuElementBase, IMenuElement, IThemeable { + private struct SValue + { + public string Text; + public int TranslationId; + public int Tag; + public CTextureRef Texture; + } + + private class CElement + { + public CText Text; + public CStatic Img; + public SRectF Bounds; + } + private readonly int _PartyModeID; private SThemeSelectSlide _Theme; @@ -138,52 +155,52 @@ namespace VocaluxeLib.Menu } } } - public bool ValueSelected + public bool IsValueSelected { get { return Selected && !_ArrowLeftSelected && !_ArrowRightSelected; } } - public bool SelectionByHover; - private bool _ArrowLeftSelected; private bool _ArrowRightSelected; - private readonly List _ValueNames; - private readonly List _ValuePartyModeIDs; - private readonly List _Textures; - private readonly List _ValueIndexes; - - private readonly List _ValueBounds = new List(); - - public bool WithTextures; + public bool SelectByHovering; + public bool DrawTextures; private int _Selection = -1; public int Selection { get { return _Selection; } - set { _Selection = value.Clamp(0, _ValueNames.Count - 1, false); } - } - - public string Value - { - get { return (_Selection >= 0 && _Selection < _ValueNames.Count) ? _ValueNames[_Selection] : null; } - } - - public int ValueIndex - { - get + set { - if (_Selection >= 0 && _ValueIndexes.Count > _Selection) - return _ValueIndexes[_Selection]; - return -1; + value = value.Clamp(0, _Values.Count - 1, false); + if (value == _Selection) + return; + _Selection = value; + _Invalidate(); } } + public string SelectedValue + { + get { return _Selection >= 0 ? _Values[_Selection].Text : null; } + set { Selection = _Values.FindIndex(val => val.Text == value); } + } + + public int SelectedTag + { + get { return _Selection >= 0 ? _Values[_Selection].Tag : -1; } + set { Selection = _Values.FindIndex(val => val.Tag == value); } + } + public int NumValues { - get { return _ValueNames.Count; } + get { return _Values.Count; } } + private readonly List _Values = new List(); + private readonly List _VisibleElements = new List(); + private bool _NeedsRevalidate = true; + private int _NumVisible = -1; private CTextureRef _Texture; private CTextureRef _TextureArrowLeft; @@ -197,10 +214,11 @@ namespace VocaluxeLib.Menu get { return _NumVisible; } set { - if (value > 0) - _NumVisible = value; + if (value <= 0 || value == _NumVisible) + return; + _NumVisible = value; - _ValueBounds.Clear(); + _Invalidate(); } } @@ -210,11 +228,6 @@ namespace VocaluxeLib.Menu ThemeLoaded = false; _TextH = 1f; _MaxW = 0f; - - _Textures = new List(); - _ValueIndexes = new List(); - _ValueNames = new List(); - _ValuePartyModeIDs = new List(); } public CSelectSlide(CSelectSlide slide) @@ -241,15 +254,11 @@ namespace VocaluxeLib.Menu _TextRelativeY = slide._TextRelativeY; _MaxW = slide._MaxW; - _Textures = new List(slide._Textures); - _ValueIndexes = new List(slide._ValueIndexes); - _ValueNames = new List(slide._ValueNames); - _ValueBounds = new List(slide._ValueBounds); - _ValuePartyModeIDs = new List(slide._ValuePartyModeIDs); + _Values.AddRange(slide._Values); _Selection = slide._Selection; _NumVisible = slide._NumVisible; - WithTextures = slide.WithTextures; + DrawTextures = slide.DrawTextures; Visible = slide.Visible; } @@ -258,11 +267,6 @@ namespace VocaluxeLib.Menu _PartyModeID = partyModeID; _Theme = theme; - _Textures = new List(); - _ValueIndexes = new List(); - _ValueNames = new List(); - _ValuePartyModeIDs = new List(); - ThemeLoaded = true; } @@ -382,58 +386,73 @@ namespace VocaluxeLib.Menu return ThemeLoaded; } - public void AddValue(string value) + private void _Invalidate() { - AddValue(value, _PartyModeID); + _NeedsRevalidate = true; } - public void AddValue(string value, int partyModeID) + /// + /// Adds an integer to the slide setting its tag to the value and its text to the text representation of the tag + /// + /// Value to add + public void AddValue(int tag) { - AddValue(value, null, _ValueIndexes.Count, partyModeID); + AddValue(tag.ToString(), null, tag); } - public void AddValue(string value, CTextureRef texture) + /// + /// Adds an entry to the slide. + /// + /// Label to show + /// Texture to show + /// User value (e.g. id of entry) + public void AddValue(string text, CTextureRef texture = null, int tag = 0) { - AddValue(value, texture, _ValueIndexes.Count, _PartyModeID); + AddValue(text, _PartyModeID, texture, tag); } - private void _AddValue(string value, CTextureRef texture, int valueIndex) + /// + /// Adds an entry to the slide. + /// + /// Label to show + /// Translation id to use for the text + /// Texture to show + /// User value (e.g. id of entry) + public void AddValue(string text, int translationId, CTextureRef texture = null, int tag = 0) { - AddValue(value, texture, valueIndex, _PartyModeID); - } + SValue value = new SValue {Text = text, TranslationId = translationId, Tag = tag, Texture = texture}; - public void AddValue(string value, CTextureRef texture, int valueIndex, int partyModeID) - { - _ValueNames.Add(value); - _Textures.Add(texture); - _ValueIndexes.Add(valueIndex); - _ValuePartyModeIDs.Add(partyModeID); + _Values.Add(value); - if (Selection == -1) + if (Selection < 0) Selection = 0; - _ValueBounds.Clear(); + _Invalidate(); } public void AddValues(IEnumerable values) { foreach (string value in values) - _AddValue(value, null, _PartyModeID); - - _ValueBounds.Clear(); + AddValue(value); } public void AddValues(string[] values, CTextureRef[] textures) { - if (values.Length != textures.Length) - return; + Debug.Assert(values.Length == textures.Length); for (int i = 0; i < values.Length; i++) AddValue(values[i], textures[i]); - if (Selection == -1) - Selection = 0; + } - _ValueBounds.Clear(); + public void RemoveValue(string text) + { + int idx = _Values.FindIndex(val => val.Text == text); + if (idx < 0) + return; + _Values.RemoveAt(idx); + if (Selection >= idx) + Selection--; + _Invalidate(); } public void SetValues(int selection) @@ -447,31 +466,20 @@ namespace VocaluxeLib.Menu RenameValue(Selection, newName); } - public void RenameValue(int selection, string newName, CTextureRef newTexture = null) + public void RenameValue(int index, string newName, CTextureRef newTexture = null) { - if (selection < 0 && selection >= _ValueNames.Count) + if (index < 0 && index >= _Values.Count) return; - _ValueNames[selection] = newName; - _Textures[selection] = newTexture; - } - - public bool SetSelectionByValueIndex(int valueIndex) - { - for (int i = 0; i < _ValueIndexes.Count; i++) - { - if (_ValueIndexes[i] == valueIndex) - { - Selection = i; - return true; - } - } - return false; + SValue value = _Values[index]; + value.Text = newName; + value.Texture = newTexture; + _Values[index] = value; } public bool SelectNextValue() { - if (Selection < _ValueNames.Count - 1) + if (Selection < _Values.Count - 1) { Selection++; return true; @@ -491,50 +499,46 @@ namespace VocaluxeLib.Menu public void SelectFirstValue() { - if (_ValueNames.Count > 0) + if (_Values.Count > 0) Selection = 0; } public void SelectLastValue() { - if (_ValueNames.Count > 0) - Selection = _ValueNames.Count - 1; + if (_Values.Count > 0) + Selection = _Values.Count - 1; } public void Clear() { + _Values.Clear(); _Selection = -1; - _ValueNames.Clear(); - _Textures.Clear(); - _ValueBounds.Clear(); - _ValueIndexes.Clear(); + _Invalidate(); + } + + private int _GetCurOffset() + { + int offset = _Selection - _NumVisible / 2; + return offset.Clamp(0, _Values.Count - _NumVisible, true); + } + + private void _SelectAtPos(int x, int y) + { + if (_NeedsRevalidate) + _Revalidate(); + int index = _VisibleElements.FindIndex(el => CHelper.IsInBounds(el.Bounds, x, y)); + if (index < 0) + return; + Selection = index + _GetCurOffset(); } public void ProcessMouseMove(int x, int y) { _ArrowLeftSelected = CHelper.IsInBounds(RectArrowLeft, x, y) && _Selection > 0; - _ArrowRightSelected = CHelper.IsInBounds(RectArrowRight, x, y) && _Selection < _ValueNames.Count - 1; + _ArrowRightSelected = CHelper.IsInBounds(RectArrowRight, x, y) && _Selection < _Values.Count - 1; - if (SelectionByHover) - { - for (int i = 0; i < _ValueBounds.Count; i++) - { - if (CHelper.IsInBounds(_ValueBounds[i], x, y)) - { - int offset = _Selection - _NumVisible / 2; - - if (_ValueNames.Count - _NumVisible - offset < 0) - offset = _ValueNames.Count - _NumVisible; - - if (offset < 0) - offset = 0; - - Selection = i + offset; - _ValueBounds.Clear(); - break; - } - } - } + if (SelectByHovering) + _SelectAtPos(x, y); } public void ProcessMouseLBClick(int x, int y) @@ -547,21 +551,78 @@ namespace VocaluxeLib.Menu if (_ArrowRightSelected) SelectNextValue(); - for (int i = 0; i < _ValueBounds.Count; i++) + _SelectAtPos(x, y); + } + + private void _Revalidate() + { + if (!_NeedsRevalidate) + return; + _NeedsRevalidate = false; + int numvis = Math.Min(_NumVisible, _Values.Count); + if (numvis != _VisibleElements.Count) { - if (CHelper.IsInBounds(_ValueBounds[i], x, y)) + _VisibleElements.Clear(); + for (int i = 0; i < numvis; i++) { - int offset = _Selection - _NumVisible / 2; + var el = new CElement + { + Text = new CText(0, 0, 0, _TextH, _MaxW, EAlignment.Center, _Theme.TextStyle, _Theme.TextFont, _TextColor, "T", _PartyModeID), + Img = new CStatic(_PartyModeID) + }; + _VisibleElements.Add(el); + } + } + if (numvis == 0) + return; - if (_ValueNames.Count - _NumVisible - offset < 0) - offset = _ValueNames.Count - _NumVisible; + float elWidth = (Rect.W - _TextRelativeX * 2) / numvis; + //Center point of the first entry + float xStart = Rect.X + _TextRelativeX + elWidth / 2f; - if (offset < 0) - offset = 0; + int offset = _GetCurOffset(); - Selection = i + offset; - _ValueBounds.Clear(); - break; + for (int i = 0; i < numvis; i++) + { + CText text = _VisibleElements[i].Text; + RectangleF textBounds; + float curX = xStart + elWidth * i; + if (String.IsNullOrEmpty(_Values[i + offset].Text)) + { + text.Visible = false; + textBounds = new RectangleF(); + } + else + { + text.Visible = true; + text.Text = _Values[i + offset].Text; + text.TranslationID = _Values[i + offset].TranslationId; + text.Color = (i + offset == Selection) ? _SelTextColor : _TextColor; + textBounds = CBase.Fonts.GetTextBounds(text); + text.X = curX; + text.Z = Rect.Z; + } + + CStatic img = _VisibleElements[i].Img; + if (!DrawTextures || _Values[i + offset].Texture == null) + { + if (text.Visible) + text.Y = Rect.Y + (Rect.H - textBounds.Height) / 2 - _TextRelativeY; + img.Visible = false; + _VisibleElements[i].Bounds = new SRectF(text.X - textBounds.Width / 2f, text.Y, textBounds.Width, textBounds.Height, Rect.Z); + } + else + { + text.Y = (int)(Rect.Y + Rect.H - textBounds.Height - _TextRelativeY); + img.Texture = _Values[i + offset].Texture; + float alpha = (i + offset == _Selection) ? 1f : 0.35f; + img.Color = new SColorF(1f, 1f, 1f, alpha); + float size = Rect.H - textBounds.Height - 2 * _TextRelativeY; + if (size > elWidth) + size = elWidth; + var imgRect = new SRectF(curX - size / 2, Rect.Y + _TextRelativeY, size, size, Rect.Z); + img.MaxRect = imgRect; + _VisibleElements[i].Bounds = imgRect; } } } @@ -584,7 +645,7 @@ namespace VocaluxeLib.Menu CBase.Drawing.DrawTexture(_TextureArrowLeft, RectArrowLeft, _ColorArrow); } - if (_Selection < _ValueNames.Count - 1 || CBase.Settings.GetProgramState() == EProgramState.EditTheme) + if (_Selection < _Values.Count - 1 || CBase.Settings.GetProgramState() == EProgramState.EditTheme) { if (_ArrowRightSelected) CBase.Drawing.DrawTexture(_SelTextureArrowRight, RectArrowRight, _SelColorArrow); @@ -592,63 +653,12 @@ namespace VocaluxeLib.Menu CBase.Drawing.DrawTexture(_TextureArrowRight, RectArrowRight, _ColorArrow); } - if (_NumVisible < 1 || _ValueNames.Count == 0) - return; - - float x = Rect.X + (Rect.W - _TextRelativeX) * 0.1f; - float dx = (Rect.W - _TextRelativeX) * 0.8f / _NumVisible; - //float y = Rect.Y + (Rect.H - TextH); - int offset = _Selection - _NumVisible / 2; - - if (_ValueNames.Count - _NumVisible - offset < 0) - offset = _ValueNames.Count - _NumVisible; - - if (offset < 0) - offset = 0; - - - int numvis = _NumVisible; - if (_ValueNames.Count < numvis) - numvis = _ValueNames.Count; - - _ValueBounds.Clear(); - for (int i = 0; i < numvis; i++) + if (_NeedsRevalidate) + _Revalidate(); + foreach (CElement element in _VisibleElements) { - var text = new CText(0, 0, 0, _TextH, _MaxW, EAlignment.Center, _Theme.TextStyle, _Theme.TextFont, _TextColor, "T", - _ValuePartyModeIDs[i + offset]); - - if (_ValueNames[i + offset] != "") - text.Text = _ValueNames[i + offset]; - else - text.Visible = false; - - var alpha = new SColorF(1f, 1f, 1f, 0.35f); - if (i + offset == _Selection) - { - text.Color = _SelTextColor; - alpha = new SColorF(1f, 1f, 1f, 1f); - } - - RectangleF bounds = CBase.Fonts.GetTextBounds(text); - text.X = (x + dx / 2f + dx * i) + _TextRelativeX; - - if (!WithTextures) - text.Y = (int)((Rect.Y + (Rect.H - bounds.Height) / 2) + _TextRelativeY); - else - text.Y = (int)((Rect.Y + (Rect.H - bounds.Height)) + _TextRelativeY); - - text.Z = Rect.Z; - text.Draw(); - - if (WithTextures) - { - float dh = text.Y - Rect.Y - Rect.H * 0.1f; - var rect = new SRectF(text.X - dh / 2, Rect.Y + Rect.H * 0.05f, dh, dh, Rect.Z); - CBase.Drawing.DrawTexture(_Textures[i + offset], rect, alpha, rect); - _ValueBounds.Add(rect); - } - else - _ValueBounds.Add(new SRectF(text.X - bounds.Width / 2f, text.Y, bounds.Width, bounds.Height, Rect.Z)); + element.Text.Draw(); + element.Img.Draw(); } } @@ -686,6 +696,7 @@ namespace VocaluxeLib.Menu _SelTexture = CBase.Themes.GetSkinTexture(_Theme.SkinSelected, _PartyModeID); _SelTextureArrowLeft = CBase.Themes.GetSkinTexture(_Theme.SkinArrowLeftSelected, _PartyModeID); _SelTextureArrowRight = CBase.Themes.GetSkinTexture(_Theme.SkinArrowRightSelected, _PartyModeID); + _Invalidate(); } public void ReloadSkin() @@ -694,11 +705,6 @@ namespace VocaluxeLib.Menu LoadSkin(); } - public object Clone() - { - return MemberwiseClone(); - } - #region ThemeEdit public void MoveElement(int stepX, int stepY) { diff --git a/VocaluxeLib/Menu/SingNotes/CSingNotes.cs b/VocaluxeLib/Menu/SingNotes/CSingNotes.cs index 4d072af0..71c09fdc 100644 --- a/VocaluxeLib/Menu/SingNotes/CSingNotes.cs +++ b/VocaluxeLib/Menu/SingNotes/CSingNotes.cs @@ -17,6 +17,8 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; using System.Xml.Serialization; using VocaluxeLib.Xml; @@ -56,6 +58,12 @@ namespace VocaluxeLib.Menu.SingNotes public readonly List PlayerNotes = new List(); + private SRectF _Rect; + public override SRectF Rect + { + get { return _Rect; } + } + public bool Selectable { get { return false; } @@ -143,6 +151,16 @@ namespace VocaluxeLib.Menu.SingNotes PlayerNotes.Clear(); for (int p = 0; p < numPlayers; p++) PlayerNotes.Add(new CNoteBars(_PartyModeID, p, _BarPos[p, numPlayers - 1], _Theme)); + if (numPlayers == 0) + _Rect = new SRectF(0, 0, 0, 0, Rect.Z); + else + { + _Rect.X = PlayerNotes.Select(bp => bp.Rect.X).Min(); + _Rect.Y = PlayerNotes.Select(bp => bp.Rect.X).Min(); + _Rect.Right = PlayerNotes.Select(bp => bp.Rect.Right).Max(); + _Rect.Bottom = PlayerNotes.Select(bp => bp.Rect.Bottom).Max(); + _Rect.Z = PlayerNotes.Select(bp => bp.Rect.Z).Average(); + } } public void Draw() @@ -155,6 +173,12 @@ namespace VocaluxeLib.Menu.SingNotes public void LoadSkin() { + Debug.Assert(_Theme.BarPos.Length > 0); + X = _Theme.BarPos.Select(bp => bp.Rect.X).Min(); + Y = _Theme.BarPos.Select(bp => bp.Rect.X).Min(); + W = X - _Theme.BarPos.Select(bp => bp.Rect.Right).Max(); + H = Y - _Theme.BarPos.Select(bp => bp.Rect.Bottom).Max(); + Z = _Theme.BarPos.Select(bp => bp.Rect.Z).Average(); foreach (SBarPosition bp in _Theme.BarPos) { int n = Int32.Parse(bp.Name.Substring(3, 1)) - 1; diff --git a/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs b/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs index d3668346..c0bfb6f3 100644 --- a/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs +++ b/VocaluxeLib/Menu/SongMenu/CSongMenuFramework.cs @@ -121,7 +121,7 @@ namespace VocaluxeLib.Menu.SongMenu else if (value >= CBase.Songs.GetNumCategories()) { value = -1; - CBase.BackgroundMusic.Stop(); + CBase.BackgroundMusic.SetPlayingPreview(false); } _PreviewNrInternal = value; @@ -371,7 +371,7 @@ namespace VocaluxeLib.Menu.SongMenu return; CBase.BackgroundMusic.StopPreview(); - + CBase.Sound.SetGlobalVolume(CBase.Config.GetMusicVolume(EMusicType.Background)); if (playBGagain) CBase.BackgroundMusic.Play(); diff --git a/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs b/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs index 99469947..f74e81f9 100644 --- a/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs +++ b/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs @@ -99,7 +99,7 @@ namespace VocaluxeLib.Menu.SongMenu if (value == base._PreviewNr) { if (!CBase.BackgroundMusic.IsPlaying() && value != -1) - CBase.BackgroundMusic.PlayPreview(); + CBase.BackgroundMusic.Play(); return; } base._PreviewNr = value; diff --git a/VocaluxeLib/PartyModes/CPartyMode.cs b/VocaluxeLib/PartyModes/CPartyMode.cs index 14192af7..5a4d2b14 100644 --- a/VocaluxeLib/PartyModes/CPartyMode.cs +++ b/VocaluxeLib/PartyModes/CPartyMode.cs @@ -16,21 +16,20 @@ #endregion using System.Collections.Generic; +using System.Diagnostics; using VocaluxeLib.Menu; namespace VocaluxeLib.PartyModes { public abstract class CPartyMode : IPartyMode { - private readonly string _Folder; private readonly int _ID; protected SScreenSongOptions _ScreenSongOptions = new SScreenSongOptions {Selection = new SSelectionOptions(), Sorting = new SSortingOptions()}; protected readonly Dictionary _Screens = new Dictionary(); - protected CPartyMode(int id, string folder) + protected CPartyMode(int id) { _ID = id; - _Folder = folder; } #region Implementation @@ -39,7 +38,15 @@ namespace VocaluxeLib.PartyModes get { return _ID; } } - public abstract bool Init(); + public int NumPlayers { get; set; } + public int NumTeams { get; set; } + + public virtual bool Init() + { + Debug.Assert(MinPlayers > 0 && MinPlayers <= MaxPlayers); + Debug.Assert(MinTeams > 0 && MinTeams <= MaxTeams); + return true; + } public void LoadTheme() { @@ -75,61 +82,6 @@ namespace VocaluxeLib.PartyModes entry.Value.SaveTheme(); } - public virtual void UpdateGame() {} - - public abstract IMenu GetStartScreen(); - - public virtual SScreenSongOptions GetScreenSongOptions() - { - return new SScreenSongOptions(); - } - - public virtual void OnSongChange(int songIndex, ref SScreenSongOptions screenSongOptions) {} - - public virtual void OnCategoryChange(int categoryIndex, ref SScreenSongOptions screenSongOptions) {} - - public virtual int GetMaxPlayer() - { - return 6; - } - - public virtual int GetMinPlayer() - { - return 1; - } - - public virtual int GetMaxTeams() - { - return 0; - } - - public virtual int GetMinTeams() - { - return 0; - } - - public virtual int GetMinPlayerPerTeam() - { - return GetMinPlayer(); - } - - public virtual int GetMaxPlayerPerTeam() - { - return GetMaxPlayer(); - } - - public virtual int GetMaxNumRounds() - { - return 1; - } - - public string GetFolder() - { - return _Folder; - } - - public virtual void SetSearchString(string searchString, bool visible) {} - public virtual void JokerUsed(int teamNr) { if (_ScreenSongOptions.Selection.NumJokers == null) @@ -142,8 +94,6 @@ namespace VocaluxeLib.PartyModes _ScreenSongOptions.Selection.NumJokers[teamNr]--; } - public abstract void SongSelected(int songID); - public virtual void FinishedSinging() { CBase.Graphics.FadeTo(EScreen.Score); @@ -159,5 +109,25 @@ namespace VocaluxeLib.PartyModes CBase.Graphics.FadeTo(EScreen.Song); } #endregion Implementation + + #region Abstract members + public abstract int MinMics { get; } + public abstract int MaxMics { get; } + public abstract int MinPlayers { get; } + public abstract int MaxPlayers { get; } + public abstract int MinTeams { get; } + public abstract int MaxTeams { get; } + public abstract int MinPlayersPerTeam { get; } + public abstract int MaxPlayersPerTeam { get; } + + public abstract void UpdateGame(); + public abstract IMenu GetStartScreen(); + public abstract SScreenSongOptions GetScreenSongOptions(); + public abstract void OnSongChange(int songIndex, ref SScreenSongOptions screenSongOptions); + public abstract void OnCategoryChange(int categoryIndex, ref SScreenSongOptions screenSongOptions); + public abstract void SetSearchString(string searchString, bool visible); + + public abstract void SongSelected(int songID); + #endregion Abstract members } } \ No newline at end of file diff --git a/VocaluxeLib/PartyModes/CPartyModeNone.cs b/VocaluxeLib/PartyModes/CPartyModeNormal.cs similarity index 68% rename from VocaluxeLib/PartyModes/CPartyModeNone.cs rename to VocaluxeLib/PartyModes/CPartyModeNormal.cs index c3e3ea6a..a84ecb73 100644 --- a/VocaluxeLib/PartyModes/CPartyModeNone.cs +++ b/VocaluxeLib/PartyModes/CPartyModeNormal.cs @@ -20,10 +20,42 @@ using VocaluxeLib.Menu; namespace VocaluxeLib.PartyModes { - public class CPartyModeNone : CPartyMode + public class CPartyModeNormal : CPartyMode { - //just a dummy for normal game mode - public CPartyModeNone(int id, string folder) : base(id, folder) + public override int MinMics + { + get { return 1; } + } + public override int MaxMics + { + get { return CBase.Config.GetMaxNumMics(); } + } + public override int MinPlayers + { + get { return 1; } + } + public override int MaxPlayers + { + get { return CBase.Settings.GetMaxNumPlayer(); } + } + 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; } + } + + public CPartyModeNormal(int id) : base(id) { _ScreenSongOptions.Selection.RandomOnly = false; _ScreenSongOptions.Selection.PartyMode = false; @@ -42,6 +74,8 @@ namespace VocaluxeLib.PartyModes return true; } + public override void UpdateGame() {} + public override IMenu GetStartScreen() { return CBase.Graphics.GetScreen(EScreen.Names); @@ -60,6 +94,10 @@ namespace VocaluxeLib.PartyModes return _ScreenSongOptions; } + public override void OnSongChange(int songIndex, ref SScreenSongOptions screenSongOptions) {} + + public override void OnCategoryChange(int categoryIndex, ref SScreenSongOptions screenSongOptions) {} + public override void SetSearchString(string searchString, bool visible) { _ScreenSongOptions.Sorting.SearchString = searchString; diff --git a/VocaluxeLib/PartyModes/IPartyMode.cs b/VocaluxeLib/PartyModes/IPartyMode.cs index d432e368..d1aa7e1f 100644 --- a/VocaluxeLib/PartyModes/IPartyMode.cs +++ b/VocaluxeLib/PartyModes/IPartyMode.cs @@ -79,9 +79,24 @@ namespace VocaluxeLib.PartyModes } #endregion Structs - public interface IPartyMode + public interface IPartyModeInfo { int ID { get; } + int MinMics { get; } + int MaxMics { get; } + int MinPlayers { get; } + int MaxPlayers { get; } + int MinTeams { get; } + int MaxTeams { get; } + int MinPlayersPerTeam { get; } + int MaxPlayersPerTeam { get; } + } + + public interface IPartyMode : IPartyModeInfo + { + int NumPlayers { get; set; } + int NumTeams { get; set; } + bool Init(); void LoadTheme(); @@ -99,14 +114,6 @@ namespace VocaluxeLib.PartyModes void OnSongChange(int songIndex, ref SScreenSongOptions screenSongOptions); void OnCategoryChange(int categoryIndex, ref SScreenSongOptions screenSongOptions); - int GetMaxPlayer(); - int GetMinPlayer(); - int GetMaxTeams(); - int GetMinTeams(); - int GetMinPlayerPerTeam(); - int GetMaxPlayerPerTeam(); - int GetMaxNumRounds(); - void SetSearchString(string searchString, bool visible); void JokerUsed(int teamNr); diff --git a/VocaluxeLib/Songs/CLineBase.cs b/VocaluxeLib/Songs/CLineBase.cs index 6c972851..577f732e 100644 --- a/VocaluxeLib/Songs/CLineBase.cs +++ b/VocaluxeLib/Songs/CLineBase.cs @@ -75,10 +75,10 @@ namespace VocaluxeLib.Songs #region Methods /// - /// Find last note with StartBeat + /// Find last note with StartBeat <= beat /// /// - /// Note index of last note with StartBeat or -1 if all notes start after beat + /// Note index of last note with StartBeat <= beat or -1 if all notes start after beat public int FindPreviousNote(int beat) { //If no notes -> No previous note diff --git a/VocaluxeLib/Structs.cs b/VocaluxeLib/Structs.cs index d59163a3..09a1b960 100644 --- a/VocaluxeLib/Structs.cs +++ b/VocaluxeLib/Structs.cs @@ -186,6 +186,7 @@ namespace VocaluxeLib public float Z; [XmlIgnore] public float Rotation; //0..360° + [XmlIgnore] public float Right { get { return X + W; } @@ -195,6 +196,8 @@ namespace VocaluxeLib Debug.Assert(W >= 0); } } + + [XmlIgnore] public float Bottom { get { return Y + H; } @@ -204,10 +207,14 @@ namespace VocaluxeLib Debug.Assert(H >= 0); } } + + [XmlIgnore] public Size SizeI { get { return new Size((int)W, (int)H); } } + + [XmlIgnore] public SizeF Size { get { return new SizeF(W, H); } diff --git a/VocaluxeLib/Utils/Combinatorics/CCombinations.cs b/VocaluxeLib/Utils/Combinatorics/CCombinations.cs new file mode 100644 index 00000000..78e5c0b7 --- /dev/null +++ b/VocaluxeLib/Utils/Combinatorics/CCombinations.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace VocaluxeLib.Utils.Combinatorics +{ + /// + /// Calculates all combinations (without repetition) of a given input sequence
+ /// Example: {A B C}, select 2 --> {A B}, {A C}, {B C} + ///
+ /// Type of the input elements + public class CCombinations : IEnumerable> + { + private readonly List _Values; + private readonly int _NumSelected; + private readonly int _Count; + + /// + /// Construct combinations for the input sequence when selecting numSelected elements
+ /// The values should not contain duplicates as this will result in duplicates in the output + ///
+ /// Input sequence + /// Number of elements to select + public CCombinations(List values, int numSelected) + { + _Values = values; + _NumSelected = numSelected; + // This also acts as a parameter check + _Count = Count(_Values.Count, _NumSelected); + } + + /// + /// Calculates how many combinations are possible when k out of n elements are selected + /// + /// Number of elements + /// Number of selected elements + /// + public static int Count(int n, int k) + { + if (n < 0 || k < 0) + throw new ArgumentException("Parameters must not be negative"); + if (n < k) + return 0; + // Try to optimize because (n k) = (n n-k) + if (n - k < k) + k = n - k; + if (k == 0) // or k == n but both are the same after the optimization above + return 1; + + long result = n; + for (long i = 1; i < k; i++) + { + checked + { + result = result * (n - i) / (i + 1); + } + } + return (int)result; + } + + /// + /// Gets the number of combinations that are generated + /// + /// + public int Count() + { + return _Count; + } + + /// + /// Gets all possible combinations as a list + /// + /// + public List> GetAll() + { + List> result = new List>(Count()); + result.AddRange(this); + return result; + } + + public IEnumerator> GetEnumerator() + { + return new CEnumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + private class CEnumerator : IEnumerator> + { + private readonly int _N; + private readonly int _K; + private readonly CCombinations _Parent; + private int[] _CurSet; + + public CEnumerator(CCombinations parent) + { + _N = parent._Values.Count; + _K = parent._NumSelected; + _Parent = parent; + Debug.Assert(_N >= 0 && _K >= 0); + } + + public void Dispose() {} + + public bool MoveNext() + { + if (_N < _K) + return false; + + if (_CurSet == null) + { + _CurSet = new int[_K]; + for (int i = 0; i < _K; i++) + _CurSet[i] = i; + return true; + } + + // Check if we reached the end + if (_K == 0 || _CurSet[0] == _N - _K) + return false; + // Search for element to increment + int idx = _K - 1; + while (idx > 0 && _CurSet[idx] == _N - _K + idx) + idx--; + _CurSet[idx]++; + // Increment all elements "right" of this to 1+their left neighbour + for (int j = idx; j < _K - 1; j++) + _CurSet[j + 1] = _CurSet[j] + 1; + return true; + } + + public void Reset() + { + _CurSet = null; + } + + public List Current + { + get + { + List result = new List(_K); + result.AddRange(_CurSet.Select(i => _Parent._Values[i])); + return result; + } + } + object IEnumerator.Current + { + get { return Current; } + } + } + } +} \ No newline at end of file diff --git a/VocaluxeLib/Utils/Player/CSongPlayer.cs b/VocaluxeLib/Utils/Player/CSongPlayer.cs index 0b22f47b..ea61b271 100644 --- a/VocaluxeLib/Utils/Player/CSongPlayer.cs +++ b/VocaluxeLib/Utils/Player/CSongPlayer.cs @@ -39,28 +39,32 @@ namespace VocaluxeLib.Utils.Player _VideoEnabled = value; if (_VideoEnabled) _LoadVideo(); - else if (_Video != null) - CBase.Video.Close(ref _Video); + else + _CloseVideo(); } } + public int SongID { get { return _Song == null ? -1 : _Song.ID; } } - public bool SongHasVideo - { - get { return _Song != null && File.Exists(Path.Combine(_Song.Folder, _Song.VideoFileName)); } - } - public string ArtistAndTitle + public bool SongHasVideo { get { - if (_Song == null) - return ""; - if (_Song.Artist != "" && _Song.Title != "") + return _Song != null && !String.IsNullOrEmpty(_Song.Folder) && !String.IsNullOrEmpty(_Song.VideoFileName) && + File.Exists(Path.Combine(_Song.Folder, _Song.VideoFileName)); + } + } + + public override string ArtistAndTitle + { + get + { + if (_Song != null && !String.IsNullOrEmpty(_Song.Artist) && !String.IsNullOrEmpty(_Song.Title)) return _Song.Artist + " - " + _Song.Title; - return Path.GetFileNameWithoutExtension(_Song.MP3FileName); + return base.ArtistAndTitle; } } @@ -69,26 +73,8 @@ namespace VocaluxeLib.Utils.Player get { return _Song == null ? CBase.Cover.GetNoCover() : _Song.CoverTextureBig; } } - public bool SongLoaded - { - get { return _StreamID != -1; } - } - public CSongPlayer(bool loop = false) : base(loop) {} - public CSongPlayer(CSong song, bool loop = false, float position = 0f, bool autoplay = false) - : base(Path.Combine(song.Folder, song.MP3FileName), loop, position, autoplay) - { - _Song = song; - _LoadVideo(); - } - - public CSongPlayer(string file, bool loop = false, float position = 0f, bool autoplay = false) - : base(file, loop, position, autoplay) - { - _Song = null; - } - public CTextureRef GetVideoTexture() { if (_Video == null || _Song == null) @@ -110,49 +96,11 @@ namespace VocaluxeLib.Utils.Player public void Load(CSong song, float position = 0f, bool autoplay = false) { if (song == null) - return; + throw new ArgumentNullException("song"); - Stop(); - - _Song = song; - - Load(Path.Combine(song.Folder, song.MP3FileName), position, autoplay); + Load(song.GetMP3(), position, autoplay); _LoadVideo(); - - if (autoplay) - Play(); - } - - public void LoadFile(string file, float position = 0f, bool autoplay = false) - { - if (String.IsNullOrEmpty(file)) - return; - - Stop(); - - Load(file, position, autoplay); - } - - public override void Stop() - { - base.Stop(); - - _Song = null; - - if (_Video != null) - CBase.Video.Close(ref _Video); - } - - public override void TogglePause() - { - if (IsPlaying && _Video != null) - { - CBase.Video.Pause(_Video); - CBase.Video.Skip(_Video, CBase.Sound.GetPosition(_StreamID) + _FadeTime, _Song.VideoGap); - } - else if (_Video != null) - CBase.Video.Resume(_Video); - base.TogglePause(); + _Song = song; } private void _LoadVideo() @@ -160,11 +108,13 @@ namespace VocaluxeLib.Utils.Player if (_Song == null) return; - string videoFilePath = Path.Combine(_Song.Folder, _Song.VideoFileName); - if (_Video != null || String.IsNullOrEmpty(videoFilePath)) + if (_Video != null || !SongHasVideo) return; + string videoFilePath = Path.Combine(_Song.Folder, _Song.VideoFileName); _Video = CBase.Video.Load(videoFilePath); - CBase.Video.Skip(_Video, 0f, _Song.VideoGap); //Use gap, otherwhise we will overwrite position in GetVideoTexture + if (_Video == null) + return; + _VideoFading = new CFading(0f, 1f, 3f); if (IsPlaying) @@ -172,6 +122,57 @@ namespace VocaluxeLib.Utils.Player CBase.Video.Skip(_Video, Position, _Song.VideoGap); CBase.Video.Resume(_Video); } + else + CBase.Video.Skip(_Video, 0f, _Song.VideoGap); + } + + public override bool Play() + { + if (!base.Play()) + return false; + + if (_Video != null) + { + CBase.Video.Skip(_Video, Position, _Song.VideoGap); + CBase.Video.Resume(_Video); + } + return true; + } + + public override bool Pause() + { + if (!base.Pause()) + return false; + + if (_Video != null) + CBase.Video.Pause(_Video); + return true; + } + + public override bool Stop() + { + if (!base.Stop()) + return false; + if (_Video != null) + { + CBase.Video.Pause(_Video); + CBase.Video.Skip(_Video, 0f, _Song.VideoGap); + } + return true; + } + + private void _CloseVideo() + { + if (_Video != null) + CBase.Video.Close(ref _Video); + } + + public override void Close() + { + base.Close(); + + _Song = null; + _CloseVideo(); } } } \ No newline at end of file diff --git a/VocaluxeLib/Utils/Player/CSoundPlayer.cs b/VocaluxeLib/Utils/Player/CSoundPlayer.cs index b132643b..51337d42 100644 --- a/VocaluxeLib/Utils/Player/CSoundPlayer.cs +++ b/VocaluxeLib/Utils/Player/CSoundPlayer.cs @@ -15,58 +15,52 @@ // along with Vocaluxe. If not, see . #endregion +using System.IO; + namespace VocaluxeLib.Utils.Player { public class CSoundPlayer { protected int _StreamID = -1; - protected int _Volume = 100; - protected float _StartPosition; protected readonly float _FadeTime = CBase.Settings.GetSoundPlayerFadeTime(); + public string FilePath { get; private set; } - public int Volume - { - set - { - _Volume = value; - _ApplyVolume(); - } - get { return _Volume; } - } public bool Loop; + /// + /// Gets the current stream position or sets it + /// public float Position { set { - if (_StreamID == -1) + if (!SoundLoaded) return; - _StartPosition = value; - } - get - { - if (_StreamID == -1) - return -1; - return CBase.Sound.GetPosition(_StreamID); + CBase.Sound.SetPosition(_StreamID, value); } + get { return !SoundLoaded ? -1 : CBase.Sound.GetPosition(_StreamID); } } public float Length { - get - { - if (_StreamID == -1) - return 0; - return CBase.Sound.GetLength(_StreamID); - } + get { return !SoundLoaded ? -1 : CBase.Sound.GetLength(_StreamID); } } - public bool RepeatSong; - public bool IsPlaying { get; protected set; } + public bool IsPlaying { get; private set; } public bool IsFinished { - get { return !RepeatSong && CBase.Sound.IsFinished(_StreamID); } + get { return !Loop && CBase.Sound.IsFinished(_StreamID); } + } + + public bool SoundLoaded + { + get { return _StreamID != -1; } + } + + public virtual string ArtistAndTitle + { + get { return string.IsNullOrEmpty(FilePath) ? "" : Path.GetFileNameWithoutExtension(FilePath); } } public CSoundPlayer(bool loop = false) @@ -74,95 +68,97 @@ namespace VocaluxeLib.Utils.Player Loop = loop; } - public CSoundPlayer(string file, bool loop = false, float position = 0f, bool autoplay = false) + public void Load(string file, float position = -1f, bool autoplay = false) { - _StreamID = CBase.Sound.Load(file, false, true); - if (position > 0f) - Position = position; - Loop = loop; - if (autoplay) - Play(); - } - - public void Load(string file, float position = 0f, bool autoplay = false) - { - if (IsPlaying) - Stop(); + Close(); _StreamID = CBase.Sound.Load(file, false, true); - if (position > 0f) - Position = position; - if (autoplay) - Play(); - } - - public void Play() - { - if (_StreamID == -1 || IsPlaying) + if (_StreamID < 0) return; + FilePath = file; + if (position > 0f) + Position = position; + if (autoplay) + Play(); + } + + /// + /// Starts or resumes the player + /// + /// True if state changed, false if nothing loaded or already playing + public virtual bool Play() + { + if (!SoundLoaded || IsPlaying) + return false; - CBase.Sound.SetPosition(_StreamID, _StartPosition); CBase.Sound.SetStreamVolume(_StreamID, 0); - CBase.Sound.Fade(_StreamID, Volume, _FadeTime); + CBase.Sound.Fade(_StreamID, 100, _FadeTime); CBase.Sound.Play(_StreamID); IsPlaying = true; + return true; } - public virtual void TogglePause() + /// + /// Pauses the player + /// + /// True if state changed, false if nothing loaded or already paused + public virtual bool Pause() { - if (_StreamID == -1) - return; + if (!SoundLoaded || CBase.Sound.IsPaused(_StreamID)) + return false; - if (IsPlaying) - CBase.Sound.Fade(_StreamID, 0, _FadeTime, EStreamAction.Pause); - else - { - CBase.Sound.Fade(_StreamID, Volume, _FadeTime); - CBase.Sound.Play(_StreamID); - } - - IsPlaying = !IsPlaying; + CBase.Sound.Fade(_StreamID, 0, _FadeTime, EStreamAction.Pause); + IsPlaying = false; + return true; } - public virtual void Stop() + /// + /// Stops the player (no playback and position is set to start) + /// + /// True if playback was stopped + public virtual bool Stop() { - if (_StreamID == -1 || !IsPlaying) + if (!SoundLoaded) + return false; + + CBase.Sound.Fade(_StreamID, 0, _FadeTime, EStreamAction.Stop); + IsPlaying = false; + return true; + } + + public virtual void Close() + { + if (!SoundLoaded) return; CBase.Sound.Fade(_StreamID, 0, _FadeTime, EStreamAction.Close); _StreamID = -1; - + FilePath = ""; IsPlaying = false; } public void Update() { - if (_StreamID == -1 || !IsPlaying) + if (!IsPlaying) return; + bool finished = CBase.Sound.IsFinished(_StreamID); + if (Loop) + { + if (finished) + { + // Restart + Stop(); + Play(); + } + return; + } + float len = CBase.Sound.GetLength(_StreamID); float timeToPlay = (len > 0f) ? len - CBase.Sound.GetPosition(_StreamID) : _FadeTime + 1f; - bool finished = CBase.Sound.IsFinished(_StreamID); if (timeToPlay <= _FadeTime || finished) - { - if (RepeatSong) - { - //Set to false for restarting - IsPlaying = false; - Play(); - } - else - Stop(); - } - } - - private void _ApplyVolume() - { - if (_StreamID == -1) - return; - - CBase.Sound.SetStreamVolume(_StreamID, Volume); + Stop(); } } } \ No newline at end of file diff --git a/VocaluxeLib/VocaluxeLib.csproj b/VocaluxeLib/VocaluxeLib.csproj index b452b5e5..e1faa2d8 100644 --- a/VocaluxeLib/VocaluxeLib.csproj +++ b/VocaluxeLib/VocaluxeLib.csproj @@ -108,6 +108,7 @@ + @@ -138,7 +139,7 @@ - + diff --git a/VocaluxeLib/Xml/CXmlDeserializer.cs b/VocaluxeLib/Xml/CXmlDeserializer.cs index cc51c26f..df8c7879 100644 --- a/VocaluxeLib/Xml/CXmlDeserializer.cs +++ b/VocaluxeLib/Xml/CXmlDeserializer.cs @@ -86,14 +86,14 @@ namespace VocaluxeLib.Xml } #endregion Debug Helpers - private readonly XmlNode _Node; + public readonly XmlNode Node; public readonly bool IsError; public CXmlException(string msg, XmlNode node, bool isError = true) : base(msg) { IsError = isError; - _Node = node; + Node = node; } public override string Message @@ -103,12 +103,22 @@ namespace VocaluxeLib.Xml public override String ToString() { - string xPath = _Node == null ? "" : _GetXPath(_Node); + string xPath = Node == null ? "" : _GetXPath(Node); string type = IsError ? "Error" : "Warning"; return type + ": " + base.Message.Replace("%n", xPath); } } + public class CXmlMissingElementException : CXmlException + { + public readonly SFieldInfo Field; + + public CXmlMissingElementException(XmlNode parent, SFieldInfo field, bool isError = true) : base("Element: " + field.Name + " is missing in %n", parent, isError) + { + Field = field; + } + } + public class CXmlInvalidValueException : CXmlException { private readonly string _Value; @@ -157,9 +167,9 @@ namespace VocaluxeLib.Xml public class CXmlDeserializer { - private class CXmlDefaultErrorHandler : IXmlErrorHandler + public class CXmlDefaultErrorHandler : IXmlErrorHandler { - public void HandleError(CXmlException e) + public virtual void HandleError(CXmlException e) { if (e.IsError) throw e; @@ -421,7 +431,7 @@ namespace VocaluxeLib.Xml Dictionary>> embLists = new Dictionary>>(); foreach (XmlNode node in nodes) { - if (node is XmlComment) + if (node is XmlComment || node.LocalName == "xsd" || node.LocalName == "xsi") continue; SFieldInfo field = new SFieldInfo(); @@ -505,7 +515,7 @@ namespace VocaluxeLib.Xml if (!_CheckAndSetDefaultValue(o, field)) { if (parent != null) - _ErrorHandler.HandleError(new CXmlException("element: " + field.Name + " is missing in %n", parent)); + _ErrorHandler.HandleError(new CXmlMissingElementException(parent, field)); object value = _GetValue(null, field.Type, field.ArrayItemName, field.GetValue(o)); if (value != null) field.SetValue(o, value); diff --git a/VocaluxeLib/Xml/CXmlSerializer.cs b/VocaluxeLib/Xml/CXmlSerializer.cs index c0db420d..46b44539 100644 --- a/VocaluxeLib/Xml/CXmlSerializer.cs +++ b/VocaluxeLib/Xml/CXmlSerializer.cs @@ -63,7 +63,7 @@ namespace VocaluxeLib.Xml /// Type of the value /// Object to write /// When true, value will be written as an attribute to the currently open node, otherwhise it will create a new node - /// >Name of the sub nodes for array types(Array,List,Dictionary), can be set by XmlArrayItemAttribute and defaults to the type name + /// Name of the sub nodes for array types(Array,List,Dictionary), can be set by XmlArrayItemAttribute and defaults to the type name /// If set, an attribute 'name' with this value will be written private void _WriteValue(XmlWriter writer, string name, Type type, object value, bool isAttribute, string arrayItemName = null, string nameAttribute = null) { @@ -165,8 +165,14 @@ namespace VocaluxeLib.Xml if (field.IsEmbeddedList) { IEnumerable values = (IEnumerable)value; + bool empty = true; foreach (object subValue in values) + { _WriteValue(writer, field.Name, field.SubType, subValue, field.IsAttribute); + empty = false; + } + if (empty && _WriteDefaults) + writer.WriteElementString(field.Name, ""); } else if (field.IsByteArray) writer.WriteElementString(field.Name, Convert.ToBase64String((byte[])value)); diff --git a/VocaluxeTests/CTestHelpers.cs b/VocaluxeTests/CTestHelpers.cs new file mode 100644 index 00000000..4ad00bf3 --- /dev/null +++ b/VocaluxeTests/CTestHelpers.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace VocaluxeTests +{ + static class CTestHelpers + { + public static void AssertFail(Action test) where T : Exception + { + try + { + test.Invoke(); + Assert.Fail("Exception " + typeof(T).Name + " not thrown!"); + } + catch (Exception e) + { + Assert.IsInstanceOfType(e, typeof(T)); + } + } + } +} \ No newline at end of file diff --git a/VocaluxeTests/CombinatoricsTest.cs b/VocaluxeTests/CombinatoricsTest.cs new file mode 100644 index 00000000..50d274e1 --- /dev/null +++ b/VocaluxeTests/CombinatoricsTest.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using VocaluxeLib.Utils.Combinatorics; + +namespace VocaluxeTests +{ + [TestClass] + public class CCombinatoricsTest + { + [TestMethod] + public void TestCounts() + { + Assert.AreEqual(4, CCombinations.Count(4, 3)); + Assert.AreEqual(6, CCombinations.Count(4, 2)); + Assert.AreEqual(66, CCombinations.Count(12, 2)); + // Corner cases + for (int i = 1; i < 12; i++) + { + Assert.AreEqual(1, CCombinations.Count(i, 0)); + Assert.AreEqual(1, CCombinations.Count(i, i)); + Assert.AreEqual(0, CCombinations.Count(i, i + 1)); + } + // Check identity (n k) = (n n-k) + for (int i = 0; i <= 12; i++) + Assert.AreEqual(CCombinations.Count(12, i), CCombinations.Count(12, 12 - i)); + CTestHelpers.AssertFail(() => CCombinations.Count(-1, -1)); + CTestHelpers.AssertFail(() => CCombinations.Count(-1, 1)); + CTestHelpers.AssertFail(() => CCombinations.Count(1, -1)); + } + + // ReSharper disable UnusedParameter.Local + private static void _CheckResults(CCombinations combs, List input) + // ReSharper restore UnusedParameter.Local + { + List> results = new List>(); + foreach (List comb in combs) + { + foreach (List other in results) + Assert.IsFalse(other.SequenceEqual(comb), "Result must be unique"); + for (int i = 0; i < comb.Count - 1; i++) + { + Assert.IsTrue(comb.IndexOf(comb[i], i + 1) < 0, "Repetition not allowed"); + Assert.IsTrue(input.Contains(comb[i]), "Output must be in input sequence"); + } + results.Add(comb); + } + Assert.AreEqual(combs.Count(), results.Count); + List> results2 = combs.GetAll(); + Assert.AreEqual(results.Count, results2.Count); + for (int i = 0; i < results2.Count; i++) + Assert.IsTrue(results[i].SequenceEqual(results2[i])); + } + + [TestMethod] + public void TestResults() + { + Random rand = new Random(); + for (int n = 0; n < 8; n++) + { + for (int k = 0; k <= n; k++) + { + List collection = new List(n); + int r = rand.Next(1000); + for (int i = 0; i < n; i++) + collection.Add(i + r); + CCombinations combs = new CCombinations(collection, k); + Assert.AreEqual(CCombinations.Count(n, k), combs.Count()); + _CheckResults(combs, collection); + } + } + } + } +} \ No newline at end of file diff --git a/VocaluxeTests/PartyModeTests.cs b/VocaluxeTests/PartyModeTests.cs new file mode 100644 index 00000000..c0363123 --- /dev/null +++ b/VocaluxeTests/PartyModeTests.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Vocaluxe.Base; +using VocaluxeLib; +using VocaluxeLib.PartyModes.Challenge; + +namespace VocaluxeTests +{ + [TestClass] + public class CPartyModeTests + { + [TestMethod] + public void TestRoundBoundaries() + { + // ReSharper disable ObjectCreationAsStatement + new CChallengeRounds(1, 1, 1); // Should succeed + // ReSharper restore ObjectCreationAsStatement + for (int inv = -1; inv <= 0; inv++) + { + int invL = inv; + CTestHelpers.AssertFail(() => new CChallengeRounds(invL, 1, 1)); + CTestHelpers.AssertFail(() => new CChallengeRounds(1, invL, 1)); + CTestHelpers.AssertFail(() => new CChallengeRounds(1, 1, invL)); + } + } + + private static void _CheckRounds(CChallengeRounds rounds, int numPlayer) + { + List numSongs = new List(numPlayer); + for (int i = 0; i < numPlayer; i++) + numSongs.Add(0); + for (int i = 0; i < rounds.Count; i++) + { + foreach (int player in rounds[i].Players) + { + Assert.IsTrue(player >= 0 && player < numPlayer); + numSongs[player]++; + } + } + Assert.IsTrue(numSongs.Min() == numSongs.Max(), "Some players have more songs than others"); + } + + [TestMethod] + public void TestRoundGeneration() + { + CBase.Game = new CBGame(); + CLog.Init(); + CBase.Log = new CBlog(); + for (int i = 0; i < 10; i++) + { + for (int numPlayer = 1; numPlayer <= 20; numPlayer++) + { + for (int numMic = 1; numMic <= 6; numMic++) + { + int roundFactor = (numPlayer % numMic == 0) ? numPlayer / numMic : numPlayer; + for (int numRounds = roundFactor; numRounds <= 100 && numRounds <= roundFactor * 5; numRounds += roundFactor) + { + CChallengeRounds rounds = new CChallengeRounds(numRounds, numPlayer, numMic); + Assert.IsTrue(rounds.Count >= numRounds); + _CheckRounds(rounds, numPlayer); + if (rounds.Count != numRounds) + CBase.Log.LogDebug("Number of rounds does not match. Expected: " + numRounds + ", Is: " + rounds.Count + " for " + numPlayer + "/" + + ((numPlayer < numMic) ? numPlayer : numMic)); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/VocaluxeTests/VocaluxeTests.csproj b/VocaluxeTests/VocaluxeTests.csproj index b3a0dade..88233b22 100644 --- a/VocaluxeTests/VocaluxeTests.csproj +++ b/VocaluxeTests/VocaluxeTests.csproj @@ -70,10 +70,17 @@ + + + + + {5a4053f1-5ad5-441f-b254-d97a088127b6} + PartyModeChallenge + {d2b6ddef-e0e1-4ddf-a73a-e6acef5c95ec} VocaluxeLib diff --git a/VocaluxeTests/XmlSerializerTest.cs b/VocaluxeTests/XmlSerializerTest.cs index 6b59e5ec..91605a7e 100644 --- a/VocaluxeTests/XmlSerializerTest.cs +++ b/VocaluxeTests/XmlSerializerTest.cs @@ -91,8 +91,7 @@ namespace VocaluxeTests private struct SDefaultSub { - [DefaultValue(111)] - public int I; + [DefaultValue(111)] public int I; } private struct SDefault @@ -107,23 +106,10 @@ namespace VocaluxeTests #pragma warning restore 169 #pragma warning restore 649 - private static void _AssertFail(Action test) where T : Exception - { - try - { - test.Invoke(); - Assert.Fail("Exception " + typeof(T).Name + " not thrown!"); - } - catch (Exception e) - { - Assert.IsInstanceOfType(e, typeof(T)); - } - } - private static void _AssertFail(String xmlString) where T2 : Exception where T : new() { var deserializer = new CXmlDeserializer(); - _AssertFail(() => deserializer.DeserializeString(xmlString)); + CTestHelpers.AssertFail(() => deserializer.DeserializeString(xmlString)); } private static T _AssertSerDeserMatch(string xmlString) where T : new() @@ -315,6 +301,11 @@ namespace VocaluxeTests 2 3 "; + private const string _XmlListEmb4 = _Head + @" + 2 + + 3 +"; [TestMethod] public void TestListEmbedded() @@ -335,6 +326,10 @@ namespace VocaluxeTests Assert.AreEqual(foo.Ints.Count, 0, "Deserialization failed"); res = ser.Serialize(foo); Assert.AreEqual(_XmlListEmb3, res, "Serialization failed"); + ser = new CXmlSerializer(true); + foo.Ints.Clear(); + res = ser.Serialize(foo); + Assert.AreEqual(_XmlListEmb4, res, "Serialization failed"); _AssertFail(_Empty); } @@ -357,6 +352,10 @@ namespace VocaluxeTests Assert.AreEqual(foo.Ints.Length, 0, "Deserialization failed"); res = ser.Serialize(foo); Assert.AreEqual(_XmlListEmb3, res, "Serialization failed"); + ser = new CXmlSerializer(true); + foo.Ints = new SEntry[0]; + res = ser.Serialize(foo); + Assert.AreEqual(_XmlListEmb4, res, "Serialization failed"); _AssertFail(_Empty); } @@ -454,7 +453,7 @@ namespace VocaluxeTests Assert.AreEqual(foo.D, 666); Assert.AreEqual(foo.Sub.I, 111); string newXml = new CXmlSerializer().Serialize(foo); - Assert.AreEqual(_Head +@" + Assert.AreEqual(_Head + @" ", newXml); }