mirror of
https://github.com/Ratstail91/Mementos.git
synced 2025-11-29 10:34:27 +11:00
Committed everything
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ink.Parsed
|
||||
{
|
||||
[System.Flags]
|
||||
public enum SequenceType
|
||||
{
|
||||
Stopping = 1, // default
|
||||
Cycle = 2,
|
||||
Shuffle = 4,
|
||||
Once = 8
|
||||
}
|
||||
|
||||
public class Sequence : Parsed.Object
|
||||
{
|
||||
|
||||
public List<Parsed.Object> sequenceElements;
|
||||
public SequenceType sequenceType;
|
||||
|
||||
public Sequence (List<ContentList> elementContentLists, SequenceType sequenceType)
|
||||
{
|
||||
this.sequenceType = sequenceType;
|
||||
this.sequenceElements = new List<Parsed.Object> ();
|
||||
|
||||
foreach (var elementContentList in elementContentLists) {
|
||||
|
||||
var contentObjs = elementContentList.content;
|
||||
|
||||
Parsed.Object seqElObject = null;
|
||||
|
||||
// Don't attempt to create a weave for the sequence element
|
||||
// if the content list is empty. Weaves don't like it!
|
||||
if (contentObjs == null || contentObjs.Count == 0)
|
||||
seqElObject = elementContentList;
|
||||
else
|
||||
seqElObject = new Weave (contentObjs);
|
||||
|
||||
this.sequenceElements.Add (seqElObject);
|
||||
AddContent (seqElObject);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate runtime code that looks like:
|
||||
//
|
||||
// chosenIndex = MIN(sequence counter, num elements) e.g. for "Stopping"
|
||||
// if chosenIndex == 0, divert to s0
|
||||
// if chosenIndex == 1, divert to s1 [etc]
|
||||
//
|
||||
// - s0:
|
||||
// <content for sequence element>
|
||||
// divert to no-op
|
||||
// - s1:
|
||||
// <content for sequence element>
|
||||
// divert to no-op
|
||||
// - s2:
|
||||
// empty branch if using "once"
|
||||
// divert to no-op
|
||||
//
|
||||
// no-op
|
||||
//
|
||||
public override Runtime.Object GenerateRuntimeObject ()
|
||||
{
|
||||
var container = new Runtime.Container ();
|
||||
container.visitsShouldBeCounted = true;
|
||||
container.countingAtStartOnly = true;
|
||||
|
||||
_sequenceDivertsToResove = new List<SequenceDivertToResolve> ();
|
||||
|
||||
// Get sequence read count
|
||||
container.AddContent (Runtime.ControlCommand.EvalStart ());
|
||||
container.AddContent (Runtime.ControlCommand.VisitIndex ());
|
||||
|
||||
bool once = (sequenceType & SequenceType.Once) > 0;
|
||||
bool cycle = (sequenceType & SequenceType.Cycle) > 0;
|
||||
bool stopping = (sequenceType & SequenceType.Stopping) > 0;
|
||||
bool shuffle = (sequenceType & SequenceType.Shuffle) > 0;
|
||||
|
||||
var seqBranchCount = sequenceElements.Count;
|
||||
if (once) seqBranchCount++;
|
||||
|
||||
// Chosen sequence index:
|
||||
// - Stopping: take the MIN(read count, num elements - 1)
|
||||
// - Once: take the MIN(read count, num elements)
|
||||
// (the last one being empty)
|
||||
if (stopping || once) {
|
||||
//var limit = stopping ? seqBranchCount-1 : seqBranchCount;
|
||||
container.AddContent (new Runtime.IntValue (seqBranchCount-1));
|
||||
container.AddContent (Runtime.NativeFunctionCall.CallWithName ("MIN"));
|
||||
}
|
||||
|
||||
// - Cycle: take (read count % num elements)
|
||||
else if (cycle) {
|
||||
container.AddContent (new Runtime.IntValue (sequenceElements.Count));
|
||||
container.AddContent (Runtime.NativeFunctionCall.CallWithName ("%"));
|
||||
}
|
||||
|
||||
// Shuffle
|
||||
if (shuffle) {
|
||||
|
||||
// Create point to return to when sequence is complete
|
||||
var postShuffleNoOp = Runtime.ControlCommand.NoOp();
|
||||
|
||||
// When visitIndex == lastIdx, we skip the shuffle
|
||||
if ( once || stopping )
|
||||
{
|
||||
// if( visitIndex == lastIdx ) -> skipShuffle
|
||||
int lastIdx = stopping ? sequenceElements.Count - 1 : sequenceElements.Count;
|
||||
container.AddContent(Runtime.ControlCommand.Duplicate());
|
||||
container.AddContent(new Runtime.IntValue(lastIdx));
|
||||
container.AddContent(Runtime.NativeFunctionCall.CallWithName("=="));
|
||||
|
||||
var skipShuffleDivert = new Runtime.Divert();
|
||||
skipShuffleDivert.isConditional = true;
|
||||
container.AddContent(skipShuffleDivert);
|
||||
|
||||
AddDivertToResolve(skipShuffleDivert, postShuffleNoOp);
|
||||
}
|
||||
|
||||
// This one's a bit more complex! Choose the index at runtime.
|
||||
var elementCountToShuffle = sequenceElements.Count;
|
||||
if (stopping) elementCountToShuffle--;
|
||||
container.AddContent (new Runtime.IntValue (elementCountToShuffle));
|
||||
container.AddContent (Runtime.ControlCommand.SequenceShuffleIndex ());
|
||||
if (once || stopping) container.AddContent(postShuffleNoOp);
|
||||
}
|
||||
|
||||
container.AddContent (Runtime.ControlCommand.EvalEnd ());
|
||||
|
||||
// Create point to return to when sequence is complete
|
||||
var postSequenceNoOp = Runtime.ControlCommand.NoOp();
|
||||
|
||||
// Each of the main sequence branches, and one extra empty branch if
|
||||
// we have a "once" sequence.
|
||||
for (var elIndex=0; elIndex<seqBranchCount; elIndex++) {
|
||||
|
||||
// This sequence element:
|
||||
// if( chosenIndex == this index ) divert to this sequence element
|
||||
// duplicate chosen sequence index, since it'll be consumed by "=="
|
||||
container.AddContent (Runtime.ControlCommand.EvalStart ());
|
||||
container.AddContent (Runtime.ControlCommand.Duplicate ());
|
||||
container.AddContent (new Runtime.IntValue (elIndex));
|
||||
container.AddContent (Runtime.NativeFunctionCall.CallWithName ("=="));
|
||||
container.AddContent (Runtime.ControlCommand.EvalEnd ());
|
||||
|
||||
// Divert branch for this sequence element
|
||||
var sequenceDivert = new Runtime.Divert ();
|
||||
sequenceDivert.isConditional = true;
|
||||
container.AddContent (sequenceDivert);
|
||||
|
||||
Runtime.Container contentContainerForSequenceBranch;
|
||||
|
||||
// Generate content for this sequence element
|
||||
if ( elIndex < sequenceElements.Count ) {
|
||||
var el = sequenceElements[elIndex];
|
||||
contentContainerForSequenceBranch = (Runtime.Container)el.runtimeObject;
|
||||
}
|
||||
|
||||
// Final empty branch for "once" sequences
|
||||
else {
|
||||
contentContainerForSequenceBranch = new Runtime.Container();
|
||||
}
|
||||
|
||||
contentContainerForSequenceBranch.name = "s" + elIndex;
|
||||
contentContainerForSequenceBranch.InsertContent(Runtime.ControlCommand.PopEvaluatedValue(), 0);
|
||||
|
||||
// When sequence element is complete, divert back to end of sequence
|
||||
var seqBranchCompleteDivert = new Runtime.Divert ();
|
||||
contentContainerForSequenceBranch.AddContent (seqBranchCompleteDivert);
|
||||
container.AddToNamedContentOnly (contentContainerForSequenceBranch);
|
||||
|
||||
// Save the diverts for reference resolution later (in ResolveReferences)
|
||||
AddDivertToResolve (sequenceDivert, contentContainerForSequenceBranch);
|
||||
AddDivertToResolve (seqBranchCompleteDivert, postSequenceNoOp);
|
||||
}
|
||||
|
||||
container.AddContent (postSequenceNoOp);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
void AddDivertToResolve(Runtime.Divert divert, Runtime.Object targetContent)
|
||||
{
|
||||
_sequenceDivertsToResove.Add( new SequenceDivertToResolve() {
|
||||
divert = divert,
|
||||
targetContent = targetContent
|
||||
});
|
||||
}
|
||||
|
||||
public override void ResolveReferences(Story context)
|
||||
{
|
||||
base.ResolveReferences (context);
|
||||
|
||||
foreach (var toResolve in _sequenceDivertsToResove) {
|
||||
toResolve.divert.targetPath = toResolve.targetContent.path;
|
||||
}
|
||||
}
|
||||
|
||||
class SequenceDivertToResolve
|
||||
{
|
||||
public Runtime.Divert divert;
|
||||
public Runtime.Object targetContent;
|
||||
}
|
||||
List<SequenceDivertToResolve> _sequenceDivertsToResove;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user