# ChoiceScript 简介

> <https://www.choiceofgames.com/make-your-own-games/choicescript-intro/>

这是一份关于 ChoiceScript 编程语言的基础指南。如果您对 ChoiceScript 有任何疑问，请在 [ChoiceScript 论坛](https://forum.choiceofgames.com/c/game-development/choicescript-help)发帖。

## 什么是 ChoiceScript？

ChoiceScript 是一种用于编写互动小说（如[《龙之抉择》](http://www.choiceofgames.com/dragon/)）的简单编程语言。使用 ChoiceScript 编写游戏既简单又有趣，即使是没有编程经验的作者也能轻松上手。

当您完成创作后，可以[将您完成的 ChoiceScript 游戏提交给我们](http://www.choiceofgames.com/make-your-own-games/let-us-host-your-choicescript-games/)，我们将为您提供公开托管服务；您将获得游戏所产生的收入分成。

（王洛木：然而，官方无法接受非英语的故事，因为他们无法审核非英语的故事，且他们的打包程序主要是为了英语而检查和开发的。所以非英语的故事需要自行寻找分发平台，比如 itch.io）

## 来试试看吧

要开始，如果您之前从来没有使用过，那么您需要安装 [Node.js](https://nodejs.org/)。（安装那个“推荐 (recommended)”版本即可。

接下来，[从 GitHub 下载 ChoiceScript 源代码](https://github.com/dfabulich/choicescript/archive/refs/heads/main.zip)。它是一个 zip 文件，一个“压缩文件夹”，里面所有的文件都被压缩在一起，变成了一个单独的文件。

你需要解压整个 zip 文件。请注意，在 Windows 系统上，如果你双击一个 zip 文件，它会打开这个压缩文件夹，让它看起来像一个普通的文件夹。你需要点击“提取”按钮，然后选择“全部提取”，才能使用 ChoiceScript。

解压 zip 文件后，你需要启动 ChoiceScript 服务器。

* **Windows**：双击 `run-server.bat` 文件。Windows 会隐藏文件名中点号之后的部分，所以 `run-server.bat`有可能看起来像 `run-server`。
  * 首次运行时，Windows 可能会弹出 Windows Defender SmartScreen 提示（“Windows 已保护你的电脑”）。点击“更多信息”，然后选择“仍要运行”。
* **Mac**：双击 `serve.command` 文件。
  * 在 Mac 上首次运行 `serve.command` 时，双击操作会失效。（系统提示“Apple无法验证 ‘serve.command’ 不含可能损害您的 Mac 或危及隐私的恶意软件。”）请前往系统设置并搜索 “Gatekeeper”。在该设置页面中，会显示“‘serve.command’已被拦截以保护您的Mac”。页面中有一个“仍要打开”按钮。点击后，双击操作即可正常使用。

启动 ChoiceScript 服务器将打开服务器窗口，同时会自动开启浏览器并显示示例游戏。关闭服务器窗口即可停止服务器。若服务器停止运行，浏览器中的 ChoiceScript 将无法刷新；您需要重新启动服务器才能继续使用 ChoiceScript。

## 您的第一个场景：`*choice` 和 `*finish`

这是一个用 ChoiceScript 编写的简单场景。您可以在 ChoiceScript 文件夹的 `web/mygame/startup.txt` 中找到它。

```
  Your majesty, your people are starving in the streets, and threaten revolution.
  Our enemies to the west are weak, but they threaten soon to invade.  What will you do?

  *choice
    #Make pre-emptive war on the western lands.
      If you can seize their territory, your kingdom will flourish.  But your army's
      morale is low and the kingdom's armory is empty.  How will you win the war?
      *choice
        #Drive the peasants like slaves; if we work hard enough, we'll win.
          Unfortunately, morale doesn't work like that.  Your army soon turns against you
          and the kingdom falls to the western barbarians.
          *finish
        #Appoint charismatic knights and give them land, peasants, and resources.
          Your majesty's people are eminently resourceful.  Your knights win the day,
          but take care: they may soon demand a convention of parliament.
          *finish
        #Steal food and weapons from the enemy in the dead of night.
          A cunning plan.  Soon your army is a match for the westerners; they choose
          not to invade for now, but how long can your majesty postpone the inevitable?
          *finish
    #Beat swords to plowshares and trade food to the westerners for protection.
      The westerners have you at the point of a sword.  They demand unfair terms
      from you.
      *choice
        #Accept the terms for now.
          Eventually, the barbarian westerners conquer you anyway, destroying their
          bread basket, and the entire region starves.
          *finish
        #Threaten to salt our fields if they don't offer better terms.
          They blink.  Your majesty gets a fair price for wheat.
          *finish
    #Abdicate the throne. I have clearly mismanaged this kingdom!
      The kingdom descends into chaos, but you manage to escape with your own hide.
      Perhaps in time you can return to restore order to this fair land.
      *finish
```

如你所见，`*choice` 命令会向用户展示一系列 #选项；每个选项对应的结果会直接缩进显示在该选项下方（形成“缩进区块”）。

若你运行此场景，首先会看到三个选项：

1. Make pre-emptive war on the western lands.
2. Beat swords to plowshares and trade food to the westerners for protection.
3. Abdicate the throne. I have clearly mismanaged this kingdom!

若选择选项一，你将决定如何赢得战争。若选择选项二，你可以决定如何与西方人谈判。若选择选项三，场景将直接结束，不再提供额外选择。

由此可见，仅凭 `*choice` 指令和 `*finish` 指令就能实现诸多功能。事实上，仅使用这两条指令并投入大量时间，你完全可以创作出一整本"选择分支"风格的作品！

## 继续探索，尽情尝试！

在你的 ChoiceScript 文件夹中，有一个 `web` 文件夹；其中包含一个 `mygame` 文件夹；在该文件夹内，你会发现一系列纯文本文件，包括 `startup.txt`。（Windows 会隐藏文件名中点号之后的部分，因此 `index.html` 看起来像 `index`，而 `startup.txt` 看起来像 `startup`。）

纯文本文件可以用“文本编辑器”进行编辑。如果你双击 `startup.txt`，将会启动一个文本编辑器，在 Windows 上是“记事本”，在 Mac 上是“文本编辑”。请在 `mygame` 文件夹中双击 `startup.txt`。

如果你修改了文本，保存文件，并在浏览器中刷新页面，你应该能看到修改的效果。（请注意，ChoiceScript 服务器必须正在运行；否则，刷新将会失败。）

## 缩进

请注意，ChoiceScript 中的缩进是强制性的。如果没有这些缩进空格，我们将无法区分嵌套在其他选项中的选项和主菜单上的选项.

你可以使用空格或 Tab 键来缩进代码块（但不能在同一文件中同时使用两者）。你可以使用任意数量的空格，但必须保持一致。像这样的代码是不允许的：

```
*choice
    #Hold 'em.
        He calls; you win!
        *finish
      #Fold 'em.
        Better luck next time.
        *finish
```

选项 1 使用了四个空格，但选项 2 使用了六个空格；由于这些缩进没有对齐，如果你尝试编写这样的场景，ChoiceScript 将显示错误信息。

## 复用代码：`*goto` 和 `*label`

ChoiceScript 除了做出选择之外，还提供了一种在场景中跳转的方式。你可以使用 `*goto` 命令跳转到场景中的任意行，前提是你首先在目标行上放置了一个 `*label`。

```
  What kind of animal will you be?
  *choice
    #Lion
      *goto claws
    #Tiger
      *label claws
      In that case, you'll have powerful claws and a mighty roar!
      *finish
    #Elephant
      Well, elephants are interesting animals, too.
      *finish
```

当执行到 `*goto claws` *行时，程序将自动跳转至 `*label claws`* 行。您可以创建任意数量的标签，并通过 `*goto` 指令跳转到其中任意标签处。

请注意，每个缩进（嵌套）代码块必须以 `*finish` *命令（用于结束场景）或 `*goto`* 行（跳转至场景内另一行）作为结尾。

（您也可通过后文将介绍的 `*goto_scene` 命令复用代码。）

## 设置和检查变量（也被称为“属性”）

在 ChoiceScript 中，你可以使用变量来让场景和决策比那种“选择一条路径”式的书籍更有趣。

要使用一个变量，你必须首先用 `*create` 定义它，然后用 `*set` 修改它，像这样：

```
*create leadership 50 *set leadership 30
```

请注意，`*create` 仅允许出现在 `startup.txt` 文件的开头部分。而 `*set` 则可以在任何你喜欢的地方使用。例如：

```
What do you prefer?
*choice
  #Leadership
    *set leadership +10
    *goto action
  #Strength
    *set strength +10
```

变量一旦设定，你就可以像这样检查其值：

```
  #Run for class president
    *if leadership > 15
      You win the election.
      *finish
    You lose the election.
    *finish
```

通过使用变量，玩家早期做出的领导力选择可以在游戏后期对故事产生影响。

你也可以像这样，在当前领导力点数的基础上增加点数：

```
  *set leadership +20
```

这将在玩家当前领导力分数上增加 20 点。这与编写 `*set leadership leadership+20` 的效果相同。你也可以使用 "`-`" 来减去点数，使用 "`*`" 来乘以点数，或者使用 "`/`" 来除以点数。

如果你需要同时使用多个运算符（例如，你需要同时进行除法和加法），你必须使用括号，像这样：`*set honesty (leadership + manners)*2`。即使算术表达式完全可理解，你也不能省略括号，错误示范：`*set honesty leadership + manners / 2`。

您还可以使用 `${}`（美元符号后跟花括号）来显示玩家当前的领导力分数，如下所示：

```
  Your leadership score is: ${leadership}
```

您也可以在统计屏幕上显示变量，该屏幕可通过点击“显示统计”按钮访问。相关内容较多，因此我们已将其单独整理为一页：[自定义 ChoiceScript 的属性界面](/zh-hans_choicescript-guide/guan-fang-zhi-nan/zi-ding-yi-choicescript-de-shu-xing-jie-mian.md)

顺便提一下，变量不仅限于数字。您还可以使用引号将文本存入变量：

```
  *set lover_name "Jamie"
```

您还可以设置真/假“布尔”变量，这非常有用，因为它们能让您的 `*if` 语句变得简洁明了。

```
*create lover true
*if lover
  I'm a lover, not a fighter.
```

## 使用 `*else` 和 `*elseif` 来提高可读性

我们可以用 `*else` 命令重写上面的 leadership 示例；这样会让代码更易于阅读。

```
  #Run for class president
    *if leadership > 15
      You win the election.
      *finish
    *else
      You lose the election.
      *finish
```

这与之前的功能完全相同，但使用 `*else` 并通过代码缩进，更清晰地表明这两个选项中只有一个是可能的。

你也可以使用 `*elseif` 命令来定义三个可能的分支，就像这样：

```
  #Run for class president
    *if leadership > 25
      You win the election by a landslide!
      *finish
    *elseif leadership > 15
      You win the election, but just barely.
      *finish
    *else
      You lose the election.
      *finish
```

## 当我们 `*finish` 时，发生了什么?

当我们 `*finish` 时，游戏会推进到下一个场景。这由位于 `startup.txt` 顶部的 `scene_list` 命令定义。以下是一个示例：

```
*scene_list
  startup
  animal
  variables
  ending
  death
```

如果你在“startup”场景中 `*finish`，我们将直接进入“animal”场景，然后是“variables”场景。

如果你想创建一个新场景，你需要在 `mygame` 文件夹中创建一个新的 txt 文件。

终于，我们来到了结局场景。这里有一个结局场景的示例：

```
   This is the last scene!  The game is over!

  *ending
```

那个最终的 `*ending` 命令指示游戏在场景末尾插入“Play Again”菜单。如果你选择“Play Again”，游戏将从“startup”场景重新开始。如果你在未出现在 `*scene_list` 中的场景里使用 `*finish`，或者你在游戏的最后一个场景中使用 `*finish`，游戏会自动插入“Play Again”菜单，效果等同于使用了 `*ending` 命令。

你并非必须使用 `*scene_list` 和 `*finish` 来推进到下一个场景；你也可以使用 `*goto_scene` 跳转到游戏中的任何场景。这里有一个示例：

```
  #Lift weights
    *if strength > 15
      You lift the weights.
      *finish
    You drop the weights and hurt yourself badly.  You never recover.

    *goto_scene death
```

当这种情况发生时，我们直接跳转到 death.txt 文件。这让你能够提供一个标准的“死亡”消息，而无需在整个游戏中复制粘贴。

您可以使用 `*goto_scene` 标签跳转到另一个场景中的特定 `*label`，如下所示：

```
    *goto_scene invitations cordial
```

这将跳转到 invitations.txt 文件，并自动定位到该文件内的 `*label cordial`。

（王洛木：特别注意！不得在 `*scene_list` 内嵌套使用 `*comment`，因为这会被这一功能直接整行解析为一个叫这行所有名字的场景。这会导致快速测试直接丢出错误并停运。）

## 使用 UTF-8 编码

**创建新的场景 txt 文件可能会破坏带重音符号的字母（如 ñáéç）**：存在多种不同类型的“纯文本”文件。这些不同的 txt 文件类型被称为“编码”。每种编码处理重音字母的方式各不相同。ChoiceScript 使用“UTF-8”编码。如果您使用其他编码创建场景，文件中的重音字母可能会显示为乱码，例如：“�”。

默认情况下，在记事本中使用“另存为…”功能时，会创建采用 “ANSI” 编码的纯文本文件。（在“另存为”界面上有“编码：”选项。）请务必在保存前将编码设置为 “UTF-8”。

## 示例

以下是一些《龙之抉择》中的示例场景。未经 Choice of Games 明确许可，请勿复制其代码。

* [startup](http://www.choiceofgames.com/dragon/scenes/startup.txt)
* [queenpolitics](http://www.choiceofgames.com/dragon/scenes/queenpolitics.txt)

## 有问题吗？

若对本文件有疑问，请在 [ChoiceScript 论坛](http://www.choiceofgames.com/forum/categories/choicescript-help)发帖咨询。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://raster.gitbook.io/zh-hans_choicescript-guide/guan-fang-zhi-nan/choicescript-jian-jie.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
