diff options
Diffstat (limited to 'addons/escoria-core/game/scenes')
42 files changed, 2225 insertions, 0 deletions
diff --git a/addons/escoria-core/game/scenes/camera_player/camera.tscn b/addons/escoria-core/game/scenes/camera_player/camera.tscn new file mode 100644 index 0000000..4dc2e9c --- /dev/null +++ b/addons/escoria-core/game/scenes/camera_player/camera.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://dmw5gicuenj53"] + +[ext_resource type="Script" uid="uid://b8xyisawuhtw3" path="res://addons/escoria-core/game/scenes/camera_player/esc_camera.gd" id="1"] + +[node name="camera" type="Camera2D"] +current = true +drag_horizontal_enabled = true +drag_vertical_enabled = true +script = ExtResource("1") diff --git a/addons/escoria-core/game/scenes/camera_player/esc_camera.gd b/addons/escoria-core/game/scenes/camera_player/esc_camera.gd new file mode 100644 index 0000000..6473121 --- /dev/null +++ b/addons/escoria-core/game/scenes/camera_player/esc_camera.gd @@ -0,0 +1,525 @@ +## Camera handling for Escoria scenes. +extends Camera2D +class_name ESCCamera + +## Reference to the tween node for animating camera movements. +var _tween: Tween3: + get = get_tween + +## Target position of the camera. +var _target: Vector2 = Vector2() + +## The object to follow. +var _follow_target: Node = null + +## Target zoom of the camera. +var _zoom_target: Vector2 + +## Prepare the tween for camera movement.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _ready(): + _tween = Tween3.new(self) + _tween.finished.connect(_target_reached) + +## Update the position if the followed target is moving.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |_delta|`Variant`|Frame delta time|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _process(_delta): + if is_instance_valid(_follow_target) and not _tween.is_running() and _follow_target.has_moved(): + self.global_position = _follow_target.global_position + +## Register this camera with the object manager so it can be used before being made active as part of the current scene tree.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |room|`Variant`|The room with which to register the camera|no|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func register(room = null): + escoria.object_manager.register_object( + ESCObject.new( + escoria.object_manager.CAMERA, + self + ), + room, + true + ) + +## The camera's tween instance.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns the camera's tween instance. (`Tween3`) +func get_tween() -> Tween3: + return _tween + +## Sets camera limits so it doesn't go out of the scene.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |limits|`ESCCameraLimits`|The limits to set|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func set_limits(limits: ESCCameraLimits): + self.limit_left = limits.limit_left + self.limit_right = limits.limit_right + self.limit_top = limits.limit_top + self.limit_bottom = limits.limit_bottom + +## Enable or disable drag margins for the camera.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |p_dm_h_enabled|`Variant`|Enable horizontal drag margin|yes|[br] +## |p_dm_v_enabled|`Variant`|Enable vertical drag margin|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func set_drag_margin_enabled(p_dm_h_enabled, p_dm_v_enabled): + self.drag_horizontal_enabled = p_dm_h_enabled + self.drag_vertical_enabled = p_dm_v_enabled + +## Set the target for the camera to move to.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |p_target|`Variant`|Object to target|yes|[br] +## |p_time|`float`|Number of seconds for the camera to reach the target|no|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func set_target(p_target, p_time : float = 0.0): + _resolve_target_and_zoom(p_target) + + escoria.logger.info( + self, + "Current camera position = %s." % str(self.global_position) + ) + + if p_time == 0.0: + self.global_position = _target + else: + # Need to wait a frame in order to ensure the screen centre position is + # recalculated. Also to allow any close-calls with the tween to finish. + await get_tree().process_frame + + if _tween.is_running(): + escoria.logger.debug( + self, + "set_target tween is still active: %f seconds of %s completed." % [ + _tween.get_total_elapsed_time(), + _tween.get_duration() + ] + ) + _tween.stop() + + set_drag_margin_enabled(false, false) + + _convert_current_global_pos_for_disabled_drag_margin() + _target = _convert_pos_for_disabled_drag_margin(_target) + + _tween.interpolate_property( + self, + "global_position", + self.global_position, + _target, + p_time, + Tween.TRANS_LINEAR, + Tween.EASE_IN_OUT + ) + _tween.play() + +## Set the camera zoom level.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |p_zoom_level|`float`|Zoom level to set|yes|[br] +## |p_time|`float`|Number of seconds for the camera to reach the zoom level|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func set_camera_zoom(p_zoom_level: float, p_time: float): + if p_zoom_level <= 0.0: + escoria.logger.error( + self, + "Tried to set negative or zero zoom level." + ) + + _zoom_target = Vector2(1, 1) * p_zoom_level + + if p_time == 0: + self.zoom = _zoom_target + else: + # Need to wait a frame in order to ensure the screen centre position is + # recalculated. Also to allow any close-calls with the tween to finish. + await get_tree().process_frame + + if _tween.is_running(): + escoria.logger.debug( + self, + "set_camera_zoom tween is still active: %f seconds of %s completed." % [ + _tween.get_total_elapsed_time(), + _tween.get_duration() + ] + ) + _tween.stop() + + set_drag_margin_enabled(false, false) + + _convert_current_global_pos_for_disabled_drag_margin() + + _tween.interpolate_property( + self, + "zoom", + self.zoom, + _zoom_target, + p_time, + Tween.TRANS_LINEAR, + Tween.EASE_IN_OUT + ) + _tween.play() + +## Push the camera towards the target in terms of position and zoom level using a given transition type and time. See https://docs.godotengine.org/en/stable/classes/class_tween.html#enumerations[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |p_target|`Variant`|Target to push to|yes|[br] +## |p_time|`float`|Number of seconds for the transition to take|no|[br] +## |p_type|`int`|Tween transition type|no|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func push(p_target, p_time: float = 0.0, p_type: int = 0): + _resolve_target_and_zoom(p_target) + + var push_target = null + + if _follow_target != null: + push_target = p_target.position + else: + push_target = _target + + if p_time == 0: + self.global_position = push_target + + if _zoom_target != Vector2(): + self.zoom = _zoom_target + else: + # Need to wait a frame in order to ensure the screen centre position is + # recalculated. Also to allow any close-calls with the tween to finish. + await get_tree().process_frame + + if _tween.is_running(): + escoria.logger.debug( + self, + "camera push tween is still active: %f seconds of %f completed." % [ + _tween.tell(), + _tween.get_runtime() + ] + ) + _tween.stop() + + if _zoom_target != Vector2(): + _tween.interpolate_property( + self, + "zoom", + self.zoom, + _zoom_target, + p_time, + p_type, + Tween.EASE_IN_OUT + ) + + set_drag_margin_enabled(false, false) + + _convert_current_global_pos_for_disabled_drag_margin() + + _tween.interpolate_property( + self, + "global_position", + self.global_position, + push_target, + p_time, + p_type, + Tween.EASE_IN_OUT + ) + + _tween.play() + +## Shift the camera by the given vector in a given time and using a specific Tween transition type. See https://docs.godotengine.org/en/stable/classes/class_tween.html#enumerations[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |p_target|`Vector2`|Vector to shift the camera by|yes|[br] +## |p_time|`float`|Number of seconds for the transition to take|yes|[br] +## |p_type|`int`|Tween transition type|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func shift(p_target: Vector2, p_time: float, p_type: int): + _follow_target = null + + var new_pos = self.global_position + p_target + _target = new_pos + + if _tween.is_running(): + # Need to wait a frame in order to ensure the screen centre position is + # recalculated. Also to allow any close-calls with the tween to finish. + await get_tree().process_frame + + escoria.logger.debug( + self, + "camera shift tween is still active: %f seconds of %f completed." % [ + _tween.tell(), + _tween.get_runtime() + ] + ) + _tween.stop() + + set_drag_margin_enabled(false, false) + + _convert_current_global_pos_for_disabled_drag_margin() + + _tween.interpolate_property( + self, + "global_position", + self.global_position, + _target, + p_time, + p_type, + Tween.EASE_IN_OUT + ) + _tween.play() + +## Checks whether the given point is contained within the viewport's limits. Note that this is different from the camera's limits when using anchor mode DRAG_CENTER.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |point|`Vector2`|Point to be tested against viewport limits.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns a `bool` value. (`bool`) +func check_point_is_inside_viewport_limits(point: Vector2) -> bool: + var viewport_rect: Rect2 = get_viewport_rect() + var screen_half_size: Vector2 = viewport_rect.size * 0.5 + + var limits_to_test: Rect2 = Rect2( + limit_left + screen_half_size.x, + limit_top + screen_half_size.y, + limit_right - limit_left - viewport_rect.size.x + 1, + limit_bottom - limit_top - viewport_rect.size.y + 1 + ) + + return limits_to_test.has_point(point) + +## The inclusive minimum and maximum values for the x-component of the current valid viewport. Mainly used in any logging messages related to same. the current valid viewport.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns the inclusive minimum and maximum values for the x-component of the current valid viewport. Mainly used in any logging messages related to same. the current valid viewport. (`Array`) +func get_current_valid_viewport_values_x() -> Array: + var viewport_rect: Rect2 = get_viewport_rect() + + return [limit_left + viewport_rect.size.x * 0.5, limit_right - viewport_rect.size.x * 0.5] + +## The inclusive minimum and maximum values for the y-component of the current valid viewport. Mainly used in any logging messages related to same. the current valid viewport.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns the inclusive minimum and maximum values for the y-component of the current valid viewport. Mainly used in any logging messages related to same. the current valid viewport. (`Array`) +func get_current_valid_viewport_values_y() -> Array: + var viewport_rect: Rect2 = get_viewport_rect() + + return [limit_top + viewport_rect.size.y * 0.5, limit_bottom - viewport_rect.size.y * 0.5] + +## The camera's current limits as a Rect2. Mainly used in any logging messages related to same.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns the camera's current limits as a Rect2. Mainly used in any logging messages related to same. (`Rect2`) +func get_camera_limit_rect() -> Rect2: + return Rect2(limit_left, limit_top, limit_right - limit_left, limit_bottom - limit_top) + +## Used when drag margins are enabled. Clamps the camera so it respects the viewport limits inside the camera limits.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func clamp_to_viewport_limits() -> void: + var viewport_rect: Rect2 = get_viewport_rect() + + var cur_camera_pos: Vector2 = self.get_screen_center_position() + var ret_position: Vector2 = cur_camera_pos + + if cur_camera_pos.x - viewport_rect.size.x * 0.5 * zoom.x <= limit_left: + ret_position.x = limit_left + viewport_rect.size.x * 0.5 * zoom.x * (1 + drag_left_margin) + elif cur_camera_pos.x + viewport_rect.size.x * 0.5 * zoom.x >= limit_right: + ret_position.x = limit_right - viewport_rect.size.x * 0.5 * zoom.x * (1 + drag_right_margin) + + if cur_camera_pos.y - viewport_rect.size.y * 0.5 * zoom.y <= limit_top: + ret_position.y = limit_top + viewport_rect.size.y * 0.5 * zoom.y * (1 + drag_top_margin) + elif cur_camera_pos.y + viewport_rect.size.y * 0.5 * zoom.y >= limit_bottom: + ret_position.y = limit_bottom - viewport_rect.size.y * 0.5 * zoom.y * (1 + drag_bottom_margin) + + self.global_position = ret_position + +## Called when the camera's target is reached. Stops and resets the tween, and re-enables drag margins.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _target_reached(): + _tween.stop() + _tween.reset() + set_drag_margin_enabled(true, true) + +## Compensates the camera's current global_position when disabling drag margins. This helps to ensure that when we disable or enable drag margins that the position on the screen is maintained without the camera "jumping". (See https://github.com/godotengine/godot/blob/3.5/scene/2d/camera_2d.cpp for more details.)[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _convert_current_global_pos_for_disabled_drag_margin() -> void: + var cur_camera_pos: Vector2 = self.get_screen_center_position() + var ret_position: Vector2 = _convert_pos_for_disabled_drag_margin(cur_camera_pos) + + self.global_position = ret_position + +## Converts the given position set with drag margins enabled to the same position when calculated with drag margins disabled. This is helpful for preventing the camera from "jumping" when disabling drag margins, e.g. in order to perform some camera translations/tweening. when rendered with drag margins disabled.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |pos|`Vector2`|Position to be converted.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns a `Vector2` value. (`Vector2`) +func _convert_pos_for_disabled_drag_margin(pos: Vector2) -> Vector2: + var viewport_rect: Rect2 = get_viewport_rect() + var ret_position: Vector2 = pos + + # If the current calculated centre of the camera/viewport is close enough to + # the set camera limits (i.e. the centre is upto and including half the + # viewport's size to the limit being tested), then we make sure the + # global_position is at the same coordinates since Camera2D will recalculate + # that position to the exact same position (i.e. no funny math). + # Otherwise, we set the global_position to be the value that would allow + # Camera2D to convert it to the value of the current calculated centre. This + # compensates for the switch when disabling drag margins. + if ret_position.x - viewport_rect.size.x * 0.5 * zoom.x <= limit_left: + ret_position.x = limit_left + viewport_rect.size.x * 0.5 * zoom.x + elif ret_position.x + viewport_rect.size.x * 0.5 * zoom.x >= limit_right: + ret_position.x = limit_right - viewport_rect.size.x * 0.5 * zoom.x + + if ret_position.y - viewport_rect.size.y * 0.5 * zoom.y <= limit_top: + ret_position.y = limit_top + viewport_rect.size.y * 0.5 * zoom.y + elif ret_position.y + viewport_rect.size.y * 0.5 * zoom.y >= limit_bottom: + ret_position.y = limit_bottom - viewport_rect.size.y * 0.5 * zoom.y + + return ret_position + +## Resolve the correct position and zoom of the target object.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |p_target|`Variant`|The target to resolve|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _resolve_target_and_zoom(p_target) -> void: + _target = Vector2() + _zoom_target = Vector2() + _follow_target = null + + if p_target is Node and "is_movable" in p_target and p_target.is_movable: + _follow_target = p_target + + if p_target is Vector2: + _target = p_target + elif p_target is Array and p_target.size() > 0: + var target_pos = Vector2() + + for obj in p_target: + target_pos += obj.get_camera_pos() + + _target = target_pos / p_target.size() + elif p_target.has_method("get_camera_node"): + if "global_position" in p_target.get_camera_node(): + _target = p_target.get_camera_node().global_position + if "zoom" in p_target.get_camera_node(): + _zoom_target = p_target.get_camera_node().zoom + else: + _target = p_target.global_position diff --git a/addons/escoria-core/game/scenes/camera_player/esc_camera.gd.uid b/addons/escoria-core/game/scenes/camera_player/esc_camera.gd.uid new file mode 100644 index 0000000..8c1b7c1 --- /dev/null +++ b/addons/escoria-core/game/scenes/camera_player/esc_camera.gd.uid @@ -0,0 +1 @@ +uid://b8xyisawuhtw3 diff --git a/addons/escoria-core/game/scenes/camera_player/esc_camera_limits.gd b/addons/escoria-core/game/scenes/camera_player/esc_camera_limits.gd new file mode 100644 index 0000000..316e392 --- /dev/null +++ b/addons/escoria-core/game/scenes/camera_player/esc_camera_limits.gd @@ -0,0 +1,40 @@ +## Describes a bounding box that limits the camera movement in the scene. +extends RefCounted +class_name ESCCameraLimits + +## The left side of the bounding box. +var limit_left: int = -10000 + +## The right side of the bounding box. +var limit_right: int = 10000 + +## The top side of the bounding box. +var limit_top: int = -10000 + +## The bottom side of the bounding box. +var limit_bottom: int = 10000 + +## Initializes the camera limits with the given bounding box values.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |left|`int`|The left side of the bounding box|yes|[br] +## |right|`int`|The right side of the bounding box|yes|[br] +## |top|`int`|The top side of the bounding box|yes|[br] +## |bottom|`int`|The bottom side of the bounding box|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _init( + left: int, + right: int, + top: int, + bottom: int +): + limit_left = left + limit_right = right + limit_top = top + limit_bottom = bottom diff --git a/addons/escoria-core/game/scenes/camera_player/esc_camera_limits.gd.uid b/addons/escoria-core/game/scenes/camera_player/esc_camera_limits.gd.uid new file mode 100644 index 0000000..0319263 --- /dev/null +++ b/addons/escoria-core/game/scenes/camera_player/esc_camera_limits.gd.uid @@ -0,0 +1 @@ +uid://dwcagpvytibk5 diff --git a/addons/escoria-core/game/scenes/dialogs/esc_dialog_manager.gd b/addons/escoria-core/game/scenes/dialogs/esc_dialog_manager.gd new file mode 100644 index 0000000..0a00456 --- /dev/null +++ b/addons/escoria-core/game/scenes/dialogs/esc_dialog_manager.gd @@ -0,0 +1,164 @@ +## A base class for dialog plugins to work with Escoria +## @MANAGER +extends Control +class_name ESCDialogManager + +## Emitted when the say function has completed showing the text[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +signal say_finished + +## Emitted when text has just become fully visible[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +signal say_visible + +## Emitted when the player has chosen an option[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |option|`Variant`|Dialog option chosen by the player.|yes|[br] +## [br] +signal option_chosen(option) + +## Checks whether a specific type is supported by the dialog plugin.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |type|`String`|Required type.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns whether the type is supported or not. (`bool`) +func has_type(type: String) -> bool: + return false + +## Checks whether a specific chooser type is supported by the dialog plugin.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |type|`String`|Required chooser type.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns whether the type is supported or not. (`bool`) +func has_chooser_type(type: String) -> bool: + return false + +## Outputs a text said by the item specified by the global id and emits `say_finished` after finishing displaying the text.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |dialog_player|`Node`|Node of the dialog player in the UI.|yes|[br] +## |global_id|`String`|Global id of the item that is speaking.|yes|[br] +## |text|`String`|Text to say, optional prefixed by a translation key separated by a ":".|yes|[br] +## |type|`String`|Type of dialog box to use.|yes|[br] +## |key|`String`|Translation key.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func say(dialog_player: Node, global_id: String, text: String, type: String, key: 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.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +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.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func disable_preserve_dialog_box() -> void: + pass + +## Presents an option chooser to the player and sends the signal `option_chosen` with the chosen dialog option.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |dialog_player|`Node`|Node of the dialog player in the UI.|yes|[br] +## |dialog|`ESCDialog`|Information about the dialog to display.|yes|[br] +## |type|`String`|The dialog chooser type to use.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func choose(dialog_player: Node, dialog: ESCDialog, type: String): + pass + +## Triggers running the dialogue faster.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func speedup(): + pass + +## Triggers an instant finish of the current dialog.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func finish(): + pass + +## The say command has been interrupted, cancel the dialog display.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func interrupt(): + pass + +## To be called if voice audio has finished.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func voice_audio_finished(): + pass diff --git a/addons/escoria-core/game/scenes/dialogs/esc_dialog_manager.gd.uid b/addons/escoria-core/game/scenes/dialogs/esc_dialog_manager.gd.uid new file mode 100644 index 0000000..25eac9e --- /dev/null +++ b/addons/escoria-core/game/scenes/dialogs/esc_dialog_manager.gd.uid @@ -0,0 +1 @@ +uid://xalkeght0hmj diff --git a/addons/escoria-core/game/scenes/dialogs/esc_dialog_options_chooser.gd b/addons/escoria-core/game/scenes/dialogs/esc_dialog_options_chooser.gd new file mode 100644 index 0000000..44e2a3f --- /dev/null +++ b/addons/escoria-core/game/scenes/dialogs/esc_dialog_options_chooser.gd @@ -0,0 +1,60 @@ +## Base class for all dialog options implementations +extends Control +class_name ESCDialogOptionsChooser + +## Emitted when an option is chosen.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |option|`Variant`|The dialog option that was chosen.|yes|[br] +## [br] +signal option_chosen(option) + +## The dialog to show +var dialog: ESCDialog + +## Sets the dialog used for the chooser.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |new_dialog|`ESCDialog`|Dialog to set.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func set_dialog(new_dialog: ESCDialog) -> void: + self.dialog = new_dialog + +## Shows the dialog chooser UI.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func show_chooser() -> void: + escoria.logger.error( + self, + "Dialog chooser does not implement the show method." + ) + +## Hides the dialog chooser UI.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func hide_chooser() -> void: + escoria.logger.error( + self, + "Dialog chooser does not implement the hide method." + ) diff --git a/addons/escoria-core/game/scenes/dialogs/esc_dialog_options_chooser.gd.uid b/addons/escoria-core/game/scenes/dialogs/esc_dialog_options_chooser.gd.uid new file mode 100644 index 0000000..9dbe944 --- /dev/null +++ b/addons/escoria-core/game/scenes/dialogs/esc_dialog_options_chooser.gd.uid @@ -0,0 +1 @@ +uid://c8rd32hdq72l2 diff --git a/addons/escoria-core/game/scenes/dialogs/esc_dialog_player.gd b/addons/escoria-core/game/scenes/dialogs/esc_dialog_player.gd new file mode 100644 index 0000000..70e61e2 --- /dev/null +++ b/addons/escoria-core/game/scenes/dialogs/esc_dialog_player.gd @@ -0,0 +1,256 @@ +## Escoria dialog player +extends Control +class_name ESCDialogPlayer + +## Emitted when an answer is chosen.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |option|`Variant`|The dialog option that was chosen.|yes|[br] +## [br] +signal option_chosen(option) + +## Emitted when a say command finished.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +signal say_finished + + +## Used when specifying dialog types in various methods. +const DIALOG_TYPE_SAY = "say" + +## Used when specifying dialog types in various methods. +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 + +## Registers the dialog player and loads the dialog resources.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _ready(): + if Engine.is_editor_hint(): + return + + escoria.dialog_player = self + +## 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.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func enable_preserve_dialog_box() -> void: + _block_say_enabled = true + +## 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.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func disable_preserve_dialog_box() -> void: + _block_say_enabled = false + _say_dialog_manager.disable_preserve_dialog_box() + +## Makes a character say some text.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |character|`String`|Character that is talking.|yes|[br] +## |type|`String`|UI to use for the dialog.|yes|[br] +## |text|`String`|Text to say.|yes|[br] +## |key|`String`|Translation key.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func say(character: String, type: String, text: String, key: String) -> void: + 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) + + if _block_say_enabled: + _say_dialog_manager.enable_preserve_dialog_box() + + _say_dialog_manager.say(self, character, text, type, key) + + +## Displays a list of choices.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |dialog|`ESCDialog`|The dialog to start.|yes|[br] +## |type|`String`|The dialog chooser type to use (default: "simple").|no|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func start_dialog_choices(dialog: ESCDialog, type: String = "simple"): + # 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) + + +## Interrupts the currently running dialog.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func interrupt() -> void: + if is_instance_valid(_say_dialog_manager): + _say_dialog_manager.interrupt() + + +## Loads the first dialog manager that supports the specified "say" type; otherwise, the engine throws an error and stops.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |type|`String`|The type the dialog manager should support, e.g. "floating".|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +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.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |type|`String`|The type the dialog manager should support, e.g. "simple".|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +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.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |dialog_type|`String`|The type of dialog that will be managed, e.g. "say" or "choose".|yes|[br] +## |current_dialog_manager|`ESCDialogManager`|The dialog manager currently being used (if any) for the specified dialog type.|yes|[br] +## |dialog_manager_type|`String`|Type name of the dialog manager implementation to instantiate.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +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_ancestor_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.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |dialog_type|`String`|The type of dialog that will be managed, e.g. "say" or "choose".|yes|[br] +## |dialog_manager_type|`String`|The dialog manager type specific to the dialog manager being requested.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns the newly-resolved dialog manager. (`ESCDialogManager`) +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 diff --git a/addons/escoria-core/game/scenes/dialogs/esc_dialog_player.gd.uid b/addons/escoria-core/game/scenes/dialogs/esc_dialog_player.gd.uid new file mode 100644 index 0000000..6a97923 --- /dev/null +++ b/addons/escoria-core/game/scenes/dialogs/esc_dialog_player.gd.uid @@ -0,0 +1 @@ +uid://dfl7khtlretr7 diff --git a/addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.gd b/addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.gd new file mode 100644 index 0000000..d538036 --- /dev/null +++ b/addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.gd @@ -0,0 +1,184 @@ +## A debug window which can run esc commands +extends Window + +## Reference to the past actions display +@onready var past_actions = $VBoxContainer/past_actions + +## Reference to the command input +@onready var command = $VBoxContainer/command + +## ESC commands kept around for references to their command names. +var _print: PrintCommand + +## History of typed commands +var commands_history: PackedStringArray + +## The current index in the command history +var commands_history_current_id: int + +## The maximum number of commands to keep in history +const COMMANDS_HISTORY_LENGTH: int = 20 + +## Called when the node is added to the scene tree for the first time.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _ready() -> void: + _print = PrintCommand.new() + escoria.logger.connect("error_message_signal",_on_error_message) + +## Handles input events for command history navigation.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |event|`InputEvent`|The input event to process.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _input(event: InputEvent): + if event.is_pressed() and event is InputEventKey: + if (event as InputEventKey).keycode == KEY_UP and not commands_history.is_empty(): + commands_history_current_id -= 1 + if commands_history_current_id < 0: + commands_history_current_id = 0 + command.text = commands_history[commands_history_current_id] + command.call_deferred("grab_focus") + if (event as InputEventKey).keycode == KEY_DOWN and not commands_history.is_empty(): + commands_history_current_id += 1 + if commands_history_current_id > commands_history.size() - 1: + commands_history_current_id = commands_history.size() - 1 + command.text = commands_history[commands_history_current_id] + command.call_deferred("grab_focus") + + +## Runs a command entered in the prompt.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |p_command_str|`String`|Command to execute.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _on_command_text_entered(p_command_str : String): + if p_command_str.is_empty(): + return + + command.text = "" + past_actions.text += "\n" + past_actions.text += "# " + p_command_str + past_actions.text += "\n" + + _historize_command(p_command_str) + + if p_command_str in ["history", "hist"]: + for ch in commands_history: + past_actions.text += ch + "\n" + return + + _historize_command(p_command_str) + + if p_command_str in ["history", "hist"]: + for ch in commands_history: + past_actions.text += ch + "\n" + return + + _historize_command(p_command_str) + + if p_command_str in ["history", "hist"]: + for ch in commands_history: + past_actions.text += ch + "\n" + return + + var errors = [] + escoria.logger.dont_assert = true + var script = escoria.esc_compiler.compile( + "%s%s" % [ESCEvent.PREFIX, _print.get_command_name(), + p_command_str + ], + get_class() + ) + + if script: + escoria.logger.dont_assert = true + escoria.event_manager.queue_event(script.events[escoria.event_manager.EVENT_PRINT]) + var ret = await escoria.event_manager.event_finished + while ret[1] != _print.get_command_name(): + ret = await escoria.event_manager.event_finished + past_actions.text += "Returned code: %d" % ret[0] + + past_actions.scroll_vertical = past_actions.get_line_count() + + past_actions.scroll_vertical = past_actions.get_line_count() + + past_actions.scroll_vertical = past_actions.get_line_count() + + +## Sets the focus to the command input field.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _on_esc_prompt_popup_about_to_show(): + command.call_deferred("grab_focus") + +## Handles error messages and displays them in the past actions display.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |message|`Variant`|The error message to display.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _on_error_message(message) -> void: + past_actions.text += message + "\n" + past_actions.scroll_vertical = past_actions.get_line_count() + + +## Adds a command to the history and manages the history size.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |p_command|`String`|The command to add to history.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _historize_command(p_command: String) -> void: + commands_history_current_id += 1 + commands_history.append(p_command) + if commands_history.size() + 1 > COMMANDS_HISTORY_LENGTH: + commands_history.remove_at(0) + commands_history_current_id = COMMANDS_HISTORY_LENGTH - 1 + + +## Handles the close request for the prompt popup.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _on_close_requested(): + escoria.main.get_node("layers/debug_layer/esc_prompt_popup").hide() diff --git a/addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.gd.uid b/addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.gd.uid new file mode 100644 index 0000000..b5f9d85 --- /dev/null +++ b/addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.gd.uid @@ -0,0 +1 @@ +uid://d2ek8auf3siqt diff --git a/addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.tscn b/addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.tscn new file mode 100644 index 0000000..08c3239 --- /dev/null +++ b/addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.tscn @@ -0,0 +1,33 @@ +[gd_scene load_steps=2 format=3 uid="uid://b0q36us3uuimq"] + +[ext_resource type="Script" uid="uid://d2ek8auf3siqt" path="res://addons/escoria-core/game/scenes/esc_prompt/esc_prompt_popup.gd" id="1"] + +[node name="esc_prompt_popup" type="Window"] +position = Vector2i(0, 36) +size = Vector2i(500, 300) +visible = false +script = ExtResource("1") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="past_actions" type="TextEdit" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +editable = false +wrap_mode = 1 + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="command" type="LineEdit" parent="VBoxContainer"] +layout_mode = 2 +caret_blink = true + +[connection signal="about_to_popup" from="." to="." method="_on_esc_prompt_popup_about_to_show"] +[connection signal="close_requested" from="." to="." method="_on_close_requested"] +[connection signal="text_submitted" from="VBoxContainer/command" to="." method="_on_command_text_entered"] diff --git a/addons/escoria-core/game/scenes/inventory/inventory_ui.gd b/addons/escoria-core/game/scenes/inventory/inventory_ui.gd new file mode 100644 index 0000000..082c250 --- /dev/null +++ b/addons/escoria-core/game/scenes/inventory/inventory_ui.gd @@ -0,0 +1,197 @@ +## Manages the inventory on the GUI connected to the inventory_ui_container variable. +extends Control +class_name ESCInventory + +## The actual container node to add items as children of. Should be a Container. +@export var inventory_ui_container: NodePath + +## A registry of inventory ESCInventoryItem nodes. +var items_ids_in_inventory: Dictionary = {} + +## Fill the items the player has from the start, do sanity checks and listen when a global has changed.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _ready(): + if inventory_ui_container == null or inventory_ui_container.is_empty(): + escoria.logger.error( + self, + "Inventory items container is empty." + ) + return + + for item_id in escoria.inventory_manager.items_in_inventory(): + call_deferred("add_new_item_by_id", item_id) + + escoria.inventory = self + escoria.globals_manager.global_changed.connect(_on_escoria_global_changed) + +## Add item to Inventory UI using its id set in its scene.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |item_id|`String`|The id of the item to add|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func add_new_item_by_id(item_id: String) -> void: + if item_id.begins_with("i/"): + item_id = item_id.rsplit("i/", false)[0] + if not items_ids_in_inventory.has(item_id): + if not escoria.object_manager.has(item_id) or not is_instance_valid( \ + escoria.object_manager.get_object(item_id).node): + var inventory_file = "%s/%s.tscn" % [ + ESCProjectSettingsManager.get_setting( + ESCProjectSettingsManager.INVENTORY_ITEMS_PATH + ).trim_suffix("/"), + item_id + ] + if ResourceLoader.exists(inventory_file): + escoria.object_manager.register_object( + ESCObject.new( + item_id, + ResourceLoader.load(inventory_file).instantiate() + ), + null, + true + ) + else: + escoria.logger.error( + self, + ( + "Item global id '%s' is not registered because the item's scene file was not found.\n" + + "Attempted scene file path: %s.\n" + + "Please ensure that the '%s' project setting points at **your inventory items folder** (current is: \"%s\")." + ) + % [ + item_id, + inventory_file, + ESCProjectSettingsManager.INVENTORY_ITEMS_PATH, + ESCProjectSettingsManager.get_setting( + ESCProjectSettingsManager.INVENTORY_ITEMS_PATH + ) + ] + ) + + var inventory_item = escoria.di.esc_inventory_item( + escoria.object_manager.get_object(item_id).node + ) + var inventory_item_button = get_node( + inventory_ui_container + ).add_item(inventory_item) + + items_ids_in_inventory[item_id] = inventory_item + + if not escoria.object_manager.has(item_id): + escoria.object_manager.register_object( + ESCObject.new( + item_id, + inventory_item_button + ), + null, + true + ) + + escoria.inputs_manager.register_inventory_item(inventory_item_button) + +## Remove item from Inventory UI using its id set in its scene.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |item_id|`String`|The id of the item to remove|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func remove_item_by_id(item_id: String) -> void: + if items_ids_in_inventory.has(item_id): + var item_inventory = items_ids_in_inventory[item_id] + var item_inventory_button = get_node( + inventory_ui_container + ).get_inventory_button(item_inventory) + + if item_inventory_button.mouse_left_inventory_item.is_connected( + escoria.inputs_manager._on_mouse_left_click_inventory_item + ): + item_inventory_button.mouse_left_inventory_item.disconnect( + escoria.inputs_manager._on_mouse_left_click_inventory_item + ) + if item_inventory_button.mouse_double_left_inventory_item.is_connected( + escoria.inputs_manager._on_mouse_double_left_click_inventory_item + ): + item_inventory_button.mouse_double_left_inventory_item.disconnect( + escoria.inputs_manager._on_mouse_double_left_click_inventory_item + ) + if item_inventory_button.mouse_right_inventory_item.is_connected( + escoria.inputs_manager._on_mouse_right_click_inventory_item + ): + item_inventory_button.mouse_right_inventory_item.disconnect( + escoria.inputs_manager._on_mouse_right_click_inventory_item + ) + if item_inventory_button.inventory_item_focused.is_connected( + escoria.inputs_manager._on_mouse_entered_inventory_item + ): + item_inventory_button.inventory_item_focused.disconnect( + escoria.inputs_manager._on_mouse_entered_inventory_item + ) + if item_inventory_button.inventory_item_unfocused.is_connected( + escoria.inputs_manager._on_mouse_exited_inventory_item + ): + item_inventory_button.inventory_item_unfocused.disconnect( + escoria.inputs_manager._on_mouse_exited_inventory_item + ) + + get_node(inventory_ui_container).remove_item(item_inventory) + items_ids_in_inventory.erase(item_id) + +## React to changes to inventory globals adding items or removing them.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |global|`String`|The global variable name|yes|[br] +## |old_value|`Variant`|The old value of the global|yes|[br] +## |new_value|`Variant`|The new value of the global|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _on_escoria_global_changed(global: String, old_value, new_value) -> void: + if !global.begins_with("i/"): + return + var item = global.rsplit("i/", false) + if item.size() == 1: + if new_value: + add_new_item_by_id(item[0]) + else: + remove_item_by_id(item[0]) + else: + escoria.logger.error( + self, + "Global must contain only one item name (received: %s)." % global + ) + +## Clear the inventory UI of all its items.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func clear() -> void: + var items_in_inventory_keys: Array = items_ids_in_inventory.keys() + for item_id in items_in_inventory_keys: + remove_item_by_id(item_id) diff --git a/addons/escoria-core/game/scenes/inventory/inventory_ui.gd.uid b/addons/escoria-core/game/scenes/inventory/inventory_ui.gd.uid new file mode 100644 index 0000000..0184ef8 --- /dev/null +++ b/addons/escoria-core/game/scenes/inventory/inventory_ui.gd.uid @@ -0,0 +1 @@ +uid://b1l4nnky23hwo diff --git a/addons/escoria-core/game/scenes/sound/esc_ambient_player.gd b/addons/escoria-core/game/scenes/sound/esc_ambient_player.gd new file mode 100644 index 0000000..298e7db --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_ambient_player.gd @@ -0,0 +1,61 @@ +## Background ambient sound player +extends Control +class_name ESCAmbientPlayer + +## Global id of the background ambient sound player. +@export var global_id: String = "_ambient" + +## The state of the music player. "default" or "off" disable music. Any other +## state refers to a music stream that should be played. +var state: String = "default" + +## Reference to the audio player. +@onready var stream: AudioStreamPlayer = $AudioStreamPlayer + +## Sets the state of this player.[br] +## [br] +## #### Parameters[br] +## [br] +## - p_state: New state to use.[br] +## - from_seconds: Sets the starting playback position.[br] +## - p_force: Override the existing state even if the stream is still playing. +func set_state(p_state: String, from_seconds: float = 0.0, p_force: bool = false) -> void: + # If already playing this stream, keep playing, unless p_force + if p_state == state and not p_force and stream.is_playing(): + return + + state = p_state + + # If state is "off"/"default", turn off music + if state == "off" or state == "default": + stream.stream = null + return + + var resource = load(p_state) + + stream.stream = resource + + if stream.stream: + if resource is AudioStreamWAV: + resource.loop_mode = AudioStreamWAV.LOOP_FORWARD + resource.loop_end = resource.mix_rate * resource.get_length() + elif "loop" in resource: + resource.loop = true + stream.play(from_seconds) + + +## Registers this music player to the object registry. +func _ready(): + process_mode = Node.PROCESS_MODE_PAUSABLE + escoria.object_manager.register_object( + ESCObject.new(global_id, self), + null, + true + ) + + +## Returns the playback position of the audio stream in seconds.[br] +## [br] +## *Returns* the playback position as a float value. +func get_playback_position() -> float: + return $AudioStreamPlayer.get_playback_position() diff --git a/addons/escoria-core/game/scenes/sound/esc_ambient_player.gd.uid b/addons/escoria-core/game/scenes/sound/esc_ambient_player.gd.uid new file mode 100644 index 0000000..7a20f5b --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_ambient_player.gd.uid @@ -0,0 +1 @@ +uid://b6kjfij1s1lpb diff --git a/addons/escoria-core/game/scenes/sound/esc_ambient_player.tscn b/addons/escoria-core/game/scenes/sound/esc_ambient_player.tscn new file mode 100644 index 0000000..ca4f039 --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_ambient_player.tscn @@ -0,0 +1,19 @@ +[gd_scene load_steps=2 format=3 uid="uid://wsdpiju6bxqd"] + +[ext_resource type="Script" uid="uid://b6kjfij1s1lpb" path="res://addons/escoria-core/game/scenes/sound/esc_ambient_player.gd" id="1_ih1im"] + +[node name="bg_ambient" type="Control"] +process_mode = 3 +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = -1680.0 +offset_bottom = -1050.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +script = ExtResource("1_ih1im") + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] +bus = &"Ambient" diff --git a/addons/escoria-core/game/scenes/sound/esc_music_player.gd b/addons/escoria-core/game/scenes/sound/esc_music_player.gd new file mode 100644 index 0000000..b8f6c45 --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_music_player.gd @@ -0,0 +1,81 @@ +## Background music player +extends Control +class_name ESCMusicPlayer + +## Global id of the background music player. +@export var global_id: String = "_music" + +## The state of the music player. "default" or "off" disable music. Any other +## state refers to a music stream that should be played. +var state: String = "default" + +## Reference to the audio player. +@onready var stream: AudioStreamPlayer = $AudioStreamPlayer + +## Sets the state of this player.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |p_state|`String`|New state to use.|yes|[br] +## |from_seconds|`float`|Sets the starting playback position.|no|[br] +## |p_force|`bool`|Override the existing state even if the stream is still playing.|no|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func set_state(p_state: String, from_seconds: float = 0.0, p_force: bool = false) -> void: + # If already playing this stream, keep playing, unless p_force + if p_state == state and not p_force and stream.is_playing(): + return + + state = p_state + + # If state is "off"/"default", turn off music + if state == "off" or state == "default": + stream.stream = null + return + + var resource = load(p_state) + + stream.stream = resource + + if stream.stream: + if resource is AudioStreamWAV: + resource.loop_mode = AudioStreamWAV.LOOP_FORWARD + resource.loop_end = resource.mix_rate * resource.get_length() + elif "loop" in resource: + resource.loop = true + stream.play(from_seconds) + + +## Registers this music player to the object registry.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _ready(): + process_mode = Node.PROCESS_MODE_PAUSABLE + escoria.object_manager.register_object( + ESCObject.new(global_id, self), + null, + true + ) + + +## The playback position of the audio stream in seconds.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns the playback position of the audio stream in seconds. the playback position as a float value. (`float`) +func get_playback_position() -> float: + return $AudioStreamPlayer.get_playback_position() diff --git a/addons/escoria-core/game/scenes/sound/esc_music_player.gd.uid b/addons/escoria-core/game/scenes/sound/esc_music_player.gd.uid new file mode 100644 index 0000000..50d1f36 --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_music_player.gd.uid @@ -0,0 +1 @@ +uid://ch8x1lue4qy34 diff --git a/addons/escoria-core/game/scenes/sound/esc_music_player.tscn b/addons/escoria-core/game/scenes/sound/esc_music_player.tscn new file mode 100644 index 0000000..5e71381 --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_music_player.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=2 format=3 uid="uid://c1txn45mpksqd"] + +[ext_resource type="Script" uid="uid://ch8x1lue4qy34" path="res://addons/escoria-core/game/scenes/sound/esc_music_player.gd" id="1"] + +[node name="bg_music" type="Control"] +process_mode = 3 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = -1680.0 +offset_bottom = -1050.0 +mouse_filter = 2 +script = ExtResource("1") + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] +bus = "Music" diff --git a/addons/escoria-core/game/scenes/sound/esc_sound_player.gd b/addons/escoria-core/game/scenes/sound/esc_sound_player.gd new file mode 100644 index 0000000..2a9fa64 --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_sound_player.gd @@ -0,0 +1,93 @@ +## Background sound player +extends Control +class_name ESCSoundPlayer + +## Global id of the sfx sound player. +@export var global_id: String = "_sound" + +## The state of the sound player. "default" or "off" disable sound. Any other +## state refers to a sound stream that should be played. +var state: String = "default" + +## Reference to the audio player. +@onready var stream: AudioStreamPlayer = $AudioStreamPlayer + +## Sets the state of this player.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |p_state|`String`|New state to use.|yes|[br] +## |from_seconds|`float`|Sets the starting playback position.|no|[br] +## |p_force|`bool`|Override the existing state even if the stream is still playing.|no|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func set_state(p_state: String, from_seconds: float = 0.0, p_force: bool = false): + # If already playing this stream, keep playing, unless p_force + if p_state == state and not p_force and stream.is_playing(): + return + + state = p_state + + # If state is "off"/"default", turn off music + if state == "off" or state == "default": + stream.stream = null + return + + var resource = load(p_state) + + stream.stream = resource + + if stream.stream: + if resource is AudioStreamWAV: + resource.loop_mode = AudioStreamWAV.LOOP_DISABLED + elif "loop" in resource: + resource.loop = false + stream.play(from_seconds) + + +## Registers this sound player to the object registry.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _ready(): + process_mode = Node.PROCESS_MODE_PAUSABLE + escoria.object_manager.register_object( + ESCObject.new(global_id, self), + null, + true + ) + + +## Sets state to default when finished playing.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _on_sound_finished(): + state = "default" + + +## The playback position of the audio stream in seconds.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns the playback position of the audio stream in seconds. The playback position in seconds. (`float`) +func get_playback_position() -> float: + return $AudioStreamPlayer.get_playback_position() diff --git a/addons/escoria-core/game/scenes/sound/esc_sound_player.gd.uid b/addons/escoria-core/game/scenes/sound/esc_sound_player.gd.uid new file mode 100644 index 0000000..2831142 --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_sound_player.gd.uid @@ -0,0 +1 @@ +uid://b4fkhx0prl41e diff --git a/addons/escoria-core/game/scenes/sound/esc_sound_player.tscn b/addons/escoria-core/game/scenes/sound/esc_sound_player.tscn new file mode 100644 index 0000000..984e040 --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_sound_player.tscn @@ -0,0 +1,20 @@ +[gd_scene load_steps=2 format=3 uid="uid://uwqpnwjmp6aq"] + +[ext_resource type="Script" uid="uid://b4fkhx0prl41e" path="res://addons/escoria-core/game/scenes/sound/esc_sound_player.gd" id="1"] + +[node name="bg_sound" type="Control"] +process_mode = 3 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = -1680.0 +offset_bottom = -1050.0 +mouse_filter = 2 +script = ExtResource("1") +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] +bus = "SFX" + +[connection signal="finished" from="AudioStreamPlayer" to="." method="_on_sound_finished"] diff --git a/addons/escoria-core/game/scenes/sound/esc_speech_player.gd b/addons/escoria-core/game/scenes/sound/esc_speech_player.gd new file mode 100644 index 0000000..31fc668 --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_speech_player.gd @@ -0,0 +1,111 @@ +## Speech player +extends Control +class_name ESCSpeechPlayer + +## Global id of the speech player. +@export var global_id: String = "_speech" + +## Reference to the audio player. +@onready var stream: AudioStreamPlayer = $AudioStreamPlayer + +## Sets the state of this player.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |p_state|`String`|New state to use.|yes|[br] +## |from_seconds|`float`|Sets the starting playback position.|no|[br] +## |p_force|`bool`|Override the existing state even if the stream is still playing.|no|[br] +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func set_state(p_state: String, from_seconds: float = 0.0, p_force: bool = false) -> void: + # If speech is disabled, return + if not ESCProjectSettingsManager.get_setting( + ESCProjectSettingsManager.SPEECH_ENABLED + ): + return + + # If state is "off"/"default", turn off speech + if p_state in ["off", "default"]: + stream.stream = null + return + + var resource = load(p_state) + stream.stream = resource + + if stream.stream: + stream.stream.set_loop(false) + $AudioStreamPlayer.play(from_seconds) + + +## Registers this speech player to the object registry.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _ready(): + process_mode = Node.PROCESS_MODE_PAUSABLE + escoria.object_manager.register_object( + ESCObject.new(global_id, self), + null, + true + ) + + +## Callback called when the audio stream player finished playing.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _on_AudioStreamPlayer_finished() -> void: + set_state("off") + + +## Pauses the speech player.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func pause(): + stream.stream_paused = true + + +## Unpauses the speech player.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func resume(): + stream.stream_paused = false + + +## The playback position of the audio stream in seconds.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns the playback position of the audio stream in seconds. The playback position in seconds. (`float`) +func get_playback_position() -> float: + return $AudioStreamPlayer.get_playback_position() diff --git a/addons/escoria-core/game/scenes/sound/esc_speech_player.gd.uid b/addons/escoria-core/game/scenes/sound/esc_speech_player.gd.uid new file mode 100644 index 0000000..63a6af9 --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_speech_player.gd.uid @@ -0,0 +1 @@ +uid://6aijk4hl0t0o diff --git a/addons/escoria-core/game/scenes/sound/esc_speech_player.tscn b/addons/escoria-core/game/scenes/sound/esc_speech_player.tscn new file mode 100644 index 0000000..2142df8 --- /dev/null +++ b/addons/escoria-core/game/scenes/sound/esc_speech_player.tscn @@ -0,0 +1,18 @@ +[gd_scene load_steps=2 format=3 uid="uid://c8ecyitwga1dx"] + +[ext_resource type="Script" uid="uid://6aijk4hl0t0o" path="res://addons/escoria-core/game/scenes/sound/esc_speech_player.gd" id="1"] + +[node name="Control" type="Control"] +process_mode = 3 +anchor_right = 1.0 +anchor_bottom = 1.0 +mouse_filter = 2 +script = ExtResource("1") +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] +bus = "Speech" + +[connection signal="finished" from="AudioStreamPlayer" to="." method="_on_AudioStreamPlayer_finished"] diff --git a/addons/escoria-core/game/scenes/transitions/esc_transition_player.gd b/addons/escoria-core/game/scenes/transitions/esc_transition_player.gd new file mode 100644 index 0000000..40b0b61 --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/esc_transition_player.gd @@ -0,0 +1,195 @@ +## A transition player for scene changes +extends ColorRect +class_name ESCTransitionPlayer + +## Emitted when the transition was played[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |transition_id|`Variant`|Identifier of the transition that completed.|yes|[br] +## [br] +signal transition_done(transition_id) + +## The valid transition modes +enum TRANSITION_MODE { + IN, + OUT +} + +## Id to represent instant/no transitions +const TRANSITION_ID_INSTANT = -1 + +## Instant transition type +const TRANSITION_INSTANT = "instant" + +## Id of the transition. Allows keeping track of the actual transition +## being played or finished +var transition_id: int = 0 + +## The tween instance to animate +var _tween: Tween3 + +## If the current tween was canceled +var _was_canceled: bool = false + +## Fade in when the scene is starting[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _ready() -> void: + anchor_left = 0 + anchor_top = 0 + anchor_right = 1 + anchor_bottom = 1 + color = Color.WHITE + color.a = 0 + mouse_filter = MOUSE_FILTER_IGNORE + _tween = Tween3.new(self) + +## Play a transition animation[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |transition_name|`String`|Name of the transition to play (if empty string, uses the default transition).|no|[br] +## |mode|`int`|Mode to transition (in/out).|no|[br] +## |duration|`float`|The duration the transition should take.|no|[br] +## [br] +## #### Returns[br] +## [br] +## Returns the transition id. (`int`) +func transition( + transition_name: String = "", + mode: int = TRANSITION_MODE.IN, + duration: float = 1.0 +) -> int: + + # We put this here instead of the constructor since if we have it in the + # constructor, the transition will ALWAYS happen on game start, which might + # not be desired if 'false' is used for automatic_transitions in a + # change_scene call in :init. + if not _tween.finished.is_connected(_on_tween_completed): + _tween.finished.connect(_on_tween_completed) + + if transition_name.is_empty(): + transition_name = ESCProjectSettingsManager.get_setting( + ESCProjectSettingsManager.DEFAULT_TRANSITION + ) + + if not has_transition(transition_name): + escoria.logger.error( + self, + "transition: Transition %s not found" % transition_name + ) + + # If this is an "instant" transition, we need to set the alpha of the base + # ColorRect to 0, since the transition materials used have a final state + # that sets this scene's root (ColorRect) alpha to 0. + if transition_name == TRANSITION_INSTANT: + color.a = 0 + return TRANSITION_ID_INSTANT + + var material_path = get_transition(transition_name) + + material = ResourceLoader.load(get_transition(transition_name)) + transition_id += 1 + + var start = 0.0 + var end = 1.0 + + if mode == TRANSITION_MODE.OUT: + start = 1.0 + end = 0.0 + + if _tween.is_running(): + _was_canceled = true + _tween.stop() + _tween.reset() + transition_done.emit(transition_id-1) + + _tween.interpolate_property( + $".", + "material:shader_parameter/cutoff", + start, + end, + duration + ) + _was_canceled = false + _tween.play() + return transition_id + + +## The full path for a transition shader based on its name[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |name|`String`|Transition name whose material path should be resolved.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns the full path for a transition shader based on its name the full path to the shader or an empty string if it can't be found. (`String`) +func get_transition(name: String) -> String: + for directory in ESCProjectSettingsManager.get_setting( + ESCProjectSettingsManager.TRANSITION_PATHS + ): + if ResourceLoader.exists(directory.path_join("%s.material" % name)): + return directory.path_join("%s.material" % name) + return "" + + +## True whether the transition scene has a transition corresponding to name provided.[br] +## [br] +## #### Parameters[br] +## [br] +## | Name | Type | Description | Required? |[br] +## |:-----|:-----|:------------|:----------|[br] +## |name|`String`|Transition name to check for availability.|yes|[br] +## [br] +## #### Returns[br] +## [br] +## Returns true whether the transition scene has a transition corresponding to name provided. true if a transition exists with given name. (`bool`) +func has_transition(name: String) -> bool: + return name == TRANSITION_INSTANT or get_transition(name) != "" + + +## Resets the current material's cutoff parameter instantly.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func reset_shader_cutoff() -> void: + if not is_instance_valid(material): + return + + material.set_shader_parameter("cutoff", 1.0) + + +## Called when the tween completes the transition.[br] +## [br] +## #### Parameters[br] +## [br] +## None. +## [br] +## #### Returns[br] +## [br] +## Returns nothing. +func _on_tween_completed(): + if not _was_canceled: + _tween.stop() + _tween.reset() + escoria.logger.debug(self, "Transition %s done." % str(transition_id)) + transition_done.emit(transition_id) diff --git a/addons/escoria-core/game/scenes/transitions/esc_transition_player.gd.uid b/addons/escoria-core/game/scenes/transitions/esc_transition_player.gd.uid new file mode 100644 index 0000000..435545c --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/esc_transition_player.gd.uid @@ -0,0 +1 @@ +uid://bo0xyume0yqcc diff --git a/addons/escoria-core/game/scenes/transitions/masks/curtain.png b/addons/escoria-core/game/scenes/transitions/masks/curtain.png Binary files differnew file mode 100644 index 0000000..befa82a --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/masks/curtain.png diff --git a/addons/escoria-core/game/scenes/transitions/masks/curtain.png.import b/addons/escoria-core/game/scenes/transitions/masks/curtain.png.import new file mode 100644 index 0000000..4766f6d --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/masks/curtain.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://djebg0o8s418r" +path="res://.godot/imported/curtain.png-fd4a78beb232b0a99b1a008eb4a104fd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/escoria-core/game/scenes/transitions/masks/curtain.png" +dest_files=["res://.godot/imported/curtain.png-fd4a78beb232b0a99b1a008eb4a104fd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/escoria-core/game/scenes/transitions/masks/from_center.png b/addons/escoria-core/game/scenes/transitions/masks/from_center.png Binary files differnew file mode 100644 index 0000000..1c28b7a --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/masks/from_center.png diff --git a/addons/escoria-core/game/scenes/transitions/masks/from_center.png.import b/addons/escoria-core/game/scenes/transitions/masks/from_center.png.import new file mode 100644 index 0000000..9d28061 --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/masks/from_center.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvkmesi350a3d" +path="res://.godot/imported/from_center.png-5a7489c4008ce50848f1d5c7238d9315.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/escoria-core/game/scenes/transitions/masks/from_center.png" +dest_files=["res://.godot/imported/from_center.png-5a7489c4008ce50848f1d5c7238d9315.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/escoria-core/game/scenes/transitions/masks/shards.png b/addons/escoria-core/game/scenes/transitions/masks/shards.png Binary files differnew file mode 100644 index 0000000..1d62b47 --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/masks/shards.png diff --git a/addons/escoria-core/game/scenes/transitions/masks/shards.png.import b/addons/escoria-core/game/scenes/transitions/masks/shards.png.import new file mode 100644 index 0000000..180b89a --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/masks/shards.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dpfnq2e14vwbg" +path="res://.godot/imported/shards.png-a75d64f3ee4c4b3daca9792e71d7f91f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/escoria-core/game/scenes/transitions/masks/shards.png" +dest_files=["res://.godot/imported/shards.png-a75d64f3ee4c4b3daca9792e71d7f91f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/escoria-core/game/scenes/transitions/shaders/curtain.material b/addons/escoria-core/game/scenes/transitions/shaders/curtain.material Binary files differnew file mode 100644 index 0000000..7ad0fab --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/shaders/curtain.material diff --git a/addons/escoria-core/game/scenes/transitions/shaders/fade_black.material b/addons/escoria-core/game/scenes/transitions/shaders/fade_black.material Binary files differnew file mode 100644 index 0000000..d0a7528 --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/shaders/fade_black.material diff --git a/addons/escoria-core/game/scenes/transitions/shaders/fade_white.material b/addons/escoria-core/game/scenes/transitions/shaders/fade_white.material Binary files differnew file mode 100644 index 0000000..8cc21c9 --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/shaders/fade_white.material diff --git a/addons/escoria-core/game/scenes/transitions/shaders/from_center.material b/addons/escoria-core/game/scenes/transitions/shaders/from_center.material Binary files differnew file mode 100644 index 0000000..acf5a47 --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/shaders/from_center.material diff --git a/addons/escoria-core/game/scenes/transitions/shaders/shards.material b/addons/escoria-core/game/scenes/transitions/shaders/shards.material Binary files differnew file mode 100644 index 0000000..f9027b1 --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/shaders/shards.material diff --git a/addons/escoria-core/game/scenes/transitions/transition.tscn b/addons/escoria-core/game/scenes/transitions/transition.tscn new file mode 100644 index 0000000..84c8dbb --- /dev/null +++ b/addons/escoria-core/game/scenes/transitions/transition.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=3 format=3 uid="uid://dep0fi7t7av8"] + +[ext_resource type="Script" uid="uid://bo0xyume0yqcc" path="res://addons/escoria-core/game/scenes/transitions/esc_transition_player.gd" id="1"] +[ext_resource type="Material" uid="uid://bwr4fkt0w426g" path="res://addons/escoria-core/game/scenes/transitions/shaders/curtain.material" id="2"] + +[node name="scene_transition" type="ColorRect"] +material = ExtResource("2") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +mouse_filter = 2 +script = ExtResource("1") |
