From 8e56975f09ca713728ae015b90900390d009a278 Mon Sep 17 00:00:00 2001 From: pennyrigate Date: Sat, 1 Mar 2025 16:39:50 -0500 Subject: [PATCH] base addon version? --- .gitattributes | 2 + .gitignore | 4 + README.md | 82 ++++++++ addons/dvn/README.md | 82 ++++++++ addons/dvn/README.txt | 82 ++++++++ addons/dvn/balloon/dvn_balloon.gd | 182 ++++++++++++++++ addons/dvn/balloon/dvn_balloon.tscn | 152 +++++++++++++ addons/dvn/default_bus_layout.tres | 21 ++ addons/dvn/dvn.gd | 316 ++++++++++++++++++++++++++++ addons/dvn/dvn.png | Bin 0 -> 458 bytes addons/dvn/dvn.png.import | 34 +++ addons/dvn/dvn.tscn | 25 +++ addons/dvn/dvn_plugin.gd | 2 + addons/dvn/label/dvn_label.gd | 134 ++++++++++++ addons/dvn/label/dvn_label.tscn | 82 ++++++++ addons/dvn/plugin.cfg | 7 + addons/dvn/sound_player/sound.gd | 4 + addons/dvn/sound_player/sound.tscn | 9 + icon.svg | 1 + icon.svg.import | 37 ++++ project.godot | 46 ++++ 21 files changed, 1304 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 README.md create mode 100644 addons/dvn/README.md create mode 100644 addons/dvn/README.txt create mode 100644 addons/dvn/balloon/dvn_balloon.gd create mode 100644 addons/dvn/balloon/dvn_balloon.tscn create mode 100644 addons/dvn/default_bus_layout.tres create mode 100644 addons/dvn/dvn.gd create mode 100644 addons/dvn/dvn.png create mode 100644 addons/dvn/dvn.png.import create mode 100644 addons/dvn/dvn.tscn create mode 100644 addons/dvn/dvn_plugin.gd create mode 100644 addons/dvn/label/dvn_label.gd create mode 100644 addons/dvn/label/dvn_label.tscn create mode 100644 addons/dvn/plugin.cfg create mode 100644 addons/dvn/sound_player/sound.gd create mode 100644 addons/dvn/sound_player/sound.tscn create mode 100644 icon.svg create mode 100644 icon.svg.import create mode 100644 project.godot diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a146c63 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# Godot 4+ specific ignores +.godot/ +/android/ +addons/dialogue_manager/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e06322 --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ +Thank you for using DVN! + +DVN is a Godot Visual novel example project. + +If you need help using features of DVN, click "Search Help" on the Top Left of +the middle editor window (to the left of "Inspector") + +DVN is made up of 3 new classes: + +- DVNScene: The class that contains all the functions that DVN uses, every scene +should inherit from this class, as well as dvn.tscn. If you want to make a new scene, +press ctrl+shift+N (or click scene>new inherited scene) and choose to inherit from dvn.tscn. +you can edit your inherited scene to your heart's content, but editing dvn.tscn itself, or dvn.gd will +change the way DVN itself works. If you want to add to DVNScene's functions, feel free to. You can also just +call super() and then run your custom code. + +etc. + +# In your scene vvv +func create_text_balloon(): + super() + #YOUR ADDITIONAL CODE HERE + +-DVNLabel: An extension of Godot Dialogue Manager's DialogueLabel compatible +with talktones and autotext. + +Within your Balloon scene you can set exports for talktones, voice clips, autotext etc. + +You shouldn't be needing to call anything from here, +but if you have trouble with the way your dialogue is being drawn, feel free to check +how it works. + +-DVNBalloon: A copy of Godot Dialogue Manager's default balloon, configured to work +with DVNLabels as well as DialogueLabels. There's a region in the script for label references, +feel free to add them there (you can also add them to your scene's script, or a global script). +You can also edit dvn_balloon.gd yourself, it's highly recommended you make a copy and edit it if +you want your baloon running custom code. + +DVN is simply an add on to an addon. You can make new classes and shit if you want. +Keep and mind i will be updating DVN through git if needed, so i recommend you dont edit anything within +the DVN folder, unless you're willing to resolve conflicts. + + +Dialogue is handled by Nathan Hoad's "Godot Dialogue Manager" extension +for help with anything related to the Godot Dialogue Manager, consult its GitHub page +https://github.com/nathanhoad/godot_dialogue_manager + +For help with anything Godot related, check the documentation. +Either by clicking "Search Help" in the top right of the script editor, +By right clicking a node type, or by going to +https://docs.godotengine.org/en/stable/ + +DVN is made for Godot 4.3, keep in mind there are major differences between +Godot 4 and Godot 3. Mostly function names. + +DVN is CC0 open source <------ lame way of saying, use my code i dont care what you do with it, and you dont need to credit me + +my name is TY TIRAMISU, if you do want to credit me :> + +as for the Godot Dialogue Manager? + +MIT License + +Copyright (c) 2022-present Nathan Hoad and Dialogue Manager contributors. + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/addons/dvn/README.md b/addons/dvn/README.md new file mode 100644 index 0000000..6e06322 --- /dev/null +++ b/addons/dvn/README.md @@ -0,0 +1,82 @@ +Thank you for using DVN! + +DVN is a Godot Visual novel example project. + +If you need help using features of DVN, click "Search Help" on the Top Left of +the middle editor window (to the left of "Inspector") + +DVN is made up of 3 new classes: + +- DVNScene: The class that contains all the functions that DVN uses, every scene +should inherit from this class, as well as dvn.tscn. If you want to make a new scene, +press ctrl+shift+N (or click scene>new inherited scene) and choose to inherit from dvn.tscn. +you can edit your inherited scene to your heart's content, but editing dvn.tscn itself, or dvn.gd will +change the way DVN itself works. If you want to add to DVNScene's functions, feel free to. You can also just +call super() and then run your custom code. + +etc. + +# In your scene vvv +func create_text_balloon(): + super() + #YOUR ADDITIONAL CODE HERE + +-DVNLabel: An extension of Godot Dialogue Manager's DialogueLabel compatible +with talktones and autotext. + +Within your Balloon scene you can set exports for talktones, voice clips, autotext etc. + +You shouldn't be needing to call anything from here, +but if you have trouble with the way your dialogue is being drawn, feel free to check +how it works. + +-DVNBalloon: A copy of Godot Dialogue Manager's default balloon, configured to work +with DVNLabels as well as DialogueLabels. There's a region in the script for label references, +feel free to add them there (you can also add them to your scene's script, or a global script). +You can also edit dvn_balloon.gd yourself, it's highly recommended you make a copy and edit it if +you want your baloon running custom code. + +DVN is simply an add on to an addon. You can make new classes and shit if you want. +Keep and mind i will be updating DVN through git if needed, so i recommend you dont edit anything within +the DVN folder, unless you're willing to resolve conflicts. + + +Dialogue is handled by Nathan Hoad's "Godot Dialogue Manager" extension +for help with anything related to the Godot Dialogue Manager, consult its GitHub page +https://github.com/nathanhoad/godot_dialogue_manager + +For help with anything Godot related, check the documentation. +Either by clicking "Search Help" in the top right of the script editor, +By right clicking a node type, or by going to +https://docs.godotengine.org/en/stable/ + +DVN is made for Godot 4.3, keep in mind there are major differences between +Godot 4 and Godot 3. Mostly function names. + +DVN is CC0 open source <------ lame way of saying, use my code i dont care what you do with it, and you dont need to credit me + +my name is TY TIRAMISU, if you do want to credit me :> + +as for the Godot Dialogue Manager? + +MIT License + +Copyright (c) 2022-present Nathan Hoad and Dialogue Manager contributors. + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/addons/dvn/README.txt b/addons/dvn/README.txt new file mode 100644 index 0000000..6e06322 --- /dev/null +++ b/addons/dvn/README.txt @@ -0,0 +1,82 @@ +Thank you for using DVN! + +DVN is a Godot Visual novel example project. + +If you need help using features of DVN, click "Search Help" on the Top Left of +the middle editor window (to the left of "Inspector") + +DVN is made up of 3 new classes: + +- DVNScene: The class that contains all the functions that DVN uses, every scene +should inherit from this class, as well as dvn.tscn. If you want to make a new scene, +press ctrl+shift+N (or click scene>new inherited scene) and choose to inherit from dvn.tscn. +you can edit your inherited scene to your heart's content, but editing dvn.tscn itself, or dvn.gd will +change the way DVN itself works. If you want to add to DVNScene's functions, feel free to. You can also just +call super() and then run your custom code. + +etc. + +# In your scene vvv +func create_text_balloon(): + super() + #YOUR ADDITIONAL CODE HERE + +-DVNLabel: An extension of Godot Dialogue Manager's DialogueLabel compatible +with talktones and autotext. + +Within your Balloon scene you can set exports for talktones, voice clips, autotext etc. + +You shouldn't be needing to call anything from here, +but if you have trouble with the way your dialogue is being drawn, feel free to check +how it works. + +-DVNBalloon: A copy of Godot Dialogue Manager's default balloon, configured to work +with DVNLabels as well as DialogueLabels. There's a region in the script for label references, +feel free to add them there (you can also add them to your scene's script, or a global script). +You can also edit dvn_balloon.gd yourself, it's highly recommended you make a copy and edit it if +you want your baloon running custom code. + +DVN is simply an add on to an addon. You can make new classes and shit if you want. +Keep and mind i will be updating DVN through git if needed, so i recommend you dont edit anything within +the DVN folder, unless you're willing to resolve conflicts. + + +Dialogue is handled by Nathan Hoad's "Godot Dialogue Manager" extension +for help with anything related to the Godot Dialogue Manager, consult its GitHub page +https://github.com/nathanhoad/godot_dialogue_manager + +For help with anything Godot related, check the documentation. +Either by clicking "Search Help" in the top right of the script editor, +By right clicking a node type, or by going to +https://docs.godotengine.org/en/stable/ + +DVN is made for Godot 4.3, keep in mind there are major differences between +Godot 4 and Godot 3. Mostly function names. + +DVN is CC0 open source <------ lame way of saying, use my code i dont care what you do with it, and you dont need to credit me + +my name is TY TIRAMISU, if you do want to credit me :> + +as for the Godot Dialogue Manager? + +MIT License + +Copyright (c) 2022-present Nathan Hoad and Dialogue Manager contributors. + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/addons/dvn/balloon/dvn_balloon.gd b/addons/dvn/balloon/dvn_balloon.gd new file mode 100644 index 0000000..37ca186 --- /dev/null +++ b/addons/dvn/balloon/dvn_balloon.gd @@ -0,0 +1,182 @@ +class_name DVNBalloon extends CanvasLayer +## A basic dialogue balloon for use with Dialogue Manager. + +## The initial label to spit text out from +@export var label:NodePath + +## The action to use for advancing the dialogue +@export var next_action: StringName = &"ui_accept" + +## The action to use to skip typing the dialogue +@export var skip_action: StringName = &"ui_cancel" + +## The dialogue resource +var resource: DialogueResource + +## Temporary game states +var temporary_game_states: Array = [] + +## See if we are waiting for the player +var is_waiting_for_input: bool = false + +## See if we are running a long mutation and should hide the balloon +var will_hide_balloon: bool = false + +## A dictionary to store any ephemeral variables +var locals: Dictionary = {} + +var _locale: String = TranslationServer.get_locale() + +## The current line +var dialogue_line: DialogueLine: + set(value): + if value: + dialogue_line = value + apply_dialogue_line() + else: + # The dialogue has finished so close the balloon + queue_free() + get: + return dialogue_line + +## A cooldown timer for delaying the balloon hide when encountering a mutation. +var mutation_cooldown: Timer = Timer.new() + +## The base balloon anchor +@onready var balloon: Control = %Balloon + +## The label showing the name of the currently speaking character +@onready var character_label: RichTextLabel = %CharacterLabel + +## The label showing the currently spoken dialogue +@onready var dialogue_label: DVNLabel = get_node(label) + +## The menu of responses +@onready var responses_menu: DialogueResponsesMenu = %ResponsesMenu + +#region Label References +#Put label references here +#endregion + + +func _ready() -> void: + balloon.hide() + Engine.get_singleton("DialogueManager").mutated.connect(_on_mutated) + # If the responses menu doesn't have a next action set, use this one + if responses_menu.next_action.is_empty(): + responses_menu.next_action = next_action + + mutation_cooldown.timeout.connect(_on_mutation_cooldown_timeout) + add_child(mutation_cooldown) + +func _unhandled_input(_event: InputEvent) -> void: + # Only the balloon is allowed to handle input while it's showing + get_viewport().set_input_as_handled() + + +func _notification(what: int) -> void: + ## Detect a change of locale and update the current dialogue line to show the new language + if what == NOTIFICATION_TRANSLATION_CHANGED and _locale != TranslationServer.get_locale() and is_instance_valid(dialogue_label): + _locale = TranslationServer.get_locale() + var visible_ratio = dialogue_label.visible_ratio + self.dialogue_line = await resource.get_next_dialogue_line(dialogue_line.id) + if visible_ratio < 1: + dialogue_label.skip_typing() + + +## Start some dialogue +func start(dialogue_resource: DialogueResource, title: String, extra_game_states: Array = []) -> void: + temporary_game_states = [self] + extra_game_states + is_waiting_for_input = false + resource = dialogue_resource + self.dialogue_line = await resource.get_next_dialogue_line(title, temporary_game_states) + + +## Apply any changes to the balloon given a new [DialogueLine]. +func apply_dialogue_line() -> void: + mutation_cooldown.stop() + + is_waiting_for_input = false + balloon.focus_mode = Control.FOCUS_ALL + balloon.grab_focus() + + character_label.visible = not dialogue_line.character.is_empty() + character_label.text = tr(dialogue_line.character, "dialogue") + + dialogue_label.hide() + dialogue_label.dialogue_line = dialogue_line + + responses_menu.hide() + responses_menu.responses = dialogue_line.responses + + # Show our balloon + balloon.show() + will_hide_balloon = false + + dialogue_label.show() + if not dialogue_line.text.is_empty(): + dialogue_label.type_out() + await dialogue_label.finished_typing + + # Wait for input + if dialogue_line.responses.size() > 0: + balloon.focus_mode = Control.FOCUS_NONE + responses_menu.show() + elif dialogue_line.time != "": + var time = dialogue_line.text.length() * 0.02 if dialogue_line.time == "auto" else dialogue_line.time.to_float() + await get_tree().create_timer(time).timeout + next(dialogue_line.next_id) + else: + is_waiting_for_input = true + balloon.focus_mode = Control.FOCUS_ALL + balloon.grab_focus() + + +## Go to the next line +func next(next_id: String) -> void: + self.dialogue_line = await resource.get_next_dialogue_line(next_id, temporary_game_states) + + +#region Signals + + +func _on_mutation_cooldown_timeout() -> void: + if will_hide_balloon: + will_hide_balloon = false + balloon.hide() + + +func _on_mutated(_mutation: Dictionary) -> void: + is_waiting_for_input = false + will_hide_balloon = true + mutation_cooldown.start(0.1) + + +func _on_balloon_gui_input(event: InputEvent) -> void: + # See if we need to skip typing of the dialogue + if dialogue_label.is_typing: + var mouse_was_clicked: bool = event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed() + var skip_button_was_pressed: bool = event.is_action_pressed(skip_action) + if mouse_was_clicked or skip_button_was_pressed: + get_viewport().set_input_as_handled() + dialogue_label.skip_typing() + return + + if not is_waiting_for_input: return + if dialogue_line.responses.size() > 0: return + + # When there are no response options the balloon itself is the clickable thing + get_viewport().set_input_as_handled() + + if event is InputEventMouseButton and event.is_pressed() and event.button_index == MOUSE_BUTTON_LEFT: + next(dialogue_line.next_id) + elif event.is_action_pressed(next_action) and get_viewport().gui_get_focus_owner() == balloon: + next(dialogue_line.next_id) + +func _process(delta: float) -> void: + print(dialogue_line.responses.size()) + +func _on_responses_menu_response_selected(response: DialogueResponse) -> void: + next(response.next_id) + +#endregion diff --git a/addons/dvn/balloon/dvn_balloon.tscn b/addons/dvn/balloon/dvn_balloon.tscn new file mode 100644 index 0000000..3f13b31 --- /dev/null +++ b/addons/dvn/balloon/dvn_balloon.tscn @@ -0,0 +1,152 @@ +[gd_scene load_steps=9 format=3 uid="uid://kssjsapnseux"] + +[ext_resource type="Script" path="res://addons/dvn/balloon/dvn_balloon.gd" id="1_7pshc"] +[ext_resource type="PackedScene" uid="uid://cca3fm3pojb41" path="res://addons/dvn/label/dvn_label.tscn" id="2_7ceuc"] +[ext_resource type="Script" path="res://addons/dialogue_manager/dialogue_responses_menu.gd" id="3_72ixx"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_spyqn"] +bg_color = Color(0, 0, 0, 1) +border_width_left = 3 +border_width_top = 3 +border_width_right = 3 +border_width_bottom = 3 +border_color = Color(0.329412, 0.329412, 0.329412, 1) +corner_radius_top_left = 5 +corner_radius_top_right = 5 +corner_radius_bottom_right = 5 +corner_radius_bottom_left = 5 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ri4m3"] +bg_color = Color(0.121569, 0.121569, 0.121569, 1) +border_width_left = 3 +border_width_top = 3 +border_width_right = 3 +border_width_bottom = 3 +border_color = Color(1, 1, 1, 1) +corner_radius_top_left = 5 +corner_radius_top_right = 5 +corner_radius_bottom_right = 5 +corner_radius_bottom_left = 5 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_e0njw"] +bg_color = Color(0, 0, 0, 1) +border_width_left = 3 +border_width_top = 3 +border_width_right = 3 +border_width_bottom = 3 +border_color = Color(0.6, 0.6, 0.6, 1) +corner_radius_top_left = 5 +corner_radius_top_right = 5 +corner_radius_bottom_right = 5 +corner_radius_bottom_left = 5 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_uy0d5"] +bg_color = Color(0, 0, 0, 1) +border_width_left = 3 +border_width_top = 3 +border_width_right = 3 +border_width_bottom = 3 +corner_radius_top_left = 5 +corner_radius_top_right = 5 +corner_radius_bottom_right = 5 +corner_radius_bottom_left = 5 + +[sub_resource type="Theme" id="Theme_qq3yp"] +default_font_size = 20 +Button/styles/disabled = SubResource("StyleBoxFlat_spyqn") +Button/styles/focus = SubResource("StyleBoxFlat_ri4m3") +Button/styles/hover = SubResource("StyleBoxFlat_e0njw") +Button/styles/normal = SubResource("StyleBoxFlat_e0njw") +MarginContainer/constants/margin_bottom = 15 +MarginContainer/constants/margin_left = 30 +MarginContainer/constants/margin_right = 30 +MarginContainer/constants/margin_top = 15 +Panel/styles/panel = SubResource("StyleBoxFlat_uy0d5") + +[node name="DVNBalloon" type="CanvasLayer"] +layer = 100 +script = ExtResource("1_7pshc") +label = NodePath("Balloon/Panel/Dialogue/VBoxContainer/DVNLabel") + +[node name="Balloon" type="Control" parent="."] +unique_name_in_owner = true +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme = SubResource("Theme_qq3yp") + +[node name="Panel" type="Panel" parent="Balloon"] +clip_children = 2 +layout_mode = 1 +anchors_preset = 12 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 21.0 +offset_top = -183.0 +offset_right = -19.0 +offset_bottom = -19.0 +grow_horizontal = 2 +grow_vertical = 0 +mouse_filter = 1 + +[node name="Dialogue" type="MarginContainer" parent="Balloon/Panel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="Balloon/Panel/Dialogue"] +layout_mode = 2 + +[node name="CharacterLabel" type="RichTextLabel" parent="Balloon/Panel/Dialogue/VBoxContainer"] +unique_name_in_owner = true +modulate = Color(1, 1, 1, 0.501961) +layout_mode = 2 +mouse_filter = 1 +bbcode_enabled = true +text = "Character" +fit_content = true +scroll_active = false + +[node name="DVNLabel" parent="Balloon/Panel/Dialogue/VBoxContainer" instance=ExtResource("2_7ceuc")] +unique_name_in_owner = true +layout_mode = 2 +talktone_player_path = NodePath("../../../../../TalktonePlayer") + +[node name="Responses" type="MarginContainer" parent="Balloon"] +layout_mode = 1 +anchors_preset = 7 +anchor_left = 0.5 +anchor_top = 1.0 +anchor_right = 0.5 +anchor_bottom = 1.0 +offset_left = -147.0 +offset_top = -558.0 +offset_right = 494.0 +offset_bottom = -154.0 +grow_horizontal = 2 +grow_vertical = 0 + +[node name="ResponsesMenu" type="VBoxContainer" parent="Balloon/Responses" node_paths=PackedStringArray("response_template")] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 8 +theme_override_constants/separation = 2 +script = ExtResource("3_72ixx") +response_template = NodePath("ResponseExample") + +[node name="ResponseExample" type="Button" parent="Balloon/Responses/ResponsesMenu"] +layout_mode = 2 +text = "Response example" + +[node name="TalktonePlayer" type="AudioStreamPlayer" parent="."] +bus = &"VOX" + +[connection signal="gui_input" from="Balloon" to="." method="_on_balloon_gui_input"] +[connection signal="response_selected" from="Balloon/Responses/ResponsesMenu" to="." method="_on_responses_menu_response_selected"] diff --git a/addons/dvn/default_bus_layout.tres b/addons/dvn/default_bus_layout.tres new file mode 100644 index 0000000..46f3686 --- /dev/null +++ b/addons/dvn/default_bus_layout.tres @@ -0,0 +1,21 @@ +[gd_resource type="AudioBusLayout" format=3 uid="uid://cv4d8sgujag0l"] + +[resource] +bus/1/name = &"BGM" +bus/1/solo = false +bus/1/mute = false +bus/1/bypass_fx = false +bus/1/volume_db = 0.0 +bus/1/send = &"Master" +bus/2/name = &"SFX" +bus/2/solo = false +bus/2/mute = false +bus/2/bypass_fx = false +bus/2/volume_db = 0.0 +bus/2/send = &"Master" +bus/3/name = &"VOX" +bus/3/solo = false +bus/3/mute = false +bus/3/bypass_fx = false +bus/3/volume_db = 0.0 +bus/3/send = &"Master" diff --git a/addons/dvn/dvn.gd b/addons/dvn/dvn.gd new file mode 100644 index 0000000..884c800 --- /dev/null +++ b/addons/dvn/dvn.gd @@ -0,0 +1,316 @@ +@icon("dvn.png") +class_name DVNScene extends Node2D +## The DVNScene Node contains all of the built in functions of DVN, excluding those affecting text. +## Every scene in the DVN engine should extend DVNScene, imagine it as a base scene. + +## Completely Invisible Color, if the alpha is increased it becomes [member Color.WHITE] +const TRANS_WHITE = Color(1,1,1,0) +## Completely Invisible Color, if the alpha is increased it becomes [member Color.BLACK] +const TRANS_BLACK = Color(0,0,0,0) + +## Called when [method fade_out_sceen] has finished fading the screen. +## [br]NOTE: Will only be called if [param async] is false!!! +signal screen_fade_out +## Called when [method fade_in_sceen] has finished fading the screen. +## [br]NOTE: Will only be called if [param async] is false!!! +signal screen_fade_in +## Called when [method fade_out_bgm] has finished fading. +## [br]NOTE: Will only be called if [param async] is false!!! +signal bgm_fade_out +## Called when [method fade_in_bgm] has finished fading. +## [br]NOTE: Will only be called if [param async] is false!!! +signal bgm_fade_in +## Called when [method fade_bgm] has finished fading. +## [br]NOTE: Will only be called if [param async] is false!!! +signal bgm_fade +## Called when [method delay] has counted all the way down. +signal delay_ended +## Called when the sound created by [method play_sound] has finished playing. +## [br]NOTE: Will only be called if [param async] is false!!! +signal sound_ended + +## Default ballon to create with [method create_text_balloon] +@export var Balloon: PackedScene = null +## Default ballon to start with [method create_text_balloon] +@export var Dialogue: DialogueResource = null + +## Set the current dialogue automation type. +## [br]see [enum DialogueAutomationTypes] for more info +@export_enum("Manual", "Auto Text", "Auto Voice") var dialogue_automation_type: int +## [param] MANUAL is the default way of handling text. The next line of dialogue is not +## drawn until the user inputs a command. +## [br][param AUTO_TEXT] Automatically skips to the next text box after the [member auto_text_delay] timer is done counting down. +## [br][param AUTO_VOICE] Automatically skips to the next text box when the voice clip is done playing. +enum DialogueAutomationTypes{MANUAL,AUTO_TEXT,AUTO_VOICE} + +## The wait time until new text is drawn when [member dialogue_automation_type] is set to auto voice. +@export var auto_text_delay:float = 1.0 + +## Default time value for fading the screen +@export var default_screen_fade_time: float = 2.0 +## Default time value for fading the BGM +@export var default_bgm_fade_time: float = 2.0 + +## Reference to BGM Player +@onready var bgm = %BGM +## Reference to built in Animation Player +@onready var animation_player = $DVN/AnimationPlayer + +## The volume of the BGM set in the editor, used +@onready var bgm_initial_volume = bgm.get_volume_db() + +## The currently active text balloon, created from [method create_text_balloon] +var current_balloon = null + + +#region Text Functions +## Create a text balloon starting from [param title] +func create_text_balloon(title:String): + current_balloon = Balloon.instantiate() + add_child(current_balloon) + current_balloon.start(Dialogue,title) + +## Wait a certain amount of [param time] until the next dialogue line is executed +func delay(time:float = 2.0): + await get_tree().create_timer(time).timeout + emit_signal("delay_ended") + screen_fade_out.connect(on_delay_ended) + +## Switch the currently selected [DVNLabel] +## [br]If [param keep_text] is true than the previously selected [DVNLabel] will stay drawn +func switch_label(label,keep_text: bool = false): + if keep_text == false: + current_balloon.dialogue_label.text = "" + current_balloon.dialogue_label = label + +## Move the selected [param label] to a specified [param position] +func move_label(label:PackedScene,position:Vector2): + current_balloon.dialogue_label.position = position + +## Change the [param color] of the currently selected label +func change_text_color(color:Color): + current_balloon.dialogue_label.set_modulate(color) + +## Set the current dialogue automation type. +## [br]see [enum DialogueAutomationTypes] for more info +func set_dialogue_automation_type(type:int): + dialogue_automation_type = type + +## Set the text speed in seconds per step +func set_text_speed(speed:float=0.02): + current_balloon.dialogue_label.seconds_per_step = speed + +## Called when the dialogue reaches an END block. +func dialogue_ended(): + pass +#endregion + +#region Voice Functions +## Set the current voice line position. Useful if you have a lot of different branches +## and loops in dialogue. +func set_voice_line(index:int): + current_balloon.dialogue_label.current_voice_line = index + +## Set if speech sounds should play at all. +func set_can_speak(truefalse:bool=true): + current_balloon.dialogue_label.can_speak = truefalse + +## Set the volume of the currently selected [DVNLabel]'s talktone player in db +func set_voice_volume(volume:float = 0.0): + current_balloon.dialogue_label.talktone_player.set_volume_db(volume) +#endregion + +#region Screen Fade Functions +## Fades in the screen. This is achieved by interpolating the alpha of [DVNScene]'s [ColorRect]. +## [br][br][param color] determines the color to fade in from. +## [br][param time] determines the amount of time for the fade to take. +## [br][param hold_time] determines the time to wait until the screen starts fading. +## [br]if [param async] is true, the fade will be performed alongside other actions, otherwise, other actions won't be performed until the fading is finished. +func fade_in_screen(color:Color = Color.BLACK,time:float = default_screen_fade_time,hold_time:float = 0,async:bool = false): + %FadeColor.color = color + %FadeColor.color.a = 1.0 + await get_tree().create_timer(hold_time).timeout + var tween = get_tree().create_tween() + tween.tween_property(%FadeColor, "color:a", 0.0, time).set_trans(Tween.TRANS_LINEAR) + if !async: + await get_tree().create_timer(time).timeout + emit_signal("screen_fade_in") + screen_fade_out.connect(on_screen_fade_in) + +## Fades out the screen. This is achieved by interpolating the alpha of [DVNScene]'s [ColorRect]. +## [br][br][param color] determines the color to fade to. +## [br][param time] determines the amount of time for the fade to take. +## [br][param hold_time] determines the extra time to hold the faded color, until the fading is considered "finished". +## [br]if [param async] is true, the fade will be performed alongside other actions, otherwise, other actions won't be performed until the fading is finished. +func fade_out_screen(color:Color = Color.BLACK,time:float = default_screen_fade_time,hold_time:float = 0,async:bool = false): + %FadeColor.color = color + %FadeColor.color.a = 0.0 + var tween = get_tree().create_tween() + tween.tween_property(%FadeColor, "color:a", 1.0, time).set_trans(Tween.TRANS_LINEAR) + if !async: + await get_tree().create_timer(time).timeout + await get_tree().create_timer(hold_time).timeout + emit_signal("screen_fade_in") + screen_fade_out.connect(on_screen_fade_in) +#endregion + +#region BGM Fade Functions +## Fades out BGM. This is achieved by interpolating the volume of [DVNScene]'s BGM [AudioStreamPlayer]. +## [br][br][param time] determines the amount of time for the fade to take. +## [br]if [param async] is true, the fade will be performed alongside other actions, otherwise, other actions won't be performed until the fading is finished. +func fade_out_bgm(time:float = default_bgm_fade_time,async:bool = false): + var tween = get_tree().create_tween() + tween.tween_property(bgm, "volume_db", -80, time) + if !async: + await get_tree().create_timer(time).timeout + emit_signal("bgm_fade_out") + bgm_fade_in.connect(on_bgm_fade_in) + +## Fades in BGM. This is achieved by interpolating the volume of [DVNScene]'s BGM [AudioStreamPlayer]. +## [br][br][param time] determines the amount of time for the fade to take. +## [br]if [param async] is true, the fade will be performed alongside other actions, otherwise, other actions won't be performed until the fading is finished. +func fade_in_bgm(time:float = default_bgm_fade_time,async:bool = false): + bgm.set_volume_db(-80) + bgm.play() + var tween = get_tree().create_tween() + tween.tween_property(bgm, "volume_db", bgm_initial_volume, time) + if !async: + await get_tree().create_timer(time).timeout + emit_signal("bgm_fade_in") + bgm_fade_in.connect(on_bgm_fade_in) + +## Fades the BGM from its current value to [param end_volume]. This is achieved by interpolating the volume of [DVNScene]'s BGM [AudioStreamPlayer]. +## [br][br][param time] determines the amount of time for the fade to take. +## [br]if [param async] is true, the fade will be performed alongside other actions, otherwise, other actions won't be performed until the fading is finished. +func fade_bgm(end_volume:float = 0.0,time:float = default_bgm_fade_time,async:bool = false): + var tween = get_tree().create_tween() + tween.tween_property(bgm, "volume_db", end_volume, time) + if !async: + await get_tree().create_timer(time).timeout + emit_signal("bgm_fade") + bgm_fade.connect(on_bgm_fade) + +## Change BGM to [param stream] +func change_bgm(stream:AudioStream): + bgm.stream = stream + +## Pause/Resume BGM +func pause_bgm(pause:bool = true): + bgm.set_stream_paused(pause) + +## STOP BGM. +func stop_bgm(): + bgm.stop() + +## Play the BGM. +##[br]Different from setting [method pause_bgm] to false as this will start the stream from the beginning +func play_bgm(): + bgm.play() + +## Set the BGM Volume in db. +## [br]Does not fade, volume change is abrupt. +func set_bgm_volume(volume:float = 0.0): + bgm.set_volume_db(volume) + +## Skip to a spot in the BGM. see [method AudioStreamPlayer.seek] +func seek_bgm(to_position:float = 0.0): + bgm.seek(to_position) +#endregion + +#region SFX Functions +## Play a sound effect. Achieved by creating an [AudioStreamPlayer] and freeing it when it's done playing. +## [br][br]The specific [param sound] can be changed, along with its [param volume] and [param pitch]. +## [br]if [param async] is true, the fade will be performed alongside other actions, otherwise, other actions won't be performed until the fading is finished. +## [br][br]The Sound effect will play from the SFX audio bus. +func play_sound(sound:AudioStream,volume:float,pitch:float,async:bool = true): + var sfx = load("res://dvn/sound_player/sound.tscn").instantiate() + sfx.stream = sound + sfx.set_volume_db(volume) + sfx.pitch_scale = pitch + add_child(sfx) + sfx.play() + if !async: + await get_tree().create_timer(sound.get_length()).timeout + emit_signal("sound_ended") + sound_ended.connect(on_sound_ended) +#endregion + + +#region Animation Functions +## Sets an [AnimationPlayer]'s [param speed]. +## [br] by default this affects the [DVNScene]'s built in [AnimationPlayer] +## [br][br] see [method AnimationPlayer.set_speed_scale] +func set_animation_speed(speed:float = 1.0,player:Node = animation_player): + animation_player.set_speed_scale(1.0) + +## Play an anim on your [AnimationPlayer]. +## [br] by default this affects the [DVNScene]'s built in [AnimationPlayer] +## [br][br] see [method AnimationPlayer.play] +func play_animtion(animation:String,player = animation_player): + player.play(animation) +#endregion + +#region Scene Functions +## Go to the next [param scene] from a node's path. [param example: "res://dvn/dvn.tscn"] +## [br]can be used to change the current scene to anything, but you generally want +## to use it to move to the next specific "scene" or "level" +func change_scene(scene:String): + get_tree().change_scene_to_file(scene) + +## Ends the scene with a screen and BGM fade out. When the screen and BGM are done fading, the scene switches to [param next_scene] +## [br][param screen_fade_time] and [param bgm_fade_time] can be adjusted, though by default they are set to [member default_screen_fade_time] and [member default_bgm_fade_time] +## [br]You can set the default fade times in [DVNScene]'s exports. +## [br]Ideally this is the kind of function you can use to smoothly end a scene in one line. +func end_scene(next_scene:String,screen_fade_time:float = default_screen_fade_time,bgm_fade_time:float = default_bgm_fade_time): + #Determine whether to end on bgm fade or screen fade + var wait_time = 0.0 + if bgm_fade_time > screen_fade_time: + wait_time = bgm_fade_time + else: + wait_time = screen_fade_time + #fade bgm and screen + fade_out_bgm(bgm_fade_time) + fade_out_screen(%FadeColor.color,screen_fade_time) + await get_tree().create_timer(wait_time).timeout #wait for bgm and screen to finish fading + change_scene(next_scene) +#endregion + +#region Signals +## Called when [method delay] has counted all the way down. +func on_delay_ended(): + pass + +## Called when [method fade_out_sceen] has finished fading the screen and [param hold_time] has counted all the way down. +## [br]NOTE: Will only be called if [param async] is false!!! +func on_screen_fade_out(): + pass + +## Called when [method fade_in_sceen] has finished fading the screen. +## [br]NOTE: Will only be called if [param async] is false!!! +func on_screen_fade_in(): + pass + +## Called when the sound created by [method play_sound] has finished playing. +## [br]NOTE: Will only be called if [param async] is false!!! +func on_sound_ended(): + pass + +## Called when [method fade_out_bgm] has finished fading. +## [br]NOTE: Will only be called if [param async] is false!!! +func on_bgm_fade_out(): + pass + +## Called when [method fade_in_bgm] has finished fading. +## [br]NOTE: Will only be called if [param async] is false!!! +func on_bgm_fade_in(): + pass + +## Called when [method fade_bgm] has finished fading. +## [br]NOTE: Will only be called if [param async] is false!!! +func on_bgm_fade(): + pass + +## Called when... when... when something happens. make good use of that [param anim_name]!!! +func _on_animation_player_animation_finished(anim_name: StringName) -> void: + pass # Replace with function body. +#endregion diff --git a/addons/dvn/dvn.png b/addons/dvn/dvn.png new file mode 100644 index 0000000000000000000000000000000000000000..3c53c732f8a91f044d1a337feb633b080e2c07ac GIT binary patch literal 458 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G~10G|-oO$`74-vDxe)PEqUoi_6qkYX(f@(Tuv{Ac*RjSplHXMsm#F#`kN zVGw3Kp1&dmC@4|l8c`CQpH@ zQ@3)efJ|Rc7sn8d;M{&rE(S#&=Iq)3_ut&Yd0MM4gHI%B|MyJh3-sY43~t zt~9gOYuAcZ=O$^EIDgXNV=`N|-_LWA&0$^EN16M>88$FZ?q>926;WLYvc%KX&t;uc GLK6Vm(`d^8 literal 0 HcmV?d00001 diff --git a/addons/dvn/dvn.png.import b/addons/dvn/dvn.png.import new file mode 100644 index 0000000..39c6d69 --- /dev/null +++ b/addons/dvn/dvn.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://be46s5lqu5hyb" +path="res://.godot/imported/dvn.png-739544208bd6b78f8b675b31cbd71369.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/dvn/dvn.png" +dest_files=["res://.godot/imported/dvn.png-739544208bd6b78f8b675b31cbd71369.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/addons/dvn/dvn.tscn b/addons/dvn/dvn.tscn new file mode 100644 index 0000000..ea4d4e4 --- /dev/null +++ b/addons/dvn/dvn.tscn @@ -0,0 +1,25 @@ +[gd_scene load_steps=3 format=3 uid="uid://bd7pbhempcian"] + +[ext_resource type="Script" path="res://addons/dvn/dvn.gd" id="1_0ao5y"] +[ext_resource type="AudioStream" uid="uid://7fnndwc2fe7i" path="res://dvn/test_resources/sound_test.wav" id="2_pjx2r"] + +[node name="Scene" type="Node2D"] +script = ExtResource("1_0ao5y") + +[node name="DVN" type="Node" parent="."] + +[node name="FadeColor" type="ColorRect" parent="DVN"] +unique_name_in_owner = true +offset_right = 1920.0 +offset_bottom = 1080.0 +color = Color(0, 0, 0, 0) + +[node name="BGM" type="AudioStreamPlayer" parent="DVN"] +unique_name_in_owner = true +stream = ExtResource("2_pjx2r") +bus = &"BGM" + +[node name="AnimationPlayer" type="AnimationPlayer" parent="DVN"] +root_node = NodePath("../..") + +[connection signal="animation_finished" from="DVN/AnimationPlayer" to="." method="_on_animation_player_animation_finished"] diff --git a/addons/dvn/dvn_plugin.gd b/addons/dvn/dvn_plugin.gd new file mode 100644 index 0000000..5af87f6 --- /dev/null +++ b/addons/dvn/dvn_plugin.gd @@ -0,0 +1,2 @@ +@tool +extends EditorPlugin diff --git a/addons/dvn/label/dvn_label.gd b/addons/dvn/label/dvn_label.gd new file mode 100644 index 0000000..c52f0eb --- /dev/null +++ b/addons/dvn/label/dvn_label.gd @@ -0,0 +1,134 @@ +@icon("res://addons/dialogue_manager/assets/icon.svg") +class_name DVNLabel extends DialogueLabel +## The DVNLabel Class takes care of dialogue related functions on the label-level + +## ToneTypes for the Talktone player. +## [br][param NONE] plays no sound when text is outputted +## [br][param VOICE] plays a [AudioStream] from [member voice_clips] at the beginning of each dialogue box, +## the index of [member voice clips] increases with each dialogue box. Use this for full voice acting. +## [br][param HALF_BEEP] plays a [member beep_noise] for every other letter outputted +## [br][param BEEP] plays a [member beep_noise] for every letter outputted +## [br][param BLABBER] plays a random [AudioStream] from [member blabber_noises] for every letter outputted. +## Its pitch is a random value between [member blabber_pitch_minumum] and [member blabber_pitch_maximum] +## [br][param MARISESE] uses rudimentary voice synthesis (a specific sound is mapped to each letter aka each [AudioStream] from values 0-25, with every other symbol being represented by value 26) +## ## Its pitch is a random value between [member marisese_pitch_minumum] and [member marisese_pitch_maximum] +enum ToneTypes{NONE,VOICE,HALF_BEEP,BEEP,BLABBER,MARISESE} +@export var talktone_player_path: NodePath +var talktone_player = null +var current_voice_line:int = 0 +# Current TalkType +@export_enum("None","Voice","Half Beep","Beep","Blabber","Marisese") var tone_type: int +# Tone Noises +@export var voice_clips: Array[Resource] = [] +@export var beep_noise: Resource +@export var blabber_noises: Array[Resource] = [] +@export var blabber_pitch_minumum: float = 1.0 +@export var blabber_pitch_maximum: float = 1.0 +@export var marisese_noises: Array[Resource] = [] +@export var marisese_pitch_minumum: float = 0.9 +@export var marisese_pitch_maximum: float = 1.1 +@export var can_speak: bool = true + +@onready var scene = get_owner().get_parent() +@onready var balloon = get_owner() + +func _init() -> void: + bbcode_enabled = true + fit_content = true + scroll_active = false + shortcut_keys_enabled = false + meta_underlined = false + hint_underlined = false + deselect_on_focus_loss_enabled = false + visible_characters_behavior = TextServer.VisibleCharactersBehavior.VC_CHARS_AFTER_SHAPING + set_anchors_preset(Control.PRESET_TOP_WIDE) + size.x = 640.0 + mouse_filter = MOUSE_FILTER_PASS + + +func _ready() -> void: + talktone_player = get_node(talktone_player_path) + talktone_player.finished.connect(on_talktone_finished) + spoke.connect(_on_spoke) + finished_typing.connect(_on_finished_typing) + +func type_out(): + super() + if tone_type == ToneTypes.VOICE && can_speak: + if current_voice_line <= voice_clips.size() - 1: + talktone_player.stream = voice_clips[current_voice_line] + talktone_player.play() + current_voice_line += 1 + +func play_beep_tone(sound:Resource = beep_noise,pitch_minimum:float = 1.0,pitch_maximum:float = 1.0,player:Node = talktone_player): + var r = randf_range(pitch_minimum,pitch_maximum) + player.stream = sound + player.pitch_scale = r + player.play() + +func play_blabber_tone(sounds:Array = blabber_noises,volume:float = 0.0,pitch_minimum:float = blabber_pitch_minumum,pitch_maximum:float = blabber_pitch_maximum,player:Node = talktone_player): + var r = randi_range(0,sounds.size() - 1) + player.stream = sounds[r] + var r2 = randf_range(pitch_minimum,pitch_maximum) + player.pitch_scale = r2 + player.play() + +func play_marisese(letter:String = "A",sounds:Array = marisese_noises,volume:float = 0.0,pitch_minimum:float = marisese_pitch_minumum,pitch_maximum:float = marisese_pitch_maximum,player:Node = talktone_player): + var snd = 26 +#region check every letter + match letter.to_upper(): + "A": snd = 0 + "B": snd = 1 + "C": snd = 2 + "D": snd = 3 + "E": snd = 4 + "F": snd = 5 + "G": snd = 6 + "H": snd = 7 + "I": snd = 8 + "J": snd = 9 + "K": snd = 10 + "L": snd = 11 + "M": snd = 12 + "N": snd = 13 + "O": snd = 14 + "P": snd = 15 + "Q": snd = 16 + "R": snd = 17 + "S": snd = 18 + "T": snd = 19 + "U": snd = 20 + "V": snd = 21 + "W": snd = 22 + "X": snd = 23 + "Y": snd = 24 + "Z": snd = 25 +#endregion + player.stream = sounds[snd] + var r = randf_range(pitch_minimum,pitch_maximum) + player.pitch_scale = r + player.play() + +func _on_spoke(letter: String, letter_index: int, speed: float) -> void: + if can_speak: + match tone_type: + ToneTypes.HALF_BEEP: + if letter_index % 2 == 0: + play_beep_tone() + ToneTypes.BEEP: + play_beep_tone() + ToneTypes.BLABBER: + play_blabber_tone() + ToneTypes.MARISESE: + play_marisese(letter) + +func on_talktone_finished(): + if scene.dialogue_automation_type == scene.DialogueAutomationTypes.AUTO_VOICE: + balloon.next(balloon.dialogue_line.next_id) + + +func _on_finished_typing(): + if scene.dialogue_automation_type == scene.DialogueAutomationTypes.AUTO_TEXT: + await get_tree().create_timer(scene.auto_text_delay).timeout + if balloon.dialogue_line.responses.size() == 0: + balloon.next(balloon.dialogue_line.next_id) diff --git a/addons/dvn/label/dvn_label.tscn b/addons/dvn/label/dvn_label.tscn new file mode 100644 index 0000000..35622ce --- /dev/null +++ b/addons/dvn/label/dvn_label.tscn @@ -0,0 +1,82 @@ +[gd_scene load_steps=71 format=3 uid="uid://cca3fm3pojb41"] + +[ext_resource type="Script" path="res://addons/dvn/label/dvn_label.gd" id="1_fv617"] +[ext_resource type="AudioStream" uid="uid://b5g1o68bedpma" path="res://dvn/test_resources/punchy_2.ogg" id="2_hquny"] +[ext_resource type="AudioStream" uid="uid://sm4230h82f5q" path="res://dvn/test_resources/blabber/pi1.wav" id="2_tuq54"] +[ext_resource type="AudioStream" uid="uid://b5kfcwr6q6dps" path="res://dvn/test_resources/blabber/fal1.wav" id="3_bmk75"] +[ext_resource type="AudioStream" uid="uid://bg3bavm00pcnk" path="res://dvn/test_resources/blabber/pe1.wav" id="3_d0ft6"] +[ext_resource type="AudioStream" uid="uid://bpgaqfi7u7lxs" path="res://dvn/test_resources/blabber/far1.wav" id="4_1qnca"] +[ext_resource type="AudioStream" uid="uid://t3re1rycy7j2" path="res://dvn/test_resources/blabber/ga1.wav" id="5_cbw33"] +[ext_resource type="AudioStream" uid="uid://0v1iv2ra8x8w" path="res://dvn/test_resources/blabber/ga2.wav" id="6_40gsr"] +[ext_resource type="AudioStream" uid="uid://b2wynph473uvs" path="res://dvn/test_resources/blabber/le1.wav" id="7_ibxmc"] +[ext_resource type="AudioStream" uid="uid://dqltsvqf3k6vc" path="res://dvn/test_resources/blabber/ne1'.wav" id="8_jtpjw"] +[ext_resource type="AudioStream" uid="uid://dfv7i773v1345" path="res://dvn/test_resources/blabber/ni.wav" id="9_54x41"] +[ext_resource type="AudioStream" uid="uid://dxfs35l47g73l" path="res://dvn/test_resources/blabber/pa1.wav" id="10_u3rmo"] +[ext_resource type="AudioStream" uid="uid://chppepwyeaxo1" path="res://dvn/test_resources/blabber/ri1.wav" id="13_qjq1i"] +[ext_resource type="AudioStream" uid="uid://dalsdbfgokvh8" path="res://dvn/test_resources/blabber/ri2.wav" id="14_ubu0w"] +[ext_resource type="AudioStream" uid="uid://mwypw3x0tsjd" path="res://dvn/test_resources/blabber/sd1.wav" id="15_8x2tu"] +[ext_resource type="AudioStream" uid="uid://g64h12p8xumh" path="res://dvn/test_resources/blabber/sd2.wav" id="16_doa2h"] +[ext_resource type="AudioStream" uid="uid://do4bmxgaj20n" path="res://dvn/test_resources/blabber/sd3.wav" id="17_l6dov"] +[ext_resource type="AudioStream" uid="uid://5fmqnqdna8lv" path="res://dvn/test_resources/blabber/sd4.wav" id="18_pdvjt"] +[ext_resource type="AudioStream" uid="uid://bxjkrlc4vt2kh" path="res://dvn/test_resources/blabber/sd5.wav" id="19_4s5lc"] +[ext_resource type="AudioStream" uid="uid://b0ys7cac48mox" path="res://dvn/test_resources/blabber/sd6.wav" id="20_m42sg"] +[ext_resource type="AudioStream" uid="uid://i77kull066ki" path="res://dvn/test_resources/blabber/sd7.wav" id="21_hcdah"] +[ext_resource type="AudioStream" uid="uid://cx76n171p3cuj" path="res://dvn/test_resources/blabber/sd8.wav" id="22_cexo3"] +[ext_resource type="AudioStream" uid="uid://cq2ogvp0ojpfn" path="res://dvn/test_resources/blabber/sd9.wav" id="23_v8lqv"] +[ext_resource type="AudioStream" uid="uid://cnre5w258b5h8" path="res://dvn/test_resources/blabber/sd10.wav" id="24_o3iql"] +[ext_resource type="AudioStream" uid="uid://0hucylbigf3v" path="res://dvn/test_resources/blabber/sd11.wav" id="25_577es"] +[ext_resource type="AudioStream" uid="uid://61m5vy2qnxog" path="res://dvn/test_resources/blabber/sd12.wav" id="26_yuaul"] +[ext_resource type="AudioStream" uid="uid://cirx6t05t8ao0" path="res://dvn/test_resources/blabber/sd13.wav" id="27_nlfp5"] +[ext_resource type="AudioStream" uid="uid://c36rbn6sic5pt" path="res://dvn/test_resources/blabber/sd14.wav" id="28_3ag1d"] +[ext_resource type="AudioStream" uid="uid://bpa2mw442i3xc" path="res://dvn/test_resources/blabber/sd15.wav" id="29_ph7ej"] +[ext_resource type="AudioStream" uid="uid://cjl1n6g2m36b" path="res://dvn/test_resources/blabber/sd16.wav" id="30_envgi"] +[ext_resource type="AudioStream" uid="uid://ge3im18rj7ay" path="res://dvn/test_resources/blabber/sd17.wav" id="31_6w17e"] +[ext_resource type="AudioStream" uid="uid://bhyypbcfh348o" path="res://dvn/test_resources/blabber/sd18.wav" id="32_ms2qy"] +[ext_resource type="AudioStream" uid="uid://gwk6piygd8ui" path="res://dvn/test_resources/blabber/sd19.wav" id="33_u3qhm"] +[ext_resource type="AudioStream" uid="uid://ceq1ke4reramj" path="res://dvn/test_resources/blabber/sd20.wav" id="34_r1oa5"] +[ext_resource type="AudioStream" uid="uid://8wjlqeg6b8xx" path="res://dvn/test_resources/blabber/sd21.wav" id="35_mqmkp"] +[ext_resource type="AudioStream" uid="uid://bqfn6evn120or" path="res://dvn/test_resources/blabber/sd22.wav" id="36_nlt07"] +[ext_resource type="AudioStream" uid="uid://i7lo7bm16vff" path="res://dvn/test_resources/blabber/sd23.wav" id="37_mstcy"] +[ext_resource type="AudioStream" uid="uid://bax606i3nxh7l" path="res://dvn/test_resources/blabber/ss1.wav" id="38_0v0fh"] +[ext_resource type="AudioStream" uid="uid://37cucmolvd3f" path="res://dvn/test_resources/blabber/ta1.wav" id="39_bhuw4"] +[ext_resource type="AudioStream" uid="uid://c58ka00u052yv" path="res://dvn/test_resources/blabber/te1.wav" id="40_i10fu"] +[ext_resource type="AudioStream" uid="uid://dcqmpdxusohbq" path="res://dvn/test_resources/blabber/ti1.wav" id="41_ijnny"] +[ext_resource type="AudioStream" uid="uid://dtdt4e3u6nvnv" path="res://dvn/test_resources/blabber/to1.wav" id="42_b88mp"] +[ext_resource type="AudioStream" uid="uid://i5d6kk1knsma" path="res://dvn/test_resources/blabber/za1.wav" id="43_2ojxd"] +[ext_resource type="AudioStream" uid="uid://lj6cmjs2fcoy" path="res://dvn/test_resources/marisese/a.ogg" id="44_0vfbl"] +[ext_resource type="AudioStream" uid="uid://hpua870udnef" path="res://dvn/test_resources/marisese/b.ogg" id="45_61hs3"] +[ext_resource type="AudioStream" uid="uid://cjvp4618k1655" path="res://dvn/test_resources/marisese/c.ogg" id="46_liuih"] +[ext_resource type="AudioStream" uid="uid://mdubpok7ngrq" path="res://dvn/test_resources/marisese/d.ogg" id="47_r6a1e"] +[ext_resource type="AudioStream" uid="uid://b4au507qswa1v" path="res://dvn/test_resources/marisese/e.ogg" id="48_llf7d"] +[ext_resource type="AudioStream" uid="uid://d1osi4yd264ha" path="res://dvn/test_resources/marisese/f.ogg" id="49_lu43n"] +[ext_resource type="AudioStream" uid="uid://d2tf84enhxeb7" path="res://dvn/test_resources/marisese/g.ogg" id="50_x05xc"] +[ext_resource type="AudioStream" uid="uid://b8bbdmrbv4enj" path="res://dvn/test_resources/marisese/h.ogg" id="51_l7627"] +[ext_resource type="AudioStream" uid="uid://d3ckkydmnk8gl" path="res://dvn/test_resources/marisese/i.ogg" id="52_ho0bb"] +[ext_resource type="AudioStream" uid="uid://cimlinpp0blqe" path="res://dvn/test_resources/marisese/j.ogg" id="53_4wpxl"] +[ext_resource type="AudioStream" uid="uid://od5mo70vksk" path="res://dvn/test_resources/marisese/k.ogg" id="54_i0f61"] +[ext_resource type="AudioStream" uid="uid://cms646gy24tg1" path="res://dvn/test_resources/marisese/l.ogg" id="55_fjfa5"] +[ext_resource type="AudioStream" uid="uid://drcrhooamcuv4" path="res://dvn/test_resources/marisese/m.ogg" id="56_u00wn"] +[ext_resource type="AudioStream" uid="uid://bqoygbln7xe5b" path="res://dvn/test_resources/marisese/n.ogg" id="57_d5p6b"] +[ext_resource type="AudioStream" uid="uid://nrhmwe1yb04k" path="res://dvn/test_resources/marisese/o.ogg" id="58_uk4g0"] +[ext_resource type="AudioStream" uid="uid://hycxcbqq6i6d" path="res://dvn/test_resources/marisese/p.ogg" id="59_nntae"] +[ext_resource type="AudioStream" uid="uid://fkdc5nuwwtrv" path="res://dvn/test_resources/marisese/q.ogg" id="60_3nwmx"] +[ext_resource type="AudioStream" uid="uid://cnw5pe2mew1ns" path="res://dvn/test_resources/marisese/r.ogg" id="61_81l4p"] +[ext_resource type="AudioStream" uid="uid://dr52n8ld32c3h" path="res://dvn/test_resources/marisese/s.ogg" id="62_mb7y7"] +[ext_resource type="AudioStream" uid="uid://loxlrrvh88gx" path="res://dvn/test_resources/marisese/t.ogg" id="63_0rkin"] +[ext_resource type="AudioStream" uid="uid://borglhy7pdu7a" path="res://dvn/test_resources/marisese/u.ogg" id="64_81htt"] +[ext_resource type="AudioStream" uid="uid://cwgc5q6gkk24m" path="res://dvn/test_resources/marisese/v.ogg" id="65_j0h54"] +[ext_resource type="AudioStream" uid="uid://d3d4qd504q88s" path="res://dvn/test_resources/marisese/w.ogg" id="66_qvihc"] +[ext_resource type="AudioStream" uid="uid://2yfoybsar237" path="res://dvn/test_resources/marisese/x.ogg" id="67_5y7v3"] +[ext_resource type="AudioStream" uid="uid://bl6crwxrpbtn1" path="res://dvn/test_resources/marisese/y.ogg" id="68_k2fgx"] +[ext_resource type="AudioStream" uid="uid://24xlk8xji84c" path="res://dvn/test_resources/marisese/z.ogg" id="69_gfbuo"] +[ext_resource type="AudioStream" uid="uid://dov7x4duhpcmv" path="res://dvn/test_resources/marisese/null.ogg" id="70_cva4i"] + +[node name="DVNLabel" type="RichTextLabel"] +script = ExtResource("1_fv617") +talktone_player_path = NodePath("../../../../../AudioStreamPlayer") +tone_type = 3 +beep_noise = ExtResource("2_hquny") +blabber_noises = Array[Resource]([ExtResource("3_bmk75"), ExtResource("4_1qnca"), ExtResource("5_cbw33"), ExtResource("6_40gsr"), ExtResource("7_ibxmc"), ExtResource("8_jtpjw"), ExtResource("9_54x41"), ExtResource("10_u3rmo"), ExtResource("3_d0ft6"), ExtResource("2_tuq54"), ExtResource("13_qjq1i"), ExtResource("14_ubu0w"), ExtResource("15_8x2tu"), ExtResource("16_doa2h"), ExtResource("17_l6dov"), ExtResource("18_pdvjt"), ExtResource("19_4s5lc"), ExtResource("20_m42sg"), ExtResource("21_hcdah"), ExtResource("22_cexo3"), ExtResource("23_v8lqv"), ExtResource("24_o3iql"), ExtResource("25_577es"), ExtResource("26_yuaul"), ExtResource("27_nlfp5"), ExtResource("28_3ag1d"), ExtResource("29_ph7ej"), ExtResource("30_envgi"), ExtResource("31_6w17e"), ExtResource("32_ms2qy"), ExtResource("33_u3qhm"), ExtResource("34_r1oa5"), ExtResource("35_mqmkp"), ExtResource("36_nlt07"), ExtResource("37_mstcy"), ExtResource("38_0v0fh"), ExtResource("39_bhuw4"), ExtResource("40_i10fu"), ExtResource("41_ijnny"), ExtResource("42_b88mp"), ExtResource("43_2ojxd")]) +marisese_noises = Array[Resource]([ExtResource("44_0vfbl"), ExtResource("45_61hs3"), ExtResource("46_liuih"), ExtResource("47_r6a1e"), ExtResource("48_llf7d"), ExtResource("49_lu43n"), ExtResource("50_x05xc"), ExtResource("51_l7627"), ExtResource("52_ho0bb"), ExtResource("53_4wpxl"), ExtResource("54_i0f61"), ExtResource("55_fjfa5"), ExtResource("56_u00wn"), ExtResource("57_d5p6b"), ExtResource("58_uk4g0"), ExtResource("59_nntae"), ExtResource("60_3nwmx"), ExtResource("61_81l4p"), ExtResource("62_mb7y7"), ExtResource("63_0rkin"), ExtResource("64_81htt"), ExtResource("65_j0h54"), ExtResource("66_qvihc"), ExtResource("67_5y7v3"), ExtResource("68_k2fgx"), ExtResource("69_gfbuo"), ExtResource("70_cva4i")]) + +[connection signal="spoke" from="." to="." method="_on_spoke"] diff --git a/addons/dvn/plugin.cfg b/addons/dvn/plugin.cfg new file mode 100644 index 0000000..7c154a2 --- /dev/null +++ b/addons/dvn/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="DVN" +description="Expansion of Nathan Hoad's \"Dialogue Manager\" addon." +author="PennyRigate" +version="1.0" +script="dvn_plugin.gd" diff --git a/addons/dvn/sound_player/sound.gd b/addons/dvn/sound_player/sound.gd new file mode 100644 index 0000000..e4235e8 --- /dev/null +++ b/addons/dvn/sound_player/sound.gd @@ -0,0 +1,4 @@ +extends AudioStreamPlayer + +func _on_finished() -> void: + queue_free() diff --git a/addons/dvn/sound_player/sound.tscn b/addons/dvn/sound_player/sound.tscn new file mode 100644 index 0000000..be11cbd --- /dev/null +++ b/addons/dvn/sound_player/sound.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://bldqqpajcj62n"] + +[ext_resource type="Script" path="res://addons/dvn/sound_player/sound.gd" id="1_boi0g"] + +[node name="Sound" type="AudioStreamPlayer"] +bus = &"SFX" +script = ExtResource("1_boi0g") + +[connection signal="finished" from="." to="." method="_on_finished"] diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..9d8b7fa --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..62b612a --- /dev/null +++ b/icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://g6mbh8mhg11n" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..a5b85b8 --- /dev/null +++ b/project.godot @@ -0,0 +1,46 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="dvn" +run/main_scene="res://dvn/test_resources/test_system.tscn" +config/features=PackedStringArray("4.3", "GL Compatibility") +config/icon="res://icon.svg" + +[audio] + +buses/default_bus_layout="res://addons/dvn/default_bus_layout.tres" + +[autoload] + +DialogueManager="*res://addons/dialogue_manager/dialogue_manager.gd" + +[dialogue_manager] + +runtime/balloon_path="res:///balloon.tscn" + +[display] + +window/size/viewport_width=640 +window/size/viewport_height=480 + +[editor_plugins] + +enabled=PackedStringArray("res://addons/dialogue_manager/plugin.cfg", "res://addons/dvn/plugin.cfg") + +[internationalization] + +locale/translations_pot_files=PackedStringArray("res://addons/dvn/test_resources/test_dialgoue.dialogue") + +[rendering] + +renderer/rendering_method="gl_compatibility" +renderer/rendering_method.mobile="gl_compatibility"