Im using Chapbook, and i want to achieve this: i have a passage with two links, [[this]] and [[that]]. Both of them link to the same passage, but i want the text of this passage to be a little different according to the way the player got there. What is the best way to modify the value of a variable after the player clicks but before the next passage shows? In the next passage the values of the variables should be evaluated.
As explained in The Vars Section documentation, variables can only be assigned a value in the Var section of a Passage.
However that Var section can belong to either the Passage being visited, or to a āchildā Passage that is being embedded (using {embed}
) within the visited Passage.
eg. the following TWEE Notation based example demonstrates such variable updating via embeddingā¦
:: Start
counter: 1
--
before embedding: Counter: { counter } (displays 1)
{embed passage: 'Increase Counter'}
after embedding: Counter: { counter } (displays 2)
:: Increase Counter
counter: counter + 1
--
Some story formats support a concept known as a āLink with Setterā (aka a āSetter Linkā), which is a link that assigns values to variables before preforming a Passage Transitionā¦
/* SugarCube based examples... */
[[Link Text|Target Passage][$variable to "value"]]
<<link 'Link Text' 'Target Passage'>><<set $variable to "value">><</link>>
/* Harlowe based example. */
(link-reveal-goto: 'Link Text', 'Target Passage')[(set: $variable to "value")]
ā¦but unfortunately Chapbookās Link Inserts currently donāt support such functionality, so you would need to create your own custom insert.
Thank you Grey!
One more question. If i made my own insert, wouldnāt i loose the visual representation of links in Twineās visual editor?
In case i remain in Chapobook, i was thinking about linking each choice to a different ghost passage that modifies, each in itās own way, the values of the variables but embeds the same real passage. Did you mean something like that?
First problem of my approach. If 5 different passages lead to the same passage in different ways, and i want to modify the value of different variables acording to the choice made, i should add 5 ghost passagesā¦
Chapbook suddenly looses its appeal. Its chapbook or Twineās Visual Editor.
Another chapbook issue: no tag expositionā¦
Yes. And the same is true if you use any of the Link Inserts.
But, the Twine 2.x applicationās āfind all links within a Passageā feature doesnāt understand what a HTML Comment is, so it doesnāt exclude a commentās content like it should when it is searching through a Passage. On the other hand Story Format runtimes do know what a HTML Comment is, so it handles them correctly when process a Passage.
So you can use this misunderstanding to your advantage while using the Twine 2.x application, by using HTML Comments to trick the āfind all links within a Passageā feature.
eg. the āfind all links within a Passageā feature will ignore the following Link Insertā¦
{link to: 'Target Passage', label: 'Label Text'}
ā¦so it wonāt create a āTarget Passageā if it is missing, or a Connection Arrow to it if it already exists. But if you add a HTML Comment like soā¦
<!-- [[Label Text|Target Passage]] -->
{link to: 'Target Passage', label: 'Label Text'}
ā¦then the āfind all links within a Passageā feature will do both things, even though it shouldnāt
You have definitely escaped the Matrix, Grey!
I have found that if you create a JavaScript tag inside a passage, and inside that tag you code a link using the function āwriteā, the linked passage is automatically created and/or linked in Twineās visual editor:
[JavaScript]
write ("[[Go left]]");
[continue]
It automatically creates a passage named āGo leftā (if it yet didnāt existed) and adds a visual connection to it.
For the same reason that having Link Markup in a comment does.
eg. The āfind all links within a Passageā feature doesnāt understand what JavaScript code is either, so it just sees the [[Go left]]
and decides that it looks like a standard Markup based link.
Using a String variable literal that contains mark-up link like characters will also trick the featureā¦
/* Chapbook */
links: '[[Apple]] [[Banana]]'
--
/* Harlowe */
(set: _links to '[[Apple]] [[Banana]]')
/* SugarCube */
<<set _links to '[[Apple]] [[Banana]]'>>
Here is a custom insert that does what you need
engine.extend('1.0.0', () => {
engine.event.prependListener('dom-click', el => {
let vars = el.dataset.cbSetVars;
if (vars) {
let result = engine.render(vars.replace(';',"\n")+"\n--");
}
});
config.template.inserts = [{
match: /^set\s+link/i,
render(passage, props) {
if (passage) {
return `<a href='javascript:void(0)'
data-cb-go="${passage}"
data-cb-set-vars="${props.set}">${props.label}</a>`;
}
}
}, ...config.template.inserts];
});
You can use it like a link {set link: 'Another passage', label: 'A link', set: 'foo: 2'}
. The code in set
is like the vars section, except that you can indicate multiple lines with a ;
instead of a line break.
e.g.
{set link: 'Another passage', label: 'A link', set: 'foo: 2;bar: 4;name "hello"'}
This will expose the Twine passage tags in Chapbook:
window.passageTags = {}; // <== object format { passage name : tags }
let _storyData = document.getElementsByTagName( 'tw-storydata' )[0];
for ( let _child = _storyData.firstChild; _child !== null; _child = _child.nextSibling ) {
if ( _child.tagName.toLowerCase() == 'tw-passagedata' ) {
passageTags[ _child.getAttribute( 'name' ) ] = _child.getAttribute( 'tags' );
}
}
window.getTags = function ( _passageName ) {
return passageTags[ _passageName ].toLowerCase();
}
It basically grabs the Twine story data and stores the tags and then you can then do whatever you want with that data. For example, I could run:
if ( getTags( passage.name ).includes( "specific-tag-name" ) ) {
// ==> do something if "specific-tag-name" exists in the current passage
}
You can also put that logic into a custom insert if need be.
If I could offer alternative getTags()
functions that both leverages Chapbookās exported APIs and returns an unmodified array of tags.
Included are two versions (use only one). The code goes into the storyās JavaScript section.
Throws an error if the specified passage is nonexistent.
CODE:
/**
* getTags(name) - Passage tags retrieval function.
*
* @param {string} name - Passage name.
* @returns {Array<string>} Passage tags.
* @throws {Error} Passage must exist.
*/
function getTags(name) {
const passage = engine.story.passageNamed(name);
if (!passage) {
throw new Error(`There is no passage named "${name}".`);
}
return passage.tags;
}
Returns an empty array if the specified passage is nonexistent.
CODE:
/**
* getTags(name) - Passage tags retrieval function.
*
* @param {string} name - Passage name.
* @returns {Array<string>} Passage tags.
*/
function getTags(name) {
const passage = engine.story.passageNamed(name);
return passage ? passage.tags : [];
}
USAGE:
if (getTags('some passage').includes('some-tag')) {
// The tag `some-tag` exists on the specified passage.
}
With thanks to @TheMadExile and @klembot, Iāve re-written my suggested insert above to be more elegant (and more performant)
Definitely, Chapbook has the best community and the most commited developers! Thanks to you all!
And Iāve scrapped my tag code altogether.
I didnāt think to do a console.log() of the passage
object. Iām such a dummy, but I still had fun figuring it out the hard way.
@TheMadExile You wouldnāt happen to have a super secret, rough draft of the API document kicking around, would you?
We are the best! All 5 or 6 of us! High fives all around!
This code doesnāt seem to work:
{set link: 'Another passage', label: 'A link', set: 'foo: 2;bar: 4;name "hello"'}
This is what is rendered in the browser:
The straight quotation marks are converted into curly quotation marks, and the returned value is rendered as a string, not as a link.
Its really messy to mix different types of quotation marks.
But if you set the value of the variable ānameā outside the insert (fin the vars section, for example) the code works flawlessly.
Youāre missing a colon after name
, I believe. Though that probably has nothing to do with the curly quotes rendering problem. I only mention it, just in case.
By the way, Iām learning so much about Chapbook from your questions and the answers from others. Thanks for that.
#METOO
No, just the code in its GitHub repo. Itās ā¦/extensibility.js file shows what it exports via the engine
API for user use.
Changing out all of the typographic (curly) quotes, both single and double, for regular quotes will probably fix the problems youāre having. Even if you do have other issues to work out, you still need to do that as typographic quotes are not valid syntax.