Follow the GDScript style guide in every script

- Types on every parameter, return value and variable, and snake_case names
  (the player name limit is the constant MAX_NAME_LENGTH).
- Spelling fixes: *_triggered, character_selected, separator, caught_errors.
  The server's catched_errors key stays as the server sends it.
- Signals are connected with signal.connect() instead of by name.
- Code is ordered signals, constants, exported vars, vars, @onready vars,
  functions, with @onready on one line and two blank lines between functions.
- Every script starts with a ## description. Template comments, old LOC notes
  and commented-out code are gone, apart from the local play code.
- Lines are at most 100 characters, apart from the local play path.
- The screenshot tour turns off the blinking text cursor so pictures match.
This commit is contained in:
Sansan committed 2026-10-06 11:53:26 +02:00
1 parent 674604425f
commit a0428e3475
45 files changed
+580 -589

No files matched your search

+9
View File
@@ -87,6 +87,7 @@ static func prepare_autoloads() -> void:
func run(on_state: Callable) -> void:
# The debug build lowers the winning score on startup; keep it out of reach
Settings.winning_score = 20
_stop_caret_blink(_main)
await _settle()
await on_state.call("startup", null)
@@ -194,6 +195,14 @@ func _call(method: String, args: Array = []) -> Variant:
return _main.callv(method, args)
# A blinking text cursor would be shown in some pictures and not in others
func _stop_caret_blink(node: Node) -> void:
if node is TextEdit || node is LineEdit:
node.caret_blink = false
for child: Node in node.get_children():
_stop_caret_blink(child)
func _server() -> FakeHttpTransport:
return MusicServerClient.transport
+8 -2
View File
@@ -58,9 +58,14 @@ const RENAMED_SCENES: Dictionary = {
"Player": "PlayerRow",
}
## Nodes renamed inside a popup: old path from the main window, and new path.
const SYNC_COLUMNS: String = "SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer"
## Nodes renamed inside a popup: the path after the moves above, and the new path.
const RENAMED_PATHS: Dictionary = {
"SearchPopup/ScrollContainer/VBoxContainer": "SearchPopup/ScrollContainer/SearchResults",
SYNC_COLUMNS + "/CatchedErrorsVBox": SYNC_COLUMNS + "/CaughtErrorsVBox",
SYNC_COLUMNS + "/CaughtErrorsVBox/CatchedErrorsLabel":
SYNC_COLUMNS + "/CaughtErrorsVBox/CaughtErrorsLabel",
}
## How far a node may be from its old place, in pixels.
@@ -102,9 +107,10 @@ static func new_path(old_path: String) -> String:
var first: String = parts[0]
parts[0] = MOVED.get(first, first)
var path: String = "/".join(parts)
# In order, so a node inside a renamed node is found after its parent's rename
for renamed: String in RENAMED_PATHS:
if path == renamed || path.begins_with(renamed + "/"):
return RENAMED_PATHS[renamed] + path.trim_prefix(renamed)
path = RENAMED_PATHS[renamed] + path.trim_prefix(renamed)
return path
+2 -1
View File
@@ -105,7 +105,8 @@ func test_rows_follow_player_order_and_numbering() -> void:
_add("Marle")
_add("Lucca")
assert_array(_rows().map(func(row: PlayerRow) -> String: return row.player_object.player_name)) \
assert_array(_rows().map(
func(row: PlayerRow) -> String: return row.player_object.player_name)) \
.contains_exactly(["Crono", "Marle", "Lucca"])
assert_array(_rows().map(func(row: PlayerRow) -> int: return row.list_index)) \
.contains_exactly([0, 1, 2])
+15 -8
View File
@@ -9,6 +9,12 @@ const MAIN_WINDOW_CHILDREN: Array[String] = [
"ShortcutsPopup", "StatisticsPopupPanel", "AboutPopup", "LogPopup",
]
## The quiz buttons that are disabled while the server syncs.
const LOCKED_BY_SYNC: Array[String] = [
"QuizToolbar/SoundTestButton", "QuizToolbar/ResetPlaylistButton",
"SongControls/ShowAnswerButton", "SongControls/NextButton",
]
const TOP_BAR_CHILDREN: Array[String] = [
"TopPanelContainer", "Title", "SyncButton", "SearchButton", "StatisticsButton",
"ShortcutsButton", "AboutButton", "QRButton",
@@ -130,7 +136,8 @@ func test_points_from_the_player_list_reach_the_song_and_log() -> void:
(_player_row(crono).get_node("HBoxContainer/AddPoint") as BaseButton).pressed.emit()
assert_array(Playlist.song_object_array[0].players_given_point).contains_exactly([crono.id])
assert_int((_window.get_node("%LogPopup").get_node("%LogVBoxContainer") as Node).get_child_count()) \
var log_rows: Node = _window.get_node("%LogPopup").get_node("%LogVBoxContainer")
assert_int(log_rows.get_child_count()) \
.is_equal(1)
@@ -143,12 +150,13 @@ func test_character_button_in_the_player_list_picks_a_new_character() -> void:
assert_bool(character_select.visible).is_true()
var texture: ImageTexture = ImageTexture.create_from_image(
Image.create(4, 4, false, Image.FORMAT_RGBA8))
character_select.new_new_character_selected.emit(texture)
character_select.character_selected.emit(texture)
assert_object(crono.character).is_same(texture)
func test_sound_test_button_fetches_the_sound_test_song() -> void:
_server.respond_bytes("/music/soundTest", FileAccess.get_file_as_bytes("res://tests/data/short.mp3"))
_server.respond_bytes("/music/soundTest",
FileAccess.get_file_as_bytes("res://tests/data/short.mp3"))
await _click_at(_center(_quiz.get_node("QuizToolbar/SoundTestButton")))
@@ -166,7 +174,8 @@ func test_loaded_song_list_shows_in_the_music_list() -> void:
_quiz.song_loader.load_song_list()
var rows: Array[Node] = _quiz.get_node("MusicListPanel/ScrollContainer/MusicList").get_children()
var rows: Array[Node] = _quiz.get_node("MusicListPanel/ScrollContainer/MusicList") \
.get_children()
assert_array(rows.map(func(row: SongRow) -> int: return row.song_object.song_number)) \
.contains_exactly([0, 1])
@@ -203,8 +212,7 @@ func test_sync_disables_quiz_buttons_until_finished() -> void:
_top_bar_button("SyncButton").pressed.emit()
sync_popup.sync_timer.stop()
for button_name: String in ["QuizToolbar/SoundTestButton", "QuizToolbar/ResetPlaylistButton", "SongControls/ShowAnswerButton",
"SongControls/NextButton"]:
for button_name: String in LOCKED_BY_SYNC:
assert_bool((_quiz.get_node(button_name) as Button).disabled) \
.override_failure_message(button_name + " not disabled").is_true()
assert_bool(_top_bar_button("SyncButton").disabled).is_false()
@@ -214,8 +222,7 @@ func test_sync_disables_quiz_buttons_until_finished() -> void:
sync_popup._on_sync_timeout()
await _runner.simulate_frames(2)
for button_name: String in ["QuizToolbar/SoundTestButton", "QuizToolbar/ResetPlaylistButton", "SongControls/ShowAnswerButton",
"SongControls/NextButton"]:
for button_name: String in LOCKED_BY_SYNC:
assert_bool((_quiz.get_node(button_name) as Button).disabled) \
.override_failure_message(button_name + " still disabled").is_false()
# The search list in the main window and the quiz playlist are both reloaded
+9 -4
View File
@@ -1,7 +1,9 @@
extends GdUnitTestSuite
## Downloading songs into the Playlist ahead of time, against a fake server.
const SONG_INFO: Dictionary = {"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time"}
const SONG_INFO: Dictionary = {
"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time",
}
var _snapshot: AutoloadSnapshot
var _server: FakeHttpTransport
@@ -32,7 +34,8 @@ func test_load_song_list_adds_songs_already_played_on_the_server() -> void:
_server.respond_json("/music/list", [
{"SongNo": 0, "Soundtrack": "Chrono Trigger", "Song": "Corridors of Time"},
])
_server.respond_json("/music/info", {"SongNo": 1, "Soundtrack": "Final Fantasy VI", "Song": "Dancing Mad"})
_server.respond_json("/music/info",
{"SongNo": 1, "Soundtrack": "Final Fantasy VI", "Song": "Dancing Mad"})
var signals: GdUnitSignalAssert = assert_signal(monitor_signals(_loader))
_loader.load_song_list()
@@ -57,7 +60,8 @@ func test_fetch_song_downloads_queues_and_adds_the_song() -> void:
_loader.fetch_song()
await signals.is_emitted("song_added")
assert_array(_server.requested_paths).contains_exactly(["/music/rand", "/music/addQue", "/music/info"])
assert_array(_server.requested_paths) \
.contains_exactly(["/music/rand", "/music/addQue", "/music/info"])
var song: SongObject = Playlist.song_object_array[0]
assert_str(song.song_title).is_equal("Corridors of Time")
assert_object(song.song).is_not_null()
@@ -75,7 +79,8 @@ func test_fetch_song_keeps_going_until_the_cache_is_full() -> void:
func test_low_played_mode_uses_its_endpoint() -> void:
Settings.use_low_played_mode = true
_server.respond_bytes("/music/rand/low", FileAccess.get_file_as_bytes("res://tests/data/short.mp3"))
_server.respond_bytes("/music/rand/low",
FileAccess.get_file_as_bytes("res://tests/data/short.mp3"))
_loader.fetch_song()
+4 -3
View File
@@ -1,4 +1,5 @@
extends GdUnitTestSuite
## The sync popup on its own: starting a sync, its progress, and how the result is shown.
var _server: FakeHttpTransport
var _snapshot: AutoloadSnapshot
@@ -132,7 +133,7 @@ func test_errors_are_listed() -> void:
_finish_sync(result)
assert_bool(_node("CatchedErrorsVBox").visible).is_true()
assert_bool(_node("CaughtErrorsVBox").visible).is_true()
func test_reopening_after_sync_shows_result_without_syncing_again() -> void:
@@ -152,7 +153,7 @@ func test_errors_section_has_errors_header() -> void:
_finish_sync(result)
assert_str((_node("CatchedErrorsVBox").get_child(0) as Label).text).is_equal("Errors")
assert_str((_node("CaughtErrorsVBox").get_child(0) as Label).text).is_equal("Errors")
func test_long_names_wrap_instead_of_widening_the_window() -> void:
@@ -173,7 +174,7 @@ func test_long_names_wrap_instead_of_widening_the_window() -> void:
var panel_width: float = (_window.get_node("SyncPanel") as Control).size.x
assert_float(_node("SyncHBoxContainer").get_combined_minimum_size().x) \
.is_less(panel_width)
assert_float(_node("CatchedErrorsVBox").get_combined_minimum_size().x) \
assert_float(_node("CaughtErrorsVBox").get_combined_minimum_size().x) \
.is_less(panel_width)
+1
View File
@@ -1,4 +1,5 @@
extends GdUnitTestSuite
## ListRow: text, alternating backgrounds and wrapping.
func _background(list_row: ListRow) -> Color:
+1
View File
@@ -1,4 +1,5 @@
extends GdUnitTestSuite
## How the music player shows a song's time, including the hidden parts.
var _music_player: MusicPlayer
var _hide_beginning: bool
+3 -1
View File
@@ -1,4 +1,5 @@
extends GdUnitTestSuite
## MusicServerClient: which paths it asks for and how it handles the answers.
var _server: FakeHttpTransport
@@ -115,7 +116,8 @@ func test_mark_song_played_sends_put() -> void:
func test_character_name_is_url_encoded() -> void:
MusicServerClient.fetch_character_image("Paper Mario.png", func(_body: PackedByteArray) -> void: pass)
MusicServerClient.fetch_character_image("Paper Mario.png",
func(_body: PackedByteArray) -> void: pass)
assert_array(_server.requested_paths).contains_exactly(["/character?name=Paper%20Mario.png"])
+7 -6
View File
@@ -1,4 +1,5 @@
extends GdUnitTestSuite
## PlayerObject: points, and the first point, match point and winner signals.
var _winning_score: int
var _player: PlayerObject
@@ -20,7 +21,7 @@ func test_first_point_triggers_first_point_signal() -> void:
_player.add_point()
assert_int(_player.player_score).is_equal(1)
await assert_signal(_player).is_emitted("first_point_triggerd")
await assert_signal(_player).is_emitted("first_point_triggered")
await assert_signal(_player).is_emitted("player_point_given")
@@ -30,7 +31,7 @@ func test_one_point_from_winning_triggers_match_point() -> void:
_player.add_point()
await assert_signal(_player).is_emitted("match_point_triggerd")
await assert_signal(_player).is_emitted("match_point_triggered")
func test_reaching_winning_score_triggers_winner() -> void:
@@ -41,7 +42,7 @@ func test_reaching_winning_score_triggers_winner() -> void:
_player.add_point()
assert_int(_player.player_score).is_equal(3)
await assert_signal(_player).is_emitted("winner_triggerd")
await assert_signal(_player).is_emitted("winner_triggered")
func test_score_does_not_go_past_winning_score() -> void:
@@ -91,7 +92,7 @@ func test_dropping_back_to_zero_allows_first_point_again() -> void:
_player.add_point()
await assert_signal(_player).is_emitted("first_point_triggerd")
await assert_signal(_player).is_emitted("first_point_triggered")
func test_reset_points() -> void:
@@ -125,7 +126,7 @@ func test_winning_score_of_one_is_won_with_first_point() -> void:
_player.add_point()
await assert_signal(_player).is_emitted("winner_triggerd")
await assert_signal(_player).is_emitted("winner_triggered")
func test_first_point_is_match_point_when_winning_score_is_two() -> void:
@@ -134,5 +135,5 @@ func test_first_point_is_match_point_when_winning_score_is_two() -> void:
_player.add_point()
await assert_signal(_player).is_emitted("match_point_triggerd")
await assert_signal(_player).is_emitted("match_point_triggered")
assert_bool(_player.is_first_point).is_false()
+1
View File
@@ -1,4 +1,5 @@
extends GdUnitTestSuite
## Playlist: moving through the songs, answering them and keeping points.
var _server: FakeHttpTransport
var _add_to_stats: bool
+3 -1
View File
@@ -1,4 +1,5 @@
extends GdUnitTestSuite
## How the search popup finds and orders matching soundtracks.
const SearchWindowScript: GDScript = preload("res://search_popup.gd")
@@ -36,7 +37,8 @@ func test_ignores_spaces() -> void:
func test_and_matches_ampersand() -> void:
assert_array(_search.find_matches("mario and luigi")).contains(["Mario & Luigi: Superstar Saga"])
assert_array(_search.find_matches("mario and luigi")) \
.contains(["Mario & Luigi: Superstar Saga"])
func test_accented_letters_match_plain_letters() -> void:
+1
View File
@@ -1,4 +1,5 @@
extends GdUnitTestSuite
## Settings: the version number.
func test_version_comes_from_project_settings() -> void:
+1
View File
@@ -1,4 +1,5 @@
extends GdUnitTestSuite
## SongObject: what it shows before and after the answer, and its points.
var _is_debug: bool
var _song: SongObject