{embed passage: '_Add Capitalization Insert'}
{embed passage: '_Add Text Collection Modifier and Insert'}
{embed passage: '_Add Conditional Insert'}
{embed passage: '_Add One Of and First Time Inserts and Modifiers'}[Javascript]
engine.extend('2.1.0', () => {
engine.template.inserts.add({
name: "^",
syntax: "{^ _variable_}",
description: "Print the contents of a variable, capitalizing it.",
completions: "^",
arguments: {
firstArgument: {
required: "ignored"
}
},
match: /^\^\s+\S+$/i,
render(firstArg, props, invocation) {
const variableToShow = invocation?.slice(1).trimStart();
const valueToShow = engine.state.get(variableToShow);
if (!valueToShow) {
return `{${invocation}}`;
}
return valueToShow.slice(0, 1).toLocaleUpperCase() + valueToShow.slice(1);
}
});
});[Javascript]
engine.state.set('__collected', '');
engine.extend('2.1.0', () => {
engine.template.modifiers.add({
name: "collect",
syntax: "[collect], [collect new], [collect no-space], [collect new-paragraph]",
description: "Collect the text in the modifier for later display.",
completions: ["collect", "collect new", "collect no-space", "collect new-paragraph"],
match: /^collect\b/i,
process(output, {state, invocation}) {
const modifier = invocation?.slice(7).trimStart().replace(/\s.*/, '').toLowerCase() || '';
if (config.testing && !(modifier === '' || modifier === 'new' || modifier === 'no-space' || modifier === 'new-paragraph')) {
console.warn(
`"collect" modifier can only be [collect], [collect new], [collect no-space], or [collect new-paragraph], but was called as [${invocation}]`
);
}
// Only perform collection if there's any text. That
// prevents weirdness from an [if ...; collect] block.
if (output.text != '') {
if (modifier === 'new') {
__collected = '';
}
else {
__collected = __collected.trimEnd();
if (modifier === 'new-paragraph') {
__collected += '\n\n';
}
else if (modifier !== 'no-space' && __collected !== '') {
__collected += ' ';
}
}
__collected += output.text.trimStart();
output.text = '';
}
}
});
});
[Javascript]
engine.extend('2.1.0', () => {
engine.template.inserts.add({
name: "show collected",
syntax: "{show collected, _keep: true_}",
description: "Show all text collected in previous [collect] modifiers. The collected text is emptied unless `keep` is true.",
completions: "show collected",
arguments: {
firstArgument: {
required: "ignored"
},
optionalProps: {
keep: "true"
}
},
match: /^show\s+collected/i,
render: (first_arg, props, invocation) => {
if (typeof(__collected) === undefined) {
if (config.testing) {
throw new Error('{show collected} called before any text was collected');
}
}
const output = __collected;
if (!props['keep']) {
__collected = '';
}
return output;
}
});
});
engine.extend('2.1.0', () => {
engine.template.inserts.add({
name: "empty collected",
syntax: "{empty collected}",
description: "Empty all text collected in previous [collect] modifiers without displaying it.",
completions: "empty collected",
arguments: {
firstArgument: {
required: "ignored"
},
},
match: /^empty\s+collected/i,
render: (first_arg, props, invocation) => {
__collected = '';
}
});
});{embed passage: "_Add Library Functions"}
[Javascript]
engine.extend('2.1.0', () => {
engine.template.inserts.add({
name: "if",
syntax: "{if _condition_: 'text to show if condition is true', _else: 'text to show if condition is false'_}",
description: "Show text if the contents of a variable evaluates to true. Text can contain {variable} inserts.",
completions: "if",
arguments: {
firstArgument: {
required: true,
placeholder: '"text if true"'
},
optionalProps: {
else: '"text if false"'
}
},
match: /^if\s+[^:,]/i,
render: (first_arg, props, invocation) => {
const condition = invocation.split(':')[0].slice(3);
const value = new Function(`return (${condition});`)();
return libfunc.replaceVariableInserts(((value) ? first_arg : props['else']) || '');
}
});
});{embed passage: "_Add Library Functions"}
[Javascript]
engine.state.set('zOneOfTracking', {});
engine.extend('2.1.0', () => {
engine.template.inserts.add({
name: "first time",
syntax: "{first time: 'text to show the first time only'}",
description: "Shows its text only the first time a player encounters it.",
completions: "first time",
arguments: {
firstArgument: {
required: true,
placeholder: '"text to show"'
}
},
match: /^first\s+time\b/i,
render: (to_print, props, invocation) => {
const hash = libfunc.hashInvocation(invocation);
if (zOneOfTracking[hash] === undefined) {
zOneOfTracking[hash] = true;
return to_print;
}
}
});
engine.template.modifiers.add({
name: "first time",
syntax: "[first time]",
description: "Show block of text only the first time the passage is viewed.",
match: /^first\s+time\b/i,
process(output, {invocation, state}) {
const hash = libfunc.hashInvocation(invocation);
if (zOneOfTracking[hash] === undefined) {
zOneOfTracking[hash] = true;
} else {
output.text = '';
output.startsNewParagraph = false;
}
}
});
});
[Javascript]
engine.extend('2.1.0', () => {
engine.template.inserts.add({
name: "one of",
syntax: "{one of: ['text', 'other text'], _select: 'variable', order: 'order'_}",
description: "Show varying text every time the player sees it. If 'select' is set to a variable that contains a number, the insert will show that value in the array. 'order' can be 'random' (the default), 'pure random', 'shuffled', 'stopping', or 'cycling'.",
completions: "one of",
arguments: {
firstArgument: {
required: true,
placeholder: '["text"]',
},
optionalProps: {
select: '"variable"',
order: '"pure random"'
}
},
match: /^one\s+of\b/i,
render(choices, props, invocation) {
const origInvocation = `{${invocation}}`;
const hash = libfunc.hashInvocation(invocation);
let prev = zOneOfTracking[hash];
let ret;
const order = (props.order || '').toLowerCase();
const expression = (props.select || '');
// Handle selecting by variable separately since it doesn't need an order
if (expression !== '') {
let errorMessage = '';
const selectValue = new Function(`return (${expression});`)();
if (typeof(selectValue) !== 'number') {
errorMessage = `The expression ${expression} must evaluate to a number to be used in a {one of} insert`;
}
else if (selectValue < 0 || selectValue >= choices.length) {
errorMessage = `The expression ${expression} must evaluate to a number between 0 and ${choices.length - 1} to be used in the {one of} insert`;
}
else {
ret = choices[selectValue];
}
if (errorMessage) {
if (config.testing) {
throw new Error(errorMessage);
}
ret = origInvocation;
}
return ret;
}
if (order === 'random' || order === '') {
let choice = prev;
while (choice == prev) {
choice = libfunc.randInt(choices.length);
}
zOneOfTracking[hash] = choice;
ret = choices[choice];
}
else if (order === 'pure random') {
ret = choices[libfunc.randInt(choices.length)];
}
else if (order === 'shuffled') {
if (prev === undefined || prev.length == 0) {
prev = libfunc.shuffleArray([...choices]);
}
ret = prev.pop();
zOneOfTracking[hash] = prev;
}
else if (order === 'stopping' || order === 'cycling') {
if (prev === undefined) {
prev = 0;
}
else {
prev++;
if (prev >= choices.length) {
prev = (order === 'stopping') ? choices.length - 1 : 0;
}
}
zOneOfTracking[hash] = prev;
ret = choices[prev];
}
else {
if (config.testing) {
throw new Error(
`The {one of} order was "${order}" but must be one of "random", "pure random", "shuffled", "stopping", or "cycling"`
);
}
ret = invocation;
}
return ret;
}
});
});[Javascript]
libfunc = {};
libfunc.randInt = (max) => {
return Math.floor(Math.random() * max); // Random int from 0 to max-1
}
libfunc.shuffleArray = (arr) => {
for (let i = arr.length - 1; i > 0; --i) {
const j = libfunc.randInt(i + 1);
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
libfunc.embarassinglySimpleHashCode = (s) => {
let hash = 0;
for (let i = 0; i < s.length; ++i) {
let chr = s.charCodeAt(i);
hash = (hash << 5) - hash + chr;
hash |= 0;
}
return hash;
}
libfunc.hashInvocation = (invocation) => {
return libfunc.embarassinglySimpleHashCode(passage.name + invocation).toString();
}
libfunc.replaceVariableInserts = (s) => {
return s.replace(/\{\S+\}/g, (insert) => {
let value;
const invocation = insert.slice(1, -1);
const dereferenceMatch = /(.+)\[(.+)\]$/.exec(invocation);
if (dereferenceMatch) {
value = engine.state.get(dereferenceMatch[1]);
if (value !== undefined) {
value = value[dereferenceMatch[2]];
}
} else {
value = engine.state.get(invocation);
}
if (value !== undefined) {
return value;
}
return insert;
});
}config.style.page.theme.enableSwitching: false
showText: false
hasKey: false
strength: 0
applesPicked: 1
pronounNum: 1
--
{embed passage: '_Add All Text Manipulation'}
{embed passage: 'List of Extensions'}[cont]
## Sargent Chapbook Extensions Demo
Let's see the extensions in action!
> [[Text Collection]]
> [[Conditional Insert]]
> [[One Of and First Time Inserts->One Of Insert]]
> [[Capitalization]]_collectModifier: "[collect]"
_contModifier: "[cont]"
_showCollectedInsert: "{show collected}"
--
## Text Collection: Overview
The `[collect]` modifier collects text to be shown later or manipulated. All text that follows the modifier
is saved to be shown later using the insert <code>{_showCollectedInsert}</code>.
Let's try it out. Here's what the underlying code looks like:
<pre>
First, some regular text.
{_collectModifier}
If everything worked, _this_ text was collected!
{_contModifier}
Second, some more text.
Finally, let's show what we collected! {_showCollectedInsert}
</pre>
Here's what it looks like when Chapbook renders it.
<blockquote>
First, some regular text.
[collect]
If everything worked, _this_ text was collected!
[cont]
Second, some more text.
Finally, let's show what we collected! {show collected}
</blockquote>
That's all you need to know to use it, though we've got more advanced examples.
> [[Collecting more than one chunk of text->Collect Multiple Texts]]
> [[Resetting or modifying what's collected->Reset or Modify Text Collection]]
> [[Summary of all text collection capabilities->Text Collection Summary]]
> **[[Back to the list of extensions->List of Extensions]]**_collectModifier: "[collect]"
_collectNoSpaceModifier: "[collect no-space]"
_collectParagraphModifier: "[collect new-paragraph]"
_ifShowCollectModifier: "[if showText; collect]"
showText: !showText
--
## Text Collection: Multiple Texts
You can use `[collect]` more than once to keep adding to what you've collected. For this example, we'll
collect text by embedding multiple passages that have collects in them.
By default, `[collect]` puts a single space between each new collection. If you're using it to build, say, a
description where you need to skip that space, you can use `[collect no-space]`. If you want a new paragraph
instead, use `[collect new-paragraph]`.
We'll also show optional collection of text using an `[if]` modifier controlled by the `showText` variable.
_On this visit, `showText` is **{showText}**._
Here's the code in this passage:
<pre>
{embed passage: 'Collect 1'}
{embed passage: 'Collect 2'}
{embed passage: 'Collect 3'}
{show collected}
</pre>
The `Collect 1` passage contains:
<pre>
{_collectModifier}
The first embedded passage has a single section of text.
</pre>
The `Collect 2` passage contains:
<pre>
{_collectModifier}
The second embedded passage has an optional section controlled by an [if showText] modifier.
{_ifShowCollectModifier}
That modifier is true, so this optional section was collected.
{_collectModifier}
The second passage ends with this separately-collected sentence.
</pre>
The `Collect 3` passage contains:
<pre>
{_collectNoSpaceModifier}
The third embedded passage used the {_collectNoSpaceModifier} modifier, so there's no space between
this sentence and the previous one.
{_collectParagraphModifier}
This last sentence is in a new paragraph.
</pre>
Here's how Chapbook renders all of that.
<blockquote>
{embed passage: 'Collect 1'}
{embed passage: 'Collect 2'}
{embed passage: 'Collect 3'}
{show collected}
</blockquote>
> [[Show this again, only this time with{if showText: 'out'} the conditional collection->Collect Multiple Texts]]
> [[Resetting or modifying what's collected->Reset or Modify Text Collection]]
> [[Summary of all text collection capabilities->Text Collection Summary]]
> **[[Back to the list of extensions->List of Extensions]]**[collect]
The first embedded passage has a single section of text.[collect]
The second embedded passage has an optional section controlled by an `[if showText]` modifier.
[if showText; collect]
That modifier is true, so this optional section was collected.
[collect]
The second passage ends with this separately-collected sentence.[collect no-space]
The third embedded passage used the `[collect no-space]` modifier, so there's no space between
this sentence and the previous one.
[collect new-paragraph]
This last sentence is in a new paragraph._collectModifier: "[collect]"
_collectNewModifier: "[collect new]"
_emptyCollected: "{empty collected}"
_contModifier: "[cont]"
_showCollectedKeepInsert: "{show collected, keep: true}"
_collectedVariableShow: "{__collected}"
_codeTag: "<code>"
_codeTagClose: "</code>"
__collected: ''
--
## Text Collection: Reset or Modify Text Collection
By default, `[collect]` adds to any text that's already been collected, and <code>{_showCollectedInsert}</code> empties the
collection so you can start over. You can change both of those behaviors.
`[collect new]` gets rid of all the previously-collected text and starts over, as does `{_emptyCollected}`.
<code>{_showCollectedKeepInsert}</code> shows the collected text without getting rid of it.
Finally, the collected text is stored in the Chapbook variable `__collected`. You can always work directly with that variable.
Let's try that out. Here's the code in this passage:
<pre>
At the start, `__collected` contains: {_codeTag}{_collectedVariableShow}{_codeTagClose}
{_collectModifier}
If this works, this text will be thrown away.
{_contModifier}
After the first collect, `__collected` contains: {_codeTag}{_collectedVariableShow}{_codeTagClose}
{_collectNewModifier}
This should be the only text that's collected.
{_contModifier}
After the second collect, `__collected` contains: {_codeTag}{_collectedVariableShow}{_codeTagClose}
Let's show the collection using the insert with `keep: true`: {_showCollectedKeepInsert}
After the insert with `keep: true`, `__collected` contains: {_codeTag}{_collectedVariableShow}{_codeTagClose}
Now let's empty the collected text without showing it. {_emptyCollected}
After the `{_emptyCollected}` insert, `__collected` contains: {_codeTag}{_collectedVariableShow}{_codeTagClose}
</pre>
Here's how Chapbook renders it.
<blockquote>
At the start, <code>__collected</code> contains: <code>{__collected}</code>
[collect]
If this works, this text will be thrown away.
[cont]
After the first collect, `__collected` contains: <code>{__collected}</code>
[collect new]
This should be the only text that's collected.
[cont]
After the second collect, `__collected` contains: <code>{__collected}</code>
Let's show the collection using the insert with `keep: true`: {show collected, keep: true}
After the insert with `keep: true`, `__collected` contains: <code>{__collected}</code>
Now let's empty the collected text without showing it. {empty collected}
After the `{_emptyCollected}` insert, `__collected` contains: <code>{__collected}</code>
</blockquote>
> [[Collecting more than one chunk of text->Collect Multiple Texts]]
> [[Summary of all text collection capabilities->Text Collection Summary]]
> **[[Back to the list of extensions->List of Extensions]]**## Text Collection: Summary
### The Modifier
| Modifier | What it does |
| -------- | ------------ |
| `[collect]` | Collect the text that follows and **add it** to any already-collected text. |
| `[collect no-space]` | Collect the text that follows and add it to any already-collected text **with no space between them**. |
| `[collect new]` | Collect the text that follows, **replacing** any already-collected text. |
### The Insert
| Insert | What it does |
| ------ | ------------ |
| <code>{show collected}</code> | Show the collected text and **empty the collection**. |
| <code>{show collected, keep: true}</code> | Show the collected text and **keep the collection**. |
| <code>{empty collected}</code> | Empty the collection **without showing it**. |
### Under the Hood
The collected text is kept in the `__collected` variable.
> [[Collecting more than one chunk of text->Collect Multiple Texts]]
> [[Resetting or modifying what's collected->Reset or Modify Text Collection]]
> **[[Back to the list of extensions->List of Extensions]]**_ifInsert1: "{if hasKey: 'You could try [[unlocking it]].'}"
_ifInsert2: "{if hasKey: 'You could try [[unlocking it]].', else: 'You need a key.'}"
_ifInsert3: "{applesPicked} apple{if (applesPicked > 1): 's'}"
hasKey: !hasKey
applesPicked: applesPicked + 1
applesPicked (applesPicked > 2): 1
--
## Conditional Insert
### Showing Text When a Condition is True
The conditional insert is like the `[if]` conditional display modifier, except it's an insert
that you can use in the middle of other text.
In this passage, the variable `hasKey` is {hasKey}. The code:
<pre>
The door is locked. {_ifInsert1}
</pre>
produces the following:
<blockquote>
The door is locked. {if hasKey: 'You could try [[unlocking it]].'}
</blockquote>
### Showing Different Text When a Condition is False
You can also provide text to show if the condition evaluates to false. The code:
<pre>
The door is locked. {_ifInsert2}
</pre>
produces the following:
<blockquote>
The door is locked. {if hasKey: 'You could try [[unlocking it]].', else: 'You need a key.'}
</blockquote>
### Adding Text Without a Space
Where the conditional insert is especially useful is in adding a snippet of text onto another word.
In the following example, the variable `applesPicked` is {applesPicked}. The code:
<pre>
You pick {_ifInsert3}.
</pre>
produces the following:
<blockquote>
You pick {applesPicked} apple{if (applesPicked > 1): 's'}.
</blockquote>
> [[Show this again, only this time with different variable values->Conditional Insert]]
> **[[Back to the list of extensions->List of Extensions]]**You unlocked the door!
> [[Return to the Conditional Insert example->Conditional Insert]]
> **[[Back to the list of extensions->List of Extensions]]**oneOfInsert: "{one of}"
firstTimeInsert: "{first time}"
firstTimeModifier: "[first time]"
_oneOfInsertHeadsAndTails: "{one of: ['heads', 'tails']}"
_oneOfInsertWithOptions: "{one of: ['Water splashes from the ceiling.', 'From ahead, the squeak of a bat echoes off of the cave walls.', 'Your torch flickers.']}"
--
## One Of and First Time Inserts: Overview
The `{oneOfInsert}` insert lets you display varying text each time a player reaches
a passage. For example, say you wanted to show different flavor text every time a
player entered a cave.
<pre>
The cave is low and dark. {_oneOfInsertWithOptions}
</pre>
The first time the player visits the passage, it might print,
<blockquote>
The cave is low and dark. From ahead, the squeak of a bat echoes off of the cave walls.
</blockquote>
The next time, it might print,
<blockquote>
The cave is low and dark. Water splashes from the ceiling.
</blockquote>
`{oneOfInsert}` takes an array of text items, called _choices_, and shows one of
those choices either randomly or selected by a separate variable. If it shows the
choices randomly, the next time, it shows a different choice. While each choice is randomly
selected, the same text won't be shown twice in a row. That is, the insert
`{_oneOfInsertHeadsAndTails}` will never show `heads` and then `heads` again.
You can specify different orders to show the choices in, including shuffling the choices or
showing them in order until they run out. You can also show a choice based on a separate
variable. Finally, there's a special case of showing choices: showing text only the first time
the player visits the passage.
> [[Controlling the order of what's randomly shown->One Of Insert Random Ordering]]
> [[Showing text based on a variable->One Of Insert Variable-Based Ordering]]
> [[Showing text the first time only->First Time Insert]]
> [[Summary of all `{oneOfInsert}` insert options->One Of Insert Summary]]
> **[[Back to the list of extensions->List of Extensions]]**_oneOfInsertRandomSummary: "{one of: ['choice 1', 'choice 2', 'choice 3'], order: 'order'}"
--
## One Of and First Time Inserts: Controlling the Random Order
You can control the order that the `{oneOfInsert}` insert randomly shows its choices using the
`order` parameter:
<pre>
{_oneOfInsertRandomSummary}
</pre>
`order` can be any of the following:
- `'random'`: Show a random choice each visit without showing the same thing twice in a row. The default.
- `'pure random'`: Like `random`, but choices can be shown twice in a row.
- `'shuffled'`: The choices are shuffled, then shown in that shuffled order. Once all of them have been shown, they're re-shuffled.
- `'stopping'`: Show the choices in order, stopping with the last one and thereafter showing it forever.
- `'cycling'`: Show the choices in order, repeating the order after the last one's shown.
> [[Show `{oneOfInsert}` ordering in action->One Of Demo]]
> [[Showing text based on a variable->One Of Insert Variable-Based Ordering]]
> [[Showing text the first time only->First Time Insert]]
> [[Summary of all `{oneOfInsert}` insert options->One Of Insert Summary]]
> **[[Back to the list of extensions->List of Extensions]]**_oneOfInsertVariableSummary: "{one of: ['weak', 'averagely strong', 'strong'], select: 'strength'}"
strength: strength + 1
strength (strength > 2): 0
--
## One Of and First Time Inserts: Showing Text Based on a Variable
Instead of letting `{oneOfInsert}` randomly show its choices, you can have it
show a choice based on the number stored in a variable. This can be useful if, for example,
you have a numeric variable tracking a player's strength and you want to give a text
description of it.
In this passage, the variable `strength` is `{strength}`. The code:
<pre>
You are {_oneOfInsertVariableSummary}.
</pre>
produces the following:
<blockquote>
You are {one of: ['weak', 'averagely strong', 'strong'], select: 'strength'}.
</blockquote>
> [[Show this again, only this time with a different strength value->One Of Insert Variable-Based Ordering]]
> [[Show `{oneOfInsert}` ordering in action->One Of Demo]]
> [[Showing text based on a variable->One Of Insert Variable-Based Ordering]]
> [[Showing text the first time only->First Time Insert]]
> [[Summary of all `{oneOfInsert}` insert options->One Of Insert Summary]]
> **[[Back to the list of extensions->List of Extensions]]**_arrayOfChoices: ['apple', 'banana', 'chainsaw', 'durian']
_oneOfDemoFirstPart: "{one of:"
_rbrace: "}"
--
## Showing One Of Ordering in Action
Here's what happens if we take the choices `{_arrayOfChoices}` and show them
in different orders.
<blockquote>
- Random: {one of: ['apple', 'banana', 'chainsaw', 'durian'], order: 'random'}
- Pure random: {one of: ['apple', 'banana', 'chainsaw', 'durian'], order: 'pure random'}
- Shuffled: {one of: ['apple', 'banana', 'chainsaw', 'durian'], order: 'shuffled'}
- Stopping: {one of: ['apple', 'banana', 'chainsaw', 'durian'], order: 'stopping'}
- Cycling: {one of: ['apple', 'banana', 'chainsaw', 'durian'], order: 'cycling'}
</blockquote>
> [[View this passage again->One Of Demo]]
> [[Showing text based on a variable->One Of Insert Variable-Based Ordering]]
> [[Showing text the first time only->First Time Insert]]
> [[Summary of all `{oneOfInsert}` insert options->One Of Insert Summary]]
> **[[Back to the list of extensions->List of Extensions]]**_firstTimeInsertExample: '{first time: "You shield your eyes, but can\'t see who\'s behind the light."}'
_firstTimeModifierExample: "[first time]\nIf you close your eyes, it almost feels like you've been here before."
--
## One Of and First Time Inserts: Showing Text the First Time
The `{firstTimeInsert}` insert only shows its snippet of text the first time the player visits the passage. The `{firstTimeModifier}` modifier does the same, but for paragraph-sized sections of text. Consider the code:
<pre>
The floodlight illuminating you is painfully bright. {_firstTimeInsertExample}
{_firstTimeModifierExample}
</pre>
The first time the player visits the passage, they'll see:
<blockquote>
The floodlight illuminating you is painfully bright. You shield your eyes, but can't
see who's behind the light.
If you close your eyes, it almost feels like you've been here before.
</blockquote>
The second time, and every time after that, the player will see:
<blockquote>
The floodlight illuminating you is painfully bright.
</blockquote>
> [[Show `{firstTimeInsert}` insert and `{firstTimeModifier}` modifier in action->First Time Demo]]
> [[Controlling the order of what's randomly shown->One Of Insert Random Ordering]]
> [[Showing text based on a variable->One Of Insert Variable-Based Ordering]]
> [[Summary of all `{oneOfInsert}` insert options->One Of Insert Summary]]
> **[[Back to the list of extensions->List of Extensions]]**_firstTimeInsertDemo: "{first time: 'You catch your foot on a stalagmite and nearly fall.'}"
_firstTimeModifierDemo: "[first time]\nYou have no memory of this place."
--
## Showing First Time in Action
This passage contains the code:
<pre>
The cave is low and dark. {_firstTimeInsertDemo}
{_firstTimeModifierDemo}
</pre>
Here's what it looks like.
<blockquote>
The cave is low and dark. {first time: 'You catch your foot on a stalagmite and nearly fall.'}
[first time]
You have no memory of this place.
[cont]
</blockquote>
> [[View this passage again->First Time Demo]]
> [[Controlling the order of what's randomly shown->One Of Insert Random Ordering]]
> [[Showing text based on a variable->One Of Insert Variable-Based Ordering]]
> [[Summary of all `{oneOfInsert}` insert options->One Of Insert Summary]]
> **[[Back to the list of extensions->List of Extensions]]**_firstTimeInsertSummary: "{first time: 'This will only show up on the first visit.'}"
_firstTimeModifierSummary: "[first time]\nThis also will only show up on the first visit."
_oneOfInsertRandomSummary: "{one of: ['choice 1', 'choice 2', 'choice 3'], order: 'order'}"
_oneOfInsertVariableSummary: "{one of: ['choice 1', 'choice 2', 'choice 3'], select: 'var'}"
--
## One Of and First Time Inserts and Modifiers: Summary
`{_firstTimeInsertSummary}` to show a short bit of text only the first time a passage is visited.
To show a longer bit of text only the first time a passage is visited:
```
{_firstTimeModifierSummary}
```
`{_oneOfInsertVariableSummary}` to show one of the array of choices based on the number in the variable `var`.
`{_oneOfInsertRandomSummary}` to show one of the array of choices randomly.
| `order` | What It Does |
| -------- | ------------ |
| `'random'` | (default) Show a random choice each visit, but no choice will be shown twice in a row. |
| `'pure random'` | Show a random choice each visit. |
| `'shuffled'` | Shuffle the choice the first time and then show one at a time in that shuffled order. When all choice have been shown, they're re-shuffled. |
| `'stopping'` | Show the choices in order. After the last one's shown, it's shown again forever after. |
| `'cycling'` | Show the choices in order. After the last one's shown, the sequence starts over with the first. |
> [[Controlling the order of what's randomly shown->One Of Insert Random Ordering]]
> [[Showing text based on a variable->One Of Insert Variable-Based Ordering]]
> [[Showing text the first time only->First Time Insert]]
> **[[Back to the list of extensions->List of Extensions]]**_capitalizationInsert: "{^ [variable]}"
_capHisInsert: "{^ companion.his}"
_hisInsert: "{companion.his}"
pronounNum: pronounNum + 1
pronounNum (pronounNum > 3): 1
companion.his (pronounNum == 1): "his"
companion.his (pronounNum == 2): "her"
companion.his (pronounNum == 3): "their"
--
## Capitalization
The capitalization insert `{_capitalizationInsert}` capitalizes
and displays the variable's content.
In this passage, the variable `companion.his` is `{companion.his}`. The code:
<pre>
{_capHisInsert} clothes are folded neatly at the foot of {_hisInsert} bed.
</pre>
produces the following:
<blockquote>
{^ companion.his} clothes are folded neatly at the foot of {companion.his} bed.
</blockquote>
> [[Show this again, only this time with a different choice of pronoun->Capitalization]]
> **[[Back to the list of extensions->List of Extensions]]**