进阶 ChoiceScript
https://www.choiceofgames.com/make-your-own-games/choicescript-advanced/
一份关于ChoiceScript编程语言进阶功能的指南。如果您对本文件有任何疑问,请在 ChoiceScript 论坛上发帖。
初学者请不要直接从这里开始学习!
在阅读这份高级文档之前,请务必先阅读我们基础的 ChoiceScript 介绍页面
更多命令
*line_break
在文本中仅插入一个换行符,类似 HTML 中的 <br> 标签。通常不应使用此命令;只需按两次回车键,ChoiceScript 便会自动插入段落分隔。但除非存在段落分隔,否则 ChoiceScript 会自动将文本行连接起来;若需要比段落分隔更小的间隔,或仅需单行换行时,再使用 *line_break。
So
this
is
all
one
line.
But this is a new paragraph.
And this
*line_break
is two lines.
该代码将显示如下:
So this is all one line
But this is a new paragraph.
And this is two lines
*input_number
与 *input_text 类似,但文本框中只允许输入数字。需指定变量名以及最小值和最大值。
*rand
将一个变量设置为随机数。你设定最小值和最大值,剩下的交给我们。例如,这会将变量 die_roll 设置为 1 到 6(含)之间的一个值:
因此,我们建议谨慎使用随机性,甚至可能将其作为最后的手段。
*bug
此命令会导致游戏停止并崩溃,并显示特定的错误信息。更多信息可在我们关于自动测试 ChoiceScript 游戏的指南中找到。
*redirect_scene
该指令的行为类似于 *goto_scene,但仅能在状态界面中使用。在状态界面中,游戏处于“状态模式”,此时屏幕顶部的按钮会显示“返回游戏”而非“状态”。状态模式如同矩阵世界 (Matrix),并非真实游戏空间。在状态模式下,使用 *goto_scene 指令仍会停留在状态模式中,不会影响主线游戏进程。若点击“返回游戏”,你将立即回到离开时的章节并切换至“游戏模式”,如同从梦境中苏醒。在状态界面中使用 *redirect_scene 指令,可实现在主线游戏中的 *goto_scene 跳转。
*looplimit
在 ChoiceScript 中,有可能写出“无限循环”的 bug,即游戏会一遍又一遍地永远运行相同的代码行。这类 bug 可能很难发现和修复。如果你的游戏存在无限循环 bug,你会看到类似这样的错误:“startup line 31: visited this line too many times (1000)”。当某一行在单次游戏流程中被运行(“访问”)了 1000 次时,就会触发此错误,这强烈表明你的游戏存在无限循环。如果没有这个机制,一旦遇到无限循环,ChoiceScript 就会永远挂起。如果你确实想在单次游戏流程中让某行代码运行 1000 次,有一个命令可以支持,即 *looplimit,你可以这样使用:
*looplimit 允许你将限制提高到或降低到你喜欢的任何数字。你也可以用 *looplimit 0 来关闭循环限制,但我们不推荐这样做。对任何人来说,一行代码运行十亿次应该都足够了。(循环限制的最大值大约是 1 万亿(12 个零),但是,你真的需要这么多么?!)
*create_array
此命令是多次输入 *create 的快捷方式。您需要指定数组长度及所有变量的初始值,例如:*create_array attributes 5 50,其效果等同于编写以下代码:您也可以为每个变量分别赋值,例如:*create_array attributes 5 10 20 30 40 50。
*temp_array
此命令与上述的 *create_array 类似,但使用 *temp 而非 *create。
检查点使用技巧
检查 *save_checkpoint 是否已执行
*save_checkpoint 是否已执行若在 *save_checkpoint 前使用 *restore_checkpoint,游戏将报错终止:
You can use a magic variable called choice_saved_checkpoint. It starts out false, but when you *save_checkpoint, it turns true.
你可以使用一个名为 choice_saved_checkpoint 的“妙妙”变量。它初始值为假,但当你执行 *save_checkpoint 时,它会变为真。
(或者,考虑在游戏开始时立即添加一个 *save_checkpoint,这将确保 *restore_checkpoint 永远不会失败。)
从检查点恢复后运行一些代码
*save_checkpoint 会设置一个名为 choice_just_restored_checkpoint 的临时变量,并将其设为假。*restore_checkpoint 会在恢复过程中将 choice_just_restored_checkpoint 设为真。
排除部分状态(临时变量不被恢复)
有些游戏会追踪你从先前检查点恢复的次数,以便扣除使用检查点的“点数”,或限制你可以恢复的次数。
*restore_checkpoint 会寻找一个名为 checkpoint_exclusions 的变量,如下所示:
被排除的变量在你执行 *restore_checkpoint 时将不会恢复为旧值。
多个检查点“槽位”
当您使用 *save_checkpoint 或 *restore_checkpoint 时,可以指定检查点“槽位”的名称。这允许您设置多个检查点,让玩家可以回溯到很久之前,或者仅仅回退一小段进度。
(每个检查点槽位都有其对应的变量。在此示例中,当您执行*save_checkpoint major 时,choice_saved_checkpoint_major变量将被设为 true。)
随时从属性界面恢复到上一个检查点
你可以编写如下代码,从状态屏幕进行恢复:
请注意,你需要使用 *if (choice_saved_checkpoint) 来确保玩家不会在第一个检查点设置之前尝试恢复。(王洛木:或者在游戏最开始就设定一个存档点。)
玩家命名的存档槽位
可以编写代码,允许玩家为自己的存档槽位命名。
ChoiceScript 集成开发环境
ChoiceScript 集成开发环境是针对 ChoiceScript 语言的强大集成开发工具。它包含用于编写和脚本编程的代码编辑器,内置 ChoiceScript 运行环境(及其两项自动化测试功能),支持代码与游戏同步测试运行。该环境能够记录错误、高亮显示(并聚焦定位)问题代码行,提供拼写检查功能,甚至自动处理代码缩进格式。
请注意,ChoiceScript IDE 并非由 Choice of Games 开发或维护。如果您对 ChoiceScript IDE 有任何疑问,请通过 ChoiceScript IDE 讨论帖直接向IDE团队提问。
(王洛木:本注释写于 2026 年,这个软件有点老旧了,很多新的命令包括 *ifid 在内都不支持,建议还是直接 VS CODE 搭配插件。)
更多条件选项
除了在每行使用 *if 外,你还可以使用嵌套的条件块。这项技术相当高级,因为很难精确控制缩进。
全局 *hide_reuse 与 *disable_reuse
*hide_reuse 与 *disable_reuse你可以通过在 ChoiceScript 文件顶部添加 *hide_reuse 或 *disable_reuse,使所有选项都不可重用。然后,你可以使用 *allow_reuse 命令来允许某些选项被重用。
数学
整数运算
你可以使用 round() 函数将变量四舍五入到最接近的整数。例如,这会将变量“foo”设置为 3:*set foo round(2.5)。你也可以使用 modulo 运算符计算除法后的余数。模运算相当奇特,但它有两个特别有趣的用途。首先,你可以通过检查 X modulo Y = 0 来判断数字 X 是否能被数字 Y 整除。其次,你可以用它来获取数字 X 的小数部分(小数点后的部分),通过计算 X modulo 1。例如,3.14 modulo 1 = 0.14。
指数与对数
你可以这样使用指数:*set foo 3^7。这会将 foo 设置为 2,187(3 的 7 次方)。你也可以这样计算对数(以 10 为底):*set foo log(1000)。(你总是可以通过除法来使用不同的对数底数,例如:*set foo log(2187)/log(3))
文本技巧
大写
你可以像这样仅将变量的首字母大写:看!$!{He} 的首字母被大写了。你也可以像这样将整个单词大写:总统 $!!{name} 在耻辱中辞职
粗体和斜体
你可以像这样将文字设置为粗体或斜体:这是[b]粗体[/b],而这是[i]斜体[/i]。
在引号字符串中使用 ${}
你可以在引号字符串中使用变量,像这样:*set name "Dr. ${last_name}"
连接
你可以像这样将文本连接在一起:*set murder "red"&"rum"
引号
你可以通过使用反斜杠在文本中添加引号,就像这样:
如果你写下 ${joke},你会得到:
she said it was "ironic"!
反斜杠
你可以通过使用更多反斜杠在文本中添加反斜杠,例如:
如果你写下 ${slashy},就会得到:
Here’s one backslash: \ and here’s two backslashes: \\
字符提取
你可以从变量中提取字符(字母或数字),像这样:
字符计数
你可以像这样统计单词中的字符数量:
*gosub 参数
*gosub 参数在 *gosub 标签之后,您可以包含任意数量的参数。当您使用 *params 命令时,它会为每个参数设置名为 param_1、param_2 等的临时变量。(它还会设置一个 param_count 临时变量来记录参数数量;在此例中,param_count 将为 2。)
由于 param_1 和 param_2 不是很好的名称,你可能会忍不住想写这样的代码:
我们预料到了这一点;您只需在 *params 后写下参数名称,我们将为您设置临时变量,就像这样:
您也可以为 *gosub_scene 使用参数。由于 *gosub_scene 允许您选择性地指定标签,例如 *gosub_scene travel visit,因此如果您想向 *gosub_scene 传递参数,则必须指定标签名称。*gosub_scene visit "Dracula" 不会使用参数;它将尝试 *gosub 到 visit.txt 中的标签 Dracula。
具有程序员思维的人应当注意,参数只是普通的 *temp 变量,其作用域覆盖整个文件,而非子程序。因此,如果您在一个 *gosub 中嵌套 *gosub,param_1 可能会在第二个子程序中被修改,并且在 *return 时不会恢复原值。
然而,*gosub_scene 为 *temp 变量定义了新的作用域,所以如果您希望 *param 的作用域限定在子程序内(例如想要使用递归),可以使用 *gosub_scene 代替 *gosub 。
这里有一个计算斐波那契数列的简单递归子程序示例。(请注意它只能与 *gosub_scene 配合使用;由于参数作用域问题,使用 *gosub 将无法正常工作。)
真正怪异的引用
可能只有程序员才会欣赏这些。请注意!它们增加了复杂性却没有带来太多价值。
花括号
将一些文本放在花括号中,我们会将其转换为命名变量的值。
这将打印:
Your honesty score is 30 你的诚实分数是 30
你也可以直接写成:你的${virtue}分数是${{virtue}}。
通过引用设置:通过变量名设置变量,例如 *set {"leadership"} 30 会将 leadership 设置为 30。可在复杂代码中如此使用:
这段代码会将 courage(勇气)设置为 30。如果这看起来仍然没什么用处,请考虑到 virtue(美德)可能由先前的选择决定,因此它也可能将 honesty(诚实)设置为 30。您还可以将其与 *rand、*input_text 和 *input_number 结合使用。
仍然不相信?不用担心;您可能永远都用不到它。
按名称跳转到标签
按名称跳转到标签:
你也可以将此与 *goto_scene 和 *gosub_scene 配合使用。请注意,Quicktest 实际上会跳过使用花括号引用的 *goto_scene 和 *gosub_scene 行。(Randomtest 则能正常工作。)如果你的文件中存在仅能通过花括号引用的 *goto_scene 命令访问的段落,请考虑在游戏的某个位置添加类似以下的部分,枚举所有可能的目的地。
Quicktest 将“运行”这些行,以验证 chap1、chap2 和 chap3 标签存在于检查点场景中,并确认这些标签确实会被 Quicktest 覆盖到。
数组括号
你可以在变量名后加上方括号,例如:foo[1],以引用变量 foo_1。但你也可以在括号内放置任何内容,包括变量,例如:strength[current_opponent]。
有问题吗?
若对本文件有疑问,请在 ChoiceScript 论坛发帖咨询。
最后更新于