176 lines
6.7 KiB
GDScript
176 lines
6.7 KiB
GDScript
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
|