MODIFIED escoria.gdgit add . Action manager extended to apply needed changes for monkey UI
This commit is contained in:
@@ -0,0 +1,364 @@
|
||||
# Manages currently carried out actions
|
||||
# MODIFIED FOR RETURN TO MONKEY UI
|
||||
extends ESCActionManager
|
||||
class_name ESCActionManagerMonkey
|
||||
|
||||
# Set the current action verb
|
||||
#
|
||||
# ## Parameters
|
||||
# - action: The action verb to set
|
||||
func set_current_action(action: String):
|
||||
# MODIFIED FOR RETURN TO MONKEY UI
|
||||
if (action != current_action) && (action_state != ACTION_INPUT_STATE.AWAITING_TARGET_ITEM):
|
||||
clear_current_tool()
|
||||
|
||||
current_action = action
|
||||
|
||||
if action_state == ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM:
|
||||
set_action_input_state(ACTION_INPUT_STATE.AWAITING_ITEM)
|
||||
elif action_state == ACTION_INPUT_STATE.AWAITING_VERB:
|
||||
set_action_input_state(ACTION_INPUT_STATE.AWAITING_VERB_CONFIRM)
|
||||
|
||||
emit_signal("action_changed")
|
||||
|
||||
|
||||
# Checks if the specified action is valid and returns the associated event;
|
||||
# otherwise, we see if there's a "fallback" event and use that if necessary and,
|
||||
# if not, we return no event as there's nothing to do.
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - action: Action to execute (defined in attached ESC file and in
|
||||
# action verbs UI) eg: arrived, use, look, pickup...
|
||||
# - target: Target ESC object
|
||||
# - combine_with: ESC object to combine with
|
||||
#
|
||||
# *Returns* the appropriate ESCEvent to queue/run, or null if none can be found
|
||||
# or there's a reason not to run an event.
|
||||
func _get_event_to_queue(
|
||||
action: String,
|
||||
target: ESCObject,
|
||||
combine_with: ESCObject = null
|
||||
) -> ESCEvent:
|
||||
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"Checking if action '%s' on '%s' is valid..." % [action, target]
|
||||
)
|
||||
|
||||
var event_to_return: ESCEvent = null
|
||||
|
||||
# If we're using an action which item requires to combine
|
||||
if target.node is ESCItem \
|
||||
and (action in target.node.combine_when_selected_action_is_in
|
||||
# MODIFIED FOR RETURN TO MONKEY UI
|
||||
or (combine_with && action in combine_with.node.combine_when_selected_action_is_in)):
|
||||
|
||||
# Check if object must be in inventory to be used
|
||||
if target.node.use_from_inventory_only:
|
||||
if escoria.inventory_manager.inventory_has(target.global_id):
|
||||
# Player has item in inventory, we check the element to use on
|
||||
if combine_with:
|
||||
var do_combine = true
|
||||
if combine_with.node is ESCItem \
|
||||
and combine_with.node.use_from_inventory_only\
|
||||
and not escoria.inventory_manager.inventory_has(
|
||||
combine_with.global_id
|
||||
):
|
||||
do_combine = false
|
||||
|
||||
if do_combine:
|
||||
var target_event = "%s %s" % [
|
||||
action,
|
||||
combine_with.global_id
|
||||
]
|
||||
var combine_with_event = "%s %s" % [
|
||||
action,
|
||||
target.global_id
|
||||
]
|
||||
|
||||
if target.events.has(target_event):
|
||||
event_to_return = target.events[target_event]
|
||||
elif combine_with.events.has(combine_with_event)\
|
||||
and not combine_with.node.combine_is_one_way:
|
||||
|
||||
event_to_return = combine_with.events[combine_with_event]
|
||||
else:
|
||||
# Check to see if there isn't a "fallback" action to
|
||||
# run before we declare this a failure.
|
||||
if escoria.action_default_script \
|
||||
and escoria.action_default_script.events.has(action):
|
||||
|
||||
event_to_return = escoria.action_default_script.events[action]
|
||||
else:
|
||||
var errors = [
|
||||
"Attempted to execute action %s between item %s and item %s" % [
|
||||
action,
|
||||
target.global_id,
|
||||
combine_with.global_id
|
||||
]
|
||||
]
|
||||
|
||||
if combine_with.node.combine_is_one_way:
|
||||
errors.append(
|
||||
("Reason: %s's item interaction " + \
|
||||
"is one-way.") % combine_with.global_id
|
||||
)
|
||||
|
||||
escoria.logger.warn(
|
||||
self,
|
||||
"Invalid action: " + str(errors)
|
||||
)
|
||||
else:
|
||||
escoria.logger.warn(
|
||||
self,
|
||||
"Invalid action on item: " +
|
||||
(
|
||||
"Trying to combine object %s with %s, "+
|
||||
"but %s is not in inventory."
|
||||
) % [
|
||||
target.global_id,
|
||||
combine_with.global_id,
|
||||
combine_with.global_id
|
||||
]
|
||||
)
|
||||
else:
|
||||
escoria.logger.warn(
|
||||
self,
|
||||
"Invalid action on item: " +
|
||||
"Trying to run action %s on object %s, " %
|
||||
[
|
||||
action,
|
||||
target.node.global_id
|
||||
]
|
||||
+ "but item must be in inventory."
|
||||
)
|
||||
else:
|
||||
if target.events.has(action):
|
||||
event_to_return = target.events[action]
|
||||
elif escoria.action_default_script \
|
||||
and escoria.action_default_script.events.has(action):
|
||||
|
||||
# If there's a "fallback" action to run, return it
|
||||
event_to_return = escoria.action_default_script.events[action]
|
||||
else:
|
||||
escoria.logger.warn(
|
||||
self,
|
||||
"Invalid action: " +
|
||||
"Event for action %s on object %s not found." % [
|
||||
action,
|
||||
target.global_id
|
||||
]
|
||||
)
|
||||
|
||||
return event_to_return
|
||||
|
||||
|
||||
# Event handler when an object/item was clicked
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - obj: Object that was left clicked
|
||||
# - event: Input event that was received
|
||||
# - default_action: if true, run the inventory default action
|
||||
func perform_inputevent_on_object(
|
||||
obj: ESCObject,
|
||||
event: InputEvent,
|
||||
default_action: bool = false
|
||||
):
|
||||
"""
|
||||
This algorithm:
|
||||
- validates the requested action
|
||||
- grabs the corresponding event for the action, if available
|
||||
- makes the player move to the clicked object location, if needed
|
||||
(if it is located in the room for example) and wait for reaching.
|
||||
- when reached, performs an action depending on current defined action
|
||||
* no current action defined: do nothing else
|
||||
* current action defined:
|
||||
* item requires no combination: perform the current action
|
||||
on the item
|
||||
* item requires combination: check the status of the combination
|
||||
A combination requires 3 elements to fulfill:
|
||||
1/ a verb action
|
||||
2/ a first "tool" (item to use)
|
||||
3/ a second "tool" (item to use ON)
|
||||
Whatever the user inputs to fulfill the combination (this is
|
||||
determined by gamedev in his game.gd script)
|
||||
- combination not fulfilled: no not perform until fulfilled
|
||||
- combination fulfilled: perform the combination.
|
||||
* else do nothing, except if default_action is requested.
|
||||
In this case, perform the default_action on the item.
|
||||
"""
|
||||
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"%s to perform event %s." % [obj.global_id, event]
|
||||
)
|
||||
|
||||
# Don't interact after player movement towards object
|
||||
# (because object is inactive for example)
|
||||
var dont_interact = false
|
||||
|
||||
# We need to have the new action input state BEFORE initiating the player
|
||||
# move so we determine now if the object clicked will require a combination
|
||||
# depending on the used action verb.
|
||||
var tool_just_set = _set_tool_and_action(obj, default_action)
|
||||
# MODIFIED FOR RETURN TO MONKEY UI
|
||||
var need_combine = _check_item_needs_combine_obj(obj)
|
||||
|
||||
# If the current tool was not set, this is our first item, make it the tool
|
||||
if not current_tool or (current_tool and not need_combine):
|
||||
current_tool = obj
|
||||
# Else, if we have a tool and combination required, this is our second item,
|
||||
# make it the target.
|
||||
elif need_combine and not tool_just_set:
|
||||
current_target = obj
|
||||
|
||||
# Update the action input state
|
||||
if action_state == ACTION_INPUT_STATE.AWAITING_TARGET_ITEM and current_target:
|
||||
set_action_input_state(ACTION_INPUT_STATE.COMPLETED)
|
||||
elif action_state == ACTION_INPUT_STATE.AWAITING_ITEM and \
|
||||
not need_combine:
|
||||
set_action_input_state(ACTION_INPUT_STATE.COMPLETED)
|
||||
elif action_state == ACTION_INPUT_STATE.AWAITING_ITEM and need_combine and not tool_just_set:
|
||||
set_action_input_state(ACTION_INPUT_STATE.AWAITING_TARGET_ITEM)
|
||||
|
||||
var event_to_queue: ESCEvent = null
|
||||
|
||||
# Manage exits
|
||||
if obj.node.is_exit and current_action in ["", ACTION_WALK]:
|
||||
event_to_queue = _get_event_to_queue(ACTION_EXIT_SCENE, obj)
|
||||
else:
|
||||
# Manage movements towards object before activating it
|
||||
if current_action in ["", ACTION_WALK] and \
|
||||
not escoria.inventory_manager.inventory_has(obj.global_id):
|
||||
event_to_queue = _get_event_to_queue(ACTION_ARRIVED, obj)
|
||||
# Manage action on object
|
||||
elif not current_action in ["", ACTION_WALK]:
|
||||
if need_combine and current_target:
|
||||
event_to_queue = _get_event_to_queue(
|
||||
current_action,
|
||||
current_tool,
|
||||
current_target
|
||||
)
|
||||
else:
|
||||
# Check if object must be in inventory to be used and update
|
||||
# action state if necessary
|
||||
if obj.node.use_from_inventory_only and \
|
||||
escoria.inventory_manager.inventory_has(obj.global_id) and \
|
||||
need_combine:
|
||||
|
||||
# We're missing a target here for our tool to be used on
|
||||
current_tool = obj
|
||||
set_action_input_state(
|
||||
ACTION_INPUT_STATE.AWAITING_TARGET_ITEM
|
||||
)
|
||||
|
||||
# We need to wait for that target
|
||||
return
|
||||
else:
|
||||
event_to_queue = _get_event_to_queue(
|
||||
current_action,
|
||||
obj
|
||||
)
|
||||
|
||||
# Get out of here if there's a specified action but an event couldn't be found.
|
||||
# Note that `event_to_queue` may still be null, but we do need to start the
|
||||
# player walking towards the destination.
|
||||
if current_action and not event_to_queue:
|
||||
clear_current_action()
|
||||
emit_signal("action_finished")
|
||||
return
|
||||
|
||||
var event_flags = event_to_queue.flags if event_to_queue else 0
|
||||
|
||||
if escoria.main.current_scene.player:
|
||||
var destination_position: Vector2 = escoria.main.current_scene.player \
|
||||
.global_position
|
||||
|
||||
# If clicked object not in inventory, player walks towards it
|
||||
if not obj.node is ESCPlayer and \
|
||||
not escoria.inventory_manager.inventory_has(obj.global_id) and \
|
||||
not event_flags & ESCEvent.FLAG_TK:
|
||||
var context = _walk_towards_object(
|
||||
obj,
|
||||
event.position,
|
||||
event.doubleclick
|
||||
)
|
||||
|
||||
if context is GDScriptFunctionState:
|
||||
context = yield(context, "completed")
|
||||
|
||||
# In case of an interrupted walk, we don't want to proceed.
|
||||
if context == null:
|
||||
return
|
||||
|
||||
destination_position = context.target_position
|
||||
dont_interact = context.dont_interact_on_arrival
|
||||
|
||||
var player_global_pos = escoria.main.current_scene.player.global_position
|
||||
var clicked_position = event.position
|
||||
|
||||
# Using this instead of is_equal_approx due to
|
||||
# https://github.com/godotengine/godot/issues/65257
|
||||
if (player_global_pos - destination_position).length() > 1:
|
||||
dont_interact = true
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"Player could not reach destination coordinates %s. " % str(destination_position) \
|
||||
+ "Any requested action for %s will not fire." % obj.global_id
|
||||
)
|
||||
if escoria.event_manager.EVENT_CANT_REACH in obj.events:
|
||||
escoria.event_manager.queue_event(obj.events[escoria.event_manager.EVENT_CANT_REACH])
|
||||
else:
|
||||
escoria.logger.info(
|
||||
self,
|
||||
"%s event not found for object %s so nothing to do." % \
|
||||
[escoria.event_manager.EVENT_CANT_REACH, obj.global_id]
|
||||
)
|
||||
|
||||
# If no interaction should happen after player has arrived, leave
|
||||
# immediately.
|
||||
if not dont_interact and event_to_queue:
|
||||
_run_event(event_to_queue)
|
||||
|
||||
# Prepare the "obj" object for current_action: if required, set the object as
|
||||
# current tool.
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - obj: the ESCObject to prepare
|
||||
# - default_action: if true, the default action set on the item is used
|
||||
#
|
||||
# *Returns* True if the tool was set in this function
|
||||
func _set_tool_and_action(obj: ESCObject, default_action: bool):
|
||||
var tool_just_set: bool = false
|
||||
# Check if current_action and current_tool are already set
|
||||
if current_action and current_tool:
|
||||
# MODIFIED FOR RETURN TO MONKEY UI
|
||||
if (not current_action in escoria.action_manager\
|
||||
.current_tool.node.combine_when_selected_action_is_in and not current_action in obj.node.combine_when_selected_action_is_in):
|
||||
current_tool = obj
|
||||
tool_just_set = true
|
||||
elif default_action:
|
||||
if escoria.inventory_manager.inventory_has(obj.global_id):
|
||||
current_action = obj.node.default_action_inventory
|
||||
else:
|
||||
current_action = obj.node.default_action
|
||||
elif current_action in obj.node.combine_when_selected_action_is_in:
|
||||
current_tool = obj
|
||||
tool_just_set = true
|
||||
return tool_just_set
|
||||
|
||||
|
||||
# Checks if object requires a combination with another, according to
|
||||
# currently selected action verb (or check with default action of the item).
|
||||
#
|
||||
# *Returns* True if current action on "obj" requires a combination
|
||||
# MODIFIED FOR RETURN TO MONKEY UI
|
||||
func _check_item_needs_combine_obj(obj: ESCObject) -> bool:
|
||||
return current_action \
|
||||
and current_tool \
|
||||
and (current_action in current_tool.node.combine_when_selected_action_is_in
|
||||
# MODIFIED FOR RETURN TO MONKEY UI
|
||||
or current_action in obj.node.combine_when_selected_action_is_in)
|
||||
Reference in New Issue
Block a user