the-lost-memory/project/addons/dialogic/Parser/DialogicParser.gd

237 lines
8.9 KiB
GDScript3
Raw Normal View History

2022-11-17 17:52:05 +00:00
extends Node
class_name DialogicParser
# adds name coloring to the dialog texts
static func parse_characters(dialog_script):
var characters = DialogicUtil.get_character_list()
var event_index := 0
for event in dialog_script['events']:
# if this is a text or question event
if event.get('event_id') in ['dialogic_001', 'dialogic_010']:
var text :String = event.get({'dialogic_001':'text', 'dialogic_010':'question'}[event.get('event_id')], '')
for character in characters:
# check whether to use the name or the display name
var char_names = [character.get('name')]
if character.get('data', {}).get('display_name_bool', false):
if character.get('display_name'): char_names.append(character.get('display_name'))
if character.get('data', {}).get('nickname_bool', false):
for nickname in character.get('data').get('nickname', '').split(',', true, 0):
if nickname.strip_edges():
char_names.append(nickname.strip_edges())
#Regex purposefully excludes [] as replacing those interferes with the second regex
var escapeRegExp = "(?=[+&|!(){}^\"~*.?:\\\\-])"
var regex = RegEx.new()
regex.compile(escapeRegExp)
char_names = regex.sub(str(char_names), "\\", true)
var regex_thing = "((\\]|^)[^\\[]*)(?<name>"+str(char_names).replace("[", "(").replace("]", ")").replace(", ", "|")+")"
regex.compile(regex_thing)
var counter = 0
for result in regex.search_all(text):
text = text.insert(result.get_start("name")+((9+8+8)*counter), '[color=#' + character['color'].to_html() + ']')
text = text.insert(result.get_end("name")+9+8+((9+8+8)*counter), '[/color]')
result = regex.search(text)
counter += 1
dialog_script['events'][event_index][{'dialogic_001':'text', 'dialogic_010':'question'}[event.get('event_id')]] = text
event_index += 1
return dialog_script
# removes empty lines, splits message at new lines
static func parse_text_lines(unparsed_dialog_script: Dictionary, preview:bool = false) -> Dictionary:
var parsed_dialog: Dictionary = unparsed_dialog_script
var new_events: Array = []
var settings = DialogicResources.get_settings_config()
var split_new_lines = settings.get_value('dialog', 'new_lines', true)
var remove_empty_messages = settings.get_value('dialog', 'remove_empty_messages', true)
# Return the same thing if it doesn't have events
if unparsed_dialog_script.has('events') == false:
return unparsed_dialog_script
# Parsing
for event in unparsed_dialog_script['events']:
if event.has('text') and event.has('character') and event.has('portrait'):
if event['text'].empty() and remove_empty_messages:
pass
elif '\n' in event['text'] and preview == false and split_new_lines:
var lines = event['text'].split('\n')
var counter = 0
for line in lines:
if not line.empty():
var n_event = {
'event_id':'dialogic_001',
'text': line,
'character': event['character'],
'portrait': event['portrait'],
}
#assigning voices to the new events
if event.has('voice_data'):
if event['voice_data'].has(str(counter)):
n_event['voice_data'] = {'0':event['voice_data'][str(counter)]}
new_events.append(n_event)
counter += 1
else:
new_events.append(event)
else:
new_events.append(event)
parsed_dialog['events'] = new_events
return parsed_dialog
# returns the text but with BBcode for glossary and the values of the variables
static func parse_definitions(current_dialog, text: String, variables: bool = true, glossary: bool = true):
var final_text: String = text
if not current_dialog.preview:
current_dialog.definitions = Dialogic._get_definitions()
if variables:
final_text = _insert_variable_definitions(current_dialog, text)
if glossary and current_dialog._should_show_glossary():
final_text = _insert_glossary_definitions(current_dialog, final_text)
return final_text
# creates a list of questions to be used at the end of choices
static func parse_branches(current_dialog, dialog_script: Dictionary) -> Dictionary:
current_dialog.questions = [] # Resetting the questions
# Return the same thing if it doesn't have events
if dialog_script.has('events') == false:
return dialog_script
var parser_queue = [] # This saves the last question opened, and it gets removed once it was consumed by a endbranch event
var event_idx: int = 0 # The current id for jumping later on
var question_idx: int = 0 # identifying the questions to assign options to it
for event in dialog_script['events']:
if event['event_id'] == 'dialogic_011':
var opened_branch = parser_queue.back()
var option = {
'question_idx': opened_branch['question_idx'],
'label': parse_definitions(current_dialog, event['choice'], true, false),
'event_idx': event_idx,
}
if event.has('condition') and event.has('definition') and event.has('value'):
option = {
'question_idx': opened_branch['question_idx'],
'label': parse_definitions(current_dialog, event['choice'], true, false),
'event_idx': event_idx,
'condition': event['condition'],
'definition': event['definition'],
'value': event['value'],
}
else:
option = {
'question_idx': opened_branch['question_idx'],
'label': parse_definitions(current_dialog, event['choice'], true, false),
'event_idx': event_idx,
'condition': '',
'definition': '',
'value': '',
}
dialog_script['events'][opened_branch['event_idx']]['options'].append(option)
event['question_idx'] = opened_branch['question_idx']
elif event['event_id'] == 'dialogic_010':
event['event_idx'] = event_idx
event['question_idx'] = question_idx
event['answered'] = false
question_idx += 1
current_dialog.questions.append(event)
parser_queue.append(event)
elif event['event_id'] == 'dialogic_012':
event['event_idx'] = event_idx
event['question_idx'] = question_idx
event['answered'] = false
question_idx += 1
current_dialog.questions.append(event)
parser_queue.append(event)
elif event['event_id'] == 'dialogic_013' and parser_queue:
event['event_idx'] = event_idx
var opened_branch = parser_queue.pop_back()
event['end_branch_of'] = opened_branch['question_idx']
dialog_script['events'][opened_branch['event_idx']]['end_idx'] = event_idx
event_idx += 1
return dialog_script
static func parse_anchors(current_dialog):
current_dialog.anchors = {}
var idx = 0
for event in current_dialog.dialog_script['events']:
if event['event_id'] == 'dialogic_015':
current_dialog.anchors[event['id']] = idx
idx += 1
# adds the alignment BBCode to text events
static func parse_alignment(current_dialog, text):
var alignment = current_dialog.current_theme.get_value('text', 'alignment', 0)
var fname = current_dialog.current_theme.get_value('settings', 'name', 'none')
if alignment in [1,4,7]:
text = '[center]' + text + '[/center]'
elif alignment in [2,5,8]:
text = '[right]' + text + '[/right]'
return text
# adds the values of the variables
static func _insert_variable_definitions(current_dialog, text: String):
var final_text := text;
# Regex for searching text inside brackets []
var regex = RegEx.new()
regex.compile('\\[(.*?)\\]')
var result = regex.search_all(final_text)
if result:
for res in result:
var r_string = res.get_string()
# Choosing a random word if there is a list like [word1,word2,word3,word4]
if ',' in r_string:
var r_string_array = r_string.replace('[', '').replace(']', '').split(',')
var new_word = r_string_array[randi() % r_string_array.size()]
# Check if the random selected word is a variable that exists and get the value
for d in current_dialog.definitions['variables']:
var name : String = d['name']
if new_word == d['name']:
new_word = str(d['value'])
# Replace the old string with the new word
final_text = final_text.replace(r_string, new_word)
else:
# Replace the name of a value [whatever] with the result
var r_string_array = r_string.replace('[', '').replace(']', '')
# Find the ID if it's got an absolute path
if '/' in r_string_array:
var variable_id=Dialogic._get_variable_from_file_name(r_string_array)
for d in current_dialog.definitions['variables']:
if d['id'] == variable_id:
final_text = final_text.replace(r_string, d['value'])
else:
for d in current_dialog.definitions['variables']:
if d['name'] == r_string_array:
final_text = final_text.replace(r_string, d['value'])
return final_text
# adds the BBCode for the glossary words
static func _insert_glossary_definitions(current_dialog, text: String):
var color = current_dialog.current_theme.get_value('definitions', 'color', '#ffbebebe')
var final_text := text
# I should use regex here, but this is way easier :)
for d in current_dialog.definitions['glossary']:
final_text = final_text.replace(d['name'],
'[url=' + d['id'] + ']' +
'[color=' + color + ']' + d['name'] + '[/color]' +
'[/url]'
)
return final_text