relocate addons

This commit is contained in:
2024-02-12 23:38:18 +01:00
parent f678fb7d5f
commit b65b5806f5
75 changed files with 41 additions and 25 deletions

1
addons
View File

@@ -1 +0,0 @@
../escoria-demo-game/addons/

1
addons/escoria-core Symbolic link
View File

@@ -0,0 +1 @@
../../escoria-demo-game/addons/escoria-core

View File

@@ -0,0 +1,100 @@
# A simple dialog chooser that shows selectable lines of text
# Supports timeout and avatar display
extends ESCDialogOptionsChooser
export(Color, RGB) var color_normal = Color(1.0,1.0,1.0,1.0)
export(Color, RGB) var color_hover = Color(165.0,42.0,42.0, 1.0)
var _no_more_options: bool = false
# Hide the chooser at the start just to be safe
func _ready() -> void:
hide_chooser()
pause_mode = PAUSE_MODE_STOP
# Process the timeout display
func _process(delta: float) -> void:
if $MarginContainer.visible and self.dialog and self.dialog.timeout > 0:
$TimerProgress.value = (
self.dialog.timeout - $Timer.time_left
) / self.dialog.timeout * 100
# Show the chooser
func show_chooser():
var _vbox = $MarginContainer/ScrollContainer/VBoxContainer
for option_node in _vbox.get_children():
_vbox.remove_child(option_node)
_remove_avatar()
for option in self.dialog.options:
if option.is_valid():
var _option_node = Button.new()
_option_node.text = (option as ESCDialogOption).option
_option_node.flat = true
_option_node.add_color_override("font_color", color_normal)
_option_node.add_color_override("font_color_hover", color_hover)
_vbox.add_child(_option_node)
_option_node.connect("pressed", self, "_on_answer_selected", [
option
])
# If we've no options left, signify as much and start the timer with a
# very short interval so the appropriate signal can be fired. Note that
# we have to fire the signal AFTER this method returns as the caller
# is almost certainly yielding after this method returns.
if _vbox.get_child_count() == 0:
_no_more_options = true
$Timer.start(0.05)
return
if self.dialog.avatar != "-":
$AvatarContainer.add_child(
ResourceLoader.load(self.dialog.avatar).instance()
)
$MarginContainer.show()
if self.dialog.timeout > 0:
$Timer.start(self.dialog.timeout)
# Hide the chooser
func hide_chooser():
$MarginContainer.hide()
# An option was choosen, emit the option
#
# #### Parameters
# - option: Option that was chosen
func _option_chosen(option: ESCDialogOption):
_remove_avatar()
$TimerProgress.value = 0
emit_signal("option_chosen", option)
# An option was chosen directly from the list
#
# #### Parameters
# - option: Option that was chosen
func _on_answer_selected(option: ESCDialogOption):
_option_chosen(option)
# The timeout came and a option was selected
func _on_Timer_timeout() -> void:
var option_chosen = null if _no_more_options else self.dialog.options[self.dialog.timeout_option - 1]
_no_more_options = false
_option_chosen(option_chosen)
# Remove the avatar
func _remove_avatar():
if $AvatarContainer.get_child_count() > 0:
$AvatarContainer.remove_child($AvatarContainer.get_child(0))

View File

@@ -0,0 +1,61 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/chooser/simple.gd" type="Script" id=1]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/theme.tres" type="Theme" id=2]
[sub_resource type="Gradient" id=1]
colors = PoolColorArray( 1, 0, 0, 1, 1, 0, 0, 1 )
[sub_resource type="GradientTexture" id=2]
gradient = SubResource( 1 )
[node name="text_dialog_choice" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_top = 560.0
margin_right = 7.0
theme = ExtResource( 2 )
script = ExtResource( 1 )
[node name="MarginContainer" type="MarginContainer" parent="."]
margin_left = 20.0
margin_top = 10.0
margin_right = 1280.0
margin_bottom = 185.0
mouse_filter = 2
custom_constants/margin_top = 20
custom_constants/margin_left = 20
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer"]
margin_left = 20.0
margin_top = 20.0
margin_right = 1260.0
margin_bottom = 175.0
scroll_horizontal_enabled = false
__meta__ = {
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/ScrollContainer"]
margin_right = 1240.0
margin_bottom = 155.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_constants/separation = 10
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Timer" type="Timer" parent="."]
one_shot = true
[node name="TimerProgress" type="TextureProgress" parent="."]
anchor_right = 1.0
rect_min_size = Vector2( 0, 20 )
texture_progress = SubResource( 2 )
nine_patch_stretch = true
[node name="AvatarContainer" type="Node2D" parent="."]
position = Vector2( 94, 68 )
[connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"]

View File

@@ -0,0 +1,50 @@
# `say_last_dialog_option`
#
# Current player says the text of the last selected dialog option.
#
# @ESC
extends ESCBaseCommand
class_name SayLastDialogOptionCommand
# Return the descriptor of the arguments of this command
func configure() -> ESCCommandArgumentDescriptor:
return ESCCommandArgumentDescriptor.new()
# Run the command
func run(_command_params: Array) -> int:
escoria.current_state = escoria.GAME_STATE.DIALOG
if !escoria.dialog_player:
escoria.logger.error(
self,
"[%s]: No dialog player was registered and the say command was encountered."
% get_command_name()
)
escoria.current_state = escoria.GAME_STATE.DEFAULT
return ESCExecution.RC_ERROR
if not escoria.main.current_scene.player:
escoria.logger.warn(
self,
"[%s]: No player item in the current scene was registered and the say command was encountered."
% get_command_name()
)
escoria.current_state = escoria.GAME_STATE.DEFAULT
return ESCExecution.RC_CANCEL
var last_chosen_option = escoria.globals_manager.get_global("ESC_DIALOG_CHOSEN_OPTION")
# Surround text with quotes. Required by escoria.dialog_player.say()
var text = "\"%s\"" % last_chosen_option
var speaking_character_global_id = escoria.main.current_scene.player.global_id
escoria.dialog_player.say(
speaking_character_global_id,
"",
text
)
yield(escoria.dialog_player, "say_finished")
escoria.current_state = escoria.GAME_STATE.DEFAULT
return ESCExecution.RC_OK

View File

@@ -0,0 +1,126 @@
# `say_random global_id list_id lenght`
#
# Displays the specified string as dialog spoken by the player. This command
# blocks further event execution until the dialog has finished being 'said'
# (either as displayed text or as audible speech from a file).
#
# Global variables can be substituted into the text by wrapping the global
# name in braces.
# e.g. say player "I have {coin_count} coins remaining".
#
# **Parameters**
#
# - *player*: Global ID of the `ESCPlayer` or `ESCItem` object that is active.
# You can specify `current_player` in order to refer to the currently active
# player, e.g. in cases where multiple players are playable such as in games
# like Maniac Mansion or Day of the Tentacle.
# - *randomizer_list_id*: ID for the list of sentences.
# - *lenght*: lenght of the list.
#
# Example: `say_random player random_list 4`
#
# @ESC
extends ESCBaseCommand
class_name SayRandomCommand
const CURRENT_PLAYER_KEYWORD = "CURRENT_PLAYER"
var rng: RandomNumberGenerator
# Constructor
func _init() -> void:
rng = RandomNumberGenerator.new()
# Return the descriptor of the arguments of this command
func configure() -> ESCCommandArgumentDescriptor:
return ESCCommandArgumentDescriptor.new(
3,
[TYPE_STRING, TYPE_STRING, TYPE_INT],
[
null,
null,
null
],
[
true,
false,
false
]
)
# Validate whether the given arguments match the command descriptor
func validate(arguments: Array):
if not .validate(arguments):
return false
if arguments[0].to_upper() != CURRENT_PLAYER_KEYWORD \
and not escoria.object_manager.has(arguments[0]):
escoria.logger.error(
self,
"[%s]: Invalid object: Object with global id %s not found."
% [get_command_name(), arguments[0]]
)
return false
return true
# Run the command
func run(command_params: Array) -> int:
escoria.current_state = escoria.GAME_STATE.DIALOG
var param_global_id = command_params[0]
var param_list_id = command_params[1]
var param_lenght = command_params[2]
if !escoria.dialog_player:
escoria.logger.error(
self,
"[%s]: No dialog player was registered and the say command was encountered."
% get_command_name()
)
escoria.current_state = escoria.GAME_STATE.DEFAULT
return ESCExecution.RC_ERROR
if not escoria.main.current_scene.player:
escoria.logger.warn(
self,
"[%s]: No player item in the current scene was registered and the say command was encountered."
% get_command_name()
)
escoria.current_state = escoria.GAME_STATE.DEFAULT
return ESCExecution.RC_CANCEL
var text = param_list_id + "_" + String(rng.randi_range(0,param_lenght -1)) + ':" "'
var speaking_character_global_id = escoria.main.current_scene.player.global_id \
if param_global_id.to_upper() == CURRENT_PLAYER_KEYWORD \
else param_global_id
escoria.dialog_player.say(
speaking_character_global_id,
"",
text
)
yield(escoria.dialog_player, "say_finished")
escoria.current_state = escoria.GAME_STATE.DEFAULT
var current_count_global_key = "%s_count" % [param_list_id]
var current_count = escoria.globals_manager.get_global(current_count_global_key)
if(current_count == null):
current_count = 0
escoria.globals_manager.set_global(current_count_global_key, current_count + 1)
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()
)

View File

@@ -0,0 +1,140 @@
# `say_random global_id list_id lenght [loop]`
#
# Displays the specified string as dialog spoken by the player. This command
# blocks further event execution until the dialog has finished being 'said'
# (either as displayed text or as audible speech from a file).
#
# Global variables can be substituted into the text by wrapping the global
# name in braces.
# e.g. say player "I have {coin_count} coins remaining".
#
# **Parameters**
#
# - *global_id*: Global ID of the `ESCPlayer` or `ESCItem` object that is active.
# You can specify `current_player` in order to refer to the currently active
# player, e.g. in cases where multiple players are playable such as in games
# like Maniac Mansion or Day of the Tentacle.
# - *randomizer_list_id*: ID for the list of sentences.
# - *lenght*: lenght of the list.
# - *loop*: . Loop the list.Can be true or false. Default: false
#
# Example: `say_random player random_list 4 false`
#
# @ESC
extends ESCBaseCommand
class_name SaySequenceCommand
const CURRENT_PLAYER_KEYWORD = "CURRENT_PLAYER"
# Return the descriptor of the arguments of this command
func configure() -> ESCCommandArgumentDescriptor:
return ESCCommandArgumentDescriptor.new(
3,
[TYPE_STRING, TYPE_STRING, TYPE_INT, TYPE_BOOL],
[
null,
null,
null,
false
],
[
true,
false,
false,
false
]
)
# Validate whether the given arguments match the command descriptor
func validate(arguments: Array):
if not .validate(arguments):
return false
if arguments[0].to_upper() != CURRENT_PLAYER_KEYWORD \
and not escoria.object_manager.has(arguments[0]):
escoria.logger.error(
self,
"[%s]: Invalid object: Object with global id %s not found."
% [get_command_name(), arguments[0]]
)
return false
return true
# Run the command
func run(command_params: Array) -> int:
escoria.current_state = escoria.GAME_STATE.DIALOG
var param_global_id = command_params[0]
var param_list_id = command_params[1]
var param_lenght = command_params[2]
var loop = command_params[3]
if !escoria.dialog_player:
escoria.logger.error(
self,
"[%s]: No dialog player was registered and the say command was encountered."
% get_command_name()
)
escoria.current_state = escoria.GAME_STATE.DEFAULT
return ESCExecution.RC_ERROR
if not escoria.main.current_scene.player:
escoria.logger.warn(
self,
"[%s]: No player item in the current scene was registered and the say command was encountered."
% get_command_name()
)
escoria.current_state = escoria.GAME_STATE.DEFAULT
return ESCExecution.RC_CANCEL
var current_index_global_key = "%s_current_iteration" % [param_list_id]
var current_index = escoria.globals_manager.get_global(current_index_global_key)
if(current_index == null):
current_index = 0
var text = '%s_%s:" "' % [param_list_id,current_index]
var speaking_character_global_id = escoria.main.current_scene.player.global_id \
if param_global_id.to_upper() == CURRENT_PLAYER_KEYWORD \
else param_global_id
escoria.dialog_player.say(
speaking_character_global_id,
"",
text
)
yield(escoria.dialog_player, "say_finished")
escoria.current_state = escoria.GAME_STATE.DEFAULT
current_index += 1
if(current_index == param_lenght):
if loop:
current_index = 0
else:
current_index = param_lenght -1 #Don't like it but for now it works.
escoria.globals_manager.set_global(current_index_global_key, current_index)
var current_count_global_key = "%s_count" % [param_list_id]
var current_count = escoria.globals_manager.get_global(current_count_global_key)
if(current_count == null):
current_count = 0
escoria.globals_manager.set_global(current_count_global_key, current_count + 1)
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()
)

View File

@@ -0,0 +1,31 @@
"""
Base interface for all states: it doesn't do anything in itself
but forces us to pass the right arguments to the methods below
and makes sure every State object had all of these methods.
"""
extends Node
signal finished(next_state_name)
# Initialize the state. E.g. change the animation
func enter():
return
# Clean up the state. Reinitialize values like a timer
func exit():
return
func handle_input(_event):
return
func update(_delta):
return
func _on_animation_finished(_anim_name):
return

View File

@@ -0,0 +1,92 @@
"""
Base interface for a generic state machine
It handles initializing, setting the machine active or not
delegating _physics_process, _input calls to the State nodes,
and changing the current/active state.
"""
extends Node
signal state_changed(current_state)
"""
You must set a starting node from the inspector or on
the node that inherits from this state machine interface
If you don't the game will crash (on purpose, so you won't
forget to initialize the state machine)
"""
export(NodePath) var START_STATE
var states_map = {}
var states_stack = [] # can also be used as a pushdown automaton
var current_state = null
var current_state_name = ""
var _active = false setget set_active
func initialize(start_state):
for child in get_children():
child.connect("finished", self, "_change_state")
set_active(true)
states_stack.push_front(start_state)
current_state = states_stack[0]
current_state.enter()
func set_active(value):
_active = value
set_physics_process(value)
set_process_input(value)
if not _active:
states_stack = []
current_state = null
func _input(event):
current_state.handle_input(event)
func _physics_process(delta):
current_state.update(delta)
func _on_animation_finished(anim_name):
if not _active:
return
current_state._on_animation_finished(anim_name)
func _change_state(state_name):
if not _active:
return
escoria.logger.trace(
self,
"Dialog State Machine: Changing state from '%s' to '%s'." % [current_state_name, state_name]
)
current_state.exit()
if state_name == "previous":
states_stack.pop_front()
else:
states_stack[0] = states_map[state_name]
current_state = states_stack[0]
emit_signal("state_changed", current_state)
#if state_name != "previous":
current_state.enter()
current_state_name = state_name
func get_current_state_name():
for key in states_map.keys():
if states_map[key] == current_state:
return key
return null

View File

@@ -0,0 +1,7 @@
[plugin]
name="Escoria Return to Monkey Island UI Dialog Simple"
description="Return to Monkey Island like UI for the Escoria Framework (Dialogs)"
author="Arkitekt"
version="0.1.0"
script="plugin.gd"

View File

@@ -0,0 +1,149 @@
# A simple dialog manager for Escoria
tool
extends EditorPlugin
class_name RTMISimpleDialogPlugin
const MANAGER_CLASS="res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/rtmi_dialog_simple.gd"
const SETTINGS_ROOT="escoria/rtmi_dialog_simple"
const READING_SPEED_IN_WPM_DEFAULT_VALUE = 200
const TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE = 100
const TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE = 25
var left_click_actions: PoolStringArray = [
RTMISimpleDialogSettings.LEFT_CLICK_ACTION_SPEED_UP,
RTMISimpleDialogSettings.LEFT_CLICK_ACTION_INSTANT_FINISH,
RTMISimpleDialogSettings.LEFT_CLICK_ACTION_NOTHING
]
var stop_talking_animation_on_options: PoolStringArray = [
RTMISimpleDialogSettings.STOP_TALKING_ANIMATION_ON_END_OF_TEXT,
RTMISimpleDialogSettings.STOP_TALKING_ANIMATION_ON_END_OF_AUDIO
]
# Override function to return the plugin name.
func get_plugin_name():
return "escoria-rtmi-dialog-simple"
# Unregister ourselves
func disable_plugin():
print("Disabling plugin Escoria Dialog Simple")
ESCProjectSettingsManager.remove_setting(
ESCProjectSettingsManager.DEFAULT_DIALOG_TYPE
)
ESCProjectSettingsManager.remove_setting(
RTMISimpleDialogSettings.AVATARS_PATH
)
ESCProjectSettingsManager.remove_setting(
RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS
)
ESCProjectSettingsManager.remove_setting(
RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_FAST
)
ESCProjectSettingsManager.remove_setting(
RTMISimpleDialogSettings.CLEAR_TEXT_BY_CLICK_ONLY
)
ESCProjectSettingsManager.remove_setting(
RTMISimpleDialogSettings.READING_SPEED_IN_WPM
)
ESCProjectSettingsManager.remove_setting(
RTMISimpleDialogSettings.LEFT_CLICK_ACTION
)
ESCProjectSettingsManager.remove_setting(
RTMISimpleDialogSettings.STOP_TALKING_ANIMATION_ON
)
EscoriaPlugin.deregister_dialog_manager(MANAGER_CLASS)
# Add ourselves to the list of dialog managers
func enable_plugin():
print("Enabling plugin Escoria Dialog Simple")
if EscoriaPlugin.register_dialog_manager(self, MANAGER_CLASS):
ESCProjectSettingsManager.register_setting(
ESCProjectSettingsManager.DEFAULT_DIALOG_TYPE,
"floating",
{
"type": TYPE_STRING
}
)
ESCProjectSettingsManager.register_setting(
RTMISimpleDialogSettings.AVATARS_PATH,
"res://game/dialog_avatars",
{
"type": TYPE_STRING,
"hint": PROPERTY_HINT_DIR
}
)
ESCProjectSettingsManager.register_setting(
RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS,
TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE,
{
"type": TYPE_REAL
}
)
ESCProjectSettingsManager.register_setting(
RTMISimpleDialogSettings.TEXT_TIME_PER_LETTER_MS_FAST,
TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE,
{
"type": TYPE_REAL
}
)
ESCProjectSettingsManager.register_setting(
RTMISimpleDialogSettings.CLEAR_TEXT_BY_CLICK_ONLY,
false,
{
"type": TYPE_BOOL
}
)
ESCProjectSettingsManager.register_setting(
RTMISimpleDialogSettings.READING_SPEED_IN_WPM,
READING_SPEED_IN_WPM_DEFAULT_VALUE,
{
"type": TYPE_INT
}
)
var left_click_actions_string: String = left_click_actions.join(",")
ESCProjectSettingsManager.register_setting(
RTMISimpleDialogSettings.LEFT_CLICK_ACTION,
RTMISimpleDialogSettings.LEFT_CLICK_ACTION_SPEED_UP,
{
"type": TYPE_STRING,
"hint": PROPERTY_HINT_ENUM,
"hint_string": left_click_actions_string
}
)
var stop_talking_animation_on_options_string: String = stop_talking_animation_on_options.join(",")
ESCProjectSettingsManager.register_setting(
RTMISimpleDialogSettings.STOP_TALKING_ANIMATION_ON,
RTMISimpleDialogSettings.STOP_TALKING_ANIMATION_ON_END_OF_AUDIO,
{
"type": TYPE_STRING,
"hint": PROPERTY_HINT_ENUM,
"hint_string": stop_talking_animation_on_options_string
}
)
else:
get_editor_interface().set_plugin_enabled(
get_plugin_name(),
false
)

View File

@@ -0,0 +1,212 @@
# A simple dialog manager for Escoria
extends ESCDialogManager
class_name ESCReturnToMonekyIslandDialogs
# State machine that governs how the dialog manager behaves
var state_machine = preload("res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/rtmi_dialog_simple_state_machine.gd").new()
# The currently running player
var _type_player: Node = null
var _preserved_type_player_type: String = ""
# Reference to the dialog player
var _dialog_player: Node = null
# Basic state tracking
var _is_saying: bool = false
# Whether to preserve the next dialog box used by `say`, or, if already
# preserving a dialog box, whether to continue using that dialog box
var _should_preserve_dialog_box: bool = false
func _ready() -> void:
add_child(state_machine)
# Check whether a specific type is supported by the
# dialog plugin
#
# #### Parameters
# - type: required type
# *Returns* Whether the type is supported or not
func has_type(type: String) -> bool:
return true if type in ["floating"] else false
# Check whether a specific chooser type is supported by the
# dialog plugin
#
# #### Parameters
# - type: required chooser type
# *Returns* Whether the type is supported or not
func has_chooser_type(type: String) -> bool:
return true if type == "simple" else false
# 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:
_should_preserve_dialog_box = 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.
func disable_preserve_dialog_box() -> void:
_should_preserve_dialog_box = false
if is_instance_valid(_dialog_player) and _dialog_player.get_children().has(_type_player):
_dialog_player.remove_child(_type_player)
_preserved_type_player_type = ""
# Output a text said by the item specified by the global id. Emit
# `say_finished` after finishing displaying the text.
#
# #### Parameters
# - dialog_player: Node of the dialog player in the UI
# - global_id: Global id of the item that is speaking
# - text: Text to say, optional prefixed by a translation key separated
# by a ":"
# - type: Type of dialog box to use
func say(dialog_player: Node, global_id: String, text: String, type: String):
_dialog_player = dialog_player
_initialize_say_states(global_id, text, type)
if _should_preserve_dialog_box:
# If the dialog box type doesn't match what's currently being reused (if anything),
# we want to remove the old one (if it exists) and then initialize and add the new dialog
# box type to the dialog player
if type != _preserved_type_player_type:
if _dialog_player.get_children().has(_type_player):
_dialog_player.remove_child(_type_player)
_init_type_player(type)
_preserved_type_player_type = type
else:
_init_type_player(type)
state_machine._change_state("say")
func do_say(global_id: String, text: String) -> void:
# Only add_child here in order to prevent _type_player from running its _process method
# before we're ready, and only if it's necessary
if not _dialog_player.get_children().has(_type_player):
_dialog_player.add_child(_type_player)
_type_player.say(global_id, text)
func _init_type_player(type: String) -> void:
if type == "floating":
_type_player = preload(\
"res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/types/floating.tscn"\
).instance()
else:
_type_player = preload(\
"res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/types/avatar.tscn"\
).instance()
_type_player.connect("say_finished", self, "_on_say_finished")
_type_player.connect("say_visible", self, "_on_say_visible")
func _initialize_say_states(global_id: String, text: String, type: String) -> void:
state_machine.states_map["say"].initialize(self, global_id, text, type)
state_machine.states_map["finish"].initialize(_dialog_player)
state_machine.states_map["say_fast"].initialize(self)
state_machine.states_map["say_finish"].initialize(self)
state_machine.states_map["visible"].initialize(self)
state_machine.states_map["interrupt"].initialize(self)
func _on_say_finished():
if not _should_preserve_dialog_box and _dialog_player.get_children().has(_type_player):
_dialog_player.remove_child(_type_player)
_is_saying = false
emit_signal("say_finished")
func _on_say_visible():
emit_signal("say_visible")
# 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
# - type: The dialog chooser type to use
func choose(dialog_player: Node, dialog: ESCDialog, type: String):
_dialog_player = dialog_player
state_machine.states_map["choices"].initialize(dialog_player, self, dialog, type)
state_machine._change_state("choices")
func do_choose(dialog_player: Node, dialog: ESCDialog, type: String = "simple"):
var chooser
if type == "simple" or type == "":
chooser = preload(\
"res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/chooser/simple.tscn"\
).instance()
dialog_player.add_child(chooser)
chooser.set_dialog(dialog)
chooser.show_chooser()
var option = yield(chooser, "option_chosen")
dialog_player.remove_child(chooser)
# MODIFIED FOR RETURN TO MONKEY UI
if option is ESCDialogOption:
escoria.globals_manager.set_global("ESC_DIALOG_CHOSEN_OPTION", option.option)
# END MODIFIED FOR RETURN TO MONKEY UI
emit_signal("option_chosen", option)
# Trigger running the dialogue faster
func speedup():
if is_instance_valid(_type_player):
_type_player.speedup()
# Trigger an instant finish of the current dialog
func finish():
if is_instance_valid(_type_player):
_type_player.finish()
# The say command has been interrupted, cancel the dialog display
func interrupt():
if _dialog_player.get_children().has(_type_player):
(
escoria.object_manager.get_object(escoria.object_manager.SPEECH).node\
as ESCSpeechPlayer
).set_state("off")
if not _should_preserve_dialog_box and _dialog_player.get_children().has(_type_player):
_dialog_player.remove_child(_type_player)
emit_signal("say_finished")
# To be called if voice audio has finished.
func voice_audio_finished():
if is_instance_valid(_type_player):
_type_player.voice_audio_finished()

View File

@@ -0,0 +1,20 @@
extends Resource
class_name RTMISimpleDialogSettings
const SETTINGS_ROOT = "escoria/rtmi_dialog_simple"
const AVATARS_PATH = "%s/avatars_path" % SETTINGS_ROOT
const TEXT_TIME_PER_LETTER_MS = "%s/text_time_per_letter_ms" % SETTINGS_ROOT
const TEXT_TIME_PER_LETTER_MS_FAST = "%s/text_time_per_fast_letter_ms" % SETTINGS_ROOT
const READING_SPEED_IN_WPM = "%s/reading_speed_in_wpm" % SETTINGS_ROOT
const CLEAR_TEXT_BY_CLICK_ONLY = "%s/clear_text_by_click_only" % SETTINGS_ROOT
const LEFT_CLICK_ACTION = "%s/left_click_action" % SETTINGS_ROOT
const STOP_TALKING_ANIMATION_ON = "%s/stop_talking_animation_on" % SETTINGS_ROOT
const LEFT_CLICK_ACTION_SPEED_UP = "Speed up"
const LEFT_CLICK_ACTION_INSTANT_FINISH = "Instant finish"
const LEFT_CLICK_ACTION_NOTHING = "None"
const STOP_TALKING_ANIMATION_ON_END_OF_TEXT = "End of text"
const STOP_TALKING_ANIMATION_ON_END_OF_AUDIO = "End of audio"

View File

@@ -0,0 +1,31 @@
extends "res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/patterns/state_machine/state_machine.gd"
func _init():
_create_states()
_add_states_to_machine()
current_state_name = "idle"
START_STATE = states_map[current_state_name]
initialize(START_STATE)
# Creates the states for this state machine.
func _create_states() -> void:
states_map = {
"idle": preload("res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_idle.gd").new(),
"say": preload("res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say.gd").new(),
"say_fast": preload("res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say_fast.gd").new(),
"say_finish": preload("res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_say_finish.gd").new(),
"visible": preload("res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_visible.gd").new(),
"finish": preload("res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_finish.gd").new(),
"interrupt": preload("res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_interrupt.gd").new(),
"choices": preload("res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/states/dialog_choices.gd").new(),
}
# 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])

View File

@@ -0,0 +1,44 @@
extends "res://addons/escoria-dialog-simple/patterns/state_machine/state.gd"
# 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_chooser_ui: ESCDialogManager, dialog: ESCDialog, type: String) -> void:
_dialog_player = dialog_player
_dialog_chooser_ui = dialog_chooser_ui
_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."
)
_ready_to_choose = true
func update(_delta):
if _ready_to_choose:
_ready_to_choose = false
_dialog_chooser_ui.do_choose(_dialog_player, _dialog, _type)
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)

View File

@@ -0,0 +1,19 @@
extends "res://addons/escoria-dialog-simple/patterns/state_machine/state.gd"
# 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")

View File

@@ -0,0 +1,5 @@
extends "res://addons/escoria-dialog-simple/patterns/state_machine/state.gd"
func enter():
escoria.logger.trace(self, "Dialog State Machine: Entered 'idle'.")

View File

@@ -0,0 +1,25 @@
extends "res://addons/escoria-dialog-simple/patterns/state_machine/state.gd"
# 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")
_dialog_manager.interrupt()
func _on_say_finished() -> void:
escoria.logger.trace(self, "Dialog State Machine: 'interrupt' -> 'finish'")
emit_signal("finished", "finish")

View File

@@ -0,0 +1,181 @@
extends "res://addons/escoria-dialog-simple/patterns/state_machine/state.gd"
# 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(dialog_manager: ESCDialogManager, character: String, text: String, type: String) -> void:
_dialog_manager = dialog_manager
_character = character
_text = text
_type = type
_stop_talking_animation_on_option = \
ESCProjectSettingsManager.get_setting(RTMISimpleDialogSettings.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(RTMISimpleDialogSettings.LEFT_CLICK_ACTION)
_handle_left_click_action(left_click_action)
func _handle_left_click_action(left_click_action: String) -> void:
match left_click_action:
RTMISimpleDialogSettings.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")
RTMISimpleDialogSettings.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 not _dialog_manager.is_connected("say_visible", self, "_on_say_visible"):
_dialog_manager.connect("say_visible", self, "_on_say_visible")
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 == RTMISimpleDialogSettings.STOP_TALKING_ANIMATION_ON_END_OF_AUDIO:
if not (
escoria.object_manager.get_object(escoria.object_manager.SPEECH).node\
as ESCSpeechPlayer
).stream.is_connected("finished", self, "_on_audio_finished"):
(
escoria.object_manager.get_object(escoria.object_manager.SPEECH).node\
as ESCSpeechPlayer
).stream.connect("finished", self, "_on_audio_finished")
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.do_say(_character, _text)
_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()

View File

@@ -0,0 +1,29 @@
extends "res://addons/escoria-dialog-simple/patterns/state_machine/state.gd"
# 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")
_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")

View File

@@ -0,0 +1,29 @@
extends "res://addons/escoria-dialog-simple/patterns/state_machine/state.gd"
# 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")
_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")

View File

@@ -0,0 +1,34 @@
extends "res://addons/escoria-dialog-simple/patterns/state_machine/state.gd"
# 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")
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")

View File

@@ -0,0 +1,19 @@
[gd_resource type="Theme" load_steps=3 format=2]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/fonts/caslonantique.tres" type="DynamicFont" id=1]
[sub_resource type="StyleBoxFlat" id=1]
content_margin_left = 5.0
content_margin_right = 5.0
content_margin_top = 5.0
content_margin_bottom = 5.0
bg_color = Color( 0, 0, 0, 0.815686 )
corner_radius_top_left = 8
corner_radius_top_right = 8
corner_radius_bottom_right = 8
corner_radius_bottom_left = 8
[resource]
default_font = ExtResource( 1 )
RichTextLabel/styles/normal = SubResource( 1 )
VBoxContainer/constants/separation = 1

View File

@@ -0,0 +1,229 @@
# A dialog GUI showing a dialog box and character portraits
extends Popup
# Signal emitted when text has been said
signal say_finished
# Signal emitted when text has just become fully visible
signal say_visible
# The text speed per character for normal display
var _text_time_per_character: float
# The text speed per character if the dialog line is skipped
var _fast_text_time_per_character: float
# The reading speed to be used in determining the length of time text remains
# on the screen.
var _reading_speed_in_wpm: int
# Used to extract words from lines of text.
var _word_regex: RegEx = RegEx.new()
# Whether the current dialog is speeding up
var _is_speeding_up: bool = false
# The current line of text being displayed.
var _current_line: String
# The node holding the avatar
onready var avatar_node = $Panel/MarginContainer/HSplitContainer/VBoxContainer\
/avatar
# The node showing the text
onready var text_node = $Panel/MarginContainer/HSplitContainer/text
# The tween node for text animations
onready var tween = $Panel/MarginContainer/HSplitContainer/text/Tween
# Whether the dialog manager is paused
onready var is_paused: bool = true
# Build up the UI
func _ready():
_text_time_per_character = ProjectSettings.get_setting(
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS
)
if _text_time_per_character < 0:
escoria.logger.warn(
self,
"%s setting must be a non-negative number. Will use default value of %s." %
[
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS,
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE
]
)
_text_time_per_character = SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE
_fast_text_time_per_character = ProjectSettings.get_setting(
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST
)
if _fast_text_time_per_character < 0:
escoria.logger.warn(
self,
"%s setting must be a non-negative number. Will use default value of %s." %
[
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST,
SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE
]
)
_fast_text_time_per_character = SimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE
_reading_speed_in_wpm = ProjectSettings.get_setting(
SimpleDialogPlugin.READING_SPEED_IN_WPM
)
if _reading_speed_in_wpm <= 0:
escoria.logger.warn(
self,
"%s setting must be a positive number. Will use default value of %s." %
[
SimpleDialogPlugin.READING_SPEED_IN_WPM,
SimpleDialogPlugin.READING_SPEED_IN_WPM_DEFAULT_VALUE
]
)
_reading_speed_in_wpm = SimpleDialogPlugin.READING_SPEED_IN_WPM_DEFAULT_VALUE
_word_regex.compile("\\S+")
text_node.bbcode_enabled = true
tween.connect(
"tween_completed",
self,
"_on_dialog_line_typed"
)
escoria.connect("paused", self, "_on_paused")
escoria.connect("resumed", self, "_on_resumed")
# Switch the current character
#
# #### Parameters
# - name: The name of the current character
func set_current_character(name: String):
if ProjectSettings.get_setting("escoria/dialog_simple/avatars_path").empty():
escoria.logger.warn(self, "Unable to load avatar '%s': Avatar path not specified" % name)
return
var avatar = "%s/%s.tres" % [
ProjectSettings.get_setting("escoria/dialog_simple/avatars_path"),
name
]
if ResourceLoader.exists(avatar):
avatar_node.texture = ResourceLoader.load(avatar)
if avatar_node.texture is AnimatedTexture:
avatar_node.texture.current_frame = 0
avatar_node.texture.pause = false
else:
escoria.logger.warn(self, "Unable to load avatar '%s': Resource not found in path '%s'" %
[name, ProjectSettings.get_setting("escoria/dialog_simple/avatars_path")])
# Make a character say something
#
# #### Parameters
# - character: The global id of the character speaking
# - line: Line to say
func say(character: String, line: String):
_current_line = line
_is_speeding_up = false
popup_centered()
set_current_character(character)
text_node.bbcode_text = tr(line)
text_node.percent_visible = 0.0
var time_show_full_text = _text_time_per_character / 1000 * len(line)
tween.interpolate_property(text_node, "percent_visible",
0.0, 1.0, time_show_full_text,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
# Called by the dialog player when the
func speedup():
if not _is_speeding_up:
_is_speeding_up = true
var time_show_full_text = _fast_text_time_per_character / 1000 * len(_current_line)
tween.remove_all()
tween.interpolate_property(text_node, "percent_visible",
text_node.percent_visible, 1.0, time_show_full_text,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
# Called by the dialog player when user wants to finish dialogue immediately.
func finish():
tween.remove_all()
tween.interpolate_property(text_node, "percent_visible",
text_node.percent_visible, 1.0, 0.0)
tween.start()
# To be called if voice audio has finished.
func voice_audio_finished():
if avatar_node and avatar_node.texture:
avatar_node.texture.current_frame = 0
avatar_node.texture.pause = true
# The dialog line was printed, start the waiting time and then finish
# the dialog
func _on_dialog_line_typed(object, key):
if avatar_node.texture is AnimatedTexture:
avatar_node.texture.current_frame = 0
avatar_node.texture.pause = true
text_node.visible_characters = -1
var time_to_disappear: float = _calculate_time_to_disappear()
$Timer.start(time_to_disappear)
$Timer.connect("timeout", self, "_on_dialog_finished")
emit_signal("say_visible")
func _calculate_time_to_disappear() -> float:
return (_get_number_of_words() / _reading_speed_in_wpm as float) * 60
func _get_number_of_words() -> int:
return _word_regex.search_all(text_node.get_text()).size()
# Ending the dialog
func _on_dialog_finished():
# Only trigger to clear the text if we aren't limiting the clearing trigger to a click.
if not ESCProjectSettingsManager.get_setting(SimpleDialogPlugin.CLEAR_TEXT_BY_CLICK_ONLY):
emit_signal("say_finished")
queue_free()
# Handler managing pause notification from Escoria
func _on_paused():
if tween.is_active():
is_paused = true
tween.stop_all()
# Handler managing resume notification from Escoria
func _on_resumed():
if not tween.is_active():
is_paused = false
tween.resume_all()

View File

@@ -0,0 +1,68 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/escoria-dialog-simple/types/avatar.gd" type="Script" id=1]
[node name="dialog_box" type="Popup"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_right = -782.0
margin_bottom = -734.0
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Timer" type="Timer" parent="."]
[node name="Panel" type="Panel" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="MarginContainer" type="MarginContainer" parent="Panel"]
anchor_right = 1.0
anchor_bottom = 1.0
custom_constants/margin_right = 20
custom_constants/margin_top = 20
custom_constants/margin_left = 20
custom_constants/margin_bottom = 20
__meta__ = {
"_edit_use_anchors_": false
}
[node name="HSplitContainer" type="HSplitContainer" parent="Panel/MarginContainer"]
margin_left = 20.0
margin_top = 20.0
margin_right = 478.0
margin_bottom = 146.0
custom_constants/separation = 35
dragger_visibility = 1
[node name="VBoxContainer" type="VBoxContainer" parent="Panel/MarginContainer/HSplitContainer"]
margin_right = 88.0
margin_bottom = 126.0
size_flags_horizontal = 3
size_flags_stretch_ratio = 0.3
[node name="avatar" type="TextureRect" parent="Panel/MarginContainer/HSplitContainer/VBoxContainer"]
margin_right = 88.0
margin_bottom = 108.0
size_flags_horizontal = 3
size_flags_vertical = 3
expand = true
[node name="text" type="RichTextLabel" parent="Panel/MarginContainer/HSplitContainer"]
margin_left = 123.0
margin_right = 458.0
margin_bottom = 126.0
size_flags_horizontal = 3
bbcode_enabled = true
bbcode_text = "Here be some text"
text = "Here be some text"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Tween" type="Tween" parent="Panel/MarginContainer/HSplitContainer/text"]

View File

@@ -0,0 +1,256 @@
# A dialog UI using a label above the head of the character
extends RichTextLabel
# Signal emitted when text has been said
signal say_finished
# Signal emitted when text has just become fully visible
signal say_visible
# The text speed per character for normal display
var _text_time_per_character: float
# The text speed per character if the dialog line is skipped
var _fast_text_time_per_character: float
# The reading speed to be used in determining the length of time text remains
# on the screen.
var _reading_speed_in_wpm: int
# Used to extract words from lines of text.
var _word_regex: RegEx = RegEx.new()
# Current character speaking, to keep track of reference for animation purposes
var _current_character
# Whether the current dialog is speeding up
var _is_speeding_up: bool = false
# The current line of text being displayed.
var _current_line: String
# Tween node for text animation
onready var tween: Tween = $Tween
# The node showing the text
onready var text_node: RichTextLabel = self
# Whether the dialog manager is paused
onready var is_paused: bool = true
# Enable bbcode and catch the signal when a tween completed
func _ready():
_text_time_per_character = ProjectSettings.get_setting(
RTMISimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS
)
if _text_time_per_character < 0:
escoria.logger.warn(
self,
"%s setting must be a non-negative number. Will use default value of %s." %
[
RTMISimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS,
RTMISimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE
]
)
_text_time_per_character = RTMISimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_DEFAULT_VALUE
_fast_text_time_per_character = ProjectSettings.get_setting(
RTMISimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST
)
if _fast_text_time_per_character < 0:
escoria.logger.warn(
self,
"%s setting must be a non-negative number. Will use default value of %s." %
[
RTMISimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST,
RTMISimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE
]
)
_fast_text_time_per_character = RTMISimpleDialogPlugin.TEXT_TIME_PER_LETTER_MS_FAST_DEFAULT_VALUE
_reading_speed_in_wpm = ProjectSettings.get_setting(
RTMISimpleDialogPlugin.READING_SPEED_IN_WPM
)
if _reading_speed_in_wpm <= 0:
escoria.logger.warn(
self,
"%s setting must be a positive number. Will use default value of %s." %
[
RTMISimpleDialogPlugin.READING_SPEED_IN_WPM,
RTMISimpleDialogPlugin.READING_SPEED_IN_WPM_DEFAULT_VALUE
]
)
_reading_speed_in_wpm = RTMISimpleDialogPlugin.READING_SPEED_IN_WPM_DEFAULT_VALUE
_word_regex.compile("\\S+")
bbcode_enabled = true
$Tween.connect("tween_completed", self, "_on_dialog_line_typed")
connect("tree_exiting", self, "_on_tree_exiting")
escoria.connect("paused", self, "_on_paused")
escoria.connect("resumed", self, "_on_resumed")
_current_line = ""
func _process(delta):
if _current_character.is_inside_tree() and \
_current_character.has_node("dialog_position"):
# Position the RichTextLabel on the character's dialog position, if any.
rect_position = _current_character.get_node("dialog_position") \
.get_global_transform_with_canvas().origin
rect_position.x -= rect_size.x / 2
if rect_position.x < 0:
rect_position.x = 0
var screen_margin = rect_position.x + rect_size.x - \
ProjectSettings.get("display/window/size/width")
if screen_margin > 0:
rect_position.x -= screen_margin
# Make a character say something
#
# #### Parameters
# - character: The global id of the character speaking
# - line: Line to say
func say(character: String, line: String) :
_current_line = line
show()
_is_speeding_up = false
# Position the RichTextLabel on the character's dialog position, if any.
_current_character = escoria.object_manager.get_object(character).node
# Set text color to color set in the actor
var text_color = _current_character.dialog_color
var text_color_html = text_color.to_html(false)
text_node.bbcode_text = "[center][color=#" + text_color_html + "]" \
.format([text_color_html]) + tr(line) + "[/color][center]"
if _current_character.is_inside_tree() and \
_current_character.has_node("dialog_position"):
rect_position = _current_character.get_node(
"dialog_position"
).get_global_transform_with_canvas().origin
rect_position.x -= rect_size.x / 2
else:
rect_position.x = 0
rect_size.x = ProjectSettings.get_setting("display/window/size/width")
if rect_position.x < 0:
rect_position.x = 0
var screen_margin = rect_position.x + rect_size.x - \
ProjectSettings.get("display/window/size/width")
if screen_margin > 0:
rect_position.x -= screen_margin
_current_character.start_talking()
text_node.percent_visible = 0.0
var time_show_full_text = _text_time_per_character / 1000 * len(_current_line)
tween.interpolate_property(text_node, "percent_visible",
0.0, 1.0, time_show_full_text,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
set_process(true)
# Called by the dialog player when user wants to finish dialogue fast.
func speedup():
if not _is_speeding_up:
_is_speeding_up = true
var time_show_full_text = _fast_text_time_per_character / 1000 * len(_current_line)
tween.remove_all()
tween.interpolate_property(text_node, "percent_visible",
text_node.percent_visible, 1.0, time_show_full_text,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
# Called by the dialog player when user wants to finish dialogue immediately.
func finish():
tween.remove_all()
tween.interpolate_property(text_node, "percent_visible",
text_node.percent_visible, 1.0, 0.0)
tween.start()
# To be called if voice audio has finished.
func voice_audio_finished():
_stop_character_talking()
# The dialog line was printed, start the waiting time and then finish
# the dialog
func _on_dialog_line_typed(object, key):
_stop_character_talking()
text_node.visible_characters = -1
var time_to_disappear: float = _calculate_time_to_disappear()
$Timer.start(time_to_disappear)
$Timer.connect("timeout", self, "_on_dialog_finished")
emit_signal("say_visible")
func _calculate_time_to_disappear() -> float:
return (_get_number_of_words() / _reading_speed_in_wpm as float) * 60
func _get_number_of_words() -> int:
return _word_regex.search_all(text_node.get_text()).size()
# Ending the dialog
func _on_dialog_finished():
# Only trigger to clear the text if we aren't limiting the clearing trigger to a click.
if not ESCProjectSettingsManager.get_setting(RTMISimpleDialogPlugin.CLEAR_TEXT_BY_CLICK_ONLY):
emit_signal("say_finished")
# Handler managing pause notification from Escoria
func _on_paused():
if tween.is_active():
is_paused = true
tween.stop_all()
# Handler managing resume notification from Escoria
func _on_resumed():
if not tween.is_active():
is_paused = false
tween.resume_all()
# Handler to deal with this node being removed
func _on_tree_exiting() -> void:
_stop_character_talking()
func _stop_character_talking():
# Make the speaking item animation stop talking, if it is still alive
if is_instance_valid(_current_character) and _current_character != null:
_current_character.stop_talking()

View File

@@ -0,0 +1,18 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://addons/escoria-dialog-simple/types/floating.gd" type="Script" id=1]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island-dialog-simple/theme.tres" type="Theme" id=2]
[node name="dialog_label" type="RichTextLabel"]
margin_right = 672.0
margin_bottom = 97.0
theme = ExtResource( 2 )
bbcode_enabled = true
bbcode_text = "[center]Here be some text.[/center]"
text = "Here be some text."
fit_content_height = true
script = ExtResource( 1 )
[node name="Tween" type="Tween" parent="."]
[node name="Timer" type="Timer" parent="."]

View File

@@ -0,0 +1,20 @@
extends TextureButton
export(Texture) var musicEnabledTexture: Texture
export(Texture) var musicEnabledHoverTexture: Texture
export(Texture) var musicDisabledTexture: Texture
export(Texture) var musicDisabledHoverTexture: Texture
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
func _process(delta: float):
if escoria.game_scene.musicEnabled == true:
texture_normal = musicEnabledTexture
texture_hover = musicEnabledHoverTexture
else:
texture_normal = musicDisabledTexture
texture_hover = musicDisabledHoverTexture

View File

@@ -0,0 +1,10 @@
extends Button
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -0,0 +1,39 @@
# `item_count_add item_id value`
#
# Add value to the count in a item.
# - item_id: string: id of the item to apply
# - value: int: number to add
#
# @ESC
extends ESCBaseCommand
class_name ItemCountAddCommand
var item_count_manager = ESCItemCountManager.new()
# Return the descriptor of the arguments of this command
func configure() -> ESCCommandArgumentDescriptor:
return ESCCommandArgumentDescriptor.new(
1,
[TYPE_STRING, TYPE_INT],
[null, 1]
)
# Validate wether the given arguments match the command descriptor
func validate(arguments: Array):
if not escoria.object_manager.has(arguments[0]):
escoria.logger.error(
self,
"Object %s not registered" % arguments[0]
)
return false
return .validate(arguments)
# Run the command
func run(command_params: Array) -> int:
item_count_manager.add(command_params[0], command_params[1])
return ESCExecution.RC_OK

View File

@@ -0,0 +1,57 @@
# `play_lib_snd filename namespace`
#
# Plays a sound from the library.
#
# **Parameters**
#
# - *file_name*: File name withot extension
# - *namespace*: Subfolder
#
# @ESC
extends ESCBaseCommand
class_name PlayLibSound
# Return the descriptor of the arguments of this command
func configure() -> ESCCommandArgumentDescriptor:
return ESCCommandArgumentDescriptor.new(
1,
[TYPE_STRING,TYPE_STRING],
[null,""]
)
# Validate whether the given arguments match the command descriptor
func validate(arguments: Array):
if not .validate(arguments):
return false
var subFolder = arguments[1]
if(arguments[1] != ""):
subFolder += "/"
var resourceFile = "res://gymkhana/sounds/" + subFolder + arguments[0] + ".ogg"
if not ResourceLoader.exists(resourceFile):
escoria.logger.error(
self,
"[%s]: invalid parameter. File %s not found."
% [get_command_name(), resourceFile]
)
return false
return true
# Run the command
func run(command_params: Array) -> int:
var resourceFile = "res://gymkhana/sounds/" + command_params[0] + ".ogg"
escoria.object_manager.get_object("_sound").node.set_state(
resourceFile
)
return ESCExecution.RC_OK
# Function called when the command is interrupted.
func interrupt():
# Do nothing
pass

View File

@@ -0,0 +1,41 @@
# `play_video file`
#
# Plays the specified video blocking the currently running event .
#
# **Parameters**
#
# - *file*: Video file to play
#
# @ESC
extends ESCBaseCommand
class_name PlayVideoCommand
# Return the descriptor of the arguments of this command
func configure() -> ESCCommandArgumentDescriptor:
return ESCCommandArgumentDescriptor.new(
1,
[TYPE_STRING, TYPE_STRING]
)
# Validate whether the given arguments match the command descriptor
func validate(arguments: Array):
if not .validate(arguments):
return false
if not ResourceLoader.exists(arguments[0]):
escoria.logger.error(
self,
"[%s]: invalid parameter. File %s not found."
% [get_command_name(), arguments[0]]
)
return false
return true
# Run the command
func run(command_params: Array) -> int:
escoria.game_scene.play_video(command_params[0])
#We wait for the video to emit "finished" signal with yield
yield(escoria.game_scene.get_video_player(),"finished")
return ESCExecution.RC_OK

View File

@@ -0,0 +1,52 @@
# `set_tooltip global_id action text`
#
# Sets the tooltip text for the given `ESCItemWithTooltip` and action.
#
# **Parameters**
#
# - *object*: Global ID of the object whose toolitp is to be updated
# - *action*: ID of the action, action1, action2, action3 or action4.
# - *toolip*: The tooltip text string
#
# @ESC
extends ESCBaseCommand
class_name SetTooltipCommand
# Return the descriptor of the arguments of this command
func configure() -> ESCCommandArgumentDescriptor:
return ESCCommandArgumentDescriptor.new(
2,
[TYPE_STRING,TYPE_STRING, TYPE_STRING],
[null, "action1", ""]
)
# Validate whether the given arguments match the command descriptor
func validate(arguments: Array):
if not .validate(arguments):
return false
if not escoria.object_manager.has(arguments[0]):
escoria.logger.error(
self,
"[%s]: invalid object. Object with global id %s not found."
% [get_command_name(), arguments[0]]
)
return false
return true
# Run the command
func run(command_params: Array) -> int:
(escoria.object_manager.get_object(command_params[0]).node as ESCItemWithTooltip)\
.set_tooltip(command_params[1],command_params[2])
return ESCExecution.RC_OK
# Function called when the command is interrupted.
func interrupt():
# Do nothing
pass

View File

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

View File

@@ -0,0 +1,75 @@
# A manager for inventory objects
extends Resource
class_name ESCItemCountManager
func add(global_id: String, value:= 1) -> void:
var item = get_item(global_id)
set(global_id, item.count + value)
func remove(global_id: String, value:= 1) -> void:
var item = get_item(global_id)
set(global_id, item.count - value)
func set(global_id: String, value: int) -> void:
var item = get_item(global_id)
item.count = value
escoria.globals_manager.set_global("count/%s" % global_id, value)
updateSprite(item)
func removeFromInventoryIfCountLessThan(global_id: String, value:= 1) -> void:
var item = get_item(global_id)
if item.count < value:
escoria.inventory_manager.remove_item(global_id)
func get_item(global_id: String) -> ESCItem:
var node = escoria.object_manager.get_object(global_id).node
if not node is ESCItem:
escoria.logger.error(
"item_count_add: invalid object",
["Object is not an ESCItem"]
)
return null
return node
func updateSprite(item: ESCItemWithTooltip) -> void:
var child_node = item.get_node("Sprite") as Sprite
if not child_node is Sprite:
escoria.logger.error(
self,
"No Sprite node found"
)
var texture_path = getCountTexturePath(item)
var texture = load(texture_path)
# Update texture in scene
var sprite = child_node as Sprite
sprite.texture = texture
# Update texture in scene
# TODO optional inventory_texture
# TODO change inventory texture without removing and adding the item
# https://github.com/godot-escoria/escoria-issues/issues/364
# https://discord.com/channels/884336424780984330/1124614097917460584/1127151969614696548
item.inventory_texture = texture
if escoria.inventory_manager.inventory_has(item.global_id):
escoria.inventory_manager.remove_item(item.global_id)
escoria.inventory_manager.add_item(item.global_id)
func getCountTexturePath(item: ESCItemWithTooltip) -> String:
var count = item.count
var textures = item.count_textures # TODO sort dictionaries by start key
var i = 0
while (i < textures.size() - 1) and count >= textures[i + 1].start:
i = i + 1
return textures[i].texture

View File

@@ -0,0 +1,72 @@
tool
extends ESCItem
class_name ESCItemWithTooltip, "res://addons/escoria-core/design/esc_item.svg"
# Action 1 Label text
export(String) var action1_text = ""
# Action 2 Label text
export(String) var action2_text = ""
# Action 3 tooltip text if item in inventory
export(String) var action3_text = ""
# Action 4 tooltip text if item in inventory
export(String) var action4_text = ""
export(Dictionary) var tooltips = {}
# Action 3 tooltip texts if item is target. Dictionary with tool's global id as key.
export(Dictionary) var action3_target_texts = {}
# Action 4 tooltip texts if item is target. Dictionary with tool's global id as key
export(Dictionary) var action4_target_texts = {}
# If action used by player is in this list, this is a valid target (second item in combination)
export(Array) var target_when_selected_action_is_in = []
# If item is countable (E.g. money) marks the quantity
export(int) var count = 0
# ESCItemComponents children of this node
var components: Dictionary = {}
var custom_data: Dictionary = {}
# If item is countable (E.g. money) marks which texture to use depending of count value.
# Each element is a Dictionary with start and texture keys:
# [
# { "start": 0, "texture": "res://gymkhana/items/inventory/assets/no_money.png"},
# { "start": 1, "texture": "res://gymkhana/items/inventory/assets/one_coin.png"},
# { "start": 2, "texture": "res://gymkhana/items/inventory/assets/two_coins.png"},
# { "start": 3, "texture": "res://gymkhana/items/inventory/assets/coins.png"},
# { "start": 10, "texture": "res://gymkhana/items/inventory/assets/bills.png"},
# ]
export(Array) var count_textures = []
func _ready():
register_components()
func set_tooltip(action: String, text: String):
tooltips[action] = text
func has_component(key: String)->bool:
return components.has(key)
func get_component(key: String):
if(has_component(key)):
return components[key]
return null
func register_components():
autoload_components()
for child in get_children():
if(child is ESCItemComponent):
child = child as ESCItemComponent
components[child.get_component_type()] = child
child.register(custom_data)
func autoload_components():
add_child(ESCItemComponentOutline.new())
add_child(ESCItemComponentInventoryChecker.new())

View File

@@ -0,0 +1,23 @@
tool
extends ESCItemWithTooltip
class_name ESCPlayerWithTooltip, "res://addons/escoria-core/design/esc_player.svg"
# Whether the player can be selected like an item
export(bool) var selectable = false
# A player is always movable
func _init():
._init()
is_movable = true
_force_registration = true
# Ready function
func _ready():
if selectable:
._ready()
else:
tooltip_name = ""

View File

@@ -0,0 +1,309 @@
# A tooltip displaying <verb> <item1> [<item2>]
tool
extends Node2D
class_name ESCRichTooltip
# Maximum width of the label
const MAX_WIDTH = 200
# Minimum height of the label
const MIN_HEIGHT = 30
# Maximum height of the label
const MAX_HEIGHT = 500
# Height of one line in the label
const ONE_LINE_HEIGHT = 16
# Color of the label
export(Color) var color setget set_color
# Vector2 defining the offset from the cursor
export(Vector2) var offset_from_cursor_action1 = Vector2(0,3)
export(Vector2) var offset_from_cursor_action2 = Vector2(0,-2)
export(Vector2) var offset_from_cursor_action3 = Vector2(0,3)
export(Vector2) var offset_from_cursor_action4 = Vector2(0,-2)
# Activates debug mode. If enabled, shows the label with a white background.
export(bool) var debug_mode = false setget set_debug_mode
# Infinitive verb
var current_action: String
# Target item/hotspot
var current_target: String setget set_target
var current_target_object: Object = null setget set_target_object
# Preposition: on, with...
var current_prep: String = "with"
# Target 2 item/hotspot
var current_target2: String
var current_size: Vector2 = Vector2(0,0) setget _set_current_size
# True if tooltip is waiting for a click on second target (use x with y)
var waiting_for_target2 = false
# Node containing the debug white background
var debug_texturerect_node: TextureRect
# Indicates whether the current room is loaded and ready
var _room_is_ready: bool = false
# Tooltips are hidden
var hidden: bool = false
signal tooltip_size_updated
# Connect relevant functions
func _ready():
if escoria.main.connect("room_ready", self, "_on_room_ready") != 0:
escoria.logger.error(self, "Error connecting room_ready with _on_room_ready")
if escoria.action_manager.connect("action_changed", self, "_on_action_selected") != 0:
escoria.logger.error(self, "Error connecting action_changed with _on_action_selected")
# Set the color of the label
#
# ## Parameters
# - p_color: the color to set the label
func set_color(p_color: Color):
color = p_color
if _room_is_ready:
update_tooltip_text()
# Enable/disable debug mode of the label. If enabled, the label is displayed
# with a white background.
#
# ## Parameters
# - p_debug_mode: if true, enable debug mode. False to disable
func set_debug_mode(p_debug_mode: bool):
debug_mode = p_debug_mode
if debug_mode:
# Add a white TextureRect behind the RTL to see its actual size
debug_texturerect_node = TextureRect.new()
add_child(debug_texturerect_node)
debug_texturerect_node.texture = load("res://addons/escoria-core/game/assets/images/white.png")
debug_texturerect_node.expand = true
debug_texturerect_node.stretch_mode = TextureRect.STRETCH_TILE
#debug_texturerect_node.size_flags_horizontal = SIZE_EXPAND_FILL
#debug_texturerect_node.size_flags_vertical = SIZE_EXPAND_FILL
debug_texturerect_node.show_behind_parent = true
debug_texturerect_node.anchor_right = 1.0
debug_texturerect_node.anchor_bottom = 1.0
debug_texturerect_node.mouse_filter = Control.MOUSE_FILTER_IGNORE
move_child(debug_texturerect_node, 2)
else:
if debug_texturerect_node:
remove_child(debug_texturerect_node)
debug_texturerect_node.queue_free()
func set_target_object(target: Object, needs_second_target: bool = false) -> void:
current_target_object = target
waiting_for_target2 = needs_second_target
if _room_is_ready:
if(target == null):
hide()
return
# show()
update_tooltip_text()
# Set the first target of the label.
#
# ## Parameters
# - target: String the target to add to the label
# - needs_second_target: if true, the label will prepare for a second target
func set_target(target: String, needs_second_target: bool = false) -> void:
current_target = target
waiting_for_target2 = needs_second_target
if _room_is_ready:
if(target == ""):
hide()
return
update_tooltip_text()
# show()
# Set the second target of the label
#
# ## Parameters
# - target2: String the second target to add to the label
func set_target2(target2: String) -> void:
current_target2 = target2
if _room_is_ready:
if(target2 == ""):
hide()
return
update_tooltip_text()
# show()
# Update the tooltip text.
# * If waiting for target item: get text from action*_target_texts dictionaries using current_tool as key
# * If item is in inventory: use action3_text and action4_text variables
# * Else: use action1_text and action2_text variables
func update_tooltip_text():
if(current_target_object == null):
return
var action1_text = "";
var action2_text = "";
if current_target_object.is_interactive and escoria.current_state == escoria.GAME_STATE.DEFAULT:
var item_in_inventory = escoria.inventory_manager.inventory_has(current_target_object.global_id)
var waiting_for_target_item = escoria.action_manager.action_state == ESCActionManager.ACTION_INPUT_STATE.AWAITING_TARGET_ITEM
action1_text = get_action_target_text(current_target_object.action3_target_texts) if waiting_for_target_item else get_tooltip_from_current_target("action3") if item_in_inventory else get_tooltip_from_current_target("action1")
action2_text = get_action_target_text(current_target_object.action4_target_texts) if waiting_for_target_item else get_tooltip_from_current_target("action4") if item_in_inventory else get_tooltip_from_current_target("action2")
$tooltip1/label.text = action1_text
$tooltip1.visible = !hidden and action1_text != "";
$tooltip2/label.text = action2_text
$tooltip2.visible = !hidden and action2_text != "";
func get_tooltip_from_current_target(verb):
var tooltips = current_target_object.get('tooltips')
if(tooltips.has(verb)):
return tooltips.get(verb)
return ""
func get_action_target_text(action_target_texts: Dictionary):
var action_target_text = action_target_texts.get(escoria.action_manager.current_tool.global_id)
return action_target_text if action_target_text else ""
# Update the tooltip size according to the text.
func update_size():
if not get_tree():
# We're not in the tree anymore. Return
return
current_size = $tooltip1/label.get_font("normal_font").get_string_size(current_target)
func get_tooltip1_size():
if not get_tree():
# We're not in the tree anymore. Return
return
return Vector2(150,20);
# escoria.logger.info(self, "get_string_size: " + String($tooltip1/label.get_font("normal_font").get_string_size(current_target)))
#return $tooltip1/label.get_font("normal_font").get_string_size(current_target)
func get_tooltip2_size():
if not get_tree():
# We're not in the tree anymore. Return
return
return Vector2(150,20);
#return $tooltip2/label.get_font("normal_font").get_string_size(current_target)
# Calculate the offset of the label depending on its position.
#
# ## Parameters
# - position: the position to test
#
# **Return**
# The calculated offset
func _offset(position: Vector2) -> Vector2:
#var center_offset_x = current_size.x / 2
#var offset_y = 5
#position.x -= center_offset_x
#position.y += offset_y
return position
# Return the tooltip distance to top edge.
#
# ## Parameters
# - position: the position to test
#
# **Return**
# The distance to the edge.
func tooltip_distance_to_edge_top(position: Vector2):
return position.y
# Return the tooltip distance to bottom edge.
#
# ## Parameters
# - position: the position to test
#
# **Return**
# The distance to the edge.
func tooltip_distance_to_edge_bottom(position: Vector2):
return escoria.game_size.y - position.y
# Return the tooltip distance to left edge.
#
# ## Parameters
# - position: the position to test
#
# **Return**
# The distance to the edge.
func tooltip_distance_to_edge_left(position: Vector2):
return position.x
# Return the tooltip distance to right edge.
#
# ## Parameters
# - position: the position to test
#
# **Return**
# The distance to the edge.
func tooltip_distance_to_edge_right(position: Vector2):
return escoria.game_size.x - position.x
func show():
escoria.logger.info(self, "show")
hidden = false
update_tooltip_text()
# if _room_is_ready:
# $tooltip1.visible = true;
# $tooltip2.visible = true;
#$icon.visible = true;
#$label.visible = true;
#$background.visible = true;
func hide():
if _room_is_ready:
$tooltip1.visible = false;
$tooltip2.visible = false;
#$icon.visible = false;
#$label.visible = false;
#$background.visible = false;
func setHidden():
hidden = true
hide()
# Clear the tooltip targets texts
func clear():
waiting_for_target2 = false
set_target("")
set_target2("")
func _set_current_size(size: Vector2):
current_size = size
# Called when the room is loaded to setup the label.
func _on_room_ready():
escoria.main.current_scene.game.tooltip_node = self
_room_is_ready = true
# Called when an action is selected in Escoria
func _on_action_selected() -> void:
current_action = escoria.action_manager.current_action
if _room_is_ready:
update_tooltip_text()
hide()

View File

@@ -0,0 +1,41 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/esc_rich_tooltip.gd" type="Script" id=1]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/cursors/rounded_mouse_right.png" type="Texture" id=2]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/cursors/rounded_mouse_left.png" type="Texture" id=3]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/theme.tres" type="Theme" id=4]
[node name="tooltipManager" type="Node2D"]
script = ExtResource( 1 )
[node name="tooltip1" type="Node2D" parent="."]
visible = false
[node name="label" type="Label" parent="tooltip1"]
margin_left = 9.0
margin_top = -6.0
margin_right = 119.0
margin_bottom = 8.0
theme = ExtResource( 4 )
text = "Text place holder"
[node name="icon" type="Sprite" parent="tooltip1"]
position = Vector2( 1, 8 )
scale = Vector2( 0.583333, 0.583333 )
texture = ExtResource( 3 )
[node name="tooltip2" type="Node2D" parent="."]
visible = false
[node name="label" type="Label" parent="tooltip2"]
margin_left = 9.0
margin_top = 35.0
margin_right = 144.0
margin_bottom = 64.0
theme = ExtResource( 4 )
text = "Text place holder"
[node name="icon" type="Sprite" parent="tooltip2"]
position = Vector2( 1, 49.5 )
scale = Vector2( 0.583333, 0.583333 )
texture = ExtResource( 2 )

View File

@@ -0,0 +1,7 @@
[gd_resource type="DynamicFont" load_steps=2 format=2]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/fonts/caslonantique.ttf" type="DynamicFontData" id=1]
[resource]
size = 21
font_data = ExtResource( 1 )

View File

@@ -0,0 +1,517 @@
extends ESCGame
# Left mouse button on item
const ACTION1 = "action1"
# Right mouse button on item
const ACTION2 = "action2"
# Left mouse button on inventory item
const ACTION3 = "action3"
# Right mouse button on inventory item
const ACTION4 = "action4"
const VERB_USE = "use"
const VERB_WALK = "walk"
"""
Implement methods to react to inputs.
- left_click_on_bg(position: Vector2)
- right_click_on_bg(position: Vector2)
- left_double_click_on_bg(position: Vector2)
- element_focused(element_id: String)
- element_unfocused()
- left_click_on_item(item_global_id: String, event: InputEvent)
- right_click_on_item(item_global_id: String, event: InputEvent)
- left_double_click_on_item(item_global_id: String, event: InputEvent)
- left_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent)
- right_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent)
- left_double_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent)
- inventory_item_focused(inventory_item_global_id: String)
- inventory_item_unfocused()
- open_inventory()
- close_inventory()
- mousewheel_action(direction: int)
- hide_ui()
- show_ui()
- pause_game()
- unpause_game()
- show_main_menu()
- hide_main_menu()
- apply_custom_settings()
- _on_event_done(event_name: String)
"""
# Value to use for `device` argument to various `Input.get_joy` methods.
const JOY_DEVICE = 0
# See https://docs.godotengine.org/en/stable/tutorials/inputs/controllers_gamepads_joysticks.html?#dead-zone
const DEADZONE = 0.2
# Multiplier to apply to axis when it exceeds DEADZONE.
const AXIS_WEIGHT = 50.0
# JOY_BUTTON_2 corresponds to the "X" button on an XBox controller
# or the Square button on a Playstation controller. These appear to
# map to the "primary action," in practice, so we treat it like a left click.
const PRIMARY_ACTION_BUTTON = JOY_BUTTON_2
# JOY_BUTTON_3 corresponds to the "Y" button on an XBox controller
# or the Triangle button on a Playstation controller. These appear to
# map to the "secondary action," in practice, so we treat it like a right click.
const CHANGE_VERB_BUTTON = JOY_BUTTON_3
# Input action for use by InputMap
const ESC_UI_CHANGE_VERB_ACTION = "esc_change_verb"
# true when a gamepad is connected.
var _is_gamepad_connected = false
# Tracks the mouse's current position onscreen.
var _current_mouse_pos = Vector2.ZERO
# A reference to the node handling tooltip2
var tooltip2_node: Object
var last_target: Object
var video_player: Object
func _ready():
# We need a slightly modified version of Action Manager to combine items with different actions.
escoria.action_manager = ESCActionManagerMonkey.new()
if $tooltip_layer/tooltip.connect("tooltip_size_updated", self, "update_tooltip_following_mouse_position", [tooltip_node]) != 0:
escoria.logger.error(self, "Error connecting tooltip_size_updated with update_tooltip_following_mouse_position")
# We get current day and month
var time = OS.get_datetime()
var day = time["day"]
var month = time["month"]
if( day == 8 and month ==2 ):
escoria.globals_manager.set_global('zorionak_eneko', true)
func _enter_tree():
var room_selector_parent = $CanvasLayer/ui/menu_button/HBoxContainer
if ESCProjectSettingsManager.get_setting(ESCProjectSettingsManager.ENABLE_ROOM_SELECTOR) \
and room_selector_parent.get_node_or_null("room_select") == null:
room_selector_parent.add_child(
preload(
"res://addons/escoria-core/ui_library/tools/room_select" +\
"/room_select.tscn"
).instance()
)
var room_selector = room_selector_parent.get_node_or_null("room_select")
if(room_selector != null):
room_selector.visible = false
var input_handler = funcref(self, "_process_input")
escoria.inputs_manager.register_custom_input_handler(input_handler)
_is_gamepad_connected = Input.is_joy_known(JOY_DEVICE)
if _is_gamepad_connected:
_on_gamepad_connected()
if Input.connect("joy_connection_changed", self, "_on_joy_connection_changed") != 0:
escoria.logger.error(self, "Error connecting joy_connection_changed")
func _exit_tree():
escoria.inputs_manager.register_custom_input_handler(null)
Input.disconnect("joy_connection_changed", self, "_on_joy_connection_changed")
if _is_gamepad_connected:
_on_gamepad_disconnected()
func toggle_room_selector_visibility():
var room_selector_parent = $CanvasLayer/ui/menu_button/VBoxContainer
var room_selector = room_selector_parent.get_node_or_null("room_select")
if(room_selector != null):
room_selector.visible = !room_selector.visible
func _input(event: InputEvent) -> void:
if escoria.get_escoria().is_ready_for_inputs():
if event.is_action_pressed("ui_show_room_selector"):
toggle_room_selector_visibility()
if event is InputEventMouseMotion:
#_current_mouse_pos = get_global_mouse_position() # Escoria core
_current_mouse_pos = get_viewport().get_mouse_position()
update_tooltip_following_mouse_position(tooltip_node)
update_tooltip_following_mouse_position(tooltip2_node)
# https://github.com/godotengine/godot-demo-projects/blob/3.4-585455e/misc/joypads/joypads.gd
# was informative in wiring up the gamepad properly.
func _on_gamepad_connected():
set_physics_process(true)
var primary_event = InputEventJoypadButton.new()
primary_event.button_index = PRIMARY_ACTION_BUTTON
InputMap.add_action(escoria.inputs_manager.ESC_UI_PRIMARY_ACTION)
InputMap.action_add_event(escoria.inputs_manager.ESC_UI_PRIMARY_ACTION, primary_event)
var verb_event = InputEventJoypadButton.new()
verb_event.button_index = CHANGE_VERB_BUTTON
InputMap.add_action(ESC_UI_CHANGE_VERB_ACTION)
InputMap.action_add_event(ESC_UI_CHANGE_VERB_ACTION, verb_event)
func _on_gamepad_disconnected():
InputMap.action_erase_events(escoria.inputs_manager.ESC_UI_PRIMARY_ACTION)
InputMap.erase_action(escoria.inputs_manager.ESC_UI_PRIMARY_ACTION)
InputMap.action_erase_events(ESC_UI_CHANGE_VERB_ACTION)
InputMap.erase_action(ESC_UI_CHANGE_VERB_ACTION)
set_physics_process(false)
_is_gamepad_connected = false
func _on_joy_connection_changed(device: int, connected: bool) -> void:
if device != JOY_DEVICE:
return
elif connected:
_on_gamepad_connected()
else:
_on_gamepad_disconnected()
func _process(_delta) -> void:
if !_is_gamepad_connected:
return
var x = Input.get_joy_axis(JOY_DEVICE, JOY_AXIS_0)
var y = Input.get_joy_axis(JOY_DEVICE, JOY_AXIS_1)
var delta_x = int(x * AXIS_WEIGHT) if abs(x) > DEADZONE else 0
var delta_y = int(y * AXIS_WEIGHT) if abs(y) > DEADZONE else 0
if delta_x or delta_y:
var direction = Vector2(delta_x, delta_y)
escoria.logger.trace("gamepad direction:", [direction])
var viewport = get_viewport()
viewport.warp_mouse(viewport.get_mouse_position() + direction)
func _process_input(event: InputEvent, is_default_state: bool) -> bool:
if not is_default_state:
# ESCBackground is not guaranteed to be set, as we may be on
# the "New Game" screen.
return false
elif _is_gamepad_connected and event is InputEventJoypadButton:
escoria.logger.trace("InputEventJoypadButton:", [event.as_text()])
if event.is_action_pressed(escoria.inputs_manager.ESC_UI_PRIMARY_ACTION):
# Admittedly, this breaks abstraction barriers and is completely
# inappropriate, but it's what works right now.
escoria.inputs_manager._on_left_click_on_bg(get_global_mouse_position())
return true
elif event.is_action_pressed(ESC_UI_CHANGE_VERB_ACTION):
escoria.logger.error("Someone invoked ESC_UI_CHANGE_VERB_ACTION:", [event.as_text()])
return true
return false
## BACKGROUND ##
func click_on_bg(position: Vector2) -> void:
# If we are using an inventory item reset mouse cursor and cancel action
if escoria.action_manager.action_state == ESCActionManager.ACTION_INPUT_STATE.AWAITING_TARGET_ITEM:
Input.set_custom_mouse_cursor(null)
escoria.action_manager.clear_current_tool()
if escoria.main.current_scene.player:
escoria.action_manager.do(
escoria.action_manager.ACTION.BACKGROUND_CLICK,
[escoria.main.current_scene.player.global_id, position],
true
)
func left_click_on_bg(position: Vector2) -> void:
click_on_bg(position)
func right_click_on_bg(position: Vector2) -> void:
click_on_bg(position)
func left_double_click_on_bg(position: Vector2) -> void:
if escoria.main.current_scene.player:
escoria.action_manager.do(
escoria.action_manager.ACTION.BACKGROUND_CLICK,
[escoria.main.current_scene.player.global_id, position, true],
true
)
## ITEM/HOTSPOT FOCUS ##
func element_focused(element_id: String) -> void:
var target_obj = escoria.object_manager.get_object(element_id).node
if target_obj is ESCItem or ESCItemWithTooltip:
$tooltip_layer/tooltip.set_target(target_obj.tooltip_name)
$tooltip_layer/tooltip.set_target_object(target_obj)
if is_instance_valid(last_target):
last_target.get_component('outline').highlight(false)
if(escoria.action_manager.has_actions(target_obj)):
target_obj.get_component('outline').highlight(true)
last_target = target_obj
func element_unfocused() -> void:
$tooltip_layer/tooltip.set_target("")
$tooltip_layer/tooltip.set_target_object(null)
if(last_target != null):
last_target.get_component('outline').highlight(false)
last_target = null
## ITEMS ##
func click_on_item(item_global_id: String, event: InputEvent, action: String) -> void:
# If we are using an inventory item reset mouse cursor and use inventory actions (change action1 for action3 and action2 for action4)
if escoria.action_manager.action_state == ESCActionManager.ACTION_INPUT_STATE.AWAITING_TARGET_ITEM:
Input.set_custom_mouse_cursor(null)
action = ACTION3 if action == ACTION1 else ACTION4
escoria.action_manager.set_current_action(action)
escoria.action_manager.do(
escoria.action_manager.ACTION.ITEM_LEFT_CLICK,
[item_global_id, event],
true
)
# Hide tooltip if some action is being performed
if escoria.action_manager.action_state == ESCActionManager.ACTION_INPUT_STATE.COMPLETED:
$tooltip_layer/tooltip.setHidden()
func left_click_on_item(item_global_id: String, event: InputEvent) -> void:
click_on_item(item_global_id, event, ACTION1)
func right_click_on_item(item_global_id: String, event: InputEvent) -> void:
click_on_item(item_global_id, event, ACTION2)
func left_double_click_on_item(item_global_id: String, event: InputEvent) -> void:
escoria.action_manager.do(
escoria.action_manager.ACTION.ITEM_LEFT_CLICK,
[item_global_id, event],
true
)
## INVENTORY ##
func click_on_inventory_item(item_global_id: String, event: InputEvent, action: String) -> void:
# If we are using an inventory item reset mouse cursor
if escoria.action_manager.action_state == ESCActionManager.ACTION_INPUT_STATE.AWAITING_TARGET_ITEM:
Input.set_custom_mouse_cursor(null)
escoria.action_manager.set_current_action(action)
var target_obj = escoria.object_manager.get_object(item_global_id).node
# If item needs combination with this action, use the item texture as mouse cursor
if action in target_obj.combine_when_selected_action_is_in:
var texture = target_obj.inventory_texture
var cursor = ImageTexture.new()
var texture_image: Image = texture.get_data()
texture_image.resize(texture_image.get_width()/2,texture_image.get_height()/2)
cursor.create_from_image(texture_image)
var middleOfTheTexture = Vector2(texture_image.get_width() / 2, texture_image.get_height() / 2)
Input.set_custom_mouse_cursor(cursor, 0, middleOfTheTexture)
escoria.action_manager.do(
escoria.action_manager.ACTION.ITEM_LEFT_CLICK,
[item_global_id, event],
true
)
# Hide tooltip if some action is being performed
if escoria.action_manager.action_state == ESCActionManager.ACTION_INPUT_STATE.COMPLETED:
$tooltip_layer/tooltip.setHidden()
func left_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent) -> void:
click_on_inventory_item(inventory_item_global_id, event, ACTION3)
func right_click_on_inventory_item(inventory_item_global_id: String, event: InputEvent) -> void:
click_on_inventory_item(inventory_item_global_id, event, ACTION4)
func inventory_item_focused(inventory_item_global_id: String) -> void:
var target_obj = escoria.object_manager.get_object(inventory_item_global_id).node
if target_obj is ESCItemWithTooltip:
$tooltip_layer/tooltip.set_target(target_obj.action3_text)
$tooltip_layer/tooltip.set_target_object(target_obj)
func inventory_item_unfocused() -> void:
element_unfocused()
func open_inventory():
$CanvasLayer/ui/HBoxContainer/inventory_ui.show_inventory()
func close_inventory():
$CanvasLayer/ui/HBoxContainer/inventory_ui.hide_inventory()
func hide_ui():
$CanvasLayer/ui/HBoxContainer/inventory_ui.hide()
$CanvasLayer/ui.hide()
func show_ui():
$CanvasLayer/ui/HBoxContainer/inventory_ui.show()
$CanvasLayer/ui.show()
func hide_main_menu():
if get_node(main_menu).visible:
get_node(main_menu).hide()
func show_main_menu():
if not get_node(main_menu).visible:
get_node(main_menu).reset()
get_node(main_menu).show()
func unpause_game():
if get_node(pause_menu).visible:
get_node(pause_menu).hide()
escoria.object_manager.get_object(ESCObjectManager.CAMERA).node.current = true
escoria.object_manager.get_object(ESCObjectManager.SPEECH).node.resume()
escoria.main.current_scene.game.show_ui()
escoria.main.current_scene.show()
func pause_game():
if get_video_player().is_playing():
get_video_player().skip()
return
if not get_node(pause_menu).visible:
get_node(main_menu).reset()
get_node(pause_menu).reset()
get_node(pause_menu).set_save_enabled(
escoria.save_manager.save_enabled
)
get_node(pause_menu).show()
escoria.object_manager.get_object(ESCObjectManager.CAMERA).node.current = false
escoria.object_manager.get_object(ESCObjectManager.SPEECH).node.pause()
escoria.main.current_scene.game.hide_ui()
escoria.main.current_scene.hide()
func apply_custom_settings(custom_settings: Dictionary):
if custom_settings.has("a_custom_setting"):
escoria.logger.info(
self,
"custom setting value loaded: %s."
% str(custom_settings["a_custom_setting"])
)
func get_custom_data() -> Dictionary:
return {
"ui_type": "simplemouse"
}
# Update the tooltip position
func update_tooltip_following_mouse_position(tooltip: ESCRichTooltip):
if tooltip == null:
return
if(escoria.action_manager.current_tool == null):
set_tooltip_position("tooltip1", tooltip, tooltip.get_tooltip1_size(), tooltip.offset_from_cursor_action1)
set_tooltip_position("tooltip2", tooltip, tooltip.get_tooltip2_size(), tooltip.offset_from_cursor_action2)
return
set_tooltip_position("tooltip1", tooltip, tooltip.get_tooltip1_size(), tooltip.offset_from_cursor_action3)
set_tooltip_position("tooltip2", tooltip, tooltip.get_tooltip2_size(), tooltip.offset_from_cursor_action4)
func set_tooltip_position(nodeId: String, tooltip: ESCRichTooltip, size: Vector2, offset: Vector2):
var mouse_position = calculateMousePosition(size)
var corrected_position = correctPosition(tooltip, size, mouse_position, offset)
tooltip.get_node(nodeId).position = corrected_position
#tooltip.get_node(nodeId).position = mouse_position
func calculateMousePosition(size: Vector2):
size.x / 2
size.y / 2
#escoria.logger.info(self, "_current_mouse_pos" + String(_current_mouse_pos.x) + " gameSize: " + escoria.game_size.x)
#return _current_mouse_pos - size
return _current_mouse_pos
func correctPosition(tooltip: ESCRichTooltip, size: Vector2, mouse_position: Vector2, offset: Vector2):
# clamp TOP
if tooltip.tooltip_distance_to_edge_top(_current_mouse_pos) <= mouse_tooltip_margin:
mouse_position.y = mouse_tooltip_margin
# clamp BOTTOM
if tooltip.tooltip_distance_to_edge_bottom(_current_mouse_pos + size) <= mouse_tooltip_margin:
mouse_position.y = escoria.game_size.y - mouse_tooltip_margin - size.y
# clamp LEFT
if tooltip.tooltip_distance_to_edge_left(_current_mouse_pos - size/2) <= mouse_tooltip_margin:
mouse_position.x = mouse_tooltip_margin
# clamp RIGHT
if tooltip.tooltip_distance_to_edge_right(_current_mouse_pos + size/2) <= mouse_tooltip_margin:
mouse_position.x = escoria.game_size.x - mouse_tooltip_margin - size.x
return mouse_position - offset
func _on_event_done(return_code: int, _event_name: String):
escoria.logger.info(self, "EVENT DONE! code=" + String(return_code))
# Reset mouse cursor (should be not needed, but avoids not resetting the cursor on bugs)
Input.set_custom_mouse_cursor(null)
# Show tooltips, they were hidden while performing action
$tooltip_layer/tooltip.show()
func _on_MenuButton_pressed() -> void:
pause_game()
func get_video_player() -> Node:
return $CanvasLayer/video_player
func play_video(video_file: String) -> void:
$CanvasLayer/video_player.visible = true
$CanvasLayer/video_player.play(video_file)
# Clears the tooltip content (if an ESCTooltip node exists in UI)
# MODIFIED FOR RTMIUI
func clear_tooltip():
if tooltip_node != null:
(tooltip_node as ESCRichTooltip).clear()
var musicEnabled = true
func _on_MusicButton_pressed():
if musicEnabled:
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(escoria.BUS_MUSIC),
linear2db(0)
)
musicEnabled = false
else:
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(escoria.BUS_MUSIC),
linear2db(
ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.MUSIC_VOLUME
)
)
)
musicEnabled = true

View File

@@ -0,0 +1,122 @@
[gd_scene load_steps=17 format=2]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/inventory/inventory_ui.tscn" type="PackedScene" id=1]
[ext_resource path="res://addons/escoria-core/game/scenes/dialogs/esc_dialog_player.gd" type="Script" id=2]
[ext_resource path="res://addons/escoria-core/game/scenes/camera_player/camera.tscn" type="PackedScene" id=3]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/esc_rich_tooltip.tscn" type="PackedScene" id=4]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/game.gd" type="Script" id=5]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/icons/music-double-note.svg" type="Texture" id=6]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/menus/main_menu/main_menu.tscn" type="PackedScene" id=7]
[ext_resource path="res://addons/escoria-core/ui_library/menus/pause_menu/pause_menu.tscn" type="PackedScene" id=8]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/theme.tres" type="Theme" id=9]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/icons/cog-64-hover.svg" type="Texture" id=10]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/icons/cog-64.svg" type="Texture" id=11]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/video_player/video_player.tscn" type="PackedScene" id=12]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/icons/music-double-note-hover.svg" type="Texture" id=13]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/MusicButton.gd" type="Script" id=14]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/icons/music-double-note-hover-disabled.svg" type="Texture" id=15]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/icons/music-double-note-disabled.svg" type="Texture" id=16]
[node name="game" type="Node2D"]
script = ExtResource( 5 )
main_menu = NodePath("CanvasLayer/main_menu")
pause_menu = NodePath("CanvasLayer/pause_menu")
mouse_tooltip_margin = 70.0
editor_debug_mode = 1
ui_parent_control_node = NodePath("CanvasLayer/ui")
[node name="camera" parent="." instance=ExtResource( 3 )]
[node name="dialog_layer" type="CanvasLayer" parent="."]
layer = 3
[node name="ESCDialogsPlayer" type="Control" parent="dialog_layer"]
theme = ExtResource( 9 )
script = ExtResource( 2 )
[node name="CanvasLayer" type="CanvasLayer" parent="."]
[node name="ui" type="Control" parent="CanvasLayer"]
anchor_top = 0.9
anchor_right = 1.0
anchor_bottom = 1.0
margin_top = -26.0
size_flags_horizontal = 3
size_flags_vertical = 3
theme = ExtResource( 9 )
[node name="menu_button" type="Control" parent="CanvasLayer/ui"]
margin_left = 1245.0
margin_top = -643.0
margin_right = 1245.0
margin_bottom = -643.0
grow_horizontal = 2
grow_vertical = 2
[node name="HBoxContainer" type="HBoxContainer" parent="CanvasLayer/ui/menu_button"]
margin_left = -135.0
margin_top = 6.0
margin_right = 21.0
margin_bottom = 76.0
alignment = 1
[node name="MusicButton" type="TextureButton" parent="CanvasLayer/ui/menu_button/HBoxContainer"]
margin_left = 44.0
margin_right = 44.0
margin_bottom = 70.0
script = ExtResource( 14 )
musicEnabledTexture = ExtResource( 6 )
musicEnabledHoverTexture = ExtResource( 13 )
musicDisabledTexture = ExtResource( 16 )
musicDisabledHoverTexture = ExtResource( 15 )
[node name="MenuButton" type="TextureButton" parent="CanvasLayer/ui/menu_button/HBoxContainer"]
margin_left = 48.0
margin_right = 112.0
margin_bottom = 70.0
texture_normal = ExtResource( 11 )
texture_hover = ExtResource( 10 )
[node name="HBoxContainer" type="HBoxContainer" parent="CanvasLayer/ui"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_top = 18.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Spacer" type="Control" parent="CanvasLayer/ui/HBoxContainer"]
margin_right = 1186.0
margin_bottom = 90.0
size_flags_horizontal = 3
[node name="inventory_ui" parent="CanvasLayer/ui/HBoxContainer" instance=ExtResource( 1 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 1190.0
margin_right = 1280.0
margin_bottom = 90.0
rect_scale = Vector2( 1, 1 )
[node name="pause_menu" parent="CanvasLayer" instance=ExtResource( 8 )]
visible = false
theme = ExtResource( 9 )
[node name="main_menu" parent="CanvasLayer" instance=ExtResource( 7 )]
visible = false
[node name="video_player" parent="CanvasLayer" instance=ExtResource( 12 )]
visible = false
[node name="tooltip_layer" type="CanvasLayer" parent="."]
layer = 2
[node name="tooltip" parent="tooltip_layer" instance=ExtResource( 4 )]
z_index = 10
color = Color( 1, 1, 1, 1 )
offset_from_cursor_action1 = Vector2( 0, 30 )
offset_from_cursor_action2 = Vector2( 0, -20 )
offset_from_cursor_action3 = Vector2( 0, 55 )
offset_from_cursor_action4 = Vector2( 0, -55 )
[connection signal="pressed" from="CanvasLayer/ui/menu_button/HBoxContainer/MusicButton" to="." method="_on_MusicButton_pressed"]
[connection signal="pressed" from="CanvasLayer/ui/menu_button/HBoxContainer/MenuButton" to="." method="_on_MenuButton_pressed"]

View File

@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 32 32"
version="1.1"
id="svg3"
sodipodi:docname="cog-32.svg"
width="32"
height="32"
inkscape:version="1.3 (1:1.3+202307231459+0e150ed6c4)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview3"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="10.219903"
inkscape:cx="46.918255"
inkscape:cy="11.497174"
inkscape:window-width="1920"
inkscape:window-height="1171"
inkscape:window-x="1920"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g3" />
<defs
id="defs3">
<filter
id="shadow-1"
height="1.1503132"
width="1.150627"
x="-0.075313492"
y="-0.075156576">
<feFlood
flood-color="rgba(255, 255, 255, 1)"
result="flood"
id="feFlood1" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite1" />
<feGaussianBlur
in="composite"
stdDeviation="15"
result="blur"
id="feGaussianBlur1" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset1" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite2" />
</filter>
<radialGradient
id="lorc-cog-gradient-1"
gradientTransform="scale(0.99909393,1.0009069)"
cx="256.8287"
cy="258.04602"
fx="256.8287"
fy="258.04602"
r="275.2504"
gradientUnits="userSpaceOnUse">
<stop
offset="0%"
stop-color="#828080"
stop-opacity="1"
id="stop2" />
<stop
offset="100%"
stop-color="#000000"
stop-opacity="1"
id="stop3" />
</radialGradient>
</defs>
<g
class=""
id="g3"
transform="matrix(0.05818161,0,0,0.05818161,1.0708312,0.97285232)">
<path
d="m 234.875,18.78 c -26.087,2.367 -51.557,8.56 -74.875,18.782 15.37,32.763 14.222,66.706 -6.72,82.407 -20.835,15.617 -54.055,7.965 -81.124,-15.69 -16.246,19.452 -29.336,41.36 -38.875,65.626 33.83,12.333 56.635,37.665 52.94,63.5 -3.698,25.835 -32.697,43.74 -68.626,46.094 2.338,25.796 8.91,50.778 18.937,73.875 17.81,-8.182 35.793,-11.09 51.095,-8.938 13.032,1.87 23.927,7.015 31.156,16.657 15.817,21.097 7.603,54.713 -16.78,81.97 19.516,16.35 42.216,29.444 66.594,39.03 12.33,-33.828 37.655,-56.634 63.5,-52.938 25.844,3.697 43.74,32.696 46.094,68.625 26.087,-2.365 51.557,-8.555 74.875,-18.78 -15.766,-32.997 -14.26,-67.588 6.843,-83.406 9.64,-7.23 22.568,-9.022 35.594,-7.125 15.112,2.16 31.19,10.25 45.563,22.78 16.088,-19.345 29.4,-41.51 38.875,-65.594 -33.83,-12.332 -56.635,-37.653 -52.938,-63.5 3.697,-25.846 32.665,-43.772 68.594,-46.125 -2.36,-25.944 -8.774,-50.663 -18.906,-73.874 -32.612,15.117 -66.66,13.145 -82.282,-7.687 -15.696,-20.944 -7.252,-53.86 16.688,-81 C 391.577,57.117 368.849,44.022 344.472,34.437 332.14,68.265 306.815,91.097 280.972,87.405 255.126,83.712 237.228,54.709 234.877,18.78 Z m 21.656,95.126 c 79.626,0 144.376,64.752 144.376,144.375 0,79.626 -64.75,144.376 -144.375,144.376 -79.624,0 -144.374,-64.75 -144.374,-144.375 0,-79.624 64.75,-144.374 144.375,-144.374 z m 0,18.688 c -69.524,0 -125.686,56.162 -125.686,125.687 0,69.526 56.162,125.69 125.687,125.69 69.526,0 125.69,-56.164 125.69,-125.69 0,-69.522 -56.164,-125.686 -125.69,-125.686 z m 0.033,15.125 c 61.094,0 110.625,49.53 110.625,110.624 0,61.095 -49.53,110.625 -110.625,110.625 -61.095,0 -110.625,-49.53 -110.625,-110.626 0,-61.095 49.53,-110.625 110.625,-110.625 z"
fill="url(#lorc-cog-gradient-1)"
filter="url(#shadow-1)"
id="path3"
style="fill:url(#lorc-cog-gradient-1)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 64 64"
version="1.1"
id="svg3"
sodipodi:docname="cog-64-hover.svg"
width="64"
height="64"
inkscape:version="1.3 (1:1.3+202307231459+0e150ed6c4)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview3"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="5.1099513"
inkscape:cx="-8.5128012"
inkscape:cy="1.4677243"
inkscape:window-width="1920"
inkscape:window-height="1171"
inkscape:window-x="1920"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g3" />
<defs
id="defs3">
<filter
id="shadow-1"
height="1.1524932"
width="1.1529045"
x="-0.076452048"
y="-0.076200418">
<feFlood
flood-color="rgba(255, 255, 255, 1)"
result="flood"
id="feFlood1" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite1" />
<feGaussianBlur
in="composite"
stdDeviation="15"
result="blur"
id="feGaussianBlur1" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset1" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite2" />
</filter>
<radialGradient
id="lorc-cog-gradient-1"
gradientTransform="scale(0.99909393,1.0009069)"
cx="256.8287"
cy="258.04602"
fx="256.8287"
fy="258.04602"
r="275.2504"
gradientUnits="userSpaceOnUse">
<stop
offset="0"
stop-color="#828080"
stop-opacity="1"
id="stop2"
style="stop-color:#d131c1;stop-opacity:1;" />
<stop
offset="100%"
stop-color="#000000"
stop-opacity="1"
id="stop3" />
</radialGradient>
</defs>
<g
class=""
id="g3"
transform="matrix(0.05818161,0,0,0.05818161,1.0708312,0.97285232)">
<path
d="m 234.875,18.78 c -26.087,2.367 -51.557,8.56 -74.875,18.782 15.37,32.763 14.222,66.706 -6.72,82.407 -20.835,15.617 -54.055,7.965 -81.124,-15.69 -16.246,19.452 -29.336,41.36 -38.875,65.626 33.83,12.333 56.635,37.665 52.94,63.5 -3.698,25.835 -32.697,43.74 -68.626,46.094 2.338,25.796 8.91,50.778 18.937,73.875 17.81,-8.182 35.793,-11.09 51.095,-8.938 13.032,1.87 23.927,7.015 31.156,16.657 15.817,21.097 7.603,54.713 -16.78,81.97 19.516,16.35 42.216,29.444 66.594,39.03 12.33,-33.828 37.655,-56.634 63.5,-52.938 25.844,3.697 43.74,32.696 46.094,68.625 26.087,-2.365 51.557,-8.555 74.875,-18.78 -15.766,-32.997 -14.26,-67.588 6.843,-83.406 9.64,-7.23 22.568,-9.022 35.594,-7.125 15.112,2.16 31.19,10.25 45.563,22.78 16.088,-19.345 29.4,-41.51 38.875,-65.594 -33.83,-12.332 -56.635,-37.653 -52.938,-63.5 3.697,-25.846 32.665,-43.772 68.594,-46.125 -2.36,-25.944 -8.774,-50.663 -18.906,-73.874 -32.612,15.117 -66.66,13.145 -82.282,-7.687 -15.696,-20.944 -7.252,-53.86 16.688,-81 C 391.577,57.117 368.849,44.022 344.472,34.437 332.14,68.265 306.815,91.097 280.972,87.405 255.126,83.712 237.228,54.709 234.877,18.78 Z m 21.656,95.126 c 79.626,0 144.376,64.752 144.376,144.375 0,79.626 -64.75,144.376 -144.375,144.376 -79.624,0 -144.374,-64.75 -144.374,-144.375 0,-79.624 64.75,-144.374 144.375,-144.374 z m 0,18.688 c -69.524,0 -125.686,56.162 -125.686,125.687 0,69.526 56.162,125.69 125.687,125.69 69.526,0 125.69,-56.164 125.69,-125.69 0,-69.522 -56.164,-125.686 -125.69,-125.686 z m 0.033,15.125 c 61.094,0 110.625,49.53 110.625,110.624 0,61.095 -49.53,110.625 -110.625,110.625 -61.095,0 -110.625,-49.53 -110.625,-110.626 0,-61.095 49.53,-110.625 110.625,-110.625 z"
fill="url(#lorc-cog-gradient-1)"
filter="url(#shadow-1)"
id="path3"
style="fill:url(#lorc-cog-gradient-1);stroke:#ffffff;stroke-opacity:1"
transform="matrix(1.9999999,0,0,1.9999999,18.404999,17.219999)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 64 64"
version="1.1"
id="svg3"
sodipodi:docname="cog-64-press.svg"
width="64"
height="64"
inkscape:version="1.3 (1:1.3+202307231459+0e150ed6c4)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview3"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="5.1099513"
inkscape:cx="-8.5128012"
inkscape:cy="1.4677243"
inkscape:window-width="1920"
inkscape:window-height="1171"
inkscape:window-x="1920"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g3" />
<defs
id="defs3">
<filter
id="shadow-1"
height="1.1524932"
width="1.1529045"
x="-0.076452048"
y="-0.076200418">
<feFlood
flood-color="rgba(255, 255, 255, 1)"
result="flood"
id="feFlood1" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite1" />
<feGaussianBlur
in="composite"
stdDeviation="15"
result="blur"
id="feGaussianBlur1" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset1" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite2" />
</filter>
<radialGradient
id="lorc-cog-gradient-1"
gradientTransform="scale(0.99909393,1.0009069)"
cx="256.8287"
cy="258.04602"
fx="256.8287"
fy="258.04602"
r="275.2504"
gradientUnits="userSpaceOnUse">
<stop
offset="0"
stop-color="#828080"
stop-opacity="1"
id="stop2"
style="stop-color:#d131c1;stop-opacity:1;" />
<stop
offset="1"
stop-color="#000000"
stop-opacity="1"
id="stop3"
style="stop-color:#bebebe;stop-opacity:1;" />
</radialGradient>
</defs>
<g
class=""
id="g3"
transform="matrix(0.05818161,0,0,0.05818161,1.0708312,0.97285232)">
<path
d="m 234.875,18.78 c -26.087,2.367 -51.557,8.56 -74.875,18.782 15.37,32.763 14.222,66.706 -6.72,82.407 -20.835,15.617 -54.055,7.965 -81.124,-15.69 -16.246,19.452 -29.336,41.36 -38.875,65.626 33.83,12.333 56.635,37.665 52.94,63.5 -3.698,25.835 -32.697,43.74 -68.626,46.094 2.338,25.796 8.91,50.778 18.937,73.875 17.81,-8.182 35.793,-11.09 51.095,-8.938 13.032,1.87 23.927,7.015 31.156,16.657 15.817,21.097 7.603,54.713 -16.78,81.97 19.516,16.35 42.216,29.444 66.594,39.03 12.33,-33.828 37.655,-56.634 63.5,-52.938 25.844,3.697 43.74,32.696 46.094,68.625 26.087,-2.365 51.557,-8.555 74.875,-18.78 -15.766,-32.997 -14.26,-67.588 6.843,-83.406 9.64,-7.23 22.568,-9.022 35.594,-7.125 15.112,2.16 31.19,10.25 45.563,22.78 16.088,-19.345 29.4,-41.51 38.875,-65.594 -33.83,-12.332 -56.635,-37.653 -52.938,-63.5 3.697,-25.846 32.665,-43.772 68.594,-46.125 -2.36,-25.944 -8.774,-50.663 -18.906,-73.874 -32.612,15.117 -66.66,13.145 -82.282,-7.687 -15.696,-20.944 -7.252,-53.86 16.688,-81 C 391.577,57.117 368.849,44.022 344.472,34.437 332.14,68.265 306.815,91.097 280.972,87.405 255.126,83.712 237.228,54.709 234.877,18.78 Z m 21.656,95.126 c 79.626,0 144.376,64.752 144.376,144.375 0,79.626 -64.75,144.376 -144.375,144.376 -79.624,0 -144.374,-64.75 -144.374,-144.375 0,-79.624 64.75,-144.374 144.375,-144.374 z m 0,18.688 c -69.524,0 -125.686,56.162 -125.686,125.687 0,69.526 56.162,125.69 125.687,125.69 69.526,0 125.69,-56.164 125.69,-125.69 0,-69.522 -56.164,-125.686 -125.69,-125.686 z m 0.033,15.125 c 61.094,0 110.625,49.53 110.625,110.624 0,61.095 -49.53,110.625 -110.625,110.625 -61.095,0 -110.625,-49.53 -110.625,-110.626 0,-61.095 49.53,-110.625 110.625,-110.625 z"
fill="url(#lorc-cog-gradient-1)"
filter="url(#shadow-1)"
id="path3"
style="fill:url(#lorc-cog-gradient-1);stroke:#ffffff;stroke-opacity:1"
transform="matrix(1.9999999,0,0,1.9999999,18.404999,17.219999)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 64 64"
version="1.1"
id="svg3"
sodipodi:docname="cog-64.svg"
width="64"
height="64"
inkscape:version="1.3 (1:1.3+202307231459+0e150ed6c4)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview3"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="5.1099513"
inkscape:cx="-8.5128012"
inkscape:cy="1.4677243"
inkscape:window-width="1920"
inkscape:window-height="1171"
inkscape:window-x="1920"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g3" />
<defs
id="defs3">
<filter
id="shadow-1"
height="1.1524932"
width="1.1529045"
x="-0.076452048"
y="-0.076200418">
<feFlood
flood-color="rgba(255, 255, 255, 1)"
result="flood"
id="feFlood1" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite1" />
<feGaussianBlur
in="composite"
stdDeviation="15"
result="blur"
id="feGaussianBlur1" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset1" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite2" />
</filter>
<radialGradient
id="lorc-cog-gradient-1"
gradientTransform="scale(0.99909393,1.0009069)"
cx="256.8287"
cy="258.04602"
fx="256.8287"
fy="258.04602"
r="275.2504"
gradientUnits="userSpaceOnUse">
<stop
offset="0%"
stop-color="#828080"
stop-opacity="1"
id="stop2" />
<stop
offset="100%"
stop-color="#000000"
stop-opacity="1"
id="stop3" />
</radialGradient>
</defs>
<g
class=""
id="g3"
transform="matrix(0.05818161,0,0,0.05818161,1.0708312,0.97285232)">
<path
d="m 234.875,18.78 c -26.087,2.367 -51.557,8.56 -74.875,18.782 15.37,32.763 14.222,66.706 -6.72,82.407 -20.835,15.617 -54.055,7.965 -81.124,-15.69 -16.246,19.452 -29.336,41.36 -38.875,65.626 33.83,12.333 56.635,37.665 52.94,63.5 -3.698,25.835 -32.697,43.74 -68.626,46.094 2.338,25.796 8.91,50.778 18.937,73.875 17.81,-8.182 35.793,-11.09 51.095,-8.938 13.032,1.87 23.927,7.015 31.156,16.657 15.817,21.097 7.603,54.713 -16.78,81.97 19.516,16.35 42.216,29.444 66.594,39.03 12.33,-33.828 37.655,-56.634 63.5,-52.938 25.844,3.697 43.74,32.696 46.094,68.625 26.087,-2.365 51.557,-8.555 74.875,-18.78 -15.766,-32.997 -14.26,-67.588 6.843,-83.406 9.64,-7.23 22.568,-9.022 35.594,-7.125 15.112,2.16 31.19,10.25 45.563,22.78 16.088,-19.345 29.4,-41.51 38.875,-65.594 -33.83,-12.332 -56.635,-37.653 -52.938,-63.5 3.697,-25.846 32.665,-43.772 68.594,-46.125 -2.36,-25.944 -8.774,-50.663 -18.906,-73.874 -32.612,15.117 -66.66,13.145 -82.282,-7.687 -15.696,-20.944 -7.252,-53.86 16.688,-81 C 391.577,57.117 368.849,44.022 344.472,34.437 332.14,68.265 306.815,91.097 280.972,87.405 255.126,83.712 237.228,54.709 234.877,18.78 Z m 21.656,95.126 c 79.626,0 144.376,64.752 144.376,144.375 0,79.626 -64.75,144.376 -144.375,144.376 -79.624,0 -144.374,-64.75 -144.374,-144.375 0,-79.624 64.75,-144.374 144.375,-144.374 z m 0,18.688 c -69.524,0 -125.686,56.162 -125.686,125.687 0,69.526 56.162,125.69 125.687,125.69 69.526,0 125.69,-56.164 125.69,-125.69 0,-69.522 -56.164,-125.686 -125.69,-125.686 z m 0.033,15.125 c 61.094,0 110.625,49.53 110.625,110.624 0,61.095 -49.53,110.625 -110.625,110.625 -61.095,0 -110.625,-49.53 -110.625,-110.626 0,-61.095 49.53,-110.625 110.625,-110.625 z"
fill="url(#lorc-cog-gradient-1)"
filter="url(#shadow-1)"
id="path3"
style="fill:url(#lorc-cog-gradient-1);stroke:#ffffff;stroke-opacity:1"
transform="matrix(1.9999999,0,0,1.9999999,18.404999,17.219999)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(255, 255, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="15" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><radialGradient id="lorc-cog-gradient-1"><stop offset="0%" stop-color="#828080" stop-opacity="1"></stop><stop offset="100%" stop-color="#000000" stop-opacity="1"></stop></radialGradient></defs><g class="" transform="translate(0,0)" style=""><path d="M234.875 18.78c-26.087 2.367-51.557 8.56-74.875 18.782 15.37 32.763 14.222 66.706-6.72 82.407-20.835 15.617-54.055 7.965-81.124-15.69-16.246 19.452-29.336 41.36-38.875 65.626 33.83 12.333 56.635 37.665 52.94 63.5-3.698 25.835-32.697 43.74-68.626 46.094 2.338 25.796 8.91 50.778 18.937 73.875 17.81-8.182 35.793-11.09 51.095-8.938 13.032 1.87 23.927 7.015 31.156 16.657 15.817 21.097 7.603 54.713-16.78 81.97 19.516 16.35 42.216 29.444 66.594 39.03 12.33-33.828 37.655-56.634 63.5-52.938 25.844 3.697 43.74 32.696 46.094 68.625 26.087-2.365 51.557-8.555 74.875-18.78-15.766-32.997-14.26-67.588 6.843-83.406 9.64-7.23 22.568-9.022 35.594-7.125 15.112 2.16 31.19 10.25 45.563 22.78 16.088-19.345 29.4-41.51 38.875-65.594-33.83-12.332-56.635-37.653-52.938-63.5 3.697-25.846 32.665-43.772 68.594-46.125-2.36-25.944-8.774-50.663-18.906-73.874-32.612 15.117-66.66 13.145-82.282-7.687-15.696-20.944-7.252-53.86 16.688-81-19.52-16.352-42.248-29.447-66.625-39.032-12.332 33.828-37.657 56.66-63.5 52.968-25.846-3.693-43.744-32.696-46.095-68.625zm21.656 95.126c79.626 0 144.376 64.752 144.376 144.375 0 79.626-64.75 144.376-144.375 144.376-79.624 0-144.374-64.75-144.374-144.375 0-79.624 64.75-144.374 144.375-144.374zm0 18.688c-69.524 0-125.686 56.162-125.686 125.687 0 69.526 56.162 125.69 125.687 125.69 69.526 0 125.69-56.164 125.69-125.69 0-69.522-56.164-125.686-125.69-125.686zm.033 15.125c61.094 0 110.625 49.53 110.625 110.624 0 61.095-49.53 110.625-110.625 110.625s-110.625-49.53-110.625-110.626c0-61.095 49.53-110.625 110.625-110.625z" fill="url(#lorc-cog-gradient-1)" filter="url(#shadow-1)"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="64"
height="64"
stroke-width="1.5"
viewBox="0 0 64 64"
fill="none"
color="#000000"
version="1.1"
id="svg3"
sodipodi:docname="music-double-note-disabled.svg"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs3" />
<sodipodi:namedview
id="namedview3"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="5.3401293"
inkscape:cx="51.215988"
inkscape:cy="36.984123"
inkscape:window-width="1920"
inkscape:window-height="971"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg3" />
<path
d="M 61.401264,38.533592 V 2.5986797 L 20.974521,9.1322999 V 45.067212"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path1"
style="fill:none;fill-opacity:1;stroke-width:5.197;stroke-dasharray:none;stroke:#000000;stroke-opacity:1" />
<path
d="m 50.375792,54.867641 h 3.675155 c 4.059581,0 7.350317,-2.925101 7.350317,-6.533623 V 38.533592 H 50.375792 c -4.059585,0 -7.350321,2.925101 -7.350321,6.53362 v 3.266806 c 0,3.608522 3.290736,6.533623 7.350321,6.533623 z"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path2"
style="fill:none;fill-opacity:1;stroke-width:5.197;stroke-dasharray:none;stroke:#000000;stroke-opacity:1" />
<path
d="m 9.9490451,61.401264 h 3.6751589 c 4.05947,0 7.350317,-2.925104 7.350317,-6.533623 V 45.067212 H 9.9490451 c -4.0594695,0 -7.3503171,2.925104 -7.3503171,6.533619 v 3.26681 c 0,3.608519 3.2908476,6.533623 7.3503171,6.533623 z"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path3"
style="fill:none;fill-opacity:1;stroke-width:5.197;stroke-dasharray:none;stroke:#000000;stroke-opacity:1" />
<path
style="fill:#ff0000;stroke:#f40a09;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-dasharray:none"
d="M 7.4308899,51.792606 53.261256,12.207394"
id="path6" />
<path
style="fill:#ff0000;stroke:#f40a09;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 53.261256,51.792606 7.4308899,12.207394"
id="path6-3" />
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="64"
height="64"
stroke-width="1.5"
viewBox="0 0 64 64"
fill="none"
color="#000000"
version="1.1"
id="svg3"
sodipodi:docname="music-double-note-hover-disabled.svg"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs3" />
<sodipodi:namedview
id="namedview3"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="5.3401293"
inkscape:cx="51.215988"
inkscape:cy="36.984123"
inkscape:window-width="1920"
inkscape:window-height="971"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg3" />
<path
d="M 61.401264,38.533592 V 2.5986797 L 20.974521,9.1322999 V 45.067212"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path1"
style="fill:none;fill-opacity:1;stroke-width:5.197;stroke-dasharray:none;stroke:#bd2ab0;stroke-opacity:1" />
<path
d="m 50.375792,54.867641 h 3.675155 c 4.059581,0 7.350317,-2.925101 7.350317,-6.533623 V 38.533592 H 50.375792 c -4.059585,0 -7.350321,2.925101 -7.350321,6.53362 v 3.266806 c 0,3.608522 3.290736,6.533623 7.350321,6.533623 z"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path2"
style="fill:none;fill-opacity:1;stroke-width:5.197;stroke-dasharray:none;stroke:#bd2ab0;stroke-opacity:1" />
<path
d="m 9.9490451,61.401264 h 3.6751589 c 4.05947,0 7.350317,-2.925104 7.350317,-6.533623 V 45.067212 H 9.9490451 c -4.0594695,0 -7.3503171,2.925104 -7.3503171,6.533619 v 3.26681 c 0,3.608519 3.2908476,6.533623 7.3503171,6.533623 z"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path3"
style="fill:none;fill-opacity:1;stroke-width:5.197;stroke-dasharray:none;stroke:#bd2ab0;stroke-opacity:1" />
<path
style="fill:#ff0000;stroke:#f40a09;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-dasharray:none"
d="M 7.4308899,51.792606 53.261256,12.207394"
id="path6" />
<path
style="fill:#ff0000;stroke:#f40a09;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 53.261256,51.792606 7.4308899,12.207394"
id="path6-3" />
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="64"
height="64"
stroke-width="1.5"
viewBox="0 0 64 64"
fill="none"
color="#000000"
version="1.1"
id="svg3"
sodipodi:docname="music-double-note-hover.svg"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs3" />
<sodipodi:namedview
id="namedview3"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="3.7760417"
inkscape:cx="88.055172"
inkscape:cy="40.915862"
inkscape:window-width="1920"
inkscape:window-height="971"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg3" />
<path
d="M 61.401264,38.533592 V 2.5986797 L 20.974521,9.1322999 V 45.067212"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path1"
style="fill:none;fill-opacity:1;stroke-width:5.197;stroke-dasharray:none;stroke:#bd2ab0;stroke-opacity:1" />
<path
d="m 50.375792,54.867641 h 3.675155 c 4.059581,0 7.350317,-2.925101 7.350317,-6.533623 V 38.533592 H 50.375792 c -4.059585,0 -7.350321,2.925101 -7.350321,6.53362 v 3.266806 c 0,3.608522 3.290736,6.533623 7.350321,6.533623 z"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path2"
style="fill:none;fill-opacity:1;stroke-width:5.197;stroke-dasharray:none;stroke:#bd2ab0;stroke-opacity:1" />
<path
d="m 9.9490451,61.401264 h 3.6751589 c 4.05947,0 7.350317,-2.925104 7.350317,-6.533623 V 45.067212 H 9.9490451 c -4.0594695,0 -7.3503171,2.925104 -7.3503171,6.533619 v 3.26681 c 0,3.608519 3.2908476,6.533623 7.3503171,6.533623 z"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path3"
style="fill:none;fill-opacity:1;stroke-width:5.197;stroke-dasharray:none;stroke:#bd2ab0;stroke-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="64"
height="64"
stroke-width="1.5"
viewBox="0 0 64 64"
fill="none"
color="#000000"
version="1.1"
id="svg3"
sodipodi:docname="music-double-note.svg"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs3" />
<sodipodi:namedview
id="namedview3"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="3.7760417"
inkscape:cx="109.50621"
inkscape:cy="128.57379"
inkscape:window-width="1920"
inkscape:window-height="971"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg3" />
<path
d="M 61.401264,38.533592 V 2.5986797 L 20.974521,9.1322999 V 45.067212"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path1" />
<path
d="m 50.375792,54.867641 h 3.675155 c 4.059581,0 7.350317,-2.925101 7.350317,-6.533623 V 38.533592 H 50.375792 c -4.059585,0 -7.350321,2.925101 -7.350321,6.53362 v 3.266806 c 0,3.608522 3.290736,6.533623 7.350321,6.533623 z"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path2" />
<path
d="m 9.9490451,61.401264 h 3.6751589 c 4.05947,0 7.350317,-2.925104 7.350317,-6.533623 V 45.067212 H 9.9490451 c -4.0594695,0 -7.3503171,2.925104 -7.3503171,6.533619 v 3.26681 c 0,3.608519 3.2908476,6.533623 7.3503171,6.533623 z"
stroke="#000000"
stroke-width="5.19747"
stroke-linecap="round"
stroke-linejoin="round"
id="path3" />
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -0,0 +1,56 @@
extends ESCInventory
# Whether the inventory is visible currently
var inventory_visible: bool = false
func _ready() -> void:
$FloatingInventory/panel.rect_position.x = ProjectSettings.get_setting("display/window/size/width") - $FloatingInventory/panel.rect_size.x
# Hide inventory by default
# $FloatingInventory/panel.rect_position.x = \
# ProjectSettings.get_setting("display/window/size/width")
func _on_inventory_button_pressed():
if $FloatingInventory/InventoryTween.is_active():
return
if inventory_visible:
hide_inventory()
else:
show_inventory()
func show_inventory():
$FloatingInventory/InventoryTween.stop_all()
$FloatingInventory/InventoryTween.remove_all()
$FloatingInventory/InventoryTween.interpolate_property(
$FloatingInventory/panel,
"rect_position:x",
$FloatingInventory/panel.rect_position.x,
$FloatingInventory/panel.rect_position.x - \
$FloatingInventory/panel.rect_size.x - \
$HBoxContainer/inventory_button.rect_size.x,
0.6
)
$FloatingInventory/InventoryTween.start()
yield($FloatingInventory/InventoryTween,"tween_all_completed")
$FloatingInventory/InventoryTween.stop_all()
inventory_visible = true
func hide_inventory():
$FloatingInventory/InventoryTween.stop_all()
$FloatingInventory/InventoryTween.remove_all()
$FloatingInventory/InventoryTween.interpolate_property(
$FloatingInventory/panel,
"rect_position:x",
$FloatingInventory/panel.rect_position.x,
$FloatingInventory/panel.rect_position.x + \
$FloatingInventory/panel.rect_size.x + \
$HBoxContainer/inventory_button.rect_size.x,
0.6
)
$FloatingInventory/InventoryTween.start()
yield($FloatingInventory/InventoryTween,"tween_all_completed")
$FloatingInventory/InventoryTween.stop_all()
inventory_visible = false

View File

@@ -0,0 +1,68 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/inventory/inventory_ui.gd" type="Script" id=1]
[ext_resource path="res://addons/escoria-core/ui_library/inventory/esc_inventory_container.gd" type="Script" id=3]
[node name="inventory_ui" type="Control"]
anchor_right = 0.5
anchor_bottom = 0.5
margin_right = 768.0
margin_bottom = 540.0
rect_min_size = Vector2( 90, 90 )
rect_scale = Vector2( 0.4, 0.4 )
size_flags_horizontal = 0
size_flags_vertical = 3
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": true
}
inventory_ui_container = NodePath("FloatingInventory/panel/MarginContainer/ScrollContainer/container")
[node name="FloatingInventory" type="CanvasLayer" parent="."]
[node name="Polygon2D" type="Polygon2D" parent="FloatingInventory"]
color = Color( 0.156863, 0.0627451, 0, 1 )
polygon = PoolVector2Array( -3, 578, 1280, 578, 1280, 752, -3, 757 )
[node name="panel" type="TextureRect" parent="FloatingInventory"]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -1276.0
margin_top = -160.0
rect_min_size = Vector2( 0, 160 )
size_flags_horizontal = 3
size_flags_vertical = 3
expand = true
[node name="MarginContainer" type="MarginContainer" parent="FloatingInventory/panel"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = -4.0
margin_top = 2.0
margin_right = -16.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_constants/margin_right = 20
custom_constants/margin_top = 20
custom_constants/margin_left = 20
custom_constants/margin_bottom = 20
[node name="ScrollContainer" type="ScrollContainer" parent="FloatingInventory/panel/MarginContainer"]
margin_left = 20.0
margin_top = 79.0
margin_right = 1244.0
margin_bottom = 79.0
size_flags_horizontal = 3
size_flags_vertical = 6
scroll_vertical_enabled = false
[node name="container" type="HBoxContainer" parent="FloatingInventory/panel/MarginContainer/ScrollContainer"]
margin_right = 1224.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_constants/separation = 20
script = ExtResource( 3 )
[node name="InventoryTween" type="Tween" parent="FloatingInventory"]

View File

@@ -0,0 +1,13 @@
extends Node
class_name ESCItemComponent
var _custom_data: Dictionary
func get_global_id():
return self.get_parent().global_id
func get_component_type():
pass
func register(custom_data: Dictionary):
pass

View File

@@ -0,0 +1,9 @@
extends ESCItemComponent
class_name ESCItemComponentInventoryChecker
func get_component_type():
return "auto-inventory-checker"
func _enter_tree():
if escoria.inventory_manager.inventory_has(get_global_id()):
escoria.object_manager.get_object(get_global_id()).active = false

View File

@@ -0,0 +1,41 @@
extends ESCItemComponent
class_name ESCItemComponentOutline
var outline: ItemOutline
var isHighlighted: bool
var lastHighlightState: bool
func get_component_type():
return "outline"
func _ready():
var collision = get_parent().collision
if collision is CollisionPolygon2D:
outline = ItemOutline.new()
outline.polygon = collision.get("polygon")
outline.color = Color(1,1,1,0.2)
outline.set_outline_width(2.0)
outline.set_outline_color(Color(1,1,1,1))
collision.add_child(outline)
outline.hide()
func highlight(value: bool):
isHighlighted = value
func _process(_delta: float):
if not outline is ItemOutline:
return
if isHighlighted != lastHighlightState:
if isHighlighted and escoria.current_state == escoria.GAME_STATE.DEFAULT and get_parent().is_interactive:
outline.show()
else:
outline.hide()
lastHighlightState = isHighlighted
func _input(event):
if event.is_action_pressed("ui_show_hints") and escoria.current_state == escoria.GAME_STATE.DEFAULT:
highlight(true)
elif (event.is_action_released("ui_show_hints")):
highlight(false)

View File

@@ -0,0 +1,21 @@
tool
extends Polygon2D
class_name ItemOutline, "res://addons/escoria-core/design/esc_item.svg"
export(Color) var OutLine = Color(0,0,0) setget set_outline_color
export(float) var Width = 2.0 setget set_outline_width
func _draw():
var poly = get_polygon()
for i in range(1 , poly.size()):
draw_line(poly[i-1] , poly[i], OutLine , Width)
draw_line(poly[poly.size() - 1] , poly[0], OutLine , Width)
func set_outline_color(color):
OutLine = color
update()
func set_outline_width(new_width):
Width = new_width
update()

View File

@@ -0,0 +1,47 @@
# A simple main menu
extends Control
# Start the game
func _on_new_game_pressed():
escoria.new_game()
# Show the load slots
func _on_load_game_pressed():
$main.hide()
$load_game.refresh_savegames()
$load_game.show()
# Show the options panel
func _on_options_pressed():
$main.hide()
$options.show()
# Quit the game
func _on_quit_pressed():
escoria.quit()
# Hide the options panel again
func _on_options_back_button_pressed():
reset()
# Hide the load panel
func _on_load_game_back_button_pressed():
reset()
# Resets the UI to initial state
func reset():
$load_game.hide()
$options.hide()
$main.show()
func _on_new_without_intro_pressed():
escoria.globals_manager.set_global("cocina_delante_intro_played",true)
escoria.globals_manager.set_global("cocina_intro_played",true)
escoria.new_game()

View File

@@ -0,0 +1,111 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/menus/main_menu/main_menu.gd" type="Script" id=1]
[ext_resource path="res://gymkhana/logo-small.png" type="Texture" id=3]
[ext_resource path="res://addons/escoria-core/ui_library/menus/options/options.tscn" type="PackedScene" id=4]
[ext_resource path="res://addons/escoria-core/ui_library/menus/load_save/load/load_game.tscn" type="PackedScene" id=5]
[node name="main_menu" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 1 )
[node name="load_game" parent="." instance=ExtResource( 5 )]
visible = false
[node name="options" parent="." instance=ExtResource( 4 )]
visible = false
[node name="main" type="Control" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
[node name="Panel" type="Panel" parent="main"]
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
"_edit_use_anchors_": false,
"_editor_description_": ""
}
[node name="main" type="VBoxContainer" parent="main"]
anchor_left = 0.5
anchor_right = 0.5
anchor_bottom = 1.0
margin_left = -308.0
margin_right = 308.0
custom_constants/separation = 100
alignment = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TextureRect" type="TextureRect" parent="main/main"]
margin_top = 55.0
margin_right = 616.0
margin_bottom = 355.0
texture = ExtResource( 3 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="buttons" type="VBoxContainer" parent="main/main"]
margin_top = 455.0
margin_right = 616.0
margin_bottom = 695.0
custom_constants/separation = 10
__meta__ = {
"_edit_use_anchors_": false
}
[node name="new_game" type="Button" parent="main/main/buttons"]
margin_right = 616.0
margin_bottom = 150.0
rect_min_size = Vector2( 0, 150 )
size_flags_vertical = 3
text = "NEW_GAME"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="new_game_without_intro" type="Button" parent="main/main/buttons"]
margin_right = 616.0
margin_bottom = 270.0
size_flags_vertical = 3
text = "NEW_GAME (without intro)"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="load_game" type="Button" parent="main/main/buttons"]
margin_top = 160.0
margin_right = 616.0
margin_bottom = 180.0
text = "LOAD_GAME"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="options" type="Button" parent="main/main/buttons"]
margin_top = 190.0
margin_right = 616.0
margin_bottom = 210.0
text = "OPTIONS"
[node name="quit" type="Button" parent="main/main/buttons"]
margin_top = 220.0
margin_right = 616.0
margin_bottom = 240.0
text = "QUIT"
__meta__ = {
"_edit_use_anchors_": false
}
[connection signal="back_button_pressed" from="load_game" to="." method="_on_load_game_back_button_pressed"]
[connection signal="back_button_pressed" from="options" to="." method="_on_options_back_button_pressed"]
[connection signal="pressed" from="main/main/buttons/new_game" to="." method="_on_new_game_pressed"]
[connection signal="pressed" from="main/main/buttons/load_game" to="." method="_on_load_game_pressed"]
[connection signal="pressed" from="main/main/buttons/options" to="." method="_on_options_pressed"]
[connection signal="pressed" from="main/main/buttons/quit" to="." method="_on_quit_pressed"]
[connection signal="pressed" from="main/main/buttons/new_game_without_intro" to="." method="_on_new_without_intro_pressed"]

View File

@@ -0,0 +1,16 @@
# Basic information about an inventory item
class_name ESCInventoryItem
# Global ID of the ESCItem that uses this ESCInventoryItem
var global_id: String = ""
# The texture for the item
var texture: Texture = null
func _init(p_item: ESCItem) -> void:
global_id = p_item.global_id
texture = p_item._get_inventory_texture()
p_item.register_components()

View File

@@ -0,0 +1,7 @@
[plugin]
name="Escoria Return to Monkey Island UI"
description="Return to Monkey Island like UI for the Escoria Framework"
author="Arkitekt"
version="0.1.0"
script="plugin.gd"

View File

@@ -0,0 +1,37 @@
# Plugin script to initialize Escoria simple mouse UI
tool
extends EditorPlugin
# Override function to return the plugin name.
func get_plugin_name():
return "escoria-ui-return-monkey-island"
# Deregister UI
func disable_plugin():
print("Disabling plugin Escoria UI Return to Monkey Island.")
EscoriaPlugin.deregister_ui("res://gymkhana/addons/escoria-ui-return-monkey-island/game.tscn")
ESCProjectSettingsManager.remove_setting(
RTMIUiSettings.SOUND_LIBRARY_FOLDER
)
# Register UI with Escoria
func enable_plugin():
print("Enabling plugin Escoria Dialog Simple")
if EscoriaPlugin.register_ui(self, "res://gymkhana/addons/escoria-ui-return-monkey-island/game.tscn"):
ESCProjectSettingsManager.register_setting(
RTMIUiSettings.SOUND_LIBRARY_FOLDER,
"res://game/sounds",
{
"type": TYPE_STRING
}
)
else:
get_editor_interface().set_plugin_enabled(
get_plugin_name(),
false
)

View File

@@ -0,0 +1,7 @@
extends Resource
class_name RTMIUiSettings
const SETTINGS_ROOT = "escoria/rtmi_ui"
const SOUND_LIBRARY_FOLDER = "%s/sound_library_folder" % SETTINGS_ROOT

View File

@@ -0,0 +1,41 @@
[gd_resource type="Theme" load_steps=5 format=2]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/fonts/caslonantique.tres" type="DynamicFont" id=1]
[sub_resource type="StyleBoxFlat" id=1]
content_margin_left = 4.0
content_margin_right = 4.0
content_margin_top = 4.0
content_margin_bottom = 4.0
bg_color = Color( 0, 0, 0, 0.462745 )
corner_radius_top_right = 5
corner_radius_bottom_right = 5
expand_margin_left = 19.0
[sub_resource type="StyleBoxFlat" id=2]
bg_color = Color( 0, 0, 0, 0.509804 )
corner_radius_top_left = 5
corner_radius_top_right = 5
corner_radius_bottom_right = 5
corner_radius_bottom_left = 5
[sub_resource type="StyleBoxFlat" id=3]
bg_color = Color( 0, 0, 0, 0.388235 )
corner_radius_top_left = 5
corner_radius_top_right = 5
corner_radius_bottom_right = 5
corner_radius_bottom_left = 5
expand_margin_left = 5.0
expand_margin_right = 5.0
expand_margin_top = 5.0
expand_margin_bottom = 5.0
[resource]
default_font = ExtResource( 1 )
Label/colors/font_color = Color( 1, 1, 1, 1 )
Label/colors/font_color_shadow = Color( 0, 0, 0, 0 )
Label/colors/font_outline_modulate = Color( 1, 0, 0, 1 )
Label/colors/label_box_bg = Color( 0, 0, 0, 0.745098 )
Label/styles/normal = SubResource( 1 )
RichTextLabel/styles/focus = SubResource( 2 )
RichTextLabel/styles/normal = SubResource( 3 )

View File

@@ -0,0 +1,27 @@
tool
extends Node
signal finished
func play(video_file: String):
$VideoPlayer.set_stream(load(video_file))
$VideoPlayer.play()
func _on_VideoPlayer_finished():
self.visible = false
emit_signal("finished")
func skip():
$VideoPlayer.stop()
self.visible = false
emit_signal("finished")
func get_player():
return $VideoPlayer
func is_playing() -> bool:
var play = $VideoPlayer.is_playing()
return play
func _on_Skip_pressed():
skip()

View File

@@ -0,0 +1,39 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://gymkhana/addons/escoria-ui-return-monkey-island/video_player/video_player.gd" type="Script" id=1]
[sub_resource type="VideoStreamTheora" id=1]
[sub_resource type="InputEventAction" id=2]
action = "ui_cancel"
[sub_resource type="ShortCut" id=3]
shortcut = SubResource( 2 )
[node name="video_player" type="Control"]
margin_right = 1285.0
margin_bottom = 753.0
script = ExtResource( 1 )
[node name="ColorRect" type="ColorRect" parent="."]
margin_right = 1275.0
margin_bottom = 744.0
color = Color( 0, 0, 0, 1 )
[node name="VideoPlayer" type="VideoPlayer" parent="."]
margin_right = 1279.0
margin_bottom = 747.0
stream = SubResource( 1 )
expand = false
[node name="Skip" type="Button" parent="."]
margin_left = 1163.0
margin_top = 680.0
margin_right = 1250.0
margin_bottom = 712.0
shortcut = SubResource( 3 )
text = "Saltar video"
flat = true
[connection signal="finished" from="VideoPlayer" to="." method="_on_VideoPlayer_finished"]
[connection signal="pressed" from="Skip" to="." method="_on_Skip_pressed"]