Files
gymkhana-actions/addons/escoria-ui-simplemouse/game.gd
2023-06-06 19:28:49 +02:00

409 lines
12 KiB
GDScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends ESCGame
const VERB_USE = "use"
const VERB_WALK = "walk"
"""
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)
"""
# Value to use for `device` argument to various `Input.get_joy` methods.
const JOY_DEVICE = 0
# See https://docs.godotengine.org/en/stable/tutorials/inputs/controllers_gamepads_joysticks.html?#dead-zone
const DEADZONE = 0.2
# Multiplier to apply to axis when it exceeds DEADZONE.
const AXIS_WEIGHT = 50.0
# JOY_BUTTON_2 corresponds to the "X" button on an XBox controller
# or the Square button on a Playstation controller. These appear to
# map to the "primary action," in practice, so we treat it like a left click.
const PRIMARY_ACTION_BUTTON = JOY_BUTTON_2
# JOY_BUTTON_3 corresponds to the "Y" button on an XBox controller
# or the Triangle button on a Playstation controller. These appear to
# map to the "secondary action," in practice, so we treat it like a right click.
const CHANGE_VERB_BUTTON = JOY_BUTTON_3
# Input action for use by InputMap
const ESC_UI_CHANGE_VERB_ACTION = "esc_change_verb"
# true when a gamepad is connected.
var _is_gamepad_connected = false
# Tracks the mouse's current position onscreen.
var _current_mouse_pos = Vector2.ZERO
func _ready():
$tooltip_layer/tooltip.connect("tooltip_size_updated", self, "update_tooltip_following_mouse_position")
func _enter_tree():
var room_selector_parent = $CanvasLayer/ui/HBoxContainer/VBoxContainer
if ESCProjectSettingsManager.get_setting(ESCProjectSettingsManager.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"
).instance()
)
var input_handler = funcref(self, "_process_input")
escoria.inputs_manager.register_custom_input_handler(input_handler)
_is_gamepad_connected = Input.is_joy_known(JOY_DEVICE)
if _is_gamepad_connected:
_on_gamepad_connected()
Input.connect("joy_connection_changed", self, "_on_joy_connection_changed")
func _exit_tree():
escoria.inputs_manager.register_custom_input_handler(null)
Input.disconnect("joy_connection_changed", self, "_on_joy_connection_changed")
if _is_gamepad_connected:
_on_gamepad_disconnected()
func _input(event: InputEvent) -> void:
if escoria.get_escoria().is_ready_for_inputs():
if event is InputEventMouseMotion:
_current_mouse_pos = get_global_mouse_position()
update_tooltip_following_mouse_position()
# https://github.com/godotengine/godot-demo-projects/blob/3.4-585455e/misc/joypads/joypads.gd
# was informative in wiring up the gamepad properly.
func _on_gamepad_connected():
set_physics_process(true)
var primary_event = InputEventJoypadButton.new()
primary_event.button_index = PRIMARY_ACTION_BUTTON
InputMap.add_action(escoria.inputs_manager.ESC_UI_PRIMARY_ACTION)
InputMap.action_add_event(escoria.inputs_manager.ESC_UI_PRIMARY_ACTION, primary_event)
var verb_event = InputEventJoypadButton.new()
verb_event.button_index = CHANGE_VERB_BUTTON
InputMap.add_action(ESC_UI_CHANGE_VERB_ACTION)
InputMap.action_add_event(ESC_UI_CHANGE_VERB_ACTION, verb_event)
func _on_gamepad_disconnected():
InputMap.action_erase_events(escoria.inputs_manager.ESC_UI_PRIMARY_ACTION)
InputMap.erase_action(escoria.inputs_manager.ESC_UI_PRIMARY_ACTION)
InputMap.action_erase_events(ESC_UI_CHANGE_VERB_ACTION)
InputMap.erase_action(ESC_UI_CHANGE_VERB_ACTION)
set_physics_process(false)
_is_gamepad_connected = false
func _on_joy_connection_changed(device: int, connected: bool) -> void:
if device != JOY_DEVICE:
return
elif connected:
_on_gamepad_connected()
else:
_on_gamepad_disconnected()
func _process(_delta) -> void:
if !_is_gamepad_connected:
return
var x = Input.get_joy_axis(JOY_DEVICE, JOY_AXIS_0)
var y = Input.get_joy_axis(JOY_DEVICE, JOY_AXIS_1)
var delta_x = int(x * AXIS_WEIGHT) if abs(x) > DEADZONE else 0
var delta_y = int(y * AXIS_WEIGHT) if abs(y) > DEADZONE else 0
if delta_x or delta_y:
var direction: Vector2
direction.x = delta_x
direction.y = delta_y
escoria.logger.trace("gamepad direction:", [direction])
var viewport = get_viewport()
viewport.warp_mouse(viewport.get_mouse_position() + direction)
func _process_input(event: InputEvent, is_default_state: bool) -> bool:
if not is_default_state:
# ESCBackground is not guaranteed to be set, as we may be on
# the "New Game" screen.
return false
elif _is_gamepad_connected and event is InputEventJoypadButton:
escoria.logger.trace("InputEventJoypadButton:", [event.as_text()])
if event.is_action_pressed(escoria.inputs_manager.ESC_UI_PRIMARY_ACTION):
# Admittedly, this breaks abstraction barriers and is completely
# inappropriate, but it's what works right now.
escoria.inputs_manager._on_left_click_on_bg(get_global_mouse_position())
return true
elif event.is_action_pressed(ESC_UI_CHANGE_VERB_ACTION):
mousewheel_action(1)
return true
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
)
$mouse_layer/verbs_menu.set_by_name(VERB_WALK)
$mouse_layer/verbs_menu.clear_tool_texture()
func right_click_on_bg(position: Vector2) -> void:
mousewheel_action(1)
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
)
$mouse_layer/verbs_menu.set_by_name(VERB_WALK)
$mouse_layer/verbs_menu.clear_tool_texture()
## ITEM/HOTSPOT FOCUS ##
func element_focused(element_id: String) -> void:
var target_obj = escoria.object_manager.get_object(element_id).node
$tooltip_layer/tooltip.set_target(target_obj.tooltip_name)
if escoria.action_manager.current_action != VERB_USE \
and escoria.action_manager.current_tool == null \
and target_obj is ESCItem:
$mouse_layer/verbs_menu.set_by_name(
target_obj.default_action
)
func element_unfocused() -> void:
$tooltip_layer/tooltip.set_target("")
## ITEMS ##
func left_click_on_item(item_global_id: String, event: InputEvent) -> void:
var target_obj = escoria.object_manager.get_object(item_global_id).node
# current_action will be empty if an event completes between when you stop
# moving the mouse and when you click.
if escoria.action_manager.current_action == "":
if target_obj is ESCItem:
$mouse_layer/verbs_menu.set_by_name(
target_obj.default_action
)
escoria.action_manager.do(
escoria.action_manager.ACTION.ITEM_LEFT_CLICK,
[item_global_id, event],
true
)
$mouse_layer/verbs_menu.clear_tool_texture()
func right_click_on_item(item_global_id: String, event: InputEvent) -> void:
mousewheel_action(1)
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]
)
if escoria.action_manager.current_action == VERB_USE:
var item = escoria.object_manager.get_object(
inventory_item_global_id
).node
if item.has_method("get_sprite") and item.get_sprite().texture:
$mouse_layer/verbs_menu.set_tool_texture(
item.get_sprite().texture
)
elif item.inventory_item.texture_normal:
$mouse_layer/verbs_menu.set_tool_texture(
item.inventory_item.texture_normal
)
func right_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent) -> void:
mousewheel_action(1)
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:
$tooltip_layer/tooltip.set_target(
escoria.object_manager.get_object(
inventory_item_global_id
).node.tooltip_name
)
func inventory_item_unfocused() -> void:
$tooltip_layer/tooltip.set_target("")
func open_inventory():
$CanvasLayer/ui/HBoxContainer/inventory_ui.show_inventory()
func close_inventory():
$CanvasLayer/ui/HBoxContainer/inventory_ui.hide_inventory()
func mousewheel_action(direction: int):
$mouse_layer/verbs_menu.iterate_actions_cursor(direction)
func hide_ui():
$CanvasLayer/ui/HBoxContainer/inventory_ui.hide()
$CanvasLayer/ui.hide()
func show_ui():
$CanvasLayer/ui/HBoxContainer/inventory_ui.show()
$CanvasLayer/ui.show()
func hide_main_menu():
if get_node(main_menu).visible:
get_node(main_menu).hide()
func show_main_menu():
if not get_node(main_menu).visible:
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()
func pause_game():
if not get_node(pause_menu).visible:
get_node(main_menu).reset()
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()
func apply_custom_settings(custom_settings: Dictionary):
if custom_settings.has("a_custom_setting"):
escoria.logger.info(
self,
"custom setting value loaded: %s."
% str(custom_settings["a_custom_setting"])
)
func get_custom_data() -> Dictionary:
return {
"ui_type": "simplemouse"
}
# Update the tooltip
func update_tooltip_following_mouse_position():
var corrected_position = _current_mouse_pos \
- Vector2(
tooltip_node.rect_size.x / 2,
tooltip_node.rect_size.y / 2
)
# clamp TOP
if tooltip_node.tooltip_distance_to_edge_top(_current_mouse_pos) <= mouse_tooltip_margin:
corrected_position.y = mouse_tooltip_margin
# clamp BOTTOM
if tooltip_node.tooltip_distance_to_edge_bottom(_current_mouse_pos + tooltip_node.rect_size) <= mouse_tooltip_margin:
corrected_position.y = escoria.game_size.y - mouse_tooltip_margin - tooltip_node.rect_size.y
# clamp LEFT
if tooltip_node.tooltip_distance_to_edge_left(_current_mouse_pos - tooltip_node.rect_size/2) <= mouse_tooltip_margin:
corrected_position.x = mouse_tooltip_margin
# clamp RIGHT
if tooltip_node.tooltip_distance_to_edge_right(_current_mouse_pos + tooltip_node.rect_size/2) <= mouse_tooltip_margin:
corrected_position.x = escoria.game_size.x - mouse_tooltip_margin - tooltip_node.rect_size.x
tooltip_node.rect_position = corrected_position + tooltip_node.offset_from_cursor
func _on_action_finished():
$mouse_layer/verbs_menu.clear_tool_texture()
$mouse_layer/verbs_menu.iterate_actions_cursor(0)
func _on_event_done(_return_code: int, _event_name: String):
if _return_code == ESCExecution.RC_OK:
escoria.action_manager.clear_current_action()
$tooltip_layer/tooltip.set_target("")
func _on_MenuButton_pressed() -> void:
pause_game()