Skip to content

Commit a0113d6

Browse files
authored
Merge pull request #35 from nndda/dev
0.8.0
2 parents 590de31 + 15d8ef2 commit a0113d6

14 files changed

+409
-194
lines changed

addons/Theatre/classes/Dialogue.gd

+4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ func _init(dlg_src : String = ""):
5656
_update_used_variables()
5757
_update_used_function_calls()
5858

59+
_sections.make_read_only()
60+
_sets.make_read_only()
61+
_used_function_calls.make_read_only()
62+
5963
## Load written [Dialogue] file from [param path]. Use [method Dialogue.new] instead to create a written [Dialogue] directly in the script.
6064
static func load(path : String) -> Dialogue:
6165
return load(path) as Dialogue

addons/Theatre/classes/DialogueLabel.gd

+42-23
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ extends RichTextLabel
1616
var _characters_draw_tick_scaled : float
1717

1818
#region NOTE: Setup --------------------------------------------------------------------------------
19+
# NOTE: These are cyclic references right?
1920
var _current_stage : Stage:
2021
set = set_stage,
2122
get = get_stage
@@ -30,8 +31,9 @@ func get_stage() -> Stage:
3031
## [b]Note:[/b] [member Stage.dialogue_label] will be set automatically when you assign
3132
## a [DialogueLabel] to the [Stage] on the inspector.
3233
func set_stage(stage : Stage) -> void:
33-
if _current_stage != null:
34-
_current_stage.dialogue_label = null
34+
# NOTE: ????????
35+
#if _current_stage != null:
36+
#_current_stage.dialogue_label = null
3537
if stage != null:
3638
_current_stage = stage
3739
if !_current_stage.skipped.is_connected(_on_stage_skipped):
@@ -93,23 +95,34 @@ var rendering_paused := false:
9395
_current_stage
9496

9597
var _delay_queue : PackedInt64Array = []
98+
var _delay_count : int = 0
9699
var _speed_queue : PackedInt64Array = []
100+
var _speed_count : int = 0
97101
var _func_queue : PackedInt64Array = []
102+
var _func_count : int = 0
98103

99104
var _delay_timer : Timer
100105
var _characters_ticker : Timer
101106

107+
var _current_dialogue_set : Dictionary = {}
108+
102109
## Start the rendering of the current [Dialogue] line text.
103110
func start_render() -> void:
111+
_current_dialogue_set = _current_stage._current_dialogue_set
112+
104113
_delay_timer.one_shot = true
105114

106115
_characters_draw_tick_scaled = characters_draw_tick /\
107116
_current_stage.speed_scale_global / _current_stage.speed_scale
108117
_characters_ticker.start(_characters_draw_tick_scaled)
109118

110-
_delay_queue = _current_stage._current_dialogue_set[DialogueParser.__TAGS][DialogueParser.__TAGS_DELAYS].keys()
111-
_speed_queue = _current_stage._current_dialogue_set[DialogueParser.__TAGS][DialogueParser.__TAGS_SPEEDS].keys()
112-
_func_queue = _current_stage._current_dialogue_set[DialogueParser.__FUNC_POS].keys()
119+
_delay_queue = _current_dialogue_set[DialogueParser.__TAGS][DialogueParser.__TAGS_DELAYS].keys()
120+
_delay_count = -_delay_queue.size()
121+
_speed_queue = _current_dialogue_set[DialogueParser.__TAGS][DialogueParser.__TAGS_SPEEDS].keys()
122+
_speed_count = -_speed_queue.size()
123+
_func_queue = _current_dialogue_set[DialogueParser.__FUNC_POS].keys()
124+
_func_count = -_func_queue.size()
125+
113126
_is_rendering = true
114127

115128
## Stop the process of rendering text, and clear the [DialogueLabel] text.
@@ -120,11 +133,16 @@ func clear_render() -> void:
120133
visible_ratio = 0
121134

122135
_delay_queue.clear()
136+
_delay_count = 0
123137
_speed_queue.clear()
138+
_speed_count = 0
124139
_func_queue.clear()
140+
_func_count = 0
125141

126142
_is_rendering = false
127143

144+
_current_dialogue_set = {}
145+
128146
## Returns [code]true[/code] if the [DialogueLabel] is in the process of rendering text.
129147
func is_rendering() -> bool:
130148
return _is_rendering
@@ -147,31 +165,31 @@ func resume_render() -> void:
147165
_characters_ticker.paused = rendering_paused
148166

149167
func _characters_ticker_timeout() -> void:
150-
if !_func_queue.is_empty():
151-
if _func_queue[0] == visible_characters:
168+
if _func_count < 0:
169+
if _func_queue[_func_count] == visible_characters:
152170
if _current_stage.allow_func:
153-
_current_stage._call_functions(
154-
_current_stage._current_dialogue_set[DialogueParser.__FUNC][
155-
_current_stage._current_dialogue_set[DialogueParser.__FUNC_POS][_func_queue[0]]
171+
_current_stage._call_function(
172+
_current_dialogue_set[DialogueParser.__FUNC][
173+
_current_dialogue_set[DialogueParser.__FUNC_POS][visible_characters]
156174
]
157175
)
158-
_func_queue.remove_at(0)
176+
_func_count += 1
159177

160-
if !_delay_queue.is_empty():
161-
if _delay_queue[0] == visible_characters:
178+
if _delay_count < 0:
179+
if _delay_queue[_delay_count] == visible_characters:
162180
_characters_ticker.stop()
163181
_delay_timer.start(
164-
_current_stage._current_dialogue_set[DialogueParser.__TAGS][DialogueParser.__TAGS_DELAYS][_delay_queue[0]]
182+
_current_dialogue_set[DialogueParser.__TAGS][DialogueParser.__TAGS_DELAYS][visible_characters]
165183
)
166184
return
167185

168-
if !_speed_queue.is_empty():
169-
if _speed_queue[0] == visible_characters:
186+
if _speed_count < 0:
187+
if _speed_queue[_speed_count] == visible_characters:
170188
_characters_ticker.wait_time = _characters_draw_tick_scaled /\
171189
_current_stage.speed_scale_global /\
172-
_current_stage._current_dialogue_set[DialogueParser.__TAGS][DialogueParser.__TAGS_SPEEDS][_speed_queue[0]]
190+
_current_dialogue_set[DialogueParser.__TAGS][DialogueParser.__TAGS_SPEEDS][visible_characters]
173191
_characters_ticker.start()
174-
_speed_queue.remove_at(0)
192+
_speed_count += 1
175193

176194
visible_characters += 1
177195

@@ -187,14 +205,15 @@ func _characters_ticker_timeout() -> void:
187205
character_drawn.emit()
188206

189207
func _delay_timer_timeout() -> void:
190-
_delay_queue.remove_at(0)
208+
_delay_count += 1
191209
_characters_ticker.start()
192210

193211
func _on_stage_skipped() -> void:
194-
for f in _func_queue:
195-
_current_stage._call_functions(
196-
_current_stage._current_dialogue_set[DialogueParser.__FUNC][
197-
_current_stage._current_dialogue_set[DialogueParser.__FUNC_POS][f]
212+
var arr_size : int = _func_queue.size()
213+
for f in _func_queue.slice(arr_size - absi(_func_count), arr_size):
214+
_current_stage._call_function(
215+
_current_dialogue_set[DialogueParser.__FUNC][
216+
_current_dialogue_set[DialogueParser.__FUNC_POS][f]
198217
]
199218
)
200219
text_rendered.emit(text)

addons/Theatre/classes/DialogueParser.gd

+45-34
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ const REGEX_FUNC_CALL :=\
2121
r"(?<caller>\w+)\.(?<name>\w+)\((?<args>.*)\)$";\
2222
static var _regex_func_call := RegEx.create_from_string(REGEX_FUNC_CALL)
2323

24+
const REGEX_FUNC_VARS :=\
25+
r"(?<![\"\'\d])\b([a-zA-Z_]\w*)\s*\.\s*([a-zA-Z_]\w*)\b(?![\"\'\d])";\
26+
static var _regex_func_vars := RegEx.create_from_string(REGEX_FUNC_VARS)
27+
2428
const REGEX_INDENT :=\
2529
r"(?<=\n{1})\s+";\
2630
static var _regex_indent := RegEx.create_from_string(REGEX_INDENT)
@@ -53,6 +57,7 @@ const __CALLER := "caller"
5357
const __NAME := "name"
5458
const __ARGS := "args"
5559
const __LN_NUM := "ln_num"
60+
const __STANDALONE := "standalone"
5661
#endregion
5762

5863
const SETS_TEMPLATE := {
@@ -105,10 +110,13 @@ const FUNC_TEMPLATE := {
105110
__NAME: EMPTY,
106111

107112
# Arguments used.
108-
__ARGS: [],
113+
__ARGS: null,
109114

110115
# Line number of where the function is written.
111116
__LN_NUM: 0,
117+
118+
__STANDALONE: true,
119+
__VARS: [],
112120
}
113121

114122
const TAG_DELAY_ALIASES : PackedStringArray = [
@@ -142,6 +150,7 @@ static func _initialize_regex() -> void:
142150
_regex_dlg_tags_newline = RegEx.create_from_string(REGEX_DLG_TAGS_NEWLINE)
143151
_regex_bbcode_tags = RegEx.create_from_string(REGEX_BBCODE_TAGS)
144152
_regex_func_call = RegEx.create_from_string(REGEX_FUNC_CALL)
153+
_regex_func_vars = RegEx.create_from_string(REGEX_FUNC_VARS)
145154
_regex_indent = RegEx.create_from_string(REGEX_INDENT)
146155
_regex_valid_dlg = RegEx.create_from_string(REGEX_VALID_DLG)
147156
_regex_section = RegEx.create_from_string(REGEX_SECTION)
@@ -179,7 +188,7 @@ func _init(src : String = ""):
179188
if dlg_raw_size < i + 1:
180189
printerr("Error: actor's name exists without a dialogue body")
181190

182-
setsl[__ACTOR] = n_stripped.trim_suffix(COLON)
191+
setsl[__ACTOR] = StringName(n_stripped.trim_suffix(COLON))
183192
setsl[__LINE_NUM] = ln_num
184193

185194
if setsl[__ACTOR] == UNDERSCORE:
@@ -213,12 +222,12 @@ func _init(src : String = ""):
213222
if regex_func_match != null:
214223
var func_dict := FUNC_TEMPLATE.duplicate(true)
215224

216-
func_dict[__CALLER] = regex_func_match.get_string(
225+
func_dict[__CALLER] = StringName(regex_func_match.get_string(
217226
regex_func_match.names[__CALLER]
218-
)
219-
func_dict[__NAME] = regex_func_match.get_string(
227+
))
228+
func_dict[__NAME] = StringName(regex_func_match.get_string(
220229
regex_func_match.names[__NAME]
221-
)
230+
))
222231

223232
# Function arguments
224233
var args_raw := regex_func_match.get_string(
@@ -229,14 +238,20 @@ func _init(src : String = ""):
229238

230239
# Parse parameter arguments
231240
var args := Expression.new()
232-
var args_err := args.parse("[%s]" % args_raw)
233-
if args_err != OK:
234-
printerr("Error: '%s' when parsing arguments on function %s.%s(%s) on line %d" % [
235-
error_string(args_err),
236-
func_dict[__CALLER], func_dict[__NAME], args_raw, ln_num
237-
])
238-
239-
func_dict[__ARGS] = args.execute() as Array
241+
var args_err := args.parse("[" + args_raw + "]")
242+
var var_matches := _regex_func_vars.search_all(args_raw)
243+
244+
if var_matches.is_empty():
245+
func_dict[__ARGS] = args.execute() as Array
246+
247+
else:
248+
func_dict[__STANDALONE] = false
249+
func_dict[__ARGS] = "[" + args_raw + "]"
250+
251+
for var_match in var_matches:
252+
func_dict[__VARS].append(var_match.get_string(1))
253+
254+
func_dict.make_read_only()
240255
output[body_pos][__FUNC].append(func_dict)
241256
#endregion
242257

@@ -289,6 +304,7 @@ func _init(src : String = ""):
289304
output[n][__FUNC_POS] = parsed_tags[__FUNC_POS]
290305
output[n][__FUNC_IDX] = parsed_tags[__FUNC_IDX]
291306

307+
output[n][__FUNC].make_read_only()
292308
output[n][__CONTENT] = body
293309

294310
## Check if [param string] is indented with tabs or spaces.
@@ -362,23 +378,19 @@ static func parse_tags(string : String) -> Dictionary:
362378
else:
363379
string = string.replace(bb.strings[0], EMPTY)
364380

365-
# TODO
366381
# Escaped Curly Brackets ===============================================
367382
# 💀💀💀💀💀💀💀💀💀💀💀
368-
#var regex_curly_brackets := RegEx.new()
369-
#regex_curly_brackets.compile(r"\\\{|\\\}")
370-
#
371-
#var esc_curly_brackets : Array[Dictionary] = []
372-
#
373-
#for cb in regex_curly_brackets.search_all(string):
374-
#esc_curly_brackets.append({
375-
#"pos": cb.get_start(),
376-
#"chr": cb.strings[0],
377-
#})
378-
#
379-
#if !esc_curly_brackets.is_empty():
380-
#esc_curly_brackets.reverse()
381-
#string = regex_curly_brackets.sub(string, "-", true)
383+
var regex_curly_brackets := RegEx.create_from_string(r"\\(\{|\})")
384+
385+
var esc_curly_brackets : Dictionary = {}
386+
387+
for cb in regex_curly_brackets.search_all(
388+
_regex_dlg_tags.sub(string, EMPTY, true)
389+
):
390+
esc_curly_brackets[cb.get_start()] = cb.strings[0]
391+
392+
if !esc_curly_brackets.is_empty():
393+
string = regex_curly_brackets.sub(string, HASH, true)
382394

383395
# Dialogue tags ========================================================
384396
var tag_pos_offset : int = 0
@@ -415,12 +427,11 @@ static func parse_tags(string : String) -> Dictionary:
415427

416428
tag_pos_offset += string_match.length()
417429

418-
# TODO
419430
# Insert back escaped curly brackets ===================================
420-
#for cb in esc_curly_brackets:
421-
#string = string\
422-
#.erase(cb["pos"])\
423-
#.insert(cb["pos"], cb["chr"])
431+
for cb in esc_curly_brackets.keys():
432+
string = string\
433+
.erase(cb)\
434+
.insert(cb, esc_curly_brackets[cb])
424435

425436
# Insert back BBCodes ==================================================
426437
string = string\

0 commit comments

Comments
 (0)