Skip to content

Commit

Permalink
Improved version of EvaluateFunction that doesn't clobber the current…
Browse files Browse the repository at this point in the history
… story state, and can be caused before Continue() has been called for the first time
  • Loading branch information
joethephish committed Aug 4, 2016
1 parent b2dfbef commit 910313a
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 25 deletions.
56 changes: 32 additions & 24 deletions ink-engine-runtime/Story.cs
Original file line number Diff line number Diff line change
Expand Up @@ -968,10 +968,10 @@ public void ChooseChoiceIndex(int choiceIdx)
/// </summary>
/// <returns>The return value as returned from the ink function with `~ return myValue`, or null if nothing is returned.</returns>
/// <param name="functionName">The name of the function as declared in ink.</param>
public object EvaluateFunction (string functionName)
public object EvaluateFunction (string functionName, params object [] arguments)
{
string _;
return EvaluateFunction (functionName, out _);
return EvaluateFunction (functionName, out _, arguments);
}

/// <summary>
Expand All @@ -980,7 +980,7 @@ public object EvaluateFunction (string functionName)
/// </summary>
/// <returns>The return value as returned from the ink function with `~ return myValue`, or null if nothing is returned.</returns>
/// <param name="functionName">The name of the function as declared in ink.</param>
public object EvaluateFunction (string functionName, out string textOutput)
public object EvaluateFunction (string functionName, out string textOutput, params object [] arguments)
{
Runtime.Container funcContainer = null;
try {
Expand All @@ -992,34 +992,43 @@ public object EvaluateFunction (string functionName, out string textOutput)
throw e;
}

int startCallStackHeight = state.callStack.elements.Count;

// Divert into the function
// We'll start a new callstack, so keep hold of the original,
// as well as the evaluation stack so we know if the function
// returned something
var originalCallstack = state.callStack;
int originalEvaluationStackHeight = state.evaluationStack.Count;

// Create a new base call stack element.
// By making it point at element 0 of the base, when NextContent is
// called, it'll actually step past the entire content of the game (!)
// and straight onto the Done. Bit of a hack :-/ We don't really have
// a better way of creating a temporary context that ends correctly.
state.callStack = new CallStack (mainContentContainer);
state.callStack.currentElement.currentContainer = mainContentContainer;
state.callStack.currentElement.currentContentIndex = 0;

// Jump into the function!
state.callStack.Push (PushPopType.Function);
state.currentContentObject = funcContainer;

int evalStackHeight = state.evaluationStack.Count;

// Evaluate the function, and collect the string output
var stringOutput = new StringBuilder ();

// Evaluate the function
while (state.callStack.elements.Count > startCallStackHeight && canContinue) {
while (canContinue) {
stringOutput.Append (Continue ());
}

textOutput = stringOutput.ToString ();

// Should have completed the function, which should
// have popped, but just in case we didn't for some reason,
// manually pop to restore the state (including currentPath).
if (state.callStack.elements.Count > startCallStackHeight) {
state.callStack.Pop ();
}
// Restore original stack
state.callStack = originalCallstack;

// Do we have a returned value?
int endStackHeight = state.evaluationStack.Count;
if (endStackHeight > evalStackHeight) {
var returnVal = state.PopEvaluationStack () as Runtime.Value;
if (state.evaluationStack.Count > originalEvaluationStackHeight) {
var poppedVal = state.PopEvaluationStack ();
if (poppedVal is Runtime.Void)
return null;

// Some kind of value, if not void
var returnVal = poppedVal as Runtime.Value;

// DivertTargets get returned as the string of components
// (rather than a Path, which isn't public)
Expand All @@ -1030,10 +1039,9 @@ public object EvaluateFunction (string functionName, out string textOutput)
// Other types can just have their exact object type:
// int, float, string. VariablePointers get returned as strings.
return returnVal.valueObject;

} else {
return null;
}

return null;
}

// Evaluate a "hot compiled" piece of ink content, as used by the REPL-like
Expand Down
2 changes: 1 addition & 1 deletion ink-engine-runtime/StoryState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public int VisitCountAtPathString(string pathString)
internal List<Choice> currentChoices { get; private set; }
internal List<string> currentErrors { get; private set; }
internal VariablesState variablesState { get; private set; }
internal CallStack callStack { get; private set; }
internal CallStack callStack { get; set; }
internal List<Runtime.Object> evaluationStack { get; private set; }
internal Runtime.Object divertedTargetObject { get; set; }
internal Dictionary<string, int> visitCounts { get; private set; }
Expand Down

0 comments on commit 910313a

Please sign in to comment.