====== 快速教程 Quick Start Tutorial ====== (版本:2018-10-16 翻译:kjiang [[https://github.com/Co0sh/BetonQuest/blob/b18b2b1521d79e3020864808f1d5c59f39f28361/docs/04-Quick-start-tutorial.md|原文链接]]) (为方便理解,本文和原文有出入) 成功安装完BetonQuest之后,你一定想先了解这个插件是怎么运作的吧?不过首先,如果你想修改对话展示方式,比如从文字该城GUI,你可以修改__config.yml__中的设置,把''default_conversation_IO''修改成''chest'',然后输入**/q reload**重载配置。 BetonQuest在成功安装之后,会默认自带一个叫Innkeeper的简单任务。如果需要在服务器中启用这个任务,你首先需要创建一个NPC,这里有两种创建方法: * 如果你没有安装Citizens: - 首先进入你的服务器,然后在地上摆放一个粘土块 - 在粘土块的上方摆放一个头颅,你可用苦力怕头颅 - 在粘土块正面贴上牌子,并写上[NPC] Innkeeper - 然后右键点击头颅,触发NPC任务对话 * 如果你安装了Citizens: - 你只需要使用''/npc create Innkeeper''指令即可 - 右键这个刚创建的Citizens NPC即可触发对话 如果NPC对话未能显示,你可能需要检查一下BetonQuest是否已被正确安装(使用**/bq version**指令确认),或NPC创建步骤是否有遗漏。 如果没有问题,你就可以接着体验这个初始任务了。一开始这个NPC会向你提供一项简单任务,当你选择接受之后,你会被要求去砍一些树。在任务过程中你可以使用**/journal**指令查看//任务日志//以及一些新的任务提示。如果要完成这个任务,不要往地上拜放原木,否则BetonQuest会相应地增加你需要砍伐的原木。当你砍伐并收集到16个原木之后(你也可以从创造模式直接拿16个原木),返回Innkeeper NPC与之对话,它会把你的木头收走并给予你奖励。 ===== 从events和conditions开始 ===== 现在你已大概了解一个简单的任务是什么样子的了,那么该怎么设计出一个类似的呢?我们先从__//events事件//__和__//conditions条件//__开始入手: ==== 事件 Events ==== 我们先打开__default__文件夹中的__events.yml__文件,然后在后面加入新的一行: foo: message Hello world! 这是一条__//事件指令//__。BetonQuest会根据这个指令执行触发相应的__//[[插件手册:betonquest:基本概念#事件_events|事件Events]]//__。在这个例子中,''foo''是你对这个事件的命名(名为''foo''的事件);''message''是事件的类型,这个是[[插件手册:betonquest:事件列表#消息message|向玩家发送消息]];而''Hello world!''则是message事件的参数,也就是消息内容。当你执行这个''foo''事件,BetonQuest就会向你显示''Hello world!''消息。 现在保存这个文件,并输入**/q reload**命令重新加载。然后我们可以测试这个__//事件//__是否有效了:在游戏中输入**/q e {name} foo**命令(备注:''q''是''quest''的缩写,''e''是''event''的缩写,''{name}''填入你的Minecraft名字,''foo''则表示上面刚刚编写的''foo''__//事件//__。如果成功,那么玩家的聊天框就会显示''Hello world!''这一段消息。 我们现在来试一试别的__//事件//__,就拿[[插件手册:betonquest:事件列表#传送teleport|传送]]''teleport''好了。只要你看过__[[插件手册:betonquest:事件列表|事件列表]]__,就知道这个传送事件需要一个座标作为参数。在游戏里按F3就可以看到你现在的座标(在左边,有三个数字分别代表''x''、''y''和''z''座标)。现在把这个座标写到__events.yml__文件的末尾: bar: teleport 100;200;300;world 记得把''100''改成你的''x''座标,''200''改为''y'',还有''300''改为''z'',''world''改为你现在所在的世界(一般情况下就是world)。然后保存这个文件、重新加载BetonQuest(**/q reload**)并照葫芦画瓢用上面的''/q event {namne} bar''命令测试这个//事件//。如无意外,你会被传送到那个座标。 现在恭喜你!你已经学会了怎么创建__//事件//__。你现在可以自己试试[[插件手册:betonquest:事件列表|事件列表]]中的其它事件。熟练之后我接着学习__//条件Conditions//__: ==== Conditions ==== Open the _conditions.yml_ file and add there a new line: foo: location 100;200;300;world;5 Can you see how we named the ''foo'' condition in the same way as the ''foo'' event? They are not connected in any way. Condition names and event names are separated, so you can give them the same name without any problems. Now let's look at the instruction string. As you can suspect, ''location'' is a type of the condition. This one means that we'll be checking if the player is near that location (you should change the location to the place where you're standing right now, so you don't have to run around the world). Note that at the end of location argument there is an additional number, ''5''. This is the maximum distance you can be away from the location to meet the condition. Alright, save the file and reload the plugin. Now walk to the location you have defined in the condition. Try to stand on the exact block corresponding to that location. Issue **/q c {name} foo** command (''c'' is shortcut for ''condition''). It should show you "checking condition blah blah blah: **true**". We're focusing on that last word, **true**. This means that you're meeting the condition: you're standing withing 5 block radius of the location. Now move 2 blocks away and issue that command again. You should still be meeting the condition. Walk 4 more blocks away and try now. It should show **false**. You are now outside of that 5 block radius. Get it? Great. Now I'll show you the simplest use of those conditions. Open the _events.yml_ file again, and at the end of ''foo'' instruction add ''conditions:foo'' argument. By the way, rename ''foo'' event to ''baz'', so the names won't get confusing. Now you should have something like baz: message Hello world! conditions:foo Now ''baz'' event will run only if it meets ''foo'' condition. Reload the plugin, walk outside of the 5 block radius and try to run ''baz'' event. Puff, nothing happens. It's because you're not meeting ''foo'' condition. Walk into the radius again and try to run that event now. It should happily display the ''Hello world!'' message. It's very nice that we can add such conditions, but the problem is: what if you wanted to display the message only if the player is _outside_ the radius? Don't worry, you don't have to specify ''inverted_location'' condition or anything like that. You can simply negate the condition. Negation makes the condition behave in the exact opposite way, in this case it ''foo'' will be met only if the player is outside of the 5 block radius, and it won't be met if he's inside. Open the _events.yml_ and add an exclamation mark before the ''foo'' condition, so it looks like baz: message Hello world! conditions:!foo This means "display message ''Hello world!'' if the ''foo'' condition is _not met_". Save the file, reload the plugin and run the event inside and outside of the radius to see how it works. ===== Basic tags ===== Now that you know how to use events and conditions I'll show you what tags are. Create new events: add_beton_tag: tag add beton del_beton_tag: tag del beton It's a good practice to give your events names that describe what they are doing. Imagine you have 100 events, ''foo24'', ''bar65'', ''baz12'' etc. You would get lost pretty quickly. So, ''add_beton_tag'' event here simply adds ''beton'' tag to the player, ''del_beton_tag'' removes it. Save the file, reload the plugin and run this event. Nothing happens... or does it? Issue **/q t {name}** command (''t'' is shortcut for ''tags''). It should show you a list with few entries. Right now focus on ''default.beton'', the rest are used by the default quest for Innkeeper. Alright, ''default'' is the name of the package in which the tag is, and ''beton'' is the name of the tag, as defined in ''add_beton_tag'' event. Now run ''del_beton_tag'' event. Guess what, ''default.beton'' disappeared from the list! And that's it, you know how to add and remove tags. Pretty useless. Nothing could be more wrong. Tags are one the most powerful things in BetonQuest. They just need to be used with ''tag'' condition. Open _conditions.yml_ and add has_beton_tag: tag beton line. As you can imagine, ''tag'' is the type of a condition (the same as ''tag'' event, but these are not the same things - one is an event, the other one is a condition) and ''beton'' is the name of the tag. You don't have to specify ''default.beton'', but you can if you want. Now save, reload and check it with a command. It should show **false**, since you have removed the tag with ''del_beton_tag'' event. Add it again with ''add_beton_tag'' event and check the ''has_beton_tag'' condition again. Now it will show **true**. Now you probably understand how powerful this system is. You could for example set a tag on the first time the player talks with an NPC, and if the NPC sees that tag next time they talk, he will tell something different, like "welcome back". ===== Creating objectives ===== Time to write some objectives! Open the _objectives.yml_ file and add a new line: kill_creepers: mobkill creeper 3 events:bar conditions:has_beton_tag Now let's analyze it. ''kill_creepers'' is a name of the objective. ''mobkill'' is a type. In this case, to complete the objective the player will have to kill some mobs. ''creeper'' is a type of the mob, so we know that these mobs will have to be Creepers. ''3'' is the amount. It means that the player has to kill 3 Creepers. ''events:bar'' means than once the player kills those Creepers, the ''bar'' event will be run (it's the teleportation event). ''conditions:has_beton_tag'' tells us that the player will have to have ''beton'' tag while killing Creepers to complete the objective. Save it, reload the plugin and issue **/q o {name} add kill_creepers** command (''o'' is for ''objective'', ''add'' tells the plugin to add an objective). Now you can check if you actually have this objective with **/q o {name}** command, it will show you all your active objectives. It should show ''default.kill_creepers''. Alright, remove (yes, remove!) the ''beton'' tag from you and find some Creepers to kill. Once you killes 3 of them you will notice that nothing happened. It's because ''has_beton_tag'' condtion is not met, so the objective does not count your progress. Now add the tag again and kill another Creepers. When the third is dead you should be teleported to the location defined in ''bar'' event. Congratulations, now you know how to use objectives. You should experiment with other types now, since objectives will be used very often in your quests. Once you're done check out the _Writing your first conversation_ chapter to use your knowledge to write your fisrt conversation. ===== Writing your first conversation ===== Now that you have seen BetonQuest in action and understood events, conditions and objectives, it's time for writing your first conversation. There's a _conversations_ directory inside the default package. It contains a single file, _innkeeper.yml_. This is the conversation with Innkeeper, the one who asks you to cut some trees. Open it, we'll use that for reference. Now create a new file, let's say _miner.yml_. Now type (don't copy-paste it, you'll learn better while typing) that into the file: quester: Miner first: greeting NPC_options: greeting: text: Hi there, traveler! It's the most basic conversation possible. The NPC named ''Miner'' upon starting the conversation will use ''greeting'' option, which means he will say ''Hi there, traveler!''. Then the conversation will end, because there are no player options defined. Now you need to link the conversation with an NPC. You do that in the _main.yml_ file. Open it now. As you can see, _inkeeper.yml_ conversation is linked to ''Innkeeper'' word. It's the one you have put on the sign, remember? Now, add another line under the Innkeeper: ''Miner: miner.yml'', save the file and reload the server. This will link our new conversation with the NPC named "Miner". Construct a new NPC on the server, give him a sign with "Miner" name and click on the head. Guess what, the conversation finished right after it started. The Miner just said ''Hi there, traveler!'', as expected. Now go to the conversation file and edit it (again, manually, no copy-paste!) so the options look like this: NPC_options: greeting: text: Hi there, traveler! pointers: hello, bye player_options: hello: text: Hello! bye: text: I need to go, sorry. When you save the file, reload the plugin and start the conversation again you will notice that there are two options for you to choose: ''Hello!'' and ''I need to go, sorry.'' Choosing any of them will end the conversation, because these options did not specify any pointers. Now add a new NPC option, for example ''weather'' with text ''Nice weather.'' and make ''hello'' player option point to it. When you save&reload, the Miner should say ''Nice weather.'' when you tell him ''Hello!''. I think you get how it works. NPC_options: greeting: text: Hi there, traveler! pointers: hello, bye weather: text: Nice weather. player_options: hello: text: Hello! pointer: weather bye: text: I need to go, sorry. Now, every time you talk to the Miner, he will say the same thing. It would be nice if the second time you talk to him he knew your name. We can do that with tags. Define a ''meet_miner'' event and ''has_met_miner'' condition. When you talk to the Miner for the first time, he will check if you have met him. If not, he will meet you (with that event) and next time you talk, the condition will be passed and he will use your name. Now, rename ''greeting'' NPC option to ''first_greeting''. Add ''meet_miner'' event and negated ''has_met_miner'' condition (negated because this option should only show if the player has not met the Miner yet). You will need to surround the condition with ''%%' '%%'', because strings cannot start with exclamation marks in YAML. It should look like this: first: first_greeting NPC_options: first_greeting: text: Hi there, traveler! condition: '!has_met_miner' event: meet_miner pointers: hello, bye This means: ''first_greeting'' should be used if the player **does not** pass ''has_met_miner'' condition (meaning he doesn't have a tag because he haven't talked to the NPC yet). When this option is used, it will fire ''meet_miner'' event and display ''hello'' and ''bye'' options. Alright, but what happens if the player met the Miner and now negated ''has_met_miner'' condition doesn't work? NPC will try to use next option defined in ''first'' setting. There is none yet, so let's add it. first: first_greeting, regular_greeting NPC_options: regular_greeting: text: Hi %player%! pointers: hello, bye This option does not have any conditions, so if the ''first_greeting'' fails, the NPC will always choose this one. Now take a look at the ''%player%'' thing. It's a variable. In this place it will show your name. There are more than this one, they are described in _Reference_ chapter. Alright, save&reload and start the conversation. If you did everything correctly, the Miner should greet you as a "traveler", and the second time you talk to him, he should greet you with your Minecraft name. Here's the whole conversation you created, so you can check if you understood everything correctly: first: first_greeting, regular_greeting NPC_options: first_greeting: text: Hi there, traveler! condition: '!has_met_miner' event: meet_miner pointers: hello, bye regular_greeting: text: Hi %player%! pointers: hello, bye weather: text: Nice weather. player_options: hello: text: Hello! pointer: weather bye: text: I need to go, sorry. Now you should experiment some more with this conversation, you can help yourself by looking at the _innkeeper.yml_ file. Try to understand how that conversation works step by step. As the excercise you should complete the Miner NPC, so he asks you to mine some iron ore, then smelt it in the furnace, next craft an armor with it and return to him wearing this armor. You might want to check out the _Reference_ chapter to see how to handle items in your quests and how to add entries to the journal. If you want to use Citizens NPCs instead of the ones made with clay you will find information you need in that chapter too. To find out more about events, conditions, objectives and variables, take a look at the appropriate lists (after the __Reference__ chapter). ---- ---- (下面是早期我们内部人员根据自己的理解编写的简易教程,供大家参考:) ===== 1.启用你的NPC ===== - 上传NPC文件至服务器后台,为了方便维护,建议文件命名方式使用:''NPC名称.yml'' - 通过重新加载的方式使得你上传的NPC文件生效,指令:''/q reload'' - 创建NPC - 放置一块染色粘土 - 在它上面放一个头 - 在粘土块的一侧放置一个牌子 - 写在第一和第二行\\ ''[NPC]''\\ ''你上传的NPC名称''(如Mycroft.yml就是Mycroft) - NPC已启用 ===== 2.为你的NPC添加事件 ===== ==== 信息事件 ==== - 在默认包中打开events.yml文件 - 最后添加一个新行:\\ ''XXX: message 烤麸烤麸考~''\\ XXX为事件名称\\ message为事件类型(此为信息事件)\\ 烤麸烤麸考~为你所要显示的信息 - 重复*1 - 使用指令执行事件XXX\\ 指令:''/ qe {name} XXX''\\ qe:q快捷方式是quest,e是快捷方式event\\ {name}是没有括号的用户名 进阶: ''message {en} &4You are banned, %player%!'' ''{pl} &4Jestes zbanowany, %player%!'' ''{de}&4Ich weiß nicht.'' {}内为语言缩写(如中文cn,英文en) &4为颜色代码 %player%指代玩家昵称 ==== 传送事件 ==== 1.在默认包中打开events.yml文件 2.在MC中按F3查看你想设定的坐标位置 3.最后添加一个新行: ''XXX: teleport 366;65;290;world'' 说明: teleport为事件类型(此为传送事件) 366;65;290;为对应XYZ坐标 world为世界名称 4.重复步骤1.1上传NPC文件、1.2重新加载NPC文件以及步骤2.4通过命令执行事件.(以后统称“进行测试”) 5.倘若正确无误,它应该将你传送到你指定的位置。 进阶: 若想使传送者转身或偏头,应用偏航与俯角 ''teleport 123;32;-789;world;180;45'' 180对应偏航(左右偏) 45对应俯角(上下偏) ==== 赋点事件 ==== ''point XXX XXXX'' point为事件类型(此事件为赋点事件) XXX为赋点对象(可以为玩家或NPC) XXXX为所赋点值(XXXX为加,-XXXX为减,*XXXX为乘,/XXXX为除) ---- **事件类快速教学到此结束,更多事件教程请查阅[[插件手册:betonquest:事件列表|事件列表]]**