插件手册:betonquest:基本概念

基本概念参考 Reference

(版本:2017-04-03 翻译:kjiang 原文链接

本章节详细描述了BetonQuest的各个方面。你应当阅读本文档至少一遍以上,这有助于在你遇到问题的时候该如何搜索信息,并帮助你更好地处理遇到的问题。

每个对话都必须定义一个NPC名字(某些对话可以不关联到NPC身上,所以即使NPC有名字了也要把他的名字写在这里),以及初始对话。

  1. quester: Name
  2. first: option1, option2
  3. stop: 'true'
  4. final_events: event1, event2
  5. NPC_options:
  6.   option1:
  7.   text: Some text in default language
  8.   events: event3, event4
  9.   conditions: condition1, !condition2
  10.   pointers: reply1, reply2
  11.   option2:
  12.   text: '&3This ends the conversation'
  13. player_options:
  14.   reply1:
  15.   text:
  16.   en: Text in English
  17.   pl: Tekst po polsku
  18.   event: event5
  19.   condition: '!condition3'
  20.   pointer: option2
  21.   reply2:
  22.   text: 'Text containing '' character'

注解 1:配置文件使用YAML语法作为基本格式。如果你不知道这是啥你应该先百度/谷歌一遍基本概念。一些基本规则是:

  1. 你需要使用两个空格而不是tab键来为层级树排版
  2. 其次你需要注意一些特殊字符,比如当你需要在对话/文字内容中使用单引号'的时候,你应用两个''而不是一个
  3. 当需要写”true“和”false“的时候你需要用引号把它套起来比如'true'
  4. 如果你需要以&作为开头的时候,整句话都需要用单引号套起来比如'&c你好,很高兴认识你'
  5. (kj译注)另外你必须注意,一切冒号都必须使用英文半角冒号:而不是中文冒号”:“,并且冒号和文字内容之间必须有空格
  6. 如果你不确定你的yaml配置文件是否符合语法规定,你可以使用这个工具检查。
  • quester是NPC的名字。这个名字应该要和所关联的NPC名字一样,当然你改别的也不会影响BetonQuest运行,只是会容易让人困惑。
  • first用于指向第一个初始对话。NPC会从中选择最合适的一个作为初始对话。
  • final_events会在对话结束的时候触发这些事件(events)。注意无论对话内容是怎么结束的,这些事件都会被触发(你可以用这个实现,比如,当玩家试图逃跑的时候守卫就会立即攻击玩家)。这个功能是可选的,如果不需要最终事件,你可以选择不填。
  • stop用来控制玩家是否在对话的过程中不能离开NPC(false)或可以离开NPC(true)。当启用的时候,玩家对话会在玩家退出游戏的时候挂起,然后重新进入游戏的时候可以接着上次的对话内容。这样玩家无论如何都必须完成整个对话内容。true和false必须被' '套起来!你还可以通过config.yml中的max_npc_distance选项决定玩家远离NPC多少距离之后才会结束对话/被传送回NPC身边。
  • NPC_options里面是一系列由NPC说的对话内容。
  • player_options里则是玩家可以选择的对话选项。
  • text必填,这是显示在屏幕上的具体对话内容。
  • conditions若需要对话显示出来,则这里指明的条件conditions都需要同时满足才行。多个条件用英文逗号,间隔。
  • events则定义了在这句对话被选择的时候,随同对话(由NPC或玩家)触发的事件events。多个事件用英文逗号,间隔。
  • pointer指向另一方(NPC/玩家)对话的选项。在玩家对话里表示指向NPC的对话,在NPC对话里指向玩家的对话选项。

当开始和NPC对话的时候,NPC会检查它每一句初始对话(first中的option1和option2)里面的conditions来决定他的第一句到底该说哪个。在上面的例子里,当option1里的conditions全都满足的时候,它就会以optoin1作为地一句对话;反之则会以option2作为第一句对话。如果全都不满足,则对话直接结束。
当option1被NPC选中之后,event3和event4就会被触发,同时NPC会提供reply1和reply2两个对话选项给玩家。不过需要注意,和NPC的选项,如果reply1或reply2里面的conditions并不满足的时候,这些对话依然不会出现在玩家选项里。这个时候玩家可以选择他的对话,选择完毕BetonQuest会根据这个玩家选项里面的pointers指回NPC选项。然后轮到NPC根据conditions选择它的对话┄┄

当玩家或NPC没有可以选择的对话的时候(无论是缺少pointers还是各自的conditions不满足),对话会直接结束。如果你在测试脚本的时候发现对话无缘无故结束了,记得检查一下服务器控制台,有可能是你的配置文件写得不对。

这个文件在编写/阅读的时候多少会有点令人迷惑,所以你在给每个对话选项命名的时候都应该留个心,要明白你将来还能理解它是什么意思。不过不要过分担心,如果你真的写错了什么,测试的时候插件会在服务器控制台告诉你什么地方错了。另外,认真分析一下那个插件自带的默认对话脚本,会对你完全理解分析这个插件有巨大帮助。

如果你想要将某个对话和另一个NPC的对话脚本链接,或将一个复杂庞大的对话脚本拆分成多个小的、更专注于某个领域的脚本,你可以将对话内容指向另一个脚本里的选项。实现这个你只需要将pointers写成conversation.npc_option这样的形式。

需要注意的是,你只可以将pointers指向NPC选项。也就是说这样的pointers只能写在first里作为对话开始的可选项,或玩家对话的pointers(player_optoins)里。如果你把跨脚本链接写在NPC对话(NPC_options)里,则会报错。

你可以在对话脚本中使用各种变量Variables。这些变量会被解析为某个值然后在对话中显示出来。一个变量通常看起来是这样的:%type.optional.arguments%type是必须的参数,它定义了这个是什么类型的参数。可选参数由这个变量类型决定,例如%npc%并没有任何可选参数,而%player%就会有“display”这个可选参数(比如%player.display%)。关于变量的更多信息你可以通过变量列表章节了解更多。

如果你错误地使用了某个变量(比如当你尝试获取某个任务目标objective属性properties而这个任务目标并未被玩家启动,或你想在message事件中使用%npc%参数时),那么这个变量会啥也不显示()。

在默认的对话脚本中,对话内容还包含了其它语言。你可以把对话内容翻译成各种语言,玩家可以通过/questlang指令选择他想要显示的语言。另外,你还可以翻译NPC/任务的名字,你只需要:

  1. quester:
  2.   en: Innkeeper
  3.   cn: 旅馆老板
  4.   pl: Karczmarz
  5.   de: Gastwirt

请注意yaml的语法格式。另外玩家只能选择messages.yml中的语言,如果并没有这个语言,对话和选项则会以config.yml规定的默认语言显示。如果连默认语言也没有,那么BetonQuest则会报错。

你还可以翻译任务日志journal内容、取消任务、和messageevent的内容。关于这部分在本文后段会有介绍。

默认情况下BetonQuest会使用最原始可靠的文字方式直接展示对话内容。玩家通过在聊天栏输入代号来选择选项。你也可以通过config.yml中的default_conversation_IO设置来更改对话展示方式。此设置默认值是simple,当更改为tellraw的时候,玩家可以直接点击文字选项(而不用在聊天栏打数字)。请注意,点击有的时候会因为聊天信息滚动过快导致玩家点错选项。你还可以设置为chest,这样对话内容就会以箱子GUI的形式展示,NPC的对话和玩家选项都会变成可点击的物品按钮。

你可以通过config.ymlconversation_colors设置,来控制对话的颜色。你必须写颜色的英文名字而不是代码。

如果你使用chest作为对话展示的方式,你可以修改按钮为其它物品。默认按钮使用末影珍珠Ender Pearl作为按钮。只需要在对话内容的前面加上特定前缀即可,例如{diamond_sword}我想开启这个任务!或者{wool:10}紫色!,物品id为Minecraft格式。

(kj译注:此功能暂不兼容BetonQuest Editor)自BetonQuest 1.11版开始,对话脚本支持“继承”功能。对话选项中如果有extends设置项,那么extends指向的内容都回被合并到这个对话选项中。BetonQuest会检测死循环(循环指向)。

  1. NPC_options:
  2. ## 对话开始
  3.   对话开始:
  4.   text: '你好啊'
  5.   extends: 见过面, 主菜单
  6.  
  7. ## 译注:被extends的这部分必须加到原对话的后面
  8.   好像见过:
  9.   text: ',我们昨天好像见过面?'
  10.   condition: 见过了
  11.  
  12. ## 主菜单
  13.   主菜单:
  14.   pointers: 问你个事, 再见

在上面的例子中,对话选项开始对话会把好像见过的文字加到原始对话的后面,并且把主菜单的选项都包含进来。所以就相当于:

  1. NPC_options:
  2. ## 对话开始
  3.   对话开始:
  4.   text: '你好啊,我们昨天好像见过面?'
  5.   condition: 见过了
  6.   pointers: 问你个事, 再见

如果你能好好利用这个功能,它可以帮你缩短对话脚本。


conditionsevents、和objectives中的内容被定义为“指令字符”,它们是以一定格式编写的、包含具体条件/事件/任务目标的文字。若想要更好地编写这些指令,你需要参阅下面的章节还有其它几个页面,那些章节介详细绍了这些指令字符的具体作用和用法。这些指令字符的具体内容都需要在特定的文件中预先设定,比如条件conditions的内容则在conditions.yml配置文件中定义。它的格式类似于name: 'the instruction string containing the data',单引号是可选的,具体请百度/谷歌“YAML格式”。

条件conditions在创建高级任务过程中是最常用的,它可以让你控制什么选项可以展现给玩家、NPC如何对玩家作出反馈、或任务目标objective什么时候才算完成。完整的条件列表请参阅条件列表

你可以通过在条件conditions前面加上!来让它们的意思反过来(注意不是中文输入法的“!”),记得感叹号只能用在对话脚本里而不是conditions.yml中。

你可以在事件中使用变量variables而不一定要输入数字,如果这个变量无法解析(比如这个变量返回空白的时候),BetonQuest则会把它当作0。

在某些时候你可能需要让某些事情发生。比如更新任务日志(journal)、设置标签(tag)、给予奖励,这些东西都可以通过事件events实现。定义它们就和上面的条件conditions一样,在events.yml中,一个名字冒号再加上指令字符。具体可定义的事件指令字符请参阅事件列表。每一个事件字符后面都可以加上conditions:/condition:作为限制条件,比如conditions:angry,!quest_started意即这个事件只会在这些条件都满足的情况下启动。

你可以在事件中使用变量variables而不一定要输入数字,如果这个变量无法解析(比如这个变量返回空白的时候),BetonQuest则会把它当作0。

在创建复杂任务的时候,任务目标objectives是你需要经常接触的部分。玩家通过objective事件events来启动任务目标。就像其它事件一样,具体的任务目标要在objectives.yml中定义(请参阅任务目标列表 Objectives List)。在每个任务目标指令的最后,你都可以加上conditions:events:任务目标会限制这些目标什么时候完成(比如在守护城门的时候必须在特定的位置消灭僵尸),完成这个目标之后会触发特定的事件(比如直接给予奖励,或设置一个标签(tag)好让玩家回去找NPC的时候NPC根据这个发放奖励)。格式是,在每一串指令的最后协商conditions:con1,con2 events:event1,event2,用英文逗号分隔每个条件/事件名字且不能有空格。如果只有单个条件/事件,你可以写condition:event:

如果你想在某个目标完成之后,马上开始同一个目标(比如die目标,当玩家死亡之后,把他传送到出生点并重新开始这个die目标),你可以在指令的最后加上persistent参数,这回导致这个任务目标永远无法结束(即使这个任务目标中的事件events还是会照常触发)。如果你要取消/中断这个任务目标,你可以触发objective delete事件

无论是否在进行中,所有任务目标都会在服务器启动的时候被加载。但如果玩家没启动它们的话,这并不会消耗任何服务器资源。换句话说,如果你一共定义了100个任务目标、有20个玩家启动了其中一个目标、另有20个玩家启动了另一个目标,那么一共就只有2个目标会消耗你的服务器资源,不是40,更不是100。


你所创建的一切内容都要按照脚本包分类存放。每一个脚本包必须包含一个main.yml文件,包中还可以包含一个存放对话脚本的conversations文件夹、events.ymlconditions.ymlobjectives.ymlitems.yml、以及journal.yml文件。BetonQuest必须有一个叫“default”的(就是存放默认任务的那个文件夹),如果你删掉它,BetonQuest会再生成一个。

如果你不介意混乱,你可以把全部任务都一股脑丢到“default”里面。这样你总有一天会遇到每个配置文件都上百行而你找不到你要改的地方在哪儿的窘境。因此分们别类存放你的脚本绝对是个非常好的习惯,比如用文件夹“主城”用来储存主城的任务、“副本”则可以存放一些有趣的副本任务,等等。

每个脚本包都可以通过各自的main.yml文件单独启用/禁用,你只需要设置enabledtruefalse

如果任务包任务包之间不能互相访问就太限制人了,因此你可以通过的前缀和名字去访问别的的内容。比如你在为包quest1编写对话脚本,此时你想触发另一个包quest2reward事件,你只需要写quest2.reward就可以触发它了。BetonQuest插件会去quest2而不是在quest1包里搜索这个reward事件。一切事件events条件conditions任务目标objectives物品items对话脚本conversations都可以用这种方式跨包访问。但是请注意,任务日志journal并不能跨包!

脚本包可以用文件夹分们别类存放。一个文件夹可以是脚本包本身,或者用来存放脚本包,决不能即存放又是脚本包。包的路径前缀就是文件夹的名字,用英文横线分隔。下面这个路径树(每一个main.yml文件代表了一个脚本包):

BetonQuest/
├─default/
└─quests/
  ├─village1/
  │ ├─quest1/
  │ │ └─main.yml
  │ └─quest2/
  │   └─main.yml
  │─village2/
  │ └─quest1/
  │   └─main.yml
  └─village3/
    └─main.yml

包含了这些脚本包

  1. default
  2. quests-village1-quest1
  3. quests-village1-quest2
  4. quests-village2-quest1
  5. quests-village3

(kjiang译注)实测这些文件夹和脚本包都可以用中文命名,路径可以使用中文,方便中文用户使用。如:

BetonQuest/
├─default/
└─国家1/
  ├─村庄1/
  │ ├─任务1/
  │ │ └─main.yml
  │ └─任务2/
  │   └─main.yml
  └─村庄2/
    └─任务1/
      └─main.yml
  1. default
  2. 国家1-村庄1-任务1
  3. 国家1-村庄1-任务2
  4. 国家1-村庄2-任务1

在跨包访问的时候,你并不一定非要输入包的全名不可。在上面的例子中,如果你想要在“quests-village1-quest1”之中引用另一个包“quests-village1-quest2”的内容,你可以就写_-quest2。这个的意思是:从这个包(quest1)开始,后退一个目录,然后找到包”quest2“。路径里面的这个_有非常特殊的意思。同样的,如果你想引用”quests-village2-quest1“这个包的内容,你可以输入_-_-village2-quest1,输入两次_会让你后退两次,接着插件就会进入”village2“目录然后是”quest1“包。

当你想在多个包之间来回引用的时候,相对路径会相当有用。不用每次都把整个路径都打上,你只需要把相对路径打出来就好了。例如你有许多个包而且需要移动这个文件夹的时候,或是在你使用BetonQuest-Editor和BetonQuestUploader工具的时候,你就用每次都把一长串完整路径都打出来。(BetonQuest-Editor的相对路径支持会在未来升级后提供)。

当你需要在某些事件条件任务目标中用到坐标位置的时候,你需要以一个固定的格式定义定义它们。一般坐标包含两部分内容:基准坐标base向量vector,只有基准坐标是必须的。 基准坐标是一切坐标的核心,目前包含两类:绝对坐标坐标变量

绝对坐标的格式类似100;200;300;world,这里100是x坐标值、200是Y、300是Z、而world则是世界,你可以输入小数,在最后你可以加上可选的偏角yaw仰角pitch决定头应该看向哪儿(例如:0.5;64;0.5;world;90;-270)。

某些情况下你也可以使用坐标变量而不需要自己输入坐标值。例,如果你需要提取玩家所在坐标,你可以输入%location%,它会被解析成实际坐标值。但有一点需要注意:你不可以在玩家不在线的时候使用这个变量(例如在玩家离线后执行的事件包folder事件或某些静态事件。),BetonQuest没办法在玩家离线的时候解析它。

向量vector相当于坐标的修改值。在某些情况下,比如配合全局变量(请看下一章节)使用的时候,它会非常有用。向量的格式类似于→(10;2.5;-13),它加在基准坐标的后面。向量的作用是用来增减基准坐标的值,比如100;200;300;world_nether→(10;2.5;-13)表示的实际坐标值应该是X=100+10=110、Y=200+2.5=202.5、Z=300-13=287。

你可以在编写事件条件、或任务目标指令的时候把全局变量 global variables作为值填进去。全局变量是类似这样的东西:$beton$(这个变量的名字就是”beton“)。当插件加载脚本的时候,这个变量会被替换成main.yml中定义的实际值,而不是在执行脚本的时候。

  1. variables:
  2.   村庄坐标: 100;200;300;world
  3.   村庄名字: Concrete

如果你需要在脚本中重复输入多次某个固定值(比如某个WorldEdit schematic),那么使用全局变量会变得很方便。你只需要打几个字就行,而不需要输入一长串的坐标、名字、甚至一大段文本(当然,是在剧本作者合理利用的情况下,内容非常短的名字就没必要用变量了)。

请注意全局变量对话脚本中用到的变量是完全不一样的概念:全局变量使用$而对话变量使用%;全局变量是在脚本执行之前就被替换成实际值,而对话变量会在脚本执行过程中变换,并且具体是和玩家有关联的。

有个功能可以让玩家取消一个正在进行中的任务。在main.yml中有一个cancel的分支,在这里定义什么任务可以被取消,以及取消的时候需要做什么。请参照默认的default包里面的自带任务作为参考例子。你可以定义的参数是:

  • name - 这会被作为名字显示在玩家的背包backpack中。名字中的下划线_都会被显示成空格。如果你想显示多语言,你也可以在这里添加(en英文这样)。
  • conditions - 条件conditions列表,用英文逗号分隔。如果玩家要取消这个任务,他要先满足列表中的这些条件。你可以用这个来判断玩家已经开始了这个任务(比如判断有没有什么标签tags),但并没有完成。
  • objectives - 需要取消的任务目标objectives列表。
  • tags - 需要删除的标签tags列表。
  • points - 需要删除的积分points列表。
  • journal - 需要取消的任务日志journal记录。
  • events - 如果你想在取消任务的时候触发另一些事件(比如给予玩家惩罚),请在这里列出。
  • loc - 可以在取消任务的时候把玩家传送到某个地方。这相当于触发一个传送事件

如果玩家要取消一个任务,他需要打开他的背包backpack(/backpack)然后点击“取消”按钮(默认是个骨头图标,如需自定义你可以在items.yml中创建一个名为“cancel_button”的物品)。点击之后就会显示一系列可以被取消的任务。

如果你想制作一个对所有玩家都有效的任务目标,无论玩家有没有开启,你可以通过“全局目标”实现。在普通的任务目标指令(objectives.yml中的指令)末尾加上global参数,那么这个任务目标就会对所有进入游戏的玩家生效。每次玩家加入服务器的时候,都会自动启动这个任务目标。

但为了避免这个任务目标在玩家每次加入服务器的时候被重复启动,系统还会给启动过这个任务目标的玩家添加一个tag,只要玩家有这个tag在身上,就不会重复启动这个任务目标。这个tag的格式是<package>.global-<id>,其中<id>是任务目标的id(如下例中是“start_quest_mine”),<package>是该任务目标所在的objectives.yml的脚本包路径。(kj译注)如果你需要这个任务目标可以被重复完成,你应该在末尾添加persistent参数,而不是删除global tag!

你可以利用这个设计出诸如在固定地点启动某些事件,或破坏某些特定方块后触发奖励的功能。

  1. start_quest_mine: 'location 100;200;300;world 5 events:start_quest_mine_folder global'

静态事件static events是指可以在一天中某个时刻自动触发的事件。这些事件不与玩家关联,所以类似于tag这样关系到玩家的事件就不属于静态事件。并且,静态事件没有条件一说,因为检查条件的时候会涉及到具体某个玩家。在事件列表中的一切静态事件都会用static特别标注。如需在固定时间发动静态事件,可以在main.ymlstatic分支写上类似这样的内容:

  1. static:
  2.   '09:00': beton
  3.   '23:59': lightning_strike
  4.   '11:23': some_command

注意时间必须用' '套起来才符合YAML格式要求。如果小时小于10则需要在前面补上”0“。betonlightnint_strike这些都是来自于events.yml的事件。每一条只能写一个事件,如果你需要同时触发多个事件你可以使用”事件包folder“

日志是一本记录你所有冒险历程的书。你可以输入/j指令或输入/b在背包里找到它。你不能将它放入任何箱子、展示框等。如果你觉得有必要解除你的日志,只需要丢掉它,它将会回到你的背包中。日志将随日志事件journal更新,其文本由配置文件journal.yml定义。如果你更新了文本并重新加载(reload)了插件,所有玩家的日志将会反映变化。日志中的颜色可以在config.yml中修改。条目可以使用颜色代码,但颜色会在页面间消失。

日志默认出现在快捷栏最后一格中。如果你想更改它,可以调试config.yml中的default_journal_slot项,尝试不同设置直到你觉得没问题。 如果你想要编译条目,做与conversation项相同的行为——换行,添加你想包括的所有语言ID与日志文本。

你可以通过config.yml文件中的日志journal部分控制日志行为。chars_per_page说明了单页上可以放置多少字符。如果你设置得过高,文本将会溢出页面,而太低则会有过多页面。one_entry_per_page允许你将所有条目放置于同一页面。在此情况下chars_per_page则被无视,BetonQuest将把全体条目放入此页面。reversed_order允许你反转条目顺序而hide_date让你从日志条目中删除日期。 您可以在config.yml的journal_colors部分中控制日记中的颜色:date是每个条目的日期颜色,line是条目分割线的颜色,text是文本的颜色。 您需要使用不带&的标准颜色代码(如:4表示深红色)。

您还可以将主页添加到日记中。 这是一个文本列表,仅在满足指定条件时显示。 您可以在main.yml文件的journal_main_page部分中定义它们:

  1. journal_main_page:
  2.   title:
  3.   priority: 1
  4.   text:
  5.   en: '&eThe Journal'
  6.   pl: '&eDziennik'
  7.   conditions: 'quest_started,!quest_completed'

每个字符串可以有不同语言的文本,条件列表用逗号分割(这些条件必须满足日志中显示的文本)和优先级(priority)——它控制文本的顺序。你可以在文本中使用会话变量,但只有在玩家使用/journal命令获取日志时才会更新它们。支持颜色代码。

如果您希望主页采用单独的页面(条目将显示在下一个空页面上),将config.yml中的full_main_page设置为“true”。

标签tags就是一小段用来在玩家身上做标记的文字,标记之后可以用来做检查/判断。在判断玩家是否开启/完成了某个任务的时候,标签是个很有用的工具。你可以通过tag事件events在玩家身上做标记,然后用tag条件conditions来检查玩家是否有这个标签。

关于路径问题,标签会和脚本包packages绑定。假如你在default包中添加了一个beton标签,那么这个标签的路径实际上就是default.beton。你可以把default包中的检查事件简写成tag beton,但实际上这个事件等效于tag default.beton。如果你要在别的脚本包里检查这个标签,注意标签的路径一定要写成完整的default.beton

积分和上面的标签类似,只不过还带了数值。你可以把它当作任务的奖励发放给玩家、用在NPC问答中记分;你还可以扣分,甚至扣到负分。积分可以按类别命名划分,比如讨伐次数闯关次数;积分还可以用来统计某个任务做了几次,或者建立声望系统统计玩家在某些部落之中的声望值等等。你可以检查玩家某项积分有没有达到/超过一定数值。具体操作请参阅事件:积分条件:积分

对话脚本conversations可以关联到NPC身上。只需要修改main.yml中的”npcs“部分即可:

  1. npcs:
  2.   '0': innkeeper
  3.   '酒店老板': innkeeper

冒号左边的内容是NPC名字,右边是对应的对话脚本文件名。如果你使用的是Citizens NPC,那么左边可以是NPC名字或ID(编号)。如果你不使用或没安装Citizens,那么你依然可以用下面的方法来创建一个NPC:

随便在某个地方放置一个染色粘土块,颜色无所谓,然后在上方放置一个头颅方块(类型无所谓但必须是头颅),接着在粘土方块的侧面贴上告示牌,并在第一行写上[NPC],第二行写NPC的ID(以上面为例,酒店老板),注意你必须有betonquest.createnpc权限才可以使用这个方法。现在恭喜你,你成功创建了一个NPC,现在你可以在两边插上拉杆(手)或者底部放个开着的栅栏门(腿)。开始对话只需右键它的头。

BetonQuest里面的所有物品都需要在items.yml文件里定义(kjiang译注:当你需要给予奖励、移除物品或检测背包的时候你不可以简单地填个物品id完事,必须提前在items.yml中定义),并且和事件events类似,每个物品items都是一段指令。基本格式如下:

  1. 某物品: MATERIAL 其它参数...

这个MATERIAL是物品ID,具体请参阅这个列表。ID不一定要全大写。”其它参数“包括定义物品名字、备注、附魔、药效等等的参数,这些参数分为两大类:1.通用的,可用来定义全部物品;2.只针对某些物品的。例如name所有物品都可以定义,而text则只针对书本

每一个参数都有两种用法:在创造物品的时候,或在检查物品是否具有某些参数的时候。第一种情况非常直截了当——BetonQuest会完全按照你的参数定义并创造出这个物品;第二种情况就有点复杂了,你可以检查某个物品,必须具有某些属性且不能有另一些属性,或干脆不管有没有另一些属性,你还可以检查某个属性的值(比如附魔级别)是否大于/小于x

下列是全部物品都通用的参数:

  • name - 物品的名字。名字中的下划线会被显示成空格,你还可以使用&彩色代码。如果你要检查某个没有名字的物品(kj:连Minecraft自带的名字都不显示?),你可以使用name:none要求某个物品没有任何名字。
  • lore - 物品名字下面的备注。这段文字格式默认是紫色斜体的。备注中的下划线都会被显示成空格,你还可以使用&彩色代码。如果需要换行请使用英文分号;字符。如果你要检查某个没有任何备注的物品,请使用name:none关键字求某个物品没有任何备注。在匹配/检查备注的时候,默认情况下要求每一行文字都能一一对应才行。如果你只是想检查整段备注里是否包含某一行文字,你可以在指令的后面加上lore-containing参数。
  • data - 物品附加值。例如不同颜色的羊毛,或镐子的损坏度。查找的时候你可以匹配完全一致的某个数字,或大于/小于某个数,在数字的后面加上+/-就可以了。
  • enchants - 附魔列表和对应的级别。每个附魔都需要包含下面这些信息,用冒号分隔:
    > name附魔名称
    > level附魔级别(正整数)
    格式是name:level。举个例子,damage_all:3锋利 III。你可以同时定义多个附魔,每样附魔之间用英文句号.分隔开。
    你可以填写none要求某个物品没有任何附魔。你还可以在后面加上+/-去检查某样附魔的级别是否大于/小于一定值。如果你不在意等级,可以用?代替数字部分。
    默认情况下所有附魔都会被匹配上。如果你只是想检查这个物品是否具有某一些附魔,请在最后加上enchants-containing参数。如果你想检查某个物品是否包含某样附魔,请在附魔名字的前面加上none-,比如enchants:none-knockback:?表示这个物品不能有击退附魔。
    请不要在没有enchants-containing的情况下使用none-,这并不符合逻辑而且会破坏检查过程。
  • unbreakable - 加上这个参数表示这个物品无法破坏。你可以直接写unbreakable或者是unbreakable:true来检查某个物品是否无法破坏。如果你想检查某个物品是否可以破坏,请使用unbreakable:false

一些例子:

name:&4空心水泥剑
name:none
lore:&c只有这把剑才可以捅死_Lord_Ruler
lore:&2任务专属物品
lore:none
data:5
data:500-
enchants:damage_all:3+,none-knockback
enchants:power:? enchants-containing
enchants:none
unbreakable
unbreakable:false



下列是只针对某些物品的参数:

下面的参数适用于以及书与笔

  • title - 书的标题。下划线都会显示为空格,你还可以使用&颜色代码。如果你需要这书没有标题,请填写none
  • author - 书的作者。下划线都会显示为空格,你还可以使用&颜色代码。如果你需要这书没有作者,请填写none
  • text - 书的内容。下划线都会显示为空格,你还可以使用&颜色代码。如果内容超过config.yml中的journal.chars_per_page规定,文字就会被自动分段成多页。如果你想自动分页,请使用|字符。换行请用\n。请留意你不可以在文字中输入空格,如果你需要文字显示空格,请使用下划线代替(_)。这是个单一参数,无论它有多长。如果你需要这书没有任何内容,请填写none

一些例子:

title:Malleus_Maleficarum
author:&eGallus_Anonymus
text:Lorem_ipsum_dolor_sit_amet,\nconsectetur_adipiscing_elit.|Pellentesque_ligula_urna(...)

下面的参数适用于药水噴溅型药水、和滞留型药水

  • type - 药水类型。具体名字请参阅药水列表。请不要和自制药水搞混,这必须是Minecraft原版自带的药水。
  • extended - 长效(在游戏里你通过添加红石获得,夜视(8:00)之于夜视(3:00))。可以是extendedextended:true。如果你想检查某个药水是长效型,请使用extended:false
  • upgraded - 高级(在游戏里你通过添加荧石获得,瞬间伤害II之于瞬间伤害)。可以是upgradedupgraded:true。如果你想检查某个药水是高级的,请使用upgraded:false
  • effects - 自定义药效列表。独立于上面的药水类型。药效之间必须用英文逗号,分隔。每一种药效都需要包含下面这些东西,且用英文冒号:隔开:
    > 药效名称(这个和上面的药水类型不一样!)
    > 时长(秒)
    > 强度
    一个例子是WITHER:2:30,表示30秒的凋灵II药效。
    如果你只想检查没有任何自定义药效的药水,请填写none。你还可以检查药效的等级或时长大于/小于(或等于)某个值,只需要在后面加上+/-即可。如果你不在意等级/时长,可以用?代替。
    默认情况下所有药效都会被匹配。如果你只是想检查这个药水是否具有某种药效,请在最后加上effects-containing参数。如果你想确认某个药水是否包含某种药效,请在药效的前面加上none-前缀。
    请不要在没有effects-containing的情况下使用none-,这并不符合逻辑而且会破坏检查过程。

一些例子:

type:instant_heal
extended
upgraded:false
effects:poison:1+:?,slow:?:45-
effects:none-weakness,invisibility:?:? effects-containing

下面的参数只适用于人类头颅

  • owner - 对应玩家的名字。不像上面的物品,颜色代码和下划线都不会起作用。如果你想检查没有对应玩家的头颅,请填写none

一些例子:

owner:Co0sh
owner:none

下面的参数适用于一切皮革装备

  • color - 皮革装备的颜色。它的值可以是具体的颜色名字,或者是以#开头的RGB颜色代码,亦或者是一个十进制数字。如果你需要这皮革装备没有指定颜色,请填写none

一些例子:

color:light_blue
color:#ff00ff
color:none

下面的参数适用于烟花火箭

  • firework - 一系列火箭特效。火箭特效之间用英文逗号,分隔。每一样特效都需要包含下面这些属性且用英文冒号:隔开:
    • 主颜色列表 - 具体格式请参考上面的皮革装备,每样颜色用英文分号;分隔。
    • 渐变颜色列表
    • true/false - 是否有拖痕(钻石效果)
    • true/false - 是否闪烁(荧石粉效果)

请特别留意分隔符号:1.英文逗号用来分隔每一样特效2.英文冒号分隔各种属性3.英文分号用来分隔特效的颜色。

如果你想检查某个没有任何//特效//的火箭,请填写''none''。如果你不在意特效的类型,可以用''?''代替。如果你想检查没有主/渐变颜色的火箭,请填写''none''。如果你不在意主/渐变颜色是啥,可以用''?''代替。如果你不在意有没有拖痕/闪烁,可以用''?''代替true/false。

默认情况下整个//特效//列表会被完全匹配。如果你只是想检查这个火箭是否具有某些//特效//,请在最后加上''firework-containing''。如果你想确认某个火箭是否__不__包含某种特效,请在//火箭特效//名字的前面加上''none-''。

//__请不要在没有''firework-containing''的情况下使用''none-''__//,这并不符合逻辑而且会破坏检查过程。
* ''power'' - 飞行时长,等级。你可以检查//飞行时长//是否大于/小于(等于)某个等级,只需要在数字后面加上''+''/''-''即可。

一些例子:

firework:ball:red;white:green;blue:true:true,ball_large:green;yellow:pink;black:false:false
firework:burst:?:none:?:? firework-containing
firework:none-creeper firework-containing
firework:none
power:3
power:2+

下面的参数适用于烟火之星

  • firework - 和上面的烟花火箭差不多,不过你只能定义一个effect,并且没有power参数。

有时候你想要某些东西在玩家死后依然保留在背包中,比如这些东西是完成整个任务的关键。你可以给这个任务物品添加这个lore让这个物品不会消失:&2任务物品(请注意这个lore必须是单独的一行),这样这个物品就不会因为玩家死亡而掉落。

例子:

  1. 神剑: 'DIAMOND_SWORD name:毁灭之刃_凝结神力 lore:用秘银锻造的大剑;&2任务物品'

(kj译注:这个&2任务物品根据你的语言设置不同而不同,如果你的config.yml语言设置是language: en英语,则需要写成&2Quest_Item,具体请看你的config.ymlmessages.yml文件)

如需打开背包,请输入指令/backpack。输入之后一个GUI就会显示,里面有你的任务物品和一些任务相关按钮。第一个物品永远是你的任务日志,取走之后这个位置会一直留空。你可以通过点击这些物品,让这些物品在背包和你的物品栏之间移动,左键移动一个物品,右键移动全部物品。只有任务相关物品才可以存入背包

如果背包中的任务物品超过一页,那么下面就会显示“下一页”按钮。你可以自定义这些按钮,在items.yml分别创建两个名为previous_button表示上一页、next_button表示下一页的物品即可,按钮的实际显示名字会被messages.yml覆盖。

任务物品只能被使用掉,而不能丢弃。你可以利用这个特性去创建一个吃饼干大赛,玩家必须吃完全部饼干才算完成任务,而不能偷偷丢掉它们。

如果你发现在创造模式下任务物品还是可以丢地上,别担心,因为这不是bug,是特性,方便你在设计任务的时候把物品放入宝箱中。

团队party是个很简单的概念,如果你已经接触过一些mmoRPG那么这个对你来说不会有什么难度。使用的时候也不需要提前创建,只需要在条件conditions事件events指令中直接定义即可(请参阅“party”条件“party”事件)。这样的指令通常第一个参数是半径,也就是团队成员所在的范围大小;第二个参数是条件conditions列表,只有满足列表要求的玩家才会被当作团队成员。条件判断是全自动的,玩家不需要做什么特别的事情(不需要输入指令、不需要GUI,只需要开始任务或拥有某个特殊物品即可),你可以通过这个来确定团队形成的条件。

为了更好地理解团队party具体是怎么工作的,我们举一个例子来讲解。首先我们让每一个玩家都启动一个按按钮的任务目标objectives,当有人按下按钮之后,就触发下面这个事件

  1. party_reward: party 50 quest_started cancel_button,teleport_to_dungeon

那么这个时候,在场的所有玩家只要他:1、在这个按了按钮的玩家的半径50范围内,并且2、满足quest_started条件的人,就会自动在他们身上触发cancel_buttonteleport_to_dungeon事件。在这个例子中,cancel_button是我们自定义的一个事件event,用来取消这些玩家的“按按钮任务目标”(因为不再需要了);第二个teleport_to_dungeon则是把这些满足条件的玩家统统传送到副本里。

假设这个按钮在一个副本准备室里,大小只有50×50。上面那么做的好处是,只有在这房间里(50米内)的玩家才会在有人按按钮之后被传送进副本。与此同时外面的玩家则不受影响,因为他们并不在50m的范围内,而且这些范围外的玩家也可以自己组队进个房间然后按按钮传送进副本。需要注意的是,没有满足quest_started(没有开始这个任务)的玩家即使在50m范围内也不会被传输进副本,因为他们不满足上面那个事件中规定的条件。

当你需要在脚本中指明/选择某种方块的时候,你需要用到“方块选择器Block Selectors”。但由于Minecraft更改物品ID的缘故,方块选择的格式在1.13之前和之后的版本会略有不同:

基本格式为: material:data

其中:

  • material - 方块的材质。你可以在这个列表搜索你要的材质。
  • data - (可选)方块的副ID。如果为空则默认无视副ID(不管副ID是啥都算匹配得上)。

例如:

  • LOG - 匹配一切类型的“原木”
  • LOG:1 - 只匹配“杉木原木”

基本格式为: prefix:material[state=数值,…]

其中:

  • prefix - (可选)材质的前缀。如果不填/留空则默认为“minecraft”
  • material - 方块的材质。你可以在这个列表搜索你要的材质。注意从1.13版开始BetonQuest支持通配符(* 和 ?),详见下面的例子。
  • state - (可选)方块状态,你可以在方括号中指定每一种方块状态并且用英文逗号隔开,请看这个列表搜索你想指定的方块状态。如果留空则不匹配任何状态。

例如:

  • minecraft:stone - 匹配所有的“石头” STONE 方块
  • redstone_wire - 匹配所有“红石粉(红石线路)” REDSTONE_WIRE 方块
  • redstone_wire[power=5] - 匹配“红石粉(红石线路)” REDSTONE_WIRE 方块,并且要求方块的充能等级=5
  • redstone_wire[power=5,north=none] - 匹配“红石粉(红石线路)” REDSTONE_WIRE 方块,并且要求方块的充能等级=5、没有和北边有任何连接
  • *_LOG - 匹配一切“原木”方块
  • * - 匹配一切(任意一种)方块
  • *[waterlogged=true] - 匹配一切泡在水中的方块
  • 插件手册/betonquest/基本概念.txt
  • 最后更改: 2020/11/15 12:42
  • 小小k酱