It looks like you're new here. If you want to get involved, click one of these buttons!
Hi there. <<first>>
First time here, eh?
<<notfirst>>
Back again already?
<<endfirst>> What are you doing?
The principle is not unlike if/else/endif, and so I created a macro based on that code. I have heavily commented it, so if you have at least a little familiarity with code you could adapt it to other uses.macros['first'] = {
handler: function (place, macroName, params, parser) {
//var condition = parser.fullArgs();
// This is the place in the text that the first clause starts
var srcOffset = parser.source.indexOf('>>', parser.matchStart) + 2;
// This is the source text, with everything up to the start
// of the first clause chopped off
var src = parser.source.slice(srcOffset);
var endPos = -1;
var firstClause = '';
var notClause = '';
// First we need to scan through the text to extract the first and second clauses.
for (var i = 0, currentClause = true; i < src.length; i++) {
// Have we reached the end of the second clause?
// If so, set endPos (the start of the rest of the text)
// and terminate the loop
// The number 12 is the the length of <<endfirst>>
if (src.substr(i, 12) == '<<endfirst>>') {
endPos = srcOffset + i + 12;
break;
}
// Have we reached the end of the first clause?
// If so, flip to doing the second clause
// and jump ahead to skip the <<notfirst>> characters.
// The number 12 is the the length of <<notfirst>>
if (src.substr(i, 12) == '<<notfirst>>') {
currentClause = false;
i += 12;
}
// We are currently in the middle of one of the clauses, so this character
// should be added to whichever clause we are on.
if (currentClause) {
firstClause += src.charAt(i);
} else {
notClause += src.charAt(i);
}
};
// this could go wrong, so get ready to catch errors!
try {
// Now we want to display the correct clause
// Note that text instead the clause is trimmed to remove
// line breaks and spaces at either end
// This is for Sugarcube, if you are using sugarcane, comment the next line, and uncomment the one after
if (visited(state.active.title) == 1) {
// if (visited(state.history[0].passage.title) == 1) {
new Wikifier(place, firstClause.trim());
} else {
new Wikifier(place, notClause.trim());
}
// Finally push the parser past the entire expression
if (endPos != -1) {
parser.nextMatch = endPos;
} else {
throwError(place, "can't find matching endfirst");
}
// Oh, and just in case there was a problem, catch those errors
} catch (e) {
throwError(place, 'bad condition: ' + e.message);
};
}
};
// Also need to register <<notfirst>> and <<endfirst>> so Twine does
// not throw an error when it hits them.
macros['notfirst'] = macros['endfirst'] = { handler: function() {} };
Comments
http://twinery.org/forum/index.php/topic,1560.0.html
And it turns out that visited() is a pretty tidy way to do what your macro does while also allowing for susequent visits, if I understand correctly.
However, what would be really, really awesome is a function like you describe that will work anywhere, independent of (but still usable for) passage visits. So I can have a piece of conditional text that could show up anywhere in the story, in a display passage for example, and using this kind of syntax to allow for more than just first time cases:
<<changingtext>>You are surprised to see a cat here!<<second>>That cat's still hanging around.<<third>>The cat meows plaintively.<<final>>You're getting sick of that damn cat.<<endchangingtext>>
I realise this is pretty different from what you're doing. Just wishing in the wind here.
A little tweak should extend it to mostly useless's issue... ::A Room
<<visits "You are surprised to see a black cat here!" "That cat's still hanging around." "The cat meows plaintively." "You're getting sick of that damn cat.">>
EDIT: Actually, hold on. Won't that just work for passage visits?
Yes, because both The Pixie and mykael solutions rely on the visited function to work.
Do you mean something like this: ?
Is that what you mean? I accidentally realized while writing something for Sharpe's last challenge that you can usefully reuse a passage by displaying it wherever you want, and having a lot of conditional code in that passage that makes what it displays vary a lot.
I hope that makes sense, and you probably already know that, so I'm not sure if I'm understanding you. :P
Call it as: The cat value is to tell it the name of the counter to use - it automatically get incremented every time the macro is called.
@mykael - and there it is! Nice! Its 3-30am and I have work tomorrow, but i will totally try that out when I get home. Thanks!