├── .gitignore ├── Example.tscn ├── LICENSE.md ├── README.md ├── TestingWorld.gd ├── addons └── dialogue_tree │ ├── assets │ ├── Icon.png │ ├── Icon.png.import │ ├── ResIcon.png │ └── ResIcon.png.import │ ├── editor_dock.gd │ ├── editor_dock.tscn │ ├── plugin.cfg │ ├── plugin.gd │ ├── resource │ ├── DialougeRes.tres │ └── dialogue_tree.gd │ ├── scenes │ ├── BasicDialogue.tscn │ ├── ChoiceContainer.tscn │ ├── ChoiceDialogue.tscn │ ├── ConditonalDialogue.tscn │ ├── EndNode.tscn │ ├── RandomChoiceContainer.tscn │ ├── RandomDialogue.tscn │ └── StartNode.tscn │ └── scripts │ ├── BasicDialogue.gd │ ├── ChoiceContainer.gd │ ├── ChoiceDialogue.gd │ ├── ConditonalDialogue.gd │ ├── EndNode.gd │ ├── RandomChoiceContainer.gd │ ├── RandomDialogue.gd │ ├── StartNode.gd │ └── dialogue.gd ├── default_env.tres ├── icon.png ├── icon.png.import └── project.godot /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Godot-specific ignores 3 | .import/ 4 | 5 | # Imported translations (automatically generated from CSV files) 6 | *.translation 7 | 8 | # Mono-specific ignores 9 | .mono/ 10 | data_*/ 11 | mono_crash.*.json 12 | 13 | # System/tool-specific ignores 14 | .directory 15 | *~ 16 | -------------------------------------------------------------------------------- /Example.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=10 format=2] 2 | 3 | [ext_resource path="res://TestingWorld.gd" type="Script" id=1] 4 | [ext_resource path="res://addons/dialogue_tree/scripts/dialogue.gd" type="Script" id=2] 5 | [ext_resource path="res://addons/dialogue_tree/assets/Icon.png" type="Texture" id=3] 6 | [ext_resource path="res://addons/dialogue_tree/assets/ResIcon.png" type="Texture" id=4] 7 | [ext_resource path="res://addons/dialogue_tree/resource/dialogue_tree.gd" type="Script" id=5] 8 | 9 | [sub_resource type="Animation" id=1] 10 | 11 | resource_name = "New Anim" 12 | length = 1.0 13 | loop = false 14 | step = 0.1 15 | 16 | [sub_resource type="Animation" id=2] 17 | 18 | resource_name = "New Anim2" 19 | length = 1.0 20 | loop = false 21 | step = 0.1 22 | 23 | [sub_resource type="Resource" id=3] 24 | 25 | script = ExtResource( 5 ) 26 | __meta__ = { 27 | "_editor_icon": ExtResource( 4 ) 28 | } 29 | connections = [ { 30 | "from": "BasicDialogue", 31 | "from_port": 0, 32 | "to": "EndNode", 33 | "to_port": 0 34 | }, { 35 | "from": "StartNode", 36 | "from_port": 0, 37 | "to": "ChoiceDialogue", 38 | "to_port": 0 39 | }, { 40 | "from": "ChoiceDialogue", 41 | "from_port": 0, 42 | "to": "BasicDialogue", 43 | "to_port": 0 44 | }, { 45 | "from": "ChoiceDialogue", 46 | "from_port": 1, 47 | "to": "BasicDialogue", 48 | "to_port": 0 49 | } ] 50 | Nodes = [ { 51 | "filename": "res://addons/dialogue_tree/scenes/EndNode.tscn", 52 | "name": "EndNode", 53 | "rect_size_x": 80.0, 54 | "rect_size_y": 55.0, 55 | "rect_x": 1055.0, 56 | "rect_y": 310.0 57 | }, { 58 | "filename": "res://addons/dialogue_tree/scenes/StartNode.tscn", 59 | "name": "StartNode", 60 | "rect_size_x": 87.0, 61 | "rect_size_y": 55.0, 62 | "rect_x": 248.0, 63 | "rect_y": 156.0 64 | }, { 65 | "Actor": "", 66 | "Dialogue": "", 67 | "RefName": "test2", 68 | "filename": "res://addons/dialogue_tree/scenes/BasicDialogue.tscn", 69 | "name": "BasicDialogue", 70 | "rect_size_x": 170.0, 71 | "rect_size_y": 114.0, 72 | "rect_x": 565.0, 73 | "rect_y": 280.0 74 | }, { 75 | "Conditonal": false, 76 | "RefName": "Test", 77 | "choices": [ { 78 | "Conditional": "", 79 | "Dialogue": "", 80 | "ToolTip": "" 81 | }, { 82 | "Conditional": "", 83 | "Dialogue": "", 84 | "ToolTip": "" 85 | }, { 86 | "Conditional": "", 87 | "Dialogue": "", 88 | "ToolTip": "" 89 | } ], 90 | "filename": "res://addons/dialogue_tree/scenes/ChoiceDialogue.tscn", 91 | "name": "ChoiceDialogue", 92 | "rect_size_x": 210.0, 93 | "rect_size_y": 168.0, 94 | "rect_x": 440.0, 95 | "rect_y": 77.0 96 | } ] 97 | DialogueTree = { 98 | "dialogue": [ { 99 | "Actor": "", 100 | "Dialogue": "", 101 | "NodeName": "BasicDialogue", 102 | "Ref": "test2", 103 | "next": "End" 104 | }, { 105 | "Choices": [ { 106 | "Conditional": "", 107 | "Dialogue": "", 108 | "ToolTip": "", 109 | "next": 0 110 | }, { 111 | "Conditional": "", 112 | "Dialogue": "", 113 | "ToolTip": "", 114 | "next": 0 115 | }, { 116 | "Conditional": "", 117 | "Dialogue": "", 118 | "ToolTip": "" 119 | } ], 120 | "NodeName": "ChoiceDialogue", 121 | "Ref": "Test" 122 | } ], 123 | "start_index": 1 124 | } 125 | 126 | [sub_resource type="Resource" id=4] 127 | 128 | script = ExtResource( 5 ) 129 | __meta__ = { 130 | "_editor_icon": ExtResource( 4 ) 131 | } 132 | connections = [ { 133 | "from": "ChoiceDialogue", 134 | "from_port": 0, 135 | "to": "BasicDialogue2", 136 | "to_port": 0 137 | }, { 138 | "from": "ChoiceDialogue", 139 | "from_port": 2, 140 | "to": "BasicDialogue2", 141 | "to_port": 0 142 | }, { 143 | "from": "BasicDialogue3", 144 | "from_port": 0, 145 | "to": "ChoiceDialogue2", 146 | "to_port": 0 147 | }, { 148 | "from": "ChoiceDialogue2", 149 | "from_port": 1, 150 | "to": "BasicDialogue5", 151 | "to_port": 0 152 | }, { 153 | "from": "BasicDialogue2", 154 | "from_port": 0, 155 | "to": "BasicDialogue6", 156 | "to_port": 0 157 | }, { 158 | "from": "BasicDialogue6", 159 | "from_port": 0, 160 | "to": "EndNode", 161 | "to_port": 0 162 | }, { 163 | "from": "BasicDialogue4", 164 | "from_port": 0, 165 | "to": "EndNode", 166 | "to_port": 0 167 | }, { 168 | "from": "ChoiceDialogue2", 169 | "from_port": 0, 170 | "to": "BasicDialogue4", 171 | "to_port": 0 172 | }, { 173 | "from": "ChoiceDialogue", 174 | "from_port": 1, 175 | "to": "BasicDialogue3", 176 | "to_port": 0 177 | }, { 178 | "from": "StartNode", 179 | "from_port": 0, 180 | "to": "BasicDialogue", 181 | "to_port": 0 182 | }, { 183 | "from": "BasicDialogue", 184 | "from_port": 0, 185 | "to": "ChoiceDialogue", 186 | "to_port": 0 187 | } ] 188 | Nodes = [ { 189 | "filename": "res://addons/dialogue_tree/scenes/EndNode.tscn", 190 | "name": "EndNode", 191 | "rect_size_x": 80.0, 192 | "rect_size_y": 55.0, 193 | "rect_x": 1554.0, 194 | "rect_y": 85.0 195 | }, { 196 | "filename": "res://addons/dialogue_tree/scenes/StartNode.tscn", 197 | "name": "StartNode", 198 | "rect_size_x": 87.0, 199 | "rect_size_y": 55.0, 200 | "rect_x": 87.0, 201 | "rect_y": 139.0 202 | }, { 203 | "Actor": "", 204 | "Dialogue": "That's awesome to hear!", 205 | "RefName": "", 206 | "filename": "res://addons/dialogue_tree/scenes/BasicDialogue.tscn", 207 | "name": "BasicDialogue2", 208 | "rect_size_x": 170.0, 209 | "rect_size_y": 114.0, 210 | "rect_x": 914.0, 211 | "rect_y": 5.0 212 | }, { 213 | "Conditonal": false, 214 | "RefName": "", 215 | "choices": [ { 216 | "Conditional": "", 217 | "Dialogue": "Not really.", 218 | "ToolTip": "" 219 | }, { 220 | "Conditional": "", 221 | "Dialogue": "Yeah, lets talk about it.", 222 | "ToolTip": "" 223 | } ], 224 | "filename": "res://addons/dialogue_tree/scenes/ChoiceDialogue.tscn", 225 | "name": "ChoiceDialogue2", 226 | "rect_size_x": 210.0, 227 | "rect_size_y": 141.0, 228 | "rect_x": 1014.0, 229 | "rect_y": 225.0 230 | }, { 231 | "Actor": "", 232 | "Dialogue": "Ah.. that's okay. Lemme know if you need anything.", 233 | "RefName": "", 234 | "filename": "res://addons/dialogue_tree/scenes/BasicDialogue.tscn", 235 | "name": "BasicDialogue4", 236 | "rect_size_x": 170.0, 237 | "rect_size_y": 114.0, 238 | "rect_x": 1294.0, 239 | "rect_y": 245.0 240 | }, { 241 | "Actor": "", 242 | "Dialogue": "Anything on your mind?", 243 | "RefName": "", 244 | "filename": "res://addons/dialogue_tree/scenes/BasicDialogue.tscn", 245 | "name": "BasicDialogue5", 246 | "rect_size_x": 170.0, 247 | "rect_size_y": 114.0, 248 | "rect_x": 1294.0, 249 | "rect_y": 385.0 250 | }, { 251 | "Actor": "", 252 | "Dialogue": "Testing sequental.", 253 | "RefName": "", 254 | "filename": "res://addons/dialogue_tree/scenes/BasicDialogue.tscn", 255 | "name": "BasicDialogue6", 256 | "rect_size_x": 170.0, 257 | "rect_size_y": 114.0, 258 | "rect_x": 1214.0, 259 | "rect_y": 5.0 260 | }, { 261 | "Actor": "", 262 | "Dialogue": "Wanna talk about it?", 263 | "RefName": "", 264 | "filename": "res://addons/dialogue_tree/scenes/BasicDialogue.tscn", 265 | "name": "BasicDialogue3", 266 | "rect_size_x": 170.0, 267 | "rect_size_y": 114.0, 268 | "rect_x": 794.0, 269 | "rect_y": 225.0 270 | }, { 271 | "Conditonal": false, 272 | "RefName": "", 273 | "choices": [ { 274 | "Conditional": "\"{test}\" == \"hello2\"", 275 | "Dialogue": "I'm okay.", 276 | "ToolTip": "Test must be hello2" 277 | }, { 278 | "Conditional": "false", 279 | "Dialogue": "I'm not feeling great.", 280 | "ToolTip": "This is disabled" 281 | }, { 282 | "Conditional": "true", 283 | "Dialogue": "I'm fantastic!", 284 | "ToolTip": "This is not disabled" 285 | } ], 286 | "filename": "res://addons/dialogue_tree/scenes/ChoiceDialogue.tscn", 287 | "name": "ChoiceDialogue", 288 | "rect_size_x": 246.0, 289 | "rect_size_y": 177.0, 290 | "rect_x": 478.0, 291 | "rect_y": 180.0 292 | }, { 293 | "Actor": "", 294 | "Dialogue": "Why hello. How are you today?", 295 | "RefName": "", 296 | "filename": "res://addons/dialogue_tree/scenes/BasicDialogue.tscn", 297 | "name": "BasicDialogue", 298 | "rect_size_x": 170.0, 299 | "rect_size_y": 114.0, 300 | "rect_x": 273.0, 301 | "rect_y": 84.0 302 | } ] 303 | DialogueTree = { 304 | "dialogue": [ { 305 | "Actor": "", 306 | "Dialogue": "That's awesome to hear!", 307 | "NodeName": "BasicDialogue2", 308 | "Ref": "", 309 | "next": 4 310 | }, { 311 | "Choices": [ { 312 | "Conditional": "", 313 | "Dialogue": "Not really.", 314 | "PassCondition": true, 315 | "ToolTip": "", 316 | "next": 2 317 | }, { 318 | "Conditional": "", 319 | "Dialogue": "Yeah, lets talk about it.", 320 | "PassCondition": true, 321 | "ToolTip": "", 322 | "next": 3 323 | } ], 324 | "Conditonal": false, 325 | "NodeName": "ChoiceDialogue2", 326 | "Ref": "" 327 | }, { 328 | "Actor": "", 329 | "Dialogue": "Ah.. that's okay. Lemme know if you need anything.", 330 | "NodeName": "BasicDialogue4", 331 | "Ref": "", 332 | "next": "End" 333 | }, { 334 | "Actor": "", 335 | "Dialogue": "Anything on your mind?", 336 | "NodeName": "BasicDialogue5", 337 | "Ref": "" 338 | }, { 339 | "Actor": "", 340 | "Dialogue": "Testing sequental.", 341 | "NodeName": "BasicDialogue6", 342 | "Ref": "", 343 | "next": "End" 344 | }, { 345 | "Actor": "", 346 | "Dialogue": "Wanna talk about it?", 347 | "NodeName": "BasicDialogue3", 348 | "Ref": "", 349 | "next": 1 350 | }, { 351 | "Choices": [ { 352 | "Conditional": "\"{test}\" == \"hello2\"", 353 | "Dialogue": "I'm okay.", 354 | "PassCondition": true, 355 | "ToolTip": "Test must be hello2", 356 | "next": 0 357 | }, { 358 | "Conditional": "false", 359 | "Dialogue": "I'm not feeling great.", 360 | "PassCondition": true, 361 | "ToolTip": "This is disabled", 362 | "next": 5 363 | }, { 364 | "Conditional": "true", 365 | "Dialogue": "I'm fantastic!", 366 | "PassCondition": true, 367 | "ToolTip": "This is not disabled", 368 | "next": 0 369 | } ], 370 | "Conditonal": false, 371 | "NodeName": "ChoiceDialogue", 372 | "Ref": "" 373 | }, { 374 | "Actor": "", 375 | "Dialogue": "Why hello. How are you today?", 376 | "NodeName": "BasicDialogue", 377 | "Ref": "", 378 | "next": 6 379 | } ], 380 | "start_index": 7 381 | } 382 | 383 | [node name="TestingWorld" type="Node2D" index="0"] 384 | 385 | script = ExtResource( 1 ) 386 | 387 | [node name="AnimationPlayer" type="AnimationPlayer" parent="." index="0"] 388 | 389 | root_node = NodePath("..") 390 | autoplay = "" 391 | playback_process_mode = 1 392 | playback_default_blend_time = 0.0 393 | playback_speed = 1.0 394 | "anims/New Anim" = SubResource( 1 ) 395 | blend_times = [ ] 396 | 397 | [node name="TEst" type="AnimationPlayer" parent="." index="1"] 398 | 399 | root_node = NodePath("..") 400 | autoplay = "" 401 | playback_process_mode = 1 402 | playback_default_blend_time = 0.0 403 | playback_speed = 1.0 404 | "anims/New Anim2" = SubResource( 2 ) 405 | blend_times = [ ] 406 | 407 | [node name="Dialogue" type="Node" parent="." index="2"] 408 | 409 | script = ExtResource( 2 ) 410 | __meta__ = { 411 | "_editor_icon": ExtResource( 3 ) 412 | } 413 | DialogueResource = SubResource( 3 ) 414 | RandomizeBeforeRandom = false 415 | 416 | [node name="Dialogue2" type="Node" parent="." index="3"] 417 | 418 | script = ExtResource( 2 ) 419 | __meta__ = { 420 | "_editor_icon": ExtResource( 3 ) 421 | } 422 | DialogueResource = SubResource( 4 ) 423 | RandomizeBeforeRandom = false 424 | 425 | [node name="CanvasLayer" type="CanvasLayer" parent="." index="4"] 426 | 427 | layer = 1 428 | offset = Vector2( 0, 0 ) 429 | rotation = 0.0 430 | scale = Vector2( 1, 1 ) 431 | transform = Transform2D( 1, 0, 0, 1, 0, 0 ) 432 | 433 | [node name="DialogueBasic" type="Panel" parent="CanvasLayer" index="0"] 434 | 435 | visible = false 436 | anchor_left = 0.5 437 | anchor_top = 1.0 438 | anchor_right = 0.5 439 | anchor_bottom = 1.0 440 | margin_left = -270.0 441 | margin_top = -101.0 442 | margin_right = 270.0 443 | margin_bottom = -14.0 444 | rect_pivot_offset = Vector2( 0, 0 ) 445 | rect_clip_content = false 446 | mouse_filter = 0 447 | mouse_default_cursor_shape = 0 448 | size_flags_horizontal = 1 449 | size_flags_vertical = 1 450 | 451 | [node name="Label" type="Label" parent="CanvasLayer/DialogueBasic" index="0"] 452 | 453 | anchor_left = 0.0 454 | anchor_top = 0.0 455 | anchor_right = 1.0 456 | anchor_bottom = 1.0 457 | rect_pivot_offset = Vector2( 0, 0 ) 458 | rect_clip_content = false 459 | mouse_filter = 2 460 | mouse_default_cursor_shape = 0 461 | size_flags_horizontal = 1 462 | size_flags_vertical = 4 463 | align = 1 464 | valign = 1 465 | percent_visible = 1.0 466 | lines_skipped = 0 467 | max_lines_visible = -1 468 | 469 | [node name="ChoiceBasic" type="Panel" parent="CanvasLayer" index="1"] 470 | 471 | visible = false 472 | anchor_left = 0.5 473 | anchor_top = 1.0 474 | anchor_right = 0.5 475 | anchor_bottom = 1.0 476 | margin_left = -270.0 477 | margin_top = -146.0 478 | margin_right = 270.0 479 | margin_bottom = -14.0 480 | rect_pivot_offset = Vector2( 0, 0 ) 481 | rect_clip_content = false 482 | mouse_filter = 0 483 | mouse_default_cursor_shape = 0 484 | size_flags_horizontal = 1 485 | size_flags_vertical = 1 486 | 487 | [node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/ChoiceBasic" index="0"] 488 | 489 | anchor_left = 0.0 490 | anchor_top = 0.0 491 | anchor_right = 1.0 492 | anchor_bottom = 1.0 493 | rect_pivot_offset = Vector2( 0, 0 ) 494 | rect_clip_content = false 495 | mouse_filter = 1 496 | mouse_default_cursor_shape = 0 497 | size_flags_horizontal = 1 498 | size_flags_vertical = 1 499 | alignment = 1 500 | 501 | [node name="NextTimer" type="Timer" parent="CanvasLayer" index="2"] 502 | 503 | process_mode = 1 504 | wait_time = 5.0 505 | one_shot = true 506 | autostart = false 507 | 508 | [connection signal="Choice_Next" from="Dialogue2" to="." method="_on_Dialogue2_Choice_Next"] 509 | 510 | [connection signal="Conditonal_Data_Needed" from="Dialogue2" to="." method="_on_Dialogue2_Conditonal_Data_Needed"] 511 | 512 | [connection signal="Dialogue_Ended" from="Dialogue2" to="." method="_on_Dialogue2_Dialogue_Ended"] 513 | 514 | [connection signal="Dialogue_Next" from="Dialogue2" to="." method="_on_Dialogue2_Dialogue_Next"] 515 | 516 | [connection signal="Dialogue_Started" from="Dialogue2" to="." method="_on_Dialogue2_Dialogue_Started"] 517 | 518 | [connection signal="timeout" from="CanvasLayer/NextTimer" to="." method="_on_NextTimer_timeout"] 519 | 520 | 521 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Alexander Emory 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DialogueTreePlugin 2 | 3 | A plug-in for godot 3.0 for dialogue trees. 4 | 5 | ## How-to 6 | 7 | Add the plug-in to your project and create a dialogue node. This node will act as the *engine* for that dialogue tree. 8 | 9 | When a dialogue node is selected, the tree editor will open. 10 | 11 | You can add new nodes via the *Add* button. 12 | 13 | The end and start nodes are meant for the beginning and end of the dialouge. 14 | 15 | The dialogue node will never display dialogue. It's up to your to build the front end. 16 | 17 | 18 | **Note: The tree resource will not save unless you press CTRL+S inside of the tree editor** 19 | 20 | ## Docs 21 | 22 | ### Signals 23 | 24 | `Dialogue_Next (ref, actor, text)` 25 | 26 | Called when a *basic dialogue* is called. 27 | 28 | - ref (string) is the name of the node, given by the first line edit the node 29 | - actor (string) is the name of the actor in the node 30 | - text (string) is the dialouge on the node 31 | 32 | `Choice_Next (ref, choices)` 33 | 34 | Called when a *choice dialogue* is called. 35 | 36 | - ref (string) is the name of the node, given by the first line edit on the node 37 | - choices (array) An array of choices, data will be displayed as follows: 38 | 39 | ```py 40 | [ 41 | { 42 | "Conditional" : "Condition here", 43 | "ToolTip" : "Tooltip here", 44 | "Dialogue" : "Dialogue here", 45 | "PassCondition" : true # If the conditon is true. (will not be false if conditionals is false on the node) 46 | }, 47 | {...} 48 | ] 49 | ``` 50 | 51 | `Conditonal_Data_Needed` 52 | 53 | Called when the dialogue needs new conditional data. If this is called, the dialogue tree is paused until `send_conditonal_data` is called. 54 | 55 | `Dialogue_Started` 56 | 57 | Called when dialogue starts. 58 | 59 | `Dialogue_Ended` 60 | 61 | Called when dialogue ends, rather prematurely, or on purpose. 62 | 63 | ### Functions 64 | 65 | `void start_dialogue(start_at = -1)` 66 | 67 | Starts the dialogue. Used to initialize, as well as resume at an index. 68 | 69 | If start_at is -1, the dialogue will start at whatever node is connected to the start node. 70 | 71 | `void next_dialogue(choice = -1, conditon = -1)` 72 | 73 | Causes the dialogue to follow the tree to the next dialogue node. 74 | 75 | - choice (int) will push a choice through. 76 | - conditon (bool) weither or not the conditon to continue is true (meant for internal calling) 77 | 78 | `void end_dialogue()` 79 | 80 | Prematurely ends the dialogue. 81 | 82 | `void send_conditonal_data(dict)` 83 | 84 | Sets the custom conditional data. Will continue the dialogue tree. 85 | 86 | ### Variables 87 | 88 | 89 | `(int) current_index` 90 | 91 | The currently running dialogue tree node. This can be used for loading and saving the current state. 92 | 93 | `(bool) in_dialogue` 94 | 95 | Whether or not the dialogue tree is running. 96 | 97 | `export (bool) RandomizeBeforeRandom` 98 | 99 | Whether or not we should call `randomize` before random number generators. 100 | 101 | `export (Resource) DialogueResource` 102 | 103 | The actual reference to the dialogue resource. This is automatically generated and saved when using the dialogue tree. 104 | 105 | ### Dialogue nodes 106 | 107 | `Basic Dialogue` 108 | 109 | This is the most basic version of dialogue. 110 | 111 | - ReferenceName The name of the node. This can be used to call events based on specific dialogue nodes. 112 | - Actor The name of the actor. 113 | - Dialogue The dialogue text. 114 | 115 | `Conditonal` 116 | 117 | This can be used to control the flow of dialogue. This will automatically call `next_dialogue`, depending on the condition. 118 | 119 | - ReferenceName The name of the node. This can be used to call events based on specific dialogue nodes. 120 | - Condition The condition to run (in gdscript) to determine whether or not the *true* output is called. This is formatted with `String.format` with the conditional data given from `send_conditonal_data` 121 | 122 | `Choice` 123 | 124 | This allows the user (or AI, up to you) to select a choice and effect the dialogue. You can add more choices with the -/+ buttons. 125 | 126 | - ReferenceName The name of the node. This can be used to call events based on specific dialogue nodes. 127 | - Conditionals Determines whether or not conditionals should be tested. 128 | 129 | `Random` 130 | 131 | This randomly selects an output. This will automatically call `next_dialogue`. You can add more choices with the -/+ buttons. 132 | 133 | - ReferenceName The name of the node. This can be used to call events based on specific dialogue nodes. 134 | - Conditionals Determines whether or not conditionals should be tested before calling `next_dialogue` 135 | -------------------------------------------------------------------------------- /TestingWorld.gd: -------------------------------------------------------------------------------- 1 | extends Node2D 2 | 3 | func _ready(): 4 | $Dialogue2.start_dialogue() 5 | 6 | func _on_Dialogue2_Dialogue_Started(): 7 | pass 8 | 9 | func _on_Dialogue2_Dialogue_Next(ref, actor, text): 10 | $CanvasLayer/ChoiceBasic.hide() 11 | $CanvasLayer/DialogueBasic.show() 12 | 13 | $CanvasLayer/DialogueBasic/Label.text = text 14 | $CanvasLayer/NextTimer.start() 15 | 16 | func _on_Dialogue2_Dialogue_Ended(): 17 | $CanvasLayer/DialogueBasic.hide() 18 | $CanvasLayer/ChoiceBasic.hide() 19 | 20 | func _on_Dialogue2_Choice_Next(ref, choices): 21 | $CanvasLayer/DialogueBasic.hide() 22 | $CanvasLayer/ChoiceBasic.show() 23 | 24 | for i in $CanvasLayer/ChoiceBasic/VBoxContainer.get_children(): 25 | i.free() 26 | 27 | for i in range(0, choices.size()): 28 | var newButton = Button.new() 29 | newButton.text = choices[i].Dialogue 30 | newButton.connect("pressed", self, "_on_choice_pressed", [i]) 31 | newButton.disabled = !choices[i]["PassCondition"] 32 | newButton.hint_tooltip = choices[i]["ToolTip"] 33 | $CanvasLayer/ChoiceBasic/VBoxContainer.add_child(newButton) 34 | 35 | func _on_choice_pressed(id): 36 | $Dialogue2.next_dialogue(id) 37 | 38 | func _on_NextTimer_timeout(): 39 | $Dialogue2.next_dialogue() 40 | 41 | func _on_Dialogue2_Conditonal_Data_Needed(): 42 | $Dialogue2.send_conditonal_data({"test" : "hello"}) 43 | -------------------------------------------------------------------------------- /addons/dialogue_tree/assets/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LexiEmory/DialogueTreePlugin/a9c1a84b1164cad8219138c42141761259f7fb46/addons/dialogue_tree/assets/Icon.png -------------------------------------------------------------------------------- /addons/dialogue_tree/assets/Icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/Icon.png-3c722fa2ec5cc3fdf6aab02b1cf039ec.stex" 6 | 7 | [deps] 8 | 9 | source_file="res://addons/dialogue_tree/assets/Icon.png" 10 | dest_files=[ "res://.import/Icon.png-3c722fa2ec5cc3fdf6aab02b1cf039ec.stex" ] 11 | 12 | [params] 13 | 14 | compress/mode=0 15 | compress/lossy_quality=0.7 16 | compress/hdr_mode=0 17 | compress/normal_map=0 18 | flags/repeat=0 19 | flags/filter=false 20 | flags/mipmaps=false 21 | flags/anisotropic=false 22 | flags/srgb=2 23 | process/fix_alpha_border=true 24 | process/premult_alpha=false 25 | process/HDR_as_SRGB=false 26 | stream=false 27 | size_limit=0 28 | detect_3d=true 29 | svg/scale=1.0 30 | -------------------------------------------------------------------------------- /addons/dialogue_tree/assets/ResIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LexiEmory/DialogueTreePlugin/a9c1a84b1164cad8219138c42141761259f7fb46/addons/dialogue_tree/assets/ResIcon.png -------------------------------------------------------------------------------- /addons/dialogue_tree/assets/ResIcon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ResIcon.png-df1275357f8a5060d4471c31fa8f836e.stex" 6 | 7 | [deps] 8 | 9 | source_file="res://addons/dialogue_tree/assets/ResIcon.png" 10 | dest_files=[ "res://.import/ResIcon.png-df1275357f8a5060d4471c31fa8f836e.stex" ] 11 | 12 | [params] 13 | 14 | compress/mode=0 15 | compress/lossy_quality=0.7 16 | compress/hdr_mode=0 17 | compress/normal_map=0 18 | flags/repeat=0 19 | flags/filter=false 20 | flags/mipmaps=false 21 | flags/anisotropic=false 22 | flags/srgb=2 23 | process/fix_alpha_border=true 24 | process/premult_alpha=false 25 | process/HDR_as_SRGB=false 26 | stream=false 27 | size_limit=0 28 | detect_3d=true 29 | svg/scale=1.0 30 | -------------------------------------------------------------------------------- /addons/dialogue_tree/editor_dock.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Panel 3 | 4 | var current_node = null 5 | 6 | const choice_dialogue = preload("res://addons/dialogue_tree/scripts/ChoiceDialogue.gd") 7 | const basic_dialogue = preload("res://addons/dialogue_tree/scripts/BasicDialogue.gd") 8 | const conditonal_dialogue = preload("res://addons/dialogue_tree/scripts/ConditonalDialogue.gd") 9 | const random_dialogue = preload("res://addons/dialogue_tree/scripts/RandomDialogue.gd") 10 | const start_dialogue = preload("res://addons/dialogue_tree/scripts/StartNode.gd") 11 | const end_dialogue = preload("res://addons/dialogue_tree/scripts/EndNode.gd") 12 | 13 | func _ready(): 14 | $TopBar/TopContainer/MenuButton.get_popup().connect("id_pressed", self, "_on_menubutton_item_pressed") 15 | 16 | # when a button on the add menu is pressed 17 | func _on_menubutton_item_pressed(id): 18 | # add basic dialogue 19 | if id == 0: 20 | var basicDialogue = load("res://addons/dialogue_tree/scenes/BasicDialogue.tscn").instance() 21 | basicDialogue.connect("close_request", self, "_on_node_close", [basicDialogue]) 22 | basicDialogue.connect("resize_request", self, "_on_node_resize", [basicDialogue]) 23 | 24 | $PrimaryGraphEditor.add_child(basicDialogue, true) 25 | if id == 1: 26 | var conditonalDialogue = load("res://addons/dialogue_tree/scenes/ConditonalDialogue.tscn").instance() 27 | conditonalDialogue.connect("close_request", self, "_on_node_close", [conditonalDialogue]) 28 | conditonalDialogue.connect("resize_request", self, "_on_node_resize", [conditonalDialogue]) 29 | 30 | $PrimaryGraphEditor.add_child(conditonalDialogue, true) 31 | if id == 2: 32 | var choiceDialogue = load("res://addons/dialogue_tree/scenes/ChoiceDialogue.tscn").instance() 33 | choiceDialogue.connect("close_request", self, "_on_node_close", [choiceDialogue]) 34 | choiceDialogue.connect("resize_request", self, "_on_node_resize", [choiceDialogue]) 35 | choiceDialogue.connect("removed", self, "remove_connection", [choiceDialogue]) 36 | 37 | $PrimaryGraphEditor.add_child(choiceDialogue, true) 38 | if id == 3: 39 | var randomDialogue = load("res://addons/dialogue_tree/scenes/RandomDialogue.tscn").instance() 40 | randomDialogue.connect("close_request", self, "_on_node_close", [randomDialogue]) 41 | randomDialogue.connect("resize_request", self, "_on_node_resize", [randomDialogue]) 42 | randomDialogue.connect("removed", self, "remove_connection", [randomDialogue]) 43 | 44 | $PrimaryGraphEditor.add_child(randomDialogue, true) 45 | 46 | # when there is a connection request 47 | func _on_PrimaryGraphEditor_connection_request(from, from_slot, to, to_slot): 48 | var all_connections = $PrimaryGraphEditor.get_connection_list() # {from_port: 0, from: "GraphNode name 0", to_port: 1, to: "GraphNode name 1" } 49 | var slot_connections = [] 50 | for connection in all_connections: 51 | if connection["from"] == from and connection["from_port"] == from_slot: 52 | slot_connections.append(connection) 53 | for slot_connection in slot_connections: 54 | $PrimaryGraphEditor.disconnect_node(slot_connection["from"], slot_connection["from_port"], slot_connection["to"], slot_connection["to_port"]) 55 | 56 | $PrimaryGraphEditor.connect_node(from, from_slot, to, to_slot) 57 | 58 | # when there is a disconnection request 59 | func _on_PrimaryGraphEditor_disconnection_request(from, from_slot, to, to_slot): 60 | $PrimaryGraphEditor.disconnect_node(from, from_slot, to, to_slot) 61 | 62 | # when a graph node is closed 63 | func _on_node_close(ref): 64 | remove_all_connections(ref) 65 | ref.queue_free() 66 | 67 | # when a graph node is resized 68 | func _on_node_resize(newSize, ref): 69 | ref.rect_size = newSize 70 | 71 | # sets the current node to edit 72 | func set_edit_node(ref): 73 | clear_all_nodes() 74 | current_node = ref 75 | 76 | if current_node != null and current_node.DialogueResource != null: 77 | for i in current_node.DialogueResource.Nodes: 78 | if i["name"] != "StartNode" and i["name"] != "EndNode": 79 | var newNode = load(i.filename).instance() 80 | newNode.name = i.name 81 | newNode.offset = Vector2(i.rect_x, i.rect_y) 82 | newNode.rect_size = Vector2(i.rect_size_x, i.rect_size_y) 83 | 84 | newNode.connect("close_request", self, "_on_node_close", [newNode]) 85 | newNode.connect("resize_request", self, "_on_node_resize", [newNode]) 86 | if newNode is choice_dialogue or newNode is random_dialogue: 87 | newNode.connect("removed", self, "remove_connection", [newNode]) 88 | 89 | $PrimaryGraphEditor.add_child(newNode, true) 90 | 91 | newNode.load_data(i) 92 | else: 93 | var editNode = $PrimaryGraphEditor.get_node(i["name"]) 94 | editNode.offset = Vector2(i["rect_x"], i["rect_y"]) 95 | editNode.rect_size = Vector2(i["rect_size_x"], i["rect_size_y"]) 96 | 97 | for i in current_node.DialogueResource.connections: 98 | $PrimaryGraphEditor.connect_node(i.from, i.from_port, i.to, i.to_port) 99 | 100 | # saves the resource to the active node 101 | func save_resource(): 102 | # if there is no current resource, create it 103 | if current_node != null: 104 | if current_node.DialogueResource == null: 105 | var newRes = create_resource() 106 | 107 | newRes.connections = $PrimaryGraphEditor.get_connection_list() 108 | 109 | for i in $PrimaryGraphEditor.get_children(): 110 | if i.has_method("save_data"): 111 | newRes.Nodes.append(i.save_data()) 112 | 113 | newRes.DialogueTree = make_exported_dialogue() 114 | 115 | ResourceSaver.save(current_node.owner.filename, newRes) 116 | current_node.DialogueResource = newRes 117 | else: 118 | var newRes = current_node.DialogueResource 119 | newRes.connections = $PrimaryGraphEditor.get_connection_list() 120 | 121 | newRes.Nodes.clear() 122 | 123 | for i in $PrimaryGraphEditor.get_children(): 124 | if i.has_method("save_data"): 125 | newRes.Nodes.append(i.save_data()) 126 | 127 | newRes.DialogueTree = make_exported_dialogue() 128 | 129 | ResourceSaver.save(current_node.DialogueResource.resource_path, newRes) 130 | 131 | # creates a new dialouge resource 132 | func create_resource(): 133 | var newRes = load("res://addons/dialogue_tree/resource/DialougeRes.tres").duplicate() 134 | return newRes 135 | 136 | # creates a json friendly version of the data for reading 137 | func make_exported_dialogue(): 138 | var exportedDict = { 139 | "start_index" : 0, 140 | "dialogue" : [] 141 | } 142 | 143 | # add all nodes 144 | for i in $PrimaryGraphEditor.get_children(): 145 | if i.name != "StartNode" and i.name != "EndNode" and i.has_method("export_values"): 146 | exportedDict.dialogue.append(i.export_values()) 147 | 148 | # create connections 149 | for i in $PrimaryGraphEditor.get_connection_list(): 150 | var fromNode = $PrimaryGraphEditor.get_node(i.from) 151 | var toNode = $PrimaryGraphEditor.get_node(i.to) 152 | 153 | # if we have a starting connection 154 | if fromNode is start_dialogue: 155 | var toIndex = find_with_name(exportedDict.dialogue, i.to) 156 | 157 | exportedDict.start_index = toIndex 158 | # for all other node types 159 | else: 160 | if fromNode.has_method("make_connection"): 161 | exportedDict = fromNode.make_connection(i, exportedDict, toNode is end_dialogue) 162 | 163 | return exportedDict 164 | 165 | # used to find the index of an exported node with a name value 166 | func find_with_name(inArray, inName): 167 | for i in range(0, inArray.size()): 168 | if inArray[i].NodeName == inName: 169 | return i 170 | 171 | return -1 172 | 173 | # used to clear everything from the graph 174 | func clear_all_nodes(): 175 | $PrimaryGraphEditor.clear_connections() 176 | for i in $PrimaryGraphEditor.get_children(): 177 | if i is GraphNode and i.name != "StartNode" and i.name != "EndNode": 178 | i.free() 179 | 180 | # removes connections going from an id 181 | func remove_connection(id, node): 182 | for i in $PrimaryGraphEditor.get_connection_list(): 183 | if i.from == node.name and i.from_port == id: 184 | $PrimaryGraphEditor.disconnect_node(i.from, i.from_port, i.to, i.to_port) 185 | 186 | # used to remove all connections going in or out of a node 187 | func remove_all_connections(node): 188 | for i in $PrimaryGraphEditor.get_connection_list(): 189 | if i.from == node.name or i.to == node.name: 190 | $PrimaryGraphEditor.disconnect_node(i.from, i.from_port, i.to, i.to_port) -------------------------------------------------------------------------------- /addons/dialogue_tree/editor_dock.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://addons/dialogue_tree/editor_dock.gd" type="Script" id=1] 4 | [ext_resource path="res://addons/dialogue_tree/scenes/EndNode.tscn" type="PackedScene" id=2] 5 | [ext_resource path="res://addons/dialogue_tree/scenes/StartNode.tscn" type="PackedScene" id=3] 6 | 7 | [node name="Editor Dock" type="Panel"] 8 | 9 | anchor_left = 0.0 10 | anchor_top = 0.0 11 | anchor_right = 0.0 12 | anchor_bottom = 0.0 13 | margin_left = -1.0 14 | margin_top = -1.0 15 | margin_right = 1023.0 16 | margin_bottom = 599.0 17 | rect_min_size = Vector2( 0, 200 ) 18 | rect_pivot_offset = Vector2( 0, 0 ) 19 | rect_clip_content = false 20 | mouse_filter = 0 21 | mouse_default_cursor_shape = 0 22 | size_flags_horizontal = 3 23 | size_flags_vertical = 3 24 | script = ExtResource( 1 ) 25 | _sections_unfolded = [ "Margin", "Rect", "Size Flags", "custom_styles" ] 26 | 27 | [node name="TopBar" type="Panel" parent="." index="0"] 28 | 29 | anchor_left = 0.0 30 | anchor_top = 0.0 31 | anchor_right = 1.0 32 | anchor_bottom = 0.0 33 | margin_bottom = 20.0 34 | rect_pivot_offset = Vector2( 0, 0 ) 35 | rect_clip_content = false 36 | mouse_filter = 0 37 | mouse_default_cursor_shape = 0 38 | size_flags_horizontal = 1 39 | size_flags_vertical = 1 40 | 41 | [node name="TopContainer" type="HBoxContainer" parent="TopBar" index="0"] 42 | 43 | anchor_left = 0.0 44 | anchor_top = 0.0 45 | anchor_right = 1.0 46 | anchor_bottom = 1.0 47 | rect_pivot_offset = Vector2( 0, 0 ) 48 | rect_clip_content = false 49 | mouse_filter = 1 50 | mouse_default_cursor_shape = 0 51 | size_flags_horizontal = 1 52 | size_flags_vertical = 1 53 | alignment = 0 54 | 55 | [node name="MenuButton" type="MenuButton" parent="TopBar/TopContainer" index="0"] 56 | 57 | anchor_left = 0.0 58 | anchor_top = 0.0 59 | anchor_right = 0.0 60 | anchor_bottom = 0.0 61 | margin_right = 37.0 62 | margin_bottom = 20.0 63 | rect_pivot_offset = Vector2( 0, 0 ) 64 | rect_clip_content = false 65 | mouse_filter = 0 66 | mouse_default_cursor_shape = 0 67 | size_flags_horizontal = 1 68 | size_flags_vertical = 1 69 | toggle_mode = false 70 | action_mode = 0 71 | enabled_focus_mode = 0 72 | shortcut = null 73 | group = null 74 | text = "Add" 75 | flat = true 76 | align = 1 77 | items = [ "Basic Dialogue", null, 0, false, false, 0, 0, null, "", false, "Conditonal", null, 0, false, false, 1, 0, null, "", false, "Choice", null, 0, false, false, 2, 0, null, "", false, "Random", null, 0, false, false, 3, 0, null, "", false ] 78 | 79 | [node name="PrimaryGraphEditor" type="GraphEdit" parent="." index="1"] 80 | 81 | anchor_left = 0.0 82 | anchor_top = 0.0 83 | anchor_right = 1.0 84 | anchor_bottom = 1.0 85 | margin_top = 21.0 86 | rect_pivot_offset = Vector2( 0, 0 ) 87 | rect_clip_content = true 88 | focus_mode = 2 89 | mouse_filter = 0 90 | mouse_default_cursor_shape = 0 91 | size_flags_horizontal = 1 92 | size_flags_vertical = 1 93 | right_disconnects = true 94 | scroll_offset = Vector2( 0, 0 ) 95 | snap_distance = 20 96 | use_snap = true 97 | zoom = 1.0 98 | 99 | [node name="EndNode" parent="PrimaryGraphEditor" index="0" instance=ExtResource( 2 )] 100 | 101 | margin_right = 55.0 102 | margin_bottom = 43.0 103 | mouse_filter = 1 104 | 105 | [node name="StartNode" parent="PrimaryGraphEditor" index="1" instance=ExtResource( 3 )] 106 | 107 | margin_right = 61.0 108 | margin_bottom = 43.0 109 | mouse_filter = 1 110 | 111 | [connection signal="connection_request" from="PrimaryGraphEditor" to="." method="_on_PrimaryGraphEditor_connection_request"] 112 | 113 | [connection signal="disconnection_request" from="PrimaryGraphEditor" to="." method="_on_PrimaryGraphEditor_disconnection_request"] 114 | 115 | 116 | -------------------------------------------------------------------------------- /addons/dialogue_tree/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="Dialogue Tree" 4 | description="A plugin for creating dialogue trees." 5 | author="EmAlexander" 6 | version="1.0" 7 | script="plugin.gd" 8 | -------------------------------------------------------------------------------- /addons/dialogue_tree/plugin.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends EditorPlugin 3 | 4 | var dock 5 | var dockButton 6 | 7 | const dialogue_script = preload("res://addons/dialogue_tree/scripts/dialogue.gd") 8 | const dialogue_resource_script = preload("res://addons/dialogue_tree/resource/dialogue_tree.gd") 9 | 10 | func _enter_tree(): 11 | dock = preload("res://addons/dialogue_tree/editor_dock.tscn").instance() 12 | 13 | dockButton = add_control_to_bottom_panel(dock, "Dialogue Tree") 14 | dockButton.hide() 15 | 16 | add_custom_type("Dialogue", "Node", dialogue_script, preload("res://addons/dialogue_tree/assets/Icon.png")) 17 | add_custom_type("DialogueResource", "Resource", dialogue_resource_script, preload("res://addons/dialogue_tree/assets/ResIcon.png")) 18 | 19 | func _exit_tree(): 20 | dock.hide() 21 | dockButton.hide() 22 | 23 | remove_control_from_bottom_panel(dock) 24 | dock.queue_free() 25 | 26 | remove_custom_type("Dialogue") 27 | remove_custom_type("DialogueResource") 28 | 29 | func make_visible(visible): 30 | dockButton.visible = visible 31 | 32 | if !visible: 33 | dock.visible = false 34 | dock.set_edit_node(null) 35 | 36 | func save_external_data(): 37 | dock.save_resource() 38 | 39 | func edit(object): 40 | if dockButton.pressed: 41 | dock.visible = true 42 | 43 | dock.set_edit_node(object) 44 | 45 | func handles(object): 46 | return object is dialogue_script -------------------------------------------------------------------------------- /addons/dialogue_tree/resource/DialougeRes.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=3 format=2] 2 | 3 | [ext_resource path="res://addons/dialogue_tree/assets/ResIcon.png" type="Texture" id=1] 4 | [ext_resource path="res://addons/dialogue_tree/resource/dialogue_tree.gd" type="Script" id=2] 5 | 6 | [resource] 7 | 8 | script = ExtResource( 2 ) 9 | __meta__ = { 10 | "_editor_icon": ExtResource( 1 ) 11 | } 12 | 13 | -------------------------------------------------------------------------------- /addons/dialogue_tree/resource/dialogue_tree.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Resource 3 | 4 | export (Array) var connections = [] 5 | export (Array) var Nodes = [] 6 | export (Dictionary) var DialogueTree = {} 7 | 8 | func _ready(): 9 | pass 10 | -------------------------------------------------------------------------------- /addons/dialogue_tree/scenes/BasicDialogue.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://addons/dialogue_tree/scripts/BasicDialogue.gd" type="Script" id=1] 4 | 5 | [node name="BasicDialogue" type="GraphNode"] 6 | 7 | anchor_left = 0.0 8 | anchor_top = 0.0 9 | anchor_right = 0.0 10 | anchor_bottom = 0.0 11 | margin_right = 139.0 12 | margin_bottom = 108.0 13 | rect_pivot_offset = Vector2( 0, 0 ) 14 | rect_clip_content = false 15 | mouse_filter = 0 16 | mouse_default_cursor_shape = 0 17 | size_flags_horizontal = 1 18 | size_flags_vertical = 1 19 | title = "Basic Dialogue" 20 | offset = Vector2( 0, 0 ) 21 | show_close = true 22 | resizable = true 23 | selected = false 24 | comment = false 25 | overlay = 0 26 | slot/0/left_enabled = true 27 | slot/0/left_type = 0 28 | slot/0/left_color = Color( 1, 1, 1, 1 ) 29 | slot/0/right_enabled = true 30 | slot/0/right_type = 0 31 | slot/0/right_color = Color( 1, 1, 1, 1 ) 32 | slot/1/left_enabled = false 33 | slot/1/left_type = 0 34 | slot/1/left_color = Color( 1, 1, 1, 1 ) 35 | slot/1/right_enabled = false 36 | slot/1/right_type = 0 37 | slot/1/right_color = Color( 1, 1, 1, 1 ) 38 | slot/2/left_enabled = false 39 | slot/2/left_type = 0 40 | slot/2/left_color = Color( 1, 1, 1, 1 ) 41 | slot/2/right_enabled = false 42 | slot/2/right_type = 0 43 | slot/2/right_color = Color( 1, 1, 1, 1 ) 44 | slot/3/left_enabled = false 45 | slot/3/left_type = 0 46 | slot/3/left_color = Color( 1, 1, 1, 1 ) 47 | slot/3/right_enabled = false 48 | slot/3/right_type = 0 49 | slot/3/right_color = Color( 1, 1, 1, 1 ) 50 | script = ExtResource( 1 ) 51 | _sections_unfolded = [ "slot", "slot/0" ] 52 | 53 | [node name="ReferenceNameEdit" type="LineEdit" parent="." index="0"] 54 | 55 | anchor_left = 0.0 56 | anchor_top = 0.0 57 | anchor_right = 0.0 58 | anchor_bottom = 0.0 59 | margin_left = 16.0 60 | margin_top = 24.0 61 | margin_right = 123.0 62 | margin_bottom = 48.0 63 | rect_pivot_offset = Vector2( 0, 0 ) 64 | rect_clip_content = false 65 | focus_mode = 2 66 | mouse_filter = 0 67 | mouse_default_cursor_shape = 1 68 | size_flags_horizontal = 1 69 | size_flags_vertical = 1 70 | focus_mode = 2 71 | context_menu_enabled = true 72 | placeholder_text = "ReferenceName" 73 | placeholder_alpha = 0.6 74 | caret_blink = false 75 | caret_blink_speed = 0.65 76 | caret_position = 0 77 | _sections_unfolded = [ "Placeholder" ] 78 | 79 | [node name="HSeparator" type="HSeparator" parent="." index="1"] 80 | 81 | anchor_left = 0.0 82 | anchor_top = 0.0 83 | anchor_right = 0.0 84 | anchor_bottom = 0.0 85 | margin_left = 16.0 86 | margin_top = 48.0 87 | margin_right = 123.0 88 | margin_bottom = 52.0 89 | rect_pivot_offset = Vector2( 0, 0 ) 90 | rect_clip_content = false 91 | mouse_filter = 0 92 | mouse_default_cursor_shape = 0 93 | size_flags_horizontal = 1 94 | size_flags_vertical = 1 95 | 96 | [node name="ActorNameEdit" type="LineEdit" parent="." index="2"] 97 | 98 | anchor_left = 0.0 99 | anchor_top = 0.0 100 | anchor_right = 0.0 101 | anchor_bottom = 0.0 102 | margin_left = 16.0 103 | margin_top = 53.0 104 | margin_right = 123.0 105 | margin_bottom = 77.0 106 | rect_pivot_offset = Vector2( 0, 0 ) 107 | rect_clip_content = false 108 | focus_mode = 2 109 | mouse_filter = 0 110 | mouse_default_cursor_shape = 1 111 | size_flags_horizontal = 1 112 | size_flags_vertical = 1 113 | focus_mode = 2 114 | context_menu_enabled = true 115 | placeholder_text = "Actor" 116 | placeholder_alpha = 0.6 117 | caret_blink = false 118 | caret_blink_speed = 0.65 119 | caret_position = 0 120 | _sections_unfolded = [ "Placeholder" ] 121 | 122 | [node name="DialogueEdit" type="LineEdit" parent="." index="3"] 123 | 124 | anchor_left = 0.0 125 | anchor_top = 0.0 126 | anchor_right = 0.0 127 | anchor_bottom = 0.0 128 | margin_left = 16.0 129 | margin_top = 78.0 130 | margin_right = 123.0 131 | margin_bottom = 102.0 132 | rect_pivot_offset = Vector2( 0, 0 ) 133 | rect_clip_content = false 134 | focus_mode = 2 135 | mouse_filter = 0 136 | mouse_default_cursor_shape = 1 137 | size_flags_horizontal = 1 138 | size_flags_vertical = 1 139 | focus_mode = 2 140 | context_menu_enabled = true 141 | placeholder_text = "Dialogue" 142 | placeholder_alpha = 0.6 143 | caret_blink = false 144 | caret_blink_speed = 0.65 145 | caret_position = 0 146 | _sections_unfolded = [ "Placeholder" ] 147 | 148 | 149 | -------------------------------------------------------------------------------- /addons/dialogue_tree/scenes/ChoiceContainer.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://addons/dialogue_tree/scripts/ChoiceContainer.gd" type="Script" id=1] 4 | 5 | [node name="ChoiceContainer" type="HBoxContainer" index="0"] 6 | 7 | anchor_left = 0.0 8 | anchor_top = 0.0 9 | anchor_right = 0.0 10 | anchor_bottom = 0.0 11 | margin_left = 16.0 12 | margin_top = 53.0 13 | margin_right = 198.0 14 | margin_bottom = 77.0 15 | rect_pivot_offset = Vector2( 0, 0 ) 16 | rect_clip_content = false 17 | mouse_filter = 1 18 | mouse_default_cursor_shape = 0 19 | size_flags_horizontal = 1 20 | size_flags_vertical = 1 21 | alignment = 0 22 | script = ExtResource( 1 ) 23 | 24 | [node name="Conditional" type="LineEdit" parent="." index="0"] 25 | 26 | anchor_left = 0.0 27 | anchor_top = 0.0 28 | anchor_right = 0.0 29 | anchor_bottom = 0.0 30 | margin_right = 58.0 31 | margin_bottom = 24.0 32 | rect_pivot_offset = Vector2( 0, 0 ) 33 | rect_clip_content = false 34 | focus_mode = 2 35 | mouse_filter = 0 36 | mouse_default_cursor_shape = 1 37 | size_flags_horizontal = 3 38 | size_flags_vertical = 3 39 | focus_mode = 2 40 | context_menu_enabled = true 41 | placeholder_text = "Conditonal" 42 | placeholder_alpha = 0.6 43 | caret_blink = false 44 | caret_blink_speed = 0.65 45 | caret_position = 0 46 | _sections_unfolded = [ "Placeholder", "Size Flags" ] 47 | 48 | [node name="ToolTip" type="LineEdit" parent="." index="1"] 49 | 50 | anchor_left = 0.0 51 | anchor_top = 0.0 52 | anchor_right = 0.0 53 | anchor_bottom = 0.0 54 | margin_left = 62.0 55 | margin_right = 120.0 56 | margin_bottom = 24.0 57 | rect_pivot_offset = Vector2( 0, 0 ) 58 | rect_clip_content = false 59 | focus_mode = 2 60 | mouse_filter = 0 61 | mouse_default_cursor_shape = 1 62 | size_flags_horizontal = 3 63 | size_flags_vertical = 3 64 | focus_mode = 2 65 | context_menu_enabled = true 66 | placeholder_text = "Tooltip" 67 | placeholder_alpha = 0.6 68 | caret_blink = false 69 | caret_blink_speed = 0.65 70 | caret_position = 0 71 | _sections_unfolded = [ "Placeholder", "Size Flags" ] 72 | 73 | [node name="Dialogue" type="LineEdit" parent="." index="2"] 74 | 75 | anchor_left = 0.0 76 | anchor_top = 0.0 77 | anchor_right = 0.0 78 | anchor_bottom = 0.0 79 | margin_left = 124.0 80 | margin_right = 182.0 81 | margin_bottom = 24.0 82 | rect_pivot_offset = Vector2( 0, 0 ) 83 | rect_clip_content = false 84 | focus_mode = 2 85 | mouse_filter = 0 86 | mouse_default_cursor_shape = 1 87 | size_flags_horizontal = 3 88 | size_flags_vertical = 3 89 | focus_mode = 2 90 | context_menu_enabled = true 91 | placeholder_text = "Dialogue" 92 | placeholder_alpha = 0.6 93 | caret_blink = false 94 | caret_blink_speed = 0.65 95 | caret_position = 0 96 | _sections_unfolded = [ "Placeholder", "Size Flags" ] 97 | 98 | 99 | -------------------------------------------------------------------------------- /addons/dialogue_tree/scenes/ChoiceDialogue.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://addons/dialogue_tree/scripts/ChoiceDialogue.gd" type="Script" id=1] 4 | 5 | [node name="ChoiceDialogue" type="GraphNode"] 6 | 7 | anchor_left = 0.0 8 | anchor_top = 0.0 9 | anchor_right = 0.0 10 | anchor_bottom = 0.0 11 | margin_right = 135.0 12 | margin_bottom = 59.0 13 | rect_pivot_offset = Vector2( 0, 0 ) 14 | rect_clip_content = false 15 | mouse_filter = 0 16 | mouse_default_cursor_shape = 0 17 | size_flags_horizontal = 1 18 | size_flags_vertical = 1 19 | title = "Choice" 20 | offset = Vector2( 0, 0 ) 21 | show_close = true 22 | resizable = true 23 | selected = false 24 | comment = false 25 | overlay = 0 26 | slot/0/left_enabled = true 27 | slot/0/left_type = 0 28 | slot/0/left_color = Color( 1, 1, 1, 1 ) 29 | slot/0/right_enabled = false 30 | slot/0/right_type = 0 31 | slot/0/right_color = Color( 1, 1, 1, 1 ) 32 | slot/1/left_enabled = false 33 | slot/1/left_type = 0 34 | slot/1/left_color = Color( 1, 1, 1, 1 ) 35 | slot/1/right_enabled = false 36 | slot/1/right_type = 0 37 | slot/1/right_color = Color( 1, 1, 1, 1 ) 38 | slot/2/left_enabled = false 39 | slot/2/left_type = 0 40 | slot/2/left_color = Color( 1, 1, 1, 1 ) 41 | slot/2/right_enabled = false 42 | slot/2/right_type = 0 43 | slot/2/right_color = Color( 1, 1, 1, 1 ) 44 | script = ExtResource( 1 ) 45 | _sections_unfolded = [ "slot", "slot/0" ] 46 | 47 | [node name="ReferenceNameEdit" type="LineEdit" parent="." index="0"] 48 | 49 | anchor_left = 0.0 50 | anchor_top = 0.0 51 | anchor_right = 0.0 52 | anchor_bottom = 0.0 53 | margin_left = 16.0 54 | margin_top = 24.0 55 | margin_right = 168.0 56 | margin_bottom = 48.0 57 | rect_pivot_offset = Vector2( 0, 0 ) 58 | rect_clip_content = false 59 | focus_mode = 2 60 | mouse_filter = 0 61 | mouse_default_cursor_shape = 1 62 | size_flags_horizontal = 1 63 | size_flags_vertical = 1 64 | focus_mode = 2 65 | context_menu_enabled = true 66 | placeholder_text = "Reference Name" 67 | placeholder_alpha = 0.6 68 | caret_blink = false 69 | caret_blink_speed = 0.65 70 | caret_position = 0 71 | _sections_unfolded = [ "Placeholder" ] 72 | 73 | [node name="EditChoices" type="HBoxContainer" parent="." index="1"] 74 | 75 | anchor_left = 0.0 76 | anchor_top = 0.0 77 | anchor_right = 0.0 78 | anchor_bottom = 0.0 79 | margin_left = 16.0 80 | margin_top = 48.0 81 | margin_right = 168.0 82 | margin_bottom = 72.0 83 | rect_pivot_offset = Vector2( 0, 0 ) 84 | rect_clip_content = false 85 | mouse_filter = 1 86 | mouse_default_cursor_shape = 0 87 | size_flags_horizontal = 1 88 | size_flags_vertical = 1 89 | alignment = 2 90 | _sections_unfolded = [ "Placeholder" ] 91 | 92 | [node name="Conditonals" type="CheckBox" parent="EditChoices" index="0"] 93 | 94 | anchor_left = 0.0 95 | anchor_top = 0.0 96 | anchor_right = 0.0 97 | anchor_bottom = 0.0 98 | margin_right = 107.0 99 | margin_bottom = 24.0 100 | rect_pivot_offset = Vector2( 0, 0 ) 101 | rect_clip_content = false 102 | focus_mode = 2 103 | mouse_filter = 0 104 | mouse_default_cursor_shape = 0 105 | size_flags_horizontal = 1 106 | size_flags_vertical = 1 107 | toggle_mode = true 108 | enabled_focus_mode = 2 109 | shortcut = null 110 | group = null 111 | text = "Conditionals" 112 | flat = false 113 | align = 0 114 | 115 | [node name="MinusButton" type="Button" parent="EditChoices" index="1"] 116 | 117 | anchor_left = 0.0 118 | anchor_top = 0.0 119 | anchor_right = 0.0 120 | anchor_bottom = 0.0 121 | margin_left = 111.0 122 | margin_right = 128.0 123 | margin_bottom = 24.0 124 | rect_pivot_offset = Vector2( 0, 0 ) 125 | rect_clip_content = false 126 | focus_mode = 2 127 | mouse_filter = 0 128 | mouse_default_cursor_shape = 0 129 | size_flags_horizontal = 1 130 | size_flags_vertical = 1 131 | toggle_mode = false 132 | enabled_focus_mode = 2 133 | shortcut = null 134 | group = null 135 | text = "-" 136 | flat = false 137 | align = 1 138 | 139 | [node name="PlusButton" type="Button" parent="EditChoices" index="2"] 140 | 141 | anchor_left = 0.0 142 | anchor_top = 0.0 143 | anchor_right = 0.0 144 | anchor_bottom = 0.0 145 | margin_left = 132.0 146 | margin_right = 152.0 147 | margin_bottom = 24.0 148 | rect_pivot_offset = Vector2( 0, 0 ) 149 | rect_clip_content = false 150 | focus_mode = 2 151 | mouse_filter = 0 152 | mouse_default_cursor_shape = 0 153 | size_flags_horizontal = 1 154 | size_flags_vertical = 1 155 | toggle_mode = false 156 | enabled_focus_mode = 2 157 | shortcut = null 158 | group = null 159 | text = "+" 160 | flat = false 161 | align = 1 162 | 163 | [node name="HSeparator" type="HSeparator" parent="." index="2"] 164 | 165 | anchor_left = 0.0 166 | anchor_top = 0.0 167 | anchor_right = 0.0 168 | anchor_bottom = 0.0 169 | margin_left = 16.0 170 | margin_top = 73.0 171 | margin_right = 168.0 172 | margin_bottom = 77.0 173 | rect_pivot_offset = Vector2( 0, 0 ) 174 | rect_clip_content = false 175 | mouse_filter = 0 176 | mouse_default_cursor_shape = 0 177 | size_flags_horizontal = 1 178 | size_flags_vertical = 1 179 | 180 | [connection signal="toggled" from="EditChoices/Conditonals" to="." method="_on_Conditonals_toggled"] 181 | 182 | [connection signal="pressed" from="EditChoices/MinusButton" to="." method="_on_MinusButton_pressed"] 183 | 184 | [connection signal="pressed" from="EditChoices/PlusButton" to="." method="_on_PlusButton_pressed"] 185 | 186 | 187 | -------------------------------------------------------------------------------- /addons/dialogue_tree/scenes/ConditonalDialogue.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://addons/dialogue_tree/scripts/ConditonalDialogue.gd" type="Script" id=1] 4 | 5 | [node name="ConditonalDialogue" type="GraphNode"] 6 | 7 | anchor_left = 0.0 8 | anchor_top = 0.0 9 | anchor_right = 0.0 10 | anchor_bottom = 0.0 11 | margin_right = 177.0 12 | margin_bottom = 98.0 13 | rect_pivot_offset = Vector2( 0, 0 ) 14 | rect_clip_content = false 15 | mouse_filter = 0 16 | mouse_default_cursor_shape = 0 17 | size_flags_horizontal = 1 18 | size_flags_vertical = 1 19 | title = "Condtional" 20 | offset = Vector2( 0, 0 ) 21 | show_close = true 22 | resizable = true 23 | selected = false 24 | comment = false 25 | overlay = 0 26 | slot/0/left_enabled = true 27 | slot/0/left_type = 0 28 | slot/0/left_color = Color( 1, 1, 1, 1 ) 29 | slot/0/right_enabled = false 30 | slot/0/right_type = 0 31 | slot/0/right_color = Color( 1, 1, 1, 1 ) 32 | slot/1/left_enabled = false 33 | slot/1/left_type = 0 34 | slot/1/left_color = Color( 1, 1, 1, 1 ) 35 | slot/1/right_enabled = false 36 | slot/1/right_type = 0 37 | slot/1/right_color = Color( 1, 1, 1, 1 ) 38 | slot/2/left_enabled = false 39 | slot/2/left_type = 0 40 | slot/2/left_color = Color( 1, 1, 1, 1 ) 41 | slot/2/right_enabled = true 42 | slot/2/right_type = 0 43 | slot/2/right_color = Color( 1, 1, 1, 1 ) 44 | slot/3/left_enabled = false 45 | slot/3/left_type = 0 46 | slot/3/left_color = Color( 1, 1, 1, 1 ) 47 | slot/3/right_enabled = true 48 | slot/3/right_type = 0 49 | slot/3/right_color = Color( 1, 1, 1, 1 ) 50 | script = ExtResource( 1 ) 51 | _sections_unfolded = [ "slot", "slot/0", "slot/2", "slot/3" ] 52 | 53 | [node name="ReferenceNameEdit" type="LineEdit" parent="." index="0"] 54 | 55 | anchor_left = 0.0 56 | anchor_top = 0.0 57 | anchor_right = 0.0 58 | anchor_bottom = 0.0 59 | margin_left = 16.0 60 | margin_top = 24.0 61 | margin_right = 161.0 62 | margin_bottom = 48.0 63 | rect_pivot_offset = Vector2( 0, 0 ) 64 | rect_clip_content = false 65 | focus_mode = 2 66 | mouse_filter = 0 67 | mouse_default_cursor_shape = 1 68 | size_flags_horizontal = 1 69 | size_flags_vertical = 1 70 | focus_mode = 2 71 | context_menu_enabled = true 72 | placeholder_text = "ReferenceName" 73 | placeholder_alpha = 0.6 74 | caret_blink = false 75 | caret_blink_speed = 0.65 76 | caret_position = 0 77 | _sections_unfolded = [ "Caret", "Placeholder" ] 78 | 79 | [node name="HSeparator" type="HSeparator" parent="." index="1"] 80 | 81 | anchor_left = 0.0 82 | anchor_top = 0.0 83 | anchor_right = 0.0 84 | anchor_bottom = 0.0 85 | margin_left = 16.0 86 | margin_top = 48.0 87 | margin_right = 161.0 88 | margin_bottom = 52.0 89 | rect_pivot_offset = Vector2( 0, 0 ) 90 | rect_clip_content = false 91 | mouse_filter = 0 92 | mouse_default_cursor_shape = 0 93 | size_flags_horizontal = 1 94 | size_flags_vertical = 1 95 | 96 | [node name="Conditional" type="LineEdit" parent="." index="2"] 97 | 98 | anchor_left = 0.0 99 | anchor_top = 0.0 100 | anchor_right = 0.0 101 | anchor_bottom = 0.0 102 | margin_left = 16.0 103 | margin_top = 53.0 104 | margin_right = 161.0 105 | margin_bottom = 77.0 106 | rect_pivot_offset = Vector2( 0, 0 ) 107 | rect_clip_content = false 108 | focus_mode = 2 109 | mouse_filter = 0 110 | mouse_default_cursor_shape = 1 111 | size_flags_horizontal = 1 112 | size_flags_vertical = 1 113 | focus_mode = 2 114 | context_menu_enabled = true 115 | placeholder_text = "Condition" 116 | placeholder_alpha = 0.6 117 | caret_blink = false 118 | caret_blink_speed = 0.65 119 | caret_position = 0 120 | _sections_unfolded = [ "Placeholder" ] 121 | 122 | [node name="TrueLabel" type="Label" parent="Conditional" index="2"] 123 | 124 | anchor_left = 0.0 125 | anchor_top = 0.0 126 | anchor_right = 1.0 127 | anchor_bottom = 1.0 128 | rect_pivot_offset = Vector2( 0, 0 ) 129 | rect_clip_content = false 130 | mouse_filter = 2 131 | mouse_default_cursor_shape = 0 132 | size_flags_horizontal = 1 133 | size_flags_vertical = 4 134 | text = "True" 135 | align = 2 136 | valign = 1 137 | percent_visible = 1.0 138 | lines_skipped = 0 139 | max_lines_visible = -1 140 | 141 | [node name="FalseLabel" type="Label" parent="." index="3"] 142 | 143 | anchor_left = 0.0 144 | anchor_top = 0.0 145 | anchor_right = 0.0 146 | anchor_bottom = 0.0 147 | margin_left = 16.0 148 | margin_top = 78.0 149 | margin_right = 161.0 150 | margin_bottom = 92.0 151 | rect_pivot_offset = Vector2( 0, 0 ) 152 | rect_clip_content = false 153 | mouse_filter = 2 154 | mouse_default_cursor_shape = 0 155 | size_flags_horizontal = 1 156 | size_flags_vertical = 4 157 | text = "False" 158 | align = 2 159 | valign = 1 160 | percent_visible = 1.0 161 | lines_skipped = 0 162 | max_lines_visible = -1 163 | 164 | 165 | -------------------------------------------------------------------------------- /addons/dialogue_tree/scenes/EndNode.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://addons/dialogue_tree/scripts/EndNode.gd" type="Script" id=1] 4 | 5 | [node name="EndNode" type="GraphNode" index="0"] 6 | 7 | anchor_left = 0.0 8 | anchor_top = 0.0 9 | anchor_right = 0.0 10 | anchor_bottom = 0.0 11 | margin_right = 32.0 12 | margin_bottom = 29.0 13 | rect_pivot_offset = Vector2( 0, 0 ) 14 | rect_clip_content = false 15 | mouse_filter = 0 16 | mouse_default_cursor_shape = 0 17 | size_flags_horizontal = 1 18 | size_flags_vertical = 1 19 | title = "End" 20 | offset = Vector2( 0, 0 ) 21 | show_close = false 22 | resizable = false 23 | selected = false 24 | comment = false 25 | overlay = 0 26 | slot/0/left_enabled = true 27 | slot/0/left_type = 0 28 | slot/0/left_color = Color( 1, 1, 1, 1 ) 29 | slot/0/right_enabled = false 30 | slot/0/right_type = 0 31 | slot/0/right_color = Color( 1, 1, 1, 1 ) 32 | script = ExtResource( 1 ) 33 | _sections_unfolded = [ "slot", "slot/0" ] 34 | 35 | [node name="Label" type="Label" parent="." index="0"] 36 | 37 | anchor_left = 0.0 38 | anchor_top = 0.0 39 | anchor_right = 0.0 40 | anchor_bottom = 0.0 41 | margin_left = 16.0 42 | margin_top = 24.0 43 | margin_right = 39.0 44 | margin_bottom = 38.0 45 | rect_pivot_offset = Vector2( 0, 0 ) 46 | rect_clip_content = false 47 | mouse_filter = 2 48 | mouse_default_cursor_shape = 0 49 | size_flags_horizontal = 1 50 | size_flags_vertical = 4 51 | percent_visible = 1.0 52 | lines_skipped = 0 53 | max_lines_visible = -1 54 | 55 | 56 | -------------------------------------------------------------------------------- /addons/dialogue_tree/scenes/RandomChoiceContainer.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://addons/dialogue_tree/scripts/RandomChoiceContainer.gd" type="Script" id=1] 4 | 5 | [node name="RandomChoiceContainer" type="HBoxContainer"] 6 | 7 | anchor_left = 0.0 8 | anchor_top = 0.0 9 | anchor_right = 0.0 10 | anchor_bottom = 0.0 11 | margin_left = 16.0 12 | margin_top = 78.0 13 | margin_right = 161.0 14 | margin_bottom = 102.0 15 | rect_min_size = Vector2( 145, 24 ) 16 | rect_pivot_offset = Vector2( 0, 0 ) 17 | rect_clip_content = false 18 | mouse_filter = 1 19 | mouse_default_cursor_shape = 0 20 | size_flags_horizontal = 1 21 | size_flags_vertical = 1 22 | alignment = 0 23 | script = ExtResource( 1 ) 24 | _sections_unfolded = [ "Rect" ] 25 | 26 | [node name="Conditonal" type="LineEdit" parent="." index="0"] 27 | 28 | anchor_left = 0.0 29 | anchor_top = 0.0 30 | anchor_right = 0.0 31 | anchor_bottom = 0.0 32 | margin_right = 145.0 33 | margin_bottom = 24.0 34 | rect_pivot_offset = Vector2( 0, 0 ) 35 | rect_clip_content = false 36 | focus_mode = 2 37 | mouse_filter = 0 38 | mouse_default_cursor_shape = 1 39 | size_flags_horizontal = 3 40 | size_flags_vertical = 3 41 | focus_mode = 2 42 | context_menu_enabled = true 43 | placeholder_alpha = 0.6 44 | caret_blink = false 45 | caret_blink_speed = 0.65 46 | caret_position = 0 47 | _sections_unfolded = [ "Rect", "Size Flags" ] 48 | 49 | 50 | -------------------------------------------------------------------------------- /addons/dialogue_tree/scenes/RandomDialogue.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://addons/dialogue_tree/scripts/RandomDialogue.gd" type="Script" id=1] 4 | 5 | [node name="RandomDialogue" type="GraphNode"] 6 | 7 | anchor_left = 0.0 8 | anchor_top = 0.0 9 | anchor_right = 0.0 10 | anchor_bottom = 0.0 11 | margin_right = 154.0 12 | margin_bottom = 80.0 13 | rect_pivot_offset = Vector2( 0, 0 ) 14 | rect_clip_content = false 15 | mouse_filter = 0 16 | mouse_default_cursor_shape = 0 17 | size_flags_horizontal = 1 18 | size_flags_vertical = 1 19 | title = "Random" 20 | offset = Vector2( 0, 0 ) 21 | show_close = true 22 | resizable = true 23 | selected = false 24 | comment = false 25 | overlay = 0 26 | slot/0/left_enabled = true 27 | slot/0/left_type = 0 28 | slot/0/left_color = Color( 1, 1, 1, 1 ) 29 | slot/0/right_enabled = false 30 | slot/0/right_type = 0 31 | slot/0/right_color = Color( 1, 1, 1, 1 ) 32 | slot/1/left_enabled = false 33 | slot/1/left_type = 0 34 | slot/1/left_color = Color( 1, 1, 1, 1 ) 35 | slot/1/right_enabled = false 36 | slot/1/right_type = 0 37 | slot/1/right_color = Color( 1, 1, 1, 1 ) 38 | slot/2/left_enabled = false 39 | slot/2/left_type = 0 40 | slot/2/left_color = Color( 1, 1, 1, 1 ) 41 | slot/2/right_enabled = false 42 | slot/2/right_type = 0 43 | slot/2/right_color = Color( 1, 1, 1, 1 ) 44 | script = ExtResource( 1 ) 45 | _sections_unfolded = [ "slot", "slot/0" ] 46 | 47 | [node name="ReferenceNameEdit" type="LineEdit" parent="." index="0"] 48 | 49 | anchor_left = 0.0 50 | anchor_top = 0.0 51 | anchor_right = 0.0 52 | anchor_bottom = 0.0 53 | margin_left = 16.0 54 | margin_top = 24.0 55 | margin_right = 161.0 56 | margin_bottom = 48.0 57 | rect_pivot_offset = Vector2( 0, 0 ) 58 | rect_clip_content = false 59 | focus_mode = 2 60 | mouse_filter = 0 61 | mouse_default_cursor_shape = 1 62 | size_flags_horizontal = 1 63 | size_flags_vertical = 1 64 | focus_mode = 2 65 | context_menu_enabled = true 66 | placeholder_text = "ReferenceName" 67 | placeholder_alpha = 0.6 68 | caret_blink = false 69 | caret_blink_speed = 0.65 70 | caret_position = 0 71 | _sections_unfolded = [ "Placeholder" ] 72 | 73 | [node name="EditBox" type="HBoxContainer" parent="." index="1"] 74 | 75 | anchor_left = 0.0 76 | anchor_top = 0.0 77 | anchor_right = 0.0 78 | anchor_bottom = 0.0 79 | margin_left = 16.0 80 | margin_top = 48.0 81 | margin_right = 161.0 82 | margin_bottom = 72.0 83 | rect_pivot_offset = Vector2( 0, 0 ) 84 | rect_clip_content = false 85 | mouse_filter = 1 86 | mouse_default_cursor_shape = 0 87 | size_flags_horizontal = 1 88 | size_flags_vertical = 1 89 | alignment = 2 90 | 91 | [node name="Conditonals" type="CheckBox" parent="EditBox" index="0"] 92 | 93 | anchor_left = 0.0 94 | anchor_top = 0.0 95 | anchor_right = 0.0 96 | anchor_bottom = 0.0 97 | margin_right = 100.0 98 | margin_bottom = 24.0 99 | rect_pivot_offset = Vector2( 0, 0 ) 100 | rect_clip_content = false 101 | focus_mode = 2 102 | mouse_filter = 0 103 | mouse_default_cursor_shape = 0 104 | size_flags_horizontal = 1 105 | size_flags_vertical = 1 106 | toggle_mode = true 107 | enabled_focus_mode = 2 108 | shortcut = null 109 | group = null 110 | text = "Conditional" 111 | flat = false 112 | align = 0 113 | 114 | [node name="MinusButton" type="Button" parent="EditBox" index="1"] 115 | 116 | anchor_left = 0.0 117 | anchor_top = 0.0 118 | anchor_right = 0.0 119 | anchor_bottom = 0.0 120 | margin_left = 104.0 121 | margin_right = 121.0 122 | margin_bottom = 24.0 123 | rect_pivot_offset = Vector2( 0, 0 ) 124 | rect_clip_content = false 125 | focus_mode = 2 126 | mouse_filter = 0 127 | mouse_default_cursor_shape = 0 128 | size_flags_horizontal = 1 129 | size_flags_vertical = 1 130 | toggle_mode = false 131 | enabled_focus_mode = 2 132 | shortcut = null 133 | group = null 134 | text = "-" 135 | flat = false 136 | align = 1 137 | 138 | [node name="PlusButton" type="Button" parent="EditBox" index="2"] 139 | 140 | anchor_left = 0.0 141 | anchor_top = 0.0 142 | anchor_right = 0.0 143 | anchor_bottom = 0.0 144 | margin_left = 125.0 145 | margin_right = 145.0 146 | margin_bottom = 24.0 147 | rect_pivot_offset = Vector2( 0, 0 ) 148 | rect_clip_content = false 149 | focus_mode = 2 150 | mouse_filter = 0 151 | mouse_default_cursor_shape = 0 152 | size_flags_horizontal = 1 153 | size_flags_vertical = 1 154 | toggle_mode = false 155 | enabled_focus_mode = 2 156 | shortcut = null 157 | group = null 158 | text = "+" 159 | flat = false 160 | align = 1 161 | 162 | [node name="HSeparator" type="HSeparator" parent="." index="2"] 163 | 164 | anchor_left = 0.0 165 | anchor_top = 0.0 166 | anchor_right = 0.0 167 | anchor_bottom = 0.0 168 | margin_left = 16.0 169 | margin_top = 73.0 170 | margin_right = 161.0 171 | margin_bottom = 77.0 172 | rect_pivot_offset = Vector2( 0, 0 ) 173 | rect_clip_content = false 174 | mouse_filter = 0 175 | mouse_default_cursor_shape = 0 176 | size_flags_horizontal = 1 177 | size_flags_vertical = 1 178 | 179 | [connection signal="toggled" from="EditBox/Conditonals" to="." method="_on_Conditonals_toggled"] 180 | 181 | [connection signal="pressed" from="EditBox/MinusButton" to="." method="_on_MinusButton_pressed"] 182 | 183 | [connection signal="pressed" from="EditBox/PlusButton" to="." method="_on_PlusButton_pressed"] 184 | 185 | 186 | -------------------------------------------------------------------------------- /addons/dialogue_tree/scenes/StartNode.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://addons/dialogue_tree/scripts/StartNode.gd" type="Script" id=1] 4 | 5 | [node name="StartNode" type="GraphNode" index="0"] 6 | 7 | anchor_left = 0.0 8 | anchor_top = 0.0 9 | anchor_right = 0.0 10 | anchor_bottom = 0.0 11 | margin_right = 32.0 12 | margin_bottom = 29.0 13 | rect_pivot_offset = Vector2( 0, 0 ) 14 | rect_clip_content = false 15 | mouse_filter = 0 16 | mouse_default_cursor_shape = 0 17 | size_flags_horizontal = 1 18 | size_flags_vertical = 1 19 | title = "Start" 20 | offset = Vector2( 0, 0 ) 21 | show_close = false 22 | resizable = false 23 | selected = false 24 | comment = false 25 | overlay = 0 26 | slot/0/left_enabled = false 27 | slot/0/left_type = 0 28 | slot/0/left_color = Color( 1, 1, 1, 1 ) 29 | slot/0/right_enabled = true 30 | slot/0/right_type = 0 31 | slot/0/right_color = Color( 1, 1, 1, 1 ) 32 | script = ExtResource( 1 ) 33 | _sections_unfolded = [ "slot", "slot/0" ] 34 | 35 | [node name="Label" type="Label" parent="." index="0"] 36 | 37 | anchor_left = 0.0 38 | anchor_top = 0.0 39 | anchor_right = 0.0 40 | anchor_bottom = 0.0 41 | margin_left = 16.0 42 | margin_top = 24.0 43 | margin_right = 45.0 44 | margin_bottom = 38.0 45 | rect_pivot_offset = Vector2( 0, 0 ) 46 | rect_clip_content = false 47 | mouse_filter = 2 48 | mouse_default_cursor_shape = 0 49 | size_flags_horizontal = 1 50 | size_flags_vertical = 4 51 | percent_visible = 1.0 52 | lines_skipped = 0 53 | max_lines_visible = -1 54 | 55 | 56 | -------------------------------------------------------------------------------- /addons/dialogue_tree/scripts/BasicDialogue.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends GraphNode 3 | 4 | func _ready(): 5 | pass 6 | 7 | # used to save node data 8 | func save_data(): 9 | var dict = { 10 | "filename" : get_filename(), 11 | "name" : name, 12 | "rect_x" : rect_position.x, 13 | "rect_y" : rect_position.y, 14 | "rect_size_x" : rect_size.x, 15 | "rect_size_y" : rect_size.y, 16 | "Actor" : $ActorNameEdit.text, 17 | "Dialogue" : $DialogueEdit.text, 18 | "RefName" : $ReferenceNameEdit.text 19 | } 20 | 21 | return dict 22 | 23 | # used to export node data 24 | func export_values(): 25 | var dict = { 26 | "NodeName" : name, 27 | "Ref" : $ReferenceNameEdit.text, 28 | "Dialogue" : $DialogueEdit.text, 29 | "Actor" : $ActorNameEdit.text 30 | } 31 | 32 | return dict 33 | 34 | # used to make connections in export 35 | func make_connection(connection, dict, isEnd = false): 36 | var fromIndex = find_with_name(dict.dialogue, connection.from) 37 | var toIndex = find_with_name(dict.dialogue, connection.to) 38 | 39 | if isEnd: 40 | dict.dialogue[fromIndex]["next"] = "End" 41 | else: 42 | if fromIndex != -1 and toIndex != -1: 43 | dict.dialogue[fromIndex]["next"] = toIndex 44 | 45 | return dict 46 | 47 | # used to load node data 48 | func load_data(dict): 49 | $ActorNameEdit.text = dict.Actor 50 | $DialogueEdit.text = dict.Dialogue 51 | $ReferenceNameEdit.text = dict.RefName 52 | 53 | # used to find the index of an exported node with a name value 54 | func find_with_name(inArray, inName): 55 | for i in range(0, inArray.size()): 56 | if inArray[i].NodeName == inName: 57 | return i 58 | 59 | return -1 -------------------------------------------------------------------------------- /addons/dialogue_tree/scripts/ChoiceContainer.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends HBoxContainer 3 | 4 | func _ready(): 5 | # Called when the node is added to the scene for the first time. 6 | # Initialization here 7 | pass 8 | 9 | func set_conditonals(newConditonals): 10 | $Conditional.visible = newConditonals 11 | $ToolTip.visible = newConditonals 12 | 13 | 14 | func save_data(): 15 | var dict = { 16 | "Conditional" : $Conditional.text, 17 | "ToolTip" : $ToolTip.text, 18 | "Dialogue" : $Dialogue.text, 19 | } 20 | 21 | return dict 22 | 23 | func export_values(): 24 | var dict = { 25 | "Conditional" : $Conditional.text, 26 | "ToolTip" : $ToolTip.text, 27 | "Dialogue" : $Dialogue.text, 28 | "PassCondition" : true 29 | } 30 | 31 | return dict 32 | 33 | func load_data(dict): 34 | $Conditional.text = dict.Conditional 35 | $ToolTip.text = dict.ToolTip 36 | $Dialogue.text = dict.Dialogue -------------------------------------------------------------------------------- /addons/dialogue_tree/scripts/ChoiceDialogue.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends GraphNode 3 | 4 | signal removed (id) 5 | 6 | const choiceContainer = preload("res://addons/dialogue_tree/scripts/ChoiceContainer.gd") 7 | 8 | func _ready(): 9 | pass 10 | 11 | # used for saving node data 12 | func save_data(): 13 | var dict = { 14 | "filename" : get_filename(), 15 | "name" : name, 16 | "rect_x" : rect_position.x, 17 | "rect_y" : rect_position.y, 18 | "rect_size_x" : rect_size.x, 19 | "rect_size_y" : rect_size.y, 20 | "Conditonal" : $EditChoices/Conditonals.pressed, 21 | "RefName" : $ReferenceNameEdit.text, 22 | "choices" : [] 23 | } 24 | 25 | for i in get_children(): 26 | if i is choiceContainer: 27 | dict.choices.append(i.save_data()) 28 | 29 | return dict 30 | 31 | # used for exporting node data 32 | func export_values(): 33 | var dict = { 34 | "NodeName" : name, 35 | "Ref" : $ReferenceNameEdit.text, 36 | "Conditonal" : $EditChoices/Conditonals.pressed, 37 | "Choices" : [] 38 | } 39 | 40 | for i in get_children(): 41 | if i is choiceContainer: 42 | dict.Choices.append(i.export_values()) 43 | 44 | return dict 45 | 46 | # used as offloading the connection processing to the node itself in export 47 | func make_connection(connection, dict, isEnd = false): 48 | var fromIndex = find_with_name(dict.dialogue, connection.from) 49 | var toIndex = find_with_name(dict.dialogue, connection.to) 50 | 51 | if isEnd: 52 | dict.dialogue[fromIndex]["Choices"][connection.from_port]["next"] = "End" 53 | else: 54 | if fromIndex != -1 and toIndex != -1: 55 | dict.dialogue[fromIndex]["Choices"][connection.from_port]["next"] = toIndex 56 | 57 | return dict 58 | 59 | # used to load node data 60 | func load_data(dict): 61 | $EditChoices/Conditonals.pressed = dict.Conditonal 62 | $ReferenceNameEdit.text = dict.RefName 63 | var choiceContainerPacked = load("res://addons/dialogue_tree/scenes/ChoiceContainer.tscn") 64 | for i in dict.choices: 65 | var newChoice = choiceContainerPacked.instance() 66 | newChoice.load_data(i) 67 | add_child(newChoice) 68 | set_slot(get_child_count() - 1, false, 0, Color(1, 1, 1), true, 0, Color(1, 1, 1)) 69 | if newChoice.has_method("set_conditonals"): 70 | newChoice.set_conditonals($EditChoices/Conditonals.pressed) 71 | 72 | func _on_PlusButton_pressed(): 73 | var newChoice = load("res://addons/dialogue_tree/scenes/ChoiceContainer.tscn").instance() 74 | add_child(newChoice) 75 | set_slot(get_child_count() - 1, false, 0, Color(1, 1, 1), true, 0, Color(1, 1, 1)) 76 | if newChoice.has_method("set_conditonals"): 77 | newChoice.set_conditonals($EditChoices/Conditonals.pressed) 78 | 79 | func _on_MinusButton_pressed(): 80 | var child = get_child(get_child_count() - 1) 81 | if child is HBoxContainer: 82 | emit_signal("removed", get_child_count() - 4) 83 | clear_slot(get_child_count() - 1) 84 | child.queue_free() 85 | 86 | func _on_Conditonals_toggled(button_pressed): 87 | for i in get_children(): 88 | if i.has_method("set_conditonals"): 89 | i.set_conditonals(button_pressed) 90 | 91 | # used to find the index of an exported node with a name value 92 | func find_with_name(inArray, inName): 93 | for i in range(0, inArray.size()): 94 | if inArray[i].NodeName == inName: 95 | return i 96 | 97 | return -1 -------------------------------------------------------------------------------- /addons/dialogue_tree/scripts/ConditonalDialogue.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends GraphNode 3 | 4 | func _ready(): 5 | # Called when the node is added to the scene for the first time. 6 | # Initialization here 7 | pass 8 | 9 | # used to save node data 10 | func save_data(): 11 | var dict = { 12 | "filename" : get_filename(), 13 | "name" : name, 14 | "rect_x" : rect_position.x, 15 | "rect_y" : rect_position.y, 16 | "rect_size_x" : rect_size.x, 17 | "rect_size_y" : rect_size.y, 18 | "conditonal" : $Conditional.text 19 | } 20 | 21 | return dict 22 | 23 | # used to export node data 24 | func export_values(): 25 | var dict = { 26 | "NodeName" : name, 27 | "Ref" : $ReferenceNameEdit.text, 28 | "Condition" : $Conditional.text 29 | } 30 | 31 | return dict 32 | 33 | # used to make connections in export 34 | func make_connection(connection, dict, isEnd = false): 35 | var convertNext = ["next", "failnext"] 36 | 37 | var fromIndex = find_with_name(dict.dialogue, connection.from) 38 | var toIndex = find_with_name(dict.dialogue, connection.to) 39 | 40 | if isEnd: 41 | dict.dialogue[fromIndex][str(convertNext[connection.from_port])] = "End" 42 | else: 43 | if fromIndex != -1 and toIndex != -1: 44 | dict.dialogue[fromIndex][str(convertNext[connection.from_port])] = toIndex 45 | 46 | if !dict.dialogue[fromIndex].has("failnext"): 47 | dict.dialogue[fromIndex]["failnext"] = "End" 48 | 49 | if !dict.dialogue[fromIndex].has("next"): 50 | dict.dialogue[fromIndex]["next"] = "End" 51 | 52 | return dict 53 | 54 | # used to load node data 55 | func load_data(dict): 56 | $Conditional.text = dict.conditonal 57 | 58 | # used to find the index of an exported node with a name value 59 | func find_with_name(inArray, inName): 60 | for i in range(0, inArray.size()): 61 | if inArray[i].NodeName == inName: 62 | return i 63 | 64 | return -1 -------------------------------------------------------------------------------- /addons/dialogue_tree/scripts/EndNode.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends GraphNode 3 | 4 | 5 | func _ready(): 6 | pass 7 | 8 | func save_data(): 9 | var dict = { 10 | "filename" : get_filename(), 11 | "name" : name, 12 | "rect_x" : rect_position.x, 13 | "rect_y" : rect_position.y, 14 | "rect_size_x" : rect_size.x, 15 | "rect_size_y" : rect_size.y 16 | } 17 | 18 | return dict 19 | 20 | func load_data(dict): 21 | pass -------------------------------------------------------------------------------- /addons/dialogue_tree/scripts/RandomChoiceContainer.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends HBoxContainer 3 | 4 | func _ready(): 5 | pass 6 | 7 | func set_conditonals(newConditonals): 8 | $Conditonal.visible = newConditonals 9 | 10 | func save_data(): 11 | var dict = { 12 | "Conditional" : $Conditonal.text 13 | } 14 | 15 | return dict 16 | 17 | func export_values(): 18 | var dict = { 19 | "Conditional" : $Conditonal.text, 20 | "PassCondition" : true 21 | } 22 | 23 | return dict 24 | 25 | func load_data(dict): 26 | $Conditonal.text = dict.Conditional -------------------------------------------------------------------------------- /addons/dialogue_tree/scripts/RandomDialogue.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends GraphNode 3 | 4 | const ChoiceConatainerScript = preload("res://addons/dialogue_tree/scripts/RandomChoiceContainer.gd") 5 | 6 | signal removed (id) 7 | 8 | func _ready(): 9 | pass 10 | 11 | # used to save node data 12 | func save_data(): 13 | var dict = { 14 | "filename" : get_filename(), 15 | "name" : name, 16 | "rect_x" : rect_position.x, 17 | "rect_y" : rect_position.y, 18 | "rect_size_x" : rect_size.x, 19 | "rect_size_y" : rect_size.y, 20 | "conditonal" : $EditBox/Conditonals.pressed, 21 | "RefName" : $ReferenceNameEdit.text, 22 | "choices" : [] 23 | } 24 | 25 | for i in get_children(): 26 | if i is ChoiceConatainerScript: 27 | dict.choices.append(i.save_data()) 28 | 29 | return dict 30 | 31 | # used to export node data 32 | func export_values(): 33 | var dict = { 34 | "NodeName" : name, 35 | "Ref" : $ReferenceNameEdit.text, 36 | "Conditonal" : $EditBox/Conditonals.pressed, 37 | "RandomChoices" : [] 38 | } 39 | 40 | for i in get_children(): 41 | if i is ChoiceConatainerScript: 42 | dict.RandomChoices.append(i.export_values()) 43 | 44 | return dict 45 | 46 | # used to make connections in export 47 | func make_connection(connection, dict, isEnd = false): 48 | var fromIndex = find_with_name(dict.dialogue, connection.from) 49 | var toIndex = find_with_name(dict.dialogue, connection.to) 50 | 51 | if isEnd: 52 | dict.dialogue[fromIndex]["RandomChoices"][connection.from_port]["next"] = "End" 53 | else: 54 | if fromIndex != -1 and toIndex != -1: 55 | dict.dialogue[fromIndex]["RandomChoices"][connection.from_port]["next"] = toIndex 56 | 57 | return dict 58 | 59 | # used to load node data 60 | func load_data(dict): 61 | $EditBox/Conditonals.pressed = dict.conditonal 62 | $ReferenceNameEdit.text = dict.RefName 63 | 64 | var choiceContainerPacked = load("res://addons/dialogue_tree/scenes/RandomChoiceContainer.tscn") 65 | for i in dict.choices: 66 | var newChoice = choiceContainerPacked.instance() 67 | newChoice.load_data(i) 68 | add_child(newChoice) 69 | set_slot(get_child_count() - 1, false, 0, Color(1, 1, 1), true, 0, Color(1, 1, 1)) 70 | if newChoice.has_method("set_conditonals"): 71 | newChoice.set_conditonals($EditBox/Conditonals.pressed) 72 | 73 | # used to find the index of an exported node with a name value 74 | func find_with_name(inArray, inName): 75 | for i in range(0, inArray.size()): 76 | if inArray[i].NodeName == inName: 77 | return i 78 | 79 | return -1 80 | 81 | 82 | func _on_MinusButton_pressed(): 83 | var child = get_child(get_child_count() - 1) 84 | if child is ChoiceConatainerScript: 85 | emit_signal("removed", get_child_count() - 4) 86 | clear_slot(get_child_count() - 1) 87 | child.queue_free() 88 | 89 | func _on_PlusButton_pressed(): 90 | var newContainer = load("res://addons/dialogue_tree/scenes/RandomChoiceContainer.tscn").instance() 91 | add_child(newContainer) 92 | set_slot(get_child_count() - 1, false, 0, Color(1, 1, 1), true, 0, Color(1, 1, 1)) 93 | if newContainer.has_method("set_conditonals"): 94 | newContainer.set_conditonals($EditBox/Conditonals.pressed) 95 | 96 | func _on_Conditonals_toggled(button_pressed): 97 | for i in get_children(): 98 | if i.has_method("set_conditonals"): 99 | i.set_conditonals(button_pressed) 100 | -------------------------------------------------------------------------------- /addons/dialogue_tree/scripts/StartNode.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends GraphNode 3 | 4 | func _ready(): 5 | pass 6 | 7 | func save_data(): 8 | var dict = { 9 | "filename" : get_filename(), 10 | "name" : name, 11 | "rect_x" : rect_position.x, 12 | "rect_y" : rect_position.y, 13 | "rect_size_x" : rect_size.x, 14 | "rect_size_y" : rect_size.y 15 | } 16 | 17 | return dict 18 | 19 | func load_data(dict): 20 | pass -------------------------------------------------------------------------------- /addons/dialogue_tree/scripts/dialogue.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | signal Dialogue_Next (ref, actor, text) 4 | signal Choice_Next (ref, choices) 5 | signal Conditonal_Data_Needed 6 | signal Dialogue_Started 7 | signal Dialogue_Ended 8 | 9 | export (Resource) var DialogueResource = null 10 | export (bool) var RandomizeBeforeRandom = false 11 | 12 | var current_index = 0 13 | var in_dialogue = false 14 | 15 | var conditonalData = {} 16 | var queued_for_conditonal = false 17 | var current_node = {} 18 | 19 | func _ready(): 20 | pass 21 | 22 | # used to start dialogue 23 | func start_dialogue(start_at = -1): 24 | if DialogueResource != null and DialogueResource.DialogueTree != {}: 25 | # start at first node if no start_at is provided 26 | emit_signal("Dialogue_Started") 27 | in_dialogue = true 28 | var tempIndex = 0 29 | 30 | var nodeDict 31 | if start_at == -1: 32 | nodeDict = DialogueResource.DialogueTree.dialogue[DialogueResource.DialogueTree.start_index] 33 | tempIndex = DialogueResource.DialogueTree.start_index 34 | else: 35 | nodeDict = DialogueResource.DialogueTree.dialogue[start_at] 36 | tempIndex = start_at 37 | 38 | _process_next(nodeDict, tempIndex) 39 | 40 | # used to switch to next dialogue 41 | func next_dialogue(choice = -1, conditon = -1): 42 | if in_dialogue: 43 | # get the current dialogue 44 | var currentDialogue = DialogueResource.DialogueTree.dialogue[current_index] 45 | # the next dialogue 46 | var nextDialogueIndex 47 | # assume choice not taken 48 | # for safety reasons, assume a node without a connection connects to end 49 | if choice == -1: 50 | if int(conditon) == -1: 51 | if currentDialogue.has("next"): 52 | nextDialogueIndex = currentDialogue.next 53 | else: 54 | end_dialogue() 55 | return 56 | else: 57 | var convertNext = ["failnext", "next"] 58 | var nextStr = str(convertNext[int(conditon)]) 59 | if current_node.has(nextStr): 60 | nextDialogueIndex = current_node[nextStr] 61 | else: 62 | if currentDialogue.has("Choices"): 63 | if currentDialogue.Choices[choice].has("next"): 64 | nextDialogueIndex = currentDialogue.Choices[choice].next 65 | else: 66 | end_dialogue() 67 | return 68 | elif currentDialogue.has("RandomChoices"): 69 | if currentDialogue.RandomChoices[choice].has("next"): 70 | nextDialogueIndex = currentDialogue.RandomChoices[choice].next 71 | else: 72 | end_dialogue() 73 | return 74 | 75 | if str(nextDialogueIndex) == "End": 76 | end_dialogue() 77 | else: 78 | var nextDialogue = DialogueResource.DialogueTree.dialogue[nextDialogueIndex] 79 | _process_next(nextDialogue, nextDialogueIndex) 80 | 81 | # processes what to do based on different events 82 | func _process_next(nextDialogue, nextIndex): 83 | current_node = nextDialogue 84 | current_index = nextIndex 85 | 86 | if nextDialogue.has("Choices"): 87 | if nextDialogue["Conditonal"]: 88 | queued_for_conditonal = true 89 | emit_signal("Conditonal_Data_Needed") 90 | else: 91 | emit_signal("Choice_Next", nextDialogue.Ref, nextDialogue.Choices) 92 | elif nextDialogue.has("RandomChoices"): 93 | if nextDialogue["Conditonal"]: 94 | queued_for_conditonal = true 95 | emit_signal("Conditonal_Data_Needed") 96 | else: 97 | if RandomizeBeforeRandom: 98 | randomize() 99 | next_dialogue(round(rand_range(0, nextDialogue["RandomChoices"].size() - 1))) 100 | elif nextDialogue.has("failnext"): 101 | queued_for_conditonal = true 102 | emit_signal("Conditonal_Data_Needed") 103 | else: 104 | emit_signal("Dialogue_Next", nextDialogue.Ref, nextDialogue.Actor, nextDialogue.Dialogue) 105 | 106 | # used to end the dialogue prematurely 107 | func end_dialogue(): 108 | emit_signal("Dialogue_Ended") 109 | in_dialogue = false 110 | 111 | # processing conditonal information 112 | # conditional nodes will automatically skip to whatever node is proper for the operation 113 | func send_conditonal_data(dict): 114 | if queued_for_conditonal: 115 | queued_for_conditonal = false 116 | conditonalData = dict 117 | if current_node.has("Choices"): 118 | var ChoicesNew = current_node.Choices 119 | for i in ChoicesNew: 120 | i["PassCondition"] = evaluate(str(i["Conditional"]).format(dict)) 121 | emit_signal("Choice_Next", current_node.Ref, ChoicesNew) 122 | elif current_node.has("failnext"): 123 | var evaledConditon = evaluate(str(current_node["Condition"]).format(dict)) 124 | next_dialogue(-1, evaledConditon) 125 | elif current_node.has("RandomChoices"): 126 | if RandomizeBeforeRandom: 127 | randomize() 128 | var selectedChoice = 0 129 | var choicePassed = false 130 | 131 | while !choicePassed: 132 | selectedChoice = round(rand_range(0, current_node["RandomChoices"].size() - 1)) 133 | choicePassed = evaluate(str(current_node["RandomChoices"][selectedChoice]["Conditional"]).format(dict)) 134 | 135 | next_dialogue(selectedChoice) 136 | 137 | # evaluates a string in gdscript 138 | func evaluate(input): 139 | var script = GDScript.new() 140 | script.set_source_code("func eval():\n\treturn " + input) 141 | script.reload() 142 | 143 | var obj = Reference.new() 144 | obj.set_script(script) 145 | 146 | return obj.eval() -------------------------------------------------------------------------------- /default_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=2 format=2] 2 | 3 | [sub_resource type="ProceduralSky" id=1] 4 | 5 | radiance_size = 4 6 | sky_top_color = Color( 0.0470588, 0.454902, 0.976471, 1 ) 7 | sky_horizon_color = Color( 0.556863, 0.823529, 0.909804, 1 ) 8 | sky_curve = 0.25 9 | sky_energy = 1.0 10 | ground_bottom_color = Color( 0.101961, 0.145098, 0.188235, 1 ) 11 | ground_horizon_color = Color( 0.482353, 0.788235, 0.952941, 1 ) 12 | ground_curve = 0.01 13 | ground_energy = 1.0 14 | sun_color = Color( 1, 1, 1, 1 ) 15 | sun_latitude = 35.0 16 | sun_longitude = 0.0 17 | sun_angle_min = 1.0 18 | sun_angle_max = 100.0 19 | sun_curve = 0.05 20 | sun_energy = 16.0 21 | texture_size = 2 22 | 23 | [resource] 24 | 25 | background_mode = 2 26 | background_sky = SubResource( 1 ) 27 | background_sky_custom_fov = 0.0 28 | background_color = Color( 0, 0, 0, 1 ) 29 | background_energy = 1.0 30 | background_canvas_max_layer = 0 31 | ambient_light_color = Color( 0, 0, 0, 1 ) 32 | ambient_light_energy = 1.0 33 | ambient_light_sky_contribution = 1.0 34 | fog_enabled = false 35 | fog_color = Color( 0.5, 0.6, 0.7, 1 ) 36 | fog_sun_color = Color( 1, 0.9, 0.7, 1 ) 37 | fog_sun_amount = 0.0 38 | fog_depth_enabled = true 39 | fog_depth_begin = 10.0 40 | fog_depth_curve = 1.0 41 | fog_transmit_enabled = false 42 | fog_transmit_curve = 1.0 43 | fog_height_enabled = false 44 | fog_height_min = 0.0 45 | fog_height_max = 100.0 46 | fog_height_curve = 1.0 47 | tonemap_mode = 0 48 | tonemap_exposure = 1.0 49 | tonemap_white = 1.0 50 | auto_exposure_enabled = false 51 | auto_exposure_scale = 0.4 52 | auto_exposure_min_luma = 0.05 53 | auto_exposure_max_luma = 8.0 54 | auto_exposure_speed = 0.5 55 | ss_reflections_enabled = false 56 | ss_reflections_max_steps = 64 57 | ss_reflections_fade_in = 0.15 58 | ss_reflections_fade_out = 2.0 59 | ss_reflections_depth_tolerance = 0.2 60 | ss_reflections_roughness = true 61 | ssao_enabled = false 62 | ssao_radius = 1.0 63 | ssao_intensity = 1.0 64 | ssao_radius2 = 0.0 65 | ssao_intensity2 = 1.0 66 | ssao_bias = 0.01 67 | ssao_light_affect = 0.0 68 | ssao_color = Color( 0, 0, 0, 1 ) 69 | ssao_quality = 0 70 | ssao_blur = 3 71 | ssao_edge_sharpness = 4.0 72 | dof_blur_far_enabled = false 73 | dof_blur_far_distance = 10.0 74 | dof_blur_far_transition = 5.0 75 | dof_blur_far_amount = 0.1 76 | dof_blur_far_quality = 1 77 | dof_blur_near_enabled = false 78 | dof_blur_near_distance = 2.0 79 | dof_blur_near_transition = 1.0 80 | dof_blur_near_amount = 0.1 81 | dof_blur_near_quality = 1 82 | glow_enabled = false 83 | glow_levels/1 = false 84 | glow_levels/2 = false 85 | glow_levels/3 = true 86 | glow_levels/4 = false 87 | glow_levels/5 = true 88 | glow_levels/6 = false 89 | glow_levels/7 = false 90 | glow_intensity = 0.8 91 | glow_strength = 1.0 92 | glow_bloom = 0.0 93 | glow_blend_mode = 2 94 | glow_hdr_threshold = 1.0 95 | glow_hdr_scale = 2.0 96 | glow_bicubic_upscale = false 97 | adjustment_enabled = false 98 | adjustment_brightness = 1.0 99 | adjustment_contrast = 1.0 100 | adjustment_saturation = 1.0 101 | 102 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LexiEmory/DialogueTreePlugin/a9c1a84b1164cad8219138c42141761259f7fb46/icon.png -------------------------------------------------------------------------------- /icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" 6 | 7 | [deps] 8 | 9 | source_file="res://icon.png" 10 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] 11 | 12 | [params] 13 | 14 | compress/mode=0 15 | compress/lossy_quality=0.7 16 | compress/hdr_mode=0 17 | compress/normal_map=0 18 | flags/repeat=0 19 | flags/filter=true 20 | flags/mipmaps=false 21 | flags/anisotropic=false 22 | flags/srgb=2 23 | process/fix_alpha_border=true 24 | process/premult_alpha=false 25 | process/HDR_as_SRGB=false 26 | stream=false 27 | size_limit=0 28 | detect_3d=true 29 | svg/scale=1.0 30 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=3 10 | 11 | [application] 12 | 13 | config/name="DialogueTreePlugin" 14 | run/main_scene="res://Example.tscn" 15 | config/icon="res://icon.png" 16 | 17 | [editor_plugins] 18 | 19 | enabled=PoolStringArray( "dialogue_tree" ) 20 | 21 | [rendering] 22 | 23 | environment/default_environment="res://default_env.tres" 24 | --------------------------------------------------------------------------------