Skip to main content

Content Creation (Data-packs)

For creating quests and groups, there is a tool created on Google AI studio QuestForge

How to make a mob a quest giver

Content in this mod is added via data packs, so you need to create a new data pack or edit an existing one. Let's look at an example of adding a mob using "guardvillagers:guard"

  • data_pack_name -> data -> guardvillagers -> quest_givers -> guard.json Contents of guard.json
{
"pool": ["name_pool_1", "name_pool_2", "name_pool_1"]
}

When generating a quest, the pool is selected randomly.

And you're done!


How to create a group

A quest cannot exist without a group; it stores information about quests and rewards. Let's look at a ready-made example of example_group.json, which should be located at the following path:

  • data_pack_name -> data -> guardvillagers* -> groups -> example_group.json * - Any namespace can be used here, but for clarity, we'll use guardvillagers. example_group.json :
{
"tasks": [
{
"task_type": "thequestforge:collect",
"value": 40,
"target": "minecraft:iron_pickaxe",
"multiplier": false,
"weight": 20,
"count": {
"min": 1,
"max": 1
},
"enchantment_count": {
"min": 1,
"max": 3
},
"enchantment": [
{
"id": "minecraft:sharpness",
"level": {
"min": 1,
"max": 1
},
"weight": 10
},
{
"id": "minecraft:unbreaking",
"level": {
"min": 1,
"max": 3
},
"weight": 10
},
{
"id": "minecraft:fortune",
"level": {
"min": 1,
"max": 14
},
"weight": 10
}
]
},
{
"task_type": "thequestforge:kill",
"value": 5,
"target": "minecraft:zombie",
"multiplier": true,
"weight": 17,
"count": {
"min": 15,
"max": 23
}
},
{
"task_type": "thequestforge:collect",
"value": 1,
"target": "minecraft:potion",
"multiplier": false,
"weight": 10,
"count": {
"min": 1,
"max": 2
},
"tag": "{Potion:\"minecraft:healing\"}"
}
],
"rewards": [
{
"target": "minecraft:diamond",
"multiplier": true,
"price": 12,
"weight": 20,
"count": {
"min": 1,
"max": 1
}
},
{
"target": "minecraft:diamond_pickaxe",
"multiplier": false,
"price": 20,
"weight": 10,
"count": {
"min": 1,
"max": 1
},
"tag": "{display:{Name:'{\"text\":\"Exemplae pickaxe\",\"italic\":false}'}}",
"enchantment": [
{
"id": "minecraft:efficiency",
"level": {
"min": 1,
"max": 2
},
"weight": 10
},
{
"id": "minecraft:fortune",
"level": {
"min": 1,
"max": 3
},
"weight": 10
}
],
"enchantment_count": {
"min": 1,
"max": 2
}
}
],
"xp_reward": {
"min": 1,
"max": 20
},
"currency_reward": {
"min": 1,
"max": 20
}
}

Fields

The tasks array stores task data.

"task_type": "thequestforge:kill"
  • This is the task type ID; it specifies what needs to be done to progress, such as collecting items, killing an entity, etc.
"value": 40
  • This is the task's value per unit. So, if you bet 4 and get 13 stones, then (4 * 13 = 52) the value of this task is 52. This is needed to ensure the quest reward is fair (This field is for the task only!!).
"price": 12
  • This is the reward price per unit (This field is for the reward only!!).
"target": "minecraft:iron_pickaxe"
  • This is the quest target you need to Find/Kill.
"multiplier": false
  • This is the multiplier flag that indicates whether the reward or task should be increased based on rarity. For example, a quest to collect wood dropped at epic rarity, and you need to collect 30 pieces. The default multiplier is 1.4 (30 * 1.4 = 42). This means you'll need to collect 42 wood. (If you're wondering, will the quest value be calculated based on 30 or 42? The answer is 42.)
"weight": 20
  • This is the weight of the quest/reward, i.e., the chance of this quest dropping.
"count":
{
"min": 1,
"max": 30
}
  • This is the range of items to collect, or creatures to kill to complete the quest.
"enchantment_count": {
"min": 1,
"max": 3
}
  • This is the range of enchantments per item. In this example, it can drop from 1 to 3 enchantments (if this property is not present, then The quantity will be 1).
"enchantment": [
{
"id": "minecraft:sharpness",
"level": {
"min": 1,
"max": 5
},
"weight": 10
}
]
  • This is an array of the enchantments themselves, where: "id": "minecraft:sharpness" is the enchantment ID. "level" - Level. "weight" - Weight (drop chance).
"tag"

Here you can set a tag for the Item/Entity. (If you want to give a potion, enchantment book, or arrow with an effect, this field will help you.)


How to Create a Quest

Once the quest group has been created, you can proceed to creating the quest. Let's look at a ready-made example of example_quest.json, which should be located at the following path:

  • data_pack_name -> data -> guardvillagers* -> quest_template -> example_quest.json * - This can be any namespace, but for clarity, we'll use guardvillagers. example_quest.json (Here's a small, compressed version so it won't overload you too much):
{
"pool": "farmer",
"type": "LOCAL",
"weight": 100,
"requirement": [],
"requirement_target": [
"minecraft:zombie"
],
"guaranteed_reward": [
"minecraft:iron_ingot"
],
"name": {
"en_us": [
"Lost Harvest",
"Empty Barn"
],
"ru_ru": [
"Lost Harvest",
"Empty Barn"
]
},
"description": {
"en_us": [
"%npc_name% needs your help to gather crops."
],
"ru_ru": [
"%npc_name% requests your help in harvesting."
]
},
"group": "thequestforge:example_group",
"task_count": {
"min": 1,
"max": 2
},
"max_reward": 2,
"time_limit": {
"min": 6,
"max": 12
},
"next_quest": "thequestforge:chain_2",
"dialogs": {
"start": {
"text": {
"en_us": ["I need you to get %target-1%. The reward will be %reward-1%."],
"ru_ru": ["I need you to get %target-1%. The reward will be %reward-1%."]
},
"buttons": [
{
"text": {
"en_us": ["Accept"],
"ru_ru": ["Accept"]
},
"to_go": "complete",
"actions": ["thequestforge:accept", "thequestforge:save"]
},
{
"text": {
"en_us": ["Decline"],
"ru_ru": ["Refuse"]
},
"to_go": "exit",
"actions": ["thequestforge:close"]
}
]
},
"complete": {
"text": {
"en_us": ["Thank you! Here is your reward."],
"ru_ru": ["Thank you! This is your reward."]
},
"buttons": [
{
"text": {
"en_us": ["Collect reward"],
"ru_ru": ["Collect reward"]
},
"to_go": "exit",
"actions": ["thequestforge:complete", "thequestforge:next_quest"]
}
]
}
}
}

Quest File Fields

"pool": "farmer"
  • Indicates which pool (e.g., villager profession) the quest is bound to.
"type": "LOCAL"
  • The quest type. Determines its behavior: LOCAL - a local quest for NPCs. STORY - also a local quest for NPCs, but when resetting quests, these remain untouched and continue to exist. GUILD - Not yet implemented
"weight": 100
  • Chance (weight) of this quest appearing among others in the pool. The higher the weight, the more often it will appear.
"requirement": []
  • An array of conditions for the quest to be selected. See the conditions themselves here
"requirement_target": [
"minecraft:zombie"
]
  • If you want your quest to 100% have the desired task (for example, kill a zombie), then you need to enter the zombie ID in this field.

It's important that what you enter (for example, "minecraft:zombie") means that this task is in the group you selected for the quest! If you want to have a guaranteed quest, but don't want it to drop randomly (when generating other quests), set the "weight" field to 0 for this quest. This will 100% exclude this quest from generation.

"guaranteed_reward": [
"minecraft:iron_ingot"
]
  • If you want this quest to have a 100% guaranteed reward, enter the ID of the desired reward in this field.

It's important that what you enter (e.g., "minecraft:iron_ingot") is in the reward group you selected for the quest! If you want to have a guaranteed reward, but don't want it to drop randomly (when generating other quests), set the "weight" field to 0 for this reward. This will 100% exclude this reward from generation.

"name": {
"en_us": ["Name1", "Name2", ...],
"ru_ru": ["Name1", "Name2", ...]
},
"description": {
"en_us": ["Description1", "Description2", ...],
"ru_ru": ["Description1", "Description2", ...]
}

IT'S IMPORTANT THAT THE NUMBER OF LOCALIZATIONS IS THE SAME EVERYWHERE (if "en_us" has 5 names, then "ru_ru" has 5 too) There must be 5 names. ALSO THE "en_us" KEY MUST EXIST!!

  • Localization objects (supports en_us, ru_ru, etc.). The language key contains an array of strings. The engine will select a random string from the array during generation, allowing for more diverse quests.

You can use variables in the text, such as %npc_name%, which will automatically be replaced with the character's name. Details here

"group": "guardvillagers:example_group"
  • This is the ID of the group (which we discussed earlier) from which the quest will take its list of tasks and rewards.
"task_count": {
"min": 1,
"max": 2
}
  • Range. Specifies how many tasks from the linked group will be given to the player (e.g., 1 to 2).
"max_reward": 2
  • The maximum number of rewards the player will receive from the group's reward pool. If this parameter is omitted, the default is 1.
"time_limit": {
"min": 6,
"max": 12
}
  • (Optional) The time range in in-game days for completing the quest. If the quest is time-limited, the minimum and maximum timer values ​​are specified here. If this parameter is omitted, the quest will have no time limit.
"next_quest": "thequestforge:chain_2"
  • (Optional) Field for creating quest chains. Specifies the ID of the next quest, which will become available after completing the current one (e.g., "thequestforge:chain_2").

dialogs Block

This object defines the entire conversation thread with NPCs. It consists of "nodes" (e.g., start, complete, exit, or custom nodes, like dialog_1).

The very first dialogue node must be named "start"

Dialogue node structure:

"text": {
"en_us": [
"Greeting text..."
],
"ru_ru": [
"Greeting text..."
]
}
  • The text spoken by the NPC. Special variables are used here.

IT IS IMPORTANT THAT THE NUMBER OF LOCALIZATIONS IS THE SAME EVERYWHERE (if "en_us" has 5 names, then "ru_ru" should also have 5 names), AND THE KEY "en_us" MUST EXIST!!

"buttons": []
  • An array of buttons for the player's response.

Dialog Buttons

"text": {
"en_us": [
"Greeting text..."
],
"ru_ru": [
"Welcome text..."
]
}
  • Button text.

IT'S IMPORTANT THAT THE NUMBER OF LOCALIZATIONS IS THE SAME EVERYWHERE (if "en_us" has 5 names, then "ru_ru" should also have 5 names), AND THE "en_us" KEY MUST EXIST!!

"give": [
{
"id": "minecraft:oak_log",
"count": 15,
"tag": "{display:{Name:'{\"text\":\"Some name\",\"italic\":false}'}}"
}
]
  • This field is an array with a simple form for storing items. If you need to give certain items to a player, you can use this field in a button.
"remove": [
{
"id": "minecraft:oak_log",
"count": 15,
"tag": "{display:{Name:'{\"text\":\"Some name\",\"italic\":false}'}}"
}
]
  • will attempt to take items from the player and even compare tags. If there are no items, it will switch to "alt_to_go" if present.
"functions": []
  • An array of functions that will be executed when the button is pressed. Functions are the vanilla mechanics of the game (a collection of commands that are executed simultaneously).
"to_go": "dialog_2"
  • The name of the dialog node to which the player will be transferred when pressed (e.g., "dialog_2").
"alt_to_go": "dialog_3"
  • An alternative node to navigate to (e.g., if the player hasn't brought all the items).
"actions": ["thequestforge:complete", "thequestforge:next_quest"]
  • An array of system actions that occur when pressed.