147 lines
4.1 KiB
GDScript
147 lines
4.1 KiB
GDScript
extends CanvasLayer
|
|
|
|
var _interactables: Array[Node] = []
|
|
var _active_interactable: Node = null
|
|
var _dialog_visible := false
|
|
|
|
var _prompt_label: Label
|
|
var _dialog_panel: PanelContainer
|
|
var _dialog_label: RichTextLabel
|
|
|
|
func _ready() -> void:
|
|
layer = 50
|
|
process_mode = Node.PROCESS_MODE_ALWAYS
|
|
_setup_ui()
|
|
_set_dialog_visible(false)
|
|
_update_prompt_visibility()
|
|
|
|
|
|
func _process(_delta: float) -> void:
|
|
if Input.is_action_just_pressed("interact"):
|
|
if _dialog_visible:
|
|
_set_dialog_visible(false)
|
|
return
|
|
if _active_interactable != null:
|
|
_open_dialog_for(_active_interactable)
|
|
|
|
|
|
func register_interactable(interactable: Node) -> void:
|
|
if interactable == null:
|
|
return
|
|
if _interactables.has(interactable):
|
|
return
|
|
_interactables.append(interactable)
|
|
_refresh_active_interactable()
|
|
|
|
|
|
func unregister_interactable(interactable: Node) -> void:
|
|
if interactable == null:
|
|
return
|
|
_interactables.erase(interactable)
|
|
if _active_interactable == interactable and _dialog_visible:
|
|
_set_dialog_visible(false)
|
|
_refresh_active_interactable()
|
|
|
|
|
|
func _refresh_active_interactable() -> void:
|
|
while _interactables.size() > 0 and not is_instance_valid(_interactables[_interactables.size() - 1]):
|
|
_interactables.pop_back()
|
|
_active_interactable = _interactables[_interactables.size() - 1] if _interactables.size() > 0 else null
|
|
if _dialog_visible and _active_interactable != null:
|
|
_dialog_label.text = _get_dialog_text(_active_interactable)
|
|
_update_prompt_visibility()
|
|
|
|
|
|
func _open_dialog_for(interactable: Node) -> void:
|
|
if _dialog_label:
|
|
_dialog_label.text = _get_dialog_text(interactable)
|
|
_set_dialog_visible(true)
|
|
|
|
|
|
func show_text(text: String) -> void:
|
|
if _dialog_label:
|
|
_dialog_label.text = text
|
|
_set_dialog_visible(true)
|
|
|
|
|
|
func close_if_text(expected_text: String) -> void:
|
|
if not _dialog_visible:
|
|
return
|
|
if _dialog_label == null:
|
|
return
|
|
if _dialog_label.text != expected_text:
|
|
return
|
|
_set_dialog_visible(false)
|
|
|
|
|
|
func _set_dialog_visible(dialog_open: bool) -> void:
|
|
_dialog_visible = dialog_open
|
|
if _dialog_panel:
|
|
_dialog_panel.visible = _dialog_visible
|
|
_update_prompt_visibility()
|
|
|
|
|
|
func _update_prompt_visibility() -> void:
|
|
if _prompt_label == null:
|
|
return
|
|
var has_active := _active_interactable != null
|
|
_prompt_label.visible = has_active and not _dialog_visible
|
|
if _prompt_label.visible:
|
|
_prompt_label.text = _get_prompt_text(_active_interactable)
|
|
|
|
|
|
func _get_prompt_text(interactable: Node) -> String:
|
|
if interactable == null:
|
|
return ""
|
|
if interactable.has_method("get_dialog_prompt"):
|
|
return String(interactable.call("get_dialog_prompt"))
|
|
return "Press E to interact"
|
|
|
|
|
|
func _get_dialog_text(interactable: Node) -> String:
|
|
if interactable == null:
|
|
return ""
|
|
if interactable.has_method("get_dialog_text"):
|
|
return String(interactable.call("get_dialog_text"))
|
|
return "..."
|
|
|
|
|
|
func _setup_ui() -> void:
|
|
var root := Control.new()
|
|
root.name = "DialogRoot"
|
|
root.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
root.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
add_child(root)
|
|
|
|
_prompt_label = Label.new()
|
|
_prompt_label.name = "PromptLabel"
|
|
_prompt_label.set_anchors_preset(Control.PRESET_CENTER_BOTTOM)
|
|
_prompt_label.offset_left = -140.0
|
|
_prompt_label.offset_top = -64.0
|
|
_prompt_label.offset_right = 140.0
|
|
_prompt_label.offset_bottom = -36.0
|
|
_prompt_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
_prompt_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
_prompt_label.text = "Press E to interact"
|
|
root.add_child(_prompt_label)
|
|
|
|
_dialog_panel = PanelContainer.new()
|
|
_dialog_panel.name = "DialogPanel"
|
|
_dialog_panel.visible = false
|
|
_dialog_panel.set_anchors_preset(Control.PRESET_CENTER_BOTTOM)
|
|
_dialog_panel.offset_left = -300.0
|
|
_dialog_panel.offset_top = -220.0
|
|
_dialog_panel.offset_right = 300.0
|
|
_dialog_panel.offset_bottom = -80.0
|
|
_dialog_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
root.add_child(_dialog_panel)
|
|
|
|
_dialog_label = RichTextLabel.new()
|
|
_dialog_label.name = "DialogText"
|
|
_dialog_label.custom_minimum_size = Vector2(560.0, 120.0)
|
|
_dialog_label.fit_content = true
|
|
_dialog_label.scroll_active = false
|
|
_dialog_label.bbcode_enabled = true
|
|
_dialog_label.text = ""
|
|
_dialog_panel.add_child(_dialog_label)
|