extends SceneTree var failures := 0 var started := 0 var won := 0 var lost := 0 func check(value: bool, message: String) -> void: if not value: failures += 1 push_error(message) func _initialize() -> void: call_deferred("run") func clean(g) -> void: g.entities.clear() g.shots.clear() g.enemy_shots.clear() g.effects.clear() g.phase="play" g.fire_delay=0 g.invulnerable=10 g.player=Vector2(146,124) func run() -> void: var g = load("res://games/robotron/Robotron.tscn").instantiate() root.add_child(g) g.set_physics_process(false) g.sound_enabled=false g.game_started.connect(func(): started+=1) g.game_won.connect(func(): won+=1) g.game_lost.connect(func(): lost+=1) check(g.start_game() and not g.start_game(),"Start guard") g._physics_process(2.1) check(g.phase=="play" and started==1,"Ready event") clean(g) g.spawn("grunt",Vector2(260,210)) g.step_world(.05,Vector2.LEFT,Vector2.UP) check(g.player.x<146 and g.shots.size()==1 and g.shots[0].velocity.y<0,"Independent movement/fire") check(is_equal_approx(g.eight_way(Vector2(1,1)).length(),1),"Normalized diagonal") Input.action_press("robotron_move_left") Input.action_press("robotron_move_up") Input.action_press("robotron_fire_right") check(g.control_vector("move_").x<0 and g.control_vector("move_").y<0 and g.control_vector("fire_").x>0,"Independent mapped sticks") Input.action_release("robotron_move_left") Input.action_release("robotron_move_up") Input.action_release("robotron_fire_right") check(g.control_vector("fire_")==Vector2.ZERO,"Release stops fire") clean(g) var human = g.spawn("human",Vector2(146,124)) for i in range(6): human.alive=true g.save_human(human) check(g.score==20000 and g.rescue_chain==5,"Escalating rescue chain") var old_lives: int=g.lives g.add_score(55000) check(g.lives==old_lives+3,"Multiple bonus thresholds") clean(g) var hulk = g.spawn("hulk",Vector2(160,124)) g.fire(Vector2.RIGHT) g.update_shots(.1) check(hulk.alive and hulk.position.x>160 and g.shots.is_empty(),"Hulk survives and is pushed") clean(g) human=g.spawn("human",Vector2(160,124)) g.fire(Vector2.RIGHT) g.update_shots(.1) check(human.alive,"Player bullets spare humans") clean(g) var obstacle=g.spawn("electrode",Vector2(160,124)) g.fire(Vector2.RIGHT) g.update_shots(.1) check(not obstacle.alive,"Electrode shot destruction") clean(g) g.spawn("hulk",Vector2(200,100)) var doomed=g.spawn("human",Vector2(201,100)) g.spawn("grunt",Vector2(270,210)) g.step_world(.01,Vector2.ZERO,Vector2.ZERO) check(not doomed.alive,"Hulk kills human") clean(g) var brain=g.spawn("brain",Vector2(170,124)) var victim=g.spawn("human",Vector2(171,124)) g.step_world(.01,Vector2.ZERO,Vector2.ZERO) check(not victim.alive and g.entities.any(func(e): return e.kind=="converting"),"Brain captures human") g.step_world(.8,Vector2.ZERO,Vector2.ZERO) check(g.entities.any(func(e): return e.kind=="prog"),"Human transforms into Prog") g.damage(brain) g.damage(brain) check(brain.alive,"Brain takes three hits") g.damage(brain) check(not brain.alive,"Brain third hit") clean(g) var spawner=g.spawn("spheroid",Vector2(230,100)) spawner.timer=0 g.step_world(.01,Vector2.ZERO,Vector2.ZERO) check(g.entities.any(func(e): return e.kind=="enforcer"),"Spheroid creates enforcers") clean(g) spawner=g.spawn("quark",Vector2(230,100)) spawner.timer=0 g.step_world(.01,Vector2.ZERO,Vector2.ZERO) check(g.entities.any(func(e): return e.kind=="tank"),"Quark creates tanks") g.projectile("shell",Vector2(282,100),Vector2(300,100)) g.update_enemy_shots(.1) check(g.enemy_shots[0].velocity.x<0 and g.enemy_shots[0].bounces==1,"Tank shell bounce") g.wave=5 g.setup_wave() check(g.entities.any(func(e): return e.kind=="brain"),"Brain wave") g.wave=7 g.setup_wave() check(g.entities.any(func(e): return e.kind=="quark"),"Tank wave") clean(g) g.wave=1 g.spawn("hulk",Vector2(250,100)) g.spawn("human",Vector2(50,50)) g.spawn("electrode",Vector2(20,200)) g.step_world(.01,Vector2.ZERO,Vector2.ZERO) check(g.phase=="transition","Only killable enemies gate wave") g._physics_process(2) check(won==1 and not g.is_running,"Room win") g.start_game() g.waves_to_win=0 g.phase="transition" g.phase_time=0 g._physics_process(.01) check(g.wave==2 and g.phase=="ready" and g.is_running,"Endless wave progression") g.reset_game() g.start_game() g.phase="play" g.lives=1 g.die() g._physics_process(1.3) check(lost==1 and not g.is_running,"Room loss") g.reset_game() g.high_score=999999 g.last_score=420 var events := Vector3i(started,won,lost) g.begin_demo() for i in range(1600): g._physics_process(1.0/60) check(not g.demo and not g.is_running and g.score==420 and g.high_score==999999,"Demo score isolation") check(events==Vector3i(started,won,lost),"Demo event isolation") g.begin_demo() check(g.start_game() and not g.demo and g.score==0,"Start interrupts demo") check(load("res://data/project_database.tres").get_game(&"robotron")!=null,"Database") print("Robotron checks: ",failures," failures") g.free() quit(failures)