Files
ElHombreAlex--FTL-Faster-Th…/tools/test_input.gd
T

432 lines
28 KiB
GDScript

extends SceneTree
var failures := 0
func check(condition: bool, message: String) -> void:
if not condition:
failures += 1
push_error(message)
func _initialize() -> void:
call_deferred("run")
func run() -> void:
var scene := load("res://tools/input_harness.gd").new() as Node3D
root.add_child(scene)
await process_frame
scene.set_process(false)
var tracker := XRControllerTracker.new()
tracker.type = XRServer.TRACKER_CONTROLLER
tracker.name = "right_hand"
tracker.set_pose("aim", Transform3D(Basis.IDENTITY, Vector3(0.1,1.2,1)), Vector3.ZERO, Vector3.ZERO, XRPose.XR_TRACKING_CONFIDENCE_HIGH)
XRServer.add_tracker(tracker)
scene._resolve_controller_pose(scene.right_hand)
check(scene.right_hand.pose == "aim" and scene.right_hand.get_is_active(), "Right hand must use the active aim tracker pose")
scene._update_pointer()
check(scene.right_laser.visible and scene.right_laser.mesh is CylinderMesh, "Tracked hand must draw a stereo-visible ray")
check(scene.right_laser.material_override.no_depth_test, "Ray must remain visible over the native menu")
check(scene.right_laser.material_override.transparency == BaseMaterial3D.TRANSPARENCY_ALPHA and scene.right_laser.material_override.render_priority == 127,"Pointer must render after transparent HUD surfaces")
check(is_equal_approx(scene.right_laser.mesh.height,1.0),"Pointer length must use node scaling, without regenerating its mesh every frame")
tracker.set_input("trigger",0.8)
check(scene._pressed(scene.right_hand,"trigger"), "Analog trigger must work without trigger_click")
tracker.invalidate_pose("aim")
tracker.set_pose("default",Transform3D.IDENTITY,Vector3.ZERO,Vector3.ZERO,XRPose.XR_TRACKING_CONFIDENCE_HIGH)
scene._resolve_controller_pose(scene.right_hand)
check(scene.right_hand.pose == "default", "Missing aim tracking must fall back to default")
scene._update_input_diagnostics(1.1)
scene.hud_state = {"ready":true,"ui_mode":"game","navigation":{"jump":true,"ship":true,"store":false}}
scene.xr_active = true
scene._refresh_navigation()
var names := []
for button in scene.nav_buttons:
if button.visible: names.append(button.get_meta("action"))
else: check(button.collision_layer == 0,"Hidden navigation buttons must not intercept rays")
check("jump" in names and "store" not in names,"Navigation must reflect live availability")
scene.hud_state.map_open = true
scene._refresh_navigation()
check(scene.map_surface.visible and scene.map_surface.get_parent() == scene,"Actual jump map must float in the world above the ship")
check(scene.map_surface.global_position.y >= scene.player_ship.global_position.y + 0.65,"Jump map must have comfortable clearance above the ship")
var pilot_id := -1
for id in scene.player_ship.room_nodes:
if scene.player_ship.room_nodes[id].get_meta("system_role", "") == "pilot": pilot_id = int(id)
check(pilot_id >= 0,"Owned Kestrel layout must provide its actual piloting room")
if pilot_id >= 0:
var pilot_point: Vector3 = scene.player_ship.to_global(scene.player_ship.room_points[pilot_id])
var bow: Vector3 = scene.player_ship.global_basis.x.normalized()
var projected: Vector3 = scene.map_surface.global_position - pilot_point
check(projected.dot(bow) > 0.20 and projected.y > 0.60,"Jump map must project above and ahead of the pilot instead of the ship center")
var original_table: Transform3D = scene.tabletop_root.transform
scene.tabletop_root.rotation.y = PI * 0.5
scene.tabletop_root.scale *= 1.8
scene._position_world_panels()
pilot_point = scene.player_ship.to_global(scene.player_ship.room_points[pilot_id])
bow = scene.player_ship.global_basis.x.normalized()
projected = scene.map_surface.global_position - pilot_point
check(projected.dot(bow) > 0.20 and projected.y > 0.60 and projected.length() < 0.70,"Pilot projection must follow ship rotation while keeping world-metre clearance at different table scales")
var saved_vertical: int = int(scene.player_ship.layout_data.get("vertical",0))
scene.player_ship.layout_data.vertical = 1
scene._update_ship_positions()
scene._position_world_panels()
pilot_point = scene.player_ship.to_global(scene.player_ship.room_points[pilot_id])
projected = scene.map_surface.global_position - pilot_point
check(projected.dot(-scene.player_ship.global_basis.z.normalized()) > 0.20,"Vertical ship layouts must project ahead of their actual bow")
scene.player_ship.layout_data.vertical = saved_vertical
scene._update_ship_positions()
scene.tabletop_root.transform = original_table
# Read the actual room roles, not the extracted blueprint's first pilot.
var alternate: int = int(scene.player_ship.room_nodes.keys().back())
if alternate != pilot_id:
scene.player_ship.room_nodes[pilot_id].set_meta("system_role", "")
var saved_role: String = scene.player_ship.room_nodes[alternate].get_meta("system_role", "")
scene.player_ship.room_nodes[alternate].set_meta("system_role", "pilot")
scene._position_world_panels()
pilot_point = scene.player_ship.to_global(scene.player_ship.room_points[alternate])
check(Vector2(scene.map_surface.global_position.x-pilot_point.x,scene.map_surface.global_position.z-pilot_point.z).length() < 0.25,"A different piloting room must move the projected map anchor with it")
scene.player_ship.room_nodes[alternate].set_meta("system_role", saved_role)
scene.player_ship.room_nodes[pilot_id].set_meta("system_role", "pilot")
scene._position_world_panels()
check(is_equal_approx(scene.enemy_hull_bar.global_position.y-scene.enemy_ship.global_position.y,0.52),"Enemy hull bar must sit slightly lower while retaining clearance over the ship")
scene.hud_state.map_open = false
scene.hud_state.tactical = true
scene._refresh_navigation()
check(scene.nav_buttons[0].get_meta("action") == "tactical","Tactical view must close with its own toggle, not Escape")
scene.hud_state.map_open = true
scene.hud_state.tactical = false
scene._refresh_navigation()
var image := Image.create(1280,720,false,Image.FORMAT_RGBA8)
image.fill(Color.WHITE)
scene.map_surface.canvas.frame_image = image
scene.nav_panel.visible = true
var pixel: Variant = scene.map_surface.ray_pixel(scene.map_surface.to_global(Vector3(0,0,1)), -scene.map_surface.global_basis.z)
check(pixel == Vector2i(715,375),"Cropped map pointer must map to the native game's original coordinates")
scene._select_from_ray(scene.map_surface.to_global(Vector3(0,0,1)), -scene.map_surface.global_basis.z)
scene._release_pointer(scene.map_surface.to_global(Vector3(0,0,1)), -scene.map_surface.global_basis.z)
check(scene.commands.size() == 2 and scene.commands[0].data.phase == "down" and scene.commands[1].data.phase == "up","Map selection must dispatch a full native mouse click")
scene.nav_panel.visible = false
check(scene.map_surface.ray_pixel(scene.map_surface.to_global(Vector3(0,0,1)), -scene.map_surface.global_basis.z) != null,"World jump map must stay usable when hand tracking is hidden")
var map: OpenXRActionMap = load("res://openxr_action_map.tres")
check(map.find_interaction_profile("/interaction_profiles/valve/frame_controller_valve") != null,"Explicit Frame profile must ship with the client")
scene.hud_state = {"ready":true,"ui_mode":"game"}
scene._sync_hud_layout()
scene._position_hud(0.0, true)
check(is_equal_approx(scene.nav_panel.scale.x, 0.6) and scene.hud_surface.get_parent()==scene and scene.hud_surface.source_rect==scene.GAMEPLAY_HUD_RECT,"Gameplay HUD must retain native upper/crew pixels, exclude the bottom strip and use independent world placement")
check(scene.hud_surface.render_order == 100 and scene.panel_theme.get_child(1).material_override.render_priority > scene.pause_label.render_priority and scene.tracking_label.render_priority < 120,"Hand screen must render over all HUD layers, including pause and modifier labels")
var hud_mode_state: Dictionary = scene.hud_state.duplicate(true)
scene.hud_state = {"ready":true,"ui_mode":"menu","panel_open":true}
scene._sync_hud_layout()
check(scene.gameplay_hud and scene.hud_surface.source_rect == scene.GAMEPLAY_HUD_RECT,"An in-run world window must not promote the headset HUD into a second full menu")
scene.hud_state = {"ready":false,"ui_mode":"menu","panel_open":true}
scene._sync_hud_layout()
check(not scene.gameplay_hud and scene.hud_surface.source_rect == Rect2(0,0,1280,720),"Initial and hangar menus must keep their full headset display")
scene.hud_state = hud_mode_state
scene._sync_hud_layout()
check(scene.help_label.get_script().resource_path.ends_with("controller_help.gd"),"Help must use a controller infographic instead of plain text")
check(scene.hover_marker.mesh.radius <= 0.003 and scene.right_laser.mesh.top_radius <= 0.001,"Pointer endpoint must support precise native UI selection")
scene.wheel.global_position = scene.camera.get_camera_transform().origin + Vector3(0.3,-0.5,-0.4)
scene._face_front(scene.wheel)
var to_head: Vector3 = (scene.camera.get_camera_transform().origin-scene.wheel.global_position).normalized()
check(scene.wheel.global_basis.z.dot(to_head) > 0.999 and scene.wheel.global_basis.z.y > 0,"Wheel face must tilt up toward the real viewer rather than the ground")
scene.hud_state = {"ready":true,"ui_mode":"game","navigation":{"jump":true},"player":{"weapons":[{"slot":0,"name":"LASER_BURST_1"}],"systems":{"shields":true}},"drone_slots":1}
scene.nav_page = "navigation"
scene._refresh_navigation()
check(scene._navigation_entries().has(["SYSTEM POWER", "page:power"]),"System Power must have a direct Navigation entry")
scene._cycle_hand_page(1)
check(scene.nav_page == "tactical" and scene.commands.back().data.screen == "tactical","Dpad right must cycle into tactical")
scene.hud_state.tactical = true
scene._cycle_hand_page(1)
check(scene.pending_page == "shortcuts" and scene.commands.back().data.screen == "tactical","Changing screen must first close the native tactical view")
scene.hud_state.tactical = false
scene._refresh_wheel()
check(scene.wheel.entries[0].enabled and not scene.wheel.entries[1].enabled and scene.wheel.entries[4].enabled,"Wheel must show only equipped weapon/drone slots as available")
scene.wheel.choose(Vector2(0,1))
check(scene.wheel.selected == 0,"Joystick up must select slot 1")
scene.wheel.choose(Vector2.ZERO)
check(scene.wheel.selected == -1,"Wheel center must cancel")
scene.hud_state.event_open = true
scene.hud_state.dialog = {"id":"test","choices":[{"index":0,"enabled":true}]}
scene.wheel_dialog_id = "test"
scene._refresh_wheel()
scene.wheel.choose(Vector2(0,1))
scene._commit_wheel()
var command_count: int = scene.commands.size()
scene._commit_wheel()
check(scene.commands.back().action == "event_choice" and scene.commands.size() == command_count,"Event wheel must commit once")
var saved_state: Dictionary = scene.hud_state.duplicate(true)
scene.hud_state = {"ready":true,"ui_mode":"game"}
scene.pending_page = ""
scene.nav_page = "navigation"
scene._toggle_power_page()
check(scene.nav_page=="power","Dpad Up action must open System Power")
scene._toggle_power_page()
check(scene.nav_page=="navigation","Dpad Up action must close System Power")
scene.hud_state.ui_mode = "menu"
scene._toggle_power_page()
check(scene.nav_page=="navigation","Dpad Up must not open unusable Power controls in a main menu")
scene.hud_state = {"ready":true,"ui_mode":"screen","map_open":true}
scene.wheel_committed = false
scene.wheel.visible = true
scene.wheel.set_entries([{"key":49,"enabled":true}],"WEAPONS")
scene.wheel.selected = 0
command_count = scene.commands.size()
scene._commit_wheel()
check(scene.commands.size()==command_count and not scene.wheel.visible,"Opening a native map must cancel equipment wheel commits")
scene.hud_state = saved_state
scene.event_surface.visible = true
scene.event_surface.canvas.frame_image = image
scene.event_surface.source_rect = Rect2(313,138,650,390)
var event_pixel: Variant = scene.event_surface.ray_pixel(scene.event_surface.to_global(Vector3(0,0,1)), -scene.event_surface.global_basis.z)
check(event_pixel == Vector2i(638,333),"Cropped event ray must retain the original native coordinates")
# A visible HUD pixel takes precedence over a physically nearer world panel.
scene.hud_surface.canvas.frame_image = image
scene.hud_surface.global_transform = Transform3D.IDENTITY
scene.world_surface.global_transform = Transform3D(Basis.IDENTITY,Vector3(0,0,0.4))
scene.world_surface.visible = true
scene.world_surface.canvas.frame_image = image
var top_hit: Dictionary = scene._surface_hit(Vector3(0,0,1),Vector3.FORWARD)
check(top_hit.surface == scene.hud_surface,"Rendered HUD priority must match click priority")
# A hand map wins against an overlapping opaque HUD pixel, regardless of distance.
scene.nav_panel.global_transform = Transform3D(Basis.IDENTITY,Vector3(0,0,0.4))
scene.nav_panel.visible = true
scene.hud_state.map_open = false
scene.hud_state.tactical = true
scene._refresh_navigation()
scene.map_surface.visible = true
scene.map_surface.canvas.frame_image = image
var hand_top: Dictionary = scene._surface_hit(Vector3(0,0,1),Vector3.FORWARD)
check(hand_top.get("surface") == scene.map_surface,"Controller screen click priority must match its foreground draw priority")
scene.map_surface.visible = false
scene._select_from_ray(Vector3(0,0,1),Vector3.FORWARD)
check(scene.held_surface == null,"Blank hand panel pixels must block clicks into the HUD behind them")
scene.nav_panel.visible = false
scene.nav_page = "power"
scene.hud_state = {"ready":true,"ui_mode":"screen","panel_open":true,"blocking_ui":true}
scene.last_hover_time = -1.0
command_count = scene.commands.size()
scene._hover_ui(Vector3(0,0,1),Vector3.FORWARD)
check(scene.commands.size()==command_count+1 and scene.commands.back().action=="ui_move","Native window hover must remain available while System Power is selected")
scene.nav_page = "navigation"
var window_image := Image.create(1280,720,false,Image.FORMAT_RGBA8)
var body_image := Image.create(650,520,false,Image.FORMAT_RGBA8)
body_image.fill(Color.WHITE)
window_image.blit_rect(body_image,Rect2i(0,0,650,520),Vector2i(300,90))
scene.world_surface.canvas.frame_image = window_image
scene.world_panel_crop_pending = true
scene.world_panel_open_age = 0.3
scene.world_panel_opened_at = 100.0
scene.world_surface.canvas.capture_time_unix = 99.0
var old_crop: Rect2 = scene.world_surface.source_rect
scene._position_world_panels()
check(scene.world_panel_crop_pending and scene.world_surface.source_rect == old_crop,"A previous panel's cached frame must not lock a new window crop")
scene.world_surface.canvas.capture_time_unix = 100.1
scene._position_world_panels()
var fixed_crop: Rect2 = scene.world_surface.source_rect
check(fixed_crop == Rect2(300,90,650,520),"Native world window crop must preserve its original pixel coordinates")
check(scene.world_surface.global_position.y > scene.player_ship.global_position.y,"Ship and store windows must hang above the VR player ship")
scene.world_surface.canvas.frame_image = image
scene._position_world_panels()
check(scene.world_surface.source_rect == fixed_crop,"Hover image changes must not resize a floating window or change pointer mapping")
scene.world_surface.canvas.capture_time_unix = 0.0
scene.world_panel_open_frame_count = scene.world_surface.canvas.received_frames
check(not scene._world_panel_has_fresh_frame(),"Legacy PNG transport must wait for a new image on panel opening")
scene.world_surface.canvas.received_frames += 1
check(scene._world_panel_has_fresh_frame(),"A newly decoded legacy PNG must remain usable without a raw timestamp")
scene.world_panel_kind = "sell"
scene.world_panel_crop_pending = true
scene._position_world_panels()
check(scene.world_surface.source_rect == Rect2(0,0,1280,720),"Shop crop must retain detached sell drop boxes and future hover panels")
check(scene.world_surface.surface_size.x <= 1.03 and scene.event_surface.surface_size.x < 1.0,"Floating ship/store and event panels must be smaller")
# The authoritative pause cue does not inherit a cached native image or forced menu freeze.
scene.hud_state = {"ready":true,"paused":true}
scene.paused = true
scene._update_hud()
scene._refresh_navigation()
check(scene.pause_label.visible and "PAUSED" in scene.nav_title.text,"Paused status must be present on HUD and hand screen from the same state")
scene.hud_state = {"ready":true,"paused":false,"frozen":true}
scene._update_hud()
scene._refresh_navigation()
check(not scene.pause_label.visible and "PAUSED" not in scene.nav_title.text,"A menu freeze must not leave a stale player-pause cue")
# Text buttons send native text operations, with no leaked UI mouse-up/hotkeys.
scene.wheel.visible = true
scene.wheel_committed = false
scene._apply_text_entry({"active":true,"id":"rename-1","kind":"crew","text":"Test","cursor":4})
check(not scene.wheel.visible and scene.wheel_committed,"Native renaming must cancel an already-open action wheel")
var count_before_modal_wheel: int = scene.commands.size()
scene.wheel_committed = false
scene._commit_wheel()
check(scene.commands.size() == count_before_modal_wheel,"Wheel release must not send a gameplay key into native text entry")
scene.rename_keyboard.global_transform = Transform3D.IDENTITY
var key: Dictionary = scene.rename_keyboard.keys[10]
var key_pixel: Vector2 = key.rect.get_center()
var key_world: Vector3 = scene.rename_keyboard.to_global(Vector3((key_pixel.x/1000.0-0.5)*0.86,(0.5-key_pixel.y/454.0)*0.39,0))
scene._select_from_ray(key_world+Vector3(0,0,1),Vector3.FORWARD)
check(scene.commands.back().action == "text_input" and scene.commands.back().data.op == "insert" and scene.commands.back().data.text == "Q" and scene.commands.back().data.entry_id == "rename-1","VR keyboard must insert into the exact active native name field")
var count_before_release: int = scene.commands.size()
scene._release_pointer(key_world+Vector3(0,0,1),Vector3.FORWARD)
check(scene.commands.size() == count_before_release,"Keyboard release must not leak a native UI click")
scene._select_from_ray(Vector3(0,20,0),Vector3.DOWN)
check(scene.commands.size() == count_before_release,"Active renaming must block background HUD, menu and scene clicks")
scene._secondary_click(Vector3.ZERO,Vector3.DOWN)
check(scene.commands.back().action == "text_input" and scene.commands.back().data.op == "cancel","B must cancel the native rename field")
scene.rename_keyboard.set_entry({"active":false})
for surface in [scene.hud_surface,scene.world_surface,scene.event_surface,scene.map_surface]: surface.visible = false
scene.hud_state = {"ready":true,"ui_mode":"screen","tactical":true}
scene.demo_mode = false
scene.bridge_connected = true
# Weapon targets and beam endpoints ignore miniatures and door colliders.
scene.weapon_selected = true
scene.battle = true
var enemy_room: int = scene.enemy_ship.room_points.keys()[0]
var enemy_point: Vector3 = scene.enemy_ship.room_target(enemy_room)
var obstruction := Area3D.new()
obstruction.set_meta("kind","door")
obstruction.set_meta("ship","enemy")
var obstruction_shape := CollisionShape3D.new()
var obstruction_box := BoxShape3D.new()
obstruction_box.size = Vector3(0.1,0.1,0.1)
obstruction_shape.shape = obstruction_box
obstruction.add_child(obstruction_shape)
scene.add_child(obstruction)
obstruction.global_position = enemy_point + Vector3(0,0.2,0)
await physics_frame
scene._select_from_ray(enemy_point+Vector3(0,1,0),Vector3.DOWN)
check(scene.commands.back().action == "target_room" and scene.commands.back().data.room_id == enemy_room,"Weapon room selection must bypass enemy crew and door colliders")
scene.beam_drag = true
scene._release_pointer(enemy_point+Vector3(0,1,0),Vector3.DOWN)
check(scene.commands.back().action == "target_room" and scene.commands.back().data.phase == "up","Beam release must use the same room-floor picking")
for kind in ["mind", "hacking", "teleporter"]:
scene.hud_state.targeting = {"active":true,"kind":kind,"ships":["enemy"]}
scene._select_from_ray(enemy_point+Vector3(0,1,0),Vector3.DOWN)
check(scene.commands.back().action == "target_room" and scene.commands.back().data.ship == "enemy" and not scene.beam_drag,"Native %s targeting must work on 3D enemy room floors" % kind)
scene.hud_state.targeting = {"active":false}
obstruction.queue_free()
var room_id: int = scene.player_ship.room_points.keys()[0]
var room_point: Vector3 = scene.player_ship.room_target(room_id)
var crew := Area3D.new()
crew.set_meta("kind","crew")
crew.set_meta("crew_id","grab-test")
crew.set_meta("ship","player")
var shape := CollisionShape3D.new()
var sphere := SphereShape3D.new()
sphere.radius = 0.04
shape.shape = sphere
crew.add_child(shape)
scene.add_child(crew)
crew.global_position = room_point + Vector3(0,0.2,0)
await physics_frame
scene.hud_state.blocking_ui = true
var blocked_count: int = scene.commands.size()
scene._select_from_ray(room_point+Vector3(0,1,0),Vector3.DOWN)
check(scene.commands.size() == blocked_count,"Real native dialogs must block background crew commands even in Tactical")
scene.hud_state.blocking_ui = false
scene.hud_state.targeting = {"active":true,"kind":"mind","ships":["player","enemy"]}
scene._select_from_ray(room_point+Vector3(0,1,0),Vector3.DOWN)
check(scene.commands.back().action == "target_room" and scene.commands.back().data.ship == "player" and scene.grabbed_crew == null,"Friendly mind control must target the room instead of grabbing its crew")
scene.hud_state.targeting = {"active":false}
scene.shift_down = true
scene._select_from_ray(room_point+Vector3(0,1,0),Vector3.DOWN)
check(scene.grabbed_crew == crew and scene.commands.back().action == "select_crew","Holding trigger on crew must begin a native selection and visual grab")
scene.crew_id_selected = "older-native-selected-crew"
scene.shift_down = false
scene._release_pointer(room_point+Vector3(0,1,0),Vector3.DOWN)
check(scene.grabbed_crew == null and scene.commands.back().action == "move_crew" and scene.commands.back().data.room_id == room_id and scene.commands.back().data.crew_id == "grab-test","Dropping crew must retain the grabbed id despite asynchronous native selection updates")
check(scene.commands.back().data.modifiers.shift,"Quick Shift-grabs must retain group selection even when grip is released before native selection acknowledgement")
scene._begin_crew_grab(crew,room_point+Vector3(0,1,0))
scene._secondary_click(Vector3(0,20,0),Vector3.UP)
check(scene.grabbed_crew == null and scene.commands.back().action == "cancel","B must cancel the grab without issuing a move")
crew.queue_free()
scene.nav_page = "power"
scene.hud_state.tactical = false
scene.hud_state.ui_mode = "game"
scene.hud_state.player = {"system_status":[{"id":0,"key":"shields","powerable":true,"allocated":2,"max_power":4},{"id":1,"key":"engines","powerable":true,"allocated":1,"max_power":3}]}
scene._refresh_navigation()
scene.nav_panel.visible = true
scene.nav_panel.global_transform = Transform3D.IDENTITY
var card: Rect2 = scene.panel_theme.power_card_rect(0)
var card_pixel: Vector2 = card.position + Vector2(3,card.size.y*0.5)
var card_point := Vector3((card_pixel.x/1150.0-0.5)*0.92,(0.5-card_pixel.y/900.0)*0.72,0.012)
var oblique_from := card_point + Vector3(-0.65,0,0.3)
var oblique_hit: Dictionary = scene._hand_panel_hit(oblique_from,(card_point-oblique_from).normalized())
check(oblique_hit.get("system_key", "") == "shields","Oblique power-page pointing must hit the visible card edge on the actual display plane")
card = scene.panel_theme.power_card_rect(1)
card_pixel = card.get_center()
card_point = Vector3((card_pixel.x/1150.0-0.5)*0.92,(0.5-card_pixel.y/900.0)*0.72,0.012)
scene.pointer_transform = Transform3D(Basis.IDENTITY,card_point+Vector3(0,0,1))
scene.ray_filter.initialized = true
scene._update_pointer()
check(scene.panel_theme.selected_system().key == "engines","Power pointing must select the current card before a same-frame left trigger press")
scene.panel_theme.step_selection(-1)
scene._update_pointer()
scene._hover_ui(scene.pointer_transform.origin,Vector3.FORWARD)
check(scene.panel_theme.selected_system().key == "shields","A stationary power-page ray must not override X/Y system selection")
scene.ray_filter.reset()
scene.panel_theme.select_system("shields")
scene.nav_panel.visible = false
scene._change_system_power(1)
check(scene.commands.back().action == "system_power" and scene.commands.back().data.system_id == 0 and scene.commands.back().data.direction == 1 and not scene.commands.back().data.modifiers.shift,"Power trigger must use installed system identity and neutral modifiers")
scene._update_power_controls(true,false,true)
check(scene.commands.back().data.system_id == 1 and scene.commands.back().data.direction == -1,"X/Y selection and bumper removal must act on the newly selected system")
var held_count: int = scene.commands.size()
scene._update_power_controls(true,false,true)
check(scene.commands.size() == held_count,"Held bumper and X/Y must dispatch once per press")
scene._update_power_controls(false,false,false)
scene._update_power_controls(false,true,false)
check(scene.panel_theme.selected_system().key == "shields","Previous-system button must wrap back through installed systems")
scene.nav_page = "tactical"
scene.pending_page = ""
scene.hud_state.tactical = true
scene.hud_state.ui_mode = "screen"
scene._toggle_tactical()
check(scene.commands.back().action == "navigate" and scene.commands.back().data.screen == "tactical","Dpad Down must close Tactical without pausing")
scene.hud_state.tactical = false
scene.hud_state.ui_mode = "game"
scene.pending_page = ""
scene._toggle_tactical()
check(scene.commands.back().data.screen == "tactical","Dpad Down must open Tactical from gameplay")
check(scene.pause_label.position.y > 0.0,"Authoritative pause cue must remain above the HUD center, clear of Autofire")
var filter := preload("res://scripts/pose_filter.gd").new()
var steady := Transform3D(Basis.IDENTITY,Vector3(0.2,1.2,-0.3))
filter.update(steady,1.0/90.0)
for i in range(90):
var jitter := steady
jitter.origin.x += 0.001 if i%2==0 else -0.001
jitter.basis = Basis(Vector3.UP,deg_to_rad(0.1 if i%2==0 else -0.1))
filter.update(jitter,1.0/90.0)
check(filter.value.is_equal_approx(steady),"Submillimetre hand/ray jitter must not move a stationary panel")
var moved := steady
moved.origin.x += 0.12
for i in range(9): filter.update(moved,1.0/90.0)
check(filter.value.origin.distance_to(moved.origin)<0.012,"Deliberate hand movement must follow within a tenth of a second")
filter.reset()
check(filter.update(moved,1.0/90.0).is_equal_approx(moved),"Reacquired tracking must snap rather than retain the previous pose")
# Recenter is explicit; combat arrival must preserve the player's ship anchor.
scene.xr_active = true
scene._recenter()
var head_point: Vector3 = scene.camera.get_camera_transform().origin
var offset: Vector3 = scene.tabletop_root.global_position - head_point
var forward: Vector3 = -scene.camera.get_camera_transform().basis.z
forward.y = 0
check(Vector2(offset.x,offset.z).length() > 0.8 and offset.dot(forward.normalized()) > 0.8 and is_equal_approx(offset.y,-0.95),"Recenter must place the table in front of the headset at its established height")
scene.battle = false
scene._update_ship_positions()
var player_position: Vector3 = scene.player_ship.global_position
scene.battle = true
scene._update_ship_positions()
check(scene.player_ship.global_position.is_equal_approx(player_position),"Another ship arriving must not shift the player's placed table")
var head_tracker := XRPositionalTracker.new()
head_tracker.name = "head"
head_tracker.type = XRServer.TRACKER_HEAD
head_tracker.set_pose("default",Transform3D(Basis.IDENTITY,Vector3(1.4,1.65,-0.9)),Vector3.ZERO,Vector3.ZERO,XRPose.XR_TRACKING_CONFIDENCE_HIGH)
XRServer.add_tracker(head_tracker)
scene.initial_table_placed = false
scene._place_initial_table()
check(scene.initial_table_placed,"First valid headset pose must place the tabletop exactly once")
var initial_position: Vector3 = scene.tabletop_root.global_position
head_tracker.set_pose("default",Transform3D(Basis.IDENTITY,Vector3(2.4,1.65,-0.9)),Vector3.ZERO,Vector3.ZERO,XRPose.XR_TRACKING_CONFIDENCE_HIGH)
scene._place_initial_table()
check(scene.tabletop_root.global_position.is_equal_approx(initial_position),"Walking after initial placement must not drag the ship with the headset")
head_tracker.set_pose("default",Transform3D.IDENTITY,Vector3.ZERO,Vector3.ZERO,XRPose.XR_TRACKING_CONFIDENCE_HIGH)
scene._recenter()
check(scene.player_ship.global_position.y < scene.camera.get_camera_transform().origin.y - 0.3,"Head-relative XR spaces with zero head height must still place the ship below the headset")
XRServer.remove_tracker(head_tracker)
XRServer.remove_tracker(tracker)
scene.queue_free()
await process_frame
print("INPUT_TESTS ", "PASS" if failures == 0 else "FAIL %d" % failures)
quit(0 if failures == 0 else 1)