Updated escoria-demo-game
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
# `block_say`
|
||||
#
|
||||
# `say` commands called subsequent to using the `block_say` command will reuse the
|
||||
# dialog box type of the previous `say` command if both dialog box types between the two `say`
|
||||
# commands match.
|
||||
#
|
||||
# Different dialog box types can be used across multiple `say` commands, with the latest one
|
||||
# used being preserved for reuse by the next `say` command should the dialog box type specified by
|
||||
# both `say` commands match.
|
||||
#
|
||||
# This reuse will continue until a call to `end_block_say` is made.
|
||||
#
|
||||
# Using `block_say` more than once prior to calling `end_block_say` is idempotent and has the
|
||||
# following behaviour:
|
||||
#
|
||||
# - If no `say` command has yet been encountered since the first use of `block_say`,
|
||||
# the result of using this command will be as described above.
|
||||
# - If a `say` command has been encountered since the previous use of `block_say`,
|
||||
# the dialog box used with that `say` command will continue to be reused for subsequent
|
||||
# `say` commands should the dialog box type requested match. Note that the dialog box used with
|
||||
# the next `say` command may be different than the one currently being reused.
|
||||
#
|
||||
# Example:
|
||||
# `block say`
|
||||
# `say player "Picture's looking good."`
|
||||
# `say player "And so am I."`
|
||||
# `end_block_say`
|
||||
#
|
||||
# This example will reuse the same dialog box type since they are the same between both `say` calls.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name BlockSayCommand
|
||||
|
||||
|
||||
# Constructor
|
||||
func _init() -> void:
|
||||
pass
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(0)
|
||||
|
||||
|
||||
# Validate whether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
return true
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.dialog_player.enable_preserve_dialog_box()
|
||||
return ESCExecution.RC_OK
|
||||
|
||||
|
||||
# Function called when the command is interrupted.
|
||||
func interrupt():
|
||||
escoria.logger.debug(
|
||||
self,
|
||||
"[%s] interrupt() function not implemented." % get_command_name()
|
||||
)
|
||||
@@ -0,0 +1,47 @@
|
||||
# `end_block_say`
|
||||
#
|
||||
# `say` commands used subsequent to using the `end_block_say` command will no longer
|
||||
# reuse the dialog box type used by the previous `say` command(s) encountered.
|
||||
#
|
||||
# Using `end_block_say` more than once is safe and idempotent.
|
||||
#
|
||||
# Example:
|
||||
# `block say`
|
||||
# `say player "Picture's looking good."`
|
||||
# `say player "And so am I."`
|
||||
# `end_block_say`
|
||||
#
|
||||
# This example will reuse the same dialog box type since they are the same between both `say` calls.
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
class_name EndBlockSayCommand
|
||||
|
||||
|
||||
# Constructor
|
||||
func _init() -> void:
|
||||
pass
|
||||
|
||||
|
||||
# Return the descriptor of the arguments of this command
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(0)
|
||||
|
||||
|
||||
# Validate whether the given arguments match the command descriptor
|
||||
func validate(arguments: Array):
|
||||
return true
|
||||
|
||||
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
escoria.dialog_player.disable_preserve_dialog_box()
|
||||
return ESCExecution.RC_OK
|
||||
|
||||
|
||||
# Function called when the command is interrupted.
|
||||
func interrupt():
|
||||
escoria.logger.debug(
|
||||
self,
|
||||
"[%s] interrupt() function not implemented." % get_command_name()
|
||||
)
|
||||
@@ -1,18 +1,11 @@
|
||||
# `hide_menu menu_type [enable_automatic_transition]`
|
||||
# `hide_menu menu_type`
|
||||
#
|
||||
# Hides either the main menu or the pause menu. The enable_automatic_transition
|
||||
# parameter can be used to specify if Escoria manages the graphical transition
|
||||
# for you or not.
|
||||
# Setting `enable_automatic_transition` to false allows you to manage the
|
||||
# transition effect for your room as it transitions in and out. Place a
|
||||
# `transition` command in the room's `setup` event to manage the look of the
|
||||
# transition in, and in the room's `exit_scene` event to manage the look of the
|
||||
# transition out.
|
||||
# Hides either the main menu or the pause menu. Transitions from the menu using
|
||||
# the default transition type (set in the Escoria project settings).
|
||||
#
|
||||
# **Parameters**
|
||||
#
|
||||
# - *menu_type*: Which menu to hide. Can be either `main` or `pause` (default: `main`)
|
||||
# - *enable_automatic_transition*: Whether to automatically transition from the menu (default: `false`)
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
@@ -23,8 +16,8 @@ class_name HideMenuCommand
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
0,
|
||||
[TYPE_STRING, TYPE_BOOL],
|
||||
["main", false]
|
||||
[TYPE_STRING],
|
||||
["main"]
|
||||
)
|
||||
|
||||
|
||||
@@ -45,26 +38,26 @@ func validate(arguments: Array):
|
||||
# Run the command
|
||||
func run(command_params: Array) -> int:
|
||||
var transition_id: int
|
||||
if command_params[1]:
|
||||
# Transition out from menu
|
||||
transition_id = escoria.main.scene_transition.transition(
|
||||
"",
|
||||
ESCTransitionPlayer.TRANSITION_MODE.OUT
|
||||
)
|
||||
|
||||
if transition_id != ESCTransitionPlayer.TRANSITION_ID_INSTANT:
|
||||
while yield(
|
||||
escoria.main.scene_transition,
|
||||
"transition_done"
|
||||
) != transition_id:
|
||||
pass
|
||||
# Transition out from menu
|
||||
transition_id = escoria.main.scene_transition.transition(
|
||||
"",
|
||||
ESCTransitionPlayer.TRANSITION_MODE.OUT
|
||||
)
|
||||
|
||||
if transition_id != ESCTransitionPlayer.TRANSITION_ID_INSTANT:
|
||||
while yield(
|
||||
escoria.main.scene_transition,
|
||||
"transition_done"
|
||||
) != transition_id:
|
||||
pass
|
||||
|
||||
if command_params[0] == "main":
|
||||
escoria.game_scene.hide_main_menu()
|
||||
elif command_params[0] == "pause":
|
||||
escoria.game_scene.unpause_game()
|
||||
|
||||
if command_params[1] and escoria.main.current_scene != null:
|
||||
if escoria.main.current_scene != null:
|
||||
transition_id = escoria.main.scene_transition.transition()
|
||||
|
||||
if transition_id != ESCTransitionPlayer.TRANSITION_ID_INSTANT:
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
# `show_menu menu_type [enable_automatic_transition]`
|
||||
# `show_menu menu_type`
|
||||
#
|
||||
# Shows either the main menu or the pause menu. The enable_automatic_transition
|
||||
# parameter can be used to specify if Escoria manages the graphical transition to
|
||||
# the menu or not.
|
||||
# Setting `enable_automatic_transition` to false allows you to manage the
|
||||
# transition effect for your menu as it transitions in and out. Place a
|
||||
# `transition` command in the menu's `setup` event to manage the look of the
|
||||
# transition in, and in the menu's `exit_scene` event to manage the look of the
|
||||
# transition out.
|
||||
# Shows either the main menu or the pause menu. Transitions to the menu using
|
||||
# the default transition type (set in the Escoria project settings).
|
||||
#
|
||||
# **Parameters**
|
||||
#
|
||||
# - *menu_type*: Which menu to show. Can be either `main` or `pause` (default: `main`)
|
||||
# - *enable_automatic_transition*: Whether to automatically transition to the menu (default: `false`)
|
||||
#
|
||||
# @ESC
|
||||
extends ESCBaseCommand
|
||||
@@ -23,8 +16,8 @@ class_name ShowMenuCommand
|
||||
func configure() -> ESCCommandArgumentDescriptor:
|
||||
return ESCCommandArgumentDescriptor.new(
|
||||
0,
|
||||
[TYPE_STRING, TYPE_BOOL],
|
||||
["main", false]
|
||||
[TYPE_STRING],
|
||||
["main"]
|
||||
)
|
||||
|
||||
|
||||
@@ -47,39 +40,33 @@ func run(command_params: Array) -> int:
|
||||
if not escoria.game_scene.is_inside_tree():
|
||||
escoria.add_child(escoria.game_scene)
|
||||
|
||||
if command_params[1]:
|
||||
# Transition out from current scene
|
||||
var transition_id = escoria.main.scene_transition.transition(
|
||||
"",
|
||||
ESCTransitionPlayer.TRANSITION_MODE.OUT
|
||||
)
|
||||
# Transition out from current scene
|
||||
var transition_id = escoria.main.scene_transition.transition(
|
||||
"",
|
||||
ESCTransitionPlayer.TRANSITION_MODE.OUT
|
||||
)
|
||||
|
||||
if transition_id != ESCTransitionPlayer.TRANSITION_ID_INSTANT:
|
||||
while yield(
|
||||
escoria.main.scene_transition,
|
||||
"transition_done"
|
||||
) != transition_id:
|
||||
pass
|
||||
if transition_id != ESCTransitionPlayer.TRANSITION_ID_INSTANT:
|
||||
while yield(
|
||||
escoria.main.scene_transition,
|
||||
"transition_done"
|
||||
) != transition_id:
|
||||
pass
|
||||
|
||||
if command_params[0] == "main":
|
||||
escoria.game_scene.show_main_menu()
|
||||
elif command_params[0] == "pause":
|
||||
escoria.game_scene.pause_game()
|
||||
if command_params[0] == "main":
|
||||
escoria.game_scene.show_main_menu()
|
||||
elif command_params[0] == "pause":
|
||||
escoria.game_scene.pause_game()
|
||||
|
||||
# Transition in to menu
|
||||
transition_id = escoria.main.scene_transition.transition()
|
||||
# Transition in to menu
|
||||
transition_id = escoria.main.scene_transition.transition()
|
||||
|
||||
if transition_id != ESCTransitionPlayer.TRANSITION_ID_INSTANT:
|
||||
while yield(
|
||||
escoria.main.scene_transition,
|
||||
"transition_done"
|
||||
) != transition_id:
|
||||
pass
|
||||
else:
|
||||
if command_params[0] == "main":
|
||||
escoria.game_scene.show_main_menu()
|
||||
elif command_params[0] == "pause":
|
||||
escoria.game_scene.pause_game()
|
||||
if transition_id != ESCTransitionPlayer.TRANSITION_ID_INSTANT:
|
||||
while yield(
|
||||
escoria.main.scene_transition,
|
||||
"transition_done"
|
||||
) != transition_id:
|
||||
pass
|
||||
|
||||
return ESCExecution.RC_OK
|
||||
|
||||
|
||||
@@ -117,5 +117,6 @@ func interrupt():
|
||||
tween.stop_all()
|
||||
|
||||
|
||||
func _on_tween_completed(tween: Tween):
|
||||
tween.queue_free()
|
||||
func _on_tween_completed(tween: Tween, _key: NodePath):
|
||||
if tween:
|
||||
tween.queue_free()
|
||||
|
||||
@@ -75,11 +75,6 @@ var action_state = ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM \
|
||||
#
|
||||
# - action: type of the action to run
|
||||
# - params: Parameters for the action
|
||||
# - BACKGROUND_CLICK: [moving_obj, target, walk_fast]
|
||||
# - ITEM_LEFT_CLICK: [item, input_event]
|
||||
# - ITEM_RIGHT_CLICK: [item, input_event]
|
||||
# - TRIGGER_IN: [trigger_id, object_id, trigger_in_verb]
|
||||
# - TRIGGER_OUT: [trigger_id, object_id, trigger_out_verb]
|
||||
# - can_interrupt: if true, this command will interrupt any ongoing event
|
||||
# before it is finished
|
||||
func do(action: int, params: Array = [], can_interrupt: bool = false) -> void:
|
||||
|
||||
@@ -121,6 +121,12 @@ func register_object(object: ESCObject, room: ESCRoom = null, force: bool = fals
|
||||
if room == null or room.global_id.empty():
|
||||
# We duplicate the key so as to not hold a reference when current_room_key
|
||||
# changes.
|
||||
if current_room_key.room_global_id.empty():
|
||||
escoria.logger.error(
|
||||
self,
|
||||
"The current room has no Global ID.\n" +
|
||||
"Please set the ESCRoom's Global ID property."
|
||||
)
|
||||
room_key.room_global_id = current_room_key.room_global_id
|
||||
room_key.room_instance_id = current_room_key.room_instance_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.hover_stack_clear()
|
||||
escoria.inputs_manager.hover_stack.clear()
|
||||
|
||||
# Check if game scene was loaded
|
||||
if not escoria.game_scene:
|
||||
|
||||
@@ -39,7 +39,7 @@ func run() -> int:
|
||||
if _is_interrupted:
|
||||
final_rc = ESCExecution.RC_INTERRUPTED
|
||||
statement.interrupt()
|
||||
emit_signal("interrupted", self, final_rc)
|
||||
emit_signal("interrupted", self, statement, final_rc)
|
||||
return final_rc
|
||||
|
||||
if statement.is_valid():
|
||||
|
||||
@@ -74,6 +74,10 @@ func _enter_tree():
|
||||
func _ready():
|
||||
mouse_filter = MOUSE_FILTER_IGNORE
|
||||
|
||||
# If background has no texture, set its rect size to viewport size
|
||||
if texture == null and rect_size == Vector2.ZERO:
|
||||
rect_size = escoria.game_size
|
||||
|
||||
if !Engine.is_editor_hint():
|
||||
escoria.inputs_manager.register_background(self)
|
||||
|
||||
|
||||
@@ -46,6 +46,9 @@ var tooltip_node: Object
|
||||
# function of game.gd script.
|
||||
var room_ready_for_inputs: bool = false
|
||||
|
||||
# Displayer node for hover stack debugging
|
||||
var hover_stack_displayer
|
||||
|
||||
|
||||
# Function called when ESCGame enters the scene tree.
|
||||
func _enter_tree():
|
||||
@@ -59,13 +62,21 @@ func _enter_tree():
|
||||
self,
|
||||
"_on_action_finished"
|
||||
)
|
||||
|
||||
escoria.main.connect(
|
||||
"room_ready",
|
||||
self,
|
||||
"_on_room_ready"
|
||||
)
|
||||
|
||||
# Debug display for hover stack
|
||||
if ProjectSettings.get_setting(ESCProjectSettingsManager.ENABLE_HOVER_STACK_VIEWER) and \
|
||||
get_node_or_null("hover_stack_layer") == null:
|
||||
hover_stack_displayer = preload(
|
||||
"res://addons/escoria-core/ui_library/tools/hover_stack/hover_stack.tscn"
|
||||
).instance()
|
||||
add_child(hover_stack_displayer)
|
||||
escoria.inputs_manager.hover_stack.connect("hover_stack_changed", hover_stack_displayer, "update")
|
||||
|
||||
|
||||
# Function called when ESCGame exits the scene tree.
|
||||
func _exit_tree():
|
||||
|
||||
@@ -300,7 +300,7 @@ func _ready():
|
||||
# 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.hover_stack.erase_item(self)
|
||||
escoria.inputs_manager.unset_hovered_node(self)
|
||||
|
||||
|
||||
@@ -321,7 +321,7 @@ class HoverStackSorter:
|
||||
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(get_global_mouse_position(), 32, [], 0x7FFFFFFF, true, true)
|
||||
var colliding: Array = physics2d_dss.intersect_point(get_global_mouse_position(), 32, [], 0x7FFFFFFF, true, true)
|
||||
var colliding_nodes = []
|
||||
for c in colliding:
|
||||
if c.collider.get("global_id") \
|
||||
@@ -331,8 +331,8 @@ func _on_input_event(_viewport: Object, event: InputEvent, _shape_idx: int):
|
||||
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.hover_stack.clear()
|
||||
escoria.inputs_manager.hover_stack.add_items(colliding_nodes)
|
||||
escoria.inputs_manager.set_hovered_node(colliding_nodes.back())
|
||||
|
||||
|
||||
@@ -587,7 +587,7 @@ func teleport_to(target: Vector2) -> void:
|
||||
escoria.logger.warn(
|
||||
self,
|
||||
"Node %s cannot \"teleport_to\". Its \"is_movable\" parameter is false." %self
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# Use the movable node to make the item walk to the given position
|
||||
@@ -603,7 +603,7 @@ func walk_to(pos: Vector2, p_walk_context: ESCWalkContext = null) -> void:
|
||||
escoria.logger.warn(
|
||||
self,
|
||||
"Node %s cannot use \"walk_to\". Its \"is_movable\" parameter is false." %self
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# Stop the movable node immediately and remain where it is at this moment,
|
||||
@@ -667,7 +667,7 @@ func set_angle(deg: int, wait: float = 0.0):
|
||||
escoria.logger.warn(
|
||||
self,
|
||||
"Node %s cannot use \"set_angle\". Its \"is_movable\" parameter is false." % self
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# Turn to face another object
|
||||
@@ -718,13 +718,13 @@ func check_talk_possible():
|
||||
)
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
|
||||
|
||||
# Play the talking animation
|
||||
func start_talking():
|
||||
if not check_talk_possible():
|
||||
return
|
||||
|
||||
|
||||
var animation_player = get_animation_player()
|
||||
|
||||
if animation_player.is_playing():
|
||||
@@ -744,7 +744,7 @@ func start_talking():
|
||||
func stop_talking():
|
||||
if not check_talk_possible():
|
||||
return
|
||||
|
||||
|
||||
var animation_player = get_animation_player()
|
||||
|
||||
if animation_player.is_playing():
|
||||
|
||||
@@ -3,15 +3,23 @@
|
||||
# automatically use an `ESCLocation` that is a child of the destination node.
|
||||
# Commands like `turn_to`--which are not movement-based--will ignore child
|
||||
# `ESCLocation`s and refer to the parent node.
|
||||
tool
|
||||
extends Position2D
|
||||
class_name ESCLocation, "res://addons/escoria-core/design/esc_location.svg"
|
||||
|
||||
|
||||
signal is_start_location_set
|
||||
|
||||
|
||||
const MULTIPLE_START_LOCATIONS_WARNING = \
|
||||
"Only 1 ESCLocation should have is_start_location set to true in an ESCRoom"
|
||||
|
||||
|
||||
# The global ID of this item
|
||||
export(String) var global_id
|
||||
|
||||
# If true, this ESCLocation is considered as a player start location
|
||||
export(bool) var is_start_location = false
|
||||
export(bool) var is_start_location = false setget set_is_start_location
|
||||
|
||||
# If true, player orients towards 'interaction_direction' as
|
||||
# player character arrives.
|
||||
@@ -22,6 +30,9 @@ export(bool) var player_orients_on_arrival = true
|
||||
export(int) var interaction_direction
|
||||
|
||||
|
||||
var _multiple_start_locations_exist: bool = false setget set_multiple_locations_exist
|
||||
|
||||
|
||||
# Used by "is" keyword to check whether a node's class_name
|
||||
# is the same as p_classname.
|
||||
#
|
||||
@@ -34,10 +45,36 @@ func is_class(p_classname: String) -> bool:
|
||||
|
||||
# Ready function
|
||||
func _ready():
|
||||
if not self.global_id.empty():
|
||||
escoria.object_manager.register_object(
|
||||
ESCObject.new(
|
||||
self.global_id,
|
||||
self
|
||||
if not Engine.is_editor_hint():
|
||||
if not self.global_id.empty():
|
||||
escoria.object_manager.register_object(
|
||||
ESCObject.new(
|
||||
self.global_id,
|
||||
self
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
if Engine.is_editor_hint():
|
||||
if is_start_location:
|
||||
emit_signal("is_start_location_set", self)
|
||||
|
||||
|
||||
func _get_configuration_warning():
|
||||
if _multiple_start_locations_exist:
|
||||
return MULTIPLE_START_LOCATIONS_WARNING
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
func set_multiple_locations_exist(value: bool) -> void:
|
||||
_multiple_start_locations_exist = value
|
||||
update_configuration_warning()
|
||||
|
||||
|
||||
func set_is_start_location(value: bool) -> void:
|
||||
is_start_location = value
|
||||
|
||||
if Engine.is_editor_hint() and is_instance_valid(get_owner()):
|
||||
emit_signal("is_start_location_set")
|
||||
|
||||
@@ -1,47 +1,24 @@
|
||||
# A cache for resources
|
||||
extends Reference
|
||||
extends Node
|
||||
class_name ESCResourceCache
|
||||
|
||||
var thread: Thread
|
||||
var mutex: Mutex
|
||||
var sem: Semaphore
|
||||
|
||||
var queue: Array = []
|
||||
var pending: Dictionary = {}
|
||||
|
||||
signal resource_loading_progress(path, progress)
|
||||
signal resource_loading_done(path)
|
||||
signal resource_queue_progress(queue_size)
|
||||
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func _lock(caller):
|
||||
mutex.lock()
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func _unlock(caller):
|
||||
mutex.unlock()
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func _post(caller):
|
||||
sem.post()
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func _wait(caller):
|
||||
sem.wait()
|
||||
var queue: Array = []
|
||||
var pending: Dictionary = {}
|
||||
|
||||
|
||||
func queue_resource(path: String, p_in_front: bool = false, p_permanent: bool = false):
|
||||
_lock("queue_resource")
|
||||
if path in pending:
|
||||
_unlock("queue_resource")
|
||||
return
|
||||
|
||||
elif ResourceLoader.has(path):
|
||||
var res = ResourceLoader.load(path)
|
||||
pending[path] = ESCResourceDescriptor.new(res, p_permanent)
|
||||
_unlock("queue_resource")
|
||||
return
|
||||
else:
|
||||
var res = ResourceLoader.load_interactive(path)
|
||||
res.set_meta("path", path)
|
||||
@@ -50,21 +27,16 @@ func queue_resource(path: String, p_in_front: bool = false, p_permanent: bool =
|
||||
else:
|
||||
queue.push_back(res)
|
||||
pending[path] = ESCResourceDescriptor.new(res, p_permanent)
|
||||
_post("queue_resource")
|
||||
_unlock("queue_resource")
|
||||
return
|
||||
|
||||
|
||||
func cancel_resource(path):
|
||||
_lock("cancel_resource")
|
||||
if path in pending:
|
||||
if pending[path].res is ResourceInteractiveLoader:
|
||||
queue.erase(pending[path].res)
|
||||
pending.erase(path)
|
||||
_unlock("cancel_resource")
|
||||
|
||||
|
||||
func clear():
|
||||
_lock("clear")
|
||||
|
||||
for p in pending.keys():
|
||||
if pending[p].permanent:
|
||||
continue
|
||||
@@ -72,11 +44,8 @@ func clear():
|
||||
#queue = []
|
||||
#pending = {}
|
||||
|
||||
_unlock("clear")
|
||||
|
||||
|
||||
func get_progress(path):
|
||||
_lock("get_progress")
|
||||
var ret = -1
|
||||
if path in pending:
|
||||
if pending[path].res is ResourceInteractiveLoader:
|
||||
@@ -85,36 +54,32 @@ func get_progress(path):
|
||||
ret = 1.0
|
||||
emit_signal("resource_loading_done", path)
|
||||
emit_signal("resource_loading_progress", path, ret)
|
||||
_unlock("get_progress")
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
func is_ready(path):
|
||||
var ret
|
||||
_lock("is_ready")
|
||||
|
||||
if path in pending:
|
||||
ret = !(pending[path].res is ResourceInteractiveLoader)
|
||||
else:
|
||||
ret = false
|
||||
|
||||
_unlock("is_ready")
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
func _wait_for_resource(res, path):
|
||||
_unlock("wait_for_resource")
|
||||
while true:
|
||||
#VisualServer.call("sync") # workaround because sync is a keyword
|
||||
VisualServer.force_sync()
|
||||
OS.delay_usec(16000) # wait 1 frame
|
||||
_lock("wait_for_resource")
|
||||
|
||||
if queue.size() == 0 || queue[0] != res:
|
||||
return pending[path].res
|
||||
_unlock("wait_for_resource")
|
||||
|
||||
|
||||
func get_resource(path):
|
||||
_lock("get_resource")
|
||||
if path in pending:
|
||||
if pending[path].res is ResourceInteractiveLoader:
|
||||
var res = pending[path].res
|
||||
@@ -127,17 +92,16 @@ func get_resource(path):
|
||||
|
||||
if !pending[path].permanent:
|
||||
pending.erase(path)
|
||||
_unlock("return")
|
||||
|
||||
return res
|
||||
|
||||
else:
|
||||
var res = pending[path].res
|
||||
if !pending[path].permanent:
|
||||
pending.erase(path)
|
||||
_unlock("return")
|
||||
|
||||
return res
|
||||
else:
|
||||
_unlock("return")
|
||||
# We can't use ESCProjectSettingsManager here since this method
|
||||
# can be called from escoria._init()
|
||||
if not ProjectSettings.get_setting("escoria/platform/skip_cache"):
|
||||
@@ -146,17 +110,32 @@ func get_resource(path):
|
||||
return res
|
||||
return ResourceLoader.load(path)
|
||||
|
||||
func thread_process():
|
||||
_wait("thread_process")
|
||||
|
||||
_lock("process")
|
||||
func print_progress(p_path, p_progress):
|
||||
printt(p_path, "loading", round(p_progress * 100), "%")
|
||||
|
||||
|
||||
func res_loaded(p_path):
|
||||
printt("loaded resource", p_path)
|
||||
|
||||
|
||||
func print_queue_progress(p_queue_size):
|
||||
printt("queue size:", p_queue_size)
|
||||
|
||||
|
||||
func start():
|
||||
pass
|
||||
## Uncomment these for debug, or wait for someone to implement log levels
|
||||
# connect("resource_loading_progress", self, "print_progress")
|
||||
# connect("resource_loading_done", self, "res_loaded")
|
||||
# connect("resource_queue_progress", self, "print_queue_progress")
|
||||
|
||||
|
||||
func _process(_delta) -> void:
|
||||
while queue.size() > 0:
|
||||
var res = queue[0]
|
||||
|
||||
_unlock("process_poll")
|
||||
var ret = res.poll()
|
||||
_lock("process_check_queue")
|
||||
|
||||
var path = res.get_meta("path")
|
||||
if ret == ERR_FILE_EOF || ret != OK:
|
||||
@@ -166,33 +145,3 @@ func thread_process():
|
||||
|
||||
queue.erase(res) # something might have been put at the front of the queue while we polled, so use erase instead of remove
|
||||
emit_signal("resource_queue_progress", queue.size())
|
||||
|
||||
get_progress(path)
|
||||
|
||||
_unlock("process")
|
||||
|
||||
#warning-ignore:unused_argument
|
||||
func thread_func(u):
|
||||
while true:
|
||||
thread_process()
|
||||
|
||||
func print_progress(p_path, p_progress):
|
||||
printt(p_path, "loading", round(p_progress * 100), "%")
|
||||
|
||||
func res_loaded(p_path):
|
||||
printt("loaded resource", p_path)
|
||||
|
||||
func print_queue_progress(p_queue_size):
|
||||
printt("queue size:", p_queue_size)
|
||||
|
||||
func start():
|
||||
mutex = Mutex.new()
|
||||
sem = Semaphore.new()
|
||||
thread = Thread.new()
|
||||
thread.start(self, "thread_func", 0)
|
||||
|
||||
|
||||
## Uncomment these for debug, or wait for someone to implement log levels
|
||||
# connect("resource_loading_progress", self, "print_progress")
|
||||
# connect("resource_loading_done", self, "res_loaded")
|
||||
# connect("resource_queue_progress", self, "print_queue_progress")
|
||||
|
||||
@@ -12,6 +12,8 @@ enum EditorRoomDebugDisplay {
|
||||
CAMERA_LIMITS
|
||||
}
|
||||
|
||||
const ESC_BACKGROUND_NAME = "escbackground"
|
||||
|
||||
|
||||
# The global id of this room
|
||||
export(String) var global_id = ""
|
||||
@@ -66,8 +68,26 @@ func _ready():
|
||||
) != self.filename:
|
||||
is_run_directly = true
|
||||
|
||||
if not Engine.is_editor_hint():
|
||||
escoria.room_manager.init_room(self)
|
||||
if Engine.is_editor_hint():
|
||||
_connect_location_nodes()
|
||||
_validate_start_locations()
|
||||
return
|
||||
|
||||
# If room has no ESCBackground child, add one
|
||||
var found_escbackground: bool = false
|
||||
for child in get_children():
|
||||
if child is ESCBackground:
|
||||
found_escbackground = true
|
||||
move_child(child, 0)
|
||||
if not found_escbackground:
|
||||
var esc_bg = ESCBackground.new()
|
||||
esc_bg.name = ESC_BACKGROUND_NAME
|
||||
if not camera_limits.empty():
|
||||
esc_bg.set_size(camera_limits.front().size)
|
||||
add_child(esc_bg)
|
||||
move_child(esc_bg, 0)
|
||||
|
||||
escoria.room_manager.init_room(self)
|
||||
|
||||
|
||||
# Draw the camera limits visualization if enabled
|
||||
@@ -97,6 +117,56 @@ func _draw():
|
||||
camera_limits[i].position.y + 30), str(i), camera_limits_colors[i])
|
||||
|
||||
|
||||
# Listen for any signals from ESCLocation indicating that the is_start_location attribute
|
||||
# has been set/unset in order to update start location validation.
|
||||
func _connect_location_nodes() -> void:
|
||||
_connect_location_nodes_in_tree(self)
|
||||
|
||||
|
||||
func _connect_location_nodes_in_tree(node: Node):
|
||||
for n in node.get_children():
|
||||
if n is ESCLocation:
|
||||
if not n.is_connected("is_start_location_set", self, "_validate_start_locations"):
|
||||
n.connect("is_start_location_set", self, "_validate_start_locations")
|
||||
|
||||
if n.get_child_count() > 0:
|
||||
_connect_location_nodes_in_tree(n)
|
||||
|
||||
|
||||
# Validate that we only have one start location for this scene. If we don't, call it out in the
|
||||
# scene tree via configuration warnings.
|
||||
#
|
||||
# We may have to ignore a node if it's being removed/deleted from the scene tree.
|
||||
func _validate_start_locations(to_ignore: ESCLocation = null):
|
||||
var esc_locations: Array = _find_esc_locations(self)
|
||||
var num_start_locations: int = 0
|
||||
|
||||
for n in esc_locations:
|
||||
if n == to_ignore:
|
||||
continue
|
||||
|
||||
num_start_locations += 1 if n.is_start_location else 0
|
||||
|
||||
for n in esc_locations:
|
||||
if n == to_ignore:
|
||||
continue
|
||||
|
||||
n.set_multiple_locations_exist(n.is_start_location and num_start_locations > 1)
|
||||
|
||||
|
||||
func _find_esc_locations(node: Node) -> Array:
|
||||
var esc_locations: Array = []
|
||||
|
||||
for n in node.get_children():
|
||||
if n is ESCLocation:
|
||||
esc_locations.append(n)
|
||||
|
||||
if n.get_child_count() > 0:
|
||||
esc_locations.append_array(_find_esc_locations(n))
|
||||
|
||||
return esc_locations
|
||||
|
||||
|
||||
# Set the camera limits
|
||||
#
|
||||
# #### Parameters
|
||||
|
||||
@@ -4,12 +4,12 @@ class_name ESCResourceDescriptor
|
||||
|
||||
|
||||
# The resource being described
|
||||
var res: Resource
|
||||
var res
|
||||
|
||||
# Whether the resource is permanent
|
||||
var permanent: bool
|
||||
|
||||
|
||||
func _init(res_in: Resource, permanent_in: bool) -> void:
|
||||
func _init(res_in, permanent_in: bool) -> void:
|
||||
res = res_in
|
||||
permanent = permanent_in
|
||||
|
||||
@@ -30,7 +30,7 @@ const ESC_UI_PRIMARY_ACTION = "esc_ui_primary_action"
|
||||
var input_mode = INPUT_ALL
|
||||
|
||||
# A LIFO stack of hovered items
|
||||
var hover_stack: Array = []
|
||||
var hover_stack: HoverStack
|
||||
|
||||
# The global id of the topmost item from the hover_stack
|
||||
var hotspot_focused: String = ""
|
||||
@@ -55,6 +55,8 @@ var _hovered_element = null
|
||||
# Constructor
|
||||
func _init():
|
||||
escoria.event_manager.connect("event_finished", self, "_on_event_finished")
|
||||
hover_stack = HoverStack.new()
|
||||
hover_stack.connect("hover_stack_changed", self, "_on_hover_stack_changed")
|
||||
|
||||
|
||||
# Called when an event is finished, so that the current hotspot is reset
|
||||
@@ -175,22 +177,12 @@ func try_custom_input_handler(event: InputEvent, is_default_state: bool) -> bool
|
||||
return false
|
||||
|
||||
|
||||
|
||||
# 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
|
||||
if hover_stack:
|
||||
set_hovered_node(hover_stack.pop_back())
|
||||
else:
|
||||
hotspot_focused = ""
|
||||
|
||||
|
||||
# Callback called by hover stack content change.
|
||||
func _on_hover_stack_changed():
|
||||
if hover_stack.empty():
|
||||
unset_hovered_node(_hovered_element)
|
||||
else:
|
||||
set_hovered_node(hover_stack.get_top_item())
|
||||
|
||||
|
||||
# Sets the hovered node and calls its mouse_entered() method if it was the top
|
||||
@@ -203,6 +195,12 @@ func unset_hovered_node(item: ESCItem):
|
||||
# **Returns**
|
||||
# True if item is the new top hovered object
|
||||
func set_hovered_node(item: ESCItem) -> bool:
|
||||
if _hovered_element != item \
|
||||
and escoria.action_manager.is_object_actionable(item.global_id) \
|
||||
or (item is ESCPlayer and not (item as ESCPlayer).selectable):
|
||||
_hovered_element = item
|
||||
_hovered_element.mouse_entered()
|
||||
return true
|
||||
# If tested item was already hovered
|
||||
# or is not actionable (not selectable for ESCPlayer) then do nothing
|
||||
if _hovered_element == item \
|
||||
@@ -211,7 +209,7 @@ func set_hovered_node(item: ESCItem) -> bool:
|
||||
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 not is_instance_valid(_hovered_element) or hover_stack.back() != item:
|
||||
if not is_instance_valid(_hovered_element) or hover_stack.get_top_item() != item:
|
||||
_hovered_element = item
|
||||
_hovered_element.mouse_entered()
|
||||
return true
|
||||
@@ -220,6 +218,20 @@ func set_hovered_node(item: ESCItem) -> bool:
|
||||
return false
|
||||
|
||||
|
||||
# Unsets the hovered node.
|
||||
#
|
||||
# **Parameters**
|
||||
#
|
||||
# - item: the item that was unfocused (mouse_exited)
|
||||
func unset_hovered_node(item: ESCItem):
|
||||
if item == null:
|
||||
return
|
||||
if _hovered_element == item:
|
||||
_hovered_element.mouse_exited()
|
||||
_hovered_element = null
|
||||
hotspot_focused = ""
|
||||
|
||||
|
||||
# The background was clicked with the LMB
|
||||
#
|
||||
# #### Parameters
|
||||
@@ -366,7 +378,7 @@ func _on_mouse_entered_item(item: ESCItem) -> void:
|
||||
hotspot_focused = ""
|
||||
escoria.main.current_scene.game.element_unfocused()
|
||||
else:
|
||||
hotspot_focused = hover_stack.back().global_id
|
||||
hotspot_focused = hover_stack.get_top_item().global_id
|
||||
escoria.main.current_scene.game.element_focused(hotspot_focused)
|
||||
return
|
||||
|
||||
@@ -394,7 +406,7 @@ func _on_mouse_entered_item(item: ESCItem) -> void:
|
||||
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)
|
||||
hover_stack.erase_item(item)
|
||||
escoria.main.current_scene.game.element_unfocused()
|
||||
return
|
||||
|
||||
@@ -413,7 +425,7 @@ func _on_mouse_exited_item(item: ESCItem) -> void:
|
||||
hotspot_focused = ""
|
||||
escoria.main.current_scene.game.element_unfocused()
|
||||
else:
|
||||
hotspot_focused = hover_stack.back().global_id
|
||||
hotspot_focused = hover_stack.get_top_item().global_id
|
||||
escoria.main.current_scene.game.element_focused(hotspot_focused)
|
||||
|
||||
|
||||
@@ -426,13 +438,13 @@ func _on_mouse_exited_item(item: ESCItem) -> void:
|
||||
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)
|
||||
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()
|
||||
var new_item = hover_stack.get_top_item()
|
||||
escoria.action_manager.set_action_input_state(ESCActionManager.ACTION_INPUT_STATE.AWAITING_VERB_OR_ITEM)
|
||||
new_item.mouse_entered()
|
||||
|
||||
@@ -454,7 +466,7 @@ func _on_mouse_left_clicked_item(item: ESCItem, event: InputEvent) -> void:
|
||||
|
||||
# Get next object in hover stack and forward event to it
|
||||
if not hover_stack.empty():
|
||||
var next_item = hover_stack.pop_back()
|
||||
var next_item = hover_stack.pop_top_item()
|
||||
_on_mouse_left_clicked_item(next_item, event)
|
||||
else: # if no next object, consider this click as background click
|
||||
hotspot_focused = ""
|
||||
@@ -498,7 +510,7 @@ func _on_mouse_left_double_clicked_item(
|
||||
|
||||
# Get next object in hover stack and forward event to it
|
||||
if not hover_stack.empty():
|
||||
var next_item = hover_stack.pop_back()
|
||||
var next_item = hover_stack.pop_top_item()
|
||||
_on_mouse_left_double_clicked_item(next_item, event)
|
||||
else: # if no next object, consider this click as background click
|
||||
hotspot_focused = ""
|
||||
@@ -536,7 +548,7 @@ func _on_mouse_right_clicked_item(item: ESCItem, event: InputEvent) -> void:
|
||||
)
|
||||
|
||||
if not hover_stack.empty():
|
||||
var next_item = hover_stack.pop_back()
|
||||
var next_item = hover_stack.pop_top_item()
|
||||
_on_mouse_right_clicked_item(next_item, event)
|
||||
return
|
||||
|
||||
@@ -553,7 +565,7 @@ func _on_mouse_right_clicked_item(item: ESCItem, event: InputEvent) -> void:
|
||||
# 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()
|
||||
actual_item = hover_stack.get_top_item()
|
||||
else:
|
||||
actual_item = item
|
||||
|
||||
@@ -594,51 +606,121 @@ 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 implementation.
|
||||
class HoverStack:
|
||||
|
||||
|
||||
# Emitted when the content of the hover stack has changed
|
||||
signal hover_stack_changed
|
||||
|
||||
# Emitted when the hover stack was emptied
|
||||
signal hover_stack_emptied
|
||||
|
||||
|
||||
# Array representing the hover stack
|
||||
var hover_stack: Array = []
|
||||
|
||||
|
||||
# Add the given item to the stack if not already in it.
|
||||
#
|
||||
# #### Parameters
|
||||
# - item: the item to add to the hover stack
|
||||
func 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)
|
||||
_sort()
|
||||
emit_signal("hover_stack_changed")
|
||||
|
||||
|
||||
# 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 add_items(items: Array):
|
||||
for item in items:
|
||||
if escoria.action_manager.is_object_actionable(item.global_id):
|
||||
add_item(item)
|
||||
|
||||
|
||||
# Clean the hover stack
|
||||
func clean():
|
||||
for e in hover_stack:
|
||||
if e == null or !is_instance_valid(e):
|
||||
hover_stack.erase(e)
|
||||
emit_signal("hover_stack_changed")
|
||||
|
||||
|
||||
# Pops the top element of the hover stack and returns it
|
||||
#
|
||||
# **Returns**
|
||||
# The top element of the hover stack
|
||||
func pop_top_item():
|
||||
var ret = hover_stack.pop_back()
|
||||
if is_instance_valid(ret):
|
||||
emit_signal("hover_stack_changed")
|
||||
return ret
|
||||
|
||||
|
||||
# Returns the top element of the hover stack a
|
||||
#
|
||||
# **Returns**
|
||||
# The top element of the hover stack
|
||||
func get_top_item():
|
||||
return hover_stack.back()
|
||||
|
||||
|
||||
# Remove the given item from the stack
|
||||
#
|
||||
# #### Parameters
|
||||
# - item: the item to remove from the hover stack
|
||||
func erase_item(item):
|
||||
hover_stack.erase(item)
|
||||
_sort()
|
||||
emit_signal("hover_stack_changed")
|
||||
|
||||
|
||||
# Clear the stack of hovered items
|
||||
func clear():
|
||||
hover_stack = []
|
||||
emit_signal("hover_stack_emptied")
|
||||
|
||||
|
||||
# Returns true if the hover stack is empty, else false
|
||||
#
|
||||
# **Returns**
|
||||
# True if hover stack is empty, else false
|
||||
func empty() -> bool:
|
||||
return hover_stack.empty()
|
||||
|
||||
|
||||
# Sort the hover stack by items' z-index
|
||||
func _sort():
|
||||
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:
|
||||
if escoria.action_manager.is_object_actionable(item.global_id):
|
||||
hover_stack_add_item(item)
|
||||
# Returns true if the hover stack contains the given item
|
||||
#
|
||||
# #### Parameters
|
||||
# - item: the item to search
|
||||
#
|
||||
# **Returns**
|
||||
# True if hover stack contains given item, else false
|
||||
func has(item) -> bool:
|
||||
return hover_stack.has(item)
|
||||
|
||||
|
||||
# Clean the hover stack
|
||||
func _clean_hover_stack():
|
||||
for e in hover_stack:
|
||||
if e == null or !is_instance_valid(e):
|
||||
hover_stack.erase(e)
|
||||
# Returns the hover stack array
|
||||
#
|
||||
# **Returns**
|
||||
# The hover stack array
|
||||
func get_all() -> Array:
|
||||
return hover_stack
|
||||
|
||||
|
||||
# Remove the given item from the stack
|
||||
#
|
||||
# #### Parameters
|
||||
# - item: the item to remove from the hover stack
|
||||
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:
|
||||
static func sort_ascending_z_index(a, b):
|
||||
if a.z_index < b.z_index:
|
||||
return true
|
||||
return false
|
||||
# Z Sorter class for hover stack
|
||||
class HoverStackSorter:
|
||||
static func sort_ascending_z_index(a, b):
|
||||
if a.z_index < b.z_index:
|
||||
return true
|
||||
return false
|
||||
|
||||
@@ -37,12 +37,15 @@ const _DEBUG_ROOT = "debug"
|
||||
|
||||
const CRASH_MESSAGE = "%s/%s/crash_message" % [_ESCORIA_SETTINGS_ROOT, _DEBUG_ROOT]
|
||||
const DEVELOPMENT_LANG = "%s/%s/development_lang" % [_ESCORIA_SETTINGS_ROOT, _DEBUG_ROOT]
|
||||
# If enabled, displays the room selection box for quick room change
|
||||
const ENABLE_ROOM_SELECTOR = "%s/%s/enable_room_selector" % [_ESCORIA_SETTINGS_ROOT, _DEBUG_ROOT]
|
||||
const LOG_FILE_PATH = "%s/%s/log_file_path" % [_ESCORIA_SETTINGS_ROOT, _DEBUG_ROOT]
|
||||
const LOG_LEVEL = "%s/%s/log_level" % [_ESCORIA_SETTINGS_ROOT, _DEBUG_ROOT]
|
||||
const ROOM_SELECTOR_ROOM_DIR = "%s/%s/room_selector_room_dir" % [_ESCORIA_SETTINGS_ROOT, _DEBUG_ROOT]
|
||||
const TERMINATE_ON_ERRORS = "%s/%s/terminate_on_errors" % [_ESCORIA_SETTINGS_ROOT, _DEBUG_ROOT]
|
||||
const TERMINATE_ON_WARNINGS = "%s/%s/terminate_on_warnings" % [_ESCORIA_SETTINGS_ROOT, _DEBUG_ROOT]
|
||||
# If enabled, displays the hover stack on screen
|
||||
const ENABLE_HOVER_STACK_VIEWER = "%s/%s/enable_hover_stack_viewer" % [_ESCORIA_SETTINGS_ROOT, _DEBUG_ROOT]
|
||||
|
||||
# Sound-related Escoria project settings
|
||||
const _SOUND_ROOT = "sound"
|
||||
|
||||
@@ -25,7 +25,6 @@ func _init():
|
||||
escoria.object_manager = ESCObjectManager.new()
|
||||
escoria.command_registry = ESCCommandRegistry.new()
|
||||
escoria.resource_cache = ESCResourceCache.new()
|
||||
escoria.resource_cache.start()
|
||||
escoria.save_manager = ESCSaveManager.new()
|
||||
escoria.inputs_manager = ESCInputsManager.new()
|
||||
escoria.settings_manager = ESCSettingsManager.new()
|
||||
@@ -45,6 +44,8 @@ func _init():
|
||||
|
||||
# Load settings
|
||||
func _ready():
|
||||
add_child(escoria.resource_cache)
|
||||
|
||||
_handle_direct_scene_run()
|
||||
|
||||
escoria.settings_manager.load_settings()
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[ext_resource path="res://addons/escoria-core/game/escoria.gd" type="Script" id=3]
|
||||
|
||||
[node name="escoria_scene" type="Node"]
|
||||
pause_mode = 2
|
||||
script = ExtResource( 3 )
|
||||
|
||||
[node name="main" parent="." instance=ExtResource( 2 )]
|
||||
|
||||
@@ -46,13 +46,35 @@ func say(dialog_player: Node, global_id: String, text: String, type: String):
|
||||
pass
|
||||
|
||||
|
||||
# Instructs the dialog manager to preserve the next dialog box used by a `say`
|
||||
# command until a call to `disable_preserve_dialog_box` is made.
|
||||
#
|
||||
# This method should be idempotent, i.e. if called after the first time and
|
||||
# prior to `disable_preserve_dialog_box` being called, the result should be the
|
||||
# same.
|
||||
func enable_preserve_dialog_box() -> void:
|
||||
pass
|
||||
|
||||
|
||||
# Instructs the dialog manager to no longer preserve the currently-preserved
|
||||
# dialog box or to not preserve the next dialog box used by a `say` command
|
||||
# (this is the default state).
|
||||
#
|
||||
# This method should be idempotent, i.e. if called after the first time and
|
||||
# prior to `enable_preserve_dialog_box` being called, the result should be the
|
||||
# same.
|
||||
func disable_preserve_dialog_box() -> void:
|
||||
pass
|
||||
|
||||
|
||||
# Present an option chooser to the player and sends the signal
|
||||
# `option_chosen` with the chosen dialog option
|
||||
#
|
||||
# #### Parameters
|
||||
# - dialog_player: Node of the dialog player in the UI
|
||||
# - dialog: Information about the dialog to display
|
||||
func choose(dialog_player: Node, dialog: ESCDialog):
|
||||
# - type: The dialog chooser type to use
|
||||
func choose(dialog_player: Node, dialog: ESCDialog, type: String):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Escoria dialog player
|
||||
extends StateMachine
|
||||
extends Node
|
||||
class_name ESCDialogPlayer
|
||||
|
||||
|
||||
@@ -14,8 +14,20 @@ signal option_chosen(option)
|
||||
signal say_finished
|
||||
|
||||
|
||||
# Reference to the currently playing dialog manager
|
||||
var _dialog_manager: ESCDialogManager = null
|
||||
# Used when specifying dialog types in various methods
|
||||
const DIALOG_TYPE_SAY = "say"
|
||||
|
||||
const DIALOG_TYPE_CHOOSE = "choose"
|
||||
|
||||
|
||||
# Reference to the currently playing "say" dialog manager
|
||||
var _say_dialog_manager: ESCDialogManager = null
|
||||
|
||||
# Reference to the currently playing "choose" dialog manager
|
||||
var _choose_dialog_manager: ESCDialogManager = null
|
||||
|
||||
# Whether to use the "dialog box preservation" feature
|
||||
var _block_say_enabled: bool = false
|
||||
|
||||
|
||||
# Register the dialog player and load the dialog resources
|
||||
@@ -25,38 +37,27 @@ func _ready():
|
||||
|
||||
escoria.dialog_player = self
|
||||
|
||||
_create_states()
|
||||
_add_states_to_machine()
|
||||
|
||||
states_map["say"].connect("dialog_manager_set", self, "_on_dialog_manager_set")
|
||||
|
||||
current_state_name = "idle"
|
||||
START_STATE = states_map[current_state_name]
|
||||
|
||||
initialize(START_STATE)
|
||||
# Instructs the dialog manager to preserve the next dialog box used by a `say`
|
||||
# command until a call to `disable_preserve_dialog_box` is made.
|
||||
#
|
||||
# This method should be idempotent, i.e. if called after the first time and
|
||||
# prior to `disable_preserve_dialog_box` being called, the result should be the
|
||||
# same.
|
||||
func enable_preserve_dialog_box() -> void:
|
||||
_block_say_enabled = true
|
||||
|
||||
|
||||
# Creates the states for this state machine.
|
||||
func _create_states() -> void:
|
||||
states_map = {
|
||||
"idle": DialogIdle.new(),
|
||||
"say": DialogSay.new(),
|
||||
"say_fast": DialogSayFast.new(),
|
||||
"say_finish": DialogSayFinish.new(),
|
||||
"visible": DialogVisible.new(),
|
||||
"finish": DialogFinish.new(),
|
||||
"interrupt": DialogInterrupt.new(),
|
||||
"choices": DialogChoices.new(),
|
||||
}
|
||||
|
||||
# This state needs a reference to this class.
|
||||
states_map["finish"].initialize(self)
|
||||
|
||||
|
||||
# Adds any created states into the state machine as children.
|
||||
func _add_states_to_machine() -> void:
|
||||
for key in states_map:
|
||||
add_child(states_map[key])
|
||||
# Instructs the dialog manager to no longer preserve the currently-preserved
|
||||
# dialog box or to not preserve the next dialog box used by a `say` command
|
||||
# (this is the default state).
|
||||
#
|
||||
# This method should be idempotent, i.e. if called after the first time and
|
||||
# prior to `enable_preserve_dialog_box` being called, the result should be the
|
||||
# same.
|
||||
func disable_preserve_dialog_box() -> void:
|
||||
_block_say_enabled = false
|
||||
_say_dialog_manager.disable_preserve_dialog_box()
|
||||
|
||||
|
||||
# Make a character say some text
|
||||
@@ -67,18 +68,19 @@ func _add_states_to_machine() -> void:
|
||||
# - type: UI to use for the dialog
|
||||
# - text: Text to say
|
||||
func say(character: String, type: String, text: String) -> void:
|
||||
states_map["say"].initialize(character, type, text)
|
||||
_change_state("say")
|
||||
if type == "":
|
||||
type = ESCProjectSettingsManager.get_setting(
|
||||
ESCProjectSettingsManager.DEFAULT_DIALOG_TYPE
|
||||
)
|
||||
|
||||
# We only need to remove the dialog manager from the scene tree if the dialog manager type
|
||||
# has changed since the last use of this method.
|
||||
_update_dialog_manager(DIALOG_TYPE_SAY, _say_dialog_manager, type)
|
||||
|
||||
# Called when a dialogue line is to be sped up.
|
||||
func speedup() -> void:
|
||||
_change_state("say_fast")
|
||||
if _block_say_enabled:
|
||||
_say_dialog_manager.enable_preserve_dialog_box()
|
||||
|
||||
|
||||
# Called when a dialogue line is to be finished immediately.
|
||||
func finish() -> void:
|
||||
_change_state("say_finish")
|
||||
_say_dialog_manager.say(self, character, text, type)
|
||||
|
||||
|
||||
# Display a list of choices
|
||||
@@ -86,22 +88,111 @@ func finish() -> void:
|
||||
# #### Parameters
|
||||
#
|
||||
# - dialog: The dialog to start
|
||||
# - type: The dialog chooser type to use (default: "simple")
|
||||
func start_dialog_choices(dialog: ESCDialog, type: String = "simple"):
|
||||
states_map["choices"].initialize(self, dialog, type)
|
||||
_change_state("choices")
|
||||
# We only need to remove the dialog manager from the scene tree if the dialog manager type
|
||||
# has changed since the last use of this method.
|
||||
_update_dialog_manager(DIALOG_TYPE_CHOOSE, _choose_dialog_manager, type)
|
||||
|
||||
_choose_dialog_manager.choose(self, dialog, type)
|
||||
|
||||
|
||||
# Interrupt the currently running dialog
|
||||
func interrupt() -> void:
|
||||
_change_state("interrupt")
|
||||
if is_instance_valid(_say_dialog_manager):
|
||||
_say_dialog_manager.interrupt()
|
||||
|
||||
|
||||
# Since the dialog manager is determined when a `say` command is performed and
|
||||
# other states need to know which one was picked, we notify the necessary states
|
||||
# via this method.
|
||||
func _on_dialog_manager_set(dialog_manager: ESCDialogManager) -> void:
|
||||
_dialog_manager = dialog_manager
|
||||
states_map["say_fast"].initialize(dialog_manager)
|
||||
states_map["say_finish"].initialize(dialog_manager)
|
||||
states_map["visible"].initialize(dialog_manager)
|
||||
states_map["interrupt"].initialize(dialog_manager)
|
||||
# Loads the first dialog manager that supports the specified "say" type; otherwise,
|
||||
# the engine throws an error and stops.
|
||||
#
|
||||
# #### Parameters
|
||||
# - type: The type the dialog manager should support, e.g. "floating"
|
||||
func _determine_say_dialog_manager(type: String) -> void:
|
||||
var dialog_manager: ESCDialogManager = null
|
||||
|
||||
for _manager_class in ESCProjectSettingsManager.get_setting(
|
||||
ESCProjectSettingsManager.DIALOG_MANAGERS
|
||||
):
|
||||
if ResourceLoader.exists(_manager_class):
|
||||
var _manager: ESCDialogManager = load(_manager_class).new()
|
||||
if _manager.has_type(type):
|
||||
dialog_manager = _manager
|
||||
else:
|
||||
dialog_manager = null
|
||||
|
||||
if not is_instance_valid(dialog_manager):
|
||||
escoria.logger.error(
|
||||
self,
|
||||
"No dialog manager called '%s' configured." % type
|
||||
)
|
||||
|
||||
_say_dialog_manager = dialog_manager
|
||||
|
||||
|
||||
# Loads the first dialog manager that supports the specified "choose" type; otherwise,
|
||||
# the engine throws an error and stops.
|
||||
#
|
||||
# #### Parameters
|
||||
# - type: The type the dialog manager should support, e.g. "simple"
|
||||
func _determine_choose_dialog_manager(type: String) -> void:
|
||||
var dialog_manager: ESCDialogManager = null
|
||||
|
||||
for _manager_class in ESCProjectSettingsManager.get_setting(
|
||||
ESCProjectSettingsManager.DIALOG_MANAGERS
|
||||
):
|
||||
if ResourceLoader.exists(_manager_class):
|
||||
var _manager: ESCDialogManager = load(_manager_class).new()
|
||||
if _manager.has_chooser_type(type):
|
||||
dialog_manager = _manager
|
||||
else:
|
||||
dialog_manager = null
|
||||
|
||||
if not is_instance_valid(dialog_manager):
|
||||
escoria.logger.error(
|
||||
self,
|
||||
"No dialog manager called '%s' configured." % type
|
||||
)
|
||||
|
||||
_choose_dialog_manager = dialog_manager
|
||||
|
||||
|
||||
# If necessary, updates the dialog manager for the specified dialog type.
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - dialog_type: The type of dialog that will be managed, e.g. "say" or "choose"
|
||||
# - current_dialog_manager: The dialog manager currently being used (if any) for the specified
|
||||
# dialog type
|
||||
# - dialog_manager_type: The dialog manager type specific to the dialog manager being requested
|
||||
func _update_dialog_manager(dialog_type: String, current_dialog_manager: ESCDialogManager, \
|
||||
dialog_manager_type: String) -> void:
|
||||
|
||||
if is_instance_valid(current_dialog_manager):
|
||||
if not current_dialog_manager.has_type(dialog_manager_type):
|
||||
if is_a_parent_of(current_dialog_manager):
|
||||
remove_child(current_dialog_manager)
|
||||
|
||||
add_child(_determine_dialog_manager(dialog_type, dialog_manager_type))
|
||||
else:
|
||||
add_child(_determine_dialog_manager(dialog_type, dialog_manager_type))
|
||||
|
||||
|
||||
# Sets the requested dialog manager type for the specified dialog function.
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - dialog_type: The type of dialog that will be managed, e.g. "say" or "choose"
|
||||
# - dialog_manager_type: The dialog manager type specific to the dialog manager being requested
|
||||
#
|
||||
# *Returns* the newly-resolved dialog manager
|
||||
func _determine_dialog_manager(dialog_type: String, dialog_manager_type: String) -> ESCDialogManager:
|
||||
if dialog_type == DIALOG_TYPE_SAY:
|
||||
_determine_say_dialog_manager(dialog_manager_type)
|
||||
return _say_dialog_manager
|
||||
elif dialog_type == DIALOG_TYPE_CHOOSE:
|
||||
_determine_choose_dialog_manager(dialog_manager_type)
|
||||
return _choose_dialog_manager
|
||||
|
||||
# This line will never be hit as a failure above will result in an Escoria error
|
||||
return null
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
extends State
|
||||
class_name DialogChoices
|
||||
|
||||
|
||||
# The owning dialog player.
|
||||
var _dialog_player
|
||||
|
||||
# The dialog to start.
|
||||
var _dialog: ESCDialog
|
||||
var _type: String = "simple"
|
||||
|
||||
var _dialog_chooser_ui: ESCDialogManager = null
|
||||
|
||||
var _ready_to_choose: bool
|
||||
|
||||
|
||||
func initialize(dialog_player, dialog: ESCDialog, type: String) -> void:
|
||||
_dialog_player = dialog_player
|
||||
_dialog = dialog
|
||||
_type = type
|
||||
|
||||
|
||||
func enter():
|
||||
escoria.logger.trace(self, "Dialog State Machine: Entered 'choices'.")
|
||||
|
||||
if _dialog.options.empty():
|
||||
escoria.logger.error(
|
||||
self,
|
||||
"Received dialog options array was empty."
|
||||
)
|
||||
|
||||
for _manager_class in ESCProjectSettingsManager.get_setting(
|
||||
ESCProjectSettingsManager.DIALOG_MANAGERS
|
||||
):
|
||||
if ResourceLoader.exists(_manager_class):
|
||||
var _manager: ESCDialogManager = load(_manager_class).new()
|
||||
if _manager.has_chooser_type(_type):
|
||||
_dialog_chooser_ui = _manager
|
||||
|
||||
if _dialog_chooser_ui == null:
|
||||
escoria.logger.error(
|
||||
self,
|
||||
"No dialog manager supports the chooser type %s." % _type
|
||||
)
|
||||
|
||||
_ready_to_choose = true
|
||||
|
||||
|
||||
func update(_delta):
|
||||
if _ready_to_choose:
|
||||
_ready_to_choose = false
|
||||
_dialog_chooser_ui.choose(self, _dialog)
|
||||
var option = yield(_dialog_chooser_ui, "option_chosen")
|
||||
|
||||
escoria.logger.trace(self, "Dialog State Machine: 'choices' -> 'idle'")
|
||||
|
||||
emit_signal("finished", "idle")
|
||||
_dialog_player.emit_signal("option_chosen", option)
|
||||
@@ -1,20 +0,0 @@
|
||||
extends State
|
||||
class_name DialogFinish
|
||||
|
||||
|
||||
# Owning dialog player
|
||||
var _dialog_player
|
||||
|
||||
|
||||
func initialize(dialog_player) -> void:
|
||||
_dialog_player = dialog_player
|
||||
|
||||
|
||||
func enter():
|
||||
escoria.logger.trace(self, "Dialog State Machine: Entered 'finish'.")
|
||||
|
||||
|
||||
func update(_delta):
|
||||
escoria.logger.trace(self, "Dialog State Machine: 'finish' -> 'idle'")
|
||||
emit_signal("finished", "idle")
|
||||
_dialog_player.emit_signal("say_finished")
|
||||
@@ -1,6 +0,0 @@
|
||||
extends State
|
||||
class_name DialogIdle
|
||||
|
||||
|
||||
func enter():
|
||||
escoria.logger.trace(self, "Dialog State Machine: Entered 'idle'.")
|
||||
@@ -1,26 +0,0 @@
|
||||
extends State
|
||||
class_name DialogInterrupt
|
||||
|
||||
|
||||
# Reference to the currently playing dialog manager
|
||||
var _dialog_manager: ESCDialogManager = null
|
||||
|
||||
|
||||
func initialize(dialog_manager: ESCDialogManager) -> void:
|
||||
_dialog_manager = dialog_manager
|
||||
|
||||
|
||||
func enter():
|
||||
escoria.logger.trace(self, "Dialog State Machine: Entered 'interrupt'.")
|
||||
|
||||
if _dialog_manager != null:
|
||||
if not _dialog_manager.is_connected("say_finished", self, "_on_say_finished"):
|
||||
_dialog_manager.connect("say_finished", self, "_on_say_finished", [], CONNECT_ONESHOT)
|
||||
|
||||
_dialog_manager.interrupt()
|
||||
|
||||
|
||||
func _on_say_finished() -> void:
|
||||
escoria.logger.trace(self, "Dialog State Machine: 'interrupt' -> 'finish'")
|
||||
emit_signal("finished", "finish")
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
extends State
|
||||
class_name DialogSay
|
||||
|
||||
|
||||
signal dialog_manager_set(dialog_manager)
|
||||
|
||||
|
||||
# A regular expression that separates the translation key from the text
|
||||
const KEYTEXT_REGEX = "^((?<key>[^:]+):)?\"(?<text>.+)\""
|
||||
|
||||
|
||||
# Reference to the currently playing dialog manager
|
||||
var _dialog_manager: ESCDialogManager = null
|
||||
|
||||
# Character that is talking
|
||||
var _character: String
|
||||
|
||||
# UI to use for the dialog
|
||||
var _type: String
|
||||
|
||||
# Text to say
|
||||
var _text: String
|
||||
|
||||
# Regular expression object for the separation of key and text
|
||||
var _keytext_regex: RegEx = RegEx.new()
|
||||
|
||||
var _ready_to_say: bool
|
||||
|
||||
var _stop_talking_animation_on_option: String
|
||||
|
||||
|
||||
# Constructor
|
||||
func _init() -> void:
|
||||
_keytext_regex.compile(KEYTEXT_REGEX)
|
||||
|
||||
|
||||
func initialize(character: String, type: String, text: String) -> void:
|
||||
_character = character
|
||||
_type = type
|
||||
_text = text
|
||||
_stop_talking_animation_on_option = \
|
||||
ESCProjectSettingsManager.get_setting(SimpleDialogPlugin.STOP_TALKING_ANIMATION_ON)
|
||||
|
||||
|
||||
func handle_input(_event):
|
||||
if _event is InputEventMouseButton and _event.pressed:
|
||||
if escoria.inputs_manager.input_mode != \
|
||||
escoria.inputs_manager.INPUT_NONE and \
|
||||
_dialog_manager != null:
|
||||
|
||||
var left_click_action = ESCProjectSettingsManager.get_setting(SimpleDialogPlugin.LEFT_CLICK_ACTION)
|
||||
|
||||
_handle_left_click_action(left_click_action)
|
||||
|
||||
|
||||
func _handle_left_click_action(left_click_action: String) -> void:
|
||||
match left_click_action:
|
||||
SimpleDialogPlugin.LEFT_CLICK_ACTION_SPEED_UP:
|
||||
if _dialog_manager.is_connected("say_visible", self, "_on_say_visible"):
|
||||
_dialog_manager.disconnect("say_visible", self, "_on_say_visible")
|
||||
|
||||
escoria.logger.trace(self, "Dialog State Machine: 'say' -> 'say_fast'")
|
||||
emit_signal("finished", "say_fast")
|
||||
SimpleDialogPlugin.LEFT_CLICK_ACTION_INSTANT_FINISH:
|
||||
if _dialog_manager.is_connected("say_visible", self, "_on_say_visible"):
|
||||
_dialog_manager.disconnect("say_visible", self, "_on_say_visible")
|
||||
|
||||
escoria.logger.trace(self, "Dialog State Machine: 'say' -> 'say_finish'")
|
||||
emit_signal("finished", "say_finish")
|
||||
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
|
||||
func enter():
|
||||
escoria.logger.trace(self, "Dialog State Machine: Entered 'say'.")
|
||||
|
||||
if _type == "":
|
||||
_type = ESCProjectSettingsManager.get_setting(
|
||||
ESCProjectSettingsManager.DEFAULT_DIALOG_TYPE
|
||||
)
|
||||
|
||||
var dialog_manager: ESCDialogManager = null
|
||||
|
||||
for _manager_class in ESCProjectSettingsManager.get_setting(
|
||||
ESCProjectSettingsManager.DIALOG_MANAGERS
|
||||
):
|
||||
if ResourceLoader.exists(_manager_class):
|
||||
var _manager: ESCDialogManager = load(_manager_class).new()
|
||||
if _manager.has_type(_type):
|
||||
dialog_manager = _manager
|
||||
else:
|
||||
dialog_manager = null
|
||||
|
||||
if dialog_manager == null:
|
||||
escoria.logger.error(
|
||||
self,
|
||||
"No dialog manager called '%s' configured." % _type
|
||||
)
|
||||
|
||||
_dialog_manager = dialog_manager
|
||||
emit_signal("dialog_manager_set", dialog_manager)
|
||||
|
||||
if not _dialog_manager.is_connected("say_visible", self, "_on_say_visible"):
|
||||
_dialog_manager.connect("say_visible", self, "_on_say_visible", [], CONNECT_ONESHOT)
|
||||
|
||||
var matches = _keytext_regex.search(_text)
|
||||
|
||||
if not matches:
|
||||
escoria.logger.error(
|
||||
self,
|
||||
"Unexpected text encountered: %s." % _text
|
||||
)
|
||||
|
||||
var key = matches.get_string("key")
|
||||
|
||||
if matches.get_string("key") != "":
|
||||
var _speech_resource = _get_voice_file(
|
||||
matches.get_string("key")
|
||||
)
|
||||
|
||||
if _speech_resource == "":
|
||||
escoria.logger.warn(
|
||||
self,
|
||||
"Unable to find voice file with key '%s'." % matches.get_string("key")
|
||||
)
|
||||
else:
|
||||
(
|
||||
escoria.object_manager.get_object(escoria.object_manager.SPEECH).node\
|
||||
as ESCSpeechPlayer
|
||||
).set_state(_speech_resource)
|
||||
|
||||
if _stop_talking_animation_on_option == SimpleDialogPlugin.STOP_TALKING_ANIMATION_ON_END_OF_AUDIO:
|
||||
(
|
||||
escoria.object_manager.get_object(escoria.object_manager.SPEECH).node\
|
||||
as ESCSpeechPlayer
|
||||
).stream.connect("finished", self, "_on_audio_finished", [], CONNECT_ONESHOT)
|
||||
|
||||
var translated_text: String = tr(matches.get_string("key"))
|
||||
|
||||
# Only update the text if the translated text was found; otherwise, raise
|
||||
# a warning and use the original, untranslated text.
|
||||
if translated_text == matches.get_string("key"):
|
||||
escoria.logger.warn(
|
||||
self,
|
||||
"Unable to find translation key '%s'. Using untranslated text." % matches.get_string("key")
|
||||
)
|
||||
_text = matches.get_string("text")
|
||||
else:
|
||||
_text = translated_text
|
||||
else:
|
||||
_text = matches.get_string("text")
|
||||
|
||||
_ready_to_say = true
|
||||
|
||||
|
||||
func update(_delta):
|
||||
if _ready_to_say:
|
||||
_dialog_manager.say(self, _character, _text, _type)
|
||||
_ready_to_say = false
|
||||
|
||||
|
||||
# Find the matching voice output file for the given key
|
||||
#
|
||||
# #### Parameters
|
||||
#
|
||||
# - key: Text key provided
|
||||
# - start: Starting folder to search for voices
|
||||
#
|
||||
# *Returns* The path to the matching voice file
|
||||
func _get_voice_file(key: String, start: String = "") -> String:
|
||||
if start == "":
|
||||
start = ESCProjectSettingsManager.get_setting(
|
||||
ESCProjectSettingsManager.SPEECH_FOLDER
|
||||
)
|
||||
var _dir = Directory.new()
|
||||
if _dir.open(start) == OK:
|
||||
_dir.list_dir_begin(true, true)
|
||||
var file_name = _dir.get_next()
|
||||
while file_name != "":
|
||||
if _dir.current_is_dir():
|
||||
var _voice_file = _get_voice_file(
|
||||
key,
|
||||
start.plus_file(file_name)
|
||||
)
|
||||
if _voice_file != "":
|
||||
return _voice_file
|
||||
else:
|
||||
if file_name == "%s.%s.import" % [
|
||||
key,
|
||||
ESCProjectSettingsManager.get_setting(
|
||||
ESCProjectSettingsManager.SPEECH_EXTENSION
|
||||
)
|
||||
]:
|
||||
return start.plus_file(file_name.trim_suffix(".import"))
|
||||
file_name = _dir.get_next()
|
||||
return ""
|
||||
|
||||
|
||||
func _on_say_visible() -> void:
|
||||
escoria.logger.trace(self, "Dialog State Machine: 'say' -> 'visible'")
|
||||
emit_signal("finished", "visible")
|
||||
|
||||
|
||||
func _on_audio_finished() -> void:
|
||||
_dialog_manager.voice_audio_finished()
|
||||
@@ -1,30 +0,0 @@
|
||||
extends State
|
||||
class_name DialogSayFast
|
||||
|
||||
|
||||
# Reference to the currently playing dialog manager
|
||||
var _dialog_manager: ESCDialogManager = null
|
||||
|
||||
|
||||
func initialize(dialog_manager: ESCDialogManager) -> void:
|
||||
_dialog_manager = dialog_manager
|
||||
|
||||
|
||||
func enter():
|
||||
escoria.logger.trace(self, "Dialog State Machine: Entered 'say_fast'.")
|
||||
|
||||
if escoria.inputs_manager.input_mode != \
|
||||
escoria.inputs_manager.INPUT_NONE and \
|
||||
_dialog_manager != null:
|
||||
|
||||
if not _dialog_manager.is_connected("say_visible", self, "_on_say_visible"):
|
||||
_dialog_manager.connect("say_visible", self, "_on_say_visible", [], CONNECT_ONESHOT)
|
||||
|
||||
_dialog_manager.speedup()
|
||||
else:
|
||||
escoria.logger.error(self, "Illegal state.")
|
||||
|
||||
|
||||
func _on_say_visible() -> void:
|
||||
escoria.logger.trace(self, "Dialog State Machine: 'say_fast' -> 'visible'")
|
||||
emit_signal("finished", "visible")
|
||||
@@ -1,30 +0,0 @@
|
||||
extends State
|
||||
class_name DialogSayFinish
|
||||
|
||||
|
||||
# Reference to the currently playing dialog manager
|
||||
var _dialog_manager: ESCDialogManager = null
|
||||
|
||||
|
||||
func initialize(dialog_manager: ESCDialogManager) -> void:
|
||||
_dialog_manager = dialog_manager
|
||||
|
||||
|
||||
func enter():
|
||||
escoria.logger.trace(self, "Dialog State Machine: Entered 'say_finish'.")
|
||||
|
||||
if escoria.inputs_manager.input_mode != \
|
||||
escoria.inputs_manager.INPUT_NONE and \
|
||||
_dialog_manager != null:
|
||||
|
||||
if not _dialog_manager.is_connected("say_visible", self, "_on_say_visible"):
|
||||
_dialog_manager.connect("say_visible", self, "_on_say_visible", [], CONNECT_ONESHOT)
|
||||
|
||||
_dialog_manager.finish()
|
||||
else:
|
||||
escoria.logger.error(self, "Illegal state.")
|
||||
|
||||
|
||||
func _on_say_visible() -> void:
|
||||
escoria.logger.trace(self, "Dialog State Machine: 'say_finish' -> 'visible'")
|
||||
emit_signal("finished", "visible")
|
||||
@@ -1,35 +0,0 @@
|
||||
extends State
|
||||
class_name DialogVisible
|
||||
|
||||
|
||||
# Reference to the currently playing dialog manager
|
||||
var _dialog_manager: ESCDialogManager = null
|
||||
|
||||
|
||||
func initialize(dialog_manager: ESCDialogManager) -> void:
|
||||
_dialog_manager = dialog_manager
|
||||
|
||||
|
||||
func enter():
|
||||
escoria.logger.trace(self, "Dialog State Machine: Entered 'visible'.")
|
||||
|
||||
if not _dialog_manager.is_connected("say_finished", self, "_on_say_finished"):
|
||||
_dialog_manager.connect("say_finished", self, "_on_say_finished", [], CONNECT_ONESHOT)
|
||||
|
||||
|
||||
func handle_input(_event):
|
||||
if _event is InputEventMouseButton and _event.pressed:
|
||||
if escoria.inputs_manager.input_mode != \
|
||||
escoria.inputs_manager.INPUT_NONE:
|
||||
|
||||
if _dialog_manager.is_connected("say_finished", self, "_on_say_finished"):
|
||||
_dialog_manager.disconnect("say_finished", self, "_on_say_finished")
|
||||
|
||||
emit_signal("finished", "interrupt")
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
|
||||
# Handles the end of a say function after it has emitted say_finished.
|
||||
func _on_say_finished():
|
||||
escoria.logger.trace(self, "Dialog State Machine: 'visible' -> 'finish'")
|
||||
emit_signal("finished", "finish")
|
||||
@@ -302,6 +302,14 @@ func set_escoria_debug_settings():
|
||||
}
|
||||
)
|
||||
|
||||
register_setting(
|
||||
ESCProjectSettingsManager.ENABLE_HOVER_STACK_VIEWER,
|
||||
false,
|
||||
{
|
||||
"type": TYPE_BOOL
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
# Prepare the settings in the Escoria sound settings
|
||||
func set_escoria_sound_settings():
|
||||
|
||||
@@ -81,6 +81,13 @@ func _on_inventory_item_gui_input(event: InputEvent):
|
||||
global_id,
|
||||
event
|
||||
)
|
||||
# Make sure fast right clicks in the inventory aren't ignored
|
||||
elif event.button_index == BUTTON_RIGHT:
|
||||
emit_signal(
|
||||
"mouse_right_inventory_item",
|
||||
global_id,
|
||||
event
|
||||
)
|
||||
else:
|
||||
if event.is_pressed():
|
||||
if event.button_index == BUTTON_LEFT:
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
slot_ui_scene = ExtResource( 2 )
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
@@ -29,7 +32,7 @@ __meta__ = {
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer"]
|
||||
margin_right = 623.0
|
||||
margin_bottom = 276.0
|
||||
margin_bottom = 336.0
|
||||
size_flags_vertical = 3
|
||||
scroll_horizontal_enabled = false
|
||||
__meta__ = {
|
||||
@@ -38,7 +41,7 @@ __meta__ = {
|
||||
|
||||
[node name="slots" type="VBoxContainer" parent="VBoxContainer/ScrollContainer"]
|
||||
margin_right = 623.0
|
||||
margin_bottom = 276.0
|
||||
margin_bottom = 336.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
__meta__ = {
|
||||
@@ -46,9 +49,9 @@ __meta__ = {
|
||||
}
|
||||
|
||||
[node name="back" type="Button" parent="VBoxContainer"]
|
||||
margin_top = 280.0
|
||||
margin_top = 340.0
|
||||
margin_right = 623.0
|
||||
margin_bottom = 300.0
|
||||
margin_bottom = 360.0
|
||||
text = "OPTIONS_BACK"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
|
||||
@@ -14,7 +14,7 @@ func _on_load_game_pressed():
|
||||
$load_game.show()
|
||||
|
||||
|
||||
# Show the optiset_gui_visible trueons panel
|
||||
# Show the options panel
|
||||
func _on_options_pressed():
|
||||
$main.hide()
|
||||
$options.show()
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="load_game" parent="." instance=ExtResource( 5 )]
|
||||
visible = false
|
||||
@@ -41,18 +44,18 @@ __meta__ = {
|
||||
}
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="main/main"]
|
||||
margin_top = 92.0
|
||||
margin_top = 162.0
|
||||
margin_right = 616.0
|
||||
margin_bottom = 318.0
|
||||
margin_bottom = 398.0
|
||||
texture = ExtResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="buttons" type="VBoxContainer" parent="main/main"]
|
||||
margin_top = 418.0
|
||||
margin_top = 498.0
|
||||
margin_right = 616.0
|
||||
margin_bottom = 658.0
|
||||
margin_bottom = 738.0
|
||||
custom_constants/separation = 10
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
|
||||
@@ -25,9 +25,9 @@ __meta__ = {
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer"]
|
||||
margin_left = 391.0
|
||||
margin_top = 265.0
|
||||
margin_top = 340.0
|
||||
margin_right = 888.0
|
||||
margin_bottom = 460.0
|
||||
margin_bottom = 535.0
|
||||
size_flags_horizontal = 6
|
||||
custom_constants/margin_right = 20
|
||||
custom_constants/margin_top = 20
|
||||
@@ -144,9 +144,9 @@ margin_right = 457.0
|
||||
margin_bottom = 155.0
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
|
||||
margin_top = 464.0
|
||||
margin_top = 539.0
|
||||
margin_right = 1280.0
|
||||
margin_bottom = 404.0
|
||||
margin_bottom = 500
|
||||
custom_constants/separation = 20
|
||||
alignment = 1
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
extends CanvasLayer
|
||||
|
||||
onready var list = $VBoxContainer/hover_stack
|
||||
|
||||
func update() -> void:
|
||||
for e in list.get_children():
|
||||
list.remove_child(e)
|
||||
e.queue_free()
|
||||
if escoria.inputs_manager.hover_stack.empty():
|
||||
return
|
||||
for e in escoria.inputs_manager.hover_stack.get_all():
|
||||
var l = Label.new()
|
||||
l.text = e.global_id
|
||||
list.add_child(l)
|
||||
@@ -0,0 +1,27 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/escoria-core/ui_library/tools/hover_stack/hover_stack.gd" type="Script" id=1]
|
||||
|
||||
[node name="hover_stack_layer" type="CanvasLayer"]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
margin_top = 32.0
|
||||
margin_right = 99.0
|
||||
margin_bottom = 72.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="title" type="RichTextLabel" parent="VBoxContainer"]
|
||||
margin_right = 99.0
|
||||
margin_bottom = 18.0
|
||||
size_flags_vertical = 3
|
||||
bbcode_enabled = true
|
||||
bbcode_text = "[u]Hover stack[/u]"
|
||||
text = "Hover stack"
|
||||
|
||||
[node name="hover_stack" type="VBoxContainer" parent="VBoxContainer"]
|
||||
margin_top = 22.0
|
||||
margin_right = 99.0
|
||||
margin_bottom = 40.0
|
||||
size_flags_vertical = 3
|
||||
Reference in New Issue
Block a user