#region license // This file is part of Vocaluxe. // // Vocaluxe is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Vocaluxe is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Vocaluxe. If not, see . #endregion using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using VocaluxeLib.Menu; using VocaluxeLib.Utils; [assembly: ComVisible(false)] namespace VocaluxeLib.PartyModes.TicTacToe { public class CRound { public int[] SongIds; public int SingerTeam1; public int SingerTeam2; public int PointsTeam1; public int PointsTeam2; public int Winner; public bool Finished; } public abstract class CPartyScreenTicTacToe : CMenuParty { protected new CPartyModeTicTacToe _PartyMode; public override void Init() { base.Init(); _PartyMode = (CPartyModeTicTacToe)base._PartyMode; } } // ReSharper disable ClassNeverInstantiated.Global public sealed class CPartyModeTicTacToe : CPartyMode // ReSharper restore ClassNeverInstantiated.Global { 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; } } public readonly EGameMode[] AvailableGameModes = { EGameMode.TR_GAMEMODE_NORMAL, EGameMode.TR_GAMEMODE_SHORTSONG, EGameMode.TR_GAMEMODE_DUET }; private enum EStage { Config, Songs, Names, Main, Singing } public struct SData { public int NumPlayerTeam1; public int NumPlayerTeam2; public int NumFields; public int NumJockers; public int Team; public List ProfileIdsTeam1; public List ProfileIdsTeam2; public ESongSource SongSource; public ESongSorting Sorting; public int CategoryIndex; public int PlaylistId; public EGameMode GameMode; public int NumMedleySongs; public List Rounds; public List Songs; public int CurrentRoundNr; public int FieldNr; public int LastWonField; public int[] NumJokerRandom; public int[] NumJokerRetry; public EOffOn RefillJokers; public EOffOn SwitchPlayer; } public SData GameData; private EStage _Stage; public CPartyModeTicTacToe(int id) : base(id) { _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; GameData = new SData { NumPlayerTeam1 = 2, NumPlayerTeam2 = 2, NumFields = 9, NumJockers = 1, ProfileIdsTeam1 = new List(), ProfileIdsTeam2 = new List(), CurrentRoundNr = 0, FieldNr = 0, Sorting = CBase.Config.GetSongSorting(), SongSource = ESongSource.TR_SONGSOURCE_ALLSONGS, PlaylistId = 0, CategoryIndex = 0, GameMode = EGameMode.TR_GAMEMODE_NORMAL, NumMedleySongs = 5, Rounds = new List(), Songs = new List(), NumJokerRandom = new int[2], NumJokerRetry = new int[2], RefillJokers = EOffOn.TR_CONFIG_OFF }; } public override void SetDefaults() { _Stage = EStage.Config; _ScreenSongOptions.Sorting.IgnoreArticles = CBase.Config.GetIgnoreArticles(); _ScreenSongOptions.Sorting.SongSorting = CBase.Config.GetSongSorting(); _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_OFF; _ScreenSongOptions.Selection.SongIndex = -1; if (CBase.Config.GetTabs() == EOffOn.TR_CONFIG_ON && _ScreenSongOptions.Sorting.SongSorting != ESongSorting.TR_CONFIG_NONE) { _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_ON; } GameData.Songs.Clear(); GameData.Rounds.Clear(); } public override bool Init() { if (!base.Init()) { return false; } SetDefaults(); return true; } public override void UpdateGame() { /* if (CBase.Songs.IsInCategory() || _ScreenSongOptions.Sorting.Tabs == EOffOn.TR_CONFIG_OFF) _ScreenSongOptions.Selection.RandomOnly = true; else _ScreenSongOptions.Selection.RandomOnly = false;*/ } private IMenu _GetNextScreen() { switch (_Stage) { case EStage.Config: return _Screens["CPartyScreenTicTacToeConfig"]; case EStage.Songs: return _Screens["CPartyScreenTicTacToeSongs"]; case EStage.Names: return _Screens["CPartyScreenTicTacToeNames"]; case EStage.Main: return _Screens["CPartyScreenTicTacToeMain"]; case EStage.Singing: return CBase.Graphics.GetScreen(EScreen.Sing); default: throw new ArgumentException("Invalid stage: " + _Stage); } } private void _FadeToScreen() { if (CBase.Graphics.GetNextScreen() != _GetNextScreen()) { CBase.Graphics.FadeTo(_GetNextScreen()); } } public void Next() { switch (_Stage) { case EStage.Config: _Stage = EStage.Songs; break; case EStage.Songs: _Stage = EStage.Names; break; case EStage.Names: _Stage = EStage.Main; GameData.Team = CBase.Game.GetRandom(100) < 50 ? 0 : 1; CBase.Songs.ResetSongSung(); GameData.CurrentRoundNr = 1; GameData.LastWonField = -1; _CreateRounds(); _SetNumJokers(); break; case EStage.Main: _Stage = EStage.Singing; _StartRound(GameData.FieldNr); break; case EStage.Singing: _Stage = EStage.Main; GameData.Team = GameData.Team == 1 ? 0 : 1; if (GameData.RefillJokers == EOffOn.TR_CONFIG_ON) { _SetNumJokers(); } break; default: throw new ArgumentException("Invalid stage: " + _Stage); } _FadeToScreen(); } public void Back() { switch (_Stage) { case EStage.Config: CBase.Graphics.FadeTo(EScreen.Party); return; case EStage.Songs: _Stage = EStage.Config; break; case EStage.Names: _Stage = EStage.Songs; break; case EStage.Main: _Stage = EStage.Names; break; default: // Rest is not allowed throw new ArgumentException("Invalid stage: " + _Stage); } _FadeToScreen(); } public override IMenu GetStartScreen() { return _Screens["CPartyScreenTicTacToeConfig"]; } public override SScreenSongOptions GetScreenSongOptions() { throw new ArgumentException("Not required!"); } public override void OnSongChange(int songIndex, ref SScreenSongOptions screenSongOptions) { throw new ArgumentException("Not required!"); } public override void OnCategoryChange(int categoryIndex, ref SScreenSongOptions screenSongOptions) { throw new ArgumentException("Not required!"); } public override void SetSearchString(string searchString, bool visible) { throw new ArgumentException("Not required!"); } public override void JokerUsed(int teamNr) { } public override void SongSelected(int songId) { throw new ArgumentException("Not required!"); } public override void LeavingHighscore() { CBase.Songs.AddPartySongSung(CBase.Game.GetSong(0).Id); _UpdateScores(); Next(); } private void _CreateRounds() { GameData.Rounds = new List(); for (var i = 0; i < GameData.NumFields; i++) { var r = new CRound(); GameData.Rounds.Add(r); } } public void UpdateSongList() { if (GameData.Songs.Count > 0) { return; } switch (GameData.SongSource) { case ESongSource.TR_SONGSOURCE_PLAYLIST: for (var i = 0; i < CBase.Playlist.GetSongCount(GameData.PlaylistId); i++) { var id = CBase.Playlist.GetSong(GameData.PlaylistId, i).SongId; if (CBase.Songs.GetSongById(id).IsGameModeAvailable(GameData.GameMode)) { GameData.Songs.Add(id); } } break; case ESongSource.TR_SONGSOURCE_ALLSONGS: var avSongs = CBase.Songs.GetSongs(); GameData.Songs.AddRange(avSongs.Where(song => song.IsGameModeAvailable(GameData.GameMode)).Select(song => song.Id)); break; case ESongSource.TR_SONGSOURCE_CATEGORY: CBase.Songs.SortSongs(GameData.Sorting, EOffOn.TR_CONFIG_ON, CBase.Config.GetIgnoreArticles(), "", EDuetOptions.All, -1); CBase.Songs.SetCategory(GameData.CategoryIndex); avSongs = CBase.Songs.GetVisibleSongs(); GameData.Songs.AddRange(avSongs.Where(song => song.IsGameModeAvailable(GameData.GameMode)).Select(song => song.Id)); CBase.Songs.SetCategory(-1); break; } GameData.Songs.Shuffle(); } private void _StartRound(int roundNr) { CBase.Game.Reset(); CBase.Game.ClearSongs(); CBase.Game.SetNumPlayer(2); var players = CBase.Game.GetPlayers(); if (players == null) { return; } if (players.Length < 2) { return; } var round = GameData.Rounds[roundNr]; for (var i = 0; i < 2; i++) { //default values players[i].ProfileId = Guid.Empty; } //try to fill with the right data players[0].ProfileId = GameData.ProfileIdsTeam1[round.SingerTeam1]; players[1].ProfileId = GameData.ProfileIdsTeam2[round.SingerTeam2]; foreach (var song in round.SongIds) { CBase.Game.AddSong(song, GameData.GameMode); } } private void _SetNumJokers() { GameData.NumJokerRandom[0] = GameData.NumJockers; GameData.NumJokerRandom[1] = GameData.NumJockers; switch (GameData.NumFields) { case 9: GameData.NumJokerRetry[0] = 0; GameData.NumJokerRetry[1] = 0; break; case 16: GameData.NumJokerRetry[0] = 1; GameData.NumJokerRetry[1] = 1; break; case 25: GameData.NumJokerRetry[0] = 2; GameData.NumJokerRetry[1] = 2; break; } } private void _UpdateScores() { if (!GameData.Rounds[GameData.FieldNr].Finished) { GameData.CurrentRoundNr++; } var points = CBase.Game.GetPoints(); var results = CBase.Game.GetPlayers(); if (results == null || results.Length < 2) { return; } //Sum up all points for (var r = 0; r < points.NumRounds; r++) { var player = points.GetPlayer(r, 2); for (var i = 0; i < 2; i++) { results[i].Points += player[i].Points; results[i].PointsGoldenNotes += player[i].PointsGoldenNotes; results[i].PointsLineBonus += player[i].PointsLineBonus; } } //Calc average of points for (var i = 0; i < 2; i++) { results[i].Points /= points.NumRounds; results[i].PointsGoldenNotes /= points.NumRounds; results[i].PointsLineBonus /= points.NumRounds; } //Decide who has won GameData.Rounds[GameData.FieldNr].PointsTeam1 = (int)Math.Round(results[0].Points); GameData.Rounds[GameData.FieldNr].PointsTeam2 = (int)Math.Round(results[1].Points); GameData.Rounds[GameData.FieldNr].Finished = true; GameData.LastWonField = GameData.FieldNr; if (GameData.Rounds[GameData.FieldNr].PointsTeam1 < GameData.Rounds[GameData.FieldNr].PointsTeam2) { GameData.Rounds[GameData.FieldNr].Winner = 2; } else if (GameData.Rounds[GameData.FieldNr].PointsTeam1 > GameData.Rounds[GameData.FieldNr].PointsTeam2) { GameData.Rounds[GameData.FieldNr].Winner = 1; } else { GameData.Rounds[GameData.FieldNr].Finished = false; GameData.LastWonField = -1; GameData.CurrentRoundNr--; } } } }