====== 基本概念参考 Reference ====== (版本:2017-04-03 翻译:kjiang [[https://github.com/Co0sh/BetonQuest/wiki/Reference/837a327deaa3fc6f804ed71ff7d07bafaad334ae|原文链接]]) 本章节详细描述了BetonQuest的各个方面。你应当阅读本文档至少一遍以上,这有助于在你遇到问题的时候该如何搜索信息,并帮助你更好地处理遇到的问题。 ===== 对话脚本 Conversations ===== 每个对话都必须定义一个NPC名字(某些对话可以不关联到NPC身上,所以即使NPC有名字了也要把他的名字写在这里),以及初始对话。 quester: Name first: option1, option2 stop: 'true' final_events: event1, event2 NPC_options: option1: text: Some text in default language events: event3, event4 conditions: condition1, !condition2 pointers: reply1, reply2 option2: text: '&3This ends the conversation' player_options: reply1: text: en: Text in English pl: Tekst po polsku event: event5 condition: '!condition3' pointer: option2 reply2: text: 'Text containing '' character' 注解 1://配置文件使用YAML语法作为基本格式。如果你不知道这是啥你应该先百度/谷歌一遍基本概念。//一些基本规则是: - 你需要**使用两个空格而不是tab键**来为层级树排版 - 其次你需要注意一些特殊字符,比如当你需要在对话/文字内容中使用单引号''%%'%%''的时候,你应用两个''%%''%%''而不是一个 - 当需要写”true“和”false“的时候你需要用引号把它套起来比如''%%'true'%%'' - 如果你需要以''&''作为开头的时候,整句话都需要用单引号套起来比如''%%'&c你好,很高兴认识你'%%'' - (kj译注)另外你必须注意,一切冒号都必须使用**英文半角冒号**'':''而不是中文冒号”:“,并且冒号和文字内容之间**必须有空格**! - 如果你不确定你的yaml配置文件是否符合语法规定,你可以使用[[https://yamlvalidator.com/|这个工具]]检查。 * ''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不满足),对话会直接结束。如果你在测试脚本的时候发现对话无缘无故结束了,记得检查一下服务器控制台,有可能是你的配置文件写得不对。 这个文件在编写/阅读的时候多少会有点令人迷惑,所以你在给每个对话选项命名的时候都应该留个心,要明白你将来还能理解它是什么意思。不过不要过分担心,如果你真的写错了什么,测试的时候插件会在服务器控制台告诉你什么地方错了。另外,认真分析一下那个插件自带的默认对话脚本,会对你完全理解分析这个插件有巨大帮助。 ==== 跨对话脚本链接 Cross-conversation Pointers ==== 如果你想要将某个对话和另一个NPC的对话脚本链接,或将一个复杂庞大的对话脚本拆分成多个小的、更专注于某个领域的脚本,你可以将对话内容指向另一个脚本里的选项。实现这个你只需要将pointers写成''conversation.npc_option''这样的形式。 需要注意的是,你只可以将pointers指向NPC选项。也就是说这样的pointers只能写在''first''里作为对话开始的可选项,或**玩家对话的''pointers''**(player_optoins)里。如果你把跨脚本链接写在NPC对话(NPC_options)里,则会报错。 ==== 对话脚本变量 Conversation Variables ==== 你可以在对话脚本中使用各种//变量Variables//。这些变量会被解析为某个值然后在对话中显示出来。一个变量通常看起来是这样的:''%type.optional.arguments%'',''type''是必须的参数,它定义了这个是什么类型的参数。可选参数由这个变量类型决定,例如''%npc%''并没有任何可选参数,而''%player%''就会有“display”这个可选参数(比如''%player.display%'')。关于变量的更多信息你可以通过[[插件手册:betonquest:变量列表|变量列表]]章节了解更多。 如果你错误地使用了某个//变量//(比如当你尝试获取某个//任务目标objective//的//属性properties//而这个//任务目标//并未被玩家启动,或你想在''message''事件中使用''%npc%''参数时),那么这个变量会啥也不显示('''')。 ==== 对话翻译 Translations ==== 在默认的对话脚本中,对话内容还包含了其它语言。你可以把对话内容翻译成各种语言,玩家可以通过''/questlang''指令选择他想要显示的语言。另外,你还可以翻译NPC/任务的名字,你只需要: quester: en: Innkeeper cn: 旅馆老板 pl: Karczmarz de: Gastwirt 请注意yaml的语法格式。另外玩家只能选择//messages.yml//中的语言,如果并没有这个语言,对话和选项则会以//config.yml//规定的默认语言显示。如果连默认语言也没有,那么BetonQuest则会报错。 你还可以翻译//任务日志journal//内容、//取消任务//、和''message''event的内容。关于这部分在本文后段会有介绍。 ==== 对话显示 Conversation Displaying ==== 默认情况下BetonQuest会使用最原始可靠的文字方式直接展示对话内容。玩家通过在聊天栏输入代号来选择选项。你也可以通过//config.yml//中的''default_conversation_IO''设置来更改对话展示方式。此设置默认值是''simple'',当更改为''tellraw''的时候,玩家可以直接点击文字选项(而不用在聊天栏打数字)。请注意,点击有的时候会因为聊天信息滚动过快导致玩家点错选项。你还可以设置为''chest'',这样对话内容就会以箱子GUI的形式展示,NPC的对话和玩家选项都会变成可点击的物品按钮。 你可以通过//config.yml//的''conversation_colors''设置,来控制对话的颜色。你必须写颜色的英文名字而不是代码。 如果你使用''chest''作为对话展示的方式,你可以修改按钮为其它物品。默认按钮使用//末影珍珠Ender Pearl//作为按钮。只需要在对话内容的前面加上特定前缀即可,例如''{diamond_sword}我想开启这个任务!''或者''{wool:10}紫色!'',物品id为Minecraft格式。 ==== 对话继承 Extends ==== (kj译注:此功能暂不兼容BetonQuest Editor)自BetonQuest 1.11版开始,对话脚本支持“继承”功能。对话选项中如果有''extends''设置项,那么''extends''指向的内容都回被合并到这个对话选项中。BetonQuest会检测死循环(循环指向)。 NPC_options: ## 对话开始 对话开始: text: '你好啊' extends: 见过面, 主菜单 ## 译注:被extends的这部分必须加到原对话的后面 好像见过: text: ',我们昨天好像见过面?' condition: 见过了 ## 主菜单 主菜单: pointers: 问你个事, 再见 在上面的例子中,对话选项''开始对话''会把''好像见过''的文字加到原始对话的后面,并且把''主菜单''的选项都包含进来。所以就相当于: NPC_options: ## 对话开始 对话开始: text: '你好啊,我们昨天好像见过面?' condition: 见过了 pointers: 问你个事, 再见 如果你能好好利用这个功能,它可以帮你缩短对话脚本。 ---- //conditions//、//events//、和//objectives//中的内容被定义为“指令字符”,它们是以一定格式编写的、包含具体//条件/事件/任务目标//的文字。若想要更好地编写这些指令,你需要参阅下面的章节还有其它几个页面,那些章节介详细绍了这些指令字符的具体作用和用法。这些指令字符的具体内容都需要在特定的文件中预先设定,比如//条件conditions//的内容则在//conditions.yml//配置文件中定义。它的格式类似于''%%name: 'the instruction string containing the data'%%'',单引号是可选的,具体请百度/谷歌“YAML格式”。 ===== 条件 Conditions ===== //条件conditions//在创建高级任务过程中是最常用的,它可以让你控制什么选项可以展现给玩家、NPC如何对玩家作出反馈、或//任务目标objective//什么时候才算完成。完整的条件列表请参阅[[插件手册:betonquest:条件列表|条件列表]]。 你可以通过在//条件conditions//前面加上''!''来让它们的意思反过来(注意不是中文输入法的“!”),记得感叹号只能用在对话脚本里而不是//conditions.yml//中。 你可以在事件中使用//变量variables//而不一定要输入数字,如果这个//变量//无法解析(比如这个变量返回空白的时候),BetonQuest则会把它当作0。 ===== 事件 Events ===== 在某些时候你可能需要让某些事情发生。比如更新任务日志(journal)、设置标签(tag)、给予奖励,这些东西都可以通过//事件events//实现。定义它们就和上面的//条件conditions//一样,在//events.yml//中,一个名字冒号再加上指令字符。具体可定义的//事件//指令字符请参阅[[插件手册:betonquest:事件列表|事件列表]]。每一个//事件//字符后面都可以加上''conditions:''/''condition:''作为限制条件,比如''conditions:angry,!quest_started''意即这个//事件//只会在这些//条件//都满足的情况下启动。 你可以在事件中使用//变量variables//而不一定要输入数字,如果这个//变量//无法解析(比如这个变量返回空白的时候),BetonQuest则会把它当作0。 ===== 任务目标 Objectives ===== 在创建复杂任务的时候,//任务目标objectives//是你需要经常接触的部分。玩家通过''objective''//事件events//来启动//任务目标//。就像其它//事件//一样,具体的任务目标要在//objectives.yml//中定义(请参阅[[插件手册:betonquest:任务目标|任务目标列表 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。 ---- ===== 脚本包 Packages ===== 你所创建的一切内容都要按照//脚本包//分类存放。每一个脚本包必须包含一个//main.yml//文件,包中还可以包含一个存放对话脚本的//conversations//文件夹、//events.yml//、//conditions.yml//、//objectives.yml//、//items.yml//、以及//journal.yml//文件。BetonQuest必须有一个叫“default”的//包//(就是存放默认任务的那个文件夹),如果你删掉它,BetonQuest会再生成一个。 如果你不介意混乱,你可以把全部任务都一股脑丢到“default”里面。这样你总有一天会遇到每个配置文件都上百行而你找不到你要改的地方在哪儿的窘境。因此分们别类存放你的脚本绝对是个非常好的习惯,比如用文件夹“主城”用来储存主城的任务、“副本”则可以存放一些有趣的副本任务,等等。 每个//脚本包//都可以通过各自的//main.yml//文件单独启用/禁用,你只需要设置''enabled''为''true''或''false''。 如果//任务包//与//任务包//之间不能互相访问就太限制人了,因此你可以通过//包//的前缀和名字去访问别的//包//的内容。比如你在为包''quest1''编写对话脚本,此时你想触发另一个包''quest2''的''reward''事件,你只需要写''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 包含了这些//脚本包//: - //default// - //quests-village1-quest1// - //quests-village1-quest2// - //quests-village2-quest1// - //quests-village3// (kjiang译注)实测这些文件夹和//脚本包//都可以用中文命名,路径可以使用中文,方便中文用户使用。如: BetonQuest/ ├─default/ └─国家1/ ├─村庄1/ │ ├─任务1/ │ │ └─main.yml │ └─任务2/ │ └─main.yml └─村庄2/ └─任务1/ └─main.yml - //default// - //国家1-村庄1-任务1// - //国家1-村庄1-任务2// - //国家1-村庄2-任务1// ==== 相对路径 Relative Paths ==== 在跨包访问的时候,你并不一定非要输入包的全名不可。在上面的例子中,如果你想要在“quests-village1-quest1”之中引用另一个包“quests-village1-quest2”的内容,你可以就写''_-quest2''。这个的意思是:从这个包(quest1)开始,后退一个目录,然后找到包”quest2“。路径里面的这个''_''有非常特殊的意思。同样的,如果你想引用”quests-village2-quest1“这个包的内容,你可以输入''_-_-village2-quest1'',输入两次''_''会让你后退两次,接着插件就会进入”village2“目录然后是”quest1“包。 当你想在多个包之间来回引用的时候,//相对路径//会相当有用。不用每次都把整个路径都打上,你只需要把//相对路径//打出来就好了。例如你有许多个包而且需要移动这个文件夹的时候,或是在你使用[[https://sellfy.com/p/nE5Y/|BetonQuest-Editor]]和BetonQuestUploader工具的时候,你就用每次都把一长串完整路径都打出来。(BetonQuest-Editor的相对路径支持会在未来升级后提供)。 ===== 统一坐标格式 Unified Location Formating ===== 当你需要在某些//事件//、//条件//、//任务目标//中用到坐标位置的时候,你需要以一个固定的格式定义定义它们。一般坐标包含两部分内容:**基准坐标base**和**向量vector**,只有基准坐标是必须的。 基准坐标是一切坐标的核心,目前包含两类:**绝对坐标**和**坐标变量**。 **绝对坐标**的格式类似''100;200;300;world'',这里''100''是x坐标值、''200''是Y、''300''是Z、而''world''则是世界,你可以输入小数,在最后你可以加上可选的//偏角yaw//和//仰角pitch//决定头应该看向哪儿(例如:''0.5;64;0.5;world;90;-270'')。 某些情况下你也可以使用**坐标变量**而不需要自己输入坐标值。例,如果你需要提取玩家所在坐标,你可以输入''%location%'',它会被解析成实际坐标值。但有一点需要注意:你不可以在玩家不在线的时候使用这个变量(例如在玩家离线后执行的//[[插件手册:betonquest:事件列表#事件包folder|事件包folder事件]]//或某些//[[插件手册:betonquest:基本概念#静态事件_static_events|静态事件]]//。),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 ===== 你可以在编写//事件//、//条件//、或//任务目标//指令的时候把//全局变量 global variables//作为值填进去。全局变量是类似这样的东西:''$beton$''(这个变量的名字就是”beton“)。当插件加载脚本的时候,这个变量会被替换成//main.yml//中定义的实际值,而**不是**在执行脚本的时候。 variables: 村庄坐标: 100;200;300;world 村庄名字: Concrete 如果你需要在脚本中重复输入多次某个固定值(比如某个WorldEdit schematic),那么使用全局变量会变得很方便。你只需要打几个字就行,而不需要输入一长串的坐标、名字、甚至一大段文本(当然,是在剧本作者合理利用的情况下,内容非常短的名字就没必要用变量了)。 请注意//全局变量//和//对话脚本//中用到的变量是完全不一样的概念:全局变量使用''$''而对话变量使用''%'';全局变量是在脚本执行之前就被替换成实际值,而对话变量会在脚本执行过程中变换,并且具体是和玩家有关联的。 ===== 取消任务 Canceling Quests ===== 有个功能可以让玩家取消一个正在进行中的任务。在//main.yml//中有一个''cancel''的分支,在这里定义什么任务可以被取消,以及取消的时候需要做什么。请参照默认的''default''包里面的自带任务作为参考例子。你可以定义的参数是: * ''name'' - 这会被作为名字显示在玩家的//背包backpack//中。名字中的下划线''_''都会被显示成空格。如果你想显示多语言,你也可以在这里添加(''en''英文这样)。 * ''conditions'' - //条件conditions//列表,用英文逗号分隔。如果玩家要取消这个任务,他要先满足列表中的这些条件。你可以用这个来判断玩家已经开始了这个任务(比如判断有没有什么//标签tags//),但并没有完成。 * ''objectives'' - 需要取消的//任务目标objectives//列表。 * ''tags'' - 需要删除的//标签tags//列表。 * ''points'' - 需要删除的//积分points//列表。 * ''journal'' - 需要取消的//任务日志journal//记录。 * ''events'' - 如果你想在取消任务的时候触发另一些事件(比如给予玩家惩罚),请在这里列出。 * ''loc'' - 可以在取消任务的时候把玩家传送到某个地方。这相当于触发一个[[插件手册:betonquest:事件列表#传送teleport|传送事件]]。 如果玩家要取消一个任务,他需要打开他的//背包backpack//(/backpack)然后点击“取消”按钮(默认是个骨头图标,如需自定义你可以在//items.yml//中创建一个名为“cancel_button”的物品)。点击之后就会显示一系列可以被取消的任务。 ===== 全局任务目标 Global Objectives ===== 如果你想制作一个对所有玩家都有效的任务目标,无论玩家有没有开启,你可以通过“全局目标”实现。在普通的任务目标指令(objectives.yml中的指令)末尾加上''global''参数,那么这个任务目标就会对所有进入游戏的玩家生效。每次玩家加入服务器的时候,都会自动启动这个任务目标。 但为了避免这个任务目标在玩家每次加入服务器的时候被重复启动,系统还会给启动过这个任务目标的玩家添加一个tag,只要玩家有这个tag在身上,就不会重复启动这个任务目标。这个tag的格式是''.global-'',其中''''是任务目标的id(如下例中是“start_quest_mine”),''''是该任务目标所在的objectives.yml的脚本包路径。(kj译注)如果你需要这个任务目标可以被重复完成,你应该在末尾添加''persistent''参数,而不是删除global tag! 你可以利用这个设计出诸如在固定地点启动某些事件,或破坏某些特定方块后触发奖励的功能。 start_quest_mine: 'location 100;200;300;world 5 events:start_quest_mine_folder global' ===== 静态事件 Static Events ===== //静态事件static events//是指可以在一天中某个时刻自动触发的事件。这些//事件//不与玩家关联,所以类似于''tag''这样关系到玩家的事件就不属于静态事件。并且,静态事件没有//条件//一说,因为检查条件的时候会涉及到具体某个玩家。在[[插件手册:betonquest:事件列表|事件列表]]中的一切//静态事件//都会用**static**特别标注。如需在固定时间发动静态事件,可以在//main.yml//的''static''分支写上类似这样的内容: static: '09:00': beton '23:59': lightning_strike '11:23': some_command 注意时间必须用''%%' '%%''套起来才符合YAML格式要求。如果小时小于10则需要在前面补上”0“。''beton''、''lightnint_strike''这些都是来自于''events.yml''的事件。每一条只能写一个//事件//,如果你需要同时触发多个事件你可以使用[[插件手册:betonquest:事件列表#事件包folder|”事件包folder“]]。 ===== 任务日志 Journal ===== 日志是一本记录你所有冒险历程的书。你可以输入**/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.ym//l的''journal_colors''部分中控制日记中的颜色:''date''是每个条目的日期颜色,''line''是条目分割线的颜色,''text''是文本的颜色。 您需要使用不带''&''的标准颜色代码(如:''4''表示深红色)。 您还可以将主页添加到日记中。 这是一个文本列表,仅在满足指定条件时显示。 您可以在//main.yml//文件的''journal_main_page''部分中定义它们: journal_main_page: title: priority: 1 text: en: '&eThe Journal' pl: '&eDziennik' conditions: 'quest_started,!quest_completed' 每个字符串可以有不同语言的文本,条件列表用逗号分割(这些条件必须满足日志中显示的文本)和优先级(''priority'')——它控制文本的顺序。你可以在文本中使用会话变量,但只有在玩家使用**/journal**命令获取日志时才会更新它们。支持颜色代码。 如果您希望主页采用单独的页面(条目将显示在下一个空页面上),将//config.yml//中的''full_main_page''设置为“true”。 ===== 标签 Tags ===== //标签tags//就是一小段用来在玩家身上做标记的文字,标记之后可以用来做检查/判断。在判断玩家是否开启/完成了某个任务的时候,//标签//是个很有用的工具。你可以通过''tag''//事件events//在玩家身上做标记,然后用''tag''//条件conditions//来检查玩家是否有这个标签。 关于路径问题,//标签//会和//脚本包packages//绑定。假如你在''default''包中添加了一个''beton''标签,那么这个标签的路径实际上就是''default.beton''。你可以把default包中的检查//事件//简写成''tag beton'',但实际上这个事件等效于''tag default.beton''。如果你要在别的//脚本包//里检查这个标签,注意标签的路径一定要写成完整的''default.beton''。 ===== 积分 Points ===== //积分//和上面的//标签//类似,只不过还带了数值。你可以把它当作任务的奖励发放给玩家、用在NPC问答中记分;你还可以扣分,甚至扣到负分。积分可以按类别命名划分,比如''讨伐次数''和''闯关次数'';积分还可以用来统计某个任务做了几次,或者建立声望系统统计玩家在某些部落之中的声望值等等。你可以检查玩家某项积分有没有达到/超过一定数值。具体操作请参阅[[插件手册:betonquest:事件列表#积分point|事件:积分]]和[[插件手册:betonquest:条件列表#积分point|条件:积分]]。 ===== NPC ===== //对话脚本conversations//可以关联到NPC身上。只需要修改//main.yml//中的”npcs“部分即可: npcs: '0': innkeeper '酒店老板': innkeeper 冒号左边的内容是NPC名字,右边是对应的//对话脚本//文件名。如果你使用的是[[插件手册:citizens:home|Citizens NPC]],那么左边可以是NPC名字或ID(编号)。如果你不使用或没安装Citizens,那么你依然可以用下面的方法来创建一个NPC: 随便在某个地方放置一个染色粘土块,颜色无所谓,然后在上方放置一个头颅方块(类型无所谓但必须是头颅),接着在粘土方块的侧面贴上告示牌,并在第一行写上''[NPC]'',第二行写NPC的ID(以上面为例,''酒店老板''),注意你必须有''betonquest.createnpc''权限才可以使用这个方法。现在恭喜你,你成功创建了一个NPC,现在你可以在两边插上拉杆(手)或者底部放个开着的栅栏门(腿)。开始对话只需右键它的头。 ===== 物品 Items ===== BetonQuest里面的所有物品都需要在//items.yml//文件里定义(kjiang译注:当你需要给予奖励、移除物品或检测背包的时候你不可以简单地填个物品id完事,必须提前在items.yml中定义),并且和//事件events//类似,每个//物品items//都是一段指令。基本格式如下: 某物品: MATERIAL 其它参数... 这个''MATERIAL''是物品ID,具体请参阅[[https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html|这个列表]]。ID不一定要全大写。”其它参数“包括定义物品名字、备注、附魔、药效等等的参数,这些参数分为两大类:1.通用的,可用来定义全部物品;2.只针对某些物品的。例如''name''所有物品都可以定义,而''text''则只针对//书本//。 每一个参数都有两种用法:在创造物品的时候,或在检查物品是否具有某些参数的时候。第一种情况非常直截了当——BetonQuest会完全按照你的参数定义并创造出这个物品;第二种情况就有点复杂了,你可以检查某个物品,必须具有某些属性且不能有另一些属性,或干脆不管有没有另一些属性,你还可以检查某个属性的值(比如附魔级别)是否大于/小于//x//。 下列是全部物品都通用的参数: * ''name'' - 物品的名字。名字中的下划线会被显示成空格,你还可以使用''&''彩色代码。如果你要检查某个没有名字的物品(kj:连Minecraft自带的名字都不显示?),你可以使用''name:none''要求某个物品没有任何名字。 * ''lore'' - 物品名字下面的备注。这段文字格式默认是紫色斜体的。备注中的下划线都会被显示成空格,你还可以使用''&''彩色代码。如果需要换行请使用英文分号'';''字符。如果你要检查某个没有任何备注的物品,请使用''name:none''关键字求某个物品没有任何备注。在匹配/检查备注的时候,默认情况下要求每一行文字都能一一对应才行。如果你只是想检查整段备注里是否包含某一行文字,你可以在//指令//的后面加上''lore-containing''参数。 * ''data'' - 物品附加值。例如不同颜色的羊毛,或镐子的损坏度。查找的时候你可以匹配完全一致的某个数字,或大于/小于某个数,在数字的后面加上''+''/''-''就可以了。 * ''enchants'' - 附魔列表和对应的级别。每个附魔都需要包含下面这些信息,用冒号分隔:\\ > ''name''[[https://hub.spigotmc.org/javadocs/spigot/org/bukkit/enchantments/Enchantment.html|附魔名称]] (你可以在这里[[插件手册:mythicmobs:物品:附魔|查阅汉化后的附魔列表]]) \\ > ''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 \\ \\ **//下列是只针对某些物品的参数://** ==== 书 Books ==== 下面的参数适用于//书//以及//书与笔//: * ''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(...) ==== 药水 Potions ==== 下面的参数适用于//药水//、//噴溅型药水//、和//滞留型药水// * ''type'' - //药水类型//。具体名字请参阅[[https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionType.html|药水列表]]。请不要和自制药水搞混,这必须是Minecraft原版自带的药水。 * ''extended'' - 长效(在游戏里你通过添加红石获得,//夜视(8:00)//之于//夜视(3:00)//)。可以是''extended''或''extended:true''。如果你想检查某个药水__不__是长效型,请使用''extended:false''。 * ''upgraded'' - 高级(在游戏里你通过添加荧石获得,//瞬间伤害II//之于//瞬间伤害//)。可以是''upgraded''或''upgraded:true''。如果你想检查某个药水__不__是高级的,请使用''upgraded:false''。 * ''effects'' - 自定义//药效//列表。独立于上面的药水类型。//药效//之间必须用英文逗号'',''分隔。每一种//药效//都需要包含下面这些东西,且用英文冒号'':''隔开:\\ > [[https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/potion/PotionEffectType.html|药效名称]](这个和上面的//药水类型//不一样!)\\ > 时长(秒)\\ > 强度\\ 一个例子是''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 ==== 头颅 Heads ==== 下面的参数只适用于//人类头颅// * ''owner'' - 对应玩家的名字。不像上面的物品,颜色代码和下划线都**不会**起作用。如果你想检查没有对应玩家的头颅,请填写''none''。 **一些例子**: owner:Co0sh owner:none ==== 皮革装备 Leather Armor ==== 下面的参数适用于一切//皮革装备// * ''color'' - 皮革装备的颜色。它的值可以是具体的[[https://hub.spigotmc.org/javadocs/spigot/org/bukkit/DyeColor.html|颜色名字]],或者是以''#''开头的RGB颜色代码,亦或者是一个十进制数字。如果你需要这//皮革装备//没有指定颜色,请填写''none''。 **一些例子**: color:light_blue color:#ff00ff color:none ==== 烟花火箭 Fireworks ==== 下面的参数适用于//烟花火箭// * ''firework'' - 一系列火箭特效。//火箭特效//之间用英文逗号'',''分隔。每一样//特效//都需要包含下面这些属性且用英文冒号'':''隔开: * [[https://hub.spigotmc.org/javadocs/spigot/org/bukkit/FireworkEffect.Type.html|火箭特效]]名字 * 主颜色列表 - 具体格式请参考上面的//皮革装备//,每样颜色用英文分号'';''分隔。 * 渐变颜色列表 * ''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 charges ==== 下面的参数适用于//烟火之星// * ''firework'' - 和上面的烟花火箭差不多,不过你只能定义一个''effect'',并且没有''power''参数。 ===== 背包 Backpack ===== 有时候你想要某些东西在玩家死后依然保留在背包中,比如这些东西是完成整个任务的关键。你可以给这个任务物品添加这个lore让这个物品不会消失:''&2任务物品''(请注意这个lore必须是单独的一行),这样这个物品就不会因为玩家死亡而掉落。 **例子:** 神剑: 'DIAMOND_SWORD name:毁灭之刃_凝结神力 lore:用秘银锻造的大剑;&2任务物品' (kj译注:这个''&2任务物品''根据你的语言设置不同而不同,如果你的//config.yml//语言设置是''language: en''英语,则需要写成''&2Quest_Item'',具体请看你的//config.yml//和//messages.yml//文件) 如需打开背包,请输入指令**/backpack**。输入之后一个GUI就会显示,里面有你的任务物品和一些任务相关按钮。第一个物品永远是你的任务日志,取走之后这个位置会一直留空。你可以通过点击这些物品,让这些物品在//背包//和你的物品栏之间移动,左键移动一个物品,右键移动全部物品。只有任务相关物品才可以存入//背包//。 如果//背包//中的任务物品超过一页,那么下面就会显示“下一页”按钮。你可以自定义这些按钮,在//items.yml//分别创建两个名为''previous_button''表示上一页、''next_button''表示下一页的物品即可,按钮的实际显示名字会被//messages.yml//覆盖。 任务物品只能被使用掉,而不能丢弃。你可以利用这个特性去创建一个吃饼干大赛,玩家必须吃完全部饼干才算完成任务,而不能偷偷丢掉它们。 如果你发现在创造模式下任务物品还是可以丢地上,别担心,因为这不是bug,是特性,方便你在设计任务的时候把物品放入宝箱中。 ===== 团队 Party ===== //团队party//是个很简单的概念,如果你已经接触过一些mmoRPG那么这个对你来说不会有什么难度。使用的时候也不需要提前创建,只需要在//条件conditions//或//事件events//指令中直接定义即可(请参阅[[插件手册:betonquest:条件列表#团队party|“party”条件]]或[[插件手册:betonquest:事件列表#团队party|“party”事件]])。这样的指令通常第一个参数是半径,也就是团队成员所在的范围大小;第二个参数是//条件conditions//列表,只有满足列表要求的玩家才会被当作团队成员。条件判断是全自动的,玩家不需要做什么特别的事情(不需要输入指令、不需要GUI,只需要开始任务或拥有某个特殊物品即可),你可以通过这个来确定团队形成的条件。 为了更好地理解//团队party//具体是怎么工作的,我们举一个例子来讲解。首先我们让每一个玩家都启动一个按按钮的//任务目标objectives//,当有人按下按钮之后,就触发下面这个//事件//: party_reward: party 50 quest_started cancel_button,teleport_to_dungeon 那么这个时候,在场的所有玩家只要他:1、在这个按了按钮的玩家的半径50范围内,并且2、满足''quest_started''条件的人,就会自动在他们身上触发''cancel_button''和''teleport_to_dungeon''事件。在这个例子中,''cancel_button''是我们自定义的一个//事件event//,用来取消这些玩家的“按按钮//任务目标//”(因为不再需要了);第二个''teleport_to_dungeon''则是把这些满足条件的玩家统统传送到副本里。 假设这个按钮在一个副本准备室里,大小只有50x50。上面那么做的好处是,只有在这房间里(50米内)的玩家才会在有人按按钮之后被传送进副本。与此同时外面的玩家则不受影响,因为他们并不在50m的范围内,而且这些范围外的玩家也可以自己组队进个房间然后按按钮传送进副本。需要注意的是,没有满足''quest_started''(没有开始这个任务)的玩家即使在50m范围内也不会被传输进副本,因为他们不满足上面那个//事件//中规定的条件。 ===== 方块选择 Block Selectors ===== 当你需要在脚本中指明/选择某种方块的时候,你需要用到“方块选择器Block Selectors”。但由于Minecraft更改物品ID的缘故,方块选择的格式在1.13之前和之后的版本会略有不同: ==== 1.12 及以下 ==== 基本格式为: ''material:data'' 其中: * ''material'' - 方块的材质。你可以在[[https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html|这个列表]]搜索你要的材质。 * ''data'' - (可选)方块的副ID。如果为空则默认无视副ID(不管副ID是啥都算匹配得上)。 例如: * ''LOG'' - 匹配一切类型的“原木” * ''LOG:1'' - 只匹配“杉木原木” ==== 1.13 及以上 ==== 基本格式为: ''prefix:material[state=数值,...]'' 其中: * ''prefix'' - (可选)材质的前缀。如果不填/留空则默认为“minecraft” * ''material'' - 方块的材质。你可以在[[https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html|这个列表]]搜索你要的材质。注意从1.13版开始BetonQuest支持通配符(* 和 ?),详见下面的例子。 * ''state'' - (可选)[[https://minecraft-zh.gamepedia.com/%E6%96%B9%E5%9D%97%E7%8A%B6%E6%80%81|方块状态]],你可以在方括号中指定每一种方块状态并且用英文逗号隔开,请看[[https://minecraft-zh.gamepedia.com/%E6%96%B9%E5%9D%97%E7%8A%B6%E6%80%81|这个列表]]搜索你想指定的方块状态。如果留空则不匹配任何状态。 例如: * ''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]'' - 匹配一切泡在水中的方块