## Any data associated with inline dialogue BBCodes. class_name DMResolvedLineData extends RefCounted ## The line's text var text: String = "" ## A map of pauses against where they are found in the text. var pauses: Dictionary = {} ## A map of speed changes against where they are found in the text. var speeds: Dictionary = {} ## A list of any mutations to run and where they are found in the text. var mutations: Array[Array] = [] ## A duration reference for the line. Represented as "auto" or a stringified number. var time: String = "" func _init(line: String) -> void: text = line pauses = {} speeds = {} mutations = [] time = "" var bbcodes: Array = [] # Remove any escaped brackets (ie. "\[") var escaped_open_brackets: PackedInt32Array = [] var escaped_close_brackets: PackedInt32Array = [] for i in range(0, text.length() - 1): if text.substr(i, 2) == "\\[": text = text.substr(0, i) + "!" + text.substr(i + 2) escaped_open_brackets.append(i) elif text.substr(i, 2) == "\\]": text = text.substr(0, i) + "!" + text.substr(i + 2) escaped_close_brackets.append(i) # Extract all of the BB codes so that we know the actual text (we could do this easier with # a RichTextLabel but then we'd need to await idle_frame which is annoying) var bbcode_positions = find_bbcode_positions_in_string(text) var accumulaive_length_offset = 0 for position in bbcode_positions: # Ignore our own markers if position.code in ["wait", "speed", "/speed", "do", "do!", "set", "next", "if", "else", "/if"]: continue bbcodes.append({ bbcode = position.bbcode, start = position.start, offset_start = position.start - accumulaive_length_offset }) accumulaive_length_offset += position.bbcode.length() for bb in bbcodes: text = text.substr(0, bb.offset_start) + text.substr(bb.offset_start + bb.bbcode.length()) # Now find any dialogue markers var next_bbcode_position = find_bbcode_positions_in_string(text, false) var limit = 0 while next_bbcode_position.size() > 0 and limit < 1000: limit += 1 var bbcode = next_bbcode_position[0] var index = bbcode.start var code = bbcode.code var raw_args = bbcode.raw_args var args = {} if code in ["do", "do!", "set"]: var compilation: DMCompilation = DMCompilation.new() args["value"] = compilation.extract_mutation("%s %s" % [code, raw_args]) else: # Could be something like: # "=1.0" # " rate=20 level=10" if raw_args and raw_args[0] == "=": raw_args = "value" + raw_args for pair in raw_args.strip_edges().split(" "): if "=" in pair: var bits = pair.split("=") args[bits[0]] = bits[1] match code: "wait": if pauses.has(index): pauses[index] += args.get("value").to_float() else: pauses[index] = args.get("value").to_float() "speed": speeds[index] = args.get("value").to_float() "/speed": speeds[index] = 1.0 "do", "do!", "set": mutations.append([index, args.get("value")]) "next": time = args.get("value") if args.has("value") else "0" # Find any BB codes that are after this index and remove the length from their start var length = bbcode.bbcode.length() for bb in bbcodes: if bb.offset_start > bbcode.start: bb.offset_start -= length bb.start -= length # Find any escaped brackets after this that need moving for i in range(0, escaped_open_brackets.size()): if escaped_open_brackets[i] > bbcode.start: escaped_open_brackets[i] -= length for i in range(0, escaped_close_brackets.size()): if escaped_close_brackets[i] > bbcode.start: escaped_close_brackets[i] -= length text = text.substr(0, index) + text.substr(index + length) next_bbcode_position = find_bbcode_positions_in_string(text, false) # Put the BB Codes back in for bb in bbcodes: text = text.insert(bb.start, bb.bbcode) # Put the escaped brackets back in for index in escaped_open_brackets: text = text.left(index) + "[" + text.right(text.length() - index - 1) for index in escaped_close_brackets: text = text.left(index) + "]" + text.right(text.length() - index - 1) func find_bbcode_positions_in_string(string: String, find_all: bool = true, include_conditions: bool = false) -> Array[Dictionary]: if not "[" in string: return [] var positions: Array[Dictionary] = [] var open_brace_count: int = 0 var start: int = 0 var bbcode: String = "" var code: String = "" var is_finished_code: bool = false for i in range(0, string.length()): if string[i] == "[": if open_brace_count == 0: start = i bbcode = "" code = "" is_finished_code = false open_brace_count += 1 else: if not is_finished_code and (string[i].to_upper() != string[i] or string[i] == "/" or string[i] == "!"): code += string[i] else: is_finished_code = true if open_brace_count > 0: bbcode += string[i] if string[i] == "]": open_brace_count -= 1 if open_brace_count == 0 and (include_conditions or not code in ["if", "else", "/if"]): positions.append({ bbcode = bbcode, code = code, start = start, end = i, raw_args = bbcode.substr(code.length() + 1, bbcode.length() - code.length() - 2).strip_edges() }) if not find_all: return positions return positions