Code/ChitChat/Data/SpeakAction.cs
using Sandbox;

namespace ChitChat;

public sealed class SpeakAction : DialogueActionBase
{
	public string Text { get; set; } = "Some text...";

	//Input
	public DialogueInputState DialogueInputState { get; set; } = DialogueInputState.WaitForInput;
	public float WaitForInputDelay { get; set; } = 0.0f;

	//Character
	public DialogueCharacter Character { get; set; }
	public int CharacterIndex { get; set; } = -1;
	public PicturePosition PicturePosition { get; set; } = 0;

	//Writing effect
	public bool UseWritingEffect { get; set; } = true;
	public float WriteSpeed { get; set; } = 20.0f;
	
	//Audio
	public DialogueAudioType AudioType { get; set; } = DialogueAudioType.None;
	public SoundEvent SoundEvent { get; set; }
	public bool UseAudioDelay { get; set; }
	public RangedFloat AudioDelay { get; set; } = new RangedFloat(0, 0);

	public SpeakAction() { }

	public SpeakAction(SpeakAction action)
	{
		Text = action.Text;
		DialogueInputState = action.DialogueInputState;
		WaitForInputDelay = action.WaitForInputDelay;
		
		Character = action.Character;
		CharacterIndex = action.CharacterIndex;
		PicturePosition = action.PicturePosition;

		UseWritingEffect = action.UseWritingEffect;
		WriteSpeed = action.WriteSpeed;

		AudioType = action.AudioType;
		SoundEvent = action.SoundEvent;
		AudioDelay = action.AudioDelay;
	}

	public Texture GetCharacterPicture() => Character.CharacterPictures[CharacterIndex].Picture;

	public override bool OnEnter(DialogueSystemComponent system, DialoguePanelComponent ui, DialogueWriterComponent writer, DialogueAudioComponent audio)
	{
		system.SetInputState(DialogueInputState, WaitForInputDelay);

		//Use writing effect
		if (UseWritingEffect)
		{
			writer.StartWriting(Text, 1 / WriteSpeed);
			ui.SetText("");
		}
		else
		{
			ui.SetText(Text);
		}

		//Sound
		if (AudioType != DialogueAudioType.None && SoundEvent.IsValid())
		{
			audio.SetAudioSettings(AudioType, SoundEvent, UseAudioDelay, AudioDelay);
		}

		//Character
		if (Character != null)
		{
			ui.SetCharacterName(Character.Name);

			if (CharacterIndex != -1 && CharacterIndex < Character.CharacterPictures.Count)
				ui.SetCharacterPicture(GetCharacterPicture(), PicturePosition);
		}
		else
		{
			ui.SetCharacterName(string.Empty);
			ui.SetCharacterPicture(null, PicturePosition.None);
		}

		//If we dont care about input then just go to next action
		if (DialogueInputState == DialogueInputState.None)
		{
			return false;
		}

		return true;
	}

	public override void OnExit() { }
}

public enum DialogueInputState
{
	None = -1,
	WaitForInput = 0,
	WaitForSeconds = 1,
	WaitForWriteEffect = 2
}

public enum DialogueAudioType
{
	None = -1,
	Once = 0,
	Loop = 1,
	ForEachCharacter = 2
}

public enum PicturePosition
{
	None = -1,
	Left = 0,
	Center = 1,
	Right = 2
}