Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Ink / InkLibs / InkCompiler / ParsedHierarchy / Sequence.cs
  1. using System.Collections.Generic;
  2. namespace Ink.Parsed
  3. {
  4. [System.Flags]
  5. public enum SequenceType
  6. {
  7. Stopping = 1, // default
  8. Cycle = 2,
  9. Shuffle = 4,
  10. Once = 8
  11. }
  12. public class Sequence : Parsed.Object
  13. {
  14. public List<Parsed.Object> sequenceElements;
  15. public SequenceType sequenceType;
  16. public Sequence (List<ContentList> elementContentLists, SequenceType sequenceType)
  17. {
  18. this.sequenceType = sequenceType;
  19. this.sequenceElements = new List<Parsed.Object> ();
  20. foreach (var elementContentList in elementContentLists) {
  21. var contentObjs = elementContentList.content;
  22. Parsed.Object seqElObject = null;
  23. // Don't attempt to create a weave for the sequence element
  24. // if the content list is empty. Weaves don't like it!
  25. if (contentObjs == null || contentObjs.Count == 0)
  26. seqElObject = elementContentList;
  27. else
  28. seqElObject = new Weave (contentObjs);
  29. this.sequenceElements.Add (seqElObject);
  30. AddContent (seqElObject);
  31. }
  32. }
  33. // Generate runtime code that looks like:
  34. //
  35. // chosenIndex = MIN(sequence counter, num elements) e.g. for "Stopping"
  36. // if chosenIndex == 0, divert to s0
  37. // if chosenIndex == 1, divert to s1 [etc]
  38. //
  39. // - s0:
  40. // <content for sequence element>
  41. // divert to no-op
  42. // - s1:
  43. // <content for sequence element>
  44. // divert to no-op
  45. // - s2:
  46. // empty branch if using "once"
  47. // divert to no-op
  48. //
  49. // no-op
  50. //
  51. public override Runtime.Object GenerateRuntimeObject ()
  52. {
  53. var container = new Runtime.Container ();
  54. container.visitsShouldBeCounted = true;
  55. container.countingAtStartOnly = true;
  56. _sequenceDivertsToResove = new List<SequenceDivertToResolve> ();
  57. // Get sequence read count
  58. container.AddContent (Runtime.ControlCommand.EvalStart ());
  59. container.AddContent (Runtime.ControlCommand.VisitIndex ());
  60. bool once = (sequenceType & SequenceType.Once) > 0;
  61. bool cycle = (sequenceType & SequenceType.Cycle) > 0;
  62. bool stopping = (sequenceType & SequenceType.Stopping) > 0;
  63. bool shuffle = (sequenceType & SequenceType.Shuffle) > 0;
  64. var seqBranchCount = sequenceElements.Count;
  65. if (once) seqBranchCount++;
  66. // Chosen sequence index:
  67. // - Stopping: take the MIN(read count, num elements - 1)
  68. // - Once: take the MIN(read count, num elements)
  69. // (the last one being empty)
  70. if (stopping || once) {
  71. //var limit = stopping ? seqBranchCount-1 : seqBranchCount;
  72. container.AddContent (new Runtime.IntValue (seqBranchCount-1));
  73. container.AddContent (Runtime.NativeFunctionCall.CallWithName ("MIN"));
  74. }
  75. // - Cycle: take (read count % num elements)
  76. else if (cycle) {
  77. container.AddContent (new Runtime.IntValue (sequenceElements.Count));
  78. container.AddContent (Runtime.NativeFunctionCall.CallWithName ("%"));
  79. }
  80. // Shuffle
  81. if (shuffle) {
  82. // Create point to return to when sequence is complete
  83. var postShuffleNoOp = Runtime.ControlCommand.NoOp();
  84. // When visitIndex == lastIdx, we skip the shuffle
  85. if ( once || stopping )
  86. {
  87. // if( visitIndex == lastIdx ) -> skipShuffle
  88. int lastIdx = stopping ? sequenceElements.Count - 1 : sequenceElements.Count;
  89. container.AddContent(Runtime.ControlCommand.Duplicate());
  90. container.AddContent(new Runtime.IntValue(lastIdx));
  91. container.AddContent(Runtime.NativeFunctionCall.CallWithName("=="));
  92. var skipShuffleDivert = new Runtime.Divert();
  93. skipShuffleDivert.isConditional = true;
  94. container.AddContent(skipShuffleDivert);
  95. AddDivertToResolve(skipShuffleDivert, postShuffleNoOp);
  96. }
  97. // This one's a bit more complex! Choose the index at runtime.
  98. var elementCountToShuffle = sequenceElements.Count;
  99. if (stopping) elementCountToShuffle--;
  100. container.AddContent (new Runtime.IntValue (elementCountToShuffle));
  101. container.AddContent (Runtime.ControlCommand.SequenceShuffleIndex ());
  102. if (once || stopping) container.AddContent(postShuffleNoOp);
  103. }
  104. container.AddContent (Runtime.ControlCommand.EvalEnd ());
  105. // Create point to return to when sequence is complete
  106. var postSequenceNoOp = Runtime.ControlCommand.NoOp();
  107. // Each of the main sequence branches, and one extra empty branch if
  108. // we have a "once" sequence.
  109. for (var elIndex=0; elIndex<seqBranchCount; elIndex++) {
  110. // This sequence element:
  111. // if( chosenIndex == this index ) divert to this sequence element
  112. // duplicate chosen sequence index, since it'll be consumed by "=="
  113. container.AddContent (Runtime.ControlCommand.EvalStart ());
  114. container.AddContent (Runtime.ControlCommand.Duplicate ());
  115. container.AddContent (new Runtime.IntValue (elIndex));
  116. container.AddContent (Runtime.NativeFunctionCall.CallWithName ("=="));
  117. container.AddContent (Runtime.ControlCommand.EvalEnd ());
  118. // Divert branch for this sequence element
  119. var sequenceDivert = new Runtime.Divert ();
  120. sequenceDivert.isConditional = true;
  121. container.AddContent (sequenceDivert);
  122. Runtime.Container contentContainerForSequenceBranch;
  123. // Generate content for this sequence element
  124. if ( elIndex < sequenceElements.Count ) {
  125. var el = sequenceElements[elIndex];
  126. contentContainerForSequenceBranch = (Runtime.Container)el.runtimeObject;
  127. }
  128. // Final empty branch for "once" sequences
  129. else {
  130. contentContainerForSequenceBranch = new Runtime.Container();
  131. }
  132. contentContainerForSequenceBranch.name = "s" + elIndex;
  133. contentContainerForSequenceBranch.InsertContent(Runtime.ControlCommand.PopEvaluatedValue(), 0);
  134. // When sequence element is complete, divert back to end of sequence
  135. var seqBranchCompleteDivert = new Runtime.Divert ();
  136. contentContainerForSequenceBranch.AddContent (seqBranchCompleteDivert);
  137. container.AddToNamedContentOnly (contentContainerForSequenceBranch);
  138. // Save the diverts for reference resolution later (in ResolveReferences)
  139. AddDivertToResolve (sequenceDivert, contentContainerForSequenceBranch);
  140. AddDivertToResolve (seqBranchCompleteDivert, postSequenceNoOp);
  141. }
  142. container.AddContent (postSequenceNoOp);
  143. return container;
  144. }
  145. void AddDivertToResolve(Runtime.Divert divert, Runtime.Object targetContent)
  146. {
  147. _sequenceDivertsToResove.Add( new SequenceDivertToResolve() {
  148. divert = divert,
  149. targetContent = targetContent
  150. });
  151. }
  152. public override void ResolveReferences(Story context)
  153. {
  154. base.ResolveReferences (context);
  155. foreach (var toResolve in _sequenceDivertsToResove) {
  156. toResolve.divert.targetPath = toResolve.targetContent.path;
  157. }
  158. }
  159. class SequenceDivertToResolve
  160. {
  161. public Runtime.Divert divert;
  162. public Runtime.Object targetContent;
  163. }
  164. List<SequenceDivertToResolve> _sequenceDivertsToResove;
  165. }
  166. }