diff --git a/Output/PartyModes/TeamSurvival.xml b/Output/PartyModes/TeamSurvival.xml
new file mode 100644
index 00000000..28b3dce4
--- /dev/null
+++ b/Output/PartyModes/TeamSurvival.xml
@@ -0,0 +1,21 @@
+
+
+ 2
+
+ TR_PARTYMODE_NAME
+ McSchneidar
+ TR_PARTYMODE_DESCRIPTION
+ TeamSurvival
+ CPartyModeTeamSurvival
+ 1
+ 0
+ TR_PARTYMODE_AUDIENCE
+
+
+ CPartyScreenTeamSurvivalMain
+ CPartyScreenTeamSurvivalConfig
+ CPartyScreenTeamSurvivalNames
+ CPartyScreenTeamSurvivalSongs
+ CPartyScreenTeamSurvivalHearts
+
+
diff --git a/Output/PartyModes/TeamSurvival/Languages/de.xml b/Output/PartyModes/TeamSurvival/Languages/de.xml
new file mode 100644
index 00000000..04ffdf6a
--- /dev/null
+++ b/Output/PartyModes/TeamSurvival/Languages/de.xml
@@ -0,0 +1,36 @@
+
+
+ Deutsch
+ Team Survival
+ Zwei Teams singen Duelle, der Verlierer verliert ein Herz, das letzte Team gewinnt.
+ Für zwei Teams mit bis zu 8 Spielern, 2 Mikrofone nötig.
+ Weiter
+ Zurück
+ Beenden
+ Ja
+ Nein
+ Duell starten
+ Songs
+ Team
+ Team Survival: Konfiguration
+ Herzen
+ Für alle gleich
+ Pro Spieler festlegen
+ Herzen pro Spieler
+ Joker pro Spieler
+ Team Survival: Teams zusammenstellen
+ Ausgewählte Spieler für dieses Team:
+ Team 1
+ Team 2
+ Zufällig wählen
+ Füge beiden Teams mindestens einen Spieler hinzu! / Ziehe Avatare in die Liste der ausgewählten Spieler! / Rechtsklick auf einen ausgewählten Avatar entfernt ihn!
+ Team Survival: Herzen pro Spieler
+ Hoch/Runter = Spieler wählen · Links/Rechts oder Herz anklicken = Herzen ändern · Enter = Weiter · ESC = Zurück
+ Team Survival
+ Willst du das Spiel wirklich beenden?
+ Durchgang
+ Duell
+ gegen
+ Gleichstand! Das Duell wird nachgesungen.
+ Siegerteam
+
diff --git a/Output/PartyModes/TeamSurvival/Languages/en.xml b/Output/PartyModes/TeamSurvival/Languages/en.xml
new file mode 100644
index 00000000..d5592adc
--- /dev/null
+++ b/Output/PartyModes/TeamSurvival/Languages/en.xml
@@ -0,0 +1,36 @@
+
+
+ English
+ Team Survival
+ Two teams sing duels, the loser loses a heart, the last team standing wins.
+ For two teams with up to 8 players each, 2 microphones needed.
+ Next
+ Back
+ Exit
+ Yes
+ No
+ Start duel
+ Songs
+ Team
+ Team Survival: Configuration
+ Hearts
+ Same for everyone
+ Set per player
+ Hearts per player
+ Jokers per player
+ Team Survival: Choose Teams
+ Selected players for this team:
+ Team 1
+ Team 2
+ Select random
+ Add at least one player to both teams! / Drag player avatars to add them to the selected players list! / Right click avatar of selected players to remove them!
+ Team Survival: Hearts per Player
+ Up/Down = Select player · Left/Right or click a heart = Change hearts · Enter = Next · ESC = Back
+ Team Survival
+ Do you really want to exit the game?
+ Round
+ Duel
+ vs.
+ Tie! The duel is sung again.
+ Winning team
+
diff --git a/Output/PartyModes/TeamSurvival/Themes/Default.xml b/Output/PartyModes/TeamSurvival/Themes/Default.xml
new file mode 100644
index 00000000..97392ded
--- /dev/null
+++ b/Output/PartyModes/TeamSurvival/Themes/Default.xml
@@ -0,0 +1,10 @@
+
+
+ 9
+
+ Default
+ McSchneidar
+ 0
+ 1
+
+
diff --git a/Output/PartyModes/TeamSurvival/Themes/Default/Default.xml b/Output/PartyModes/TeamSurvival/Themes/Default/Default.xml
new file mode 100644
index 00000000..5d5694e3
--- /dev/null
+++ b/Output/PartyModes/TeamSurvival/Themes/Default/Default.xml
@@ -0,0 +1,16 @@
+
+
+ 4
+
+ Default
+ McSchneidar
+ 0
+ 1
+
+
+
+ Heart.png
+ PartyModeIcon.png
+
+
+
diff --git a/Output/PartyModes/TeamSurvival/Themes/Default/Heart.png b/Output/PartyModes/TeamSurvival/Themes/Default/Heart.png
new file mode 100644
index 00000000..76af991a
Binary files /dev/null and b/Output/PartyModes/TeamSurvival/Themes/Default/Heart.png differ
diff --git a/Output/PartyModes/TeamSurvival/Themes/Default/PartyModeIcon.png b/Output/PartyModes/TeamSurvival/Themes/Default/PartyModeIcon.png
new file mode 100644
index 00000000..3f421a17
Binary files /dev/null and b/Output/PartyModes/TeamSurvival/Themes/Default/PartyModeIcon.png differ
diff --git a/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalConfig.xml b/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalConfig.xml
new file mode 100644
index 00000000..987a31b1
--- /dev/null
+++ b/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalConfig.xml
@@ -0,0 +1,295 @@
+
+
+
+ PartyScreenTeamSurvivalConfig
+ 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_HEARTSMODE
+
+
+ 112.5
+ 247.5
+ 0
+ 40.5
+ 0
+
+
+ Left
+ Center
+
+ Outline
+ TR_SCREENCONFIG_NUMHEARTS
+
+
+ 112.5
+ 337.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
+
+
+
+
+
+
+
+
+
diff --git a/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalHearts.xml b/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalHearts.xml
new file mode 100644
index 00000000..d55d58e5
--- /dev/null
+++ b/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalHearts.xml
@@ -0,0 +1,262 @@
+
+
+
+ PartyScreenTeamSurvivalHearts
+ 1
+
+
+
+ Video
+
+
+ BG_Default
+
+
+
+
+
+
+
+
+ 0
+ 60
+ 1920
+ 67.5
+ 1
+
+
+
+
+
+ 0.1
+ 0.09
+ 0.25
+ 0.75
+
+
+ 140
+ 200
+ 800
+ 640
+ 0.8
+
+
+
+
+
+ 0.1
+ 0.09
+ 0.25
+ 0.75
+
+
+ 1000
+ 200
+ 800
+ 640
+ 0.8
+
+
+
+
+
+ 1
+ 0.8
+ 0
+ 0.18
+
+
+ 0
+ 0
+ 760
+ 62
+ 0.6
+
+
+
+
+
+
+ 0
+ 0
+ 54
+ 54
+ 0.4
+
+
+
+ Heart
+
+ 1
+ 0.3
+ 0.4
+ 1
+
+
+ 0
+ 0
+ 46
+ 46
+ 0.3
+
+
+
+
+
+ 960
+ 75
+ 0
+ 40.5
+ 0
+
+
+ Center
+ Center
+
+ Outline
+ TR_SCREENHEARTS_TITLE
+
+
+ 540
+ 210
+ 0
+ 40
+ 0
+
+
+ Center
+ Center
+
+ Outline
+ TR_SCREENNAMES_TEAM1
+
+
+ 1400
+ 210
+ 0
+ 40
+ 0
+
+
+ Center
+ Center
+
+ Outline
+ TR_SCREENNAMES_TEAM2
+
+
+ 0
+ 0
+ 0
+ 34
+ 330
+
+
+ Left
+ Center
+
+ Outline
+
+
+
+ 960
+ 860
+ 0
+ 30
+ 1600
+
+ 0.75
+ 0.78
+ 0.85
+ 1
+
+
+ Center
+ Center
+
+ Outline
+ TR_SCREENHEARTS_HINT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalMain.xml b/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalMain.xml
new file mode 100644
index 00000000..95668a5c
--- /dev/null
+++ b/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalMain.xml
@@ -0,0 +1,586 @@
+
+
+
+ PartyScreenTeamSurvivalMain
+ 1
+
+
+
+ Video
+
+
+ BG_Default
+
+
+
+
+
+
+
+
+ 0
+ 60
+ 1920
+ 67.5
+ 1
+
+
+
+ PopupBG
+
+
+ 0
+ 0
+ 1920
+ 1080
+ -1
+
+
+
+
+
+ 0.1
+ 0.09
+ 0.25
+ 0.75
+
+
+ 40
+ 190
+ 560
+ 720
+ 0.8
+
+
+
+
+
+ 0.1
+ 0.09
+ 0.25
+ 0.75
+
+
+ 1320
+ 190
+ 560
+ 720
+ 0.8
+
+
+
+
+
+ 0.1
+ 0.09
+ 0.25
+ 0.9
+
+
+ 0
+ 0
+ 520
+ 68
+ 0.5
+
+
+
+
+
+ 1
+ 0.8
+ 0
+ 1
+
+
+ 0
+ 0
+ 528
+ 76
+ 0.6
+
+
+
+
+
+
+ 0
+ 0
+ 56
+ 56
+ 0.4
+
+
+
+ Heart
+
+ 1
+ 0.3
+ 0.4
+ 1
+
+
+ 0
+ 0
+ 32
+ 32
+ 0.3
+
+
+
+
+
+ 1
+ 1
+ 1
+ 1
+
+
+ 652
+ 292
+ 216
+ 216
+ 0.5
+
+
+
+
+
+
+ 660
+ 300
+ 200
+ 200
+ 0.4
+
+
+
+
+
+ 1
+ 1
+ 1
+ 1
+
+
+ 1052
+ 292
+ 216
+ 216
+ 0.5
+
+
+
+
+
+
+ 1060
+ 300
+ 200
+ 200
+ 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
+
+
+ 320
+ 205
+ 0
+ 44
+ 0
+
+
+ Center
+ Center
+
+ Outline
+
+
+
+ 1600
+ 205
+ 0
+ 44
+ 0
+
+
+ Center
+ Center
+
+ Outline
+
+
+
+ 960
+ 150
+ 0
+ 34
+ 0
+
+ 0.75
+ 0.78
+ 0.85
+ 1
+
+
+ Center
+ Center
+
+ Outline
+
+
+
+ 0
+ 0
+ 0
+ 32
+ 0
+
+
+ Left
+ Center
+
+ Outline
+
+
+
+ 760
+ 520
+ 0
+ 40
+ 260
+
+
+ Center
+ Center
+
+ Outline
+
+
+
+ 1160
+ 520
+ 0
+ 40
+ 260
+
+
+ Center
+ Center
+
+ Outline
+
+
+
+ 960
+ 375
+ 0
+ 44
+ 0
+
+ 1
+ 0.8
+ 0
+ 1
+
+
+ Center
+ Center
+
+ Outline
+ TR_SCREENMAIN_VERSUS
+
+
+ 960
+ 600
+ 0
+ 34
+ 600
+
+ 1
+ 0.8
+ 0
+ 1
+
+
+ Center
+ Center
+
+ Outline
+ TR_SCREENMAIN_REMATCH
+
+
+ 960
+ 300
+ 0
+ 36
+ 0
+
+ 1
+ 0.8
+ 0
+ 1
+
+
+ Center
+ Center
+
+ Outline
+ TR_SCREENMAIN_CHAMPION
+
+
+ 960
+ 350
+ 0
+ 70
+ 600
+
+ 1
+ 0.8
+ 0
+ 1
+
+
+ Center
+ Center
+
+ Outline
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Star
+
+ 660
+ 280
+ 600
+ 340
+ -1
+
+
+ 1
+ 0.8
+ 0
+ 1
+
+ Star
+ 18
+ 40
+
+
+
+
diff --git a/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalNames.xml b/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalNames.xml
new file mode 100644
index 00000000..79390c4e
--- /dev/null
+++ b/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalNames.xml
@@ -0,0 +1,410 @@
+
+
+
+ PartyScreenTeamSurvivalNames
+ 1
+
+
+
+ Video
+
+
+ BG_Default
+
+
+
+
+
+
+
+
+ 0
+ 60
+ 1920
+ 67.5
+ 1
+
+
+
+
+
+ 960
+ 75
+ 0
+ 40.5
+ 0
+
+
+ Center
+ Center
+
+ Outline
+ TR_SCREENNAMES_TITLE
+
+
+ 960
+ 232.5
+ 0
+ 30
+ 0
+
+
+ Center
+ Center
+
+ Outline
+ TR_SCREENNAMES_SELPLAYERSTITLE
+
+
+ 960
+ 1054.5
+ 0
+ 24
+ 1800
+
+
+ Center
+ Center
+
+ Outline
+ TR_SCREENNAMES_HELPMESSAGE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SelectSlideArrowLeft
+ SelectSlideArrowRight
+ SelectSlide
+ SelectSlideArrowLeft
+ SelectSlideArrowRight
+
+ 60
+ 150
+ 1582.5
+ 75
+ 0
+
+
+ 67.5
+ 157.5
+ 60
+ 60
+ 0
+
+
+ 1575
+ 157.5
+ 60
+ 60
+ 0
+
+
+
+
+
+
+
+ 40.5
+ 75
+ 0
+ 300
+ Outline
+ Bold
+ 2
+
+
+
+ SelectSlideArrowLeft
+ SelectSlideArrowRight
+ SelectSlidePlayer
+ SelectSlideArrowLeft
+ SelectSlideArrowRight
+
+ 60
+ 270
+ 1582.5
+ 225
+ 0
+
+
+ 67.5
+ 345
+ 60
+ 60
+ 0
+
+
+ 1575
+ 345
+ 60
+ 60
+ 0
+
+
+
+
+
+
+
+ 40.5
+ 75
+ 7.5
+ 300
+ Outline
+ Bold
+ 8
+
+
+
+
+
+
+ 142.5
+ 525
+ 1800
+ 589.5
+ 0
+
+ CoverTile
+
+ PlayerSelector
+
+ 150
+ 150
+ 10
+ 2
+ 15
+ 15
+
+ -30
+ 25.5
+ Outline
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalSongs.xml b/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalSongs.xml
new file mode 100644
index 00000000..27b45756
--- /dev/null
+++ b/Output/PartyModes/TeamSurvival/Themes/Default/Screens/PartyScreenTeamSurvivalSongs.xml
@@ -0,0 +1,407 @@
+
+
+
+ PartyScreenTeamSurvivalSongs
+ 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/PartyModeTeamSurvival/CPartyModeTeamSurvival.cs b/PartyModes/PartyModeTeamSurvival/CPartyModeTeamSurvival.cs
new file mode 100644
index 00000000..177b3aa8
--- /dev/null
+++ b/PartyModes/PartyModeTeamSurvival/CPartyModeTeamSurvival.cs
@@ -0,0 +1,769 @@
+#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.TeamSurvival
+{
+ public class CSurvivalPlayer
+ {
+ public Guid ProfileId;
+ public int Team;
+ public int StartHearts;
+ public int Hearts;
+ public int Jokers;
+ public int DuelsInPass;
+
+ public bool IsOut
+ {
+ get { return Hearts <= 0; }
+ }
+ }
+
+ public class CSurvivalDuel
+ {
+ public CSurvivalPlayer[] Players = new CSurvivalPlayer[2];
+ public int[] Scores = new int[2];
+ public int Loser = -1;
+ }
+
+ public abstract class CPartyScreenTeamSurvival : CMenuParty
+ {
+ protected new CPartyModeTeamSurvival _PartyMode;
+
+ public override void Init()
+ {
+ base.Init();
+ _PartyMode = (CPartyModeTeamSurvival)base._PartyMode;
+ }
+ }
+
+ public sealed class CPartyModeTeamSurvival : CPartyMode
+ {
+ public const int TeamCount = 2;
+ public const int MaxHearts = 5;
+ public const int MaxJokers = 3;
+ public const int MaxPlayersInTeam = 8;
+
+ public override int MinMics
+ {
+ get { return TeamCount; }
+ }
+ public override int MaxMics
+ {
+ get { return CBase.Config.GetMaxNumMics(); }
+ }
+ public override int MinPlayers
+ {
+ get { return TeamCount; }
+ }
+ public override int MaxPlayers
+ {
+ get { return TeamCount * MaxPlayersInTeam; }
+ }
+ public override int MinTeams
+ {
+ get { return TeamCount; }
+ }
+ public override int MaxTeams
+ {
+ get { return TeamCount; }
+ }
+ public override int MinPlayersPerTeam
+ {
+ get { return 1; }
+ }
+ public override int MaxPlayersPerTeam
+ {
+ get { return MaxPlayersInTeam; }
+ }
+
+ private enum EStage
+ {
+ Config,
+ Songs,
+ Names,
+ Hearts,
+ Main,
+ SongSelection,
+ Singing,
+ MedleySinging
+ }
+
+ public struct SData
+ {
+ public bool HeartsPerPlayer;
+ public int NumHearts;
+ public int NumJokers;
+ public Dictionary PlayerHearts;
+
+ public int NumPlayerTeam1;
+ public int NumPlayerTeam2;
+ 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 Players;
+ public List PassDuels;
+ public int PassNr;
+ public int DuelIndex;
+ public int NumDuelsPlayed;
+ public bool IsRematch;
+ public CSurvivalDuel LastDecidedDuel;
+ public int WinnerTeam;
+
+ public List Songs;
+ }
+
+ public SData GameData;
+ private EStage _Stage;
+
+ public CPartyModeTeamSurvival(int id) : base(id)
+ {
+ _ScreenSongOptions.Selection.RandomOnly = false;
+ _ScreenSongOptions.Selection.PartyMode = true;
+ _ScreenSongOptions.Selection.CategoryChangeAllowed = true;
+ _ScreenSongOptions.Selection.NumJokers = new int[] { 1, 1 };
+ _ScreenSongOptions.Selection.TeamNames = new string[] { "foo", "bar" };
+
+ _ScreenSongOptions.Sorting.SearchString = string.Empty;
+ _ScreenSongOptions.Sorting.SearchActive = false;
+ _ScreenSongOptions.Sorting.DuetOptions = EDuetOptions.NoDuets;
+ _ScreenSongOptions.Sorting.FilterPlaylistId = -1;
+
+ GameData = new SData
+ {
+ HeartsPerPlayer = false,
+ NumHearts = 2,
+ NumJokers = 1,
+ PlayerHearts = new Dictionary(),
+ NumPlayerTeam1 = 2,
+ NumPlayerTeam2 = 2,
+ ProfileIdsTeam1 = new List(),
+ ProfileIdsTeam2 = 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(),
+ PassDuels = new List(),
+ WinnerTeam = -1,
+ 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 bool IsFinished
+ {
+ get { return GameData.WinnerTeam >= 0; }
+ }
+
+ public CSurvivalDuel CurrentDuel
+ {
+ get
+ {
+ if (IsFinished || GameData.DuelIndex >= GameData.PassDuels.Count)
+ {
+ return null;
+ }
+
+ return GameData.PassDuels[GameData.DuelIndex];
+ }
+ }
+
+ public List GetTeam(int team)
+ {
+ return GameData.Players.Where(player => player.Team == team).ToList();
+ }
+
+ public int GetStartHearts(Guid profileId)
+ {
+ int hearts;
+ if (GameData.HeartsPerPlayer && GameData.PlayerHearts.TryGetValue(profileId, out hearts))
+ {
+ return hearts;
+ }
+
+ return GameData.NumHearts;
+ }
+
+ private IMenu _GetNextScreen()
+ {
+ switch (_Stage)
+ {
+ case EStage.Config:
+ return _Screens["CPartyScreenTeamSurvivalConfig"];
+ case EStage.Songs:
+ return _Screens["CPartyScreenTeamSurvivalSongs"];
+ case EStage.Names:
+ return _Screens["CPartyScreenTeamSurvivalNames"];
+ case EStage.Hearts:
+ return _Screens["CPartyScreenTeamSurvivalHearts"];
+ case EStage.Main:
+ return _Screens["CPartyScreenTeamSurvivalMain"];
+ 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:
+ if (GameData.HeartsPerPlayer)
+ {
+ _Stage = EStage.Hearts;
+ }
+ else
+ {
+ _StartGame();
+ }
+
+ break;
+ case EStage.Hearts:
+ _StartGame();
+ break;
+ case EStage.Main:
+ if (CurrentDuel == 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.Hearts:
+ _Stage = EStage.Names;
+ break;
+ case EStage.Main:
+ _Stage = GameData.HeartsPerPlayer ? EStage.Hearts : EStage.Names;
+ break;
+ default:
+ throw new ArgumentException("Invalid stage: " + _Stage);
+ }
+
+ _FadeToScreen();
+ }
+
+ public override IMenu GetStartScreen()
+ {
+ return _Screens["CPartyScreenTeamSurvivalConfig"];
+ }
+
+ 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 duel = CurrentDuel;
+ if (duel != null && duel.Players[teamNr].Jokers > 0)
+ {
+ duel.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()
+ {
+ _Stage = EStage.Main;
+ CBase.Songs.ResetSongSung();
+
+ GameData.Players = new List();
+ var teams = new List[] { GameData.ProfileIdsTeam1, GameData.ProfileIdsTeam2 };
+ for (var team = 0; team < TeamCount; team++)
+ {
+ foreach (var profileId in teams[team])
+ {
+ var hearts = GetStartHearts(profileId);
+ GameData.Players.Add(new CSurvivalPlayer { ProfileId = profileId, Team = team, StartHearts = hearts, Hearts = hearts, Jokers = GameData.NumJokers });
+ }
+ }
+
+ GameData.PassNr = 0;
+ GameData.NumDuelsPlayed = 0;
+ GameData.IsRematch = false;
+ GameData.LastDecidedDuel = null;
+ GameData.WinnerTeam = -1;
+ GameData.Songs = new List();
+ _StartPass();
+ }
+
+ private void _StartPass()
+ {
+ GameData.PassNr++;
+ GameData.DuelIndex = 0;
+ GameData.PassDuels = new List();
+
+ var teams = new List[TeamCount];
+ var numDuels = 0;
+ for (var team = 0; team < TeamCount; team++)
+ {
+ teams[team] = GetTeam(team).Where(player => !player.IsOut).ToList();
+ teams[team].Shuffle();
+ foreach (var player in teams[team])
+ {
+ player.DuelsInPass = 0;
+ }
+
+ numDuels = Math.Max(numDuels, teams[team].Count);
+ }
+
+ for (var i = 0; i < numDuels; i++)
+ {
+ GameData.PassDuels.Add(new CSurvivalDuel());
+ }
+
+ for (var team = 0; team < TeamCount; team++)
+ {
+ var order = new List(teams[team]);
+ while (order.Count < numDuels)
+ {
+ var extra = new List(teams[team]);
+ extra.Shuffle();
+ order.AddRange(extra);
+ }
+
+ for (var i = 1; i < numDuels; i++)
+ {
+ if (order[i] != order[i - 1] || teams[team].Count < 2)
+ {
+ continue;
+ }
+
+ for (var j = i + 1; j < order.Count; j++)
+ {
+ if (order[j] != order[i - 1] && (i + 1 >= numDuels || order[j] != order[i + 1]))
+ {
+ var swap = order[i];
+ order[i] = order[j];
+ order[j] = swap;
+ break;
+ }
+ }
+ }
+
+ for (var i = 0; i < numDuels; i++)
+ {
+ GameData.PassDuels[i].Players[team] = order[i];
+ }
+ }
+ }
+
+ private CSurvivalPlayer _GetReplacement(int team)
+ {
+ var candidates = GetTeam(team).Where(player => !player.IsOut).ToList();
+ if (candidates.Count == 0)
+ {
+ return null;
+ }
+
+ var minDuels = candidates.Min(player => player.DuelsInPass);
+ candidates = candidates.Where(player => player.DuelsInPass == minDuels).ToList();
+ return candidates[CBase.Game.GetRandom(candidates.Count)];
+ }
+
+ private void _ValidateCurrentDuel()
+ {
+ var duel = CurrentDuel;
+ if (duel == null)
+ {
+ return;
+ }
+
+ for (var team = 0; team < TeamCount; team++)
+ {
+ if (duel.Players[team] == null || duel.Players[team].IsOut)
+ {
+ duel.Players[team] = _GetReplacement(team);
+ }
+ }
+ }
+
+ private void _PrepareMedleyRound()
+ {
+ var songIds = new List();
+ for (var i = 0; i < GameData.NumMedleySongs; i++)
+ {
+ if (GameData.Songs.Count == 0)
+ {
+ _UpdateSongList();
+ }
+
+ if (GameData.Songs.Count == 0)
+ {
+ break;
+ }
+
+ songIds.Add(GameData.Songs[0]);
+ GameData.Songs.RemoveAt(0);
+ }
+
+ _PrepareRound(songIds.ToArray());
+ }
+
+ private void _PrepareSongSelection()
+ {
+ _ScreenSongOptions.Selection.RandomOnly = true;
+ _ScreenSongOptions.Selection.SelectNextRandomSong = true;
+
+ _ScreenSongOptions.Sorting.IgnoreArticles = CBase.Config.GetIgnoreArticles();
+
+ switch (GameData.SongSource)
+ {
+ case ESongSource.TR_SONGSOURCE_ALLSONGS:
+ _ScreenSongOptions.Sorting.SongSorting = CBase.Config.GetSongSorting();
+ _ScreenSongOptions.Sorting.Tabs = CBase.Config.GetTabs();
+ _ScreenSongOptions.Sorting.FilterPlaylistId = -1;
+
+ _ScreenSongOptions.Selection.SongIndex = -1;
+ _ScreenSongOptions.Selection.CategoryIndex = -1;
+ _ScreenSongOptions.Selection.CategoryChangeAllowed = true;
+ break;
+
+ case ESongSource.TR_SONGSOURCE_CATEGORY:
+ _ScreenSongOptions.Sorting.SongSorting = GameData.Sorting;
+ _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_ON;
+ _ScreenSongOptions.Sorting.FilterPlaylistId = -1;
+
+ _ScreenSongOptions.Selection.CategoryIndex = GameData.CategoryIndex;
+ _ScreenSongOptions.Selection.CategoryChangeAllowed = false;
+ break;
+
+ case ESongSource.TR_SONGSOURCE_PLAYLIST:
+ _ScreenSongOptions.Sorting.SongSorting = CBase.Config.GetSongSorting();
+ _ScreenSongOptions.Sorting.Tabs = EOffOn.TR_CONFIG_OFF;
+ _ScreenSongOptions.Sorting.FilterPlaylistId = GameData.PlaylistId;
+
+ _ScreenSongOptions.Selection.CategoryChangeAllowed = false;
+ break;
+ }
+
+ var duel = CurrentDuel;
+ _ScreenSongOptions.Selection.NumJokers = new int[] { duel.Players[0].Jokers, duel.Players[1].Jokers };
+ _ScreenSongOptions.Selection.TeamNames = new string[]
+ {
+ CBase.Profiles.GetPlayerName(duel.Players[0].ProfileId),
+ CBase.Profiles.GetPlayerName(duel.Players[1].ProfileId)
+ };
+ }
+
+ private bool _PrepareRound(int[] songIds)
+ {
+ CBase.Game.Reset();
+ CBase.Game.ClearSongs();
+
+ CBase.Game.SetNumPlayer(TeamCount);
+ var players = CBase.Game.GetPlayers();
+ var duel = CurrentDuel;
+ if (players == null || players.Length < TeamCount || duel == null)
+ {
+ return false;
+ }
+
+ for (var team = 0; team < TeamCount; team++)
+ {
+ players[team].ProfileId = duel.Players[team].ProfileId;
+ }
+
+ foreach (var songId in songIds)
+ {
+ var gameMode = GameData.GameMode;
+ if (GameData.IsRematch && gameMode != EGameMode.TR_GAMEMODE_MEDLEY && CBase.Songs.GetSongById(songId).IsGameModeAvailable(EGameMode.TR_GAMEMODE_SHORTSONG))
+ {
+ gameMode = EGameMode.TR_GAMEMODE_SHORTSONG;
+ }
+
+ CBase.Game.AddSong(songId, gameMode);
+ }
+
+ return true;
+ }
+
+ private void _UpdateSongList()
+ {
+ if (GameData.Songs.Count > 0)
+ {
+ return;
+ }
+
+ switch (GameData.SongSource)
+ {
+ case ESongSource.TR_SONGSOURCE_PLAYLIST:
+ for (var i = 0; i < CBase.Playlist.GetSongCount(GameData.PlaylistId); i++)
+ {
+ var id = CBase.Playlist.GetSong(GameData.PlaylistId, i).SongId;
+ if (CBase.Songs.GetSongById(id).IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY))
+ {
+ GameData.Songs.Add(id);
+ }
+ }
+
+ break;
+
+ case ESongSource.TR_SONGSOURCE_ALLSONGS:
+ var avSongs = CBase.Songs.GetSongs();
+ GameData.Songs.AddRange(avSongs.Where(song => song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY)).Select(song => song.Id));
+ break;
+
+ case ESongSource.TR_SONGSOURCE_CATEGORY:
+ var oldSorting = CBase.Config.GetSongSorting();
+ CBase.Songs.SortSongs(GameData.Sorting, EOffOn.TR_CONFIG_ON, CBase.Config.GetIgnoreArticles(), string.Empty, EDuetOptions.NoDuets, -1);
+
+ CBase.Songs.SetCategory(GameData.CategoryIndex);
+ avSongs = CBase.Songs.GetVisibleSongs();
+ GameData.Songs.AddRange(avSongs.Where(song => song.IsGameModeAvailable(EGameMode.TR_GAMEMODE_MEDLEY)).Select(song => song.Id));
+
+ CBase.Songs.SetCategory(-1);
+ CBase.Songs.SortSongs(oldSorting, CBase.Config.GetTabs(), CBase.Config.GetIgnoreArticles(), string.Empty, EDuetOptions.NoDuets, -1);
+ break;
+ }
+
+ GameData.Songs.Shuffle();
+ }
+
+ private void _UpdateScores()
+ {
+ var duel = CurrentDuel;
+ if (duel == null)
+ {
+ return;
+ }
+
+ var points = CBase.Game.GetPoints();
+ if (points == null || points.NumRounds == 0)
+ {
+ return;
+ }
+
+ var scores = new double[TeamCount];
+ for (var round = 0; round < points.NumRounds; round++)
+ {
+ var res = points.GetPlayer(round, TeamCount);
+ if (res == null || res.Length < TeamCount)
+ {
+ return;
+ }
+
+ for (var p = 0; p < TeamCount; p++)
+ {
+ scores[p] += res[p].Points;
+ }
+ }
+
+ for (var p = 0; p < TeamCount; p++)
+ {
+ duel.Scores[p] = (int)Math.Round(scores[p] / points.NumRounds);
+ }
+
+ GameData.NumDuelsPlayed++;
+
+ if (duel.Scores[0] == duel.Scores[1])
+ {
+ GameData.IsRematch = true;
+ return;
+ }
+
+ GameData.IsRematch = false;
+ duel.Loser = duel.Scores[0] < duel.Scores[1] ? 0 : 1;
+ duel.Players[duel.Loser].Hearts--;
+ foreach (var player in duel.Players)
+ {
+ player.DuelsInPass++;
+ }
+
+ GameData.LastDecidedDuel = duel;
+
+ for (var team = 0; team < TeamCount; team++)
+ {
+ if (GetTeam(team).All(player => player.IsOut))
+ {
+ GameData.WinnerTeam = 1 - team;
+ return;
+ }
+ }
+
+ GameData.DuelIndex++;
+ if (GameData.DuelIndex >= GameData.PassDuels.Count)
+ {
+ _StartPass();
+ }
+
+ _ValidateCurrentDuel();
+ }
+ }
+}
diff --git a/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalConfig.cs b/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalConfig.cs
new file mode 100644
index 00000000..01a9ffc7
--- /dev/null
+++ b/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalConfig.cs
@@ -0,0 +1,145 @@
+#region license
+// This file is part of Vocaluxe.
+//
+// Vocaluxe is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Vocaluxe is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Vocaluxe. If not, see .
+#endregion
+
+using System.Windows.Forms;
+
+namespace VocaluxeLib.PartyModes.TeamSurvival
+{
+ public class CPartyScreenTeamSurvivalConfig : CPartyScreenTeamSurvival
+ {
+ protected override int _ScreenVersion
+ {
+ get { return 1; }
+ }
+
+ private const string _SelectSlideHeartsMode = "SelectSlideHeartsMode";
+ private const string _SelectSlideNumHearts = "SelectSlideNumHearts";
+ private const string _SelectSlideNumJokers = "SelectSlideNumJokers";
+ private const string _ButtonNext = "ButtonNext";
+ private const string _ButtonBack = "ButtonBack";
+
+ public override void Init()
+ {
+ base.Init();
+
+ _ThemeSelectSlides = new string[] { _SelectSlideHeartsMode, _SelectSlideNumHearts, _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[_SelectSlideHeartsMode].Clear();
+ _SelectSlides[_SelectSlideHeartsMode].AddValue(CBase.Language.Translate("TR_SCREENCONFIG_HEARTS_EQUAL", PartyModeId));
+ _SelectSlides[_SelectSlideHeartsMode].AddValue(CBase.Language.Translate("TR_SCREENCONFIG_HEARTS_PERPLAYER", PartyModeId));
+ _SelectSlides[_SelectSlideHeartsMode].Selection = _PartyMode.GameData.HeartsPerPlayer ? 1 : 0;
+
+ _SelectSlides[_SelectSlideNumHearts].Clear();
+ for (var i = 1; i <= CPartyModeTeamSurvival.MaxHearts; i++)
+ {
+ _SelectSlides[_SelectSlideNumHearts].AddValue(i.ToString());
+ }
+
+ _SelectSlides[_SelectSlideNumHearts].SelectedValue = _PartyMode.GameData.NumHearts.ToString();
+
+ _SelectSlides[_SelectSlideNumJokers].Clear();
+ for (var i = 0; i <= CPartyModeTeamSurvival.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.HeartsPerPlayer = _SelectSlides[_SelectSlideHeartsMode].Selection == 1;
+ _PartyMode.GameData.NumHearts = _SelectSlides[_SelectSlideNumHearts].Selection + 1;
+ _PartyMode.GameData.NumJokers = _SelectSlides[_SelectSlideNumJokers].Selection;
+ }
+ }
+}
diff --git a/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalHearts.cs b/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalHearts.cs
new file mode 100644
index 00000000..a00a0bfa
--- /dev/null
+++ b/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalHearts.cs
@@ -0,0 +1,374 @@
+#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.Windows.Forms;
+using VocaluxeLib.Menu;
+
+namespace VocaluxeLib.PartyModes.TeamSurvival
+{
+ class CHeartsRow
+ {
+ public Guid ProfileId;
+ public CStatic Highlight;
+ public CStatic Avatar;
+ public CText Name;
+ public CStatic[] Hearts;
+ }
+
+ public class CPartyScreenTeamSurvivalHearts : CPartyScreenTeamSurvival
+ {
+ protected override int _ScreenVersion
+ {
+ get { return 1; }
+ }
+
+ private const string _ButtonNext = "ButtonNext";
+ private const string _ButtonBack = "ButtonBack";
+
+ private const string _StaticRowHighlight = "StaticRowHighlight";
+ private const string _StaticRowAvatar = "StaticRowAvatar";
+ private const string _StaticHeart = "StaticHeart";
+ private const string _TextRowName = "TextRowName";
+
+ private const float _FirstRowY = 260f;
+ private const float _RowH = 70f;
+ private const float _HeartSize = 46f;
+ private const float _HeartSpace = 10f;
+ private const float _LostHeartAlpha = 0.2f;
+
+ private readonly float[] _ColumnX = new float[] { 160f, 1020f };
+
+ private List _Rows;
+ private int _NumRowsUsed;
+ private int _SelectedRow;
+ private bool _OnButtons;
+
+ public override void Init()
+ {
+ base.Init();
+
+ _ThemeButtons = new string[] { _ButtonNext, _ButtonBack };
+ _ThemeStatics = new string[] { _StaticRowHighlight, _StaticRowAvatar, _StaticHeart };
+ _ThemeTexts = new string[] { _TextRowName };
+ }
+
+ public override void LoadTheme(string xmlPath)
+ {
+ base.LoadTheme(xmlPath);
+
+ _Rows = new List();
+ for (var i = 0; i < CPartyModeTeamSurvival.TeamCount * CPartyModeTeamSurvival.MaxPlayersInTeam; i++)
+ {
+ var row = new CHeartsRow
+ {
+ Highlight = GetNewStatic(_Statics[_StaticRowHighlight]),
+ Avatar = GetNewStatic(_Statics[_StaticRowAvatar]),
+ Name = GetNewText(_Texts[_TextRowName]),
+ Hearts = new CStatic[CPartyModeTeamSurvival.MaxHearts]
+ };
+ row.Avatar.Aspect = EAspect.Crop;
+ _AddStatic(row.Highlight);
+ _AddStatic(row.Avatar);
+ _AddText(row.Name);
+ for (var h = 0; h < CPartyModeTeamSurvival.MaxHearts; h++)
+ {
+ row.Hearts[h] = GetNewStatic(_Statics[_StaticHeart]);
+ _AddStatic(row.Hearts[h]);
+ }
+
+ _Rows.Add(row);
+ }
+
+ _Statics[_StaticRowHighlight].Visible = false;
+ _Statics[_StaticRowAvatar].Visible = false;
+ _Statics[_StaticHeart].Visible = false;
+ _Texts[_TextRowName].Visible = false;
+ }
+
+ public override void OnShow()
+ {
+ base.OnShow();
+
+ _NumRowsUsed = 0;
+ var teams = new List[] { _PartyMode.GameData.ProfileIdsTeam1, _PartyMode.GameData.ProfileIdsTeam2 };
+ for (var team = 0; team < teams.Length; team++)
+ {
+ for (var i = 0; i < teams[team].Count && i < CPartyModeTeamSurvival.MaxPlayersInTeam; i++)
+ {
+ var row = _Rows[_NumRowsUsed++];
+ row.ProfileId = teams[team][i];
+ _PlaceRow(row, _ColumnX[team], _FirstRowY + i * _RowH);
+ row.Avatar.Texture = CBase.Profiles.GetAvatar(row.ProfileId);
+ row.Name.Text = CBase.Profiles.GetPlayerName(row.ProfileId);
+ }
+ }
+
+ for (var i = 0; i < _Rows.Count; i++)
+ {
+ var visible = i < _NumRowsUsed;
+ _Rows[i].Avatar.Visible = visible;
+ _Rows[i].Name.Visible = visible;
+ foreach (var heart in _Rows[i].Hearts)
+ {
+ heart.Visible = visible;
+ }
+ }
+
+ _SelectedRow = 0;
+ _UpdateRows();
+ _FocusRows();
+ }
+
+ public override bool UpdateGame()
+ {
+ return true;
+ }
+
+ public override bool HandleInput(SKeyEvent keyEvent)
+ {
+ if (keyEvent.KeyPressed)
+ {
+ return true;
+ }
+
+ switch (keyEvent.Key)
+ {
+ case Keys.Back:
+ case Keys.Escape:
+ _PartyMode.Back();
+ break;
+
+ case Keys.Enter:
+ if (_OnButtons && _Buttons[_ButtonBack].Selected)
+ {
+ _PartyMode.Back();
+ }
+ else
+ {
+ _PartyMode.Next();
+ }
+
+ break;
+
+ case Keys.Up:
+ if (_OnButtons)
+ {
+ _FocusRows();
+ }
+ else
+ {
+ _SelectRow(_SelectedRow - 1);
+ }
+
+ break;
+
+ case Keys.Down:
+ if (_OnButtons)
+ {
+ break;
+ }
+
+ if (_SelectedRow + 1 < _NumRowsUsed)
+ {
+ _SelectRow(_SelectedRow + 1);
+ }
+ else
+ {
+ _FocusButtons();
+ }
+
+ break;
+
+ case Keys.Left:
+ case Keys.Right:
+ if (_OnButtons)
+ {
+ _SwitchButton();
+ }
+ else
+ {
+ _ChangeHearts(_SelectedRow, _GetHearts(_SelectedRow) + (keyEvent.Key == Keys.Left ? -1 : 1));
+ }
+
+ break;
+
+ case Keys.Tab:
+ if (_OnButtons)
+ {
+ _SwitchButton();
+ }
+ else
+ {
+ _FocusButtons();
+ }
+
+ break;
+ }
+
+ return true;
+ }
+
+ public override bool HandleMouse(SMouseEvent mouseEvent)
+ {
+ base.HandleMouse(mouseEvent);
+ if (_Buttons[_ButtonBack].Selected || _Buttons[_ButtonNext].Selected)
+ {
+ _OnButtons = true;
+ }
+
+ if (mouseEvent.LB)
+ {
+ for (var r = 0; r < _NumRowsUsed; r++)
+ {
+ for (var h = 0; h < CPartyModeTeamSurvival.MaxHearts; h++)
+ {
+ if (CHelper.IsInBounds(_Rows[r].Hearts[h].Rect, mouseEvent))
+ {
+ _SelectRow(r);
+ _ChangeHearts(r, h + 1);
+ return true;
+ }
+ }
+
+ if (CHelper.IsInBounds(_Rows[r].Highlight.Rect, mouseEvent))
+ {
+ _SelectRow(r);
+ return true;
+ }
+ }
+
+ if (_IsMouseOverCurSelection(mouseEvent))
+ {
+ if (_Buttons[_ButtonBack].Selected)
+ {
+ _PartyMode.Back();
+ }
+
+ if (_Buttons[_ButtonNext].Selected)
+ {
+ _PartyMode.Next();
+ }
+ }
+ }
+
+ if (mouseEvent.RB)
+ {
+ _PartyMode.Back();
+ }
+
+ return true;
+ }
+
+ private void _PlaceRow(CHeartsRow row, float x, float y)
+ {
+ var highlight = _Statics[_StaticRowHighlight].Rect;
+ row.Highlight.MaxRect = new SRectF(x, y, highlight.W, highlight.H, highlight.Z);
+
+ var avatar = _Statics[_StaticRowAvatar].Rect;
+ row.Avatar.MaxRect = new SRectF(x + 8f, y + (highlight.H - avatar.H) / 2, avatar.W, avatar.H, avatar.Z);
+
+ row.Name.X = x + avatar.W + 24f;
+ row.Name.Y = y + (highlight.H - row.Name.H) / 2;
+
+ var heartsX = x + highlight.W - CPartyModeTeamSurvival.MaxHearts * (_HeartSize + _HeartSpace);
+ for (var h = 0; h < row.Hearts.Length; h++)
+ {
+ row.Hearts[h].MaxRect = new SRectF(heartsX + h * (_HeartSize + _HeartSpace), y + (highlight.H - _HeartSize) / 2, _HeartSize, _HeartSize,
+ _Statics[_StaticHeart].Rect.Z);
+ }
+ }
+
+ private int _GetHearts(int row)
+ {
+ if (row < 0 || row >= _NumRowsUsed)
+ {
+ return 0;
+ }
+
+ return _PartyMode.GetStartHearts(_Rows[row].ProfileId);
+ }
+
+ private void _ChangeHearts(int row, int hearts)
+ {
+ if (row < 0 || row >= _NumRowsUsed)
+ {
+ return;
+ }
+
+ hearts = Math.Max(1, Math.Min(CPartyModeTeamSurvival.MaxHearts, hearts));
+ _PartyMode.GameData.PlayerHearts[_Rows[row].ProfileId] = hearts;
+ _UpdateRows();
+ }
+
+ private void _FocusRows()
+ {
+ _OnButtons = false;
+ _Buttons[_ButtonBack].Selected = false;
+ _Buttons[_ButtonNext].Selected = false;
+ _UpdateRows();
+ }
+
+ private void _FocusButtons()
+ {
+ _OnButtons = true;
+ _SelectElement(_Buttons[_ButtonNext]);
+ _UpdateRows();
+ }
+
+ private void _SwitchButton()
+ {
+ _SelectElement(_Buttons[_ButtonNext].Selected ? _Buttons[_ButtonBack] : _Buttons[_ButtonNext]);
+ }
+
+ private void _SelectRow(int row)
+ {
+ _OnButtons = false;
+ _Buttons[_ButtonBack].Selected = false;
+ _Buttons[_ButtonNext].Selected = false;
+ if (_NumRowsUsed == 0)
+ {
+ return;
+ }
+
+ _SelectedRow = Math.Max(0, Math.Min(_NumRowsUsed - 1, row));
+ _UpdateRows();
+ }
+
+ private void _UpdateRows()
+ {
+ for (var r = 0; r < _NumRowsUsed; r++)
+ {
+ var row = _Rows[r];
+ row.Highlight.Visible = r == _SelectedRow && !_OnButtons;
+
+ var hearts = _GetHearts(r);
+ var color = _Statics[_StaticHeart].Color;
+ for (var h = 0; h < row.Hearts.Length; h++)
+ {
+ row.Hearts[h].Color = new SColorF(color.R, color.G, color.B, h < hearts ? color.A : color.A * _LostHeartAlpha);
+ }
+ }
+
+ for (var r = _NumRowsUsed; r < _Rows.Count; r++)
+ {
+ _Rows[r].Highlight.Visible = false;
+ }
+ }
+ }
+}
diff --git a/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalMain.cs b/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalMain.cs
new file mode 100644
index 00000000..8b8c7410
--- /dev/null
+++ b/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalMain.cs
@@ -0,0 +1,560 @@
+#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.TeamSurvival
+{
+ class CPlayerCard
+ {
+ public CSurvivalPlayer Player;
+ public CStatic Active;
+ public CStatic Box;
+ public CStatic Avatar;
+ public CText Name;
+ public CStatic[] Hearts;
+ public SRectF[] HeartRects;
+ }
+
+ public class CPartyScreenTeamSurvivalMain : CPartyScreenTeamSurvival
+ {
+ protected override int _ScreenVersion
+ {
+ get { return 1; }
+ }
+
+ private const string _TextPopupReallyExit = "TextPopupReallyExit";
+ private const string _TextTeam1 = "TextTeam1";
+ private const string _TextTeam2 = "TextTeam2";
+ private const string _TextPass = "TextPass";
+ private const string _TextCardName = "TextCardName";
+ private const string _TextDuelName1 = "TextDuelName1";
+ private const string _TextDuelName2 = "TextDuelName2";
+ private const string _TextVersus = "TextVersus";
+ private const string _TextRematch = "TextRematch";
+ 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 _StaticCardBox = "StaticCardBox";
+ private const string _StaticCardActive = "StaticCardActive";
+ private const string _StaticCardAvatar = "StaticCardAvatar";
+ private const string _StaticHeart = "StaticHeart";
+ private const string _StaticDuelFrame1 = "StaticDuelFrame1";
+ private const string _StaticDuelFrame2 = "StaticDuelFrame2";
+ private const string _StaticDuelAvatar1 = "StaticDuelAvatar1";
+ private const string _StaticDuelAvatar2 = "StaticDuelAvatar2";
+
+ private const string _ParticleEffectChampion = "ParticleEffectChampion";
+
+ private const float _CardFirstY = 265f;
+ private const float _CardStep = 76f;
+ private const float _ActiveBorder = 4f;
+ private const float _HeartSize = 32f;
+ private const float _HeartSpace = 6f;
+ private const float _LostHeartAlpha = 0.18f;
+ private const float _OutAlpha = 0.35f;
+ private const float _SurvivorSize = 110f;
+ private const float _SurvivorY = 470f;
+ private const float _SurvivorSpace = 16f;
+
+ private const float _HeartLossDelay = 400f;
+ private const float _HeartLossDuration = 800f;
+ private const float _ChampionPopDuration = 700f;
+
+ private readonly float[] _CardX = new float[] { 60f, 1340f };
+
+ private bool _ExitPopupVisible;
+ private List _Cards;
+ private List _Survivors;
+ private readonly Stopwatch _AnimTimer = new Stopwatch();
+ private CPlayerCard _LosingCard;
+ private int _LostHeart;
+ private bool _LosingCardOut;
+ private float _ChampionHeight;
+
+ public override void Init()
+ {
+ base.Init();
+
+ _ThemeTexts = new string[]
+ {
+ _TextPopupReallyExit, _TextTeam1, _TextTeam2, _TextPass, _TextCardName, _TextDuelName1, _TextDuelName2, _TextVersus, _TextRematch, _TextChampionLabel,
+ _TextChampion
+ };
+ _ThemeButtons = new string[] { _ButtonNextRound, _ButtonBack, _ButtonExit, _ButtonPopupYes, _ButtonPopupNo };
+ _ThemeStatics = new string[]
+ {
+ _StaticPopupBG, _StaticCardBox, _StaticCardActive, _StaticCardAvatar, _StaticHeart, _StaticDuelFrame1, _StaticDuelFrame2, _StaticDuelAvatar1,
+ _StaticDuelAvatar2
+ };
+ _ThemeParticleEffects = new string[] { _ParticleEffectChampion };
+ }
+
+ public override void LoadTheme(string xmlPath)
+ {
+ base.LoadTheme(xmlPath);
+
+ _Cards = new List();
+ for (var i = 0; i < CPartyModeTeamSurvival.TeamCount * CPartyModeTeamSurvival.MaxPlayersInTeam; i++)
+ {
+ var card = new CPlayerCard
+ {
+ Active = GetNewStatic(_Statics[_StaticCardActive]),
+ Box = GetNewStatic(_Statics[_StaticCardBox]),
+ Avatar = GetNewStatic(_Statics[_StaticCardAvatar]),
+ Name = GetNewText(_Texts[_TextCardName]),
+ Hearts = new CStatic[CPartyModeTeamSurvival.MaxHearts],
+ HeartRects = new SRectF[CPartyModeTeamSurvival.MaxHearts]
+ };
+ card.Avatar.Aspect = EAspect.Crop;
+ _AddStatic(card.Active);
+ _AddStatic(card.Box);
+ _AddStatic(card.Avatar);
+ _AddText(card.Name);
+ for (var h = 0; h < CPartyModeTeamSurvival.MaxHearts; h++)
+ {
+ card.Hearts[h] = GetNewStatic(_Statics[_StaticHeart]);
+ _AddStatic(card.Hearts[h]);
+ }
+
+ _Cards.Add(card);
+ }
+
+ _Survivors = new List();
+ for (var i = 0; i < CPartyModeTeamSurvival.MaxPlayersInTeam; i++)
+ {
+ var survivor = GetNewStatic(_Statics[_StaticCardAvatar]);
+ survivor.Aspect = EAspect.Crop;
+ _AddStatic(survivor);
+ _Survivors.Add(survivor);
+ }
+
+ _Statics[_StaticCardBox].Visible = false;
+ _Statics[_StaticCardActive].Visible = false;
+ _Statics[_StaticCardAvatar].Visible = false;
+ _Statics[_StaticHeart].Visible = false;
+ _Texts[_TextCardName].Visible = false;
+ _Statics[_StaticDuelAvatar1].Aspect = EAspect.Crop;
+ _Statics[_StaticDuelAvatar2].Aspect = EAspect.Crop;
+
+ _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();
+
+ _BuildCards();
+ _UpdateCards();
+ _UpdateDuel();
+
+ _LosingCard = null;
+ var decided = _PartyMode.GameData.LastDecidedDuel;
+ _PartyMode.GameData.LastDecidedDuel = null;
+ if (decided != null)
+ {
+ _LosingCard = _FindCard(decided.Players[decided.Loser]);
+ _LostHeart = decided.Players[decided.Loser].Hearts;
+ _LosingCardOut = decided.Players[decided.Loser].IsOut;
+ }
+
+ _AnimTimer.Reset();
+ _AnimTimer.Start();
+ _UpdateHeartLoss();
+
+ var started = _PartyMode.GameData.NumDuelsPlayed > 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()
+ {
+ _UpdateHeartLoss();
+
+ if (_PartyMode.IsFinished)
+ {
+ _UpdateChampion();
+ }
+
+ return true;
+ }
+
+ private void _OnBack()
+ {
+ if (_ExitPopupVisible)
+ {
+ _ShowPopup(false);
+ }
+ else if (_PartyMode.GameData.NumDuelsPlayed == 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 _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 static SColorF _WithAlpha(SColorF color, float alpha)
+ {
+ return new SColorF(color.R, color.G, color.B, color.A * alpha);
+ }
+
+ private string _GetTeamName(int team)
+ {
+ return CBase.Language.Translate("TR_TEAM", PartyModeId) + " " + (team + 1);
+ }
+
+ private CPlayerCard _FindCard(CSurvivalPlayer player)
+ {
+ foreach (var card in _Cards)
+ {
+ if (card.Player == player)
+ {
+ return card;
+ }
+ }
+
+ return null;
+ }
+
+ private void _BuildCards()
+ {
+ var cardNr = 0;
+ for (var team = 0; team < CPartyModeTeamSurvival.TeamCount; team++)
+ {
+ var players = _PartyMode.GetTeam(team);
+ for (var i = 0; i < players.Count && cardNr < _Cards.Count; i++)
+ {
+ var card = _Cards[cardNr++];
+ card.Player = players[i];
+
+ var boxTemplate = _Statics[_StaticCardBox].Rect;
+ var box = new SRectF(_CardX[team], _CardFirstY + i * _CardStep, boxTemplate.W, boxTemplate.H, boxTemplate.Z);
+ card.Box.MaxRect = box;
+ card.Active.MaxRect = new SRectF(box.X - _ActiveBorder, box.Y - _ActiveBorder, box.W + 2 * _ActiveBorder, box.H + 2 * _ActiveBorder,
+ _Statics[_StaticCardActive].Rect.Z);
+
+ var avatarTemplate = _Statics[_StaticCardAvatar].Rect;
+ card.Avatar.MaxRect = new SRectF(box.X + 6f, box.Y + (box.H - avatarTemplate.H) / 2, avatarTemplate.W, avatarTemplate.H, avatarTemplate.Z);
+ card.Avatar.Texture = CBase.Profiles.GetAvatar(card.Player.ProfileId);
+
+ card.Name.Text = CBase.Profiles.GetPlayerName(card.Player.ProfileId);
+ card.Name.X = box.X + avatarTemplate.W + 18f;
+ card.Name.Y = box.Y + (box.H - card.Name.H) / 2;
+ card.Name.W = box.W - avatarTemplate.W - 30f - CPartyModeTeamSurvival.MaxHearts * (_HeartSize + _HeartSpace);
+
+ var heartsX = box.X + box.W - 10f - card.Player.StartHearts * (_HeartSize + _HeartSpace);
+ for (var h = 0; h < card.Hearts.Length; h++)
+ {
+ card.HeartRects[h] = new SRectF(heartsX + h * (_HeartSize + _HeartSpace), box.Y + (box.H - _HeartSize) / 2, _HeartSize, _HeartSize,
+ _Statics[_StaticHeart].Rect.Z);
+ card.Hearts[h].MaxRect = card.HeartRects[h];
+ }
+ }
+ }
+
+ for (var i = cardNr; i < _Cards.Count; i++)
+ {
+ _Cards[i].Player = null;
+ }
+ }
+
+ private void _UpdateCards()
+ {
+ var duel = _PartyMode.CurrentDuel;
+ foreach (var card in _Cards)
+ {
+ var visible = card.Player != null;
+ card.Box.Visible = visible;
+ card.Avatar.Visible = visible;
+ card.Name.Visible = visible;
+ card.Active.Visible = visible && duel != null && (duel.Players[0] == card.Player || duel.Players[1] == card.Player);
+ for (var h = 0; h < card.Hearts.Length; h++)
+ {
+ card.Hearts[h].Visible = visible && h < card.Player.StartHearts;
+ }
+
+ if (visible)
+ {
+ _SetCardAlpha(card, card.Player.IsOut ? _OutAlpha : 1f);
+ _SetHeartAlphas(card, card.Player.Hearts);
+ }
+ }
+
+ for (var team = 0; team < CPartyModeTeamSurvival.TeamCount; team++)
+ {
+ var text = _Texts[team == 0 ? _TextTeam1 : _TextTeam2];
+ text.Text = _GetTeamName(team);
+ text.Color = CBase.Themes.GetPlayerColor(team + 1);
+ }
+ }
+
+ private void _SetCardAlpha(CPlayerCard card, float alpha)
+ {
+ card.Box.Color = _WithAlpha(_Statics[_StaticCardBox].Color, alpha);
+ card.Avatar.Color = _WithAlpha(_Statics[_StaticCardAvatar].Color, alpha);
+ card.Name.Color = _WithAlpha(_Texts[_TextCardName].Color, alpha);
+ }
+
+ private void _SetHeartAlphas(CPlayerCard card, int hearts)
+ {
+ for (var h = 0; h < card.Hearts.Length; h++)
+ {
+ card.Hearts[h].MaxRect = card.HeartRects[h];
+ card.Hearts[h].Color = _WithAlpha(_Statics[_StaticHeart].Color, h < hearts ? 1f : _LostHeartAlpha);
+ }
+ }
+
+ private void _UpdateHeartLoss()
+ {
+ if (_LosingCard == null || _LostHeart < 0 || _LostHeart >= _LosingCard.Hearts.Length)
+ {
+ return;
+ }
+
+ var progress = Math.Max(0f, Math.Min(1f, (_AnimTimer.ElapsedMilliseconds - _HeartLossDelay) / _HeartLossDuration));
+ var heart = _LosingCard.Hearts[_LostHeart];
+ var rect = _LosingCard.HeartRects[_LostHeart];
+ var scale = 1f + progress;
+ var size = rect.W * scale;
+ heart.MaxRect = new SRectF(rect.X + (rect.W - size) / 2, rect.Y + (rect.H - size) / 2, size, size, rect.Z);
+ heart.Color = _WithAlpha(_Statics[_StaticHeart].Color, 1f - (1f - _LostHeartAlpha) * progress);
+
+ if (_LosingCardOut)
+ {
+ _SetCardAlpha(_LosingCard, 1f - (1f - _OutAlpha) * progress);
+ }
+
+ if (progress >= 1f)
+ {
+ heart.MaxRect = rect;
+ _LosingCard = null;
+ }
+ }
+
+ private void _UpdateDuel()
+ {
+ var finished = _PartyMode.IsFinished;
+ var duel = _PartyMode.CurrentDuel;
+ var showDuel = !finished && duel != null;
+
+ _Statics[_StaticDuelFrame1].Visible = showDuel;
+ _Statics[_StaticDuelFrame2].Visible = showDuel;
+ _Statics[_StaticDuelAvatar1].Visible = showDuel;
+ _Statics[_StaticDuelAvatar2].Visible = showDuel;
+ _Texts[_TextDuelName1].Visible = showDuel;
+ _Texts[_TextDuelName2].Visible = showDuel;
+ _Texts[_TextVersus].Visible = showDuel;
+ _Texts[_TextPass].Visible = showDuel;
+ _Texts[_TextRematch].Visible = showDuel && _PartyMode.GameData.IsRematch;
+
+ if (showDuel)
+ {
+ _Statics[_StaticDuelFrame1].Color = CBase.Themes.GetPlayerColor(1);
+ _Statics[_StaticDuelFrame2].Color = CBase.Themes.GetPlayerColor(2);
+ _Statics[_StaticDuelAvatar1].Texture = CBase.Profiles.GetAvatar(duel.Players[0].ProfileId);
+ _Statics[_StaticDuelAvatar2].Texture = CBase.Profiles.GetAvatar(duel.Players[1].ProfileId);
+ _Texts[_TextDuelName1].Text = CBase.Profiles.GetPlayerName(duel.Players[0].ProfileId);
+ _Texts[_TextDuelName2].Text = CBase.Profiles.GetPlayerName(duel.Players[1].ProfileId);
+ _Texts[_TextPass].Text = CBase.Language.Translate("TR_SCREENMAIN_PASS", PartyModeId) + " " + _PartyMode.GameData.PassNr + " · " +
+ CBase.Language.Translate("TR_SCREENMAIN_DUEL", PartyModeId) + " " + (_PartyMode.GameData.DuelIndex + 1) + " / " +
+ _PartyMode.GameData.PassDuels.Count;
+ }
+
+ _Texts[_TextChampionLabel].Visible = finished;
+ _Texts[_TextChampion].Visible = finished;
+ _ParticleEffects[_ParticleEffectChampion].Visible = finished;
+
+ var survivors = new List();
+ if (finished)
+ {
+ _Texts[_TextChampion].Text = _GetTeamName(_PartyMode.GameData.WinnerTeam);
+ foreach (var player in _PartyMode.GetTeam(_PartyMode.GameData.WinnerTeam))
+ {
+ if (!player.IsOut)
+ {
+ survivors.Add(player);
+ }
+ }
+ }
+
+ var x = (CBase.Settings.GetRenderW() - survivors.Count * _SurvivorSize - (survivors.Count - 1) * _SurvivorSpace) / 2;
+ for (var i = 0; i < _Survivors.Count; i++)
+ {
+ _Survivors[i].Visible = i < survivors.Count;
+ if (i >= survivors.Count)
+ {
+ continue;
+ }
+
+ _Survivors[i].Texture = CBase.Profiles.GetAvatar(survivors[i].ProfileId);
+ _Survivors[i].MaxRect = new SRectF(x, _SurvivorY, _SurvivorSize, _SurvivorSize, _Statics[_StaticCardAvatar].Rect.Z);
+ x += _SurvivorSize + _SurvivorSpace;
+ }
+ }
+
+ private void _UpdateChampion()
+ {
+ var time = _AnimTimer.ElapsedMilliseconds;
+ float scale;
+ if (time < _ChampionPopDuration)
+ {
+ scale = 0.3f + 0.7f * _EaseOutBack(time / _ChampionPopDuration);
+ }
+ else
+ {
+ scale = 1f + 0.03f * (float)Math.Sin((time - _ChampionPopDuration) / 1000.0 * Math.PI * 1.4);
+ }
+
+ _Texts[_TextChampion].Font.Height = _ChampionHeight * scale;
+ }
+ }
+}
diff --git a/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalNames.cs b/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalNames.cs
new file mode 100644
index 00000000..7e512150
--- /dev/null
+++ b/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalNames.cs
@@ -0,0 +1,88 @@
+#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.TeamSurvival
+{
+ public class CPartyScreenTeamSurvivalNames : CMenuPartyNameSelection
+ {
+ protected override int _ScreenVersion
+ {
+ get { return 1; }
+ }
+
+ private new CPartyModeTeamSurvival _PartyMode;
+
+ public override void Init()
+ {
+ base.Init();
+ _PartyMode = (CPartyModeTeamSurvival)base._PartyMode;
+ }
+
+ public override void OnShow()
+ {
+ base.OnShow();
+
+ while (_PartyMode.GameData.ProfileIdsTeam1.Count > _PartyMode.GameData.NumPlayerTeam1)
+ {
+ _PartyMode.GameData.ProfileIdsTeam1.RemoveAt(_PartyMode.GameData.ProfileIdsTeam1.Count - 1);
+ }
+
+ while (_PartyMode.GameData.ProfileIdsTeam2.Count > _PartyMode.GameData.NumPlayerTeam2)
+ {
+ _PartyMode.GameData.ProfileIdsTeam2.RemoveAt(_PartyMode.GameData.ProfileIdsTeam2.Count - 1);
+ }
+
+ SetPartyModeData(CPartyModeTeamSurvival.TeamCount, _PartyMode.GameData.NumPlayerTeam1 + _PartyMode.GameData.NumPlayerTeam2,
+ new int[] { _PartyMode.GameData.NumPlayerTeam1, _PartyMode.GameData.NumPlayerTeam2 });
+ var ids = new List[] { _PartyMode.GameData.ProfileIdsTeam1, _PartyMode.GameData.ProfileIdsTeam2 };
+ SetPartyModeProfiles(ids);
+ }
+
+ public override void Back()
+ {
+ _SaveTeams();
+ _PartyMode.Back();
+ }
+
+ public override void Next()
+ {
+ _SaveTeams();
+ _PartyMode.GameData.NumPlayerTeam1 = _PartyMode.GameData.ProfileIdsTeam1.Count;
+ _PartyMode.GameData.NumPlayerTeam2 = _PartyMode.GameData.ProfileIdsTeam2.Count;
+ _PartyMode.Next();
+ }
+
+ private void _SaveTeams()
+ {
+ if (_TeamList.Length == CPartyModeTeamSurvival.TeamCount)
+ {
+ _PartyMode.GameData.ProfileIdsTeam1 = _TeamList[0];
+ _PartyMode.GameData.ProfileIdsTeam2 = _TeamList[1];
+ }
+
+ if (_NumPlayerTeams.Length == CPartyModeTeamSurvival.TeamCount)
+ {
+ _PartyMode.GameData.NumPlayerTeam1 = _NumPlayerTeams[0];
+ _PartyMode.GameData.NumPlayerTeam2 = _NumPlayerTeams[1];
+ }
+ }
+ }
+}
diff --git a/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalSongs.cs b/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalSongs.cs
new file mode 100644
index 00000000..543def64
--- /dev/null
+++ b/PartyModes/PartyModeTeamSurvival/CPartyScreenTeamSurvivalSongs.cs
@@ -0,0 +1,66 @@
+using VocaluxeLib.Menu;
+
+namespace VocaluxeLib.PartyModes.TeamSurvival
+{
+ class CPartyScreenTeamSurvivalSongs : CMenuPartySongSelection
+ {
+ protected override int _ScreenVersion
+ {
+ get { return 1; }
+ }
+
+ private new CPartyModeTeamSurvival _PartyMode;
+
+ public override void Init()
+ {
+ base.Init();
+ _PartyMode = (CPartyModeTeamSurvival)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/PartyModeTeamSurvival/GlobalSuppressions.cs b/PartyModes/PartyModeTeamSurvival/GlobalSuppressions.cs
new file mode 100644
index 00000000..e661ff03
Binary files /dev/null and b/PartyModes/PartyModeTeamSurvival/GlobalSuppressions.cs differ
diff --git a/PartyModes/PartyModeTeamSurvival/PartyModeTeamSurvival.csproj b/PartyModes/PartyModeTeamSurvival/PartyModeTeamSurvival.csproj
new file mode 100644
index 00000000..be08e00b
--- /dev/null
+++ b/PartyModes/PartyModeTeamSurvival/PartyModeTeamSurvival.csproj
@@ -0,0 +1,119 @@
+
+
+
+ DebugWin
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}
+ Library
+ Properties
+ VocaluxeLib.PartyModes.TeamSurvival
+ TeamSurvival
+ 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/PartyModeTeamSurvival/Settings.StyleCop b/PartyModes/PartyModeTeamSurvival/Settings.StyleCop
new file mode 100644
index 00000000..f4a4ea2a
--- /dev/null
+++ b/PartyModes/PartyModeTeamSurvival/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 423e9884..2681e92a 100644
--- a/Vocaluxe.sln
+++ b/Vocaluxe.sln
@@ -4,6 +4,7 @@ VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocaluxe.csproj", "{2A1E0F2D-5392-4BB7-B0A1-A9DFA13E79FF}"
ProjectSection(ProjectDependencies) = postProject
+ {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}
{D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} = {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC}
@@ -23,6 +24,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PitchTracker", "PitchTracke
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{8EDF4429-251A-416D-BB68-93F227191BCF}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeTeamSurvival", "PartyModes\PartyModeTeamSurvival\PartyModeTeamSurvival.csproj", "{7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
DebugLinux|x64 = DebugLinux|x64
@@ -173,6 +176,26 @@ Global
{8EDF4429-251A-416D-BB68-93F227191BCF}.ReleaseWin|x64.Build.0 = Release|x64
{8EDF4429-251A-416D-BB68-93F227191BCF}.ReleaseWin|x86.ActiveCfg = Release|x86
{8EDF4429-251A-416D-BB68-93F227191BCF}.ReleaseWin|x86.Build.0 = Release|x86
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.DebugLinux|x64.ActiveCfg = DebugLinux|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.DebugLinux|x64.Build.0 = DebugLinux|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.DebugLinux|x86.ActiveCfg = DebugLinux|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.DebugLinux|x86.Build.0 = DebugLinux|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.DebugWin|x64.ActiveCfg = DebugWin|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.DebugWin|x64.Build.0 = DebugWin|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.DebugWin|x86.ActiveCfg = DebugWin|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.DebugWin|x86.Build.0 = DebugWin|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.InstallerWin|x64.ActiveCfg = InstallerWin|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.InstallerWin|x64.Build.0 = InstallerWin|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.InstallerWin|x86.ActiveCfg = InstallerWin|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.InstallerWin|x86.Build.0 = InstallerWin|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.ReleaseLinux|x64.Build.0 = ReleaseLinux|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.ReleaseLinux|x86.ActiveCfg = ReleaseLinux|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.ReleaseLinux|x86.Build.0 = ReleaseLinux|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.ReleaseWin|x64.ActiveCfg = ReleaseWin|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU
+ {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE