extends SceneTree # Headless test: run with # godot --headless -s res://tests/test_music_theme.gd # Forgejo #148: the main theme plays all the time. # # "All the time" is the requirement, so what is checked is CONTINUITY rather # than "a sound was started once": the same player has to survive the main # menu becoming the game, the game becoming a planet surface, and the # surface becoming the game again - and there must never be two of it, # because a second copy is the theme playing over itself. # # Covers: # A. loading a scene starts the theme # B. it is parented to the tree root, not to the scene - the thing that # makes it survive change_scene_to_file at all # C. the stream loops, so "all the time" outlasts one play-through of it # D. it keeps playing while a dialog has the game stopped (#128) # E. swapping scenes neither restarts it nor stacks a second one up var game_state: Node var scene: Node var player: AudioStreamPlayer var stage: int = 0 var elapsed: float = 0.0 func _initialize() -> void: # GameState is an autoload: a bare GameState. does not # compile in a SceneTree script, so the node is fetched by name instead. game_state = root.get_node("GameState") game_state.reset_new_game() game_state.intro_active = false game_state.reset_quests() func _fail(message: String) -> bool: print("TEST_MUSIC_THEME: FAIL (%s)" % message) quit(1) return true func _players() -> Array: var found: Array = [] for node in root.get_children(): if node is AudioStreamPlayer: found.append(node) return found func _load(path: String) -> void: scene = load(path).instantiate() root.add_child(scene) current_scene = scene func _process(delta: float) -> bool: elapsed += delta match stage: 0: if not _players().is_empty(): return _fail("something was already playing before any scene loaded") _load("res://world/Main.tscn") elapsed = 0.0 stage = 1 return false 1: # The player is added deferred, so it arrives a frame later. if elapsed < 0.4: return false # --- A and B. it exists, at the root --------------------- var players: Array = _players() if players.size() != 1: return _fail("%d music players at the root, expected 1" % players.size()) player = players[0] if player.get_parent() != root: return _fail("the music player hangs off %s - it would die with the scene" \ % player.get_parent()) if not player.playing: return _fail("the theme is not playing") if player.stream == null: return _fail("the music player has no stream on it") print("theme playing from %s, parented to the tree root" % player.stream.resource_path) # --- C. and it comes round again ------------------------- if not ("loop" in player.stream) or not player.stream.loop: return _fail("the theme does not loop - it would fall silent after one play") if player.stream.get_length() < 10.0: return _fail("the theme is %.1fs long - that is not a main theme" \ % player.stream.get_length()) print("%.0fs of theme, looping" % player.stream.get_length()) # --- D. and a dialog does not stop it -------------------- var narration: Control = scene.get_node("UI/NarrationBanner") narration.say("Stopping everything else.", "TEST") if not paused: return _fail("the dialog did not stop the game, so this proves nothing") if not player.can_process(): return _fail("the music stops whenever a dialog is up") print("a dialog stops the game and the music keeps playing") while narration.dismiss(): pass elapsed = 0.0 stage = 2 return false 2: if elapsed < 0.3: return false # --- E. through a scene change --------------------------- game_state.planet_name = "Music Test" game_state.planet_id = "music:test" game_state.planet_definition_id = "rocky" scene.free() _load("res://surface/PlanetSurface.tscn") elapsed = 0.0 stage = 3 return false 3: if elapsed < 0.4: return false var players2: Array = _players() if players2.size() != 1: return _fail("%d music players after a scene change - the theme is playing over itself" \ % players2.size()) if players2[0] != player: return _fail("the scene change replaced the music player, restarting the theme") if not player.playing: return _fail("the theme stopped when the scene changed") print("scene changed to a planet surface: same player, still playing") scene.free() _load("res://world/Main.tscn") elapsed = 0.0 stage = 4 return false 4: if elapsed < 0.4: return false if _players().size() != 1 or _players()[0] != player: return _fail("coming back from a surface left %d players" % _players().size()) if not player.playing: return _fail("the theme stopped on the way back from a surface") print("and back again: still one player, still the same one") print("TEST_MUSIC_THEME: PASS") quit(0) return true return false