extends Control @export_group("Project") @export var database: ProjectDatabase @export var room: RoomDefinition @export_group("Runtime Defaults") @export var default_scenario_id: StringName = &"two_cabinet_test" @onready var room_controller: RoomController = ( $RoomController ) @onready var editor_workspace: EscapeRoomWorkspace = ( $MarginContainer/VBoxContainer/ EditorArea/EscapeRoomWorkspace ) @onready var runtime_scenario_select: OptionButton = ( $MarginContainer/VBoxContainer/ OperatorBar/RuntimeScenarioSelect ) @onready var room_status_label: Label = ( $MarginContainer/VBoxContainer/ OperatorBar/RoomStatusLabel ) @onready var cabinet_status_container: VBoxContainer = ( $MarginContainer/VBoxContainer/ CabinetStatusContainer ) var runtime_scenario_ids: Array[StringName] = [] var cabinet_status_labels: Dictionary = {} func _ready() -> void: if database == null: push_error( "OperatorConsole has no ProjectDatabase assigned." ) return if room == null: push_error( "OperatorConsole has no RoomDefinition assigned." ) return room_controller.configure( database, room ) _connect_room_controller_signals() _setup_editor_workspace() _populate_runtime_scenarios() func _connect_room_controller_signals() -> void: room_controller.scenario_loaded.connect( _on_runtime_scenario_loaded ) room_controller.validation_completed.connect( _on_runtime_validation_completed ) room_controller.cabinet_status_changed.connect( _on_cabinet_status_changed ) room_controller.room_status_changed.connect( _on_room_status_changed ) func _setup_editor_workspace() -> void: if editor_workspace == null: return if not editor_workspace.configure( database, room ): push_error( "Failed to configure EscapeRoomWorkspace." ) func _populate_runtime_scenarios() -> void: runtime_scenario_select.clear() runtime_scenario_ids.clear() for scenario in database.scenarios: if scenario == null: continue runtime_scenario_select.add_item( scenario.display_name ) runtime_scenario_ids.append( scenario.scenario_id ) if runtime_scenario_ids.is_empty(): room_status_label.text = ( "ROOM STATUS: NO SCENARIOS" ) return var default_index := 0 for index in range( runtime_scenario_ids.size() ): if ( runtime_scenario_ids[index] == default_scenario_id ): default_index = index break runtime_scenario_select.select( default_index ) _load_selected_runtime_scenario() func _load_selected_runtime_scenario() -> void: var index := runtime_scenario_select.selected if ( index < 0 or index >= runtime_scenario_ids.size() ): return var scenario_id := ( runtime_scenario_ids[index] ) room_controller.load_scenario( scenario_id ) func _on_runtime_scenario_select_item_selected( _index: int ) -> void: _load_selected_runtime_scenario() func _on_validate_room_button_pressed() -> void: room_controller.validate_active_scenario() func _on_prep_room_button_pressed() -> void: room_controller.prep_room() func _on_runtime_scenario_loaded( scenario: ScenarioDefinition ) -> void: _rebuild_cabinet_status_list( scenario ) room_status_label.text = ( "ROOM STATUS: LOADED — %s v%d" % [ scenario.display_name, scenario.version ] ) func _rebuild_cabinet_status_list( scenario: ScenarioDefinition ) -> void: for child in cabinet_status_container.get_children(): child.queue_free() cabinet_status_labels.clear() for assignment in scenario.assignments: if assignment == null: continue _add_cabinet_status_row( assignment ) func _add_cabinet_status_row( assignment: ScenarioAssignment ) -> void: var panel := PanelContainer.new() var margin := MarginContainer.new() var row := HBoxContainer.new() var details := VBoxContainer.new() var cabinet_label := Label.new() var game_label := Label.new() var variant_label := Label.new() var status_label := Label.new() if assignment.cabinet != null: cabinet_label.text = ( assignment.cabinet.display_name ) else: cabinet_label.text = ( "MISSING CABINET" ) if assignment.game != null: game_label.text = ( "Game: %s" % assignment.game.display_name ) else: game_label.text = ( "Game: MISSING" ) variant_label.text = ( "Variant: %s" % assignment.variant ) status_label.text = ( "NOT PREPARED" ) status_label.horizontal_alignment = ( HORIZONTAL_ALIGNMENT_RIGHT ) status_label.custom_minimum_size.x = ( 160.0 ) details.add_child( cabinet_label ) details.add_child( game_label ) details.add_child( variant_label ) var spacer := Control.new() spacer.size_flags_horizontal = ( Control.SIZE_EXPAND_FILL ) row.add_child( details ) row.add_child( spacer ) row.add_child( status_label ) margin.add_child( row ) panel.add_child( margin ) cabinet_status_container.add_child( panel ) if assignment.cabinet != null: cabinet_status_labels[ assignment.cabinet.cabinet_id ] = status_label func _on_runtime_validation_completed( result: ValidationResult ) -> void: if result.is_valid(): room_status_label.text = ( "ROOM STATUS: %s" % result.get_summary() ) else: room_status_label.text = ( "ROOM STATUS: INVALID — %s" % result.get_summary() ) for error in result.errors: print( "[RUNTIME VALIDATION] ERROR: ", error ) for warning in result.warnings: print( "[RUNTIME VALIDATION] WARNING: ", warning ) func _on_cabinet_status_changed( cabinet_id: StringName, status: StringName ) -> void: if not cabinet_status_labels.has( cabinet_id ): return var label: Label = ( cabinet_status_labels[ cabinet_id ] ) label.text = String( status ) func _on_room_status_changed( status: StringName ) -> void: room_status_label.text = ( "ROOM STATUS: %s" % status )