Skip to content

Commit c5f2a85

Browse files
authored
Implement better autoadvance system (#1755)
A new autoadvance system that allows for - a more complex calculation of the delay [(per_word+per_character)*modifier+fixed] - a more complex system for disabeling/enabeling autoadvance: - until user input - until next event - until disabled in code Many smaller fixes and additions included. Co-authored-by: Jowan Spooner
1 parent a93f53f commit c5f2a85

File tree

8 files changed

+615
-200
lines changed

8 files changed

+615
-200
lines changed

addons/dialogic/Modules/Settings/subsystem_settings.gd

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ extends DialogicSubsystem
22

33
## Subsystem that allows setting and getting settings that are automatically saved slot independent.
44
## All settings that are stored in the project settings dialogic/settings section are supported.
5-
## For example the text_speed setting is stored there.
5+
## For example the text_speed setting is stored there.
66
## Thus it can be acessed like this:
77
## Dialogic.Settings.text_speed = 0.05
8+
##
89
## Settings stored there can also be changed with the Settings event.
910

1011
var settings := {}
@@ -25,7 +26,7 @@ func _reload_settings() -> void:
2526
for prop in ProjectSettings.get_property_list():
2627
if prop.name.begins_with('dialogic/settings'):
2728
settings[prop.name.trim_prefix('dialogic/settings/')] = ProjectSettings.get_setting(prop.name)
28-
29+
2930
if dialogic.has_subsystem('Save'):
3031
for i in settings:
3132
settings[i] = dialogic.Save.get_global_info(i, settings[i])
@@ -49,7 +50,7 @@ func _get(property:StringName) -> Variant:
4950
func _setting_changed(property:StringName, value:Variant) -> void:
5051
if !property in _connections:
5152
return
52-
53+
5354
for i in _connections[property]:
5455
i.call(value)
5556

addons/dialogic/Modules/Text/default_input_handler.gd

Lines changed: 115 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,24 @@ var action_was_consumed := false
1414
################################################################################
1515
## INPUT
1616
################################################################################
17-
func _input(event:InputEvent) -> void:
17+
func _input(event: InputEvent) -> void:
1818
if event.is_action_pressed(ProjectSettings.get_setting('dialogic/text/input_action', 'dialogic_default_action')):
19-
19+
2020
if Dialogic.paused or is_input_blocked():
2121
return
22-
22+
23+
# We want to stop auto-advancing that cancels on user inputs.
24+
if (!action_was_consumed and Dialogic.Text.is_autoadvance_enabled()
25+
and Dialogic.Text.get_autoadvance_info()['waiting_for_user_input']):
26+
Dialogic.Text.set_autoadvance_until_user_input(false)
27+
return
28+
2329
dialogic_action_priority.emit()
30+
2431
if action_was_consumed:
2532
action_was_consumed = false
2633
return
27-
34+
2835
dialogic_action.emit()
2936

3037

@@ -42,21 +49,95 @@ func block_input(time:=skip_delay) -> void:
4249
####################################################################################################
4350
## AUTO-ADVANCING
4451
####################################################################################################
45-
func _ready() -> void:
46-
add_child(autoadvance_timer)
47-
autoadvance_timer.one_shot = true
48-
autoadvance_timer.timeout.connect(_on_autoadvance_timer_timeout)
4952

50-
add_child(input_block_timer)
51-
input_block_timer.one_shot = true
53+
func start_autoadvance() -> void:
54+
if not Dialogic.Text.is_autoadvance_enabled():
55+
return
56+
57+
var delay := _calculate_autoadvance_delay(
58+
Dialogic.Text.get_autoadvance_info(),
59+
Dialogic.current_state_info['text_parsed'])
60+
if delay == 0:
61+
_on_autoadvance_timer_timeout()
62+
else:
63+
await get_tree().process_frame
64+
autoadvance_timer.start(delay)
65+
66+
67+
## Calculates the autoadvance-time based on settings and text.
68+
##
69+
## Takes into account:
70+
## - temporary delay time override
71+
## - delay per word
72+
## - delay per character
73+
## - fixed delay
74+
## - text time taken
75+
## - autoadvance delay modifier
76+
## - voice audio
77+
func _calculate_autoadvance_delay(info:Dictionary, text:String="") -> float:
78+
var delay := 0.0
79+
80+
# Check for temporary time override
81+
if info['override_delay_for_current_event'] >= 0:
82+
delay = info['override_delay_for_current_event']
83+
else:
84+
# Add per word and per character delay
85+
delay = _calculate_per_word_delay(text, info) + _calculate_per_character_delay(text, info)
86+
delay *= Dialogic.Settings.get_setting('autoadvance_delay_modifier', 1)
87+
# Apply fixed delay last, so it's not affected by the delay modifier
88+
delay += info['fixed_delay']
89+
90+
delay = max(0, delay)
91+
92+
# Wait for the voice clip (if longer than the current delay)
93+
if info['await_playing_voice'] and Dialogic.has_subsystem('Voice') and Dialogic.Voice.is_running():
94+
delay = max(delay, Dialogic.Voice.get_remaining_time())
95+
96+
return delay
5297

5398

54-
func start_autoadvance() -> void:
55-
autoadvance_timer.start(Dialogic.Text.get_autoadvance_time())
99+
## Checks how many words can be found by separating the text by whitespace.
100+
## (Uses ` ` aka SPACE right now, could be extended in the future)
101+
func _calculate_per_word_delay(text: String, info:Dictionary) -> float:
102+
return float(text.split(' ', false).size() * info['per_word_delay'])
103+
104+
105+
## Checks how many characters can be found by iterating each letter.
106+
func _calculate_per_character_delay(text: String, info:Dictionary) -> float:
107+
var per_character_delay: float = info['per_character_delay']
108+
var calculated_delay: float = 0
109+
110+
if per_character_delay > 0:
111+
# If we have characters to ignore, we will iterate each letter.
112+
if info['ignored_characters_enabled']:
113+
for character in text:
114+
if character in info['ignored_characters']:
115+
continue
116+
calculated_delay += per_character_delay
117+
118+
# Otherwise, we can just multiply the length of the text by the delay.
119+
else:
120+
calculated_delay = text.length() * per_character_delay
121+
122+
return calculated_delay
56123

57124

58125
func _on_autoadvance_timer_timeout() -> void:
59126
autoadvance.emit()
127+
autoadvance_timer.stop()
128+
129+
130+
## Switches the auto-advance mode on or off based on [param is_enabled].
131+
func _on_autoadvance_enabled_change(is_enabled: bool) -> void:
132+
# If auto-advance is enabled and we are not auto-advancing yet,
133+
# we will initiate the auto-advance mode.
134+
if (is_enabled and !is_autoadvancing() and Dialogic.current_state == Dialogic.States.IDLE and not Dialogic.current_state_info['text'].is_empty()):
135+
start_autoadvance()
136+
137+
# If auto-advance is disabled and we are auto-advancing,
138+
# we want to cancel the auto-advance mode.
139+
elif !is_enabled and is_autoadvancing():
140+
stop()
60141

61142

62143
func is_autoadvancing() -> bool:
@@ -67,10 +148,32 @@ func get_autoadvance_time_left() -> float:
67148
return autoadvance_timer.time_left
68149

69150

151+
func get_autoadvance_time() -> float:
152+
return autoadvance_timer.wait_time
153+
154+
155+
156+
157+
func _ready() -> void:
158+
add_child(autoadvance_timer)
159+
autoadvance_timer.one_shot = true
160+
autoadvance_timer.timeout.connect(_on_autoadvance_timer_timeout)
161+
Dialogic.Text.autoadvance_changed.connect(_on_autoadvance_enabled_change)
162+
163+
add_child(input_block_timer)
164+
input_block_timer.one_shot = true
165+
166+
70167
func pause() -> void:
71168
autoadvance_timer.paused = true
72169
input_block_timer.paused = true
73170

171+
172+
func stop() -> void:
173+
autoadvance_timer.stop()
174+
input_block_timer.stop()
175+
176+
74177
func resume() -> void:
75178
autoadvance_timer.paused = false
76179
input_block_timer.paused = false

0 commit comments

Comments
 (0)