godot-vn/dialog_controller.gd

173 lines
4.6 KiB
GDScript

extends Reference
const Dialog = preload("res://dialog_vm.gd")
# classes from vm
const DialogSegment = Dialog.DialogSegment
const DialogWithSubjectSegment = Dialog.DialogWithSubjectSegment
const DialogWithSubjectExpressionSegment = Dialog.DialogWithSubjectExpressionSegment
const QuestionSegment = Dialog.QuestionSegment
const ChoiceSegment = Dialog.ChoiceSegment
const ChoiceWithJump = Dialog.ChoiceWithJump
const Choice = Dialog.Choice
const WaitSegment = Dialog.YieldCallSegment
# current dialog vm
var current_dialog
var audio_player
# dialog controller related state, internal
# speed at which dialog prints characters
var chars_per_second = 16 # initialized from which character is speaking
var reading_speed_mul = 1
var special_speed_mul = 1
# intermediate state for dialog
var waiting_for_answer = false
var print_done = false setget _on_print_set
var print_target = 0
var print_delta = 0
# ui button controlled state
var is_auto_advancing = false
var auto_advance_delay = 1
var auto_advance_timer = 0
var is_new_word = false
var is_fastforwarding = false
var ff_speed_mul = 1
# character printing sound related state
var sound_playing = false
var sound_play_time = 2.08 # TODO: maybe adjust this too depending on voice sample/chars per second
var sound_played_time = 0
# signals
signal on_printing_done()
signal on_printing_changed(status)
signal on_update_dialog(segment)
signal on_dialog_completed(d)
func _init(d, a):
current_dialog = d
audio_player = a
func reset():
self.print_done = true
print_target = 0
print_delta = 0
# sfx related
func sound_play():
sound_playing = true
audio_player.play()
func sound_stop():
audio_player.stop()
sound_playing = false
func sound_done_playing(delta):
sound_played_time += delta * reading_speed_mul * special_speed_mul
if sound_played_time >= sound_play_time / chars_per_second:
sound_played_time = 0
sound_playing = false
return not sound_playing
# temporary hopefully
func _advance_dialog():
var current_segment = current_dialog.advance()
if not current_segment == null:
emit_signal("on_update_dialog", current_segment)
else:
emit_signal("on_dialog_completed", self)
func _on_body_click(is_visible, event):
if is_visible and not waiting_for_answer:
if event.is_action_pressed("dialog_click"):
if print_done == false: # if still printing, jump forwards now
print_delta = print_target - 1
self.print_done = true
else:
_advance_dialog()
# interior callbacks
func _on_print_set(v):
print_done = v
if print_done:
emit_signal("on_printing_done")
emit_signal("on_printing_changed", v)
func set_reading_speed(spd):
reading_speed_mul = spd
func set_advance_state(s):
is_auto_advancing = s
func set_fastforward_state(s):
is_fastforwarding = s
if is_fastforwarding:
is_auto_advancing = true
ff_speed_mul = 10
auto_advance_delay = 0.1
else:
ff_speed_mul = 1
auto_advance_delay = 1
func update_logic_dialog(segment):
if segment is QuestionSegment:
var new_content = segment.get_content()
print_target = new_content.length()
self.print_done = false
print_delta = 0
elif segment is ChoiceSegment:
waiting_for_answer = true
elif segment is Choice:
var new_content = segment.get_response()
if typeof(new_content) == TYPE_OBJECT and (new_content is DialogWithSubjectSegment or new_content is DialogWithSubjectExpressionSegment):
_update_logic_dialog(new_content)
else:
print_target = new_content.length()
self.print_done = false
print_delta = 0
elif segment is DialogSegment or segment is DialogWithSubjectSegment or segment is DialogWithSubjectExpressionSegment:
var new_content = segment.get_content()
print_target = new_content.length()
self.print_done = false
print_delta = 0
elif segment is WaitSegment:
var new_content = segment.get_content()
print_target = new_content.length()
self.print_done = false
print_delta = 0
else:
print("encountered unknown segment: " + segment.get_content())
func tick(delta, body_label):
if not current_dialog.is_eof():
var cur_segment = current_dialog.segments[current_dialog.segment_index]
if cur_segment is WaitSegment and cur_segment.finished: _advance_dialog()
if print_target != 0:
if print_delta >= print_target:
self.print_done = true
auto_advance_timer = auto_advance_delay
print_target = 0
print_delta = 0
else:
if sound_done_playing(delta) and not is_fastforwarding: sound_play()
body_label.visible_characters = print_delta
print_delta += delta * (chars_per_second * reading_speed_mul) * ff_speed_mul
elif print_target == 0:
auto_advance_timer -= delta
if auto_advance_timer <= 0 and is_auto_advancing and not waiting_for_answer:
call_deferred("_advance_dialog")