From 944022f30b684b960323dc14e53561e9ad5b09f5 Mon Sep 17 00:00:00 2001 From: McSchneidar <262792195+McSchneidar@users.noreply.github.com> Date: Sun, 18 Oct 2026 10:36:19 +0200 Subject: [PATCH] Add knockout tournament party mode (#913) A new party mode for 3 to 16 players who sing against each other in one-on-one duels. Whoever scores more points moves on, the loser is out, until only the champion is left. - The bracket is shown mirrored: both halves lead towards the final in the center, where the champion is crowned - Players are drawn randomly; if the number of players doesn't fill the bracket, some players get a bye in the first round - Songs are picked randomly from all songs, a category or a playlist, sung as normal, short or medley version, and no song is played twice - Each player has up to 3 jokers for the whole tournament to skip a song they don't like - On a tie, the duel is sung again - The winner of each duel visibly moves on to the next round, and the champion is celebrated at the end Also fixes "Select random" in the player selection of party modes, which only filled half of the slots. Co-authored-by: Florian Ostertag --- Output/PartyModes/Tournament.xml | 20 + Output/PartyModes/Tournament/Languages/de.xml | 31 + Output/PartyModes/Tournament/Languages/en.xml | 31 + .../PartyModes/Tournament/Themes/Default.xml | 10 + .../Tournament/Themes/Default/Default.xml | 15 + .../Themes/Default/PartyModeIcon.png | Bin 0 -> 3741 bytes .../Screens/PartyScreenTournamentConfig.xml | 239 ++++++ .../Screens/PartyScreenTournamentMain.xml | 491 +++++++++++ .../Screens/PartyScreenTournamentNames.xml | 382 +++++++++ .../Screens/PartyScreenTournamentSongs.xml | 407 +++++++++ .../CPartyModeTournament.cs | 711 +++++++++++++++ .../CPartyScreenTournamentConfig.cs | 138 +++ .../CPartyScreenTournamentMain.cs | 716 ++++++++++++++++ .../CPartyScreenTournamentNames.cs | 74 ++ .../CPartyScreenTournamentSongs.cs | 66 ++ .../PartyModeTournament/GlobalSuppressions.cs | Bin 0 -> 1704 bytes .../PartyModeTournament.csproj | 118 +++ .../PartyModeTournament/Settings.StyleCop | 809 ++++++++++++++++++ Vocaluxe.sln | 23 + VocaluxeLib/Menu/CNameSelection.cs | 25 +- 20 files changed, 4285 insertions(+), 21 deletions(-) create mode 100644 Output/PartyModes/Tournament.xml create mode 100644 Output/PartyModes/Tournament/Languages/de.xml create mode 100644 Output/PartyModes/Tournament/Languages/en.xml create mode 100644 Output/PartyModes/Tournament/Themes/Default.xml create mode 100644 Output/PartyModes/Tournament/Themes/Default/Default.xml create mode 100644 Output/PartyModes/Tournament/Themes/Default/PartyModeIcon.png create mode 100644 Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentConfig.xml create mode 100644 Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentMain.xml create mode 100644 Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentNames.xml create mode 100644 Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentSongs.xml create mode 100644 PartyModes/PartyModeTournament/CPartyModeTournament.cs create mode 100644 PartyModes/PartyModeTournament/CPartyScreenTournamentConfig.cs create mode 100644 PartyModes/PartyModeTournament/CPartyScreenTournamentMain.cs create mode 100644 PartyModes/PartyModeTournament/CPartyScreenTournamentNames.cs create mode 100644 PartyModes/PartyModeTournament/CPartyScreenTournamentSongs.cs create mode 100644 PartyModes/PartyModeTournament/GlobalSuppressions.cs create mode 100644 PartyModes/PartyModeTournament/PartyModeTournament.csproj create mode 100644 PartyModes/PartyModeTournament/Settings.StyleCop diff --git a/Output/PartyModes/Tournament.xml b/Output/PartyModes/Tournament.xml new file mode 100644 index 00000000..490aceaf --- /dev/null +++ b/Output/PartyModes/Tournament.xml @@ -0,0 +1,20 @@ + + + 2 + + TR_PARTYMODE_NAME + McSchneidar + TR_PARTYMODE_DESCRIPTION + Tournament + CPartyModeTournament + 1 + 0 + TR_PARTYMODE_AUDIENCE + + + CPartyScreenTournamentMain + CPartyScreenTournamentConfig + CPartyScreenTournamentNames + CPartyScreenTournamentSongs + + diff --git a/Output/PartyModes/Tournament/Languages/de.xml b/Output/PartyModes/Tournament/Languages/de.xml new file mode 100644 index 00000000..dda4780b --- /dev/null +++ b/Output/PartyModes/Tournament/Languages/de.xml @@ -0,0 +1,31 @@ + + + Deutsch + K.O.-Turnier + Singt Duelle im K.O.-System, bis nur noch ein Sieger übrig ist. + Für 3 bis 16 Spieler, die einen echten Wettkampf mögen. + Weiter + Zurück + Start + Beenden + Ja + Nein + Duell starten + Songs + K.O.-Turnier: Konfiguration + Anzahl der Spieler + Joker pro Spieler + K.O.-Turnier: Spieler auswählen + Zufällig wählen + K.O.-Turnier + Willst du das Turnier wirklich beenden? + Achtelfinale + Viertelfinale + Halbfinale + Finale + Freilos + Sieger + Nächstes Duell: + gegen + Gleichstand! Das Duell wird nachgesungen. + diff --git a/Output/PartyModes/Tournament/Languages/en.xml b/Output/PartyModes/Tournament/Languages/en.xml new file mode 100644 index 00000000..a622bd06 --- /dev/null +++ b/Output/PartyModes/Tournament/Languages/en.xml @@ -0,0 +1,31 @@ + + + English + Knockout Tournament + Sing duels in a knockout bracket until only one champion is left. + For 3 to 16 players who like a real competition. + Next + Back + Start + Exit + Yes + No + Start duel + Songs + Knockout Tournament: Configuration + Number of players + Jokers per player + Knockout Tournament: Choose Players + Select random + Knockout Tournament + Do you really want to exit the tournament? + Round of 16 + Quarterfinal + Semifinal + Final + Bye + Champion + Next duel: + vs. + Tie! The duel is sung again. + diff --git a/Output/PartyModes/Tournament/Themes/Default.xml b/Output/PartyModes/Tournament/Themes/Default.xml new file mode 100644 index 00000000..97392ded --- /dev/null +++ b/Output/PartyModes/Tournament/Themes/Default.xml @@ -0,0 +1,10 @@ + + + 9 + + Default + McSchneidar + 0 + 1 + + diff --git a/Output/PartyModes/Tournament/Themes/Default/Default.xml b/Output/PartyModes/Tournament/Themes/Default/Default.xml new file mode 100644 index 00000000..d88d34b4 --- /dev/null +++ b/Output/PartyModes/Tournament/Themes/Default/Default.xml @@ -0,0 +1,15 @@ + + + 4 + + Default + McSchneidar + 0 + 1 + + + + PartyModeIcon.png + + + diff --git a/Output/PartyModes/Tournament/Themes/Default/PartyModeIcon.png b/Output/PartyModes/Tournament/Themes/Default/PartyModeIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..a8a9b3bc495ebb7114d7530df4fec2f34461c010 GIT binary patch literal 3741 zcmds4XHe5y7XPQbi1-pfMI}@LQ2_y!4nmfW7?2`}bVP+vCG;Q(51-;gKu`gZ5(ESc zC4z(wQGA46lp=(Vlt>dIfe^~Zo!Qyh4?8>iZFfK1Id$gVbI(1$bI+rz=EiVdBrgB} za8nZlD*ym-SrEVj;}XZf!rMP3td+4IP}(iR;0gw}uAAOQqXAhi&jWxSdI8X%F5HFW zE&zZKK>&nHK|ggw@ZYT4>5AP$%s{KX~=v^<7R%)2HCOnL>+zy@~? zg*+h>XAmt0eWH8NJt*$xvwWFSp5lH3$w`>#;nUHD!pCI}+sUA&jn<^13~AWY{!iUr z>-q&}a~e16H*BmJj5iMRS)7b2^J~Ea{SCn#j{p!D%EK>#BK%J?RCB1gQOV4B1J1&5 z>CW`dmqHB~ZP)B$6D}}teQz@SzWA9*^?DJt1`u>>=KSp9-Kf3wq7FySZIA7EPiXeD zw(GB|L>}Hd@IDsSyP|}vVP>Cg6oOB7+-cgIWvpv8uSa5+TyNJljC z7FL8c#K7+A*BMcUc5s)L!+mk2;VkdxwUi|oxeCH~zhSd`b1uePJq1s?b|=3=m^#)S z4wphrMu3Yp-}b}E^+r*P5sQIxU}!17C;qYdJqOK7kbGOy30;+FIavk@h)g7UEk~o&xM)gp2%+xe>%(p>|IlM+k49N<7}J$rfyLk;G}T0}D(oAPb6yoKL;)6cO=|@zQ1x z5`m+mYxiT*UGq`_y5LmEmEDn$&lVS%S(M~#Sf!c(oM?yXtghHS(qfRU{cZgn-ru3k zqI7Tghcclj!e`Cln_roO{3Hx3#vJjdri5Cils^>Q3nA(bIK_X}A!i^_x-0MN z+FIz2ipF7Z;>1>c(rAyhX>F$&LE6NP$L44+AZv^6h9*Om|E;1Po(9#By;A>tYa-UE z(sF({T$T%V5(HK+l|;+$OBkty9^t9#O)+iP^o(=Is^L7grG?V+#QYkKe=(jJ8% zX$b_vl5K9IvHAX1rc^yl$yijO?BRe&Fg%+mHq`uRnD(gO0rO>zr80XJFnB^r}qGf0#8r!}T zS%oWk>$#q@ql)saS*5+eT-ohe20D%3)7fQ( z8JwNkgF*;S52}M=(PNMxsESudlSKrln=Pa5Vzsa<_H~yMZ;RBv42ponYBi2IWBDE> z1~!)p-JU_=BXb>e&&U>%Py!kNCb|rc|~c z(bl#4Hew}=(w@cX21YIJ)SJ0%&y`b3j=i1DWdsk^+jl24?Zt!)O5%Xd-R7&_V>>e`%o|UgR1;^uU&ySTP{Xs| zu)>$i4xJ-emHvL6X)U^@M%a-z^Z_@?e!O~iNUxY(gaO#Eb0zlzZ6-l?d;#cak@L=ZQbV29ROLols$*QMSZF#DRkGb=EiuNc zam>~6v?1J8biUX=Dn-!KHG@|J;TToY%k_xZmHd<$UJ;+-(9u^EOMqR?yLzrG%y+kE zt4}9gd$DLY`%y}+wEzfCG|3S&VIJVy!BOzt8FU|8>#w<>E0zyplEbu&_GgF=#TTn* z`vbAE(nQcvSz9xeEcg9OQT6BDM*QV#&}r$<6b|#OEzgGc3F*_NP{pY7r4_YOC$N?j%Iqul_ee=A}jkP``>z5q5 z1KMx=Iq^__6aLye=Y!P} z@v?leMC$U9FhyVTdGW)f~lJ=2i?8_PS9?Jp_RvsIlu0JaHi!wp*t+9n* zXy-(Wh~h`K3uF#+-sSq-34Z6+bI=FNzaG^Z))qWeuJWb*TD;bRmfJ)+m2YO}&pZZQ z9N9GPe)>;`bB|}f2Y&kjGm2`WuhC{NaH= zI)BHNSL)+@}LY1R#*^eJbMaC45_+}S} z%)1OOsxO_1#6V(8=~=AR>7@OWbroX?;aiknt*GZ$`-0QL2yZD|cIL9(x_{Tg4F7ovJRc{6@aw@P3G`1PGv-^BubIU}6eJ9rg;Jh||D#FFxQq-wW0P3pU! z{Dyh-EJe|&=H+fHp0dKN+hbv->Klx9`=zDqHA-KHfHkD`L8jJtrn-^CSmL(w^eL)k z%nj}6%iPrGW7?jh$_cP1zsidIM+z#L4}5C=?5I9?Z7Ltf=k$!V80=1ah%x_knBP+c z)C1V&stQE2xh;u}k(2_H4tfG4%a^g#NbX~fR7nzu9^je=3eg6xIv}`fV|r^W6~i@Q z`eh`Qvbpu*g7z?QRRM`ZZ^UbcN{ZLFZDn9c*0=4_!Ail6QW=6aSm1H zd_q1;HQ>>nTWvL0Aq$~CF34|j`kaPxqrjeI?b8XVz&x=!mim^*6QEgnElLL@5MTj_ zKjL^q;s`MEy?lDNA}vC5uF}F13wPyQ$Xj96?gk>-C)0+a`1=drBdKSG8><<04J@=4 zt#C`}=~$kc!tXG$6X?Mbt9C4~^isuGUKu)+DZDL$YH}O&E7uRjExUA!NX^(&W5@C= zZU*aA^jW&Yi4ZR#ceUXtQjD>J;sL9Wr_MTWi$Fm(@68AZX?>ohYbeMU?^`8tsD}ht zZ?p$bbORR>a3#gT0t@`Tfaa55Pm=ApmsR$>QUNT=P2PdzlTel{5wuiUK4?hPM?n@) z7w%J?xnpTXN*3tB}vLT(_a}4n! zxNG>xYLae|`Un0nlSx*fIBsEjaX)&@Ly=jU$dr!?8xvL$-My+yV`kC`$-_Kk!Yr3o8@|A&!=JC9lO?uaAqFOcoe SW<38n8k!oK8 + + + PartyScreenTournamentConfig + 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_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 + 10 + + + + + + + + + diff --git a/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentMain.xml b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentMain.xml new file mode 100644 index 00000000..e2cef273 --- /dev/null +++ b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentMain.xml @@ -0,0 +1,491 @@ + + + + PartyScreenTournamentMain + 1 + + + + Video + + + BG_Default + + + + + + + + + 0 + 60 + 1920 + 67.5 + 1 + + + + PopupBG + + + 0 + 0 + 1920 + 1080 + -1 + + + + + + 0.1 + 0.09 + 0.25 + 0.92 + + + 0 + 0 + 380 + 100 + 0.5 + + + + + + 1 + 0.8 + 0 + 1 + + + 0 + 0 + 388 + 108 + 0.6 + + + + + + + 0 + 0 + 38 + 38 + 0.4 + + + + + + 1 + 1 + 1 + 0.5 + + + 0 + 0 + 3 + 3 + 0.7 + + + + + + 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 + + + 0 + 150 + 0 + 34 + 0 + + 0.75 + 0.78 + 0.85 + 1 + + + Center + Center + + Outline + + + + 0 + 0 + 0 + 30 + 0 + + + Left + Center + + Outline + + + + 0 + 0 + 0 + 30 + 0 + + 0.31 + 0.82 + 0.91 + 1 + + + Left + Center + + Outline + + + + 0 + 0 + 0 + 30 + 0 + + 0.6 + 0.62 + 0.68 + 1 + + + Left + Center + + Outline + + + + 0 + 0 + 0 + 30 + 0 + + + Right + Center + + Outline + + + + 960 + 320 + 0 + 36 + 0 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + TR_SCREENMAIN_CHAMPION + + + 960 + 365 + 0 + 54 + 500 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + + + + 960 + 860 + 0 + 40.5 + 1500 + + + Center + Center + + Outline + + + + 960 + 908 + 0 + 34 + 1500 + + 1 + 0.8 + 0 + 1 + + + Center + Center + + Outline + TR_SCREENMAIN_REMATCH + + + + + + + + + + + + + + + + + + + Star + + 700 + 290 + 520 + 170 + -1 + + + 1 + 0.8 + 0 + 0.6 + + Star + 18 + 40 + + + + diff --git a/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentNames.xml b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentNames.xml new file mode 100644 index 00000000..2550c469 --- /dev/null +++ b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentNames.xml @@ -0,0 +1,382 @@ + + + + PartyScreenTournamentNames + 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/Tournament/Themes/Default/Screens/PartyScreenTournamentSongs.xml b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentSongs.xml new file mode 100644 index 00000000..8819866f --- /dev/null +++ b/Output/PartyModes/Tournament/Themes/Default/Screens/PartyScreenTournamentSongs.xml @@ -0,0 +1,407 @@ + + + + PartyScreenTournamentSongs + 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/PartyModeTournament/CPartyModeTournament.cs b/PartyModes/PartyModeTournament/CPartyModeTournament.cs new file mode 100644 index 00000000..f21093c5 --- /dev/null +++ b/PartyModes/PartyModeTournament/CPartyModeTournament.cs @@ -0,0 +1,711 @@ +#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.Tournament +{ + public class CTournamentMatch + { + public int Round; + public int Index; + public int Player1 = -1; + public int Player2 = -1; + public int Score1; + public int Score2; + public int Winner = -1; + public bool Bye; + + public bool Played + { + get { return Winner >= 0; } + } + + public bool Ready + { + get { return !Played && Player1 >= 0 && Player2 >= 0; } + } + + public int WinnerPlayer + { + get + { + if (Winner == 0) + { + return Player1; + } + + return Winner == 1 ? Player2 : -1; + } + } + + public int LoserPlayer + { + get + { + if (Winner == 0) + { + return Player2; + } + + return Winner == 1 ? Player1 : -1; + } + } + } + + public abstract class CPartyScreenTournament : CMenuParty + { + protected new CPartyModeTournament _PartyMode; + + public override void Init() + { + base.Init(); + _PartyMode = (CPartyModeTournament)base._PartyMode; + } + } + + public sealed class CPartyModeTournament : CPartyMode + { + public const int NumPlayerAtOnce = 2; + public const int MaxJokers = 3; + + public override int MinMics + { + get { return NumPlayerAtOnce; } + } + public override int MaxMics + { + get { return CBase.Config.GetMaxNumMics(); } + } + public override int MinPlayers + { + get { return 3; } + } + public override int MaxPlayers + { + get { return 16; } + } + 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 NumJokers; + public int[] Jokers; + public List ProfileIds; + + public ESongSource SongSource; + public ESongSorting Sorting; + public int CategoryIndex; + public int PlaylistId; + + public EGameMode GameMode; + public int NumMedleySongs; + + public List Rounds; + public bool IsRematch; + public int NumMatchesPlayed; + public CTournamentMatch LastDecidedMatch; + + public List Songs; + } + + public SData GameData; + private EStage _Stage; + + public CPartyModeTournament(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 + { + NumPlayer = 8, + 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, + Rounds = 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; + } + + GameData.Rounds = new List(); + } + + public override bool Init() + { + if (!base.Init()) + { + return false; + } + + SetDefaults(); + return true; + } + + public override void UpdateGame() { } + + public int NumRounds + { + get { return GameData.Rounds.Count; } + } + + public CTournamentMatch FinalMatch + { + get { return GameData.Rounds.Count > 0 ? GameData.Rounds[GameData.Rounds.Count - 1][0] : null; } + } + + public bool IsFinished + { + get { return FinalMatch != null && FinalMatch.Played; } + } + + public CTournamentMatch CurrentMatch + { + get + { + foreach (var round in GameData.Rounds) + { + foreach (var match in round) + { + if (match.Ready) + { + return match; + } + } + } + + return null; + } + } + + private IMenu _GetNextScreen() + { + switch (_Stage) + { + case EStage.Config: + return _Screens["CPartyScreenTournamentConfig"]; + case EStage.Songs: + return _Screens["CPartyScreenTournamentSongs"]; + case EStage.Names: + return _Screens["CPartyScreenTournamentNames"]; + case EStage.Main: + return _Screens["CPartyScreenTournamentMain"]; + 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; + CBase.Songs.ResetSongSung(); + _CreateBracket(); + break; + case EStage.Main: + if (CurrentMatch == 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["CPartyScreenTournamentConfig"]; + } + + 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 match = CurrentMatch; + if (match != null && GameData.Jokers != null) + { + var player = teamNr == 0 ? match.Player1 : match.Player2; + if (GameData.Jokers[player] > 0) + { + GameData.Jokers[player]--; + } + } + + _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 _CreateBracket() + { + var size = 4; + while (size < GameData.NumPlayer) + { + size *= 2; + } + + GameData.Rounds = new List(); + for (var count = size / 2; count >= 1; count /= 2) + { + var round = new CTournamentMatch[count]; + for (var i = 0; i < count; i++) + { + round[i] = new CTournamentMatch { Round = GameData.Rounds.Count, Index = i }; + } + + GameData.Rounds.Add(round); + } + + var firstRound = GameData.Rounds[0]; + var half = firstRound.Length / 2; + var byeOrder = new List(); + for (var i = 0; i < half; i++) + { + byeOrder.Add(i); + byeOrder.Add(half + i); + } + + var numByes = size - GameData.NumPlayer; + for (var i = 0; i < numByes; i++) + { + firstRound[byeOrder[i]].Bye = true; + } + + var players = Enumerable.Range(0, GameData.NumPlayer).ToList(); + players.Shuffle(); + var next = 0; + foreach (var match in firstRound) + { + match.Player1 = players[next++]; + if (!match.Bye) + { + match.Player2 = players[next++]; + } + } + + foreach (var match in firstRound) + { + if (match.Bye) + { + match.Winner = 0; + _Advance(match); + } + } + + GameData.Jokers = new int[GameData.NumPlayer]; + for (var i = 0; i < GameData.NumPlayer; i++) + { + GameData.Jokers[i] = GameData.NumJokers; + } + + GameData.IsRematch = false; + GameData.NumMatchesPlayed = 0; + GameData.LastDecidedMatch = null; + GameData.Songs = new List(); + } + + private void _Advance(CTournamentMatch match) + { + if (match.Round + 1 >= GameData.Rounds.Count) + { + return; + } + + var nextMatch = GameData.Rounds[match.Round + 1][match.Index / 2]; + if (match.Index % 2 == 0) + { + nextMatch.Player1 = match.WinnerPlayer; + } + else + { + nextMatch.Player2 = match.WinnerPlayer; + } + } + + 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 match = CurrentMatch; + _ScreenSongOptions.Selection.NumJokers = new int[] { GameData.Jokers[match.Player1], GameData.Jokers[match.Player2] }; + _ScreenSongOptions.Selection.TeamNames = new string[] + { + CBase.Profiles.GetPlayerName(GameData.ProfileIds[match.Player1]), + CBase.Profiles.GetPlayerName(GameData.ProfileIds[match.Player2]) + }; + } + + private bool _PrepareRound(int[] songIds) + { + CBase.Game.Reset(); + CBase.Game.ClearSongs(); + + CBase.Game.SetNumPlayer(NumPlayerAtOnce); + var players = CBase.Game.GetPlayers(); + var match = CurrentMatch; + if (players == null || players.Length < NumPlayerAtOnce || match == null) + { + return false; + } + + players[0].ProfileId = GameData.ProfileIds[match.Player1]; + players[1].ProfileId = GameData.ProfileIds[match.Player2]; + + 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 match = CurrentMatch; + if (match == null) + { + return; + } + + var points = CBase.Game.GetPoints(); + if (points == null || points.NumRounds == 0) + { + return; + } + + var scores = new double[NumPlayerAtOnce]; + for (var round = 0; round < points.NumRounds; round++) + { + var res = points.GetPlayer(round, NumPlayerAtOnce); + if (res == null || res.Length < NumPlayerAtOnce) + { + return; + } + + for (var p = 0; p < NumPlayerAtOnce; p++) + { + scores[p] += res[p].Points; + } + } + + match.Score1 = (int)Math.Round(scores[0] / points.NumRounds); + match.Score2 = (int)Math.Round(scores[1] / points.NumRounds); + GameData.NumMatchesPlayed++; + + if (match.Score1 == match.Score2) + { + GameData.IsRematch = true; + return; + } + + GameData.IsRematch = false; + GameData.LastDecidedMatch = match; + match.Winner = match.Score1 > match.Score2 ? 0 : 1; + _Advance(match); + } + } +} diff --git a/PartyModes/PartyModeTournament/CPartyScreenTournamentConfig.cs b/PartyModes/PartyModeTournament/CPartyScreenTournamentConfig.cs new file mode 100644 index 00000000..48a5230b --- /dev/null +++ b/PartyModes/PartyModeTournament/CPartyScreenTournamentConfig.cs @@ -0,0 +1,138 @@ +#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.Tournament +{ + public class CPartyScreenTournamentConfig : CPartyScreenTournament + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private const string _SelectSlideNumPlayers = "SelectSlideNumPlayers"; + 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, _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(); + + _SelectSlides[_SelectSlideNumJokers].Clear(); + for (var i = 0; i <= CPartyModeTournament.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.NumJokers = _SelectSlides[_SelectSlideNumJokers].Selection; + } + } +} diff --git a/PartyModes/PartyModeTournament/CPartyScreenTournamentMain.cs b/PartyModes/PartyModeTournament/CPartyScreenTournamentMain.cs new file mode 100644 index 00000000..59e2dbb6 --- /dev/null +++ b/PartyModes/PartyModeTournament/CPartyScreenTournamentMain.cs @@ -0,0 +1,716 @@ +#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.Tournament +{ + class CMatchBox + { + public CStatic Box; + public CStatic Active; + public CStatic[] Avatars; + public CText[] Names; + public CText[] Scores; + } + + public class CPartyScreenTournamentMain : CPartyScreenTournament + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private const string _TextPopupReallyExit = "TextPopupReallyExit"; + private const string _TextRoundLabel = "TextRoundLabel"; + private const string _TextMatchName = "TextMatchName"; + private const string _TextMatchNameWinner = "TextMatchNameWinner"; + private const string _TextMatchNameLoser = "TextMatchNameLoser"; + private const string _TextMatchScore = "TextMatchScore"; + private const string _TextChampionLabel = "TextChampionLabel"; + private const string _TextChampion = "TextChampion"; + private const string _TextNextMatch = "TextNextMatch"; + private const string _TextRematch = "TextRematch"; + + 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 _StaticMatchBox = "StaticMatchBox"; + private const string _StaticMatchActive = "StaticMatchActive"; + private const string _StaticMatchAvatar = "StaticMatchAvatar"; + private const string _StaticBracketLine = "StaticBracketLine"; + + private const string _ParticleEffectChampion = "ParticleEffectChampion"; + + private const int _MaxMatches = 15; + private const int _MaxColumns = 7; + private const int _MaxLines = 32; + private const float _Margin = 40f; + private const float _AreaTop = 210f; + private const float _AreaBottom = 830f; + private const float _MaxBoxW = 380f; + private const float _ColumnGap = 24f; + private const float _ScoreW = 70f; + private const float _RowH = 46f; + private const float _BoxPadding = 4f; + private const float _ActiveBorder = 4f; + private const float _LineThickness = 3f; + private const float _AdvanceDelay = 600f; + private const float _AdvanceDuration = 900f; + private const float _ChampionPopDuration = 700f; + private const float _FlyZ = -0.5f; + + private bool _ExitPopupVisible; + + private List _MatchBoxes; + private List _RoundLabels; + private List _Lines; + private int _NumLinesUsed; + + private readonly Stopwatch _AnimTimer = new Stopwatch(); + private CTournamentMatch _AdvanceMatch; + private CTournamentMatch _AdvanceTarget; + private int _AdvanceSlot; + private bool _ChampionShown; + private float _ChampionHeight; + + private CStatic _FlyBorder; + private CStatic _FlyBox; + private CStatic _FlyAvatar; + private CText _FlyName; + + public override void Init() + { + base.Init(); + + _ThemeTexts = new string[] + { + _TextPopupReallyExit, _TextRoundLabel, _TextMatchName, _TextMatchNameWinner, _TextMatchNameLoser, _TextMatchScore, _TextChampionLabel, _TextChampion, + _TextNextMatch, _TextRematch + }; + _ThemeButtons = new string[] { _ButtonNextRound, _ButtonBack, _ButtonExit, _ButtonPopupYes, _ButtonPopupNo }; + _ThemeStatics = new string[] { _StaticPopupBG, _StaticMatchBox, _StaticMatchActive, _StaticMatchAvatar, _StaticBracketLine }; + _ThemeParticleEffects = new string[] { _ParticleEffectChampion }; + } + + public override void LoadTheme(string xmlPath) + { + base.LoadTheme(xmlPath); + + _Lines = new List(); + for (var i = 0; i < _MaxLines; i++) + { + var line = GetNewStatic(_Statics[_StaticBracketLine]); + _AddStatic(line); + _Lines.Add(line); + } + + _MatchBoxes = new List(); + for (var i = 0; i < _MaxMatches; i++) + { + var matchBox = new CMatchBox + { + Active = GetNewStatic(_Statics[_StaticMatchActive]), + Box = GetNewStatic(_Statics[_StaticMatchBox]), + Avatars = new CStatic[CPartyModeTournament.NumPlayerAtOnce], + Names = new CText[CPartyModeTournament.NumPlayerAtOnce], + Scores = new CText[CPartyModeTournament.NumPlayerAtOnce] + }; + _AddStatic(matchBox.Active); + _AddStatic(matchBox.Box); + + for (var p = 0; p < CPartyModeTournament.NumPlayerAtOnce; p++) + { + matchBox.Avatars[p] = GetNewStatic(_Statics[_StaticMatchAvatar]); + matchBox.Avatars[p].Aspect = EAspect.Crop; + _AddStatic(matchBox.Avatars[p]); + matchBox.Names[p] = GetNewText(_Texts[_TextMatchName]); + _AddText(matchBox.Names[p]); + matchBox.Scores[p] = GetNewText(_Texts[_TextMatchScore]); + _AddText(matchBox.Scores[p]); + } + + _MatchBoxes.Add(matchBox); + } + + _RoundLabels = new List(); + for (var i = 0; i < _MaxColumns; i++) + { + var label = GetNewText(_Texts[_TextRoundLabel]); + _AddText(label); + _RoundLabels.Add(label); + } + + _Statics[_StaticMatchBox].Visible = false; + _Statics[_StaticMatchActive].Visible = false; + _Statics[_StaticMatchAvatar].Visible = false; + _Statics[_StaticBracketLine].Visible = false; + _Texts[_TextRoundLabel].Visible = false; + _Texts[_TextMatchName].Visible = false; + _Texts[_TextMatchNameWinner].Visible = false; + _Texts[_TextMatchNameLoser].Visible = false; + _Texts[_TextMatchScore].Visible = false; + + _FlyBorder = GetNewStatic(_Statics[_StaticMatchActive]); + _FlyBox = GetNewStatic(_Statics[_StaticMatchBox]); + _FlyAvatar = GetNewStatic(_Statics[_StaticMatchAvatar]); + _FlyAvatar.Aspect = EAspect.Crop; + _FlyName = GetNewText(_Texts[_TextMatchNameWinner]); + _FlyName.Z = _FlyZ - 0.15f; + _AddStatic(_FlyBorder); + _AddStatic(_FlyBox); + _AddStatic(_FlyAvatar); + _AddText(_FlyName); + _SetFlyVisible(false); + + _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(); + + _AdvanceMatch = _PartyMode.GameData.LastDecidedMatch; + _PartyMode.GameData.LastDecidedMatch = null; + _AdvanceTarget = null; + if (_AdvanceMatch != null && _AdvanceMatch.Round + 1 < _PartyMode.NumRounds) + { + _AdvanceTarget = _PartyMode.GameData.Rounds[_AdvanceMatch.Round + 1][_AdvanceMatch.Index / 2]; + _AdvanceSlot = _AdvanceMatch.Index % 2; + } + + _ChampionShown = _PartyMode.IsFinished && _AdvanceMatch == null; + _AnimTimer.Reset(); + _AnimTimer.Start(); + _SetFlyVisible(false); + + _UpdateBracket(); + _UpdateInfo(); + + var started = _PartyMode.GameData.NumMatchesPlayed > 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() + { + if (_AdvanceMatch != null) + { + _UpdateAdvance(); + } + + if (_ChampionShown) + { + _UpdateChampion(); + } + + return true; + } + + 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 void _SetFlyVisible(bool visible) + { + _FlyBorder.Visible = visible; + _FlyBox.Visible = visible; + _FlyAvatar.Visible = visible; + _FlyName.Visible = visible; + } + + private SRectF _GetRowRect(int round, int index, int slot) + { + var box = _GetBoxRect(round, index); + return new SRectF(box.X, box.Y + _BoxPadding + slot * _RowH, box.W, _RowH, 0f); + } + + private void _UpdateAdvance() + { + var time = _AnimTimer.ElapsedMilliseconds - _AdvanceDelay; + if (time < 0) + { + return; + } + + if (_AdvanceTarget == null) + { + _AdvanceMatch = null; + _ChampionShown = true; + _AnimTimer.Reset(); + _AnimTimer.Start(); + _UpdateInfo(); + return; + } + + var progress = Math.Min(1f, time / _AdvanceDuration); + if (progress >= 1f) + { + _AdvanceMatch = null; + _AdvanceTarget = null; + _SetFlyVisible(false); + _UpdateBracket(); + return; + } + + var from = _GetRowRect(_AdvanceMatch.Round, _AdvanceMatch.Index, _AdvanceMatch.Winner); + var to = _GetRowRect(_AdvanceTarget.Round, _AdvanceTarget.Index, _AdvanceSlot); + var eased = _EaseInOut(progress); + var row = new SRectF(from.X + (to.X - from.X) * eased, from.Y + (to.Y - from.Y) * eased, from.W + (to.W - from.W) * eased, _RowH, 0f); + + var avatarSize = _RowH - 8f; + _FlyBox.MaxRect = new SRectF(row.X, row.Y, row.W, row.H, _FlyZ - 0.05f); + _FlyBorder.MaxRect = new SRectF(row.X - _ActiveBorder, row.Y - _ActiveBorder, row.W + 2 * _ActiveBorder, row.H + 2 * _ActiveBorder, _FlyZ); + _FlyAvatar.MaxRect = new SRectF(row.X + 8f, row.Y + 4f, avatarSize, avatarSize, _FlyZ - 0.1f); + _FlyAvatar.Texture = CBase.Profiles.GetAvatar(_PartyMode.GameData.ProfileIds[_AdvanceMatch.WinnerPlayer]); + _FlyName.Text = _GetName(_AdvanceMatch.WinnerPlayer); + _FlyName.X = row.X + 16f + avatarSize; + _FlyName.Y = row.Y + (_RowH - _FlyName.Rect.H) / 2; + _FlyName.W = row.W - avatarSize - 24f; + _SetFlyVisible(true); + } + + 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; + } + + private void _OnBack() + { + if (_ExitPopupVisible) + { + _ShowPopup(false); + } + else if (_PartyMode.GameData.NumMatchesPlayed == 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 string _GetName(int player) + { + return CBase.Profiles.GetPlayerName(_PartyMode.GameData.ProfileIds[player]); + } + + private string _GetRoundName(int round) + { + var fromEnd = _PartyMode.NumRounds - 1 - round; + switch (fromEnd) + { + case 0: + return "TR_SCREENMAIN_ROUND_FINAL"; + case 1: + return "TR_SCREENMAIN_ROUND_SEMIFINAL"; + case 2: + return "TR_SCREENMAIN_ROUND_QUARTERFINAL"; + default: + return "TR_SCREENMAIN_ROUND_EIGHTHFINAL"; + } + } + + private int _GetColumn(int round, int index) + { + var numRounds = _PartyMode.NumRounds; + if (round == numRounds - 1) + { + return round; + } + + var count = _PartyMode.GameData.Rounds[round].Length; + return index < count / 2 ? round : 2 * numRounds - 2 - round; + } + + private float _GetColumnWidth() + { + var numColumns = 2 * _PartyMode.NumRounds - 1; + return (CBase.Settings.GetRenderW() - 2 * _Margin) / numColumns; + } + + private float _GetBoxWidth() + { + return Math.Min(_GetColumnWidth() - _ColumnGap, _MaxBoxW); + } + + private float _GetBoxHeight() + { + return CPartyModeTournament.NumPlayerAtOnce * _RowH + 2 * _BoxPadding; + } + + private SRectF _GetBoxRect(int round, int index) + { + var columnW = _GetColumnWidth(); + var boxW = _GetBoxWidth(); + var boxH = _GetBoxHeight(); + var x = _Margin + _GetColumn(round, index) * columnW + (columnW - boxW) / 2; + + var areaH = _AreaBottom - _AreaTop; + float centerY; + if (round == _PartyMode.NumRounds - 1) + { + centerY = _AreaTop + areaH / 2; + } + else + { + var perSide = _PartyMode.GameData.Rounds[round].Length / 2; + var position = index % perSide; + centerY = _AreaTop + areaH * (position + 0.5f) / perSide; + } + + return new SRectF(x, centerY - boxH / 2, boxW, boxH, _Statics[_StaticMatchBox].Rect.Z); + } + + private void _UpdateBracket() + { + var current = _PartyMode.CurrentMatch; + var boxNr = 0; + _NumLinesUsed = 0; + + foreach (var round in _PartyMode.GameData.Rounds) + { + foreach (var match in round) + { + _UpdateMatchBox(_MatchBoxes[boxNr], match, match == current); + boxNr++; + + if (match.Round < _PartyMode.NumRounds - 1) + { + _AddConnector(match); + } + } + } + + for (var i = boxNr; i < _MatchBoxes.Count; i++) + { + _SetMatchBoxVisible(_MatchBoxes[i], false); + } + + for (var i = _NumLinesUsed; i < _Lines.Count; i++) + { + _Lines[i].Visible = false; + } + + var numColumns = 2 * _PartyMode.NumRounds - 1; + var columnW = _GetColumnWidth(); + for (var c = 0; c < _RoundLabels.Count; c++) + { + _RoundLabels[c].Visible = c < numColumns; + if (c >= numColumns) + { + continue; + } + + var round = c < _PartyMode.NumRounds ? c : numColumns - 1 - c; + _RoundLabels[c].X = _Margin + c * columnW + columnW / 2; + _RoundLabels[c].Text = _GetRoundName(round); + } + + var final = _GetBoxRect(_PartyMode.NumRounds - 1, 0); + _Texts[_TextChampionLabel].X = final.X + final.W / 2; + _Texts[_TextChampion].X = final.X + final.W / 2; + } + + private void _SetMatchBoxVisible(CMatchBox matchBox, bool visible) + { + matchBox.Box.Visible = visible; + matchBox.Active.Visible = false; + for (var p = 0; p < CPartyModeTournament.NumPlayerAtOnce; p++) + { + matchBox.Avatars[p].Visible = visible; + matchBox.Names[p].Visible = visible; + matchBox.Scores[p].Visible = visible; + } + } + + private void _UpdateMatchBox(CMatchBox matchBox, CTournamentMatch match, bool isCurrent) + { + var rect = _GetBoxRect(match.Round, match.Index); + _SetMatchBoxVisible(matchBox, true); + + matchBox.Box.MaxRect = rect; + matchBox.Active.MaxRect = new SRectF(rect.X - _ActiveBorder, rect.Y - _ActiveBorder, rect.W + 2 * _ActiveBorder, rect.H + 2 * _ActiveBorder, _Statics[_StaticMatchActive].Rect.Z); + matchBox.Active.Visible = isCurrent; + + var avatarSize = _RowH - 8f; + var showScore = (match.Played && !match.Bye) || (_PartyMode.GameData.IsRematch && isCurrent); + for (var p = 0; p < CPartyModeTournament.NumPlayerAtOnce; p++) + { + var player = p == 0 ? match.Player1 : match.Player2; + if (match == _AdvanceTarget && p == _AdvanceSlot) + { + player = -1; + } + + var rowY = rect.Y + _BoxPadding + p * _RowH; + + var avatar = matchBox.Avatars[p]; + avatar.MaxRect = new SRectF(rect.X + 8f, rowY + 4f, avatarSize, avatarSize, _Statics[_StaticMatchAvatar].Rect.Z); + avatar.Texture = player >= 0 ? CBase.Profiles.GetAvatar(_PartyMode.GameData.ProfileIds[player]) : null; + avatar.Visible = player >= 0; + + var name = matchBox.Names[p]; + name.X = rect.X + 16f + avatarSize; + name.Y = rowY + (_RowH - name.Rect.H) / 2; + name.W = rect.W - avatarSize - 24f - (showScore ? _ScoreW : 0f); + + var score = matchBox.Scores[p]; + score.X = rect.X + rect.W - 10f; + score.Y = name.Y; + + if (player >= 0) + { + name.Text = _GetName(player); + } + else if (match.Bye) + { + name.Text = "TR_SCREENMAIN_BYE"; + } + else + { + name.Text = "?"; + } + + score.Text = showScore ? (p == 0 ? match.Score1 : match.Score2).ToString() : string.Empty; + + if (match.Played) + { + name.Color = match.Winner == p ? _Texts[_TextMatchNameWinner].Color : _Texts[_TextMatchNameLoser].Color; + } + else + { + name.Color = player >= 0 ? _Texts[_TextMatchName].Color : _Texts[_TextMatchNameLoser].Color; + } + + score.Color = name.Color; + } + } + + private void _AddLine(float x1, float y1, float x2, float y2) + { + if (_NumLinesUsed >= _Lines.Count) + { + return; + } + + var line = _Lines[_NumLinesUsed++]; + var z = _Statics[_StaticBracketLine].Rect.Z; + if (Math.Abs(y1 - y2) < 0.5f) + { + line.MaxRect = new SRectF(Math.Min(x1, x2), y1 - _LineThickness / 2, Math.Abs(x2 - x1), _LineThickness, z); + } + else + { + line.MaxRect = new SRectF(x1 - _LineThickness / 2, Math.Min(y1, y2), _LineThickness, Math.Abs(y2 - y1), z); + } + + line.Visible = true; + } + + private void _AddConnector(CTournamentMatch match) + { + var box = _GetBoxRect(match.Round, match.Index); + var target = _GetBoxRect(match.Round + 1, match.Index / 2); + var leftSide = _GetColumn(match.Round, match.Index) < _PartyMode.NumRounds - 1; + var boxEdge = leftSide ? box.X + box.W : box.X; + var targetEdge = leftSide ? target.X : target.X + target.W; + var boxCenterY = box.Y + box.H / 2; + var targetCenterY = target.Y + target.H / 2; + + if (match.Round + 1 == _PartyMode.NumRounds - 1) + { + _AddLine(boxEdge, boxCenterY, targetEdge, boxCenterY); + return; + } + + var middleX = (boxEdge + targetEdge) / 2; + _AddLine(boxEdge, boxCenterY, middleX, boxCenterY); + + if (match.Index % 2 == 0) + { + var sibling = _GetBoxRect(match.Round, match.Index + 1); + _AddLine(middleX, boxCenterY, middleX, sibling.Y + sibling.H / 2); + _AddLine(middleX, targetCenterY, targetEdge, targetCenterY); + } + } + + private void _UpdateInfo() + { + var current = _PartyMode.CurrentMatch; + var finished = _PartyMode.IsFinished; + + _Texts[_TextChampion].Visible = finished && _ChampionShown; + _ParticleEffects[_ParticleEffectChampion].Visible = finished && _ChampionShown; + _Texts[_TextNextMatch].Visible = !finished && current != null; + _Texts[_TextRematch].Visible = !finished && _PartyMode.GameData.IsRematch; + + if (finished) + { + _Texts[_TextChampion].Text = _GetName(_PartyMode.FinalMatch.WinnerPlayer); + } + else if (current != null) + { + _Texts[_TextNextMatch].Text = CBase.Language.Translate("TR_SCREENMAIN_NEXT_MATCH", PartyModeId) + " " + _GetName(current.Player1) + " " + + CBase.Language.Translate("TR_SCREENMAIN_VERSUS", PartyModeId) + " " + _GetName(current.Player2); + } + } + } +} diff --git a/PartyModes/PartyModeTournament/CPartyScreenTournamentNames.cs b/PartyModes/PartyModeTournament/CPartyScreenTournamentNames.cs new file mode 100644 index 00000000..fa4de4b2 --- /dev/null +++ b/PartyModes/PartyModeTournament/CPartyScreenTournamentNames.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.Tournament +{ + public class CPartyScreenTournamentNames : CMenuPartyNameSelection + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private new CPartyModeTournament _PartyMode; + + public override void Init() + { + base.Init(); + _PartyMode = (CPartyModeTournament)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/PartyModeTournament/CPartyScreenTournamentSongs.cs b/PartyModes/PartyModeTournament/CPartyScreenTournamentSongs.cs new file mode 100644 index 00000000..842f305f --- /dev/null +++ b/PartyModes/PartyModeTournament/CPartyScreenTournamentSongs.cs @@ -0,0 +1,66 @@ +using VocaluxeLib.Menu; + +namespace VocaluxeLib.PartyModes.Tournament +{ + class CPartyScreenTournamentSongs : CMenuPartySongSelection + { + protected override int _ScreenVersion + { + get { return 1; } + } + + private new CPartyModeTournament _PartyMode; + + public override void Init() + { + base.Init(); + _PartyMode = (CPartyModeTournament)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/PartyModeTournament/GlobalSuppressions.cs b/PartyModes/PartyModeTournament/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/PartyModeTournament/PartyModeTournament.csproj b/PartyModes/PartyModeTournament/PartyModeTournament.csproj new file mode 100644 index 00000000..6404e834 --- /dev/null +++ b/PartyModes/PartyModeTournament/PartyModeTournament.csproj @@ -0,0 +1,118 @@ + + + + DebugWin + AnyCPU + 8.0.30703 + 2.0 + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20} + Library + Properties + VocaluxeLib.PartyModes.Tournament + Tournament + 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/PartyModeTournament/Settings.StyleCop b/PartyModes/PartyModeTournament/Settings.StyleCop new file mode 100644 index 00000000..f4a4ea2a --- /dev/null +++ b/PartyModes/PartyModeTournament/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 21d9d0f9..b1556cb0 100644 --- a/Vocaluxe.sln +++ b/Vocaluxe.sln @@ -10,6 +10,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocalu {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} + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20} = {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20} {54A48AF7-515C-4EDD-B395-2BFFA096050A} = {54A48AF7-515C-4EDD-B395-2BFFA096050A} {2E6A9B48-71C3-4D05-8F2B-C4A7D19E6E3F} = {2E6A9B48-71C3-4D05-8F2B-C4A7D19E6E3F} EndProjectSection @@ -22,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeTicTacToe", "Party EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeChallenge", "PartyModes\PartyModeChallenge\PartyModeChallenge.csproj", "{5A4053F1-5AD5-441F-B254-D97A088127B6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeTournament", "PartyModes\PartyModeTournament\PartyModeTournament.csproj", "{3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebserverInitalConfig", "WebserverInitalConfig\WebserverInitalConfig.csproj", "{55F89808-4E79-4FFE-BC13-48258913F5C9}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeRuleRoulette", "PartyModes\PartyModeRuleRoulette\PartyModeRuleRoulette.csproj", "{2E6A9B48-71C3-4D05-8F2B-C4A7D19E6E3F}" @@ -146,6 +149,26 @@ Global {5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU {5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU {5A4053F1-5AD5-441F-B254-D97A088127B6}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugLinux|x64.ActiveCfg = DebugLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugLinux|x64.Build.0 = DebugLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugLinux|x86.ActiveCfg = DebugLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugLinux|x86.Build.0 = DebugLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugWin|x64.ActiveCfg = DebugWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugWin|x64.Build.0 = DebugWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugWin|x86.ActiveCfg = DebugWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.DebugWin|x86.Build.0 = DebugWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.InstallerWin|x64.ActiveCfg = InstallerWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.InstallerWin|x64.Build.0 = InstallerWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.InstallerWin|x86.ActiveCfg = InstallerWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.InstallerWin|x86.Build.0 = InstallerWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseLinux|x64.Build.0 = ReleaseLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseLinux|x86.ActiveCfg = ReleaseLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseLinux|x86.Build.0 = ReleaseLinux|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseWin|x64.ActiveCfg = ReleaseWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU + {3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU {55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugLinux|x64.ActiveCfg = Debug|Any CPU {55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugLinux|x86.ActiveCfg = Debug|Any CPU {55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugWin|x64.ActiveCfg = Debug|Any CPU diff --git a/VocaluxeLib/Menu/CNameSelection.cs b/VocaluxeLib/Menu/CNameSelection.cs index 971745c3..4e66c6d2 100644 --- a/VocaluxeLib/Menu/CNameSelection.cs +++ b/VocaluxeLib/Menu/CNameSelection.cs @@ -479,30 +479,13 @@ namespace VocaluxeLib.Menu public Guid GetRandomUnusedProfile() { - var id = Guid.Empty; - - if (_VisibleProfiles.Count == 0) + var unusedProfiles = _VisibleProfiles.Where(profileId => !_UsedProfiles.Contains(profileId)).ToList(); + if (unusedProfiles.Count == 0) { - return id; + return Guid.Empty; } - if (_VisibleProfiles.Count == _UsedProfiles.Count) - { - return id; - } - - while (id == Guid.Empty) - { - var rand = CBase.Game.GetRandom(_VisibleProfiles.Count); - if (_UsedProfiles.Contains(_VisibleProfiles[rand])) - { - continue; - } - - id = _VisibleProfiles.ElementAt(rand); - } - - return id; + return unusedProfiles[CBase.Game.GetRandom(unusedProfiles.Count)]; } private void _PrepareTiles()