diff --git a/game/themes/Deluxe/Blue.ini b/game/themes/Deluxe/Blue.ini
index c545578d6..08eb10c27 100644
--- a/game/themes/Deluxe/Blue.ini
+++ b/game/themes/Deluxe/Blue.ini
@@ -137,12 +137,12 @@ ScoreEndCap = [score]endcap.png
ScoreLine = [score]line.png
PlayerNumberBox = [main]playerNumberBox.png
-PlayerIDBox01 = [sing.player1]lyric_active.png
-PlayerIDBox02 = [sing.player2]lyric_active.png
-PlayerIDBox03 = [sing.player3]lyric_active.png
-PlayerIDBox04 = [sing.player4]lyric_active.png
-PlayerIDBox05 = [sing.player5]lyric_active.png
-PlayerIDBox06 = [sing.player6]lyric_active.png
+PlayerIDBox01 = [sing.player]lyric_active.png
+PlayerIDBox02 = [sing.player]lyric_active.png
+PlayerIDBox03 = [sing.player]lyric_active.png
+PlayerIDBox04 = [sing.player]lyric_active.png
+PlayerIDBox05 = [sing.player]lyric_active.png
+PlayerIDBox06 = [sing.player]lyric_active.png
# these icons are part of the tango icon set
# licensed under Creative Commons Attribution Share-Alike license
@@ -251,18 +251,18 @@ BGFade = [special]bg_fade.png
# # # D U E T # # #
-LyricIcon_P1 = [sing.player1]lyric_active.png
-LyricIconD_P1 = [sing.player1]lyric_inactive.png
-LyricIcon_P2 = [sing.player2]lyric_active.png
-LyricIconD_P2 = [sing.player2]lyric_inactive.png
-LyricIcon_P3 = [sing.player3]lyric_active.png
-LyricIconD_P3 = [sing.player3]lyric_inactive.png
-LyricIcon_P4 = [sing.player4]lyric_active.png
-LyricIconD_P4 = [sing.player4]lyric_inactive.png
-LyricIcon_P5 = [sing.player5]lyric_active.png
-LyricIconD_P5 = [sing.player5]lyric_inactive.png
-LyricIcon_P6 = [sing.player6]lyric_active.png
-LyricIconD_P6 = [sing.player6]lyric_inactive.png
+LyricIcon_P1 = [sing.player]lyric_active.png
+LyricIconD_P1 = [sing.player]lyric_inactive.png
+LyricIcon_P2 = [sing.player]lyric_active.png
+LyricIconD_P2 = [sing.player]lyric_inactive.png
+LyricIcon_P3 = [sing.player]lyric_active.png
+LyricIconD_P3 = [sing.player]lyric_inactive.png
+LyricIcon_P4 = [sing.player]lyric_active.png
+LyricIconD_P4 = [sing.player]lyric_inactive.png
+LyricIcon_P5 = [sing.player]lyric_active.png
+LyricIconD_P5 = [sing.player]lyric_inactive.png
+LyricIcon_P6 = [sing.player]lyric_active.png
+LyricIconD_P6 = [sing.player]lyric_inactive.png
# # # DOWNLOAD SCORE # # #
@@ -316,9 +316,9 @@ SelectFrame = [name]select.png
AvatarFrame2 = [score]frame.png
# # # NO AVATARS # # #
-NoAvatar_P1 = [name]noavatarP1.png
-NoAvatar_P2 = [name]noavatarP2.png
-NoAvatar_P3 = [name]noavatarP3.png
-NoAvatar_P4 = [name]noavatarP4.png
-NoAvatar_P5 = [name]noavatarP5.png
-NoAvatar_P6 = [name]noavatarP6.png
+NoAvatar_P1 = [name]noavatar.png
+NoAvatar_P2 = [name]noavatar.png
+NoAvatar_P3 = [name]noavatar.png
+NoAvatar_P4 = [name]noavatar.png
+NoAvatar_P5 = [name]noavatar.png
+NoAvatar_P6 = [name]noavatar.png
diff --git a/game/themes/Deluxe/Fall.ini b/game/themes/Deluxe/Fall.ini
index 909f0f609..5fd2b779a 100644
--- a/game/themes/Deluxe/Fall.ini
+++ b/game/themes/Deluxe/Fall.ini
@@ -137,12 +137,12 @@ ScoreEndCap = [score]endcap.png
ScoreLine = [score]line.png
PlayerNumberBox = [main]playerNumberBox.png
-PlayerIDBox01 = [sing.player1]lyric_active.png
-PlayerIDBox02 = [sing.player2]lyric_active.png
-PlayerIDBox03 = [sing.player3]lyric_active.png
-PlayerIDBox04 = [sing.player4]lyric_active.png
-PlayerIDBox05 = [sing.player5]lyric_active.png
-PlayerIDBox06 = [sing.player6]lyric_active.png
+PlayerIDBox01 = [sing.player]lyric_active.png
+PlayerIDBox02 = [sing.player]lyric_active.png
+PlayerIDBox03 = [sing.player]lyric_active.png
+PlayerIDBox04 = [sing.player]lyric_active.png
+PlayerIDBox05 = [sing.player]lyric_active.png
+PlayerIDBox06 = [sing.player]lyric_active.png
# these icons are part of the tango icon set
# licensed under Creative Commons Attribution Share-Alike license
@@ -251,18 +251,18 @@ BGFade = [special]bg_fade.png
# # # D U E T # # #
-LyricIcon_P1 = [sing.player1]lyric_active.png
-LyricIconD_P1 = [sing.player1]lyric_inactive.png
-LyricIcon_P2 = [sing.player2]lyric_active.png
-LyricIconD_P2 = [sing.player2]lyric_inactive.png
-LyricIcon_P3 = [sing.player3]lyric_active.png
-LyricIconD_P3 = [sing.player3]lyric_inactive.png
-LyricIcon_P4 = [sing.player4]lyric_active.png
-LyricIconD_P4 = [sing.player4]lyric_inactive.png
-LyricIcon_P5 = [sing.player5]lyric_active.png
-LyricIconD_P5 = [sing.player5]lyric_inactive.png
-LyricIcon_P6 = [sing.player6]lyric_active.png
-LyricIconD_P6 = [sing.player6]lyric_inactive.png
+LyricIcon_P1 = [sing.player]lyric_active.png
+LyricIconD_P1 = [sing.player]lyric_inactive.png
+LyricIcon_P2 = [sing.player]lyric_active.png
+LyricIconD_P2 = [sing.player]lyric_inactive.png
+LyricIcon_P3 = [sing.player]lyric_active.png
+LyricIconD_P3 = [sing.player]lyric_inactive.png
+LyricIcon_P4 = [sing.player]lyric_active.png
+LyricIconD_P4 = [sing.player]lyric_inactive.png
+LyricIcon_P5 = [sing.player]lyric_active.png
+LyricIconD_P5 = [sing.player]lyric_inactive.png
+LyricIcon_P6 = [sing.player]lyric_active.png
+LyricIconD_P6 = [sing.player]lyric_inactive.png
# # # DOWNLOAD SCORE # # #
@@ -316,9 +316,9 @@ SelectFrame = [name]select.png
AvatarFrame2 = [score]frame.png
# # # NO AVATARS # # #
-NoAvatar_P1 = [name]noavatarP1.png
-NoAvatar_P2 = [name]noavatarP2.png
-NoAvatar_P3 = [name]noavatarP3.png
-NoAvatar_P4 = [name]noavatarP4.png
-NoAvatar_P5 = [name]noavatarP5.png
-NoAvatar_P6 = [name]noavatarP6.png
+NoAvatar_P1 = [name]noavatar.png
+NoAvatar_P2 = [name]noavatar.png
+NoAvatar_P3 = [name]noavatar.png
+NoAvatar_P4 = [name]noavatar.png
+NoAvatar_P5 = [name]noavatar.png
+NoAvatar_P6 = [name]noavatar.png
diff --git a/game/themes/Deluxe/Ocean.ini b/game/themes/Deluxe/Ocean.ini
index 1c35f72cf..ecae95978 100644
--- a/game/themes/Deluxe/Ocean.ini
+++ b/game/themes/Deluxe/Ocean.ini
@@ -137,12 +137,12 @@ ScoreEndCap = [score]endcap.png
ScoreLine = [score]line.png
PlayerNumberBox = [main]playerNumberBox.png
-PlayerIDBox01 = [sing.player1]lyric_active.png
-PlayerIDBox02 = [sing.player2]lyric_active.png
-PlayerIDBox03 = [sing.player3]lyric_active.png
-PlayerIDBox04 = [sing.player4]lyric_active.png
-PlayerIDBox05 = [sing.player5]lyric_active.png
-PlayerIDBox06 = [sing.player6]lyric_active.png
+PlayerIDBox01 = [sing.player]lyric_active.png
+PlayerIDBox02 = [sing.player]lyric_active.png
+PlayerIDBox03 = [sing.player]lyric_active.png
+PlayerIDBox04 = [sing.player]lyric_active.png
+PlayerIDBox05 = [sing.player]lyric_active.png
+PlayerIDBox06 = [sing.player]lyric_active.png
# these icons are part of the tango icon set
# licensed under Creative Commons Attribution Share-Alike license
@@ -251,18 +251,18 @@ BGFade = [special]bg_fade.png
# # # D U E T # # #
-LyricIcon_P1 = [sing.player1]lyric_active.png
-LyricIconD_P1 = [sing.player1]lyric_inactive.png
-LyricIcon_P2 = [sing.player2]lyric_active.png
-LyricIconD_P2 = [sing.player2]lyric_inactive.png
-LyricIcon_P3 = [sing.player3]lyric_active.png
-LyricIconD_P3 = [sing.player3]lyric_inactive.png
-LyricIcon_P4 = [sing.player4]lyric_active.png
-LyricIconD_P4 = [sing.player4]lyric_inactive.png
-LyricIcon_P5 = [sing.player5]lyric_active.png
-LyricIconD_P5 = [sing.player5]lyric_inactive.png
-LyricIcon_P6 = [sing.player6]lyric_active.png
-LyricIconD_P6 = [sing.player6]lyric_inactive.png
+LyricIcon_P1 = [sing.player]lyric_active.png
+LyricIconD_P1 = [sing.player]lyric_inactive.png
+LyricIcon_P2 = [sing.player]lyric_active.png
+LyricIconD_P2 = [sing.player]lyric_inactive.png
+LyricIcon_P3 = [sing.player]lyric_active.png
+LyricIconD_P3 = [sing.player]lyric_inactive.png
+LyricIcon_P4 = [sing.player]lyric_active.png
+LyricIconD_P4 = [sing.player]lyric_inactive.png
+LyricIcon_P5 = [sing.player]lyric_active.png
+LyricIconD_P5 = [sing.player]lyric_inactive.png
+LyricIcon_P6 = [sing.player]lyric_active.png
+LyricIconD_P6 = [sing.player]lyric_inactive.png
# # # DOWNLOAD SCORE # # #
@@ -316,9 +316,9 @@ SelectFrame = [name]select.png
AvatarFrame2 = [score]frame.png
# # # NO AVATARS # # #
-NoAvatar_P1 = [name]noavatarP1.png
-NoAvatar_P2 = [name]noavatarP2.png
-NoAvatar_P3 = [name]noavatarP3.png
-NoAvatar_P4 = [name]noavatarP4.png
-NoAvatar_P5 = [name]noavatarP5.png
-NoAvatar_P6 = [name]noavatarP6.png
+NoAvatar_P1 = [name]noavatar.png
+NoAvatar_P2 = [name]noavatar.png
+NoAvatar_P3 = [name]noavatar.png
+NoAvatar_P4 = [name]noavatar.png
+NoAvatar_P5 = [name]noavatar.png
+NoAvatar_P6 = [name]noavatar.png
diff --git a/game/themes/Deluxe/Ribbon.ini b/game/themes/Deluxe/Ribbon.ini
index 25fb22dc2..f86fe0b8c 100644
--- a/game/themes/Deluxe/Ribbon.ini
+++ b/game/themes/Deluxe/Ribbon.ini
@@ -137,12 +137,12 @@ ScoreEndCap = [score]endcap.png
ScoreLine = [score]line.png
PlayerNumberBox = [main]playerNumberBox.png
-PlayerIDBox01 = [sing.player1]lyric_active.png
-PlayerIDBox02 = [sing.player2]lyric_active.png
-PlayerIDBox03 = [sing.player3]lyric_active.png
-PlayerIDBox04 = [sing.player4]lyric_active.png
-PlayerIDBox05 = [sing.player5]lyric_active.png
-PlayerIDBox06 = [sing.player6]lyric_active.png
+PlayerIDBox01 = [sing.player]lyric_active.png
+PlayerIDBox02 = [sing.player]lyric_active.png
+PlayerIDBox03 = [sing.player]lyric_active.png
+PlayerIDBox04 = [sing.player]lyric_active.png
+PlayerIDBox05 = [sing.player]lyric_active.png
+PlayerIDBox06 = [sing.player]lyric_active.png
# these icons are part of the tango icon set
# licensed under Creative Commons Attribution Share-Alike license
@@ -251,18 +251,18 @@ BGFade = [special]bg_fade.png
# # # D U E T # # #
-LyricIcon_P1 = [sing.player1]lyric_active.png
-LyricIconD_P1 = [sing.player1]lyric_inactive.png
-LyricIcon_P2 = [sing.player2]lyric_active.png
-LyricIconD_P2 = [sing.player2]lyric_inactive.png
-LyricIcon_P3 = [sing.player3]lyric_active.png
-LyricIconD_P3 = [sing.player3]lyric_inactive.png
-LyricIcon_P4 = [sing.player4]lyric_active.png
-LyricIconD_P4 = [sing.player4]lyric_inactive.png
-LyricIcon_P5 = [sing.player5]lyric_active.png
-LyricIconD_P5 = [sing.player5]lyric_inactive.png
-LyricIcon_P6 = [sing.player6]lyric_active.png
-LyricIconD_P6 = [sing.player6]lyric_inactive.png
+LyricIcon_P1 = [sing.player]lyric_active.png
+LyricIconD_P1 = [sing.player]lyric_inactive.png
+LyricIcon_P2 = [sing.player]lyric_active.png
+LyricIconD_P2 = [sing.player]lyric_inactive.png
+LyricIcon_P3 = [sing.player]lyric_active.png
+LyricIconD_P3 = [sing.player]lyric_inactive.png
+LyricIcon_P4 = [sing.player]lyric_active.png
+LyricIconD_P4 = [sing.player]lyric_inactive.png
+LyricIcon_P5 = [sing.player]lyric_active.png
+LyricIconD_P5 = [sing.player]lyric_inactive.png
+LyricIcon_P6 = [sing.player]lyric_active.png
+LyricIconD_P6 = [sing.player]lyric_inactive.png
# # # DOWNLOAD SCORE # # #
@@ -316,9 +316,9 @@ SelectFrame = [name]select.png
AvatarFrame2 = [score]frame.png
# # # NO AVATARS # # #
-NoAvatar_P1 = [name]noavatarP1.png
-NoAvatar_P2 = [name]noavatarP2.png
-NoAvatar_P3 = [name]noavatarP3.png
-NoAvatar_P4 = [name]noavatarP4.png
-NoAvatar_P5 = [name]noavatarP5.png
-NoAvatar_P6 = [name]noavatarP6.png
+NoAvatar_P1 = [name]noavatar.png
+NoAvatar_P2 = [name]noavatar.png
+NoAvatar_P3 = [name]noavatar.png
+NoAvatar_P4 = [name]noavatar.png
+NoAvatar_P5 = [name]noavatar.png
+NoAvatar_P6 = [name]noavatar.png
diff --git a/game/themes/Deluxe/Summer.ini b/game/themes/Deluxe/Summer.ini
index dd3985851..9a5c7e1ea 100644
--- a/game/themes/Deluxe/Summer.ini
+++ b/game/themes/Deluxe/Summer.ini
@@ -137,12 +137,12 @@ ScoreEndCap = [score]endcap.png
ScoreLine = [score]line.png
PlayerNumberBox = [main]playerNumberBox.png
-PlayerIDBox01 = [sing.player1]lyric_active.png
-PlayerIDBox02 = [sing.player2]lyric_active.png
-PlayerIDBox03 = [sing.player3]lyric_active.png
-PlayerIDBox04 = [sing.player4]lyric_active.png
-PlayerIDBox05 = [sing.player5]lyric_active.png
-PlayerIDBox06 = [sing.player6]lyric_active.png
+PlayerIDBox01 = [sing.player]lyric_active.png
+PlayerIDBox02 = [sing.player]lyric_active.png
+PlayerIDBox03 = [sing.player]lyric_active.png
+PlayerIDBox04 = [sing.player]lyric_active.png
+PlayerIDBox05 = [sing.player]lyric_active.png
+PlayerIDBox06 = [sing.player]lyric_active.png
# these icons are part of the tango icon set
# licensed under Creative Commons Attribution Share-Alike license
@@ -251,18 +251,18 @@ BGFade = [special]bg_fade.png
# # # D U E T # # #
-LyricIcon_P1 = [sing.player1]lyric_active.png
-LyricIconD_P1 = [sing.player1]lyric_inactive.png
-LyricIcon_P2 = [sing.player2]lyric_active.png
-LyricIconD_P2 = [sing.player2]lyric_inactive.png
-LyricIcon_P3 = [sing.player3]lyric_active.png
-LyricIconD_P3 = [sing.player3]lyric_inactive.png
-LyricIcon_P4 = [sing.player4]lyric_active.png
-LyricIconD_P4 = [sing.player4]lyric_inactive.png
-LyricIcon_P5 = [sing.player5]lyric_active.png
-LyricIconD_P5 = [sing.player5]lyric_inactive.png
-LyricIcon_P6 = [sing.player6]lyric_active.png
-LyricIconD_P6 = [sing.player6]lyric_inactive.png
+LyricIcon_P1 = [sing.player]lyric_active.png
+LyricIconD_P1 = [sing.player]lyric_inactive.png
+LyricIcon_P2 = [sing.player]lyric_active.png
+LyricIconD_P2 = [sing.player]lyric_inactive.png
+LyricIcon_P3 = [sing.player]lyric_active.png
+LyricIconD_P3 = [sing.player]lyric_inactive.png
+LyricIcon_P4 = [sing.player]lyric_active.png
+LyricIconD_P4 = [sing.player]lyric_inactive.png
+LyricIcon_P5 = [sing.player]lyric_active.png
+LyricIconD_P5 = [sing.player]lyric_inactive.png
+LyricIcon_P6 = [sing.player]lyric_active.png
+LyricIconD_P6 = [sing.player]lyric_inactive.png
# # # DOWNLOAD SCORE # # #
@@ -316,9 +316,9 @@ SelectFrame = [name]select.png
AvatarFrame2 = [score]frame.png
# # # NO AVATARS # # #
-NoAvatar_P1 = [name]noavatarP1.png
-NoAvatar_P2 = [name]noavatarP2.png
-NoAvatar_P3 = [name]noavatarP3.png
-NoAvatar_P4 = [name]noavatarP4.png
-NoAvatar_P5 = [name]noavatarP5.png
-NoAvatar_P6 = [name]noavatarP6.png
+NoAvatar_P1 = [name]noavatar.png
+NoAvatar_P2 = [name]noavatar.png
+NoAvatar_P3 = [name]noavatar.png
+NoAvatar_P4 = [name]noavatar.png
+NoAvatar_P5 = [name]noavatar.png
+NoAvatar_P6 = [name]noavatar.png
diff --git a/game/themes/Deluxe/Winter.ini b/game/themes/Deluxe/Winter.ini
index cda26287a..d3b5d165c 100644
--- a/game/themes/Deluxe/Winter.ini
+++ b/game/themes/Deluxe/Winter.ini
@@ -137,12 +137,12 @@ ScoreEndCap = [score]endcap.png
ScoreLine = [score]line.png
PlayerNumberBox = [main]playerNumberBox.png
-PlayerIDBox01 = [sing.player1]lyric_active.png
-PlayerIDBox02 = [sing.player2]lyric_active.png
-PlayerIDBox03 = [sing.player3]lyric_active.png
-PlayerIDBox04 = [sing.player4]lyric_active.png
-PlayerIDBox05 = [sing.player5]lyric_active.png
-PlayerIDBox06 = [sing.player6]lyric_active.png
+PlayerIDBox01 = [sing.player]lyric_active.png
+PlayerIDBox02 = [sing.player]lyric_active.png
+PlayerIDBox03 = [sing.player]lyric_active.png
+PlayerIDBox04 = [sing.player]lyric_active.png
+PlayerIDBox05 = [sing.player]lyric_active.png
+PlayerIDBox06 = [sing.player]lyric_active.png
# these icons are part of the tango icon set
# licensed under Creative Commons Attribution Share-Alike license
@@ -251,18 +251,18 @@ BGFade = [special]bg_fade.png
# # # D U E T # # #
-LyricIcon_P1 = [sing.player1]lyric_active.png
-LyricIconD_P1 = [sing.player1]lyric_inactive.png
-LyricIcon_P2 = [sing.player2]lyric_active.png
-LyricIconD_P2 = [sing.player2]lyric_inactive.png
-LyricIcon_P3 = [sing.player3]lyric_active.png
-LyricIconD_P3 = [sing.player3]lyric_inactive.png
-LyricIcon_P4 = [sing.player4]lyric_active.png
-LyricIconD_P4 = [sing.player4]lyric_inactive.png
-LyricIcon_P5 = [sing.player5]lyric_active.png
-LyricIconD_P5 = [sing.player5]lyric_inactive.png
-LyricIcon_P6 = [sing.player6]lyric_active.png
-LyricIconD_P6 = [sing.player6]lyric_inactive.png
+LyricIcon_P1 = [sing.player]lyric_active.png
+LyricIconD_P1 = [sing.player]lyric_inactive.png
+LyricIcon_P2 = [sing.player]lyric_active.png
+LyricIconD_P2 = [sing.player]lyric_inactive.png
+LyricIcon_P3 = [sing.player]lyric_active.png
+LyricIconD_P3 = [sing.player]lyric_inactive.png
+LyricIcon_P4 = [sing.player]lyric_active.png
+LyricIconD_P4 = [sing.player]lyric_inactive.png
+LyricIcon_P5 = [sing.player]lyric_active.png
+LyricIconD_P5 = [sing.player]lyric_inactive.png
+LyricIcon_P6 = [sing.player]lyric_active.png
+LyricIconD_P6 = [sing.player]lyric_inactive.png
# # # DOWNLOAD SCORE # # #
@@ -316,9 +316,9 @@ SelectFrame = [name]select.png
AvatarFrame2 = [score]frame.png
# # # NO AVATARS # # #
-NoAvatar_P1 = [name]noavatarP1.png
-NoAvatar_P2 = [name]noavatarP2.png
-NoAvatar_P3 = [name]noavatarP3.png
-NoAvatar_P4 = [name]noavatarP4.png
-NoAvatar_P5 = [name]noavatarP5.png
-NoAvatar_P6 = [name]noavatarP6.png
+NoAvatar_P1 = [name]noavatar.png
+NoAvatar_P2 = [name]noavatar.png
+NoAvatar_P3 = [name]noavatar.png
+NoAvatar_P4 = [name]noavatar.png
+NoAvatar_P5 = [name]noavatar.png
+NoAvatar_P6 = [name]noavatar.png
diff --git a/game/themes/Deluxe/[name]noavatar.png b/game/themes/Deluxe/[name]noavatar.png
new file mode 100644
index 000000000..00bf0f074
Binary files /dev/null and b/game/themes/Deluxe/[name]noavatar.png differ
diff --git a/game/themes/Deluxe/[name]noavatarP1.png b/game/themes/Deluxe/[name]noavatarP1.png
deleted file mode 100644
index 538991420..000000000
Binary files a/game/themes/Deluxe/[name]noavatarP1.png and /dev/null differ
diff --git a/game/themes/Deluxe/[name]noavatarP2.png b/game/themes/Deluxe/[name]noavatarP2.png
deleted file mode 100644
index 3dd7ac345..000000000
Binary files a/game/themes/Deluxe/[name]noavatarP2.png and /dev/null differ
diff --git a/game/themes/Deluxe/[name]noavatarP3.png b/game/themes/Deluxe/[name]noavatarP3.png
deleted file mode 100644
index def60a40e..000000000
Binary files a/game/themes/Deluxe/[name]noavatarP3.png and /dev/null differ
diff --git a/game/themes/Deluxe/[name]noavatarP4.png b/game/themes/Deluxe/[name]noavatarP4.png
deleted file mode 100644
index e0b164ea6..000000000
Binary files a/game/themes/Deluxe/[name]noavatarP4.png and /dev/null differ
diff --git a/game/themes/Deluxe/[name]noavatarP5.png b/game/themes/Deluxe/[name]noavatarP5.png
deleted file mode 100644
index 24a06bb6a..000000000
Binary files a/game/themes/Deluxe/[name]noavatarP5.png and /dev/null differ
diff --git a/game/themes/Deluxe/[name]noavatarP6.png b/game/themes/Deluxe/[name]noavatarP6.png
deleted file mode 100644
index c202e6d8e..000000000
Binary files a/game/themes/Deluxe/[name]noavatarP6.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player1]lyric_active.png b/game/themes/Deluxe/[sing.player1]lyric_active.png
deleted file mode 100644
index 089c8c5e7..000000000
Binary files a/game/themes/Deluxe/[sing.player1]lyric_active.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player1]lyric_inactive.png b/game/themes/Deluxe/[sing.player1]lyric_inactive.png
deleted file mode 100644
index a349007d9..000000000
Binary files a/game/themes/Deluxe/[sing.player1]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player2]lyric_active.png b/game/themes/Deluxe/[sing.player2]lyric_active.png
deleted file mode 100644
index 509767fa2..000000000
Binary files a/game/themes/Deluxe/[sing.player2]lyric_active.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player2]lyric_inactive.png b/game/themes/Deluxe/[sing.player2]lyric_inactive.png
deleted file mode 100644
index ac40ec61d..000000000
Binary files a/game/themes/Deluxe/[sing.player2]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player3]lyric_active.png b/game/themes/Deluxe/[sing.player3]lyric_active.png
deleted file mode 100644
index 7b130ac5b..000000000
Binary files a/game/themes/Deluxe/[sing.player3]lyric_active.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player3]lyric_inactive.png b/game/themes/Deluxe/[sing.player3]lyric_inactive.png
deleted file mode 100644
index c5a00600d..000000000
Binary files a/game/themes/Deluxe/[sing.player3]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player4]lyric_active.png b/game/themes/Deluxe/[sing.player4]lyric_active.png
deleted file mode 100644
index 993041fd5..000000000
Binary files a/game/themes/Deluxe/[sing.player4]lyric_active.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player4]lyric_inactive.png b/game/themes/Deluxe/[sing.player4]lyric_inactive.png
deleted file mode 100644
index f09669b22..000000000
Binary files a/game/themes/Deluxe/[sing.player4]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player5]lyric_active.png b/game/themes/Deluxe/[sing.player5]lyric_active.png
deleted file mode 100644
index 631dc9c33..000000000
Binary files a/game/themes/Deluxe/[sing.player5]lyric_active.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player5]lyric_inactive.png b/game/themes/Deluxe/[sing.player5]lyric_inactive.png
deleted file mode 100644
index 716071e82..000000000
Binary files a/game/themes/Deluxe/[sing.player5]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player6]lyric_active.png b/game/themes/Deluxe/[sing.player6]lyric_active.png
deleted file mode 100644
index 65133d034..000000000
Binary files a/game/themes/Deluxe/[sing.player6]lyric_active.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player6]lyric_inactive.png b/game/themes/Deluxe/[sing.player6]lyric_inactive.png
deleted file mode 100644
index 0c5f34d31..000000000
Binary files a/game/themes/Deluxe/[sing.player6]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Deluxe/[sing.player]lyric_active.png b/game/themes/Deluxe/[sing.player]lyric_active.png
new file mode 100644
index 000000000..6297a7010
Binary files /dev/null and b/game/themes/Deluxe/[sing.player]lyric_active.png differ
diff --git a/game/themes/Deluxe/[sing.player]lyric_inactive.png b/game/themes/Deluxe/[sing.player]lyric_inactive.png
new file mode 100644
index 000000000..3a1f8a4a9
Binary files /dev/null and b/game/themes/Deluxe/[sing.player]lyric_inactive.png differ
diff --git a/game/themes/Modern.ini b/game/themes/Modern.ini
index 5bcbe16b4..9fe9da192 100644
--- a/game/themes/Modern.ini
+++ b/game/themes/Modern.ini
@@ -468,6 +468,114 @@ H = 8
# O N E P L A Y E R M O D E # # # # # # # # # # # # # # # # # # # #
#PlayerOne
+[SingPlayerTemplateStatic]
+Inherits = SingDefaultAvatarFrame
+Color = P1Dark
+
+[SingPlayerTemplateText]
+Inherits = SingDefaultPlayerText
+
+[SingPlayerTemplateStatic2]
+Inherits = SingDefaultScoreBG
+Color = P1Dark
+
+[SingPlayerTemplateTextScore]
+Inherits = SingDefaultPlayerTextScore
+
+[SingPlayerTemplateSingBar]
+Inherits = SingDefaultSingBar
+
+[SingPlayerTemplateAvatar]
+Inherits = SingDefaultAvatar
+
+[SingPlayerGrid]
+# Left edge of the sing lane area.
+LaneAreaX = 20
+# Top edge of the sing lane area.
+LaneAreaY = 110
+# Top edge of the sing lane area when top lyrics space is not reserved.
+LaneAreaYNoLyrics = 50
+# Width of the sing lane area shared by all player columns.
+LaneAreaW = 760
+# Lane area height when top lyrics space is reserved (duet/reserved layout).
+LaneAreaHReserved = 365
+# Lane area height when top lyrics space is not reserved.
+LaneAreaHNoLyrics = 425
+# Horizontal gap between player columns.
+LaneColumnGap = 20
+# Additional vertical gap between player rows.
+LaneRowGap = 20
+# Extra inset applied to the note grid to the left of the lane column.
+LaneGridLeftInset = 0
+# Base note-line spacing reference for vertical scaling.
+LaneBaseLineSpacing = 15
+# Number of horizontal guide lines drawn per slot.
+LaneGuideLineCount = 9
+# Guide-line index used as the note row anchor (0-based from the top).
+LaneRowAnchorGuideIndex = 7
+# Reference lane width for widget/note scaling calculations.
+WidgetScaleReferenceW = 300
+# Per-player widget scale reduction factor.
+WidgetScalePerPlayer = 0.02
+# Minimum widget scale factor.
+WidgetScaleMin = 0.82
+
+[SingPlayerWidgetPlacement]
+# Minimum avatar frame width after scaling.
+MinFrameW = 26
+# Minimum avatar frame height after scaling.
+MinFrameH = 26
+# Minimum score box width after scaling.
+MinScoreW = 56
+# Minimum score box height after scaling.
+MinScoreH = 18
+# Horizontal offset from lane left edge to header group start.
+HeaderLeftOffset = 0
+# Vertical offset from row anchor to header group.
+HeaderTopOffsetBase = 148
+# Extra header vertical offset per additional row.
+HeaderTopOffsetPerExtraRow = 0
+# Minimum inset of avatar texture inside its frame (X).
+AvatarInsetMinX = 1
+# Minimum inset of avatar texture inside its frame (Y).
+AvatarInsetMinY = 1
+# Base horizontal gap between avatar frame and player name.
+NameGapX = 10
+# Minimum horizontal gap between avatar frame and player name.
+NameGapMinX = 8
+# Base horizontal text padding for player name.
+NamePaddingX = 6
+# Minimum horizontal text padding for player name.
+NamePaddingMinX = 4
+# Base vertical text padding for player name.
+NamePaddingY = 6
+# Minimum vertical text padding for player name.
+NamePaddingMinY = 3
+# Minimum width allocated to player name text.
+NameMinW = 24
+# Minimum height allocated to player name text.
+NameMinH = 14
+# Minimum font size for player name text.
+NameMinSize = 10
+# Max fraction of lane width reserved for score box.
+ScoreWidthFractionOfLane = 0.36
+# Base vertical gap between player name and oscilloscope.
+OscilloscopeGapY = 4
+# Minimum vertical gap between player name and oscilloscope.
+OscilloscopeGapMinY = 2
+# Minimum oscilloscope width.
+OscilloscopeMinW = 40
+# Minimum oscilloscope height.
+OscilloscopeMinH = 8
+# Solo mode popup Y offset.
+PopupYOffsetSolo = 65
+# Duet mode popup Y offset.
+PopupYOffsetDuet = 40
+# Solo mode popup font size.
+PopupFontSizeSolo = 18
+# Duet mode popup font size.
+PopupFontSizeDuet = 14
+
[SingP1Static]
Inherits = SingDefaultAvatarFrame
Color = P1Dark
@@ -685,6 +793,242 @@ Text = SONG_SCORE_WHEREAMI
#end of main stuff
# # # # # # # # # # # # # # # # # # One Player Score # # # # # # # # # # # #
+[ScorePlayerSlotArea]
+AreaX = 20
+AreaY = 110
+AreaW = 760
+AreaH = 420
+ExtraColsBias = 1
+
+# Score player template used for all dynamic score screen layouts.
+[ScorePlayerTemplateTextName]
+X = 197
+Y = 280
+Font = 0
+Style = 1
+Size = 40
+Text = P1
+Color = White
+Align = 0
+
+# Rating
+[ScorePlayerTemplateStaticRatingPicture]
+X = 385
+Y = 165
+H = 75
+W = 75
+
+[ScorePlayerTemplateTextScore]
+X = 422
+Y = 235
+W = 100
+Color = White
+Font = 0
+Style = 0
+Size = 27
+Text = Tone Deaf
+Align = 1
+
+# Note Score
+[ScorePlayerTemplateStaticBoxDark]
+Tex = ScoreBar_box_dark
+X = 200
+Y = 327
+W = 22
+H = 20
+Color = P1Dark
+Type = Colorized
+
+[ScorePlayerTemplateTextNotes]
+X = 227
+Y = 322
+Color = White
+Font = 0
+Style = 0
+Size = 30
+Text = SING_NOTES
+Align = 0
+
+[ScorePlayerTemplateTextNotesScore]
+X = 487
+Y = 322
+Color = White
+Font = 0
+Style = 0
+Size = 30
+Align = 2
+Text = 0
+
+# A simple line
+[ScorePlayerTemplateStatic1]
+Tex = ScoreLine
+X = 200
+Y = 351
+W = 287
+H = 1
+Color = White
+Type = Colorized
+
+# Line Bonus
+[ScorePlayerTemplateStaticBoxLight]
+Inherits = ScorePlayerTemplateStaticBoxDark
+Tex = ScoreBar_box_light
+Y = 358
+Color = P1Light
+
+[ScorePlayerTemplateTextLineBonus]
+Inherits = ScorePlayerTemplateTextNotes
+Y = 352
+Text = SING_PHRASE_BONUS
+
+[ScorePlayerTemplateTextLineBonusScore]
+Inherits = ScorePlayerTemplateTextNotesScore
+Y = 352
+
+# A simple line
+[ScorePlayerTemplateStatic2]
+Inherits = ScorePlayerTemplateStatic1
+Y = 382
+
+# Golden Notes
+[ScorePlayerTemplateStaticBoxLightest]
+Inherits = ScorePlayerTemplateStaticBoxDark
+Tex = ScoreBar_box_lightest
+Y = 390
+Color = P1Lightest
+
+[ScorePlayerTemplateTextGoldenNotes]
+Inherits = ScorePlayerTemplateTextNotes
+Y = 383
+Text = SING_GOLDEN_NOTES
+
+[ScorePlayerTemplateTextGoldenNotesScore]
+Inherits = ScorePlayerTemplateTextNotesScore
+Y = 383
+
+[ScorePlayerTemplateTextTotal]
+X = 237
+Y = 454
+Color = White
+Font = 0
+Style = 0
+Size = 30
+Text = SING_TOTAL
+Align = 0
+Reflection = 1
+ReflectionSpacing = 26
+
+[ScorePlayerTemplateTextTotalScore]
+X = 487
+Y = 444
+Color = White
+Font = 0
+Style = 0
+Size = 42
+Align = 2
+Text = 0
+Reflection = 1
+ReflectionSpacing = 24
+
+#ScoreBar
+[ScorePlayerTemplateStaticBackLevel]
+Tex = ScoreLevel
+X = 503
+Y = 168
+W = 95
+H = 310
+Color = P1Lightest
+Type = Colorized
+
+[ScorePlayerTemplateStaticBackLevelRound]
+Tex = ScoreLevelRound
+X = 503
+Y = 138
+W = 95
+H = 8
+Color = P1Lightest
+Type = Colorized
+
+[ScorePlayerTemplateStaticLevel]
+Tex = ScoreLevel
+X = 503
+Y = 400
+W = 95
+H = 10
+Color = P1Dark
+Type = Colorized
+
+[ScorePlayerTemplateStaticLevelRound]
+Tex = ScoreLevelRound
+X = 503
+Y = 392
+W = 95
+H = 8
+Color = P1Dark
+Type = Colorized
+
+[ScorePlayerTemplateStatic3]
+Tex = ScoreEndCap
+X = 499
+Y = 478
+W = 110
+H = 30
+z = 0.9
+Color = P1Dark
+Type = Colorized
+Reflection = 1
+ReflectionSpacing = 0
+
+[ScorePlayerTemplateStatic4]
+Tex = ScoreGlassBox
+X = 499
+Y = 148
+W = 113
+H = 331
+z = 0.89
+Color = White
+Type = Transparent
+
+[ScorePlayerTemplateStatic5]
+Tex = P
+X = 200
+Y = 455
+W = 26
+H = 23
+Color = P1Dark
+Type = Colorized
+Reflection = 1
+ReflectionSpacing = 31
+
+[ScorePlayerTemplateText1]
+Text = P1
+X = 204
+Y = 458
+Size = 18
+Font = 0
+Style = 1
+Color = White
+Type = Colorized
+Reflection = 1
+ReflectionSpacing = 40
+
+[ScorePlayerTemplateAvatar]
+X = 203
+Y = 168
+W = 104
+H = 104
+Z = 1
+
+[ScorePlayerTemplateStatic6]
+X = 195
+Y = 160
+W = 120
+H = 120
+Z = 0.9
+Tex = AvatarFrame2
+Color = P1Dark
+Type = Transparent
+
[ScoreTextName1]
X = 197
Y = 280
@@ -2743,6 +3087,45 @@ H = 35
SkipX = 10
SBGW = 360
+[NamePlayerSelectTemplateFrame]
+X = 100
+Y = 185
+W = 70
+H = 60
+Tex = AvatarFrame2
+Color = P1Dark
+Type = Transparent
+Z = 1
+
+[NamePlayerSelectTemplateText]
+X = 135
+Y = 248
+Font = 0
+Style = 1
+Size = 16
+Align = 1
+Color = White
+Z = 1
+
+[NamePlayerSelectTemplateAvatar]
+X = 105
+Y = 190
+W = 60
+H = 51
+Z = 1
+
+[NamePlayerSelectGrid]
+GridX = 30
+GridY = 185
+GridW = 760
+GridH = 155
+MinimumVisibleSlots = 2
+MaximumColumns = 12
+RowVerticalSpreadDivisor = 1.5
+MaxScaleUpTo2Players = 1.35
+MaxScaleUpTo4Players = 1.15
+MaxScaleDefault = 1.0
+
[NamePlayerSelectStatic1]
X = 100
Y = 185
@@ -2836,11 +3219,11 @@ Inherits = NamePlayerSelectStatic1Avatar
X = 635
[NamePlayerSelectCurrent]
-X = -10
+X = 90
Y = 175
W = 90
-H = 100
-Z = 0.95
+H = 90
+Z = 0
Tex = SelectFrame
Color = ColorLight
DColor = ColorDark
@@ -6511,6 +6894,12 @@ Size = 20
Align = 1
Color = White
+[SongRouletteDuetSingerArea]
+X = 530
+Y = 340
+
+#############################
+
[SongRouletteStatic2PlayersDuetSingerP2]
Inherits = SongRouletteStatic2PlayersDuetSingerP1
Y = 445
@@ -6586,6 +6975,10 @@ Inherits = SongRouletteText2PlayersDuetSingerP1
X = 630
Y = 245
+[SongListDuetSingerArea]
+X = 525
+Y = 110
+
[SongListStatic2PlayersDuetSingerP2]
Inherits = SongListStatic2PlayersDuetSingerP1
Y = 270
@@ -6662,6 +7055,10 @@ Inherits = SongRouletteText2PlayersDuetSingerP1
X = 387
Y = 440
+[SongChessboardDuetSingerArea]
+X = 450
+Y = 420
+
[SongChessboardStatic2PlayersDuetSingerP2]
Inherits = SongChessboardStatic2PlayersDuetSingerP1
Y = 465
@@ -9721,6 +10118,14 @@ Y = 185
# O N E P L A Y E R M O D E # # # # # # # # # # # # # # # # # # # #
#PlayerOne
+[SingPlayerTemplateOscilloscope]
+X = 80
+Y = 275
+H = 30
+W = 100
+
+## 4/6 Players One Screen ##
+
[SingP1Oscilloscope]
X = 80
Y = 275
diff --git a/game/themes/Modern/Blue.ini b/game/themes/Modern/Blue.ini
index 7933ffd46..04ae51fd4 100644
--- a/game/themes/Modern/Blue.ini
+++ b/game/themes/Modern/Blue.ini
@@ -137,12 +137,12 @@ ScoreEndCap = [score]endcap.png
ScoreLine = [score]line.png
PlayerNumberBox = [main]playerNumberBox.png
-PlayerIDBox01 = [sing.player1]lyric_active.png
-PlayerIDBox02 = [sing.player2]lyric_active.png
-PlayerIDBox03 = [sing.player3]lyric_active.png
-PlayerIDBox04 = [sing.player4]lyric_active.png
-PlayerIDBox05 = [sing.player5]lyric_active.png
-PlayerIDBox06 = [sing.player6]lyric_active.png
+PlayerIDBox01 = [sing.player]lyric_active.png
+PlayerIDBox02 = [sing.player]lyric_active.png
+PlayerIDBox03 = [sing.player]lyric_active.png
+PlayerIDBox04 = [sing.player]lyric_active.png
+PlayerIDBox05 = [sing.player]lyric_active.png
+PlayerIDBox06 = [sing.player]lyric_active.png
# these icons are part of the tango icon set
# licensed under Creative Commons Attribution Share-Alike license
@@ -251,18 +251,18 @@ BGFade = [special]bg_fade.png
# # # D U E T # # #
-LyricIcon_P1 = [sing.player1]lyric_active.png
-LyricIconD_P1 = [sing.player1]lyric_inactive.png
-LyricIcon_P2 = [sing.player2]lyric_active.png
-LyricIconD_P2 = [sing.player2]lyric_inactive.png
-LyricIcon_P3 = [sing.player3]lyric_active.png
-LyricIconD_P3 = [sing.player3]lyric_inactive.png
-LyricIcon_P4 = [sing.player4]lyric_active.png
-LyricIconD_P4 = [sing.player4]lyric_inactive.png
-LyricIcon_P5 = [sing.player5]lyric_active.png
-LyricIconD_P5 = [sing.player5]lyric_inactive.png
-LyricIcon_P6 = [sing.player6]lyric_active.png
-LyricIconD_P6 = [sing.player6]lyric_inactive.png
+LyricIcon_P1 = [sing.player]lyric_active.png
+LyricIconD_P1 = [sing.player]lyric_inactive.png
+LyricIcon_P2 = [sing.player]lyric_active.png
+LyricIconD_P2 = [sing.player]lyric_inactive.png
+LyricIcon_P3 = [sing.player]lyric_active.png
+LyricIconD_P3 = [sing.player]lyric_inactive.png
+LyricIcon_P4 = [sing.player]lyric_active.png
+LyricIconD_P4 = [sing.player]lyric_inactive.png
+LyricIcon_P5 = [sing.player]lyric_active.png
+LyricIconD_P5 = [sing.player]lyric_inactive.png
+LyricIcon_P6 = [sing.player]lyric_active.png
+LyricIconD_P6 = [sing.player]lyric_inactive.png
# # # DOWNLOAD SCORE # # #
@@ -316,9 +316,9 @@ SelectFrame = [name]select.png
AvatarFrame2 = [score]frame.png
# # # NO AVATARS # # #
-NoAvatar_P1 = [name]noavatarP1.png
-NoAvatar_P2 = [name]noavatarP2.png
-NoAvatar_P3 = [name]noavatarP3.png
-NoAvatar_P4 = [name]noavatarP4.png
-NoAvatar_P5 = [name]noavatarP5.png
-NoAvatar_P6 = [name]noavatarP6.png
+NoAvatar_P1 = [name]noavatar.png
+NoAvatar_P2 = [name]noavatar.png
+NoAvatar_P3 = [name]noavatar.png
+NoAvatar_P4 = [name]noavatar.png
+NoAvatar_P5 = [name]noavatar.png
+NoAvatar_P6 = [name]noavatar.png
diff --git a/game/themes/Modern/Winter.ini b/game/themes/Modern/Winter.ini
index a72468c78..e5c7cd7cf 100644
--- a/game/themes/Modern/Winter.ini
+++ b/game/themes/Modern/Winter.ini
@@ -137,12 +137,12 @@ ScoreEndCap = [score]endcap.png
ScoreLine = [score]line.png
PlayerNumberBox = [main]playerNumberBox.png
-PlayerIDBox01 = [sing.player1]lyric_active.png
-PlayerIDBox02 = [sing.player2]lyric_active.png
-PlayerIDBox03 = [sing.player3]lyric_active.png
-PlayerIDBox04 = [sing.player4]lyric_active.png
-PlayerIDBox05 = [sing.player5]lyric_active.png
-PlayerIDBox06 = [sing.player6]lyric_active.png
+PlayerIDBox01 = [sing.player]lyric_active.png
+PlayerIDBox02 = [sing.player]lyric_active.png
+PlayerIDBox03 = [sing.player]lyric_active.png
+PlayerIDBox04 = [sing.player]lyric_active.png
+PlayerIDBox05 = [sing.player]lyric_active.png
+PlayerIDBox06 = [sing.player]lyric_active.png
# these icons are part of the tango icon set
# licensed under Creative Commons Attribution Share-Alike license
@@ -251,18 +251,18 @@ BGFade = [special]bg_fade.png
# # # D U E T # # #
-LyricIcon_P1 = [sing.player1]lyric_active.png
-LyricIconD_P1 = [sing.player1]lyric_inactive.png
-LyricIcon_P2 = [sing.player2]lyric_active.png
-LyricIconD_P2 = [sing.player2]lyric_inactive.png
-LyricIcon_P3 = [sing.player3]lyric_active.png
-LyricIconD_P3 = [sing.player3]lyric_inactive.png
-LyricIcon_P4 = [sing.player4]lyric_active.png
-LyricIconD_P4 = [sing.player4]lyric_inactive.png
-LyricIcon_P5 = [sing.player5]lyric_active.png
-LyricIconD_P5 = [sing.player5]lyric_inactive.png
-LyricIcon_P6 = [sing.player6]lyric_active.png
-LyricIconD_P6 = [sing.player6]lyric_inactive.png
+LyricIcon_P1 = [sing.player]lyric_active.png
+LyricIconD_P1 = [sing.player]lyric_inactive.png
+LyricIcon_P2 = [sing.player]lyric_active.png
+LyricIconD_P2 = [sing.player]lyric_inactive.png
+LyricIcon_P3 = [sing.player]lyric_active.png
+LyricIconD_P3 = [sing.player]lyric_inactive.png
+LyricIcon_P4 = [sing.player]lyric_active.png
+LyricIconD_P4 = [sing.player]lyric_inactive.png
+LyricIcon_P5 = [sing.player]lyric_active.png
+LyricIconD_P5 = [sing.player]lyric_inactive.png
+LyricIcon_P6 = [sing.player]lyric_active.png
+LyricIconD_P6 = [sing.player]lyric_inactive.png
# # # DOWNLOAD SCORE # # #
@@ -316,9 +316,9 @@ SelectFrame = [name]select.png
AvatarFrame2 = [score]frame.png
# # # NO AVATARS # # #
-NoAvatar_P1 = [name]noavatarP1.png
-NoAvatar_P2 = [name]noavatarP2.png
-NoAvatar_P3 = [name]noavatarP3.png
-NoAvatar_P4 = [name]noavatarP4.png
-NoAvatar_P5 = [name]noavatarP5.png
-NoAvatar_P6 = [name]noavatarP6.png
+NoAvatar_P1 = [name]noavatar.png
+NoAvatar_P2 = [name]noavatar.png
+NoAvatar_P3 = [name]noavatar.png
+NoAvatar_P4 = [name]noavatar.png
+NoAvatar_P5 = [name]noavatar.png
+NoAvatar_P6 = [name]noavatar.png
diff --git a/game/themes/Modern/[name]noavatar.png b/game/themes/Modern/[name]noavatar.png
new file mode 100644
index 000000000..00bf0f074
Binary files /dev/null and b/game/themes/Modern/[name]noavatar.png differ
diff --git a/game/themes/Modern/[name]noavatarP1.png b/game/themes/Modern/[name]noavatarP1.png
deleted file mode 100644
index 538991420..000000000
Binary files a/game/themes/Modern/[name]noavatarP1.png and /dev/null differ
diff --git a/game/themes/Modern/[name]noavatarP10.png b/game/themes/Modern/[name]noavatarP10.png
deleted file mode 100644
index 0bed45788..000000000
Binary files a/game/themes/Modern/[name]noavatarP10.png and /dev/null differ
diff --git a/game/themes/Modern/[name]noavatarP11.png b/game/themes/Modern/[name]noavatarP11.png
deleted file mode 100644
index 0bed45788..000000000
Binary files a/game/themes/Modern/[name]noavatarP11.png and /dev/null differ
diff --git a/game/themes/Modern/[name]noavatarP12.png b/game/themes/Modern/[name]noavatarP12.png
deleted file mode 100644
index 0bed45788..000000000
Binary files a/game/themes/Modern/[name]noavatarP12.png and /dev/null differ
diff --git a/game/themes/Modern/[name]noavatarP2.png b/game/themes/Modern/[name]noavatarP2.png
deleted file mode 100644
index 3dd7ac345..000000000
Binary files a/game/themes/Modern/[name]noavatarP2.png and /dev/null differ
diff --git a/game/themes/Modern/[name]noavatarP3.png b/game/themes/Modern/[name]noavatarP3.png
deleted file mode 100644
index def60a40e..000000000
Binary files a/game/themes/Modern/[name]noavatarP3.png and /dev/null differ
diff --git a/game/themes/Modern/[name]noavatarP4.png b/game/themes/Modern/[name]noavatarP4.png
deleted file mode 100644
index e0b164ea6..000000000
Binary files a/game/themes/Modern/[name]noavatarP4.png and /dev/null differ
diff --git a/game/themes/Modern/[name]noavatarP5.png b/game/themes/Modern/[name]noavatarP5.png
deleted file mode 100644
index 24a06bb6a..000000000
Binary files a/game/themes/Modern/[name]noavatarP5.png and /dev/null differ
diff --git a/game/themes/Modern/[name]noavatarP6.png b/game/themes/Modern/[name]noavatarP6.png
deleted file mode 100644
index c202e6d8e..000000000
Binary files a/game/themes/Modern/[name]noavatarP6.png and /dev/null differ
diff --git a/game/themes/Modern/[name]noavatarP7.png b/game/themes/Modern/[name]noavatarP7.png
deleted file mode 100644
index 0bed45788..000000000
Binary files a/game/themes/Modern/[name]noavatarP7.png and /dev/null differ
diff --git a/game/themes/Modern/[name]noavatarP8.png b/game/themes/Modern/[name]noavatarP8.png
deleted file mode 100644
index 0bed45788..000000000
Binary files a/game/themes/Modern/[name]noavatarP8.png and /dev/null differ
diff --git a/game/themes/Modern/[name]noavatarP9.png b/game/themes/Modern/[name]noavatarP9.png
deleted file mode 100644
index 0bed45788..000000000
Binary files a/game/themes/Modern/[name]noavatarP9.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player1]lyric_active.png b/game/themes/Modern/[sing.player1]lyric_active.png
deleted file mode 100644
index 089c8c5e7..000000000
Binary files a/game/themes/Modern/[sing.player1]lyric_active.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player1]lyric_inactive.png b/game/themes/Modern/[sing.player1]lyric_inactive.png
deleted file mode 100644
index a349007d9..000000000
Binary files a/game/themes/Modern/[sing.player1]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player2]lyric_active.png b/game/themes/Modern/[sing.player2]lyric_active.png
deleted file mode 100644
index 509767fa2..000000000
Binary files a/game/themes/Modern/[sing.player2]lyric_active.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player2]lyric_inactive.png b/game/themes/Modern/[sing.player2]lyric_inactive.png
deleted file mode 100644
index ac40ec61d..000000000
Binary files a/game/themes/Modern/[sing.player2]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player3]lyric_active.png b/game/themes/Modern/[sing.player3]lyric_active.png
deleted file mode 100644
index 7b130ac5b..000000000
Binary files a/game/themes/Modern/[sing.player3]lyric_active.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player3]lyric_inactive.png b/game/themes/Modern/[sing.player3]lyric_inactive.png
deleted file mode 100644
index c5a00600d..000000000
Binary files a/game/themes/Modern/[sing.player3]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player4]lyric_active.png b/game/themes/Modern/[sing.player4]lyric_active.png
deleted file mode 100644
index 993041fd5..000000000
Binary files a/game/themes/Modern/[sing.player4]lyric_active.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player4]lyric_inactive.png b/game/themes/Modern/[sing.player4]lyric_inactive.png
deleted file mode 100644
index f09669b22..000000000
Binary files a/game/themes/Modern/[sing.player4]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player5]lyric_active.png b/game/themes/Modern/[sing.player5]lyric_active.png
deleted file mode 100644
index 631dc9c33..000000000
Binary files a/game/themes/Modern/[sing.player5]lyric_active.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player5]lyric_inactive.png b/game/themes/Modern/[sing.player5]lyric_inactive.png
deleted file mode 100644
index 716071e82..000000000
Binary files a/game/themes/Modern/[sing.player5]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player6]lyric_active.png b/game/themes/Modern/[sing.player6]lyric_active.png
deleted file mode 100644
index 65133d034..000000000
Binary files a/game/themes/Modern/[sing.player6]lyric_active.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player6]lyric_inactive.png b/game/themes/Modern/[sing.player6]lyric_inactive.png
deleted file mode 100644
index 0c5f34d31..000000000
Binary files a/game/themes/Modern/[sing.player6]lyric_inactive.png and /dev/null differ
diff --git a/game/themes/Modern/[sing.player]lyric_active.png b/game/themes/Modern/[sing.player]lyric_active.png
new file mode 100644
index 000000000..6297a7010
Binary files /dev/null and b/game/themes/Modern/[sing.player]lyric_active.png differ
diff --git a/game/themes/Modern/[sing.player]lyric_inactive.png b/game/themes/Modern/[sing.player]lyric_inactive.png
new file mode 100644
index 000000000..3a1f8a4a9
Binary files /dev/null and b/game/themes/Modern/[sing.player]lyric_inactive.png differ
diff --git a/src/base/UDraw.pas b/src/base/UDraw.pas
index 691aa4f93..f25eea231 100644
--- a/src/base/UDraw.pas
+++ b/src/base/UDraw.pas
@@ -38,7 +38,8 @@ interface
UThemes,
sdl2,
UGraphicClasses,
- UIni;
+ UIni,
+ UPlayerLayout;
procedure SingDraw;
procedure SingDrawLines;
@@ -410,124 +411,98 @@ procedure SingDrawJukeboxBlackBackground;
end;
procedure SingDrawOscilloscopes;
-begin;
- if PlayersPlay = 1 then
- SingDrawOscilloscope(Theme.Sing.Solo1PP1.Oscilloscope, 0);
-
- if PlayersPlay = 2 then
+ function GetBaseOscilloscopePosition: TThemePosition;
begin
- SingDrawOscilloscope(Theme.Sing.Solo2PP1.Oscilloscope, 0);
- SingDrawOscilloscope(Theme.Sing.Solo2PP2.Oscilloscope, 1);
+ Result := Theme.Sing.PlayerTemplate.Oscilloscope;
end;
-
- if PlayersPlay = 3 then
+ function GetBaseSingPlayerTemplate: TThemeSingPlayer;
begin
- if (CurrentSong.isDuet) then
- begin
- SingDrawOscilloscope(Theme.Sing.Duet3PP1.Oscilloscope, 0);
- SingDrawOscilloscope(Theme.Sing.Duet3PP2.Oscilloscope, 1);
- SingDrawOscilloscope(Theme.Sing.Duet3PP3.Oscilloscope, 2);
- end
- else
- begin
- SingDrawOscilloscope(Theme.Sing.Solo3PP1.Oscilloscope, 0);
- SingDrawOscilloscope(Theme.Sing.Solo3PP2.Oscilloscope, 1);
- SingDrawOscilloscope(Theme.Sing.Solo3PP3.Oscilloscope, 2);
- end;
+ Result := Theme.Sing.PlayerTemplate;
end;
-
- if PlayersPlay = 4 then
+ procedure GetLaneLayout(const PlayerCountOnScreen, PlayerIndexOnScreen: integer;
+ out LaneLeft, LaneRight, LaneTop, LaneWidth: integer);
+ var
+ Layout: TSingLaneLayout;
begin
- if (Ini.Screens = 1) then
- begin
- if ScreenAct = 1 then
- begin
- SingDrawOscilloscope(Theme.Sing.Solo2PP1.Oscilloscope, 0);
- SingDrawOscilloscope(Theme.Sing.Solo2PP2.Oscilloscope, 1);
- end;
- if ScreenAct = 2 then
- begin
- SingDrawOscilloscope(Theme.Sing.Solo2PP1.Oscilloscope, 2);
- SingDrawOscilloscope(Theme.Sing.Solo2PP2.Oscilloscope, 3);
- end;
- end
- else
- begin
- if (CurrentSong.isDuet) then
- begin
- SingDrawOscilloscope(Theme.Sing.Duet4PP1.Oscilloscope, 0);
- SingDrawOscilloscope(Theme.Sing.Duet4PP2.Oscilloscope, 1);
- SingDrawOscilloscope(Theme.Sing.Duet4PP3.Oscilloscope, 2);
- SingDrawOscilloscope(Theme.Sing.Duet4PP4.Oscilloscope, 3);
- end
- else
- begin
- SingDrawOscilloscope(Theme.Sing.Solo4PP1.Oscilloscope, 0);
- SingDrawOscilloscope(Theme.Sing.Solo4PP2.Oscilloscope, 1);
- SingDrawOscilloscope(Theme.Sing.Solo4PP3.Oscilloscope, 2);
- SingDrawOscilloscope(Theme.Sing.Solo4PP4.Oscilloscope, 3);
- end;
- end;
+ Layout := GetSingLaneLayout(PlayerCountOnScreen, PlayerIndexOnScreen, Theme.Sing.PlayerLayout,
+ CurrentSong.isDuet and (PlayersPlay <> 1));
+ LaneLeft := Layout.ColumnLeft;
+ LaneRight := Layout.ColumnRight;
+ LaneTop := Layout.RowAnchorY;
+ LaneWidth := Layout.ColumnWidth;
end;
-
- if PlayersPlay = 6 then
+ function GetOscilloscopePosition(PlayerIndex: integer): TThemePosition;
+ var
+ BaseTemplate: TThemeSingPlayer;
+ BasePosition: TThemePosition;
+ LocalPlayerCount: integer;
+ LocalIndex: integer;
+ LaneLeft: integer;
+ LaneRight: integer;
+ LaneTop: integer;
+ LaneWidth: integer;
+ Scale: real;
+ FrameW: integer;
+ FrameH: integer;
+ ScoreW: integer;
+ ScoreH: integer;
+ NameX: integer;
+ NameY: integer;
+ NameW: integer;
+ GroupTop: integer;
+ HeaderOffsetLeft: integer;
+ Layout: TSingLaneLayout;
begin
- if (Ini.Screens = 1) then
+ if Screens > 1 then
begin
- if (CurrentSong.isDuet) then
- begin
- if ScreenAct = 1 then
- begin
- SingDrawOscilloscope(Theme.Sing.Duet3PP1.Oscilloscope, 0);
- SingDrawOscilloscope(Theme.Sing.Duet3PP2.Oscilloscope, 1);
- SingDrawOscilloscope(Theme.Sing.Duet3PP3.Oscilloscope, 2);
- end;
- if ScreenAct = 2 then
- begin
- SingDrawOscilloscope(Theme.Sing.Duet3PP1.Oscilloscope, 3);
- SingDrawOscilloscope(Theme.Sing.Duet3PP2.Oscilloscope, 4);
- SingDrawOscilloscope(Theme.Sing.Duet3PP3.Oscilloscope, 5);
- end;
- end
- else
- begin
- if ScreenAct = 1 then
- begin
- SingDrawOscilloscope(Theme.Sing.Solo3PP1.Oscilloscope, 0);
- SingDrawOscilloscope(Theme.Sing.Solo3PP2.Oscilloscope, 1);
- SingDrawOscilloscope(Theme.Sing.Solo3PP3.Oscilloscope, 2);
- end;
-
- if ScreenAct = 2 then
- begin
- SingDrawOscilloscope(Theme.Sing.Solo3PP1.Oscilloscope, 3);
- SingDrawOscilloscope(Theme.Sing.Solo3PP2.Oscilloscope, 4);
- SingDrawOscilloscope(Theme.Sing.Solo3PP3.Oscilloscope, 5);
- end;
- end;
+ LocalPlayerCount := GetScreenPlayerCount(PlayersPlay, Screens, ScreenAct);
+ LocalIndex := GetPlayerIndexOnScreen(PlayerIndex, PlayersPlay, Screens);
end
else
begin
- if (CurrentSong.isDuet) then
- begin
- SingDrawOscilloscope(Theme.Sing.Duet6PP1.Oscilloscope, 0);
- SingDrawOscilloscope(Theme.Sing.Duet6PP2.Oscilloscope, 1);
- SingDrawOscilloscope(Theme.Sing.Duet6PP3.Oscilloscope, 2);
- SingDrawOscilloscope(Theme.Sing.Duet6PP4.Oscilloscope, 3);
- SingDrawOscilloscope(Theme.Sing.Duet6PP5.Oscilloscope, 4);
- SingDrawOscilloscope(Theme.Sing.Duet6PP6.Oscilloscope, 5);
- end
- else
- begin
- SingDrawOscilloscope(Theme.Sing.Solo6PP1.Oscilloscope, 0);
- SingDrawOscilloscope(Theme.Sing.Solo6PP2.Oscilloscope, 1);
- SingDrawOscilloscope(Theme.Sing.Solo6PP3.Oscilloscope, 2);
- SingDrawOscilloscope(Theme.Sing.Solo6PP4.Oscilloscope, 3);
- SingDrawOscilloscope(Theme.Sing.Solo6PP5.Oscilloscope, 4);
- SingDrawOscilloscope(Theme.Sing.Solo6PP6.Oscilloscope, 5);
- end;
+ LocalPlayerCount := PlayersPlay;
+ LocalIndex := PlayerIndex;
end;
+
+ BaseTemplate := GetBaseSingPlayerTemplate;
+ BasePosition := GetBaseOscilloscopePosition;
+ Layout := GetSingLaneLayout(LocalPlayerCount, LocalIndex, Theme.Sing.PlayerLayout,
+ CurrentSong.isDuet and (PlayersPlay <> 1));
+ GetLaneLayout(LocalPlayerCount, LocalIndex, LaneLeft, LaneRight, LaneTop, LaneWidth);
+ Scale := Layout.WidgetScale;
+
+ FrameW := Max(Theme.Sing.PlayerWidgetLayout.MinFrameW, Round(BaseTemplate.AvatarFrame.W * Scale));
+ FrameH := Max(Theme.Sing.PlayerWidgetLayout.MinFrameH, Round(BaseTemplate.AvatarFrame.H * Scale));
+ ScoreW := Max(Theme.Sing.PlayerWidgetLayout.MinScoreW, Round(BaseTemplate.ScoreBackground.W * Scale));
+ ScoreH := Max(Theme.Sing.PlayerWidgetLayout.MinScoreH, Round(BaseTemplate.ScoreBackground.H * Scale));
+ HeaderOffsetLeft := Round(Theme.Sing.PlayerWidgetLayout.HeaderOffsetLeft * Scale);
+ GroupTop := Max(10, LaneTop -
+ GetSingHeaderTopOffset(Theme.Sing.PlayerWidgetLayout, Layout.GridRows, Scale));
+ NameX := Max(0, LaneLeft - HeaderOffsetLeft) + FrameW +
+ Max(Theme.Sing.PlayerWidgetLayout.NameGapMinX, Round(Theme.Sing.PlayerWidgetLayout.NameGapBaseX * Scale));
+ NameW := Max(Theme.Sing.PlayerWidgetLayout.NameMinW,
+ (LaneRight - ScoreW - Max(Theme.Sing.PlayerWidgetLayout.NameGapMinX,
+ Round(Theme.Sing.PlayerWidgetLayout.NameGapBaseX * Scale))) - NameX);
+ NameY := GroupTop + Max(0, (FrameH - Max(12, Round(BaseTemplate.Name.Size * Scale))) div 2);
+ NameX := Max(0, NameX - Max(Theme.Sing.PlayerWidgetLayout.NamePaddingMinX,
+ Round(Theme.Sing.PlayerWidgetLayout.NamePaddingBaseX * Scale)));
+ NameY := Max(0, NameY - Max(Theme.Sing.PlayerWidgetLayout.NamePaddingMinY,
+ Round(Theme.Sing.PlayerWidgetLayout.NamePaddingBaseY * Scale)));
+
+ Result := BasePosition;
+ Result.X := NameX;
+ Result.Y := NameY + Max(12, Round(BaseTemplate.Name.H * Scale)) +
+ Max(Theme.Sing.PlayerWidgetLayout.OscilloscopeGapMinY,
+ Round(Theme.Sing.PlayerWidgetLayout.OscilloscopeGapBaseY * Scale));
+ Result.W := Min(NameW, Max(Theme.Sing.PlayerWidgetLayout.OscilloscopeMinW, Round(BasePosition.W * Scale)));
+ Result.H := Max(Theme.Sing.PlayerWidgetLayout.OscilloscopeMinH, Round(BasePosition.H * Scale));
end;
+var
+ PlayerIndex: integer;
+begin;
+ for PlayerIndex := 0 to PlayersPlay - 1 do
+ if (Screens <= 1) or (GetPlayerScreen(PlayerIndex, PlayersPlay, Screens) = ScreenAct) then
+ SingDrawOscilloscope(GetOscilloscopePosition(PlayerIndex), PlayerIndex);
end;
procedure SingDrawOscilloscope(Position: TThemePosition; NrSound: integer);
@@ -853,6 +828,9 @@ procedure SingDrawPlayerBGLine(Left, Top, Right: real; Track, PlayerIndex: integ
Count: integer;
TempR: real;
W, H: real;
+ GlowPadX: real;
+ GlowExtraW: real;
+ GlowExtraH: real;
begin
if (ScreenSing.settings.NotesVisible[PlayerIndex]) then
begin
@@ -873,10 +851,11 @@ procedure SingDrawPlayerBGLine(Left, Top, Right: real; Track, PlayerIndex: integ
begin
if NoteType <> ntFreestyle then
begin
- // begin: 14, 20
- // easy: 6, 11
- W := NotesW[PlayerIndex] * 2 + 2;
- H := NotesH[PlayerIndex] * 1.5 + 3.5;
+ GlowPadX := Max(1.0, NotesW[PlayerIndex] * 0.65);
+ GlowExtraW := Max(1.0, NotesW[PlayerIndex] * 0.35);
+ GlowExtraH := Max(1.5, NotesH[PlayerIndex] * 0.3);
+ W := NotesW[PlayerIndex] * 2 + GlowExtraW;
+ H := NotesH[PlayerIndex] * 1.5 + GlowExtraH;
{
X2 := (Start-CurrentSong.Tracks[Track].Lines[CurrentSong.Tracks[Track].Current].Notes[0].Start) * TempR + Left + 0.5 + 4;
@@ -887,7 +866,7 @@ procedure SingDrawPlayerBGLine(Left, Top, Right: real; Track, PlayerIndex: integ
}
// left
- Rec.Right := (StartBeat - CurrentSong.Tracks[Track].Lines[CurrentSong.Tracks[Track].CurrentLine].Notes[0].StartBeat) * TempR + Left + 0.5 + 4;
+ Rec.Right := (StartBeat - CurrentSong.Tracks[Track].Lines[CurrentSong.Tracks[Track].CurrentLine].Notes[0].StartBeat) * TempR + Left + 0.5 + GlowPadX;
Rec.Left := Rec.Right - W;
Rec.Top := Top - (Tone-BaseNote)*LineSpacing/2 - H;
Rec.Bottom := Rec.Top + 2 * H;
@@ -909,7 +888,7 @@ procedure SingDrawPlayerBGLine(Left, Top, Right: real; Track, PlayerIndex: integ
// middle part
Rec.Left := Rec.Right;
- Rec.Right := (StartBeat + Duration - CurrentSong.Tracks[Track].Lines[CurrentSong.Tracks[Track].CurrentLine].Notes[0].StartBeat) * TempR + Left - 0.5 - 4;
+ Rec.Right := (StartBeat + Duration - CurrentSong.Tracks[Track].Lines[CurrentSong.Tracks[Track].CurrentLine].Notes[0].StartBeat) * TempR + Left - 0.5 - GlowPadX;
// the left note is more right than the right note itself, sounds weird - so we fix that xD
if Rec.Right <= Rec.Left then
@@ -1065,26 +1044,10 @@ procedure SingDrawLyricHelper(CP: integer; Left, LyricsMid: real);
if (CurrentSong.isDuet) then
begin
- if (PlayersPlay = 1) or (PlayersPlay = 2) then
- Col := GetLyricBarColor(Ini.SingColor[CP])
+ if (Screens > 1) and (GetScreenPlayerCount(PlayersPlay, Screens, ScreenAct) = 2) then
+ Col := GetLyricBarColor(Ini.SingColor[GetFirstPlayerIndexForScreen(PlayersPlay, Screens, ScreenAct) + CP])
else
- begin
- if (PlayersPlay = 3) or (PlayersPlay = 6) then
- begin
- //if (PlayersPlay = 3) then
- Col := GetLyricBarColor(Ini.SingColor[CP]);
-
- //if (PlayersPlay = 6) then
- // Col := GetLyricBarColor(CP + 1);
- end
- else
- begin
- if ScreenAct = 1 then
- Col := GetLyricBarColor(Ini.SingColor[CP])
- else
- Col := GetLyricBarColor(Ini.SingColor[CP + 2]);
- end;
- end;
+ Col := GetLyricBarColor(Ini.SingColor[CP]);
end
else
Col := GetLyricBarColor(1);
@@ -1215,6 +1178,35 @@ procedure SingDrawLyricHelperJukebox(Left, LyricsMid: real);
procedure SingDrawLines;
var
NR: TRecR; // lyrics area bounds (NR = NoteRec?)
+ PlayerIndex: integer;
+ LocalIndex: integer;
+ LineTop: real;
+ LineSpacing: integer;
+ PlayerCountOnScreen: integer;
+ LaneLeft: real;
+ LaneRight: real;
+ procedure GetLaneLayout(const CurrentPlayerIndex: integer; out Left, Right, Top: real; out Spacing: integer);
+ var
+ Layout: TSingLaneLayout;
+ begin
+ if Screens > 1 then
+ begin
+ PlayerCountOnScreen := GetScreenPlayerCount(PlayersPlay, Screens, ScreenAct);
+ LocalIndex := GetPlayerIndexOnScreen(CurrentPlayerIndex, PlayersPlay, Screens);
+ end
+ else
+ begin
+ PlayerCountOnScreen := PlayersPlay;
+ LocalIndex := CurrentPlayerIndex;
+ end;
+
+ Layout := GetSingLaneLayout(PlayerCountOnScreen, LocalIndex, Theme.Sing.PlayerLayout,
+ CurrentSong.isDuet and (PlayersPlay <> 1));
+ Left := Layout.GridLeft;
+ Right := Layout.GridRight;
+ Top := Layout.GuideTopY;
+ Spacing := Layout.NoteLineSpacing;
+ end;
begin
// positions
NR.Left := 20;
@@ -1225,85 +1217,18 @@ procedure SingDrawLines;
// draw note-lines
- // to-do : needs fix when party mode works w/ 2 screens
- if (PlayersPlay = 1) and (Ini.NoteLines = 1) and (ScreenSing.settings.NotesVisible[0]) then
- SingDrawNoteLines(NR.Left, Skin_P2_NotesB - 105, NR.Right, 15);
+ if Ini.NoteLines <> 1 then
+ Exit;
- if (PlayersPlay = 2) and (Ini.NoteLines = 1) then
+ for PlayerIndex := 0 to PlayersPlay - 1 do
begin
- if (ScreenSing.settings.NotesVisible[0]) then
- SingDrawNoteLines(Nr.Left, Skin_P1_NotesB - 105, Nr.Right, 15);
- if (ScreenSing.settings.NotesVisible[1]) then
- SingDrawNoteLines(Nr.Left, Skin_P2_NotesB - 105, Nr.Right, 15);
- end;
+ if (Screens > 1) and (GetPlayerScreen(PlayerIndex, PlayersPlay, Screens) <> ScreenAct) then
+ Continue;
+ if not ScreenSing.Settings.NotesVisible[PlayerIndex] then
+ Continue;
- if (PlayersPlay = 3) and (Ini.NoteLines = 1) then begin
- if (ScreenSing.settings.NotesVisible[0]) then
- SingDrawNoteLines(Nr.Left, 120, Nr.Right, 12);
- if (ScreenSing.settings.NotesVisible[1]) then
- SingDrawNoteLines(Nr.Left, 245, Nr.Right, 12);
- if (ScreenSing.settings.NotesVisible[2]) then
- SingDrawNoteLines(Nr.Left, 370, Nr.Right, 12);
- end;
-
- if (PlayersPlay = 4) and (Ini.NoteLines = 1) then
- begin
- if (ScreenSing.settings.NotesVisible[0]) then
- begin
- if (Ini.Screens = 1) then
- SingDrawNoteLines(Nr.Left, Skin_P1_NotesB - 105, Nr.Right, 15)
- else
- begin
- SingDrawNoteLines(Nr.Left, Skin_P1_NotesB - 105, Nr.Right/2 - 5, 15);
- SingDrawNoteLines(Nr.Right/2 - 20 + Nr.Left, Skin_P1_NotesB - 105, Nr.Right, 15)
- end;
- end;
-
- if (ScreenSing.settings.NotesVisible[1]) then
- begin
- if (Ini.Screens = 1) then
- SingDrawNoteLines(Nr.Left, Skin_P2_NotesB - 105, Nr.Right, 15)
- else
- begin
- SingDrawNoteLines(Nr.Left, Skin_P2_NotesB - 105, Nr.Right/2 - 5, 15);
- SingDrawNoteLines(Nr.Right/2 - 20 + Nr.Left, Skin_P2_NotesB - 105, Nr.Right, 15)
- end;
- end;
- end;
-
- if (PlayersPlay = 6) and (Ini.NoteLines = 1) then begin
- if (ScreenSing.settings.NotesVisible[0]) then
- begin
- if (Ini.Screens = 1) then
- SingDrawNoteLines(Nr.Left, 120, Nr.Right, 12)
- else
- begin
- SingDrawNoteLines(Nr.Left, 120, Nr.Right/2 - 5, 12);
- SingDrawNoteLines(Nr.Right/2 - 20 + Nr.Left, 120, Nr.Right, 12);
- end;
- end;
-
- if (ScreenSing.settings.NotesVisible[1]) then
- begin
- if (Ini.Screens = 1) then
- SingDrawNoteLines(Nr.Left, 245, Nr.Right, 12)
- else
- begin
- SingDrawNoteLines(Nr.Left, 245, Nr.Right/2 - 5, 12);
- SingDrawNoteLines(Nr.Right/2 - 20 + Nr.Left, 245, Nr.Right, 12);
- end;
- end;
-
- if (ScreenSing.settings.NotesVisible[2]) then
- begin
- if (Ini.Screens = 1) then
- SingDrawNoteLines(Nr.Left, 370, Nr.Right, 12)
- else
- begin
- SingDrawNoteLines(Nr.Left, 370, Nr.Right/2 - 5, 12);
- SingDrawNoteLines(Nr.Right/2 - 20 + Nr.Left, 370, Nr.Right, 12);
- end;
- end;
+ GetLaneLayout(PlayerIndex, LaneLeft, LaneRight, LineTop, LineSpacing);
+ SingDrawNoteLines(LaneLeft, LineTop, LaneRight, LineSpacing);
end;
end;
@@ -1315,18 +1240,40 @@ procedure SingDraw;
LyricEngineDuetP2: TLyricEngine;
I: integer;
Difficulty: integer;
- TrackP1, TrackP2, TrackP3, TrackP4, TrackP5, TrackP6: integer;
-const
- LineSpacingOneRow = 15;
- LineSpacingTwoRows = 15;
- LineSpacingThreeRows = 12;
- // TODO: it looks like all these TopXRowsY constants are actually referring to the bottom. But all the functions they call have historically called it Top.
- TopOneRow1 = Skin_P2_NotesB;
- TopTwoRows1 = Skin_P1_NotesB;
- TopTwoRows2 = Skin_P2_NotesB;
- TopThreeRows1 = 120+95;
- TopThreeRows2 = 245+95;
- TopThreeRows3 = 370+95;
+ PlayerCountOnScreen: integer;
+ PlayerIndex: integer;
+ LocalIndex: integer;
+ LineTop: real;
+ LineSpacing: integer;
+ TrackIndex: integer;
+ LaneLeft: real;
+ LaneRight: real;
+ LaneWidth: real;
+ Layout: TSingLaneLayout;
+ ContentScale: real;
+ BaseNoteH: real;
+ BaseNoteW: real;
+ procedure GetLaneLayout(const CurrentPlayerIndex: integer; out Left, Right, Width, Top: real; out Spacing: integer);
+ begin
+ if Screens > 1 then
+ begin
+ PlayerCountOnScreen := GetScreenPlayerCount(PlayersPlay, Screens, ScreenAct);
+ LocalIndex := GetPlayerIndexOnScreen(CurrentPlayerIndex, PlayersPlay, Screens);
+ end
+ else
+ begin
+ PlayerCountOnScreen := PlayersPlay;
+ LocalIndex := CurrentPlayerIndex;
+ end;
+
+ Layout := GetSingLaneLayout(PlayerCountOnScreen, LocalIndex, Theme.Sing.PlayerLayout,
+ CurrentSong.isDuet and (PlayersPlay <> 1));
+ Left := Layout.GridLeft;
+ Right := Layout.GridRight;
+ Width := Right - Left;
+ Top := Layout.RowAnchorY;
+ Spacing := Layout.NoteLineSpacing;
+ end;
begin
// positions
NR.Left := 20;
@@ -1334,21 +1281,11 @@ procedure SingDraw;
NR.Width := 760; //NR.Right - NR.Left;
NR.WMid := 380; //NR.Width / 2;
NR.Mid := 400; //NR.Left + NR.WMid;
-
- TrackP1 := 0;
- TrackP2 := 0;
- TrackP3 := 0;
- TrackP4 := 0;
- TrackP5 := 0;
- TrackP6 := 0;
// FIXME: accessing ScreenSing is not that generic
if (CurrentSong.isDuet) and (PlayersPlay <> 1) then
begin
LyricEngineDuetP1 := ScreenSing.LyricsDuetP1;
LyricEngineDuetP2 := ScreenSing.LyricsDuetP2;
- TrackP2 := 1;
- TrackP4 := 1;
- TrackP6 := 1;
end
else
LyricEngine := ScreenSing.Lyrics;
@@ -1379,7 +1316,6 @@ procedure SingDraw;
for I := 1 to PlayersPlay do
begin
-
if (ScreenSong.Mode = smNormal) or (ScreenSong.Mode = smMedley) then
Difficulty := Player[I - 1].Level
else
@@ -1388,195 +1324,62 @@ procedure SingDraw;
case Difficulty of
0:
begin
- NotesH[I - 1] := 11; // 9
- NotesW[I - 1] := 6; // 5
+ BaseNoteH := 11;
+ BaseNoteW := 6;
end;
1:
begin
- NotesH[I - 1] := 8; // 7
- NotesW[I - 1] := 4; // 4
+ BaseNoteH := 8;
+ BaseNoteW := 4;
end;
2:
begin
- NotesH[I - 1] := 5;
- NotesW[I - 1] := 3;
+ BaseNoteH := 5;
+ BaseNoteW := 3;
end;
- end;
-
- if PlayersPlay = 3 then
- begin
- NotesW[I - 1] := NotesW[I - 1] * 0.8;
- NotesH[I - 1] := NotesH[I - 1] * 0.8;
- end;
-
- if PlayersPlay = 4 then
- begin
- if (Ini.Screens = 0) then
+ else
begin
- NotesW[I - 1] := NotesW[I - 1] * 0.9;
+ BaseNoteH := 8;
+ BaseNoteW := 4;
end;
end;
- if PlayersPlay = 6 then
+ if Screens > 1 then
begin
- NotesW[I - 1] := NotesW[I - 1] * 0.8;
- NotesH[I - 1] := NotesH[I - 1] * 0.8;
+ PlayerCountOnScreen := GetScreenPlayerCount(PlayersPlay, Screens, ScreenAct);
+ LocalIndex := GetPlayerIndexOnScreen(I - 1, PlayersPlay, Screens);
+ end
+ else
+ begin
+ PlayerCountOnScreen := PlayersPlay;
+ LocalIndex := I - 1;
end;
+ Layout := GetSingLaneLayout(PlayerCountOnScreen, LocalIndex, Theme.Sing.PlayerLayout,
+ CurrentSong.isDuet and (PlayersPlay <> 1));
+ ContentScale := Layout.ContentScale;
+ NotesH[I - 1] := Max(2.0, BaseNoteH * ContentScale);
+ NotesW[I - 1] := Max(1.0, BaseNoteW * ContentScale);
end;
// draw notes lines
if (ScreenSing.Settings.InputVisible) then
SingDrawLines;
// Draw the Notes
- if (PlayersPlay = 1) then
+ for PlayerIndex := 0 to PlayersPlay - 1 do
begin
- // SINGLESCREEN
- SingDrawPlayerBGLine(NR.Left + 20, TopOneRow1, NR.Right - 20, TrackP1, 0, LineSpacingOneRow); // Background glow - colorized in playercolor
- SingDrawLine(NR.Left + 20, TopOneRow1, NR.Right - 20, TrackP1, 0, LineSpacingOneRow); // Plain unsung notes - colorized in playercolor
- SingDrawPlayerLine(NR.Left + 20, TopOneRow1, NR.Width - 40, TrackP1, 0, LineSpacingOneRow); // imho the sung notes
- end;
+ if (Screens > 1) and (GetPlayerScreen(PlayerIndex, PlayersPlay, Screens) <> ScreenAct) then
+ Continue;
- if (PlayersPlay = 2) then
- begin
- // SINGLESCREEN
- SingDrawPlayerBGLine(NR.Left + 20, TopTwoRows1, NR.Right - 20, TrackP1, 0, LineSpacingTwoRows);
- SingDrawLine(NR.Left + 20, TopTwoRows1, NR.Right - 20, TrackP1, 0, LineSpacingTwoRows);
- SingDrawPlayerLine(NR.Left + 20, TopTwoRows1, NR.Width - 40, TrackP1, 0, LineSpacingTwoRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopTwoRows2, NR.Right - 20, TrackP2, 1, LineSpacingTwoRows);
- SingDrawLine(NR.Left + 20, TopTwoRows2, NR.Right - 20, TrackP2, 1, LineSpacingTwoRows);
- SingDrawPlayerLine(NR.Left + 20, TopTwoRows2, NR.Width - 40, TrackP2, 1, LineSpacingTwoRows);
- end;
+ GetLaneLayout(PlayerIndex, LaneLeft, LaneRight, LaneWidth, LineTop, LineSpacing);
- if (PlayersPlay = 3) then
- begin
- // SINGLESCREEN
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows1, NR.Right - 20, TrackP1, 0, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows1, NR.Right - 20, TrackP1, 0, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows1, NR.Width - 40, TrackP1, 0, LineSpacingThreeRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows2, NR.Right - 20, TrackP2, 1, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows2, NR.Right - 20, TrackP2, 1, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows2, NR.Width - 40, TrackP2, 1, LineSpacingThreeRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows3, NR.Right - 20, TrackP3, 2, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows3, NR.Right - 20, TrackP3, 2, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows3, NR.Width - 40, TrackP3, 2, LineSpacingThreeRows);
- end;
+ TrackIndex := 0;
+ if (CurrentSong.isDuet) and (PlayersPlay <> 1) and Odd(PlayerIndex) then
+ TrackIndex := 1;
- if (PlayersPlay = 4) then
- begin
- if (Ini.Screens = 1) then
- begin
- // MULTISCREEN
- if (ScreenAct = 1) then
- begin
- // MULTISCREEN - SCREEN 1
- SingDrawPlayerBGLine(NR.Left + 20, TopTwoRows1, NR.Right - 20, TrackP1, 0, LineSpacingTwoRows);
- SingDrawLine(NR.Left + 20, TopTwoRows1, NR.Right - 20, TrackP1, 0, LineSpacingTwoRows);
- SingDrawPlayerLine(NR.Left + 20, TopTwoRows1, NR.Width - 40, TrackP1, 0, LineSpacingTwoRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopTwoRows2, NR.Right - 20, TrackP2, 1, LineSpacingTwoRows);
- SingDrawLine(NR.Left + 20, TopTwoRows2, NR.Right - 20, TrackP2, 1, LineSpacingTwoRows);
- SingDrawPlayerLine(NR.Left + 20, TopTwoRows2, NR.Width - 40, TrackP2, 1, LineSpacingTwoRows);
- end;
- if (ScreenAct = 2) then
- begin
- // MULTISCREEN - SCREEN 2
- SingDrawPlayerBGLine(NR.Left + 20, TopTwoRows1, NR.Right - 20, TrackP3, 2, LineSpacingTwoRows);
- SingDrawLine(NR.Left + 20, TopTwoRows1, NR.Right - 20, TrackP3, 2, LineSpacingTwoRows);
- SingDrawPlayerLine(NR.Left + 20, TopTwoRows1, NR.Width - 40, TrackP3, 2, LineSpacingTwoRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopTwoRows2, NR.Right - 20, TrackP4, 3, LineSpacingTwoRows);
- SingDrawLine(NR.Left + 20, TopTwoRows2, NR.Right - 20, TrackP4, 3, LineSpacingTwoRows);
- SingDrawPlayerLine(NR.Left + 20, TopTwoRows2, NR.Width - 40, TrackP4, 3, LineSpacingTwoRows);
- end;
- end
- else
- begin
- // SINGLESCREEN
- SingDrawPlayerBGLine(NR.Left + 20, TopTwoRows1, NR.Right/2 - 20, TrackP1, 0, LineSpacingTwoRows);
- SingDrawLine(NR.Left + 20, TopTwoRows1, NR.Right/2 - 20, TrackP1, 0, LineSpacingTwoRows);
- SingDrawPlayerLine(NR.Left + 20, TopTwoRows1, NR.Width/2 - 50, TrackP1, 0, LineSpacingTwoRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopTwoRows2, NR.Right/2 - 20, TrackP2, 1, LineSpacingTwoRows);
- SingDrawLine(NR.Left + 20, TopTwoRows2, NR.Right/2 - 20, TrackP2, 1, LineSpacingTwoRows);
- SingDrawPlayerLine(NR.Left + 20, TopTwoRows2, NR.Width/2 - 50, TrackP2, 1, LineSpacingTwoRows);
-
- SingDrawPlayerBGLine(NR.Right/2 - 20 + NR.Left + 20, TopTwoRows1, NR.Right - 20, TrackP3, 2, LineSpacingTwoRows);
- SingDrawLine(NR.Right/2 - 20 + NR.Left + 20, TopTwoRows1, NR.Right - 20, TrackP3, 2, LineSpacingTwoRows);
- SingDrawPlayerLine(NR.Width/2 - 10 + NR.Left + 20, TopTwoRows1, NR.Width/2 - 30, TrackP3, 2, LineSpacingTwoRows);
-
- SingDrawPlayerBGLine(NR.Right/2 - 20 + NR.Left + 20, TopTwoRows2, NR.Right - 20, TrackP4, 3, LineSpacingTwoRows);
- SingDrawLine(NR.Right/2 - 20 + NR.Left + 20, TopTwoRows2, NR.Right - 20, TrackP4, 3, LineSpacingTwoRows);
- SingDrawPlayerLine(NR.Width/2 - 10 + NR.Left + 20, TopTwoRows2, NR.Width/2 - 30, TrackP4, 3, LineSpacingTwoRows);
- end;
- end;
-
- if (PlayersPlay = 6) then
- begin
- if (Ini.Screens = 1) then
- begin
- // MULTISCREEN
- if (ScreenAct = 1) then
- begin
- // MULTISCREEN - SCREEN 1
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows1, NR.Right - 20, TrackP1, 0, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows1, NR.Right - 20, TrackP1, 0, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows1, NR.Width - 40, TrackP1, 0, LineSpacingThreeRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows2, NR.Right - 20, TrackP2, 1, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows2, NR.Right - 20, TrackP2, 1, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows2, NR.Width - 40, TrackP2, 1, LineSpacingThreeRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows3, NR.Right - 20, TrackP3, 2, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows3, NR.Right - 20, TrackP3, 2, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows3, NR.Width - 40, TrackP3, 2, LineSpacingThreeRows);
- end;
- if (ScreenAct = 2) then
- begin
- // MULTISCREEN - SCREEN 2
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows1, NR.Right - 20, TrackP4, 3, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows1, NR.Right - 20, TrackP4, 3, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows1, NR.Width - 40, TrackP4, 3, LineSpacingThreeRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows2, NR.Right - 20, TrackP5, 4, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows2, NR.Right - 20, TrackP5, 4, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows2, NR.Width - 40, TrackP5, 4, LineSpacingThreeRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows3, NR.Right - 20, TrackP6, 5, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows3, NR.Right - 20, TrackP6, 5, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows3, NR.Width - 40, TrackP6, 5, LineSpacingThreeRows);
- end;
- end
- else
- begin
- // SINGLESCREEN
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows1, NR.Right/2 - 20, TrackP1, 0, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows1, NR.Right/2 - 20, TrackP1, 0, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows1, NR.Width/2 - 50, TrackP1, 0, LineSpacingThreeRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows2, NR.Right/2 - 20, TrackP2, 1, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows2, NR.Right/2 - 20, TrackP2, 1, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows2, NR.Width/2 - 50, TrackP2, 1, LineSpacingThreeRows);
-
- SingDrawPlayerBGLine(NR.Left + 20, TopThreeRows3, NR.Right/2 - 20, TrackP3, 2, LineSpacingThreeRows);
- SingDrawLine(NR.Left + 20, TopThreeRows3, NR.Right/2 - 20, TrackP3, 2, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Left + 20, TopThreeRows3, NR.Width/2 - 50, TrackP3, 2, LineSpacingThreeRows);
-
- SingDrawPlayerBGLine(NR.Right/2 - 20 + NR.Left + 20, TopThreeRows1, NR.Right - 20, TrackP4, 3, LineSpacingThreeRows);
- SingDrawLine(NR.Right/2 - 20 + NR.Left + 20, TopThreeRows1, NR.Right - 20, TrackP4, 3, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Width/2 - 10 + NR.Left + 20, TopThreeRows1, NR.Width/2 - 30, TrackP4, 3, LineSpacingThreeRows);
-
- SingDrawPlayerBGLine(NR.Right/2 - 20 + NR.Left + 20, TopThreeRows2, NR.Right - 20, TrackP5, 4, LineSpacingThreeRows);
- SingDrawLine(NR.Right/2 - 20 + NR.Left + 20, TopThreeRows2, NR.Right - 20, TrackP5, 4, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Width/2 - 10 + NR.Left + 20, TopThreeRows2, NR.Width/2 - 30, TrackP5, 4, LineSpacingThreeRows);
-
- SingDrawPlayerBGLine(NR.Right/2 - 20 + NR.Left + 20, TopThreeRows3, NR.Right - 20, TrackP6, 5, LineSpacingThreeRows);
- SingDrawLine(NR.Right/2 - 20 + NR.Left + 20, TopThreeRows3, NR.Right - 20, TrackP6, 5, LineSpacingThreeRows);
- SingDrawPlayerLine(NR.Width/2 - 10 + NR.Left + 20, TopThreeRows3, NR.Width/2 - 30, TrackP6, 5, LineSpacingThreeRows);
- end;
+ SingDrawPlayerBGLine(LaneLeft, LineTop, LaneRight, TrackIndex, PlayerIndex, LineSpacing);
+ SingDrawLine(LaneLeft, LineTop, LaneRight, TrackIndex, PlayerIndex, LineSpacing);
+ SingDrawPlayerLine(LaneLeft, LineTop, LaneWidth, TrackIndex, PlayerIndex, LineSpacing);
end;
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
@@ -1866,4 +1669,3 @@ procedure SingDrawJukeboxTimeBar();
end;
end.
-
diff --git a/src/base/UGraphicClasses.pas b/src/base/UGraphicClasses.pas
index 1a41faa9f..899dc6fc8 100644
--- a/src/base/UGraphicClasses.pas
+++ b/src/base/UGraphicClasses.pas
@@ -37,6 +37,7 @@ interface
UTexture,
ULog,
UIni,
+ UPlayerLayout,
SDL2;
const
@@ -665,109 +666,42 @@ procedure TEffectManager.SpawnPerfectLineTwinkle();
P, I, Life: cardinal;
Left, Right, Top, Bottom: cardinal;
cScreen, Nstars: integer;
+ ScreenCount: integer;
+ LocalPlayerCount: integer;
+ LocalPlayerIndex: integer;
+ SlotRect: TPlayerSlotRect;
+const
+ NotesAreaLeft = 30;
+ NotesAreaTop = 130;
+ NotesAreaRight = 770;
+ NotesAreaBottom = 465;
begin
-// calculation of coordinates done with hardcoded values like in UDraw.pas
-// might need to be adjusted if drawing of SingScreen is modified
-// coordinates may still be a bit weird and need adjustment
- Left := 30;
- Right := 770;
+ ScreenCount := Ini.Screens + 1;
// spawn effect for every player with a perfect line
for P := 0 to PlayersPlay-1 do
if Player[P].LastSentencePerfect then
begin
- // 3 and 6 players in 1 screen
- if (Ini.Screens = 0) then
- begin
- if (PlayersPlay = 4) then
- begin
- if (P <= 1) then
- begin
- Left := 30;
- Right := 385;
- end
- else
- begin
- Left := 415;
- Right := 770;
- end;
- end;
-
- if (PlayersPlay = 6) then
- begin
- if (P <= 2) then
- begin
- Left := 30;
- Right := 385;
- end
- else
- begin
- Left := 415;
- Right := 770;
- end;
- end;
- end;
-
- // calculate area where notes of this player are drawn
- case PlayersPlay of
- 1: begin
- Bottom := Skin_P2_NotesB+10;
- Top := Bottom-105;
- cScreen := 1;
- end;
- 2,4: begin
- case P of
- 0,2: begin
- Bottom := Skin_P1_NotesB+10;
- Top := Bottom-105;
- end;
- else begin
- Bottom := Skin_P2_NotesB+10;
- Top := Bottom-105;
- end;
- end;
- case P of
- 0,1: cScreen := 1;
- else
- begin
- if (Ini.Screens = 1) then
- cScreen := 2
- else
- cScreen := 1;
- end;
- end;
- end;
- 3,6: begin
- case P of
- 0,3: begin
- Top := 130;
- Bottom := Top+85;
- end;
- 1,4: begin
- Top := 255;
- Bottom := Top+85;
- end;
- 2,5: begin
- Top := 380;
- Bottom := Top+85;
- end;
- end;
- case P of
- 0,1,2: cScreen := 1;
- else
- begin
- if (Ini.Screens = 1) then
- cScreen := 2
- else
- cScreen := 1;
- end;
- end;
- end;
- end;
+ cScreen := GetPlayerScreen(P, PlayersPlay, ScreenCount);
+ LocalPlayerCount := GetScreenPlayerCount(PlayersPlay, ScreenCount, cScreen);
+ LocalPlayerIndex := GetPlayerIndexOnScreen(P, PlayersPlay, ScreenCount);
+ SlotRect := GetPlayerSlotRect(
+ LocalPlayerIndex,
+ LocalPlayerCount,
+ NotesAreaLeft,
+ NotesAreaTop,
+ NotesAreaRight - NotesAreaLeft,
+ NotesAreaBottom - NotesAreaTop
+ );
+
+ Left := SlotRect.X;
+ Right := SlotRect.X + SlotRect.W;
+ Top := SlotRect.Y;
+ Bottom := SlotRect.Y + SlotRect.H;
// spawn Sparkling Stars inside calculated coordinates
Nstars := 80;
- if (Ini.Screens = 0) and (PlayersPlay > 3) then
+ if LocalPlayerCount > 3 then
Nstars := 40;
for I := 0 to Nstars do
@@ -775,12 +709,8 @@ procedure TEffectManager.SpawnPerfectLineTwinkle();
Life := RandomRange(8,16);
Spawn(RandomRange(Left,Right), RandomRange(Top,Bottom), cScreen, Life, 16-Life, -1, PerfectLineTwinkle, P);
- //spawn also on second screen if the amount of players is <=3
- if (Screens = 2) and (PlayersPlay <= 3) then
- Spawn(RandomRange(Left,Right), RandomRange(Top,Bottom), 2, Life, 16-Life, -1, PerfectLineTwinkle, P);
end;
end;
end;
end.
-
diff --git a/src/base/UIni.pas b/src/base/UIni.pas
index 27baafe11..734ff08af 100644
--- a/src/base/UIni.pas
+++ b/src/base/UIni.pas
@@ -77,21 +77,16 @@ TInputDeviceConfig = record
LATENCY_AUTODETECT = -1; // for field Latency
DEFAULT_RESOLUTION = '800x600';
DEFAULT_THEME = 'Modern';
- // TODO: the menu options only go up to 6, but there are internals that still go up to 12
- // IMaxPlayerCount is untouched because lowering (or raising) it causes very strange behaviour, such as:
- // * the game starts in a completely different language than the config specifies
- // * the game crashes randomly
- // 8 and 12 players have never worked at any point in history
- // it all needs refactoring at some point anyway because:
- // * a lot of code works with the _index_ of IPlayers (instead of just the number of actual players)
- // * it should be possible to play with 5 players [without duplicating a lot of code]
- // * there might be a valid usecase for 0 players
- IMaxPlayerCount = 12;
- // Switch colors for players 2 and 4, since player 2 line color is used
- // for the second part in duet, and yellow (4) looks better than red (2)
- DefaultPlayerColors: array[0..IMaxPlayerCount-1] of integer = (1, 4, 3, 2, 5, 6, 7, 8, 9, 10, 11, 12);
- IPlayers: array[0..4] of UTF8String = ('1', '2', '3', '4', '6');
- IPlayersVals: array[0..4] of integer = ( 1 , 2 , 3 , 4 , 6 );
+ IMaxPlayerCount = 24;
+
+type
+ TUTF8StringArray = array of UTF8String;
+ TIntegerArray = array of integer;
+
+function GetNameTemplateIndexFromKey(const Key: cardinal): integer;
+function CreateNumericOptionArray(const FirstValue, LastValue: integer): TUTF8StringArray;
+function GetPlayerColorOptionCount: integer;
+function TryGetMixedPlayerColorPair(ColorIndex: integer; out LeftColor, RightColor: integer): boolean;
type
@@ -124,7 +119,7 @@ TIni = class
// Players or Teams colors
SingColor: array[0..(IMaxPlayerCount-1)] of integer;
- Name: array[0..15] of UTF8String;
+ Name: array[0..(IMaxPlayerCount-1)] of UTF8String;
PlayerColor: array[0..(IMaxPlayerCount-1)] of integer;
TeamColor: array[0..2] of integer;
@@ -461,7 +456,6 @@ TIni = class
IJukeboxTimebarMode: array[0..2] of UTF8String = ('Current', 'Remaining', 'Total');
// Recording options
- IChannelPlayer: array[0..6] of UTF8String = ('Off', '1', '2', '3', '4', '5', '6');
IMicBoost: array[0..3] of UTF8String = ('Off', '+6dB', '+12dB', '+18dB');
// Webcam
@@ -474,6 +468,9 @@ TIni = class
*}
var
+ IPlayers: TUTF8StringArray;
+ IPlayersVals: TIntegerArray;
+ IChannelPlayer: TUTF8StringArray;
ILanguageTranslated: array of UTF8String;
ILyricsFont: array of UTF8String;
@@ -528,7 +525,7 @@ TIni = class
ILyricsEffectTranslated: array[0..4] of UTF8String = ('Simple', 'Zoom', 'Slide', 'Ball', 'Shift');
INoteLinesTranslated: array[0..1] of UTF8String = ('Off', 'On');
IColorTranslated: array[0..8] of UTF8String = ('Blue', 'Green', 'Pink', 'Red', 'Violet', 'Orange', 'Yellow', 'Brown', 'Black');
- IPlayerColorTranslated: array[0..15] of UTF8String = ('Blue', 'Red', 'Green', 'Yellow', 'Orange', 'Pink', 'Violet', 'Brown', 'Gray', 'Dark Blue', 'Sky', 'Cyan', 'Flame', 'Orchid', 'Harlequin', 'Lime');
+ IPlayerColorTranslated: TUTF8StringArray;
// for lyric colors
ILineTranslated: array[0..2] of UTF8String = ('Sing', 'Actual', 'Next');
@@ -559,13 +556,13 @@ TIni = class
IJukeboxTimebarModeTranslated: array[0..2] of UTF8String = ('Current', 'Remaining', 'Total');
// Recording options
- IChannelPlayerTranslated: array[0..IMaxPlayerCount] of UTF8String = ('Off', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12');
+ IChannelPlayerTranslated: TUTF8StringArray;
IMicBoostTranslated: array[0..3] of UTF8String = ('Off', '+6dB', '+12dB', '+18dB');
// Network
ISendNameTranslated: array[0..1] of UTF8String = ('Off', 'On');
IAutoModeTranslated: array[0..2] of UTF8String = ('Off', 'Send', 'Guardar');
- IAutoPlayerTranslated: array[0..IMaxPlayerCount] of UTF8String = ('Player 1', 'Player 2', 'Player 3', 'Player 4', 'Player 5', 'Player 6', 'Player 7', 'Player 8', 'Player 9', 'Player 10', 'Player 11', 'Player 12', 'All');
+ IAutoPlayerTranslated: TUTF8StringArray;
IAutoScoreEasyTranslated: array of UTF8String;
IAutoScoreMediumTranslated: array of UTF8String;
IAutoScoreHardTranslated: array of UTF8String;
@@ -578,7 +575,7 @@ TIni = class
IWebcamEffectTranslated: array [0..10] of UTF8String;
// Name
- IPlayerTranslated: array[0..(IMaxPlayerCount-1)] of UTF8String = ('Player 1', 'Player 2', 'Player 3', 'Player 4', 'Player 5', 'Player 6', 'Player 7', 'Player 8', 'Player 9', 'Player 10', 'Player 11', 'Player 12');
+ IPlayerTranslated: TUTF8StringArray;
IRed: array[0..255] of UTF8String;
IGreen: array[0..255] of UTF8String;
@@ -616,6 +613,160 @@ TSafeIniFile = class(TIniFile)
const
IGNORE_INDEX = -1;
+ BASE_PLAYER_COLOR_COUNT = 16;
+
+ PLAYER_COLOR_DEFAULTS: array[0..15] of UTF8String = (
+ 'Blue', 'Red', 'Green', 'Yellow', 'Orange', 'Pink', 'Violet', 'Brown',
+ 'Gray', 'Dark Blue', 'Sky', 'Cyan', 'Flame', 'Orchid', 'Harlequin', 'Lime'
+ );
+
+ PLAYER_COLOR_TRANSLATION_KEYS: array[0..15] of UTF8String = (
+ 'OPTION_VALUE_BLUE', 'OPTION_VALUE_RED', 'OPTION_VALUE_GREEN',
+ 'OPTION_VALUE_YELLOW', 'OPTION_VALUE_ORANGE', 'OPTION_VALUE_PINK',
+ 'OPTION_VALUE_VIOLET', 'OPTION_VALUE_BROWN', 'OPTION_VALUE_GRAY',
+ 'OPTION_VALUE_DARKBLUE', 'OPTION_VALUE_SKY', 'OPTION_VALUE_CYAN',
+ 'OPTION_VALUE_FLAME', 'OPTION_VALUE_ORCHID', 'OPTION_VALUE_HARLEQUIN',
+ 'OPTION_VALUE_GREENYELLOW'
+ );
+
+function GetNameTemplateIndexFromKey(const Key: cardinal): integer;
+begin
+ case Key of
+ SDLK_F1: Result := 0;
+ SDLK_F2: Result := 1;
+ SDLK_F3: Result := 2;
+ SDLK_F4: Result := 3;
+ SDLK_F5: Result := 4;
+ SDLK_F6: Result := 5;
+ SDLK_F7: Result := 6;
+ SDLK_F8: Result := 7;
+ SDLK_F9: Result := 8;
+ SDLK_F10: Result := 9;
+ SDLK_F11: Result := 10;
+ SDLK_F12: Result := 11;
+ else
+ Result := -1;
+ end;
+end;
+
+function CreateNumericOptionArray(const FirstValue, LastValue: integer): TUTF8StringArray;
+var
+ I: integer;
+begin
+ if LastValue < FirstValue then
+ begin
+ SetLength(Result, 0);
+ Exit;
+ end;
+
+ SetLength(Result, LastValue - FirstValue + 1);
+ for I := 0 to High(Result) do
+ Result[I] := IntToStr(FirstValue + I);
+end;
+
+function GetPlayerColorOptionCount: integer;
+begin
+ Result := (IMaxPlayerCount * 3 + 1) div 2;
+ if Result < BASE_PLAYER_COLOR_COUNT then
+ Result := BASE_PLAYER_COLOR_COUNT;
+end;
+
+function TryGetMixedPlayerColorPair(ColorIndex: integer; out LeftColor, RightColor: integer): boolean;
+var
+ Remaining: integer;
+ Sum: integer;
+ LeftCandidate: integer;
+ RightCandidate: integer;
+begin
+ Result := false;
+ LeftColor := 0;
+ RightColor := 0;
+
+ if ColorIndex <= BASE_PLAYER_COLOR_COUNT then
+ Exit;
+
+ Remaining := ColorIndex - BASE_PLAYER_COLOR_COUNT;
+ for Sum := BASE_PLAYER_COLOR_COUNT + 1 to BASE_PLAYER_COLOR_COUNT * 2 - 1 do
+ begin
+ LeftCandidate := Sum - BASE_PLAYER_COLOR_COUNT;
+ if LeftCandidate < 1 then
+ LeftCandidate := 1;
+ while LeftCandidate <= ((Sum - 1) div 2) do
+ begin
+ RightCandidate := Sum - LeftCandidate;
+ if LeftCandidate >= RightCandidate then
+ begin
+ Inc(LeftCandidate);
+ Continue;
+ end;
+
+ Dec(Remaining);
+ if Remaining = 0 then
+ begin
+ LeftColor := LeftCandidate;
+ RightColor := RightCandidate;
+ Result := true;
+ Exit;
+ end;
+
+ Inc(LeftCandidate);
+ end;
+ end;
+end;
+
+function GetDefaultPlayerColor(PlayerIndex: integer): integer;
+begin
+ if Length(IPlayerColorTranslated) = 0 then
+ Exit(0);
+
+ Result := (PlayerIndex mod Length(IPlayerColorTranslated)) + 1;
+end;
+
+procedure InitializePlayerOptionArrays;
+var
+ I: integer;
+ LeftColor: integer;
+ RightColor: integer;
+begin
+ SetLength(IPlayerColorTranslated, GetPlayerColorOptionCount);
+ for I := 0 to High(IPlayerColorTranslated) do
+ begin
+ if I < Length(PLAYER_COLOR_DEFAULTS) then
+ IPlayerColorTranslated[I] := PLAYER_COLOR_DEFAULTS[I]
+ else if TryGetMixedPlayerColorPair(I + 1, LeftColor, RightColor) then
+ IPlayerColorTranslated[I] := PLAYER_COLOR_DEFAULTS[LeftColor - 1] + ' + ' + PLAYER_COLOR_DEFAULTS[RightColor - 1]
+ else
+ IPlayerColorTranslated[I] := PLAYER_COLOR_DEFAULTS[I mod Length(PLAYER_COLOR_DEFAULTS)];
+ end;
+
+ SetLength(IPlayers, IMaxPlayerCount);
+ SetLength(IPlayersVals, IMaxPlayerCount);
+ for I := 0 to IMaxPlayerCount - 1 do
+ begin
+ IPlayers[I] := IntToStr(I + 1);
+ IPlayersVals[I] := I + 1;
+ end;
+
+ SetLength(IChannelPlayer, IMaxPlayerCount + 1);
+ IChannelPlayer[0] := 'Off';
+ for I := 1 to IMaxPlayerCount do
+ IChannelPlayer[I] := IntToStr(I);
+
+ SetLength(IChannelPlayerTranslated, IMaxPlayerCount + 1);
+ SetLength(IAutoPlayerTranslated, IMaxPlayerCount + 1);
+ SetLength(IPlayerTranslated, IMaxPlayerCount);
+
+ IChannelPlayerTranslated[0] := 'Off';
+ for I := 1 to IMaxPlayerCount do
+ IChannelPlayerTranslated[I] := IntToStr(I);
+
+ for I := 0 to IMaxPlayerCount - 1 do
+ IPlayerTranslated[I] := 'Player ' + IntToStr(I + 1);
+
+ for I := 0 to IMaxPlayerCount - 1 do
+ IAutoPlayerTranslated[I] := 'Player ' + IntToStr(I + 1);
+ IAutoPlayerTranslated[IMaxPlayerCount] := 'All';
+end;
constructor TSafeIniFile.Create(const FileName, LogSource: string);
begin
@@ -666,7 +817,12 @@ procedure TIni.TranslateOptionValues;
var
I: integer;
Zeros: string;
+ BasePlayerColorNames: array[0..BASE_PLAYER_COLOR_COUNT-1] of UTF8String;
+ LeftColor: integer;
+ RightColor: integer;
begin
+ InitializePlayerOptionArrays;
+
// Load language file, fallback to config language if param is invalid
if (Params.Language > -1) and (Params.Language < Length(ILanguage)) then
ULanguage.Language.ChangeLanguage(ILanguage[Params.Language])
@@ -846,22 +1002,18 @@ procedure TIni.TranslateOptionValues;
IColorTranslated[7] := ULanguage.Language.Translate('OPTION_VALUE_BROWN');
IColorTranslated[8] := ULanguage.Language.Translate('OPTION_VALUE_BLACK');
- IPlayerColorTranslated[0] := ULanguage.Language.Translate('OPTION_VALUE_BLUE');
- IPlayerColorTranslated[1] := ULanguage.Language.Translate('OPTION_VALUE_RED');
- IPlayerColorTranslated[2] := ULanguage.Language.Translate('OPTION_VALUE_GREEN');
- IPlayerColorTranslated[3] := ULanguage.Language.Translate('OPTION_VALUE_YELLOW');
- IPlayerColorTranslated[4] := ULanguage.Language.Translate('OPTION_VALUE_ORANGE');
- IPlayerColorTranslated[5] := ULanguage.Language.Translate('OPTION_VALUE_PINK');
- IPlayerColorTranslated[6] := ULanguage.Language.Translate('OPTION_VALUE_VIOLET');
- IPlayerColorTranslated[7] := ULanguage.Language.Translate('OPTION_VALUE_BROWN');
- IPlayerColorTranslated[8] := ULanguage.Language.Translate('OPTION_VALUE_GRAY');
- IPlayerColorTranslated[9] := ULanguage.Language.Translate('OPTION_VALUE_DARKBLUE');
- IPlayerColorTranslated[10] := ULanguage.Language.Translate('OPTION_VALUE_SKY');
- IPlayerColorTranslated[11] := ULanguage.Language.Translate('OPTION_VALUE_CYAN');
- IPlayerColorTranslated[12] := ULanguage.Language.Translate('OPTION_VALUE_FLAME');
- IPlayerColorTranslated[13] := ULanguage.Language.Translate('OPTION_VALUE_ORCHID');
- IPlayerColorTranslated[14] := ULanguage.Language.Translate('OPTION_VALUE_HARLEQUIN');
- IPlayerColorTranslated[15] := ULanguage.Language.Translate('OPTION_VALUE_GREENYELLOW');
+ for I := 0 to High(BasePlayerColorNames) do
+ BasePlayerColorNames[I] := ULanguage.Language.Translate(PLAYER_COLOR_TRANSLATION_KEYS[I]);
+
+ for I := 0 to High(IPlayerColorTranslated) do
+ begin
+ if I < Length(BasePlayerColorNames) then
+ IPlayerColorTranslated[I] := BasePlayerColorNames[I]
+ else if TryGetMixedPlayerColorPair(I + 1, LeftColor, RightColor) then
+ IPlayerColorTranslated[I] := BasePlayerColorNames[LeftColor - 1] + ' + ' + BasePlayerColorNames[RightColor - 1]
+ else
+ IPlayerColorTranslated[I] := BasePlayerColorNames[I mod Length(BasePlayerColorNames)];
+ end;
// Advanced
ILoadAnimationTranslated[0] := ULanguage.Language.Translate('OPTION_VALUE_OFF');
@@ -973,9 +1125,12 @@ procedure TIni.TranslateOptionValues;
for I:=0 to IMaxPlayerCount-1 do
begin
- IAutoPlayerTranslated[I] :=ULanguage.Language.Translate('OPTION_PLAYER_' + IntToStr(I));
+ IAutoPlayerTranslated[I] := ULanguage.Language.Translate('OPTION_PLAYER_' + IntToStr(I + 1));
end;
- IAutoPlayerTranslated[12] := ULanguage.Language.Translate('OPTION_ALL_PLAYERS');
+ IAutoPlayerTranslated[IMaxPlayerCount] := ULanguage.Language.Translate('OPTION_ALL_PLAYERS');
+
+ for I := 0 to IMaxPlayerCount - 1 do
+ IPlayerTranslated[I] := ULanguage.Language.Translate('OPTION_PLAYER_' + IntToStr(I + 1));
// Webcam
IWebcamFlipTranslated[0] := ULanguage.Language.Translate('OPTION_VALUE_OFF');
@@ -1499,6 +1654,7 @@ procedure TIni.Load();
Result := 100;
end;
begin
+ InitializePlayerOptionArrays;
LoadFontFamilyNames;
ILyricsFont := FontFamilyNames;
GamePath := Platform.GetGameUserPath;
@@ -1513,12 +1669,12 @@ procedure TIni.Load();
Log.LogStatus('Using config : ' + FileName.ToNative, 'Ini');
IniFile := TMemIniFile.Create(FileName.ToNative);
- for I := 0 to IMaxPlayerCount-1 do
+ for I := 0 to High(Name) do
begin
// Name
Name[I] := IniFile.ReadString('Name', 'P'+IntToStr(I+1), 'Player'+IntToStr(I+1));
// Color Player
- PlayerColor[I] := IniFile.ReadInteger('PlayerColor', 'P'+IntToStr(I+1), DefaultPlayerColors[I]);
+ PlayerColor[I] := IniFile.ReadInteger('PlayerColor', 'P'+IntToStr(I+1), GetDefaultPlayerColor(I));
// Initialize session sing colors from the saved player colors so they are usable before the first song
SingColor[I] := PlayerColor[I];
// Avatar Player
@@ -1534,7 +1690,7 @@ procedure TIni.Load();
// Templates for Names Mod
for I := 0 to 2 do
NameTeam[I] := IniFile.ReadString('NameTeam', 'T'+IntToStr(I+1), 'Team'+IntToStr(I+1));
- for I := 0 to 11 do
+ for I := 0 to High(NameTemplate) do
NameTemplate[I] := IniFile.ReadString('NameTemplate', 'Name'+IntToStr(I+1), 'Template'+IntToStr(I+1));
// Players
diff --git a/src/base/UPlayerLayout.pas b/src/base/UPlayerLayout.pas
new file mode 100644
index 000000000..adab48469
--- /dev/null
+++ b/src/base/UPlayerLayout.pas
@@ -0,0 +1,515 @@
+{*
+ * Shared player-count layout helpers.
+ *}
+
+unit UPlayerLayout;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+uses
+ Math;
+
+type
+ TPlayerGrid = record
+ Cols: integer;
+ Rows: integer;
+ end;
+
+ TPlayerSlotRect = record
+ X: integer;
+ Y: integer;
+ W: integer;
+ H: integer;
+ end;
+
+ TSingPlayerLayoutConfig = record
+ ColumnContainerLeft: integer;
+ ColumnContainerTopReserved: integer;
+ ColumnContainerTopNoLyrics: integer;
+ ColumnContainerWidth: integer;
+ LaneHeightReserved: integer;
+ LaneHeightNoLyrics: integer;
+ ColumnGap: integer;
+ RowGap: integer;
+ GridExtraLeft: integer;
+ BaseLineSpacing: integer;
+ GuideLineCount: integer;
+ RowAnchorGuideIndex: integer;
+ WidgetScaleBaseWidth: integer;
+ WidgetScalePerPlayer: real;
+ WidgetScaleMin: real;
+ end;
+
+ TSingLaneLayout = record
+ GridCols: integer;
+ GridRows: integer;
+ ColumnLeft: integer;
+ ColumnRight: integer;
+ ColumnWidth: integer;
+ GridLeft: integer;
+ GridRight: integer;
+ GridWidth: integer;
+ RowAnchorY: integer;
+ GuideTopY: integer;
+ NoteLineSpacing: integer;
+ SlotScale: real;
+ ContentScale: real;
+ WidgetScale: real;
+ end;
+
+function GetPlayerGrid(PlayerCount: integer; Flip: boolean = false): TPlayerGrid;
+function GetPlayerGridForArea(PlayerCount, AreaW, AreaH: integer; SmallCountWide: boolean): TPlayerGrid;
+function GetScorePlayerGrid(PlayerCount, AreaW, AreaH, ExtraColsBias: integer): TPlayerGrid;
+function GetSingPlayerGrid(PlayerCountOnScreen: integer; const Config: TSingPlayerLayoutConfig;
+ ReserveTopLyricsSpace: boolean = true): TPlayerGrid;
+procedure GetPlayerColumnLayout(ColIndex, ColCount, ContainerLeft, ContainerWidth, ColumnGap: integer;
+ out LaneLeft, LaneRight, LaneWidth: integer);
+function GetPlayerWidgetScale(PlayerCount: integer; const Config: TSingPlayerLayoutConfig): real;
+function GetSingLaneLayout(PlayerCountOnScreen, PlayerIndexOnScreen: integer;
+ const Config: TSingPlayerLayoutConfig; ReserveTopLyricsSpace: boolean = true): TSingLaneLayout;
+function GetScreenPlayerCount(PlayerCount, ScreenCount, ScreenIndex: integer): integer;
+function GetFirstPlayerIndexForScreen(PlayerCount, ScreenCount, ScreenIndex: integer): integer;
+function GetPlayerScreen(PlayerIndex, PlayerCount, ScreenCount: integer): integer;
+function GetPlayerIndexOnScreen(PlayerIndex, PlayerCount, ScreenCount: integer): integer;
+function GetPlayerSlotRect(PlayerIndexOnScreen, PlayerCountOnScreen: integer;
+ ContainerX, ContainerY, ContainerW, ContainerH: integer; Flip: boolean = false): TPlayerSlotRect; overload;
+function GetPlayerSlotRect(PlayerIndexOnScreen: integer; const Grid: TPlayerGrid;
+ ContainerX, ContainerY, ContainerW, ContainerH: integer): TPlayerSlotRect; overload;
+function GetScaledGridLayoutBounds(const BaseBounds, AreaBounds: TPlayerSlotRect;
+ const Grid: TPlayerGrid): TPlayerSlotRect; overload;
+function GetScaledGridLayoutBounds(const BaseBounds, AreaBounds: TPlayerSlotRect;
+ PlayerCount: integer; Wide: boolean): TPlayerSlotRect; overload;
+function ScaleCoordToSlot(const Value, SourceStart, SourceSize, TargetStart, TargetSize: integer): integer;
+function ScaleLengthToSlot(const Value, SourceSize, TargetSize: integer): integer;
+function GetFittedSlotRect(const SourceBounds, SlotRect: TPlayerSlotRect; MaxScale: real): TPlayerSlotRect;
+
+implementation
+
+function GetGridAspectScore(const Grid: TPlayerGrid; AreaW, AreaH: integer): real;
+var
+ AreaAspect: real;
+ GridAspect: real;
+begin
+ if (Grid.Cols <= 0) or (Grid.Rows <= 0) or (AreaW <= 0) or (AreaH <= 0) then
+ Exit(0);
+
+ AreaAspect := AreaW / Max(1.0, AreaH);
+ GridAspect := Grid.Cols / Max(1.0, Grid.Rows);
+ Result := Min(AreaAspect, GridAspect) / Max(AreaAspect, GridAspect);
+end;
+
+function GetGridSlotSquareScore(const Grid: TPlayerGrid; AreaW, AreaH: integer): real;
+var
+ SlotAspect: real;
+begin
+ if (Grid.Cols <= 0) or (Grid.Rows <= 0) or (AreaW <= 0) or (AreaH <= 0) then
+ Exit(0);
+
+ SlotAspect := (AreaW / Max(1.0, Grid.Cols)) / (AreaH / Max(1.0, Grid.Rows));
+ Result := Min(SlotAspect, 1.0 / Max(0.0001, SlotAspect));
+end;
+
+function GetGridSlotMinSize(const Grid: TPlayerGrid; AreaW, AreaH: integer): real;
+begin
+ if (Grid.Cols <= 0) or (Grid.Rows <= 0) or (AreaW <= 0) or (AreaH <= 0) then
+ Exit(0);
+
+ Result := Min(AreaW / Max(1.0, Grid.Cols), AreaH / Max(1.0, Grid.Rows));
+end;
+
+function GetGridUnusedSlots(const Grid: TPlayerGrid; PlayerCount: integer): integer;
+begin
+ Result := Max(0, Grid.Cols * Grid.Rows - PlayerCount);
+end;
+
+function GetPlayerGrid(PlayerCount: integer; Flip: boolean = false): TPlayerGrid;
+var
+ temp: integer;
+begin
+ if PlayerCount <= 3 then
+ begin
+ Result.Cols := PlayerCount;
+ Result.Rows := 1;
+ end
+ else
+ begin
+ Result.Rows := Trunc(Ceil(Sqrt(PlayerCount)));
+ Result.Cols := Trunc(Ceil(PlayerCount / Result.Rows));
+ end;
+ if Flip then
+ begin
+ temp := Result.Cols;
+ Result.Cols := Result.Rows;
+ Result.Rows := temp;
+ end;
+end;
+
+function GetPlayerGridForArea(PlayerCount, AreaW, AreaH: integer; SmallCountWide: boolean): TPlayerGrid;
+var
+ TallGrid: TPlayerGrid;
+ WideGrid: TPlayerGrid;
+begin
+ if PlayerCount <= 3 then
+ begin
+ if SmallCountWide then
+ begin
+ Result.Cols := PlayerCount;
+ Result.Rows := 1;
+ end
+ else
+ begin
+ Result.Cols := 1;
+ Result.Rows := PlayerCount;
+ end;
+ end
+ else
+ begin
+ TallGrid := GetPlayerGrid(PlayerCount, false);
+ WideGrid := GetPlayerGrid(PlayerCount, true);
+
+ if GetGridAspectScore(WideGrid, AreaW, AreaH) >= GetGridAspectScore(TallGrid, AreaW, AreaH) then
+ Result := WideGrid
+ else
+ Result := TallGrid;
+ end;
+end;
+
+function GetScorePlayerGrid(PlayerCount, AreaW, AreaH, ExtraColsBias: integer): TPlayerGrid;
+var
+ BiasedGrid: TPlayerGrid;
+ BaseSquareScore: real;
+ BiasedSquareScore: real;
+ BaseMinSize: real;
+ BiasedMinSize: real;
+ BaseUnusedSlots: integer;
+ BiasedUnusedSlots: integer;
+begin
+ Result := GetPlayerGridForArea(PlayerCount, AreaW, AreaH, true);
+
+ if (PlayerCount <= 3) or (ExtraColsBias <= 0) then
+ Exit;
+
+ BiasedGrid := Result;
+ BiasedGrid.Cols := Min(PlayerCount, Result.Cols + ExtraColsBias);
+ BiasedGrid.Rows := Trunc(Ceil(PlayerCount / Max(1.0, BiasedGrid.Cols)));
+
+ if (BiasedGrid.Cols = Result.Cols) and (BiasedGrid.Rows = Result.Rows) then
+ Exit;
+
+ BaseSquareScore := GetGridSlotSquareScore(Result, AreaW, AreaH);
+ BiasedSquareScore := GetGridSlotSquareScore(BiasedGrid, AreaW, AreaH);
+ BaseMinSize := GetGridSlotMinSize(Result, AreaW, AreaH);
+ BiasedMinSize := GetGridSlotMinSize(BiasedGrid, AreaW, AreaH);
+ BaseUnusedSlots := GetGridUnusedSlots(Result, PlayerCount);
+ BiasedUnusedSlots := GetGridUnusedSlots(BiasedGrid, PlayerCount);
+
+ if ((BiasedSquareScore > BaseSquareScore) and (BiasedUnusedSlots <= BaseUnusedSlots + 1)) or
+ ((BiasedUnusedSlots < BaseUnusedSlots) and (BiasedMinSize > BaseMinSize) and
+ (BiasedSquareScore >= BaseSquareScore - 0.05)) then
+ Result := BiasedGrid;
+end;
+
+function GetSingPlayerGrid(PlayerCountOnScreen: integer; const Config: TSingPlayerLayoutConfig;
+ ReserveTopLyricsSpace: boolean = true): TPlayerGrid;
+var
+ BaseGrid: TPlayerGrid;
+ TallGrid: TPlayerGrid;
+ LayoutHeight: integer;
+begin
+ if ReserveTopLyricsSpace then
+ LayoutHeight := Max(1, Config.LaneHeightReserved)
+ else
+ LayoutHeight := Max(1, Config.LaneHeightNoLyrics);
+
+ BaseGrid := GetPlayerGridForArea(PlayerCountOnScreen, Config.ColumnContainerWidth, LayoutHeight, false);
+
+ if (not ReserveTopLyricsSpace) and (PlayerCountOnScreen > 3) then
+ begin
+ TallGrid := GetPlayerGrid(PlayerCountOnScreen, false);
+ if (TallGrid.Rows > BaseGrid.Rows) then
+ Result := TallGrid
+ else
+ Result := BaseGrid;
+ end
+ else
+ Result := BaseGrid;
+end;
+
+procedure GetPlayerColumnLayout(ColIndex, ColCount, ContainerLeft, ContainerWidth, ColumnGap: integer;
+ out LaneLeft, LaneRight, LaneWidth: integer);
+var
+ ColumnWidth: integer;
+begin
+ LaneLeft := ContainerLeft;
+ LaneWidth := ContainerWidth;
+ LaneRight := ContainerLeft + ContainerWidth;
+
+ if ColCount <= 1 then
+ Exit;
+
+ ColumnWidth := Round((ContainerWidth - (ColumnGap * (ColCount - 1))) / ColCount);
+ LaneLeft := ContainerLeft + ColIndex * (ColumnWidth + ColumnGap);
+ LaneWidth := ColumnWidth;
+ LaneRight := LaneLeft + ColumnWidth;
+end;
+
+function GetPlayerWidgetScale(PlayerCount: integer; const Config: TSingPlayerLayoutConfig): real;
+begin
+ Result := 1.0 - Max(0, PlayerCount - 1) * Config.WidgetScalePerPlayer;
+ if Result < Config.WidgetScaleMin then
+ Result := Config.WidgetScaleMin;
+end;
+
+function GetSingLaneLayout(PlayerCountOnScreen, PlayerIndexOnScreen: integer;
+ const Config: TSingPlayerLayoutConfig; ReserveTopLyricsSpace: boolean = true): TSingLaneLayout;
+var
+ Grid: TPlayerGrid;
+ ColIndex: integer;
+ RowIndex: integer;
+ AreaTop: integer;
+ AreaHeight: integer;
+ RowGap: integer;
+ SlotTopY: integer;
+ SlotBottomY: integer;
+ SlotHeight: integer;
+ TopPadding: integer;
+ MaxLineSpacing: integer;
+ GuideLineCount: integer;
+ RowAnchorGuideIndex: integer;
+ ColumnScale: real;
+ AvailableRowScale: real;
+ BaseLineSpacing: integer;
+ GridInsetX: integer;
+begin
+ Grid := GetSingPlayerGrid(PlayerCountOnScreen, Config, ReserveTopLyricsSpace);
+ Result.GridCols := Grid.Cols;
+ Result.GridRows := Grid.Rows;
+ ColIndex := PlayerIndexOnScreen div Grid.Rows;
+ RowIndex := PlayerIndexOnScreen mod Grid.Rows;
+
+ if ReserveTopLyricsSpace then
+ begin
+ AreaTop := Config.ColumnContainerTopReserved;
+ AreaHeight := Max(1, Config.LaneHeightReserved)
+ end
+ else
+ begin
+ AreaTop := Config.ColumnContainerTopNoLyrics;
+ AreaHeight := Max(1, Config.LaneHeightNoLyrics);
+ end;
+ RowGap := Max(0, Config.RowGap);
+ if Grid.Rows > 1 then
+ SlotTopY := AreaTop + RowIndex * RowGap +
+ Round(RowIndex * Max(1.0, AreaHeight - RowGap * (Grid.Rows - 1)) / Grid.Rows)
+ else
+ SlotTopY := AreaTop;
+ if Grid.Rows > 1 then
+ SlotBottomY := AreaTop + RowIndex * RowGap +
+ Round((RowIndex + 1) * Max(1.0, AreaHeight - RowGap * (Grid.Rows - 1)) / Grid.Rows)
+ else
+ SlotBottomY := AreaTop + AreaHeight;
+ SlotHeight := Max(1, SlotBottomY - SlotTopY);
+
+ GetPlayerColumnLayout(ColIndex, Grid.Cols, Config.ColumnContainerLeft, Config.ColumnContainerWidth,
+ Max(0, Config.ColumnGap), Result.ColumnLeft, Result.ColumnRight, Result.ColumnWidth);
+ GuideLineCount := Max(2, Config.GuideLineCount);
+ RowAnchorGuideIndex := EnsureRange(Config.RowAnchorGuideIndex, 0, GuideLineCount - 1);
+ BaseLineSpacing := Max(1, Config.BaseLineSpacing);
+ ColumnScale := Result.ColumnWidth / Max(1.0, Config.WidgetScaleBaseWidth);
+ MaxLineSpacing := Max(6, SlotHeight div GuideLineCount);
+ AvailableRowScale := MaxLineSpacing / Max(1.0, BaseLineSpacing);
+ Result.SlotScale := Min(1.0, Min(ColumnScale, AvailableRowScale));
+ Result.ContentScale := Result.SlotScale * GetPlayerWidgetScale(PlayerCountOnScreen, Config);
+ Result.NoteLineSpacing := Max(6, Min(MaxLineSpacing, Round(BaseLineSpacing * Result.ContentScale)));
+ TopPadding := Max(0, SlotHeight - GuideLineCount * Result.NoteLineSpacing);
+ Result.GuideTopY := SlotTopY + (TopPadding div 2);
+ Result.RowAnchorY := Result.GuideTopY + RowAnchorGuideIndex * Result.NoteLineSpacing;
+ GridInsetX := Max(1, Round(Config.GridExtraLeft * Result.ContentScale));
+ Result.GridLeft := Result.ColumnLeft - GridInsetX;
+ Result.GridRight := Result.ColumnRight;
+ Result.GridWidth := Result.GridRight - Result.GridLeft;
+ Result.WidgetScale := Result.ContentScale;
+end;
+
+function GetScreenPlayerCount(PlayerCount, ScreenCount, ScreenIndex: integer): integer;
+var
+ BaseCount: integer;
+ Remainder: integer;
+begin
+ if (PlayerCount <= 0) or (ScreenCount <= 0) or (ScreenIndex <= 0) or (ScreenIndex > ScreenCount) then
+ Exit(0);
+
+ BaseCount := PlayerCount div ScreenCount;
+ Remainder := PlayerCount mod ScreenCount;
+
+ Result := BaseCount;
+ if ScreenIndex <= Remainder then
+ Inc(Result);
+end;
+
+function GetFirstPlayerIndexForScreen(PlayerCount, ScreenCount, ScreenIndex: integer): integer;
+var
+ CurrentScreen: integer;
+begin
+ if (PlayerCount <= 0) or (ScreenCount <= 0) or (ScreenIndex <= 0) or (ScreenIndex > ScreenCount) then
+ Exit(0);
+
+ Result := 0;
+ for CurrentScreen := 1 to ScreenIndex - 1 do
+ Inc(Result, GetScreenPlayerCount(PlayerCount, ScreenCount, CurrentScreen));
+end;
+
+function GetPlayerScreen(PlayerIndex, PlayerCount, ScreenCount: integer): integer;
+var
+ CurrentScreen: integer;
+ RemainingPlayers: integer;
+ PlayersOnScreen: integer;
+begin
+ if (PlayerIndex < 0) or (PlayerIndex >= PlayerCount) or (ScreenCount <= 0) then
+ Exit(0);
+
+ RemainingPlayers := PlayerIndex;
+ for CurrentScreen := 1 to ScreenCount do
+ begin
+ PlayersOnScreen := GetScreenPlayerCount(PlayerCount, ScreenCount, CurrentScreen);
+ if RemainingPlayers < PlayersOnScreen then
+ Exit(CurrentScreen);
+ Dec(RemainingPlayers, PlayersOnScreen);
+ end;
+
+ Result := 0;
+end;
+
+function GetPlayerIndexOnScreen(PlayerIndex, PlayerCount, ScreenCount: integer): integer;
+var
+ CurrentScreen: integer;
+ TargetScreen: integer;
+begin
+ Result := PlayerIndex;
+ TargetScreen := GetPlayerScreen(PlayerIndex, PlayerCount, ScreenCount);
+
+ for CurrentScreen := 1 to TargetScreen - 1 do
+ Dec(Result, GetScreenPlayerCount(PlayerCount, ScreenCount, CurrentScreen));
+end;
+
+function GetPlayerSlotRect(PlayerIndexOnScreen, PlayerCountOnScreen: integer;
+ ContainerX, ContainerY, ContainerW, ContainerH: integer; Flip: boolean = false): TPlayerSlotRect;
+var
+ Grid: TPlayerGrid;
+begin
+ Grid := GetPlayerGrid(PlayerCountOnScreen, Flip);
+ Result := GetPlayerSlotRect(PlayerIndexOnScreen, Grid, ContainerX, ContainerY, ContainerW, ContainerH);
+end;
+
+function GetPlayerSlotRect(PlayerIndexOnScreen: integer; const Grid: TPlayerGrid;
+ ContainerX, ContainerY, ContainerW, ContainerH: integer): TPlayerSlotRect;
+var
+ ColIndex: integer;
+ RowIndex: integer;
+ ColWidth: integer;
+ RowHeight: integer;
+begin
+ if (PlayerIndexOnScreen < 0) or (PlayerIndexOnScreen >= Grid.Cols * Grid.Rows) or
+ (ContainerW <= 0) or (ContainerH <= 0) then
+ begin
+ Result.X := ContainerX;
+ Result.Y := ContainerY;
+ Result.W := 0;
+ Result.H := 0;
+ Exit;
+ end;
+
+ if (Grid.Cols <= 0) or (Grid.Rows <= 0) then
+ begin
+ Result.X := ContainerX;
+ Result.Y := ContainerY;
+ Result.W := 0;
+ Result.H := 0;
+ Exit;
+ end;
+
+ ColIndex := PlayerIndexOnScreen div Grid.Rows;
+ RowIndex := PlayerIndexOnScreen mod Grid.Rows;
+ ColWidth := ContainerW div Grid.Cols;
+ RowHeight := ContainerH div Grid.Rows;
+
+ Result.X := ContainerX + (ColIndex * ColWidth);
+ Result.Y := ContainerY + (RowIndex * RowHeight);
+
+ if ColIndex = Grid.Cols - 1 then
+ Result.W := ContainerX + ContainerW - Result.X
+ else
+ Result.W := ColWidth;
+
+ if RowIndex = Grid.Rows - 1 then
+ Result.H := ContainerY + ContainerH - Result.Y
+ else
+ Result.H := RowHeight;
+end;
+
+function GetScaledGridLayoutBounds(const BaseBounds, AreaBounds: TPlayerSlotRect;
+ const Grid: TPlayerGrid): TPlayerSlotRect;
+var
+ Scale: real;
+ ScaleX: real;
+ ScaleY: real;
+begin
+ if (Grid.Cols <= 0) or (Grid.Rows <= 0) or (BaseBounds.W <= 0) or (BaseBounds.H <= 0) then
+ Exit(BaseBounds);
+
+ ScaleX := AreaBounds.W / Max(1.0, BaseBounds.W * Grid.Cols);
+ ScaleY := AreaBounds.H / Max(1.0, BaseBounds.H * Grid.Rows);
+ Scale := Min(1.0, Min(ScaleX, ScaleY));
+
+ Result.W := Round(BaseBounds.W * Grid.Cols * Scale);
+ Result.H := Round(BaseBounds.H * Grid.Rows * Scale);
+ Result.X := AreaBounds.X + Max(0, (AreaBounds.W - Result.W) div 2);
+ Result.Y := AreaBounds.Y + Max(0, (AreaBounds.H - Result.H) div 2);
+end;
+
+function GetScaledGridLayoutBounds(const BaseBounds, AreaBounds: TPlayerSlotRect;
+ PlayerCount: integer; Wide: boolean): TPlayerSlotRect;
+var
+ Grid: TPlayerGrid;
+begin
+ Grid := GetPlayerGridForArea(PlayerCount, AreaBounds.W, AreaBounds.H, Wide);
+ Result := GetScaledGridLayoutBounds(BaseBounds, AreaBounds, Grid);
+end;
+
+function ScaleCoordToSlot(const Value, SourceStart, SourceSize, TargetStart, TargetSize: integer): integer;
+begin
+ if SourceSize <= 0 then
+ Exit(TargetStart);
+
+ Result := TargetStart + Round((Value - SourceStart) * TargetSize / SourceSize);
+end;
+
+function ScaleLengthToSlot(const Value, SourceSize, TargetSize: integer): integer;
+begin
+ if SourceSize <= 0 then
+ Exit(Value);
+
+ Result := Round(Value * TargetSize / SourceSize);
+end;
+
+function GetFittedSlotRect(const SourceBounds, SlotRect: TPlayerSlotRect; MaxScale: real): TPlayerSlotRect;
+var
+ Scale: real;
+begin
+ Result := SlotRect;
+
+ if (SourceBounds.W <= 0) or (SourceBounds.H <= 0) or (SlotRect.W <= 0) or (SlotRect.H <= 0) then
+ Exit;
+
+ Scale := Min(MaxScale, Min(SlotRect.W / Max(1.0, SourceBounds.W), SlotRect.H / Max(1.0, SourceBounds.H)));
+ Result.W := Max(1, Round(SourceBounds.W * Scale));
+ Result.H := Max(1, Round(SourceBounds.H * Scale));
+ Result.X := SlotRect.X + (SlotRect.W - Result.W) div 2;
+ Result.Y := SlotRect.Y;
+end;
+
+end.
diff --git a/src/base/USingScores.pas b/src/base/USingScores.pas
index 749ddf3ca..10dd409b9 100644
--- a/src/base/USingScores.pas
+++ b/src/base/USingScores.pas
@@ -36,6 +36,8 @@ interface
uses
dglOpenGL,
UCommon,
+ UIni,
+ UPlayerLayout,
UThemes,
UTexture;
@@ -51,8 +53,8 @@ interface
// some constants containing options that could change by time
const
- MaxPlayers = 6; // maximum of players that could be added
- MaxPositions = 6; // maximum of score positions that could be added
+ MaxPlayers = UIni.IMaxPlayerCount; // maximum of players that could be added
+ MaxPositions = MaxPlayers; // maximum of score positions that could be added
type
//-----------
@@ -242,6 +244,108 @@ implementation
UNote,
UGraphic;
+function IsPlayerVisibleOnScreen(const EncodedPosition: byte; const Screen: integer): boolean;
+begin
+ if EncodedPosition = High(byte) then
+ Exit(false);
+
+ if Screens <= 1 then
+ Exit(true);
+
+ Result := (((EncodedPosition and 128) = 0) = (Screen = 1));
+end;
+
+function GetScorePositionForPlayer(const PlayerIndex: integer): TScorePosition;
+var
+ BaseTemplate: TThemeSingPlayer;
+ PlayerCountOnScreen: integer;
+ LocalIndex: integer;
+ LaneLeft: integer;
+ LaneRight: integer;
+ LaneWidth: integer;
+ Scale: real;
+ FrameH: integer;
+ ScoreH: integer;
+ ScoreScale: real;
+ ScoreOffsetX: integer;
+ ScoreOffsetY: integer;
+ RatingOffsetX: integer;
+ RatingOffsetY: integer;
+ PopupYOffset: integer;
+ PopupFontSize: integer;
+ GroupTop: real;
+ Layout: TSingLaneLayout;
+begin
+ if Screens > 1 then
+ begin
+ PlayerCountOnScreen := GetScreenPlayerCount(PlayersPlay, Screens, ScreenAct);
+ LocalIndex := GetPlayerIndexOnScreen(PlayerIndex, PlayersPlay, Screens);
+ end
+ else
+ begin
+ PlayerCountOnScreen := PlayersPlay;
+ LocalIndex := PlayerIndex;
+ end;
+
+ Layout := GetSingLaneLayout(PlayerCountOnScreen, LocalIndex, Theme.Sing.PlayerLayout,
+ CurrentSong.isDuet and (PlayersPlay <> 1));
+ LaneLeft := Layout.ColumnLeft;
+ LaneRight := Layout.ColumnRight;
+ LaneWidth := Layout.ColumnWidth;
+
+ BaseTemplate := Theme.Sing.PlayerTemplate;
+ Scale := Layout.WidgetScale;
+
+ ScoreScale := Min(Scale, (LaneWidth * Theme.Sing.PlayerWidgetLayout.ScoreWidthFraction) /
+ Max(1.0, BaseTemplate.ScoreBackground.W * 1.0));
+
+ FrameH := Max(Theme.Sing.PlayerWidgetLayout.MinFrameH, Round(BaseTemplate.AvatarFrame.H * Scale));
+ ScoreH := Max(Theme.Sing.PlayerWidgetLayout.MinScoreH, Round(BaseTemplate.ScoreBackground.H * Scale));
+ Result.PlayerCount := 0;
+ Result.BGW := Round(BaseTemplate.ScoreBackground.W * ScoreScale);
+ Result.BGH := Round(BaseTemplate.ScoreBackground.H * ScoreScale);
+ Result.BGX := LaneRight - Result.BGW;
+ GroupTop := Max(10, Layout.RowAnchorY -
+ GetSingHeaderTopOffset(Theme.Sing.PlayerWidgetLayout, Layout.GridRows, Scale));
+ Result.BGY := GroupTop;
+
+ ScoreOffsetX := BaseTemplate.Score.X - BaseTemplate.ScoreBackground.X;
+ ScoreOffsetY := BaseTemplate.Score.Y - BaseTemplate.ScoreBackground.Y;
+ Result.TextX := Result.BGX + Round(ScoreOffsetX * ScoreScale);
+ Result.TextY := Result.BGY + Round(ScoreOffsetY * ScoreScale);
+ Result.TextFont := BaseTemplate.Score.Font;
+ Result.TextStyle := BaseTemplate.Score.Style;
+ Result.TextSize := Max(1, Round(BaseTemplate.Score.Size * ScoreScale));
+
+ RatingOffsetX := BaseTemplate.SingBar.X - BaseTemplate.ScoreBackground.X;
+ RatingOffsetY := BaseTemplate.SingBar.Y - BaseTemplate.ScoreBackground.Y;
+ Result.RBX := Result.BGX + Round(RatingOffsetX * ScoreScale);
+ Result.RBY := Result.BGY + Round(RatingOffsetY * ScoreScale);
+ Result.RBW := Round(BaseTemplate.SingBar.W * ScoreScale);
+ Result.RBH := Round(BaseTemplate.SingBar.H * ScoreScale);
+
+ if CurrentSong.isDuet then
+ begin
+ PopupYOffset := Theme.Sing.PlayerWidgetLayout.PopupYOffsetDuet;
+ PopupFontSize := Theme.Sing.PlayerWidgetLayout.PopupFontSizeDuet;
+ end
+ else
+ begin
+ PopupYOffset := Theme.Sing.PlayerWidgetLayout.PopupYOffsetSolo;
+ PopupFontSize := Theme.Sing.PlayerWidgetLayout.PopupFontSizeSolo;
+ end;
+
+ Result.PUW := Result.BGW;
+ Result.PUH := Result.BGH;
+ Result.PUFont := 0;
+ Result.PUStyle := ftOutline;
+ Result.PUSize := Max(1, Round(PopupFontSize * Scale));
+ Result.PUStartX := Result.BGX;
+ Result.PUStartY := Result.TextY + Round(PopupYOffset * Scale);
+ Result.PUTargetX := Result.BGX;
+ Result.PUTargetY := Result.TextY;
+end;
+
{**
* sets some standard settings
*}
@@ -358,43 +462,6 @@ procedure TSingScores.Clear;
procedure TSingScores.LoadfromTheme;
var
I: integer;
- procedure AddbyStatics(const PC: byte; const ScoreStatic: TThemePosition; const SingBarStatic: TThemePosition; ScoreText: TThemeText);
- var
- nPosition: TScorePosition;
- begin
- nPosition.PlayerCount := PC; // only for one player playing
-
- nPosition.BGX := ScoreStatic.X;
- nPosition.BGY := ScoreStatic.Y;
- nPosition.BGW := ScoreStatic.W;
- nPosition.BGH := ScoreStatic.H;
-
- nPosition.TextX := ScoreText.X;
- nPosition.TextY := ScoreText.Y;
- nPosition.TextFont := ScoreText.Font;
- nPosition.TextStyle := ScoreText.Style;
- nPosition.TextSize := ScoreText.Size;
-
- nPosition.RBX := SingBarStatic.X;
- nPosition.RBY := SingBarStatic.Y;
- nPosition.RBW := SingBarStatic.W;
- nPosition.RBH := SingBarStatic.H;
-
- nPosition.PUW := nPosition.BGW;
- nPosition.PUH := nPosition.BGH;
-
- nPosition.PUFont := 0;
- nPosition.PUStyle := ftOutline;
- nPosition.PUSize := 18;
-
- nPosition.PUStartX := nPosition.BGX;
- nPosition.PUStartY := nPosition.TextY + 65;
-
- nPosition.PUTargetX := nPosition.BGX;
- nPosition.PUTargetY := nPosition.TextY;
-
- AddPosition(@nPosition);
- end;
begin
Clear;
@@ -407,21 +474,6 @@ procedure TSingScores.LoadfromTheme;
Settings.RatingBar_BG_Tex := Tex_SingBar_Back;
Settings.RatingBar_FG_Tex := Tex_SingBar_Front;
Settings.RatingBar_Bar_Tex := Tex_SingBar_Bar;
-
- // load positions from theme
-
- // player 1:
- AddByStatics(1, Theme.Sing.Solo1PP1.ScoreBackground, Theme.Sing.Solo1PP1.SingBar, Theme.Sing.Solo1PP1.Score);
- AddByStatics(2, Theme.Sing.Solo2PP1.ScoreBackground, Theme.Sing.Solo2PP1.SingBar, Theme.Sing.Solo2PP1.Score);
- AddByStatics(4, Theme.Sing.Solo3PP1.ScoreBackground, Theme.Sing.Solo3PP1.SingBar, Theme.Sing.Solo3PP1.Score);
-
- // player 2:
- AddByStatics(2, Theme.Sing.Solo2PP2.ScoreBackground, Theme.Sing.Solo2PP2.SingBar, Theme.Sing.Solo2PP2.Score);
- AddByStatics(4, Theme.Sing.Solo3PP2.ScoreBackground, Theme.Sing.Solo3PP2.SingBar, Theme.Sing.Solo3PP2.Score);
-
- // player 3:
- AddByStatics(4, Theme.Sing.Solo3PP3.ScoreBackground, Theme.Sing.Solo3PP3.SingBar, Theme.Sing.Solo3PP3.Score);
-
end;
{**
@@ -581,104 +633,15 @@ function TSingScores.GetPopUpPoints(const Index: integer): integer;
*}
procedure TSingScores.Init;
var
- PlC: array [0..1] of byte; // playercount first screen and second screen
- I, J: integer;
- MaxPlayersperScreen: byte;
- CurPlayer: byte;
-
- function GetPositionCountbyPlayerCount(bPlayerCount: byte): byte;
- var
- I: integer;
- begin
- Result := 0;
- bPlayerCount := 1 shl (bPlayerCount - 1);
-
- for I := 0 to PositionCount - 1 do
- begin
- if ((aPositions[I].PlayerCount and bPlayerCount) <> 0) then
- Inc(Result);
- end;
- end;
-
- function GetPositionbyPlayernum(bPlayerCount, bPlayer: byte): byte;
- var
- I: integer;
- begin
- bPlayerCount := 1 shl (bPlayerCount - 1);
- Result := High(byte);
-
- for I := 0 to PositionCount - 1 do
- begin
- if ((aPositions[I].PlayerCount and bPlayerCount) <> 0) then
- begin
- if (bPlayer = 0) then
- begin
- Result := I;
- Break;
- end
- else
- Dec(bPlayer);
- end;
- end;
- end;
-
+ I: integer;
begin
- MaxPlayersPerScreen := 0;
-
- for I := 1 to 6 do
+ for I := 0 to PlayerCount - 1 do
begin
- // if there are enough positions -> write to maxplayers
- if (Screens = 2) or (PlayersPlay <= 3) then
- begin
- if (GetPositionCountbyPlayerCount(I) = I) then
- MaxPlayersPerScreen := I
- else
- Break;
- end
+ if Screens > 1 then
+ aPlayers[I].Position := GetPlayerIndexOnScreen(I, PlayerCount, Screens) or ((GetPlayerScreen(I, PlayerCount, Screens) - 1) shl 7)
else
- begin
- // DIRTY HACK for 4/6 players one screen
- MaxPlayersPerScreen := PlayersPlay;
- //oPlayerCount := PlayersPlay;
- end;
- end;
-
- // split players to both screens or display on one screen
- if (Screens = 2) and (MaxPlayersPerScreen < PlayerCount) then
- begin
- PlC[0] := PlayerCount div 2 + PlayerCount mod 2;
- PlC[1] := PlayerCount div 2;
- end
- else
- begin
- PlC[0] := PlayerCount;
- PlC[1] := 0;
- end;
-
- // check if there are enough positions for all players
- for I := 0 to Screens - 1 do
- begin
- if (PlC[I] > MaxPlayersperScreen) then
- begin
- PlC[I] := MaxPlayersperScreen;
- Log.LogError('More Players than available Positions, TSingScores');
- end;
+ aPlayers[I].Position := I;
end;
-
- CurPlayer := 0;
- // give every player a position
- for I := 0 to Screens - 1 do
- for J := 0 to PlC[I]-1 do
- begin
- // DIRTY HACK for 4/6 players one screen
- if (Screens = 2) or (PlayersPlay <= 3) then
- aPlayers[CurPlayer].Position := GetPositionbyPlayernum(PlC[I], J) or (I shl 7)
- else
- aPlayers[CurPlayer].Position := J;
-
- //Log.LogError('Player ' + InttoStr(CurPlayer) + ' gets Position: ' + InttoStr(aPlayers[CurPlayer].Position));
- Inc(CurPlayer);
- end;
end;
{**
@@ -782,36 +745,8 @@ procedure TSingScores.DrawPopUp(const PopUp: PScorePopUp);
TextLen: real;
ScoretoAdd: word;
PosDiff: real;
- procedure aPositionsInternal(index: integer; themeElements: TThemeSingPlayer);
- var
- yOffset: integer;
- puSize: integer;
- begin
- if (CurrentSong.isDuet) then begin
- yOffset := 40;
- puSize := 14;
- end else begin
- yOffset := 65;
- puSize := 18;
- end;
- aPositions[PIndex].PUSize := puSize;
-
- aPositions[PIndex].PUW := themeElements.ScoreBackground.W;
- aPositions[PIndex].PUH := themeElements.ScoreBackground.H;
-
- aPositions[PIndex].PUStartX := themeElements.ScoreBackground.X;
- aPositions[PIndex].PUStartY := themeElements.Score.Y + yOffset;
-
- aPositions[PIndex].PUTargetX := themeElements.ScoreBackground.X;
- aPositions[PIndex].PUTargetY := themeElements.Score.Y;
-
- end;
+ Position: TScorePosition;
begin
-{ if screens = 2 and playerplay <= 3 the 2nd screen shows the
- textures of screen 1 }
- if (Screens = 2) and (PlayersPlay <= 3) then
- ScreenAct := 1;
-
if (PopUp <> nil) then
begin
// only draw if player has a position
@@ -819,7 +754,7 @@ procedure TSingScores.DrawPopUp(const PopUp: PScorePopUp);
if PIndex <> High(byte) then
begin
// only draw if player is on cur screen
- if ((Players[PopUp.Player].Position and 128) = 0) = (ScreenAct = 1) then
+ if IsPlayerVisibleOnScreen(Players[PopUp.Player].Position, ScreenAct) then
begin
CurTime := SDL_GetTicks;
if not (Enabled and Players[PopUp.Player].Enabled) then
@@ -831,85 +766,7 @@ procedure TSingScores.DrawPopUp(const PopUp: PScorePopUp);
// get position of popup
PIndex := PIndex and 127;
-
- // DIRTY HACK
- // correct position for duet with 3/6 players and 4/6 players in one screen
- if (Screens = 1) and ((PlayersPlay = 4) or (PlayersPlay = 6)) then
- begin
- if (PlayersPlay = 4) then
- begin
- if (CurrentSong.isDuet) then
- begin
- case (PopUp.Player) of
- 0: aPositionsInternal(PIndex, Theme.Sing.Duet4PP1);
- 1: aPositionsInternal(PIndex, Theme.Sing.Duet4PP2);
- 2: aPositionsInternal(PIndex, Theme.Sing.Duet4PP3);
- 3: aPositionsInternal(PIndex, Theme.Sing.Duet4PP4);
- end;
- end
- else
- begin
- case (PopUp.Player) of
- 0: aPositionsInternal(PIndex, Theme.Sing.Solo4PP1);
- 1: aPositionsInternal(PIndex, Theme.Sing.Solo4PP2);
- 2: aPositionsInternal(PIndex, Theme.Sing.Solo4PP3);
- 3: aPositionsInternal(PIndex, Theme.Sing.Solo4PP4);
- end;
- end;
- end;
-
- if (PlayersPlay = 6) then
- begin
- if (CurrentSong.isDuet) then
- begin
- case (PopUp.Player) of
- 0: aPositionsInternal(PIndex, Theme.Sing.Duet6PP1);
- 1: aPositionsInternal(PIndex, Theme.Sing.Duet6PP2);
- 2: aPositionsInternal(PIndex, Theme.Sing.Duet6PP3);
- 3: aPositionsInternal(PIndex, Theme.Sing.Duet6PP4);
- 4: aPositionsInternal(PIndex, Theme.Sing.Duet6PP5);
- 5: aPositionsInternal(PIndex, Theme.Sing.Duet6PP6);
- end;
- end
- else
- begin
- case (PopUp.Player) of
- 0: aPositionsInternal(0, Theme.Sing.Solo6PP1);
- 1: aPositionsInternal(1, Theme.Sing.Solo6PP2);
- 2: aPositionsInternal(2, Theme.Sing.Solo6PP3);
- 3: aPositionsInternal(3, Theme.Sing.Solo6PP4);
- 4: aPositionsInternal(4, Theme.Sing.Solo6PP5);
- 5: aPositionsInternal(5, Theme.Sing.Solo6PP6);
- end;
- end;
- end;
- end
- else
- begin
-
- if (CurrentSong.isDuet) then
- begin
- if ((PlayersPlay = 3) or (PlayersPlay = 6)) then
- begin
- case (PopUp.Player) of
- 0, 3, 6: aPositionsInternal(PIndex, Theme.Sing.Duet3PP1);
- 1, 4, 7: aPositionsInternal(PIndex, Theme.Sing.Duet3PP2);
- 2, 5, 8: aPositionsInternal(PIndex, Theme.Sing.Duet3PP3);
- end;
- end;
- end
- else
- begin
- if ((PlayersPlay = 3) or (PlayersPlay = 6)) then
- begin
- case (PopUp.Player) of
- 0, 3, 6: aPositionsInternal(PIndex, Theme.Sing.Solo3PP1);
- 1, 4, 7: aPositionsInternal(PIndex, Theme.Sing.Solo3PP2);
- 2, 5, 8: aPositionsInternal(PIndex, Theme.Sing.Solo3PP3);
- end;
- end;
- end;
- end;
+ Position := GetScorePositionForPlayer(PopUp.Player);
// check for phase ...
if (TimeDiff <= Settings.Phase1Time) then
@@ -918,13 +775,13 @@ procedure TSingScores.DrawPopUp(const PopUp: PScorePopUp);
Progress := TimeDiff / Settings.Phase1Time;
- W := aPositions[PIndex].PUW * Sin(Progress/2*Pi);
- H := aPositions[PIndex].PUH * Sin(Progress/2*Pi);
+ W := Position.PUW * Sin(Progress/2*Pi);
+ H := Position.PUH * Sin(Progress/2*Pi);
- X := aPositions[PIndex].PUStartX + (aPositions[PIndex].PUW - W)/2;
- Y := aPositions[PIndex].PUStartY + (aPositions[PIndex].PUH - H)/2;
+ X := Position.PUStartX + (Position.PUW - W)/2;
+ Y := Position.PUStartY + (Position.PUH - H)/2;
- FontSize := Round(Progress * aPositions[PIndex].PUSize);
+ FontSize := Round(Progress * Position.PUSize);
FontOffset := (H - FontSize) / 2;
Alpha := 1;
end
@@ -934,20 +791,20 @@ procedure TSingScores.DrawPopUp(const PopUp: PScorePopUp);
// phase 2 - the moving
Progress := (TimeDiff - Settings.Phase1Time) / Settings.Phase2Time;
- W := aPositions[PIndex].PUW;
- H := aPositions[PIndex].PUH;
+ W := Position.PUW;
+ H := Position.PUH;
- PosDiff := aPositions[PIndex].PUTargetX - aPositions[PIndex].PUStartX;
+ PosDiff := Position.PUTargetX - Position.PUStartX;
if PosDiff > 0 then
PosDiff := PosDiff + W;
- X := aPositions[PIndex].PUStartX + PosDiff * sqr(Progress);
+ X := Position.PUStartX + PosDiff * sqr(Progress);
- PosDiff := aPositions[PIndex].PUTargetY - aPositions[PIndex].PUStartY;
+ PosDiff := Position.PUTargetY - Position.PUStartY;
if PosDiff < 0 then
- PosDiff := PosDiff + aPositions[PIndex].BGH;
- Y := aPositions[PIndex].PUStartY + PosDiff * sqr(Progress);
+ PosDiff := PosDiff + Position.BGH;
+ Y := Position.PUStartY + PosDiff * sqr(Progress);
- FontSize := aPositions[PIndex].PUSize;
+ FontSize := Position.PUSize;
FontOffset := (H - FontSize) / 2;
Alpha := 1 - 0.3 * Progress;
end
@@ -980,24 +837,24 @@ procedure TSingScores.DrawPopUp(const PopUp: PScorePopUp);
// set positions etc.
Alpha := 0.7 - 0.7 * Progress;
- W := aPositions[PIndex].PUW;
- H := aPositions[PIndex].PUH;
+ W := Position.PUW;
+ H := Position.PUH;
- PosDiff := aPositions[PIndex].PUTargetX - aPositions[PIndex].PUStartX;
+ PosDiff := Position.PUTargetX - Position.PUStartX;
if (PosDiff > 0) then
PosDiff := W
else
PosDiff := 0;
- X := aPositions[PIndex].PUTargetX + PosDiff * Progress;
+ X := Position.PUTargetX + PosDiff * Progress;
- PosDiff := aPositions[PIndex].PUTargetY - aPositions[PIndex].PUStartY;
+ PosDiff := Position.PUTargetY - Position.PUStartY;
if (PosDiff < 0) then
- PosDiff := -aPositions[PIndex].BGH
+ PosDiff := -Position.BGH
else
PosDiff := 0;
- Y := aPositions[PIndex].PUTargetY - PosDiff * (1 - Progress);
+ Y := Position.PUTargetY - PosDiff * (1 - Progress);
- FontSize := aPositions[PIndex].PUSize;
+ FontSize := Position.PUSize;
FontOffset := (H - FontSize) / 2;
end
else
@@ -1034,8 +891,8 @@ procedure TSingScores.DrawPopUp(const PopUp: PScorePopUp);
glDisable(GL_BLEND);
// set font style and size
- SetFontFamily(aPositions[PIndex].PUFont);
- SetFontStyle(aPositions[PIndex].PUStyle);
+ SetFontFamily(Position.PUFont);
+ SetFontStyle(Position.PUStyle);
SetFontItalic(false);
SetFontSize(FontSize);
SetFontReflection(false, 0);
@@ -1065,106 +922,16 @@ procedure TSingScores.DrawScore(const Index: integer);
Position: TScorePosition;
ScoreStr: String;
Drawing: boolean;
- procedure updatePosition(themeElements: TThemeSingPlayer);
- begin
- Position.BGX := themeElements.ScoreBackground.X;
- Position.BGY := themeElements.ScoreBackground.Y;
- Position.BGW := themeElements.ScoreBackground.W;
- Position.BGH := themeElements.ScoreBackground.H;
-
- Position.TextX := themeElements.Score.X;
- Position.TextY := themeElements.Score.Y;
- Position.TextFont := themeElements.Score.Font;
- Position.TextStyle := themeElements.Score.Style;
- Position.TextSize := themeElements.Score.Size;
- end;
begin
Drawing := false;
- { if screens = 2 and playerplay <= 3 the 2nd screen shows the
- textures of screen 1 }
- if (Screens = 2) and (PlayersPlay <= 3) then
- ScreenAct := 1;
-
- // DIRTY HACK
- // correct position for duet with 3/6 players and 4/6 players one screen
- if (Screens = 1) and ((PlayersPlay = 4) or (PlayersPlay = 6)) then
+ if Players[Index].Position <> High(byte) then
begin
-
- Position := aPositions[Players[Index].Position and 127];
- Drawing := true;
-
- if (PlayersPlay = 4) then
- begin
- if (CurrentSong.isDuet) then
- begin
- case Index of
- 0: updatePosition(Theme.Sing.Duet4PP1);
- 1: updatePosition(Theme.Sing.Duet4PP2);
- 2: updatePosition(Theme.Sing.Duet4PP3);
- 3: updatePosition(Theme.Sing.Duet4PP4);
- end;
- end
- else
- begin
- case Index of
- 0: updatePosition(Theme.Sing.Solo4PP1);
- 1: updatePosition(Theme.Sing.Solo4PP2);
- 2: updatePosition(Theme.Sing.Solo4PP3);
- 3: updatePosition(Theme.Sing.Solo4PP4);
- end;
- end;
- end
- else
+ if IsPlayerVisibleOnScreen(Players[Index].Position, ScreenAct) and Players[Index].Visible then
begin
- // 6 players
- if (CurrentSong.isDuet) then
- begin
- case Index of
- 0: updatePosition(Theme.Sing.Duet6PP1);
- 1: updatePosition(Theme.Sing.Duet6PP2);
- 2: updatePosition(Theme.Sing.Duet6PP3);
- 3: updatePosition(Theme.Sing.Duet6PP4);
- 4: updatePosition(Theme.Sing.Duet6PP5);
- 5: updatePosition(Theme.Sing.Duet6PP6);
- end;
- end
- else
- begin
- case Index of
- 0: updatePosition(Theme.Sing.Solo6PP1);
- 1: updatePosition(Theme.Sing.Solo6PP2);
- 2: updatePosition(Theme.Sing.Solo6PP3);
- 3: updatePosition(Theme.Sing.Solo6PP4);
- 4: updatePosition(Theme.Sing.Solo6PP5);
- 5: updatePosition(Theme.Sing.Solo6PP6);
- end;
- end;
+ Position := GetScorePositionForPlayer(Index);
+ Drawing := true;
end;
- end
- else
- begin
-
- // only draw if player has a position
- if Players[Index].Position <> High(byte) then
- begin
- // only draw if player is on cur screen
- if (((Players[Index].Position and 128) = 0) = (ScreenAct = 1)) and Players[Index].Visible then
- begin
- Position := aPositions[Players[Index].Position and 127];
-
- Drawing := true;
-
- if (CurrentSong.isDuet) and ((PlayersPlay = 3) or (PlayersPlay = 6)) then
- begin
- case Index of
- 0, 3, 6: updatePosition(Theme.Sing.Duet3PP1);
- 1, 4, 7: updatePosition(Theme.Sing.Duet3PP2);
- 2, 5, 8: updatePosition(Theme.Sing.Duet3PP3);
- end;
- end;
- end;
- end;
end;
if (Drawing) then
@@ -1210,101 +977,17 @@ procedure TSingScores.DrawRatingBar(const Index: integer);
R, G, B: real;
Size, Diff: real;
Drawing: boolean;
- procedure updatePosition(themeElements: TThemeSingPlayer);
- begin
- Position.RBX := themeElements.SingBar.X;
- Position.RBY := themeElements.SingBar.Y;
- Position.RBW := themeElements.SingBar.W;
- Position.RBH := themeElements.SingBar.H;
- end;
begin
- { if screens = 2 and playerplay <= 3 the 2nd screen shows the
- textures of screen 1 }
- if (Screens = 2) and (PlayersPlay <= 3) then
- ScreenAct := 1;
-
Drawing := false;
- // DIRTY HACK
- // correct position for duet with 3/6 players and 4/6 players in one screen
- if (Screens = 1) and ((PlayersPlay = 4) or (PlayersPlay = 6)) then
+ if Players[Index].Position <> High(byte) then
begin
- Drawing := true;
-
- if (PlayersPlay = 4) then
+ if IsPlayerVisibleOnScreen(Players[Index].Position, ScreenAct) and
+ Players[index].RBVisible and
+ Players[index].Visible then
begin
-
- if (CurrentSong.isDuet) then
- begin
- case Index of
- 0: updatePosition(Theme.Sing.Duet4PP1);
- 1: updatePosition(Theme.Sing.Duet4PP2);
- 2: updatePosition(Theme.Sing.Duet4PP3);
- 3: updatePosition(Theme.Sing.Duet4PP4);
- end;
- end
- else
- begin
- case Index of
- 0: updatePosition(Theme.Sing.Solo4PP1);
- 1: updatePosition(Theme.Sing.Solo4PP2);
- 2: updatePosition(Theme.Sing.Solo4PP3);
- 3: updatePosition(Theme.Sing.Solo4PP4);
- end;
- end;
- end
- else
- begin
- // 6 players
- if (CurrentSong.isDuet) then
- begin
- case Index of
- 0: updatePosition(Theme.Sing.Duet6PP1);
- 1: updatePosition(Theme.Sing.Duet6PP2);
- 2: updatePosition(Theme.Sing.Duet6PP3);
- 3: updatePosition(Theme.Sing.Duet6PP4);
- 4: updatePosition(Theme.Sing.Duet6PP5);
- 5: updatePosition(Theme.Sing.Duet6PP6);
- end;
- end
- else
- begin
- case Index of
- 0: updatePosition(Theme.Sing.Solo6PP1);
- 1: updatePosition(Theme.Sing.Solo6PP2);
- 2: updatePosition(Theme.Sing.Solo6PP3);
- 3: updatePosition(Theme.Sing.Solo6PP4);
- 4: updatePosition(Theme.Sing.Solo6PP5);
- 5: updatePosition(Theme.Sing.Solo6PP6);
- end;
- end;
- end;
- end
- else
- begin
- // only draw if player has a position
- if Players[Index].Position <> High(byte) then
- begin
- // only draw if player is on cur screen
- if (((Players[Index].Position and 128) = 0) = (ScreenAct = 1) and
- Players[index].RBVisible and
- Players[index].Visible) then
- begin
- Drawing := true;
-
- Position := aPositions[Players[Index].Position and 127];
-
- // DIRTY HACK
- // correct position for duet with 3/6 players
- if (CurrentSong.isDuet) and ((PlayersPlay = 3) or (PlayersPlay = 6)) then
- begin
- case Index of
- 0, 3, 6: updatePosition(Theme.Sing.Duet3PP1);
- 1, 4, 7: updatePosition(Theme.Sing.Duet3PP2);
- 2, 5, 8: updatePosition(Theme.Sing.Duet3PP3);
- end;
- end;
- end;
+ Drawing := true;
+ Position := GetScorePositionForPlayer(Index);
end;
end;
diff --git a/src/base/UThemes.pas b/src/base/UThemes.pas
index 31d3791bd..4f303d505 100644
--- a/src/base/UThemes.pas
+++ b/src/base/UThemes.pas
@@ -40,6 +40,7 @@ interface
UCommon,
ULog,
UIni,
+ UPlayerLayout,
UTexture,
UPath;
type
@@ -288,6 +289,46 @@ TThemeSingPlayer = record
Oscilloscope: TThemePosition;
end;
+ TThemeNamePlayerSelectLayout = record
+ Area: TPlayerSlotRect;
+ MinPlayerCount: integer;
+ MaxColumns: integer;
+ RowHeightDivisor: real;
+ MaxScaleSmall: real;
+ MaxScaleMedium: real;
+ MaxScaleDefault: real;
+ end;
+
+ TThemeSingPlayerWidgetLayout = record
+ MinFrameW: integer;
+ MinFrameH: integer;
+ MinScoreW: integer;
+ MinScoreH: integer;
+ HeaderOffsetLeft: integer;
+ HeaderOffsetTopBase: integer;
+ HeaderOffsetTopPerExtraRow: integer;
+ MinAvatarInsetX: integer;
+ MinAvatarInsetY: integer;
+ NameGapBaseX: integer;
+ NameGapMinX: integer;
+ NamePaddingBaseX: integer;
+ NamePaddingMinX: integer;
+ NamePaddingBaseY: integer;
+ NamePaddingMinY: integer;
+ NameMinW: integer;
+ NameMinH: integer;
+ NameMinSize: integer;
+ ScoreWidthFraction: real;
+ OscilloscopeGapBaseY: integer;
+ OscilloscopeGapMinY: integer;
+ OscilloscopeMinW: integer;
+ OscilloscopeMinH: integer;
+ PopupYOffsetSolo: integer;
+ PopupYOffsetDuet: integer;
+ PopupFontSizeSolo: integer;
+ PopupFontSizeDuet: integer;
+ end;
+
TThemeLoading = class(TThemeBasic)
StaticAnimation: TThemeStatic;
TextLoading: TThemeText;
@@ -320,11 +361,15 @@ TThemeName = class(TThemeBasic)
PlayerAvatar: TThemeButton;
+ PlayerSelectTemplateFrame: TThemeStatic;
+ PlayerSelectTemplateText: TThemeText;
+ PlayerSelectTemplateAvatar: TThemeStaticRectangle;
+ PlayerSelectLayout: TThemeNamePlayerSelectLayout;
PlayerSelect: array [0..UIni.IMaxPlayerCount-1] of TThemeStatic;
PlayerSelectText: array [0..UIni.IMaxPlayerCount-1] of TThemeText;
PlayerSelectAvatar: array [0..UIni.IMaxPlayerCount-1] of TThemeStaticRectangle;
PlayerSelectCurrent: TThemeButton;
-
+
SelectPlayersCount: TThemeSelectSlide;
SelectPlayerColor: TThemeSelectSlide;
SelectPlayerLevel: TThemeSelectSlide;
@@ -466,6 +511,7 @@ TThemeSong = class(TThemeBasic)
Text3PlayersDuetSingerP1: TThemeText;
Text3PlayersDuetSingerP2: TThemeText;
Text3PlayersDuetSingerP3: TThemeText;
+ DuetSingerArea: TThemePosition;
end;
TThemeSing = class(TThemeBasic)
@@ -518,6 +564,10 @@ TThemeSing = class(TThemeBasic)
Duet6PP5: TThemeSingPlayer;
Duet6PP6: TThemeSingPlayer;
+ PlayerTemplate: TThemeSingPlayer;
+ PlayerLayout: TSingPlayerLayoutConfig;
+ PlayerWidgetLayout: TThemeSingPlayerWidgetLayout;
+
StaticSongName: TThemeStatic;
TextSongName: TThemeText;
@@ -614,6 +664,8 @@ TThemeScore = class(TThemeBasic)
TextTitle: TThemeText;
TextArtistTitle: TThemeText;
+ PlayerLayoutArea: TPlayerSlotRect;
+ PlayerLayoutExtraColsBias: integer;
PlayerStatic: array[1..UIni.IMaxPlayerCount] of AThemeStatic;
PlayerTexts: array[1..UIni.IMaxPlayerCount] of AThemeText;
@@ -643,7 +695,7 @@ TThemeScore = class(TThemeBasic)
StaticLevel: array[1..UIni.IMaxPlayerCount] of TThemeStatic;
StaticLevelRound: array[1..UIni.IMaxPlayerCount] of TThemeStatic;
- ButtonSend: array[1..UIni.IMaxPlayerCount] of TThemeButton;
+ ButtonSend: array[1..3] of TThemeButton;
StaticNavigate: TThemeStatic;
TextNavigate: TThemeText;
@@ -1223,6 +1275,7 @@ TTheme = class
procedure ThemeLoadPosition(var ThemePosition: TThemePosition; const Name: string);
procedure ThemeLoadLyricBar(var LyricBar: TThemeLyricBar; const Name: string);
+ procedure ThemeScoreLoadData;
procedure ThemeScoreLoad;
procedure ThemePartyLoad;
procedure ThemeSongLoad;
@@ -1251,6 +1304,18 @@ function GetLyricGrayColor(Color: integer): TRGB;
function GetLyricOutlineColor(Color: integer): TRGB;
function GetLyricBarColor(Color: integer): TRGB;
+function GetThemePlayerBounds(const ThemePlayer: TThemeSingPlayer): TPlayerSlotRect;
+function GetThemePlayerScoreLayoutBounds(const BaseBounds, LayoutArea: TPlayerSlotRect;
+ PlayerCountOnScreen: integer): TPlayerSlotRect;
+function GetNamePlayerSelectBaseBounds(const NameTheme: TThemeName): TPlayerSlotRect;
+function GetNamePlayerSelectLayoutBounds(const BaseBounds: TPlayerSlotRect;
+ const Layout: TThemeNamePlayerSelectLayout): TPlayerSlotRect;
+function GetNamePlayerSelectSlotRect(PlayerIndex, PlayerCount: integer;
+ const BaseBounds, LayoutBounds: TPlayerSlotRect; const Layout: TThemeNamePlayerSelectLayout): TPlayerSlotRect;
+function GetNamePlayerSelectMaxScale(PlayerCount: integer; const Layout: TThemeNamePlayerSelectLayout): real;
+function GetSingHeaderTopOffset(const Layout: TThemeSingPlayerWidgetLayout;
+ RowCount: integer; Scale: real): integer;
+
function GetPlayerColor(Color: integer): TRGB;
function GetPlayerLightColor(Color: integer): TRGB;
procedure LoadPlayersColors;
@@ -1277,6 +1342,350 @@ implementation
const
MAX_INHERITANCE = 10;
+type
+ TScoreSlotThemeTemplate = record
+ PlayerStatic: AThemeStatic;
+ PlayerTexts: AThemeText;
+ TextName: TThemeText;
+ TextScore: TThemeText;
+ AvatarStatic: TThemeStatic;
+ TextNotes: TThemeText;
+ TextNotesScore: TThemeText;
+ TextLineBonus: TThemeText;
+ TextLineBonusScore: TThemeText;
+ TextGoldenNotes: TThemeText;
+ TextGoldenNotesScore: TThemeText;
+ TextTotal: TThemeText;
+ TextTotalScore: TThemeText;
+ StaticBoxLightest: TThemeStatic;
+ StaticBoxLight: TThemeStatic;
+ StaticBoxDark: TThemeStatic;
+ StaticRatings: TThemeStatic;
+ StaticBackLevel: TThemeStatic;
+ StaticBackLevelRound: TThemeStatic;
+ StaticLevel: TThemeStatic;
+ StaticLevelRound: TThemeStatic;
+ end;
+
+ TNamePlayerSelectTemplate = record
+ Frame: TThemeStatic;
+ Text: TThemeText;
+ Avatar: TThemeStaticRectangle;
+ end;
+
+procedure ExpandScoreBounds(var Bounds: TPlayerSlotRect; X, Y, W, H: integer; var Initialized: boolean);
+var
+ MaxX: integer;
+ MaxY: integer;
+begin
+ MaxX := X + W;
+ MaxY := Y + H;
+
+ if not Initialized then
+ begin
+ Bounds.X := X;
+ Bounds.Y := Y;
+ Bounds.W := W;
+ Bounds.H := H;
+ Initialized := true;
+ Exit;
+ end;
+
+ Bounds.W := Max(Bounds.X + Bounds.W, MaxX) - Min(Bounds.X, X);
+ Bounds.H := Max(Bounds.Y + Bounds.H, MaxY) - Min(Bounds.Y, Y);
+ Bounds.X := Min(Bounds.X, X);
+ Bounds.Y := Min(Bounds.Y, Y);
+end;
+
+function GetScoreTemplateBounds(const Template: TScoreSlotThemeTemplate): TPlayerSlotRect;
+var
+ Initialized: boolean;
+ I: integer;
+begin
+ Initialized := false;
+
+ ExpandScoreBounds(Result, Template.TextName.X, Template.TextName.Y, Template.TextName.W, Template.TextName.H, Initialized);
+ ExpandScoreBounds(Result, Template.TextScore.X, Template.TextScore.Y, Template.TextScore.W, Template.TextScore.H, Initialized);
+ ExpandScoreBounds(Result, Template.AvatarStatic.X, Template.AvatarStatic.Y, Template.AvatarStatic.W, Template.AvatarStatic.H, Initialized);
+ ExpandScoreBounds(Result, Template.TextNotes.X, Template.TextNotes.Y, Template.TextNotes.W, Template.TextNotes.H, Initialized);
+ ExpandScoreBounds(Result, Template.TextNotesScore.X, Template.TextNotesScore.Y, Template.TextNotesScore.W, Template.TextNotesScore.H, Initialized);
+ ExpandScoreBounds(Result, Template.TextLineBonus.X, Template.TextLineBonus.Y, Template.TextLineBonus.W, Template.TextLineBonus.H, Initialized);
+ ExpandScoreBounds(Result, Template.TextLineBonusScore.X, Template.TextLineBonusScore.Y, Template.TextLineBonusScore.W, Template.TextLineBonusScore.H, Initialized);
+ ExpandScoreBounds(Result, Template.TextGoldenNotes.X, Template.TextGoldenNotes.Y, Template.TextGoldenNotes.W, Template.TextGoldenNotes.H, Initialized);
+ ExpandScoreBounds(Result, Template.TextGoldenNotesScore.X, Template.TextGoldenNotesScore.Y, Template.TextGoldenNotesScore.W, Template.TextGoldenNotesScore.H, Initialized);
+ ExpandScoreBounds(Result, Template.TextTotal.X, Template.TextTotal.Y, Template.TextTotal.W, Template.TextTotal.H, Initialized);
+ ExpandScoreBounds(Result, Template.TextTotalScore.X, Template.TextTotalScore.Y, Template.TextTotalScore.W, Template.TextTotalScore.H, Initialized);
+ ExpandScoreBounds(Result, Template.StaticBoxLightest.X, Template.StaticBoxLightest.Y, Template.StaticBoxLightest.W, Template.StaticBoxLightest.H, Initialized);
+ ExpandScoreBounds(Result, Template.StaticBoxLight.X, Template.StaticBoxLight.Y, Template.StaticBoxLight.W, Template.StaticBoxLight.H, Initialized);
+ ExpandScoreBounds(Result, Template.StaticBoxDark.X, Template.StaticBoxDark.Y, Template.StaticBoxDark.W, Template.StaticBoxDark.H, Initialized);
+ ExpandScoreBounds(Result, Template.StaticRatings.X, Template.StaticRatings.Y, Template.StaticRatings.W, Template.StaticRatings.H, Initialized);
+ ExpandScoreBounds(Result, Template.StaticBackLevel.X, Template.StaticBackLevel.Y, Template.StaticBackLevel.W, Template.StaticBackLevel.H, Initialized);
+ ExpandScoreBounds(Result, Template.StaticBackLevelRound.X, Template.StaticBackLevelRound.Y, Template.StaticBackLevelRound.W, Template.StaticBackLevelRound.H, Initialized);
+ ExpandScoreBounds(Result, Template.StaticLevel.X, Template.StaticLevel.Y, Template.StaticLevel.W, Template.StaticLevel.H, Initialized);
+ ExpandScoreBounds(Result, Template.StaticLevelRound.X, Template.StaticLevelRound.Y, Template.StaticLevelRound.W, Template.StaticLevelRound.H, Initialized);
+
+ for I := 0 to High(Template.PlayerStatic) do
+ ExpandScoreBounds(Result, Template.PlayerStatic[I].X, Template.PlayerStatic[I].Y, Template.PlayerStatic[I].W, Template.PlayerStatic[I].H, Initialized);
+
+ for I := 0 to High(Template.PlayerTexts) do
+ ExpandScoreBounds(Result, Template.PlayerTexts[I].X, Template.PlayerTexts[I].Y, Template.PlayerTexts[I].W, Template.PlayerTexts[I].H, Initialized);
+end;
+
+function GetThemePlayerBounds(const ThemePlayer: TThemeSingPlayer): TPlayerSlotRect;
+var
+ MinX: integer;
+ MinY: integer;
+ MaxX: integer;
+ MaxY: integer;
+begin
+ MinX := Min(ThemePlayer.ScoreBackground.X, ThemePlayer.SingBar.X);
+ MinY := Min(ThemePlayer.ScoreBackground.Y, ThemePlayer.Score.Y);
+ MaxX := Max(ThemePlayer.ScoreBackground.X + ThemePlayer.ScoreBackground.W,
+ ThemePlayer.SingBar.X + ThemePlayer.SingBar.W);
+ MaxY := Max(ThemePlayer.ScoreBackground.Y + ThemePlayer.ScoreBackground.H,
+ ThemePlayer.SingBar.Y + ThemePlayer.SingBar.H);
+
+ Result.X := MinX;
+ Result.Y := MinY;
+ Result.W := MaxX - MinX;
+ Result.H := MaxY - MinY;
+end;
+
+function GetNamePlayerSelectTemplateBounds(const Template: TNamePlayerSelectTemplate): TPlayerSlotRect;
+var
+ Initialized: boolean;
+begin
+ Initialized := false;
+ ExpandScoreBounds(Result, Template.Frame.X, Template.Frame.Y, Template.Frame.W, Template.Frame.H, Initialized);
+ ExpandScoreBounds(Result, Template.Avatar.X, Template.Avatar.Y, Template.Avatar.W, Template.Avatar.H, Initialized);
+ ExpandScoreBounds(Result, Template.Text.X, Template.Text.Y, Max(Template.Frame.W, 1), Max(Template.Text.H, 1), Initialized);
+end;
+
+function GetNamePlayerSelectBaseBounds(const NameTheme: TThemeName): TPlayerSlotRect;
+var
+ Initialized: boolean;
+begin
+ Initialized := false;
+ ExpandScoreBounds(Result, NameTheme.PlayerSelectTemplateFrame.X, NameTheme.PlayerSelectTemplateFrame.Y,
+ NameTheme.PlayerSelectTemplateFrame.W, NameTheme.PlayerSelectTemplateFrame.H, Initialized);
+ ExpandScoreBounds(Result, NameTheme.PlayerSelectTemplateAvatar.X, NameTheme.PlayerSelectTemplateAvatar.Y,
+ NameTheme.PlayerSelectTemplateAvatar.W, NameTheme.PlayerSelectTemplateAvatar.H, Initialized);
+ ExpandScoreBounds(Result, NameTheme.PlayerSelectTemplateText.X, NameTheme.PlayerSelectTemplateText.Y,
+ Max(NameTheme.PlayerSelectTemplateFrame.W, 1), Max(NameTheme.PlayerSelectTemplateText.H, 1), Initialized);
+end;
+
+function GetNamePlayerSelectLayoutBounds(const BaseBounds: TPlayerSlotRect;
+ const Layout: TThemeNamePlayerSelectLayout): TPlayerSlotRect;
+begin
+ Result := Layout.Area;
+
+ if BaseBounds.W > 0 then
+ Result.W := Max(Result.W, BaseBounds.W);
+ if BaseBounds.H > 0 then
+ Result.H := Max(Result.H, BaseBounds.H);
+end;
+
+function GetNamePlayerSelectSlotRect(PlayerIndex, PlayerCount: integer;
+ const BaseBounds, LayoutBounds: TPlayerSlotRect; const Layout: TThemeNamePlayerSelectLayout): TPlayerSlotRect;
+var
+ LayoutPlayerCount: integer;
+ Cols: integer;
+ Rows: integer;
+ ColIndex: integer;
+ RowIndex: integer;
+ SlotWidth: integer;
+ SlotHeight: integer;
+begin
+ Result := BaseBounds;
+
+ if (PlayerIndex < 0) or (PlayerIndex >= PlayerCount) then
+ Exit;
+
+ LayoutPlayerCount := Max(PlayerCount, Layout.MinPlayerCount);
+ Cols := Min(Layout.MaxColumns, LayoutPlayerCount);
+ Rows := (LayoutPlayerCount + Cols - 1) div Cols;
+ if (Cols <= 0) or (Rows <= 0) then
+ Exit;
+
+ ColIndex := PlayerIndex mod Cols;
+ RowIndex := PlayerIndex div Cols;
+
+ SlotWidth := LayoutBounds.W div Cols;
+ SlotHeight := LayoutBounds.H div Rows;
+
+ Result.X := LayoutBounds.X + ColIndex * SlotWidth;
+ Result.Y := LayoutBounds.Y + Round(RowIndex * (SlotHeight / Max(Layout.RowHeightDivisor, 1.0)));
+
+ if ColIndex = Cols - 1 then
+ Result.W := LayoutBounds.X + LayoutBounds.W - Result.X
+ else
+ Result.W := SlotWidth;
+
+ if RowIndex = Rows - 1 then
+ Result.H := LayoutBounds.Y + LayoutBounds.H - Result.Y
+ else
+ Result.H := SlotHeight;
+end;
+
+function GetNamePlayerSelectMaxScale(PlayerCount: integer; const Layout: TThemeNamePlayerSelectLayout): real;
+begin
+ if PlayerCount <= 2 then
+ Exit(Layout.MaxScaleSmall);
+ if PlayerCount <= 4 then
+ Exit(Layout.MaxScaleMedium);
+ Result := Layout.MaxScaleDefault;
+end;
+
+function GetSingHeaderTopOffset(const Layout: TThemeSingPlayerWidgetLayout;
+ RowCount: integer; Scale: real): integer;
+var
+ BaseOffset: integer;
+begin
+ BaseOffset := Layout.HeaderOffsetTopBase +
+ Max(0, RowCount - 1) * Layout.HeaderOffsetTopPerExtraRow;
+ Result := Round(BaseOffset * Scale);
+end;
+
+function TransformNamePlayerSelectStatic(const Source: TThemeStatic; const SourceBounds, SlotRect: TPlayerSlotRect): TThemeStatic;
+var
+ FittedRect: TPlayerSlotRect;
+begin
+ Result := Source;
+ FittedRect := GetFittedSlotRect(SourceBounds, SlotRect, 1.0);
+ Result.X := ScaleCoordToSlot(Source.X, SourceBounds.X, SourceBounds.W, FittedRect.X, FittedRect.W);
+ Result.Y := ScaleCoordToSlot(Source.Y, SourceBounds.Y, SourceBounds.H, FittedRect.Y, FittedRect.H);
+ Result.W := ScaleLengthToSlot(Source.W, SourceBounds.W, FittedRect.W);
+ Result.H := ScaleLengthToSlot(Source.H, SourceBounds.H, FittedRect.H);
+end;
+
+function TransformNamePlayerSelectText(const Source: TThemeText; const SourceBounds, SlotRect: TPlayerSlotRect): TThemeText;
+var
+ FittedRect: TPlayerSlotRect;
+begin
+ Result := Source;
+ FittedRect := GetFittedSlotRect(SourceBounds, SlotRect, 1.0);
+ Result.X := ScaleCoordToSlot(Source.X, SourceBounds.X, SourceBounds.W, FittedRect.X, FittedRect.W);
+ Result.Y := ScaleCoordToSlot(Source.Y, SourceBounds.Y, SourceBounds.H, FittedRect.Y, FittedRect.H);
+ Result.Size := Max(8, ScaleLengthToSlot(Source.Size, SourceBounds.H, FittedRect.H));
+end;
+
+function TransformNamePlayerSelectAvatar(const Source: TThemeStaticRectangle; const SourceBounds, SlotRect: TPlayerSlotRect): TThemeStaticRectangle;
+var
+ FittedRect: TPlayerSlotRect;
+begin
+ Result := Source;
+ FittedRect := GetFittedSlotRect(SourceBounds, SlotRect, 1.0);
+ Result.X := ScaleCoordToSlot(Source.X, SourceBounds.X, SourceBounds.W, FittedRect.X, FittedRect.W);
+ Result.Y := ScaleCoordToSlot(Source.Y, SourceBounds.Y, SourceBounds.H, FittedRect.Y, FittedRect.H);
+ Result.W := ScaleLengthToSlot(Source.W, SourceBounds.W, FittedRect.W);
+ Result.H := ScaleLengthToSlot(Source.H, SourceBounds.H, FittedRect.H);
+end;
+
+procedure AssignNamePlayerSelectSlot(var NameTheme: TThemeName; const Template: TNamePlayerSelectTemplate;
+ const SourceBounds, LayoutBounds: TPlayerSlotRect; PlayerIndex: integer);
+var
+ SlotRect: TPlayerSlotRect;
+begin
+ SlotRect := GetNamePlayerSelectSlotRect(PlayerIndex, UIni.IMaxPlayerCount, SourceBounds, LayoutBounds, NameTheme.PlayerSelectLayout);
+ NameTheme.PlayerSelect[PlayerIndex] := TransformNamePlayerSelectStatic(Template.Frame, SourceBounds, SlotRect);
+ NameTheme.PlayerSelectText[PlayerIndex] := TransformNamePlayerSelectText(Template.Text, SourceBounds, SlotRect);
+ NameTheme.PlayerSelectAvatar[PlayerIndex] := TransformNamePlayerSelectAvatar(Template.Avatar, SourceBounds, SlotRect);
+end;
+
+function GetThemePlayerScoreLayoutBounds(const BaseBounds, LayoutArea: TPlayerSlotRect;
+ PlayerCountOnScreen: integer): TPlayerSlotRect;
+var
+ Grid: TPlayerGrid;
+begin
+ Grid := GetScorePlayerGrid(PlayerCountOnScreen, LayoutArea.W, LayoutArea.H,
+ Theme.Score.PlayerLayoutExtraColsBias);
+ Result := GetScaledGridLayoutBounds(BaseBounds, LayoutArea, Grid);
+end;
+
+function TransformScoreStatic(const Source: TThemeStatic; const SourceBounds, SlotRect: TPlayerSlotRect): TThemeStatic;
+var
+ Scale: real;
+begin
+ Result := Source;
+ Result.X := ScaleCoordToSlot(Source.X, SourceBounds.X, SourceBounds.W, SlotRect.X, SlotRect.W);
+ Result.Y := ScaleCoordToSlot(Source.Y, SourceBounds.Y, SourceBounds.H, SlotRect.Y, SlotRect.H);
+ Result.W := ScaleLengthToSlot(Source.W, SourceBounds.W, SlotRect.W);
+ Result.H := ScaleLengthToSlot(Source.H, SourceBounds.H, SlotRect.H);
+ // Preserve 1px theme separators as hairlines instead of scaling them into bands.
+ if Source.W = 1 then
+ Result.W := 1;
+ if Source.H = 1 then
+ Result.H := 1;
+ Scale := Min(SlotRect.W / Max(1.0, SourceBounds.W), SlotRect.H / Max(1.0, SourceBounds.H));
+ Result.Reflectionspacing := Source.Reflectionspacing * Scale;
+end;
+
+function TransformScoreText(const Source: TThemeText; const SourceBounds, SlotRect: TPlayerSlotRect): TThemeText;
+var
+ Scale: real;
+begin
+ Result := Source;
+ Result.X := ScaleCoordToSlot(Source.X, SourceBounds.X, SourceBounds.W, SlotRect.X, SlotRect.W);
+ Result.Y := ScaleCoordToSlot(Source.Y, SourceBounds.Y, SourceBounds.H, SlotRect.Y, SlotRect.H);
+ Result.W := ScaleLengthToSlot(Source.W, SourceBounds.W, SlotRect.W);
+ Result.H := ScaleLengthToSlot(Source.H, SourceBounds.H, SlotRect.H);
+
+ Scale := Min(SlotRect.W / Max(1.0, SourceBounds.W), SlotRect.H / Max(1.0, SourceBounds.H));
+ Result.Size := Max(1, Round(Source.Size * Scale));
+ Result.ReflectionSpacing := Source.ReflectionSpacing * Scale;
+end;
+
+function TransformScoreStatics(const Source: AThemeStatic; const SourceBounds, SlotRect: TPlayerSlotRect): AThemeStatic;
+var
+ I: integer;
+begin
+ SetLength(Result, Length(Source));
+ for I := 0 to High(Source) do
+ Result[I] := TransformScoreStatic(Source[I], SourceBounds, SlotRect);
+end;
+
+function TransformScoreTexts(const Source: AThemeText; const SourceBounds, SlotRect: TPlayerSlotRect): AThemeText;
+var
+ I: integer;
+begin
+ SetLength(Result, Length(Source));
+ for I := 0 to High(Source) do
+ Result[I] := TransformScoreText(Source[I], SourceBounds, SlotRect);
+end;
+
+procedure AssignScoreThemeSlot(var ScoreTheme: TThemeScore; const Template: TScoreSlotThemeTemplate;
+ const SourceBounds, LayoutBounds: TPlayerSlotRect; LayoutPlayerCount, LayoutPlayerIndex, TargetSlotIndex: integer);
+var
+ SlotRect: TPlayerSlotRect;
+ Grid: TPlayerGrid;
+begin
+ Grid := GetScorePlayerGrid(LayoutPlayerCount, LayoutBounds.W, LayoutBounds.H,
+ ScoreTheme.PlayerLayoutExtraColsBias);
+ SlotRect := GetPlayerSlotRect(LayoutPlayerIndex, Grid, LayoutBounds.X, LayoutBounds.Y, LayoutBounds.W, LayoutBounds.H);
+
+ ScoreTheme.PlayerStatic[TargetSlotIndex] := TransformScoreStatics(Template.PlayerStatic, SourceBounds, SlotRect);
+ ScoreTheme.PlayerTexts[TargetSlotIndex] := TransformScoreTexts(Template.PlayerTexts, SourceBounds, SlotRect);
+ ScoreTheme.TextName[TargetSlotIndex] := TransformScoreText(Template.TextName, SourceBounds, SlotRect);
+ ScoreTheme.TextScore[TargetSlotIndex] := TransformScoreText(Template.TextScore, SourceBounds, SlotRect);
+ ScoreTheme.AvatarStatic[TargetSlotIndex] := TransformScoreStatic(Template.AvatarStatic, SourceBounds, SlotRect);
+ ScoreTheme.TextNotes[TargetSlotIndex] := TransformScoreText(Template.TextNotes, SourceBounds, SlotRect);
+ ScoreTheme.TextNotesScore[TargetSlotIndex] := TransformScoreText(Template.TextNotesScore, SourceBounds, SlotRect);
+ ScoreTheme.TextLineBonus[TargetSlotIndex] := TransformScoreText(Template.TextLineBonus, SourceBounds, SlotRect);
+ ScoreTheme.TextLineBonusScore[TargetSlotIndex] := TransformScoreText(Template.TextLineBonusScore, SourceBounds, SlotRect);
+ ScoreTheme.TextGoldenNotes[TargetSlotIndex] := TransformScoreText(Template.TextGoldenNotes, SourceBounds, SlotRect);
+ ScoreTheme.TextGoldenNotesScore[TargetSlotIndex] := TransformScoreText(Template.TextGoldenNotesScore, SourceBounds, SlotRect);
+ ScoreTheme.TextTotal[TargetSlotIndex] := TransformScoreText(Template.TextTotal, SourceBounds, SlotRect);
+ ScoreTheme.TextTotalScore[TargetSlotIndex] := TransformScoreText(Template.TextTotalScore, SourceBounds, SlotRect);
+ ScoreTheme.StaticBoxLightest[TargetSlotIndex] := TransformScoreStatic(Template.StaticBoxLightest, SourceBounds, SlotRect);
+ ScoreTheme.StaticBoxLight[TargetSlotIndex] := TransformScoreStatic(Template.StaticBoxLight, SourceBounds, SlotRect);
+ ScoreTheme.StaticBoxDark[TargetSlotIndex] := TransformScoreStatic(Template.StaticBoxDark, SourceBounds, SlotRect);
+ ScoreTheme.StaticRatings[TargetSlotIndex] := TransformScoreStatic(Template.StaticRatings, SourceBounds, SlotRect);
+ ScoreTheme.StaticBackLevel[TargetSlotIndex] := TransformScoreStatic(Template.StaticBackLevel, SourceBounds, SlotRect);
+ ScoreTheme.StaticBackLevelRound[TargetSlotIndex] := TransformScoreStatic(Template.StaticBackLevelRound, SourceBounds, SlotRect);
+ ScoreTheme.StaticLevel[TargetSlotIndex] := TransformScoreStatic(Template.StaticLevel, SourceBounds, SlotRect);
+ ScoreTheme.StaticLevelRound[TargetSlotIndex] := TransformScoreStatic(Template.StaticLevelRound, SourceBounds, SlotRect);
+end;
+
//-----------
//Helper procs to use TRGB in Opengl ...maybe this should be somewhere else
//-----------
@@ -1461,6 +1870,10 @@ function TTheme.LoadTheme(ThemeNum: integer; sColor: integer): boolean;
var
I, J: integer;
IniFile: TMemIniFile;
+ SectionList: TThemeSectionList;
+ NamePlayerSelectTemplate: TNamePlayerSelectTemplate;
+ NamePlayerSelectBounds: TPlayerSlotRect;
+ NamePlayerSelectLayoutBounds: TPlayerSlotRect;
begin
Result := false;
@@ -1551,12 +1964,36 @@ function TTheme.LoadTheme(ThemeNum: integer; sColor: integer): boolean;
ThemeLoadSelectSlide(Name.SelectPlayerColor, 'NameSelectPlayerColor');
ThemeLoadSelectSlide(Name.SelectPlayerLevel, 'NameSelectPlayerLevel');
+ ThemeLoadStatic(NamePlayerSelectTemplate.Frame, 'NamePlayerSelectTemplateFrame');
+ ThemeLoadText(NamePlayerSelectTemplate.Text, 'NamePlayerSelectTemplateText');
+ ThemeLoadStaticRectangle(NamePlayerSelectTemplate.Avatar, 'NamePlayerSelectTemplateAvatar');
+ Name.PlayerSelectTemplateFrame := NamePlayerSelectTemplate.Frame;
+ Name.PlayerSelectTemplateText := NamePlayerSelectTemplate.Text;
+ Name.PlayerSelectTemplateAvatar := NamePlayerSelectTemplate.Avatar;
+ SectionList := GetSectionList('NamePlayerSelectGrid');
+ if Length(SectionList) = 0 then
+ SectionList := GetSectionList('NamePlayerSelectLayout');
+ Name.PlayerSelectLayout.Area.X := ReadInteger(SectionList, 'GridX', ReadInteger(SectionList, 'X', 30));
+ Name.PlayerSelectLayout.Area.Y := ReadInteger(SectionList, 'GridY', ReadInteger(SectionList, 'Y', 185));
+ Name.PlayerSelectLayout.Area.W := ReadInteger(SectionList, 'GridW', ReadInteger(SectionList, 'W', 760));
+ Name.PlayerSelectLayout.Area.H := ReadInteger(SectionList, 'GridH', ReadInteger(SectionList, 'H', 155));
+ Name.PlayerSelectLayout.MinPlayerCount := ReadInteger(SectionList, 'MinimumVisibleSlots',
+ ReadInteger(SectionList, 'MinPlayerCount', 2));
+ Name.PlayerSelectLayout.MaxColumns := ReadInteger(SectionList, 'MaximumColumns',
+ ReadInteger(SectionList, 'MaxColumns', 12));
+ Name.PlayerSelectLayout.RowHeightDivisor := ReadFloat(SectionList, 'RowVerticalSpreadDivisor',
+ ReadFloat(SectionList, 'RowHeightDivisor', 1.5));
+ Name.PlayerSelectLayout.MaxScaleSmall := ReadFloat(SectionList, 'MaxScaleUpTo2Players',
+ ReadFloat(SectionList, 'MaxScaleSmall', 1.35));
+ Name.PlayerSelectLayout.MaxScaleMedium := ReadFloat(SectionList, 'MaxScaleUpTo4Players',
+ ReadFloat(SectionList, 'MaxScaleMedium', 1.15));
+ Name.PlayerSelectLayout.MaxScaleDefault := ReadFloat(SectionList, 'MaxScaleDefault',
+ ReadFloat(SectionList, 'MaxScaleDefault', 1.0));
+ NamePlayerSelectBounds := GetNamePlayerSelectTemplateBounds(NamePlayerSelectTemplate);
+ NamePlayerSelectLayoutBounds := GetNamePlayerSelectLayoutBounds(NamePlayerSelectBounds, Name.PlayerSelectLayout);
+
for I := 0 to UIni.IMaxPlayerCount-1 do
- begin
- ThemeLoadOptionalStatic(Name.PlayerSelect[I], 'NamePlayerSelectStatic' + IntToStr((I + 1)));
- ThemeLoadText(Name.PlayerSelectText[I], 'NamePlayerSelectStatic' + IntToStr((I + 1)) + 'Text');
- ThemeLoadOptionalStaticRectangle(Name.PlayerSelectAvatar[I], 'NamePlayerSelectStatic' + IntToStr((I + 1)) + 'Avatar');
- end;
+ AssignNamePlayerSelectSlot(Name, NamePlayerSelectTemplate, NamePlayerSelectBounds, NamePlayerSelectLayoutBounds, I);
ThemeLoadButton(Name.PlayerSelectCurrent, 'NamePlayerSelectCurrent');
@@ -1702,9 +2139,6 @@ function TTheme.LoadTheme(ThemeNum: integer; sColor: integer): boolean;
ThemeLoadPosition(Sing.Solo3PP3.SingBar, 'SingP3SingBar');
ThemeLoadPosition(Sing.Solo3PP3.Oscilloscope, 'SingP3ROscilloscope');
- ThemeLoadStatic(Sing.StaticSongName, 'SingSongNameStatic');
- ThemeLoadText(Sing.TextSongName, 'SingSongNameText');
-
// 3/6 players duet
ThemeLoadSingPlayerStatics(Sing.Duet3PP1, 'DuetP1ThreeP');
ThemeLoadSingPlayerStatics(Sing.Duet3PP2, 'DuetP2M');
@@ -1736,6 +2170,72 @@ function TTheme.LoadTheme(ThemeNum: integer; sColor: integer): boolean;
ThemeLoadSingPlayerStatics(Sing.Duet6PP5, 'P5DuetSixP');
ThemeLoadSingPlayerStatics(Sing.Duet6PP6, 'P6DuetSixP');
+ ThemeLoadSingPlayerStatics(Sing.PlayerTemplate, 'PlayerTemplate');
+ SectionList := GetSectionList('SingPlayerGrid');
+ Sing.PlayerLayout.ColumnContainerLeft := ReadInteger(SectionList, 'LaneAreaX', 40);
+ Sing.PlayerLayout.ColumnContainerTopReserved := ReadInteger(SectionList, 'LaneAreaY', 120);
+ Sing.PlayerLayout.ColumnContainerTopNoLyrics := ReadInteger(SectionList, 'LaneAreaYNoLyrics',
+ Sing.PlayerLayout.ColumnContainerTopReserved);
+ Sing.PlayerLayout.ColumnContainerWidth := ReadInteger(SectionList, 'LaneAreaW', 750);
+ Sing.PlayerLayout.LaneHeightReserved := ReadInteger(SectionList, 'LaneAreaHReserved', 335);
+ Sing.PlayerLayout.LaneHeightNoLyrics := ReadInteger(SectionList, 'LaneAreaHNoLyrics', 395);
+ Sing.PlayerLayout.ColumnGap := ReadInteger(SectionList, 'LaneColumnGap', 50);
+ Sing.PlayerLayout.RowGap := ReadInteger(SectionList, 'LaneRowGap', 0);
+ Sing.PlayerLayout.GridExtraLeft := ReadInteger(SectionList, 'LaneGridLeftInset', 20);
+ Sing.PlayerLayout.BaseLineSpacing := ReadInteger(SectionList, 'LaneBaseLineSpacing', 15);
+ Sing.PlayerLayout.GuideLineCount := ReadInteger(SectionList, 'LaneGuideLineCount', 9);
+ Sing.PlayerLayout.RowAnchorGuideIndex := ReadInteger(SectionList, 'LaneRowAnchorGuideIndex', 7);
+ Sing.PlayerLayout.WidgetScaleBaseWidth := ReadInteger(SectionList, 'WidgetScaleReferenceW', 300);
+ Sing.PlayerLayout.WidgetScalePerPlayer := ReadFloat(SectionList, 'WidgetScalePerPlayer', 0.02);
+ Sing.PlayerLayout.WidgetScaleMin := ReadFloat(SectionList, 'WidgetScaleMin', 0.82);
+
+ Sing.PlayerLayout.ColumnContainerWidth := Max(1, Sing.PlayerLayout.ColumnContainerWidth);
+ Sing.PlayerLayout.LaneHeightReserved := Max(1, Sing.PlayerLayout.LaneHeightReserved);
+ Sing.PlayerLayout.LaneHeightNoLyrics := Max(1, Sing.PlayerLayout.LaneHeightNoLyrics);
+ Sing.PlayerLayout.ColumnGap := Max(0, Sing.PlayerLayout.ColumnGap);
+ Sing.PlayerLayout.RowGap := Max(0, Sing.PlayerLayout.RowGap);
+ Sing.PlayerLayout.GridExtraLeft := Max(0, Sing.PlayerLayout.GridExtraLeft);
+ Sing.PlayerLayout.BaseLineSpacing := Max(1, Sing.PlayerLayout.BaseLineSpacing);
+ Sing.PlayerLayout.GuideLineCount := Max(2, Sing.PlayerLayout.GuideLineCount);
+ Sing.PlayerLayout.RowAnchorGuideIndex := EnsureRange(Sing.PlayerLayout.RowAnchorGuideIndex,
+ 0, Sing.PlayerLayout.GuideLineCount - 1);
+ Sing.PlayerLayout.WidgetScaleBaseWidth := Max(1, Sing.PlayerLayout.WidgetScaleBaseWidth);
+ Sing.PlayerLayout.WidgetScalePerPlayer := Max(0.0, Sing.PlayerLayout.WidgetScalePerPlayer);
+ Sing.PlayerLayout.WidgetScaleMin := EnsureRange(Sing.PlayerLayout.WidgetScaleMin, 0.1, 1.0);
+
+ SectionList := GetSectionList('SingPlayerWidgetPlacement');
+ Sing.PlayerWidgetLayout.MinFrameW := ReadInteger(SectionList, 'MinFrameW', 26);
+ Sing.PlayerWidgetLayout.MinFrameH := ReadInteger(SectionList, 'MinFrameH', 26);
+ Sing.PlayerWidgetLayout.MinScoreW := ReadInteger(SectionList, 'MinScoreW', 56);
+ Sing.PlayerWidgetLayout.MinScoreH := ReadInteger(SectionList, 'MinScoreH', 18);
+ Sing.PlayerWidgetLayout.HeaderOffsetLeft := ReadInteger(SectionList, 'HeaderLeftOffset', 30);
+ Sing.PlayerWidgetLayout.HeaderOffsetTopBase := ReadInteger(SectionList, 'HeaderTopOffsetBase', 40);
+ Sing.PlayerWidgetLayout.HeaderOffsetTopPerExtraRow := ReadInteger(SectionList,
+ 'HeaderTopOffsetPerExtraRow', 0);
+ Sing.PlayerWidgetLayout.MinAvatarInsetX := ReadInteger(SectionList, 'AvatarInsetMinX', 1);
+ Sing.PlayerWidgetLayout.MinAvatarInsetY := ReadInteger(SectionList, 'AvatarInsetMinY', 1);
+ Sing.PlayerWidgetLayout.NameGapBaseX := ReadInteger(SectionList, 'NameGapX', 10);
+ Sing.PlayerWidgetLayout.NameGapMinX := ReadInteger(SectionList, 'NameGapMinX', 8);
+ Sing.PlayerWidgetLayout.NamePaddingBaseX := ReadInteger(SectionList, 'NamePaddingX', 6);
+ Sing.PlayerWidgetLayout.NamePaddingMinX := ReadInteger(SectionList, 'NamePaddingMinX', 4);
+ Sing.PlayerWidgetLayout.NamePaddingBaseY := ReadInteger(SectionList, 'NamePaddingY', 6);
+ Sing.PlayerWidgetLayout.NamePaddingMinY := ReadInteger(SectionList, 'NamePaddingMinY', 3);
+ Sing.PlayerWidgetLayout.NameMinW := ReadInteger(SectionList, 'NameMinW', 24);
+ Sing.PlayerWidgetLayout.NameMinH := ReadInteger(SectionList, 'NameMinH', 14);
+ Sing.PlayerWidgetLayout.NameMinSize := ReadInteger(SectionList, 'NameMinSize', 10);
+ Sing.PlayerWidgetLayout.ScoreWidthFraction := ReadFloat(SectionList, 'ScoreWidthFractionOfLane', 0.36);
+ Sing.PlayerWidgetLayout.OscilloscopeGapBaseY := ReadInteger(SectionList, 'OscilloscopeGapY', 4);
+ Sing.PlayerWidgetLayout.OscilloscopeGapMinY := ReadInteger(SectionList, 'OscilloscopeGapMinY', 2);
+ Sing.PlayerWidgetLayout.OscilloscopeMinW := ReadInteger(SectionList, 'OscilloscopeMinW', 40);
+ Sing.PlayerWidgetLayout.OscilloscopeMinH := ReadInteger(SectionList, 'OscilloscopeMinH', 8);
+ Sing.PlayerWidgetLayout.PopupYOffsetSolo := ReadInteger(SectionList, 'PopupYOffsetSolo', 65);
+ Sing.PlayerWidgetLayout.PopupYOffsetDuet := ReadInteger(SectionList, 'PopupYOffsetDuet', 40);
+ Sing.PlayerWidgetLayout.PopupFontSizeSolo := ReadInteger(SectionList, 'PopupFontSizeSolo', 18);
+ Sing.PlayerWidgetLayout.PopupFontSizeDuet := ReadInteger(SectionList, 'PopupFontSizeDuet', 14);
+
+ ThemeLoadStatic(Sing.StaticSongName, 'SingSongNameStatic');
+ ThemeLoadText(Sing.TextSongName, 'SingSongNameText');
+
//Line Bonus Texts
Sing.LineBonusText[0] := Language.Translate('POPUP_AWFUL');
Sing.LineBonusText[1] := Sing.LineBonusText[0];
@@ -1751,18 +2251,7 @@ function TTheme.LoadTheme(ThemeNum: integer; sColor: integer): boolean;
ThemeLoadStatic(Sing.PausePopUp, 'PausePopUpStatic');
// Score
- ThemeLoadBasic(Score, 'Score');
-
- ThemeLoadText(Score.TextArtist, 'ScoreTextArtist');
- ThemeLoadText(Score.TextTitle, 'ScoreTextTitle');
- ThemeLoadText(Score.TextArtistTitle, 'ScoreTextArtistTitle');
-
- // Send Button's
- for I := 1 to 3 do
- ThemeLoadButton(Score.ButtonSend[I], 'ScoreButtonSend' + IntToStr(I));
-
- ThemeLoadStatic(Score.StaticNavigate, 'ScoreStaticNavigate');
- ThemeLoadText(Score.TextNavigate, 'ScoreTextNavigate');
+ ThemeScoreLoadData;
// Top5
ThemeLoadBasic(Top5, 'Top5');
@@ -3085,7 +3574,14 @@ function GetSystemColor(Color: integer): TRGB;
end;
end;
-function GetPlayerColor(Color: integer): TRGB;
+function BlendColors(const LeftColor, RightColor: TRGB): TRGB;
+begin
+ Result.R := (LeftColor.R + RightColor.R) / 2;
+ Result.G := (LeftColor.G + RightColor.G) / 2;
+ Result.B := (LeftColor.B + RightColor.B) / 2;
+end;
+
+function GetBasePlayerColor(Color: integer): TRGB;
begin
case (Color) of
1://blue
@@ -3193,7 +3689,18 @@ function GetPlayerColor(Color: integer): TRGB;
end;
end;
-function GetPlayerLightColor(Color: integer): TRGB;
+function GetPlayerColor(Color: integer): TRGB;
+var
+ LeftColor: integer;
+ RightColor: integer;
+begin
+ if TryGetMixedPlayerColorPair(Color, LeftColor, RightColor) then
+ Result := BlendColors(GetBasePlayerColor(LeftColor), GetBasePlayerColor(RightColor))
+ else
+ Result := GetBasePlayerColor(Color);
+end;
+
+function GetBasePlayerLightColor(Color: integer): TRGB;
begin
case (Color) of
1://blue
@@ -3301,6 +3808,17 @@ function GetPlayerLightColor(Color: integer): TRGB;
end;
end;
+function GetPlayerLightColor(Color: integer): TRGB;
+var
+ LeftColor: integer;
+ RightColor: integer;
+begin
+ if TryGetMixedPlayerColorPair(Color, LeftColor, RightColor) then
+ Result := BlendColors(GetBasePlayerLightColor(LeftColor), GetBasePlayerLightColor(RightColor))
+ else
+ Result := GetBasePlayerLightColor(Color);
+end;
+
function ColorSqrt(RGB: TRGB): TRGB;
begin
Result.R := sqrt(RGB.R);
@@ -3708,64 +4226,100 @@ procedure TTheme.ThemePartyLoad;
CloseFile;
end;
-procedure TTheme.ThemeScoreLoad;
+procedure TTheme.ThemeScoreLoadData;
var
I: integer;
- prefix: string;
+ ScreenCount: integer;
+ LayoutPlayerCount: integer;
+ LayoutPlayerIndex: integer;
+ SectionList: TThemeSectionList;
+ BaseTemplate: TScoreSlotThemeTemplate;
+ BaseBounds: TPlayerSlotRect;
+ LayoutBounds: TPlayerSlotRect;
begin
-
- OpenFile(Ini.Theme);
-
// Score
ThemeLoadBasic(Score, 'Score');
ThemeLoadText(Score.TextArtist, 'ScoreTextArtist');
ThemeLoadText(Score.TextTitle, 'ScoreTextTitle');
ThemeLoadText(Score.TextArtistTitle, 'ScoreTextArtistTitle');
-
- if (Ini.Players < 3) or (Ini.Screens = 1) then
- prefix := ''
- else
+ SectionList := GetSectionList('ScorePlayerSlotArea');
+ if Length(SectionList) = 0 then
+ SectionList := GetSectionList('ScorePlayerLayout');
+ Score.PlayerLayoutArea.X := ReadInteger(SectionList, 'AreaX', ReadInteger(SectionList, 'X', 20));
+ Score.PlayerLayoutArea.Y := ReadInteger(SectionList, 'AreaY', ReadInteger(SectionList, 'Y', 110));
+ Score.PlayerLayoutArea.W := ReadInteger(SectionList, 'AreaW', ReadInteger(SectionList, 'W', 760));
+ Score.PlayerLayoutArea.H := ReadInteger(SectionList, 'AreaH', ReadInteger(SectionList, 'H', 420));
+ Score.PlayerLayoutExtraColsBias := ReadInteger(SectionList, 'ExtraColsBias', 0);
+
+ for I := 1 to UIni.IMaxPlayerCount do
begin
- // 4 players 1 screen
- if (Ini.Players = 3) then
- prefix := 'FourP';
-
- // 6 players 1 screen
- if (Ini.Players = 4) then
- prefix := 'SixP';
+ SetLength(Score.PlayerStatic[I], 0);
+ SetLength(Score.PlayerTexts[I], 0);
+ Score.TextName[I] := Default(TThemeText);
+ Score.TextScore[I] := Default(TThemeText);
+ Score.AvatarStatic[I] := Default(TThemeStatic);
+ Score.TextNotes[I] := Default(TThemeText);
+ Score.TextNotesScore[I] := Default(TThemeText);
+ Score.TextLineBonus[I] := Default(TThemeText);
+ Score.TextLineBonusScore[I] := Default(TThemeText);
+ Score.TextGoldenNotes[I] := Default(TThemeText);
+ Score.TextGoldenNotesScore[I] := Default(TThemeText);
+ Score.TextTotal[I] := Default(TThemeText);
+ Score.TextTotalScore[I] := Default(TThemeText);
+ Score.StaticBoxLightest[I] := Default(TThemeStatic);
+ Score.StaticBoxLight[I] := Default(TThemeStatic);
+ Score.StaticBoxDark[I] := Default(TThemeStatic);
+ Score.StaticRatings[I] := Default(TThemeStatic);
+ Score.StaticBackLevel[I] := Default(TThemeStatic);
+ Score.StaticBackLevelRound[I] := Default(TThemeStatic);
+ Score.StaticLevel[I] := Default(TThemeStatic);
+ Score.StaticLevelRound[I] := Default(TThemeStatic);
end;
- for I := 1 to 6 do
- begin
- ThemeLoadStatics(Score.PlayerStatic[I], 'Score' + prefix + 'Player' + IntToStr(I) + 'Static');
- ThemeLoadTexts(Score.PlayerTexts[I], 'Score' + prefix + 'Player' + IntToStr(I) + 'Text');
- ThemeLoadStatic(Score.AvatarStatic[I], 'Score' + prefix + 'Player' + IntToStr(I) + 'Avatar');
-
- ThemeLoadText(Score.TextName[I], 'Score' + prefix + 'TextName' + IntToStr(I));
- ThemeLoadText(Score.TextScore[I], 'Score' + prefix + 'TextScore' + IntToStr(I));
- ThemeLoadText(Score.TextNotes[I], 'Score' + prefix + 'TextNotes' + IntToStr(I));
- ThemeLoadText(Score.TextNotesScore[I], 'Score' + prefix + 'TextNotesScore' + IntToStr(I));
- ThemeLoadText(Score.TextLineBonus[I], 'Score' + prefix + 'TextLineBonus' + IntToStr(I));
- ThemeLoadText(Score.TextLineBonusScore[I], 'Score' + prefix + 'TextLineBonusScore' + IntToStr(I));
- ThemeLoadText(Score.TextGoldenNotes[I], 'Score' + prefix + 'TextGoldenNotes' + IntToStr(I));
- ThemeLoadText(Score.TextGoldenNotesScore[I], 'Score' + prefix + 'TextGoldenNotesScore' + IntToStr(I));
- ThemeLoadText(Score.TextTotal[I], 'Score' + prefix + 'TextTotal' + IntToStr(I));
- ThemeLoadText(Score.TextTotalScore[I], 'Score' + prefix + 'TextTotalScore' + IntToStr(I));
-
- ThemeLoadStatic(Score.StaticBoxLightest[I], 'Score' + prefix + 'StaticBoxLightest' + IntToStr(I));
- ThemeLoadStatic(Score.StaticBoxLight[I], 'Score' + prefix + 'StaticBoxLight' + IntToStr(I));
- ThemeLoadStatic(Score.StaticBoxDark[I], 'Score' + prefix + 'StaticBoxDark' + IntToStr(I));
-
- ThemeLoadStatic(Score.StaticBackLevel[I], 'Score' + prefix + 'StaticBackLevel' + IntToStr(I));
- ThemeLoadStatic(Score.StaticBackLevelRound[I], 'Score' + prefix + 'StaticBackLevelRound' + IntToStr(I));
- ThemeLoadStatic(Score.StaticLevel[I], 'Score' + prefix + 'StaticLevel' + IntToStr(I));
- ThemeLoadStatic(Score.StaticLevelRound[I], 'Score' + prefix + 'StaticLevelRound' + IntToStr(I));
- ThemeLoadStatic(Score.StaticRatings[I], 'Score' + prefix + 'StaticRatingPicture' + IntToStr(I));
- end;
+ ThemeLoadStatics(BaseTemplate.PlayerStatic, 'ScorePlayerTemplateStatic');
+ ThemeLoadTexts(BaseTemplate.PlayerTexts, 'ScorePlayerTemplateText');
+ ThemeLoadStatic(BaseTemplate.AvatarStatic, 'ScorePlayerTemplateAvatar');
+ ThemeLoadText(BaseTemplate.TextName, 'ScorePlayerTemplateTextName');
+ ThemeLoadText(BaseTemplate.TextScore, 'ScorePlayerTemplateTextScore');
+ ThemeLoadText(BaseTemplate.TextNotes, 'ScorePlayerTemplateTextNotes');
+ ThemeLoadText(BaseTemplate.TextNotesScore, 'ScorePlayerTemplateTextNotesScore');
+ ThemeLoadText(BaseTemplate.TextLineBonus, 'ScorePlayerTemplateTextLineBonus');
+ ThemeLoadText(BaseTemplate.TextLineBonusScore, 'ScorePlayerTemplateTextLineBonusScore');
+ ThemeLoadText(BaseTemplate.TextGoldenNotes, 'ScorePlayerTemplateTextGoldenNotes');
+ ThemeLoadText(BaseTemplate.TextGoldenNotesScore, 'ScorePlayerTemplateTextGoldenNotesScore');
+ ThemeLoadText(BaseTemplate.TextTotal, 'ScorePlayerTemplateTextTotal');
+ ThemeLoadText(BaseTemplate.TextTotalScore, 'ScorePlayerTemplateTextTotalScore');
+ ThemeLoadStatic(BaseTemplate.StaticBoxLightest, 'ScorePlayerTemplateStaticBoxLightest');
+ ThemeLoadStatic(BaseTemplate.StaticBoxLight, 'ScorePlayerTemplateStaticBoxLight');
+ ThemeLoadStatic(BaseTemplate.StaticBoxDark, 'ScorePlayerTemplateStaticBoxDark');
+ ThemeLoadStatic(BaseTemplate.StaticBackLevel, 'ScorePlayerTemplateStaticBackLevel');
+ ThemeLoadStatic(BaseTemplate.StaticBackLevelRound, 'ScorePlayerTemplateStaticBackLevelRound');
+ ThemeLoadStatic(BaseTemplate.StaticLevel, 'ScorePlayerTemplateStaticLevel');
+ ThemeLoadStatic(BaseTemplate.StaticLevelRound, 'ScorePlayerTemplateStaticLevelRound');
+ ThemeLoadStatic(BaseTemplate.StaticRatings, 'ScorePlayerTemplateStaticRatingPicture');
+ for I := 1 to High(Score.ButtonSend) do
+ ThemeLoadButton(Score.ButtonSend[I], 'ScoreButtonSend' + IntToStr(I));
+ ThemeLoadStatic(Score.StaticNavigate, 'ScoreStaticNavigate');
+ ThemeLoadText(Score.TextNavigate, 'ScoreTextNavigate');
+
+ BaseBounds := GetScoreTemplateBounds(BaseTemplate);
+
+ ScreenCount := Ini.Screens + 1;
+ if ScreenCount > 1 then
+ LayoutPlayerCount := GetScreenPlayerCount(UIni.IPlayersVals[Ini.Players], ScreenCount, 1)
+ else
+ LayoutPlayerCount := UIni.IPlayersVals[Ini.Players];
+ LayoutBounds := GetThemePlayerScoreLayoutBounds(BaseBounds, Score.PlayerLayoutArea, LayoutPlayerCount);
+ for LayoutPlayerIndex := 0 to LayoutPlayerCount - 1 do
+ AssignScoreThemeSlot(Score, BaseTemplate, BaseBounds, LayoutBounds, LayoutPlayerCount, LayoutPlayerIndex, LayoutPlayerIndex + 1);
+end;
+procedure TTheme.ThemeScoreLoad;
+begin
+ OpenFile(Ini.Theme);
+ ThemeScoreLoadData;
CloseFile;
-
end;
procedure TTheme.ThemeSongLoad;
@@ -3831,7 +4385,7 @@ procedure TTheme.ThemeSongLoad;
Song.Cover.H := ReadInteger(SectionList, 'H', 200);
// Song menu modes: 0 - roulette, 1 - chessboard, 2 - list
-
+
if (TSongMenuMode(Ini.SongMenu) = smChessboard) then
begin
Song.Cover.Rows := ReadInteger(SectionList, 'Rows', 4);
@@ -3925,17 +4479,11 @@ procedure TTheme.ThemeSongLoad;
// Duet Singers
ThemeLoadStatic (Song.Static2PlayersDuetSingerP1, 'Song' + prefix + 'Static2PlayersDuetSingerP1');
ThemeLoadStatic (Song.Static2PlayersDuetSingerP2, 'Song' + prefix + 'Static2PlayersDuetSingerP2');
- ThemeLoadText (Song.Text2PlayersDuetSingerP1, 'Song' + prefix + 'Text2PlayersDuetSingerP1');
- ThemeLoadText (Song.Text2PlayersDuetSingerP2, 'Song' + prefix + 'Text2PlayersDuetSingerP2');
ThemeLoadStatic (Song.Static3PlayersDuetSingerP1, 'Song' + prefix + 'Static3PlayersDuetSingerP1');
ThemeLoadStatic (Song.Static3PlayersDuetSingerP2, 'Song' + prefix + 'Static3PlayersDuetSingerP2');
ThemeLoadStatic (Song.Static3PlayersDuetSingerP3, 'Song' + prefix + 'Static3PlayersDuetSingerP3');
- ThemeLoadText (Song.Text3PlayersDuetSingerP1, 'Song' + prefix + 'Text3PlayersDuetSingerP1');
- ThemeLoadText (Song.Text3PlayersDuetSingerP2, 'Song' + prefix + 'Text3PlayersDuetSingerP2');
- ThemeLoadText (Song.Text3PlayersDuetSingerP3, 'Song' + prefix + 'Text3PlayersDuetSingerP3');
- // 4/6 players 1 screen
ThemeLoadStatic (Song.Static4PlayersDuetSingerP3, 'Song' + prefix + 'Static4PlayersDuetSingerP3');
ThemeLoadStatic (Song.Static4PlayersDuetSingerP4, 'Song' + prefix + 'Static4PlayersDuetSingerP4');
@@ -3943,6 +4491,19 @@ procedure TTheme.ThemeSongLoad;
ThemeLoadStatic (Song.Static6PlayersDuetSingerP5, 'Song' + prefix + 'Static6PlayersDuetSingerP5');
ThemeLoadStatic (Song.Static6PlayersDuetSingerP6, 'Song' + prefix + 'Static6PlayersDuetSingerP6');
+ ThemeLoadText (Song.Text2PlayersDuetSingerP1, 'Song' + prefix + 'Text2PlayersDuetSingerP1');
+ ThemeLoadText (Song.Text2PlayersDuetSingerP2, 'Song' + prefix + 'Text2PlayersDuetSingerP2');
+
+ ThemeLoadText (Song.Text3PlayersDuetSingerP1, 'Song' + prefix + 'Text3PlayersDuetSingerP1');
+ ThemeLoadText (Song.Text3PlayersDuetSingerP2, 'Song' + prefix + 'Text3PlayersDuetSingerP2');
+ ThemeLoadText (Song.Text3PlayersDuetSingerP3, 'Song' + prefix + 'Text3PlayersDuetSingerP3');
+
+ SectionList := GetSectionList('Song' + prefix + 'DuetSingerArea');
+ Song.DuetSingerArea.X := ReadInteger(SectionList, 'X', Song.Static2PlayersDuetSingerP1.X);
+ Song.DuetSingerArea.Y := ReadInteger(SectionList, 'Y', Song.Static2PlayersDuetSingerP1.Y);
+ Song.DuetSingerArea.W := ReadInteger(SectionList, 'W', Song.Static2PlayersDuetSingerP1.W);
+ Song.DuetSingerArea.H := ReadInteger(SectionList, 'H', Song.Static2PlayersDuetSingerP1.H);
+
//Party Mode
ThemeLoadStatic(Song.StaticTeam1Joker1, 'Song' + prefix + 'StaticTeam1Joker1');
ThemeLoadStatic(Song.StaticTeam1Joker2, 'Song' + prefix + 'StaticTeam1Joker2');
diff --git a/src/screens/UScreenMain.pas b/src/screens/UScreenMain.pas
index 4408f14b3..3cc330cb1 100644
--- a/src/screens/UScreenMain.pas
+++ b/src/screens/UScreenMain.pas
@@ -172,10 +172,7 @@ function TScreenMain.ParseInput(PressedKey: Cardinal; CharCode: UCS4Char;
begin
if (Songs.SongList.Count >= 1) then
begin
- if (Ini.Players >= 0) and (Ini.Players <= 3) then
- PlayersPlay := Ini.Players + 1;
- if (Ini.Players = 4) then
- PlayersPlay := 6;
+ PlayersPlay := UIni.IPlayersVals[Ini.Players];
if Ini.OnSongClick = sSelectPlayer then
FadeTo(@ScreenSong)
diff --git a/src/screens/UScreenName.pas b/src/screens/UScreenName.pas
index 43193cab1..d2a192d80 100644
--- a/src/screens/UScreenName.pas
+++ b/src/screens/UScreenName.pas
@@ -55,11 +55,16 @@ interface
TScreenName = class(TMenu)
private
PlayersCount: cardinal;
+ PlayersCountIID: integer;
PlayerAvatar: cardinal;
PlayerName: cardinal;
+ PlayerNameIID: integer;
PlayerColor: cardinal;
+ PlayerColorIID: integer;
PlayerSelect: cardinal;
+ PlayerSelectIID: integer;
PlayerSelectLevel: cardinal;
+ PlayerSelectLevelIID: integer;
CountIndex: integer;
PlayerIndex: integer;
@@ -90,7 +95,7 @@ TScreenName = class(TMenu)
PlayerAvatarButtonMD5: array of UTF8String;
public
Goto_SingScreen: boolean; //If true then next Screen in SingScreen
-
+
constructor Create; override;
function ShouldHandleInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean; out SuppressKey: boolean): boolean; override;
function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
@@ -114,6 +119,7 @@ TScreenName = class(TMenu)
procedure GenerateAvatars();
procedure SetPlayerAvatar(Player: integer);
+ procedure ApplyPlayerSelectLayout(Player, PlayerCount: integer);
end;
var
@@ -134,12 +140,54 @@ implementation
UMain,
UMenuButton,
UPath,
+ UPlayerLayout,
USkins,
USongs,
UTime,
UUnicodeUtils,
Math;
+function GetNamePlayerSelectBaseBounds: TPlayerSlotRect;
+begin
+ Result := UThemes.GetNamePlayerSelectBaseBounds(Theme.Name);
+end;
+
+function GetNamePlayerSelectLayoutBounds(const BaseBounds: TPlayerSlotRect; PlayerCount: integer): TPlayerSlotRect;
+begin
+ Result := UThemes.GetNamePlayerSelectLayoutBounds(BaseBounds, Theme.Name.PlayerSelectLayout);
+end;
+
+function GetNamePlayerSelectSlotRect(PlayerIndex, PlayerCount: integer; const BaseBounds, LayoutBounds: TPlayerSlotRect): TPlayerSlotRect;
+begin
+ Result := UThemes.GetNamePlayerSelectSlotRect(PlayerIndex, PlayerCount, BaseBounds, LayoutBounds, Theme.Name.PlayerSelectLayout);
+end;
+
+function ScaleNameCoord(const Value, SourceStart, SourceSize, TargetStart, TargetSize: integer): integer;
+begin
+ Result := ScaleCoordToSlot(Value, SourceStart, SourceSize, TargetStart, TargetSize);
+end;
+
+function ScaleNameLength(const Value, SourceSize, TargetSize: integer): integer;
+begin
+ Result := ScaleLengthToSlot(Value, SourceSize, TargetSize);
+end;
+
+function GetNamePlayerSelectFittedRect(PlayerIndex, PlayerCount: integer): TPlayerSlotRect;
+var
+ BaseBounds: TPlayerSlotRect;
+ LayoutBounds: TPlayerSlotRect;
+ SlotRect: TPlayerSlotRect;
+ MaxScale: real;
+begin
+ BaseBounds := GetNamePlayerSelectBaseBounds;
+ LayoutBounds := GetNamePlayerSelectLayoutBounds(BaseBounds, PlayerCount);
+ SlotRect := GetNamePlayerSelectSlotRect(PlayerIndex, PlayerCount, BaseBounds, LayoutBounds);
+
+ MaxScale := UThemes.GetNamePlayerSelectMaxScale(PlayerCount, Theme.Name.PlayerSelectLayout);
+
+ Result := GetFittedSlotRect(BaseBounds, SlotRect, MaxScale);
+end;
+
function TScreenName.ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: integer): boolean;
var
I: integer;
@@ -183,7 +231,7 @@ function TScreenName.ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: in
if InRegion(X, Y, Button[PlayerAvatarButton[Btn]].GetMouseOverArea) then
begin
- Interaction := 2;
+ Interaction := PlayerAvatarIID;
ParseInput(SDLK_LEFT, 0, true);
ParseInput(SDLK_LEFT, 0, true);
@@ -196,7 +244,7 @@ function TScreenName.ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: in
if InRegion(X, Y, Button[PlayerAvatarButton[Btn]].GetMouseOverArea) then
begin
- Interaction := 2;
+ Interaction := PlayerAvatarIID;
ParseInput(SDLK_LEFT, 0, true);
end;
@@ -208,7 +256,7 @@ function TScreenName.ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: in
if InRegion(X, Y, Button[PlayerAvatarButton[Btn]].GetMouseOverArea) then
begin
- Interaction := 2;
+ Interaction := PlayerAvatarIID;
ParseInput(SDLK_RIGHT, 0, true);
end;
@@ -220,17 +268,18 @@ function TScreenName.ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: in
if InRegion(X, Y, Button[PlayerAvatarButton[Btn]].GetMouseOverArea) then
begin
- Interaction := 2;
+ Interaction := PlayerAvatarIID;
ParseInput(SDLK_RIGHT, 0, true);
ParseInput(SDLK_RIGHT, 0, true);
end;
// click for change player profile
- for I := 0 to 5 do
+ for I := 0 to High(PlayerCurrent) do
begin
if Statics[PlayerCurrent[I]].Visible and InRegion(X, Y, Statics[PlayerCurrent[I]].GetMouseOverArea) then
begin
+ Interaction := PlayerSelectIID;
PlayerIndex := I;
RefreshProfile();
@@ -247,18 +296,11 @@ function TScreenName.ShouldHandleInput(PressedKey: cardinal; CharCode: UCS4Char;
begin
Result := inherited;
// only suppress special keys for now
- case PressedKey of
- // Templates for Names Mod
- SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_F11, SDLK_F12:
- if (Button[PlayerName].Selected) then
- begin
- SuppressKey := true;
- end
- else
- begin
- Result := false;
- end;
- end;
+ if GetNameTemplateIndexFromKey(PressedKey) <> -1 then
+ if (Button[PlayerName].Selected) then
+ SuppressKey := true
+ else
+ Result := false;
end;
function TScreenName.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
@@ -285,6 +327,15 @@ function TScreenName.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Presse
end;
end;
+ procedure HandleTemplateHotkey;
+ var
+ TemplateIndex: integer;
+ begin
+ TemplateIndex := GetNameTemplateIndexFromKey(PressedKey);
+ if (TemplateIndex >= 0) and (TemplateIndex <= High(Ini.NameTemplate)) then
+ HandleNameTemplate(TemplateIndex);
+ end;
+
begin
Result := true;
if (PressedDown) then
@@ -304,7 +355,7 @@ function TScreenName.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Presse
end;
end;
end
- else if (Interaction = 3) and (IsPrintableChar(CharCode)) then
+ else if (Interaction = PlayerNameIID) and (IsPrintableChar(CharCode)) then
begin
// pass printable chars to button
Button[PlayerName].Text[0].Text := Button[PlayerName].Text[0].Text +
@@ -317,23 +368,13 @@ function TScreenName.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Presse
// check special keys
case PressedKey of
- // Templates for Names Mod
- SDLK_F1: HandleNameTemplate(0);
- SDLK_F2: HandleNameTemplate(1);
- SDLK_F3: HandleNameTemplate(2);
- SDLK_F4: HandleNameTemplate(3);
- SDLK_F5: HandleNameTemplate(4);
- SDLK_F6: HandleNameTemplate(5);
- SDLK_F7: HandleNameTemplate(6);
- SDLK_F8: HandleNameTemplate(7);
- SDLK_F9: HandleNameTemplate(8);
- SDLK_F10: HandleNameTemplate(9);
- SDLK_F11: HandleNameTemplate(10);
- SDLK_F12: HandleNameTemplate(11);
+ SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, SDLK_F6,
+ SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_F11, SDLK_F12:
+ HandleTemplateHotkey;
SDLK_BACKSPACE:
begin
- if (Interaction = 3) then
+ if (Interaction = PlayerNameIID) then
begin
Button[PlayerName].Text[0].DeleteLastLetter();
PlayerNames[PlayerIndex] := Button[PlayerName].Text[0].Text;
@@ -449,13 +490,13 @@ function TScreenName.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Presse
begin
AudioPlayback.PlaySound(SoundLib.Change);
- if (Interaction in [0, 4, 5]) then
+ if (Interaction in [PlayersCountIID, PlayerColorIID, PlayerSelectLevelIID]) then
InteractInc;
- if (Interaction = 0) then
+ if (Interaction = PlayersCountIID) then
RefreshPlayers();
- if (Interaction = 1) then
+ if (Interaction = PlayerSelectIID) then
begin //TODO: adapt this to new playersize
if (PlayerIndex < UIni.IPlayersVals[CountIndex]-1) then
begin
@@ -468,7 +509,7 @@ function TScreenName.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Presse
end;
end;
- if (Interaction = 2) then
+ if (Interaction = PlayerAvatarIID) then
begin
SelectNext;
SetAvatarScroll;
@@ -476,13 +517,13 @@ function TScreenName.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Presse
SetPlayerAvatar(PlayerIndex);
end;
- if (Interaction = 4) then
+ if (Interaction = PlayerColorIID) then
begin
RefreshColor();
SelectsS[PlayerColor].SetSelect(true);
end;
- if (Interaction = 5) then
+ if (Interaction = PlayerSelectLevelIID) then
begin
PlayerLevel[PlayerIndex] := LevelIndex;
end;
@@ -492,13 +533,13 @@ function TScreenName.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Presse
begin
AudioPlayback.PlaySound(SoundLib.Change);
- if (Interaction in [0, 4, 5]) then
+ if (Interaction in [PlayersCountIID, PlayerColorIID, PlayerSelectLevelIID]) then
InteractDec;
- if (Interaction = 0) then
+ if (Interaction = PlayersCountIID) then
RefreshPlayers();
- if (Interaction = 1) then
+ if (Interaction = PlayerSelectIID) then
begin
if (PlayerIndex > 0) then
begin
@@ -511,7 +552,7 @@ function TScreenName.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Presse
end;
end;
- if (Interaction = 2) then
+ if (Interaction = PlayerAvatarIID) then
begin
SelectPrev;
SetAvatarScroll;
@@ -519,16 +560,17 @@ function TScreenName.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Presse
SetPlayerAvatar(PlayerIndex);
end;
- if (Interaction = 4) then
+ if (Interaction = PlayerColorIID) then
begin
RefreshColor();
SelectsS[PlayerColor].SetSelect(true);
end;
- if (Interaction = 5) then
+ if (Interaction = PlayerSelectLevelIID) then
begin
PlayerLevel[PlayerIndex] := LevelIndex;
end;
+
end;
end;
@@ -542,15 +584,27 @@ procedure TScreenName.GenerateAvatars();
Avatar: TAvatar;
AvatarFile: IPath;
Hash: string;
+ GenericNoAvatarFile: IPath;
+ NoAvatarFile: IPath;
begin
SetLength(PlayerAvatarButton, Length(AvatarsList) + 1);
SetLength(PlayerAvatarButtonMD5, Length(AvatarsList) + 1);
// 1st no-avatar dummy
+ GenericNoAvatarFile := Skin.SkinPath.Append(Path('[name]noavatar.png'));
for I := 1 to UIni.IMaxPlayerCount do
begin
- NoAvatarTexture[I] := Texture.GetTexture(Skin.GetTextureFileName('NoAvatar_P' + IntToStr(I)), TEXTURE_TYPE_TRANSPARENT, $FFFFFF);
+ if GenericNoAvatarFile.IsFile() then
+ NoAvatarFile := GenericNoAvatarFile
+ else
+ begin
+ NoAvatarFile := Skin.GetTextureFileName('NoAvatar_P' + IntToStr(I));
+ if not NoAvatarFile.IsSet then
+ NoAvatarFile := Skin.GetTextureFileName('NoAvatar_P1');
+ end;
+
+ NoAvatarTexture[I] := Texture.GetTexture(NoAvatarFile, TEXTURE_TYPE_TRANSPARENT, $FFFFFF);
end;
// create no-avatar
@@ -592,8 +646,69 @@ procedure TScreenName.GenerateAvatars();
end;
procedure TScreenName.ChangeSelectPlayerPosition(Player: integer);
+var
+ BaseBounds: TPlayerSlotRect;
+ Count: integer;
+ FittedRect: TPlayerSlotRect;
+ SelectButton: integer;
+begin
+ Count := UIni.IPlayersVals[CountIndex];
+ BaseBounds := GetNamePlayerSelectBaseBounds;
+ FittedRect := GetNamePlayerSelectFittedRect(Player, Count);
+
+ Button[PlayerSelect].X := ScaleNameCoord(
+ Theme.Name.PlayerSelectCurrent.X, BaseBounds.X, BaseBounds.W, FittedRect.X, FittedRect.W);
+ Button[PlayerSelect].Y := ScaleNameCoord(
+ Theme.Name.PlayerSelectCurrent.Y, BaseBounds.Y, BaseBounds.H, FittedRect.Y, FittedRect.H);
+ Button[PlayerSelect].W := ScaleNameLength(
+ Theme.Name.PlayerSelectCurrent.W, BaseBounds.W, FittedRect.W);
+ Button[PlayerSelect].H := ScaleNameLength(
+ Theme.Name.PlayerSelectCurrent.H, BaseBounds.H, FittedRect.H);
+ Button[PlayerSelect].SelectW := Button[PlayerSelect].W;
+ Button[PlayerSelect].SelectH := Button[PlayerSelect].H;
+
+ SelectButton := Interactions[PlayerSelectIID].Num;
+ Button[SelectButton].X := Button[PlayerSelect].X;
+ Button[SelectButton].Y := Button[PlayerSelect].Y;
+ Button[SelectButton].W := Button[PlayerSelect].W;
+ Button[SelectButton].H := Button[PlayerSelect].H;
+ Button[SelectButton].SelectW := Button[PlayerSelect].SelectW;
+ Button[SelectButton].SelectH := Button[PlayerSelect].SelectH;
+end;
+
+procedure TScreenName.ApplyPlayerSelectLayout(Player, PlayerCount: integer);
+var
+ BaseBounds: TPlayerSlotRect;
+ FittedRect: TPlayerSlotRect;
begin
- Button[PlayerSelect].X := Theme.Name.PlayerSelect[Player].X + Theme.Name.PlayerSelectCurrent.X;
+ BaseBounds := GetNamePlayerSelectBaseBounds;
+ FittedRect := GetNamePlayerSelectFittedRect(Player, PlayerCount);
+
+ Statics[PlayerCurrent[Player]].Texture.X := ScaleNameCoord(
+ Theme.Name.PlayerSelectTemplateFrame.X, BaseBounds.X, BaseBounds.W, FittedRect.X, FittedRect.W);
+ Statics[PlayerCurrent[Player]].Texture.Y := ScaleNameCoord(
+ Theme.Name.PlayerSelectTemplateFrame.Y, BaseBounds.Y, BaseBounds.H, FittedRect.Y, FittedRect.H);
+ Statics[PlayerCurrent[Player]].Texture.W := ScaleNameLength(
+ Theme.Name.PlayerSelectTemplateFrame.W, BaseBounds.W, FittedRect.W);
+ Statics[PlayerCurrent[Player]].Texture.H := ScaleNameLength(
+ Theme.Name.PlayerSelectTemplateFrame.H, BaseBounds.H, FittedRect.H);
+
+ Text[PlayerCurrentText[Player]].X := ScaleNameCoord(
+ Theme.Name.PlayerSelectTemplateText.X, BaseBounds.X, BaseBounds.W, FittedRect.X, FittedRect.W);
+ Text[PlayerCurrentText[Player]].Y := ScaleNameCoord(
+ Theme.Name.PlayerSelectTemplateText.Y, BaseBounds.Y, BaseBounds.H, FittedRect.Y, FittedRect.H) -
+ Max(2, ScaleNameLength(4, BaseBounds.H, FittedRect.H));
+ Text[PlayerCurrentText[Player]].Size := Max(8, ScaleNameLength(
+ Theme.Name.PlayerSelectTemplateText.Size, BaseBounds.H, FittedRect.H));
+
+ Statics[PlayerCurrentAvatar[Player]].Texture.X := ScaleNameCoord(
+ Theme.Name.PlayerSelectTemplateAvatar.X, BaseBounds.X, BaseBounds.W, FittedRect.X, FittedRect.W);
+ Statics[PlayerCurrentAvatar[Player]].Texture.Y := ScaleNameCoord(
+ Theme.Name.PlayerSelectTemplateAvatar.Y, BaseBounds.Y, BaseBounds.H, FittedRect.Y, FittedRect.H);
+ Statics[PlayerCurrentAvatar[Player]].Texture.W := ScaleNameLength(
+ Theme.Name.PlayerSelectTemplateAvatar.W, BaseBounds.W, FittedRect.W);
+ Statics[PlayerCurrentAvatar[Player]].Texture.H := ScaleNameLength(
+ Theme.Name.PlayerSelectTemplateAvatar.H, BaseBounds.H, FittedRect.H);
end;
procedure TScreenName.RefreshPlayers();
@@ -608,8 +723,10 @@ procedure TScreenName.RefreshPlayers();
PlayerIndex := PlayerIndex - 1;
// Player Colors
- for I := Count-1 downto 0 do
+ for I := 0 to Count-1 do
begin
+ ApplyPlayerSelectLayout(I, Count);
+
if (Ini.PlayerColor[I] > 0) then
Num[I] := NoRepeatColors(Ini.PlayerColor[I], I, 1)
else
@@ -808,6 +925,7 @@ constructor TScreenName.Create;
Theme.Name.SelectPlayersCount.oneItemOnly := true;
Theme.Name.SelectPlayersCount.showArrows := true;
PlayersCount := AddSelectSlide(Theme.Name.SelectPlayersCount, CountIndex, IPlayers);
+ PlayersCountIID := High(Interactions);
for I := 0 to UIni.IMaxPlayerCount -1 do
begin
@@ -817,20 +935,31 @@ constructor TScreenName.Create;
end;
PlayerSelect := AddButton(Theme.Name.PlayerSelectCurrent);
+ Button[PlayerSelect].Selectable := false;
+
+ AddButton(0, 0, 0, 0, Skin.GetTextureFileName(Theme.Name.PlayerSelectCurrent.Tex), Theme.Name.PlayerSelectCurrent.Typ, false);
+ PlayerSelectIID := High(Interactions);
+ Button[Interactions[PlayerSelectIID].Num].SelectInt := 0;
+ Button[Interactions[PlayerSelectIID].Num].DeselectInt := 0;
+ Button[Interactions[PlayerSelectIID].Num].Texture.Alpha := 0;
+ Button[Interactions[PlayerSelectIID].Num].DeSelectTexture.Alpha := 0;
PlayerAvatar := AddButton(Theme.Name.PlayerButtonAvatar);
PlayerAvatarIID := High(Interactions);
PlayerName := AddButton(Theme.Name.PlayerButtonName);
+ PlayerNameIID := High(Interactions);
Button[PlayerName].Text[0].Writable := true;
Theme.Name.SelectPlayerColor.oneItemOnly := true;
Theme.Name.SelectPlayerColor.showArrows := true;
PlayerColor := AddSelectSlide(Theme.Name.SelectPlayerColor, ColorIndex, IPlayerColorTranslated);
+ PlayerColorIID := High(Interactions);
Theme.Name.SelectPlayerLevel.oneItemOnly := true;
Theme.Name.SelectPlayerLevel.showArrows := true;
PlayerSelectLevel := AddSelectSlide(Theme.Name.SelectPlayerLevel, LevelIndex, IDifficultyTranslated);
+ PlayerSelectLevelIID := High(Interactions);
isScrolling := false;
@@ -845,7 +974,17 @@ constructor TScreenName.Create;
procedure TScreenName.SetPlayerAvatar(Player: integer);
var
Col: TRGB;
+ X: real;
+ Y: real;
+ W: real;
+ H: real;
+ Z: real;
begin
+ X := Statics[PlayerCurrentAvatar[Player]].Texture.X;
+ Y := Statics[PlayerCurrentAvatar[Player]].Texture.Y;
+ W := Statics[PlayerCurrentAvatar[Player]].Texture.W;
+ H := Statics[PlayerCurrentAvatar[Player]].Texture.H;
+ Z := Statics[PlayerCurrentAvatar[Player]].Texture.Z;
if (PlayerAvatars[Player] = 0) then
begin
@@ -860,12 +999,11 @@ procedure TScreenName.SetPlayerAvatar(Player: integer);
else
Statics[PlayerCurrentAvatar[Player]].Texture := Button[PlayerAvatarButton[PlayerAvatars[Player]]].Texture;
- Statics[PlayerCurrentAvatar[Player]].Texture.X := Theme.Name.PlayerSelectAvatar[Player].X;
- Statics[PlayerCurrentAvatar[Player]].Texture.Y := Theme.Name.PlayerSelectAvatar[Player].Y;
- Statics[PlayerCurrentAvatar[Player]].Texture.W := Theme.Name.PlayerSelectAvatar[Player].W;
- Statics[PlayerCurrentAvatar[Player]].Texture.H := Theme.Name.PlayerSelectAvatar[Player].H;
- Statics[PlayerCurrentAvatar[Player]].Texture.Z := Theme.Name.PlayerSelectAvatar[Player].Z;
-
+ Statics[PlayerCurrentAvatar[Player]].Texture.X := X;
+ Statics[PlayerCurrentAvatar[Player]].Texture.Y := Y;
+ Statics[PlayerCurrentAvatar[Player]].Texture.W := W;
+ Statics[PlayerCurrentAvatar[Player]].Texture.H := H;
+ Statics[PlayerCurrentAvatar[Player]].Texture.Z := Z;
Statics[PlayerCurrentAvatar[Player]].Texture.Int := 1;
end;
@@ -994,7 +1132,7 @@ procedure TScreenName.SetAvatarScroll;
Button[B].Y := Theme.Name.PlayerAvatar.Y;
AvatarCurrent := AvatarTarget;
-
+
isScrolling := false;
end
diff --git a/src/screens/UScreenPartyPlayer.pas b/src/screens/UScreenPartyPlayer.pas
index 8e0e59d51..7270cc4bd 100644
--- a/src/screens/UScreenPartyPlayer.pas
+++ b/src/screens/UScreenPartyPlayer.pas
@@ -97,10 +97,6 @@ TScreenPartyPlayer = class(TMenu)
end;
-const
- ITeams: array[0..1] of UTF8String = ('2', '3');
- IPlayers: array[0..3] of UTF8String = ('1', '2', '3', '4');
-
const
ID='ID_031'; //for help system
@@ -246,18 +242,11 @@ function TScreenPartyPlayer.ShouldHandleInput(PressedKey: cardinal; CharCode: UC
begin
Result := inherited;
// only suppress special keys for now
- case PressedKey of
- // Templates for Names Mod
- SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_F11, SDLK_F12:
- if (Button[Interactions[Interaction].Num].Selected) then
- begin
- SuppressKey := true;
- end
- else
- begin
- Result := false;
- end;
- end;
+ if GetNameTemplateIndexFromKey(PressedKey) <> -1 then
+ if (Button[Interactions[Interaction].Num].Selected) then
+ SuppressKey := true
+ else
+ Result := false;
end;
function TScreenPartyPlayer.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
@@ -294,6 +283,14 @@ function TScreenPartyPlayer.ParseInput(PressedKey: cardinal; CharCode: UCS4Char;
if isAlternate then Ini.NameTemplate[index] := Button[Interactions[Interaction].Num].Text[0].Text
else Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[index];
end;
+ procedure HandleTemplateHotkey;
+ var
+ TemplateIndex: integer;
+ begin
+ TemplateIndex := GetNameTemplateIndexFromKey(PressedKey);
+ if (TemplateIndex >= 0) and (TemplateIndex <= High(Ini.NameTemplate)) then
+ HandleNameTemplate(TemplateIndex);
+ end;
begin
Result := true;
@@ -318,20 +315,9 @@ function TScreenPartyPlayer.ParseInput(PressedKey: cardinal; CharCode: UCS4Char;
// check special keys
case PressedKey of
- // Templates for Names Mod
- SDLK_F1: HandleNameTemplate(0);
- SDLK_F2: HandleNameTemplate(1);
- SDLK_F3: HandleNameTemplate(2);
- SDLK_F4: HandleNameTemplate(3);
- SDLK_F5: HandleNameTemplate(4);
- SDLK_F6: HandleNameTemplate(5);
- SDLK_F7: HandleNameTemplate(6);
- SDLK_F8: HandleNameTemplate(7);
- SDLK_F9: HandleNameTemplate(8);
- SDLK_F10: HandleNameTemplate(9);
- SDLK_F11: HandleNameTemplate(10);
- SDLK_F12: HandleNameTemplate(11);
-
+ SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, SDLK_F6,
+ SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_F11, SDLK_F12:
+ HandleTemplateHotkey;
SDLK_BACKSPACE:
begin
Button[Interactions[Interaction].Num].Text[0].DeleteLastLetter;
@@ -492,21 +478,26 @@ function TScreenPartyPlayer.ParseMouse(MouseButton: integer; BtnDown: boolean; X
constructor TScreenPartyPlayer.Create;
var
ButtonID: integer;
+ TeamOptions: TUTF8StringArray;
+ PlayerOptions: TUTF8StringArray;
begin
inherited Create;
LoadFromTheme(Theme.PartyPlayer);
+ TeamOptions := CreateNumericOptionArray(2, 3);
+ PlayerOptions := CreateNumericOptionArray(1, 4);
+
Theme.PartyPlayer.SelectTeams.oneItemOnly := true;
Theme.PartyPlayer.SelectTeams.showArrows := true;
- SelectTeams := AddSelectSlide(Theme.PartyPlayer.SelectTeams, CountTeams, ITeams);
+ SelectTeams := AddSelectSlide(Theme.PartyPlayer.SelectTeams, CountTeams, TeamOptions);
Team1Name := AddButton(Theme.PartyPlayer.Team1Name);
Button[Team1Name].Text[0].Writable := true;
Theme.PartyPlayer.SelectPlayers1.oneItemOnly := true;
Theme.PartyPlayer.SelectPlayers1.showArrows := true;
- SelectPlayers[0] := AddSelectSlide(Theme.PartyPlayer.SelectPlayers1, CountPlayer[0], IPlayers);
+ SelectPlayers[0] := AddSelectSlide(Theme.PartyPlayer.SelectPlayers1, CountPlayer[0], PlayerOptions);
ButtonID := AddButton(Theme.PartyPlayer.Player1Name);
Button[ButtonID].Text[0].Writable := true;
@@ -525,7 +516,7 @@ constructor TScreenPartyPlayer.Create;
Theme.PartyPlayer.SelectPlayers2.oneItemOnly := true;
Theme.PartyPlayer.SelectPlayers2.showArrows := true;
- SelectPlayers[1] := AddSelectSlide(Theme.PartyPlayer.SelectPlayers2, CountPlayer[1], IPlayers);
+ SelectPlayers[1] := AddSelectSlide(Theme.PartyPlayer.SelectPlayers2, CountPlayer[1], PlayerOptions);
ButtonID := AddButton(Theme.PartyPlayer.Player5Name);
Button[ButtonID].Text[0].Writable := true;
@@ -544,7 +535,7 @@ constructor TScreenPartyPlayer.Create;
Theme.PartyPlayer.SelectPlayers3.oneItemOnly := true;
Theme.PartyPlayer.SelectPlayers3.showArrows := true;
- SelectPlayers[2] := AddSelectSlide(Theme.PartyPlayer.SelectPlayers3, CountPlayer[2], IPlayers);
+ SelectPlayers[2] := AddSelectSlide(Theme.PartyPlayer.SelectPlayers3, CountPlayer[2], PlayerOptions);
ButtonID := AddButton(Theme.PartyPlayer.Player9Name);
Button[ButtonID].Text[0].Writable := true;
diff --git a/src/screens/UScreenPartyTournamentPlayer.pas b/src/screens/UScreenPartyTournamentPlayer.pas
index 0d281a9a8..18624ed30 100644
--- a/src/screens/UScreenPartyTournamentPlayer.pas
+++ b/src/screens/UScreenPartyTournamentPlayer.pas
@@ -80,7 +80,6 @@ TScreenPartyTournamentPlayer = class(TMenu)
const
ID='ID_036'; //for help system
- ITournamentPlayers: array[0..14] of UTF8String = ('2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16');
implementation
@@ -153,24 +152,18 @@ function TScreenPartyTournamentPlayer.ShouldHandleInput(PressedKey: cardinal; Ch
begin
Result := inherited;
// only suppress special keys for now
- case PressedKey of
- // Templates for Names Mod
- SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_F11, SDLK_F12:
- if (Button[Interactions[Interaction].Num].Selected) then
- begin
- SuppressKey := true;
- end
- else
- begin
- Result := false;
- end;
- end;
+ if GetNameTemplateIndexFromKey(PressedKey) <> -1 then
+ if (Button[Interactions[Interaction].Num].Selected) then
+ SuppressKey := true
+ else
+ Result := false;
end;
function TScreenPartyTournamentPlayer.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
var
SDL_ModState: word;
isAlternate: boolean;
+ TemplateIndex: integer;
procedure IntNext;
begin
repeat
@@ -215,116 +208,16 @@ function TScreenPartyTournamentPlayer.ParseInput(PressedKey: cardinal; CharCode:
isAlternate := (SDL_ModState = KMOD_LSHIFT) or (SDL_ModState = KMOD_RSHIFT);
isAlternate := isAlternate or (SDL_ModState = KMOD_LALT); // legacy key combination
case PressedKey of
- // Templates for Names Mod
- SDLK_F1:
- if isAlternate then
- begin
- Ini.NameTemplate[0] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[0];
- end;
- SDLK_F2:
- if isAlternate then
- begin
- Ini.NameTemplate[1] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[1];
- end;
- SDLK_F3:
- if isAlternate then
- begin
- Ini.NameTemplate[2] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[2];
- end;
- SDLK_F4:
- if isAlternate then
- begin
- Ini.NameTemplate[3] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[3];
- end;
- SDLK_F5:
- if isAlternate then
- begin
- Ini.NameTemplate[4] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[4];
- end;
- SDLK_F6:
- if isAlternate then
- begin
- Ini.NameTemplate[5] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[5];
- end;
- SDLK_F7:
- if isAlternate then
- begin
- Ini.NameTemplate[6] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[6];
- end;
- SDLK_F8:
- if isAlternate then
- begin
- Ini.NameTemplate[7] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[7];
- end;
- SDLK_F9:
- if isAlternate then
- begin
- Ini.NameTemplate[8] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[8];
- end;
- SDLK_F10:
- if isAlternate then
- begin
- Ini.NameTemplate[9] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[9];
- end;
- SDLK_F11:
- if isAlternate then
- begin
- Ini.NameTemplate[10] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[10];
- end;
- SDLK_F12:
- if isAlternate then
- begin
- Ini.NameTemplate[11] := Button[Interactions[Interaction].Num].Text[0].Text;
- end
- else
- begin
- Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[11];
- end;
-
+ SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, SDLK_F6,
+ SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_F11, SDLK_F12:
+ begin
+ TemplateIndex := GetNameTemplateIndexFromKey(PressedKey);
+ if (TemplateIndex >= 0) and (TemplateIndex <= High(Ini.NameTemplate)) then
+ if isAlternate then
+ Ini.NameTemplate[TemplateIndex] := Button[Interactions[Interaction].Num].Text[0].Text
+ else
+ Button[Interactions[Interaction].Num].Text[0].Text := Ini.NameTemplate[TemplateIndex];
+ end;
SDLK_BACKSPACE:
begin
Button[Interactions[Interaction].Num].Text[0].DeleteLastLetter;
@@ -384,14 +277,18 @@ function TScreenPartyTournamentPlayer.ParseInput(PressedKey: cardinal; CharCode:
end;
constructor TScreenPartyTournamentPlayer.Create;
+var
+ TournamentPlayerOptions: TUTF8StringArray;
begin
inherited Create;
LoadFromTheme(Theme.PartyTournamentPlayer);
+ TournamentPlayerOptions := CreateNumericOptionArray(2, 16);
+
Theme.PartyTournamentPlayer.SelectPlayers.oneItemOnly := true;
Theme.PartyTournamentPlayer.SelectPlayers.showArrows := true;
- SelectPlayers := AddSelectSlide(Theme.PartyTournamentPlayer.SelectPlayers, CountPlayer, ITournamentPlayers);
+ SelectPlayers := AddSelectSlide(Theme.PartyTournamentPlayer.SelectPlayers, CountPlayer, TournamentPlayerOptions);
AddButton(Theme.PartyTournamentPlayer.Player1Name);
AddButton(Theme.PartyTournamentPlayer.Player2Name);
diff --git a/src/screens/UScreenScore.pas b/src/screens/UScreenScore.pas
index d2dbc27ac..7ae8ef83a 100644
--- a/src/screens/UScreenScore.pas
+++ b/src/screens/UScreenScore.pas
@@ -58,7 +58,7 @@ interface
type
TScoreBarType = (sbtScore, sbtLine, sbtGolden);
- TPlayerScoreScreenTexture = record // holds all colorized textures for up to 6 players
+ TPlayerScoreScreenTexture = record // holds all colorized textures for one player
//Bar textures
Score_NoteBarLevel_Dark: TTexture; // Note
Score_NoteBarRound_Dark: TTexture; // that's the round thing on top
@@ -85,9 +85,8 @@ TPlayerScoreRatingPics = record // a fine array of the rating pi
{ hold maps of players to the different positions }
TPlayerPositionMap = record
- Position: byte; // 1..6: Position of Player; 0: no position (e.g. too little screens)
+ Position: byte; // local slot index on the assigned screen; 0 if unused
Screen: byte; // 0 - Screen 1; 1 - Screen 2
- BothScreens: boolean; // true if player is drawn on both screens
end;
APlayerPositionMap = array of TPlayerPositionMap;
@@ -131,30 +130,22 @@ TScreenScore = class(TMenu)
TextTotalScore: array[1..UIni.IMaxPlayerCount] of integer;
PlayerStatic: array[1..UIni.IMaxPlayerCount] of array of integer;
- AvatarStatic: array[1..UIni.IMaxPlayerCount] of integer;
AvatarStaticRef: array[1..UIni.IMaxPlayerCount] of Integer;
{ texture pairs for swapping when screens = 2
- first array level: index of player ( actually this is a position
- 1 - Player 1 if PlayersPlay = 1 <- we don't need swapping here
- 2..3 - Player 1 and 2 or 3 and 4 if PlayersPlay = 2 or 4
- 4..6 - Player 1 - 3 or 4 - 6 if PlayersPlay = 3 or 6 )
- second array level: different playerstatics for positions
- third array level: texture for screen 1 or 2 }
- PlayerStaticTextures: array[1..UIni.IMaxPlayerCount] of array of array [1..2] of TPlayerStaticTexture;
+ first array level: slot index on a screen
+ second array level: static index within that slot
+ third array level: precolored texture for the target player }
+ PlayerStaticTextures: array[1..UIni.IMaxPlayerCount] of array of array [1..UIni.IMaxPlayerCount] of TPlayerStaticTexture;
PlayerTexts: array[1..UIni.IMaxPlayerCount] of array of integer;
StaticBoxLightest: array[1..UIni.IMaxPlayerCount] of integer;
StaticBoxLight: array[1..UIni.IMaxPlayerCount] of integer;
StaticBoxDark: array[1..UIni.IMaxPlayerCount] of integer;
{ texture pairs for swapping when screens = 2
- for boxes
- first array level: index of player ( actually this is a position
- 1 - Player 1 if PlayersPlay = 1 <- we don't need swapping here
- 2..3 - Player 1 and 2 or 3 and 4 if PlayersPlay = 2 or 4
- 4..6 - Player 1 - 3 or 4 - 6 if PlayersPlay = 3 or 6 )
- second array level: different boxes for positions (0: lightest; 1: light; 2: dark)
- third array level: texture for screen 1 or 2 }
- PlayerBoxTextures: array[1..UIni.IMaxPlayerCount] of array[0..2] of array [1..2] of TPlayerStaticTexture;
+ first array level: slot index on a screen
+ second array level: box variant (0: lightest; 1: light; 2: dark)
+ third array level: precolored texture for the target player }
+ PlayerBoxTextures: array[1..UIni.IMaxPlayerCount] of array[0..2] of array [1..UIni.IMaxPlayerCount] of TPlayerStaticTexture;
StaticBackLevel: array[1..UIni.IMaxPlayerCount] of integer;
StaticBackLevelRound: array[1..UIni.IMaxPlayerCount] of integer;
@@ -167,7 +158,7 @@ TScreenScore = class(TMenu)
TextPhrase_ActualValue: array[1..UIni.IMaxPlayerCount] of integer;
TextGolden_ActualValue: array[1..UIni.IMaxPlayerCount] of integer;
- ButtonSend: array[1..UIni.IMaxPlayerCount] of integer;
+ ButtonSend: array[1..3] of integer;
CurrentRound: integer;
StaticNavigate: integer;
TextNavigate: integer;
@@ -226,6 +217,7 @@ implementation
ULog,
UMenuStatic,
UNote,
+ UPlayerLayout,
UPathUtils,
UScreenPopup,
UScreenSong,
@@ -234,6 +226,205 @@ implementation
UTime,
UUnicodeUtils;
+function GetScoreSlotIndex(PlayerIndex, PlayerCount, ScreenCount: integer): integer;
+begin
+ Result := GetPlayerIndexOnScreen(PlayerIndex, PlayerCount, ScreenCount) + 1;
+end;
+
+function ReplaceBasePlayerColor(const Color: string; TargetPlayer: integer): string;
+var
+ SourcePrefix: string;
+begin
+ Result := Color;
+ SourcePrefix := 'P1';
+ if Copy(Color, 1, Length(SourcePrefix)) = SourcePrefix then
+ Result := 'P' + IntToStr(TargetPlayer) + Copy(Color, Length(SourcePrefix) + 1, MaxInt);
+end;
+
+function GetScorePlayerThemeColor(TargetPlayer: integer; const ThemeColor: string; out Col: TRGB): boolean;
+var
+ BaseColor: integer;
+begin
+ Result := false;
+ if (TargetPlayer < 1) or (TargetPlayer > Length(Ini.PlayerColor)) then
+ Exit;
+
+ if Pos('P1', ThemeColor) <> 1 then
+ Exit;
+
+ BaseColor := Ini.PlayerColor[TargetPlayer - 1];
+ if Pos('Lightest', ThemeColor) = 3 then
+ Col := ColorSqrt(GetPlayerLightColor(BaseColor))
+ else if Pos('Light', ThemeColor) = 3 then
+ Col := GetPlayerLightColor(BaseColor)
+ else
+ Col := GetPlayerColor(BaseColor);
+
+ Result := true;
+end;
+
+function ResolvePlayerThemeColor(const ThemeColor: string; TargetPlayer: integer; out Col: TRGB): boolean;
+var
+ ResolvedColor: string;
+ R: real;
+ G: real;
+ B: real;
+begin
+ Result := false;
+ if ThemeColor = '' then
+ Exit;
+
+ if GetScorePlayerThemeColor(TargetPlayer, ThemeColor, Col) then
+ Exit(true);
+
+ ResolvedColor := ReplaceBasePlayerColor(ThemeColor, TargetPlayer);
+ if ResolvedColor <> ThemeColor then
+ begin
+ LoadColor(R, G, B, ResolvedColor);
+ Col.R := R;
+ Col.G := G;
+ Col.B := B;
+ Result := true;
+ end;
+end;
+
+procedure ApplyThemeStaticForPlayer(const ScreenScore: TScreenScore; StaticIndex: integer;
+ const ThemeStatic: TThemeStatic; TargetPlayer: integer);
+var
+ Col: TRGB;
+ CurrentTexture: TTexture;
+begin
+ CurrentTexture := ScreenScore.Statics[StaticIndex].Texture;
+ if ResolvePlayerThemeColor(ThemeStatic.Color, TargetPlayer, Col) then
+ begin
+ if ThemeStatic.Typ = Texture_Type_Colorized then
+ begin
+ ScreenScore.Statics[StaticIndex].Texture :=
+ Texture.GetTexture(Skin.GetTextureFileName(ThemeStatic.Tex), ThemeStatic.Typ,
+ RGBFloatToInt(Col.R, Col.G, Col.B));
+ ScreenScore.Statics[StaticIndex].Texture.X := CurrentTexture.X;
+ ScreenScore.Statics[StaticIndex].Texture.Y := CurrentTexture.Y;
+ ScreenScore.Statics[StaticIndex].Texture.W := CurrentTexture.W;
+ ScreenScore.Statics[StaticIndex].Texture.H := CurrentTexture.H;
+ ScreenScore.Statics[StaticIndex].Texture.Z := CurrentTexture.Z;
+ ScreenScore.Statics[StaticIndex].Texture.Alpha := CurrentTexture.Alpha;
+ end
+ else
+ begin
+ ScreenScore.Statics[StaticIndex].Texture.ColR := Col.R;
+ ScreenScore.Statics[StaticIndex].Texture.ColG := Col.G;
+ ScreenScore.Statics[StaticIndex].Texture.ColB := Col.B;
+ end;
+ end;
+end;
+
+function GetScoreButtonLayout(PlayerCount, ScreenCount: integer): integer;
+begin
+ Result := EnsureRange(GetScorePlayerGrid(PlayerCount,
+ Theme.Score.PlayerLayoutArea.W, Theme.Score.PlayerLayoutArea.H,
+ Theme.Score.PlayerLayoutExtraColsBias).Cols, 1, 3);
+end;
+
+procedure SetScoreSlotScoreAlpha(const ScreenScore: TScreenScore; SlotIndex: integer; Alpha: real);
+begin
+ ScreenScore.Text[ScreenScore.TextScore[SlotIndex]].Alpha := Alpha;
+ ScreenScore.Text[ScreenScore.TextNotes[SlotIndex]].Alpha := Alpha;
+ ScreenScore.Text[ScreenScore.TextNotesScore[SlotIndex]].Alpha := Alpha;
+ ScreenScore.Text[ScreenScore.TextLineBonus[SlotIndex]].Alpha := Alpha;
+ ScreenScore.Text[ScreenScore.TextLineBonusScore[SlotIndex]].Alpha := Alpha;
+ ScreenScore.Text[ScreenScore.TextGoldenNotes[SlotIndex]].Alpha := Alpha;
+ ScreenScore.Text[ScreenScore.TextGoldenNotesScore[SlotIndex]].Alpha := Alpha;
+ ScreenScore.Text[ScreenScore.TextTotal[SlotIndex]].Alpha := Alpha;
+ ScreenScore.Text[ScreenScore.TextTotalScore[SlotIndex]].Alpha := Alpha;
+ ScreenScore.Statics[ScreenScore.StaticBoxLightest[SlotIndex]].Texture.Alpha := Alpha;
+ ScreenScore.Statics[ScreenScore.StaticBoxLight[SlotIndex]].Texture.Alpha := Alpha;
+ ScreenScore.Statics[ScreenScore.StaticBoxDark[SlotIndex]].Texture.Alpha := Alpha;
+end;
+
+procedure SetScoreSlotVisible(const ScreenScore: TScreenScore; SlotIndex: integer; Visible: boolean);
+var
+ I: integer;
+begin
+ ScreenScore.Text[ScreenScore.TextName[SlotIndex]].Visible := Visible;
+ ScreenScore.Text[ScreenScore.TextScore[SlotIndex]].Visible := Visible;
+ ScreenScore.Text[ScreenScore.TextNotes[SlotIndex]].Visible := Visible;
+ ScreenScore.Text[ScreenScore.TextNotesScore[SlotIndex]].Visible := Visible;
+ ScreenScore.Text[ScreenScore.TextLineBonus[SlotIndex]].Visible := Visible;
+ ScreenScore.Text[ScreenScore.TextLineBonusScore[SlotIndex]].Visible := Visible;
+ ScreenScore.Text[ScreenScore.TextGoldenNotes[SlotIndex]].Visible := Visible;
+ ScreenScore.Text[ScreenScore.TextGoldenNotesScore[SlotIndex]].Visible := Visible;
+ ScreenScore.Text[ScreenScore.TextTotal[SlotIndex]].Visible := Visible;
+ ScreenScore.Text[ScreenScore.TextTotalScore[SlotIndex]].Visible := Visible;
+
+ for I := 0 to High(ScreenScore.PlayerStatic[SlotIndex]) do
+ ScreenScore.Statics[ScreenScore.PlayerStatic[SlotIndex, I]].Visible := Visible;
+
+ for I := 0 to High(ScreenScore.PlayerTexts[SlotIndex]) do
+ ScreenScore.Text[ScreenScore.PlayerTexts[SlotIndex, I]].Visible := Visible;
+
+ ScreenScore.Statics[ScreenScore.StaticBoxLightest[SlotIndex]].Visible := Visible;
+ ScreenScore.Statics[ScreenScore.StaticBoxLight[SlotIndex]].Visible := Visible;
+ ScreenScore.Statics[ScreenScore.StaticBoxDark[SlotIndex]].Visible := Visible;
+end;
+
+procedure ApplyScoreSlotTextColors(const ScreenScore: TScreenScore; SlotIndex, TargetPlayer: integer);
+var
+ I: integer;
+ procedure ApplyTextColor(TextIndex: integer; const ThemeColor: string);
+ var
+ Col: TRGB;
+ begin
+ if ResolvePlayerThemeColor(ThemeColor, TargetPlayer, Col) then
+ begin
+ ScreenScore.Text[TextIndex].ColR := Col.R;
+ ScreenScore.Text[TextIndex].ColG := Col.G;
+ ScreenScore.Text[TextIndex].ColB := Col.B;
+ end;
+ end;
+begin
+ for I := 0 to High(ScreenScore.PlayerTexts[SlotIndex]) do
+ ApplyTextColor(ScreenScore.PlayerTexts[SlotIndex, I], Theme.Score.PlayerTexts[SlotIndex, I].Color);
+
+ ApplyTextColor(ScreenScore.TextName[SlotIndex], Theme.Score.TextName[SlotIndex].Color);
+ ApplyTextColor(ScreenScore.TextScore[SlotIndex], Theme.Score.TextScore[SlotIndex].Color);
+ ApplyTextColor(ScreenScore.TextNotes[SlotIndex], Theme.Score.TextNotes[SlotIndex].Color);
+ ApplyTextColor(ScreenScore.TextNotesScore[SlotIndex], Theme.Score.TextNotesScore[SlotIndex].Color);
+ ApplyTextColor(ScreenScore.TextLineBonus[SlotIndex], Theme.Score.TextLineBonus[SlotIndex].Color);
+ ApplyTextColor(ScreenScore.TextLineBonusScore[SlotIndex], Theme.Score.TextLineBonusScore[SlotIndex].Color);
+ ApplyTextColor(ScreenScore.TextGoldenNotes[SlotIndex], Theme.Score.TextGoldenNotes[SlotIndex].Color);
+ ApplyTextColor(ScreenScore.TextGoldenNotesScore[SlotIndex], Theme.Score.TextGoldenNotesScore[SlotIndex].Color);
+ ApplyTextColor(ScreenScore.TextTotal[SlotIndex], Theme.Score.TextTotal[SlotIndex].Color);
+ ApplyTextColor(ScreenScore.TextTotalScore[SlotIndex], Theme.Score.TextTotalScore[SlotIndex].Color);
+end;
+
+procedure ApplyScoreSlotPlayerVisuals(const ScreenScore: TScreenScore; SlotIndex, TargetPlayer: integer);
+var
+ I: integer;
+begin
+ ApplyScoreSlotTextColors(ScreenScore, SlotIndex, TargetPlayer);
+
+ for I := 0 to High(ScreenScore.PlayerStatic[SlotIndex]) do
+ ApplyThemeStaticForPlayer(ScreenScore, ScreenScore.PlayerStatic[SlotIndex, I],
+ Theme.Score.PlayerStatic[SlotIndex, I], TargetPlayer);
+
+ ApplyThemeStaticForPlayer(ScreenScore, ScreenScore.StaticBoxLightest[SlotIndex],
+ Theme.Score.StaticBoxLightest[SlotIndex], TargetPlayer);
+ ApplyThemeStaticForPlayer(ScreenScore, ScreenScore.StaticBoxLight[SlotIndex],
+ Theme.Score.StaticBoxLight[SlotIndex], TargetPlayer);
+ ApplyThemeStaticForPlayer(ScreenScore, ScreenScore.StaticBoxDark[SlotIndex],
+ Theme.Score.StaticBoxDark[SlotIndex], TargetPlayer);
+ ApplyThemeStaticForPlayer(ScreenScore, ScreenScore.StaticBackLevel[SlotIndex],
+ Theme.Score.StaticBackLevel[SlotIndex], TargetPlayer);
+ ApplyThemeStaticForPlayer(ScreenScore, ScreenScore.StaticBackLevelRound[SlotIndex],
+ Theme.Score.StaticBackLevelRound[SlotIndex], TargetPlayer);
+ ApplyThemeStaticForPlayer(ScreenScore, ScreenScore.StaticLevel[SlotIndex],
+ Theme.Score.StaticLevel[SlotIndex], TargetPlayer);
+ ApplyThemeStaticForPlayer(ScreenScore, ScreenScore.StaticLevelRound[SlotIndex],
+ Theme.Score.StaticLevelRound[SlotIndex], TargetPlayer);
+ ApplyThemeStaticForPlayer(ScreenScore, ScreenScore.AvatarStaticRef[TargetPlayer],
+ Theme.Score.AvatarStatic[SlotIndex], TargetPlayer);
+end;
+
{
*****************************
** 100: NOT A VALID DLL :p
@@ -480,14 +671,7 @@ function TScreenScore.ParseMouse(MouseButton: Integer; BtnDown: Boolean; X, Y: i
begin
Result := True;
- //TODO: adapt for players 7 to 12
- case PlayersPlay of
- 1 : button_s := ButtonSend[1];
- 2, 4: button_s := ButtonSend[2];
- 3, 6: button_s := ButtonSend[3];
- else
- button_s := ButtonSend[3];
- end;
+ button_s := ButtonSend[GetScoreButtonLayout(PlayersPlay, Screens)];
// transfer mousecords to the 800x600 raster we use to draw
X := Round((X / (ScreenW / Screens)) * RenderW);
@@ -548,96 +732,42 @@ procedure TScreenScore.RefreshTexts;
ResetScores;
end;
-//TODO: adapt for players 7 to 12
procedure TScreenScore.LoadSwapTextures;
- var
- P, I: integer;
- PlayerNum, PlayerNum2: integer;
- Color: string;
- R, G, B: real;
- StaticNum: integer;
- ThemeStatic: TThemeStatic;
+var
+ P, I, TargetPlayer: integer;
+ Col: TRGB;
+ StaticNum: integer;
+ ThemeStatic: TThemeStatic;
begin
- { we only need to load swapping textures if in dualscreen mode }
if Screens = 2 then
begin
- { load swapping textures for custom statics }
for P := low(PlayerStatic) to High(PlayerStatic) do
begin
SetLength(PlayerStaticTextures[P], Length(PlayerStatic[P]));
- { get the players that actually are on this position }
- case P of
- 1: begin
- PlayerNum := 1;
- PlayerNum2 := 1;
- end;
-
- 2, 3: begin
- PlayerNum := P - 1;
- PlayerNum2 := PlayerNum + 2;
- end;
-
- 4..6: begin
- PlayerNum := P - 3;
- PlayerNum2 := PlayerNum + 3;
- end;
- end;
-
for I := 0 to High(PlayerStatic[P]) do
begin
- // copy current statics texture to texture for screen 1
- PlayerStaticTextures[P, I, 1].Tex := Statics[PlayerStatic[P, I]].Texture;
-
- // fallback to first screen texture for 2nd screen
- PlayerStaticTextures[P, I, 2].Tex := PlayerStaticTextures[P, I, 1].Tex;
-
- { texture for second screen }
- { we only change color for statics with playercolor
- and with Texture type colorized
- also we don't need to swap for one player position }
- if (P <> 1) and
- (Theme.Score.PlayerStatic[P, I].Typ = Texture_Type_Colorized) and
- (Length(Theme.Score.PlayerStatic[P, I].Color) >= 2) and
- (copy(Theme.Score.PlayerStatic[P, I].Color, 1, 2) = 'P' + IntToStr(PlayerNum)) then
+ for TargetPlayer := 1 to PlayersPlay do
begin
- // get the color
- Color := Theme.Score.PlayerStatic[P, I].Color;
- Color[2] := IntToStr(PlayerNum2)[1];
- LoadColor(R, G, B, Color);
-
- with Theme.Score.PlayerStatic[P, I] do
- PlayerStaticTextures[P, I, 2].Tex := Texture.GetTexture(Skin.GetTextureFileName(Tex), Typ, RGBFloatToInt(R, G, B));
-
- PlayerStaticTextures[P, I, 2].Tex.X := Statics[PlayerStatic[P, I]].Texture.X;
- PlayerStaticTextures[P, I, 2].Tex.Y := Statics[PlayerStatic[P, I]].Texture.Y;
- PlayerStaticTextures[P, I, 2].Tex.W := Statics[PlayerStatic[P, I]].Texture.W;
- PlayerStaticTextures[P, I, 2].Tex.H := Statics[PlayerStatic[P, I]].Texture.H;
+ PlayerStaticTextures[P, I, TargetPlayer].Tex := Statics[PlayerStatic[P, I]].Texture;
+
+ if (Theme.Score.PlayerStatic[P, I].Typ = Texture_Type_Colorized) and
+ ResolvePlayerThemeColor(Theme.Score.PlayerStatic[P, I].Color, TargetPlayer, Col) then
+ begin
+ with Theme.Score.PlayerStatic[P, I] do
+ PlayerStaticTextures[P, I, TargetPlayer].Tex := Texture.GetTexture(Skin.GetTextureFileName(Tex), Typ, RGBFloatToInt(Col.R, Col.G, Col.B));
+
+ PlayerStaticTextures[P, I, TargetPlayer].Tex.X := Statics[PlayerStatic[P, I]].Texture.X;
+ PlayerStaticTextures[P, I, TargetPlayer].Tex.Y := Statics[PlayerStatic[P, I]].Texture.Y;
+ PlayerStaticTextures[P, I, TargetPlayer].Tex.W := Statics[PlayerStatic[P, I]].Texture.W;
+ PlayerStaticTextures[P, I, TargetPlayer].Tex.H := Statics[PlayerStatic[P, I]].Texture.H;
+ end;
end;
end;
end;
- { load swap textures for boxes }
for P := low(PlayerBoxTextures) to High(PlayerBoxTextures) do
begin
- { get the players that actually are on this position }
- case P of
- 1: begin
- PlayerNum := 1;
- PlayerNum2 := 1;
- end;
-
- 2, 3: begin
- PlayerNum := P - 1;
- PlayerNum2 := PlayerNum + 2;
- end;
-
- 4..6: begin
- PlayerNum := P - 3;
- PlayerNum2 := PlayerNum + 3;
- end;
- end;
-
for I := 0 to High(PlayerBoxTextures[P]) do
begin
case I of
@@ -654,46 +784,32 @@ procedure TScreenScore.LoadSwapTextures;
ThemeStatic := Theme.Score.StaticBoxDark[P];
end;
end;
- // copy current statics texture to texture for screen 1
- PlayerBoxTextures[P, I, 1].Tex := Statics[StaticNum].Texture;
-
- // fallback to first screen texture for 2nd screen
- PlayerBoxTextures[P, I, 2].Tex := PlayerBoxTextures[P, I, 1].Tex;
-
- { texture for second screen }
- { we only change color for statics with playercolor
- and with Texture type colorized
- also we don't need to swap for one player position }
- if (P <> 1) and
- (ThemeStatic.Typ = Texture_Type_Colorized) and
- (Length(ThemeStatic.Color) >= 2) and
- (copy(ThemeStatic.Color, 1, 2) = 'P' + IntToStr(PlayerNum)) then
+ for TargetPlayer := 1 to PlayersPlay do
begin
- // get the color
- Color := ThemeStatic.Color;
- Color[2] := IntToStr(PlayerNum2)[1];
- LoadColor(R, G, B, Color);
-
- with ThemeStatic do
- PlayerBoxTextures[P, I, 2].Tex := Texture.GetTexture(Skin.GetTextureFileName(Tex), Typ, RGBFloatToInt(R, G, B));
-
- PlayerBoxTextures[P, I, 2].Tex.X := Statics[StaticNum].Texture.X;
- PlayerBoxTextures[P, I, 2].Tex.Y := Statics[StaticNum].Texture.Y;
- PlayerBoxTextures[P, I, 2].Tex.W := Statics[StaticNum].Texture.W;
- PlayerBoxTextures[P, I, 2].Tex.H := Statics[StaticNum].Texture.H;
+ PlayerBoxTextures[P, I, TargetPlayer].Tex := Statics[StaticNum].Texture;
+
+ if (ThemeStatic.Typ = Texture_Type_Colorized) and
+ ResolvePlayerThemeColor(ThemeStatic.Color, TargetPlayer, Col) then
+ begin
+ with ThemeStatic do
+ PlayerBoxTextures[P, I, TargetPlayer].Tex := Texture.GetTexture(Skin.GetTextureFileName(Tex), Typ, RGBFloatToInt(Col.R, Col.G, Col.B));
+
+ PlayerBoxTextures[P, I, TargetPlayer].Tex.X := Statics[StaticNum].Texture.X;
+ PlayerBoxTextures[P, I, TargetPlayer].Tex.Y := Statics[StaticNum].Texture.Y;
+ PlayerBoxTextures[P, I, TargetPlayer].Tex.W := Statics[StaticNum].Texture.W;
+ PlayerBoxTextures[P, I, TargetPlayer].Tex.H := Statics[StaticNum].Texture.H;
+ end;
end;
end;
end;
end;
end;
-//TODO: adapt for players 7 to 12
procedure TScreenScore.SwapToScreen(Screen: integer);
var
- P, I, J, Max: integer;
- Col: TRGB;
+ P, I, J: integer;
- function FindPlayerIndexForThemeSlot(const ThemeSlot, TargetScreen: integer): integer;
+ function FindPlayerIndexForSlot(const SlotIndex, TargetScreen: integer): integer;
var
PlayerIdx: integer;
begin
@@ -704,151 +820,42 @@ procedure TScreenScore.SwapToScreen(Screen: integer);
for PlayerIdx := Low(PlayerPositionMap) to High(PlayerPositionMap) do
begin
- if (PlayerPositionMap[PlayerIdx].Position = ThemeSlot) and
- ((TargetScreen = PlayerPositionMap[PlayerIdx].Screen) or PlayerPositionMap[PlayerIdx].BothScreens) then
+ if (PlayerPositionMap[PlayerIdx].Position = SlotIndex) and
+ (TargetScreen = PlayerPositionMap[PlayerIdx].Screen) then
begin
Result := PlayerIdx;
Exit;
end;
end;
end;
-begin
- case PlayersPlay of
- 1: Max := 1;
- 2, 4: Max := 2;
- 3, 6: Max := 3;
- 8: Max := 4;
- 12: Max := 6;
- else
- Max := 0; //this should never happen
- end;
-
- { if screens = 2 and playerplay <= 3 the 2nd screen shows the
- textures of screen 1 }
- if (PlayersPlay <= 3) and (Screen = 2) then
- Screen := 1;
-
- { set correct box textures }
+begin
if (Screens = 2) then
begin
-
- for I:= 0 to Max - 1 do
+ for P := 1 to UIni.IMaxPlayerCount do
begin
+ J := FindPlayerIndexForSlot(P, Screen);
+ SetScoreSlotVisible(Self, P, J <> -1);
- J := FindPlayerIndexForThemeSlot(I + 1 + Max, Screen);
- if (J <> -1) and (J <= High(Ini.PlayerColor)) then
- Col := GetPlayerColor(Ini.PlayerColor[J])
- else if (Screen = 2) and (I + Max <= High(Ini.PlayerColor)) then
- Col := GetPlayerColor(Ini.PlayerColor[I + Max])
- else if (I <= High(Ini.PlayerColor)) then
- Col := GetPlayerColor(Ini.PlayerColor[I])
- else
+ if J = -1 then
Continue;
- if (copy(Theme.Score.TextName[I + 1 + Max].Color, 1, 2) = 'P' + IntToStr(I + 1)) then
- begin
- Text[TextName[I + 1 + Max]].ColR := Col.R;
- Text[TextName[I + 1 + Max]].ColG := Col.G;
- Text[TextName[I + 1 + Max]].ColB := Col.B;
- end;
-
- if (copy(Theme.Score.TextScore[I + 1 + Max].Color, 1, 2) = 'P' + IntToStr(I + 1)) then
- begin
- Text[TextScore[I + 1 + Max]].ColR := Col.R;
- Text[TextScore[I + 1 + Max]].ColG := Col.G;
- Text[TextScore[I + 1 + Max]].ColB := Col.B;
- end;
-
- if (copy(Theme.Score.TextNotes[I + 1 + Max].Color, 1, 2) = 'P' + IntToStr(I + 1)) then
- begin
- Text[TextNotes[I + 1 + Max]].ColR := Col.R;
- Text[TextNotes[I + 1 + Max]].ColG := Col.G;
- Text[TextNotes[I + 1 + Max]].ColB := Col.B;
- end;
-
- if (copy(Theme.Score.TextNotesScore[I + 1 + Max].Color, 1, 2) = 'P' + IntToStr(I + 1)) then
- begin
- Text[TextNotesScore[I + 1 + Max]].ColR := Col.R;
- Text[TextNotesScore[I + 1 + Max]].ColG := Col.G;
- Text[TextNotesScore[I + 1 + Max]].ColB := Col.B;
- end;
-
- if (copy(Theme.Score.TextLineBonus[I + 1 + Max].Color, 1, 2) = 'P' + IntToStr(I + 1)) then
- begin
- Text[TextLineBonus[I + 1 + Max]].ColR := Col.R;
- Text[TextLineBonus[I + 1 + Max]].ColG := Col.G;
- Text[TextLineBonus[I + 1 + Max]].ColB := Col.B;
- end;
-
- if (copy(Theme.Score.TextLineBonusScore[I + 1 + Max].Color, 1, 2) = 'P' + IntToStr(I + 1)) then
- begin
- Text[TextLineBonusScore[I + 1 + Max]].ColR := Col.R;
- Text[TextLineBonusScore[I + 1 + Max]].ColG := Col.G;
- Text[TextLineBonusScore[I + 1 + Max]].ColB := Col.B;
- end;
-
- if (copy(Theme.Score.TextGoldenNotes[I + 1 + Max].Color, 1, 2) = 'P' + IntToStr(I + 1)) then
- begin
- Text[TextGoldenNotes[I + 1 + Max]].ColR := Col.R;
- Text[TextGoldenNotes[I + 1 + Max]].ColG := Col.G;
- Text[TextGoldenNotes[I + 1 + Max]].ColB := Col.B;
- end;
-
- if (copy(Theme.Score.TextGoldenNotesScore[I + 1 + Max].Color, 1, 2) = 'P' + IntToStr(I + 1)) then
- begin
- Text[TextGoldenNotesScore[I + 1 + Max]].ColR := Col.R;
- Text[TextGoldenNotesScore[I + 1 + Max]].ColG := Col.G;
- Text[TextGoldenNotesScore[I + 1 + Max]].ColB := Col.B;
- end;
-
- if (copy(Theme.Score.TextTotal[I + 1 + Max].Color, 1, 2) = 'P' + IntToStr(I + 1)) then
+ for I := 0 to High(PlayerStatic[P]) do
begin
- Text[TextTotal[I + 1 + Max]].ColR := Col.R;
- Text[TextTotal[I + 1 + Max]].ColG := Col.G;
- Text[TextTotal[I + 1 + Max]].ColB := Col.B;
+ Statics[PlayerStatic[P, I]].Texture := PlayerStaticTextures[P, I, J + 1].Tex;
end;
- if (copy(Theme.Score.TextTotalScore[I + 1 + Max].Color, 1, 2) = 'P' + IntToStr(I + 1)) then
- begin
- Text[TextTotalScore[I + 1 + Max]].ColR := Col.R;
- Text[TextTotalScore[I + 1 + Max]].ColG := Col.G;
- Text[TextTotalScore[I + 1 + Max]].ColB := Col.B;
- end;
- if((PlayersPlay > Max) and (Screen = 2)) then
- begin
- Statics[AvatarStaticRef[PlayersPlay-Max+I+1]].Visible:=true;
- end
- else if((PlayersPlay > Max) and (Screen = 1)) then
- begin
- Statics[AvatarStaticRef[PlayersPlay-Max+I+1]].Visible:=false;
- end;
+ Statics[StaticBoxLightest[P]].Texture := PlayerBoxTextures[P, 0, J + 1].Tex;
+ Statics[StaticBoxLight[P]].Texture := PlayerBoxTextures[P, 1, J + 1].Tex;
+ Statics[StaticBoxDark[P]].Texture := PlayerBoxTextures[P, 2, J + 1].Tex;
+ ApplyScoreSlotPlayerVisuals(Self, P, J + 1);
end;
- { to keep it simple we just swap all statics, not just the shown ones }
- for P := Low(PlayerStatic) to High(PlayerStatic) do
- for I := 0 to High(PlayerStatic[P]) do
- begin
- Statics[PlayerStatic[P, I]].Texture := PlayerStaticTextures[P, I, Screen].Tex;
- if (Theme.Score.PlayerStatic[P, I].Typ <> Texture_Type_Colorized) then
- begin
- J := FindPlayerIndexForThemeSlot(P, Screen);
- if (J <> -1) and (J <= High(Ini.PlayerColor)) then
- begin
- Col := GetPlayerColor(Ini.PlayerColor[J]);
- Statics[PlayerStatic[P, I]].Texture.ColR := Col.R;
- Statics[PlayerStatic[P, I]].Texture.ColG := Col.G;
- Statics[PlayerStatic[P, I]].Texture.ColB := Col.B;
- end;
- end;
- end;
-
- { box statics }
- for P := Low(PlayerStatic) to High(PlayerStatic) do
+ for P := 1 to PlayersPlay do
begin
- Statics[StaticBoxLightest[P]].Texture := PlayerBoxTextures[P, 0, Screen].Tex;
- Statics[StaticBoxLight[P]].Texture := PlayerBoxTextures[P, 1, Screen].Tex;
- Statics[StaticBoxDark[P]].Texture := PlayerBoxTextures[P, 2, Screen].Tex;
+ Statics[AvatarStaticRef[P]].Visible :=
+ (PlayerPositionMap[P-1].Position > 0) and
+ (Screen = PlayerPositionMap[P-1].Screen);
end;
end;
end;
@@ -858,9 +865,10 @@ constructor TScreenScore.Create;
Player: integer;
Counter: integer;
I: integer;
- R, G, B: real;
- Col2: integer;
- ArrayStartModifier: integer;
+ ColDark: TRGB;
+ ColLight: TRGB;
+ ColLightest: TRGB;
+ SlotIndex: integer;
begin
inherited Create;
@@ -911,22 +919,19 @@ constructor TScreenScore.Create;
//## the bars that visualize the score ##
//NoteBar ScoreBar
- LoadColor(R, G, B, 'P' + IntToStr(Player) + 'Dark');
- Col2 := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255);
- Tex_Score_NoteBarLevel_Dark[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Dark'), TEXTURE_TYPE_COLORIZED, Col2);
- Tex_Score_NoteBarRound_Dark[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Dark_Round'), TEXTURE_TYPE_COLORIZED, Col2);
+ ColDark := GetPlayerColor(Ini.PlayerColor[Player - 1]);
+ Tex_Score_NoteBarLevel_Dark[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Dark'), TEXTURE_TYPE_COLORIZED, RGBFloatToInt(ColDark.R, ColDark.G, ColDark.B));
+ Tex_Score_NoteBarRound_Dark[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Dark_Round'), TEXTURE_TYPE_COLORIZED, RGBFloatToInt(ColDark.R, ColDark.G, ColDark.B));
//LineBonus ScoreBar
- LoadColor(R, G, B, 'P' + IntToStr(Player) + 'Light');
- Col2 := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255);
- Tex_Score_NoteBarLevel_Light[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Light'), TEXTURE_TYPE_COLORIZED, Col2);
- Tex_Score_NoteBarRound_Light[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Light_Round'), TEXTURE_TYPE_COLORIZED, Col2);
+ ColLight := GetPlayerLightColor(Ini.PlayerColor[Player - 1]);
+ Tex_Score_NoteBarLevel_Light[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Light'), TEXTURE_TYPE_COLORIZED, RGBFloatToInt(ColLight.R, ColLight.G, ColLight.B));
+ Tex_Score_NoteBarRound_Light[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Light_Round'), TEXTURE_TYPE_COLORIZED, RGBFloatToInt(ColLight.R, ColLight.G, ColLight.B));
//GoldenNotes ScoreBar
- LoadColor(R, G, B, 'P' + IntToStr(Player) + 'Lightest');
- Col2 := $10000 * Round(R*255) + $100 * Round(G*255) + Round(B*255);
- Tex_Score_NoteBarLevel_Lightest[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Lightest'), TEXTURE_TYPE_COLORIZED, Col2);
- Tex_Score_NoteBarRound_Lightest[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Lightest_Round'), TEXTURE_TYPE_COLORIZED, Col2);
+ ColLightest := ColorSqrt(ColLight);
+ Tex_Score_NoteBarLevel_Lightest[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Lightest'), TEXTURE_TYPE_COLORIZED, RGBFloatToInt(ColLightest.R, ColLightest.G, ColLightest.B));
+ Tex_Score_NoteBarRound_Lightest[Player] := Texture.LoadTexture(Skin.GetTextureFileName('ScoreLevel_Lightest_Round'), TEXTURE_TYPE_COLORIZED, RGBFloatToInt(ColLightest.R, ColLightest.G, ColLightest.B));
//textures
aPlayerScoreScreenTextures[Player].Score_NoteBarLevel_Dark := Tex_Score_NoteBarLevel_Dark[Player];
@@ -939,65 +944,31 @@ constructor TScreenScore.Create;
aPlayerScoreScreenTextures[Player].Score_NoteBarRound_Lightest := Tex_Score_NoteBarRound_Lightest[Player];
end;
- //TODO: adapt for players 7 to 12
- // avatars
- case PlayersPlay of
- 1: ArrayStartModifier := 0;
- 2: ArrayStartModifier := 1;
- 3: ArrayStartModifier := 3;
- 4: begin
- if (Screens = 1) then
- ArrayStartModifier := 0
- else
- ArrayStartModifier := 1;
- end;
- 6: begin
- if (Screens = 1) then
- ArrayStartModifier := 0
- else
- ArrayStartModifier := 3;
- end;
- else
- ArrayStartModifier := 0; //this should never happen
- end;
+ MapPlayersToPosition;
for I := 1 to PlayersPlay do
begin
- if((Screens = 2) and (PlayersPlay > 3) and (I > Trunc(PlayersPlay/2))) then
- begin
- AvatarStatic[I + ArrayStartModifier] := AddStatic(Theme.Score.AvatarStatic[I-Trunc(PlayersPlay/2) + ArrayStartModifier]);
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture := AvatarPlayerTextures[I];
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.X := Theme.Score.AvatarStatic[I-Trunc(PlayersPlay/2) + ArrayStartModifier].X;
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.Y := Theme.Score.AvatarStatic[I-Trunc(PlayersPlay/2) + ArrayStartModifier].Y;
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.H := Theme.Score.AvatarStatic[I-Trunc(PlayersPlay/2) + ArrayStartModifier].H;
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.W := Theme.Score.AvatarStatic[I-Trunc(PlayersPlay/2) + ArrayStartModifier].W;
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.Z := Theme.Score.AvatarStatic[I-Trunc(PlayersPlay/2) + ArrayStartModifier].Z;
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.Alpha := Theme.Score.AvatarStatic[I-Trunc(PlayersPlay/2) + ArrayStartModifier].Alpha;
- end
- else
- begin
- AvatarStatic[I + ArrayStartModifier] := AddStatic(Theme.Score.AvatarStatic[I + ArrayStartModifier]);
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture := AvatarPlayerTextures[I];
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.X := Theme.Score.AvatarStatic[I + ArrayStartModifier].X;
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.Y := Theme.Score.AvatarStatic[I + ArrayStartModifier].Y;
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.H := Theme.Score.AvatarStatic[I + ArrayStartModifier].H;
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.W := Theme.Score.AvatarStatic[I + ArrayStartModifier].W;
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.Z := Theme.Score.AvatarStatic[I + ArrayStartModifier].Z;
- Statics[AvatarStatic[I + ArrayStartModifier]].Texture.Alpha := Theme.Score.AvatarStatic[I + ArrayStartModifier].Alpha;
- end;
- Statics[AvatarStatic[I + ArrayStartModifier]].Visible := true;
- AvatarStaticRef[I]:=AvatarStatic[I + ArrayStartModifier];
+ SlotIndex := PlayerPositionMap[I - 1].Position;
+ AvatarStaticRef[I] := AddStatic(Theme.Score.AvatarStatic[SlotIndex]);
+ Statics[AvatarStaticRef[I]].Texture := AvatarPlayerTextures[I];
+ Statics[AvatarStaticRef[I]].Texture.X := Theme.Score.AvatarStatic[SlotIndex].X;
+ Statics[AvatarStaticRef[I]].Texture.Y := Theme.Score.AvatarStatic[SlotIndex].Y;
+ Statics[AvatarStaticRef[I]].Texture.H := Theme.Score.AvatarStatic[SlotIndex].H;
+ Statics[AvatarStaticRef[I]].Texture.W := Theme.Score.AvatarStatic[SlotIndex].W;
+ Statics[AvatarStaticRef[I]].Texture.Z := Theme.Score.AvatarStatic[SlotIndex].Z;
+ Statics[AvatarStaticRef[I]].Texture.Alpha := Theme.Score.AvatarStatic[SlotIndex].Alpha;
+ Statics[AvatarStaticRef[I]].Visible := true;
+ ApplyScoreSlotPlayerVisuals(Self, SlotIndex, I);
end;
StaticNavigate := AddStatic(Theme.Score.StaticNavigate);
TextNavigate := AddText(Theme.Score.TextNavigate);
- if (PlayersPlay <= 3) or (Screens = 2) then
+ if Screens = 2 then
LoadSwapTextures;
- //TODO: adapt for players 4 to 12
- //Send Buttons
- for I := 1 to 3 do
+ // Send buttons are chosen from the current column layout at runtime.
+ for I := 1 to High(ButtonSend) do
ButtonSend[I] := AddButton(Theme.Score.ButtonSend[I]);
end;
@@ -1018,59 +989,19 @@ destructor TScreenScore.Destroy;
inherited;
end;
-//TODO: adapt for players 7 to 12
procedure TScreenScore.MapPlayersToPosition;
- var
- ArrayStartModifier: integer;
- PlayersPerScreen: integer;
- I: integer;
+var
+ I: integer;
+ ScreenIndex: integer;
begin
- // all statics / texts are loaded at start - so that we have them all even if we change the amount of players
- // To show the corrects statics / text from the them, we simply modify the start of the according arrays
- // 1 Player -> Player[0].Score (The score for one player starts at 0)
- // -> Statics[1] (The statics for the one player screen start at 1)
- // 2 Player -> Player[0..1].Score
- // -> Statics[2..3]
- // 3 Player -> Player[0..5].Score
- // -> Statics[4..6]
- case PlayersPlay of
- 1: ArrayStartModifier := 1;
- 2, 4: ArrayStartModifier := 2;
- 3, 6: ArrayStartModifier := 4;
- else
- ArrayStartModifier := 0; //this should never happen
- end;
-
- if (PlayersPlay <= 3) or ((PlayersPlay > 3) and (Screens = 1)) then
- PlayersPerScreen := PlayersPlay
- else
- PlayersPerScreen := PlayersPlay div 2;
-
SetLength(PlayerPositionMap, PlayersPlay);
- // actually map players to positions
- if (PlayersPlay <= 3) or (Screens = 2) then
- begin
- for I := 0 to PlayersPlay - 1 do
- begin
- PlayerPositionMap[I].Screen := (I div PlayersPerScreen) + 1;
- if (PlayerPositionMap[I].Screen > Screens) then
- PlayerPositionMap[I].Position := 0
- else
- PlayerPositionMap[I].Position := ArrayStartModifier + (I mod PlayersPerScreen);
- PlayerPositionMap[I].BothScreens := (PlayersPlay <= 3) and (Screens > 1);
- end;
- end
- else
+ for I := 0 to PlayersPlay - 1 do
begin
- for I := 0 to PlayersPlay - 1 do
- begin
- PlayerPositionMap[I].Screen := 0;
- PlayerPositionMap[I].Position := I + 1;
- PlayerPositionMap[I].BothScreens := true;
- end;
+ ScreenIndex := GetPlayerScreen(I, PlayersPlay, Screens);
+ PlayerPositionMap[I].Screen := ScreenIndex;
+ PlayerPositionMap[I].Position := GetScoreSlotIndex(I, PlayersPlay, Screens);
end;
-
end;
procedure TScreenScore.UpdateAnimation;
@@ -1110,7 +1041,7 @@ procedure TScreenScore.DrawPlayerBars;
begin
for I := 0 to PlayersPlay - 1 do
begin
- if (PlayerPositionMap[I].Position > 0) and ((ScreenAct = PlayerPositionMap[I].Screen) or (PlayerPositionMap[I].BothScreens)) then
+ if (PlayerPositionMap[I].Position > 0) and (ScreenAct = PlayerPositionMap[I].Screen) then
begin
if (BarScore_EaseOut_Step >= (EaseOut_MaxSteps * 10)) then
begin
@@ -1173,82 +1104,14 @@ procedure TScreenScore.OnShow;
Text[TextTitle].Text := CurrentSong.Title;
Text[TextArtistTitle].Text := CurrentSong.Artist + ' - ' + CurrentSong.Title;
- //TODO: adapt for players 7 to 12
- // set visibility
- case PlayersPlay of
- 1: begin
- V[1] := true;
- V[2] := false;
- V[3] := false;
- V[4] := false;
- V[5] := false;
- V[6] := false;
- end;
- 2, 4: begin
- if (PlayersPlay = 2) or ((PlayersPlay = 4) and (Screens = 2)) then
- begin
- V[1] := false;
- V[2] := true;
- V[3] := true;
- V[4] := false;
- V[5] := false;
- V[6] := false;
- end
- else
- begin
- V[1] := true;
- V[2] := true;
- V[3] := true;
- V[4] := true;
- V[5] := false;
- V[6] := false;
- end;
- end;
- 3, 6: begin
- if (PlayersPlay = 3) or ((PlayersPlay = 6) and (Screens = 2)) then
- begin
- V[1] := false;
- V[2] := false;
- V[3] := false;
- V[4] := true;
- V[5] := true;
- V[6] := true;
- end
- else
- begin
- V[1] := true;
- V[2] := true;
- V[3] := true;
- V[4] := true;
- V[5] := true;
- V[6] := true;
- end;
- end;
- end;
+ FillChar(V, SizeOf(V), 0);
+ for P := 0 to PlayersPlay - 1 do
+ if PlayerPositionMap[P].Position > 0 then
+ V[PlayerPositionMap[P].Position] := true;
for P := 1 to UIni.IMaxPlayerCount do
begin
- Text[TextName[P]].Visible := V[P];
- Text[TextScore[P]].Visible := V[P];
-
- Text[TextNotes[P]].Visible := V[P];
- Text[TextNotesScore[P]].Visible := V[P];
- Text[TextLineBonus[P]].Visible := V[P];
- Text[TextLineBonusScore[P]].Visible := V[P];
- Text[TextGoldenNotes[P]].Visible := V[P];
- Text[TextGoldenNotesScore[P]].Visible := V[P];
- Text[TextTotal[P]].Visible := V[P];
- Text[TextTotalScore[P]].Visible := V[P];
-
- for I := 0 to high(PlayerStatic[P]) do
- Statics[PlayerStatic[P, I]].Visible := V[P];
-
- for I := 0 to high(PlayerTexts[P]) do
- Text[PlayerTexts[P, I]].Visible := V[P];
-
- Statics[StaticBoxLightest[P]].Visible := V[P];
- Statics[StaticBoxLight[P]].Visible := V[P];
- Statics[StaticBoxDark[P]].Visible := V[P];
+ SetScoreSlotVisible(Self, P, V[P]);
// we draw that on our own
Statics[StaticBackLevel[P]].Visible := false;
@@ -1257,6 +1120,9 @@ procedure TScreenScore.OnShow;
Statics[StaticLevelRound[P]].Visible := false;
end;
+ for P := 1 to PlayersPlay do
+ ApplyScoreSlotPlayerVisuals(Self, PlayerPositionMap[P - 1].Position, P);
+
for I := 0 to 2 do
begin
Button[I].Visible := false;
@@ -1266,20 +1132,9 @@ procedure TScreenScore.OnShow;
// Show Send Score Buttons
if (ScreenSing.SungToEnd) and (Length(DllMan.Websites) > 0) then
begin
- case PlayersPlay of
- 1: begin
- Button[0].Visible := true;
- Button[0].Selectable := true;
- end;
- 2,4: begin
- Button[1].Visible := true;
- Button[1].Selectable := true;
- end;
- 3,6: begin
- Button[2].Visible := true;
- Button[2].Selectable := true;
- end;
- end;
+ I := GetScoreButtonLayout(PlayersPlay, Screens) - 1;
+ Button[I].Visible := true;
+ Button[I].Selectable := true;
end;
Interaction := -1;
@@ -1317,21 +1172,7 @@ procedure TScreenScore.ResetScores;
end;
for P := 1 to UIni.IMaxPlayerCount do
- begin
- // We set alpha to 0 , so we can nicely blend them in when we need them
- Text[TextScore[P]].Alpha := 0;
- Text[TextNotesScore[P]].Alpha := 0;
- Text[TextNotes[P]].Alpha := 0;
- Text[TextLineBonus[P]].Alpha := 0;
- Text[TextLineBonusScore[P]].Alpha := 0;
- Text[TextGoldenNotes[P]].Alpha := 0;
- Text[TextGoldenNotesScore[P]].Alpha := 0;
- Text[TextTotal[P]].Alpha := 0;
- Text[TextTotalScore[P]].Alpha := 0;
- Statics[StaticBoxLightest[P]].Texture.Alpha := 0;
- Statics[StaticBoxLight[P]].Texture.Alpha := 0;
- Statics[StaticBoxDark[P]].Texture.Alpha := 0;
- end;
+ SetScoreSlotScoreAlpha(Self, P, 0);
BarScore_EaseOut_Step := 1;
BarPhrase_EaseOut_Step := 1;
@@ -1418,7 +1259,7 @@ function TScreenScore.Draw: boolean;
// we have to swap the themeobjects values on every draw
// to support dual screen
- for PlayerCounter := 1 to PlayersPlay do //TODO: adapt for players 7 to 12
+ for PlayerCounter := 1 to PlayersPlay do
begin
FillPlayerItems(PlayerCounter);
end;
@@ -1429,40 +1270,40 @@ function TScreenScore.Draw: boolean;
procedure TscreenScore.FillPlayerItems(PlayerNumber: integer);
var
- ThemeIndex: integer;
+ SlotIndex: integer;
begin
- ThemeIndex := PlayerPositionMap[PlayerNumber-1].Position;
- if (ThemeIndex > 0) and ((ScreenAct = PlayerPositionMap[PlayerNumber-1].Screen) or (PlayerPositionMap[PlayerNumber-1].BothScreens)) then
+ SlotIndex := PlayerPositionMap[PlayerNumber-1].Position;
+ if (SlotIndex > 0) and (ScreenAct = PlayerPositionMap[PlayerNumber-1].Screen) then
begin
- Text[TextName[ThemeIndex]].Text := Player[PlayerNumber-1].Name;
+ Text[TextName[SlotIndex]].Text := Player[PlayerNumber-1].Name;
// end todo
//golden
- Text[TextGoldenNotesScore[ThemeIndex]].Text := IntToStr(TextGolden_ActualValue[PlayerNumber]);
- Text[TextGoldenNotesScore[ThemeIndex]].Alpha := (BarGolden_EaseOut_Step / 100);
+ Text[TextGoldenNotesScore[SlotIndex]].Text := IntToStr(TextGolden_ActualValue[PlayerNumber]);
+ Text[TextGoldenNotesScore[SlotIndex]].Alpha := (BarGolden_EaseOut_Step / 100);
- Statics[StaticBoxLightest[ThemeIndex]].Texture.Alpha := (BarGolden_EaseOut_Step / 100);
- Text[TextGoldenNotes[ThemeIndex]].Alpha := (BarGolden_EaseOut_Step / 100);
+ Statics[StaticBoxLightest[SlotIndex]].Texture.Alpha := (BarGolden_EaseOut_Step / 100);
+ Text[TextGoldenNotes[SlotIndex]].Alpha := (BarGolden_EaseOut_Step / 100);
// line bonus
- Text[TextLineBonusScore[ThemeIndex]].Text := IntToStr(TextPhrase_ActualValue[PlayerNumber]);
- Text[TextLineBonusScore[ThemeIndex]].Alpha := (BarPhrase_EaseOut_Step / 100);
+ Text[TextLineBonusScore[SlotIndex]].Text := IntToStr(TextPhrase_ActualValue[PlayerNumber]);
+ Text[TextLineBonusScore[SlotIndex]].Alpha := (BarPhrase_EaseOut_Step / 100);
- Statics[StaticBoxLight[ThemeIndex]].Texture.Alpha := (BarPhrase_EaseOut_Step / 100);
- Text[TextLineBonus[ThemeIndex]].Alpha := (BarPhrase_EaseOut_Step / 100);
+ Statics[StaticBoxLight[SlotIndex]].Texture.Alpha := (BarPhrase_EaseOut_Step / 100);
+ Text[TextLineBonus[SlotIndex]].Alpha := (BarPhrase_EaseOut_Step / 100);
// plain score
- Text[TextNotesScore[ThemeIndex]].Text := IntToStr(TextScore_ActualValue[PlayerNumber]);
- Text[TextNotes[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100);
+ Text[TextNotesScore[SlotIndex]].Text := IntToStr(TextScore_ActualValue[PlayerNumber]);
+ Text[TextNotes[SlotIndex]].Alpha := (BarScore_EaseOut_Step / 100);
- Statics[StaticBoxDark[ThemeIndex]].Texture.Alpha := (BarScore_EaseOut_Step / 100);
- Text[TextNotesScore[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100);
+ Statics[StaticBoxDark[SlotIndex]].Texture.Alpha := (BarScore_EaseOut_Step / 100);
+ Text[TextNotesScore[SlotIndex]].Alpha := (BarScore_EaseOut_Step / 100);
// total score
- Text[TextTotalScore[ThemeIndex]].Text := IntToStr(TextScore_ActualValue[PlayerNumber] + TextPhrase_ActualValue[PlayerNumber] + TextGolden_ActualValue[PlayerNumber]);
- Text[TextTotalScore[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100);
+ Text[TextTotalScore[SlotIndex]].Text := IntToStr(TextScore_ActualValue[PlayerNumber] + TextPhrase_ActualValue[PlayerNumber] + TextGolden_ActualValue[PlayerNumber]);
+ Text[TextTotalScore[SlotIndex]].Alpha := (BarScore_EaseOut_Step / 100);
- Text[TextTotal[ThemeIndex]].Alpha := (BarScore_EaseOut_Step / 100);
+ Text[TextTotal[SlotIndex]].Alpha := (BarScore_EaseOut_Step / 100);
if(BarGolden_EaseOut_Step = 100) then
begin
@@ -1474,50 +1315,50 @@ procedure TscreenScore.FillPlayerItems(PlayerNumber: integer);
procedure TScreenScore.ShowRating(PlayerNumber: integer);
var
Rating: integer;
- ThemeIndex: integer;
+ SlotIndex: integer;
begin
- ThemeIndex := PlayerPositionMap[PlayerNumber-1].Position;
- if (ThemeIndex > 0) and ((ScreenAct = PlayerPositionMap[PlayerNumber-1].Screen) or (PlayerPositionMap[PlayerNumber-1].BothScreens)) then
+ SlotIndex := PlayerPositionMap[PlayerNumber-1].Position;
+ if (SlotIndex > 0) and (ScreenAct = PlayerPositionMap[PlayerNumber-1].Screen) then
begin
case (Player[PlayerNumber-1].ScoreTotalInt) of
0..2009:
begin
- Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_TONE_DEAF');
+ Text[TextScore[SlotIndex]].Text := Language.Translate('SING_SCORE_TONE_DEAF');
Rating := 0;
end;
2010..4009:
begin
- Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_AMATEUR');
+ Text[TextScore[SlotIndex]].Text := Language.Translate('SING_SCORE_AMATEUR');
Rating := 1;
end;
4010..5009:
begin
- Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_WANNABE');
+ Text[TextScore[SlotIndex]].Text := Language.Translate('SING_SCORE_WANNABE');
Rating := 2;
end;
5010..6009:
begin
- Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_HOPEFUL');
+ Text[TextScore[SlotIndex]].Text := Language.Translate('SING_SCORE_HOPEFUL');
Rating := 3;
end;
6010..7509:
begin
- Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_RISING_STAR');
+ Text[TextScore[SlotIndex]].Text := Language.Translate('SING_SCORE_RISING_STAR');
Rating := 4;
end;
7510..8509:
begin
- Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_LEAD_SINGER');
+ Text[TextScore[SlotIndex]].Text := Language.Translate('SING_SCORE_LEAD_SINGER');
Rating := 5;
end;
8510..9009:
begin
- Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_SUPERSTAR');
+ Text[TextScore[SlotIndex]].Text := Language.Translate('SING_SCORE_SUPERSTAR');
Rating := 6;
end;
9010..10000:
begin
- Text[TextScore[ThemeIndex]].Text := Language.Translate('SING_SCORE_ULTRASTAR');
+ Text[TextScore[SlotIndex]].Text := Language.Translate('SING_SCORE_ULTRASTAR');
Rating := 7;
end;
else
@@ -1525,9 +1366,9 @@ procedure TScreenScore.ShowRating(PlayerNumber: integer);
end;
//todo: this could break if the width is not given, for instance when there's a skin with no picture for ratings
- if ( Theme.Score.StaticRatings[ThemeIndex].W > 0 ) and ( aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue > 0 ) then
+ if ( Theme.Score.StaticRatings[SlotIndex].W > 0 ) and ( aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue > 0 ) then
begin
- Text[TextScore[ThemeIndex]].Alpha := aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue / Theme.Score.StaticRatings[ThemeIndex].W;
+ Text[TextScore[SlotIndex]].Alpha := aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue / Theme.Score.StaticRatings[SlotIndex].W;
end;
// end todo
@@ -1540,14 +1381,14 @@ procedure TscreenScore.DrawRating(PlayerNumber: integer; Rating: integer);
Posx: real;
Posy: real;
Width: real;
- ThemeIndex: integer;
+ SlotIndex: integer;
begin
- ThemeIndex := PlayerPositionMap[PlayerNumber-1].Position;
+ SlotIndex := PlayerPositionMap[PlayerNumber-1].Position;
- if (Theme.Score.StaticRatings[ThemeIndex].W <> 0) and (Theme.Score.StaticRatings[ThemeIndex].H <> 0) then
+ if (Theme.Score.StaticRatings[SlotIndex].W <> 0) and (Theme.Score.StaticRatings[SlotIndex].H <> 0) then
begin
- PosX := Theme.Score.StaticRatings[ThemeIndex].X + (Theme.Score.StaticRatings[ThemeIndex].W * 0.5);
- PosY := Theme.Score.StaticRatings[ThemeIndex].Y + (Theme.Score.StaticRatings[ThemeIndex].H * 0.5); ;
+ PosX := Theme.Score.StaticRatings[SlotIndex].X + (Theme.Score.StaticRatings[SlotIndex].W * 0.5);
+ PosY := Theme.Score.StaticRatings[SlotIndex].Y + (Theme.Score.StaticRatings[SlotIndex].H * 0.5); ;
Width := aPlayerScoreScreenRatings[PlayerNumber].RateEaseValue/2;
@@ -1577,12 +1418,12 @@ function TscreenScore.CalculateBouncing(PlayerNumber: integer): real;
RaiseStep, MaxVal: real;
EaseOut_Step: integer;
- ThemeIndex: integer;
+ SlotIndex: integer;
begin
- ThemeIndex := PlayerPositionMap[PlayerNumber-1].Position;
+ SlotIndex := PlayerPositionMap[PlayerNumber-1].Position;
EaseOut_Step := aPlayerScoreScreenRatings[PlayerNumber].RateEaseStep;
- MaxVal := Theme.Score.StaticRatings[ThemeIndex].W;
+ MaxVal := Theme.Score.StaticRatings[SlotIndex].W;
RaiseStep := EaseOut_Step;
@@ -1619,10 +1460,10 @@ procedure TscreenScore.EaseBarIn(PlayerNumber: integer; BarType: TScoreBarType);
lTmp: real;
Score: integer;
- ThemeIndex: integer;
+ SlotIndex: integer;
begin
- ThemeIndex := PlayerPositionMap[PlayerNumber-1].Position;
- MaxHeight := Theme.Score.StaticBackLevel[ThemeIndex].H;
+ SlotIndex := PlayerPositionMap[PlayerNumber-1].Position;
+ MaxHeight := Theme.Score.StaticBackLevel[SlotIndex].H;
// let's get the points according to the bar we draw
// score array starts at 0, which means the score for player 1 is in score[0]
@@ -1631,19 +1472,19 @@ procedure TscreenScore.EaseBarIn(PlayerNumber: integer; BarType: TScoreBarType);
begin
Score := Player[PlayerNumber - 1].ScoreInt;
RaiseStep := BarScore_EaseOut_Step;
- BarStartPosY := Theme.Score.StaticBackLevel[ThemeIndex].Y + MaxHeight;
+ BarStartPosY := Theme.Score.StaticBackLevel[SlotIndex].Y + MaxHeight;
end
else if (BarType = sbtLine) then
begin
Score := Player[PlayerNumber - 1].ScoreLineInt;
RaiseStep := BarPhrase_EaseOut_Step;
- BarStartPosY := Theme.Score.StaticBackLevel[ThemeIndex].Y - aPlayerScoreScreenDatas[PlayerNumber].BarScore_ActualHeight + MaxHeight;
+ BarStartPosY := Theme.Score.StaticBackLevel[SlotIndex].Y - aPlayerScoreScreenDatas[PlayerNumber].BarScore_ActualHeight + MaxHeight;
end
else if (BarType = sbtGolden) then
begin
Score := Player[PlayerNumber - 1].ScoreGoldenInt;
RaiseStep := BarGolden_EaseOut_Step;
- BarStartPosY := Theme.Score.StaticBackLevel[ThemeIndex].Y - aPlayerScoreScreenDatas[PlayerNumber].BarScore_ActualHeight - aPlayerScoreScreenDatas[PlayerNumber].BarLine_ActualHeight + MaxHeight;
+ BarStartPosY := Theme.Score.StaticBackLevel[SlotIndex].Y - aPlayerScoreScreenDatas[PlayerNumber].BarScore_ActualHeight - aPlayerScoreScreenDatas[PlayerNumber].BarLine_ActualHeight + MaxHeight;
end;
// the height dependend of the score
@@ -1680,13 +1521,13 @@ procedure TscreenScore.DrawBar(BarType: TScoreBarType; PlayerNumber: integer; Ba
var
Width: real;
BarStartPosX: real;
- ThemeIndex: integer;
+ SlotIndex: integer;
begin
- ThemeIndex := PlayerPositionMap[PlayerNumber-1].Position;
+ SlotIndex := PlayerPositionMap[PlayerNumber-1].Position;
// this is solely for better readability of the drawing
- Width := Theme.Score.StaticBackLevel[ThemeIndex].W;
- BarStartPosX := Theme.Score.StaticBackLevel[ThemeIndex].X;
+ Width := Theme.Score.StaticBackLevel[SlotIndex].W;
+ BarStartPosX := Theme.Score.StaticBackLevel[SlotIndex].X;
glColor4f(1, 1, 1, 1);
@@ -1726,8 +1567,8 @@ procedure TscreenScore.DrawBar(BarType: TScoreBarType; PlayerNumber: integer; Ba
glEnable(GL_BLEND);
glBegin(GL_QUADS);
- glTexCoord2f(0, 0); glVertex3f(BarStartPosX, (BarStartPosY - Statics[StaticLevelRound[ThemeIndex]].Texture.h) - NewHeight, ZBars);
- glTexCoord2f(1, 0); glVertex3f(BarStartPosX + Width, (BarStartPosY - Statics[StaticLevelRound[ThemeIndex]].Texture.h) - NewHeight, ZBars);
+ glTexCoord2f(0, 0); glVertex3f(BarStartPosX, (BarStartPosY - Statics[StaticLevelRound[SlotIndex]].Texture.h) - NewHeight, ZBars);
+ glTexCoord2f(1, 0); glVertex3f(BarStartPosX + Width, (BarStartPosY - Statics[StaticLevelRound[SlotIndex]].Texture.h) - NewHeight, ZBars);
glTexCoord2f(1, 1); glVertex3f(BarStartPosX + Width, BarStartPosY - NewHeight, ZBars);
glTexCoord2f(0, 1); glVertex3f(BarStartPosX, BarStartPosY - NewHeight, ZBars);
glEnd;
diff --git a/src/screens/UScreenSong.pas b/src/screens/UScreenSong.pas
index 8aec83681..c91da598e 100644
--- a/src/screens/UScreenSong.pas
+++ b/src/screens/UScreenSong.pas
@@ -45,6 +45,7 @@ interface
UMenu,
UMenuEqualizer,
UMusic,
+ UPlayerLayout,
UPath,
USong,
USongs,
@@ -195,26 +196,10 @@ TScreenSong = class(TMenu)
InfoMessageBG: cardinal;
InfoMessageText: cardinal;
- Static2PlayersDuetSingerP1: cardinal;
- Static2PlayersDuetSingerP2: cardinal;
- Text2PlayersDuetSingerP1: cardinal;
- Text2PlayersDuetSingerP2: cardinal;
-
- Static3PlayersDuetSingerP1: cardinal;
- Static3PlayersDuetSingerP2: cardinal;
- Static3PlayersDuetSingerP3: cardinal;
- Text3PlayersDuetSingerP1: cardinal;
- Text3PlayersDuetSingerP2: cardinal;
- Text3PlayersDuetSingerP3: cardinal;
-
- Static4PlayersDuetSingerP3: cardinal;
- Static4PlayersDuetSingerP4: cardinal;
-
- Static6PlayersDuetSingerP4: cardinal;
- Static6PlayersDuetSingerP5: cardinal;
- Static6PlayersDuetSingerP6: cardinal;
-
- ColPlayer: array[0..UIni.IMaxPlayerCount-1] of TRGB;
+ DuetSingerStatics: array[0..UIni.IMaxPlayerCount-1] of cardinal;
+ DuetSingerTexts: array[0..UIni.IMaxPlayerCount-1] of cardinal;
+ DuetSingerBaseStatic: TThemeStatic;
+ DuetSingerBaseText: TThemeText;
//CurrentPartyTime: cardinal;
//PartyTime: cardinal;
@@ -241,6 +226,7 @@ TScreenSong = class(TMenu)
procedure SetRouletteScrollRefresh;
procedure SetChessboardScrollRefresh;
procedure SetListScrollRefresh;
+ procedure SyncDuetSingerTheme;
function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
@@ -310,6 +296,9 @@ TScreenSong = class(TMenu)
function getVisibleMedleyArr(MinSource: TMedleySource): TVisArr;
procedure ColorDuetNameSingers;
+ procedure LayoutDuetSingerWidgets(PlayerCount: integer);
+ procedure SetDuetSingerVisibility(Count: integer);
+ procedure SetDuetSingerTexts(Count, FirstNameIndex: integer);
procedure StopMusicPreview();
procedure StopVideoPreview();
@@ -342,6 +331,17 @@ implementation
dglOpenGL,
Math;
+function GetSongPlayerColor(PlayerIndex: integer): TRGB;
+begin
+ Result := GetPlayerColor(Ini.SingColor[PlayerIndex]);
+end;
+
+procedure TScreenSong.SyncDuetSingerTheme;
+begin
+ DuetSingerBaseStatic := Theme.Song.Static2PlayersDuetSingerP1;
+ DuetSingerBaseText := Theme.Song.Text2PlayersDuetSingerP1;
+end;
+
const
MAX_TIME = 30;
MAX_MESSAGE = 3;
@@ -1824,25 +1824,13 @@ constructor TScreenSong.Create;
InfoMessageBG := AddStatic(Theme.Song.InfoMessageBG);
InfoMessageText := AddText(Theme.Song.InfoMessageText);
- // Duet Names Singers
- Static4PlayersDuetSingerP3 := AddStatic(Theme.Song.Static4PlayersDuetSingerP3);
- Static4PlayersDuetSingerP4 := AddStatic(Theme.Song.Static4PlayersDuetSingerP4);
-
- Static6PlayersDuetSingerP4 := AddStatic(Theme.Song.Static6PlayersDuetSingerP4);
- Static6PlayersDuetSingerP5 := AddStatic(Theme.Song.Static6PlayersDuetSingerP5);
- Static6PlayersDuetSingerP6 := AddStatic(Theme.Song.Static6PlayersDuetSingerP6);
-
- Text2PlayersDuetSingerP1 := AddText(Theme.Song.Text2PlayersDuetSingerP1);
- Text2PlayersDuetSingerP2 := AddText(Theme.Song.Text2PlayersDuetSingerP2);
- Static2PlayersDuetSingerP1 := AddStatic(Theme.Song.Static2PlayersDuetSingerP1);
- Static2PlayersDuetSingerP2 := AddStatic(Theme.Song.Static2PlayersDuetSingerP2);
-
- Text3PlayersDuetSingerP1 := AddText(Theme.Song.Text3PlayersDuetSingerP1);
- Text3PlayersDuetSingerP2 := AddText(Theme.Song.Text3PlayersDuetSingerP2);
- Text3PlayersDuetSingerP3 := AddText(Theme.Song.Text3PlayersDuetSingerP3);
- Static3PlayersDuetSingerP1 := AddStatic(Theme.Song.Static3PlayersDuetSingerP1);
- Static3PlayersDuetSingerP2 := AddStatic(Theme.Song.Static3PlayersDuetSingerP2);
- Static3PlayersDuetSingerP3 := AddStatic(Theme.Song.Static3PlayersDuetSingerP3);
+ // Duet singer labels are created from a single base template and laid out at runtime.
+ SyncDuetSingerTheme;
+ for I := 0 to High(DuetSingerStatics) do
+ begin
+ DuetSingerStatics[I] := AddStatic(DuetSingerBaseStatic);
+ DuetSingerTexts[I] := AddText(DuetSingerBaseText);
+ end;
// Medley Playlist
SetLength(TextMedleyArtist, Theme.Song.TextMedleyMax);
@@ -1959,6 +1947,11 @@ constructor TScreenSong.Create;
end;
procedure TScreenSong.ColorDuetNameSingers();
+var
+ LocalPlayerCount: integer;
+ LocalStartIndex: integer;
+ VisibleCount: integer;
+ I: integer;
procedure setColor(static: integer; color: TRGB);
begin
Statics[static].Texture.ColR := color.R;
@@ -1966,78 +1959,120 @@ procedure TScreenSong.ColorDuetNameSingers();
Statics[static].Texture.ColB := color.B;
end;
begin
- if (PlayersPlay = 1) then
+ if Screens > 1 then
begin
- setColor(Static2PlayersDuetSingerP1, ColPlayer[0]);
- // this one is different from all the others
- setColor(Static2PlayersDuetSingerP2, GetPlayerLightColor(Ini.SingColor[0]));
- end;
-
- if (PlayersPlay = 2) then
+ LocalPlayerCount := GetScreenPlayerCount(PlayersPlay, Screens, ScreenAct);
+ LocalStartIndex := GetFirstPlayerIndexForScreen(PlayersPlay, Screens, ScreenAct);
+ end
+ else
begin
- setColor(Static2PlayersDuetSingerP1, ColPlayer[0]);
- setColor(Static2PlayersDuetSingerP2, ColPlayer[1]);
+ LocalPlayerCount := PlayersPlay;
+ LocalStartIndex := 0;
end;
- if (PlayersPlay = 3) then
+ VisibleCount := Max(2, LocalPlayerCount);
+ LayoutDuetSingerWidgets(VisibleCount);
+ if LocalPlayerCount = 1 then
begin
- setColor(Static3PlayersDuetSingerP1, ColPlayer[0]);
- setColor(Static3PlayersDuetSingerP2, ColPlayer[1]);
- setColor(Static3PlayersDuetSingerP3, ColPlayer[2]);
+ setColor(DuetSingerStatics[0], GetSongPlayerColor(LocalStartIndex));
+ setColor(DuetSingerStatics[1], GetPlayerLightColor(Ini.SingColor[LocalStartIndex]));
+ end
+ else
+ begin
+ for I := 0 to VisibleCount - 1 do
+ setColor(DuetSingerStatics[I], GetSongPlayerColor(LocalStartIndex + I));
end;
+end;
+
+procedure TScreenSong.LayoutDuetSingerWidgets(PlayerCount: integer);
+var
+ I: integer;
+ Grid: TPlayerGrid;
+ SlotRect: TPlayerSlotRect;
+ RawTextOffsetX: real;
+ RawTextOffsetY: real;
+ TextOffsetX: real;
+ TextOffsetY: real;
+ RowScale: real;
+ BoxWidth: integer;
+ BoxHeight: integer;
+ ContainerX: integer;
+ ContainerY: integer;
+ ContainerW: integer;
+ ContainerH: integer;
+ TotalWidth: integer;
+const
+ TextNudgeX = 3;
+begin
+ if PlayerCount <= 0 then
+ Exit;
+
+ SyncDuetSingerTheme;
+ Grid := GetPlayerGrid(PlayerCount);
+ RowScale := Max(0.72, 1.0 - 0.08 * (Grid.Rows - 1));
+ BoxWidth := Max(1, Round(DuetSingerBaseStatic.W * 0.68 * RowScale));
+ BoxHeight := Max(1, Round(DuetSingerBaseStatic.H * RowScale));
+ RawTextOffsetX := DuetSingerBaseText.X - DuetSingerBaseStatic.X;
+ RawTextOffsetY := DuetSingerBaseText.Y - DuetSingerBaseStatic.Y;
+ if (RawTextOffsetX < 0) or (RawTextOffsetX > DuetSingerBaseStatic.W) then
+ TextOffsetX := BoxWidth * 0.35
+ else
+ TextOffsetX := RawTextOffsetX * (BoxWidth / Max(1.0, DuetSingerBaseStatic.W));
+ if (RawTextOffsetY < 0) or (RawTextOffsetY > DuetSingerBaseStatic.H) then
+ TextOffsetY := BoxHeight * 0.15
+ else
+ TextOffsetY := RawTextOffsetY * (BoxHeight / Max(1.0, DuetSingerBaseStatic.H));
+ TotalWidth := Grid.Cols * BoxWidth;
+ if Grid.Cols > 1 then
+ Inc(TotalWidth, (Grid.Cols - 1) * 8);
- if (PlayersPlay = 4) then
+ ContainerX := Theme.Song.DuetSingerArea.X;
+ ContainerY := Theme.Song.DuetSingerArea.Y;
+ ContainerH := Grid.Rows * BoxHeight;
+ ContainerW := TotalWidth;
+
+ for I := 0 to High(DuetSingerStatics) do
begin
- if (Screens = 1) then
+ if I < PlayerCount then
begin
- setColor(Static2PlayersDuetSingerP1, ColPlayer[0]);
- setColor(Static2PlayersDuetSingerP2, ColPlayer[1]);
- setColor(Static4PlayersDuetSingerP3, ColPlayer[2]);
- setColor(Static4PlayersDuetSingerP4, ColPlayer[3]);
- end
- else
- begin
- if (ScreenAct = 1) then
- begin
- setColor(Static2PlayersDuetSingerP1, ColPlayer[0]);
- setColor(Static2PlayersDuetSingerP2, ColPlayer[1]);
- end;
-
- if (ScreenAct = 2) then
- begin
- setColor(Static2PlayersDuetSingerP1, ColPlayer[2]);
- setColor(Static2PlayersDuetSingerP2, ColPlayer[3]);
- end;
+ SlotRect := GetPlayerSlotRect(I, PlayerCount, ContainerX, ContainerY, ContainerW, ContainerH);
+ Statics[DuetSingerStatics[I]].Texture.X := SlotRect.X;
+ Statics[DuetSingerStatics[I]].Texture.Y := SlotRect.Y;
+ Statics[DuetSingerStatics[I]].Texture.W := BoxWidth;
+ Statics[DuetSingerStatics[I]].Texture.H := BoxHeight;
+ Statics[DuetSingerStatics[I]].Texture.Z := Max(DuetSingerBaseStatic.Z, 0.995);
+
+ Text[DuetSingerTexts[I]].X := Statics[DuetSingerStatics[I]].Texture.X + TextOffsetX + TextNudgeX;
+ Text[DuetSingerTexts[I]].Y := Statics[DuetSingerStatics[I]].Texture.Y + TextOffsetY;
+ Text[DuetSingerTexts[I]].W := BoxWidth;
+ Text[DuetSingerTexts[I]].H := Max(1, Round(DuetSingerBaseText.H * RowScale));
+ Text[DuetSingerTexts[I]].Size := Max(8, Round(DuetSingerBaseText.Size * RowScale));
+ Text[DuetSingerTexts[I]].Z := Max(DuetSingerBaseText.Z, 0.996);
end;
end;
+end;
- if (PlayersPlay = 6) then
+procedure TScreenSong.SetDuetSingerVisibility(Count: integer);
+var
+ I: integer;
+begin
+ for I := 0 to High(DuetSingerStatics) do
begin
- if (Screens = 1) then
- begin
- setColor(Static3PlayersDuetSingerP1, ColPlayer[0]);
- setColor(Static3PlayersDuetSingerP2, ColPlayer[1]);
- setColor(Static3PlayersDuetSingerP3, ColPlayer[2]);
- setColor(Static6PlayersDuetSingerP4, ColPlayer[3]);
- setColor(Static6PlayersDuetSingerP5, ColPlayer[4]);
- setColor(Static6PlayersDuetSingerP6, ColPlayer[5]);
- end
- else
- begin
- if (ScreenAct = 1) then
- begin
- setColor(Static3PlayersDuetSingerP1, ColPlayer[0]);
- setColor(Static3PlayersDuetSingerP2, ColPlayer[1]);
- setColor(Static3PlayersDuetSingerP3, ColPlayer[2]);
- end;
+ Statics[DuetSingerStatics[I]].Visible := I < Count;
+ Text[DuetSingerTexts[I]].Visible := I < Count;
+ end;
+end;
- if (ScreenAct = 2) then
- begin
- setColor(Static3PlayersDuetSingerP1, ColPlayer[3]);
- setColor(Static3PlayersDuetSingerP2, ColPlayer[4]);
- setColor(Static3PlayersDuetSingerP3, ColPlayer[5]);
- end;
- end;
+procedure TScreenSong.SetDuetSingerTexts(Count, FirstNameIndex: integer);
+var
+ I: integer;
+begin
+ for I := 0 to High(DuetSingerTexts) do
+ begin
+ if I < Count then
+ Text[DuetSingerTexts[I]].Text := CatSongs.Song[Interaction].DuetNames[(FirstNameIndex + (I mod 2)) mod 2]
+ else
+ Text[DuetSingerTexts[I]].Text := '';
end;
end;
@@ -2156,29 +2191,10 @@ procedure TScreenSong.SetScrollRefresh;
procedure TScreenSong.SetScroll;
var
VS, B, SongsInCat: integer;
- procedure HideDuetElements;
- begin
- Text[Text2PlayersDuetSingerP1].Visible := false;
- Text[Text2PlayersDuetSingerP2].Visible := false;
-
- Statics[Static2PlayersDuetSingerP1].Visible := false;
- Statics[Static2PlayersDuetSingerP2].Visible := false;
-
- Text[Text3PlayersDuetSingerP1].Visible := false;
- Text[Text3PlayersDuetSingerP2].Visible := false;
- Text[Text3PlayersDuetSingerP3].Visible := false;
-
- Statics[Static3PlayersDuetSingerP1].Visible := false;
- Statics[Static3PlayersDuetSingerP2].Visible := false;
- Statics[Static3PlayersDuetSingerP3].Visible := false;
-
- Statics[Static4PlayersDuetSingerP3].Visible := false;
- Statics[Static4PlayersDuetSingerP4].Visible := false;
-
- Statics[Static6PlayersDuetSingerP4].Visible := false;
- Statics[Static6PlayersDuetSingerP5].Visible := false;
- Statics[Static6PlayersDuetSingerP6].Visible := false;
- end;
+ LocalPlayerCount: integer;
+ LocalStartIndex: integer;
+ BaseNameIndex: integer;
+ VisibleCount: integer;
begin
VS := CatSongs.VisibleSongs;
if VS > 0 then
@@ -2218,108 +2234,40 @@ procedure TScreenSong.SetScroll;
Text[TextYear].Text := '';
end;
- HideDuetElements;
+ SetDuetSingerVisibility(0);
// Duet Singers
if (CatSongs.Song[Interaction].isDuet) then
begin
- if (PlayersPlay = 3) or (PlayersPlay = 6) then
+ if Screens > 1 then
begin
- Text[Text3PlayersDuetSingerP1].Visible := true;
- Text[Text3PlayersDuetSingerP2].Visible := true;
- Text[Text3PlayersDuetSingerP3].Visible := true;
-
- Statics[Static3PlayersDuetSingerP1].Visible := true;
- Statics[Static3PlayersDuetSingerP2].Visible := true;
- Statics[Static3PlayersDuetSingerP3].Visible := true;
-
- if (Screens = 1) and (PlayersPlay = 6) then
- begin
- Statics[Static6PlayersDuetSingerP4].Visible := true;
- Statics[Static6PlayersDuetSingerP5].Visible := true;
- Statics[Static6PlayersDuetSingerP6].Visible := true;
- end;
+ LocalPlayerCount := GetScreenPlayerCount(PlayersPlay, Screens, ScreenAct);
+ LocalStartIndex := GetFirstPlayerIndexForScreen(PlayersPlay, Screens, ScreenAct);
end
else
begin
- Text[Text2PlayersDuetSingerP1].Visible := true;
- Text[Text2PlayersDuetSingerP2].Visible := true;
-
- Statics[Static2PlayersDuetSingerP1].Visible := true;
- Statics[Static2PlayersDuetSingerP2].Visible := true;
-
- if (Screens = 1) and (PlayersPlay = 4) then
- begin
- Statics[Static4PlayersDuetSingerP3].Visible := true;
- Statics[Static4PlayersDuetSingerP4].Visible := true;
- end;
+ LocalPlayerCount := PlayersPlay;
+ LocalStartIndex := 0;
end;
+ VisibleCount := Max(2, LocalPlayerCount);
+ LayoutDuetSingerWidgets(VisibleCount);
+ SetDuetSingerVisibility(VisibleCount);
+
// Set duet texts
- if (DuetChange) then
+ if Screens > 1 then
begin
- if (PlayersPlay = 3) or (PlayersPlay = 6) then
- begin
- if (PlayersPlay = 3) then
- begin
- Text[Text3PlayersDuetSingerP1].Text := CatSongs.Song[Interaction].DuetNames[1];
- Text[Text3PlayersDuetSingerP2].Text := CatSongs.Song[Interaction].DuetNames[0];
- Text[Text3PlayersDuetSingerP3].Text := CatSongs.Song[Interaction].DuetNames[1];
- end
- else
- begin
- if (ScreenAct = 1) then
- begin
- Text[Text3PlayersDuetSingerP1].Text := CatSongs.Song[Interaction].DuetNames[1];
- Text[Text3PlayersDuetSingerP2].Text := CatSongs.Song[Interaction].DuetNames[0];
- Text[Text3PlayersDuetSingerP3].Text := CatSongs.Song[Interaction].DuetNames[1];
- end
- else
- begin
- Text[Text3PlayersDuetSingerP1].Text := CatSongs.Song[Interaction].DuetNames[0];
- Text[Text3PlayersDuetSingerP2].Text := CatSongs.Song[Interaction].DuetNames[1];
- Text[Text3PlayersDuetSingerP3].Text := CatSongs.Song[Interaction].DuetNames[0];
- end;
- end;
- end
+ if LocalPlayerCount <= 2 then
+ BaseNameIndex := Ord(not DuetChange)
else
- begin
- Text[Text2PlayersDuetSingerP1].Text := CatSongs.Song[Interaction].DuetNames[1];
- Text[Text2PlayersDuetSingerP2].Text := CatSongs.Song[Interaction].DuetNames[0];
- end;
+ BaseNameIndex := (LocalStartIndex + Ord(DuetChange)) mod 2;
end
else
begin
- if (PlayersPlay = 3) or (PlayersPlay = 6) then
- begin
- if (PlayersPlay = 3) then
- begin
- Text[Text3PlayersDuetSingerP1].Text := CatSongs.Song[Interaction].DuetNames[0];
- Text[Text3PlayersDuetSingerP2].Text := CatSongs.Song[Interaction].DuetNames[1];
- Text[Text3PlayersDuetSingerP3].Text := CatSongs.Song[Interaction].DuetNames[0];
- end
- else
- begin
- if (ScreenAct = 1) then
- begin
- Text[Text3PlayersDuetSingerP1].Text := CatSongs.Song[Interaction].DuetNames[0];
- Text[Text3PlayersDuetSingerP2].Text := CatSongs.Song[Interaction].DuetNames[1];
- Text[Text3PlayersDuetSingerP3].Text := CatSongs.Song[Interaction].DuetNames[0];
- end
- else
- begin
- Text[Text3PlayersDuetSingerP1].Text := CatSongs.Song[Interaction].DuetNames[1];
- Text[Text3PlayersDuetSingerP2].Text := CatSongs.Song[Interaction].DuetNames[0];
- Text[Text3PlayersDuetSingerP3].Text := CatSongs.Song[Interaction].DuetNames[1];
- end;
- end;
- end
- else
- begin
- Text[Text2PlayersDuetSingerP1].Text := CatSongs.Song[Interaction].DuetNames[0];
- Text[Text2PlayersDuetSingerP2].Text := CatSongs.Song[Interaction].DuetNames[1];
- end;
+ BaseNameIndex := Ord(DuetChange);
end;
+
+ SetDuetSingerTexts(VisibleCount, BaseNameIndex);
end;
//Set Song Score
SongScore;
@@ -2354,7 +2302,7 @@ procedure TScreenSong.SetScroll;
Statics[VideoIcon].Visible := false;
- HideDuetElements;
+ SetDuetSingerVisibility(0);
for B := 0 to High(Button) do
Button[B].Visible := false;
@@ -2844,6 +2792,7 @@ procedure TScreenSong.OnShow;
I: integer;
begin
inherited;
+ SyncDuetSingerTheme;
CloseMessage();
@@ -2920,14 +2869,6 @@ procedure TScreenSong.OnShow;
Statics[RapToFreestyleIcon].Visible := false;
end;
- // for duet names
- ScreenSong.ColPlayer[0] := GetPlayerColor(Ini.SingColor[0]);
- ScreenSong.ColPlayer[1] := GetPlayerColor(Ini.SingColor[1]);
- ScreenSong.ColPlayer[2] := GetPlayerColor(Ini.SingColor[2]);
- ScreenSong.ColPlayer[3] := GetPlayerColor(Ini.SingColor[3]);
- ScreenSong.ColPlayer[4] := GetPlayerColor(Ini.SingColor[4]);
- ScreenSong.ColPlayer[5] := GetPlayerColor(Ini.SingColor[5]);
-
{**
* Pause background music
*}
@@ -2948,8 +2889,7 @@ procedure TScreenSong.OnShow;
if Mode = smMedley then
Mode := smNormal;
- if Ini.Players <= 3 then PlayersPlay := Ini.Players + 1;
- if Ini.Players = 4 then PlayersPlay := 6;
+ PlayersPlay := UIni.IPlayersVals[Ini.Players];
//Cat Mod etc
if (Ini.TabsAtStartup = 1) and (CatSongs.CatNumShow = -1) then
@@ -3019,6 +2959,7 @@ procedure TScreenSong.OnShowFinish;
begin
DuetChange := false;
RapToFreestyle := false;
+ SyncDuetSingerTheme;
isScrolling := true;
CoverTime := 10;
@@ -3036,6 +2977,7 @@ procedure TScreenSong.OnShowFinish;
SetScrollRefresh;
FixSelected;
+ SetScroll;
//if (Mode = smPartyTournament) then
// PartyTime := SDL_GetTicks();
@@ -3323,6 +3265,17 @@ function TScreenSong.Draw: boolean;
for I := 0 to High(Text) do
Text[I].Draw;
+ // Keep duet assignment widgets in the foreground to avoid mode-specific overlap.
+ if CatSongs.Song[Interaction].isDuet then
+ begin
+ for I := 0 to High(DuetSingerStatics) do
+ if Statics[DuetSingerStatics[I]].Visible then
+ Statics[DuetSingerStatics[I]].Draw;
+ for I := 0 to High(DuetSingerTexts) do
+ if Text[DuetSingerTexts[I]].Visible then
+ Text[DuetSingerTexts[I]].Draw;
+ end;
+
Equalizer.Draw;
DrawExtensions;
@@ -4396,7 +4349,7 @@ procedure TScreenSong.SongScore;
end;
begin
- if (CatSongs.Song[Interaction].isDuet) or (RapToFreestyle) or ((Mode <> smNormal) or (Ini.ShowScores = 0) or (CatSongs.Song[Interaction].Edition = '') or ((Ini.ShowScores = 1) and ((Text[TextMaxScore2].Text = '0') and (Text[TextMaxScoreLocal].Text = '0')))) then
+ if RapToFreestyle or ((Mode <> smNormal) or (Ini.ShowScores = 0) or (CatSongs.Song[Interaction].Edition = '') or ((Ini.ShowScores = 1) and ((Text[TextMaxScore2].Text = '0') and (Text[TextMaxScoreLocal].Text = '0')))) then
begin
hide([
TextScore, TextMaxScore, TextMediaScore,
diff --git a/src/screens/controllers/UScreenSingController.pas b/src/screens/controllers/UScreenSingController.pas
index da01af249..f2e32e8eb 100644
--- a/src/screens/controllers/UScreenSingController.pas
+++ b/src/screens/controllers/UScreenSingController.pas
@@ -689,7 +689,7 @@ destructor TScreenSingController.Destroy;
procedure TScreenSingController.OnShow;
var
- BadPlayer: integer;
+ BadPlayer, I: integer;
Col, ColP1, ColP2: TRGB;
begin
inherited;
@@ -745,17 +745,6 @@ procedure TScreenSingController.OnShow;
CheckPlayerConfigOnNextSong := false;
end;
- if (CurrentSong.isDuet) then
- begin
- if (PlayersPlay = 4) then
- begin
- screenSingViewRef.ColPlayer[0] := GetPlayerColor(Ini.PlayerColor[0]);
- screenSingViewRef.ColPlayer[1] := GetPlayerColor(Ini.PlayerColor[1]);
- screenSingViewRef.ColPlayer[2] := GetPlayerColor(Ini.PlayerColor[2]);
- screenSingViewRef.ColPlayer[3] := GetPlayerColor(Ini.PlayerColor[3]);
- end;
- end;
-
// set custom options
if (CurrentSong.isDuet) and (PlayersPlay <> 1) then
begin
@@ -1391,193 +1380,7 @@ procedure TScreenSingController.OnHide;
end;
function TScreenSingController.Draw: boolean;
-var
- V1: boolean;
- V1TwoP: boolean; // position of score box in two player mode
- V1ThreeP: boolean; // position of score box in three player mode
- V2R: boolean;
- V2M: boolean;
- V3R: boolean;
- VDuet1ThreeP: boolean;
- VDuet2M: boolean;
- VDuet3R: boolean;
- V1FourP: boolean;
- V2FourP: boolean;
- V3FourP: boolean;
- V4FourP: boolean;
- V1SixP: boolean;
- V2SixP: boolean;
- V3SixP: boolean;
- V4SixP: boolean;
- V5SixP: boolean;
- V6SixP: boolean;
- V1DuetFourP: boolean;
- V2DuetFourP: boolean;
- V3DuetFourP: boolean;
- V4DuetFourP: boolean;
- V1DuetSixP: boolean;
- V2DuetSixP: boolean;
- V3DuetSixP: boolean;
- V4DuetSixP: boolean;
- V5DuetSixP: boolean;
- V6DuetSixP: boolean;
begin
- V1 := false;
- V1TwoP := false;
- V1ThreeP := false;
- V2R := false;
- V2M := false;
- V3R := false;
-
- VDuet1ThreeP := false;
- VDuet2M := false;
- VDuet3R := false;
-
- V1FourP := false;
- V2FourP := false;
- V3FourP := false;
- V4FourP := false;
-
- V1SixP := false;
- V2SixP := false;
- V3SixP := false;
- V4SixP := false;
- V5SixP := false;
- V6SixP := false;
-
- V1DuetFourP := false;
- V2DuetFourP := false;
- V3DuetFourP := false;
- V4DuetFourP := false;
-
- V1DuetSixP := false;
- V2DuetSixP := false;
- V3DuetSixP := false;
- V4DuetSixP := false;
- V5DuetSixP := false;
- V6DuetSixP := false;
-
- case PlayersPlay of
- 1:
- begin
- V1 := true;
- end;
- 2:
- begin
- V1TwoP := true;
- V2R := true;
- end;
- 3:
- begin
- if (CurrentSong.isDuet) then
- begin
- VDuet1ThreeP := true;
- VDuet2M := true;
- VDuet3R := true;
- end
- else
- begin
- V1ThreeP := true;
- V2M := true;
- V3R := true;
- end;
- end;
- 4:
- begin // double screen
- if (Ini.Screens = 1) then
- begin
- V1TwoP := true;
- V2R := true;
- end
- else
- begin
- if (CurrentSong.isDuet) then
- begin
- V1DuetFourP := true;
- V2DuetFourP := true;
- V3DuetFourP := true;
- V4DuetFourP := true;
- end
- else
- begin
- V1FourP := true;
- V2FourP := true;
- V3FourP := true;
- V4FourP := true;
- end;
- end;
- end;
- 6:
- begin // double screen
- if (Ini.Screens = 1) then
- begin
- if (CurrentSong.isDuet) then
- begin
- VDuet1ThreeP := true;
- VDuet2M := true;
- VDuet3R := true;
- end
- else
- begin
- V1ThreeP := true;
- V2M := true;
- V3R := true;
- end;
- end
- else
- begin
- if (CurrentSong.isDuet) then
- begin
- V1DuetSixP := true;
- V2DuetSixP := true;
- V3DuetSixP := true;
- V4DuetSixP := true;
- V5DuetSixP := true;
- V6DuetSixP := true;
- end
- else
- begin
- V1SixP := true;
- V2SixP := true;
- V3SixP := true;
- V4SixP := true;
- V5SixP := true;
- V6SixP := true;
- end;
- end;
- end;
- end;
-
- Text[screenSingViewRef.TextP1].Visible := V1 and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP1TwoP].Visible := V1TwoP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP2R].Visible := V2R and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP1ThreeP].Visible := V1ThreeP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP2M].Visible := V2M and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP3R].Visible := V3R and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextDuetP1ThreeP].Visible := VDuet1ThreeP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextDuetP2M].Visible := VDuet2M and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextDuetP3R].Visible := VDuet3R and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP1FourP].Visible := V1FourP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP2FourP].Visible := V2FourP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP3FourP].Visible := V3FourP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP4FourP].Visible := V4FourP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP1SixP].Visible := V1SixP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP2SixP].Visible := V2SixP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP3SixP].Visible := V3SixP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP4SixP].Visible := V4SixP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP5SixP].Visible := V5SixP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP6SixP].Visible := V6SixP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP1DuetFourP].Visible := V1DuetFourP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP2DuetFourP].Visible := V2DuetFourP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP3DuetFourP].Visible := V3DuetFourP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP4DuetFourP].Visible := V4DuetFourP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP1DuetSixP].Visible := V1DuetSixP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP2DuetSixP].Visible := V2DuetSixP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP3DuetSixP].Visible := V3DuetSixP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP4DuetSixP].Visible := V4DuetSixP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP5DuetSixP].Visible := V5DuetSixP and ScreenSing.Settings.AvatarsVisible;
- Text[screenSingViewRef.TextP6DuetSixP].Visible := V6DuetSixP and ScreenSing.Settings.AvatarsVisible;
-
Result := screenSingViewRef.Draw();
end;
@@ -2014,4 +1817,3 @@ procedure TScreenSingController.AutoSaveScore;
end;
end.
-
diff --git a/src/screens/views/UScreenSingView.pas b/src/screens/views/UScreenSingView.pas
index 2dfd15d19..2c597e67a 100644
--- a/src/screens/views/UScreenSingView.pas
+++ b/src/screens/views/UScreenSingView.pas
@@ -47,6 +47,7 @@ interface
UAvatars,
UMenu,
UMusic,
+ UPlayerLayout,
USingScores,
USongs,
UTexture,
@@ -59,8 +60,6 @@ TScreenSingView = class
public
//StaticDuet: array of cardinal;
- ColPlayer: array[0..3] of TRGB;
-
// lyrics bar fields
StaticLyricsBar: integer;
StaticLyricsBarDuet: integer;
@@ -71,118 +70,9 @@ TScreenSingView = class
TextTimeLabelText: integer;
TextTimeText: integer;
- StaticP1: array [0..1] of integer;
- TextP1: integer;
- StaticP1Avatar: array [0..1] of integer;
-
- // shown when game is in 2/4 player modus
- StaticP1TwoP: array [0..1] of integer;
- TextP1TwoP: integer;
- StaticP1TwoPAvatar: array [0..1] of integer;
-
- // shown when game is in 3/6 player modus
- StaticP1ThreeP: array [0..1] of integer;
- TextP1ThreeP: integer;
- StaticP1ThreePAvatar: array [0..1] of integer;
-
- StaticP2R: array [0..1] of integer;
- TextP2R: integer;
- StaticP2RAvatar: array [0..1] of integer;
-
- StaticP2M: array [0..1] of integer;
- TextP2M: integer;
- StaticP2MAvatar: array [0..1] of integer;
-
- StaticP3R: array [0..1] of integer;
- TextP3R: integer;
- StaticP3RAvatar: array [0..1] of integer;
-
- // 4/6 players in one screen
- StaticP1FourP: integer;
- StaticP2FourP: integer;
- StaticP3FourP: integer;
- StaticP4FourP: integer;
-
- StaticP1FourPAvatar: integer;
- StaticP2FourPAvatar: integer;
- StaticP3FourPAvatar: integer;
- StaticP4FourPAvatar: integer;
-
- TextP1FourP: integer;
- TextP2FourP: integer;
- TextP3FourP: integer;
- TextP4FourP: integer;
-
- StaticP1SixP: integer;
- StaticP2SixP: integer;
- StaticP3SixP: integer;
- StaticP4SixP: integer;
- StaticP5SixP: integer;
- StaticP6SixP: integer;
-
- StaticP1SixPAvatar: integer;
- StaticP2SixPAvatar: integer;
- StaticP3SixPAvatar: integer;
- StaticP4SixPAvatar: integer;
- StaticP5SixPAvatar: integer;
- StaticP6SixPAvatar: integer;
-
- TextP1SixP: integer;
- TextP2SixP: integer;
- TextP3SixP: integer;
- TextP4SixP: integer;
- TextP5SixP: integer;
- TextP6SixP: integer;
-
- // 3/6 players duet
- StaticDuetP1ThreeP: array [0..1] of integer;
- TextDuetP1ThreeP: integer;
- StaticDuetP1ThreePAvatar: array [0..1] of integer;
-
- StaticDuetP2M: array [0..1] of integer;
- TextDuetP2M: integer;
- StaticDuetP2MAvatar: array [0..1] of integer;
-
- StaticDuetP3R: array [0..1] of integer;
- TextDuetP3R: integer;
- StaticDuetP3RAvatar: array [0..1] of integer;
-
- // 4/6 players duet one screen
- StaticP1DuetFourP: integer;
- StaticP2DuetFourP: integer;
- StaticP3DuetFourP: integer;
- StaticP4DuetFourP: integer;
-
- StaticP1DuetFourPAvatar: integer;
- StaticP2DuetFourPAvatar: integer;
- StaticP3DuetFourPAvatar: integer;
- StaticP4DuetFourPAvatar: integer;
-
- TextP1DuetFourP: integer;
- TextP2DuetFourP: integer;
- TextP3DuetFourP: integer;
- TextP4DuetFourP: integer;
-
- StaticP1DuetSixP: integer;
- StaticP2DuetSixP: integer;
- StaticP3DuetSixP: integer;
- StaticP4DuetSixP: integer;
- StaticP5DuetSixP: integer;
- StaticP6DuetSixP: integer;
-
- StaticP1DuetSixPAvatar: integer;
- StaticP2DuetSixPAvatar: integer;
- StaticP3DuetSixPAvatar: integer;
- StaticP4DuetSixPAvatar: integer;
- StaticP5DuetSixPAvatar: integer;
- StaticP6DuetSixPAvatar: integer;
-
- TextP1DuetSixP: integer;
- TextP2DuetSixP: integer;
- TextP3DuetSixP: integer;
- TextP4DuetSixP: integer;
- TextP5DuetSixP: integer;
- TextP6DuetSixP: integer;
+ PlayerFrameSlots: array [1..UIni.IMaxPlayerCount, 0..UIni.IMaxPlayerCount-1] of integer;
+ PlayerAvatarSlots: array [1..UIni.IMaxPlayerCount, 0..UIni.IMaxPlayerCount-1] of integer;
+ PlayerTextSlots: array [1..UIni.IMaxPlayerCount, 0..UIni.IMaxPlayerCount-1] of integer;
StaticPausePopup: integer;
@@ -239,202 +129,232 @@ implementation
const
MAX_MESSAGE = 3;
+type
+ TSlotArray = array of integer;
+
+procedure GetSingWidgetSlots(const View: TScreenSingView; LayoutPlayerCount: integer;
+ out FrameSlots, AvatarSlots: TSlotArray);
+var
+ SlotIndex: integer;
+begin
+ SetLength(FrameSlots, LayoutPlayerCount);
+ SetLength(AvatarSlots, LayoutPlayerCount);
+ for SlotIndex := 0 to LayoutPlayerCount - 1 do
+ begin
+ FrameSlots[SlotIndex] := View.PlayerFrameSlots[LayoutPlayerCount, SlotIndex];
+ AvatarSlots[SlotIndex] := View.PlayerAvatarSlots[LayoutPlayerCount, SlotIndex];
+ end;
+end;
+
+procedure GetSingTextSlots(const View: TScreenSingView; LayoutPlayerCount: integer;
+ out TextSlots: TSlotArray);
+var
+ SlotIndex: integer;
+begin
+ SetLength(TextSlots, LayoutPlayerCount);
+ for SlotIndex := 0 to LayoutPlayerCount - 1 do
+ TextSlots[SlotIndex] := View.PlayerTextSlots[LayoutPlayerCount, SlotIndex];
+end;
+
+function GetSingPlayerColor(PlayerIndex: integer): TRGB;
+begin
+ Result := GetPlayerColor(Ini.PlayerColor[PlayerIndex]);
+end;
+
+function IsCurrentSongDuet: boolean;
+begin
+ Result := Assigned(CurrentSong) and CurrentSong.isDuet;
+end;
+
+function BuildSingPlayerTemplate(const PlayerCountOnScreen, PlayerIndexOnScreen: integer): TThemeSingPlayer;
+var
+ BaseTemplate: TThemeSingPlayer;
+ LaneLeft: integer;
+ LaneRight: integer;
+ LaneTop: integer;
+ LaneWidth: integer;
+ Scale: real;
+ FrameW: integer;
+ FrameH: integer;
+ AvatarInsetX: integer;
+ AvatarInsetY: integer;
+ ScoreW: integer;
+ ScoreH: integer;
+ NameX: integer;
+ NameY: integer;
+ NameW: integer;
+ GroupTop: integer;
+ HeaderOffsetLeft: integer;
+ Layout: TSingLaneLayout;
+begin
+ BaseTemplate := Theme.Sing.PlayerTemplate;
+ Layout := GetSingLaneLayout(PlayerCountOnScreen, PlayerIndexOnScreen, Theme.Sing.PlayerLayout,
+ IsCurrentSongDuet and (PlayersPlay <> 1));
+ LaneLeft := Layout.ColumnLeft;
+ LaneRight := Layout.ColumnRight;
+ LaneTop := Layout.RowAnchorY;
+ LaneWidth := Layout.ColumnWidth;
+ Scale := Layout.WidgetScale;
+
+ FrameW := Max(Theme.Sing.PlayerWidgetLayout.MinFrameW, Round(BaseTemplate.AvatarFrame.W * Scale));
+ FrameH := Max(Theme.Sing.PlayerWidgetLayout.MinFrameH, Round(BaseTemplate.AvatarFrame.H * Scale));
+ ScoreW := Max(Theme.Sing.PlayerWidgetLayout.MinScoreW, Round(BaseTemplate.ScoreBackground.W * Scale));
+ ScoreH := Max(Theme.Sing.PlayerWidgetLayout.MinScoreH, Round(BaseTemplate.ScoreBackground.H * Scale));
+ HeaderOffsetLeft := Round(Theme.Sing.PlayerWidgetLayout.HeaderOffsetLeft * Scale);
+ GroupTop := Max(10, LaneTop -
+ GetSingHeaderTopOffset(Theme.Sing.PlayerWidgetLayout, Layout.GridRows, Scale));
+ AvatarInsetX := Max(Theme.Sing.PlayerWidgetLayout.MinAvatarInsetX,
+ Round((BaseTemplate.Avatar.X - BaseTemplate.AvatarFrame.X) * Scale));
+ AvatarInsetY := Max(Theme.Sing.PlayerWidgetLayout.MinAvatarInsetY,
+ Round((BaseTemplate.Avatar.Y - BaseTemplate.AvatarFrame.Y) * Scale));
+ NameX := Max(0, LaneLeft - HeaderOffsetLeft) + FrameW +
+ Max(Theme.Sing.PlayerWidgetLayout.NameGapMinX, Round(Theme.Sing.PlayerWidgetLayout.NameGapBaseX * Scale));
+ NameW := Max(Theme.Sing.PlayerWidgetLayout.NameMinW,
+ (LaneRight - ScoreW - Max(Theme.Sing.PlayerWidgetLayout.NameGapMinX,
+ Round(Theme.Sing.PlayerWidgetLayout.NameGapBaseX * Scale))) - NameX);
+ NameY := GroupTop + Max(0, (FrameH - Max(12, Round(BaseTemplate.Name.Size * Scale))) div 2);
+
+ Result := BaseTemplate;
+ Result.AvatarFrame.X := Max(0, LaneLeft - HeaderOffsetLeft);
+ Result.AvatarFrame.Y := GroupTop;
+ Result.AvatarFrame.W := FrameW;
+ Result.AvatarFrame.H := FrameH;
+
+ Result.Avatar.X := Result.AvatarFrame.X + AvatarInsetX;
+ Result.Avatar.Y := Result.AvatarFrame.Y + AvatarInsetY;
+ Result.Avatar.W := Max(1, FrameW - 2 * AvatarInsetX);
+ Result.Avatar.H := Max(1, FrameH - 2 * AvatarInsetY);
+
+ Result.Name.X := Max(0, NameX - Max(Theme.Sing.PlayerWidgetLayout.NamePaddingMinX,
+ Round(Theme.Sing.PlayerWidgetLayout.NamePaddingBaseX * Scale)));
+ Result.Name.Y := Max(0, NameY - Max(Theme.Sing.PlayerWidgetLayout.NamePaddingMinY,
+ Round(Theme.Sing.PlayerWidgetLayout.NamePaddingBaseY * Scale)));
+ Result.Name.W := NameW;
+ Result.Name.H := Max(Theme.Sing.PlayerWidgetLayout.NameMinH, Round(BaseTemplate.Name.H * Scale));
+ Result.Name.Size := Max(Theme.Sing.PlayerWidgetLayout.NameMinSize, Round(BaseTemplate.Name.Size * Scale));
+ if LaneWidth <= 0 then
+ Result.Name.W := 0;
+end;
+
+procedure ApplySingPlayerTemplate(const SingPlayer: TThemeSingPlayer; FrameSlot, AvatarSlot, TextSlot: integer);
+begin
+ ScreenSing.Statics[FrameSlot].Texture.X := SingPlayer.AvatarFrame.X;
+ ScreenSing.Statics[FrameSlot].Texture.Y := SingPlayer.AvatarFrame.Y;
+ ScreenSing.Statics[FrameSlot].Texture.W := SingPlayer.AvatarFrame.W;
+ ScreenSing.Statics[FrameSlot].Texture.H := SingPlayer.AvatarFrame.H;
+ ScreenSing.Statics[FrameSlot].Texture.Z := SingPlayer.AvatarFrame.Z;
+ ScreenSing.Statics[FrameSlot].Texture.Alpha := SingPlayer.AvatarFrame.Alpha;
+
+ ScreenSing.Statics[AvatarSlot].Texture.X := SingPlayer.Avatar.X;
+ ScreenSing.Statics[AvatarSlot].Texture.Y := SingPlayer.Avatar.Y;
+ ScreenSing.Statics[AvatarSlot].Texture.W := SingPlayer.Avatar.W;
+ ScreenSing.Statics[AvatarSlot].Texture.H := SingPlayer.Avatar.H;
+ ScreenSing.Statics[AvatarSlot].Texture.Z := SingPlayer.Avatar.Z;
+ ScreenSing.Statics[AvatarSlot].Texture.Alpha := SingPlayer.Avatar.Alpha;
+
+ ScreenSing.Text[TextSlot].X := SingPlayer.Name.X;
+ ScreenSing.Text[TextSlot].Y := SingPlayer.Name.Y;
+ ScreenSing.Text[TextSlot].W := SingPlayer.Name.W;
+ ScreenSing.Text[TextSlot].H := SingPlayer.Name.H;
+ ScreenSing.Text[TextSlot].Z := SingPlayer.Name.Z;
+ ScreenSing.Text[TextSlot].Size := SingPlayer.Name.Size;
+end;
+
//ToDo basisbit: check this again
// Dirty HacK
procedure TScreenSingView.SwapToScreen(Screen: integer);
- procedure setVisible(elements: array of integer; visible: boolean);
+var
+ LocalPlayerCount: integer;
+ FirstPlayerIndex: integer;
+ FrameSlots: TSlotArray;
+ AvatarSlots: TSlotArray;
+ IterLayoutPlayerCount: integer;
+ procedure setVisible(const elements: TSlotArray; visible: boolean);
var
J: integer;
begin
for J := 0 to High(elements) do
ScreenSing.Statics[elements[J]].Visible := visible;
end;
- procedure hide(elements: array of integer);
+ procedure hide(const elements: TSlotArray);
begin
setVisible(elements, false);
end;
- procedure maybeShow(elements: array of integer);
+ procedure maybeShowCount(const elements: TSlotArray; Count: integer);
+ var
+ J: integer;
begin
- setVisible(elements, ScreenSing.Settings.AvatarsVisible);
+ if not ScreenSing.Settings.AvatarsVisible then
+ Exit;
+
+ for J := 0 to Count - 1 do
+ ScreenSing.Statics[elements[J]].Visible := true;
end;
-begin
- { if screens = 2 and playerplay <= 3 the 2nd screen shows the
- textures of screen 1 }
- if (PlayersPlay <= 3) and (Screen = 2) then
- Screen := 1;
-
- hide([
- // 1P - screen 1
- StaticP1[0], StaticP1Avatar[0],
- // 2P - screen 1
- StaticP1TwoP[0], StaticP1TwoPAvatar[0],
- StaticP2R[0], StaticP2RAvatar[0],
- // 3P - screen 1
- StaticP1ThreeP[0], StaticP1ThreePAvatar[0],
- StaticP2M[0], StaticP2MAvatar[0],
- StaticP3R[0], StaticP3RAvatar[0],
- // 1P - screen 2 (2 players across 2 screens)
- StaticP1[1], StaticP1Avatar[1],
- // 2P - screen 2 (4 players across 2 screens)
- StaticP1TwoP[1], StaticP1TwoPAvatar[1],
- StaticP2R[1], StaticP2RAvatar[1],
- // 3P - screen 2 (6 players across 2 screens)
- StaticP1ThreeP[1], StaticP1ThreePAvatar[1],
- StaticP2M[1], StaticP2MAvatar[1],
- StaticP3R[1], StaticP3RAvatar[1],
- // 3P duet - screen 1
- StaticDuetP1ThreeP[0], StaticDuetP1ThreePAvatar[0],
- StaticDuetP2M[0], StaticDuetP2MAvatar[0],
- StaticDuetP3R[0], StaticDuetP3RAvatar[0],
- // 3P duet - screen 2 (6 players across 2 screens)
- StaticDuetP1ThreeP[1], StaticDuetP1ThreePAvatar[1],
- StaticDuetP2M[1], StaticDuetP2MAvatar[1],
- StaticDuetP3R[1], StaticDuetP3RAvatar[1],
- // 4P - screen 1
- StaticP1FourP, StaticP1FourPAvatar,
- StaticP2FourP, StaticP2FourPAvatar,
- StaticP3FourP, StaticP3FourPAvatar,
- StaticP4FourP, StaticP4FourPAvatar,
- // 4P duet - screen 1
- StaticP1DuetFourP, StaticP1DuetFourPAvatar,
- StaticP2DuetFourP, StaticP2DuetFourPAvatar,
- StaticP3DuetFourP, StaticP3DuetFourPAvatar,
- StaticP4DuetFourP, StaticP4DuetFourPAvatar,
- // 6P - screen 1
- StaticP1SixP, StaticP1SixPAvatar,
- StaticP2SixP, StaticP2SixPAvatar,
- StaticP3SixP, StaticP3SixPAvatar,
- StaticP4SixP, StaticP4SixPAvatar,
- StaticP5SixP, StaticP5SixPAvatar,
- StaticP6SixP, StaticP6SixPAvatar,
- // 6P duet - screen 1
- StaticP1DuetSixP, StaticP1DuetSixPAvatar,
- StaticP2DuetSixP, StaticP2DuetSixPAvatar,
- StaticP3DuetSixP, StaticP3DuetSixPAvatar,
- StaticP4DuetSixP, StaticP4DuetSixPAvatar,
- StaticP5DuetSixP, StaticP5DuetSixPAvatar,
- StaticP6DuetSixP, StaticP6DuetSixPAvatar
- ]);
-
- if (PlayersPlay = 1) then
+ procedure hideGroup(APlayerCount: integer);
begin
- // this is actually correct! it just puts the sole player on all screens
- maybeShow([StaticP1[0], StaticP1Avatar[0]]);
+ GetSingWidgetSlots(Self, APlayerCount, FrameSlots, AvatarSlots);
+ hide(FrameSlots);
+ hide(AvatarSlots);
end;
-
- if (PlayersPlay = 2) or ((PlayersPlay = 4) and (Ini.Screens = 1)) then
+ procedure setStaticColor(StaticIndex, PlayerIndex: integer);
+ var
+ PlayerColor: TRGB;
begin
- if (Screen = 2) then
- begin
- maybeShow([
- StaticP1TwoP[1], StaticP1TwoPAvatar[1],
- StaticP2R[1], StaticP2RAvatar[1]
- ]);
- end;
-
- if (Screen = 1) then
- begin
- maybeShow([
- StaticP1TwoP[0], StaticP1TwoPAvatar[0],
- StaticP2R[0], StaticP2RAvatar[0]
- ]);
- end;
+ PlayerColor := GetPlayerColor(Ini.SingColor[PlayerIndex]);
+ ScreenSing.Statics[StaticIndex].Texture.ColR := PlayerColor.R;
+ ScreenSing.Statics[StaticIndex].Texture.ColG := PlayerColor.G;
+ ScreenSing.Statics[StaticIndex].Texture.ColB := PlayerColor.B;
end;
-
- if (PlayersPlay = 3) or ((PlayersPlay = 6) and (Ini.Screens = 1)) then
+ procedure setVisibleSlotColors(const Slots: TSlotArray; Count, FirstIndex: integer);
+ var
+ J: integer;
begin
- if (CurrentSong.isDuet) then
- begin
- if (Screen = 2) then
- begin
- maybeShow([
- StaticDuetP1ThreeP[1], StaticDuetP1ThreePAvatar[1],
- StaticDuetP2M[1], StaticDuetP2MAvatar[1],
- StaticDuetP3R[1], StaticDuetP3RAvatar[1]
- ]);
- end;
-
- if (Screen = 1) then
- begin
- maybeShow([
- StaticDuetP1ThreeP[0], StaticDuetP1ThreePAvatar[0],
- StaticDuetP2M[0], StaticDuetP2MAvatar[0],
- StaticDuetP3R[0], StaticDuetP3RAvatar[0]
- ]);
- end;
- end
- else
+ for J := 0 to Count - 1 do
+ setStaticColor(Slots[J], FirstIndex + J);
+ end;
+ procedure setVisibleSlotAvatars(const Slots: TSlotArray; Count, FirstIndex: integer);
+ var
+ J: integer;
+ PlayerIndex: integer;
+ CurrentTexture: TTexture;
+ begin
+ for J := 0 to Count - 1 do
begin
- if (Screen = 2) then
- begin
- maybeShow([
- StaticP1ThreeP[1], StaticP1ThreePAvatar[1],
- StaticP2M[1], StaticP2MAvatar[1],
- StaticP3R[1], StaticP3RAvatar[1]
- ]);
- end;
-
- if (Screen = 1) then
+ PlayerIndex := FirstIndex + J + 1;
+ if (PlayerIndex >= 1) and (PlayerIndex <= UIni.IMaxPlayerCount) then
begin
- maybeShow([
- StaticP1ThreeP[0], StaticP1ThreePAvatar[0],
- StaticP2M[0], StaticP2MAvatar[0],
- StaticP3R[0], StaticP3RAvatar[0]
- ]);
+ CurrentTexture := ScreenSing.Statics[Slots[J]].Texture;
+ ScreenSing.Statics[Slots[J]].Texture := AvatarPlayerTextures[PlayerIndex];
+ ScreenSing.Statics[Slots[J]].Texture.X := CurrentTexture.X;
+ ScreenSing.Statics[Slots[J]].Texture.Y := CurrentTexture.Y;
+ ScreenSing.Statics[Slots[J]].Texture.W := CurrentTexture.W;
+ ScreenSing.Statics[Slots[J]].Texture.H := CurrentTexture.H;
+ ScreenSing.Statics[Slots[J]].Texture.Z := CurrentTexture.Z;
+ ScreenSing.Statics[Slots[J]].Texture.Alpha := CurrentTexture.Alpha;
end;
end;
end;
+begin
+ for IterLayoutPlayerCount := 1 to UIni.IMaxPlayerCount do
+ hideGroup(IterLayoutPlayerCount);
- // 4 Players in 1 Screen
- if (PlayersPlay = 4) and (Ini.Screens = 0) then
+ if Ini.Screens = 1 then
begin
- if (CurrentSong.isDuet) then
- begin
- maybeShow([
- StaticP1DuetFourP, StaticP1DuetFourPAvatar,
- StaticP2DuetFourP, StaticP2DuetFourPAvatar,
- StaticP3DuetFourP, StaticP3DuetFourPAvatar,
- StaticP4DuetFourP, StaticP4DuetFourPAvatar
- ]);
- end
- else
- begin
- maybeShow([
- StaticP1FourP, StaticP1FourPAvatar,
- StaticP2FourP, StaticP2FourPAvatar,
- StaticP3FourP, StaticP3FourPAvatar,
- StaticP4FourP, StaticP4FourPAvatar
- ]);
- end;
- end;
-
- // 6 Players in 1 Screen
- if (PlayersPlay = 6) and (Ini.Screens = 0) then
+ LocalPlayerCount := GetScreenPlayerCount(PlayersPlay, 2, Screen);
+ FirstPlayerIndex := GetFirstPlayerIndexForScreen(PlayersPlay, 2, Screen);
+ end
+ else
begin
- if (CurrentSong.isDuet) then
- begin
- maybeShow([
- StaticP1DuetSixP, StaticP1DuetSixPAvatar,
- StaticP2DuetSixP, StaticP2DuetSixPAvatar,
- StaticP3DuetSixP, StaticP3DuetSixPAvatar,
- StaticP4DuetSixP, StaticP4DuetSixPAvatar,
- StaticP5DuetSixP, StaticP5DuetSixPAvatar,
- StaticP6DuetSixP, StaticP6DuetSixPAvatar
- ]);
- end
- else
- begin
- maybeShow([
- StaticP1SixP, StaticP1SixPAvatar,
- StaticP2SixP, StaticP2SixPAvatar,
- StaticP3SixP, StaticP3SixPAvatar,
- StaticP4SixP, StaticP4SixPAvatar,
- StaticP5SixP, StaticP5SixPAvatar,
- StaticP6SixP, StaticP6SixPAvatar
- ]);
- end;
+ LocalPlayerCount := PlayersPlay;
+ FirstPlayerIndex := 0;
end;
+ GetSingWidgetSlots(Self, LocalPlayerCount, FrameSlots, AvatarSlots);
+ setVisibleSlotColors(FrameSlots, LocalPlayerCount, FirstPlayerIndex);
+ setVisibleSlotAvatars(AvatarSlots, LocalPlayerCount, FirstPlayerIndex);
+ maybeShowCount(FrameSlots, LocalPlayerCount);
+ maybeShowCount(AvatarSlots, LocalPlayerCount);
+
end;
constructor TScreenSingView.Create;
@@ -454,12 +374,26 @@ constructor TScreenSingView.Create;
setColor(avatarFrame, color);
static := ScreenSing.AddStatic(avatarFrame);
end;
+ procedure setColorAndAssignAvatarFrameStaticForSlot(const PlayerCountOnScreen, PlayerIndexOnScreen: integer; var static: integer; color: TRGB);
+ var
+ SingPlayer: TThemeSingPlayer;
+ begin
+ SingPlayer := BuildSingPlayerTemplate(PlayerCountOnScreen, PlayerIndexOnScreen);
+ setColorAndAssignAvatarFrameStatic(SingPlayer.AvatarFrame, static, color);
+ end;
// passing the integers for the statics by reference is deliberate
procedure setColorAndAssignStatics(var singPlayer: TThemeSingPlayer; var avatarFrameStatic: integer; var nameStatic: integer; color: TRGB);
begin
setColorAndAssignAvatarFrameStatic(singPlayer.AvatarFrame, avatarFrameStatic, color);
nameStatic := ScreenSing.AddText(singPlayer.Name);
end;
+ procedure setColorAndAssignStaticsForSlot(const PlayerCountOnScreen, PlayerIndexOnScreen: integer; var avatarFrameStatic: integer; var nameStatic: integer; color: TRGB);
+ var
+ SingPlayer: TThemeSingPlayer;
+ begin
+ SingPlayer := BuildSingPlayerTemplate(PlayerCountOnScreen, PlayerIndexOnScreen);
+ setColorAndAssignStatics(SingPlayer, avatarFrameStatic, nameStatic, color);
+ end;
// passing the integer for the static by reference is deliberate
procedure assignAvatarStatic(var singPlayer: TThemeSingPlayer; var avatarStatic: integer; var texture: TTexture);
begin
@@ -472,6 +406,53 @@ constructor TScreenSingView.Create;
ScreenSing.Statics[avatarStatic].Texture.Z := singPlayer.Avatar.Z;
ScreenSing.Statics[avatarStatic].Texture.Alpha := singPlayer.Avatar.Alpha;
end;
+ procedure assignAvatarStaticForSlot(const PlayerCountOnScreen, PlayerIndexOnScreen: integer; var avatarStatic: integer; var texture: TTexture);
+ var
+ SingPlayer: TThemeSingPlayer;
+ begin
+ SingPlayer := BuildSingPlayerTemplate(PlayerCountOnScreen, PlayerIndexOnScreen);
+ assignAvatarStatic(SingPlayer, avatarStatic, texture);
+ end;
+ procedure InitFrameSlots(MinLayoutPlayerCount, MaxLayoutPlayerCount: integer; CreateTextSlots: boolean);
+ var
+ LayoutPlayerCount: integer;
+ SlotIndex: integer;
+ ColorIndex: integer;
+ begin
+ for LayoutPlayerCount := MinLayoutPlayerCount to MaxLayoutPlayerCount do
+ begin
+ for SlotIndex := 0 to LayoutPlayerCount - 1 do
+ begin
+ ColorIndex := (SlotIndex mod UIni.IMaxPlayerCount) + 1;
+ if CreateTextSlots then
+ setColorAndAssignStaticsForSlot(LayoutPlayerCount, SlotIndex,
+ PlayerFrameSlots[LayoutPlayerCount, SlotIndex],
+ PlayerTextSlots[LayoutPlayerCount, SlotIndex],
+ Col[ColorIndex])
+ else
+ setColorAndAssignAvatarFrameStaticForSlot(LayoutPlayerCount, SlotIndex,
+ PlayerFrameSlots[LayoutPlayerCount, SlotIndex],
+ Col[ColorIndex]);
+ end;
+ end;
+ end;
+ procedure InitAvatarSlots(MaxLayoutPlayerCount: integer);
+ var
+ LayoutPlayerCount: integer;
+ SlotIndex: integer;
+ PlayerIndex: integer;
+ begin
+ for LayoutPlayerCount := 1 to MaxLayoutPlayerCount do
+ begin
+ for SlotIndex := 0 to LayoutPlayerCount - 1 do
+ begin
+ PlayerIndex := (SlotIndex mod UIni.IMaxPlayerCount) + 1;
+ assignAvatarStaticForSlot(LayoutPlayerCount, SlotIndex,
+ PlayerAvatarSlots[LayoutPlayerCount, SlotIndex],
+ AvatarPlayerTextures[PlayerIndex]);
+ end;
+ end;
+ end;
begin
lastVolume:= -1;
//too dangerous, a mouse button is quickly pressed by accident
@@ -506,41 +487,7 @@ constructor TScreenSingView.Create;
for I := 1 to UIni.IMaxPlayerCount do
Col[I] := GetPlayerColor(Ini.SingColor[I - 1]);
- // SCREEN 1
- // 1 player
- setColorAndAssignAvatarFrameStatic(Theme.Sing.Solo1PP1.AvatarFrame, StaticP1[0], Col[1]);
-
- // 2 or 4 players
- setColorAndAssignAvatarFrameStatic(Theme.Sing.Solo2PP1.AvatarFrame, StaticP1TwoP[0], Col[1]);
- setColorAndAssignAvatarFrameStatic(Theme.Sing.Solo2PP2.AvatarFrame, StaticP2R[0] , Col[2]);
-
- // 3 or 6 players
- setColorAndAssignAvatarFrameStatic(Theme.Sing.Solo3PP1.AvatarFrame, StaticP1ThreeP[0], Col[1]);
- setColorAndAssignAvatarFrameStatic(Theme.Sing.Solo3PP2.AvatarFrame, StaticP2M[0] , Col[2]);
- setColorAndAssignAvatarFrameStatic(Theme.Sing.Solo3PP3.AvatarFrame, StaticP3R[0] , Col[3]);
-
- // 3 or 6 players duet
- setColorAndAssignAvatarFrameStatic(Theme.Sing.Duet3PP1.AvatarFrame, StaticDuetP1ThreeP[0], Col[1]);
- setColorAndAssignAvatarFrameStatic(Theme.Sing.Duet3PP2.AvatarFrame, StaticDuetP2M[0] , Col[2]);
- setColorAndAssignAvatarFrameStatic(Theme.Sing.Duet3PP3.AvatarFrame, StaticDuetP3R[0] , Col[3]);
-
- // SCREEN 2
- // 1 player
- setColorAndAssignStatics(Theme.Sing.Solo1PP1, StaticP1[1], TextP1, Col[1]);
-
- // 2 or 4 players
- setColorAndAssignStatics(Theme.Sing.Solo2PP1, StaticP1TwoP[1], TextP1TwoP, Col[3]);
- setColorAndAssignStatics(Theme.Sing.Solo2PP2, StaticP2R[1] , TextP2R , Col[4]);
-
- // 3 or 6 players
- setColorAndAssignStatics(Theme.Sing.Solo3PP1, StaticP1ThreeP[1], TextP1ThreeP, Col[4]);
- setColorAndAssignStatics(Theme.Sing.Solo3PP2, StaticP2M[1] , TextP2M , Col[5]);
- setColorAndAssignStatics(Theme.Sing.Solo3PP3, StaticP3R[1] , TextP3R , Col[6]);
-
- // 3 or 6 players duet
- setColorAndAssignStatics(Theme.Sing.Duet3PP1, StaticDuetP1ThreeP[1], TextDuetP1ThreeP, Col[4]);
- setColorAndAssignStatics(Theme.Sing.Duet3PP2, StaticDuetP2M[1] , TextDuetP2M , Col[5]);
- setColorAndAssignStatics(Theme.Sing.Duet3PP3, StaticDuetP3R[1] , TextDuetP3R , Col[6]);
+ InitFrameSlots(1, UIni.IMaxPlayerCount, true);
for I := 1 to PlayersPlay do
begin
@@ -555,35 +502,6 @@ constructor TScreenSingView.Create;
ScreenSing.PlayerDuetNames[I] := ScreenSing.PlayerNames[I];
end;
- // 4 players in 1 screen
- setColorAndAssignStatics(Theme.Sing.Solo4PP1, StaticP1FourP, TextP1FourP, Col[1]);
- setColorAndAssignStatics(Theme.Sing.Solo4PP2, StaticP2FourP, TextP2FourP, Col[2]);
- setColorAndAssignStatics(Theme.Sing.Solo4PP3, StaticP3FourP, TextP3FourP, Col[3]);
- setColorAndAssignStatics(Theme.Sing.Solo4PP4, StaticP4FourP, TextP4FourP, Col[4]);
-
- // 6 players in 1 screen
- setColorAndAssignStatics(Theme.Sing.Solo6PP1, StaticP1SixP, TextP1SixP, Col[1]);
- setColorAndAssignStatics(Theme.Sing.Solo6PP2, StaticP2SixP, TextP2SixP, Col[2]);
- setColorAndAssignStatics(Theme.Sing.Solo6PP3, StaticP3SixP, TextP3SixP, Col[3]);
- setColorAndAssignStatics(Theme.Sing.Solo6PP4, StaticP4SixP, TextP4SixP, Col[4]);
- setColorAndAssignStatics(Theme.Sing.Solo6PP5, StaticP5SixP, TextP5SixP, Col[5]);
- setColorAndAssignStatics(Theme.Sing.Solo6PP6, StaticP6SixP, TextP6SixP, Col[6]);
-
-
- // 4 players duet in 1 screen
- setColorAndAssignStatics(Theme.Sing.Duet4PP1, StaticP1DuetFourP, TextP1DuetFourP, Col[1]);
- setColorAndAssignStatics(Theme.Sing.Duet4PP2, StaticP2DuetFourP, TextP2DuetFourP, Col[2]);
- setColorAndAssignStatics(Theme.Sing.Duet4PP3, StaticP3DuetFourP, TextP3DuetFourP, Col[3]);
- setColorAndAssignStatics(Theme.Sing.Duet4PP4, StaticP4DuetFourP, TextP4DuetFourP, Col[4]);
-
- // 6 players duet in 1 screen
- setColorAndAssignStatics(Theme.Sing.Duet6PP1, StaticP1DuetSixP, TextP1DuetSixP, Col[1]);
- setColorAndAssignStatics(Theme.Sing.Duet6PP2, StaticP2DuetSixP, TextP2DuetSixP, Col[2]);
- setColorAndAssignStatics(Theme.Sing.Duet6PP3, StaticP3DuetSixP, TextP3DuetSixP, Col[3]);
- setColorAndAssignStatics(Theme.Sing.Duet6PP4, StaticP4DuetSixP, TextP4DuetSixP, Col[4]);
- setColorAndAssignStatics(Theme.Sing.Duet6PP5, StaticP5DuetSixP, TextP5DuetSixP, Col[5]);
- setColorAndAssignStatics(Theme.Sing.Duet6PP6, StaticP6DuetSixP, TextP6DuetSixP, Col[6]);
-
// Sing Bars
// P1-6
for I := 1 to UIni.IMaxPlayerCount do
@@ -659,60 +577,7 @@ constructor TScreenSingView.Create;
ScreenSing.InfoMessageBG := ScreenSing.AddStatic(Theme.Sing.InfoMessageBG);
ScreenSing.InfoMessageText := ScreenSing.AddText(Theme.Sing.InfoMessageText);
- // avatars
- // SCREEN 1
- // 1P
- assignAvatarStatic(Theme.Sing.Solo1PP1, StaticP1Avatar[0], AvatarPlayerTextures[1]);
- // 2P
- assignAvatarStatic(Theme.Sing.Solo2PP1, StaticP1TwoPAvatar[0], AvatarPlayerTextures[1]);
- assignAvatarStatic(Theme.Sing.Solo2PP2, StaticP2RAvatar[0] , AvatarPlayerTextures[2]);
- // 3P
- assignAvatarStatic(Theme.Sing.Solo3PP1, StaticP1ThreePAvatar[0], AvatarPlayerTextures[1]);
- assignAvatarStatic(Theme.Sing.Solo3PP2, StaticP2MAvatar[0] , AvatarPlayerTextures[2]);
- assignAvatarStatic(Theme.Sing.Solo3PP3, StaticP3RAvatar[0] , AvatarPlayerTextures[3]);
- // 3P duet
- assignAvatarStatic(Theme.Sing.Duet3PP1, StaticDuetP1ThreePAvatar[0], AvatarPlayerTextures[1]);
- assignAvatarStatic(Theme.Sing.Duet3PP2, StaticDuetP2MAvatar[0] , AvatarPlayerTextures[2]);
- assignAvatarStatic(Theme.Sing.Duet3PP3, StaticDuetP3RAvatar[0] , AvatarPlayerTextures[3]);
- // 4P
- assignAvatarStatic(Theme.Sing.Solo4PP1, StaticP1FourPAvatar, AvatarPlayerTextures[1]);
- assignAvatarStatic(Theme.Sing.Solo4PP2, StaticP2FourPAvatar, AvatarPlayerTextures[2]);
- assignAvatarStatic(Theme.Sing.Solo4PP3, StaticP3FourPAvatar, AvatarPlayerTextures[3]);
- assignAvatarStatic(Theme.Sing.Solo4PP4, StaticP4FourPAvatar, AvatarPlayerTextures[4]);
- // 4P duet
- assignAvatarStatic(Theme.Sing.Duet4PP1, StaticP1DuetFourPAvatar, AvatarPlayerTextures[1]);
- assignAvatarStatic(Theme.Sing.Duet4PP2, StaticP2DuetFourPAvatar, AvatarPlayerTextures[2]);
- assignAvatarStatic(Theme.Sing.Duet4PP3, StaticP3DuetFourPAvatar, AvatarPlayerTextures[3]);
- assignAvatarStatic(Theme.Sing.Duet4PP4, StaticP4DuetFourPAvatar, AvatarPlayerTextures[4]);
- // 6P
- assignAvatarStatic(Theme.Sing.Solo6PP1, StaticP1SixPAvatar, AvatarPlayerTextures[1]);
- assignAvatarStatic(Theme.Sing.Solo6PP2, StaticP2SixPAvatar, AvatarPlayerTextures[2]);
- assignAvatarStatic(Theme.Sing.Solo6PP3, StaticP3SixPAvatar, AvatarPlayerTextures[3]);
- assignAvatarStatic(Theme.Sing.Solo6PP4, StaticP4SixPAvatar, AvatarPlayerTextures[4]);
- assignAvatarStatic(Theme.Sing.Solo6PP5, StaticP5SixPAvatar, AvatarPlayerTextures[5]);
- assignAvatarStatic(Theme.Sing.Solo6PP6, StaticP6SixPAvatar, AvatarPlayerTextures[6]);
- // 6P duet
- assignAvatarStatic(Theme.Sing.Duet6PP1, StaticP1DuetSixPAvatar, AvatarPlayerTextures[1]);
- assignAvatarStatic(Theme.Sing.Duet6PP2, StaticP2DuetSixPAvatar, AvatarPlayerTextures[2]);
- assignAvatarStatic(Theme.Sing.Duet6PP3, StaticP3DuetSixPAvatar, AvatarPlayerTextures[3]);
- assignAvatarStatic(Theme.Sing.Duet6PP4, StaticP4DuetSixPAvatar, AvatarPlayerTextures[4]);
- assignAvatarStatic(Theme.Sing.Duet6PP5, StaticP5DuetSixPAvatar, AvatarPlayerTextures[5]);
- assignAvatarStatic(Theme.Sing.Duet6PP6, StaticP6DuetSixPAvatar, AvatarPlayerTextures[6]);
-
- // SCREEN 2
- // 1P
- assignAvatarStatic(Theme.Sing.Solo1PP1, StaticP1Avatar[1], AvatarPlayerTextures[2]);
- // 2P
- assignAvatarStatic(Theme.Sing.Solo2PP1, StaticP1TwoPAvatar[1], AvatarPlayerTextures[3]);
- assignAvatarStatic(Theme.Sing.Solo2PP2, StaticP2RAvatar[1] , AvatarPlayerTextures[4]);
- // 3P
- assignAvatarStatic(Theme.Sing.Solo3PP1, StaticP1ThreePAvatar[1], AvatarPlayerTextures[4]);
- assignAvatarStatic(Theme.Sing.Solo3PP2, StaticP2MAvatar[1] , AvatarPlayerTextures[5]);
- assignAvatarStatic(Theme.Sing.Solo3PP3, StaticP3RAvatar[1] , AvatarPlayerTextures[6]);
- // 3P duet
- assignAvatarStatic(Theme.Sing.Duet3PP1, StaticDuetP1ThreePAvatar[1], AvatarPlayerTextures[4]);
- assignAvatarStatic(Theme.Sing.Duet3PP2, StaticDuetP2MAvatar[1] , AvatarPlayerTextures[5]);
- assignAvatarStatic(Theme.Sing.Duet3PP3, StaticDuetP3RAvatar[1] , AvatarPlayerTextures[6]);
+ InitAvatarSlots(UIni.IMaxPlayerCount);
end;
destructor TScreenSingView.Destroy;
@@ -763,6 +628,54 @@ function TScreenSingView.Draw: boolean;
medley_end: boolean;
medley_start_applause: boolean;
LastLineSungToEnd: boolean;
+ LocalPlayerCount: integer;
+ LocalStartIndex: integer;
+ TextSlots: TSlotArray;
+ IterLayoutPlayerCount: integer;
+ SlotIndex: integer;
+ SingPlayer: TThemeSingPlayer;
+ procedure SetPlayerNameTexts(const Slots: TSlotArray; FirstPlayerIndex: integer; UseDuetNames: boolean);
+ var
+ J: integer;
+ PlayerIndex: integer;
+ begin
+ for J := 0 to High(Slots) do
+ begin
+ PlayerIndex := FirstPlayerIndex + J;
+ if (PlayerIndex >= 1) and (PlayerIndex <= PlayersPlay) then
+ begin
+ if UseDuetNames then
+ ScreenSing.Text[Slots[J]].Text := ScreenSing.PlayerDuetNames[PlayerIndex]
+ else
+ ScreenSing.Text[Slots[J]].Text := ScreenSing.PlayerNames[PlayerIndex];
+ end
+ else
+ begin
+ ScreenSing.Text[Slots[J]].Text := '';
+ end;
+ end;
+ end;
+ procedure SetTextVisibility(const Slots: TSlotArray; VisibleCount: integer; Visible: boolean);
+ var
+ J: integer;
+ begin
+ for J := 0 to High(Slots) do
+ ScreenSing.Text[Slots[J]].Visible := Visible and (J < VisibleCount) and ScreenSing.Settings.AvatarsVisible;
+ end;
+ procedure SetLyricsDuetColors(FirstPlayerIndex: integer);
+ var
+ PlayerColor: TRGB;
+ begin
+ PlayerColor := GetSingPlayerColor(FirstPlayerIndex - 1);
+ ScreenSing.LyricsDuetP1.LineColor_act.R := PlayerColor.R;
+ ScreenSing.LyricsDuetP1.LineColor_act.G := PlayerColor.G;
+ ScreenSing.LyricsDuetP1.LineColor_act.B := PlayerColor.B;
+
+ PlayerColor := GetSingPlayerColor(FirstPlayerIndex);
+ ScreenSing.LyricsDuetP2.LineColor_act.R := PlayerColor.R;
+ ScreenSing.LyricsDuetP2.LineColor_act.G := PlayerColor.G;
+ ScreenSing.LyricsDuetP2.LineColor_act.B := PlayerColor.B;
+ end;
begin
ScreenSing.Background.Draw;
@@ -791,91 +704,31 @@ function TScreenSingView.Draw: boolean;
if (ScreenSing.fShowWebCam) then
SingDrawWebCamFrame;
- // set player names (for 2 screens and only singstar skin)
- if ScreenAct = 1 then
- begin
- ScreenSing.Text[TextP1].Text := ScreenSing.PlayerNames[1];
- ScreenSing.Text[TextP1TwoP].Text := ScreenSing.PlayerNames[1];
- ScreenSing.Text[TextP1ThreeP].Text := ScreenSing.PlayerNames[1];
- ScreenSing.Text[TextP2R].Text := ScreenSing.PlayerNames[2];
- ScreenSing.Text[TextP2M].Text := ScreenSing.PlayerNames[2];
- ScreenSing.Text[TextP3R].Text := ScreenSing.PlayerNames[3];
- ScreenSing.Text[TextDuetP1ThreeP].Text := ScreenSing.PlayerDuetNames[1];
- ScreenSing.Text[TextDuetP2M].Text := ScreenSing.PlayerDuetNames[2];
- ScreenSing.Text[TextDuetP3R].Text := ScreenSing.PlayerDuetNames[3];
- ScreenSing.Text[TextP1FourP].Text := ScreenSing.PlayerNames[1];
- ScreenSing.Text[TextP2FourP].Text := ScreenSing.PlayerNames[2];
- ScreenSing.Text[TextP3FourP].Text := ScreenSing.PlayerNames[3];
- ScreenSing.Text[TextP4FourP].Text := ScreenSing.PlayerNames[4];
- ScreenSing.Text[TextP1DuetFourP].Text := ScreenSing.PlayerDuetNames[1];
- ScreenSing.Text[TextP2DuetFourP].Text := ScreenSing.PlayerDuetNames[2];
- ScreenSing.Text[TextP3DuetFourP].Text := ScreenSing.PlayerDuetNames[3];
- ScreenSing.Text[TextP4DuetFourP].Text := ScreenSing.PlayerDuetNames[4];
- ScreenSing.Text[TextP1SixP].Text := ScreenSing.PlayerNames[1];
- ScreenSing.Text[TextP2SixP].Text := ScreenSing.PlayerNames[2];
- ScreenSing.Text[TextP3SixP].Text := ScreenSing.PlayerNames[3];
- ScreenSing.Text[TextP4SixP].Text := ScreenSing.PlayerNames[4];
- ScreenSing.Text[TextP5SixP].Text := ScreenSing.PlayerNames[5];
- ScreenSing.Text[TextP6SixP].Text := ScreenSing.PlayerNames[6];
- ScreenSing.Text[TextP1DuetSixP].Text := ScreenSing.PlayerDuetNames[1];
- ScreenSing.Text[TextP2DuetSixP].Text := ScreenSing.PlayerDuetNames[2];
- ScreenSing.Text[TextP3DuetSixP].Text := ScreenSing.PlayerDuetNames[3];
- ScreenSing.Text[TextP4DuetSixP].Text := ScreenSing.PlayerDuetNames[4];
- ScreenSing.Text[TextP5DuetSixP].Text := ScreenSing.PlayerDuetNames[5];
- ScreenSing.Text[TextP6DuetSixP].Text := ScreenSing.PlayerDuetNames[6];
-
- if (CurrentSong.isDuet) then
- begin
- if (PlayersPlay = 4) then
- begin
- ScreenSing.LyricsDuetP1.LineColor_act.R := ColPlayer[0].R;
- ScreenSing.LyricsDuetP1.LineColor_act.G := ColPlayer[0].G;
- ScreenSing.LyricsDuetP1.LineColor_act.B := ColPlayer[0].B;
+ LocalPlayerCount := GetScreenPlayerCount(PlayersPlay, Screens, ScreenAct);
+ LocalStartIndex := GetFirstPlayerIndexForScreen(PlayersPlay, Screens, ScreenAct) + 1;
- ScreenSing.LyricsDuetP2.LineColor_act.R := ColPlayer[1].R;
- ScreenSing.LyricsDuetP2.LineColor_act.G := ColPlayer[1].G;
- ScreenSing.LyricsDuetP2.LineColor_act.B := ColPlayer[1].B;
- end;
- end;
+ for IterLayoutPlayerCount := 1 to UIni.IMaxPlayerCount do
+ begin
+ GetSingTextSlots(Self, IterLayoutPlayerCount, TextSlots);
+ SetTextVisibility(TextSlots, 0, false);
end;
- if ScreenAct = 2 then
+ GetSingTextSlots(Self, LocalPlayerCount, TextSlots);
+ for SlotIndex := 0 to LocalPlayerCount - 1 do
begin
- case PlayersPlay of
- 4:
- begin
- ScreenSing.Text[TextP1TwoP].Text := ScreenSing.PlayerNames[3];
- ScreenSing.Text[TextP2R].Text := ScreenSing.PlayerNames[4];
-
- if (CurrentSong.isDuet) and (PlayersPlay = 4) then
- begin
- ScreenSing.LyricsDuetP1.LineColor_act.R := ColPlayer[2].R;
- ScreenSing.LyricsDuetP1.LineColor_act.G := ColPlayer[2].G;
- ScreenSing.LyricsDuetP1.LineColor_act.B := ColPlayer[2].B;
-
- ScreenSing.LyricsDuetP2.LineColor_act.R := ColPlayer[3].R;
- ScreenSing.LyricsDuetP2.LineColor_act.G := ColPlayer[3].G;
- ScreenSing.LyricsDuetP2.LineColor_act.B := ColPlayer[3].B;
- end;
+ SingPlayer := BuildSingPlayerTemplate(LocalPlayerCount, SlotIndex);
+ ApplySingPlayerTemplate(
+ SingPlayer,
+ PlayerFrameSlots[LocalPlayerCount, SlotIndex],
+ PlayerAvatarSlots[LocalPlayerCount, SlotIndex],
+ PlayerTextSlots[LocalPlayerCount, SlotIndex]
+ );
+ end;
+ SetPlayerNameTexts(TextSlots, LocalStartIndex, IsCurrentSongDuet and (LocalPlayerCount >= 3));
+ SetTextVisibility(TextSlots, LocalPlayerCount, true);
- end;
- 6:
- begin
- if (CurrentSong.isDuet) then
- begin
- ScreenSing.Text[TextDuetP1ThreeP].Text := ScreenSing.PlayerDuetNames[4];
- ScreenSing.Text[TextDuetP2M].Text := ScreenSing.PlayerDuetNames[5];
- ScreenSing.Text[TextDuetP3R].Text := ScreenSing.PlayerDuetNames[6];
- end
- else
- begin
- ScreenSing.Text[TextP1ThreeP].Text := ScreenSing.PlayerNames[4];
- ScreenSing.Text[TextP2M].Text := ScreenSing.PlayerNames[5];
- ScreenSing.Text[TextP3R].Text := ScreenSing.PlayerNames[6];
- end;
- end;
- end; // case
- end; // if
+ if IsCurrentSongDuet and (LocalPlayerCount = 2) then
+ SetLyricsDuetColors(LocalStartIndex);
// retrieve current lyrics time, we have to store the value to avoid
// that min- and sec-values do not match
@@ -1032,19 +885,19 @@ function TScreenSingView.Draw: boolean;
if (ScreenSing.Settings.TimeBarVisible) then
DrawInfoLyricBar;
+ // draw scores
+ if (ScreenSing.Settings.ScoresVisible) and ((Ini.SingScores = 1) or (Party.bPartyGame)) then
+ ScreenSing.Scores.Draw;
+
// always draw custom items
ScreenSing.Statics[StaticLyricsBar].Visible := ScreenSing.Settings.LyricsVisible;
- ScreenSing.Statics[StaticLyricsBarDuet].Visible := ScreenSing.Settings.LyricsVisible and (CurrentSong.isDuet) and (PlayersPlay <> 1);
+ ScreenSing.Statics[StaticLyricsBarDuet].Visible := ScreenSing.Settings.LyricsVisible and IsCurrentSongDuet and (PlayersPlay <> 1);
ScreenSing.Statics[StaticTimeBar].Visible := ScreenSing.Settings.TimeBarVisible;
SingDraw;
// goldennotestarstwinkle
GoldenRec.SpawnRec;
- // draw scores
- if (ScreenSing.Settings.ScoresVisible) and ((Ini.SingScores = 1) or (Party.bPartyGame)) then
- ScreenSing.Scores.Draw;
-
FadeMessage();
// draw pausepopup
@@ -1367,4 +1220,3 @@ procedure TScreenSingView.DrawInfoLyricBar();
end;
end.
-
diff --git a/src/ultrastardx-unix.lpi b/src/ultrastardx-unix.lpi
index 04b8826ae..e283ebbc0 100644
--- a/src/ultrastardx-unix.lpi
+++ b/src/ultrastardx-unix.lpi
@@ -544,6 +544,11 @@
+
+
+
+
+
diff --git a/src/ultrastardx-win.lpi b/src/ultrastardx-win.lpi
index 80b5be170..78e995725 100644
--- a/src/ultrastardx-win.lpi
+++ b/src/ultrastardx-win.lpi
@@ -560,6 +560,10 @@
+
+
+
+
diff --git a/src/ultrastardx.dpr b/src/ultrastardx.dpr
index f319dedf8..9df63db22 100644
--- a/src/ultrastardx.dpr
+++ b/src/ultrastardx.dpr
@@ -215,6 +215,7 @@ uses
UPathUtils in 'base\UPathUtils.pas',
UNote in 'base\UNote.pas',
UBeatTimer in 'base\UBeatTimer.pas',
+ UPlayerLayout in 'base\UPlayerLayout.pas',
TextGL in 'base\TextGL.pas',
UUnicodeUtils in 'base\UUnicodeUtils.pas',