extends Node @export var hardware_scenario: ScenarioDefinition = preload("res://data/scenarios/proof_of_concept.tres") ## Standalone arcade selector. Room/scenario startup remains separate. const GAMES := [ ["Pac-Man", "pacman/Pacman", "pacman", "JOYSTICK"], ["Galaga", "galaga/Galaga", "galaga", "JOYSTICK / FIRE"], ["Tempest", "tempest/Tempest", "tempest", "JOYSTICK OR TRACKBALL / FIRE / SUPERZAPPER"], ["Missile Command", "missile_command/MissileCommand", "missilecommand", "TRACKBALL / THREE LAUNCH BUTTONS"], ["Frogger", "frogger/Frogger", "frogger", "JOYSTICK"], ["Space Invaders", "space_invaders/SpaceInvaders", "spaceinvaders", "JOYSTICK / FIRE"], ["Robotron 2084", "robotron/Robotron", "robotron", "JOYSTICK / FOUR DIRECTIONAL FIRE BUTTONS"], ] var selected := 0 var game: Node var menu: Control var list: ItemList var description: Label var switching := false var setup: CanvasLayer var control_status: Label var gpio_status: Label func _ready() -> void: if "--managed-cabinet" in OS.get_cmdline_user_args(): set_process_input(false) add_child(preload("res://core/network/managed_cabinet.gd").new()) return if "--operator" in OS.get_cmdline_user_args(): set_process_input(false) add_child(preload("res://operator/ArcadeRoomOperator.tscn").instantiate()) return var layer := CanvasLayer.new() add_child(layer) menu = Control.new() menu.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) layer.add_child(menu) var background := ColorRect.new() background.color = Color("080d18") background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) menu.add_child(background) var center := CenterContainer.new() center.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) menu.add_child(center) var column := VBoxContainer.new() column.custom_minimum_size = Vector2(700, 0) column.add_theme_constant_override("separation", 18) center.add_child(column) var title := Label.new() title.text = "ARCADE GALLERY" title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER title.add_theme_font_size_override("font_size", 46) title.modulate = Color("75e8ef") column.add_child(title) list = ItemList.new() list.custom_minimum_size = Vector2(700, 520) list.fixed_icon_size = Vector2i(48, 48) list.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST list.add_theme_font_size_override("font_size", 28) list.add_theme_constant_override("v_separation", 12) list.focus_mode = Control.FOCUS_NONE column.add_child(list) for entry in GAMES: list.add_item(entry[0], load("res://games/launcher/icons/ico_%s.png" % entry[2])) list.add_item("Control Setup") list.item_selected.connect(_select) list.item_activated.connect(func(index: int): _select(index); launch.call_deferred()) description = Label.new() description.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER description.add_theme_font_size_override("font_size", 18) column.add_child(description) var hint := Label.new() hint.text = "JOYSTICK: CHOOSE START: PLAY SELECT: RETURN TO MENU" hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER hint.modulate = Color("91a1bb") column.add_child(hint) control_status = Label.new() control_status.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER control_status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART control_status.add_theme_font_size_override("font_size", 16) column.add_child(control_status) ArcadeControls.changed.connect(_refresh_control_status) _refresh_control_status() gpio_status = Label.new() gpio_status.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER gpio_status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART gpio_status.text = HardwareManager.status column.add_child(gpio_status) HardwareManager.status_changed.connect(func(message: String): gpio_status.text = message) _select(0) if ArcadeControls.bindings.is_empty(): open_setup.call_deferred() func _refresh_control_status() -> void: control_status.text = ArcadeControls.problem if not ArcadeControls.problem.is_empty() else "CONTROL SETUP: LAST MENU ENTRY / F1" func _select(index: int) -> void: selected = wrapi(index, 0, GAMES.size() + 1) list.select(selected) list.ensure_current_is_visible() description.text = GAMES[selected][3] if selected < GAMES.size() else "CONFIGURE THIS CABINET'S JOYSTICKS AND BUTTONS" func _input(event: InputEvent) -> void: if ArcadeControls.handle_quit(event): return if is_instance_valid(setup): return if event.is_echo() or switching: return if event is InputEventKey and event.pressed and event.physical_keycode == KEY_F1: get_viewport().set_input_as_handled() if is_instance_valid(game): return_to_menu() open_setup.call_deferred() return if is_instance_valid(game): if event.is_action_pressed("arcade_menu"): get_viewport().set_input_as_handled() switching = true return_to_menu.call_deferred() return if event.is_action_pressed("arcade_down"): _select(selected + 1) elif event.is_action_pressed("arcade_up"): _select(selected - 1) elif event.is_action_pressed("arcade_start"): switching = true launch.call_deferred() else: return get_viewport().set_input_as_handled() func launch() -> void: if selected == GAMES.size(): open_setup() switching = false return if is_instance_valid(game): return var scene := load("res://games/%s.tscn" % GAMES[selected][1]) as PackedScene if scene == null: switching = false return game = scene.instantiate() RoomRuntime.active_assignment = null if hardware_scenario != null: for assignment in hardware_scenario.assignments: if assignment.game != null and assignment.game.scene == scene: RoomRuntime.configure(assignment) game.game_started.connect(func(): RoomRuntime.fire_game_event(GameEvents.STARTED)) game.game_won.connect(func(): RoomRuntime.fire_game_event(GameEvents.WON)) game.game_lost.connect(func(): RoomRuntime.fire_game_event(GameEvents.LOST)) game.game_reset.connect(func(): RoomRuntime.fire_game_event(GameEvents.RESET)) break if GAMES[selected][2] == "missilecommand": game.set("relative_mouse_aim", true) if GAMES[selected][2] in ["missilecommand", "tempest"]: Input.mouse_mode = Input.MOUSE_MODE_CAPTURED menu.hide() add_child(game) # Present the game's attract screen; Start begins its own opening sequence. switching = false func open_setup() -> void: if is_instance_valid(setup): return setup = preload("res://games/launcher/control_setup.gd").new() menu.hide() Input.mouse_mode = Input.MOUSE_MODE_VISIBLE setup.closed.connect(func(): menu.show(); _select(selected)) add_child(setup) func return_to_menu() -> void: if is_instance_valid(game): remove_child(game) game.queue_free() game = null RoomRuntime.active_assignment = null HardwareManager.active_cabinet = null Input.mouse_mode = Input.MOUSE_MODE_VISIBLE menu.show() _select(selected) switching = false