Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Advanced Passage Connectivity Testing

I raised this as an enhancement issue at the twinejs repo already, but I'd just like to post here as well.

One feature that would be widely useful is telling the user what branches are reachable from a starting passage. By reachable I mean not just are there edges that can be traced back to the starting passage, but whether it's possible to have the values of state needed to use those edges to actually get there, since edges are usually conditional (e.g. a character must pass a variable test to be able to take a certain path). Currently, when you hover over a passage, there are 4 buttons (delete, edit, test from, and start from), and I envision this to be a 5th button (see all possible branches from).

What this would boil down to is the user can select any passage as the starting point, and initiate a DFS-like sort of search, where you recursively evaluate the code in every passage and then do the same for all passages that are linked into from there (as visible after evaluating the control structure). Recognizing loops (same passage and same state, note that if you end up in the same passage but with a different state that's not really a true loop) is easy by storing the hash of the state and "colorizing" each passage visited with the current state hash. The user (author of story) would be able to specify which set of variables is considered the state.

I realize after reading through the twine source that twine doesn't really know what the storyformats are doing. Passage navigation is a storyformat function, so I would like to make a prototype of this for SugarCube 2. I'm wondering if TheMadExile could tell me how passage navigation and code execution inside a passage works.


  • So some prototype JS:
    // passage traceback object
    var passageNode = function(passageName, parentPassage) {
    	this.passageName = passageName;
    	this.parentPassage = parentPassage;
    // global states to be updated inside the visiting function
    // hold the hash of all states to know whether passage has been visited
    var reachedStates = new Set();
    // holds all unique passage states visited (can have the same passage with dif parent)
    var reachedPassages = [];
    // array holding string name of story variables that user thinks is important to state
    var userStateVars = [];
    function hash(state) {
    	// ... somehow hash the state
    	return statehash;
    // pick only the part of the state that the user is interested in
    function userState() {
    	return userStateVars.reduce(function(us,var){ 
    		us[var] = SugarCube.State.variables[var];
    		return us;}, {});
    function visit(parentPassage, DOMElemToClick) {
    	if (DOMElemToClick)	// initial call is null;
    	var state = userState();
    	var statehash = hash(state);
    	if (reachedStates.has(statehash)) {
    		State.backward();	// restore back to previous state
    	// new passage
    	var newPassage = new passageNode(State.passage, parentPassage);
    	// get all reachable links from passage
    	var links = $("#passages .link-internal");
    	for (var i = 0, len = links.length; i < len; ++i) {
    		visit(newPassage, links[i]);
    // after visit is run on the initial passage, 
    // iterate through reachedPassages and colour them inside Twine IDE
    // not entirely sure how to do this yet, maybe through the setup parameter
    // that the story format exports back to Twine (how Harlowe does syntax highlighting) 
  • I just tested the prototype code by injecting it through Chrome console on a test story (with some modifications, such as adding passage name to always be part of state, making the hash just be JSON.stringify(state), fixing the var keyword conflict, and prepending each State with SugarCube for testing in browser).

    After setting userStateVars, testing on the current displayed passage (in play or test mode) with
    visit(SugarCube.State.passage, null)
    it seems to work, with reachedPassages containing only the valid passageNode objects (purposely made some unreachable because you can never get a variable that high through any branch).

    I would now like to iterate through all passageNode objects in reachedPassages, set them to a different color in the story map mode, and draw dashed back arrows to the passage(s) they were reached from. As I mentioned above, I would also like to add an additional passage on-hover button that would call visit(hovered_passage, null) and then perform the colorization. Any suggestions for how I can proceed from here?
Sign In or Register to comment.