You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
4.7 KiB
175 lines
4.7 KiB
6 months ago
|
extends DialogicSubsystem
|
||
|
|
||
|
## Subsystem that handles glossaries.
|
||
|
|
||
|
## List of glossary resources that are used.
|
||
|
var glossaries := []
|
||
|
## If false, no parsing will be done.
|
||
|
var enabled := true
|
||
|
|
||
|
## Any key in this dictionary will overwrite the color for any item with that name.
|
||
|
var color_overrides := {}
|
||
|
|
||
|
const SETTING_DEFAULT_COLOR := 'dialogic/glossary/default_color'
|
||
|
|
||
|
|
||
|
#region STATE
|
||
|
####################################################################################################
|
||
|
|
||
|
func clear_game_state(_clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
|
||
|
glossaries = []
|
||
|
|
||
|
for path: String in ProjectSettings.get_setting('dialogic/glossary/glossary_files', []):
|
||
|
add_glossary(path)
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
|
||
|
#region MAIN METHODS
|
||
|
####################################################################################################
|
||
|
|
||
|
func parse_glossary(text: String) -> String:
|
||
|
if not enabled:
|
||
|
return text
|
||
|
|
||
|
var def_case_sensitive: bool = ProjectSettings.get_setting('dialogic/glossary/default_case_sensitive', true)
|
||
|
var def_color: Color = ProjectSettings.get_setting(SETTING_DEFAULT_COLOR, Color.POWDER_BLUE)
|
||
|
var regex := RegEx.new()
|
||
|
|
||
|
for glossary: DialogicGlossary in glossaries:
|
||
|
|
||
|
if !glossary.enabled:
|
||
|
continue
|
||
|
|
||
|
for entry_value: Variant in glossary.entries.values():
|
||
|
|
||
|
if not entry_value is Dictionary:
|
||
|
continue
|
||
|
|
||
|
var entry: Dictionary = entry_value
|
||
|
var entry_key: String = entry.get(DialogicGlossary.NAME_PROPERTY, "")
|
||
|
|
||
|
# Older versions of the glossary resource do not have a property
|
||
|
# for their name, we must skip these.
|
||
|
# They can be updated by opening the resource in the glossary
|
||
|
# editor.
|
||
|
if entry_key.is_empty():
|
||
|
continue
|
||
|
|
||
|
if not entry.get('enabled', true):
|
||
|
continue
|
||
|
|
||
|
var regex_options := glossary.get_set_regex_option(entry_key)
|
||
|
|
||
|
if regex_options.is_empty():
|
||
|
continue
|
||
|
|
||
|
var pattern: String = '(?<=\\W|^)(?<!\\\\)(?<word>' + regex_options + ')(?!])(?=\\W|$)'
|
||
|
|
||
|
if entry.get('case_sensitive', def_case_sensitive):
|
||
|
regex.compile(pattern)
|
||
|
|
||
|
else:
|
||
|
regex.compile('(?i)'+pattern)
|
||
|
|
||
|
var color: String = entry.get('color', def_color).to_html()
|
||
|
|
||
|
if entry_key in color_overrides:
|
||
|
color = color_overrides[entry_key].to_html()
|
||
|
|
||
|
text = regex.sub(text,
|
||
|
'[url=' + entry_key + ']' +
|
||
|
'[color=' + color + ']${word}[/color]' +
|
||
|
'[/url]',
|
||
|
true
|
||
|
)
|
||
|
|
||
|
return text
|
||
|
|
||
|
|
||
|
func add_glossary(path:String) -> void:
|
||
|
if ResourceLoader.exists(path):
|
||
|
var resource: DialogicGlossary = load(path)
|
||
|
|
||
|
if resource is DialogicGlossary:
|
||
|
glossaries.append(resource)
|
||
|
else:
|
||
|
printerr('[Dialogic] The glossary file "' + path + '" is missing. Make sure it exists.')
|
||
|
|
||
|
|
||
|
## Iterates over all glossaries and returns the first one that matches the
|
||
|
## [param entry_key].
|
||
|
##
|
||
|
## Runtime complexity:
|
||
|
## O(n), where n is the number of glossaries.
|
||
|
func find_glossary(entry_key: String) -> DialogicGlossary:
|
||
|
for glossary: DialogicGlossary in glossaries:
|
||
|
|
||
|
if glossary.entries.has(entry_key):
|
||
|
return glossary
|
||
|
|
||
|
return null
|
||
|
|
||
|
|
||
|
## Returns the first match for a given entry key.
|
||
|
## If translation is available and enabled, it will be translated
|
||
|
func get_entry(entry_key: String) -> Dictionary:
|
||
|
var glossary: DialogicGlossary = dialogic.Glossary.find_glossary(entry_key)
|
||
|
|
||
|
var result := {
|
||
|
"title": "",
|
||
|
"text": "",
|
||
|
"extra": "",
|
||
|
"color": Color.WHITE,
|
||
|
}
|
||
|
|
||
|
if glossary == null:
|
||
|
return {}
|
||
|
|
||
|
var is_translation_enabled: bool = ProjectSettings.get_setting('dialogic/translation/enabled', false)
|
||
|
|
||
|
var entry := glossary.get_entry(entry_key)
|
||
|
|
||
|
if entry.is_empty():
|
||
|
return {}
|
||
|
|
||
|
result.color = entry.get("color")
|
||
|
if result.color == null:
|
||
|
result.color = ProjectSettings.get_setting(SETTING_DEFAULT_COLOR, Color.POWDER_BLUE)
|
||
|
|
||
|
if is_translation_enabled and not glossary._translation_id.is_empty():
|
||
|
var translation_key: String = glossary._translation_keys.get(entry_key)
|
||
|
var last_slash := translation_key.rfind('/')
|
||
|
|
||
|
if last_slash == -1:
|
||
|
return {}
|
||
|
|
||
|
var tr_base := translation_key.substr(0, last_slash)
|
||
|
|
||
|
result.title = translate(tr_base, "title", entry)
|
||
|
result.text = translate(tr_base, "text", entry)
|
||
|
result.extra = translate(tr_base, "extra", entry)
|
||
|
else:
|
||
|
result.title = entry.get("title", "")
|
||
|
result.text = entry.get("text", "")
|
||
|
result.extra = entry.get("extra", "")
|
||
|
|
||
|
## PARSE TEXTS FOR VARIABLES
|
||
|
result.title = dialogic.VAR.parse_variables(result.title)
|
||
|
result.text = dialogic.VAR.parse_variables(result.text)
|
||
|
result.extra = dialogic.VAR.parse_variables(result.extra)
|
||
|
|
||
|
return result
|
||
|
|
||
|
|
||
|
|
||
|
## Tries to translate the property with the given
|
||
|
func translate(tr_base: String, property: StringName, fallback_entry: Dictionary) -> String:
|
||
|
var tr_key := tr_base.path_join(property)
|
||
|
var tr_value := tr(tr_key)
|
||
|
|
||
|
if tr_key == tr_value:
|
||
|
tr_value = fallback_entry.get(property, "")
|
||
|
|
||
|
return tr_value
|