diff --git a/ink-engine-runtime/ControlCommand.cs b/ink-engine-runtime/ControlCommand.cs
index ecfef5dc..8c666315 100644
--- a/ink-engine-runtime/ControlCommand.cs
+++ b/ink-engine-runtime/ControlCommand.cs
@@ -19,6 +19,7 @@ public enum CommandType
NoOp,
ChoiceCount,
TurnsSince,
+ ReadCount,
Random,
SeedRandom,
VisitIndex,
@@ -104,6 +105,11 @@ internal override Object Copy()
return new ControlCommand(CommandType.TurnsSince);
}
+ public static ControlCommand ReadCount ()
+ {
+ return new ControlCommand (CommandType.ReadCount);
+ }
+
public static ControlCommand Random ()
{
return new ControlCommand (CommandType.Random);
diff --git a/ink-engine-runtime/JsonSerialisation.cs b/ink-engine-runtime/JsonSerialisation.cs
index 93665bda..0ddc86bb 100644
--- a/ink-engine-runtime/JsonSerialisation.cs
+++ b/ink-engine-runtime/JsonSerialisation.cs
@@ -653,6 +653,7 @@ static Json()
_controlCommandNames [(int)ControlCommand.CommandType.NoOp] = "nop";
_controlCommandNames [(int)ControlCommand.CommandType.ChoiceCount] = "choiceCnt";
_controlCommandNames [(int)ControlCommand.CommandType.TurnsSince] = "turns";
+ _controlCommandNames [(int)ControlCommand.CommandType.ReadCount] = "readc";
_controlCommandNames [(int)ControlCommand.CommandType.Random] = "rnd";
_controlCommandNames [(int)ControlCommand.CommandType.SeedRandom] = "srnd";
_controlCommandNames [(int)ControlCommand.CommandType.VisitIndex] = "visit";
diff --git a/ink-engine-runtime/Story.cs b/ink-engine-runtime/Story.cs
index 7e96eff0..c33de134 100644
--- a/ink-engine-runtime/Story.cs
+++ b/ink-engine-runtime/Story.cs
@@ -15,7 +15,7 @@ public class Story : Runtime.Object
///
/// The current version of the ink story file format.
///
- public const int inkVersionCurrent = 16;
+ public const int inkVersionCurrent = 17;
// Version numbers are for engine itself and story file, rather
// than the story state save format (which is um, currently nonexistant)
@@ -853,6 +853,7 @@ bool PerformLogicAndFlowControl(Runtime.Object contentObj)
break;
case ControlCommand.CommandType.TurnsSince:
+ case ControlCommand.CommandType.ReadCount:
var target = state.PopEvaluationStack();
if( !(target is DivertTargetValue) ) {
string extraNote = "";
@@ -864,8 +865,14 @@ bool PerformLogicAndFlowControl(Runtime.Object contentObj)
var divertTarget = target as DivertTargetValue;
var container = ContentAtPath (divertTarget.targetPath) as Container;
- int turnCount = TurnsSinceForContainer (container);
- state.PushEvaluationStack (new IntValue (turnCount));
+
+ int eitherCount;
+ if (evalCommand.commandType == ControlCommand.CommandType.TurnsSince)
+ eitherCount = TurnsSinceForContainer (container);
+ else
+ eitherCount = VisitCountForContainer (container);
+
+ state.PushEvaluationStack (new IntValue (eitherCount));
break;
case ControlCommand.CommandType.Random:
diff --git a/ink-engine-runtime/StoryState.cs b/ink-engine-runtime/StoryState.cs
index 0a26c807..da0f9377 100755
--- a/ink-engine-runtime/StoryState.cs
+++ b/ink-engine-runtime/StoryState.cs
@@ -17,7 +17,7 @@ public class StoryState
///
/// The current version of the state save file JSON-based format.
///
- public const int kInkSaveStateVersion = 6;
+ public const int kInkSaveStateVersion = 7;
const int kMinCompatibleLoadVersion = 6;
///
diff --git a/inklecate/ParsedHierarchy/DivertTarget.cs b/inklecate/ParsedHierarchy/DivertTarget.cs
index 54f6a932..ef0bcaf6 100644
--- a/inklecate/ParsedHierarchy/DivertTarget.cs
+++ b/inklecate/ParsedHierarchy/DivertTarget.cs
@@ -50,7 +50,7 @@ public override void ResolveReferences (Story context)
}
else if( usageParent is FunctionCall ) {
var funcCall = usageParent as FunctionCall;
- if( !funcCall.isTurnsSince ) {
+ if( !funcCall.isTurnsSince && !funcCall.isReadCount ) {
badUsage = true;
}
foundUsage = true;
diff --git a/inklecate/ParsedHierarchy/FunctionCall.cs b/inklecate/ParsedHierarchy/FunctionCall.cs
index c8de341c..815f45d2 100644
--- a/inklecate/ParsedHierarchy/FunctionCall.cs
+++ b/inklecate/ParsedHierarchy/FunctionCall.cs
@@ -12,6 +12,7 @@ internal class FunctionCall : Expression
public bool isRandom { get { return name == "RANDOM"; } }
public bool isSeedRandom { get { return name == "SEED_RANDOM"; } }
public bool isListRange { get { return name == "LIST_RANGE"; } }
+ public bool isReadCount { get { return name == "READ_COUNT"; } }
public bool shouldPopReturnedValue;
@@ -33,34 +34,37 @@ public override void GenerateIntoContainer (Runtime.Container container)
container.AddContent (Runtime.ControlCommand.ChoiceCount ());
- } else if (isTurnsSince) {
+ } else if (isTurnsSince || isReadCount) {
var divertTarget = arguments [0] as DivertTarget;
var variableDivertTarget = arguments [0] as VariableReference;
if (arguments.Count != 1 || (divertTarget == null && variableDivertTarget == null)) {
- Error ("The TURNS_SINCE() function should take one argument: a divert target to the target knot, stitch, gather or choice you want to check. e.g. TURNS_SINCE(-> myKnot)");
+ Error ("The "+name+"() function should take one argument: a divert target to the target knot, stitch, gather or choice you want to check. e.g. TURNS_SINCE(-> myKnot)");
return;
}
if (divertTarget) {
- _turnCountDivertTarget = divertTarget;
- AddContent (_turnCountDivertTarget);
+ _divertTargetToCount = divertTarget;
+ AddContent (_divertTargetToCount);
- _turnCountDivertTarget.GenerateIntoContainer (container);
+ _divertTargetToCount.GenerateIntoContainer (container);
} else {
- _turnCountVariableReference = variableDivertTarget;
- AddContent (_turnCountVariableReference);
+ _variableReferenceToCount = variableDivertTarget;
+ AddContent (_variableReferenceToCount);
- _turnCountVariableReference.GenerateIntoContainer (container);
+ _variableReferenceToCount.GenerateIntoContainer (container);
if (!story.countAllVisits) {
Error ("Attempting to get TURNS_SINCE for a variable target without -c compiler option. You need the compiler switch turned on so that it can track turn counts for everything, not just those you directly reference.");
}
}
-
- container.AddContent (Runtime.ControlCommand.TurnsSince ());
+ if (isTurnsSince)
+ container.AddContent (Runtime.ControlCommand.TurnsSince ());
+ else
+ container.AddContent (Runtime.ControlCommand.ReadCount ());
+
} else if (isRandom) {
if (arguments.Count != 2)
Error ("RANDOM should take 2 parameters: a minimum and a maximum integer");
@@ -103,7 +107,7 @@ public override void GenerateIntoContainer (Runtime.Container container)
// Don't attempt to resolve as a divert
content.Remove (_proxyDivert);
- } else if (Runtime.NativeFunctionCall.CallExistsWithName(name)) {
+ } else if (Runtime.NativeFunctionCall.CallExistsWithName (name)) {
var nativeCall = Runtime.NativeFunctionCall.CallWithName (name);
@@ -121,8 +125,7 @@ public override void GenerateIntoContainer (Runtime.Container container)
// Don't attempt to resolve as a divert
content.Remove (_proxyDivert);
- }
- else if (foundList != null) {
+ } else if (foundList != null) {
if (arguments.Count > 1)
Error ("Can currently only construct a list from one integer (or an empty list from a given list definition)");
@@ -131,7 +134,7 @@ public override void GenerateIntoContainer (Runtime.Container container)
container.AddContent (new Runtime.StringValue (name));
arguments [0].GenerateIntoContainer (container);
container.AddContent (Runtime.ControlCommand.ListFromInt ());
- }
+ }
// Empty list with given origin.
else {
@@ -144,8 +147,8 @@ public override void GenerateIntoContainer (Runtime.Container container)
content.Remove (_proxyDivert);
}
- // Normal function call
- else {
+ // Normal function call
+ else {
container.AddContent (_proxyDivert.runtimeObject);
}
@@ -170,8 +173,8 @@ public override void ResolveReferences (Story context)
arg.ResolveReferences (context);
}
- if( _turnCountDivertTarget ) {
- var divert = _turnCountDivertTarget.divert;
+ if( _divertTargetToCount ) {
+ var divert = _divertTargetToCount.divert;
var attemptingTurnCountOfVariableTarget = divert.runtimeDivert.variableDivertName != null;
if( attemptingTurnCountOfVariableTarget ) {
@@ -189,10 +192,10 @@ public override void ResolveReferences (Story context)
}
}
- else if( _turnCountVariableReference ) {
- var runtimeVarRef = _turnCountVariableReference.runtimeVarRef;
+ else if( _variableReferenceToCount ) {
+ var runtimeVarRef = _variableReferenceToCount.runtimeVarRef;
if( runtimeVarRef.pathForCount != null ) {
- Error("Should be TURNS_SINCE(-> "+_turnCountVariableReference.name+"). Without the '->' it expects a variable target");
+ Error("Should be "+name+"(-> "+_variableReferenceToCount.name+"). Usage without the '->' only makes sense for variable targets.");
}
}
}
@@ -202,7 +205,12 @@ public static bool IsBuiltIn(string name)
if (Runtime.NativeFunctionCall.CallExistsWithName (name))
return true;
- return name == "CHOICE_COUNT" || name == "TURNS_SINCE" || name == "RANDOM" || name == "SEED_RANDOM" || name == "LIST_VALUE";
+ return name == "CHOICE_COUNT"
+ || name == "TURNS_SINCE"
+ || name == "RANDOM"
+ || name == "SEED_RANDOM"
+ || name == "LIST_VALUE"
+ || name == "READ_COUNT";
}
public override string ToString ()
@@ -212,8 +220,8 @@ public override string ToString ()
}
Parsed.Divert _proxyDivert;
- Parsed.DivertTarget _turnCountDivertTarget;
- Parsed.VariableReference _turnCountVariableReference;
+ Parsed.DivertTarget _divertTargetToCount;
+ Parsed.VariableReference _variableReferenceToCount;
}
}
diff --git a/tests/Tests.cs b/tests/Tests.cs
index eb6c2ca7..4e089ac9 100644
--- a/tests/Tests.cs
+++ b/tests/Tests.cs
@@ -2889,6 +2889,34 @@ public void TestTunnelOnwardsWithParamDefaultChoice ()
Assert.AreEqual ("8\n", story.ContinueMaximally ());
}
+
+ [Test ()]
+ public void TestReadCountVariableTarget ()
+ {
+ var storyStr =
+@"
+VAR x = ->knot
+
+Count start: {READ_COUNT (x)} {READ_COUNT (-> knot)} {knot}
+
+-> x (1) ->
+-> x (2) ->
+-> x (3) ->
+
+Count end: {READ_COUNT (x)} {READ_COUNT (-> knot)} {knot}
+-> END
+
+
+== knot (a) ==
+{a}
+->->
+";
+
+ var story = CompileString (storyStr, countAllVisits:true);
+ Assert.AreEqual ("Count start: 0 0 0\n1\n2\n3\nCount end: 3 3 3\n", story.ContinueMaximally ());
+ }
+
+
[Test ()]
public void TestDivertTargetsWithParameters ()
{