extends SceneTree var failed := 0 var total := 0 func _initialize() -> void: call_deferred("run") func check(ok: bool, title: String) -> void: total += 1 if not ok: failed += 1 print("PASS " if ok else "FAIL ", title) func run() -> void: var game: Node3D = load("res://scenes/main.tscn").instantiate() root.add_child(game) game.port = 27986 game.host({"server_name":"Foundation", "mode":"FFA", "max_players":2, "bots":0, "score_limit":100, "time_limit":600}) game.set_physics_process(false) var p: Fighter = game.players[1] p.set_physics_process(false) p.set_process(false) p.reset_at(Vector3(0, 0.1, 28)) check(p.shape.shape is CapsuleShape3D and p.find_children("*", "CollisionShape3D", true, false).size() == 1, "fighter exclusively uses one capsule") var scans: Node = game.arena.get_node("QuarryRouteRocks") var bodies: Array[Node] = scans.find_children("*", "StaticBody3D", true, false) check(bodies.size() == 2, "two scan mesh colliders restored on headless host") var boxes := true for body in bodies: boxes = boxes and body.get_child(0).shape is ConcavePolygonShape3D check(boxes, "route scans use original triangle collision") var motion := InputEventMouseMotion.new() motion.screen_relative = Vector2(20, -10) motion.relative = Vector2(999,999) FpsCamera.mouse(p, motion, 0.001) check(is_equal_approx(p.yaw, -0.02) and is_equal_approx(p.pitch, 0.01), "raw screen-relative mouse input applied without smoothing") p.view_controller.begin_physics(p) var body_position := p.global_position for rate in [60, 120, 144, 240]: p.view_controller.render(p, 1.0 / rate) check(p.global_position == body_position and is_equal_approx(p.camera.global_rotation.y, p.yaw), "camera render preserves physics and direct yaw at %s Hz" % rate) game.headless = false game.hud.hit_time = 0 game.shot_event(p.eye(), p.peer_id, p.weapon, false, false) check(p.gun.muzzle.visible and p.gun.recoil_velocity.length() > 0 and game.hud.shot_time > 0, "single shot event immediately starts flash, recoil and crosshair pulse") check(game.hud.hit_time == 0, "miss does not fake a hitmarker") var recoil_before: Vector2 = p.gun.recoil_velocity p.magazines[p.weapon] -= 1 p.shot_serial += 1 p.gun.animate(p, 0.0) check(p.gun.recoil_velocity.is_equal_approx(recoil_before), "snapshot ammo change does not duplicate recoil") game.shot_event(p.eye(), p.peer_id, p.weapon, true, true) check(game.hud.hit_time > 0 and game.hud.head_hit, "confirmed headshot adds hit feedback in same event") p.weapon = 0 p.reload_left = 0 p.melee_left = 0 p.mantle_left = 0 p.rope_active = false p.infinite_left = 0 p.magazines[0] = 0 p.reserves[0] = 30 p.input_data = {} game.combat.actions(p) check(p.reload_left > 0, "empty magazine reloads without firing or pressing reload") p.reload_left = 0 p.reserves[0] = 0 game.combat.actions(p) check(p.reload_left == 0, "no reload without reserve ammunition") p.reserves[0] = 30 p.infinite_left = 10 game.combat.actions(p) check(p.reload_left == 0, "infinite ammunition prevents automatic reload") game.leave() game.queue_free() await process_frame print("AUTO RELOAD RESULT ", total - failed, "/", total) quit(1 if failed else 0)