diff --git a/Assets/Dialog/doc-first-encounter.dtl b/Assets/Dialog/doc-first-encounter.dtl new file mode 100644 index 0000000..81a4a6c --- /dev/null +++ b/Assets/Dialog/doc-first-encounter.dtl @@ -0,0 +1,26 @@ +Join Doc +Doc: The name... +Doc: is... +Doc: I'm the Two Time, back-to-back, consecutive years... +Doc: You were still in your little diapers... +Doc: Still in your little onesies, pajamas, little footsy pajamas. He-man pajamas. Spiderman pajamas. +Doc: You are still sleeping on the top of your bunk bed, underneath your blankets, scared to death of the boogieman underneath your bed! +Doc: You were still there. +Doc: While I was out. +Doc: At Marine World. +Doc: Winning. +Doc: Two years in a row. +Doc: The 1993-1994 Blockbuster video game championship. +Doc: Right in front of the killer whale exhibit. 200+ TVs. NBA Jam. +Doc: I AM THE... +Doc: I'm an international video game superstar. +Doc: I'm 6'8", 37" vertical leap. A jawline that will cut, slice, deliver anything that you will ever dream of right to your front door. +Doc: Nothing but success. Nothing but success. +Doc: That's what my life's about. Period. +Doc: And the arena today, ladies and gentlemen... +Doc: is wide open, and the crowds are flooding in. VIP seating. Skybox section. Reserved for the Slick Daddy Club. +Doc: The Slick Daddy Club looking so damn good today. I'm feeling so damn good, it's OBVIOUS. +Doc: The V of success. +Challenge Doc, The Two Time? +- Yes +- No diff --git a/Assets/Dialog/doc.dialogue b/Assets/Dialog/doc.dialogue new file mode 100644 index 0000000..38eaf46 --- /dev/null +++ b/Assets/Dialog/doc.dialogue @@ -0,0 +1,28 @@ +~ duel + +Doc, The Two Time: The name... +Doc, The Two Time: is Doctor... +Doc, The Two Time: Disrespect. +Doc, The Two Time: I'm the two-time, back to back, consecutive years... +Doc, The Two Time: A lot of you were still in your little diapers. +Doc, The Two Time: Still in your little onesies, pajamas. Little footsy pajamas. He-Man pajamas. Spiderman pajamas. +Doc, The Two Time: A lot of you were still sleeping on the top of your bunk bed, underneath your blankets, scared to death of the boogieman underneath your bed. +Doc, The Two Time: A lot of you were still there. +Doc, The Two Time: While I was out... +Doc, The Two Time: at Marine World. +Doc, The Two Time: Winning. +Doc, The Two Time: Two years in a row. The 1993-1994 Blockbuster video game championship right in front of the killer whale exhibit. 200+ TVs. NBA Jam. +Doc, The Two Time: I AM THE... +Doc, The Two Time: I'm an international videogame superstar. I'm 6'8", 37" vertical leap. A jawline that will cut, slice, deliver anything that you will ever dream of right to your front door. +Doc, The Two Time: Nothing but success. +Doc, The Two Time: That's what my life's about. Period. +Doc, The Two Time: And the arena today, ladies and gentlemen... +Doc, The Two Time: is wide open, and the crowds are flooding in. VIP seating. Skybox section. Reserved for the Slick Daddy Club. +Doc, The Two Time: The Slick Daddy Club looking so damn good today. I'm feeling so damn good. It's obvious. +Doc, The Two Time: The V of success. +Challenge [b]Doc, The Two Time[/b]? +- Yes + do emit("SummonBoss", "Doc") +- No => END + +=> END diff --git a/Assets/Dialog/doc.dialogue.import b/Assets/Dialog/doc.dialogue.import new file mode 100644 index 0000000..7a77b67 --- /dev/null +++ b/Assets/Dialog/doc.dialogue.import @@ -0,0 +1,15 @@ +[remap] + +importer="dialogue_manager_compiler_8" +type="Resource" +uid="uid://dntkvjjr8mrgf" +path="res://.godot/imported/doc.dialogue-9af7b89bed22cfead99a33235819bbdf.tres" + +[deps] + +source_file="res://Assets/Dialog/doc.dialogue" +dest_files=["res://.godot/imported/doc.dialogue-9af7b89bed22cfead99a33235819bbdf.tres"] + +[params] + +defaults=true diff --git a/Assets/Sounds/calm-storm-ambient.mp3 b/Assets/Sounds/calm-storm-ambient.mp3 new file mode 100644 index 0000000..843dd51 Binary files /dev/null and b/Assets/Sounds/calm-storm-ambient.mp3 differ diff --git a/Assets/Sounds/calm-storm-ambient.mp3.import b/Assets/Sounds/calm-storm-ambient.mp3.import new file mode 100644 index 0000000..e1ed847 --- /dev/null +++ b/Assets/Sounds/calm-storm-ambient.mp3.import @@ -0,0 +1,19 @@ +[remap] + +importer="mp3" +type="AudioStreamMP3" +uid="uid://dy4qjflo1k28b" +path="res://.godot/imported/calm-storm-ambient.mp3-0433d7efeb05231869c7e6e6134f0645.mp3str" + +[deps] + +source_file="res://Assets/Sounds/calm-storm-ambient.mp3" +dest_files=["res://.godot/imported/calm-storm-ambient.mp3-0433d7efeb05231869c7e6e6134f0645.mp3str"] + +[params] + +loop=false +loop_offset=0 +bpm=0 +beat_count=0 +bar_beats=4 diff --git a/Assets/Sprites/Characters/doc.ase b/Assets/Sprites/Characters/doc.ase index 14a189e..b20a9be 100644 Binary files a/Assets/Sprites/Characters/doc.ase and b/Assets/Sprites/Characters/doc.ase differ diff --git a/Assets/Sprites/Characters/doc.png b/Assets/Sprites/Characters/doc.png index 2141d27..d537e24 100644 Binary files a/Assets/Sprites/Characters/doc.png and b/Assets/Sprites/Characters/doc.png differ diff --git a/Assets/Sprites/Particles/DocIntroParticles.tres b/Assets/Sprites/Particles/DocIntroParticles.tres index ab58291..bcb9aa7 100644 --- a/Assets/Sprites/Particles/DocIntroParticles.tres +++ b/Assets/Sprites/Particles/DocIntroParticles.tres @@ -1,13 +1,14 @@ [gd_resource type="ParticleProcessMaterial" load_steps=3 format=3 uid="uid://rcjujd5dv7lm"] [sub_resource type="Gradient" id="Gradient_v7xci"] -offsets = PackedFloat32Array(0.525926, 0.6) +offsets = PackedFloat32Array(0.525926, 0.585185) colors = PackedColorArray(0, 0, 0, 1, 1, 0, 0, 1) [sub_resource type="GradientTexture1D" id="GradientTexture1D_pntll"] gradient = SubResource("Gradient_v7xci") [resource] +particle_flag_rotate_y = true particle_flag_disable_z = true spread = 180.0 gravity = Vector3(0, 0, 0) diff --git a/Characters/Boss.cs b/Characters/Boss.cs index f9c57dc..de30fd4 100644 --- a/Characters/Boss.cs +++ b/Characters/Boss.cs @@ -19,7 +19,7 @@ public abstract partial class Boss : Enemy private bool _isActive; [Export] - public bool IsActive + public virtual bool IsActive { get => _isActive; set diff --git a/Characters/Doc.cs b/Characters/Doc.cs index b39e7bb..18b4c8e 100644 --- a/Characters/Doc.cs +++ b/Characters/Doc.cs @@ -2,6 +2,7 @@ using Godot; using GodotUtilities; using SupaLidlGame.Extensions; using SupaLidlGame.State.Character; +using DialogueManagerRuntime; namespace SupaLidlGame.Characters; @@ -9,6 +10,8 @@ public partial class Doc : Boss { public AnimationPlayer TelegraphAnimation { get; set; } + public AnimationPlayer MiscAnimation { get; set; } + [Export] public Items.Weapons.Sword Lance { get; set; } @@ -16,6 +19,19 @@ public partial class Doc : Boss protected CharacterDashState _dashState; protected float _originalDashModifier; + [Export] + public override bool IsActive + { + get => base.IsActive; + set + { + base.IsActive = value; + var introState = BossStateMachine + .GetNode("Intro"); + BossStateMachine.ChangeState(introState); + } + } + public override float Health { get => base.Health; @@ -58,11 +74,34 @@ public partial class Doc : Boss public override void _Ready() { TelegraphAnimation = GetNode("Animations/Telegraph"); + MiscAnimation = GetNode("Animations/Misc"); + base._Ready(); _dashState = StateMachine.FindChildOfType(); _originalDashModifier = _dashState.VelocityModifier; + var dialog = GD.Load("res://Assets/Dialog/doc.dialogue"); + + GetNode("InteractionTrigger") + .Interaction += () => + { + //DialogueManager.ShowExampleDialogueBalloon(dialog, "duel"); + this.GetAncestor().DialogueBalloon + .Start(dialog, "duel"); + //.Call("start", dialog, "duel"); + }; + + GetNode("/root/GlobalState") + .SummonBoss += (string name) => + { + if (name == "Doc") + { + IsActive = true; + Inventory.SelectedItem = Lance; + } + }; + // when we are hurt, start the boss fight Hurt += (Events.HealthChangedArgs args) => @@ -71,6 +110,7 @@ public partial class Doc : Boss { IsActive = true; Inventory.SelectedItem = Lance; + //DialogueManager.ShowExampleDialogueBalloon(); } }; } diff --git a/Characters/Doc.tscn b/Characters/Doc.tscn index 09b70e9..28576e7 100644 --- a/Characters/Doc.tscn +++ b/Characters/Doc.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=62 format=3 uid="uid://d2skjvvx6fal0"] +[gd_scene load_steps=66 format=3 uid="uid://d2skjvvx6fal0"] [ext_resource type="Script" path="res://Characters/Doc.cs" id="2_3elet"] [ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="2_5jxom"] @@ -19,6 +19,7 @@ [ext_resource type="AudioStream" uid="uid://k6kpdj1kv0jg" path="res://Assets/Sounds/splat.ogg" id="9_stm0e"] [ext_resource type="Script" path="res://State/NPC/Doc/DocShungiteSpikeState.cs" id="10_bgs6o"] [ext_resource type="PackedScene" uid="uid://cqx56u46g2c16" path="res://Entities/CompactDisc.tscn" id="11_23p3o"] +[ext_resource type="Script" path="res://State/NPC/Doc/DocIntroState.cs" id="11_lt771"] [ext_resource type="Script" path="res://State/NPC/Doc/DocChooseAttackState.cs" id="12_45x13"] [ext_resource type="Script" path="res://State/NPC/Doc/DocUnwantedFrequencyState.cs" id="12_d51jv"] [ext_resource type="PackedScene" uid="uid://1y5r6sklwgrp" path="res://Entities/UnwantedFrequency.tscn" id="13_lpj21"] @@ -32,6 +33,7 @@ [ext_resource type="PackedScene" uid="uid://p7oijq6dbvvk" path="res://Items/Weapons/DocLance.tscn" id="24_2es2r"] [ext_resource type="PackedScene" uid="uid://bauucuqvjwbxp" path="res://Items/Weapons/DocLanceHold.tscn" id="26_0tntj"] [ext_resource type="AudioStream" uid="uid://cqj44je3mvk60" path="res://Assets/Sounds/rauuul.wav" id="26_js7p2"] +[ext_resource type="PackedScene" uid="uid://dldnp8eunxj3q" path="res://BoundingBoxes/InteractionTrigger.tscn" id="33_08dyq"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_7n7iy"] resource_local_to_scene = true @@ -397,11 +399,102 @@ _data = { "stun": ExtResource("21_ixn4k") } +[sub_resource type="Animation" id="Animation_ucpsk"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("../Sprite:frame") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [0] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("../Effects/IntroParticles:emitting") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [false] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("../Sprite:scale") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(1, 1)] +} + [sub_resource type="Animation" id="Animation_uemm6"] resource_name = "intro" +length = 3.0 +tracks/0/type = "method" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("../Effects/BattleCry") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"values": [{ +"args": [0.0], +"method": &"play" +}] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("../Sprite:frame") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [16] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("../Effects/IntroParticles:emitting") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 3), +"transitions": PackedFloat32Array(1, 1), +"update": 1, +"values": [true, false] +} +tracks/3/type = "value" +tracks/3/imported = false +tracks/3/enabled = true +tracks/3/path = NodePath("../Sprite:scale") +tracks/3/interp = 1 +tracks/3/loop_wrap = true +tracks/3/keys = { +"times": PackedFloat32Array(0, 0.1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(2, 0.5), Vector2(1, 1)] +} [sub_resource type="AnimationLibrary" id="AnimationLibrary_kjxam"] _data = { +"RESET": SubResource("Animation_ucpsk"), "intro": SubResource("Animation_uemm6") } @@ -456,6 +549,9 @@ size = Vector2(11, 5) [sub_resource type="RectangleShape2D" id="RectangleShape2D_8lxmf"] size = Vector2(16, 19) +[sub_resource type="CircleShape2D" id="CircleShape2D_8hwat"] +radius = 16.0 + [node name="Doc" type="CharacterBody2D" node_paths=PackedStringArray("Lance", "BossStateMachine", "Sprite", "Inventory", "StateMachine", "Hurtbox")] y_sort_enabled = true texture_filter = 3 @@ -500,6 +596,11 @@ Character = NodePath("../..") script = ExtResource("6_kjpug") InitialState = NodePath("Telegraph") +[node name="Intro" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("NextState", "NPC")] +script = ExtResource("11_lt771") +NextState = NodePath("../Telegraph") +NPC = NodePath("../..") + [node name="Telegraph" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("TelegraphAnimationPlayer", "AttackState", "NPC")] script = ExtResource("7_tfwbh") TelegraphAnimationPlayer = NodePath("../../Animations/Telegraph") @@ -533,17 +634,22 @@ ChooseAttackState = NodePath("../ChooseAttack") Doc = NodePath("../..") NPC = NodePath("../..") +[node name="LanceIntro" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("NextState", "NPC")] +script = ExtResource("11_lt771") +NextState = NodePath("../Lance") +NPC = NodePath("../..") + [node name="Lance" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("ExitState", "NPC")] script = ExtResource("15_dmd05") ExitState = NodePath("../Exit") NPC = NodePath("../..") -[node name="ChooseAttack" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("DartState", "SpikeState", "UnwantedFrequencyState", "LanceState", "ExitState", "NPC")] +[node name="ChooseAttack" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("DartState", "SpikeState", "UnwantedFrequencyState", "LanceIntroState", "ExitState", "NPC")] script = ExtResource("12_45x13") DartState = NodePath("../Dart") SpikeState = NodePath("../Spike") UnwantedFrequencyState = NodePath("../UnwantedFrequency") -LanceState = NodePath("../Lance") +LanceIntroState = NodePath("../LanceIntro") ExitState = NodePath("../Exit") NPC = NodePath("../..") @@ -607,6 +713,7 @@ emitting = false amount = 32 process_material = ExtResource("19_q4rt1") texture = ExtResource("19_p0p6c") +lifetime = 0.5 [node name="Dash" type="GPUParticles2D" parent="Effects"] position = Vector2(0, -8) @@ -626,7 +733,7 @@ use_parent_material = true position = Vector2(-0.5, 0) texture = ExtResource("3_rs44f") offset = Vector2(0, -8) -hframes = 16 +hframes = 17 [node name="CollisionShape2D" type="CollisionShape2D" parent="."] position = Vector2(-0.5, -1.5) @@ -652,4 +759,11 @@ Items = Array[Node2D]([]) [node name="HurtSound" type="AudioStreamPlayer2D" parent="."] stream = ExtResource("9_stm0e") +[node name="InteractionTrigger" parent="." instance=ExtResource("33_08dyq")] + +[node name="CollisionShape2D" parent="InteractionTrigger" index="0"] +position = Vector2(0, -8) +shape = SubResource("CircleShape2D_8hwat") + [editable path="Hurtbox"] +[editable path="InteractionTrigger"] diff --git a/Dialogue/Balloon.cs b/Dialogue/Balloon.cs new file mode 100644 index 0000000..c1f057c --- /dev/null +++ b/Dialogue/Balloon.cs @@ -0,0 +1,271 @@ +using Godot; +using Godot.Collections; +using DialogueManagerRuntime; + +namespace SupaLidlGame.Dialogue; + +// https://github.com/nathanhoad/godot_dialogue_manager/blob/main/examples/csharp_balloon/Balloon.cs +// TODO: rewrite this + +public partial class Balloon : CanvasLayer +{ + Color VISIBLE = new Color(1f, 1f, 1f, 1f); + Color INVISIBLE = new Color(1f, 1f, 1f, 0f); + + ColorRect balloon; + MarginContainer margin; + RichTextLabel characterLabel; + RichTextLabel dialogueLabel; + VBoxContainer responsesMenu; + RichTextLabel responseTemplate; + + Resource resource; + Array temporaryGameStates = new Array(); + bool isWaitingForInput = false; + + DialogueLine dialogueLine; + DialogueLine DialogueLine + { + get => dialogueLine; + set + { + isWaitingForInput = false; + + if (value == null) + { + QueueFree(); + return; + } + + dialogueLine = value; + + UpdateDialogueLine(); + } + } + + + public override void _Ready() + { + balloon = GetNode("Balloon"); + margin = GetNode("Balloon/Margin"); + characterLabel = GetNode("Balloon/Margin/VBox/CharacterLabel"); + dialogueLabel = GetNode("Balloon/Margin/VBox/DialogueLabel"); + responsesMenu = GetNode("Balloon/Margin/VBox/Responses"); + responseTemplate = GetNode("Balloon/Margin/VBox/ResponseTemplate"); + GD.Print("responses menu is " + responsesMenu); + GD.Print("lulw"); + + responseTemplate.Hide(); + balloon.Hide(); + balloon.CustomMinimumSize = new Vector2(balloon.GetViewportRect().Size.X, balloon.CustomMinimumSize.Y); + + balloon.GuiInput += (inputEvent) => + { + + if (!isWaitingForInput) return; + if (GetResponses().Count > 0) return; + + GetViewport().SetInputAsHandled(); + + if (inputEvent is InputEventMouseButton && inputEvent.IsPressed() && (inputEvent as InputEventMouseButton).ButtonIndex == MouseButton.Left) + { + Next(dialogueLine.NextId); + } + else if (inputEvent.IsActionPressed("ui_accept") && GetViewport().GuiGetFocusOwner() == balloon) + { + Next(dialogueLine.NextId); + } + + }; + + margin.Resized += () => HandleResize(); + + Engine.GetSingleton("DialogueManager").Connect("mutated", Callable.From((Dictionary mutation) => + { + isWaitingForInput = false; + balloon.Hide(); + })); + } + + + public override void _UnhandledInput(InputEvent inputEvent) + { + // Only the balloon is allowed to handle input while it's showing + GetViewport().SetInputAsHandled(); + } + + + public async void Start(Resource dialogueResource, string title, Array extraGameStates = null) + { + temporaryGameStates = extraGameStates; + isWaitingForInput = false; + resource = dialogueResource; + + DialogueLine = await DialogueManager.GetNextDialogueLine(resource, title, temporaryGameStates ?? new Array()); + } + + + private async void Next(string nextId) + { + DialogueLine = await DialogueManager.GetNextDialogueLine(resource, nextId, temporaryGameStates ?? new Array()); + } + + + /// Helpers + + + private void ConfigureMenu() + { + balloon.FocusMode = Control.FocusModeEnum.None; + + var items = GetResponses(); + for (int i = 0; i < items.Count; i++) + { + var item = items[i]; + + item.FocusMode = Control.FocusModeEnum.All; + + item.FocusNeighborLeft = item.GetPath(); + item.FocusNeighborRight = item.GetPath(); + + if (i == 0) + { + item.FocusNeighborTop = item.GetPath(); + item.FocusPrevious = item.GetPath(); + } + else + { + item.FocusNeighborTop = items[i - 1].GetPath(); + item.FocusPrevious = items[i - 1].GetPath(); + } + + if (i == items.Count - 1) + { + item.FocusNeighborBottom = item.GetPath(); + item.FocusNext = item.GetPath(); + } + else + { + item.FocusNeighborBottom = items[i + 1].GetPath(); + item.FocusNext = items[i + 1].GetPath(); + } + + item.MouseEntered += () => + { + if (item.Name.ToString().Contains("Disallowed")) return; + + item.GrabFocus(); + }; + item.GuiInput += (inputEvent) => + { + if (item.Name.ToString().Contains("Disallowed")) return; + + if (inputEvent is InputEventMouseButton && inputEvent.IsPressed() && (inputEvent as InputEventMouseButton).ButtonIndex == MouseButton.Left) + { + Next(dialogueLine.Responses[item.GetIndex()].NextId); + } + else if (inputEvent.IsActionPressed("ui_accept") && GetResponses().Contains(item)) + { + Next(dialogueLine.Responses[item.GetIndex()].NextId); + } + }; + } + + items[0].GrabFocus(); + } + + + private Array GetResponses() + { + Array items = new Array(); + foreach (Control child in responsesMenu.GetChildren()) + { + if (child.Name.ToString().Contains("Disallowed")) continue; + + items.Add(child); + } + + return items; + } + + + private void HandleResize() + { + if (!IsInstanceValid(margin)) + { + CallDeferred("HandleResize"); + return; + } + + balloon.CustomMinimumSize = new Vector2(balloon.CustomMinimumSize.X, margin.Size.Y); + balloon.Size = new Vector2(balloon.Size.X, 0); + Vector2 viewportSize = balloon.GetViewportRect().Size; + balloon.GlobalPosition = new Vector2((viewportSize.X - balloon.Size.X) * 0.5f, viewportSize.Y - balloon.Size.Y); + } + + + private async void UpdateDialogueLine() + { + foreach (Control child in responsesMenu.GetChildren()) + { + child.Free(); + } + + characterLabel.Visible = !string.IsNullOrEmpty(dialogueLine.Character); + characterLabel.Text = dialogueLine.Character; + + dialogueLabel.Modulate = INVISIBLE; + dialogueLabel.CustomMinimumSize = new Vector2(dialogueLabel.GetParent().Size.X - 1, dialogueLabel.CustomMinimumSize.Y); + dialogueLabel.Set("dialogue_line", dialogueLine); + + // Show any responses we have + responsesMenu.Modulate = INVISIBLE; + foreach (var response in dialogueLine.Responses) + { + RichTextLabel item = (RichTextLabel)responseTemplate.Duplicate(); + item.Name = $"Response{responsesMenu.GetChildCount()}"; + if (!response.IsAllowed) + { + item.Name = item.Name + "Disallowed"; + item.Modulate = new Color(item.Modulate, 0.4f); + } + item.Text = response.Text; + item.Show(); + responsesMenu.AddChild(item); + } + + // Show the balloon + balloon.Show(); + + dialogueLabel.Modulate = VISIBLE; + if (!string.IsNullOrEmpty(dialogueLine.Text)) + { + dialogueLabel.Call("type_out"); + await ToSignal(dialogueLabel, "finished_typing"); + } + + // Wait for input + if (dialogueLine.Responses.Count > 0) + { + responsesMenu.Modulate = VISIBLE; + ConfigureMenu(); + } + else if (!string.IsNullOrEmpty(dialogueLine.Time)) + { + float time = 0f; + if (!float.TryParse(dialogueLine.Time, out time)) + { + time = dialogueLine.Text.Length * 0.02f; + } + await ToSignal(GetTree().CreateTimer(time), "timeout"); + Next(dialogueLine.NextId); + } + else + { + isWaitingForInput = true; + balloon.FocusMode = Control.FocusModeEnum.All; + } + } +} + + diff --git a/Dialogue/balloon.gd b/Dialogue/balloon.gd new file mode 100644 index 0000000..58d1433 --- /dev/null +++ b/Dialogue/balloon.gd @@ -0,0 +1,212 @@ +extends CanvasLayer + + +@onready var balloon: ColorRect = $Balloon +@onready var margin: MarginContainer = $Balloon/Margin +@onready var character_label: RichTextLabel = $Balloon/Margin/VBox/CharacterLabel +@onready var dialogue_label := $Balloon/Margin/VBox/DialogueLabel +@onready var responses_menu: VBoxContainer = $Balloon/Margin/VBox/Responses +@onready var response_template: RichTextLabel = %ResponseTemplate + +## 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 + +## The current line +var dialogue_line: DialogueLine: + set(next_dialogue_line): + is_waiting_for_input = false + + if not next_dialogue_line: + queue_free() + return + + # Remove any previous responses + for child in responses_menu.get_children(): + responses_menu.remove_child(child) + child.queue_free() + + dialogue_line = next_dialogue_line + + character_label.visible = not dialogue_line.character.is_empty() + character_label.text = tr(dialogue_line.character, "dialogue") + + dialogue_label.modulate.a = 0 + dialogue_label.custom_minimum_size.x = dialogue_label.get_parent().size.x - 1 + dialogue_label.dialogue_line = dialogue_line + + # Show any responses we have + responses_menu.modulate.a = 0 + if dialogue_line.responses.size() > 0: + for response in dialogue_line.responses: + # Duplicate the template so we can grab the fonts, sizing, etc + var item: RichTextLabel = response_template.duplicate(0) + item.name = "Response%d" % responses_menu.get_child_count() + if not response.is_allowed: + item.name = String(item.name) + "Disallowed" + item.modulate.a = 0.4 + item.text = response.text + item.show() + responses_menu.add_child(item) + + # Show our balloon + balloon.show() + will_hide_balloon = false + + dialogue_label.modulate.a = 1 + 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: + responses_menu.modulate.a = 1 + configure_menu() + elif dialogue_line.time != null: + 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() + get: + return dialogue_line + + +func _ready() -> void: + response_template.hide() + balloon.hide() + balloon.custom_minimum_size.x = balloon.get_viewport_rect().size.x + + Engine.get_singleton("DialogueManager").mutated.connect(_on_mutated) + + +func _unhandled_input(_event: InputEvent) -> void: + # Only the balloon is allowed to handle input while it's showing + get_viewport().set_input_as_handled() + + +## Start some dialogue +func start(dialogue_resource: DialogueResource, title: String, extra_game_states: Array = []) -> void: + temporary_game_states = extra_game_states + is_waiting_for_input = false + resource = dialogue_resource + + self.dialogue_line = await resource.get_next_dialogue_line(title, temporary_game_states) + + +## 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) + + +### Helpers + + +# Set up keyboard movement and signals for the response menu +func configure_menu() -> void: + balloon.focus_mode = Control.FOCUS_NONE + + var items = get_responses() + for i in items.size(): + var item: Control = items[i] + + item.focus_mode = Control.FOCUS_ALL + + item.focus_neighbor_left = item.get_path() + item.focus_neighbor_right = item.get_path() + + if i == 0: + item.focus_neighbor_top = item.get_path() + item.focus_previous = item.get_path() + else: + item.focus_neighbor_top = items[i - 1].get_path() + item.focus_previous = items[i - 1].get_path() + + if i == items.size() - 1: + item.focus_neighbor_bottom = item.get_path() + item.focus_next = item.get_path() + else: + item.focus_neighbor_bottom = items[i + 1].get_path() + item.focus_next = items[i + 1].get_path() + + item.mouse_entered.connect(_on_response_mouse_entered.bind(item)) + item.gui_input.connect(_on_response_gui_input.bind(item)) + + items[0].grab_focus() + + +# Get a list of enabled items +func get_responses() -> Array: + var items: Array = [] + for child in responses_menu.get_children(): + if "Disallowed" in child.name: continue + items.append(child) + + return items + + +func handle_resize() -> void: + if not is_instance_valid(margin): + call_deferred("handle_resize") + return + + balloon.custom_minimum_size.y = margin.size.y + # Force a resize on only the height + balloon.size.y = 0 + var viewport_size = balloon.get_viewport_rect().size + balloon.global_position = Vector2((viewport_size.x - balloon.size.x) * 0.5, viewport_size.y - balloon.size.y) + + +### Signals + + +func _on_mutated(_mutation: Dictionary) -> void: + is_waiting_for_input = false + will_hide_balloon = true + get_tree().create_timer(0.1).timeout.connect(func(): + if will_hide_balloon: + will_hide_balloon = false + balloon.hide() + ) + + +func _on_response_mouse_entered(item: Control) -> void: + if "Disallowed" in item.name: return + + item.grab_focus() + + +func _on_response_gui_input(event: InputEvent, item: Control) -> void: + if "Disallowed" in item.name: return + + if event is InputEventMouseButton and event.is_pressed() and event.button_index == 1: + next(dialogue_line.responses[item.get_index()].next_id) + elif event.is_action_pressed("ui_accept") and item in get_responses(): + next(dialogue_line.responses[item.get_index()].next_id) + + +func _on_balloon_gui_input(event: InputEvent) -> void: + 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 == 1: + next(dialogue_line.next_id) + elif event.is_action_pressed("ui_accept") and get_viewport().gui_get_focus_owner() == balloon: + next(dialogue_line.next_id) + + +func _on_margin_resized() -> void: + handle_resize() diff --git a/Dialogue/balloon.tscn b/Dialogue/balloon.tscn new file mode 100644 index 0000000..39c9509 --- /dev/null +++ b/Dialogue/balloon.tscn @@ -0,0 +1,85 @@ +[gd_scene load_steps=7 format=3 uid="uid://73jm5qjy52vq"] + +[ext_resource type="Script" path="res://Dialogue/Balloon.cs" id="1_obwi7"] +[ext_resource type="PackedScene" uid="uid://ckvgyvclnwggo" path="res://addons/dialogue_manager/dialogue_label.tscn" id="2_a8ve6"] +[ext_resource type="Theme" uid="uid://cksjbu3vrup5" path="res://UI/Themes/supalidl.tres" id="2_kowbc"] +[ext_resource type="FontFile" uid="uid://bo3obq6sos7lu" path="res://Assets/Fonts/compass-pro.ttf" id="4_8e5aq"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5d24i"] +content_margin_left = 40.0 +content_margin_top = 5.0 +content_margin_right = 5.0 +content_margin_bottom = 5.0 +bg_color = Color(1, 1, 1, 0.25098) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_oj3c8"] +content_margin_left = 40.0 +content_margin_top = 5.0 +content_margin_right = 5.0 +content_margin_bottom = 5.0 +draw_center = false + +[node name="DialogBalloon" type="CanvasLayer"] +layer = 100 +script = ExtResource("1_obwi7") + +[node name="Balloon" type="ColorRect" parent="."] +color = Color(0.117647, 0.113725, 0.223529, 0.313726) + +[node name="Margin" type="MarginContainer" parent="Balloon"] +layout_mode = 0 +anchor_right = 1.0 +offset_bottom = 119.0 +grow_horizontal = 2 +theme_override_constants/margin_left = 20 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 20 +theme_override_constants/margin_bottom = 10 +metadata/_edit_layout_mode = 1 + +[node name="VBox" type="VBoxContainer" parent="Balloon/Margin"] +layout_mode = 2 +theme = ExtResource("2_kowbc") +theme_override_constants/separation = 10 + +[node name="CharacterLabel" type="RichTextLabel" parent="Balloon/Margin/VBox"] +layout_mode = 2 +mouse_filter = 1 +theme_override_colors/font_shadow_color = Color(0.0352941, 0.0392157, 0.0784314, 1) +theme_override_colors/font_outline_color = Color(0.117647, 0.113725, 0.223529, 1) +theme_override_constants/shadow_offset_x = 2 +theme_override_constants/shadow_offset_y = 3 +theme_override_constants/outline_size = 8 +bbcode_enabled = true +text = "Character" +fit_content = true +scroll_active = false + +[node name="DialogueLabel" parent="Balloon/Margin/VBox" instance=ExtResource("2_a8ve6")] +layout_mode = 2 +theme_override_colors/font_outline_color = Color(0.117647, 0.113725, 0.223529, 1) +theme_override_constants/outline_size = 4 +theme_override_fonts/normal_font = ExtResource("4_8e5aq") +text = "I bought a whole bunch of shungite." + +[node name="Responses" type="VBoxContainer" parent="Balloon/Margin/VBox"] +layout_mode = 2 +theme_override_constants/separation = 2 + +[node name="ResponseTemplate" type="RichTextLabel" parent="Balloon/Margin/VBox"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_colors/font_outline_color = Color(0.117647, 0.113725, 0.223529, 1) +theme_override_constants/outline_size = 4 +theme_override_styles/focus = SubResource("StyleBoxFlat_5d24i") +theme_override_styles/normal = SubResource("StyleBoxFlat_oj3c8") +bbcode_enabled = true +text = "Response" +fit_content = true +scroll_active = false +shortcut_keys_enabled = false +meta_underlined = false +hint_underlined = false + +[connection signal="gui_input" from="Balloon" to="." method="_on_balloon_gui_input"] +[connection signal="resized" from="Balloon/Margin" to="." method="_on_margin_resized"] diff --git a/Dialogue/small_balloon.tscn b/Dialogue/small_balloon.tscn new file mode 100644 index 0000000..ae1e4d9 --- /dev/null +++ b/Dialogue/small_balloon.tscn @@ -0,0 +1,87 @@ +[gd_scene load_steps=8 format=3 uid="uid://b361p61jmf257"] + +[ext_resource type="Script" path="res://Dialogue/balloon.gd" id="1_4u26j"] +[ext_resource type="PackedScene" uid="uid://ckvgyvclnwggo" path="res://addons/dialogue_manager/dialogue_label.tscn" id="2_a8ve6"] + +[sub_resource type="Theme" id="Theme_isg48"] +default_font_size = 9 + +[sub_resource type="Theme" id="Theme_owda0"] +default_font_size = 9 + +[sub_resource type="Theme" id="Theme_fakos"] +default_font_size = 9 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5d24i"] +content_margin_left = 20.0 +content_margin_top = 2.0 +content_margin_right = 2.0 +content_margin_bottom = 2.0 +bg_color = Color(1, 1, 1, 0.25098) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_oj3c8"] +content_margin_left = 20.0 +content_margin_top = 2.0 +content_margin_right = 2.0 +content_margin_bottom = 2.0 +draw_center = false + +[node name="ExampleBalloon" type="CanvasLayer"] +layer = 100 +script = ExtResource("1_4u26j") + +[node name="Balloon" type="ColorRect" parent="."] +color = Color(0, 0, 0, 1) + +[node name="Margin" type="MarginContainer" parent="Balloon"] +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +offset_bottom = 75.0 +grow_horizontal = 2 +theme_override_constants/margin_left = 20 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 20 +theme_override_constants/margin_bottom = 10 +metadata/_edit_layout_mode = 1 + +[node name="VBox" type="VBoxContainer" parent="Balloon/Margin"] +layout_mode = 2 +theme_override_constants/separation = 4 + +[node name="CharacterLabel" type="RichTextLabel" parent="Balloon/Margin/VBox"] +modulate = Color(1, 1, 1, 0.501961) +layout_mode = 2 +mouse_filter = 1 +theme = SubResource("Theme_isg48") +bbcode_enabled = true +text = "Character" +fit_content = true +scroll_active = false + +[node name="DialogueLabel" parent="Balloon/Margin/VBox" instance=ExtResource("2_a8ve6")] +layout_mode = 2 +theme = SubResource("Theme_owda0") +text = "Dialogue" + +[node name="Responses" type="VBoxContainer" parent="Balloon/Margin/VBox"] +layout_mode = 2 +theme_override_constants/separation = 1 + +[node name="ResponseTemplate" type="RichTextLabel" parent="Balloon/Margin/VBox"] +unique_name_in_owner = true +layout_mode = 2 +focus_mode = 2 +theme = SubResource("Theme_fakos") +theme_override_styles/focus = SubResource("StyleBoxFlat_5d24i") +theme_override_styles/normal = SubResource("StyleBoxFlat_oj3c8") +bbcode_enabled = true +text = "Response" +fit_content = true +scroll_active = false +shortcut_keys_enabled = false +meta_underlined = false +hint_underlined = false + +[connection signal="gui_input" from="Balloon" to="." method="_on_balloon_gui_input"] +[connection signal="resized" from="Balloon/Margin" to="." method="_on_margin_resized"] diff --git a/Scenes/Level.tscn b/Scenes/Level.tscn index 8c736b2..eb51199 100644 --- a/Scenes/Level.tscn +++ b/Scenes/Level.tscn @@ -1,16 +1,18 @@ -[gd_scene load_steps=6 format=3 uid="uid://1pb3mpmrl7lc"] +[gd_scene load_steps=7 format=3 uid="uid://1pb3mpmrl7lc"] [ext_resource type="Script" path="res://Utils/World.cs" id="1_1k6ew"] [ext_resource type="PackedScene" uid="uid://b2x17su05ou5w" path="res://Scenes/Maps/Arena.tscn" id="2_avsrq"] [ext_resource type="PackedScene" uid="uid://bxo553hblp6nf" path="res://UI/HealthBar.tscn" id="3_5rhge"] [ext_resource type="Script" path="res://UI/UIController.cs" id="3_fe62s"] [ext_resource type="PackedScene" uid="uid://01d24ij5av1y" path="res://UI/BossBar.tscn" id="5_8njq4"] +[ext_resource type="PackedScene" uid="uid://73jm5qjy52vq" path="res://Dialogue/balloon.tscn" id="6_2bdwl"] -[node name="World" type="Node2D" node_paths=PackedStringArray("UIController", "MusicPlayer")] +[node name="World" type="Node2D" node_paths=PackedStringArray("UIController", "MusicPlayer", "DialogueBalloon")] script = ExtResource("1_1k6ew") StartingArea = ExtResource("2_avsrq") UIController = NodePath("CanvasLayer/UI") MusicPlayer = NodePath("MusicPlayer") +DialogueBalloon = NodePath("DialogBalloon") [node name="CanvasLayer" type="CanvasLayer" parent="."] @@ -70,3 +72,5 @@ grow_horizontal = 2 grow_vertical = 2 [node name="MusicPlayer" type="AudioStreamPlayer" parent="."] + +[node name="DialogBalloon" parent="." instance=ExtResource("6_2bdwl")] diff --git a/Scenes/Maps/Arena.tscn b/Scenes/Maps/Arena.tscn index edd55cc..d575289 100644 --- a/Scenes/Maps/Arena.tscn +++ b/Scenes/Maps/Arena.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=15 format=3 uid="uid://b2x17su05ou5w"] +[gd_scene load_steps=16 format=3 uid="uid://b2x17su05ou5w"] [ext_resource type="PackedScene" uid="uid://clwv2owvk6abe" path="res://Scenes/BaseMap.tscn" id="1_ifiic"] [ext_resource type="Texture2D" uid="uid://b0yiy7w8nxmas" path="res://Assets/Sprites/arena-tileset.png" id="2_wnjm0"] @@ -7,6 +7,7 @@ [ext_resource type="PackedScene" uid="uid://c1w7t6irnohfx" path="res://Entities/Torch.tscn" id="6_1wwor"] [ext_resource type="PackedScene" uid="uid://ceadk7pam7vab" path="res://Entities/TorchLamp.tscn" id="6_jy3pc"] [ext_resource type="Texture2D" uid="uid://d1ukste16yq6v" path="res://Assets/Sprites/Particles/player-light.png" id="7_y7j0e"] +[ext_resource type="AudioStream" uid="uid://dy4qjflo1k28b" path="res://Assets/Sounds/calm-storm-ambient.mp3" id="8_wox7d"] [sub_resource type="CanvasTexture" id="CanvasTexture_3n6aa"] diffuse_texture = ExtResource("2_wnjm0") @@ -251,7 +252,7 @@ physics_layer_0/collision_layer = 1 sources/2 = SubResource("TileSetAtlasSource_5yxvt") sources/0 = SubResource("TileSetAtlasSource_fcd6d") -[sub_resource type="ShaderMaterial" id="ShaderMaterial_q3ile"] +[sub_resource type="ShaderMaterial" id="ShaderMaterial_i75i0"] resource_local_to_scene = true shader = ExtResource("5_h8k5p") shader_parameter/color = Quaternion(1, 1, 1, 1) @@ -343,7 +344,7 @@ visible = false position = Vector2(120, -112) [node name="Doc" parent="Entities" index="18" instance=ExtResource("4_ej0f3")] -material = SubResource("ShaderMaterial_q3ile") +material = SubResource("ShaderMaterial_i75i0") [node name="PointLight2D" type="PointLight2D" parent="Entities" index="19"] position = Vector2(168, -42) @@ -357,6 +358,12 @@ height = 16.0 [node name="CanvasGroup" type="CanvasGroup" parent="Entities" index="20"] +[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="Entities" index="21"] +position = Vector2(19, 23) +stream = ExtResource("8_wox7d") +volume_db = -5.0 +autoplay = true + [node name="Areas" parent="." index="2"] visible = false diff --git a/State/Global/GlobalState.cs b/State/Global/GlobalState.cs index 0299471..714f0dc 100644 --- a/State/Global/GlobalState.cs +++ b/State/Global/GlobalState.cs @@ -7,4 +7,7 @@ public partial class GlobalState : Node public Utils.World World { get; set; } public Progression Progression { get; set; } + + [Signal] + public delegate void SummonBossEventHandler(string bossName); } diff --git a/State/NPC/Doc/DocChooseAttackState.cs b/State/NPC/Doc/DocChooseAttackState.cs index 2b0453f..c5d583a 100644 --- a/State/NPC/Doc/DocChooseAttackState.cs +++ b/State/NPC/Doc/DocChooseAttackState.cs @@ -16,7 +16,7 @@ public partial class DocChooseAttackState : NPCState public DocUnwantedFrequencyState UnwantedFrequencyState { get; set; } [Export] - public DocLanceState LanceState { get; set; } + public DocIntroState LanceIntroState { get; set; } [Export] public DocExitState ExitState { get; set; } @@ -44,7 +44,7 @@ public partial class DocChooseAttackState : NPCState { if (Doc.Intensity == 3) { - return LanceState; + return LanceIntroState; } if (previous is not DocTelegraphState) diff --git a/State/NPC/Doc/DocIntroState.cs b/State/NPC/Doc/DocIntroState.cs new file mode 100644 index 0000000..6e9a3c8 --- /dev/null +++ b/State/NPC/Doc/DocIntroState.cs @@ -0,0 +1,38 @@ +using Godot; + +namespace SupaLidlGame.State.NPC.Doc; + +public partial class DocIntroState : NPCState +{ + [Export] + public NPCState NextState { get; set; } + + [Export] + public double Duration { get; set; } + + private double _currentDuration; + private Characters.Doc _doc; + + public override void _Ready() + { + base._Ready(); + _doc = NPC as Characters.Doc; + } + + public override NPCState Enter(IState previousState) + { + _currentDuration = Duration; + _doc.MiscAnimation.Play("intro"); + return null; + } + + public override NPCState Process(double delta) + { + if ((_currentDuration -= delta) <= 0) + { + return NextState; + } + + return null; + } +} diff --git a/State/NPC/Doc/DocLanceState.cs b/State/NPC/Doc/DocLanceState.cs index c73daf7..edf0373 100644 --- a/State/NPC/Doc/DocLanceState.cs +++ b/State/NPC/Doc/DocLanceState.cs @@ -36,52 +36,13 @@ public partial class DocLanceState : DocAttackState { var state = base.Enter(previousState); _doc.ShouldMove = true; - _doc.GetNode("Effects/BattleCry").Play(); - - //if (_doc.Intensity > 2) - //{ - // if (_doc.Inventory.SelectedItem != _doc.LanceHold) - // { - // _doc.Inventory.SelectedItem = _doc.LanceHold; - // _doc.UseCurrentItem(); - // _doc.CanAttack = false; - // } - //} - //else - //{ - // // wtf are we doing here? - // throw new System.InvalidOperationException(); - //} - - //_oldFriction = _doc.Friction; - //_doc.Friction = 0; - - //Attack(); return state; } - public override void Exit(IState nextState) - { - //_doc.Friction = _oldFriction; - //_doc.ApplyImpulse(Vector2.Zero, true); - //_doc.DeuseCurrentItem(); - //_doc.CanAttack = true; - base.Exit(nextState); - } - protected override void Attack() { - //var pos = _doc.GlobalPosition; - //var player = _world.CurrentPlayer; - //var playerPos = player.GlobalPosition; - //var predictedPos = Utils.Physics.PredictNewPosition( - // pos, DashSpeed, playerPos, player.Velocity, out float time); - //var dir = _doc.GlobalPosition.DirectionTo(predictedPos); - //_currentAttackDuration = AttackDuration = time; - - //_doc.ApplyImpulse(dir * DashSpeed, true); } public override NPCState Process(double delta) diff --git a/UI/BossBar.tscn b/UI/BossBar.tscn index 1a2efd4..3791087 100644 --- a/UI/BossBar.tscn +++ b/UI/BossBar.tscn @@ -35,9 +35,9 @@ horizontal_alignment = 1 [node name="BarMargin" type="MarginContainer" parent="."] layout_mode = 2 size_flags_vertical = 3 -theme_override_constants/margin_left = 64 -theme_override_constants/margin_right = 64 -theme_override_constants/margin_bottom = 8 +theme_override_constants/margin_left = 128 +theme_override_constants/margin_right = 128 +theme_override_constants/margin_bottom = 32 [node name="BossBar" type="TextureProgressBar" parent="BarMargin"] texture_filter = 1 diff --git a/Utils/World.cs b/Utils/World.cs index d876215..621d291 100644 --- a/Utils/World.cs +++ b/Utils/World.cs @@ -1,5 +1,6 @@ using Godot; using SupaLidlGame.Characters; +using SupaLidlGame.Extensions; using SupaLidlGame.Scenes; using System.Collections.Generic; using System.Linq; @@ -26,6 +27,9 @@ public partial class World : Node2D [Export] public AudioStreamPlayer MusicPlayer { get; set; } + [Export] + public Dialogue.Balloon DialogueBalloon { get; set; } + private Dictionary _maps; private string _currentConnector; @@ -255,4 +259,6 @@ public partial class World : Node2D CurrentPlayer.GlobalPosition = SaveLocation; CurrentPlayer.Spawn(); } + + public Node FindEntity(string name) => CurrentMap.Entities.GetNode(name); } diff --git a/project.godot b/project.godot index ab0dc94..ef6983a 100644 --- a/project.godot +++ b/project.godot @@ -18,6 +18,12 @@ config/icon="res://icon.svg" [autoload] DebugConsole="*res://Debug/DebugConsole.cs" +DialogueManager="*res://addons/dialogue_manager/dialogue_manager.gd" +GlobalState="*res://State/Global/GlobalState.cs" + +[dialogue_manager] + +general/states=["GlobalState"] [display] @@ -30,6 +36,10 @@ window/stretch/aspect="expand" project/assembly_name="SupaLidlGame" +[editor_plugins] + +enabled=PackedStringArray("res://addons/dialogue_manager/plugin.cfg") + [input] ui_left={ @@ -93,6 +103,10 @@ equip_3={ ] } +[internationalization] + +locale/translations_pot_files=PackedStringArray("res://Assets/Dialog/doc.dialogue") + [layer_names] 2d_physics/layer_1="World"