implementing a Back mechanic for stacked sub passages - jackdarker/TwineTest GitHub Wiki
In many passages I'm using <%s.player.location=window.passage.name;%> to memorize at which location the player currently is.
But some passages might not be related to locations. F.e. you might have an Inventory-screen where you an dig through your items and each item might have its own passage for description.
Or a Status-Panel with several subpages, all implemented as passages.
A back-Button would fit nicely on those occasions. I wanted it to be simple with out much programming in each passage. Something like this:
:: Info_Jake [back]
Jake is here.</br>
[[Back|_back]]</br>
Notice the Back-Link pointing to _back and the tag back. _back is used as a codeword in the logic implemented here:
First we need a passageStack-variable holding a stack of passagenames when going into passages with tag=back.
Then override the window.story.show function to intercept _back-Links.
//when show is called the previous passage is stored if the new has [back]-tag
//if the new has no back-tag, the stack gets cleared
window.gm.pushPassage=function(id) {
if(!window.story.state.hasOwnProperty("vars")) return; //vars exist only after initGame
if(window.story.state.vars.passageStack.length>0 && window.story.state.vars.passageStack[window.story.state.vars.passageStack.length-1]===id){
//already pushed
} else {
window.story.state.vars.passageStack.push(id);
}
};
//call on [back]-passages to get the previous passage
window.gm.popPassage=function() {
var pass = window.story.state.vars.passageStack.pop();
if(!pass) return('nothing to pop from stack');
return(pass);
};
//overriding show:
var _origStoryShow = window.story.__proto__.show;
window.story.__proto__.show = function(idOrName, noHistory = false) {
var next = idOrName;
if(idOrName === '_back') { //going back
next = window.gm.popPassage();
} else { //going forward
var tagsnext = window.story.passage(next).tags;
var namenext = window.story.passage(next).name;
if(tagsnext.indexOf('back')>=0 ) { //push on stack but only if not re-showing itself
if(namenext!=window.passage.name) window.gm.pushPassage(window.passage.name);
} else if(window.story.state.hasOwnProperty("vars")) {
window.story.state.vars.passageStack.splice(0,window.story.state.vars.passageStack.length);
}
}
_origStoryShow.call(window.story,next, noHistory);
};
When returning from the Back-passage to your original passage, the code in this passage will be executed again.
We need to add a flag (_done) to memorize if the code was run once before and also memorize the result.
When finally leaving the page, reset the flag to be able to get triggered again. Instead of a local flag you could of course use a variable in your game-data.
:: DngPC
You just triggered a trap! </br><div id='output'></div>
<a0 onclick='_done=false,window.story.show(window.story.state.DngSY.prevLocation)'>retreat</a>. <!--when leaving the page, reset done!-->
<script>{var _triggered,_done,_x=window.gm.player.Stats.get("mystatMax").value-window.gm.player.Stats.get("mystat").value;
//notice the additional {} around the script to avoid pollution of global space
//and dont initilize _done & _triggered
if(!_done) { _done=true; //if done is not initilized we run the calculation
if(_x>=5){window.gm.player.Stats.increment("mystat",_x/3);
_triggered=true; //we might need to memorize the result of calculation
} else { _triggered=false;}
}
if(_triggered){ //if we return from back, we will just update the screen but dont recalculate
window.gm.printOutput("That gas somehow clouds your mind, you need to get out of here !</br>")
} else { window.gm.printOutput("Whatever the fumes should do, you dont notice any effect.")
}}</script>