main/ holds the main window and top bar, quiz/ the quiz and its parts, player/ the music player, popups/ every popup and what they share, data/ the songs, players, playlist and settings, server/ the MusicServer client, common/ the list row and GameLog, and themes/ the themes and style boxes.
299 lines
10 KiB
GDScript
299 lines
10 KiB
GDScript
class_name Quiz
|
|
extends Control
|
|
## The quiz: the song that is playing, the playlist, the players and their points, and
|
|
## the popups opened from here (settings, character select, winner and log).
|
|
##
|
|
## The main window shows the quiz below its top bar. Pictures and buttons keep the
|
|
## positions they had in the main window, so the quiz fills the whole window and lets
|
|
## clicks through where it has nothing.
|
|
|
|
## Emitted when another MusicServer is picked in the settings, after the quiz has
|
|
## reloaded from it.
|
|
|
|
signal server_changed
|
|
|
|
## Emitted with a line for the game log, e.g. when a player gets a point.
|
|
signal event_logged(text: String)
|
|
|
|
var songs: Array = []
|
|
var current_player_row: PlayerRow
|
|
|
|
## True while statistics are off because a player won, until points are reset.
|
|
var stats_paused_by_win: bool = false
|
|
|
|
## Dims the window behind an open popup and keeps clicks from reaching the buttons under it.
|
|
var popup_backdrop: PopupBackdrop
|
|
|
|
@onready var open_button: Button = $Open
|
|
@onready var file_dialog: FileDialog = $FileDialog
|
|
@onready var inspiration_list: InspirationList = $InspirationList
|
|
@onready var now_playing: NowPlaying = $NowPlaying
|
|
@onready var players_panel: PlayersPanel = $PlayersPanel
|
|
@onready var toolbar: QuizToolbar = $QuizToolbar
|
|
@onready var settings_popup: SettingsPopup = $SettingsPopup
|
|
@onready var winner_popup: WinnerPopup = %WinnerPopup
|
|
@onready var song_controls: SongControls = $SongControls
|
|
@onready var song_loader: SongLoader = $SongLoader
|
|
@onready var music_list_panel: MusicListPanel = $MusicListPanel
|
|
@onready var character_select_popup: CharacterSelectPopup = %CharacterSelectPopup
|
|
@onready var music_player: MusicPlayer = $MusicPlayer
|
|
@onready var debug_label: Label = $DebugLabel
|
|
|
|
|
|
func _ready() -> void:
|
|
popup_backdrop = PopupBackdrop.add_to(self, _popups())
|
|
if OS.has_feature("debug"):
|
|
GameLog.debug("is_debug")
|
|
debug_label.visible = true
|
|
Settings.is_debug = true
|
|
settings_popup.set_winning_score(5)
|
|
settings_popup.set_selected_server(4)
|
|
song_controls.next_pressed.connect(play_next_song)
|
|
song_controls.show_answer_pressed.connect(show_answer_pressed)
|
|
toolbar.sound_test_pressed.connect(music_player.get_sound_test_song)
|
|
toolbar.settings_pressed.connect(show_settings)
|
|
toolbar.reset_playlist_pressed.connect(reset_playlist)
|
|
toolbar.reset_points_pressed.connect(reset_points)
|
|
song_loader.song_list_loaded.connect(update_song_list)
|
|
song_loader.song_added.connect(_on_song_added)
|
|
|
|
character_select_popup.character_selected.connect(_on_new_character_selected)
|
|
music_list_panel.song_clicked.connect(song_object_clicked)
|
|
players_panel.player_added.connect(_on_player_added)
|
|
players_panel.player_removed.connect(_on_player_removed)
|
|
players_panel.change_character_requested.connect(_on_change_character_requested)
|
|
music_player.play_next_song.connect(play_next_song)
|
|
music_player.update_song_list.connect(update_song_list)
|
|
settings_popup.server_changed.connect(_on_server_changed)
|
|
settings_popup.visibility_changed.connect(_on_settings_popup_visibility_changed)
|
|
|
|
open_button.pressed.connect(open)
|
|
|
|
inspiration_list.load_from_server()
|
|
song_loader.load_song_list()
|
|
character_select_popup.load_characters()
|
|
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if event is InputEventKey and event.pressed:
|
|
if event.alt_pressed && event.keycode == KEY_UP:
|
|
GameLog.debug("Alt + UP pressed")
|
|
music_player.change_volume(0.05)
|
|
if event.alt_pressed && event.keycode == KEY_DOWN:
|
|
GameLog.debug("Alt + DOWN pressed")
|
|
music_player.change_volume(-0.05)
|
|
if event.alt_pressed && event.ctrl_pressed && event.keycode == KEY_LEFT:
|
|
GameLog.debug("Ctrl + Alt + LEFT pressed")
|
|
music_player.restart()
|
|
elif event.alt_pressed && event.keycode == KEY_LEFT:
|
|
GameLog.debug("Alt + LEFT pressed")
|
|
music_player.seek(-5)
|
|
if event.alt_pressed && event.keycode == KEY_RIGHT:
|
|
GameLog.debug("Alt + RIGHT pressed")
|
|
music_player.seek(5)
|
|
|
|
|
|
## Disables the buttons that use the song list while the server syncs it.
|
|
func lock_for_sync() -> void:
|
|
toolbar.set_locked(true)
|
|
song_controls.set_locked(true)
|
|
|
|
|
|
## Reloads from the server after a sync and starts a new game.
|
|
func on_sync_finished() -> void:
|
|
refresh_from_server()
|
|
toolbar.set_locked(false)
|
|
song_controls.set_locked(false)
|
|
reset_points()
|
|
|
|
|
|
## Reloads the soundtracks, playlist and characters from the server.
|
|
func refresh_from_server() -> void:
|
|
GameLog.debug("refresh_from_server")
|
|
inspiration_list.load_from_server()
|
|
reset_playlist()
|
|
character_select_popup.load_characters()
|
|
|
|
|
|
func _on_server_changed() -> void:
|
|
GameLog.debug("_on_server_changed")
|
|
refresh_from_server()
|
|
reset_points()
|
|
server_changed.emit()
|
|
|
|
|
|
func show_answer_pressed() -> void:
|
|
GameLog.debug("show_answer_pressed")
|
|
Playlist.song_is_answered()
|
|
update_song_list()
|
|
|
|
|
|
func play_next_song() -> void:
|
|
GameLog.debug("play_next_song ", Playlist.latest_played_song)
|
|
if Playlist.first_song_played:
|
|
Playlist.set_latest_played_song()
|
|
Playlist.first_song_played = true
|
|
music_player.play_song_object(Playlist.latest_played_song)
|
|
if !(Playlist.get_preloaded_songs() > 0):
|
|
song_controls.set_next_enabled(false)
|
|
song_loader.fetch_song_if_idle()
|
|
|
|
|
|
func _popups() -> Array[BasePopup]:
|
|
return [settings_popup, character_select_popup, winner_popup]
|
|
|
|
|
|
# The cache size can be changed in the settings. Waiting until the settings are closed
|
|
# avoids starting downloads while the user is still clicking the number up and down.
|
|
func _on_settings_popup_visibility_changed() -> void:
|
|
if !settings_popup.visible:
|
|
song_loader.fill_cache()
|
|
|
|
|
|
func _on_song_added() -> void:
|
|
song_controls.set_next_enabled(true)
|
|
if Settings.is_debug:
|
|
update_song_list()
|
|
|
|
|
|
func update_song_list() -> void:
|
|
GameLog.debug("update_song_list")
|
|
if Playlist.currently_playing_song >= 0:
|
|
now_playing.show_song(Playlist.get_current_soundtrack_title(),
|
|
Playlist.get_current_song_title())
|
|
music_list_panel.refresh()
|
|
|
|
|
|
func song_object_clicked(song_no: int) -> void:
|
|
GameLog.debug("Clicked Song Object: ", Playlist.song_object_array[song_no].to_string())
|
|
if !Settings.character_select_open:
|
|
if Playlist.get_song(song_no) == null:
|
|
GameLog.debug("has no song, need to download")
|
|
var song_downloaded: Callable = func song_downloaded(body: PackedByteArray) -> void:
|
|
var sound: AudioStream = AudioStreamMP3.new()
|
|
sound.data = body
|
|
Playlist.add_song_to_song_object(song_no, sound)
|
|
music_player.play_song_object(song_no)
|
|
MusicServerClient.fetch_song(song_no, song_downloaded)
|
|
else:
|
|
GameLog.debug("song already downloaded")
|
|
music_player.play_song_object(song_no)
|
|
|
|
|
|
func reset_playlist() -> void:
|
|
GameLog.debug("reset_playlist")
|
|
var playlist_reset_done: Callable = func playlist_reset_done() -> void:
|
|
Playlist.reset_playlist()
|
|
song_loader.load_song_list()
|
|
|
|
MusicServerClient.reset_playlist(playlist_reset_done)
|
|
|
|
|
|
func reset_points() -> void:
|
|
GameLog.debug("reset_points")
|
|
for player_objects: PlayerObject in Settings.player_array:
|
|
player_objects.reset_points()
|
|
players_panel.reload()
|
|
# A new game starts, so turn statistics back on if winning turned them off
|
|
if stats_paused_by_win:
|
|
Settings.add_to_stats = true
|
|
stats_paused_by_win = false
|
|
|
|
|
|
func show_settings() -> void:
|
|
GameLog.debug("show_settings")
|
|
settings_popup.open()
|
|
|
|
|
|
# Each new player's points reach the music player, the log and the winner popup.
|
|
func _on_player_added(new_player_object: PlayerObject) -> void:
|
|
new_player_object.first_point_triggered.connect(music_player._on_point_triggered.bind("first"))
|
|
new_player_object.match_point_triggered.connect(music_player._on_point_triggered.bind("match"))
|
|
new_player_object.winner_triggered.connect(_on_player_won.bind(new_player_object))
|
|
new_player_object.point_given_sound.connect(_on_make_point_given_sound)
|
|
new_player_object.player_point_given.connect(_on_point_given.bind(new_player_object))
|
|
new_player_object.player_point_taken.connect(_on_point_taken.bind(new_player_object))
|
|
|
|
|
|
func _on_point_given(player_object: PlayerObject) -> void:
|
|
GameLog.debug("_on_point_given")
|
|
event_logged.emit(player_object.player_name + " got a point")
|
|
if Playlist.currently_playing_song >= 0:
|
|
Playlist.add_point(player_object.id)
|
|
update_song_list()
|
|
|
|
|
|
func _on_make_point_given_sound() -> void:
|
|
music_player.play_sound_effect(preload("res://sounds/itemopen.wav"))
|
|
|
|
|
|
func _on_point_taken(player_object: PlayerObject) -> void:
|
|
GameLog.debug("_on_point_taken")
|
|
event_logged.emit(player_object.player_name + " lost a point")
|
|
music_player.play_sound_effect(preload("res://sounds/itemequip.wav"))
|
|
if Playlist.currently_playing_song >= 0:
|
|
Playlist.remove_point(player_object.id)
|
|
update_song_list()
|
|
|
|
|
|
func _on_player_won(player_object: PlayerObject) -> void:
|
|
GameLog.debug("_on_player_won")
|
|
winner_popup.show_winner(player_object)
|
|
music_player.play_song(preload("res://sounds/winning.mp3"))
|
|
# Songs played after the game is won don't count towards the statistics
|
|
if Settings.add_to_stats:
|
|
Settings.add_to_stats = false
|
|
stats_paused_by_win = true
|
|
|
|
|
|
func _on_player_removed(player_object: PlayerObject) -> void:
|
|
Playlist.remove_player_from_list(player_object.id)
|
|
update_song_list()
|
|
|
|
|
|
func _on_change_character_requested(new_player: PlayerRow, player_name: String) -> void:
|
|
GameLog.debug("_on_player_change_character_clicked")
|
|
current_player_row = new_player
|
|
GameLog.debug("Change character for: " + player_name)
|
|
character_select_popup.show_grid(player_name)
|
|
|
|
|
|
func _on_new_character_selected(character_texture: ImageTexture) -> void:
|
|
GameLog.debug("_on_new_character_selected")
|
|
current_player_row.new_character_selected(character_texture)
|
|
|
|
|
|
###Local
|
|
|
|
var local_path: String = '/Users/sebastian/ResilioSync/Sorterat_test/Metal Gear Solid 4 - Guns of the Patriots/2-16 Metal Gear Saga.mp3'
|
|
|
|
|
|
func open() -> void:
|
|
file_dialog.popup()
|
|
|
|
|
|
func _on_file_dialog_dir_selected(path: String) -> void:
|
|
GameLog.debug(path)
|
|
dir_contents(path)
|
|
|
|
|
|
func dir_contents(path: String) -> void:
|
|
var dir: DirAccess = DirAccess.open(path)
|
|
if dir:
|
|
dir.list_dir_begin()
|
|
var file_name: String = dir.get_next()
|
|
songs.clear()
|
|
var soundtracks: Array = []
|
|
while file_name != "":
|
|
if dir.current_is_dir():
|
|
#GameLog.debug("Found directory: " + file_name)
|
|
soundtracks.append(file_name)
|
|
else:
|
|
#GameLog.debug("Found file: " + file_name)
|
|
if file_name.ends_with(".mp3"):
|
|
songs.append(path + "/" + file_name)
|
|
file_name = dir.get_next()
|
|
inspiration_list.show_soundtracks(soundtracks)
|
|
else:
|
|
GameLog.warning("An error occurred when trying to access the path.")
|