extends SceneTree var failures := 0 func _initialize() -> void: call_deferred("run") func check(ok: bool, label: String) -> void: if not ok: failures += 1 push_error(label) func run() -> void: var controls = root.get_node("ArcadeControls") controls.path = "res://.godot/test_controls.cfg" var pads := [{"id": 2, "guid": "one", "name": "Encoder A"}, {"id": 5, "guid": "two", "name": "Encoder B"}] var press := InputEventJoypadButton.new() press.device = 2 press.button_index = 3 press.pressed = true var binding: Dictionary = controls.encode(press, pads) var decoded: InputEvent = controls.decode(binding, pads) check(decoded.device == 2, "Binding uses a specific device") InputMap.action_erase_events("arcade_action_1") InputMap.action_add_event("arcade_action_1", decoded) check(InputMap.event_is_action(press, "arcade_action_1"), "Player one matches") press.device = 5 check(not InputMap.event_is_action(press, "arcade_action_1"), "Player two does not match the same button") var reordered := [{"id": 0, "guid": "two", "name": "Encoder B"}, {"id": 4, "guid": "one", "name": "Encoder A"}] check(controls.decode(binding, reordered).device == 4, "Identity survives changed device index") check(controls.decode(binding, []) == null, "Missing device never falls back to all devices") var twins := [{"id": 0, "guid": "same", "name": "USB"}, {"id": 1, "guid": "same", "name": "USB"}] press.device = 1 var twin: Dictionary = controls.encode(press, twins) check(controls.decode(twin, twins).device == 1, "Identical encoders isolated by slot") check(controls.decode(twin, [twins[1]]) == null, "Unplugged twin does not reassign inputs") var draft := {} for i in range(controls.STEPS.size()): draft[controls.STEPS[i][0]] = {"kind": "key", "code": KEY_A + i, "logical": 0} check(controls.save_profile(draft) == OK, "Save profile") controls.bindings.clear() check(controls.load_profile(), "Reload profile") check(controls.bindings == draft, "Bindings survive reload") check(InputMap.action_get_events("arcade_up")[0].physical_keycode == KEY_C, "Saved override applied") check(InputMap.action_get_events("robotron_move_up")[0].physical_keycode == KEY_C, "Robotron reuses player one movement") draft.arcade_start.code = KEY_P check(controls.save_profile(draft) == OK and controls.load_profile(), "Replace existing profile") check(controls.bindings.arcade_start.code == KEY_P, "Replacement persists") var before: Dictionary = controls.bindings.duplicate(true) controls.path = "res://.godot/missing_directory/controls.cfg" check(controls.save_profile(draft) != OK and controls.bindings == before, "Failed save leaves active bindings intact") check(not controls.valid({"arcade_start": {"kind": "axis"}}), "Incomplete profile rejected") var setup = load("res://games/launcher/control_setup.gd").new() root.add_child(setup) setup.begin() setup.armed_at = 0 var key := InputEventKey.new() key.physical_keycode = KEY_ENTER key.pressed = true setup._input(key) check(setup.step == 0 and setup.waiting != null, "Capture waits for release") setup._input(key) check(setup.step == 0, "Held input cannot fill next step") key.pressed = false setup._input(key) check(setup.step == 1 and setup.waiting == null, "Release advances wizard") check(not setup.conflict("arcade_menu", setup.draft.arcade_start).is_empty(), "Duplicate Start/Select rejected") setup.draft.arcade_action_1 = {"kind": "key", "code": KEY_SPACE, "logical": 0} check(setup.conflict("robotron_fire_up", setup.draft.arcade_action_1).is_empty(), "Game fire button can be reused for Robotron") setup.begin() for i in range(controls.STEPS.size()): setup.armed_at = 0 key.physical_keycode = KEY_A + i key.pressed = true setup._input(key) key.pressed = false setup._input(key) check(setup.step == controls.STEPS.size() and setup.draft.size() == 13, "Complete wizard reaches review") check(controls.bindings == before, "Draft does not change live bindings") controls.path = "res://.godot/test_controls.cfg" setup.save() await process_frame check(controls.load_profile() and controls.bindings.arcade_start.code == KEY_A, "Wizard save survives restart") print("Control setup checks: %d failures" % failures) quit(1 if failures else 0)