mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-13 23:15:55 +00:00
Updated dialogic
This commit is contained in:
parent
1d11462073
commit
cbb82512ee
483 changed files with 5743 additions and 2177 deletions
|
|
@ -1 +1 @@
|
|||
uid://tesbnlcthnxh
|
||||
uid://cj42eg6uts07a
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://b4qa43srwtbnf
|
||||
uid://umnf6yt0lb06
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ func set_default_button(enabled:bool) -> void:
|
|||
|
||||
func preview() -> void:
|
||||
$Preview.load_overwrite(get_mood_info())
|
||||
$Preview._on_started_revealing_text()
|
||||
var preview_timer := Timer.new()
|
||||
DialogicUtil.update_timer_process_callback(preview_timer)
|
||||
add_child(preview_timer)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://x84nluahuf1e
|
||||
uid://6qkd50m2lqnx
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
[gd_scene load_steps=9 format=3 uid="uid://8ad1pwbjuqpt"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://x84nluahuf1e" path="res://addons/dialogic/Modules/Text/character_settings/character_moods_settings.gd" id="1_3px07"]
|
||||
[ext_resource type="Script" uid="uid://6qkd50m2lqnx" path="res://addons/dialogic/Modules/Text/character_settings/character_moods_settings.gd" id="1_3px07"]
|
||||
[ext_resource type="PackedScene" uid="uid://7mvxuaulctcq" path="res://addons/dialogic/Editor/Events/Fields/field_file.tscn" id="2_e1vyd"]
|
||||
[ext_resource type="PackedScene" uid="uid://kdpp3mibml33" path="res://addons/dialogic/Editor/Events/Fields/field_number.tscn" id="3_yjcns"]
|
||||
[ext_resource type="Script" uid="uid://bkfrnlul8c6cv" path="res://addons/dialogic/Modules/Text/node_type_sound.gd" id="5_yscws"]
|
||||
[ext_resource type="Script" uid="uid://dpv2dfiv5dhmr" path="res://addons/dialogic/Modules/Text/node_type_sound.gd" id="5_yscws"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_y7t05"]
|
||||
content_margin_left = 10.0
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ func _get_title() -> String:
|
|||
|
||||
|
||||
func _ready() -> void:
|
||||
%PortraitMood.get_suggestions_func = mood_suggestions
|
||||
%PortraitMood.suggestions_func = mood_suggestions
|
||||
%PortraitMood.resource_icon = get_theme_icon("AudioStreamPlayer", "EditorIcons")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://b6fg02bv71snt
|
||||
uid://vphe6s7nv242
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://bvfiv5uhmkqq7"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://b6fg02bv71snt" path="res://addons/dialogic/Modules/Text/character_settings/character_portrait_mood_settings.gd" id="1_5ni5u"]
|
||||
[ext_resource type="Script" uid="uid://vphe6s7nv242" path="res://addons/dialogic/Modules/Text/character_settings/character_portrait_mood_settings.gd" id="1_5ni5u"]
|
||||
[ext_resource type="PackedScene" uid="uid://dpwhshre1n4t6" path="res://addons/dialogic/Editor/Events/Fields/field_options_dynamic.tscn" id="1_oggvu"]
|
||||
|
||||
[node name="Typing Sound Mood" type="HBoxContainer"]
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ var text := ""
|
|||
## it will play.
|
||||
var character: DialogicCharacter = null
|
||||
## If a character is set, this setting can change the portrait of that character.
|
||||
## If a runtime-character is created, the portrait can instead be a color (hex or color name).
|
||||
var portrait := ""
|
||||
|
||||
### Helpers
|
||||
|
|
@ -24,15 +25,15 @@ var portrait := ""
|
|||
## Used to set the character resource from the unique name identifier and vice versa
|
||||
var character_identifier: String:
|
||||
get:
|
||||
if character:
|
||||
var identifier := DialogicResourceUtil.get_unique_identifier(character.resource_path)
|
||||
if character and not "{" in character_identifier:
|
||||
var identifier := character.get_identifier()
|
||||
if not identifier.is_empty():
|
||||
return identifier
|
||||
return character_identifier
|
||||
set(value):
|
||||
character_identifier = value
|
||||
character = DialogicResourceUtil.get_character_resource(value)
|
||||
if not character.portraits.has(portrait):
|
||||
if Engine.is_editor_hint() and ((not character) or (character and not character.portraits.has(portrait))):
|
||||
portrait = ""
|
||||
ui_update_needed.emit()
|
||||
|
||||
|
|
@ -51,44 +52,65 @@ func _clear_state() -> void:
|
|||
dialogic.current_state_info.erase('text_sub_idx')
|
||||
_disconnect_signals()
|
||||
|
||||
|
||||
func _execute() -> void:
|
||||
if text.is_empty():
|
||||
finish()
|
||||
return
|
||||
|
||||
if (not character or character.custom_info.get('style', '').is_empty()) and dialogic.has_subsystem('Styles'):
|
||||
# if previous characters had a custom style change back to base style
|
||||
if dialogic.current_state_info.get('base_style') != dialogic.current_state_info.get('style'):
|
||||
dialogic.Styles.change_style(dialogic.current_state_info.get('base_style', 'Default'))
|
||||
await dialogic.get_tree().process_frame
|
||||
## If the speaker is provided as an expression, parse it now.
|
||||
if "{" in character_identifier:
|
||||
character = null
|
||||
var character_name: String = dialogic.Expressions.execute_string(character_identifier)
|
||||
get_or_create_character(character_name)
|
||||
|
||||
var character_name_text := dialogic.Text.get_character_name_parsed(character)
|
||||
if character:
|
||||
if dialogic.has_subsystem('Styles') and character.custom_info.get('style', null):
|
||||
dialogic.Styles.change_style(character.custom_info.style, false)
|
||||
await dialogic.get_tree().process_frame
|
||||
## Change Portrait and Active Speaker
|
||||
if dialogic.has_subsystem("Portraits"):
|
||||
if character:
|
||||
|
||||
dialogic.Portraits.change_speaker(character, portrait)
|
||||
|
||||
if portrait and dialogic.has_subsystem('Portraits') and dialogic.Portraits.is_character_joined(character):
|
||||
dialogic.Portraits.change_character_portrait(character, portrait)
|
||||
dialogic.Portraits.change_speaker(character, portrait)
|
||||
var check_portrait: String = portrait if !portrait.is_empty() else dialogic.current_state_info['portraits'].get(character.resource_path, {}).get('portrait', '')
|
||||
if portrait and dialogic.Portraits.is_character_joined(character):
|
||||
dialogic.Portraits.change_character_portrait(character, portrait)
|
||||
|
||||
if check_portrait and character.portraits.get(check_portrait, {}).get('sound_mood', '') in character.custom_info.get('sound_moods', {}):
|
||||
dialogic.Text.update_typing_sound_mood(character.custom_info.get('sound_moods', {}).get(character.portraits[check_portrait].get('sound_mood', {}), {}))
|
||||
elif !character.custom_info.get('sound_mood_default', '').is_empty():
|
||||
dialogic.Text.update_typing_sound_mood(character.custom_info.get('sound_moods', {}).get(character.custom_info.get('sound_mood_default'), {}))
|
||||
else:
|
||||
dialogic.Text.update_typing_sound_mood()
|
||||
dialogic.Portraits.change_speaker(null)
|
||||
|
||||
## Change and Type Sound Mood
|
||||
if character:
|
||||
dialogic.Text.update_name_label(character)
|
||||
|
||||
var current_portrait: String = portrait
|
||||
if portrait.is_empty():
|
||||
current_portrait = dialogic.current_state_info["portraits"].get(character.get_identifier(), {}).get("portrait", "")
|
||||
|
||||
var current_portrait_sound_mood: String = character.portraits.get(current_portrait, {}).get("sound_mood", "")
|
||||
dialogic.Text.update_typing_sound_mood_from_character(character, current_portrait_sound_mood)
|
||||
|
||||
else:
|
||||
dialogic.Portraits.change_speaker(null)
|
||||
dialogic.Text.update_name_label(null)
|
||||
dialogic.Text.update_typing_sound_mood()
|
||||
|
||||
|
||||
## Handle style changes
|
||||
if dialogic.has_subsystem("Styles"):
|
||||
var current_base_style: String = dialogic.current_state_info.get("base_style")
|
||||
var current_style: String = dialogic.current_state_info.get("style", "")
|
||||
var character_style: String = "" if not character else character.custom_info.get("style", "")
|
||||
|
||||
## Change back to base style, if another characters style is currently used
|
||||
if (not character or character_style.is_empty()) and (current_base_style != current_style):
|
||||
dialogic.Styles.change_style(dialogic.current_state_info.get("base_style", "Default"))
|
||||
await dialogic.get_tree().process_frame
|
||||
|
||||
## Change to the characters style if this character has one
|
||||
elif character and not character_style.is_empty():
|
||||
dialogic.Styles.change_style(character_style, false)
|
||||
await dialogic.get_tree().process_frame
|
||||
|
||||
_connect_signals()
|
||||
|
||||
var character_name_text := dialogic.Text.get_character_name_parsed(character)
|
||||
var final_text: String = get_property_translated('text')
|
||||
if ProjectSettings.get_setting('dialogic/text/split_at_new_lines', false):
|
||||
match ProjectSettings.get_setting('dialogic/text/split_at_new_lines_as', 0):
|
||||
|
|
@ -114,10 +136,10 @@ func _execute() -> void:
|
|||
|
||||
dialogic.current_state_info['text_sub_idx'] = section_idx
|
||||
|
||||
var segment: String = dialogic.Text.parse_text(split_text[section_idx][0])
|
||||
var segment: String = dialogic.Text.parse_text(split_text[section_idx][0], 0)
|
||||
var is_append: bool = split_text[section_idx][1]
|
||||
|
||||
final_text = segment
|
||||
final_text = ProjectSettings.get_setting("dialogic/text/dialog_text_prefix", "")+segment
|
||||
dialogic.Text.about_to_show_text.emit({'text':final_text, 'character':character, 'portrait':portrait, 'append': is_append})
|
||||
|
||||
await dialogic.Text.update_textbox(final_text, false)
|
||||
|
|
@ -126,6 +148,8 @@ func _execute() -> void:
|
|||
_try_play_current_line_voice()
|
||||
final_text = dialogic.Text.update_dialog_text(final_text, false, is_append)
|
||||
|
||||
dialogic.Text.text_started.emit({'text':final_text, 'character':character, 'portrait':portrait, 'append': is_append})
|
||||
|
||||
_mark_as_read(character_name_text, final_text)
|
||||
|
||||
# We must skip text animation before we potentially return when there
|
||||
|
|
@ -257,22 +281,23 @@ func _init() -> void:
|
|||
event_category = "Main"
|
||||
event_sorting_index = 0
|
||||
expand_by_default = true
|
||||
help_page_path = "https://docs.dialogic.pro/writing-text-events.html"
|
||||
help_page_path = "https://docs.dialogic.pro/writing-texts.html"
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
## SAVING/LOADING
|
||||
#region SAVING/LOADING
|
||||
################################################################################
|
||||
|
||||
func to_text() -> String:
|
||||
var result := text.replace('\n', '\\\n')
|
||||
var result := text.replace('\n', '\\\n').strip_edges(false).trim_suffix("\\")
|
||||
result = result.replace(':', '\\:')
|
||||
if result.is_empty():
|
||||
result = "<Empty Text Event>"
|
||||
|
||||
if character:
|
||||
var name := DialogicResourceUtil.get_unique_identifier(character.resource_path)
|
||||
if character or character_identifier:
|
||||
var name := character_identifier
|
||||
if character:
|
||||
name = character.get_identifier()
|
||||
if name.count(" ") > 0:
|
||||
name = '"' + name + '"'
|
||||
if not portrait.is_empty():
|
||||
|
|
@ -293,27 +318,45 @@ func from_text(string:String) -> void:
|
|||
character = DialogicResourceUtil.get_character_resource(character_identifier)
|
||||
|
||||
var result := regex.search(string.trim_prefix('\\'))
|
||||
|
||||
if result.get_string('portrait'):
|
||||
portrait = result.get_string('portrait').strip_edges().trim_prefix('(').trim_suffix(')')
|
||||
|
||||
if result and not result.get_string('name').is_empty():
|
||||
var name := result.get_string('name').strip_edges()
|
||||
|
||||
if name == '_':
|
||||
character = null
|
||||
elif "{" in name:
|
||||
## If it's an expression, we load the character in _execute.
|
||||
character_identifier = name
|
||||
character = null
|
||||
else:
|
||||
character = DialogicResourceUtil.get_character_resource(name)
|
||||
get_or_create_character(name)
|
||||
|
||||
if character == null and Engine.is_editor_hint() == false:
|
||||
character = DialogicCharacter.new()
|
||||
character.display_name = name
|
||||
character.resource_path = "user://"+name+".dch"
|
||||
DialogicResourceUtil.add_resource_to_directory(character.resource_path, DialogicResourceUtil.get_character_directory())
|
||||
if not result:
|
||||
return
|
||||
|
||||
if !result.get_string('portrait').is_empty():
|
||||
portrait = result.get_string('portrait').strip_edges().trim_prefix('(').trim_suffix(')')
|
||||
text = result.get_string('text').replace("\\\n", "\n").replace('\\:', ':').strip_edges().trim_prefix('\\')
|
||||
if text == '<Empty Text Event>':
|
||||
text = ""
|
||||
|
||||
if result:
|
||||
text = result.get_string('text').replace("\\\n", "\n").replace('\\:', ':').strip_edges().trim_prefix('\\')
|
||||
if text == '<Empty Text Event>':
|
||||
text = ""
|
||||
|
||||
func get_or_create_character(name:String) -> void:
|
||||
character = DialogicResourceUtil.get_character_resource(name)
|
||||
|
||||
if character == null:
|
||||
if Engine.is_editor_hint() == false:
|
||||
character = DialogicCharacter.new()
|
||||
character.display_name = name
|
||||
character.set_identifier(name)
|
||||
if portrait:
|
||||
if "{" in portrait:
|
||||
character.color = Color(dialogic.Expressions.execute_string(portrait))
|
||||
else:
|
||||
character.color = Color(portrait)
|
||||
else:
|
||||
character_identifier = name
|
||||
|
||||
|
||||
func is_valid_event(_string:String) -> bool:
|
||||
|
|
@ -329,8 +372,8 @@ func is_string_full_event(string:String) -> bool:
|
|||
func get_shortcode_parameters() -> Dictionary:
|
||||
return {
|
||||
#param_name : property_info
|
||||
"character" : {"property": "character_identifier", "default": ""},
|
||||
"portrait" : {"property": "portrait", "default": ""},
|
||||
"character" : {"property": "character_identifier", "default": "", "ext_file":true},
|
||||
"portrait" : {"property": "portrait", "default": ""},
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
|
@ -364,7 +407,7 @@ func build_event_editor() -> void:
|
|||
{'file_extension' : '.dch',
|
||||
'mode' : 2,
|
||||
'suggestions_func' : get_character_suggestions,
|
||||
'empty_text' : '(No one)',
|
||||
'placeholder' : '(No one)',
|
||||
'icon' : load("res://addons/dialogic/Editor/Images/Resources/character.svg")}, 'do_any_characters_exist()')
|
||||
add_header_edit('portrait', ValueType.DYNAMIC_OPTIONS,
|
||||
{'suggestions_func' : get_portrait_suggestions,
|
||||
|
|
@ -384,8 +427,13 @@ func do_any_characters_exist() -> bool:
|
|||
|
||||
|
||||
func get_character_suggestions(search_text:String) -> Dictionary:
|
||||
return DialogicUtil.get_character_suggestions(search_text, character, true, false, editor_node)
|
||||
|
||||
var suggestions := DialogicUtil.get_character_suggestions(search_text, character, true, false, editor_node)
|
||||
if search_text and not search_text in suggestions:
|
||||
suggestions[search_text] = {
|
||||
"value":search_text,
|
||||
"tooltip": "A temporary character, created on the spot.",
|
||||
"editor_icon":["GuiEllipsis", "EditorIcons"]}
|
||||
return suggestions
|
||||
|
||||
func get_portrait_suggestions(search_text:String) -> Dictionary:
|
||||
return DialogicUtil.get_portrait_suggestions(search_text, character, true, "Don't change")
|
||||
|
|
@ -429,7 +477,7 @@ func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:Str
|
|||
|
||||
|
||||
func _get_start_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
|
||||
CodeCompletionHelper.suggest_characters(TextNode, CodeEdit.KIND_CLASS, true)
|
||||
CodeCompletionHelper.suggest_characters(TextNode, CodeEdit.KIND_CLASS, self)
|
||||
|
||||
|
||||
func suggest_bbcode(TextNode:CodeEdit):
|
||||
|
|
@ -462,10 +510,10 @@ var text_effect_color := Color('#898276')
|
|||
func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, line:String) -> Dictionary:
|
||||
load_text_effects()
|
||||
if text_random_word_regex.get_pattern().is_empty():
|
||||
text_random_word_regex.compile("(?<!\\\\)\\<[^\\[\\>]+(\\/[^\\>]*)\\>")
|
||||
text_random_word_regex.compile(r"(?<!\\)\<[^\>]+(\/[^\>]*)\>")
|
||||
|
||||
var result := regex.search(line)
|
||||
if !result:
|
||||
if not result:
|
||||
return dict
|
||||
if Highlighter.mode == Highlighter.Modes.FULL_HIGHLIGHTING:
|
||||
if result.get_string('name'):
|
||||
|
|
@ -475,24 +523,29 @@ func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, li
|
|||
dict[result.get_start('portrait')] = {"color":Highlighter.character_portrait_color}
|
||||
dict[result.get_end('portrait')] = {"color":Highlighter.normal_color}
|
||||
if result.get_string('text'):
|
||||
var effects_result := text_effects_regex.search_all(line)
|
||||
for eff in effects_result:
|
||||
dict[eff.get_start()] = {"color":text_effect_color}
|
||||
dict[eff.get_end()] = {"color":Highlighter.normal_color}
|
||||
dict = Highlighter.color_region(dict, Highlighter.variable_color, line, '{', '}', result.get_start('text'))
|
||||
|
||||
## Color the random selection modifier
|
||||
for replace_mod_match in text_random_word_regex.search_all(result.get_string('text')):
|
||||
var color: Color = Highlighter.string_color
|
||||
color = color.lerp(Highlighter.normal_color, 0.4)
|
||||
dict[replace_mod_match.get_start()+result.get_start('text')] = {'color':Highlighter.string_color}
|
||||
var offset := 1
|
||||
for b in replace_mod_match.get_string().trim_suffix('>').trim_prefix('<').split('/'):
|
||||
for b:RegExMatch in RegEx.create_from_string(r"(\[[^\]]*\]|[^\/]|\/\/)+").search_all(replace_mod_match.get_string().trim_prefix("<").trim_suffix(">")):
|
||||
color.h = wrap(color.h+0.2, 0, 1)
|
||||
dict[replace_mod_match.get_start()+result.get_start('text')+offset] = {'color':color}
|
||||
offset += len(b)
|
||||
offset += len(b.get_string())
|
||||
dict[replace_mod_match.get_start()+result.get_start('text')+offset] = {'color':Highlighter.string_color}
|
||||
offset += 1
|
||||
dict[replace_mod_match.get_end()+result.get_start('text')] = {'color':Highlighter.normal_color}
|
||||
|
||||
## Color bbcode and text effects
|
||||
var effects_result := text_effects_regex.search_all(line)
|
||||
for eff in effects_result:
|
||||
var prev_color: Color = Highlighter.dict_get_color_at_column(dict, eff.get_start())
|
||||
dict[eff.get_start()] = {"color":text_effect_color.lerp(prev_color, 0.4)}
|
||||
dict[eff.get_end()] = {"color":prev_color}
|
||||
dict = Highlighter.color_region(dict, Highlighter.variable_color, line, '{', '}', result.get_start('text'))
|
||||
|
||||
return dict
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://v1q0c4baexov
|
||||
uid://datmius068d8h
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://8cq5nqyn5kaa
|
||||
uid://bthukngr7e6io
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://d3jie3vjagf3x
|
||||
uid://dbx6k01krd1xx
|
||||
|
|
|
|||
|
|
@ -52,6 +52,12 @@ func _ready() -> void:
|
|||
textbox_root.hide()
|
||||
text = ""
|
||||
|
||||
var custom_bbcode_effects: Array = ProjectSettings.get_setting("dialogic/text/custom_bbcode_effects", "").split(",", false)
|
||||
for i in custom_bbcode_effects:
|
||||
var x : Resource = load(i.strip_edges())
|
||||
if x is RichTextEffect:
|
||||
custom_effects.append(x)
|
||||
|
||||
|
||||
# this is called by the DialogicGameHandler to set text
|
||||
|
||||
|
|
@ -60,6 +66,8 @@ func reveal_text(_text: String, keep_previous:=false) -> void:
|
|||
return
|
||||
show()
|
||||
|
||||
custom_fx_reset()
|
||||
|
||||
if !keep_previous:
|
||||
text = _text
|
||||
base_visible_characters = 0
|
||||
|
|
@ -73,6 +81,7 @@ func reveal_text(_text: String, keep_previous:=false) -> void:
|
|||
else:
|
||||
base_visible_characters = len(text)
|
||||
visible_characters = len(get_parsed_text())
|
||||
custom_fx_update()
|
||||
text = text + _text
|
||||
|
||||
# If Auto-Skip is enabled and we append the text (keep_previous),
|
||||
|
|
@ -113,16 +122,21 @@ func continue_reveal() -> void:
|
|||
|
||||
if visible_characters > -1 and visible_characters <= len(get_parsed_text()):
|
||||
continued_revealing_text.emit(get_parsed_text()[visible_characters-1])
|
||||
|
||||
custom_fx_update()
|
||||
else:
|
||||
finish_text()
|
||||
finish_text(true)
|
||||
# if the text finished organically, add a small input block
|
||||
# this prevents accidental skipping when you expected the text to be longer
|
||||
DialogicUtil.autoload().Inputs.block_input(ProjectSettings.get_setting('dialogic/text/advance_delay', 0.1))
|
||||
|
||||
|
||||
## Reveals the entire text instantly.
|
||||
func finish_text() -> void:
|
||||
func finish_text(is_organic := false) -> void:
|
||||
visible_ratio = 1
|
||||
custom_fx_update()
|
||||
if not is_organic:
|
||||
custom_fx_skip()
|
||||
DialogicUtil.autoload().Text.execute_effects(-1, self, true)
|
||||
revealing = false
|
||||
DialogicUtil.autoload().current_state = DialogicGameHandler.States.IDLE
|
||||
|
|
@ -156,3 +170,21 @@ func _on_meta_clicked(_meta:Variant) -> void:
|
|||
## Handle mouse input
|
||||
func on_gui_input(event:InputEvent) -> void:
|
||||
DialogicUtil.autoload().Inputs.handle_node_gui_input(event)
|
||||
|
||||
|
||||
func custom_fx_update() -> void:
|
||||
for effect in custom_effects:
|
||||
if "visible_characters" in effect:
|
||||
effect.visible_characters = visible_characters
|
||||
|
||||
|
||||
func custom_fx_reset() -> void:
|
||||
for effect in custom_effects:
|
||||
if effect.has_method("reset"):
|
||||
effect.reset()
|
||||
|
||||
|
||||
func custom_fx_skip() -> void:
|
||||
for effect in custom_effects:
|
||||
if effect.has_method("skip"):
|
||||
effect.skip()
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://ddkvkdb6nxtyi
|
||||
uid://drhfq6rmdeuri
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://do47nn7beuhn5
|
||||
uid://ctog34kdg222q
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://be3h8wr0w68dx
|
||||
uid://bak74s0kcr0ao
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://dk0xy5qppo033
|
||||
uid://dve1vwse2peji
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://bkfrnlul8c6cv
|
||||
uid://dpv2dfiv5dhmr
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ const _SETTING_TEXT_REVEAL_SKIPPABLE_DELAY := 'dialogic/text/text_reveal_skip_d
|
|||
const _SETTING_TEXT_ADVANCE_DELAY := 'dialogic/text/advance_delay'
|
||||
|
||||
const _SETTING_AUTOCOLOR_NAMES := 'dialogic/text/autocolor_names'
|
||||
const _SETTING_TEXT_PREFIX := 'dialogic/text/dialog_text_prefix'
|
||||
const _SETTING_CUSTOM_BBCODE_EFFECTS := 'dialogic/text/custom_bbcode_effects'
|
||||
const _SETTING_SPLIT_AT_NEW_LINES := 'dialogic/text/split_at_new_lines'
|
||||
const _SETTING_SPLIT_AT_NEW_LINES_AS := 'dialogic/text/split_at_new_lines_as'
|
||||
|
||||
|
|
@ -44,6 +46,8 @@ func _ready() -> void:
|
|||
%AdvanceDelay.value_changed.connect(_on_float_set.bind(_SETTING_TEXT_ADVANCE_DELAY))
|
||||
|
||||
%AutocolorNames.toggled.connect(_on_bool_set.bind(_SETTING_AUTOCOLOR_NAMES))
|
||||
%TextPrefix.text_changed.connect(_on_string_set.bind(_SETTING_TEXT_PREFIX))
|
||||
%CustomBBCodeEffects.text_changed.connect(_on_string_set.bind(_SETTING_CUSTOM_BBCODE_EFFECTS))
|
||||
|
||||
%NewEvents.toggled.connect(_on_bool_set.bind(_SETTING_SPLIT_AT_NEW_LINES))
|
||||
|
||||
|
|
@ -62,13 +66,15 @@ func _refresh() -> void:
|
|||
|
||||
%InputAction.resource_icon = get_theme_icon(&"Mouse", &"EditorIcons")
|
||||
%InputAction.set_value(ProjectSettings.get_setting(_SETTING_INPUT_ACTION, &'dialogic_default_action'))
|
||||
%InputAction.get_suggestions_func = suggest_actions
|
||||
%InputAction.suggestions_func = suggest_actions
|
||||
|
||||
%Skippable.button_pressed = ProjectSettings.get_setting(_SETTING_TEXT_REVEAL_SKIPPABLE, true)
|
||||
%SkippableDelay.value = ProjectSettings.get_setting(_SETTING_TEXT_REVEAL_SKIPPABLE_DELAY, 0.1)
|
||||
%AdvanceDelay.value = ProjectSettings.get_setting(_SETTING_TEXT_ADVANCE_DELAY, 0.1)
|
||||
|
||||
%AutocolorNames.button_pressed = ProjectSettings.get_setting(_SETTING_AUTOCOLOR_NAMES, false)
|
||||
%TextPrefix.text = ProjectSettings.get_setting(_SETTING_TEXT_PREFIX, "")
|
||||
%CustomBBCodeEffects.text = ProjectSettings.get_setting(_SETTING_CUSTOM_BBCODE_EFFECTS, "")
|
||||
|
||||
%NewEvents.button_pressed = ProjectSettings.get_setting(_SETTING_SPLIT_AT_NEW_LINES, false)
|
||||
%NewEventOption.select(ProjectSettings.get_setting(_SETTING_SPLIT_AT_NEW_LINES_AS, 0))
|
||||
|
|
@ -115,14 +121,18 @@ func _on_float_set(value:float, setting:String) -> void:
|
|||
ProjectSettings.save()
|
||||
|
||||
|
||||
func _on_string_set(value:String, setting:String) -> void:
|
||||
ProjectSettings.set_setting(setting, value)
|
||||
ProjectSettings.save()
|
||||
|
||||
#region BEHAVIOUR
|
||||
################################################################################
|
||||
|
||||
func _on_InputAction_value_changed(property_name:String, value:String) -> void:
|
||||
func _on_InputAction_value_changed(_property_name:String, value:String) -> void:
|
||||
ProjectSettings.set_setting(_SETTING_INPUT_ACTION, value)
|
||||
ProjectSettings.save()
|
||||
|
||||
func suggest_actions(search:String) -> Dictionary:
|
||||
func suggest_actions(_search:String) -> Dictionary:
|
||||
var suggs := {}
|
||||
for prop in ProjectSettings.get_property_list():
|
||||
if prop.name.begins_with('input/') and not prop.name.begins_with('input/ui_') :
|
||||
|
|
@ -237,4 +247,3 @@ func _on_remove_autopauses_set_pressed(index: int) -> void:
|
|||
for key in autopause_sets[index]:
|
||||
autopause_sets[index][key].queue_free()
|
||||
autopause_sets.erase(index)
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://b5ltnfwvbfbfc
|
||||
uid://cdxck874xobqh
|
||||
|
|
|
|||
|
|
@ -1,26 +1,13 @@
|
|||
[gd_scene load_steps=6 format=3 uid="uid://cf3qks3v18xmr"]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://cf3qks3v18xmr"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://b5ltnfwvbfbfc" path="res://addons/dialogic/Modules/Text/settings_text.gd" id="2"]
|
||||
[ext_resource type="Script" uid="uid://cdxck874xobqh" path="res://addons/dialogic/Modules/Text/settings_text.gd" id="2"]
|
||||
[ext_resource type="PackedScene" uid="uid://dpwhshre1n4t6" path="res://addons/dialogic/Editor/Events/Fields/field_options_dynamic.tscn" id="3"]
|
||||
[ext_resource type="PackedScene" uid="uid://dbpkta2tjsqim" path="res://addons/dialogic/Editor/Common/hint_tooltip_icon.tscn" id="3_s7xhj"]
|
||||
|
||||
[sub_resource type="Image" id="Image_15d2e"]
|
||||
data = {
|
||||
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
|
||||
"format": "RGBA8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id="ImageTexture_3xcp4"]
|
||||
image = SubResource("Image_15d2e")
|
||||
|
||||
[node name="DialogText" type="VBoxContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_bottom = -156.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("2")
|
||||
|
|
@ -48,7 +35,7 @@ text = "Default letter speed"
|
|||
[node name="HintTooltip2" parent="VBoxContainer/VBox/DefaultSpeedLabel" instance=ExtResource("3_s7xhj")]
|
||||
layout_mode = 2
|
||||
tooltip_text = "The speed in seconds per character. A speed of 0 will reveal the full text instantly (still taking pauses into consideration)."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "The speed in seconds per character. A speed of 0 will reveal the full text instantly (still taking pauses into consideration)."
|
||||
|
||||
[node name="DefaultSpeed" type="SpinBox" parent="VBoxContainer/VBox"]
|
||||
|
|
@ -67,7 +54,7 @@ text = "Input action"
|
|||
layout_mode = 2
|
||||
tooltip_text = "The action that skips text and generally advances to the next event.
|
||||
You can modify actions in the Project Settings > Input Map."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "The action that skips text and generally advances to the next event.
|
||||
You can modify actions in the Project Settings > Input Map."
|
||||
|
||||
|
|
@ -87,7 +74,7 @@ text = "Text Reveal Skippable"
|
|||
layout_mode = 2
|
||||
tooltip_text = "If enabled the revealing of text can be skipped with the input action.
|
||||
If disabled you can only advance to the next event when revealing has finnished."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "If enabled the revealing of text can be skipped with the input action.
|
||||
If disabled you can only advance to the next event when revealing has finnished."
|
||||
|
||||
|
|
@ -110,7 +97,7 @@ layout_mode = 2
|
|||
tooltip_text = "Delay before you can skip.
|
||||
|
||||
Use this to prevent users from skipping through your timeline to quickly."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "Delay before you can skip.
|
||||
|
||||
Use this to prevent users from skipping through your timeline too quickly."
|
||||
|
|
@ -134,7 +121,7 @@ layout_mode = 2
|
|||
tooltip_text = "Delay before you can advance (if the text finishes revealing on its own).
|
||||
|
||||
This is used to prevent players from advancing when they actually wanted to skip the revealing, but did so very shortly after the text was already fully revealed."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "Delay before you can advance (only if the text finishes revealing on its own).
|
||||
|
||||
This is used to prevent players from advancing when they actually wanted to skip the revealing, but did so very shortly after the text was already fully revealed."
|
||||
|
|
@ -156,13 +143,47 @@ text = "Autocolor names"
|
|||
[node name="HintTooltip5" parent="VBoxContainer/VBox/ColorNames" instance=ExtResource("3_s7xhj")]
|
||||
layout_mode = 2
|
||||
tooltip_text = "If enabled character names will be colored in the characters color in text events."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "If enabled character names will be colored in the characters color in text events."
|
||||
|
||||
[node name="AutocolorNames" type="CheckBox" parent="VBoxContainer/VBox"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="TextPrefixLabel" type="HBoxContainer" parent="VBoxContainer/VBox"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label4" type="Label" parent="VBoxContainer/VBox/TextPrefixLabel"]
|
||||
layout_mode = 2
|
||||
text = "Text prefix"
|
||||
|
||||
[node name="HintTooltip5" parent="VBoxContainer/VBox/TextPrefixLabel" instance=ExtResource("3_s7xhj")]
|
||||
layout_mode = 2
|
||||
tooltip_text = "If enabled character names will be colored in the characters color in text events."
|
||||
texture = null
|
||||
hint_text = "This is put before the text. Can be used to apply bbcode effects to all texts."
|
||||
|
||||
[node name="TextPrefix" type="LineEdit" parent="VBoxContainer/VBox"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="BBCodeEffectLabel" type="HBoxContainer" parent="VBoxContainer/VBox"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label4" type="Label" parent="VBoxContainer/VBox/BBCodeEffectLabel"]
|
||||
layout_mode = 2
|
||||
text = "Custom BBCode Effects"
|
||||
|
||||
[node name="HintTooltip5" parent="VBoxContainer/VBox/BBCodeEffectLabel" instance=ExtResource("3_s7xhj")]
|
||||
layout_mode = 2
|
||||
tooltip_text = "This is put before the text. Can be used to apply bbcode effects to all texts."
|
||||
texture = null
|
||||
hint_text = "Supply a list of bbcode effect resources (paths or uids) separated by comma."
|
||||
|
||||
[node name="CustomBBCodeEffects" type="LineEdit" parent="VBoxContainer/VBox"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HBoxContainer3" type="HBoxContainer" parent="VBoxContainer/VBox"]
|
||||
layout_mode = 2
|
||||
|
||||
|
|
@ -174,7 +195,7 @@ text = "New lines as new events"
|
|||
layout_mode = 2
|
||||
tooltip_text = "If enabled dialogic, new lines will be treated as [n] effects,
|
||||
seemingly waiting for input before starting a new text."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "If enabled dialogic, new lines will be treated as [n] effects,
|
||||
seemingly waiting for input before starting a new text."
|
||||
|
||||
|
|
@ -188,9 +209,9 @@ layout_mode = 2
|
|||
[node name="NewEventOption" type="OptionButton" parent="VBoxContainer/VBox/HBoxContainer4"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
item_count = 2
|
||||
selected = 0
|
||||
fit_to_longest_item = false
|
||||
item_count = 2
|
||||
popup/item_0/text = "As new event"
|
||||
popup/item_0/id = 0
|
||||
popup/item_1/text = "Appended"
|
||||
|
|
@ -219,7 +240,7 @@ These add up, so if any of them is true, Auto-Advance will happen.
|
|||
Unless manual advancement is disabled, the Auto-Advance time can always be skipped by the player.
|
||||
|
||||
The Auto-Advance will wait for Voice audio to finish playing. This behaviour can be disabled via code. "
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "Autoadvance is the concept of automatically progressing to the next event upon completing text display, usually after a certain delay.
|
||||
|
||||
You can enabled Auto-Advance from code using either:
|
||||
|
|
@ -245,7 +266,7 @@ text = "Base Delay"
|
|||
[node name="HintTooltip" parent="VBoxContainer/AutoadvanceSettings/HBox_BaseDelay2" instance=ExtResource("3_s7xhj")]
|
||||
layout_mode = 2
|
||||
tooltip_text = "This is the base delay for autoadvancment."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "This is the base delay for autoadvancment."
|
||||
|
||||
[node name="FixedDelay" type="SpinBox" parent="VBoxContainer/AutoadvanceSettings"]
|
||||
|
|
@ -268,7 +289,7 @@ layout_mode = 2
|
|||
tooltip_text = "An additional delay per character or word can be added.
|
||||
|
||||
Note: When changing values via code, you can actually use both modes simultaniously."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "An additional delay per character or word can be added.
|
||||
|
||||
Note: When changing values via code, you can actually use both modes simultaniously."
|
||||
|
|
@ -279,9 +300,9 @@ layout_mode = 2
|
|||
[node name="AdditionalDelayMode" type="OptionButton" parent="VBoxContainer/AutoadvanceSettings/HBoxContainer2"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
item_count = 3
|
||||
selected = 0
|
||||
fit_to_longest_item = false
|
||||
item_count = 3
|
||||
popup/item_0/text = "None"
|
||||
popup/item_0/id = 0
|
||||
popup/item_1/text = "Per Word"
|
||||
|
|
@ -308,7 +329,7 @@ tooltip_text = "An ignored character will add no delay, this is useful to exclud
|
|||
|
||||
If disabled, the general line of text length will be used, stripping the BBCode tags first.
|
||||
If enabled, the text will be scanned and the matching characters will be skipped."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "An ignored character will add no delay, this is useful to exclude interpunction and whitespaces.
|
||||
|
||||
If disabled, the general line of text length will be used, stripping the BBCode tags first.
|
||||
|
|
@ -336,7 +357,7 @@ layout_mode = 2
|
|||
tooltip_text = "While you would usually enable Auto-Advance via code,
|
||||
if this is true it will be initially enabled.
|
||||
This kind of Auto-Advance (system) only stops when disabled via code. "
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "While you would usually enable Auto-Advance via code,
|
||||
if this is true it will be initially enabled.
|
||||
This kind of Auto-Advance (system) only stops when disabled via code. "
|
||||
|
|
@ -366,7 +387,7 @@ Dialogic.Inputs.auto_skip.enabled = true
|
|||
By default, Auto-Skip will cancel on user input.
|
||||
You can disable this by calling:
|
||||
Dialogic.Inputs.auto_skip.disable_on_user_input = false"
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "Auto-Skip is the concept of automatically skipping Timeline Events to the next unread Text Event or Event demanding user inputs (e.g. Choice, Wait Input, and Text Input).
|
||||
|
||||
You can enable Auto-Skip from code via:
|
||||
|
|
@ -393,7 +414,7 @@ tooltip_text = "The time until Auto-Skip will execute the next event.
|
|||
|
||||
If this is set to 0.1s, each event should finish within that time.
|
||||
Custom events must respect this time, built-in events already handle Auto-Skip."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "The time until Auto-Skip will execute the next event.
|
||||
|
||||
If this is set to 0.1s, each event should finish within that time.
|
||||
|
|
@ -424,7 +445,7 @@ tooltip_text = "Adds pauses after certain letters.
|
|||
|
||||
Each set can contain multiple letters that will (individually)
|
||||
have a pause of the given length added after them."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "Adds pauses after certain letters.
|
||||
|
||||
Each set can contain multiple letters that will (individually)
|
||||
|
|
@ -452,7 +473,7 @@ text = "Absolute auto-pause times"
|
|||
[node name="HintTooltip7" parent="VBoxContainer/HBoxContainer3" instance=ExtResource("3_s7xhj")]
|
||||
layout_mode = 2
|
||||
tooltip_text = "If not enabled autopauses will be multiplied by the speed and user speed. When enabled those will be ignored."
|
||||
texture = SubResource("ImageTexture_3xcp4")
|
||||
texture = null
|
||||
hint_text = "If not enabled autopauses will be multiplied by the speed and user speed. When enabled those will be ignored."
|
||||
|
||||
[node name="AutoPausesAbsolute" type="CheckBox" parent="VBoxContainer/HBoxContainer3"]
|
||||
|
|
|
|||
|
|
@ -4,18 +4,48 @@ extends DialogicSubsystem
|
|||
|
||||
#region SIGNALS
|
||||
|
||||
## Emitted when a text event is reached or a new text section is about to be shown.
|
||||
## Gives a dictionary with the following keys: [br]
|
||||
## [br]
|
||||
## Key | Value Type | Value [br]
|
||||
## ----------- | ------------- | ----- [br]
|
||||
## `text` | [type String] | The text that is being displayed. [br]
|
||||
## `character` | [type DialogicCharacter] | The character that says this text. [br]
|
||||
## `portrait` | [type String] | The name of the portrait the character will use. [br]
|
||||
## `append` | [type bool] | Whether the text will be appended to the previous text. [br]
|
||||
@warning_ignore("unused_signal") # This is emitted by the text event.
|
||||
signal about_to_show_text(info:Dictionary)
|
||||
## Emitted when a text event (or a new text section) starts displaying.
|
||||
## This will be AFTER the textox animation, while [signal about_to_show_text] is before.
|
||||
## Gives a dictionary with the same values as [signal about_to_show_text]
|
||||
@warning_ignore("unused_signal") # This is emitted by the text event.
|
||||
signal text_started(info:Dictionary)
|
||||
## When the text has finished revealing.
|
||||
## Gives a dictionary with the keys text and character.
|
||||
signal text_finished(info:Dictionary)
|
||||
## Emitted when the speaker changes.
|
||||
signal speaker_updated(character:DialogicCharacter)
|
||||
## Emitted when the textbox is shown or hidden.
|
||||
signal textbox_visibility_changed(visible:bool)
|
||||
|
||||
signal animation_textbox_new_text
|
||||
## Emitted when the textbox appears.
|
||||
## Use this together with the Animations subsystem to implement animations.
|
||||
## If you start an animation and want dialogic to wait for it to finish before showing text,
|
||||
## call Dialogic.Animations.start_animating() and then Dialogic.animation_finished() once it's done.
|
||||
signal animation_textbox_show
|
||||
## Emitted when the textbox is hiding. Use like [signal animation_textbox_show].
|
||||
signal animation_textbox_hide
|
||||
## Emitted when a new text starts. Use like [signal animation_textbox_show].
|
||||
signal animation_textbox_new_text
|
||||
|
||||
# forwards of the dialog_text signals of all present dialog_text nodes
|
||||
signal meta_hover_ended(meta:Variant)
|
||||
## Emitted when a meta text on any DialogText node is hovered.
|
||||
@warning_ignore("unused_signal") # These are emitted by the NodeDialogText
|
||||
signal meta_hover_started(meta:Variant)
|
||||
## Emitted when a meta text on any DialogText node is not hovered anymore.
|
||||
@warning_ignore("unused_signal") # These are emitted by the NodeDialogText
|
||||
signal meta_hover_ended(meta:Variant)
|
||||
## Emitted when a meta text on any DialogText node is clicked.
|
||||
@warning_ignore("unused_signal") # These are emitted by the NodeDialogText
|
||||
signal meta_clicked(meta:Variant)
|
||||
|
||||
#endregion
|
||||
|
|
@ -29,7 +59,7 @@ var text_already_read := false
|
|||
var text_effects := {}
|
||||
var parsed_text_effect_info: Array[Dictionary] = []
|
||||
var text_effects_regex := RegEx.new()
|
||||
enum TextModifierModes {ALL=-1, TEXT_ONLY=0, CHOICES_ONLY=1}
|
||||
enum ParserModes {ALL=-1, TEXT_ONLY=0, CHOICES_ONLY=1}
|
||||
enum TextTypes {DIALOG_TEXT, CHOICE_TEXT}
|
||||
var text_modifiers := []
|
||||
|
||||
|
|
@ -44,15 +74,17 @@ var _voice_synced_text := false
|
|||
|
||||
var _autopauses := {}
|
||||
|
||||
var parse_stack: Array[Dictionary] = []
|
||||
|
||||
|
||||
#region STATE
|
||||
####################################################################################################
|
||||
|
||||
func clear_game_state(_clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
|
||||
update_dialog_text('', true)
|
||||
update_dialog_text("", true)
|
||||
update_name_label(null)
|
||||
dialogic.current_state_info['speaker'] = ""
|
||||
dialogic.current_state_info['text'] = ''
|
||||
dialogic.current_state_info["speaker"] = ""
|
||||
dialogic.current_state_info["text"] = ""
|
||||
|
||||
set_text_reveal_skippable(ProjectSettings.get_setting('dialogic/text/initial_text_reveal_skippable', true))
|
||||
|
||||
|
|
@ -65,9 +97,7 @@ func clear_game_state(_clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR) ->
|
|||
func load_game_state(_load_flag:=LoadFlags.FULL_LOAD) -> void:
|
||||
update_textbox(dialogic.current_state_info.get('text', ''), true)
|
||||
update_dialog_text(dialogic.current_state_info.get('text', ''), true)
|
||||
var character: DialogicCharacter = null
|
||||
if dialogic.current_state_info.get('speaker', ""):
|
||||
character = load(dialogic.current_state_info.get('speaker', ""))
|
||||
var character: DialogicCharacter = get_current_speaker()
|
||||
|
||||
if character:
|
||||
update_name_label(character)
|
||||
|
|
@ -85,21 +115,57 @@ func post_install() -> void:
|
|||
#region MAIN METHODS
|
||||
####################################################################################################
|
||||
|
||||
## Applies modifiers, effects and coloring to the text
|
||||
func parse_text(text:String, type:int=TextTypes.DIALOG_TEXT, variables := true, glossary := true, modifiers:= true, effects:= true, color_names:= true) -> String:
|
||||
if modifiers:
|
||||
text = parse_text_modifiers(text, type)
|
||||
if variables and dialogic.has_subsystem('VAR'):
|
||||
text = dialogic.VAR.parse_variables(text)
|
||||
if effects:
|
||||
text = parse_text_effects(text)
|
||||
if color_names:
|
||||
text = color_character_names(text)
|
||||
if glossary and dialogic.has_subsystem('Glossary'):
|
||||
text = dialogic.Glossary.parse_glossary(text)
|
||||
## Applies modifiers, effects and coloring to the text.
|
||||
## Utilizes the parse stack created and sorted in [method load_parse_stack()].
|
||||
func parse_text(text:String, type:int=TextTypes.DIALOG_TEXT) -> String:
|
||||
if parse_stack.is_empty():
|
||||
load_parse_stack()
|
||||
|
||||
for i in parse_stack:
|
||||
if i.type != ParserModes.ALL and type != -1 and i.type != type:
|
||||
continue
|
||||
text = i.method.call(text)
|
||||
|
||||
return text
|
||||
|
||||
|
||||
## Creates and sorts a stack of methods that take a text and return it.
|
||||
## This includes: variables, text modifiers, text effects, autocolor names and the glossary.
|
||||
func load_parse_stack() -> void:
|
||||
parse_stack.clear()
|
||||
|
||||
if dialogic.has_subsystem('VAR'):
|
||||
parse_stack.append(
|
||||
{
|
||||
"method":dialogic.VAR.parse_variables,
|
||||
"type": ParserModes.ALL,
|
||||
"order": 30,
|
||||
})
|
||||
|
||||
parse_stack.append(
|
||||
{
|
||||
"method": parse_text_effects,
|
||||
"type": ParserModes.TEXT_ONLY,
|
||||
"order": 50,
|
||||
})
|
||||
for i in text_modifiers:
|
||||
parse_stack.append(i)
|
||||
parse_stack.append(
|
||||
{
|
||||
"method": color_character_names,
|
||||
"type": ParserModes.TEXT_ONLY,
|
||||
"order": 90,
|
||||
})
|
||||
parse_stack.append(
|
||||
{
|
||||
"method": dialogic.Glossary.parse_glossary,
|
||||
"type": ParserModes.TEXT_ONLY,
|
||||
"order": 95,
|
||||
})
|
||||
|
||||
parse_stack.sort_custom(func(a,b):return a["order"] < b["order"])
|
||||
|
||||
|
||||
## When an event updates the text spoken, this can adjust the state of
|
||||
## the dialog text box.
|
||||
## This method is async.
|
||||
|
|
@ -138,6 +204,13 @@ func update_dialog_text(text: String, instant := false, additional := false) ->
|
|||
text_node.text = text
|
||||
|
||||
else:
|
||||
var current_character := get_current_speaker()
|
||||
|
||||
if current_character:
|
||||
var character_prefix: String = current_character.custom_info.get(DialogicCharacterPrefixSuffixSection.PREFIX_CUSTOM_KEY, DialogicCharacterPrefixSuffixSection.DEFAULT_PREFIX)
|
||||
var character_suffix: String = current_character.custom_info.get(DialogicCharacterPrefixSuffixSection.SUFFIX_CUSTOM_KEY, DialogicCharacterPrefixSuffixSection.DEFAULT_SUFFIX)
|
||||
text = character_prefix + text + character_suffix
|
||||
|
||||
text_node.reveal_text(text, additional)
|
||||
|
||||
if !text_node.finished_revealing_text.is_connected(_on_dialog_text_finished):
|
||||
|
|
@ -158,18 +231,18 @@ func update_dialog_text(text: String, instant := false, additional := false) ->
|
|||
|
||||
|
||||
func _on_dialog_text_finished() -> void:
|
||||
text_finished.emit({'text':dialogic.current_state_info['text'], 'character':dialogic.current_state_info['speaker']})
|
||||
text_finished.emit({"text":dialogic.current_state_info["text"], "character":dialogic.current_state_info["speaker"]})
|
||||
|
||||
|
||||
## Updates the visible name on all name labels nodes.
|
||||
## If a name changes, the [signal speaker_updated] signal is emitted.
|
||||
func update_name_label(character:DialogicCharacter):
|
||||
var character_path := character.resource_path if character else ""
|
||||
var current_character_path: String = dialogic.current_state_info.get("speaker", "")
|
||||
var character_id := character.get_identifier() if character else ""
|
||||
var current_character_id: String = dialogic.current_state_info.get("speaker", "")
|
||||
|
||||
if character_path != current_character_path:
|
||||
dialogic.current_state_info['speaker'] = character_path
|
||||
if character_id != current_character_id:
|
||||
speaker_updated.emit(character)
|
||||
dialogic.current_state_info["speaker"] = character_id
|
||||
|
||||
var name_label_text := get_character_name_parsed(character)
|
||||
|
||||
|
|
@ -182,8 +255,19 @@ func update_name_label(character:DialogicCharacter):
|
|||
name_label.self_modulate = Color(1,1,1,1)
|
||||
|
||||
|
||||
func update_typing_sound_mood_from_character(character:DialogicCharacter, mood:String) -> void:
|
||||
if character.custom_info.get("sound_moods", {}).is_empty():
|
||||
update_typing_sound_mood()
|
||||
elif mood in character.custom_info.get("sound_moods", {}):
|
||||
update_typing_sound_mood(character.custom_info.get("sound_moods", {})[mood])
|
||||
else:
|
||||
var default_mood : String = character.custom_info.get("sound_mood_default", "")
|
||||
update_typing_sound_mood(character.custom_info.get("sound_moods", {}).get(default_mood, {}))
|
||||
|
||||
|
||||
|
||||
func update_typing_sound_mood(mood:Dictionary = {}) -> void:
|
||||
for typing_sound in get_tree().get_nodes_in_group('dialogic_type_sounds'):
|
||||
for typing_sound in get_tree().get_nodes_in_group("dialogic_type_sounds"):
|
||||
typing_sound.load_overwrite(mood)
|
||||
|
||||
|
||||
|
|
@ -335,8 +419,12 @@ func collect_text_effects() -> void:
|
|||
## Use get_parsed_text_effects() after calling this to get all effect information
|
||||
func parse_text_effects(text:String) -> String:
|
||||
parsed_text_effect_info.clear()
|
||||
var rtl := RichTextLabel.new()
|
||||
rtl.bbcode_enabled = true
|
||||
var rtl: RichTextLabel = null
|
||||
if get_tree().get_first_node_in_group("dialogic_dialog_text"):
|
||||
rtl = get_tree().get_first_node_in_group("dialogic_dialog_text").duplicate()
|
||||
else:
|
||||
rtl = RichTextLabel.new()
|
||||
rtl.bbcode_enabled = true
|
||||
var position_correction := 0
|
||||
var bbcode_correction := 0
|
||||
for effect_match in text_effects_regex.search_all(text):
|
||||
|
|
@ -361,7 +449,9 @@ func execute_effects(current_index:int, text_node:Control, skipping := false) ->
|
|||
if current_index != -1 and current_index < parsed_text_effect_info[0]['index']:
|
||||
return
|
||||
var effect: Dictionary = parsed_text_effect_info.pop_front()
|
||||
await (effect['execution_info']['callable'] as Callable).call(text_node, skipping, effect['value'])
|
||||
var callable: Callable = effect['execution_info']['callable']
|
||||
if is_instance_valid(text_node):
|
||||
await callable.call(text_node, skipping, effect['value'])
|
||||
|
||||
|
||||
func collect_text_modifiers() -> void:
|
||||
|
|
@ -372,15 +462,8 @@ func collect_text_modifiers() -> void:
|
|||
text_modifiers.append({'method':Callable(dialogic.get_subsystem(modifier.subsystem), modifier.method)})
|
||||
elif modifier.has('node_path') and modifier.has('method'):
|
||||
text_modifiers.append({'method':Callable(get_node(modifier.node_path), modifier.method)})
|
||||
text_modifiers[-1]['mode'] = modifier.get('mode', TextModifierModes.TEXT_ONLY)
|
||||
|
||||
|
||||
func parse_text_modifiers(text:String, type:int=TextTypes.DIALOG_TEXT) -> String:
|
||||
for mod in text_modifiers:
|
||||
if mod.mode != TextModifierModes.ALL and type != -1 and type != mod.mode:
|
||||
continue
|
||||
text = mod.method.call(text)
|
||||
return text
|
||||
text_modifiers[-1]['type'] = modifier.get('mode', ParserModes.TEXT_ONLY)
|
||||
text_modifiers[-1]['order'] = modifier.get('order', 40)
|
||||
|
||||
|
||||
#endregion
|
||||
|
|
@ -415,19 +498,12 @@ func get_character_name_parsed(character:DialogicCharacter) -> String:
|
|||
## Returns the [class DialogicCharacter] of the current speaker.
|
||||
## If there is no current speaker or the speaker is not found, returns null.
|
||||
func get_current_speaker() -> DialogicCharacter:
|
||||
var speaker_path: String = dialogic.current_state_info.get("speaker", "")
|
||||
var speaker_id: String = dialogic.current_state_info.get("speaker", "")
|
||||
|
||||
if speaker_path.is_empty():
|
||||
if speaker_id.is_empty():
|
||||
return null
|
||||
|
||||
var speaker_resource := load(speaker_path)
|
||||
|
||||
if speaker_resource == null:
|
||||
return null
|
||||
|
||||
var speaker_character := speaker_resource as DialogicCharacter
|
||||
|
||||
return speaker_character
|
||||
return DialogicResourceUtil.get_character_resource(speaker_id)
|
||||
|
||||
|
||||
func _update_user_speed(_user_speed:float) -> void:
|
||||
|
|
@ -475,8 +551,8 @@ func collect_character_names() -> void:
|
|||
|
||||
character_colors = {}
|
||||
|
||||
for dch_path in DialogicResourceUtil.get_character_directory().values():
|
||||
var character := (load(dch_path) as DialogicCharacter)
|
||||
for dch_identifier in DialogicResourceUtil.get_character_directory():
|
||||
var character := (DialogicResourceUtil.get_character_resource(dch_identifier) as DialogicCharacter)
|
||||
|
||||
if character.display_name:
|
||||
if "{" in character.display_name and "}" in character.display_name:
|
||||
|
|
@ -564,19 +640,20 @@ func effect_signal(_text_node:Control, _skipped:bool, argument:String) -> void:
|
|||
|
||||
func effect_mood(_text_node:Control, _skipped:bool, argument:String) -> void:
|
||||
if argument.is_empty(): return
|
||||
if dialogic.current_state_info.get('speaker', ""):
|
||||
if get_current_speaker():
|
||||
update_typing_sound_mood(
|
||||
load(dialogic.current_state_info.speaker).custom_info.get('sound_moods', {}).get(argument, {}))
|
||||
get_current_speaker().custom_info.get('sound_moods', {}).get(argument, {}))
|
||||
|
||||
|
||||
var modifier_words_select_regex := RegEx.create_from_string(r"(?<!\\)\<[^\[\>]+(\/[^\>]*)\>")
|
||||
var modifier_select_regex := RegEx.create_from_string(r"(?<!\\)\<[^\>]+(\/[^\>]*)\>")
|
||||
var modifier_select_split_regex := RegEx.create_from_string(r"(\[[^\]]*\]|[^\/]|\/\/)+")
|
||||
func modifier_random_selection(text:String) -> String:
|
||||
for replace_mod_match in modifier_words_select_regex.search_all(text):
|
||||
for replace_mod_match: RegExMatch in modifier_select_regex.search_all(text):
|
||||
var string: String = replace_mod_match.get_string().trim_prefix("<").trim_suffix(">")
|
||||
string = string.replace('//', '<slash>')
|
||||
var list: PackedStringArray = string.split('/')
|
||||
var item: String = list[randi()%len(list)]
|
||||
item = item.replace('<slash>', '/')
|
||||
var options := []
|
||||
for split: RegExMatch in modifier_select_split_regex.search_all(string):
|
||||
options.append(split.get_string())
|
||||
var item: String = options.pick_random()
|
||||
text = text.replace(replace_mod_match.get_string(), item.strip_edges())
|
||||
return text
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://dtxvpn61hx7ki
|
||||
uid://os6fyykwoljl
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue