Skip to content

Instantly share code, notes, and snippets.

@Putnam3145
Created July 28, 2020 05:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Putnam3145/61c237ec118cd6e4f05ac1edde09e470 to your computer and use it in GitHub Desktop.
Save Putnam3145/61c237ec118cd6e4f05ac1edde09e470 to your computer and use it in GitHub Desktop.
A dialogue box for Godot.
[gd_scene load_steps=2 format=2]
[sub_resource type="GDScript" id=1]
script/source = "extends PopupPanel
\"\"\"
The run function expects an array, containing a series of strings or modifiers.
A string will be displayed one letter at a time, with the current delay,
using the current talk sound.
Modifiers are an array, containing arguments. The first entry in the array
is the type of the modifier; the second and on are arguments. Available
modifier types are as follows:
instant:
Displays text with no sound attached and no lettering delay. Argument:
Text.
pause:
Does nothing but wait for a while. It has only one argument:
The length of the pause.
meta:
Pushes a meta tag to the tag stack, then will pop it two later. Argument:
The data that will be pushed.
sound:
Plays a sound from the AudioStreamPlayer attached to the dialogue box. Arguments:
The sound file that will be played, or 'disable', which stops talksounds.
'play' to play the sound immediately or 'talksound' to set the talk sound to this file.
signal:
Sends a text_event signal to any listeners. Argument:
The single argument to text_event.
pop:
Pops the tag stack. No arguments.
new_line:
Requires user to press ui_accept; once done, will clear the text box. No arguments.
require_confirmation:
As new_line, without clearing. No arguments.
clear:
Clears the entire dialogue box.
delay:
Sets the text delay. Argument:
Amount of delay, in seconds.
reset_delay:
Resets the text delay to the default. No arguments.
image:
Displays an image in text. Argument:
Image file to display.
talksprite:
A sprite that shows on the left side of the dialogue box,
intended to represent the person who is talking at the moment. Argument:
The image file for the talk sprite.
notalksprite:
Removes the talk sprite.
\"\"\"
var set_skip=false
signal text_event(data)
signal meta_clicked(data)
signal meta_hover_ended(data)
signal meta_hover_started(data)
signal dialogue_done
var confirmation_required=false
var cur_delay=0.05
var talk_sound = false
var popped_already=false
var clear_next=false
var text_queue=[]
var meta_counter=-1
var processing=false
var stay = false
func init_texture_rect():
$Control/TextureRect.show()
$Control/TextureRect.set_anchor_and_margin(MARGIN_RIGHT,0.12,0)
$Control/RichTextLabel.set_anchor_and_margin(MARGIN_LEFT,0.12,0)
func deinit_texture_rect():
$Control/TextureRect.hide()
$Control/TextureRect.set_anchor_and_margin(MARGIN_RIGHT,0,0)
$Control/RichTextLabel.set_anchor_and_margin(MARGIN_LEFT,0,0)
func _ready():
$Control/RichTextLabel.connect(\"meta_clicked\",self,\"_meta_clicked\")
$Control/RichTextLabel.connect(\"meta_hover_ended\",self,\"_meta_hover_ended\")
$Control/RichTextLabel.connect(\"meta_hover_started\",self,\"_meta_hover_started\")
popup_exclusive=true
func _meta_clicked(data):
emit_signal(\"meta_clicked\",data)
func _meta_hover_ended(data):
emit_signal(\"meta_hover_ended\",data)
func _meta_hover_started(data):
emit_signal(\"meta_hover_started\",data)
func _process(delta):
if confirmation_required and Input.is_action_pressed(\"ui_accept\"):
confirmation_required=false
if processing and Input.is_action_pressed(\"skip_text\"):
set_skip=true
if !processing:
while text_queue.size()>0:
processing=true
meta_counter-=1
if meta_counter==0:
meta_counter=-1
$Control/RichTextLabel.pop()
var entry=text_queue.front()
set_skip=false
if confirmation_required:
yield(get_tree().create_timer(0.017), \"timeout\")
elif clear_next:
$Control/RichTextLabel.clear()
clear_next=false
else:
match typeof(entry):
TYPE_STRING:
if not popped_already:
popup()
yield(get_tree().create_timer(cur_delay), \"timeout\")
var bb_mode=false
var tag_string=\"\"
var popped=false
for letter in String(entry):
if bb_mode or letter==\"[\":
bb_mode=true
tag_string=tag_string+letter
if letter==\"]\":
bb_mode=false
if not popped:
$Control/RichTextLabel.append_bbcode(tag_string)
else:
popped=false
tag_string=\"\"
elif letter==\"/\":
bb_mode=false
popped=true
$Control/RichTextLabel.pop()
tag_string=\"\"
else:
$Control/RichTextLabel.append_bbcode(letter)
if talk_sound:
$AudioStreamPlayer.stop()
$AudioStreamPlayer.play(0)
if letter!=\" \":
var new_delay=cur_delay
match letter:
\"?\":
new_delay*=8
\"!\":
new_delay*=8
\".\":
new_delay*=8
\";\":
new_delay*=6
\":\":
new_delay*=5
\",\":
new_delay*=4
\"q\":
new_delay*=0.5
new_delay=clamp(new_delay,0,1)
if !set_skip and new_delay>0:
yield(get_tree().create_timer(new_delay), \"timeout\")
TYPE_ARRAY:
match entry[0]:
\"instant\":
if not popped_already:
popup()
$Control/RichTextLabel.append_bbcode(entry[1])
\"pause\":
if !set_skip:
yield(get_tree().create_timer(entry[1]), \"timeout\")
\"meta\":
$Control/RichTextLabel.push_meta(entry[1])
meta_counter=2
\"sound\":
if(entry[1] == \"disable\"):
talk_sound = false
else:
var old_sound = $AudioStreamPlayer.stream
$AudioStreamPlayer.stream=load(entry[1])
match(entry[2]):
\"play\":
$AudioStreamPlayer.play(0)
if talk_sound:
yield($AudioStreamPlayer,\"finished\")
$AudioStreamPlayer.stream = old_sound
\"talksound\":
talk_sound = true
\"signal\":
emit_signal(\"text_event\",entry[1])
\"pop\":
$Control/RichTextLabel.pop()
\"require_confirmation\":
confirmation_required=true
\"clear\":
$Control/RichTextLabel.clear()
\"delay\":
cur_delay=entry[1]
\"reset_delay\":
cur_delay=0.05
\"new_line\":
confirmation_required=true
clear_next=true
\"image\":
$Control/RichTextLabel.add_image(load(entry[1]))
\"talksprite\":
init_texture_rect()
$Control/TextureRect.texture = load(entry[1])
$Control/TextureRect.show()
\"notalksprite\":
deinit_texture_rect()
text_queue.pop_front()
processing=false
emit_signal(\"dialogue_done\")
if !stay and Input.is_action_pressed(\"ui_accept\") or Input.is_action_pressed(\"ui_cancel\"):
hide()
func run(args):
for entry in args:
text_queue.push_back(entry)
func _on_Dialogue_Box_popup_hide():
$Control/RichTextLabel.clear()
popped_already=false
cur_delay=0.05
func _on_Dialogue_Box_about_to_show():
popped_already=true
"
[node name="Dialogue Box" type="PopupPanel"]
anchor_left = 0.15
anchor_top = 0.05
anchor_right = 0.85
anchor_bottom = 0.2
script = SubResource( 1 )
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
bus = "Text sounds"
[node name="Control" type="Control" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 4.0
margin_top = 4.0
margin_right = -4.0
margin_bottom = -4.0
[node name="RichTextLabel" type="RichTextLabel" parent="Control"]
anchor_left = 0.12
anchor_right = 1.0
anchor_bottom = 1.0
margin_top = 4.0
margin_right = -4.0
margin_bottom = -4.0
bbcode_enabled = true
scroll_following = true
[node name="TextureRect" type="TextureRect" parent="Control"]
anchor_right = 0.12
anchor_bottom = 1.0
expand = true
stretch_mode = 1
[connection signal="about_to_show" from="." to="." method="_on_Dialogue_Box_about_to_show"]
[connection signal="popup_hide" from="." to="." method="_on_Dialogue_Box_popup_hide"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment