diff --git a/addons/dialogue_nodes/nodes/DialogueNode.tscn b/addons/dialogue_nodes/nodes/DialogueNode.tscn index d4ece89..11f0b29 100644 --- a/addons/dialogue_nodes/nodes/DialogueNode.tscn +++ b/addons/dialogue_nodes/nodes/DialogueNode.tscn @@ -74,6 +74,8 @@ rect_min_size = Vector2( 0, 91 ) hint_tooltip = "The dialogue displayed in the DialogueBox. Use [bbcodes] to add extra effects to your dialogue." size_flags_vertical = 3 +syntax_highlighting = true +highlight_all_occurrences = true wrap_enabled = true [node name="Option1" type="LineEdit" parent="."] diff --git a/addons/dialogue_nodes/nodes/dialogueNode.gd b/addons/dialogue_nodes/nodes/dialogueNode.gd index 6d20d05..b624a60 100644 --- a/addons/dialogue_nodes/nodes/dialogueNode.gd +++ b/addons/dialogue_nodes/nodes/dialogueNode.gd @@ -21,6 +21,7 @@ func _ready(): option.connect("text_entered", self, "_on_option_entered", [options[0]]) option.connect("focus_exited", self, "_on_option_entered", ['', options[0]]) set_slot(option.get_index(), false, 0, Color.white, true, 0, Color.white) + dialogue.add_color_region('[', ']', Color('a5efac')) func add_option(new_text= ''): diff --git a/addons/dialogue_nodes/objects/bbcodeWait.gd b/addons/dialogue_nodes/objects/bbcodeWait.gd index 1f2caa4..37eae80 100644 --- a/addons/dialogue_nodes/objects/bbcodeWait.gd +++ b/addons/dialogue_nodes/objects/bbcodeWait.gd @@ -2,18 +2,24 @@ tool extends RichTextEffect class_name RichTextWait +signal wait_finished + var bbcode = 'wait' -var current_char = 0 +var finished = false func _process_custom_fx(char_fx): - var waitTime = char_fx.env.get('time', 0.0) - var speed = char_fx.env.get('speed', 10.0) + var waitTime = float(char_fx.env.get('time', 0.0)) + var speed = float(char_fx.env.get('speed', 40.0)) + var last = int(char_fx.env.get('last', 0)) - if char_fx.elapsed_time > waitTime: - char_fx.visible = false - if float(char_fx.elapsed_time) > float(char_fx.absolute_index / speed) + float(waitTime) : - char_fx.visible = true + if float(char_fx.elapsed_time) > float(char_fx.absolute_index / speed) + waitTime : + char_fx.visible = true + + if char_fx.absolute_index >= last and not finished: + emit_signal("wait_finished") + finished = true else: char_fx.visible = false + finished = false return true diff --git a/addons/dialogue_nodes/objects/dialogueBox.gd b/addons/dialogue_nodes/objects/dialogueBox.gd index 6af3201..e854f28 100644 --- a/addons/dialogue_nodes/objects/dialogueBox.gd +++ b/addons/dialogue_nodes/objects/dialogueBox.gd @@ -74,6 +74,11 @@ func _enter_tree(): func _ready(): if dict: init_variables(dict['variables']) + + for effect in custom_effects: + if effect is RichTextWait: + effect.connect("wait_finished", self, "show_options") + break func load_file(path): @@ -178,6 +183,7 @@ func set_dialogue(dict): dialogue.bbcode_text = process_text(dict['dialogue']) # hide all options + options.hide() for option in options.get_children(): option.icon = null option.hide() @@ -185,7 +191,7 @@ func set_dialogue(dict): # set options for idx in dict['options']: var option = options.get_child(int(idx)) - option.text = process_text(dict['options'][idx]['text']) + option.text = process_text(dict['options'][idx]['text'], false) if option.is_connected('pressed', self, 'proceed'): option.disconnect("pressed", self, 'proceed') option.connect("pressed", self, 'proceed', [dict['options'][idx]['link']]) @@ -194,29 +200,33 @@ func set_dialogue(dict): # if single empty option if len(dict['options']) == 1 and options.get_child(0).text == '': options.get_child(0).icon = next_icon - - # wait some time then grab focus - yield(get_tree().create_timer(0.5), "timeout") - options.get_child(0).grab_focus() -func process_text(text : String): - for i in range(text.count('{{')): - # Find tag position - var tag_start = text.find('{{')+2 - var tag_len = text.find('}}') - tag_start - - # Find variable value - var var_name = text.substr(tag_start, tag_len) - var value = 'undefined' - if variables.has(var_name): - value = variables[var_name] - - # Remove tag - text.erase(tag_start-2, tag_len+4) - - # Insert value - text = text.insert(tag_start-2, value) +func process_text(text : String, is_dialogue = true): + # Fill if empty + if text == '' and is_dialogue: + text = ' ' + + # Add variables + text = text.format(variables, '{{_}}') + + # Add a wait if none present + if text.count('[wait') == 0 and is_dialogue: + text = '[wait]' + text + '[/wait]' + + # Update [wait] with last attribute for showing options + # Find the actual position of the last character sans bbcode + var last := text.length()-1 + var find_pos = 0 + for i in range(text.count(']')): + var tag_start = text.findn('[', find_pos) + var tag_end = text.findn(']', find_pos) + var tag_len = (tag_end - tag_start) +1 + find_pos = tag_end + 1 + last -= tag_len + last -= text.count('\n') + # Update tags + text = text.replace('[wait', '[wait last='+str(last)) return text @@ -315,6 +325,11 @@ func handle_condition(cond_dict): proceed(cond_dict[str(result).to_lower()]) +func show_options(): + options.show() + options.get_child(0).grab_focus() + + func _set_options_alignment(value): options_alignment = value if options: diff --git a/addons/dialogue_nodes/plugin.cfg b/addons/dialogue_nodes/plugin.cfg index 6264049..80e07f6 100644 --- a/addons/dialogue_nodes/plugin.cfg +++ b/addons/dialogue_nodes/plugin.cfg @@ -4,5 +4,5 @@ name="Dialogue Nodes" description="A plugin to create dialogue trees using nodes and convert them to easy-to use JSON files." author="nagi" -version="0.1.0" +version="0.2.0" script="plugin.gd" diff --git a/examples/Demo.tscn b/examples/Demo.tscn index 7c3f5ff..05b9df0 100644 --- a/examples/Demo.tscn +++ b/examples/Demo.tscn @@ -1,11 +1,10 @@ -[gd_scene load_steps=20 format=2] +[gd_scene load_steps=19 format=2] [ext_resource path="res://addons/dialogue_nodes/objects/dialogueBox.gd" type="Script" id=1] [ext_resource path="res://examples/demo.gd" type="Script" id=2] [ext_resource path="res://icon.png" type="Texture" id=3] [ext_resource path="res://examples/Montserrat-Regular.ttf" type="DynamicFontData" id=4] [ext_resource path="res://addons/dialogue_nodes/objects/bbcodeWait.gd" type="Script" id=5] -[ext_resource path="res://Mango.gd" type="Script" id=6] [sub_resource type="StyleBoxFlat" id=2] content_margin_left = 6.0 @@ -201,11 +200,11 @@ margin_bottom = 11.0 text = "Start Demo" [node name="Particles" type="CPUParticles2D" parent="."] -position = Vector2( 510.17, 235.463 ) +position = Vector2( 527.817, 268.304 ) emitting = false amount = 64 one_shot = true -speed_scale = 2.0 +speed_scale = 1.5 explosiveness = 0.9 randomness = 0.2 lifetime_randomness = 0.5 @@ -225,22 +224,14 @@ anchor_top = 1.0 anchor_right = 0.5 anchor_bottom = 1.0 margin_left = -269.0 -margin_top = -150.0 +margin_top = -170.0 margin_right = 269.0 rect_min_size = Vector2( 300, 72 ) popup_exclusive = true script = ExtResource( 1 ) -dialogue_file = "res://examples/Example4.json" -start_id = "SIGNALS" +dialogue_file = "res://examples/Example1.json" +start_id = "START" custom_effects = [ SubResource( 13 ) ] -[node name="Control" type="Control" parent="."] -margin_right = 40.0 -margin_bottom = 40.0 -script = ExtResource( 6 ) -__meta__ = { -"_edit_use_anchors_": false -} - [connection signal="pressed" from="Button" to="." method="_on_Button_pressed"] [connection signal="dialogue_signal" from="DialogueBox" to="." method="_on_dialogue_signal"] diff --git a/examples/Example3.json b/examples/Example3.json index efc8edb..3f9a5d6 100644 --- a/examples/Example3.json +++ b/examples/Example3.json @@ -1 +1 @@ -{"0_1":{"link":"1_2","offset":{"x":0,"y":0},"start_id":"START"},"1_2":{"dialogue":"Do you want learn about [u]bbcodes[/u]?","offset":{"x":200,"y":0},"options":{"0":{"link":"1_6","text":"yah"},"1":{"link":"1_4","text":"Nah"}},"size":{"x":279.000122,"y":282},"speaker":"Fred"},"1_4":{"dialogue":"[shake rate=20 level=6]Oh too bad. :([/shake]","offset":{"x":540,"y":220},"options":{"0":{"link":"1_6","text":"On second thoughts..."},"1":{"link":"END","text":"Sorry"}},"size":{"x":388.999939,"y":282},"speaker":"Fred"},"1_6":{"dialogue":"Ok so, in the dialogue section of a dialogue Node, you can insert special keywords between [ ] to have certain effects.","offset":{"x":540,"y":-60},"options":{"0":{"link":"1_7","text":""}},"size":{"x":383.999939,"y":255},"speaker":"Fred"},"1_7":{"dialogue":"For example:\nputting the letter u between [ ] gives [u]text an underline[/u].\nEnd the effect with [/*], where * is the name of the effect (here, u).","offset":{"x":960,"y":-60},"options":{"0":{"link":"1_8","text":""}},"size":{"x":533.000122,"y":255},"speaker":"Fred"},"1_8":{"dialogue":"Some more examples:\n[ [fade length=5] fade [/fade] ]\n\n[ [color=red] color=red [/color] ]\n\n[ [shake rate=20 level=6] shake rate=15 level=6 [/shake] ]\n\n[ [wave] wave [/wave] ]\n\n[ [tornado] tornado [/tornado]]\n\n[ [rainbow] rainbow [/rainbow] ]","offset":{"x":1540,"y":-60},"options":{"0":{"link":"1_9","text":""}},"size":{"x":311.000122,"y":440},"speaker":"Fred"},"1_9":{"dialogue":"you can even combine effects like:\n[E1] [E2] text [/E2] [E1]\nWhere E1 and E2 could be anything.\n\n[rainbow] [wave] Example: Rainbow + Wave [/wave] [/rainbow]","offset":{"x":1900,"y":-60},"options":{"0":{"link":"1_6","text":"One more time?"},"1":{"link":"END","text":"Ok got it!"}},"size":{"x":429.998779,"y":312},"speaker":"Fred"},"2_1":{"comment":"This example shows how to use bbcodes in your dialogues, as well as an example of a looping dialogue tree.","offset":{"x":-20,"y":100},"size":{"x":200.000168,"y":200.000015}},"comments":{"0":"2_1"},"start":{"START":"0_1"},"strays":{},"variables":{}} +{"0_1":{"link":"1_2","offset":{"x":0,"y":0},"start_id":"START"},"0_2":{"link":"1_5","offset":{"x":0,"y":600},"start_id":"WAIT"},"1_1":{"dialogue":"[wait speed=5]1 2 3 4[/wait][shake rate=45 level=7]\n[wait speed=500 time=1.5]I[/wait] [wait speed=500 time=2]DECLARE[/wait] [wait speed=500 time=2.5]A THUMB[/wait] [wait speed=500 time=3]WAR![/wait]","offset":{"x":640,"y":600},"options":{"0":{"link":"1_3","text":""}},"size":{"x":601,"y":254.999756},"speaker":"Martha"},"1_10":{"dialogue":"[wait speed=10000]This text has custom speed. It does not use the default animation.\nWanna see a more complex example?","offset":{"x":420,"y":600},"options":{"0":{"link":"1_1","text":""}},"size":{"x":200.000122,"y":254.999756},"speaker":"Martha"},"1_2":{"dialogue":"Do you want learn about [u]bbcodes[/u]?","offset":{"x":200,"y":0},"options":{"0":{"link":"1_6","text":"yah"},"1":{"link":"1_4","text":"Nah"}},"size":{"x":279.000549,"y":282},"speaker":"Fred"},"1_3":{"dialogue":"Hey!\nDo you wanna play or not?","offset":{"x":1260,"y":600},"options":{"0":{"link":"END","text":"Sure!"},"1":{"link":"END","text":"Umm..."}},"size":{"x":200.000488,"y":281.999756},"speaker":"Martha"},"1_4":{"dialogue":"[shake rate=20 level=6]Oh too bad. :([/shake]","offset":{"x":540,"y":220},"options":{"0":{"link":"1_6","text":"On second thoughts..."},"1":{"link":"END","text":"Sorry"}},"size":{"x":388.999878,"y":282.000061},"speaker":"Fred"},"1_5":{"dialogue":"This text has default animation. It works without adding anything.","offset":{"x":200,"y":600},"options":{"0":{"link":"1_10","text":""}},"size":{"x":200.000183,"y":254.999756},"speaker":"Martha"},"1_6":{"dialogue":"Ok so, in the dialogue section of a dialogue Node, you can insert special keywords between [ ] to have certain effects.","offset":{"x":540,"y":-60},"options":{"0":{"link":"1_7","text":""}},"size":{"x":383.999634,"y":255},"speaker":"Fred"},"1_7":{"dialogue":"For example:\nputting the letter u between [ ] gives [u]text an underline[/u].\nEnd the effect with [/*], where * is the name of the effect (here, u).","offset":{"x":960,"y":-60},"options":{"0":{"link":"1_8","text":""}},"size":{"x":533.000244,"y":255},"speaker":"Fred"},"1_8":{"dialogue":"Some more examples:\n[ [fade length=5] fade [/fade] ]\n\n[ [color=red] color=red [/color] ]\n\n[ [shake rate=20 level=6] shake rate=15 level=6 [/shake] ]\n\n[ [wave] wave [/wave] ]\n\n[ [tornado] tornado [/tornado]]\n\n[ [rainbow] rainbow [/rainbow] ]","offset":{"x":1540,"y":-60},"options":{"0":{"link":"1_9","text":""}},"size":{"x":311,"y":440.000061},"speaker":"Fred"},"1_9":{"dialogue":"you can even combine effects like:\n[E1] [E2] text [/E2] [E1]\nWhere E1 and E2 could be anything.\n\n[rainbow] [wave] Example: Rainbow + Wave [/wave] [/rainbow]","offset":{"x":1900,"y":-60},"options":{"0":{"link":"1_6","text":"One more time?"},"1":{"link":"END","text":"Ok got it!"}},"size":{"x":429.997803,"y":312},"speaker":"Fred"},"2_1":{"comment":"This example shows how to use bbcodes in your dialogues, as well as an example of a looping dialogue tree.","offset":{"x":-20,"y":100},"size":{"x":200.000366,"y":200.000015}},"comments":{"0":"2_1"},"start":{"START":"0_1","WAIT":"0_2"},"strays":{},"variables":{}} diff --git a/examples/Example4.json b/examples/Example4.json index d2717e1..56f1251 100644 --- a/examples/Example4.json +++ b/examples/Example4.json @@ -1 +1 @@ -{"0_1":{"link":"1_1","offset":{"x":0,"y":0},"start_id":"SIGNALS"},"0_2":{"link":"1_5","offset":{"x":0,"y":260},"start_id":"SETGET"},"0_3":{"link":"1_3","offset":{"x":0,"y":540},"start_id":"CONDITION"},"1_1":{"dialogue":"Wanna see an explosion?","offset":{"x":200,"y":0},"options":{"0":{"link":"3_1","text":"Yeah!"},"1":{"link":"1_2","text":"Nah!"}},"size":{"x":200.000183,"y":255},"speaker":"Fred"},"1_2":{"dialogue":"Bye bye!","offset":{"x":680,"y":0},"options":{"0":{"link":"END","text":""}},"size":{"x":200.000305,"y":255},"speaker":"Fred"},"1_3":{"dialogue":"This item costs $8","offset":{"x":200,"y":540},"options":{"0":{"link":"5_1","text":"Buy it!"}},"size":{"x":200,"y":228},"speaker":"Harold"},"1_4":{"dialogue":"Ok","offset":{"x":680,"y":540},"options":{"0":{"link":"END","text":""}},"size":{"x":200.000061,"y":228},"speaker":"Harold"},"1_5":{"dialogue":"You have {{Coins}} coins.","offset":{"x":200,"y":260},"options":{"0":{"link":"4_1","text":"Buy item"}},"size":{"x":200,"y":228},"speaker":"Luke"},"1_6":{"dialogue":"Now, you have {{Coins}} left!","offset":{"x":680,"y":260},"options":{"0":{"link":"END","text":""}},"size":{"x":200.000061,"y":228},"speaker":"Luke"},"1_7":{"dialogue":"You can't afford that!","offset":{"x":680,"y":800},"options":{"0":{"link":"END","text":""}},"size":{"x":200.000061,"y":228},"speaker":"Harold"},"2_1":{"comment":"You can add Signal Nodes in the paths to emit signals.","offset":{"x":-20,"y":80},"size":{"x":200.000122,"y":130.000031}},"2_2":{"comment":"You can even add, get and set variables within the dialogue tree.","offset":{"x":-20,"y":340},"size":{"x":200.000122,"y":141.000061}},"2_3":{"comment":"Condition nodes can be used to control the flow of dialogues.","offset":{"x":-20,"y":620},"size":{"x":201.000122,"y":143.000061}},"3_1":{"link":"1_2","offset":{"x":440,"y":0},"signalValue":"explode"},"4_1":{"link":"1_6","offset":{"x":420,"y":280},"type":2,"value":"3","variable":"Coins"},"5_1":{"false":"1_7","offset":{"x":420,"y":560},"operator":4,"true":"1_4","value1":"{{Coins}}","value2":"8"},"comments":{"0":"2_1","1":"2_2","2":"2_3"},"start":{"CONDITION":"0_3","SETGET":"0_2","SIGNALS":"0_1"},"strays":{},"variables":{"Coins":{"type":2,"value":"10"},"Name":{"type":4,"value":"Joe Biden"},"Subbed":{"type":1,"value":"true"}}} +{"0_1":{"link":"1_1","offset":{"x":0,"y":0},"start_id":"SIGNALS"},"0_2":{"link":"1_5","offset":{"x":0,"y":400},"start_id":"SETGET"},"0_3":{"link":"1_3","offset":{"x":0,"y":800},"start_id":"CONDITION"},"1_1":{"dialogue":"Wanna see an explosion?","offset":{"x":200,"y":0},"options":{"0":{"link":"3_1","text":"Yeah!"},"1":{"link":"1_2","text":"Nah!"}},"size":{"x":200.000214,"y":282},"speaker":"Fred"},"1_2":{"dialogue":"Bye bye!","offset":{"x":680,"y":0},"options":{"0":{"link":"END","text":""}},"size":{"x":200.000488,"y":255.000061},"speaker":"Fred"},"1_3":{"dialogue":"This item costs $8","offset":{"x":200,"y":800},"options":{"0":{"link":"5_1","text":"Buy it!"}},"size":{"x":200,"y":255},"speaker":"Harold"},"1_4":{"dialogue":"Ok","offset":{"x":680,"y":800},"options":{"0":{"link":"END","text":""}},"size":{"x":200.000244,"y":255},"speaker":"Harold"},"1_5":{"dialogue":"You have {{Coins}} coins.","offset":{"x":200,"y":400},"options":{"0":{"link":"4_1","text":"Buy item"}},"size":{"x":200,"y":255.000092},"speaker":"Luke"},"1_6":{"dialogue":"Now, you have {{Coins}} left!","offset":{"x":680,"y":400},"options":{"0":{"link":"END","text":""}},"size":{"x":200.000244,"y":255.000092},"speaker":"Luke"},"1_7":{"dialogue":"You can't afford that!","offset":{"x":680,"y":1060},"options":{"0":{"link":"END","text":""}},"size":{"x":200.000244,"y":255},"speaker":"Harold"},"2_1":{"comment":"You can add Signal Nodes in the paths to emit signals.","offset":{"x":-20,"y":80},"size":{"x":200.000183,"y":130.000061}},"2_2":{"comment":"You can even add, get and set variables within the dialogue tree.","offset":{"x":-20,"y":480},"size":{"x":200.000183,"y":141.000122}},"2_3":{"comment":"Condition nodes can be used to control the flow of dialogues.","offset":{"x":-20,"y":880},"size":{"x":201.000183,"y":143.000122}},"3_1":{"link":"1_2","offset":{"x":440,"y":0},"signalValue":"explode"},"4_1":{"link":"1_6","offset":{"x":420,"y":420},"type":2,"value":"3","variable":"Coins"},"5_1":{"false":"1_7","offset":{"x":420,"y":820},"operator":4,"true":"1_4","value1":"{{Coins}}","value2":"8"},"comments":{"0":"2_1","1":"2_2","2":"2_3"},"start":{"CONDITION":"0_3","SETGET":"0_2","SIGNALS":"0_1"},"strays":{},"variables":{"Coins":{"type":2,"value":"10"},"Name":{"type":4,"value":"Joe Biden"},"Subbed":{"type":1,"value":"true"}}}