Квест на убийство (ЧАСТИЧНО)
TODO: предупреждение о том, какие разделы нужно прочитать перед началом.
TODO: пошаговое руководство по написанию квеста на убийство с NPC.
Историческая версия
Старое обучающее видео всё ещё можно посмотреть, но учтите, что часть приёмов в нём устарели — в первую очередь теги флагов. Если решите смотреть видео, пройдитесь по списку «Изменения после выхода обучающих видео».
Пример скрипта
Это руководство ещё не написано, но ниже — скрипт с поясняющими комментариями, который показывает одну из возможных реализаций квеста на убийство с NPC.
Этот пример подразумевает, что у вас современный конфиг-файл Denizen. То есть ваш plugins/Denizen/config.yml был сгенерирован после июня 2021 года (релиз 1743 или новее). Если у вас более старый конфиг, но вы хотите использовать этот скрипт, можно либо
A: удалить
config.ymlи перезапустить сервер, чтобы Denizen сгенерировал новый.либо B: открыть
config.ymlв текстовом редакторе, найти строкуQueue speed: 0.5sподInteract:и заменить0.5sнаinstant, после чего выполнить/denizen reload config
Скрипт устроен так, что вы можете скопировать его, загрузить на сервер и привязать к NPC через /npc assign --set npc_killquest или /ex assignment set npc_killquest — и всё заработает. Дальше его можно кастомизировать или использовать как образец для обучения.
В редакторе скриптов его читать удобнее, чем на этой странице.
# Core assignment script to be given to the NPC
npc_killquest:
type: assignment
actions:
on assignment:
# Enable both triggers that will be used
- trigger name:click state:true
- trigger name:chat state:true
interact scripts:
# And link the interact script below
- npc_killquest_interact
# Alternate chat format for the NPC if you don't like default 'chat'
# if you make multiple NPCs with this script as a template, remember that you only need the format scripts *once* (unless you have it different per NPC)
cchat:
type: format
format: <&b><npc.name> <&f>to you<&co> <&2><[text]>
# A clean but simple format for instructions given to the player by the script rather than by the NPC
# (The Out-Of-Character clarification of what the NPC said In-Character).
instruction_format:
type: format
# Light Gray + Italic
# Can also be written like <gray><italic>
format: <&7><&o>[<[text]><&7><&o>]
npc_killquest_interact:
type: interact
steps:
# Default step: waiting for player to interact
waiting*:
# The player's initial interaction with this NPC is always just right clicking it
click trigger:
script:
# Example of doing engage per-player with a flag
# Engaging is a way to prevent players from spamming interactions with an NPC and glitching the scripts out as a result.
# It just forces the player to wait on their next interaction until the current one is finished.
# It works by using a has_flag check at the start of each interaction to stop early, and adding/removing before/after slow interactions like the narrates with waits below.
- if <player.has_flag[npc_engaged]>:
- stop
# Check for a cooldown before dealing with engage so we don't have to disengage inside the if
- if <player.has_flag[kill_zombie_quest_cooldown]>:
# While a cooldown *could* be a step or a `cooldown` command, having it as a flag allows you to track and display the cooldown timer clearly, which players will appreciate.
- narrate format:instruction_format "You can repeat this quest in <player.flag_expiration[kill_zombie_quest_cooldown].from_now.formatted>."
# If we put the script *after* an engage, the disengage would go here - just before any 'stop' command.
- stop
# Add the engage flag for one minute - either it will be cleared via the flag command, or if something bugs, it will clear on its own after a minute
- flag player npc_engaged expire:1m
# Alternately, instead of the player flags, you can use engage commands to engage per-NPC,
# which is simpler to do (it's all in the one short command) but gets in the way of other players often
#- engage
- narrate format:cchat "Hello there. Would you care for a special prize?"
- wait 5t
- narrate format:cchat "If so, you can kill 5 zombies for me."
- wait 5t
- narrate format:cchat "Will you accept this request?"
- wait 5t
# The player can type 'yes' or 'no' into chat normally, OR click the word to automatically say it
- narrate format:instruction_format "Type <&b><&o><element[Yes].click_chat[yes]><&7><&o> or <&b><&o><element[No].click_chat[no]>"
# Zap to the step that contains the chat trigger. Add a five minute limit so if the player runs away and comes back, the NPC isn't still expecting a response.
- zap accept_question 5m
- flag player npc_engaged:!
#- disengage
# Second step: only active while waiting for a response to the question given in the click trigger
accept_question:
chat trigger:
1:
# Simple main chat trigger: if the player says yes, they start the quest
trigger: "/Yes/ I accept the quest"
script:
- if <player.has_flag[npc_engaged]>:
- stop
- flag player npc_engaged expire:1m
#- engage
- narrate format:cchat "Okay great!"
- wait 5t
- narrate format:instruction_format "Kill 5 zombies!"
# Start a counter flag at zero (no zombies killed yet).
- flag player kill_zombie_quest_count:0
# Jump to the step for finishing the quest and lock it in (no timeout).
- zap finish_quest
- flag player npc_engaged:!
#- disengage
2:
# Even though it's not really needed, add a 'no' response that just zaps back
trigger: "/No/ I don't"
script:
- if <player.has_flag[npc_engaged]>:
- stop
# More frequently shown messages can get annoying to players who have to see them constantly.
# Adding randomness to some messages is a little touch that makes scripts just that little bit nicer for players
- random:
- narrate format:cchat "Okay screw off!"
- narrate format:cchat "Okay then."
- narrate format:cchat "Screw you then!"
# They refused, so hop back to the default step and wait.
- zap *
# 3rd step: only allowed interaction is click, they're stuck here til they finish the quest
finish_quest:
click trigger:
script:
# This step doesn't have delayed interactions, so no engage needed.
# If the quest is marked as completed, give rewards.
- if <player.has_flag[kill_zombie_quest_complete]>:
- narrate format:cchat "Great work! Here's your reward!"
- give diamond
# Then remove the 'complete' flag and set the cooldown
- flag player kill_zombie_quest_complete:!
- flag player kill_zombie_quest_cooldown expire:24h
# And zap back to the default step so they can retry the quest after the cooldown is done.
- zap *
- else:
# Otherwise, just give idle waiting chatter.
- random:
- narrate format:cchat "You killed those zombies yet?"
- narrate format:cchat "I'm still waiting on the zombies."
- narrate format:cchat "Are you gonna kill those zombies or what?"
killquest_zombie_world:
type: world
events:
# Listen to the event of a player killing zombies
# Only listen when the counter flag is present
after player kills zombie flagged:kill_zombie_quest_count:
# After the kill, bump the player's kill counter
- flag player kill_zombie_quest_count:++
# When it hits five, you're done!
- if <player.flag[kill_zombie_quest_count]> == 5:
- narrate format:instruction_format "Zombie Quest Complete: Return to the NPC"
# So remove the counter (to avoid it continuing to count up) and add a new flag indicating the quest is complete
- flag player kill_zombie_quest_count:!
# Alternatively to the flag, using '- zap npc_killquest_interact quest_completed' and a corresponding new step would also work.
# The flag + if/else was chosen mostly for the sake of having examples of different methodologies.
- flag player kill_zombie_quest_complete