summaryrefslogtreecommitdiff
path: root/addons/escoria-ui-keyboard-9verbs
diff options
context:
space:
mode:
Diffstat (limited to 'addons/escoria-ui-keyboard-9verbs')
-rw-r--r--addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.tres7
-rw-r--r--addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.ttfbin0 -> 147756 bytes
-rw-r--r--addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.ttf.import36
-rw-r--r--addons/escoria-ui-keyboard-9verbs/game.gd404
-rw-r--r--addons/escoria-ui-keyboard-9verbs/game.gd.uid1
-rw-r--r--addons/escoria-ui-keyboard-9verbs/game.tscn133
-rw-r--r--addons/escoria-ui-keyboard-9verbs/input_map.gd60
-rw-r--r--addons/escoria-ui-keyboard-9verbs/input_map.gd.uid1
-rw-r--r--addons/escoria-ui-keyboard-9verbs/inventory/inventory_ui.tscn31
-rw-r--r--addons/escoria-ui-keyboard-9verbs/plugin.cfg7
-rw-r--r--addons/escoria-ui-keyboard-9verbs/plugin.gd24
-rw-r--r--addons/escoria-ui-keyboard-9verbs/plugin.gd.uid1
-rw-r--r--addons/escoria-ui-keyboard-9verbs/theme.tres6
-rw-r--r--addons/escoria-ui-keyboard-9verbs/tooltip/action_target_tooltip.tscn14
-rw-r--r--addons/escoria-ui-keyboard-9verbs/tooltip/tooltip_action_target.gd34
-rw-r--r--addons/escoria-ui-keyboard-9verbs/tooltip/tooltip_action_target.gd.uid1
-rw-r--r--addons/escoria-ui-keyboard-9verbs/verbs_menu.gd32
-rw-r--r--addons/escoria-ui-keyboard-9verbs/verbs_menu.gd.uid1
-rw-r--r--addons/escoria-ui-keyboard-9verbs/verbs_menu.tscn125
19 files changed, 918 insertions, 0 deletions
diff --git a/addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.tres b/addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.tres
new file mode 100644
index 0000000..f64ce3b
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.tres
@@ -0,0 +1,7 @@
+[gd_resource type="FontFile" load_steps=2 format=2]
+
+[ext_resource path="res://addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.ttf" type="FontFile" id=1]
+
+[resource]
+size = 21
+font_data = ExtResource( 1 )
diff --git a/addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.ttf b/addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.ttf
new file mode 100644
index 0000000..eec6f63
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.ttf
Binary files differ
diff --git a/addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.ttf.import b/addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.ttf.import
new file mode 100644
index 0000000..6799af1
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.ttf.import
@@ -0,0 +1,36 @@
+[remap]
+
+importer="font_data_dynamic"
+type="FontFile"
+uid="uid://bl733mjk2noo8"
+path="res://.godot/imported/caslonantique.ttf-2e335cc87aa9bb7b4f1f86dffaccc876.fontdata"
+
+[deps]
+
+source_file="res://addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.ttf"
+dest_files=["res://.godot/imported/caslonantique.ttf-2e335cc87aa9bb7b4f1f86dffaccc876.fontdata"]
+
+[params]
+
+Rendering=null
+antialiasing=1
+generate_mipmaps=false
+disable_embedded_bitmaps=true
+multichannel_signed_distance_field=false
+msdf_pixel_range=8
+msdf_size=48
+allow_system_fallback=true
+force_autohinter=false
+modulate_color_glyphs=false
+hinting=1
+subpixel_positioning=4
+keep_rounding_remainders=true
+oversampling=0.0
+Fallbacks=null
+fallbacks=[]
+Compress=null
+compress=true
+preload=[]
+language_support={}
+script_support={}
+opentype_features={}
diff --git a/addons/escoria-ui-keyboard-9verbs/game.gd b/addons/escoria-ui-keyboard-9verbs/game.gd
new file mode 100644
index 0000000..0e55973
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/game.gd
@@ -0,0 +1,404 @@
+extends ESCGame
+
+
+const VERB_CLOSE = "close"
+const VERB_GIVE = "give"
+const VERB_LOOK = "look"
+const VERB_OPEN = "open"
+const VERB_PICKUP = "pickup"
+const VERB_PULL = "pull"
+const VERB_PUSH = "push"
+const VERB_TALK = "talk"
+const VERB_USE = "use"
+
+
+"""
+Implement methods to react to inputs.
+
+- left_click_on_bg(position: Vector2)
+- right_click_on_bg(position: Vector2)
+- left_double_click_on_bg(position: Vector2)
+
+- element_focused(element_id: String)
+- element_unfocused()
+
+- left_click_on_item(item_global_id: String, event: InputEvent)
+- right_click_on_item(item_global_id: String, event: InputEvent)
+- left_double_click_on_item(item_global_id: String, event: InputEvent)
+
+- left_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent)
+- right_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent)
+- left_double_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent)
+- inventory_item_focused(inventory_item_global_id: String)
+- inventory_item_unfocused()
+- open_inventory()
+- close_inventory()
+
+- mousewheel_action(direction: int)
+
+- hide_ui()
+- show_ui()
+
+- pause_game()
+- unpause_game()
+- show_main_menu()
+- hide_main_menu()
+
+- apply_custom_settings()
+
+- _on_event_done(event_name: String)
+"""
+
+
+@onready var verbs_menu = $ui/Control/panel_down/VBoxContainer/HBoxContainer\
+ /VerbsMargin/verbs_menu
+@onready var tooltip = $ui/Control/panel_down/VBoxContainer/MarginContainer\
+ /tooltip
+@onready var room_select = $ui/Control/panel_down/VBoxContainer/HBoxContainer\
+ /MainMargin/VBoxContainer/room_select
+@onready var inventory_ui = $ui/Control/panel_down/VBoxContainer/HBoxContainer\
+ /InventoryMargin/inventory_ui
+const input_map = preload("res://addons/escoria-ui-keyboard-9verbs/input_map.gd")
+
+func _enter_tree():
+ var room_selector_parent = $ui/Control/panel_down/VBoxContainer\
+ /HBoxContainer/MainMargin/VBoxContainer
+
+ if ProjectSettings.get_setting("escoria/debug/enable_room_selector") and \
+ room_selector_parent.get_node_or_null("room_select") == null:
+ room_selector_parent.add_child(
+ preload(
+ "res://addons/escoria-core/ui_library/tools/room_select" +\
+ "/room_select.tscn"
+ ).instantiate()
+ )
+
+ var input_handler = Callable(self, "_process_input")
+ escoria.inputs_manager.register_custom_input_handler(input_handler)
+ input_map.add_actions_to_input_map()
+
+
+func _exit_tree():
+ escoria.inputs_manager.register_custom_input_handler(null)
+ input_map.erase_actions_from_input_map()
+
+
+func _process_input(event: InputEvent, is_default_state: bool) -> bool:
+ if not is_default_state:
+ return false
+ elif event.is_action_pressed(input_map.ACTION_SET_VERB_OPEN):
+ verbs_menu.on_action_selected(VERB_OPEN)
+ return true
+ elif event.is_action_pressed(input_map.ACTION_SET_VERB_PICKUP):
+ verbs_menu.on_action_selected(VERB_PICKUP)
+ return true
+ elif event.is_action_pressed(input_map.ACTION_SET_VERB_PUSH):
+ verbs_menu.on_action_selected(VERB_PUSH)
+ return true
+ elif event.is_action_pressed(input_map.ACTION_SET_VERB_CLOSE):
+ verbs_menu.on_action_selected(VERB_CLOSE)
+ return true
+ elif event.is_action_pressed(input_map.ACTION_SET_VERB_LOOK):
+ verbs_menu.on_action_selected(VERB_LOOK)
+ return true
+ elif event.is_action_pressed(input_map.ACTION_SET_VERB_PULL):
+ verbs_menu.on_action_selected(VERB_PULL)
+ return true
+ elif event.is_action_pressed(input_map.ACTION_SET_VERB_GIVE):
+ verbs_menu.on_action_selected(VERB_GIVE)
+ return true
+ elif event.is_action_pressed(input_map.ACTION_SET_VERB_USE):
+ verbs_menu.on_action_selected(VERB_USE)
+ return true
+ elif event.is_action_pressed(input_map.ACTION_SET_VERB_TALK):
+ verbs_menu.on_action_selected(VERB_TALK)
+ return true
+ else:
+ return false
+
+
+## BACKGROUND ##
+
+func left_click_on_bg(position: Vector2) -> void:
+ if escoria.main.current_scene.player:
+ escoria.action_manager.do(
+ escoria.action_manager.ACTION.BACKGROUND_CLICK,
+ [escoria.main.current_scene.player.global_id, position],
+ true
+ )
+ escoria.action_manager.clear_current_action()
+ escoria.action_manager.clear_current_tool()
+ tooltip.clear()
+ verbs_menu.unselect_actions()
+
+
+func right_click_on_bg(position: Vector2) -> void:
+ if escoria.main.current_scene.player:
+ escoria.action_manager.do(
+ escoria.action_manager.ACTION.BACKGROUND_CLICK,
+ [escoria.main.current_scene.player.global_id, position],
+ true
+ )
+ escoria.action_manager.clear_current_action()
+ escoria.action_manager.clear_current_tool()
+ tooltip.clear()
+ verbs_menu.unselect_actions()
+
+
+func left_double_click_on_bg(position: Vector2) -> void:
+ if escoria.main.current_scene.player:
+ escoria.action_manager.do(
+ escoria.action_manager.ACTION.BACKGROUND_CLICK,
+ [escoria.main.current_scene.player.global_id, position, true],
+ true
+ )
+ escoria.action_manager.clear_current_action()
+ verbs_menu.unselect_actions()
+
+
+## ITEM FOCUS ##
+
+func element_focused(element_id: String) -> void:
+ var target_obj = escoria.object_manager.get_object(element_id).node
+
+ match escoria.action_manager.action_state:
+ # Don't change the tooltip if an action input is completed
+ # (ie verb+item(+target)) because the action is now being executed
+ # and the tooltip is already set because the item was focused
+ # (see element_focused() and inventory_item_focused())
+ ESCActionManager.ACTION_INPUT_STATE.COMPLETED:
+ return
+
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM, \
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_ITEM:
+ tooltip.set_target(target_obj.tooltip_name)
+
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_TARGET_ITEM:
+ tooltip.set_target2(target_obj.tooltip_name)
+
+
+func element_unfocused() -> void:
+ match escoria.action_manager.action_state:
+ # Don't change the tooltip if an action input is completed
+ # (ie verb+item(+target)) because the action is now being executed
+ # and the tooltip is already set because the item was focused
+ # (see element_focused() and inventory_item_focused())
+ ESCActionManager.ACTION_INPUT_STATE.COMPLETED:
+ return
+
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM, \
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_ITEM:
+ tooltip.set_target("")
+ verbs_menu.unselect_actions()
+
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_TARGET_ITEM:
+ tooltip.set_target2("")
+
+
+
+## ITEMS ##
+func left_click_on_item(item_global_id: String, event: InputEvent) -> void:
+ escoria.action_manager.do(
+ escoria.action_manager.ACTION.ITEM_LEFT_CLICK,
+ [item_global_id, event],
+ true
+ )
+
+ var target_obj = escoria.object_manager.get_object(
+ item_global_id
+ ).node
+
+ match escoria.action_manager.action_state:
+ # Don't change the tooltip if an action input is completed
+ # (ie verb+item(+target)) because the action is now being executed
+ # and the tooltip is already set because the item was focused
+ # (see element_focused() and inventory_item_focused())
+ ESCActionManager.ACTION_INPUT_STATE.COMPLETED:
+ return
+
+ # Just clicked on the item
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM, \
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_ITEM:
+ tooltip.set_target(target_obj.tooltip_name)
+
+ # Clicked on item and now we're awaiting a target item
+ # This means we clicked the tool and we now need a target
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_TARGET_ITEM:
+ tooltip.set_target(target_obj.tooltip_name, true)
+
+
+
+func right_click_on_item(item_global_id: String, event: InputEvent) -> void:
+ escoria.action_manager.set_current_action(verbs_menu.selected_action)
+ escoria.action_manager.do(
+ escoria.action_manager.ACTION.ITEM_RIGHT_CLICK,
+ [item_global_id, event],
+ true
+ )
+
+
+func left_double_click_on_item(item_global_id: String, event: InputEvent) -> void:
+ escoria.action_manager.do(
+ escoria.action_manager.ACTION.ITEM_LEFT_CLICK,
+ [item_global_id, event],
+ true
+ )
+
+
+## INVENTORY ##
+func left_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent) -> void:
+ escoria.action_manager.do(
+ escoria.action_manager.ACTION.ITEM_LEFT_CLICK,
+ [inventory_item_global_id, event]
+ )
+
+ var target_obj = escoria.object_manager.get_object(
+ inventory_item_global_id
+ ).node
+
+ match escoria.action_manager.action_state:
+ # Don't change the tooltip if an action input is completed
+ # (ie verb+item(+target)) because the action is now being executed
+ # and the tooltip is already set because the item was focused
+ # (see element_focused() and inventory_item_focused())
+ ESCActionManager.ACTION_INPUT_STATE.COMPLETED:
+ return
+
+ # Just clicked on the inventory item: do nothing special
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM, \
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_ITEM:
+ return
+
+ # Clicked on inventory item and now we're awaiting a target item
+ # This means we clicked the tool and we now need a target
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_TARGET_ITEM:
+ tooltip.set_target(target_obj.tooltip_name, true)
+
+
+func right_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent) -> void:
+ escoria.action_manager.set_current_action(verbs_menu.selected_action)
+ escoria.action_manager.do(
+ escoria.action_manager.ACTION.ITEM_RIGHT_CLICK,
+ [inventory_item_global_id, event]
+ )
+
+
+func left_double_click_on_inventory_item(_inventory_item_global_id: String, _event: InputEvent) -> void:
+ pass
+
+
+func inventory_item_focused(inventory_item_global_id: String) -> void:
+ var target_obj = escoria.object_manager.get_object(
+ inventory_item_global_id
+ ).node
+
+ match escoria.action_manager.action_state:
+ # Don't change the tooltip if an action input is completed
+ # (ie verb+item(+target)) because the action is now being executed
+ # and the tooltip is already set because the item was focused
+ # (see element_focused() and inventory_item_focused())
+ ESCActionManager.ACTION_INPUT_STATE.COMPLETED:
+ return
+
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM, \
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_ITEM:
+ tooltip.set_target(target_obj.tooltip_name)
+
+ # Hovering an ESCItem highlights its default action
+ if escoria.action_manager.current_action != VERB_USE and target_obj is ESCItem:
+ verbs_menu.set_by_name(target_obj.default_action)
+
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_TARGET_ITEM:
+ tooltip.set_target2(target_obj.tooltip_name)
+
+
+func inventory_item_unfocused() -> void:
+
+ match escoria.action_manager.action_state:
+ ESCActionManager.ACTION_INPUT_STATE.COMPLETED:
+ # Don't change the tooltip if an action input is completed
+ # (ie verb+item(+target)) because the action is now being executed
+ return
+
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM, \
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_ITEM:
+ tooltip.set_target("")
+ verbs_menu.unselect_actions()
+
+ ESCActionManager.ACTION_INPUT_STATE.AWAITING_TARGET_ITEM:
+ tooltip.set_target2("")
+
+
+func open_inventory():
+ pass
+
+
+func close_inventory():
+ pass
+
+
+func mousewheel_action(_direction: int):
+ pass
+
+
+func hide_ui():
+ $ui/Control.hide()
+ verbs_menu.hide()
+ if ProjectSettings.get("escoria/debug/enable_room_selector") == true:
+ room_select.hide()
+ inventory_ui.hide()
+ tooltip.hide()
+
+
+func show_ui():
+ $ui/Control.show()
+ verbs_menu.show()
+ if ProjectSettings.get("escoria/debug/enable_room_selector") == true:
+ room_select.show()
+ inventory_ui.show()
+ tooltip.show()
+
+func hide_main_menu():
+ if get_node(main_menu).visible:
+ get_node(main_menu).hide()
+ show_ui()
+
+func show_main_menu():
+ if not get_node(main_menu).visible:
+ hide_ui()
+ get_node(main_menu).reset()
+ get_node(main_menu).show()
+
+func unpause_game():
+ if get_node(pause_menu).visible:
+ get_node(pause_menu).hide()
+ escoria.object_manager.get_object(ESCObjectManager.CAMERA).node.current = true
+ escoria.object_manager.get_object(ESCObjectManager.SPEECH).node.resume()
+ escoria.main.current_scene.game.show_ui()
+ escoria.main.current_scene.show()
+ escoria.set_game_paused(false)
+
+func pause_game():
+ if not get_node(pause_menu).visible:
+ get_node(pause_menu).reset()
+ get_node(pause_menu).set_save_enabled(escoria.save_manager.save_enabled)
+ get_node(pause_menu).show()
+ escoria.object_manager.get_object(ESCObjectManager.CAMERA).node.current = false
+ escoria.object_manager.get_object(ESCObjectManager.SPEECH).node.pause()
+ escoria.main.current_scene.game.hide_ui()
+ escoria.main.current_scene.hide()
+ escoria.set_game_paused(true)
+
+
+func _on_MenuButton_pressed() -> void:
+ pause_game()
+
+
+func _on_action_finished() -> void:
+ verbs_menu.unselect_actions()
+ tooltip.clear()
+
+func _on_event_done(_return_code: int, _event_name: String):
+ if _return_code == ESCExecution.RC_OK:
+ escoria.action_manager.clear_current_action()
+ verbs_menu.unselect_actions()
diff --git a/addons/escoria-ui-keyboard-9verbs/game.gd.uid b/addons/escoria-ui-keyboard-9verbs/game.gd.uid
new file mode 100644
index 0000000..f400c73
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/game.gd.uid
@@ -0,0 +1 @@
+uid://bb1iia3lec7ja
diff --git a/addons/escoria-ui-keyboard-9verbs/game.tscn b/addons/escoria-ui-keyboard-9verbs/game.tscn
new file mode 100644
index 0000000..6fa40b4
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/game.tscn
@@ -0,0 +1,133 @@
+[gd_scene load_steps=11 format=3 uid="uid://bygij2fuc74p5"]
+
+[ext_resource type="PackedScene" uid="uid://yv8r2xh0jvft" path="res://addons/escoria-ui-keyboard-9verbs/tooltip/action_target_tooltip.tscn" id="1"]
+[ext_resource type="PackedScene" uid="uid://b5yss2p8c83cp" path="res://addons/escoria-ui-keyboard-9verbs/inventory/inventory_ui.tscn" id="2"]
+[ext_resource type="PackedScene" uid="uid://c7fwywnj0glve" path="res://addons/escoria-ui-keyboard-9verbs/verbs_menu.tscn" id="3"]
+[ext_resource type="Script" uid="uid://dfl7khtlretr7" path="res://addons/escoria-core/game/scenes/dialogs/esc_dialog_player.gd" id="4"]
+[ext_resource type="Script" uid="uid://bb1iia3lec7ja" path="res://addons/escoria-ui-keyboard-9verbs/game.gd" id="5"]
+[ext_resource type="PackedScene" uid="uid://dmw5gicuenj53" path="res://addons/escoria-core/game/scenes/camera_player/camera.tscn" id="6"]
+[ext_resource type="PackedScene" uid="uid://u8an5av5fuxx" path="res://addons/escoria-core/ui_library/menus/main_menu/main_menu.tscn" id="7"]
+[ext_resource type="PackedScene" uid="uid://gfjgmbcafyyt" path="res://addons/escoria-core/ui_library/menus/pause_menu/pause_menu.tscn" id="9"]
+[ext_resource type="Theme" uid="uid://bcxggcvu105e5" path="res://addons/escoria-ui-keyboard-9verbs/theme.tres" id="10"]
+
+[sub_resource type="StyleBoxFlat" id="1"]
+bg_color = Color(0.6, 0.6, 0.6, 0.5)
+
+[node name="game" type="Node2D"]
+script = ExtResource("5")
+main_menu = NodePath("ui/main_menu")
+pause_menu = NodePath("ui/pause_menu")
+ui_parent_control_node = NodePath("ui/Control")
+
+[node name="dialog_layer" type="CanvasLayer" parent="."]
+
+[node name="ESCDialogPlayer" type="Control" parent="dialog_layer"]
+layout_mode = 3
+anchors_preset = 0
+theme = ExtResource("10")
+script = ExtResource("4")
+metadata/_custom_type_script = "uid://dfl7khtlretr7"
+
+[node name="ui" type="CanvasLayer" parent="."]
+
+[node name="Control" type="Control" parent="ui"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 2
+theme = ExtResource("10")
+
+[node name="panel_down" type="PanelContainer" parent="ui/Control"]
+layout_mode = 0
+anchor_top = 0.7
+anchor_right = 1.0
+anchor_bottom = 1.0
+size_flags_vertical = 3
+theme_override_styles/panel = SubResource("1")
+
+[node name="VBoxContainer" type="VBoxContainer" parent="ui/Control/panel_down"]
+layout_mode = 2
+
+[node name="MarginContainer" type="MarginContainer" parent="ui/Control/panel_down/VBoxContainer"]
+layout_mode = 2
+theme_override_constants/margin_top = 10
+
+[node name="tooltip" parent="ui/Control/panel_down/VBoxContainer/MarginContainer" instance=ExtResource("1")]
+custom_minimum_size = Vector2(0, 20)
+layout_mode = 2
+text = "Test"
+color = Color(1, 1, 1, 1)
+
+[node name="HSeparator" type="HSeparator" parent="ui/Control/panel_down/VBoxContainer"]
+layout_mode = 2
+theme_override_constants/separation = 10
+
+[node name="HBoxContainer" type="HBoxContainer" parent="ui/Control/panel_down/VBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 3
+
+[node name="VerbsMargin" type="MarginContainer" parent="ui/Control/panel_down/VBoxContainer/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+theme_override_constants/margin_left = 20
+theme_override_constants/margin_top = 20
+theme_override_constants/margin_right = 20
+theme_override_constants/margin_bottom = 20
+
+[node name="verbs_menu" parent="ui/Control/panel_down/VBoxContainer/HBoxContainer/VerbsMargin" instance=ExtResource("3")]
+layout_mode = 2
+
+[node name="MainMargin" type="MarginContainer" parent="ui/Control/panel_down/VBoxContainer/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_constants/margin_left = 20
+theme_override_constants/margin_top = 20
+theme_override_constants/margin_right = 20
+theme_override_constants/margin_bottom = 20
+
+[node name="VBoxContainer" type="VBoxContainer" parent="ui/Control/panel_down/VBoxContainer/HBoxContainer/MainMargin"]
+layout_mode = 2
+
+[node name="MarginContainer" type="MarginContainer" parent="ui/Control/panel_down/VBoxContainer/HBoxContainer/MainMargin/VBoxContainer"]
+custom_minimum_size = Vector2(100, 40)
+layout_mode = 2
+size_flags_horizontal = 6
+size_flags_vertical = 6
+
+[node name="MenuButton" type="Button" parent="ui/Control/panel_down/VBoxContainer/HBoxContainer/MainMargin/VBoxContainer/MarginContainer"]
+layout_mode = 2
+text = "Menu"
+
+[node name="InventoryMargin" type="MarginContainer" parent="ui/Control/panel_down/VBoxContainer/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_constants/margin_left = 20
+theme_override_constants/margin_top = 20
+theme_override_constants/margin_right = 20
+theme_override_constants/margin_bottom = 20
+
+[node name="inventory_ui" parent="ui/Control/panel_down/VBoxContainer/HBoxContainer/InventoryMargin" instance=ExtResource("2")]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+
+[node name="hover_stack" type="Label" parent="ui"]
+offset_left = 1085.0
+offset_top = 2.81912
+offset_right = 1283.0
+offset_bottom = 107.819
+
+[node name="main_menu" parent="ui" instance=ExtResource("7")]
+visible = false
+
+[node name="pause_menu" parent="ui" instance=ExtResource("9")]
+visible = false
+theme = ExtResource("10")
+
+[node name="camera" parent="." instance=ExtResource("6")]
+
+[connection signal="pressed" from="ui/Control/panel_down/VBoxContainer/HBoxContainer/MainMargin/VBoxContainer/MarginContainer/MenuButton" to="." method="_on_MenuButton_pressed"]
diff --git a/addons/escoria-ui-keyboard-9verbs/input_map.gd b/addons/escoria-ui-keyboard-9verbs/input_map.gd
new file mode 100644
index 0000000..8e819c8
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/input_map.gd
@@ -0,0 +1,60 @@
+const ACTION_SET_VERB_OPEN = "set_action_verb_open"
+const ACTION_SET_VERB_PICKUP = "set_action_verb_pickup"
+const ACTION_SET_VERB_PUSH = "set_action_verb_push"
+const ACTION_SET_VERB_CLOSE = "set_action_verb_close"
+const ACTION_SET_VERB_LOOK = "set_action_verb_look"
+const ACTION_SET_VERB_PULL = "set_action_verb_pull"
+const ACTION_SET_VERB_GIVE = "set_action_verb_give"
+const ACTION_SET_VERB_USE = "set_action_verb_use"
+const ACTION_SET_VERB_TALK = "set_action_verb_talk"
+
+"""
+The keyboard shortcuts are chosen to match the geometric layout in the
+9verb UI (example below assumes QWERTY, but implementation should work
+for non-QWERTY, as well):
+
+```
+open | pickup | push -> Q | W | E
+close | look | pull -> A | S | D
+give | use | talk -> Z | X | C
+```
+"""
+
+
+# Implemented as an array of arrays rather than a dict because dict
+# does not have an items() method to enumerate entries together:
+# https://github.com/godotengine/godot-proposals/issues/1965
+const action_to_scancode = [
+ [ACTION_SET_VERB_OPEN, KEY_Q],
+ [ACTION_SET_VERB_PICKUP, KEY_W],
+ [ACTION_SET_VERB_PUSH, KEY_E],
+
+ [ACTION_SET_VERB_CLOSE, KEY_A],
+ [ACTION_SET_VERB_LOOK, KEY_S],
+ [ACTION_SET_VERB_PULL, KEY_D],
+
+ [ACTION_SET_VERB_GIVE, KEY_Z],
+ [ACTION_SET_VERB_USE, KEY_X],
+ [ACTION_SET_VERB_TALK, KEY_C],
+]
+
+
+static func add_actions_to_input_map() -> void:
+ for entry in action_to_scancode:
+ var action = entry[0]
+ var keycode = entry[1]
+ var event = InputEventKey.new()
+ # Based on https://github.com/godotengine/godot/pull/18020,
+ # `physical_scancode` seems like a more appropriate property than
+ # `scancode` in order to support non-QWERTY keyboard layouts while
+ # preserving the geometric pattern of the shortcuts.
+ event.physical_keycode = keycode
+ InputMap.add_action(action)
+ InputMap.action_add_event(action, event)
+
+
+static func erase_actions_from_input_map() -> void:
+ for entry in action_to_scancode:
+ var action = entry[0]
+ InputMap.action_erase_events(action)
+ InputMap.erase_action(action)
diff --git a/addons/escoria-ui-keyboard-9verbs/input_map.gd.uid b/addons/escoria-ui-keyboard-9verbs/input_map.gd.uid
new file mode 100644
index 0000000..9fa83a4
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/input_map.gd.uid
@@ -0,0 +1 @@
+uid://bq3fqtmv6rbiq
diff --git a/addons/escoria-ui-keyboard-9verbs/inventory/inventory_ui.tscn b/addons/escoria-ui-keyboard-9verbs/inventory/inventory_ui.tscn
new file mode 100644
index 0000000..8ade917
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/inventory/inventory_ui.tscn
@@ -0,0 +1,31 @@
+[gd_scene load_steps=3 format=3 uid="uid://b5yss2p8c83cp"]
+
+[ext_resource type="Script" uid="uid://b1l4nnky23hwo" path="res://addons/escoria-core/game/scenes/inventory/inventory_ui.gd" id="1"]
+[ext_resource type="Script" uid="uid://c4syt26p7mg66" path="res://addons/escoria-core/ui_library/inventory/esc_inventory_container.gd" id="3"]
+
+[node name="inventory_ui" type="PanelContainer"]
+offset_right = 600.0
+offset_bottom = 175.0
+script = ExtResource("1")
+__meta__ = {
+"_edit_use_anchors_": false
+}
+inventory_ui_container = NodePath("ScrollContainer/GridContainer")
+
+[node name="ScrollContainer" type="ScrollContainer" parent="."]
+offset_left = 7.0
+offset_top = 7.0
+offset_right = 593.0
+offset_bottom = 168.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+
+[node name="GridContainer" type="GridContainer" parent="ScrollContainer"]
+offset_right = 586.0
+offset_bottom = 161.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+theme_override_constants/v_separation = 16
+theme_override_constants/h_separation = 16
+columns = 4
+script = ExtResource("3")
diff --git a/addons/escoria-ui-keyboard-9verbs/plugin.cfg b/addons/escoria-ui-keyboard-9verbs/plugin.cfg
new file mode 100644
index 0000000..2a005b1
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/plugin.cfg
@@ -0,0 +1,7 @@
+[plugin]
+
+name="Escoria 9 Verbs UI + keyboard"
+description="Classical LucasArts style 9-verbs UI for the Escoria Framework with keyboard control"
+author="Escoria project"
+version="0.1.0"
+script="plugin.gd"
diff --git a/addons/escoria-ui-keyboard-9verbs/plugin.gd b/addons/escoria-ui-keyboard-9verbs/plugin.gd
new file mode 100644
index 0000000..c075745
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/plugin.gd
@@ -0,0 +1,24 @@
+@tool
+# Plugin script to initialize Escoria 9-verbs with keyboard plugin
+extends EditorPlugin
+
+
+# Override function to return the plugin name.
+func _get_plugin_name():
+ return "escoria-ui-keyboard-9verbs"
+
+
+# Deregister UI
+func _disable_plugin() -> void:
+ print("Disabling plugin Escoria UI 9-verbs with keyboard.")
+ EscoriaPlugin.deregister_ui("res://addons/escoria-ui-keyboard-9verbs/game.tscn")
+
+
+# Register UI with Escoria
+func _enable_plugin():
+ print("Enabling plugin Escoria UI 9-verbs with keyboard.")
+ if not EscoriaPlugin.register_ui(self, "res://addons/escoria-ui-keyboard-9verbs/game.tscn"):
+ get_editor_interface().set_plugin_enabled(
+ _get_plugin_name(),
+ false
+ )
diff --git a/addons/escoria-ui-keyboard-9verbs/plugin.gd.uid b/addons/escoria-ui-keyboard-9verbs/plugin.gd.uid
new file mode 100644
index 0000000..c3ac821
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/plugin.gd.uid
@@ -0,0 +1 @@
+uid://nrcailyukdvy
diff --git a/addons/escoria-ui-keyboard-9verbs/theme.tres b/addons/escoria-ui-keyboard-9verbs/theme.tres
new file mode 100644
index 0000000..a01dee5
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/theme.tres
@@ -0,0 +1,6 @@
+[gd_resource type="Theme" load_steps=2 format=3 uid="uid://bcxggcvu105e5"]
+
+[ext_resource type="FontFile" path="res://addons/escoria-ui-keyboard-9verbs/fonts/caslonantique.tres" id="1"]
+
+[resource]
+default_font = ExtResource("1")
diff --git a/addons/escoria-ui-keyboard-9verbs/tooltip/action_target_tooltip.tscn b/addons/escoria-ui-keyboard-9verbs/tooltip/action_target_tooltip.tscn
new file mode 100644
index 0000000..ab5d677
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/tooltip/action_target_tooltip.tscn
@@ -0,0 +1,14 @@
+[gd_scene load_steps=2 format=3 uid="uid://yv8r2xh0jvft"]
+
+[ext_resource type="Script" uid="uid://bxwtb3w78gtbe" path="res://addons/escoria-ui-keyboard-9verbs/tooltip/tooltip_action_target.gd" id="1"]
+
+[node name="tooltip" type="RichTextLabel"]
+anchor_right = 1.0
+anchor_bottom = 1.0
+bbcode_enabled = true
+text = "[center][/center]"
+scroll_active = false
+script = ExtResource("1")
+__meta__ = {
+"_edit_use_anchors_": false
+}
diff --git a/addons/escoria-ui-keyboard-9verbs/tooltip/tooltip_action_target.gd b/addons/escoria-ui-keyboard-9verbs/tooltip/tooltip_action_target.gd
new file mode 100644
index 0000000..8fcd477
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/tooltip/tooltip_action_target.gd
@@ -0,0 +1,34 @@
+extends ESCTooltip
+
+@export var prepositions = {"use": "with", "give": "to"}
+
+func update_tooltip_text():
+ text = "[center]"
+ text += "[color=#" + color.to_html(false) + "]"
+ if !current_action.is_empty():
+ text += current_action + "\t"
+ text += current_target
+
+ if waiting_for_target2 and current_target2.is_empty():
+ current_prep = prepositions.get(current_action, current_prep)
+ text += "\t" + current_prep + " \t"
+
+ if !current_target2.is_empty():
+ text += "\t" + current_prep + " \t" + current_target2
+
+ text += "[/color]"
+ text += "[/center]"
+
+# push_align(RichTextLabel.ALIGN_CENTER)
+# if !current_action.empty():
+# add_text(current_action + "\t")
+#
+# add_text(current_target)
+#
+# if waiting_for_target2 and current_target2.empty():
+# add_text("\t" + current_prep)
+#
+# if !current_target2.empty():
+# add_text("\t" + current_prep + "\t" + current_target2)
+#
+# pop()
diff --git a/addons/escoria-ui-keyboard-9verbs/tooltip/tooltip_action_target.gd.uid b/addons/escoria-ui-keyboard-9verbs/tooltip/tooltip_action_target.gd.uid
new file mode 100644
index 0000000..b715479
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/tooltip/tooltip_action_target.gd.uid
@@ -0,0 +1 @@
+uid://bxwtb3w78gtbe
diff --git a/addons/escoria-ui-keyboard-9verbs/verbs_menu.gd b/addons/escoria-ui-keyboard-9verbs/verbs_menu.gd
new file mode 100644
index 0000000..22c417c
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/verbs_menu.gd
@@ -0,0 +1,32 @@
+extends Control
+
+"""
+This script is out of Escoria's scope. It controls the UI reaction to an
+UI event (eg right click) to change the cursor accordingly.
+"""
+
+var selected_action
+
+func _ready():
+ for but in get_children():
+ but.connect("pressed", Callable(self, "on_action_selected").bind(but.name))
+ but.toggle_mode = true
+
+func on_action_selected(action: String):
+ if escoria.inputs_manager.input_mode != escoria.inputs_manager.INPUT_ALL:
+ unselect_actions()
+ return
+
+ escoria.action_manager.set_current_action(action)
+
+ for but in get_children():
+ but.set_pressed(but.get_name() == action)
+
+func unselect_actions():
+ for but in get_children():
+ but.set_pressed(false)
+
+func set_by_name(action_name: String):
+ selected_action = action_name
+ for but in get_children():
+ but.set_pressed(but.get_name() == action_name)
diff --git a/addons/escoria-ui-keyboard-9verbs/verbs_menu.gd.uid b/addons/escoria-ui-keyboard-9verbs/verbs_menu.gd.uid
new file mode 100644
index 0000000..b1b44f0
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/verbs_menu.gd.uid
@@ -0,0 +1 @@
+uid://bkkwcatncswop
diff --git a/addons/escoria-ui-keyboard-9verbs/verbs_menu.tscn b/addons/escoria-ui-keyboard-9verbs/verbs_menu.tscn
new file mode 100644
index 0000000..07b5885
--- /dev/null
+++ b/addons/escoria-ui-keyboard-9verbs/verbs_menu.tscn
@@ -0,0 +1,125 @@
+[gd_scene load_steps=2 format=3 uid="uid://c7fwywnj0glve"]
+
+[ext_resource type="Script" uid="uid://bkkwcatncswop" path="res://addons/escoria-ui-keyboard-9verbs/verbs_menu.gd" id="1"]
+
+[node name="actions" type="GridContainer"]
+offset_right = 493.0
+offset_bottom = 263.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+columns = 3
+script = ExtResource("1")
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="open" type="Button" parent="."]
+offset_right = 161.0
+offset_bottom = 85.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+toggle_mode = true
+text = "Open"
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="pickup" type="Button" parent="."]
+offset_left = 165.0
+offset_right = 326.0
+offset_bottom = 85.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+toggle_mode = true
+text = "Pick up"
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="push" type="Button" parent="."]
+offset_left = 330.0
+offset_right = 491.0
+offset_bottom = 85.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+toggle_mode = true
+text = "Push"
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="close" type="Button" parent="."]
+offset_top = 89.0
+offset_right = 161.0
+offset_bottom = 174.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+toggle_mode = true
+text = "Close"
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="look" type="Button" parent="."]
+offset_left = 165.0
+offset_top = 89.0
+offset_right = 326.0
+offset_bottom = 174.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+toggle_mode = true
+text = "Look at"
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="pull" type="Button" parent="."]
+offset_left = 330.0
+offset_top = 89.0
+offset_right = 491.0
+offset_bottom = 174.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+toggle_mode = true
+text = "Pull"
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="give" type="Button" parent="."]
+offset_top = 178.0
+offset_right = 161.0
+offset_bottom = 263.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+toggle_mode = true
+text = "Give"
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="use" type="Button" parent="."]
+offset_left = 165.0
+offset_top = 178.0
+offset_right = 326.0
+offset_bottom = 263.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+toggle_mode = true
+text = "Use"
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="talk" type="Button" parent="."]
+offset_left = 330.0
+offset_top = 178.0
+offset_right = 491.0
+offset_bottom = 263.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+toggle_mode = true
+text = "Talk"
+__meta__ = {
+"_edit_use_anchors_": false
+}