为了便于您理解,接下来会用游戏内一个实际出现的脚本,来解释一次典型的对话是如何被写作的。
我们选取哈妮作为参考范文,一方面是因为喜欢她的人比较多,另一方面是其脚本写得非常简单。
脚本结构

哈妮的脚本由3个部分组成。实际上,大部分普通角色的脚本都由3个部分组成,分别是:
角色名_1/2/3.yarn:这个角色的入口和基本的循环。
角色名_1/2/3_SheAsk.yarn:这个角色向我们提问的可用项。
角色名_1/2/3_WeAsk.yarn:我们向这个角色提问的可用项。
Victim_1
title: Entry_Victim // 所有角色直播对话时的入口名字都要保持一致
subtitle:one // 只有subtitle不同
when: once // 条件1:只可以被访问一次
when: $Today >= 2 // 条件2:如果今天在第二天以后。条件1和条件2是交集。
tracking:always // 不用管
---
<<set $LastSpokenCharacter = "Victim">> // 将最后对话过的角色设置为Victim,基本无用
Aistalt: 嗨。
Victim: Nah Maman, in nabayad khili geron Basheh. Adamayi keh onja npastan az cpehmeh jaye dania Npastan. // 沙地语。这里是为了教学翻译功能所以刻意使用原文。
Aistalt: 正在调用翻译服务……不,妈妈,这应该不会太花钱。上面的人来自世界各地。<<if Tech()>=1>>#Tech #state:Idle // 将爱式塔设置为Idle状态;如果技术大于1,那么会翻译。
Victim: [suprise][F="Chi? Vasl misheh?"]什么?接通了吗?[/F][/suprise] #state:Shy
// [suprise]的情绪标签,以及[F=""]的使用,此外她切换为了shy状态。
Victim: [confuse]你、你好?你听得到我的声音吗?[/confuse]
Aistalt: 当然。你是哪里人?
Victim: [confuse]什么?[/confuse]
Aistalt: 你是哪里人。Hal kojayi?
Victim: [excite][F="Ey jan!Vāghe’an dāri be zabun-e mā harf mizani? Cheghadr āli! Man too-ye Edgeon zendegi mikonam. "]哇,你居然说我们的语言?太好了!我住在末城。[/F][/excite][happy]不过,我们要用新语交配。[/happy] #state:Happy
<<detour SCheck_Easy_Culture>> // 一个自动的被动检定,玩家无感
=>Aistalt: 末城的平民……她是一个肯德人。<<if $Check_Result>> #Empathy // 如果检定成功
<<set $Memory_Protocol_Kend = true>>
<<detour SCheck_Easy_History>>
=>Aistalt: 一个肯德女孩,住在末城的隔离区内?日子估计不太好过。<<if $Check_Result>> #Troll
<<set $Memory_Protocol_Kend = true>>
Aistalt: 呃……如果是指交换信息,那个词是“交流”。
Victim: [confuse]等等,那交配是何意味?[/confuse] #state:Shy
Aistalt: 它指的是[F="Joft-giri"]像动物般做爱。[/F]
Victim: …………………… #state:Fear
Victim: [fear]坏啊[/fear]。我昨天就是这么跟关卡的士兵说的!他们笑得可开心了,我连证件都没带,他们就直接放我进去了!
Aistalt: ……而你打破了那几个小伙子的期待? #state:Funny
Victim: [funny]我显然不是那个意思![/funny] #state:Shy
<<set $Memory_Protocol_Victim_Dialect_Saudi = true>>
<<jump Victim_1_Hub>> // 跳转到Victim_1_Hub,这是游戏的正式循环。
===
title: Victim_1_Hub // 对话的正式循环,你可以把这个想象成是一种回合制游戏。我们问一个问题,对面问一个问题。
---
<<detour Victim_1_WeAskHub>> // 我们问她问题
<<detour Victim_1_SheAsk>> // 她问我们问题
<<jump Victim_1_Hub>> // 跳转回自身
===
title:Victim_1_End
---
Aistalt: 我想我们聊得够久了。
Aistalt: 无论是作为语言练习还是闲聊,这都……还算稍微有点价值。#Tech
Aistalt: 直接说“很高兴认识你”会死机吗?#Kitsch #state:Funny
// --- 分支:如果之前帮她修好了井 ---
<<if $Memory_Victim_Well_Fixed == true>>
Victim: 等等!在此之前……窝还要再次谢您。 #state:Happy
Victim: 那口井还在出水!大家都 [happy]坏开心的![/happy]
Aistalt: 记得别让巡逻队发现那个阀门被动过手脚。 #state:Idle
Victim: 妈妈说您一定是沙漠里的精怪变的,是来帮我们的[happy]好灵[/happy]。
Aistalt: 呃……精怪?这听起来不像是夸人的词…… #state:Shy
Victim: [happy][F="Khoda negahdār!"]无论如何,愿主保佑您![/F][/happy]
<<elseif $Victim_Love >= 2>>
Victim: 谢谢您陪窝说话,老师。 #state:Happy
Aistalt: 老师?我?
Victim: 似鸭。您没有像其他人一样切掉我,还教了我新语。
Victim: 我会记住那些词的。“没有武器”,还有“缓冲区”。
Aistalt: 希望你永远只用得上“缓冲区”,而用不上“没有武器”。 #state:Idle
Victim: [happy]嘿嘿[/happy],我会努力练习的!
// --- 分支:普通/低好感(没骂人,但也没怎么帮忙) ---
<<else>>
Victim: 谢谢。虽然您说话有些……[sad]奇怪[/sad],但至少您听完了我的话。#state:Idle
Aistalt: 祝你好运。
<<endif>>
// --- 统一结尾 ---
Victim: 啊,宣礼塔响叻。我得去祈祷了。
Victim: [F="Be omid-e didār."]再见,好心的陌生人。[/F]
<<Solo Aistalt>> // 安全起见,顺手的事,清理一下。
<<jump Live_Hub>> // 回到主循环。
===
Victim_1_SheAsk
title:Victim_1_SheAsk
subtitle: Auto_6b842d3414
tracking:always
when:once
---
对白略去
===
title:Victim_1_SheAsk
subtitle: Auto_15a252e8a0
tracking:always
when:once
---
对白略去
===
title:Victim_1_SheAsk
subtitle: Auto_7dcbd31883
tracking:always
when:once
---
对白略去
===
这3个节点本身没啥好讲的。值得注意的是,这里就是Yarn Spinner官方文档中提到的Node Group(节点组)的典型应用。当你创建了一个同名(title)的节点时,当我们遇到了jump/detour命令时,就会跳转到这些节点中的其中一个。
此时,会依据其显著性(Saliency)进行排序。显著性是由一个节点本身条件的复杂度决定的,譬如,如果一个节点的进入条件是:
when: 今天是第三天以后
那么它的显著性是1(只有1个条件)
而另一一个节点的进入条件是:
when: 今天是第五天,且已经跟罗莎连麦过了,且键政属性>5
那么它的显著性是3(有3个条件)。
在选择这些节点时,高显著性的总是排到低显著性的上面,被优先选择。在相同显著性的节点之间,则是随机选择。
Victim_1_WeAsk
title:Victim_1_WeAskHub
---
->你是来学新语的么?<<once>>
<<detour Victim_1_Answer_LearnNew>>
->为什么想学新语?<<once if visited("Victim_1_Answer_LearnNew")>>
<<detour Victim_1_Answer_WhyNew>>
->末城不是共和国的么?<<once if visited("Victim_1_Answer_WhyNew")>>
<<detour Victim_1_Answer_YourCity>>
->你和家人住一起?<<once>>
<<detour Victim_1_Answer_Family>>
->能和我讲讲沙地的历史吗?<<once if not $Memory_Protocol_Cerorio>>
<<detour Victim_1_Answer_History>>
->你是拜水教的信徒?<<once if $Level_Topic_Culture>=1 and visited("Victim_1_SheAsk")>> #Topic:Topic_Culture:1
<<detour Victim_1_TheFlow>>
->我可以帮你制订一份新语的学习计划。 <<once if visited("Victim_1_Answer_WhyNew")>>
<<detour Victim_1_Answer_Sinnolish>>
-> 抵抗组织?<<once if visited("Victim_1_Answer_WhyNew")>>
<<detour Victim_1_Answer_Rebel>>
-> 我也许可以帮你修那口井<<once if visited("Victim_1_Answer_YourCity") and $Level_Topic_Engineer>=1>> #Check:Tech:12:Topic_Engineer #Topic:Topic_Engineer:1
<<detour Victim_1_FixWell>>
-> 沙猴是不会说人话吗?<<once if $Level_Topic_RightWing>=1>> #Topic:Topic_RightWing:1
<<detour Victim_1_Sauni>>
-> 再见<<if visited_count("Victim_1_Hub")>=2>>
<<jump Victim_1_End>>
===
这也是一个典型的结构,即把所有玩家问的问题,都集成到一个统一的 Hub中;之后你只需要在这个Hub里增加或减少选项即可。每个选项的内容倒是(在逻辑上)乏善可陈。