====== 高级技巧 Tips and Tricks ======
(版本:2018-10-16 翻译:kjiang [[https://github.com/Co0sh/BetonQuest/blob/b18b2b1521d79e3020864808f1d5c59f39f28361/docs/11-Tips-and-tricks.md|原文链接]])
(为便于理解,本文和原文有所出入)
===== Handling death in your quests =====
Sometimes, while writing a dangerous quest you will want something specific to happen when the player dies. If it's a boss battle you may want to fail the quest, if it's a dungeon you may want to respawn the player at the beginning of a level etc. You can do that with ''die'' objective - simply start it for the player at the beginning of the quest and make it fire events that will do the thing you want (like teleporting the player to desired respawn point, removing tags set during the quest etc). You can add ''persistent'' argument to the objective instruction string to make it active even after completing it. Remember to ''delete'' it after the quest is done!
===== Creating regions for one player at the time =====
Imagine you have a room to which the player is teleported. Then suddenly mobs start to spawn and the player must kill them (because it's a trap or something). The player has killed all the mobs, he got a tag and wants to proceed but all of the sudden another player teleports into the room and all the mobs start to spawn again. The first player is quickly killed and the second one easily kills all mobs. You can prevent such situations by using ''party'' condition. Just check with it if the party consisting of "players inside the room" has greater amount of players that 1. Set the range to something big enough so it covers the room and the party condition can be tag or location.
===== Racing with folder event =====
Since ''folder'' event can run ''tag'' events even for offline players you can create races. Create ''location'' objective where you want the finish line to be and condition it with negated "race_failed" tag (or similar). It will mean that "if the player has not failed the race, he can win it by reaching the location". Now when the race starts fire ''folder'' event with the amount of time you want to give your players to complete the race. This event should set "race_failed" tag. If the player reaches the location before this tag is set, he will fire all events in that ''location'' objective, but if the time has passed, the objective will not be completed. You can figure the rest out for yourself.
===== Random daily quests =====
Starting the random quest must be blocked with a special tag. If there is no such tag, the conversation option should appear. Create a few quests, each of them started with single ''folder'' event (they **must** be started by single event!). Now add those events to another ''folder'' event and make it ''random:1''. At the end of every quest add ''delay'' which will reset the special blocking tag. Now add that ''folder'' event to the conversation option. When the player chooses it he will start one random quest, and the conversation option will become available after defined in ''delay'' objective time after completing the quest.
===== 每日固定随机任务 =====
(所有人都是同一个随机任务)
通过设置[[插件手册:betonquest:基本概念#静态事件_static_events|静态事件]],配合[[插件手册:betonquest:事件列表#事件包folder|事件包folder]]就可以创建一个每天都固定的随机任务。思路是让BetonQuest每天在固定的时刻随机更改某个座标上的方块,然后在玩家和NPC对话中,判断这个座标上的方块种类,展示相对应的对话内容。
具体实现步骤如下:
- 首先编辑你的__main.yml__,在**static**新增加一个静态事件(如果没有static就创建一个。):
static:
'23:59': 刷新随机任务
这会在每天的23:59刷新这个随机任务。
- 然后在__events.yml__创建一个叫“刷新随机任务”的事件:
刷新随机任务: folder 改成紫色羊毛,改成黄色羊毛,改成黑色羊毛 random:1
这里的“改成紫色羊毛”是另一个事件,它会修改某个座标的方块种类,例如:
刷新随机任务: folder 改成紫色羊毛,改成黄色羊毛,改成黑色羊毛 random:1
改成紫色羊毛: setblock PURPLE_WOOL 123;64;456;world
改成黄色羊毛: setblock YELLOW_WOOL 123;64;456;world
改成黑色羊毛: setblock BLACK_WOOL 123;64;456;world
(你可以查看[[插件手册:betonquest:事件列表#设置方块setblock|设置方块setblock]]的用法和参数格式)例子中123;64;456;world座标是随便举的例子,你应该把这个座标设置在碰不到的地方,比如搜保护的领地内。
- 在任务NPC的各个初始对话中各插入一个[[插件手册:betonquest:条件列表#方块检测testforblock|方块检测testforblock]]条件__//conditions//__,比如:
quester: 工会NPC
start: 任务A,任务B,任务C
NPC_options:
任务A:
text: '今天工会提供任务A哦,你要接受吗?'
conditions: 是紫色羊毛
任务B:
text: '今天工会提供任务B哦,你要接受吗?'
conditions: 是黄色羊毛
任务C:
text: '今天工会提供任务C哦,你要接受吗?'
conditions: 是黑色羊毛
- 别忘了你的__conditions.yml__:
是紫色羊毛: testforblock 123;64;456;world PURPLE_WOOL
是黄色羊毛: testforblock 123;64;456;world YELLOW_WOOL
是黑色羊毛: testforblock 123;64;456;world BLACK_WOOL
===== 让NPC表现得更随机一些 =====
假设你需要某个NPC有15%的机率玩家相信玩家、35%的机率怀疑、剩下50%的机率完全不相信玩家,那么怎么设计呢?
基本思路是,设计出一段__//对话conversation//__,让NPC有15%的概率显示对话a、35%概率显示对话b、50%概率显示对话c。我们可以借助[[插件手册:betonquest:条件列表#随机概率random|随机/概率random]]这个condition实现。那么我们先制作出三段对话:
quester: 怀疑者
start: 初始对话
NPC_options:
初始对话:
text: "我要怎么相信你?"
pointer: "相信我"
我相信: # 有15%的概率会显示这段对话
text: "行吧,我相信你。"
conditions: 相信的概率
我怀疑: # 有35%的概率会显示
text: "我没空,下次再说吧。"
conditions: 怀疑的概率
我不信: # 有50%的概率会显示
text: "我不信,除非你证明给我看。"
conditions: 不信的概率
player_optoins:
相信我:
text: "相信我, 我是认真的!"
pointer: 我相信,我怀疑,我不信
然后是''相信的概率''、''怀疑的概率''、''怀疑的概率'':
相信的概率: random 15-100 # =15%
怀疑的概率: random 35-85 # =(35%)/{1-15%}=35%/85%=46.6666%
不信的概率: random 50-50 # =(50%)/{(1-15%)(1-35%/85%)}=50/50=100%
注意这里''怀疑的概率''填的并不是“35-100”,''不信的概率''也不是“50-100”,为什么?
因为BetonQuest在判断conditions的时候是按顺序逐个计算的,注意对话文件的第20行:
pointer: 我相信,我怀疑,我不信
在这里,NPC有三个选项,BetonQuest在决定NPC的下一段对话的时候,会按照如下顺序计算conditions:
- 先计算''我相信''对话里的conditions条件(''相信的概率'')是否满足,如果满足则显示“我相信你。”
- 如果“我相信”里的conditions不满足,则计算''我怀疑''里的conditions条件(''怀疑的概率''),满足则显示“我没空,下次再说吧。”
- 如果“我怀疑”也不满足,最后则计算''我不信''的conditions条件(''不信的概率'')
我们逐个分析:
* 首先第一个选项“我相信”很好理解,BetonQuest开始计算“我相信”中的conditions''相信的概率'',因为“相信的概率”是''random 15-100'',也就是说第一段对话有15/100的概率“满足”,也就是15%的概率会显示出来。但如果不满足,
* 然后BetonQuest就会开始计算“我怀疑”的conditinos''怀疑的概率'',注意,因为BetonQuest是按顺序计算conditions条件,所以**这个计算是在上一个条件“相信的概率”不满足的大前提下计算的**。上一个选项不满足条件的概率是100%-15%=85%,如果你“怀疑的概率”填写的是“35-100”,那么玩家实际触发这个“我怀疑”对话的概率是=(85%)x(35%)=29.75%,并不是你所想的35%。所以我们应该填''35-85'',因为{第一个选项不满足条件的概率}x{第二个选项不满足条件的概率}={85%}x{35/85}刚好等于你想要的35%
* 如果“我怀疑”也不满足,现在BetonQuest需要计算最后一个选项“我不信”,同样它的conditions条件需要在**之前两个选项都不满足的大前提下计算**。我们知道__第一个选项不满足条件的概率__是85%,而__第二个选项不满足条件的概率__是100%-(35/85)%=(50/85)%(注意这里我们用“35-85”计算不满足率),那么第三个需要填写的概率应该是''50-50'',因为{第一个选项不满足条件的概率}x{第二个选项不满足条件的概率}x{第三个选项满足条件的概率}={85%}x{50/85}x{50/50}=50/100刚好等于50%
因为计算的概率和pointer(''pointer: 我相信,我怀疑,我不信'')的排序有强烈关系,所以**pointer里填写的(“我相信”、“我怀疑”和“我不信”)顺序不能打乱,否则实际概率会变!**
这里有一个快速计算公式,假设你有a%、b%、c%、d%、e%...种概率:
- 第一个填写的概率 - ''a-100''
- 第二个填写的概率 - ''b-{100-a}''
- 第三个填写的概率 - ''c-{100-a-b}''
- 第四个填写的概率 - ''d-{100-a-b-c}''
- 第五个填写的概率 - ''e-{100-a-b-c-d}''
- ...
- 最后一个填写的概率 - ''100-100'' 其实不用填,因为一定等于100%
例如,a=3、b=7、c=15、d=31...:
- 第一个 - ''a满足: random 3-100''
- 第二个 - 7-{100-3}=7-97 ''b满足: random 7-97''
- 第三个 - 15-{100-3-7}=15-90 ''c满足: random 15-90''
- 第四个 - 31-{100-3-7-15}=31-75 ''d满足: random 31-75''
- ...
- 最后一个 - (不用写conditions)
===== Quest GUI =====
If you want your players to be able to choose a quest everywhere, every time, then you can create a conversation which can be started with an item. This one is a little hacky but it shows flexibility of BetonQuest. First you need a conversation which behaves as a quest choosing GUI. Name the NPC "Quester", add one option for each quest etc. Now you need an objective which will start this conversation using ''conversation'' event. It should be ''action'' objective, set to right click on any block. Add ''hand'' condition to make it accept only clicks with a specific item and make the objective ''persistent'' (so players can use it multiple times). The item used here should be marked as Quest Item so players can't drop it. Now define new global location covering your whole map and using it start the objective and give players the item. This way all players (existing and new) will get the quest item, which opens a GUI with quests when right clicked.