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()