进阶 ChoiceScript

https://www.choiceofgames.com/make-your-own-games/choicescript-advanced/arrow-up-right

一份关于ChoiceScript编程语言进阶功能的指南。如果您对本文件有任何疑问,请在 ChoiceScript 论坛arrow-up-right上发帖。

初学者请不要直接从这里开始学习!

在阅读这份高级文档之前,请务必先阅读我们基础的 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 前使用 *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 讨论帖arrow-up-right直接向IDE团队提问。

(王洛木:本注释写于 2026 年,这个软件有点老旧了,很多新的命令包括 *ifid 在内都不支持,建议还是直接 VS CODE 搭配插件。)

更多条件选项

除了在每行使用 *if 外,你还可以使用嵌套的条件块。这项技术相当高级,因为很难精确控制缩进。

全局 *hide_reuse*disable_reuse

你可以通过在 ChoiceScript 文件顶部添加 *hide_reuse*disable_reuse,使所有选项都不可重用。然后,你可以使用 *allow_reuse 命令来允许某些选项被重用。

数学

整数运算

你可以使用 round() 函数将变量四舍五入到最接近的整数。例如,这会将变量“foo”设置为 3:*set foo round(2.5)。你也可以使用 modulo 运算符arrow-up-right计算除法后的余数。模运算相当奇特,但它有两个特别有趣的用途。首先,你可以通过检查 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 标签之后,您可以包含任意数量的参数。当您使用 *params 命令时,它会为每个参数设置名为 param_1param_2 等的临时变量。(它还会设置一个 param_count 临时变量来记录参数数量;在此例中,param_count 将为 2。)

由于 param_1param_2 不是很好的名称,你可能会忍不住想写这样的代码:

我们预料到了这一点;您只需在 *params 后写下参数名称,我们将为您设置临时变量,就像这样:

您也可以为 *gosub_scene 使用参数。由于 *gosub_scene 允许您选择性地指定标签,例如 *gosub_scene travel visit,因此如果您想向 *gosub_scene 传递参数,则必须指定标签名称。*gosub_scene visit "Dracula" 不会使用参数;它将尝试 *gosubvisit.txt 中的标签 Dracula

具有程序员思维的人应当注意,参数只是普通的 *temp 变量,其作用域覆盖整个文件,而非子程序。因此,如果您在一个 *gosub 中嵌套 *gosubparam_1 可能会在第二个子程序中被修改,并且在 *return 时不会恢复原值。

然而,*gosub_scene*temp 变量定义了新的作用域,所以如果您希望 *param 的作用域限定在子程序内(例如想要使用递归),可以使用 *gosub_scene 代替 *gosub

这里有一个计算斐波那契数列arrow-up-right的简单递归子程序示例。(请注意它只能与 *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 论坛arrow-up-right发帖咨询。

最后更新于