OctoCore 0.0.1
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1be27ce87e441a545bd6f3fdd3c18b61
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace OctoCore.Dialogue.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Component to trigger dialogue events.
|
||||
/// Listens to dialogue start/end and invokes UnityEvents.
|
||||
/// </summary>
|
||||
public class OctoDialogueEvent : MonoBehaviour
|
||||
{
|
||||
[SerializeField, Tooltip("Dialogue data to listen for")]
|
||||
private Data.OctoDialogueData _dialogue;
|
||||
|
||||
[SerializeField, Tooltip("Called when the specified dialogue starts")]
|
||||
private UnityEvent _onDialogueStarted;
|
||||
|
||||
[SerializeField, Tooltip("Called when the specified dialogue ends")]
|
||||
private UnityEvent _onDialogueEnded;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (OctoDialogueManager.Instance != null)
|
||||
{
|
||||
// Subscribe to manager events
|
||||
OctoDialogueManager.Instance.GetComponent<OctoDialogueManager>()
|
||||
._events.OnDialogueStarted.AddListener(OnDialogueStarted);
|
||||
OctoDialogueManager.Instance.GetComponent<OctoDialogueManager>()
|
||||
._events.OnDialogueEnded.AddListener(OnDialogueEnded);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (OctoDialogueManager.Instance != null)
|
||||
{
|
||||
// Unsubscribe from manager events
|
||||
OctoDialogueManager.Instance.GetComponent<OctoDialogueManager>()
|
||||
._events.OnDialogueStarted.RemoveListener(OnDialogueStarted);
|
||||
OctoDialogueManager.Instance.GetComponent<OctoDialogueManager>()
|
||||
._events.OnDialogueEnded.RemoveListener(OnDialogueEnded);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDialogueStarted()
|
||||
{
|
||||
if (OctoDialogueManager.Instance == null)
|
||||
return;
|
||||
|
||||
var currentDialogue = OctoDialogueManager.Instance.GetCurrentDialogue();
|
||||
if (currentDialogue == _dialogue)
|
||||
{
|
||||
_onDialogueStarted?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDialogueEnded()
|
||||
{
|
||||
// Dialogue already ended, so we check if it was our dialogue
|
||||
// Note: This might not work perfectly if dialogue changes rapidly
|
||||
// A better implementation would track the last active dialogue
|
||||
_onDialogueEnded?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7c573c7064e10f4ba4855e8f448ee81
|
||||
@@ -0,0 +1,291 @@
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
using OctoCore.Localization;
|
||||
using OctoCore.Components;
|
||||
|
||||
namespace OctoCore.Dialogue.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialogue manager component.
|
||||
/// Singleton that handles dialogue display and flow.
|
||||
/// Uses UI Text components if assigned, otherwise falls back to GUI.
|
||||
/// </summary>
|
||||
public class OctoDialogueManager : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton instance.
|
||||
/// </summary>
|
||||
public static OctoDialogueManager Instance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// References to UI components.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class References
|
||||
{
|
||||
[Tooltip("Legacy UI Text component (optional)")]
|
||||
public Text Text;
|
||||
|
||||
[Tooltip("TextMeshPro component (optional)")]
|
||||
public TextMeshPro TextMeshPro;
|
||||
|
||||
[Tooltip("TextMeshPro UGUI component (optional)")]
|
||||
public TextMeshProUGUI TextMeshProUGUI;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dialogue events.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Events
|
||||
{
|
||||
[Tooltip("Called when a dialogue starts")]
|
||||
public UnityEvent OnDialogueStarted;
|
||||
|
||||
[Tooltip("Called when a new entry starts displaying")]
|
||||
public UnityEvent OnEntryStarted;
|
||||
|
||||
[Tooltip("Called when a choice is selected")]
|
||||
public UnityEvent OnChoiceSelected;
|
||||
|
||||
[Tooltip("Called when a dialogue ends")]
|
||||
public UnityEvent OnDialogueEnded;
|
||||
}
|
||||
|
||||
[SerializeField] private References _references;
|
||||
[SerializeField] public Events _events;
|
||||
|
||||
private Data.OctoDialogueData _currentDialogue;
|
||||
private int _currentEntryIndex;
|
||||
private List<OctoDialogueChoice> _availableChoices = new List<OctoDialogueChoice>();
|
||||
private bool _isActive;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (Instance == this)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a new dialogue.
|
||||
/// Automatically displays the first entry.
|
||||
/// </summary>
|
||||
public void StartDialogue(Data.OctoDialogueData dialogue)
|
||||
{
|
||||
if (dialogue == null || dialogue.Entries == null || dialogue.Entries.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("[OctoDialogueManager] Cannot start dialogue: null or empty");
|
||||
return;
|
||||
}
|
||||
|
||||
_currentDialogue = dialogue;
|
||||
_currentEntryIndex = 0;
|
||||
_isActive = true;
|
||||
|
||||
_events.OnDialogueStarted?.Invoke();
|
||||
if (OctoPlayer.Instance) OctoPlayer.Instance.Pause(true); // TMP
|
||||
DisplayCurrentEntry();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display the current dialogue entry.
|
||||
/// </summary>
|
||||
private void DisplayCurrentEntry()
|
||||
{
|
||||
if (_currentDialogue == null || _currentEntryIndex >= _currentDialogue.Entries.Length)
|
||||
{
|
||||
EndDialogue();
|
||||
return;
|
||||
}
|
||||
|
||||
OctoDialogueEntry entry = _currentDialogue.Entries[_currentEntryIndex];
|
||||
|
||||
_events.OnEntryStarted?.Invoke();
|
||||
|
||||
// Display text
|
||||
string text = OctoLocalization.GetLocalizedText(entry.Text);
|
||||
SetText(text);
|
||||
|
||||
// Build available choices
|
||||
_availableChoices.Clear();
|
||||
if (entry.Choices != null)
|
||||
{
|
||||
foreach (var choice in entry.Choices)
|
||||
{
|
||||
if (choice.IsAvailable())
|
||||
{
|
||||
_availableChoices.Add(choice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select a choice by index.
|
||||
/// </summary>
|
||||
public void SelectChoice(int choiceIndex)
|
||||
{
|
||||
if (!_isActive || choiceIndex < 0 || choiceIndex >= _availableChoices.Count)
|
||||
return;
|
||||
|
||||
OctoDialogueChoice choice = _availableChoices[choiceIndex];
|
||||
|
||||
_events.OnChoiceSelected?.Invoke();
|
||||
|
||||
if (choice.NextDialogue != null)
|
||||
{
|
||||
StartDialogue(choice.NextDialogue);
|
||||
}
|
||||
else
|
||||
{
|
||||
EndDialogue();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Continue to next entry (when no choices available).
|
||||
/// </summary>
|
||||
public void Continue()
|
||||
{
|
||||
if (!_isActive)
|
||||
return;
|
||||
|
||||
if (_availableChoices.Count == 0)
|
||||
{
|
||||
_currentEntryIndex++;
|
||||
DisplayCurrentEntry();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End the current dialogue.
|
||||
/// </summary>
|
||||
private void EndDialogue()
|
||||
{
|
||||
_isActive = false;
|
||||
_currentDialogue = null;
|
||||
_currentEntryIndex = 0;
|
||||
_availableChoices.Clear();
|
||||
|
||||
if (OctoPlayer.Instance) OctoPlayer.Instance.Pause(false); // TMP
|
||||
_events.OnDialogueEnded?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set text using available UI component or GUI fallback.
|
||||
/// </summary>
|
||||
private void SetText(string text)
|
||||
{
|
||||
if (_references.Text != null)
|
||||
{
|
||||
_references.Text.text = text;
|
||||
}
|
||||
else if (_references.TextMeshPro != null)
|
||||
{
|
||||
_references.TextMeshPro.text = text;
|
||||
}
|
||||
else if (_references.TextMeshProUGUI != null)
|
||||
{
|
||||
_references.TextMeshProUGUI.text = text;
|
||||
}
|
||||
// GUI fallback handled in OnGUI
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
// Only use GUI if no text component is assigned
|
||||
if (_references.Text != null || _references.TextMeshPro != null || _references.TextMeshProUGUI != null)
|
||||
return;
|
||||
|
||||
if (!_isActive || _currentDialogue == null)
|
||||
return;
|
||||
|
||||
if (_currentEntryIndex >= _currentDialogue.Entries.Length)
|
||||
return;
|
||||
|
||||
OctoDialogueEntry entry = _currentDialogue.Entries[_currentEntryIndex];
|
||||
|
||||
GUILayout.BeginArea(new Rect(50, Screen.height - 200, Screen.width - 100, 150));
|
||||
GUILayout.Box("", GUILayout.Width(Screen.width - 100), GUILayout.Height(150));
|
||||
|
||||
GUILayout.BeginArea(new Rect(10, 10, Screen.width - 120, 130));
|
||||
|
||||
// Speaker name
|
||||
if (entry.Speaker != null && entry.Speaker.Name != null)
|
||||
{
|
||||
string speakerName = OctoLocalization.GetLocalizedText(entry.Speaker.Name);
|
||||
GUILayout.Label(speakerName, GUI.skin.box);
|
||||
}
|
||||
|
||||
// Dialogue text
|
||||
string text = OctoLocalization.GetLocalizedText(entry.Text);
|
||||
GUILayout.Label(text, GUILayout.ExpandHeight(true));
|
||||
|
||||
// Choices
|
||||
if (_availableChoices.Count > 0)
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
for (int i = 0; i < _availableChoices.Count; i++)
|
||||
{
|
||||
string choiceText = OctoLocalization.GetLocalizedText(_availableChoices[i].Text);
|
||||
if (GUILayout.Button(choiceText))
|
||||
{
|
||||
SelectChoice(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
if (GUILayout.Button("→"))
|
||||
{
|
||||
Continue();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndArea();
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current dialogue data.
|
||||
/// </summary>
|
||||
public Data.OctoDialogueData GetCurrentDialogue()
|
||||
{
|
||||
return _currentDialogue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get available choices for current entry.
|
||||
/// </summary>
|
||||
public List<OctoDialogueChoice> GetAvailableChoices()
|
||||
{
|
||||
return new List<OctoDialogueChoice>(_availableChoices);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if dialogue is currently active.
|
||||
/// </summary>
|
||||
public bool IsActive()
|
||||
{
|
||||
return _isActive;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a41b5f79f61ad94c9479c28b4397de4
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be1a654d39699564cb1dc1342aa93085
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OctoCore.Dialogue.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialogue data containing a sequence of entries.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "dialogue_", menuName = "OctoCore/Dialogue/Dialogue Data", order = 1)]
|
||||
public class OctoDialogueData : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Sequence of dialogue entries.
|
||||
/// First entry starts automatically.
|
||||
/// </summary>
|
||||
[Tooltip("Sequence of dialogue entries")]
|
||||
public OctoDialogueEntry[] Entries;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c6fdb9b9b4581f4b912b64147fa3969
|
||||
@@ -0,0 +1,25 @@
|
||||
using UnityEngine;
|
||||
using OctoCore.Localization;
|
||||
|
||||
namespace OctoCore.Dialogue.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Speaker data for dialogue system.
|
||||
/// Contains localized name and sprite.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "speaker_", menuName = "OctoCore/Dialogue/Speaker Data", order = 0)]
|
||||
public class OctoSpeakerData : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Localized name of the speaker.
|
||||
/// </summary>
|
||||
[Tooltip("Localized name of the speaker")]
|
||||
public OctoLocalizedTextData Name;
|
||||
|
||||
/// <summary>
|
||||
/// Speaker portrait sprite.
|
||||
/// </summary>
|
||||
[Tooltip("Speaker portrait sprite")]
|
||||
public Sprite Sprite;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a14c37f184ae07b4b8f641e7e2896ed7
|
||||
@@ -0,0 +1,43 @@
|
||||
using UnityEngine;
|
||||
using OctoCore.Localization;
|
||||
|
||||
namespace OctoCore.Dialogue
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialogue choice with condition and next dialogue.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class OctoDialogueChoice
|
||||
{
|
||||
/// <summary>
|
||||
/// Localized text for this choice.
|
||||
/// </summary>
|
||||
[Tooltip("Localized text for this choice")]
|
||||
public OctoLocalizedTextData Text;
|
||||
|
||||
/// <summary>
|
||||
/// Condition to display this choice.
|
||||
/// If null or condition is true, choice is available.
|
||||
/// </summary>
|
||||
[Tooltip("Condition to display this choice (null = always show)")]
|
||||
public OctoDialogueCondition Condition;
|
||||
|
||||
/// <summary>
|
||||
/// Next dialogue to load when this choice is selected.
|
||||
/// If null, dialogue ends.
|
||||
/// </summary>
|
||||
[Tooltip("Next dialogue when selected (null = end dialogue)")]
|
||||
public Data.OctoDialogueData NextDialogue;
|
||||
|
||||
/// <summary>
|
||||
/// Check if this choice should be available.
|
||||
/// </summary>
|
||||
public bool IsAvailable()
|
||||
{
|
||||
if (Condition == null)
|
||||
return true;
|
||||
|
||||
return Condition.Evaluate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b828f206b626c94a964cbb5e4aaddc4
|
||||
@@ -0,0 +1,90 @@
|
||||
using UnityEngine;
|
||||
using OctoCore.Save.Data;
|
||||
|
||||
namespace OctoCore.Dialogue
|
||||
{
|
||||
/// <summary>
|
||||
/// Condition for dialogue choices.
|
||||
/// Supports OctoDataBool, OctoDataInt, and OctoDataFloat.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class OctoDialogueCondition
|
||||
{
|
||||
/// <summary>
|
||||
/// Source data to evaluate (OctoDataBool, OctoDataInt, or OctoDataFloat).
|
||||
/// </summary>
|
||||
[Tooltip("Source data to evaluate")]
|
||||
public OctoData Source;
|
||||
|
||||
/// <summary>
|
||||
/// Operation to perform.
|
||||
/// </summary>
|
||||
[Tooltip("Operation to perform")]
|
||||
public OctoDialogueOperation Operation = OctoDialogueOperation.Equal;
|
||||
|
||||
/// <summary>
|
||||
/// Value to compare against.
|
||||
/// For bool: 0 = false, 1 = true
|
||||
/// For int/float: direct comparison
|
||||
/// </summary>
|
||||
[Tooltip("Value to compare against (bool: 0=false, 1=true)")]
|
||||
public float Value;
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate if the condition is met.
|
||||
/// </summary>
|
||||
public bool Evaluate()
|
||||
{
|
||||
if (Source == null)
|
||||
return true; // No condition = always true
|
||||
|
||||
float sourceValue = GetSourceValue();
|
||||
|
||||
switch (Operation)
|
||||
{
|
||||
case OctoDialogueOperation.Equal:
|
||||
return Mathf.Approximately(sourceValue, Value);
|
||||
|
||||
case OctoDialogueOperation.NotEqual:
|
||||
return !Mathf.Approximately(sourceValue, Value);
|
||||
|
||||
case OctoDialogueOperation.GreaterThan:
|
||||
return sourceValue > Value;
|
||||
|
||||
case OctoDialogueOperation.GreaterOrEqual:
|
||||
return sourceValue >= Value;
|
||||
|
||||
case OctoDialogueOperation.LessThan:
|
||||
return sourceValue < Value;
|
||||
|
||||
case OctoDialogueOperation.LessOrEqual:
|
||||
return sourceValue <= Value;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private float GetSourceValue()
|
||||
{
|
||||
if (!OctoCore.Instance)
|
||||
return 0f;
|
||||
|
||||
if (Source is OctoDataBool dataBool)
|
||||
{
|
||||
return OctoCore.Instance.Save.Get(dataBool) ? 1f : 0f;
|
||||
}
|
||||
else if (Source is OctoDataInt dataInt)
|
||||
{
|
||||
return OctoCore.Instance.Save.Get(dataInt);
|
||||
}
|
||||
else if (Source is OctoDataFloat dataFloat)
|
||||
{
|
||||
return OctoCore.Instance.Save.Get(dataFloat);
|
||||
}
|
||||
|
||||
Debug.LogWarning("[OctoDialogueCondition] Unsupported data type: " + Source.GetType().Name);
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 553d5d510ff034f44b70a8a032565a4e
|
||||
@@ -0,0 +1,31 @@
|
||||
using UnityEngine;
|
||||
using OctoCore.Localization;
|
||||
|
||||
namespace OctoCore.Dialogue
|
||||
{
|
||||
/// <summary>
|
||||
/// Single dialogue entry with speaker, text, and choices.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class OctoDialogueEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Speaker for this entry.
|
||||
/// </summary>
|
||||
[Tooltip("Speaker for this entry")]
|
||||
public Data.OctoSpeakerData Speaker;
|
||||
|
||||
/// <summary>
|
||||
/// Localized dialogue text.
|
||||
/// </summary>
|
||||
[Tooltip("Localized dialogue text")]
|
||||
public OctoLocalizedTextData Text;
|
||||
|
||||
/// <summary>
|
||||
/// Available choices for this entry.
|
||||
/// If empty, dialogue continues automatically or ends.
|
||||
/// </summary>
|
||||
[Tooltip("Available choices (empty = auto-continue or end)")]
|
||||
public OctoDialogueChoice[] Choices;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec95cc134f0fa214eb3cd8c0e9016347
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace OctoCore.Dialogue
|
||||
{
|
||||
/// <summary>
|
||||
/// Operations for dialogue conditions.
|
||||
/// </summary>
|
||||
public enum OctoDialogueOperation
|
||||
{
|
||||
/// <summary>Equal (bool, int, float)</summary>
|
||||
Equal,
|
||||
|
||||
/// <summary>Not equal (bool, int, float)</summary>
|
||||
NotEqual,
|
||||
|
||||
/// <summary>Greater than (int, float only)</summary>
|
||||
GreaterThan,
|
||||
|
||||
/// <summary>Greater or equal (int, float only)</summary>
|
||||
GreaterOrEqual,
|
||||
|
||||
/// <summary>Less than (int, float only)</summary>
|
||||
LessThan,
|
||||
|
||||
/// <summary>Less or equal (int, float only)</summary>
|
||||
LessOrEqual
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4c04f460edc6d949933bd4237fb2e0a
|
||||
Reference in New Issue
Block a user