Fix when ESCPlayer is not selectable or interactive manage click through
This commit is contained in:
@@ -100,7 +100,17 @@ func run(command_params: Array) -> int:
|
||||
"[%s]: No dialog player was registered and the say command was encountered."
|
||||
% get_command_name()
|
||||
)
|
||||
escoria.current_state = escoria.GAME_STATE.DEFAULT
|
||||
return ESCExecution.RC_ERROR
|
||||
|
||||
if not escoria.main.current_scene.player:
|
||||
escoria.logger.warn(
|
||||
self,
|
||||
"[%s]: No player item in the current scene was registered and the say command was encountered."
|
||||
% get_command_name()
|
||||
)
|
||||
escoria.current_state = escoria.GAME_STATE.DEFAULT
|
||||
return ESCExecution.RC_CANCEL
|
||||
|
||||
# Replace the names of any globals in "{ }" with their value
|
||||
command_params[1] = escoria.globals_manager.replace_globals(command_params[1])
|
||||
|
||||
@@ -748,13 +748,13 @@ func _is_object_actionable(obj: ESCObject) -> bool:
|
||||
return false
|
||||
|
||||
if not obj.active:
|
||||
escoria.logger.debug(
|
||||
escoria.logger.trace(
|
||||
self,
|
||||
"Item %s is not active." % obj.global_id
|
||||
)
|
||||
object_is_actionable = false
|
||||
elif not obj.interactive:
|
||||
escoria.logger.debug(
|
||||
escoria.logger.trace(
|
||||
self,
|
||||
"Item %s is not interactive." % obj.global_id
|
||||
)
|
||||
|
||||
@@ -89,7 +89,7 @@ func change_scene(room_path: String, enable_automatic_transitions: bool) -> void
|
||||
if escoria.dialog_player:
|
||||
escoria.dialog_player.interrupt()
|
||||
|
||||
escoria.inputs_manager.clear_stack()
|
||||
escoria.inputs_manager.hover_stack_clear()
|
||||
|
||||
# Check if game scene was loaded
|
||||
if not escoria.game_scene:
|
||||
|
||||
@@ -97,6 +97,9 @@ func _get_interactive() -> bool:
|
||||
func _set_interactive(value: bool):
|
||||
if "is_interactive" in self.node:
|
||||
self.node.is_interactive = value
|
||||
if not value:
|
||||
escoria.game_scene.clear_tooltip()
|
||||
escoria.inputs_manager.on_item_non_interactive(self.node)
|
||||
|
||||
|
||||
# Return the data of the object to be inserted in a savegame file.
|
||||
|
||||
@@ -111,6 +111,12 @@ func _draw():
|
||||
draw_rect(mouse_limits, ColorN("red"), false, 10.0)
|
||||
|
||||
|
||||
# Clears the tooltip content (if an ESCTooltip node exists in UI)
|
||||
func clear_tooltip():
|
||||
if tooltip_node != null:
|
||||
(tooltip_node as ESCTooltip).clear()
|
||||
|
||||
|
||||
# Sets up and performs default walking action
|
||||
#
|
||||
# #### Parameters
|
||||
|
||||
@@ -188,8 +188,8 @@ func _ready():
|
||||
|
||||
validate_animations(animations)
|
||||
|
||||
if not self.is_connected("mouse_entered", self, "_on_mouse_entered"):
|
||||
connect("mouse_entered", self, "_on_mouse_entered")
|
||||
if not self.is_connected("input_event", self, "_on_input_event"):
|
||||
connect("input_event", self, "_on_input_event")
|
||||
if not self.is_connected("mouse_exited", self, "_on_mouse_exited"):
|
||||
connect("mouse_exited", self, "_on_mouse_exited")
|
||||
|
||||
@@ -294,6 +294,47 @@ func _ready():
|
||||
_movable.last_scale = scale
|
||||
_movable.update_terrain()
|
||||
|
||||
|
||||
# Mouse exited happens on any item that mouse cursor exited, even those UNDER
|
||||
# the top level of overlapping stack.
|
||||
func _on_mouse_exited():
|
||||
if escoria.inputs_manager.hover_stack.has(self):
|
||||
escoria.inputs_manager.hover_stack_erase_item(self)
|
||||
escoria.inputs_manager.unset_hovered_node(self)
|
||||
|
||||
|
||||
class HoverStackSorter:
|
||||
static func sort_ascending_z_index(a, b):
|
||||
if a.z_index < b.z_index:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
# Manage input events on the item
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - _viewport: the viewport node the event entered
|
||||
# - event: the input event
|
||||
# - _shape_idx is the child index of the clicked Shape2D.
|
||||
func _on_input_event(_viewport: Object, event: InputEvent, _shape_idx: int):
|
||||
if event is InputEventMouseMotion:
|
||||
var physics2d_dss: Physics2DDirectSpaceState = get_world_2d().direct_space_state
|
||||
var colliding: Array = physics2d_dss.intersect_point(event.global_position, 32, [], 0x7FFFFFFF, true, true)
|
||||
var colliding_nodes = []
|
||||
for c in colliding:
|
||||
if c.collider.get("global_id") \
|
||||
and escoria.action_manager.is_object_actionable(c.collider.global_id):
|
||||
colliding_nodes.push_back(c.collider)
|
||||
|
||||
if colliding_nodes.empty():
|
||||
return
|
||||
colliding_nodes.sort_custom(HoverStackSorter, "sort_ascending_z_index")
|
||||
escoria.inputs_manager.hover_stack_clear()
|
||||
escoria.inputs_manager.hover_stack_add_items(colliding_nodes)
|
||||
escoria.inputs_manager.set_hovered_node(colliding_nodes.back())
|
||||
|
||||
|
||||
# Manage mouse button clicks on this item by sending out signals
|
||||
#
|
||||
# #### Parameters
|
||||
@@ -334,7 +375,7 @@ func _unhandled_input(input_event: InputEvent) -> void:
|
||||
)
|
||||
return
|
||||
var p = get_global_mouse_position()
|
||||
if _is_in_shape(p):
|
||||
if _is_in_shape(p) and escoria.action_manager.is_object_actionable(global_id):
|
||||
if event.doubleclick and event.button_index == BUTTON_LEFT:
|
||||
emit_signal("mouse_double_left_clicked_item", self, event)
|
||||
get_tree().set_input_as_handled()
|
||||
@@ -472,12 +513,13 @@ func get_interact_position() -> Vector2:
|
||||
|
||||
|
||||
# React to the mouse entering the item by emitting the respective signal
|
||||
func _on_mouse_entered():
|
||||
emit_signal("mouse_entered_item", self)
|
||||
func mouse_entered():
|
||||
if escoria.action_manager.is_object_actionable(global_id):
|
||||
emit_signal("mouse_entered_item", self)
|
||||
|
||||
|
||||
# React to the mouse exiting the item by emitting the respective signal
|
||||
func _on_mouse_exited():
|
||||
func mouse_exited():
|
||||
emit_signal("mouse_exited_item", self)
|
||||
|
||||
|
||||
|
||||
@@ -22,5 +22,3 @@ func _ready():
|
||||
._ready()
|
||||
else:
|
||||
tooltip_name = ""
|
||||
if is_connected("input_event", self, "manage_input"):
|
||||
disconnect("input_event", self, "manage_input")
|
||||
|
||||
@@ -48,6 +48,27 @@ var hotspot_focused: String = ""
|
||||
# **Returns** Whether the function processed the event.
|
||||
var custom_input_handler = null
|
||||
|
||||
# The currently hovered element. Usually the one on top of the hover stack.
|
||||
var _hovered_element = null
|
||||
|
||||
|
||||
# Constructor
|
||||
func _init():
|
||||
escoria.event_manager.connect("event_finished", self, "_on_event_finished")
|
||||
|
||||
|
||||
# Called when an event is finished, so that the current hotspot is reset
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - return_code: The return code of the event
|
||||
# - event_name: the name of the event
|
||||
#
|
||||
func _on_event_finished(return_code: int, event_name: String):
|
||||
if _hovered_element == null:
|
||||
hotspot_focused = ""
|
||||
|
||||
|
||||
# Register core signals (from escoria.gd)
|
||||
func register_core():
|
||||
escoria.game_scene.connect(
|
||||
@@ -154,9 +175,44 @@ func try_custom_input_handler(event: InputEvent, is_default_state: bool) -> bool
|
||||
return false
|
||||
|
||||
|
||||
# Clear the stack of hovered items
|
||||
func clear_stack():
|
||||
hover_stack = []
|
||||
|
||||
# Unsets the hovered node.
|
||||
#
|
||||
# **Parameters**
|
||||
#
|
||||
# - item: the item that was unfocused (mouse_exited)
|
||||
func unset_hovered_node(item: ESCItem):
|
||||
if _hovered_element == item:
|
||||
_hovered_element.mouse_exited()
|
||||
_hovered_element = null
|
||||
hotspot_focused = ""
|
||||
|
||||
|
||||
# Sets the hovered node and calls its mouse_entered() method if it was the top
|
||||
# most item in hover_stack.
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - item: the item that was focused (mouse_entered)
|
||||
#
|
||||
# **Returns**
|
||||
# True if item is the new top hovered object
|
||||
func set_hovered_node(item: ESCItem) -> bool:
|
||||
# If tested item was already hovered
|
||||
# or is not actionable (not selectable for ESCPlayer) then do nothing
|
||||
if _hovered_element == item \
|
||||
or not escoria.action_manager.is_object_actionable(item.global_id) \
|
||||
or (item is ESCPlayer and not (item as ESCPlayer).selectable):
|
||||
return true
|
||||
# Else if the tested item is on top of hover stack (or null)
|
||||
# Set that item as hovered and call that item's mouse_entered()
|
||||
if _hovered_element == null or hover_stack.back() != item:
|
||||
_hovered_element = item
|
||||
_hovered_element.mouse_entered()
|
||||
return true
|
||||
# Else, the tested item is currently on top of hover stack, then do nothing
|
||||
else:
|
||||
return false
|
||||
|
||||
|
||||
# The background was clicked with the LMB
|
||||
@@ -165,7 +221,8 @@ func clear_stack():
|
||||
#
|
||||
# - position: Position of the click
|
||||
func _on_left_click_on_bg(position: Vector2) -> void:
|
||||
if input_mode == INPUT_ALL and hotspot_focused.empty():
|
||||
if input_mode == INPUT_ALL: # and hotspot_focused.empty():
|
||||
hotspot_focused = ""
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"Left click on background at %s." % str(position)
|
||||
@@ -179,7 +236,8 @@ func _on_left_click_on_bg(position: Vector2) -> void:
|
||||
#
|
||||
# - position: Position of the click
|
||||
func _on_double_left_click_on_bg(position: Vector2) -> void:
|
||||
if input_mode == INPUT_ALL and hotspot_focused.empty():
|
||||
if input_mode == INPUT_ALL: # and hotspot_focused.empty():
|
||||
hotspot_focused = ""
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"Double left click on background at %s." % str(position)
|
||||
@@ -295,31 +353,32 @@ func _on_mouse_exited_inventory_item() -> void:
|
||||
# - item: The Escoria item hovered
|
||||
func _on_mouse_entered_item(item: ESCItem) -> void:
|
||||
if item as ESCPlayer and not (item as ESCPlayer).selectable:
|
||||
escoria.logger.debug(
|
||||
self,
|
||||
"Ignoring mouse entering player %s: Player not selectable." % [item.global_id]
|
||||
)
|
||||
return
|
||||
|
||||
escoria.logger.trace(
|
||||
self,
|
||||
"Ignoring mouse entering player %s: Player not selectable." % [item.global_id]
|
||||
)
|
||||
if hover_stack.empty():
|
||||
hotspot_focused = ""
|
||||
escoria.main.current_scene.game.element_unfocused()
|
||||
else:
|
||||
hotspot_focused = hover_stack.back().global_id
|
||||
escoria.main.current_scene.game.element_focused(hotspot_focused)
|
||||
return
|
||||
|
||||
if not escoria.action_manager.is_object_actionable(item.global_id):
|
||||
escoria.logger.debug(
|
||||
self,
|
||||
"Ignoring mouse entering item %s." % [item.global_id]
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"Item focused: %s" % item.global_id
|
||||
)
|
||||
_clean_hover_stack()
|
||||
|
||||
hover_stack.push_back(item)
|
||||
hover_stack.sort_custom(HoverStackSorter, "sort_ascending_z_index")
|
||||
|
||||
hotspot_focused = hover_stack.back().global_id
|
||||
escoria.main.current_scene.game.element_focused(hotspot_focused)
|
||||
hotspot_focused = item.global_id
|
||||
escoria.main.current_scene.game.element_focused(item.global_id)
|
||||
|
||||
|
||||
# The mouse exited an Escoria item
|
||||
@@ -328,11 +387,23 @@ func _on_mouse_entered_item(item: ESCItem) -> void:
|
||||
#
|
||||
# - item: The Escoria item hovered
|
||||
func _on_mouse_exited_item(item: ESCItem) -> void:
|
||||
var object: ESCObject = escoria.object_manager.get_object(item.global_id)
|
||||
if object and not object.interactive:
|
||||
hover_stack_erase_item(item)
|
||||
escoria.main.current_scene.game.element_unfocused()
|
||||
return
|
||||
|
||||
if object and not object.interactive:
|
||||
return
|
||||
if object and object.node is ESCPlayer and not (object.node as ESCPlayer).selectable:
|
||||
hotspot_focused = ""
|
||||
return
|
||||
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"Item unfocused: %s" % item.global_id
|
||||
"Item unfocused: %s" % hotspot_focused
|
||||
)
|
||||
_hover_stack_erase_item(item)
|
||||
|
||||
if hover_stack.empty():
|
||||
hotspot_focused = ""
|
||||
escoria.main.current_scene.game.element_unfocused()
|
||||
@@ -341,6 +412,25 @@ func _on_mouse_exited_item(item: ESCItem) -> void:
|
||||
escoria.main.current_scene.game.element_focused(hotspot_focused)
|
||||
|
||||
|
||||
# Function called when the item is set interactive, to re-trigger an input on
|
||||
# underlying item.
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - item: The ESCCItem that was set non-interactive
|
||||
func on_item_non_interactive(item: ESCItem) -> void:
|
||||
var object: ESCObject = escoria.object_manager.get_object(item.global_id)
|
||||
if object and not object.interactive:
|
||||
hover_stack_erase_item(item)
|
||||
escoria.main.current_scene.game.element_unfocused()
|
||||
hover_stack.sort_custom(HoverStackSorter, "sort_ascending_z_index")
|
||||
if hover_stack.empty():
|
||||
return
|
||||
else:
|
||||
var new_item = hover_stack.back()
|
||||
escoria.action_manager.set_action_input_state(ESCActionManager.ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM)
|
||||
new_item.mouse_entered()
|
||||
|
||||
# An Escoria item was clicked with the LMB
|
||||
#
|
||||
# #### Parameters
|
||||
@@ -349,39 +439,37 @@ func _on_mouse_exited_item(item: ESCItem) -> void:
|
||||
# - event: The input event from the click
|
||||
func _on_mouse_left_clicked_item(item: ESCItem, event: InputEvent) -> void:
|
||||
if input_mode == INPUT_ALL:
|
||||
# Manage clicking through ESCPlayer (if ESCPlayer.selectable is false)
|
||||
if item as ESCPlayer and not (item as ESCPlayer).selectable:
|
||||
escoria.logger.debug(
|
||||
escoria.logger.trace(
|
||||
self,
|
||||
"Ignoring left click on player %s: Player not selectable." % [item.global_id]
|
||||
"Ignoring left click on player %s: Player not selectable."
|
||||
% [item.global_id]
|
||||
)
|
||||
|
||||
|
||||
# Get next object in hover stack and forward event to it
|
||||
if not hover_stack.empty():
|
||||
var next_item = hover_stack.pop_back()
|
||||
_on_mouse_left_clicked_item(next_item, event)
|
||||
|
||||
else: # if no next object, consider this click as background click
|
||||
hotspot_focused = ""
|
||||
_on_left_click_on_bg(event.position)
|
||||
return
|
||||
|
||||
if not escoria.action_manager.is_object_actionable(item.global_id):
|
||||
escoria.logger.debug(
|
||||
self,
|
||||
"Ignoring left click on %s with event %s." % [item.global_id, event]
|
||||
)
|
||||
|
||||
# Treat this as a background click now
|
||||
# Clicked object can't be actioned and there is no other object behind
|
||||
# We consider this click as a background click
|
||||
if not escoria.action_manager.is_object_actionable(item.global_id) \
|
||||
and hover_stack.empty():
|
||||
hotspot_focused = ""
|
||||
_on_left_click_on_bg(event.position)
|
||||
|
||||
return
|
||||
|
||||
if hover_stack.empty() or hover_stack.back() == item:
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"Item %s left clicked with event %s." % [item.global_id, event]
|
||||
)
|
||||
hotspot_focused = item.global_id
|
||||
escoria.main.current_scene.game.left_click_on_item(
|
||||
item.global_id,
|
||||
event
|
||||
)
|
||||
|
||||
# Finally, execute the action on the ESCItem
|
||||
hotspot_focused = item.global_id
|
||||
escoria.main.current_scene.game.left_click_on_item(
|
||||
item.global_id,
|
||||
event
|
||||
)
|
||||
|
||||
|
||||
# An Escoria item was double-clicked with the LMB
|
||||
@@ -395,33 +483,32 @@ func _on_mouse_left_double_clicked_item(
|
||||
event: InputEvent
|
||||
) -> void:
|
||||
if input_mode == INPUT_ALL:
|
||||
# Manage clicking through ESCPlayer (if ESCPlayer.selectable is false)
|
||||
if item as ESCPlayer and not (item as ESCPlayer).selectable:
|
||||
escoria.logger.debug(
|
||||
escoria.logger.trace(
|
||||
self,
|
||||
"Ignoring double-left click on player %s: Player not selectable." % [item.global_id]
|
||||
"Ignoring double left click on player %s: Player not selectable."
|
||||
% [item.global_id]
|
||||
)
|
||||
|
||||
|
||||
# Get next object in hover stack and forward event to it
|
||||
if not hover_stack.empty():
|
||||
var next_item = hover_stack.pop_back()
|
||||
_on_mouse_left_double_clicked_item(next_item, event)
|
||||
|
||||
else: # if no next object, consider this click as background click
|
||||
hotspot_focused = ""
|
||||
_on_double_left_click_on_bg(event.position)
|
||||
return
|
||||
|
||||
if not escoria.action_manager.is_object_actionable(item.global_id):
|
||||
escoria.logger.debug(
|
||||
self,
|
||||
"Ignoring double-left click on %s with event %s." % [item.global_id, event]
|
||||
)
|
||||
|
||||
# Treat this as a background click now
|
||||
# Clicked object can't be actioned and there is no other object behind
|
||||
# We consider this click as a background click
|
||||
if not escoria.action_manager.is_object_actionable(item.global_id) \
|
||||
and hover_stack.empty():
|
||||
hotspot_focused = ""
|
||||
_on_double_left_click_on_bg(event.position)
|
||||
|
||||
return
|
||||
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"Item %s left double clicked with event %s." % [item.global_id, event]
|
||||
)
|
||||
|
||||
# Finally, execute the action on the ESCItem
|
||||
hotspot_focused = item.global_id
|
||||
escoria.main.current_scene.game.left_double_click_on_item(
|
||||
item.global_id,
|
||||
@@ -446,29 +533,46 @@ func _on_mouse_right_clicked_item(item: ESCItem, event: InputEvent) -> void:
|
||||
if not hover_stack.empty():
|
||||
var next_item = hover_stack.pop_back()
|
||||
_on_mouse_right_clicked_item(next_item, event)
|
||||
|
||||
return
|
||||
|
||||
if not escoria.action_manager.is_object_actionable(item.global_id):
|
||||
escoria.logger.debug(
|
||||
if not escoria.action_manager.is_object_actionable(item.global_id) \
|
||||
and hover_stack.empty():
|
||||
# Treat this as a background click now
|
||||
hotspot_focused = ""
|
||||
_on_right_click_on_bg(event.position)
|
||||
return
|
||||
|
||||
var actual_item
|
||||
|
||||
# We check if the clicked object is ESCPlayer and not selectable. If so
|
||||
# we consider we clicked through it.
|
||||
var object: ESCObject = escoria.object_manager.get_object(item.global_id)
|
||||
if object.node is ESCPlayer and not (object.node as ESCPlayer).selectable:
|
||||
actual_item = hover_stack.back()
|
||||
else:
|
||||
actual_item = item
|
||||
|
||||
if actual_item == null:
|
||||
if event.position:
|
||||
(escoria.main.current_scene.game as ESCGame).right_click_on_bg(event.position)
|
||||
else:
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"Clicked item %s with event %s cannot be activated (player not selectable or not interactive).\n"
|
||||
% [item.global_id, event] +
|
||||
"No valid item found in the items stack. Action cancelled."
|
||||
)
|
||||
else:
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"Ignoring right click on %s with event %s." % [item.global_id, event]
|
||||
"Item %s right clicked with event %s." % [actual_item.global_id, event]
|
||||
)
|
||||
hotspot_focused = actual_item.global_id
|
||||
escoria.main.current_scene.game.right_click_on_item(
|
||||
actual_item.global_id,
|
||||
event
|
||||
)
|
||||
|
||||
# Treat this as a background click now
|
||||
_on_right_click_on_bg(event.position)
|
||||
|
||||
return
|
||||
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"Item %s right clicked with event %s." % [item.global_id, event]
|
||||
)
|
||||
hotspot_focused = item.global_id
|
||||
escoria.main.current_scene.game.right_click_on_item(
|
||||
item.global_id,
|
||||
event
|
||||
)
|
||||
|
||||
|
||||
# The mousewheel was turned
|
||||
@@ -485,6 +589,27 @@ func _on_pause_menu_requested():
|
||||
escoria.main.current_scene.game.pause_game()
|
||||
|
||||
|
||||
# Add the given item to the stack if not already in it.
|
||||
#
|
||||
# #### Parameters
|
||||
# - item: the item to add to the hover stack
|
||||
func hover_stack_add_item(item):
|
||||
if item is ESCPlayer and not (item as ESCPlayer).selectable:
|
||||
return
|
||||
if not hover_stack.has(item):
|
||||
hover_stack.push_back(item)
|
||||
hover_stack.sort_custom(HoverStackSorter, "sort_ascending_z_index")
|
||||
|
||||
|
||||
# Add the items contained in given list to the stack if not already in it.
|
||||
#
|
||||
# #### Parameters
|
||||
# - items: the items list (array) to add to the hover stack
|
||||
func hover_stack_add_items(items: Array):
|
||||
for item in items:
|
||||
hover_stack_add_item(item)
|
||||
|
||||
|
||||
# Clean the hover stack
|
||||
func _clean_hover_stack():
|
||||
for e in hover_stack:
|
||||
@@ -496,8 +621,14 @@ func _clean_hover_stack():
|
||||
#
|
||||
# #### Parameters
|
||||
# - item: the item to remove from the hover stack
|
||||
func _hover_stack_erase_item(item):
|
||||
func hover_stack_erase_item(item):
|
||||
hover_stack.erase(item)
|
||||
hover_stack.sort_custom(HoverStackSorter, "sort_ascending_z_index")
|
||||
|
||||
|
||||
# Clear the stack of hovered items
|
||||
func hover_stack_clear():
|
||||
hover_stack = []
|
||||
|
||||
|
||||
class HoverStackSorter:
|
||||
|
||||
Reference in New Issue
Block a user