撰写了文章 更新于 2018-03-10 22:02:44
Twine | Harlowe使用向导 (2)宏 基础
宏 Macros
基础 basics
(set:) → Instant
(set:… VariableToValue) → Instant
“set”宏的Harlowe版本,适用于大多数Twine故事格式。
使用案例
- (set: $battlecry to "Save a " + $favouritefood + " for me!") 会设置一个名称为$battlecry 的变量。
- (set: _dist to $altitude - $enemyAltitude) 会设置一个名称为 _dist 的临时变量。
解释
Harlowe中有两种变量。通常变量,名称以“$”开始,在多个文章中持续存在,应用于存储某些贯穿整个游戏的数据。临时变量,名称以“_”开始,仅在被(set:)定义的hook或文章中存在,并且在hook或文章结束后被遗忘。如果你不想意外地影响到其它文章中的变量(在其它事情正在使用的变量名称上用了(set:)),应该采用临时变量。在与他人合作共同完成一个独立故事,或者在多个故事中使用同样代码时,这是至关重要的。
Harlowe的变量有许多用途:跟踪玩家已完成的任务,管理故事的其他状态,存储hook样式和转换指令等等。你可以通过将其放在文章文本中,或是附加到hook上,以显示变量,并且可以使用(set:)和(put:)宏更改变量。
详细
在基本形式当中,变量由“(set: 变量 to 值)”创建或更改。你还可以在一个(set:)中设置多个变量,只需将每个“变量to值”用半角逗号分开,比如“(set: $weapon to 'hands', $armour to 'naked')”。
你还可以在“to”的右边使用“it”。与其他表达式一样,它是左侧内容的缩写:“(set: $vases to it + 1)”是“(set: $vases to $vases + 1) ”的缩写。
如果目标物并非是可改变的,比如将一个裸值设置给另一个值,像是(set: true to 2),就会出现一个错误。修改数组也会这样,(set: (a:2,3)'s 1st to 1)也是一个错误。
另见
(push:), (move:)
(put:) → Instant
(put:… VariableToValue) → Instant
(set:)的由左到右版,但需要“into”而非“to”。
解释
该宏拥有和(set:)相同的功能,可以创建和更改变量。详情请参见(set:)的解释。
几乎所有编程语言都有一个(set:)结构,其中大多数都将变量放在左边。也有一小部分把变量放在右边,比如HyperTalk。Harlowe中两者都可以使用,取决于个人喜好。(set:)的表达形式是(set: 变量 to 值),(put:)的表达形式是(put: 值 into 变量)。
详细
正如(set:)一样,使用(put: 值 into 变量)可以更改变量。你仍可以在(put:)设置多个变量,只需用半角逗号隔开每一组变量和值即可:(put: 2 into $batteries, 4 into $bottles) ,如此。
(put:)中仍可使用“it”,但有趣的是它需要被用在表达式的右侧:(put: $eggs + 2 into it)
另见
(see:), (move:)
(move:) → Instant
(move: … VariableToValue) à Instant
(put:)语句的变体,复制源值后删除它。实际上是将源值移动到目标上。
使用案例
(move: $arr's 1st into $var) |
解释
你可能经常会用到数组或是数据图这样的数据结构作为仅用一次的值的存储空间,比如有待打印的一份名称列表。当你用到他们时,你可以将其从结构中删除并一次性取回。
在该宏中你需要像(put:)一样使用“into”作为关键字。因为值的目标在右侧,而源在左侧。
你同样可以在(move:)中设置多个值,使用多个逗号隔开:(move: $a's 1st into $b, $a's into $c) ,如此。
如果你取数的值不能被移除,比如它是一个数组的长度,那么就会产生一个错误。
另见
(push:),(set:)
(print:) → Command
(print: Any) à Command
print宏的Harlowe版本,适用于多数故事格式。
使用案例
(print: $var + "s") |
详细
它能够打印(text:)指令不能转换为字符串的东西,例如转换指令(changer command)。但是这些通常会变成完全的描述性文本,比如[A (font:) command]。你可能会发现这对debug有用。
该命令可以被储存在一个变量中,而非即时执行。需要注意的是,要打印的表达式存储在命令中,而不是在最终执行的时候重新评估。所以,一个段落包含以下:
(set: $name to "四") (set: $p to (print: "李" + $name)) (set: $name to "三") $p |
的最终文本是“李四”。与设“&p”为字符串相比,这不是特别有用,但是仍然可用。
另见
(text:), (display:)
(display:) → Command
(display: string) à Command
该命令会根据给定字符串名称写出文章内容。如果该名称的文章不存在,将会产生错误。
使用案例
(display: "引用文章") |
将会打印一篇名为“引用文章”的文章。
解释
假设你有一段代码或源码需要添加到数个不同的文章当中。它可以是状态展示或是数行描述性文本。相较于手动将它粘贴到每个文章中,一个更好的办法是将其设为一篇文章,并使用(display:)在每个要用的文章中展示。这给你很大的灵活性:你可以直接修改引用文章中的代码,而不用一篇接一篇地修改。
详细
被引用文章中的文本定位宏(如(replace:))将会在(display:)前影响到引用文章中的文本和hook。例如,若文章A包含“(replace: "王子")[青蛙]”,那么包含“王子(display:'A')”的文章中,最终文本会是“青蛙”。
像所有命令一样,你可以为其设置一个变量。它在这种情况下不是特别有用,但你可以使用该变量代替该指令,例如编写“$var”代替“(display: "世界树")
(if:) → Changer
(if: boolean ) → changer
该宏仅接受布尔值,并会在附加到hook上时产生一个指令,当值为“false”时会隐藏hook。
使用案例
(if: $legs is 8)[你是一只蜘蛛!] |
若“$legs”的值为“8”,则会显示“你是一只蜘蛛!”,否则它不会运行。
解释
在多线程故事中,某些特定事件会发生或是不会发生,你可能会需要根据当前世界的状态微调你的文章。例如(if:),(unless:),(else-if:),(else:)这样的宏可以打开或关闭这些调整,取决于根据选择导致的变量、比较和计算。
详细
请注意, (if:)宏只运行一次,在包含它的文章或hook被呈现时。其后任何对状况的改变(比如一个包含了用于改变变量的(set:)的(link:)宏)都不会使其“重新运行”,并重新显示/隐藏该hook。
然而,如果你附加(if:)到一个指名钩链,并且该hook被(if:)隐藏,你可以稍后在文章中手动显示该hook(比如当一个(link:)被点击后),只需使用(show:)定位该hook。由(if:)隐藏的指名钩链因此相当于隐藏指名钩链,像是“|this)[]”。
替换方案
(if:)和(hidden:)宏不是仅有的可以用来隐藏或显示hook的附件!事实上,带有布尔值的变量也可以放在上述宏的位置。比如:
(set: $isAWizard to $foundWand and $foundHat and $foundBeard) $isAWizard[你长长的胡须随风飘扬。] 你走进古老的图书馆。 $isAWizard[羊皮卷的味道使你安心。] |
通过为“$isAWizard”设置布尔值,你可以在故事中反复使用它以显示或隐藏hook。
*译者注:这里省略了为“$foundWand”等变量设置布尔值的过程,即“(set: $foundeWand to (if: $foundWand is 1))”,后面两个由and连接的变量也需这样设置。
另见
(unless:),(else-if:),(else:),(hidden:)
(unless:) → Changer
(unless: boolean) → changer
在Harlowe里该宏用作(if:)的相反面:它仅接受布尔值,并在值为true时输出一个指令,隐藏所附hook。
更多信息请见(if:)的介绍。
(else-if:) → Changer
(else-if: boolean) → changer
该宏会依照前置的hook是否被显示进行改变。如果前面的hook被显示了,则该宏所附hook会被隐藏。否则该宏会作为(if:)生效,若判断为是则会显示所附hook,若判断为否则会隐藏所附hook。若没有设置前置hook,则会产生一个错误。
使用案例
你的肚子发出{(if: $size is '山一样')[ 隆隆的声音!](else-if: $size is '鼓起来')[ 咆哮的声音。](else:)[ 微弱的咕噜声。]} |
解释
在使用(if:)的过程中,你可能会发现你经常只想在分支中显示一组hook中的一个。为了这样做,你必须将你的(if:)表达式按顺序排列,比如“如果A发生了”“如果A没发生B发生了”“如果A和B没发生但C发生了”,等等。
(else:)和(else-if:)宏会让这变得更容易一些:你只用在代码中设定“如果A发生了”“或者发生的是B”“或者发生的是C”。
详细
和(if:)宏一样, (else-if:)只会在文本被展示时做一次状态调取。
(else:)和(else-if:)宏并非仅能和(if:)匹配!你可以使(else:)和(else-if:)宏和布尔变量结合,例如:
$married[你希望这个战士终有一天会理解你的爱。] (else-if: not $date)[你希望这个战士星期天有空(你周六要加班)。] |
如果你附加(else-if:)到一个指名钩链,并且(else-if:)隐藏起了该钩链,你可以稍后在文章中用(show:)宏定位该钩链以使其显现。
另见
(if:),(unless:),(else:),(hidden:)
(else:) → Changer
(else:) → changer
这是(else-if:)宏一个方便的有限变体。如果前置的hook被隐藏,它将显示所附hook,否则则会隐藏所附hook。如果没有前置hook,则会出现错误。
解释
在写了一系列由(if:)和(if-else:)引导的hook后,通常会有上述情况都不包含的分支。(else:)是(else-if:)“上述情况都不包含”情况下的变体,不需要提供布尔表达式。它相当于(else-if: true),但是更简便,也更具可读性。
更多信息请查阅(else-if:)的说明。
注意
和(if:)宏一样, (else:)只会在文本被展示时做一次状态调取。
由于一个神秘问题,你可以一次性使用多个(else:)宏调用:
$isUtterlyEvil[你突然间抓住他们的脚踝,你温暖的笑容转变成穷凶极恶的笑容] (else:)[在沉默之中,你轻轻地,虔诚地骚动他们的脚底板] (else:)[在他们反应过来之前,你发动了痒痒攻势!] (else:)[他们放心地叹了口气,让你虔诚的心充满快乐。] |
这种用法可能会导致一些令人困惑的文章结构,其中每个(else:)都会在可见/不可见的情况下交替出现。所以,尽量避免这种情况。
如果你附加(else:)到一个指名钩链,并且(else:)隐藏了该钩链,你可以稍后在文章中用(show:)宏定位该钩链以使其显现。
另见
(if:),(unless:),(else-if:),(hidden:)
(for:) → Changer (即(loop:))
(for: lambda, …Any ) → changer (即(loop:))
一个重复所附hook的指令,每次重复时为一个临时变量设置不同的值。
使用案例
会打印“你拥有”以及$arr中的每个道具。 |
会打印“制作”,以及$ingredient中包含“草药”的部分。 |
解释
假设你正在使用数组储存代表库存道具的字串,或者是字符数据图、其它种类的按顺序排列的游戏信息,甚至只是(history:)这种内置的数组,并且你想为每个道具打印一句话或一个段落。(for:)宏可以轻松地为数组中的“每个”道具打印一些东西,只需用临时变量写好一个hook,临时变量里的每个道具都需要被打印或是用到,然后给定一个(for:)和lambda表达式,使用相同的临时变量。
详细
不要觉得你可以在每次循环中通过(set:)临时变量来修改数组,像是(for: each _a, … $arr)[(set: _a to it +1)]。它不会改变数组,只有临时变量会改变(而且会在下一个循环前终止,下一个循环里会把$arr中的另一个值放进去)。如果你要逐项更改一个数组,可以使用(altered:)宏。
Hook内部的临时变量将会影响到外部的所有同名临时变量:如果你(set: _a to 1),接着(for: each _a, 2,3)[(print: _a)],则hook里面会打印出“2”和“3”,而你将无法打印或设置“外面的”_a。
你可能只想打印一定次数某hook,没有任何特定的数组数据被循环。你可以使用(range:)宏作为替代:“(for: each _i in ... (range:1,10))”,而不必使用临时变量。
作为一个转换宏,(for:)的值是一个可以被储存到变量中的转换指令。该指令会存储所有的初始数据,但此后不会因值或内部数组的改变而改变。
替换方案
你可能会使用(for:),但不打印任何东西,而是用(if:)在数组中找东西,或是用(set:)展示“全部”。其实你可以尝试一些lambda宏,(find:)和(folded:)。
另见
(find:),(folded:),(if:)
(either:) → Any
(either: … Any) → Any
给该宏数个值,用逗号分隔,它会随机给出其中一个值。
使用案例
一根(either: "细小的", "粗糙的", "光滑的")手杖。 |
将会随机显示出“一根细小的手杖”“一根粗糙的手杖”“一根光滑的手杖”。
解释
很多情况下你的故事都会需要随机元素:文本内的随机形容词会为重复展现增添多样化,也可以为“迷宫”添加随机的区域链接。(either:)宏提供了这种多选一的功能。
详细
与许多宏一样,你可以使用点符“...”将所有数据存入一个数组或数据集(dataset)中,放入(either:),并会随机从中选取数值。例如,“(either: ... $array)”将会随机从“$array”中选取一种可能。
如果你想随机选取两个或两个以上的值,你可能会想用(shuffled:)宏,并从中选取结果。
另见
(random:),(shuffled:)
(enchant:) → Command
(enchant: hookname or string, changer) → command
对文章中hook或字符串的每一次工作都添加一个转换指令,并将该转换指令应用到同一文章中随后出现的任何工作上。
使用案例
|
解释
尽管转换指令能使你风格化或者转换一篇文章中的特定hook,但在你撰写故事时,特别是所附转换指令非常复杂时,很有可能出现单调乏味且容易出现的错误。你可以将转换指令储存在短变量中,通过附加变量来简化操作。如下所示:
(set: _ghost to (text-style:'outline')) _ghost[Awoo] _ghost[Ooooh] |
然而,这可能是不可取的:你可能会想要在随后的开发中删除_ghost样式,这将迫使你删除附加的变量以免产生一个错误;你可能会想让某个单词或短语风格化,却发现它不适合被放在一个hook中;你可能仅仅不想让代码出现在文章开头,比如(set:)宏;你可能不想跟踪哪些变量关系哪些转换指令。
相反,你可以给出指名“ghost”的hook,随后(enchant:)他们:
|ghost>[Awoo] |ghost>[Ooooh] (enchant: ?ghost, (text-style:'outline')) |
最终的(enchant:)宏可以针对单词而不针对hook,很像(click:)——仅提供一个字符串,而非一个hook名称。
这个宏在“header”标记的文章中运行良好——使用许多的(enchant:)指令可以让每个文章中的特定单词或部分风格化,实际上你可以写下特定的“风格化语言”,使特定hook名称等同于特定颜色或表现。(大体相当于使用CSS风格化class name,但只是用了宏)
详细
与(click:)一样,“enchantment”会影响(display:)生成的文本,以及以后由(replace:)宏改变的hook,等等,直到玩家点击下一回合。
?Page,?Passage,?Sidebar,?Link这样的预置指名钩链会被该宏定位,并且可以为每篇文章风格化。
另见
(click:)
目录
Shitake 1年前
这软件在 GitHub 上 GPL 开源 用 vue 开发的貌似 桌面端用的nwjs 看起来可以搞一波汉化什么的 @琪露诺
琪露诺 1年前
森一 [作者] 1年前
琪露诺 1年前
森一 [作者] 1年前
Shitake 1年前
森一 [作者] 1年前
发布