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.jsonContents 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 useguardvillagers.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 useguardvillagers.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
groupwill 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.