#region license // This file is part of Vocaluxe. // // Vocaluxe is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Vocaluxe is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Vocaluxe. If not, see . #endregion using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Runtime.InteropServices; using VocaluxeLib.Game; using VocaluxeLib.Menu; using VocaluxeLib.Songs; using VocaluxeLib.Profile; [assembly: ComVisible(false)] namespace VocaluxeLib.PartyModes.ChallengeMedley { #region Communication #region ToScreen public struct SDataToScreenConfig { public int NumPlayer; public int NumPlayerAtOnce; public int NumRounds; } public struct SDataToScreenNames { public int NumPlayer; public List ProfileIDs; } public struct SDataToScreenMain { public int CurrentRoundNr; public int NumPlayerAtOnce; public List Combs; public int[,] Results; public List ResultTable; public List ProfileIDs; } public class CResultTableRow : IComparable { public int Position; public int PlayerID; public int NumPlayed; public int NumWon; public int NumSingPoints; public int NumGamePoints; public int CompareTo(object obj) { CResultTableRow row = obj as CResultTableRow; if (row != null) { int res = row.NumGamePoints.CompareTo(NumGamePoints); if (res == 0) { res = row.NumSingPoints.CompareTo(NumSingPoints); if (res == 0) res = row.NumWon.CompareTo(NumWon); } return res; } throw new ArgumentException("object is not a ResultTableRow"); } } #endregion ToScreen #region FromScreen public struct SDataFromScreen { public SFromScreenConfig ScreenConfig; public SFromScreenNames ScreenNames; public SFromScreenMain ScreenMain; } public struct SFromScreenConfig { public int NumPlayer; public int NumPlayerAtOnce; public int NumRounds; } public struct SFromScreenNames { public bool FadeToConfig; public List ProfileIDs; } public struct SFromScreenMain { public bool FadeToSongSelection; public bool FadeToNameSelection; } #endregion FromScreen #endregion Communication public sealed class CPartyModeChallengeMedley : CPartyMode { 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; private enum EStage { NotStarted, Config, Names, Main, Singing } private struct SData { public int NumPlayer; public int NumPlayerAtOnce; public int NumRounds; public List ProfileIDs; public CChallengeRounds Rounds; public List ResultTable; public int[,] Results; public int CurrentRoundNr; public int[] CatSongIndices; } private struct SStats { public int ProfileID; public int SingPoints; public int GamePoints; public int Won; } private SDataToScreenConfig _ToScreenConfig; private SDataToScreenNames _ToScreenNames; private SDataToScreenMain _ToScreenMain; private SData _GameData; private EStage _Stage; public CPartyModeChallengeMedley() { _ScreenSongOptions.Selection.RandomOnly = false; _ScreenSongOptions.Selection.PartyMode = true; _ScreenSongOptions.Selection.CategoryChangeAllowed = true; _ScreenSongOptions.Selection.NumJokers = new int[] {5, 5}; _ScreenSongOptions.Selection.TeamNames = new string[] {"foo", "bar"}; _ScreenSongOptions.Sorting.SearchString = String.Empty; _ScreenSongOptions.Sorting.SearchActive = false; _ScreenSongOptions.Sorting.DuetOptions = EDuetOptions.NoDuets; _Stage = EStage.NotStarted; _ToScreenConfig = new SDataToScreenConfig(); _ToScreenNames = new SDataToScreenNames(); _ToScreenMain = new SDataToScreenMain(); _GameData = new SData {NumPlayer = 4, NumPlayerAtOnce = 2, NumRounds = 2, CurrentRoundNr = 1, ProfileIDs = new List(), CatSongIndices = null, Results = null}; } public override bool Init() { _Stage = EStage.NotStarted; _ScreenSongOptions.Sorting.IgnoreArticles = EOffOn.TR_CONFIG_OFF; _ScreenSongOptions.Sorting.SongSorting = ESongSorting.TR_CONFIG_NONE; _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_OFF; _ScreenSongOptions.Selection.SongIndex = -1; _ToScreenMain.ResultTable = new List(); _GameData.ResultTable = new List(); CBase.Songs.SortSongs(ESongSorting.TR_CONFIG_NONE, EOffOn.TR_CONFIG_OFF, EOffOn.TR_CONFIG_OFF, String.Empty, EDuetOptions.NoDuets); CBase.Songs.SetCategory(0); return true; } public override void DataFromScreen(string screenName, Object data) { SDataFromScreen dataFrom; switch (screenName) { case "PartyScreenChallengeMedleyConfig": try { dataFrom = (SDataFromScreen)data; _GameData.NumPlayer = dataFrom.ScreenConfig.NumPlayer; _GameData.NumPlayerAtOnce = dataFrom.ScreenConfig.NumPlayerAtOnce; _GameData.NumRounds = dataFrom.ScreenConfig.NumRounds; _Stage = EStage.Config; CBase.Graphics.FadeTo(EScreens.ScreenPartyDummy); } catch (Exception e) { CBase.Log.LogError("Error in party mode challenge. Can't cast received data from screen " + screenName + ". " + e.Message); } break; case "PartyScreenChallengeMedleyNames": try { dataFrom = (SDataFromScreen)data; if (dataFrom.ScreenNames.FadeToConfig) _Stage = EStage.NotStarted; else { _GameData.ProfileIDs = dataFrom.ScreenNames.ProfileIDs; _Stage = EStage.Names; } CBase.Graphics.FadeTo(EScreens.ScreenPartyDummy); } catch (Exception e) { CBase.Log.LogError("Error in party mode challenge. Can't cast received data from screen " + screenName + ". " + e.Message); } break; case "PartyScreenChallengeMedleyMain": try { dataFrom = (SDataFromScreen)data; if (dataFrom.ScreenMain.FadeToSongSelection) _Stage = EStage.Singing; if (dataFrom.ScreenMain.FadeToNameSelection) _Stage = EStage.Config; } catch (Exception e) { CBase.Log.LogError("Error in party mode challenge. Can't cast received data from screen " + screenName + ". " + e.Message); } if (_Stage == EStage.Singing) _StartNextRound(); if (_Stage == EStage.Config) CBase.Graphics.FadeTo(EScreens.ScreenPartyDummy); break; default: CBase.Log.LogError("Error in party mode challenge. Wrong screen is sending: " + screenName); break; } } public override void UpdateGame() { /* if (CBase.Songs.GetCurrentCategoryIndex() != -1 || _ScreenSongOptions.Sorting.Tabs == EOffOn.TR_CONFIG_OFF) _ScreenSongOptions.Selection.RandomOnly = true; else _ScreenSongOptions.Selection.RandomOnly = false;*/ } public override CMenuParty GetNextPartyScreen(out EScreens alternativeScreen) { CMenuParty screen = null; alternativeScreen = EScreens.ScreenSong; switch (_Stage) { case EStage.NotStarted: _Screens.TryGetValue("CPartyScreenChallengeMedleyConfig", out screen); if (screen != null) { _ToScreenConfig.NumPlayer = _GameData.NumPlayer; _ToScreenConfig.NumPlayerAtOnce = _GameData.NumPlayerAtOnce; _ToScreenConfig.NumRounds = _GameData.NumRounds; screen.DataToScreen(_ToScreenConfig); } break; case EStage.Config: _Screens.TryGetValue("CPartyScreenChallengeMedleyNames", out screen); if (screen != null) { _ToScreenNames.NumPlayer = _GameData.NumPlayer; _ToScreenNames.ProfileIDs = _GameData.ProfileIDs; screen.DataToScreen(_ToScreenNames); } break; case EStage.Names: _Screens.TryGetValue("CPartyScreenChallengeMedleyMain", out screen); if (screen != null) { CBase.Songs.ResetSongSung(); _ToScreenMain.ResultTable = new List(); _GameData.ResultTable = new List(); _GameData.Rounds = new CChallengeRounds(_GameData.NumRounds, _GameData.NumPlayer, _GameData.NumPlayerAtOnce); _GameData.CurrentRoundNr = 1; _ToScreenMain.CurrentRoundNr = 1; _ToScreenMain.NumPlayerAtOnce = _GameData.NumPlayerAtOnce; _ToScreenMain.Combs = _GameData.Rounds.Rounds; _ToScreenMain.ProfileIDs = _GameData.ProfileIDs; _UpdateScores(); _ToScreenMain.ResultTable = _GameData.ResultTable; _ToScreenMain.Results = _GameData.Results; screen.DataToScreen(_ToScreenMain); } break; case EStage.Main: //nothing to do break; case EStage.Singing: _Screens.TryGetValue("CPartyScreenChallengeMedleyMain", out screen); if (screen != null) { _UpdateScores(); _ToScreenMain.CurrentRoundNr = _GameData.CurrentRoundNr; _ToScreenMain.Combs = _GameData.Rounds.Rounds; _ToScreenMain.Results = _GameData.Results; screen.DataToScreen(_ToScreenMain); } break; } return screen; } public override EScreens GetStartScreen() { return EScreens.ScreenPartyDummy; } public override EScreens GetMainScreen() { return EScreens.ScreenPartyDummy; } public override SScreenSongOptions GetScreenSongOptions() { _ScreenSongOptions.Sorting.SongSorting = CBase.Config.GetSongSorting(); _ScreenSongOptions.Sorting.Tabs = CBase.Config.GetTabs(); _ScreenSongOptions.Sorting.IgnoreArticles = CBase.Config.GetIgnoreArticles(); return _ScreenSongOptions; } // ReSharper disable RedundantAssignment public override void OnSongChange(int songIndex, ref SScreenSongOptions screenSongOptions) // ReSharper restore RedundantAssignment { _ScreenSongOptions.Selection.SongIndex = -1; if (_ScreenSongOptions.Selection.SelectNextRandomSong && songIndex != -1) { _ScreenSongOptions.Selection.SelectNextRandomSong = false; _CreateCatSongIndices(); if (_GameData.CatSongIndices != null) { if (_GameData.CatSongIndices[CBase.Songs.GetCurrentCategoryIndex()] == -1) _GameData.CatSongIndices[CBase.Songs.GetCurrentCategoryIndex()] = songIndex; } } screenSongOptions = _ScreenSongOptions; } // ReSharper disable RedundantAssignment public override void OnCategoryChange(int categoryIndex, ref SScreenSongOptions screenSongOptions) // ReSharper restore RedundantAssignment { if (_GameData.CatSongIndices != null && categoryIndex != -1) { if (_GameData.CatSongIndices[categoryIndex] == -1) _ScreenSongOptions.Selection.SelectNextRandomSong = true; else _ScreenSongOptions.Selection.SongIndex = _GameData.CatSongIndices[categoryIndex]; } if (_GameData.CatSongIndices == null && categoryIndex != -1) _ScreenSongOptions.Selection.SelectNextRandomSong = true; if (categoryIndex == -1) _ScreenSongOptions.Selection.RandomOnly = false; if (_ScreenSongOptions.Sorting.Tabs == EOffOn.TR_CONFIG_OFF || categoryIndex != -1) _ScreenSongOptions.Selection.RandomOnly = true; screenSongOptions = _ScreenSongOptions; } public override void SetSearchString(string searchString, bool visible) { _ScreenSongOptions.Sorting.SearchString = searchString; _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) return; if (teamNr >= _ScreenSongOptions.Selection.NumJokers.Length) return; _ScreenSongOptions.Selection.NumJokers[teamNr]--; _ScreenSongOptions.Selection.RandomOnly = true; _ScreenSongOptions.Selection.CategoryChangeAllowed = false; } public override void SongSelected(int songID) {} public override void LeavingHighscore() { _GameData.CurrentRoundNr++; CBase.Graphics.FadeTo(EScreens.ScreenPartyDummy); } private void _StartNextRound() { _ScreenSongOptions.Selection.RandomOnly = _ScreenSongOptions.Sorting.Tabs != EOffOn.TR_CONFIG_ON; _ScreenSongOptions.Selection.CategoryChangeAllowed = _ScreenSongOptions.Sorting.Tabs == EOffOn.TR_CONFIG_ON; _SetNumJokers(); _SetTeamNames(); _GameData.CatSongIndices = null; if (_RandomizeSongs()) CBase.Graphics.FadeTo(EScreens.ScreenSing); } private bool _RandomizeSongs() { CBase.Game.Reset(); CBase.Game.ClearSongs(); #region PlayerNames CBase.Game.SetNumPlayer(_GameData.NumPlayerAtOnce); SPlayer[] players = CBase.Game.GetPlayers(); if (players == null) return false; if (players.Length < _GameData.NumPlayerAtOnce) return false; CCombination c = _GameData.Rounds.GetRound(_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]]; else players[i].ProfileID = -1; } #endregion PlayerNames #region SongQueue if (CBase.Songs.GetNumSongsVisible() < _NumSongs) CBase.Songs.ResetSongSung(); List ids = new List(); ReadOnlyCollection visibleSongs = CBase.Songs.GetVisibleSongs(); if (visibleSongs.Count == 0) { CBase.Log.LogError("CPartyChallengeMedleyMode Error: There are no songs!"); CBase.Graphics.FadeTo(EScreens.ScreenParty); return false; } //Calc avarage sing-count int totalCounts = 0; foreach (CSong song in visibleSongs) totalCounts += song.NumPlayedSession; int averageCount = totalCounts / visibleSongs.Count; // ReSharper disable LoopCanBeConvertedToQuery foreach (CSong song in visibleSongs) { foreach (EGameMode mode in song.AvailableGameModes) { if (mode == EGameMode.TR_GAMEMODE_MEDLEY && song.NumPlayedSession <= averageCount) ids.Add(song.ID); } } // ReSharper restore LoopCanBeConvertedToQuery if (ids.Count == 0) { CBase.Log.LogError("CPartyChallengeMedleyMode Error: There are no medley songs!"); CBase.Graphics.FadeTo(EScreens.ScreenParty); return false; } int s = 0; while (s < _NumSongs && ids.Count > 0) { int songID = ids[CBase.Game.GetRandom(ids.Count)]; CBase.Game.AddSong(songID, EGameMode.TR_GAMEMODE_MEDLEY); CBase.Songs.AddPartySongSung(songID); ids.Remove(songID); s++; } return true; #endregion SongQueue } private void _SetNumJokers() { switch (_GameData.NumPlayerAtOnce) { case 1: _ScreenSongOptions.Selection.NumJokers = new int[] {10}; break; case 2: _ScreenSongOptions.Selection.NumJokers = new int[] {5, 5}; break; case 3: _ScreenSongOptions.Selection.NumJokers = new int[] {4, 4, 4}; break; case 4: _ScreenSongOptions.Selection.NumJokers = new int[] {3, 3, 3, 3}; break; case 5: _ScreenSongOptions.Selection.NumJokers = new int[] {2, 2, 2, 2, 2}; break; case 6: _ScreenSongOptions.Selection.NumJokers = new int[] {2, 2, 2, 2, 2, 2}; break; default: _ScreenSongOptions.Selection.NumJokers = new int[] {5, 5}; break; } } private void _SetTeamNames() { CProfile[] profiles = CBase.Profiles.GetProfiles(); if (profiles == null) { _ScreenSongOptions.Selection.TeamNames = new string[] {"foo", "bar"}; return; } if (_GameData.NumPlayerAtOnce < 1 || _GameData.ProfileIDs.Count < _GameData.NumPlayerAtOnce || profiles.Length < _GameData.NumPlayerAtOnce) { _ScreenSongOptions.Selection.TeamNames = new string[] {"foo", "bar"}; return; } _ScreenSongOptions.Selection.TeamNames = new string[_GameData.NumPlayerAtOnce]; CCombination c = _GameData.Rounds.GetRound(_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; else _ScreenSongOptions.Selection.TeamNames[i] = "foobar"; } else _ScreenSongOptions.Selection.TeamNames[i] = "foobar"; } } private void _UpdateScores() { if (_GameData.ResultTable.Count == 0) { for (int i = 0; i < _GameData.NumPlayer; i++) { CResultTableRow row = new CResultTableRow {PlayerID = _GameData.ProfileIDs[i], NumPlayed = 0, NumWon = 0, NumSingPoints = 0, NumGamePoints = 0}; _GameData.ResultTable.Add(row); } _GameData.Results = new int[_GameData.NumRounds,_GameData.NumPlayerAtOnce]; for (int i = 0; i < _GameData.NumRounds; i++) { for (int j = 0; j < _GameData.NumPlayerAtOnce; j++) _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++) { SPlayer[] temp = gamePoints.GetPlayer(i, _GameData.NumPlayerAtOnce); for (int p = 0; p < _GameData.NumPlayerAtOnce; p++) results[p].Points += temp[p].Points; } 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); } List points = _GetPointsForPlayer(results); 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.Sort(); //Update position-number int pos = 1; int lastPoints = 0; int lastSingPoints = 0; foreach (CResultTableRow resultRow in _GameData.ResultTable) { if (lastPoints > resultRow.NumGamePoints || lastSingPoints > resultRow.NumSingPoints) pos++; resultRow.Position = pos; lastPoints = resultRow.NumGamePoints; lastSingPoints = resultRow.NumSingPoints; } } private List _GetPointsForPlayer(SPlayer[] results) { List result = new List(); for (int i = 0; i < _GameData.NumPlayerAtOnce; i++) { SStats stat = new SStats {ProfileID = results[i].ProfileID, SingPoints = (int)Math.Round(results[i].Points), Won = 0, GamePoints = 0}; result.Add(stat); } result.Sort((s1, s2) => s1.SingPoints.CompareTo(s2.SingPoints)); int current = result[result.Count - 1].SingPoints; int points = result.Count; bool wonset = false; for (int i = result.Count - 1; i >= 0; i--) { SStats res = result[i]; if (i < result.Count - 1) { if (current > res.SingPoints) { res.GamePoints = i * 2; wonset = true; points = res.GamePoints; } else { if (!wonset) res.Won = 1; res.GamePoints = points; } } else { res.GamePoints = i * 2; res.Won = 1; } current = res.SingPoints; result[i] = res; } return result; } private void _CreateCatSongIndices() { if (_GameData.CatSongIndices == null && CBase.Songs.GetNumCategories() > 0 && _ScreenSongOptions.Sorting.Tabs == EOffOn.TR_CONFIG_ON) { _GameData.CatSongIndices = new int[CBase.Songs.GetNumCategories()]; for (int i = 0; i < _GameData.CatSongIndices.Length; i++) _GameData.CatSongIndices[i] = -1; } if (CBase.Songs.GetNumCategories() == 0 || _ScreenSongOptions.Sorting.Tabs == EOffOn.TR_CONFIG_OFF) _GameData.CatSongIndices = null; } } }