Skip to content

Commit e9bec2f

Browse files
authored
Merge pull request #17 from nndda/dev
v0.3.6-alpha
2 parents 459e8f5 + 66aeabd commit e9bec2f

12 files changed

+137
-175
lines changed

addons/Theatre/classes/Dialogue.gd

+16-12
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class Parser extends RefCounted:
1414
var output : Array[Dictionary]
1515

1616
const REGEX_DLG_TAGS :=\
17-
r"\{\s*(\w+)\s*=\s*(.+?)\s*\}"
17+
r"\{\s*(?<tag>\w+)\s*(\=\s*(?<arg>.+?)\s*)*\}"
1818
const REGEX_FUNC_CALL :=\
1919
r"(?<caller>\w+)\.(?<name>\w+)\((?<args>.*)\)$"
2020
const REGEX_PLACEHOLDER :=\
@@ -73,10 +73,12 @@ class Parser extends RefCounted:
7373
if dlg_raw.size() < i + 1:
7474
assert(false, "Error: Dialogue name exists without a body")
7575

76-
setsl["actor"] = n.trim_suffix(":")
76+
setsl["actor"] = n.strip_edges().trim_suffix(":")
7777

7878
if setsl["actor"] == "_":
7979
setsl["actor"] = ""
80+
elif setsl["actor"] == "":
81+
setsl["actor"] = output[output.size() - 1]["actor"]
8082

8183
output.append(setsl)
8284
body_pos = output.size() - 1
@@ -85,7 +87,7 @@ class Parser extends RefCounted:
8587
# Function calls
8688
var regex_func := RegEx.new()
8789
regex_func.compile(REGEX_FUNC_CALL)
88-
var regex_func_match := regex_func.search(dlg_raw[i].dedent())
90+
var regex_func_match := regex_func.search(dlg_raw[i].strip_edges())
8991

9092
if regex_func_match != null:
9193
var func_dict := FUNC_TEMPLATE.duplicate(true)
@@ -110,7 +112,7 @@ class Parser extends RefCounted:
110112

111113
# Dialogue text body
112114
else:
113-
var dlg_body := dlg_raw[i].dedent() + " "
115+
var dlg_body := dlg_raw[i].strip_edges() + " "
114116

115117
output[body_pos]["line_raw"] += dlg_body
116118
output[body_pos]["line"] += dlg_body
@@ -126,7 +128,7 @@ class Parser extends RefCounted:
126128

127129
## Check if [param string] is indented with tabs or spaces.
128130
func is_indented(string : String) -> bool:
129-
return string.begins_with(" ") or string.begins_with("\t")
131+
return string != string.lstrip(" \t")
130132

131133
## Check if [param string] is written in a valid Dialogue string format/syntax or not.
132134
static func is_valid_source(string : String) -> bool:
@@ -167,15 +169,17 @@ class Parser extends RefCounted:
167169
string = string.replace(b.strings[0], "")
168170

169171
var tag_pos : int = b.get_start() - tag_pos_offset
170-
var tag_key := b.strings[1].to_upper()
171-
var tag_value := b.strings[2]
172+
var tag_key := b.get_string("tag").to_upper()
173+
var tag_value := b.get_string("arg")
172174

173175
tag_pos_offset += b.strings[0].length()
174176

175177
if ["DELAY", "WAIT", "D", "W"].has(tag_key):
176178
tags["delays"][tag_pos] = float(tag_value)
177179
elif ["SPEED", "SPD", "S"].has(tag_key):
178-
tags["speeds"][tag_pos] = float(tag_value)
180+
tags["speeds"][tag_pos] = float(
181+
1.0 if tag_value.is_empty() else tag_value
182+
)
179183
else:
180184
push_warning("Unknown tags: ", b.strings[0])
181185

@@ -239,10 +243,10 @@ static func load(dlg_src : String) -> Dialogue:
239243
# Find filename alias
240244
var dlg_compiled := dlg_src.trim_suffix(".txt")
241245

242-
if FileAccess.file_exists(dlg_compiled + ".dlg.res"):
243-
dlg_compiled += ".dlg.res"
244-
elif FileAccess.file_exists(dlg_compiled + ".dlg.tres"):
245-
dlg_compiled += ".dlg.tres"
246+
if FileAccess.file_exists(dlg_compiled + ".res"):
247+
dlg_compiled += ".res"
248+
elif FileAccess.file_exists(dlg_compiled + ".tres"):
249+
dlg_compiled += ".tres"
246250

247251
print("Getting Dialogue from file: ", dlg_compiled)
248252

addons/Theatre/classes/DialogueLabel.gd

+13-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ class_name DialogueLabel
22
extends RichTextLabel
33

44
var current_stage : Stage
5-
var offset_queue : PackedInt32Array = []
65
var delay_queue : PackedInt32Array = []
76
var speed_queue : PackedInt32Array = []
87

@@ -35,12 +34,19 @@ func start_render() -> void:
3534

3635
speed_queue = current_stage.current_dialogue_set["tags"]["speeds"].keys()
3736
delay_queue = current_stage.current_dialogue_set["tags"]["delays"].keys()
38-
offset_queue = current_stage.current_dialogue_set["offsets"].keys()
3937

40-
func rerender() -> void:
41-
visible_characters = 0
38+
func clear_render() -> void:
39+
delay_queue.clear()
40+
speed_queue.clear()
41+
4242
delay_timer.stop()
4343
characters_ticker.stop()
44+
45+
visible_ratio = 0
46+
visible_characters = -1
47+
48+
func rerender() -> void:
49+
clear_render()
4450
start_render()
4551

4652
func characters_ticker_timeout() -> void:
@@ -70,3 +76,6 @@ func characters_ticker_timeout() -> void:
7076
characters_ticker.stop()
7177
text_rendered.emit(text)
7278
characters_ticker.wait_time = characters_draw_tick_scaled
79+
80+
if current_stage.step == -1:
81+
clear_render()

addons/Theatre/classes/Stage.gd

+45-32
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ extends Object
33

44
var allow_skip := true
55

6+
var allow_cancel := true
7+
68
var allow_func := true
79

810
var auto := false
@@ -44,7 +46,7 @@ var actor_label : Label
4446

4547
var caller : Dictionary = {}
4648

47-
## [RichTextLabel] node that displays the dialogue body [member Dialogue.set_current.dlg]. This element is [b]required[/b] for the dialogue to run.
49+
## [DialogueLabel] node that displays the dialogue body [member Dialogue.set_current.dlg]. This is [b]required[/b] for the dialogue to run
4850
var dialogue_label : DialogueLabel
4951

5052
## Current progress of the Dialogue.
@@ -95,6 +97,7 @@ func _init(parameters : Dictionary):
9597

9698
var constructor_property : PackedStringArray = [
9799
"allow_skip",
100+
"allow_cancel",
98101
"allow_func",
99102
"auto",
100103
"auto_delay",
@@ -108,8 +111,6 @@ func _init(parameters : Dictionary):
108111
else:
109112
push_error("Error constructing Stage, `%s` does not exists" % property)
110113

111-
Theatre.locale_changed.connect(switch_lang)
112-
113114
## Emitted when [Dialogue] started ([member step] == 0)
114115
signal started
115116
## Emitted when [Dialogue] finished ([member step] == [member step.size()])
@@ -127,19 +128,23 @@ func get_current_set() -> Dictionary:
127128
func is_playing() -> bool:
128129
return step >= 0
129130

130-
## Progress the [Dialogue] by 1 step. If [member progress_tween] is still running, [member progress_tween.stop()] and [member progress_tween_reset] will be called, and the [Dialogue] will not progressed.
131+
## Progress the [Dialogue] by 1 step.
131132
func progress() -> void:
132-
if current_dialogue != null:
133+
if current_dialogue == null:
134+
push_warning("No Dialogue present")
135+
else:
133136
# Skip dialogue
134137
if dialogue_label.visible_ratio < 1.0:
135138
if allow_skip:
136-
dialogue_label.visible_characters = current_dialogue_set["line"].length()
139+
dialogue_label.clear_render()
140+
dialogue_label.visible_ratio = 1.0
137141

138142
# Progress dialogue
139143
else:
140144
if step + 1 < current_dialogue_length:
145+
dialogue_label.clear_render()
146+
141147
step += 1
142-
dialogue_label.visible_characters = 0
143148
current_dialogue_set = current_dialogue.sets[step]
144149
body_text_length = current_dialogue_set["line"].length()
145150

@@ -167,8 +172,7 @@ func progress() -> void:
167172
else:
168173
caller[f["caller"]].callv(f["name"], f["args"])
169174

170-
if dialogue_label != null:
171-
dialogue_label.start_render()
175+
dialogue_label.start_render()
172176

173177
progressed.emit(step, current_dialogue_set)
174178

@@ -177,36 +181,46 @@ func progress() -> void:
177181
finished.emit()
178182

179183
## Stop Dialogue and resets everything
180-
func reset(keep_dialogue : bool = false) -> void:
181-
print("Resetting Dialogue [%s]..." % current_dialogue.source_path)
182-
resetted.emit(step,
183-
current_dialogue.sets[step] if step != -1 else\
184-
Dialogue.Parser.SETS_TEMPLATE
185-
)
184+
func reset() -> void:
185+
if !allow_cancel:
186+
print("Resetting Dialogue is not allowed")
187+
else:
188+
if current_dialogue != null:
189+
print("Resetting Dialogue [%s]..." % current_dialogue.source_path)
190+
resetted.emit(step,
191+
current_dialogue.sets[step] if step != -1 else\
192+
Dialogue.Parser.SETS_TEMPLATE
193+
)
186194

187-
if !keep_dialogue:
188-
current_dialogue = null
189-
step = -1
195+
step = -1
190196

191-
if actor_label != null:
192-
actor_label.text = ""
193-
dialogue_label.text = ""
197+
if actor_label != null:
198+
actor_label.text = ""
199+
200+
dialogue_label.clear_render()
201+
dialogue_label.text = ""
202+
203+
current_dialogue = null
194204

195205
## Start the [Dialogue] at step 0 or at defined preprogress parameter.
196206
## If no parameter (or null) is passed, it will run the [member current_dialogue] if present
197207
func start(dialogue : Dialogue = null) -> void:
198-
if dialogue != null:
199-
current_dialogue = dialogue
200-
201-
if current_dialogue == null:
202-
push_error("Cannot start the Stage: `current_dialogue` is null")
208+
if is_playing():
209+
push_warning("Theres already a running Dialogue!")
203210
else:
204-
print("Starting Dialogue [%s]..." % current_dialogue.source_path)
205-
current_dialogue_length = current_dialogue.sets.size()
211+
if dialogue != null:
212+
current_dialogue = dialogue
213+
214+
if current_dialogue == null:
215+
push_error("Cannot start the Stage: `current_dialogue` is null")
216+
else:
217+
print("Starting Dialogue [%s]..." % current_dialogue.source_path)
218+
current_dialogue_length = current_dialogue.sets.size()
206219

207-
progress()
208-
started.emit()
220+
progress()
221+
started.emit()
209222

223+
# TODO
210224
func switch_lang(lang : String = "") -> void:
211225
if current_dialogue == null:
212226
push_error("Failed switching lang: current_dialogue is null")
@@ -242,8 +256,7 @@ func switch_lang(lang : String = "") -> void:
242256
if is_playing():
243257
current_dialogue_set = current_dialogue.sets[step]
244258
update_display()
245-
if dialogue_label != null:
246-
dialogue_label.rerender()
259+
dialogue_label.rerender()
247260

248261
func add_caller(id : String, node : Node) -> void:
249262
caller[id] = node

addons/Theatre/classes/Theatre.gd

+6-11
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
@icon("res://addons/Theatre/assets/icons/Theatre.svg")
2-
extends Node
2+
extends Object
3+
class_name Theatre
34

4-
var speed_scale : float = 1.0
5+
static var speed_scale : float = 1.0
56

6-
var lamg : String = ""
7-
var default_lang : String = "en"
7+
static var lamg : String = ""
8+
static var default_lang : String = "en"
89

9-
signal locale_changed(lang : String)
10-
11-
# TODO: would be nice if this can be triggered when `TranslationServer.set_locale()` is called
12-
func set_locale(lang : String = "") -> void:
13-
locale_changed.emit(lang)
14-
15-
func print_silly() -> void:
10+
static func print_silly() -> void:
1611
print("silly :p")

addons/Theatre/classes/TheatrePlugin.gd

+2-9
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ class Config extends RefCounted:
4040
if err != OK:
4141
push_error("Error saving Theatre config: ", err)
4242

43-
# BUG: theres a black rectangle on top left corner when Godot starts
4443
var plugin_submenu : PopupMenu = preload(
4544
"res://addons/Theatre/components/tool_submenu.tscn"
4645
).instantiate()
@@ -60,9 +59,6 @@ func _enter_tree() -> void:
6059
plugin_submenu.id_pressed.connect(tool_submenu_id_pressed)
6160
add_tool_submenu_item("🎭 Theatre", plugin_submenu)
6261

63-
# Add Theatre singleton
64-
add_autoload_singleton("Theatre", "res://addons/Theatre/classes/Theatre.gd")
65-
6662
func _exit_tree() -> void:
6763
print("🎭 Disabling Theatre...")
6864
# Clear project settings
@@ -72,9 +68,6 @@ func _exit_tree() -> void:
7268
plugin_submenu.id_pressed.disconnect(tool_submenu_id_pressed)
7369
remove_tool_menu_item("🎭 Theatre")
7470

75-
# Remove Theatre singleton
76-
remove_autoload_singleton("Theatre")
77-
7871
func crawl(path : String = "res://") -> void:
7972
var dir := DirAccess.open(path)
8073
var ignored_directories : PackedStringArray = (ProjectSettings.get_setting(
@@ -98,9 +91,9 @@ func crawl(path : String = "res://") -> void:
9891
print("Crawling " + new_dir + " for dialogue resources...")
9992
crawl(new_dir)
10093
else:
101-
if file_name.ends_with(".txt"):
94+
if file_name.ends_with(".dlg.txt"):
10295
var file := path + "/" + file_name
103-
var file_com := file.trim_suffix(".txt") + ".dlg.res"
96+
var file_com := file.trim_suffix(".txt") + ".res"
10497

10598
if FileAccess.file_exists(file_com):
10699
var rem_err := DirAccess.remove_absolute(file_com)

addons/Theatre/plugin.cfg

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
name="Theatre"
44
description="Text based dialogue plugin"
55
author="nnda"
6-
version="0.0.1-alpha.6"
6+
version="0.3.6-alpha"
77
script="classes/TheatrePlugin.gd"

project.godot

-4
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ run/main_scene="res://theatre_demo/intro_1.tscn"
1515
config/features=PackedStringArray("4.2")
1616
config/icon="res://addons/Theatre/assets/icons/Theatre.svg"
1717

18-
[autoload]
19-
20-
Theatre="*res://addons/Theatre/classes/Theatre.gd"
21-
2218
[display]
2319

2420
window/stretch/mode="canvas_items"

theatre_demo/demo_dialogue.dlg.txt

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
Dia:
2+
"Welcome to the Theatre!{d = 0.5} Hi there!{d = 0.4}
3+
this is a demo dialogue to demonstrate Theatre addon's core feature."
4+
5+
:
6+
"There are 5 main classes that makes part of Theatre plugin:{delay = 0.7}
7+
Dialogue, {d = 0.7}
8+
DialogueLabel, {d = 0.7}
9+
Stage, {d = 0.7}
10+
Theatre, {d = 0.7}
11+
& TheatrePlugin."
12+
13+
:
14+
"Lets start with Dialogue:{d = 0.8} Its a resource, containing the writing of
15+
your{s = 0.035}...{s}{d = 0.5} well,{d = 0.8} dialogue!{d = 1.0}
16+
You write them in a plain text file,{d = 0.9}
17+
the written dialogue then get parsed to a resource,{d = 0.9}
18+
that you can then use in your project"
19+
20+
:
21+
"And {s = 0.9}um{s = 0.04}...{s} Thats it!{s = 0.035}...{s} for now."
22+
23+
:
24+
"We also have an official documentation page,{d = 0.85}
25+
live at nndda.github.io/Theatre"
26+
27+
:
28+
"Stay tuned for the next updates!"

0 commit comments

Comments
 (0)