TinyAdventure/addons/dialogue_manager/example_balloon/ExampleBalloon.cs

219 lines
5.6 KiB
C#

using Godot;
using Godot.Collections;
namespace DialogueManagerRuntime
{
public partial class ExampleBalloon : CanvasLayer
{
[Export] public string NextAction = "ui_accept";
[Export] public string SkipAction = "ui_cancel";
Control balloon;
RichTextLabel characterLabel;
RichTextLabel dialogueLabel;
VBoxContainer responsesMenu;
Resource resource;
Array<Variant> temporaryGameStates = new Array<Variant>();
bool isWaitingForInput = false;
bool willHideBalloon = false;
DialogueLine dialogueLine;
DialogueLine DialogueLine
{
get => dialogueLine;
set
{
isWaitingForInput = false;
balloon.FocusMode = Control.FocusModeEnum.All;
balloon.GrabFocus();
if (value == null)
{
QueueFree();
return;
}
dialogueLine = value;
UpdateDialogue();
}
}
public override void _Ready()
{
balloon = GetNode<Control>("%Balloon");
characterLabel = GetNode<RichTextLabel>("%CharacterLabel");
dialogueLabel = GetNode<RichTextLabel>("%DialogueLabel");
responsesMenu = GetNode<VBoxContainer>("%ResponsesMenu");
balloon.Hide();
balloon.GuiInput += (@event) =>
{
if ((bool)dialogueLabel.Get("is_typing"))
{
bool mouseWasClicked = @event is InputEventMouseButton && (@event as InputEventMouseButton).ButtonIndex == MouseButton.Left && @event.IsPressed();
bool skipButtonWasPressed = @event.IsActionPressed(SkipAction);
if (mouseWasClicked || skipButtonWasPressed)
{
GetViewport().SetInputAsHandled();
dialogueLabel.Call("skip_typing");
return;
}
}
if (!isWaitingForInput) return;
if (dialogueLine.Responses.Count > 0) return;
GetViewport().SetInputAsHandled();
if (@event is InputEventMouseButton && @event.IsPressed() && (@event as InputEventMouseButton).ButtonIndex == MouseButton.Left)
{
Next(dialogueLine.NextId);
}
else if (@event.IsActionPressed(NextAction) && GetViewport().GuiGetFocusOwner() == balloon)
{
Next(dialogueLine.NextId);
}
};
if (string.IsNullOrEmpty((string)responsesMenu.Get("next_action")))
{
responsesMenu.Set("next_action", NextAction);
}
responsesMenu.Connect("response_selected", Callable.From((DialogueResponse response) =>
{
Next(response.NextId);
}));
DialogueManager.Mutated += OnMutated;
}
public override void _ExitTree()
{
DialogueManager.Mutated -= OnMutated;
}
public override void _UnhandledInput(InputEvent @event)
{
// Only the balloon is allowed to handle input while it's showing
GetViewport().SetInputAsHandled();
}
public override async void _Notification(int what)
{
// Detect a change of locale and update the current dialogue line to show the new language
if (what == NotificationTranslationChanged)
{
float visibleRatio = dialogueLabel.VisibleRatio;
DialogueLine = await DialogueManager.GetNextDialogueLine(resource, DialogueLine.Id, temporaryGameStates);
if (visibleRatio < 1.0f)
{
dialogueLabel.Call("skip_typing");
}
}
}
public async void Start(Resource dialogueResource, string title, Array<Variant> extraGameStates = null)
{
temporaryGameStates = extraGameStates ?? new Array<Variant>();
isWaitingForInput = false;
resource = dialogueResource;
DialogueLine = await DialogueManager.GetNextDialogueLine(resource, title, temporaryGameStates);
}
public async void Next(string nextId)
{
DialogueLine = await DialogueManager.GetNextDialogueLine(resource, nextId, temporaryGameStates);
}
#region Helpers
private async void UpdateDialogue()
{
if (!IsNodeReady())
{
await ToSignal(this, SignalName.Ready);
}
// Set up the character name
characterLabel.Visible = !string.IsNullOrEmpty(dialogueLine.Character);
characterLabel.Text = Tr(dialogueLine.Character, "dialogue");
// Set up the dialogue
dialogueLabel.Hide();
dialogueLabel.Set("dialogue_line", dialogueLine);
// Set up the responses
responsesMenu.Hide();
responsesMenu.Set("responses", dialogueLine.Responses);
// Type out the text
balloon.Show();
willHideBalloon = false;
dialogueLabel.Show();
if (!string.IsNullOrEmpty(dialogueLine.Text))
{
dialogueLabel.Call("type_out");
await ToSignal(dialogueLabel, "finished_typing");
}
// Wait for input
if (dialogueLine.Responses.Count > 0)
{
balloon.FocusMode = Control.FocusModeEnum.None;
responsesMenu.Show();
}
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;
balloon.GrabFocus();
}
}
#endregion
#region signals
private void OnMutated(Dictionary _mutation)
{
isWaitingForInput = false;
willHideBalloon = true;
GetTree().CreateTimer(0.1f).Timeout += () =>
{
if (willHideBalloon)
{
willHideBalloon = false;
balloon.Hide();
}
};
}
#endregion
}
}