using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using KairoEngine.Core; using Ink.Runtime; using UniRx; namespace KairoEngine.StorySystem { // Todo: Request events for getting and setting story variables public class StoryController { private TextAsset inkJSONAsset = null; private Story story; private string name; private bool logText = false; private bool started = false; private int lineInverval = 250; public bool wait = false; private CompositeDisposable disposables = new CompositeDisposable(); private List storyObjects; public StoryController(TextAsset inkJSONAsset, string storyName, bool logText = false) { this.inkJSONAsset = inkJSONAsset; this.name = storyName; this.story = new Story (inkJSONAsset.text); this.logText = logText; } public StoryController(TextAsset inkJSONAsset, string storyName, List storyObjects, Transform parent = null, bool logText = false, int lineInverval = 250) { this.inkJSONAsset = inkJSONAsset; this.name = storyName; this.story = new Story (inkJSONAsset.text); this.logText = logText; this.lineInverval = lineInverval; this.storyObjects = storyObjects; foreach (var item in storyObjects) { item.instance = GameObject.Instantiate(item.prefab, parent); item.instance.SetActive(false); item.instance.name = item.instance.name.Replace("(Clone)", ""); } } public void Start() { if(started) return; started = true; GenericEvents.StartListening(name, JumpToPath); EventManager.broadcast.StartListening(name, SelectStoryBranch); EventManager.broadcast.StartListening(name, PublishStorylineToObservers); if(logText) Debug.Log($"Starting {name}"); story.BindExternalFunction ("WaitForTime", (int time) => Wait(time), false); story.BindExternalFunction ("Enable", (string name) => EnableGameObject(name), false); story.BindExternalFunction ("Disable", (string name) => DisableGameObject(name), false); story.BindExternalFunction ("TriggerEvent", (string name) => GenericEvents.Trigger(name), false); var storyStream = Observable.Interval(TimeSpan.FromMilliseconds(250)) //.Where(_ => wait == false) .Subscribe(_ => StoryLoop()) .AddTo(disposables); } public void Stop() { GenericEvents.StopListening(name, JumpToPath); EventManager.broadcast.StopListening(name, SelectStoryBranch); EventManager.broadcast.StopListening(name, PublishStorylineToObservers); disposables.Clear(); started = false; if(logText) Debug.Log($"{name} has stoped."); } private void StoryLoop() { //Debug.Log(wait); if(wait) return; // Read all the content until we can't continue any more if (story.canContinue) { // Continue gets the next line of the story string text = story.Continue (); // This removes any white space from the text. text = text.Trim(); // Create StoryStepData StoryStepData storyStep = new StoryStepData(StoryStepType.Line, text, story.currentTags, null); EventManager.broadcast.Trigger(name, storyStep); // Display the text if log is enabled if(logText) Debug.Log(storyStep.text); } else if( story.currentChoices.Count > 0 ) { List choices = new List(); for (int i = 0; i < story.currentChoices.Count; ++i) { Choice choice = story.currentChoices [i]; choices.Add(choice.text); if(logText) Debug.Log($"Choice {i + 1}. {choice.text}"); } StoryStepData storyStep = new StoryStepData(StoryStepType.Branch, "", story.currentTags, choices); EventManager.broadcast.Trigger(name, storyStep); wait = true; } else Stop(); } private void SelectStoryBranch(StoryStepData storyStep) { if(storyStep.category == StoryStepType.Path) { story.ChooseChoiceIndex (storyStep.path); wait = false; StoryLoop(); } } static Subject subject; public static IObservable Lines() { if(subject == null) subject = new Subject(); return subject.AsObservable(); } private void PublishStorylineToObservers(StoryStepData storyStep) { if(subject != null) subject.OnNext(storyStep); } public void JumpToPath(string path) { if(story != null) { if(logText) Debug.Log($"Jumping to story knot \"{path}\""); story.ChoosePathString(path); wait = false; } } #region ExternalStoryFunctions private void Wait(int time) { wait = true; Timer.Execute(time, () => wait = false); } private void EnableGameObject(string name) { for (int i = 0; i < storyObjects.Count; i++) { if(storyObjects[i].name == name) storyObjects[i].instance.SetActive(true); } } private void DisableGameObject(string name) { for (int i = 0; i < storyObjects.Count; i++) { if(storyObjects[i].name == name) storyObjects[i].instance.SetActive(false); } } #endregion } }