From 3bdf22c8708b99e98075ab8f9f347e052f8c960e Mon Sep 17 00:00:00 2001 From: McSchneidar <262792195+McSchneidar@users.noreply.github.com> Date: Sun, 18 Oct 2026 08:20:24 +0200 Subject: [PATCH] New party mode: Partner Swap (#915) * Add partner swap party mode A new party mode for 3 to 12 players that only needs 2 microphones. Everyone plays for themselves, but always sings together with a partner. Both singers get the score of the pair, and the partners change every round. - In each round every player sings once, with a partner they haven't sung with yet; with an odd number of players someone takes a break, in turns - Ranking by the average score per song, so breaks are no disadvantage - Optional harmony bonus of 500 points when both singers are no more than 500 points apart - Duet songs are sung with both voices; duets can be mixed in, used exclusively or left out - Up to 3 jokers per player to skip a song - The best pair is shown all the time, and the winner and the best pair of the night are celebrated at the end * Rename the harmony bonus points constant to avoid shadowing --------- Co-authored-by: Florian Ostertag --- Output/PartyModes/PartnerSwap.xml | 20 + .../PartyModes/PartnerSwap/Languages/de.xml | 42 + .../PartyModes/PartnerSwap/Languages/en.xml | 42 + .../PartyModes/PartnerSwap/Themes/Default.xml | 10 + .../PartnerSwap/Themes/Default/Default.xml | 15 + .../Themes/Default/PartyModeIcon.png | Bin 0 -> 7476 bytes .../Screens/PartyScreenPartnerSwapConfig.xml | 407 +++++++++ .../Screens/PartyScreenPartnerSwapMain.xml | 738 ++++++++++++++++ .../Screens/PartyScreenPartnerSwapNames.xml | 382 +++++++++ .../Screens/PartyScreenPartnerSwapSongs.xml | 407 +++++++++ .../CPartyModePartnerSwap.cs | 734 ++++++++++++++++ .../CPartyScreenPartnerSwapConfig.cs | 173 ++++ .../CPartyScreenPartnerSwapMain.cs | 527 ++++++++++++ .../CPartyScreenPartnerSwapNames.cs | 74 ++ .../CPartyScreenPartnerSwapSongs.cs | 66 ++ .../GlobalSuppressions.cs | Bin 0 -> 1704 bytes .../PartyModePartnerSwap.csproj | 118 +++ .../PartyModePartnerSwap/Settings.StyleCop | 809 ++++++++++++++++++ Vocaluxe.sln | 23 + 19 files changed, 4587 insertions(+) create mode 100644 Output/PartyModes/PartnerSwap.xml create mode 100644 Output/PartyModes/PartnerSwap/Languages/de.xml create mode 100644 Output/PartyModes/PartnerSwap/Languages/en.xml create mode 100644 Output/PartyModes/PartnerSwap/Themes/Default.xml create mode 100644 Output/PartyModes/PartnerSwap/Themes/Default/Default.xml create mode 100644 Output/PartyModes/PartnerSwap/Themes/Default/PartyModeIcon.png create mode 100644 Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapConfig.xml create mode 100644 Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapMain.xml create mode 100644 Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapNames.xml create mode 100644 Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapSongs.xml create mode 100644 PartyModes/PartyModePartnerSwap/CPartyModePartnerSwap.cs create mode 100644 PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapConfig.cs create mode 100644 PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapMain.cs create mode 100644 PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapNames.cs create mode 100644 PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapSongs.cs create mode 100644 PartyModes/PartyModePartnerSwap/GlobalSuppressions.cs create mode 100644 PartyModes/PartyModePartnerSwap/PartyModePartnerSwap.csproj create mode 100644 PartyModes/PartyModePartnerSwap/Settings.StyleCop diff --git a/Output/PartyModes/PartnerSwap.xml b/Output/PartyModes/PartnerSwap.xml new file mode 100644 index 00000000..2b7446ac --- /dev/null +++ b/Output/PartyModes/PartnerSwap.xml @@ -0,0 +1,20 @@ + + + 2 + + TR_PARTYMODE_NAME + McSchneidar + TR_PARTYMODE_DESCRIPTION + PartnerSwap + CPartyModePartnerSwap + 1 + 0 + TR_PARTYMODE_AUDIENCE + + + CPartyScreenPartnerSwapMain + CPartyScreenPartnerSwapConfig + CPartyScreenPartnerSwapNames + CPartyScreenPartnerSwapSongs + + diff --git a/Output/PartyModes/PartnerSwap/Languages/de.xml b/Output/PartyModes/PartnerSwap/Languages/de.xml new file mode 100644 index 00000000..520024ee --- /dev/null +++ b/Output/PartyModes/PartnerSwap/Languages/de.xml @@ -0,0 +1,42 @@ + + + Deutsch + Partnertausch + Singt zu zweit mit ständig wechselnden Partnern. Beide Sänger bekommen die Punkte des Paares, der beste Durchschnitt gewinnt. + Für 3 bis 12 Spieler, die gern gemeinsam singen, 2 Mikrofone nötig. + Weiter + Zurück + Start + Beenden + Ja + Nein + Song starten + Songs + Partnertausch: Konfiguration + Anzahl der Spieler + Durchgänge + Gleichklang-Bonus + Duett-Songs + Gemischt + Nur Duette + Keine Duette + Joker pro Spieler + Partnertausch: Spieler auswählen + Zufällig wählen + Partnertausch + Willst du das Spiel wirklich beenden? + Pos + Name + Songs + Ø + Durchgang + Song + Pause: + singen zum ersten Mal zusammen + singen zum %n. Mal zusammen + Letzter Song: + Gleichklang-Bonus + Bestes Paar bisher + Bestes Paar des Abends + Sieger + diff --git a/Output/PartyModes/PartnerSwap/Languages/en.xml b/Output/PartyModes/PartnerSwap/Languages/en.xml new file mode 100644 index 00000000..b904cc81 --- /dev/null +++ b/Output/PartyModes/PartnerSwap/Languages/en.xml @@ -0,0 +1,42 @@ + + + English + Partner Swap + Sing in pairs with ever-changing partners. Both singers of a pair get the pair score, the best average wins. + For 3 to 12 players who like to sing together, 2 microphones needed. + Next + Back + Start + Exit + Yes + No + Start song + Songs + Partner Swap: Configuration + Number of players + Rounds + Harmony bonus + Duet songs + Mixed + Duets only + No duets + Jokers per player + Partner Swap: Choose Players + Select random + Partner Swap + Do you really want to exit the game? + Pos + Name + Songs + Ø + Round + Song + Taking a break: + singing together for the first time + singing together for the %n. time + Last song: + Harmony bonus + Best pair so far + Best pair of the night + Winner + diff --git a/Output/PartyModes/PartnerSwap/Themes/Default.xml b/Output/PartyModes/PartnerSwap/Themes/Default.xml new file mode 100644 index 00000000..97392ded --- /dev/null +++ b/Output/PartyModes/PartnerSwap/Themes/Default.xml @@ -0,0 +1,10 @@ + + + 9 + + Default + McSchneidar + 0 + 1 + + diff --git a/Output/PartyModes/PartnerSwap/Themes/Default/Default.xml b/Output/PartyModes/PartnerSwap/Themes/Default/Default.xml new file mode 100644 index 00000000..d88d34b4 --- /dev/null +++ b/Output/PartyModes/PartnerSwap/Themes/Default/Default.xml @@ -0,0 +1,15 @@ + + + 4 + + Default + McSchneidar + 0 + 1 + + + + PartyModeIcon.png + + + diff --git a/Output/PartyModes/PartnerSwap/Themes/Default/PartyModeIcon.png b/Output/PartyModes/PartnerSwap/Themes/Default/PartyModeIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..d19b643121c3456e3c9b8759934c3b187f041210 GIT binary patch literal 7476 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 + + + PartyScreenPartnerSwapConfig + 1 + + + + Video + + + BG_Default + + + + + + + + + 0 + 60 + 1920 + 67.5 + 1 + + + + + + 960 + 75 + 0 + 40.5 + 0 + + + Center + Center + + Outline + TR_SCREENCONFIG_TITLE + + + 112.5 + 157.5 + 0 + 40.5 + 0 + + + Left + Center + + Outline + TR_SCREENCONFIG_NUMPLAYERS + + + 112.5 + 247.5 + 0 + 40.5 + 0 + + + Left + Center + + Outline + TR_SCREENCONFIG_NUMPASSES + + + 112.5 + 337.5 + 0 + 40.5 + 0 + + + Left + Center + + Outline + TR_SCREENCONFIG_HARMONYBONUS + + + 112.5 + 427.5 + 0 + 40.5 + 0 + + + Left + Center + + Outline + TR_SCREENCONFIG_DUETS + + + 112.5 + 517.5 + 0 + 40.5 + 0 + + + Left + Center + + Outline + TR_SCREENCONFIG_NUMJOKERS + + + + + + + + + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 150 + 1050 + 75 + 0 + + + 757.5 + 157.5 + 60 + 60 + 0 + + + 1732.5 + 157.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 300 + Outline + Bold + 9 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 240 + 1050 + 75 + 0 + + + 757.5 + 247.5 + 60 + 60 + 0 + + + 1732.5 + 247.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 300 + Outline + Bold + 9 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 330 + 1050 + 75 + 0 + + + 757.5 + 337.5 + 60 + 60 + 0 + + + 1732.5 + 337.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 300 + Outline + Bold + 9 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 420 + 1050 + 75 + 0 + + + 757.5 + 427.5 + 60 + 60 + 0 + + + 1732.5 + 427.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 300 + Outline + Bold + 9 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 510 + 1050 + 75 + 0 + + + 757.5 + 517.5 + 60 + 60 + 0 + + + 1732.5 + 517.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 300 + Outline + Bold + 9 + + + + + + + + + diff --git a/Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapMain.xml b/Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapMain.xml new file mode 100644 index 00000000..26070008 --- /dev/null +++ b/Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapMain.xml @@ -0,0 +1,738 @@ + + + + PartyScreenPartnerSwapMain + 1 + + + + Video + + + BG_Default + + + + + + + + + 0 + 60 + 1920 + 67.5 + 1 + + + + PopupBG + + + 0 + 0 + 1920 + 1080 + -1 + + + + + + 0.1 + 0.09 + 0.25 + 0.75 + + + 30 + 190 + 760 + 720 + 0.8 + + + + + + 0.1 + 0.09 + 0.25 + 0.75 + + + 1470 + 190 + 420 + 292 + 0.8 + + + + + + 1 + 0.8 + 0 + 0.18 + + + 40 + 0 + 740 + 48 + 0.6 + + + + + + + 125 + 0 + 42 + 42 + 0.4 + + + + + + + 925 + 290 + 170 + 170 + 0.4 + + + + + + + 1165 + 290 + 170 + 170 + 0.4 + + + + + + + 1585 + 260 + 90 + 90 + 0.4 + + + + + + + 1685 + 260 + 90 + 90 + 0.4 + + + + + + 960 + 75 + 0 + 40.5 + 0 + + + Center + Center + + Outline + TR_SCREENMAIN_TITLE + + + 960 + 405 + -11 + 40.5 + 570 + + + Center + Center + + Outline + TR_SCREENMAIN_POPUP_REALLYEXIT + + + 110 + 205 + 0 + 34 + 0 + + 0.75 + 0.78 + 0.85 + 1 + + + Right + Center + + Outline + TR_SCREENMAIN_HEADER_POS + + + 180 + 205 + 0 + 34 + 0 + + 0.75 + 0.78 + 0.85 + 1 + + + Left + Center + + Outline + TR_SCREENMAIN_HEADER_NAME + + + 560 + 205 + 0 + 34 + 0 + + 0.75 + 0.78 + 0.85 + 1 + + + Right + Center + + Outline + TR_SCREENMAIN_HEADER_SONGS + + + 765 + 205 + 0 + 34 + 0 + + 0.75 + 0.78 + 0.85 + 1 + + + Right + Center + + Outline + TR_SCREENMAIN_HEADER_AVERAGE + + + 110 + 0 + 0 + 36 + 0 + + + Right + Center + + Outline + + + + 180 + 0 + 0 + 36 + 300 + + + Left + Center + + Outline + + + + 560 + 0 + 0 + 36 + 0 + + + Right + Center + + Outline + + + + 765 + 0 + 0 + 36 + 0 + + + Right + Center + + Outline + + + + 1130 + 205 + 0 + 32 + 620 + + 0.75 + 0.78 + 0.85 + 1 + + + Center + Center + + Outline + + + + 1010 + 478 + 0 + 38 + 220 + + + Center + Center + + Outline + + + + 1250 + 478 + 0 + 38 + 220 + + + Center + Center + + Outline + + + + 1130 + 345 + 0 + 56 + 0 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + & + + + 1130 + 535 + 0 + 30 + 620 + + 0.75 + 0.78 + 0.85 + 1 + + + Center + Center + + Outline + + + + 1130 + 575 + 0 + 30 + 620 + + 0.75 + 0.78 + 0.85 + 1 + + + Center + Center + + Outline + + + + 1130 + 660 + 0 + 32 + 640 + + + Center + Center + + Outline + + + + 1130 + 705 + 0 + 32 + 640 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + + + + 1680 + 210 + 0 + 32 + 400 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + TR_SCREENMAIN_BEST_PAIR + + + 1680 + 365 + 0 + 32 + 400 + + + Center + Center + + Outline + + + + 1680 + 410 + 0 + 48 + 0 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + + + + 1130 + 215 + 0 + 36 + 0 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + TR_SCREENMAIN_CHAMPION + + + 1130 + 262 + 0 + 64 + 600 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + + + + + + + + + + + + + + + + + + + + Star + + 850 + 200 + 560 + 380 + -1 + + + 1 + 0.8 + 0 + 0.6 + + Star + 18 + 40 + + + + diff --git a/Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapNames.xml b/Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapNames.xml new file mode 100644 index 00000000..3d8c2be7 --- /dev/null +++ b/Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapNames.xml @@ -0,0 +1,382 @@ + + + + PartyScreenPartnerSwapNames + 1 + + + + Video + + + BG_Default + + + + + + + + + 0 + 60 + 1920 + 67.5 + 1 + + + + + + 960 + 75 + 0 + 40.5 + 0 + + + Center + Center + + Outline + TR_SCREENNAMES_TITLE + + + + + + + + + + + + + + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 60 + 150 + 1800 + 75 + 0 + + + 67.5 + 157.5 + 60 + 60 + 0 + + + 1792.5 + 157.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 300 + Outline + Bold + 2 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlidePlayer + SelectSlideArrowLeft + SelectSlideArrowRight + + 60 + 240 + 1800 + 225 + 0 + + + 67.5 + 315 + 60 + 60 + 0 + + + 1792.5 + 315 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 5 + 300 + Outline + Bold + 8 + + + + + + + 142.5 + 525 + 1800 + 589.5 + 0 + + CoverTile + + PlayerSelector + + 150 + 150 + 10 + 2 + 15 + 15 + + -20 + 25.5 + Outline + + + + + + + + + + + diff --git a/Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapSongs.xml b/Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapSongs.xml new file mode 100644 index 00000000..d3129f36 --- /dev/null +++ b/Output/PartyModes/PartnerSwap/Themes/Default/Screens/PartyScreenPartnerSwapSongs.xml @@ -0,0 +1,407 @@ + + + + PartyScreenPartnerSwapSongs + 1 + + + + Video + + + BG_Default + + + + + + + + + 0 + 60 + 1920 + 67.5 + 1 + + + + + + 960 + 75 + 0 + 40.5 + 0 + + + Center + Center + + Outline + TR_SCREENCONFIG_TITLE + + + 112.5 + 157.5 + 0 + 40.5 + 0 + + + Left + Center + + Outline + TR_SONGSOURCE + + + 112.5 + 435 + 0 + 40.5 + 0 + + + Left + Center + + Outline + TR_GAMEMODE + + + + + + + + + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 150 + 1050 + 75 + 0 + + + 757.5 + 157.5 + 60 + 60 + 0 + + + 1732.5 + 157.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 308 + Outline + Bold + 3 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 240 + 1050 + 75 + 0 + + + 757.5 + 247.5 + 60 + 60 + 0 + + + 1732.5 + 247.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 900 + Outline + Bold + 3 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 240 + 1050 + 75 + 0 + + + 757.5 + 247.5 + 60 + 60 + 0 + + + 1732.5 + 247.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 900 + Outline + Bold + 3 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 330 + 1050 + 75 + 0 + + + 757.5 + 337.5 + 60 + 60 + 0 + + + 1732.5 + 337.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 900 + Outline + Bold + 1 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 435 + 1050 + 75 + 0 + + + 757.5 + 442.5 + 60 + 60 + 0 + + + 1732.5 + 442.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 308 + Outline + Bold + 2 + + + + SelectSlideArrowLeft + SelectSlideArrowRight + SelectSlide + SelectSlideArrowLeft + SelectSlideArrowRight + + 750 + 540 + 1050 + 75 + 0 + + + 757.5 + 547.5 + 60 + 60 + 0 + + + 1732.5 + 547.5 + 60 + 60 + 0 + + + + + + + + 40.5 + 75 + 0 + 308 + Outline + Bold + 5 + + + + + + + + + diff --git a/PartyModes/PartyModePartnerSwap/CPartyModePartnerSwap.cs b/PartyModes/PartyModePartnerSwap/CPartyModePartnerSwap.cs new file mode 100644 index 00000000..1fe85f75 --- /dev/null +++ b/PartyModes/PartyModePartnerSwap/CPartyModePartnerSwap.cs @@ -0,0 +1,734 @@ +#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.PartnerSwap +{ + public enum EDuetSongs + { + Mixed, + DuetsOnly, + NoDuets + } + + public class CSwapPlayer + { + public Guid ProfileId; + public int TotalPoints; + public int NumSongs; + public int Jokers; + + public int Average + { + get { return NumSongs == 0 ? 0 : (int)Math.Round((double)TotalPoints / NumSongs); } + } + } + + public class CSwapPair + { + public CSwapPlayer[] Players = new CSwapPlayer[2]; + public int[] Scores = new int[2]; + public int Bonus; + public bool Sung; + + public int PairScore + { + get { return Scores[0] + Scores[1] + Bonus; } + } + } + + public abstract class CPartyScreenPartnerSwap : CMenuParty + { + protected new CPartyModePartnerSwap _PartyMode; + + public override void Init() + { + base.Init(); + _PartyMode = (CPartyModePartnerSwap)base._PartyMode; + } + } + + public sealed class CPartyModePartnerSwap : CPartyMode + { + public const int PlayersPerSong = 2; + public const int MaxJokers = 3; + public const int HarmonyRange = 500; + public const int HarmonyBonusPoints = 500; + + public override int MinMics + { + get { return PlayersPerSong; } + } + public override int MaxMics + { + get { return CBase.Config.GetMaxNumMics(); } + } + public override int MinPlayers + { + get { return 3; } + } + 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, + Songs, + Names, + Main, + SongSelection, + Singing, + MedleySinging + } + + public struct SData + { + public int NumPlayer; + public int NumPasses; + public bool HarmonyBonus; + public EDuetSongs DuetSongs; + public int NumJokers; + public List ProfileIds; + + public ESongSource SongSource; + public ESongSorting Sorting; + public int CategoryIndex; + public int PlaylistId; + + public EGameMode GameMode; + public int NumMedleySongs; + + public List Players; + public List> Passes; + public List PassBreaks; + public int PassIndex; + public int PairIndex; + public int NumSongsSung; + public CSwapPair BestPair; + public CSwapPair LastPair; + public List PreviousRanking; + + public List Songs; + } + + public SData GameData; + private EStage _Stage; + + public CPartyModePartnerSwap(int id) : base(id) + { + _ScreenSongOptions.Selection.RandomOnly = false; + _ScreenSongOptions.Selection.PartyMode = true; + _ScreenSongOptions.Selection.CategoryChangeAllowed = true; + _ScreenSongOptions.Selection.NumJokers = new int[] { 1, 1 }; + _ScreenSongOptions.Selection.TeamNames = new string[] { "foo", "bar" }; + + _ScreenSongOptions.Sorting.SearchString = string.Empty; + _ScreenSongOptions.Sorting.SearchActive = false; + _ScreenSongOptions.Sorting.DuetOptions = EDuetOptions.All; + _ScreenSongOptions.Sorting.FilterPlaylistId = -1; + + GameData = new SData + { + NumPlayer = 6, + NumPasses = 3, + HarmonyBonus = true, + DuetSongs = EDuetSongs.Mixed, + NumJokers = 1, + ProfileIds = new List(), + Sorting = CBase.Config.GetSongSorting(), + SongSource = ESongSource.TR_SONGSOURCE_ALLSONGS, + PlaylistId = 0, + CategoryIndex = 0, + GameMode = EGameMode.TR_GAMEMODE_NORMAL, + NumMedleySongs = 5, + Players = new List(), + Passes = new List>(), + PassBreaks = new List(), + PreviousRanking = new List(), + Songs = new List() + }; + } + + public override void SetDefaults() + { + _Stage = EStage.Config; + + _ScreenSongOptions.Sorting.IgnoreArticles = CBase.Config.GetIgnoreArticles(); + _ScreenSongOptions.Sorting.SongSorting = CBase.Config.GetSongSorting(); + _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_OFF; + _ScreenSongOptions.Selection.SongIndex = -1; + _ScreenSongOptions.Selection.CategoryIndex = -1; + + if (CBase.Config.GetTabs() == EOffOn.TR_CONFIG_ON && _ScreenSongOptions.Sorting.SongSorting != ESongSorting.TR_CONFIG_NONE) + { + _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_ON; + } + } + + public override bool Init() + { + if (!base.Init()) + { + return false; + } + + SetDefaults(); + return true; + } + + public override void UpdateGame() { } + + public static int GetMaxPasses(int numPlayer) + { + return numPlayer % 2 == 0 ? numPlayer - 1 : numPlayer; + } + + public bool IsFinished + { + get { return GameData.Passes.Count > 0 && GameData.PassIndex >= GameData.Passes.Count; } + } + + public CSwapPair CurrentPair + { + get + { + if (IsFinished || GameData.Passes.Count == 0) + { + return null; + } + + return GameData.Passes[GameData.PassIndex][GameData.PairIndex]; + } + } + + public CSwapPlayer CurrentBreak + { + get { return IsFinished || GameData.PassIndex >= GameData.PassBreaks.Count ? null : GameData.PassBreaks[GameData.PassIndex]; } + } + + public List GetRanking() + { + return GameData.Players.OrderByDescending(player => player.Average).ThenByDescending(player => player.TotalPoints).ToList(); + } + + public int GetTimesTogether(CSwapPlayer player1, CSwapPlayer player2) + { + var count = 0; + foreach (var pass in GameData.Passes) + { + foreach (var pair in pass) + { + if (pair.Sung && pair.Players.Contains(player1) && pair.Players.Contains(player2)) + { + count++; + } + } + } + + return count; + } + + private IMenu _GetNextScreen() + { + switch (_Stage) + { + case EStage.Config: + return _Screens["CPartyScreenPartnerSwapConfig"]; + case EStage.Songs: + return _Screens["CPartyScreenPartnerSwapSongs"]; + case EStage.Names: + return _Screens["CPartyScreenPartnerSwapNames"]; + case EStage.Main: + return _Screens["CPartyScreenPartnerSwapMain"]; + case EStage.SongSelection: + return CBase.Graphics.GetScreen(EScreen.Song); + case EStage.Singing: + case EStage.MedleySinging: + return CBase.Graphics.GetScreen(EScreen.Sing); + default: + throw new ArgumentException("Invalid stage: " + _Stage); + } + } + + private void _FadeToScreen() + { + CBase.Graphics.FadeTo(_GetNextScreen()); + } + + public void Next() + { + switch (_Stage) + { + case EStage.Config: + _Stage = EStage.Songs; + break; + case EStage.Songs: + _Stage = EStage.Names; + break; + case EStage.Names: + _Stage = EStage.Main; + _StartGame(); + break; + case EStage.Main: + if (CurrentPair == null) + { + return; + } + + if (GameData.GameMode == EGameMode.TR_GAMEMODE_MEDLEY) + { + _Stage = EStage.MedleySinging; + _PrepareMedleyRound(); + } + else + { + _Stage = EStage.SongSelection; + _PrepareSongSelection(); + } + + break; + case EStage.SongSelection: + _Stage = EStage.Singing; + break; + case EStage.MedleySinging: + case EStage.Singing: + _Stage = EStage.Main; + _UpdateScores(); + break; + default: + throw new ArgumentException("Invalid stage: " + _Stage); + } + + _FadeToScreen(); + } + + public void Back() + { + switch (_Stage) + { + case EStage.Config: + CBase.Graphics.FadeTo(EScreen.Party); + return; + case EStage.Songs: + _Stage = EStage.Config; + break; + case EStage.Names: + _Stage = EStage.Songs; + break; + case EStage.Main: + _Stage = EStage.Names; + break; + default: + throw new ArgumentException("Invalid stage: " + _Stage); + } + + _FadeToScreen(); + } + + public override IMenu GetStartScreen() + { + return _Screens["CPartyScreenPartnerSwapConfig"]; + } + + public override SScreenSongOptions GetScreenSongOptions() + { + return _ScreenSongOptions; + } + + public override void OnSongChange(int songIndex, ref SScreenSongOptions screenSongOptions) + { + if (_ScreenSongOptions.Selection.SelectNextRandomSong && songIndex != -1) + { + _ScreenSongOptions.Selection.SelectNextRandomSong = false; + } + + _ScreenSongOptions.Selection.SongIndex = songIndex; + + screenSongOptions = _ScreenSongOptions; + } + + public override void OnCategoryChange(int categoryIndex, ref SScreenSongOptions screenSongOptions) + { + if (categoryIndex != -1 || CBase.Config.GetTabs() == EOffOn.TR_CONFIG_OFF) + { + _ScreenSongOptions.Selection.SelectNextRandomSong = true; + _ScreenSongOptions.Selection.RandomOnly = true; + } + else + { + _ScreenSongOptions.Selection.SongIndex = -1; + _ScreenSongOptions.Selection.RandomOnly = false; + } + + _ScreenSongOptions.Selection.CategoryIndex = categoryIndex; + + screenSongOptions = _ScreenSongOptions; + } + + public override void SetSearchString(string searchString, bool visible) + { + _ScreenSongOptions.Sorting.SearchString = searchString; + _ScreenSongOptions.Sorting.SearchActive = visible; + } + + public override void JokerUsed(int teamNr) + { + if (_ScreenSongOptions.Selection.NumJokers == null || teamNr >= _ScreenSongOptions.Selection.NumJokers.Length) + { + return; + } + + var pair = CurrentPair; + if (pair != null && pair.Players[teamNr].Jokers > 0) + { + pair.Players[teamNr].Jokers--; + } + + _ScreenSongOptions.Selection.NumJokers[teamNr]--; + _ScreenSongOptions.Selection.RandomOnly = true; + _ScreenSongOptions.Selection.CategoryChangeAllowed = false; + } + + public override void SongSelected(int songId) + { + _PrepareRound(new int[] { songId }); + + Next(); + } + + public override void LeavingHighscore() + { + for (var i = 0; i < CBase.Game.GetNumSongs(); i++) + { + CBase.Songs.AddPartySongSung(CBase.Game.GetSong(i).Id); + } + + Next(); + } + + private void _StartGame() + { + CBase.Songs.ResetSongSung(); + + GameData.Players = new List(); + foreach (var profileId in GameData.ProfileIds) + { + GameData.Players.Add(new CSwapPlayer { ProfileId = profileId, Jokers = GameData.NumJokers }); + } + + var slots = new List(GameData.Players); + slots.Shuffle(); + if (slots.Count % 2 == 1) + { + slots.Add(null); + } + + GameData.Passes = new List>(); + GameData.PassBreaks = new List(); + var numPasses = Math.Max(1, Math.Min(GameData.NumPasses, GetMaxPasses(GameData.Players.Count))); + for (var pass = 0; pass < numPasses; pass++) + { + var pairs = new List(); + CSwapPlayer pause = null; + for (var i = 0; i < slots.Count / 2; i++) + { + var player1 = slots[i]; + var player2 = slots[slots.Count - 1 - i]; + if (player1 == null || player2 == null) + { + pause = player1 ?? player2; + continue; + } + + var pair = new CSwapPair(); + pair.Players[0] = player1; + pair.Players[1] = player2; + pairs.Add(pair); + } + + pairs.Shuffle(); + GameData.Passes.Add(pairs); + GameData.PassBreaks.Add(pause); + + var last = slots[slots.Count - 1]; + slots.RemoveAt(slots.Count - 1); + slots.Insert(1, last); + } + + GameData.PassIndex = 0; + GameData.PairIndex = 0; + GameData.NumSongsSung = 0; + GameData.BestPair = null; + GameData.LastPair = null; + GameData.PreviousRanking = GetRanking(); + GameData.Songs = new List(); + } + + private EDuetOptions _GetDuetOptions() + { + switch (GameData.DuetSongs) + { + case EDuetSongs.NoDuets: + return EDuetOptions.NoDuets; + case EDuetSongs.DuetsOnly: + return CBase.Songs.GetSongs().Any(song => song.IsDuet) ? EDuetOptions.Duets : EDuetOptions.All; + default: + return EDuetOptions.All; + } + } + + private void _PrepareMedleyRound() + { + var songIds = new List(); + for (var i = 0; i < GameData.NumMedleySongs; i++) + { + if (GameData.Songs.Count == 0) + { + _UpdateSongList(); + } + + if (GameData.Songs.Count == 0) + { + break; + } + + songIds.Add(GameData.Songs[0]); + GameData.Songs.RemoveAt(0); + } + + _PrepareRound(songIds.ToArray()); + } + + private void _PrepareSongSelection() + { + _ScreenSongOptions.Selection.RandomOnly = true; + _ScreenSongOptions.Selection.SelectNextRandomSong = true; + + _ScreenSongOptions.Sorting.IgnoreArticles = CBase.Config.GetIgnoreArticles(); + _ScreenSongOptions.Sorting.DuetOptions = _GetDuetOptions(); + + switch (GameData.SongSource) + { + case ESongSource.TR_SONGSOURCE_ALLSONGS: + _ScreenSongOptions.Sorting.SongSorting = CBase.Config.GetSongSorting(); + _ScreenSongOptions.Sorting.Tabs = CBase.Config.GetTabs(); + _ScreenSongOptions.Sorting.FilterPlaylistId = -1; + + _ScreenSongOptions.Selection.SongIndex = -1; + _ScreenSongOptions.Selection.CategoryIndex = -1; + _ScreenSongOptions.Selection.CategoryChangeAllowed = true; + break; + + case ESongSource.TR_SONGSOURCE_CATEGORY: + _ScreenSongOptions.Sorting.SongSorting = GameData.Sorting; + _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_ON; + _ScreenSongOptions.Sorting.FilterPlaylistId = -1; + + _ScreenSongOptions.Selection.CategoryIndex = GameData.CategoryIndex; + _ScreenSongOptions.Selection.CategoryChangeAllowed = false; + break; + + case ESongSource.TR_SONGSOURCE_PLAYLIST: + _ScreenSongOptions.Sorting.SongSorting = CBase.Config.GetSongSorting(); + _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_OFF; + _ScreenSongOptions.Sorting.FilterPlaylistId = GameData.PlaylistId; + + _ScreenSongOptions.Selection.CategoryChangeAllowed = false; + break; + } + + var pair = CurrentPair; + _ScreenSongOptions.Selection.NumJokers = new int[] { pair.Players[0].Jokers, pair.Players[1].Jokers }; + _ScreenSongOptions.Selection.TeamNames = new string[] + { + CBase.Profiles.GetPlayerName(pair.Players[0].ProfileId), + CBase.Profiles.GetPlayerName(pair.Players[1].ProfileId) + }; + } + + private bool _PrepareRound(int[] songIds) + { + CBase.Game.Reset(); + CBase.Game.ClearSongs(); + + CBase.Game.SetNumPlayer(PlayersPerSong); + var players = CBase.Game.GetPlayers(); + var pair = CurrentPair; + if (players == null || players.Length < PlayersPerSong || pair == null) + { + return false; + } + + for (var p = 0; p < PlayersPerSong; p++) + { + players[p].ProfileId = pair.Players[p].ProfileId; + players[p].VoiceNr = p; + } + + foreach (var songId in songIds) + { + var song = CBase.Songs.GetSongById(songId); + var gameMode = GameData.GameMode; + if (gameMode != EGameMode.TR_GAMEMODE_MEDLEY) + { + if (song.IsDuet) + { + gameMode = EGameMode.TR_GAMEMODE_DUET; + } + else if (!song.IsGameModeAvailable(gameMode)) + { + gameMode = EGameMode.TR_GAMEMODE_NORMAL; + } + } + + CBase.Game.AddSong(songId, gameMode); + } + + return true; + } + + private void _UpdateSongList() + { + if (GameData.Songs.Count > 0) + { + return; + } + + switch (GameData.SongSource) + { + case ESongSource.TR_SONGSOURCE_PLAYLIST: + for (var i = 0; i < CBase.Playlist.GetSongCount(GameData.PlaylistId); i++) + { + var id = CBase.Playlist.GetSong(GameData.PlaylistId, i).SongId; + var song = CBase.Songs.GetSongById(id); + if (song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY) && !song.IsDuet) + { + GameData.Songs.Add(id); + } + } + + break; + + case ESongSource.TR_SONGSOURCE_ALLSONGS: + var avSongs = CBase.Songs.GetSongs(); + GameData.Songs.AddRange(avSongs.Where(song => song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY) && !song.IsDuet).Select(song => song.Id)); + break; + + case ESongSource.TR_SONGSOURCE_CATEGORY: + var oldSorting = CBase.Config.GetSongSorting(); + CBase.Songs.SortSongs(GameData.Sorting, EOffOn.TR_CONFIG_ON, CBase.Config.GetIgnoreArticles(), string.Empty, EDuetOptions.NoDuets, -1); + + CBase.Songs.SetCategory(GameData.CategoryIndex); + avSongs = CBase.Songs.GetVisibleSongs(); + GameData.Songs.AddRange(avSongs.Where(song => song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY) && !song.IsDuet).Select(song => song.Id)); + + CBase.Songs.SetCategory(-1); + CBase.Songs.SortSongs(oldSorting, CBase.Config.GetTabs(), CBase.Config.GetIgnoreArticles(), string.Empty, EDuetOptions.NoDuets, -1); + break; + } + + GameData.Songs.Shuffle(); + } + + private void _UpdateScores() + { + var pair = CurrentPair; + if (pair == null) + { + return; + } + + var points = CBase.Game.GetPoints(); + if (points == null || points.NumRounds == 0) + { + return; + } + + var scores = new double[PlayersPerSong]; + for (var round = 0; round < points.NumRounds; round++) + { + var res = points.GetPlayer(round, PlayersPerSong); + if (res == null || res.Length < PlayersPerSong) + { + return; + } + + for (var p = 0; p < PlayersPerSong; p++) + { + scores[p] += res[p].Points; + } + } + + GameData.PreviousRanking = GetRanking(); + + for (var p = 0; p < PlayersPerSong; p++) + { + pair.Scores[p] = (int)Math.Round(scores[p] / points.NumRounds); + } + + pair.Bonus = GameData.HarmonyBonus && Math.Abs(pair.Scores[0] - pair.Scores[1]) <= HarmonyRange ? HarmonyBonusPoints : 0; + pair.Sung = true; + + foreach (var player in pair.Players) + { + player.TotalPoints += pair.PairScore; + player.NumSongs++; + } + + if (GameData.BestPair == null || pair.PairScore > GameData.BestPair.PairScore) + { + GameData.BestPair = pair; + } + + GameData.LastPair = pair; + GameData.NumSongsSung++; + + GameData.PairIndex++; + if (GameData.PairIndex >= GameData.Passes[GameData.PassIndex].Count) + { + GameData.PairIndex = 0; + GameData.PassIndex++; + } + } + } +} diff --git a/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapConfig.cs b/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapConfig.cs new file mode 100644 index 00000000..f087a5a6 --- /dev/null +++ b/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapConfig.cs @@ -0,0 +1,173 @@ +#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.Windows.Forms; + +namespace VocaluxeLib.PartyModes.PartnerSwap +{ + public class CPartyScreenPartnerSwapConfig : CPartyScreenPartnerSwap + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private const string _SelectSlideNumPlayers = "SelectSlideNumPlayers"; + private const string _SelectSlideNumPasses = "SelectSlideNumPasses"; + private const string _SelectSlideHarmonyBonus = "SelectSlideHarmonyBonus"; + private const string _SelectSlideDuetSongs = "SelectSlideDuetSongs"; + private const string _SelectSlideNumJokers = "SelectSlideNumJokers"; + private const string _ButtonNext = "ButtonNext"; + private const string _ButtonBack = "ButtonBack"; + + public override void Init() + { + base.Init(); + + _ThemeSelectSlides = new string[] { _SelectSlideNumPlayers, _SelectSlideNumPasses, _SelectSlideHarmonyBonus, _SelectSlideDuetSongs, _SelectSlideNumJokers }; + _ThemeButtons = new string[] { _ButtonNext, _ButtonBack }; + } + + public override bool HandleInput(SKeyEvent keyEvent) + { + base.HandleInput(keyEvent); + + if (!keyEvent.KeyPressed) + { + switch (keyEvent.Key) + { + case Keys.Back: + case Keys.Escape: + _PartyMode.Back(); + break; + + case Keys.Enter: + _UpdateSlides(); + + if (_Buttons[_ButtonBack].Selected) + { + _PartyMode.Back(); + } + + if (_Buttons[_ButtonNext].Selected) + { + _PartyMode.Next(); + } + + break; + + case Keys.Left: + case Keys.Right: + _UpdateSlides(); + break; + } + } + + return true; + } + + public override bool HandleMouse(SMouseEvent mouseEvent) + { + base.HandleMouse(mouseEvent); + + if (mouseEvent.LB && _IsMouseOverCurSelection(mouseEvent)) + { + _UpdateSlides(); + if (_Buttons[_ButtonBack].Selected) + { + _PartyMode.Back(); + } + + if (_Buttons[_ButtonNext].Selected) + { + _PartyMode.Next(); + } + } + + if (mouseEvent.RB) + { + _PartyMode.Back(); + } + + return true; + } + + public override void OnShow() + { + base.OnShow(); + + _SelectSlides[_SelectSlideNumPlayers].Clear(); + for (var i = _PartyMode.MinPlayers; i <= _PartyMode.MaxPlayers; i++) + { + _SelectSlides[_SelectSlideNumPlayers].AddValue(i.ToString()); + } + + _SelectSlides[_SelectSlideNumPlayers].SelectedValue = _PartyMode.GameData.NumPlayer.ToString(); + + _UpdatePassesSlide(); + + _SelectSlides[_SelectSlideHarmonyBonus].Clear(); + _SelectSlides[_SelectSlideHarmonyBonus].AddValue(CBase.Language.Translate("TR_BUTTON_NO", PartyModeId)); + _SelectSlides[_SelectSlideHarmonyBonus].AddValue(CBase.Language.Translate("TR_BUTTON_YES", PartyModeId)); + _SelectSlides[_SelectSlideHarmonyBonus].Selection = _PartyMode.GameData.HarmonyBonus ? 1 : 0; + + _SelectSlides[_SelectSlideDuetSongs].Clear(); + _SelectSlides[_SelectSlideDuetSongs].AddValue(CBase.Language.Translate("TR_SCREENCONFIG_DUETS_MIXED", PartyModeId)); + _SelectSlides[_SelectSlideDuetSongs].AddValue(CBase.Language.Translate("TR_SCREENCONFIG_DUETS_ONLY", PartyModeId)); + _SelectSlides[_SelectSlideDuetSongs].AddValue(CBase.Language.Translate("TR_SCREENCONFIG_DUETS_NONE", PartyModeId)); + _SelectSlides[_SelectSlideDuetSongs].Selection = (int)_PartyMode.GameData.DuetSongs; + + _SelectSlides[_SelectSlideNumJokers].Clear(); + for (var i = 0; i <= CPartyModePartnerSwap.MaxJokers; i++) + { + _SelectSlides[_SelectSlideNumJokers].AddValue(i.ToString()); + } + + _SelectSlides[_SelectSlideNumJokers].SelectedValue = _PartyMode.GameData.NumJokers.ToString(); + } + + public override bool UpdateGame() + { + return true; + } + + private void _UpdateSlides() + { + _PartyMode.GameData.NumPlayer = _SelectSlides[_SelectSlideNumPlayers].Selection + _PartyMode.MinPlayers; + _PartyMode.GameData.NumPasses = _SelectSlides[_SelectSlideNumPasses].Selection + 1; + _PartyMode.GameData.HarmonyBonus = _SelectSlides[_SelectSlideHarmonyBonus].Selection == 1; + _PartyMode.GameData.DuetSongs = (EDuetSongs)_SelectSlides[_SelectSlideDuetSongs].Selection; + _PartyMode.GameData.NumJokers = _SelectSlides[_SelectSlideNumJokers].Selection; + _UpdatePassesSlide(); + } + + private void _UpdatePassesSlide() + { + var maxPasses = CPartyModePartnerSwap.GetMaxPasses(_PartyMode.GameData.NumPlayer); + _PartyMode.GameData.NumPasses = Math.Max(1, Math.Min(maxPasses, _PartyMode.GameData.NumPasses)); + + _SelectSlides[_SelectSlideNumPasses].Clear(); + for (var i = 1; i <= maxPasses; i++) + { + _SelectSlides[_SelectSlideNumPasses].AddValue(i.ToString()); + } + + _SelectSlides[_SelectSlideNumPasses].Selection = _PartyMode.GameData.NumPasses - 1; + } + } +} diff --git a/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapMain.cs b/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapMain.cs new file mode 100644 index 00000000..f5a1bfd9 --- /dev/null +++ b/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapMain.cs @@ -0,0 +1,527 @@ +#region license +// This file is part of Vocaluxe. +// +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Windows.Forms; +using VocaluxeLib.Menu; + +namespace VocaluxeLib.PartyModes.PartnerSwap +{ + class CRankRow + { + public CSwapPlayer Player; + public CStatic Highlight; + public CStatic Avatar; + public CText Pos; + public CText Name; + public CText Songs; + public CText Average; + public int OldRank; + public int NewRank; + } + + public class CPartyScreenPartnerSwapMain : CPartyScreenPartnerSwap + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private const string _TextPopupReallyExit = "TextPopupReallyExit"; + private const string _TextPass = "TextPass"; + private const string _TextRowPos = "TextRowPos"; + private const string _TextRowName = "TextRowName"; + private const string _TextRowSongs = "TextRowSongs"; + private const string _TextRowAverage = "TextRowAverage"; + private const string _TextPairName1 = "TextPairName1"; + private const string _TextPairName2 = "TextPairName2"; + private const string _TextAmp = "TextAmp"; + private const string _TextTogether = "TextTogether"; + private const string _TextPause = "TextPause"; + private const string _TextLastResult = "TextLastResult"; + private const string _TextHarmony = "TextHarmony"; + private const string _TextBestLabel = "TextBestLabel"; + private const string _TextBestNames = "TextBestNames"; + private const string _TextBestScore = "TextBestScore"; + private const string _TextChampionLabel = "TextChampionLabel"; + private const string _TextChampion = "TextChampion"; + + private const string _ButtonNextRound = "ButtonNextRound"; + private const string _ButtonBack = "ButtonBack"; + private const string _ButtonExit = "ButtonExit"; + private const string _ButtonPopupYes = "ButtonPopupYes"; + private const string _ButtonPopupNo = "ButtonPopupNo"; + + private const string _StaticPopupBG = "StaticPopupBG"; + private const string _StaticRowHighlight = "StaticRowHighlight"; + private const string _StaticRowAvatar = "StaticRowAvatar"; + private const string _StaticPairAvatar1 = "StaticPairAvatar1"; + private const string _StaticPairAvatar2 = "StaticPairAvatar2"; + private const string _StaticBestAvatar1 = "StaticBestAvatar1"; + private const string _StaticBestAvatar2 = "StaticBestAvatar2"; + + private const string _ParticleEffectChampion = "ParticleEffectChampion"; + + private const float _FirstRowY = 260f; + private const float _RowStep = 54f; + private const float _RankDelay = 300f; + private const float _RankDuration = 700f; + private const float _PopDuration = 700f; + + private readonly string[] _RankColors = new string[] { "Top1Color", "Top2Color", "Top3Color" }; + + private bool _ExitPopupVisible; + private List _Rows; + private readonly Stopwatch _AnimTimer = new Stopwatch(); + private bool _ShowNewResult; + private int _LastSeenSongs = -1; + private float _LastResultHeight; + private float _HarmonyHeight; + private float _ChampionHeight; + private SRectF _PairAvatar1Rect; + + public override void Init() + { + base.Init(); + + _ThemeTexts = new string[] + { + _TextPopupReallyExit, _TextPass, _TextRowPos, _TextRowName, _TextRowSongs, _TextRowAverage, _TextPairName1, _TextPairName2, _TextAmp, _TextTogether, + _TextPause, _TextLastResult, _TextHarmony, _TextBestLabel, _TextBestNames, _TextBestScore, _TextChampionLabel, _TextChampion + }; + _ThemeButtons = new string[] { _ButtonNextRound, _ButtonBack, _ButtonExit, _ButtonPopupYes, _ButtonPopupNo }; + _ThemeStatics = new string[] + { + _StaticPopupBG, _StaticRowHighlight, _StaticRowAvatar, _StaticPairAvatar1, _StaticPairAvatar2, _StaticBestAvatar1, + _StaticBestAvatar2 + }; + _ThemeParticleEffects = new string[] { _ParticleEffectChampion }; + } + + public override void LoadTheme(string xmlPath) + { + base.LoadTheme(xmlPath); + + _Rows = new List(); + for (var i = 0; i < _PartyMode.MaxPlayers; i++) + { + var row = new CRankRow + { + Highlight = GetNewStatic(_Statics[_StaticRowHighlight]), + Avatar = GetNewStatic(_Statics[_StaticRowAvatar]), + Pos = GetNewText(_Texts[_TextRowPos]), + Name = GetNewText(_Texts[_TextRowName]), + Songs = GetNewText(_Texts[_TextRowSongs]), + Average = GetNewText(_Texts[_TextRowAverage]) + }; + row.Avatar.Aspect = EAspect.Crop; + _AddStatic(row.Highlight); + _AddStatic(row.Avatar); + _AddText(row.Pos); + _AddText(row.Name); + _AddText(row.Songs); + _AddText(row.Average); + _Rows.Add(row); + } + + _Statics[_StaticRowHighlight].Visible = false; + _Statics[_StaticRowAvatar].Visible = false; + _Texts[_TextRowPos].Visible = false; + _Texts[_TextRowName].Visible = false; + _Texts[_TextRowSongs].Visible = false; + _Texts[_TextRowAverage].Visible = false; + + _Statics[_StaticPairAvatar1].Aspect = EAspect.Crop; + _Statics[_StaticPairAvatar2].Aspect = EAspect.Crop; + _Statics[_StaticBestAvatar1].Aspect = EAspect.Crop; + _Statics[_StaticBestAvatar2].Aspect = EAspect.Crop; + _PairAvatar1Rect = _Statics[_StaticPairAvatar1].Rect; + + _LastResultHeight = _Texts[_TextLastResult].Font.Height; + _HarmonyHeight = _Texts[_TextHarmony].Font.Height; + _ChampionHeight = _Texts[_TextChampion].Font.Height; + } + + public override bool HandleInput(SKeyEvent keyEvent) + { + base.HandleInput(keyEvent); + + if (!keyEvent.KeyPressed) + { + switch (keyEvent.Key) + { + case Keys.Back: + case Keys.Escape: + _OnBack(); + break; + + case Keys.Enter: + _OnSelect(); + break; + } + } + + return true; + } + + public override bool HandleMouse(SMouseEvent mouseEvent) + { + base.HandleMouse(mouseEvent); + + if (mouseEvent.LB && _IsMouseOverCurSelection(mouseEvent)) + { + _OnSelect(); + } + + if (mouseEvent.RB) + { + _OnBack(); + } + + return true; + } + + public override void OnShow() + { + base.OnShow(); + + _ShowNewResult = _PartyMode.GameData.LastPair != null && _PartyMode.GameData.NumSongsSung != _LastSeenSongs; + _LastSeenSongs = _PartyMode.GameData.NumSongsSung; + + _UpdateRanking(); + _UpdatePair(); + _UpdateBestPair(); + _UpdateLastResult(); + + _AnimTimer.Reset(); + _AnimTimer.Start(); + _UpdateAnimations(); + + var started = _PartyMode.GameData.NumSongsSung > 0; + _Buttons[_ButtonBack].Visible = !started; + _Buttons[_ButtonExit].Visible = started; + _Buttons[_ButtonNextRound].Visible = !_PartyMode.IsFinished; + + _ShowPopup(false); + + if (_PartyMode.IsFinished) + { + _SelectElement(_Buttons[_ButtonExit]); + } + else + { + _SelectElement(_Buttons[_ButtonNextRound]); + } + } + + public override bool UpdateGame() + { + _UpdateAnimations(); + return true; + } + + private void _OnBack() + { + if (_ExitPopupVisible) + { + _ShowPopup(false); + } + else if (_PartyMode.GameData.NumSongsSung == 0) + { + _PartyMode.Back(); + } + else if (_PartyMode.IsFinished) + { + _EndParty(); + } + else + { + _ShowPopup(true); + } + } + + private void _OnSelect() + { + if (_ExitPopupVisible) + { + if (_Buttons[_ButtonPopupYes].Selected) + { + _EndParty(); + } + + if (_Buttons[_ButtonPopupNo].Selected) + { + _ShowPopup(false); + } + + return; + } + + if (_Buttons[_ButtonNextRound].Selected && _Buttons[_ButtonNextRound].Visible) + { + _PartyMode.Next(); + } + + if (_Buttons[_ButtonBack].Selected && _Buttons[_ButtonBack].Visible) + { + _PartyMode.Back(); + } + + if (_Buttons[_ButtonExit].Selected && _Buttons[_ButtonExit].Visible) + { + if (_PartyMode.IsFinished) + { + _EndParty(); + } + else + { + _ShowPopup(true); + } + } + } + + private void _EndParty() + { + CBase.Graphics.FadeTo(EScreen.Party); + } + + private void _ShowPopup(bool visible) + { + _ExitPopupVisible = visible; + + _Statics[_StaticPopupBG].Visible = _ExitPopupVisible; + _Texts[_TextPopupReallyExit].Visible = _ExitPopupVisible; + _Buttons[_ButtonPopupYes].Visible = _ExitPopupVisible; + _Buttons[_ButtonPopupNo].Visible = _ExitPopupVisible; + + if (_ExitPopupVisible) + { + _SelectElement(_Buttons[_ButtonPopupNo]); + } + } + + private static float _EaseInOut(float t) + { + return t < 0.5f ? 4f * t * t * t : 1f - (float)Math.Pow(-2f * t + 2f, 3) / 2f; + } + + private static float _EaseOutBack(float t) + { + const float c1 = 1.70158f; + const float c3 = c1 + 1f; + return 1f + c3 * (float)Math.Pow(t - 1f, 3) + c1 * (float)Math.Pow(t - 1f, 2); + } + + private string _GetName(CSwapPlayer player) + { + return CBase.Profiles.GetPlayerName(player.ProfileId); + } + + private string _GetPairNames(CSwapPair pair) + { + return _GetName(pair.Players[0]) + " & " + _GetName(pair.Players[1]); + } + + private void _UpdateRanking() + { + var ranking = _PartyMode.GetRanking(); + var previous = _ShowNewResult ? _PartyMode.GameData.PreviousRanking : ranking; + + for (var i = 0; i < _Rows.Count; i++) + { + var row = _Rows[i]; + var visible = i < ranking.Count; + row.Player = visible ? _PartyMode.GameData.Players[i] : null; + row.Avatar.Visible = visible; + row.Pos.Visible = visible; + row.Name.Visible = visible; + row.Songs.Visible = visible; + row.Average.Visible = visible; + row.Highlight.Visible = false; + if (!visible) + { + continue; + } + + row.NewRank = ranking.IndexOf(row.Player); + row.OldRank = previous.IndexOf(row.Player); + if (row.OldRank < 0) + { + row.OldRank = row.NewRank; + } + + row.Avatar.Texture = CBase.Profiles.GetAvatar(row.Player.ProfileId); + row.Name.Text = _GetName(row.Player); + row.Songs.Text = row.Player.NumSongs.ToString(); + row.Average.Text = row.Player.Average.ToString("N0"); + row.Pos.Text = (row.NewRank + 1) + "."; + row.Highlight.Visible = row.NewRank == 0 && row.Player.NumSongs > 0; + + SColorF rankColor; + var color = _Texts[_TextRowName].Color; + if (row.Player.NumSongs > 0 && row.NewRank < _RankColors.Length && CBase.Themes.GetColor(_RankColors[row.NewRank], PartyModeId, out rankColor)) + { + color = rankColor; + } + + row.Pos.Color = color; + row.Name.Color = color; + } + } + + private void _PlaceRow(CRankRow row, float y) + { + row.Highlight.Y = y + (_Texts[_TextRowName].H - row.Highlight.H) / 2; + row.Avatar.Y = y + (_Texts[_TextRowName].H - row.Avatar.H) / 2; + row.Pos.Y = y; + row.Name.Y = y; + row.Songs.Y = y; + row.Average.Y = y; + } + + private void _UpdatePair() + { + var finished = _PartyMode.IsFinished; + var pair = _PartyMode.CurrentPair; + var showPair = !finished && pair != null; + + _Statics[_StaticPairAvatar2].Visible = showPair; + _Texts[_TextPairName1].Visible = showPair; + _Texts[_TextPairName2].Visible = showPair; + _Texts[_TextAmp].Visible = showPair; + _Texts[_TextTogether].Visible = showPair; + _Texts[_TextPass].Visible = showPair; + + var pause = _PartyMode.CurrentBreak; + _Texts[_TextPause].Visible = showPair && pause != null; + if (pause != null) + { + _Texts[_TextPause].Text = CBase.Language.Translate("TR_SCREENMAIN_PAUSE", PartyModeId) + " " + _GetName(pause); + } + + _Statics[_StaticPairAvatar1].MaxRect = _PairAvatar1Rect; + _Statics[_StaticPairAvatar1].Visible = showPair || finished; + + if (showPair) + { + _Statics[_StaticPairAvatar1].Texture = CBase.Profiles.GetAvatar(pair.Players[0].ProfileId); + _Statics[_StaticPairAvatar2].Texture = CBase.Profiles.GetAvatar(pair.Players[1].ProfileId); + _Texts[_TextPairName1].Text = _GetName(pair.Players[0]); + _Texts[_TextPairName2].Text = _GetName(pair.Players[1]); + + var together = _PartyMode.GetTimesTogether(pair.Players[0], pair.Players[1]); + _Texts[_TextTogether].Text = together == 0 + ? CBase.Language.Translate("TR_SCREENMAIN_FIRST_TIME", PartyModeId) + : CBase.Language.Translate("TR_SCREENMAIN_TIMES_TOGETHER", PartyModeId).Replace("%n", (together + 1).ToString()); + + _Texts[_TextPass].Text = CBase.Language.Translate("TR_SCREENMAIN_PASS", PartyModeId) + " " + (_PartyMode.GameData.PassIndex + 1) + " / " + + _PartyMode.GameData.Passes.Count + " · " + CBase.Language.Translate("TR_SCREENMAIN_SONG", PartyModeId) + " " + + (_PartyMode.GameData.PairIndex + 1) + " / " + _PartyMode.GameData.Passes[_PartyMode.GameData.PassIndex].Count; + } + + _Texts[_TextChampionLabel].Visible = finished; + _Texts[_TextChampion].Visible = finished; + _ParticleEffects[_ParticleEffectChampion].Visible = finished; + + if (finished) + { + var champion = _PartyMode.GetRanking()[0]; + _Texts[_TextChampion].Text = _GetName(champion); + _Statics[_StaticPairAvatar1].Texture = CBase.Profiles.GetAvatar(champion.ProfileId); + var centerX = (_PairAvatar1Rect.X + _Statics[_StaticPairAvatar2].Rect.X + _Statics[_StaticPairAvatar2].Rect.W) / 2; + _Statics[_StaticPairAvatar1].X = centerX - _PairAvatar1Rect.W / 2; + _Statics[_StaticPairAvatar1].Y = _PairAvatar1Rect.Y + 60f; + } + } + + private void _UpdateBestPair() + { + var best = _PartyMode.GameData.BestPair; + var visible = best != null; + _Statics[_StaticBestAvatar1].Visible = visible; + _Statics[_StaticBestAvatar2].Visible = visible; + _Texts[_TextBestNames].Visible = visible; + _Texts[_TextBestScore].Visible = visible; + _Texts[_TextBestLabel].Text = _PartyMode.IsFinished ? "TR_SCREENMAIN_BEST_PAIR_FINAL" : "TR_SCREENMAIN_BEST_PAIR"; + + if (!visible) + { + return; + } + + _Statics[_StaticBestAvatar1].Texture = CBase.Profiles.GetAvatar(best.Players[0].ProfileId); + _Statics[_StaticBestAvatar2].Texture = CBase.Profiles.GetAvatar(best.Players[1].ProfileId); + _Texts[_TextBestNames].Text = _GetPairNames(best); + _Texts[_TextBestScore].Text = best.PairScore.ToString("N0"); + } + + private void _UpdateLastResult() + { + var last = _PartyMode.GameData.LastPair; + _Texts[_TextLastResult].Visible = last != null && !_PartyMode.IsFinished; + _Texts[_TextHarmony].Visible = last != null && last.Bonus > 0 && !_PartyMode.IsFinished; + + if (last == null) + { + return; + } + + _Texts[_TextLastResult].Text = CBase.Language.Translate("TR_SCREENMAIN_LAST_SONG", PartyModeId) + " " + _GetPairNames(last) + " · " + + last.PairScore.ToString("N0"); + _Texts[_TextHarmony].Text = CBase.Language.Translate("TR_SCREENMAIN_HARMONY_BONUS", PartyModeId) + " +" + last.Bonus; + } + + private void _UpdateAnimations() + { + var time = _AnimTimer.ElapsedMilliseconds; + + var rankProgress = _ShowNewResult ? _EaseInOut(Math.Max(0f, Math.Min(1f, (time - _RankDelay) / _RankDuration))) : 1f; + foreach (var row in _Rows) + { + if (row.Player == null) + { + continue; + } + + var oldY = _FirstRowY + row.OldRank * _RowStep; + var newY = _FirstRowY + row.NewRank * _RowStep; + _PlaceRow(row, oldY + (newY - oldY) * rankProgress); + } + + var popScale = _ShowNewResult && time < _PopDuration ? 0.3f + 0.7f * _EaseOutBack(time / _PopDuration) : 1f; + _Texts[_TextLastResult].Font.Height = _LastResultHeight * popScale; + _Texts[_TextHarmony].Font.Height = _HarmonyHeight * popScale; + + if (_PartyMode.IsFinished) + { + float scale; + if (time < _PopDuration) + { + scale = 0.3f + 0.7f * _EaseOutBack(time / _PopDuration); + } + else + { + scale = 1f + 0.03f * (float)Math.Sin((time - _PopDuration) / 1000.0 * Math.PI * 1.4); + } + + _Texts[_TextChampion].Font.Height = _ChampionHeight * scale; + } + } + } +} diff --git a/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapNames.cs b/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapNames.cs new file mode 100644 index 00000000..f28695e4 --- /dev/null +++ b/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapNames.cs @@ -0,0 +1,74 @@ +#region license +// This file is part of Vocaluxe. +// +// Vocaluxe is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Vocaluxe is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Vocaluxe. If not, see . +#endregion + +using System; +using System.Collections.Generic; +using VocaluxeLib.Menu; + +namespace VocaluxeLib.PartyModes.PartnerSwap +{ + public class CPartyScreenPartnerSwapNames : CMenuPartyNameSelection + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private new CPartyModePartnerSwap _PartyMode; + + public override void Init() + { + base.Init(); + _PartyMode = (CPartyModePartnerSwap)base._PartyMode; + _AllowChangePlayerNum = false; + _Teams = false; + } + + public override void OnShow() + { + base.OnShow(); + SetPartyModeData(_PartyMode.GameData.NumPlayer); + while (_PartyMode.GameData.ProfileIds.Count > _NumPlayer) + { + _PartyMode.GameData.ProfileIds.RemoveAt(_PartyMode.GameData.ProfileIds.Count - 1); + } + + var ids = new List[] { _PartyMode.GameData.ProfileIds }; + SetPartyModeProfiles(ids); + } + + public override void Back() + { + if (_TeamList.Length == 1) + { + _PartyMode.GameData.ProfileIds = _TeamList[0]; + } + + _PartyMode.Back(); + } + + public override void Next() + { + if (_TeamList.Length == 1) + { + _PartyMode.GameData.ProfileIds = _TeamList[0]; + } + + _PartyMode.Next(); + } + } +} \ No newline at end of file diff --git a/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapSongs.cs b/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapSongs.cs new file mode 100644 index 00000000..0fa5df20 --- /dev/null +++ b/PartyModes/PartyModePartnerSwap/CPartyScreenPartnerSwapSongs.cs @@ -0,0 +1,66 @@ +using VocaluxeLib.Menu; + +namespace VocaluxeLib.PartyModes.PartnerSwap +{ + class CPartyScreenPartnerSwapSongs : CMenuPartySongSelection + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private new CPartyModePartnerSwap _PartyMode; + + public override void Init() + { + base.Init(); + _PartyMode = (CPartyModePartnerSwap)base._PartyMode; + } + + public override void OnShow() + { + Source = _PartyMode.GameData.SongSource; + Sorting = _PartyMode.GameData.Sorting; + Category = _PartyMode.GameData.CategoryIndex; + Playlist = _PartyMode.GameData.PlaylistId; + SongMode = _PartyMode.GameData.GameMode; + NumMedleySongs = _PartyMode.GameData.NumMedleySongs; + + base.OnShow(); + } + + public override void Back() + { + _SaveConfig(); + _PartyMode.Back(); + } + + public override void Next() + { + _SaveConfig(); + _PartyMode.Next(); + } + + public override bool UpdateGame() + { + return true; + } + + protected override void _SetAllowedOptions() + { + base._SetAllowedOptions(); + + AllowedSongModes = new EGameMode[] { EGameMode.TR_GAMEMODE_NORMAL, EGameMode.TR_GAMEMODE_SHORTSONG, EGameMode.TR_GAMEMODE_MEDLEY }; + } + + private void _SaveConfig() + { + _PartyMode.GameData.SongSource = Source; + _PartyMode.GameData.Sorting = Sorting; + _PartyMode.GameData.CategoryIndex = Category; + _PartyMode.GameData.PlaylistId = Playlist; + _PartyMode.GameData.GameMode = SongMode; + _PartyMode.GameData.NumMedleySongs = NumMedleySongs; + } + } +} \ No newline at end of file diff --git a/PartyModes/PartyModePartnerSwap/GlobalSuppressions.cs b/PartyModes/PartyModePartnerSwap/GlobalSuppressions.cs new file mode 100644 index 0000000000000000000000000000000000000000..e661ff030ad7d32272d04b4b0dafd6d8f44c9c78 GIT binary patch literal 1704 zcmbW2-)j>=5Xa|P@PAm+mljH@2tHU5Vl-7q+G0{m5g+p7(j1=2k-J#)&#RyB>|HOB z`e0cuyE{8O^PTU^PJaJ7u(c(2YpJblX~8m9QzT0(_>;YX^zfcAf(_k&!$q(jl8AW>&X~PpG!xeG zz9RnN*ox{r*b8L)k?doX1##7|a|miN8JU;O6%o`PkJyXjEpz6Yk->ex|5pJIJvlz5t376vMmJSUaTa}@Gh>DddcyWawgQVde_cU={$-5hTnm`$43|c(ND+Tf~W78 zgd$dM&-dr(4jIb+1-FD%H7A@SG`d94_no9yNH5VFa;uG=swh@dLww~7q0s4|n&l(0Lu(ea{s7Ok8_oa# literal 0 HcmV?d00001 diff --git a/PartyModes/PartyModePartnerSwap/PartyModePartnerSwap.csproj b/PartyModes/PartyModePartnerSwap/PartyModePartnerSwap.csproj new file mode 100644 index 00000000..f015ffb3 --- /dev/null +++ b/PartyModes/PartyModePartnerSwap/PartyModePartnerSwap.csproj @@ -0,0 +1,118 @@ + + + + DebugWin + AnyCPU + 8.0.30703 + 2.0 + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53} + Library + Properties + VocaluxeLib.PartyModes.PartnerSwap + PartnerSwap + v4.8.1 + + + 512 + + + AnyCPU + true + full + false + bin + TRACE;DEBUG;WIN + prompt + 4 + Off + ..\..\CheckingRules.ruleset + false + 9.0 + + + AnyCPU + pdbonly + true + bin + prompt + 4 + false + WIN + Off + false + true + 9.0 + + + AnyCPU + true + full + false + bin + TRACE;DEBUG;LINUX + prompt + 4 + Off + false + 9.0 + + + AnyCPU + pdbonly + true + bin + prompt + 4 + false + LINUX + Off + false + true + 9.0 + + + bin + WIN + true + AnyCPU + false + Off + prompt + ManagedMinimumRules.ruleset + false + pdbonly + true + 9.0 + + + + + + + + + + + + {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} + VocaluxeLib + False + + + + + + + + + + if exist "$(SolutionDir)Output\PartyModes\$(TargetName)\Code" rd "$(SolutionDir)Output\PartyModes\$(TargetName)\Code" /S /Q +cd $(SolutionDir)Partymodes\ +xcopy "$(ProjectDir)*.cs" "$(SolutionDir)Output\PartyModes\$(TargetName)\Code\" /EXCLUDE:Excludes.txt /I /Y + rm -rf "$(SolutionDir)Output\PartyModes\$(TargetName)\Code" +mkdir -p "$(SolutionDir)Output\PartyModes\$(TargetName)\Code\" +cp -R $(ProjectDir)*.cs "$(SolutionDir)Output\PartyModes\$(TargetName)\Code\" +rm -f "$(SolutionDir)Output\PartyModes\$(TargetName)\Code\GlobalSuppressions.cs" + + + \ No newline at end of file diff --git a/PartyModes/PartyModePartnerSwap/Settings.StyleCop b/PartyModes/PartyModePartnerSwap/Settings.StyleCop new file mode 100644 index 00000000..f4a4ea2a --- /dev/null +++ b/PartyModes/PartyModePartnerSwap/Settings.StyleCop @@ -0,0 +1,809 @@ + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + False + + + + + + + \ No newline at end of file diff --git a/Vocaluxe.sln b/Vocaluxe.sln index 2681e92a..ad929fc1 100644 --- a/Vocaluxe.sln +++ b/Vocaluxe.sln @@ -7,6 +7,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocalu {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41} = {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41} {55F89808-4E79-4FFE-BC13-48258913F5C9} = {55F89808-4E79-4FFE-BC13-48258913F5C9} {6F3E1874-F28A-40E9-AFBD-31934D593679} = {6F3E1874-F28A-40E9-AFBD-31934D593679} + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53} = {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53} {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} = {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} {5A4053F1-5AD5-441F-B254-D97A088127B6} = {5A4053F1-5AD5-441F-B254-D97A088127B6} {54A48AF7-515C-4EDD-B395-2BFFA096050A} = {54A48AF7-515C-4EDD-B395-2BFFA096050A} @@ -14,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocalu EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VocaluxeLib", "VocaluxeLib\VocaluxeLib.csproj", "{D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModePartnerSwap", "PartyModes\PartyModePartnerSwap\PartyModePartnerSwap.csproj", "{9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeTicTacToe", "PartyModes\PartyModeTicTacToe\PartyModeTicTacToe.csproj", "{6F3E1874-F28A-40E9-AFBD-31934D593679}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeChallenge", "PartyModes\PartyModeChallenge\PartyModeChallenge.csproj", "{5A4053F1-5AD5-441F-B254-D97A088127B6}" @@ -80,6 +83,26 @@ Global {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.DebugLinux|x64.ActiveCfg = DebugLinux|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.DebugLinux|x64.Build.0 = DebugLinux|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.DebugLinux|x86.ActiveCfg = DebugLinux|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.DebugLinux|x86.Build.0 = DebugLinux|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.DebugWin|x64.ActiveCfg = DebugWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.DebugWin|x64.Build.0 = DebugWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.DebugWin|x86.ActiveCfg = DebugWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.DebugWin|x86.Build.0 = DebugWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.InstallerWin|x64.ActiveCfg = InstallerWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.InstallerWin|x64.Build.0 = InstallerWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.InstallerWin|x86.ActiveCfg = InstallerWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.InstallerWin|x86.Build.0 = InstallerWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.ReleaseLinux|x64.Build.0 = ReleaseLinux|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.ReleaseLinux|x86.ActiveCfg = ReleaseLinux|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.ReleaseLinux|x86.Build.0 = ReleaseLinux|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.ReleaseWin|x64.ActiveCfg = ReleaseWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU + {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU {6F3E1874-F28A-40E9-AFBD-31934D593679}.DebugLinux|x64.ActiveCfg = DebugLinux|Any CPU {6F3E1874-F28A-40E9-AFBD-31934D593679}.DebugLinux|x64.Build.0 = DebugLinux|Any CPU {6F3E1874-F28A-40E9-AFBD-31934D593679}.DebugLinux|x86.ActiveCfg = DebugLinux|Any CPU