BetonQuest full beginners guide

A deep dive tutorial made for beginners

Introduction

So you want to learn BetonQuest? Not a problem at all. This guide will teach you everything you need to know to get started in an optimal way. This is less of a quick start tutorial and more of a full guide.

The guide is not written like a documentation, this is a step by step tutorial to learn everything you need to know in an order which makes sense to a new BetonQuest user. If you wish to view the official documention of BetonQuest you find it here.

If you ever need help with BetonQuest they have really good support on their Discord, you can also ask about BetonQuest on the community support in MC Models Discord.

BetonQuest quest plugin logo

Support the writing and updating of this guide

I do not want any donations or anything directly to me who is writing this guide, I do it because the community around BetonQuest is amazing. If you wish to show support for this project I would be very happy for these options:

  1. BetonQuest Patreon, they deserve it, so much work put into an open source free plugin is crazy, and the constant updates is amazing.
  2. Give BetonQuest a good review on Spigot, yet again, they deserve it.
  3. Consider buying pre-made BetonQuest packages from our MC Models team members and support them, the people posting those are quite active members of the BetonQuest community.

You can click these buttons to jump between the chapters:

Chapter 1: The building blocks of BetonQuest

This chapter is a lengthy one and will contain a lot of new information. So grab yourself a hot drink of choice and sit down for the ride while we get a basic understanding of the building blocks that make BetonQuest the amazing system we all love.

Chapter one goes through a bunch of examples, just to give you an idea of what each building block is and what it’s used for. There is no need to create your own package with these examples, we’ll do that in later chapters.

Packages

Packages can in the most simple way be described as a way for you to organize the content you create for the plugin, each package can contain conversations, objectives and all other building blocks that we create in BetonQuest. When you install the plugin you will have 1 package called “default”.

A common mistake in the beginning is to create multiple quests inside of the “default” package which you find in the BetonQuest plugin folder.
Instead create multiple packages, this is an example of a folder structure inside of the BetonQuest plugin folder:

  • BetonQuest
    • Default
    • Simple Quests
      • Simple Quest 1
      • Simple Quest 2
    • Daily Quests
      • Daily Quest 1
    • Fighters-guild-from-Skyrim-recreation
      • Quest 1
      • Quest 2
      • Random conversations
      • Anything

Each package can have the same file structure inside of it as your default package (but only requires the main.yml), which is:

BetonQuest Package

A package is not limited to the events and content of it’s own package, you can create relative paths to other packages, so for example any package can run a specific event inside another package but more on this later.

/bq create {package} – this command will create a new package for you with default configs.

The contents of a package

A package, or a bit simplified: a quest, in BetonQuest is built up by a few things great to understand right away. The main parts to understand right now are:

  • Conversations
  • Conditions
  • Events
  • Objectives
  • Items
  • Journal

Conversations

Conversations are the actual spoken lines of NPCs and the player. A really simple conversation could look like this:

quester: "Robin"
first: "npc_1"
NPC_options:
    npc_1:
        text: "Hello %player.display%, what a nice day we're having."
        pointer: "player_1,player_2"
    npc_2:
        text: "Hope to see you again soon."
player_options:
    player_1:
        text: "Hello Robin, yes we do."
        pointer: "npc_2"
    player_2:
        text: "Bye"

What happens is that an NPC named Robin will say “Hello [Player], what a nice day we’re having.” when you talk to it, the player will have 2 conversation options: “Hello Robin, yes we do.” and “Bye”, because of the pointers in npc_1.

If the player chooses option 1, then the NPC will say “Hope to see you again soon” because of the pointer in player_1, and then the conversation ends because npc_2 has no pointers.

If the player chooses option 2, the player will say “Bye” and then the conversation ends without the NPC responding because player_2 has no pointers.

Conditions

Conditions allow you to control what’s available in a conversation, what’s required for an objective to be completed and much more. Let’s add a simple condition and another conversation option to our example.

First let’s add the condition to the conditions.yml

is_daytime: time 6-18

What I did was create a condition within this package called “is_daytime” and I’m using the Time condition, where we can specify an hour interval within the world that have to be true (24-hour format).

Let’s do something fun to our example conversation:

quester: Robin
first: npc_1,npc_2
NPC_options:
    npc_1:
        text: Hello %player.display%, what a nice day we're having.
        conditions: is_daytime
        pointer: player_1,player_2
    npc_1_2:
        text: Hello %player.display%, we're having a really cold night.
        conditions: !is_daytime
        pointer: player_1,player_2
    npc_2:
        text: Hope to see you again soon.
player_options:
    player_1:
        text: Hello Robin, yes we do.
        pointer: npc_2
    player_2:
        text: Bye

What I’ve done here is added another NPC option called “npc_1_2” and I’ve added it to the “first” section, which determines which options the conversation can start with. So now it’s allowed to start with 2 out of the 3 NPC dialogue options.

I’ve also added the condition “is_daytime” to npc_1, which means that one can only happen when the condition is true (when it’s daytime in the current world).

I’ve inverted the condition on NPC option “npc_1_2” by adding a ! in front of it, which means for that conversation option to happen the condition have to be not true (night time in the current world).

Now let’s add some fun conditions to the player options by having different lines depending on if it’s day or night. We begin by creation new conditions:

is_daytime: time 6-18
ender: advancement minecraft:end/kill_dragon

Now we’ve created a condition called “ender” which checks if the player has the advancement from killing the ender dragon.

Let’s add a player option during night time that only shows up if you’ve killed the ender dragon.

quester: Robin
first: npc_1,npc_2
NPC_options:
    npc_1:
        text: Hello %player.display%, what a nice day we're having.
        conditions: is_daytime
        pointer: player_1,player_2
    npc_1_2:
        text: Hello %player.display%, we're having a really cold night.
        conditions: !is_daytime
        pointer: player_1,player_2,player_1_2
    npc_2:
        text: Hope to see you again soon.
player_options:
    player_1:
        text: Hello Robin, yes we do.
        pointer: npc_2
    player_1_2:
        text: Haha night time never scares me, I killed the ender dragon.
        conditions: ender
    player_2:
        text: Bye

We added player option player_1_2, this shows up after the NPC option npc_1_2 thanks to it’s new pointer setting. However it will only show up if you have the condition “ender” true. We don’t actually have to give player_1_2 the condition for day or night time since It will only show up on the NPC option that has it as a pointer.

Fun fact: The Advancement condition is not limited to vanilla advancements, thanks to having the namespace defined.

You can find all conditions usable on the conditions page of the official BetonQuest documentation.

Events

During a conversation or when an objective completes you may want something to happen. Things like running a command, updating the quest journal or even just giving a quest item to a player. There are tons of event types, a total of 46 as of writing this guide.

Let’s create two simple events in the events.yml

open_sesame: door 100;200;300;world1 on
close_sesame: door 100;200;300;world1 off

The event “open_sesame” will open a door (have to be the lower part coordinate of the door), trapdoor or fence gate at the coordinates x100 y200 z300 in the world called world1.

The event “close_sesame” will close the same door. In our chapter example I would love for a door to only open when someone says they killed the ender dragon, but then close after a few seconds. So let’s add a “folder” event.

open_sesame: door 100;200;300;world1 on
close_sesame: door 100;200;300;world1 off
sesame: folder open_sesame,close_sesame delay:2 period:4

Now we have a folder event called “sesame” that will run multiple events for us after a 2 second delay, with a period of time in between each event of 4 seconds.

Let’s add it to our conversation:

quester: Robin
first: npc_1,npc_2
NPC_options:
    npc_1:
        text: Hello %player.display%, what a nice day we're having.
        conditions: is_daytime
        pointer: player_1,player_2
    npc_1_2:
        text: Hello %player.display%, we're having a really cold night.
        conditions: !is_daytime
        pointer: player_1,player_2,player_1_2
    npc_2:
        text: Hope to see you again soon.
player_options:
    player_1:
        text: Hello Robin, yes we do.
        pointer: npc_2
    player_1_2:
        text: Haha night time never scares me, I killed the ender dragon.
        conditions: ender
        events: sesame
    player_2:
        text: Bye

Now when the player clicks option player_1_2 a door will open after 2 seconds, and stay open for 4 seconds for the player to walk through.

Objectives

Objectives are very useful for creating classic style quests, it could be simple things like “eat an apple” or “fish 5 salmon” but combined with conditions.

Let’s make a simple objective where you have to kill 5 zombies while inside of a dark forest biome. First we edit our conditions file and add a new condition:

in_dark_forest: biome dark_forest

Then we create the objective inside the objectives.yml

cool_zombie_objective: mobkill ZOMBIE 5 conditions:in_dark_forest

If we wish for something to happen when we complete the objective we can add events to it, so first let’s create another folder event in the events.yml

zombies_completed: folder zombie1,zombie2
zombie1: notify Objective Complete io:title
zombie2: give diamond:1

We now have 2 events that can be run as a folder, one is a notify event that will send a message to the player and the other will give them 1 diamond. To give someone a diamond you have to define it in items.yml:

diamond: DIAMOND

The notify event has been made with an IO called title, so it will say across the whole screen “Objective Complete”.

Fun tip: There are a lot of notify IO’s: Chat, Advancements, ActionBar, Title, Subtitle, TotemIO, Sound. See all here.

Let’s add the folder event to our objectives.yml:

cool_zombie_objective: mobkill ZOMBIE 5 conditions:in_dark_forest events:zombies_complete

Now the event “zombies_complete” will run as the objective completes. Before we can add it to the conversation we need to create an event that gives the objective to the player, so let’s edit our events.yml again:

zombies_completed: folder zombie1,zombie2
zombie1: notify Objective Complete io:title
zombie2: give diamond:1
give_objective_zombie: objective start cool_zombie_objective

Next up let’s make sure the player gets the objective within the conversation.

quester: Robin
first: npc_1,npc_2
NPC_options:
    npc_1:
        text: Hello %player.display%, what a nice day we're having.
        conditions: is_daytime
        pointer: player_1,player_2
    npc_1_2:
        text: Hello %player.display%, we're having a really cold night.
        conditions: !is_daytime
        pointer: player_1,player_2,player_1_2
    npc_2:
        text: Could you help me kill 5 zombies within a dark forest? You'll be rewarded with 1 diamond.
        pointer: player_3,player_2
player_options:
    player_1:
        text: Hello Robin, yes we do.
        pointer: npc_2
    player_1_2:
        text: Haha night time never scares me, I killed the ender dragon.
        conditions: ender
        events: sesame
    player_2:
        text: Bye
    player_3:
        text: Consider it done!
        events: give_objective_zombie

Here we have changed NPC option npc_2 and added player option player_3.

We have also made it so that if the player ever clicks player_3 option it will run the event to give them the objective we’ve made.

Items

Items that you reference within BetonQuest have to be a part of the items.yml, the format works like the events or condition files.

There are tons of options for different items: books, potions etc. So in this chapter we will just mention the most useful tools you have:

/bq item {package.ItemID} – This command will add the item you are holding in your hand to the specific package with the ID you give it. So if you want to use oak_logs in your quest it’s a good idea to hold a oak log in your hand and just use the command to add it to the config.

This also works with lore and everything else so if you have a Vote Key for your crate system, you can add that too and then use objectives in BetonQuest to obtain said item.

See all item documentation here or in our more advanced BetonQuest tutorials here.

Journal

The journal is a book item where all the players achievements, progress and goals can be described. You get the item in-game by typing /j or /journal.

This is usually where we start when making a quest, because we want to write the story and the lore of the quest and then we can build all the configs to make the quest happen.

In this example we will use a modified tutorial file structure made by Wolf on the BetonQuest team, you can download your version here.

First off let’s look at the journal.yml inside our package of the quest we’re making (not default folder).

# Example
step_1: >-
    $journal_headline$
      I was assigned a task that needs to be completed!

Here we can see that there is a journal entry we can give the player that says ” I was assigned a task that needs to be completed!”.

If we modify this file to fit our chapter example that we’ve been playing around with we could have 2 different journal entries:

# Example
step_1: >-
    $journal_headline$
      Robin asked me to kill 5 zombies inside a dark forest biome.
step_2: >-
    $journal_headline$
      I killed 5 zombies inside a dark forest biome like Robin asked me to and was rewarded with 1 diamond.

Now we have 2 entries that we can give the players journal, one when the objective is added and one when we complete the objective.

We add and remove entries into the journal through events, so in the example events.yml we find these 2 events:

journal_add_step_1: journal add step_1
journal_del_step_1: journal del step_1

These events can be run to add a journal entry or remove one.

Chapter conclusion

By now you should have an idea of what conversations, conditions, events, objectives and the journal is. If you do, you’ll understand more and get to play with them in chapter 2, 3 and 4.

In the next chapter we’re looking at how to get a good and expandable formatting for your journal.

Chapter 2: Setting up the journal for success

In this chapter we’ll be going through how we get a nicely formatted journal for all our players. The way it’s done in the pictures above is an edited version of Wolf’s public template that he posts in the Published-Quests channel in the BetonQuest Discord.

First off we want to edit the main plugin config.yml to make sure we have these settings:

journal:
  chars_per_line: '20'
  lines_per_page: '13'
  one_entry_per_page: 'true'
  reversed_order: 'true'
  hide_date: 'true'
  full_main_page: 'true'
journal_colors:
  date:
    day: '9'
    hour: '6'
  line: '4'
  text: '0'

Next we want to edit our main.yml in the default package and add our variables:

A big mistake a lot of users do here is to add a second “variables” section to the main.yml, please only have 1 variables section in the entire document.

variables:
    # Colors for the journal configuration
    journal_color_head: '&9'
    journal_color_head_deco: '&1'
    journal_color_text: '&0'
    journal_status_1: '&2'
    journal_status_2: '&6'
    journal_status_3: '&8'
    journal_status_4: '&7'
    #The diffrent quest states
    journal_status_1_name: $journal_status_1$Can be Started
    journal_status_2_name: $journal_status_2$Started
    journal_status_3_name: $journal_status_3$Finished/Cooldown
    journal_status_4_name: $journal_status_4$Locked
    #Formatting for headlines
    journal_head_prefix_text: '-'
    journal_head_suffix_text: '-'
    journal_head_prefix: $default.journal_color_head_deco$$default.journal_head_prefix_text$$default.journal_color_head$
    journal_head_suffix: $default.journal_color_head_deco$$default.journal_head_suffix_text$$default.journal_color_text$
    #Misc colors for use in quests
    color_highlight: '&2'
    color_npc: '&9'
    color_action: '&c'

These control our color formatting in the journal.

Next we’ll also add our journal main page settings:

variables:
    # Colors for the journal configuration
    journal_color_head: '&9'
    journal_color_head_deco: '&1'
    journal_color_text: '&0'
    journal_status_1: '&2'
    journal_status_2: '&6'
    journal_status_3: '&8'
    journal_status_4: '&7'
    #The diffrent quest states
    journal_status_1_name: $journal_status_1$Can be Started
    journal_status_2_name: $journal_status_2$Started
    journal_status_3_name: $journal_status_3$Finished/Cooldown
    journal_status_4_name: $journal_status_4$Locked
    #Formatting for headlines
    journal_head_prefix_text: '-'
    journal_head_suffix_text: '-'
    journal_head_prefix: $default.journal_color_head_deco$$default.journal_head_prefix_text$$default.journal_color_head$
    journal_head_suffix: $default.journal_color_head_deco$$default.journal_head_suffix_text$$default.journal_color_text$
    #Misc colors for use in quests
    color_highlight: '&2'
    color_npc: '&9'
    color_action: '&c'
journal_main_page:
    legende:
        priority: 0
        text: >-
            $journal_head_prefix$Quest Status$journal_head_suffix$
              $journal_status_4_name$
              $journal_status_1_name$
              $journal_status_2_name$
              $journal_status_3_name$

            $journal_head_prefix$Quest List$journal_head_suffix$
    quests:
        priority: 5
        text: >-

            $journal_head_prefix$Repeatable Quests$journal_head_suffix$

The journal_main_page settings control what we show on the main page/pages of the journal, in this case it’s the example list of quest states and then a list of quests on the server. In chapter 4 we’ll edit these settings more to add in separate information about repeatable/daily quests.

Now edit the custom.yml in the default package and add in:

notifications:
    # A fixed format for a notification, when a quest is started
    quest_started:
        io: advancement
        frame: task
        icon: written_book
        sound: item.book.page_turn
    # new_journal_entry is a fixed plugin notification. This configures the notification for new journal entries
    new_journal_entry:
        io: advancement
        frame: task
        icon: written_book
        sound: ui.cartography_table.take_result
    # A fixed format for a notification, when a quest is finished
    quest_finished:
        io: advancement
        frame: challenge
        icon: written_book
        sound: ui.toast.challenge_complete
    # A fixed format for a notification, when a quest is cancelled
    quest_cancelled:
        io: advancement
        frame: goal
        icon: written_book
        sound: block.conduit.deactivate

These notifications we’ll use when setting up our first quest in chapter 4.

Chapter 3: Quest Markers

Quest markers are typically indicators that an NPC has to show that you can get a quest from them, have a quest in progress or can turn in a quest.

There are a few different ways of making quest markers in BetonQuest, here is a brief list off the top of my head:

  • CustomModelData items, like in the pictures above.
  • Hologram with text like “Quest Available” and such.
  • Default items hovering over the NPC, could use different colored wool.
  • Particle Effects around/on top of the NPC using EffectsLib.

In this guide we’ll be going with the first option and we’ll use a lovely free resource on this website made by Bendy_Straw, you can download it here.

How to use the quest markers

  • Turn on the resource pack provided in the download, you can merge it with your existing resource pack as well (see our Resource Pack tutorials by clicking here).
  • Open the items.yml in the package we wish to use the markers in and add this:
quest_marker_available: "GOLD_INGOT custom-model-data:33"
quest_marker_incomplete: "IRON_INGOT custom-model-data:63"
quest_marker_complete: "GOLD_INGOT custom-model-data:63"
quest_marker_future: "IRON_INGOT custom-model-data:33"
  • Open the custom.yml in the BetonQuest package where we want the markers and add the following:
npc_holograms:
  check_interval: 100
  follow: false
  disabled: false

  #
  quest_marker_available:
    lines:
      - "item:quest_marker_available"
    vector: 0;3;0
    conditions: "!tag_started"
    npcs:
      - 100
  quest_marker_incomplete:
    lines:
      - "item:quest_marker_incomplete"
    vector: 0;3;0
    conditions: "tag_started,!tag_done"
    npcs:
      - 100
  quest_marker_complete:
    lines:
      - "item:quest_marker_complete"
    vector: 0;3;0
    conditions: "tag_done,!tag_rewarded"
    npcs:
      - 100
  quest_marker_future:
    lines:
      - "item:quest_marker_future"
    vector: 0;3;0
    conditions: "tag_done,!tag_started"
    npcs:
      - 100
  • Change the NPC id to the Citizens ID of your quest giver (in config above it’s set to npc ID 100)
    • You can find out the ID of a NPC by walking up to it, typing /npc sel and then /npc id

We’re going to have to change the conditions for when these are shown according to how we set up our quest conditions but you’ll go through that in the next chapter when we create our very first quest together.

Chapter 4: Your first quest

To make sure that you learn the optimal way to make multi-stage or multi-objective quest lines we’re not just going to be making a simple 1 task quest (using tags), that could teach you incorrect (but fast) ways to create these that won’t work very well on longer quests.

So the way we’re going to do it is using a steps system utilizing the point events, which might feel overwhelming to a new users at first but pay attention and take it slowly, this way you will create amazing quests.

This chapter it’s best to follow along and make your own quest, alternatively scroll to the end of the chapter and download the whole package that we make while writing this guide.

The first 7 steps are to make ourselves a nice template package that we can duplicate and make more quests out of later.

Step 1 Create your package – /bq create BetonTutorial

This command will create a brand new package in the plugin folder called BetonTutorial.

Step 2 Create your NPC we’ll be using – /npc create TutorialJane

I would also like to give a nice skin to TutorialJane, I’ll do so by hosting it on mineskin.org and copying the texture url into our Citizens command (In this example a Beidou skin from Genshin Impact made by maki on PMC).

Cool fact: mineskin.org hosts the skins on Mojang servers using volunteer accounts so the link we get is a minecraft.net url.

/npc skin –url http://textures.minecraft.net/texture/85da43c4634bcc4585426f3107aec03260d99fc89ac266602187e950ec1d54df

Step 3 get the NPC ID and paste it in your main.yml

/npc id – This command gives us the NPC ID.
In my server this NPC has the ID 425.

Now let’s add it to our conversation by editing main.yml in the new package.

npcs:
  '425': TutorialJane

Let’s also add in our variables for the journal while inside of main.yml

npcs:
  '425': TutorialJane
variables:
    quest_name: A Tutorial Quest
    quester_name: TutorialJane
    journal_headline: $default.journal_head_prefix$$quest_name$$default.journal_head_suffix$

These variables will control the name of the quest and formatting on the main journal page that the player sees.

Next add in our Journal main page settings for the package.

npcs:
  '425': "TutorialJane"
variables:
    quest_name: "A Tutorial Quest"
    quester_name: "TutorialJane"
    journal_headline: "$default.journal_head_prefix$$quest_name$$default.journal_head_suffix$"
journal_main_page:
    can_started:
        priority: 2
        text: '  $default.journal_status_1$$quest_name$'
        conditions: '!started,!finished'
    started:
        priority: 1
        text: '  $default.journal_status_2$$quest_name$'
        conditions: 'started'
    finished:
        priority: 3
        text: '  $default.journal_status_3$$quest_name$'
        conditions: 'finished'

These control the formatting of the quest name in the journal main page for the player (Available, Started, Finished).

Step 4 set up our basic conditions in conditions.yml

started: point step 1
finished: point step -1 equal

step_1: point step 1
step_2: point step 2
step_3: point step 3
step_4: point step 4
step_5: point step 5
step_6: point step 6
step_7: point step 7
step_8: point step 8
step_9: point step 9
step_10: point step 10

Here we have our started and finished conditions to control quest markers and journal quest status.

We also have our step conditions which we’ll talk more about in a second.

Step 5 conversation basic setup

Go into the conversations folder, you should have a conversation called “innkeeper” please rename this to TutorialJane.

Replace everything inside that file with:

quester: 'TutorialJane'
first: 'npc_1'
stop: 'false'
NPC_options:
    npc_1:
        text: |
            
            Example Text
        pointer: player_1
player_options:
    player_1:
        text: Example player response

You may see that the NPC option is a bit weirdly formatted, this is the way we’ll create them for this quest so they look better, this formatting was given to me by Wolf (BQ Dev), see why we use it:

With normal formatting
With our custom formatting provided by Wolf

It simply gives us some more spacing and looks very nice once we write longer messages. The difference is not very obvious from these pictures but you’ll see further down.

Step 6 replace everything in the events.yml with our main step events.

journal_update: journal update
step_add: point step 1
step_rem: point step -1
step_del: point step *0
step_finish: folder step_del,step_rem

started_quest_journal_delay: folder journal_add_step_1,journal_update delay:1
started_quest: folder step_add,started_quest_journal_delay
finished_quest_notify: notify io:totem custommodeldata:4 sound:ui.toast.challenge_complete category:quest_finished
finished_quest: folder step_finish,finished_quest_notify

journal_add_step_1: journal add step_1
journal_del_step_1: journal delete step_1

These are the basics we’re going to need to create an amazing quest.

Step 7 get rid of all the other default quest stuff in the files that was created when doing BQ Create command.

If you wish to download the whole pack I’ve created so far above, click here.

Your files should now look like this.

main.yml

variables:
    quest_name: A Tutorial Quest
    quester_name: TutorialJane
    journal_headline: $default.journal_head_prefix$$quest_name$$default.journal_head_suffix$
npcs:
  '425': TutorialJane
journal_main_page:
    can_started:
        priority: 2
        text: '  $default.journal_status_1$$quest_name$'
        conditions: '!started,!finished'
    started:
        priority: 1
        text: '  $default.journal_status_2$$quest_name$'
        conditions: 'started'
    finished:
        priority: 3
        text: '  $default.journal_status_3$$quest_name$'
        conditions: 'finished'

conditions.yml

started: point step 1
finished: point step -1 equal

step_1: point step 1
step_2: point step 2
step_3: point step 3
step_4: point step 4
step_5: point step 5
step_6: point step 6
step_7: point step 7
step_8: point step 8
step_9: point step 9
step_10: point step 10

events.yml

journal_update: journal update
step_add: point step 1
step_rem: point step -1
step_del: point step *0
step_finish: folder step_del,step_rem

started_quest_journal_delay: folder journal_add_step_1,journal_update delay:1
started_quest: folder step_add,started_quest_journal_delay
finished_quest_notify: notify io:totem custommodeldata:4 sound:ui.toast.challenge_complete category:quest_finished
finished_quest: folder step_finish,finished_quest_notify

journal_add_step_1: journal add step_1
journal_del_step_1: journal delete step_1

TutorialJane.yml (in conversations)

quester: 'TutorialJane'
first: 'npc_1'
stop: 'false'
NPC_options:
    npc_1:
        text: |
            
            Example Text
        pointer: player_1
player_options:
    player_1:
        text: Example player response

The rest of the files should be empty.

If you now reload BQ you should see “A tutorial quest” in the journal quest list:

If your journal don’t have Quest Status and Quest list, I suggest checking out chapter 2 where we walked through how to create a nice journal setup in the default package.

You now have a very good template package that you can duplicate and create multiple quests with.

It’s time to actually write our quest and story. Many people start writing the NPC conversation first because it feels natural but the best practice is to write all the journal entries first, this gives you a written storyboard that you can then develop the configs around.

So let’s start by writing some story that the player will be able to read in their journal (edit journal.yml):

step_1: >-
    $journal_headline$
      TutorialJane has asked me to mine 10 iron ore and then bring her 5 Iron Ingots.
step_2: >-
    $journal_headline$
      I've mined the 10 iron ore that TutorialJane asked me to, I should bring her 5 Iron Ingots.
step_3: >-
    $journal_headline$
      TutorialJane gave me 1 diamond as a reward for the 5 ingots I brought her, I wonder if she has another task for me.
step_4: >-
    $journal_headline$
      TutorialJane gave me 1 diamond as a reward for the 5 ingots, now she wants me to kill 10 zombies.
step_5: >-
    $journal_headline$
      I've killed the 10 zombies, I should return to TutorialJane.
step_6: >-
    $journal_headline$
      TutorialJane rewarded me with a Netherite Sword for completing some tasks.

Here you can see that we’ve added 6 steps to this quest. First the NPC shall ask us to mine 10 iron ore and then bring her 5 iron ingots. After that she’ll ask us to kill 10 zombies and if we complete the entire quest we will get rewarded with a Netherite Sword.

Step 3 might seem unnecessary right now, but this step is created so that if the player interrupts the conversation in between turning in the first task and accepting the next one we have some content to make them go back there.

This is a very simple quest and there is not much story to it, I’m sure your imagination after this tutorial will be much better.

Now to be able to create this quest we’ll have to edit our events.yml and add in all the journal steps we need:

journal_update: journal update
step_add: point step 1
step_rem: point step -1
step_del: point step *0
step_finish: folder step_del,step_rem

started_quest_journal_delay: folder journal_add_step_1,journal_update delay:1
started_quest: folder step_add,started_quest_journal_delay
finished_quest_notify: notify io:totem custommodeldata:4 sound:ui.toast.challenge_complete category:quest_finished
finished_quest: folder step_finish,finished_quest_notify

journal_add_step_1: journal add step_1
journal_del_step_1: journal delete step_1

step_1_completed: folder step_add,journal_del_step_1,journal_add_step_2,journal_update
journal_add_step_2: journal add step_2
journal_del_step_2: journal delete step_2

step_2_completed: folder step_add,journal_del_step_2,journal_add_step_3,journal_update
journal_add_step_3: journal add step_3
journal_del_step_3: journal delete step_3

step_3_completed: folder step_add,journal_del_step_3,journal_add_step_4,journal_update
journal_add_step_4: journal add step_4
journal_del_step_4: journal delete step_4

step_4_completed: folder step_add,journal_del_step_4,journal_add_step_5,journal_update
journal_add_step_5: journal add step_5
journal_del_step_5: journal delete step_5

step_5_completed: folder step_add,journal_del_step_5,journal_add_step_6,journal_update
journal_add_step_6: journal add step_6

These new entries into our events.yml (in bold) are made for a few things:

  • step_add
    • This will add 1 point to our point system, see further down for more info.
  • journal_del_step_X
    • This event will delete the previous journal entry.
  • journal_add_step_X
    • This event will add our next journal entry.
  • journal_update
    • This will update the journal in the players inventory.

The points system we use for steps in the quest

The point event gives the player a specified amount of points within a category that you can name, we use the name “step” for the quest step system.

It’s a nice and easy way to to keep track of where in a quest the player is at, remember the conditions we created? Example:

step_3: point step 3
step_4: point step 4
  • Adding step_3 condition to a conversation option will make it only be available if the player has the point named “step” as 3 or higher.
  • This means that we can add step_3 and !step_4 (see the ! this means it’s negated) and that makes the conversation option only available if you are on step 3 or higher and NOT step 4 or higher in the point system (so only on step 3) .

We also added these events in our events.yml:

step_add: point step 1
step_rem: point step -1
step_del: point step *0
step_finish: folder step_del,step_rem
  • step_add adds 1 point to the point “step”, just like we explained above.
  • step_rem is something we can use if we ever want to remove a point.
  • step_del would reset the entire point “step” for the user to 0.
  • step_finish will reset the point to 0 and then go to -1
    • This makes it so we always know that -1 means we’ve completed the entire quest.

Other things you can use the point system for:

  • Reputation with factions/guilds/towns like an in an RPG.
    • Unlock new shops, ranks, titles, quests and more depending on your reputation.
  • Keeping track and creating placeholders for amount of daily quests completed today (see next chapter).
  • Whatever your imagination can come up with..

Items used in the quest

It’s time to set up the different items we want in the quest. The easiest way to do this is to hold the item and typing /bq item {package.itemID}

Let’s start by adding our iron ingots that we’ll need to complete task 1. Hold an iron ingot in your hand and type /q item BetonTutorial.ironingot

This will automatically add this line to the items.yml:

ironingot: IRON_INGOT

Next let’s add the Netherite Sword that we want to give as a reward on quest completion, I’ll be using a sword that looks like this:

By holding it and typing /bq item BetonTutorial.RewardSword – we’ll get this config:

ironingot: IRON_INGOT
RewardSword: NETHERITE_SWORD name:§f§lTutorialJane's_Netherite_Sword enchants:DAMAGE_ALL:2,DURABILITY:2

And then lastly the block we wish to mine for an objective, but I want to spice things up and let the player mine both normal Iron ore and deepslate iron ore. So let’s add a variable.

To make that variable we open the main.yml again and add it in:

variables:
    quest_name: A Tutorial Quest
    quester_name: TutorialJane
    journal_headline: $default.journal_head_prefix$$quest_name$$default.journal_head_suffix$
    customore: '.*iron_ore'

npcs:
  '425': TutorialJane
journal_main_page:
    can_started:
        priority: 2
        text: '  $default.journal_status_1$$quest_name$'
        conditions: '!started,!finished'
    started:
        priority: 1
        text: '  $default.journal_status_2$$quest_name$'
        conditions: 'started'
    finished:
        priority: 3
        text: '  $default.journal_status_3$$quest_name$'
        conditions: 'finished'

This new variable “customore” will match with any blocks which name ends with “iron_ore” including deepslate_iron_ore.

The default package in BetonQuest also has a similar example variable that matches with all blocks ending with _log

Next up let’s create the objectives we need for the quest

In this planned quest we need 2 objectives, we need one to mine 10 iron ore and one to kill 10 zombies. Open the objectives.yml and type this:

mineore: block $customore$ -10 event:step_1_completed
slayzombies: mobkill ZOMBIE 10 event:step_4_completed

As you can see we now have 2 objectives that when completed runs the step_X_completed events that fits with our journal.yml story.

Time to write some conversation.yml lines, so lets open our TutorialJane.yml and write this:

quester: 'TutorialJane'
first: 'npc_0_1'
stop: 'false'
NPC_options:
    npc_0_1:
        text: |
            
            Hello adventurer, what a fine day we're having!
        pointer: player_0_1,player_0_2,player_end
        conditions: '!started,!finished,!step_1'
    npc_0_2:
        text: |
            
            If you have some time to spare I would love help with a few tasks.
            There's a weapon and a diamond in it for you.
        pointer: player_0_3,player_end
    npc_0_3:
        text: |
            
            I'd love it if you mine 10 iron ore and then bring me back 5 iron ingots.
            Could you do that?
        pointer: player_0_4,player_end
player_options:
    player_0_1:
        text: Yes we are!
        pointer: npc_0_2
    player_0_2:
        text: Do you have a quest for me?
        pointer: npc_0_2
    player_0_3:
        text: That sound nice, how can I help?
        pointer: npc_0_3
    player_0_4:
        text: Consider it done!
        events: started_quest
    player_end:
        text: Good bye

This gives us all the conversation we need until task number 1, which is to mine 10 iron ore.

A few important facts to pay attention to here:

  • As you can tell I’ve named all our current conversation options npc_0_X and player_0_X, this is to keep track on that we are at step 0 in the quest, as soon as we run the “started_quest” event we end up on step 1.
  • You can see at the top of the file we have first: ‘npc_0_1’ this means that the conversation with this NPC can only start on that npc option.
  • The NPC option npc_0_1 has some conditions, which is:
    • !started (not started the quest)
    • !finished (not finished the quest)
    • !step_1 (not on step 1 or above)

These conditions will make it so once we start the quest we can not talk to the npc again without adding more npc options to the “first” setting.

However we have not actually given ourselves the objective yet. So let’s make sure that happens on player option player_0_4 event “started_quest”

Open the Events.yml

journal_update: journal update
step_add: point step 1
step_rem: point step -1
step_del: point step *0
step_finish: folder step_del,step_rem

started_quest_journal_delay: folder journal_add_step_1,journal_update delay:1
started_quest: folder step_add,started_quest_journal_delay,give_objective_1
finished_quest_notify: notify io:totem custommodeldata:4 sound:ui.toast.challenge_complete category:quest_finished
finished_quest: folder step_finish,finished_quest_notify

give_objective_1: objective start mineore

journal_add_step_1: journal add step_1
journal_del_step_1: journal delete step_1

step_1_completed: folder step_add,journal_del_step_1,journal_add_step_2,journal_update
journal_add_step_2: journal add step_2
journal_del_step_2: journal delete step_2

step_2_completed: folder step_add,journal_del_step_2,journal_add_step_3,journal_update
journal_add_step_3: journal add step_3
journal_del_step_3: journal delete step_3

step_3_completed: folder step_add,journal_del_step_3,journal_add_step_4,journal_update
journal_add_step_4: journal add step_4
journal_del_step_4: journal delete step_4

step_4_completed: folder step_add,journal_del_step_4,journal_add_step_5,journal_update
journal_add_step_5: journal add step_5
journal_del_step_5: journal delete step_5

step_5_completed: folder step_add,journal_del_step_5,journal_add_step_6,journal_update
journal_add_step_6: journal add step_6

Here I’ve added 2 things, I created the “give_objective_1” event + added it to the “started_quest” event folder which we run when the player clicks player_0_4.

As we can see, if we now accept the quest from TutorialJane we have 2 changes in our Journal, the main page has changed and the quest name “A Tutorial Quest” has become yellow/gold because it’s started and we’ve got our first quest entry on the last page of the journal.

And as soon as we mine a total of 10 iron ore or deepslate iron ore, it updates to this thanks to the objective completing and running the event “step_1_completed”, this also gives the player a notification as if they are getting an achievement that says “journal updated”, thanks to the event journal_update.

Next let’s add a conversation update that happens on step 1. Which means:

  • The quest is started.
  • We’ve not reached step 2 yet (mined the ore).

Update your TutorialJane.yml

quester: 'TutorialJane'
first: 'npc_0_1,npc_1_1'
stop: 'false'
NPC_options:
    npc_0_1:
        text: |
            
            Hello adventurer, what a fine day we're having!
        pointer: player_0_1,player_0_2,player_end
        conditions: '!started,!finished,!step_1'
    npc_0_2:
        text: |
            
            If you have some time to spare I would love help with a few tasks.
            There's a weapon and a diamond in it for you.
        pointer: player_0_3,player_end
    npc_0_3:
        text: |
            
            I'd love it if you mine 10 iron ore and then bring me back 5 iron ingots.
            Could you do that?
        pointer: player_0_4,player_end

    npc_1_1:
        text: |
            
            Hello again, did you mine those 10 iron ore I asked?
        pointer: player_1_1
        conditions: 'step_1,!step_2'

player_options:
    player_0_1:
        text: Yes we are!
        pointer: npc_0_2
    player_0_2:
        text: Do you have a quest for me?
        pointer: npc_0_2
    player_0_3:
        text: That sound nice, how can I help?
        pointer: npc_0_3
    player_0_4:
        text: Consider it done!
        events: started_quest

    player_1_1:
        text: Not yet.

    player_end:
        text: Good bye

Now we’ve changed these things:

  • Added another “first” option, so if the conditions of NPC option npc_1_1 is all valid, that’s where the conversation starts.
  • Added a player response called player_1_1.

This is what it looks like:

Next let’s add options for if the player is on step 2:

quester: 'TutorialJane'
first: 'npc_0_1,npc_1_1'
stop: 'false'
NPC_options:
    npc_0_1:
        text: |
            
            Hello adventurer, what a fine day we're having!
        pointer: player_0_1,player_0_2,player_end
        conditions: '!started,!finished,!step_1'
    npc_0_2:
        text: |
            
            If you have some time to spare I would love help with a few tasks.
            There's a weapon and a diamond in it for you.
        pointer: player_0_3,player_end
    npc_0_3:
        text: |
            
            I'd love it if you mine 10 iron ore and then bring me back 5 iron ingots.
            Could you do that?
        pointer: player_0_4,player_end

    npc_1_1:
        text: |
            
            Hello again, did you mine those 10 iron ore I asked?
        pointer: player_2_1,player_1_1
        conditions: 'step_1,!step_3'

    npc_2_1:
        text: |
            
            Too bad, come back when you have them.

player_options:
    player_0_1:
        text: Yes we are!
        pointer: npc_0_2
    player_0_2:
        text: Do you have a quest for me?
        pointer: npc_0_2
    player_0_3:
        text: That sound nice, how can I help?
        pointer: npc_0_3
    player_0_4:
        text: Consider it done!
        events: started_quest

    player_1_1:
        text: Not yet.

    player_2_1:
        text: Yes, but I don't have the 5 iron ingots yet.
        conditions: 'step_2'
        pointer: npc_2_1

    player_end:
        text: Good bye

Here we have changed these things:

  • Changed so that npc_1_1 has a new pointer and changed the condition !step_2 to !step_3, so that it shows up if you are on step 1 or 2.
  • New player option player_2_1 that only shows up if we are on step 2, not step 1.

Here’s what the new conversations look like:

Now we’re going to have to create a condition to see if the player has 5 or more iron ingots in their inventory, so open conditions.yml and add this:

started: point step 1
finished: point step -1 equal

step_1: point step 1
step_2: point step 2
step_3: point step 3
step_4: point step 4
step_5: point step 5
step_6: point step 6
step_7: point step 7
step_8: point step 8
step_9: point step 9
step_10: point step 10

iron_inventory: item ironingot:5

With this new condition “iron_inventory” we can check if the player has 5 iron ingots in their inventory.

Let’s also add an event to take the ingots from the player. Edit events.yml

journal_update: journal update
step_add: point step 1
step_rem: point step -1
step_del: point step *0
step_finish: folder step_del,step_rem

started_quest_journal_delay: folder journal_add_step_1,journal_update delay:1
started_quest: folder step_add,started_quest_journal_delay,give_objective_1
finished_quest_notify: notify io:totem custommodeldata:4 sound:ui.toast.challenge_complete category:quest_finished
finished_quest: folder step_finish,finished_quest_notify

give_objective_1: objective start mineore

journal_add_step_1: journal add step_1
journal_del_step_1: journal delete step_1

step_1_completed: folder step_add,journal_del_step_1,journal_add_step_2,journal_update
journal_add_step_2: journal add step_2
journal_del_step_2: journal delete step_2

step_2_completed: folder step_add,journal_del_step_2,journal_add_step_3,journal_update
journal_add_step_3: journal add step_3
journal_del_step_3: journal delete step_3

take_ingots: take ironingot:5 notify

step_3_completed: folder step_add,journal_del_step_3,journal_add_step_4,journal_update
journal_add_step_4: journal add step_4
journal_del_step_4: journal delete step_4

step_4_completed: folder step_add,journal_del_step_4,journal_add_step_5,journal_update
journal_add_step_5: journal add step_5
journal_del_step_5: journal delete step_5

step_5_completed: folder step_add,journal_del_step_5,journal_add_step_6,journal_update
journal_add_step_6: journal add step_6

We added the new event “take_ingot”, which will take 5 ironingots (defined in items.yml) and notify the player that it’s happened.

We can now add more conversation options but first we create the event for adding our zombie killing objective in the events.yml

journal_update: journal update
step_add: point step 1
step_rem: point step -1
step_del: point step *0
step_finish: folder step_del,step_rem

started_quest_journal_delay: folder journal_add_step_1,journal_update delay:1
started_quest: folder step_add,started_quest_journal_delay,give_objective_1
finished_quest_notify: notify io:totem custommodeldata:4 sound:ui.toast.challenge_complete category:quest_finished
finished_quest: folder step_finish,finished_quest_notify

give_objective_1: objective start mineore

journal_add_step_1: journal add step_1
journal_del_step_1: journal delete step_1

step_1_completed: folder step_add,journal_del_step_1,journal_add_step_2,journal_update
journal_add_step_2: journal add step_2
journal_del_step_2: journal delete step_2

step_2_completed: folder step_add,journal_del_step_2,journal_add_step_3,journal_update
journal_add_step_3: journal add step_3
journal_del_step_3: journal delete step_3

take_ingots: take ironingot:5 notify

step_3_completed: folder step_add,journal_del_step_3,journal_add_step_4,journal_update
journal_add_step_4: journal add step_4
journal_del_step_4: journal delete step_4

give_objective_2: objective start slayzombies

step_4_completed: folder step_add,journal_del_step_4,journal_add_step_5,journal_update
journal_add_step_5: journal add step_5
journal_del_step_5: journal delete step_5

step_5_completed: folder step_add,journal_del_step_5,journal_add_step_6,journal_update
journal_add_step_6: journal add step_6

Now we can continue building our conversation:

quester: 'TutorialJane'
first: 'npc_0_1,npc_1_1,npc_3_1'
stop: 'false'
NPC_options:
    npc_0_1:
        text: |
            
            Hello adventurer, what a fine day we're having!
        pointer: player_0_1,player_0_2,player_end
        conditions: '!started,!finished,!step_1'
    npc_0_2:
        text: |
            
            If you have some time to spare I would love help with a few tasks.
            There's a weapon and a diamond in it for you.
        pointer: player_0_3,player_end
    npc_0_3:
        text: |
            
            I'd love it if you mine 10 iron ore and then bring me back 5 iron ingots.
            Could you do that?
        pointer: player_0_4,player_end

    npc_1_1:
        text: |
            
            Hello again, did you mine those 10 iron ore I asked?
        pointer: player_2_2,player_2_1,player_1_1
        conditions: 'step_1,!step_3'

    npc_2_1:
        text: |
            
            Too bad, come back when you have them.
    npc_2_2:
        text: |
            
            Thank you for the ingots! Are you ready for your next task?
        pointer: player_3_1,player_end

    npc_3_1:
        text: |
            
            Your next task is to kill 10 zombies, are you up for the challange?
        pointer: player_3_2,player_end
        conditions: 'step_3,!step_4'

player_options:
    player_0_1:
        text: Yes we are!
        pointer: npc_0_2
    player_0_2:
        text: Do you have a quest for me?
        pointer: npc_0_2
    player_0_3:
        text: That sound nice, how can I help?
        pointer: npc_0_3
    player_0_4:
        text: Consider it done!
        events: started_quest

    player_1_1:
        text: Not yet.

    player_2_1:
        text: Yes, but I don't have the 5 iron ingots yet.
        conditions: 'step_2,!iron_inventory'
        pointer: npc_2_1
    player_2_2:
        text: Yes, and I have your ingots.
        conditions: 'step_2,iron_inventory'
        pointer: npc_2_2
        events: 'take_ingots,step_2_completed'

    player_3_1:
        text: Yes
        pointer: npc_3_1
    player_3_2:
        text: I will kill the 10 zombies, don't worry.
        events: 'step_3_completed,give_objective_2'

    player_end:
        text: Good bye

As you can see here we’ve added in a few more conversation options.

  • By now you’ve realized that I keep making spaces in between each quest step, so player_1_x has an empty row before player_2_x. This is a nice way to keep track of where we are in the quest compared to our journal story.
  • We now have a third pointer on npc_1_1
    • player_2_2 shows if we have completed the mining of ore + have the ingots in our inventory.
    • player_2_1 shows if we have completed the mining and don’t have the ingots.
    • player_1_1 shows if we have not completed the mining.
  • We’ve added another “first” option so the conversation can start on npc_3_1 if the player interrupts the conversation between turning in the old task and getting the new one.
  • player_3_2 will give the player the objective to kill zombies + complete step 3/give us step 4.

Here’s how the new conversations look when talking to the NPC:

Let’s add a simple start npc option for when you are on step 4 (have the objective to kill zombies but have not killed them yet).

quester: 'TutorialJane'
first: 'npc_0_1,npc_1_1,npc_3_1,npc_4_1'
stop: 'false'
NPC_options:
    npc_0_1:
        text: |
            
            Hello adventurer, what a fine day we're having!
        pointer: player_0_1,player_0_2,player_end
        conditions: '!started,!finished,!step_1'
    npc_0_2:
        text: |
            
            If you have some time to spare I would love help with a few tasks.
            There's a weapon and a diamond in it for you.
        pointer: player_0_3,player_end
    npc_0_3:
        text: |
            
            I'd love it if you mine 10 iron ore and then bring me back 5 iron ingots.
            Could you do that?
        pointer: player_0_4,player_end

    npc_1_1:
        text: |
            
            Hello again, did you mine those 10 iron ore I asked?
        pointer: player_2_2,player_2_1,player_1_1
        conditions: 'step_1,!step_3'

    npc_2_1:
        text: |
            
            Too bad, come back when you have them.
    npc_2_2:
        text: |
            
            Thank you for the ingots! Are you ready for your next task?
        pointer: player_3_1,player_end

    npc_3_1:
        text: |
            
            Your next task is to kill 10 zombies, are you up for the challange?
        pointer: player_3_2,player_end
        conditions: 'step_3,!step_4'

    npc_4_1:
        text: |
            
            Come back when you killed 10 zombies.
        conditions: 'step_4,!step_5'

player_options:
    player_0_1:
        text: Yes we are!
        pointer: npc_0_2
    player_0_2:
        text: Do you have a quest for me?
        pointer: npc_0_2
    player_0_3:
        text: That sound nice, how can I help?
        pointer: npc_0_3
    player_0_4:
        text: Consider it done!
        events: started_quest

    player_1_1:
        text: Not yet.

    player_2_1:
        text: Yes, but I don't have the 5 iron ingots yet.
        conditions: 'step_2,!iron_inventory'
        pointer: npc_2_1
    player_2_2:
        text: Yes, and I have your ingots.
        conditions: 'step_2,iron_inventory'
        pointer: npc_2_2
        events: 'take_ingots,step_2_completed'

    player_3_1:
        text: Yes
        pointer: npc_3_1
    player_3_2:
        text: I will kill the 10 zombies, don't worry.
        events: 'step_3_completed,give_objective_2'

    player_end:
        text: Good bye

Here’s what that will show:

Now our final conversations, turning in the quest and something nice for the npc to say when we try to talk to her after completing the entire quest. But first let’s add the event to give us the final reward, open events.yml:

journal_update: journal update
step_add: point step 1
step_rem: point step -1
step_del: point step *0
step_finish: folder step_del,step_rem

started_quest_journal_delay: folder journal_add_step_1,journal_update delay:1
started_quest: folder step_add,started_quest_journal_delay,give_objective_1
finished_quest_notify: notify io:totem custommodeldata:4 sound:ui.toast.challenge_complete category:quest_finished
finished_quest: folder step_finish,finished_quest_notify

give_objective_1: objective start mineore

journal_add_step_1: journal add step_1
journal_del_step_1: journal delete step_1

step_1_completed: folder step_add,journal_del_step_1,journal_add_step_2,journal_update
journal_add_step_2: journal add step_2
journal_del_step_2: journal delete step_2

step_2_completed: folder step_add,journal_del_step_2,journal_add_step_3,journal_update
journal_add_step_3: journal add step_3
journal_del_step_3: journal delete step_3

take_ingots: take ironingot:5 notify

step_3_completed: folder step_add,journal_del_step_3,journal_add_step_4,journal_update
journal_add_step_4: journal add step_4
journal_del_step_4: journal delete step_4

give_objective_2: objective start slayzombies

step_4_completed: folder step_add,journal_del_step_4,journal_add_step_5,journal_update
journal_add_step_5: journal add step_5
journal_del_step_5: journal delete step_5

step_5_completed: folder step_add,journal_del_step_5,journal_add_step_6,journal_update
journal_add_step_6: journal add step_6

reward_player: give RewardSword:1

Now we have the event “reward_player” that will give us the enchanted netherite sword defines in items.yml.

Final conversation edits:

quester: 'TutorialJane'
first: 'npc_0_1,npc_1_1,npc_3_1,npc_4_1,npc_5_1,npc_6_1'
stop: 'false'
NPC_options:
    npc_0_1:
        text: |
            
            Hello adventurer, what a fine day we're having!
        pointer: player_0_1,player_0_2,player_end
        conditions: '!started,!finished,!step_1'
    npc_0_2:
        text: |
            
            If you have some time to spare I would love help with a few tasks.
            There's a weapon and a diamond in it for you.
        pointer: player_0_3,player_end
    npc_0_3:
        text: |
            
            I'd love it if you mine 10 iron ore and then bring me back 5 iron ingots.
            Could you do that?
        pointer: player_0_4,player_end

    npc_1_1:
        text: |
            
            Hello again, did you mine those 10 iron ore I asked?
        pointer: player_2_2,player_2_1,player_1_1
        conditions: 'step_1,!step_3'

    npc_2_1:
        text: |
            
            Too bad, come back when you have them.
    npc_2_2:
        text: |
            
            Thank you for the ingots! Are you ready for your next task?
        pointer: player_3_1,player_end

    npc_3_1:
        text: |
            
            Your next task is to kill 10 zombies, are you up for the challange?
        pointer: player_3_2,player_end
        conditions: 'step_3,!step_4'

    npc_4_1:
        text: |
            
            Come back when you killed 10 zombies.
        conditions: 'step_4,!step_5'

    npc_5_1:
        text: |
            
            You killed the zombies! Thank you for the help.
        conditions: 'step_5,!finished'
        pointer: player_5_1

    npc_6_1:
        text: |
            
            Thank you for the help yet again, I hope that sword came to good use.
        conditions: 'finished'

player_options:
    player_0_1:
        text: Yes we are!
        pointer: npc_0_2
    player_0_2:
        text: Do you have a quest for me?
        pointer: npc_0_2
    player_0_3:
        text: That sound nice, how can I help?
        pointer: npc_0_3
    player_0_4:
        text: Consider it done!
        events: started_quest

    player_1_1:
        text: Not yet.

    player_2_1:
        text: Yes, but I don't have the 5 iron ingots yet.
        conditions: 'step_2,!iron_inventory'
        pointer: npc_2_1
    player_2_2:
        text: Yes, and I have your ingots.
        conditions: 'step_2,iron_inventory'
        pointer: npc_2_2
        events: 'take_ingots,step_2_completed'

    player_3_1:
        text: Yes
        pointer: npc_3_1
    player_3_2:
        text: I will kill the 10 zombies, don't worry.
        events: 'step_3_completed,give_objective_2'

    player_5_1:
        text: You're very welcome!
        events: 'step_5_completed,reward_player,step_finish'

    player_end:
        text: Good bye

This was our final conversation edit and the quest is now fully functional!

What we changed:

  • Added npc_5_1 which is available after the player has killed the 10 zombies.
  • Added player_5_1 which is the players response to npc_5_1 and also completes the quest + gives you the netherite sword.
  • Added npc_6_1 which is a conversation option for when the quest is completed and you return to the NPC.
  • Added npc_6_1 to the first options so the conversation can start with it.

Well done! Here is a download of the entire BetonTutorial package/quest we’ve made together: Download here.

Chapter 5: Repeatable/Daily Quests

You’ve reached chapter 5? Well done adventurer, you’re on a great track to becoming a quest master.

It’s time to make repeatable quests, or daily quests as most call them. Here we’re going to step into the world of content that a server can redo day after day. What we’ll learn:

  • How to use global point events (Like a normal point value but for all players combined).
  • How to run static events to reset systems at midnight.
  • How to use tags.
  • How to use placeholders to display and inform the players about their progress, both individual and globally.
  • How to reward players for reaching global daily goals together.
  • … and probably a bunch more.

There are tons of ways to do daily quests, this is our favorite method that rewards the player for each quest and the entire server for reaching global goals.

In this chapter we’ll be making the global systems for dailys to hook into and then a fishing daily quest. If you don’t want to follow along step by step the quest will be available for download at the end of the chapter.

Let’s start by creating some event’s inside our default package events.yml

point_daily_add: point totaldailies 1
point_daily_reset: point totaldailies *0

globalpoint_add_point: globalpoint totaldailies 1
globalpoint_daily_reset: globalpoint totaldailies *0

globalpoint_daily_add: folder globalpoint_add_point,dailynotify,reward_all_players

dailynotify: notifyall Quest Goal Reached!\nEveryone gets 2x Vote Keys io:title conditions:totaldailies

reward_all_players: folder reward_keys,globalpoint_daily_reset conditions:totaldailies
reward_keys: command crates giveall p vote 2

Now we have a few new events in the default package that we can call upon from all daily quests packages we’ll make.

  • globalpoint totaldailies – This value shows how many daily quests the entire server has completed.
    • Can be shown using PlaceholderAPI %betonquest_default:globalpoint.totaldailies.amount%
  • point totaldailies – This value shows how many daily quests the specific player has completed.
    • Can be shown using PlaceholderAPI %betonquest_default:point.totaldailies.amount%
  • I’ve also added in a folder event to reward all players on the server if we hit a target daily goal. To make this work we need to create our condition in the default package:
totaldailies: globalpoint totaldailies 24

To reset these values at midnight server time we need to edit the main.yml and add in some static events:

static:
  '00:00': globalpoint_daily_reset
  '00:00': point_daily_reset

These static events run our reset events we created above.

While we’re in the main.yml config we might as well set up our daily/repeatable quests for the journal. We’ll add some stuff to our journal_main_page settings.

journal_main_page:
    legende:
        priority: 0
        text: >-
            $journal_head_prefix$Quest Status$journal_head_suffix$
              $journal_status_4_name$
              $journal_status_1_name$
              $journal_status_2_name$
              $journal_status_3_name$

            $journal_head_prefix$Quest List$journal_head_suffix$
    quests:
        priority: 5
        text: >-
            $journal_head_prefix$Repeatable Quests$journal_head_suffix$
    dailyquests:
        priority: 10
        text: >-
        
            
    dailyquestservergoal:
        priority: 25
        text: >-
            |$journal_head_prefix$Server Daily Goals$journal_head_suffix$
            
            If the whole server complete 25 daily quests together in a day, everyone online at that moment get 2x Vote Keys each.
            Currently: &6%globalpoint.totaldailies.amount%/25.
            &7&oType &0&o/journal &7&oagain to refresh stats.

We’ve added:

  • $journal_head_prefix$Repeatable Quests$journal_head_suffix$
    • A page header for our list of daily quests.
  • A daily quests section with priority 10+
    • This means that when we create our daily quests, we can set them to priority over 10 and they will end up in a seperate list from the normal quests that are 5-9 priority.
  • Dailyquestsservergoal section with information about the global daily goal for the server.

Here’s some example pictures:

Let’s make a new package for a daily quest.

The way we tend to structure daily quests is per hub or per city. So we recommend that you make folders within the betonquest plugin folder like this:

  • BetonQuest
    • default
    • dailys
      • quest 1
      • quest 2
      • quest 3

We will not go through how to create an NPC again, for that please go back to the previous chapter.

Let’s start off by writing our journal for the quest.

step_1: >-
    $journal_headline$
      Rita seems to be crazy about fishing and asked me to catch 25 salmon.
step_2: >-
    $journal_headline$
      I've cought the 25 salmon for Rita and should go see her in the spawn harbour.
step_3: >-
    $journal_headline$
      Rita gave me 50 coins and 2 gems for catching 25 salmon, and I got to keep the fish.

In this daily quest our NPC “Rita” will ask the player to catch 25 salmon, she will also let the player keep the fish on turning the quest in.

Next up we’ll need some events, let’s start tags which we’ll use instead of the step system from the previous chapter:

clear_all: folder step_del,journal_del_step_all
clear_all_tags: 'tag del started,done,rewarded'
tag_started: 'tag add started'
tag_done: 'tag add done'
tag_rewarded: 'tag add rewarded'

What are tags?

Tags are just a text based piece of information assigned to a player, which we can check in conditions if the player has them or not. It’s easier to use for short and simple quests then the point system used in our previous chapter.

Let’s have a look at the conditions that go with these tags:

started_tag: 'tag started'
done_tag: 'tag done'
rewarded_tag: 'tag rewarded'

Here we can see we have 3 conditions: the first one checks if the player has the tag “started”, the second checks if the player has the tag “done” and the third checks if the player has the tag “rewarded”.

We’ll be using these with our 3 steps in the journal accordingly.

Next up let’s write up the conversation first bit of conversation to understand tags more:

quester: Rita
first: dialog_1_1
NPC_options:
    dialog_1_1:
        text: |
            
            Hello there! Do you like fishing?
        pointer: dialog_1_1_1,dialog_1_1_2
        conditions: '!started_tag'

Here we see that Rita will say to the player “Hello there! Do you like fishing?”, but only if the conditions started_tag is false.

The rest of our conversation:

# Example
quester: Rita
first: dialog_1_1,dialog_1_4,dialog_1_3,dialog_2_2
NPC_options:
    dialog_1_1:
        text: |
            
            Hello there! Do you like fishing?
        pointer: dialog_1_1_1,dialog_1_1_2
        conditions: '!started_tag'
    dialog_1_2:
        text: |
            
            OH that's great, Fluff and I LOVE fishing! Maybe you could help me catch 25 salmon? I'll give you 50 coins.
        pointer: dialog_1_1_3,dialog_1_1_2
    dialog_1_3:
        text: |
            
            Have you had any luck with those 25 salmon yet? Come back when you cought them!
        conditions: 'started_tag,!done_tag'
    dialog_1_4:
        text: |
            
            You did great! Keep the salmon, I am just happy someone else likes fishing. Come back tomorrow if you want to do this again.
            Your Reward:
                $default.color_highlight$- 50 coins.
        conditions: 'done_tag,!rewarded_tag'
        events: reward_player,completed_quest_journal,salmoncountremove,tag_finished
    dialog_2_2:
        text: |
            
            Thank you again for fishing with me! Come back tomorrow if you want to go again.
        conditions: 'rewarded_tag'
player_options:
    dialog_1_1_1:
        text: Yeah, I enjoy fishing sometimes.
        pointer: dialog_1_2
    dialog_1_1_2:
        text: No, bye.
    dialog_1_1_3:
        text: Sure I'll catch 25 salmon.
        events: 'started_quest,salmon,salmoncount'

In this conversation we’ve added events in 2 places:

  • dialog_1_4
    • These are the events we’ll run when we finish the daily quest.
    • reward_player = our folder event for rewards.
    • completed_quest_journal = Folder event to add journal step 3, delete journal event step 2 and update the journal.
    • salmoncountremove, remove the objective we’ll create further down that gives our players a nice quest progress update notify event.
    • tag_done = tags the player with the tag “done”.
  • dialog_1_1_3
    • started_quest = folder event to run everything we need to tag the player, add the first journal step and update the journal.
    • salmon = our quest objective.
    • salmoncount = our objective to notify the player on quest progression, more on that further down.

What the conversation will look like:

Let’s create our objective and journal events first:

clear_all: folder step_del,journal_del_step_all,salmonremove,salmoncountremove
clear_all_tags: 'tag del started,done,rewarded'
tag_started: 'tag add started'
tag_done: 'tag add done'
tag_rewarded: 'tag add rewarded'



salmon: objective start salmon
salmonremove: objective delete salmon

salmoncount: objective start salmoncount
salmoncountremove: objective delete salmoncount
counter: notify Catch %objective.salmon.left% more salmon. io:actionbar

journal_update: journal update


started_quest: folder tag_started,journal_add_step_1,journal_update, delay:1

journal_add_step_1: journal add step_1
journal_del_step_1: journal delete step_1

completed_objective: folder tag_done,journal_add_step_2,journal_del_step_1,journal_update delay:1
journal_add_step_2: journal add step_2
journal_del_step_2: journal delete step_2

completed_quest_journal: folder journal_add_step_3,journal_del_step_2,journal_update delay:1
journal_add_step_3: journal add step_3
journal_del_step_3: journal delete step_3

journal_del_step_all: folder journal_del_step_2,journal_del_step_3,journal_del_step_1

For our objective events to work we need to create the objectives:

salmon: fish SALMON 25 events:completed_objective,salmoncountremove
salmoncount: fish salmon 1 events:counter persistent

The salmon event is quite easy to understand, we need to fish 25 salmon and then the events completed_objective and salmoncountremove runs.

salmoncount, this objective is an interesting one what we have here is a persistent event, which means that every time we complete it, we get the objective again. The objective is to catch 1 salmon, and every time we do the event “counter” will run, which tells us how many salmon we have left to catch from the objective “salmon”. Completing the main salmon objective removes the counter objective.

Like this:

This uses the notify event and the notify IO “actionbar” we can also use IO’s like:

Advancement

Bossbar

Chat

And quite a few more IO’s for the notify event, see all in the official BetonQuest documentation for IO’s and Categories.

Next up: Let’s add our reward events, which is going to bring us into how to make global placeholders that all daily quests can hook into:

clear_all: folder step_del,journal_del_step_all,salmonremove,salmoncountremove
clear_all_tags: 'tag del started,done,rewarded'
tag_started: 'tag add started'
tag_done: 'tag add done'
tag_rewarded: 'tag add rewarded'



salmon: objective start salmon
salmonremove: objective delete salmon

salmoncount: objective start salmoncount
salmoncountremove: objective delete salmoncount
counter: notify Catch %objective.salmon.left% more salmon. io:actionbar

journal_update: journal update


started_quest: folder tag_started,journal_add_step_1,journal_update, delay:1

journal_add_step_1: journal add step_1
journal_del_step_1: journal delete step_1

completed_objective: folder tag_done,journal_add_step_2,journal_del_step_1,journal_update delay:1
journal_add_step_2: journal add step_2
journal_del_step_2: journal delete step_2

completed_quest_journal: folder journal_add_step_3,journal_del_step_2,journal_update delay:1
journal_add_step_3: journal add step_3
journal_del_step_3: journal delete step_3

journal_del_step_all: folder journal_del_step_2,journal_del_step_3,journal_del_step_1

reward_player: folder reward_1,default.globalpoint_daily_add,default.point_daily_add
reward_1: command money give %player% 50

Here we have added the event folder reward_player, which will run our 2 events from the default package in BetonQuest.

Next let’s make sure the actual daily quest package resets at midnight as well, so edit the main.yml in the daily quest package:

static:
  '00:00': clear_all
  '00:00': clear_all_tags

Let’s make sure these show up nicely in our journal.

First edit main.yml in the daily quest package and make sure your journal_main_page settings look like this:

journal_main_page:
    can_started:
        priority: 13
        text: '  $default.journal_status_1$$quest_name$'
        conditions: '!started_tag'
    started:
        priority: 12
        text: '  $default.journal_status_2$$quest_name$'
        conditions: 'started_tag'
    finished:
        priority: 14
        text: '  $default.journal_status_3$$quest_name$'
        conditions: 'finished_tag,!started_tag'

You are done creating your first repeatable quest!

Well done, if you want to download our fishing quest package you can do so here.

Chapter 6: RPGMenu – The only GUI plugin/system you will ever need.

RPGMenu has always been a standalone addon for BetonQuest published by Joblo but on the git contributor list we find the awesome devs behind BetonQuest as well (click here to see the spigot page), however as of writing this guide it’s now built into BetonQuest 2.0 (dev builds), so that’s how we’ll explain how to use it.

The tutorial can also be used with the standalone addon.

An introduction

If you ever used a GUI plugin before you know that the configs usually include making an item, choosing what slot in the GUI it’s displayed on and what happens if you click it.

More advanced plugins out there like DeluxeMenus can also display different items in the same slot depending on permissions, now imagine that but with the addition of using BetonQuest conditions (“now that’s love if I ever saw it” – Esron).

The basics

We create menus inside of BetonQuest packages, so let’s create a template menu over on our default package.

I’ll call it menu1.yml for simplicity and place it in the menus folder inside the BetonQuest package.

Here’s a template menu with every setting we could ever use inside of a menu, just use this for reference:

height: 3 #determines how many rows we want the GUI to be, 1-7.
title: '&9&lOur Awesome Menu' #the title of the GUI that shows up at the top.
bind: menu_example_bind #an item inside of of items.yml that you bind the menu to be opened with. (optional)
command: '/questscommand' #command to open the menu (optional)
open_conditions: 'condition1' #conditions required to be met to be able to open the menu (optional)
open_events: 'event1,event2' #events that run when we open the menu (optional)
items: #here we will define all the items that we want inside of the GUI.
  example_1:
    item: menu_quests_1 #this is the displayed item that will show up, defined in items.yml.
    amount: 1 #how many items in the stack visually.
    conditions: 'example_condition_1' #conditions for this item to be shown.
    text: #define the text/lore on the item.
      en: #you can use multiple languages just like in the rest of BetonQuest
        - '&7[Quest] &f&lBone ripper'
        - '&f&oRipp some skeletons off'
        - '&f&otheir bones to complete'
        - '&f&othis quest.'
        - '&f&o'
        - '&eLeft click to locate npc'
        - '&eRight click to cancel quest'
    click: #what happens if you click the item.
      right: 'menu_quests_1_cancel,menu_quests_1_cancel_msg' #events
      left: 'menu_quests_1_compass,menu_quests_1_location_msg' #events 
    close: true #should the menu close when you click this?
  example_2:
    item: menu_quests_1
    amount: 1
    conditions: '!example_condition_1'
    text:
      en:
        - '&2[Quest] &f&lBone ripper'
        - '&f&oRipp some skeletons off'
        - '&f&otheir bones to complete'
        - '&f&othis quest.'
        - '&f&o'
        - '&2Quest completed!'
    close: false
slots: #which items shall display on which slots in the GUI, remember that a gui starts on slot 0.
  4: 'example_1,example_2' #here we display our example items on the same slot, whichever has it's conditions met will show.
  5: example_1
  6: example_2

All hash-tagged comments are not part of the actual config.

Making a daily quest GUI for our work in the previous chapter

Now that we have an understanding of the config structure, let’s make a GUI that fits our daily quest system we made in the previous chapter. I’m making another menu in the default package where we have our point values from the daily quest chapter.

First let’s add our information and close items, I’m naming the file dailyquests.yml:

height: 5
title: '&9&lDaily Quests'
command: '/dailyquests'
items: 
  info_1:
    item: menu_daily_info
    amount: 1
    conditions: ''
    text:
      en:
        - '&3&lDaily Quests'
        - '&f'
        - '&f&oHere you will find info'
        - '&f&oabout the daily quests'
        - '&f&oavailable on our server.'
    close: false
  info_2:
    item: menu_daily_goal
    amount: 1
    conditions: ''
    text:
      en:
        - '&3&lServer Daily Goal'
        - '&f'
        - '&fProgress: %point.totaldailies.amount%/25'
        - '&f'
        - '&fWhen we complete the goal'
        - '&ftogether, everyone online'
        - '&fgets 2x Vote Keys.'
    close: false
  close:
    item: menu_close
    amount: 1
    conditions: ''
    text:
      en:
        - '&3&lClose Menu'
    close: true
slots:
  0: info_1
  36: info_2
  40: close

As you can see we have added 3 items and now we need to define them in items.yml so let’s do that from in-game.

  • Hold a barrier in your hand and type /bq item default.menu_close
    • This creates a barrier item in items.yml within the default package.
  • Hold a banner_pattern in your hand and type /bq item default.menu_daily_info
  • Hold a nether_star in your hand and type /bq item default.menu_daily_goal

Now we’ve got our 3 items defined we can reload BetonQuest and test our menu using /rpgmenu open default.daiilyquests

Next let’s add in our Fishing daily quest:

height: 5
title: '&9&lDaily Quests'
command: '/dailyquests'
items: 
  info_1:
    item: menu_daily_info
    amount: 1
    conditions: ''
    text:
      en:
        - '&3&lDaily Quests'
        - '&f'
        - '&f&oHere you will find info'
        - '&f&oabout the daily quests'
        - '&f&oavailable on our server.'
    close: false
  info_2:
    item: menu_daily_goal
    amount: 1
    conditions: ''
    text:
      en:
        - '&3&lServer Daily Goal'
        - '&f'
        - '&fProgress: %point.totaldailies.amount%/25'
        - '&f'
        - '&fWhen we complete the goal'
        - '&ftogether, everyone online'
        - '&fgets 2x Vote Keys.'
    close: false
  close:
    item: menu_close
    amount: 1
    conditions: ''
    text:
      en:
        - '&3&lClose Menu'
    close: true

  quest_1_1:
    item: menu_daily_available
    amount: 1
    conditions: '!dailyquests-fishingdaily.started_tag'
    text:
      en:
        - '&f&l[Quest] &fFishing Daily'
        - '&f'
        - '&fRita loves fishing and'
        - '&fwants someone to fish'
        - '&fwith her and Fluff.'
        - '&F'
        - '&fStatus: Available'
    close: false
  quest_1_2:
    item: menu_daily_accepted
    amount: 1
    conditions: 'dailyquests-fishingdaily.started_tag,!dailyquests-fishingdaily.rewarded_tag'
    text:
      en:
        - '&9&l[Quest] &fFishing Daily'
        - '&f'
        - '&fRita loves fishing and'
        - '&fwants someone to fish'
        - '&fwith her and Fluff.'
        - '&F'
        - '&fStatus: &9Accepted'
    close: false
  quest_1_3:
    item: menu_daily_finished
    amount: 1
    conditions: 'dailyquests-fishingdaily.rewarded_tag'
    text:
      en:
        - '&2&l[Quest] &fFishing Daily'
        - '&f'
        - '&fRita loves fishing and'
        - '&fwants someone to fish'
        - '&fwith her and Fluff.'
        - '&F'
        - '&fStatus: &2Finished'
    close: false
slots:
  0: info_1
  19: 'quest_1_1,quest_1_2,quest_1_3'
  36: info_2
  40: close

Here we are calling conditions from another package which is located in /BetonQuest/dailyquests/fishingdaily
We do this so that we can display different items depending on the conditions in the specific quest package.

Let’s create the items we need:

  • Hold a book and type /bq item default.menu_daily_available
  • Hold a written book and type /bq item default.menu_daily_accepted
  • Hold a knowledge book and type /bq item default.menu_daily_finished

Now let’s reload BetonQuest and test the menu:

Quest available

Quest accepted

Quest finished/completed

You’ve made a functioning GUI and can add all your daily quests that you make to it.

Obviously your imagination is the limit when using placeholders and conditions, can’t wait to see what you post in the showcase channel on BetonQuest Discord.

Cahpter 7: Reputation Systems

In this chapter we’re going to assume that you’ve played RPGs before and have a vague understanding of what a reputation system is.

The short description

A reputation system (rep for short) is often used for a specific faction or group of NPCs, it describes how well known or liked you are within that group and usually unlocks more quests, shops and rewards.

Let’s create some packages

I would recommend creating a structure which looks like this:

  • BetonQuest
    • default
    • guild1
      • main
      • quest1
      • quest2

In this example I’m calling the group of NPCs we’d like to create a reputation system for guild1, inspired by the guild system in The Elder Scrolls series (that would be Skyrim for all you kids).

We’re not going to be creating a whole guild system in this tutorial, you already have the knowledge to do that if you’ve read this whole guide. We’re simply going to describe and show you how to access and save point events in the guild1-main package from your quests, in the mindset of creating a reputation system.

It’s very much like how we did it for the daily quest placeholders, but we’re keeping it within the guild1 packages.

First let’s edit the guild1-main package events.

rep_guild1_add: point guild1 1
rep_guild1_rem: point guild1 -1
rep_guild1_del: point guild1 *0

Now let’s create some conditions in the same pack:

rep_1: point guild1 1
rep_2: point guild1 2
rep_3: point guild1 3
rep_4: point guild1 4
rep_5: point guild1 5
rep_6: point guild1 6
rep_7: point guild1 7
rep_8: point guild1 8
rep_9: point guild1 9
rep_10: point guild1 10
rep_11: point guild1 11
rep_12: point guild1 12
rep_13: point guild1 13
rep_14: point guild1 14
rep_15: point guild1 15
rep_16: point guild1 16
rep_17: point guild1 17
rep_18: point guild1 18
rep_19: point guild1 19
rep_20: point guild1 20
rep_21: point guild1 21
rep_22: point guild1 22
rep_23: point guild1 23
rep_24: point guild1 24
rep_25: point guild1 25
rep_26: point guild1 26
rep_27: point guild1 27
rep_28: point guild1 28
rep_29: point guild1 29
rep_30: point guild1 30

Now we have reputation up to 30 we can call on, you can obviously add more of them.

Now within the other quest packages in guild1 we can simply call on the event to add, remove or reset/delete the rep for the player.

How to run the events from a different package:

randomevent: guild1-main.rep_guild1_add

That event called “randomevent” will now run the event “rep_guild1_add” in the package “guild1-main”.

We can in the same way use conditions from the main pack in our events, conversations, custom.yml stuff and more.

Example conversation:

quester: Alice
first: dialog_1,dialog_1_1
NPC_options:
    dialog_1:
        text: |
            
            HEY what are you doing in here? You need to be rep 5 with the guild to talk to me.
        conditions: '!guild1-main.rep_5'
    dialog_1_1:
        text: |
            
            Hi there newcomer!
            Lovely to see you here
        conditions: 'guild1-main.rep_5'

That NPC will run dialog_1 if you are below rep 5 and dialog_1_1 if you are 5 or above.

Another cool way to use the rep system would be to have different rewards for a daily quest depending on your rep, see these event examples:

reward_folder: folder reward_5,reward_10,reward_20

reward_5: folder reward_5_1,reward_5_2 conditions:guild1-main.rep_5,!guild1-main.rep_10
reward_5_1: money 500
reward_5_2: give diamond:10

reward_10: folder reward_10_1,reward_10_2 conditions:guild1-main.rep_10,!guild1-main.rep_20
reward_10_1: money 5000
reward_10_2: give diamond:20

reward_20: folder reward_20_1,reward_20_2 conditions:guild1-main.rep_20
reward_20_1: money 50000
reward_20_2: give diamond:100

Now running the event “reward_folder” will give different rewards depending on your rep.

  • 5 or above but not yet reached 10
    • 500 vault money
    • 10 diamonds
  • 10 or above, but not yet reached 20
    • 5000 vault money
    • 20 diamonds
  • 20 or above
    • 50000 vault money
    • 100 diamonds

Well done, you now understand rep systems.

Chapter 8: Tips & Tricks

This chapter has small but inspirational tips that might spark a whole adventure.

Show debug messages in-game

Requires BetonQuest 2.0+

Type /bq debug ingame * error
Now you get all errors in your chat while testing packages/quests.

If you want errors for specific packages do:
/bq debug ingame package.name error

When hovering on exception

Make BetonQuest paste worldedit schematics

Here’s a cool example of where we have an NPC regenerate a new player island on a survival world when asked to do it (using FastAsyncWorldEdit).

Read the official documentation on Worldedit Compatibility here.

Import items from in-game to items.yml

The best way to learn how items.yml formatting works is to import an item that you’re holding in-game by typing:

/bq item packagename.itemname

Chapter 9: Links to more guides