An easy to use Unity 3D library for creating illustrated Interactive Fiction games and more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

250 lines
5.4 KiB

using UnityEngine;
using UnityEngine.Serialization;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Fungus
{
/**
* The Sequence class has been renamed to Block to be more descriptive.
*/
[ExecuteInEditMode]
[RequireComponent(typeof(Flowchart))]
[AddComponentMenu("")]
[Obsolete("Use Block class instead")]
public class Sequence : Block
{}
[ExecuteInEditMode]
[RequireComponent(typeof(Flowchart))]
[AddComponentMenu("")]
public class Block : Node
{
[FormerlySerializedAs("sequenceName")]
public string blockName = "New Block";
[TextArea(2, 5)]
[Tooltip("Description text to display under the block node")]
public string description = "";
[Tooltip("Slow down execution in the editor to make it easier to visualise program flow")]
public bool runSlowInEditor = true;
public EventHandler eventHandler;
[HideInInspector]
[System.NonSerialized]
public Command activeCommand;
// Index of last command executed before the current one
// -1 indicates no previous command
[HideInInspector]
[System.NonSerialized]
public int previousActiveCommandIndex = -1;
[HideInInspector]
[System.NonSerialized]
public float executingIconTimer;
[HideInInspector]
public List<Command> commandList = new List<Command>();
protected int executionCount;
protected virtual void Awake()
{
// Give each child command a reference back to its parent block
// and tell each command its index in the list.
int index = 0;
foreach (Command command in commandList)
{
command.parentBlock = this;
command.commandIndex = index++;
}
}
#if UNITY_EDITOR
// The user can modify the command list order while playing in the editor,
// so we keep the command indices updated every frame. There's no need to
// do this in player builds so we compile this bit out for those builds.
void Update()
{
int index = 0;
foreach (Command command in commandList)
{
if (command == null) // Null entry will be deleted automatically later
{
continue;
}
command.commandIndex = index++;
}
}
#endif
public virtual Flowchart GetFlowchart()
{
Flowchart flowchart = GetComponent<Flowchart>();
if (flowchart == null)
{
// Legacy support for earlier system where Blocks were children of the Flowchart
if (transform.parent != null)
{
flowchart = transform.parent.GetComponent<Flowchart>();
}
}
return flowchart;
}
public virtual bool HasError()
{
foreach (Command command in commandList)
{
if (command.errorMessage.Length > 0)
{
return true;
}
}
return false;
}
public virtual bool IsExecuting()
{
Flowchart flowchart = GetFlowchart();
if (flowchart == null)
{
return false;
}
return (activeCommand != null);
}
public virtual int GetExecutionCount()
{
return executionCount;
}
public virtual void ExecuteCommand(int commandIndex)
{
if (activeCommand == null)
{
previousActiveCommandIndex = -1;
}
else
{
previousActiveCommandIndex = activeCommand.commandIndex;
}
if (commandIndex >= commandList.Count)
{
Stop();
return;
}
if (commandIndex == 0)
{
executionCount++;
}
Flowchart flowchart = GetFlowchart();
// Skip disabled commands, comments and labels
while (commandIndex < commandList.Count &&
(!commandList[commandIndex].enabled ||
commandList[commandIndex].GetType() == typeof(Comment) ||
commandList[commandIndex].GetType() == typeof(Label)))
{
commandIndex = commandList[commandIndex].commandIndex + 1;
}
if (commandIndex >= commandList.Count)
{
Stop();
return;
}
Command nextCommand = commandList[commandIndex];
activeCommand = null;
executingIconTimer = 0.5f;
if (nextCommand == null)
{
Stop();
}
else
{
if (flowchart.gameObject.activeInHierarchy)
{
// Auto select a command in some situations
if ((flowchart.selectedCommands.Count == 0 && commandIndex == 0) ||
(flowchart.selectedCommands.Count == 1 && flowchart.selectedCommands[0].commandIndex == previousActiveCommandIndex))
{
flowchart.ClearSelectedCommands();
flowchart.AddSelectedCommand(nextCommand);
}
if (runSlowInEditor &&
nextCommand.RunSlowInEditor())
{
StartCoroutine(ExecuteAfterDelay(nextCommand, flowchart.runSlowDuration));
}
else
{
activeCommand = nextCommand;
nextCommand.Execute();
}
}
}
}
IEnumerator ExecuteAfterDelay(Command nextCommand, float delay)
{
activeCommand = nextCommand;
yield return new WaitForSeconds(delay);
nextCommand.Execute();
}
public virtual void Stop()
{
Flowchart flowchart = GetFlowchart();
if (flowchart == null)
{
return;
}
activeCommand = null;
flowchart.ClearSelectedCommands();
}
public virtual List<Block> GetConnectedBlocks()
{
List<Block> connectedBlocks = new List<Block>();
foreach (Command command in commandList)
{
if (command != null)
{
command.GetConnectedBlocks(ref connectedBlocks);
}
}
return connectedBlocks;
}
public virtual System.Type GetPreviousActiveCommandType()
{
if (previousActiveCommandIndex >= 0 &&
previousActiveCommandIndex < commandList.Count)
{
return commandList[previousActiveCommandIndex].GetType();
}
return null;
}
}
}