Implicit Control Flow

Implicit control flow is an optional modification to the way ChoiceScript behaves. It changes ChoiceScript's requirements by removing the need for *finish, *goto, *goto_scene, or *ending at the end of *choice, *elseif, and *else. 隐式控制流是对 ChoiceScript 行为方式的一种可选修改。它改变了 ChoiceScript 的要求,移除了在 *choice*elseif*else 末尾需要使用 *finish*goto*goto_scene*ending 的必要性。

Devblog update: https://forum.choiceofgames.com/t/new-choicescript-features-implicit-control-flow-gosub-parameters/30042arrow-up-right 开发博客更新:https://forum.choiceofgames.com/t/new-choicescript-features-implicit-control-flow-gosub-parameters/30042

Usage

用法

To use implicit control flow, simply add the following to your *create variable section in startup.txt: 要使用隐式控制流,只需在startup.txt文件的*create变量部分添加以下内容:

*create implicit_control_flow true

(You can also *set implicit_control_flow true or false in other places in your scene files.) (您也可以在场景文件的其他位置*set implicit_control_flowtruefalse。)

Features

特性

Usually, in ChoiceScript, the code below would produce an error: 通常,在ChoiceScript中,以下代码会产生错误:

*temp player_gender "Male"

Coming inside, your friend greets you.

*if (player_gender = "Female")
    "Hey girl!"
*elseif (player_gender = "Nonbinary")
    "Hey pal!"
*else
    "Hey man!"

Still smilling, your friend continues, "How're you today?"

The error produced here would be: 此处产生的错误为:

"It is illegal to fall in to an *else statement; you must *goto or *finish before the end of the indented block."

As seen in the previous *choice, *elseif, and *else pages, ChoiceScript requires that all of these commands have either a *finish, *goto, *goto_scene, or *ending at the end of the code block; otherwise, the code will throw up an error. 如先前 *choice*elseif*else 页面所述,ChoiceScript要求所有这些命令在代码块末尾必须包含 *finish*goto*goto_scene*ending;否则,代码将抛出错误。

So to correct that, the following changes would be needed: 因此,要修正这一点,需要进行以下更改:

As seen here, if you want to simply proceed down the file, the use of several *gotos is quite redundant. Games that feature heavy use of *if, *elseif, and *else might end up with dozens or more of these extra *gotos and *labels just to proceed through simple *if/*elseif/*else sequences. 正如这里所见,如果你只想简单地按顺序执行文件中的代码,使用多个 *goto 语句就显得相当冗余。那些大量使用 *if*elseif*else 语句的游戏,可能最终会为了处理简单的 *if/*elseif/*else 序列而添加数十个甚至更多的额外 *goto*label 语句。

By using implicit control flow, however, the requirement for *gotos and *labels is removed. Our very first code example would not flag any errors and would proceed down the code without requiring the extra *gotos and *labels. 然而,通过使用隐式控制流,就无需 *goto*label 语句了。我们最初的代码示例将不会标记任何错误,并且可以在不需要额外 *goto*label 语句的情况下顺序执行代码。

When implicit control flow is enabled, *choice works basically the same as *fake_choice, except you can also freely nest a *choice inside another *choice with implicit control flow. 启用隐式控制流时,*choice 的功能基本与 *fake_choice 相同,区别在于你还可以在隐式控制流中,自由地将一个 *choice 嵌套在另一个 *choice 内部。

Notes

注意事项

Implicit control flow is convenient, but ChoiceScript's original behavior can help find unintended bugs. 隐式控制流虽然方便,但 ChoiceScript 的原始行为有助于发现意外的程序错误。

In the following example, the *choice will behave as a *fake_choice; all options will proceed down the code. If choice #1 is selected, it will mention that Santa refused to give you a present—but because the code continues down, you will still receive the video game. 在以下示例中,*choice 将表现得像 *fake_choice;所有选项都会继续执行后续代码。如果选择了选项 #1,它会提到圣诞老人拒绝给你礼物——但由于代码继续向下执行,你仍然会收到视频游戏。

Therefore, if the author forgets to include a different branch for choice #1, the previous error message could remind them to check their branching. 因此,如果作者忘记为选项 #1 设计不同的分支,之前的错误提示可以提醒他们检查分支逻辑。

Another advantage of implicit control flow is that branches are immediately apparent because of using *goto; any #options that do not branch will not have a *goto following. 隐式控制流的另一个优势在于,由于使用了 *goto 指令,分支结构一目了然;任何未设置分支的 #options 都不会跟随 *goto 指令。

To use the Santa example, with original CS, you would need: 以圣诞老人为例,在原始ChoiceScript中,你需要编写:

With implicit control flow, the same passage could read: 通过隐式控制流,同一段文字可以这样表达:

It's immediately visible that #option A branches, but #B and #C fall directly through. 可以立即看出,#选项A 会分支,但 #B#C 会直接顺序执行。

Known Bug

已知错误

While implicit control flow seems like a powerful tool, there's a specific scenario where it doesn't function well. 虽然隐式控制流看起来是一个强大的工具,但在某些特定场景下它并不能很好地发挥作用。

The expected interpretation of that code would be the player is given an only choice #varA upon the first visit of "haha". Picking #varA would loop the player back to the beginning of "haha," but now they can pick either #varA again or the now-revealed #varB. 这段代码的预期解释是,玩家在首次访问"haha"时仅获得选项 #varA。选择 #varA 会使玩家循环回到"haha"的开头,但此时他们可以再次选择 #varA,或选择现已显示的 #varB

However, CS throws an error when the player picks #varA: "It is illegal to fall out of a *choice statement; you must *goto or *finish before the end of the indented block." Removing the command *set varB true, however, fixes the error, although the player will now be trapped in an infinite limbo of #varA. A simple fix would be moving the *goto hehe inside the body of #varA, though this begs up the question, "why bother using implicit control flow at all?" 然而,当玩家选择 #varA 时,CS 会抛出一个错误:"从 *choice 语句中跳出是非法的;在缩进块结束前必须使用 *goto*finish。"不过,移除命令 *set varB true 可以修复此错误,尽管玩家现在将陷入 #varA 的无限循环困境。一个简单的解决方法是将 *goto hehe 移到 #varA 的代码块内部,但这引出了一个问题:"何必费心使用隐式控制流呢?"

Comparison

比较

Here is a simple visual comparison with ICF on and off: 以下是开启与关闭隐式控制流的简单视觉对比: