extends SceneTree var failures := 0 var wins := 0 var losses := 0 func check(value: bool,message: String) -> void: if not value: push_error(message) failures += 1 func _initialize() -> void: call_deferred("run") func run() -> void: var definition = load("res://data/games/missile_command.tres") check(definition != null and definition.game_id == &"missile_command","game definition loads") var game = load("res://games/missile_command/MissileCommand.tscn").instantiate() root.add_child(game) game.set_physics_process(false) game.game_won.connect(func(): wins += 1) game.game_lost.connect(func(): losses += 1) game._physics_process(9.1) check(game.phase == "leaderboard","title destruction leads to leaderboard") game._physics_process(7.1) check(game.phase == "title","attract loops") check(game.start_game() and not game.start_game(),"single start") check(game.phase == "ready" and not game.fire(1),"DEFEND CITIES before combat") game._physics_process(2.3) game.set_aim(Vector2(100,100)) check(game.fire(0) and game.fire(1) and game.fire(2),"three independent batteries") check(game.ammo == [9,9,9] and not game.fire(0),"ammo and cooldown") check(game.interceptors[1].speed > game.interceptors[0].speed,"center battery faster") game.cooldown.fill(0) var had_action := InputMap.has_action("arcade_action_1") if not had_action: InputMap.add_action("arcade_action_1") var space := InputEventKey.new() space.physical_keycode = KEY_SPACE InputMap.action_add_event("arcade_action_1",space) space.pressed = true var count: int = game.interceptors.size() game._unhandled_input(space) check(game.interceptors.size() == count+1,"mapped Space fires only one battery") InputMap.action_erase_event("arcade_action_1",space) if not had_action: InputMap.erase_action("arcade_action_1") game.display.destination = Rect2(50,20,512,462) check(game.display.to_logical(Vector2(306,251)) == Vector2(128,115.5),"letterboxed mouse coordinates") game.incoming.clear() game.remaining = 0 game.interceptors.clear() game.explosion(Vector2(100,100)) game.spawn_missile(Vector2(100,100)) game.incoming[0].target = Vector2(100,211) game._step(.1) check(game.incoming.is_empty() and game.score == 25,"explosion destroys incoming and scores") game.blasts.clear() game._impact(Vector2(game.CITY_X[0],211)) check(not game.cities[0],"city impact") game._impact(Vector2(game.BASE_X[1],204)) check(not game.bases[1] and game.ammo[1] == 0 and not game.fire(1),"battery impact disables firing") game.add_score(game.bonus_city_interval) check(game.bonus_bank == 1,"bonus city banked") game._restore_cities() check(game.cities[0] and game.bonus_bank == 0,"lost city restored") game.blasts.clear() game._step(.1) check(game.phase == "bonus" and game.wave_bonus > 0,"wave completion awards bonus once") game._physics_process(3.1) check(game.wave == 2 and game.ammo == [10,10,10] and game.bases == [true,true,true],"new wave restores batteries") game.wave = game.waves_to_win game.phase = "bonus" game.phase_time = .1 game._physics_process(.2) game._physics_process(.2) check(game.phase == "won" and wins == 1 and not game.is_running,"single room win") game.reset_game() game.start_game() game.phase = "play" game.cities.fill(false) game._step(.01) check(game.phase == "lost" and losses == 1 and not game.is_running,"all cities lost") game._physics_process(5.1) check(game.phase == "title","loss returns attract") game.set_aim(Vector2(-10,999)) check(game.aim == Vector2(1,199),"aim clamp") game.add_trackball_motion(Vector2(10,-10)) check(game.aim == Vector2(11,189),"relative trackball API") game.reset_game() game.start_game() game.phase = "play" game.wave = 5 game.spawn_time = 999 game.remaining = 1 game.spawn_missile(Vector2(128,91),"splitter") game._step(.01) check(game.incoming.size() == 3,"missile splits") for frame in range(3600): if game.phase == "play": game.set_aim(Vector2(20+(frame%210),100)) if frame%9 == 0: game.fire((frame/9)%3) game._physics_process(1.0/60) print("Missile Command tests: ",failures," failures") game.get_node("Audio").stop() await create_timer(.2).timeout game.queue_free() await process_frame quit(failures)