Compatibility
Minecraft: Java Edition
Platforms
Supported environments
Links
Tags
Creators
Details
Mebahel's RPG: Villager Quests & Companions
Turn every village into the beginning of a new adventure, filled with stories to uncover, choices to make, and unlikely allies to meet along the way.
Mebahel's RPG: Villager Quests & Companions adds story-driven villager quests, rumors, named enemies, branching choices, quest tracking, RPG-style notifications, and recruitable companions. Villagers are no longer just traders standing near a bell. They can ask for help, warn you about nearby threats, send you toward strange structures, reveal hidden stories through rumors, or pull you into choices that change what happens next.
Quest boards bring even more life to villages with a changing selection of contracts, challenges, and rewards for players looking for their next adventure.
Some quests are simple village jobs. Others become full story arcs with investigations, moral decisions, ambushes, raids, hidden follow-ups, named targets, and enemies who might not deserve the axe you were sent to bring.
If you like vanilla Minecraft but want villages to give you more reasons to explore, protect, question, and return, this mod is built for that.
Dependencies
Forge / NeoForge
Fabric
Compatible Mods
The following compatibility has been confirmed by the mod author or tested by players:
- Guard Villagers — supported through a dedicated configuration file that lets guards offer selected quests when the mod is installed.
- Villagers Reborn — confirmed compatible. Its villager model and interaction changes can be used alongside this mod's quests.
- Epic Villages — tested by players and confirmed working with the quest system.
- Luki's Grand Capitals — tested by players and confirmed working with the quest system.
- Villager Retaliation — both mods can be used together. Their quest systems remain separate, but the core features can coexist.
Village overhaul mods are generally compatible because quests can be assigned to villagers inside both vanilla and modded villages or structures.
What This Mod Adds
- Over 50 included quests built around villages, roads, mines, raids, ruined portals, witches, raiders, skeletons, undead soldiers, false heroes, strange survivors, and hidden contracts.
- Branching storylines where killing, sparing, exposing, defending, escorting, delivering, or investigating can lead to different follow-up quests.
- Named quest targets with custom dialogue, equipment, locations, health, mounts, drops, ambushes, and spare/attack choices.
- Recruitable companions from selected mercy paths, including restored enemies who can later fight beside you.
- Villager rumors that unlock hidden quests gradually instead of dumping every story on day one.
- Quest journal and HUD tracking for active objectives, coordinates, structures, destinations, and threat targets.
- RPG-style quest notifications with custom sounds when quests start, update, or complete.
- Many objective types: kill, collect, deliver, read, escort, bring back, reach a structure, break blocks, place blocks, detonate TNT, enter or leave the Nether, defend raids, wait for time to pass, talk to entities, and return to the quest giver.
- Datapack and mod support so creators can add quests and rumors with JSON files.
Quest Boards and Dynamic Contracts
Quest boards offer repeatable adventures that evolve as you complete contracts and build your reputation. Choose from several kinds of contracts across multiple difficulty levels.
Accepted contracts appear directly in the quest journal, making them easy to follow alongside the mod's story quests.
How It Feels In Game
You arrive at a village. A farmer heard something moving near an old portal. A smith remembers smoke below a mine. Someone claims a celebrated hero may be wearing stolen glory. A witch outside the village might be a threat, or she might be the only person telling the truth.
You talk, choose responses, accept the quest, track it in your journal, follow coordinates or structure clues, and return for rewards. Some targets fight immediately. Some talk first. Some can be spared. Sometimes mercy opens a longer path. Sometimes it brings danger back to the village.
The goal is to make villages feel like places with memory, consequences, and unfinished business.
Included Story Arcs
The Armed Dead
Investigate a ruined portal guarded by Sir Alaric Ashward, an armed zombie with fragments of a soldier's memory. Kill him to seal the restless gate, or spare him and help recover the identity buried under the undead curse. The mercy path can lead to a recruitable companion.
No-Banner Vindicator
Rurik, a vindicator without a banner, stands outside the usual raider order. Is he hunting, mourning, hiding, or trying to escape what he used to serve? Your choice can end his story or push him toward a trial that may turn an enemy into an ally.
The False Hero
A village champion may be celebrated for courage that belonged to someone else. Follow the evidence, find the last witness, and decide whether to bury the truth or expose the person the village has been praising.
The Witch at the Hut
The village fears a witch. The easy answer is to kill her. The harder answer is to listen. Sparing her can reveal a larger plot involving curses, raiders, undead proxies, and an evoker pushing danger toward the village.
Village Defense and the Quiet Ledger
Prepare a village for attack, raise iron golems, survive a raid, and earn a reputation. But fame has consequences. After the bell rings, a hidden follow-up can draw assassins from the Quiet Ledger.
The Cold Forge
A rumor about a cold forge leads into a darker thread about a smith, an old mine, and a curse tied to the forge's last work.
The Ash Court
Trace ash-marked skeletons into the Nether, discover an old bargain beneath the village, recover written evidence, and decide whether to break or renegotiate a debt that may have protected the village for too long.
Rumors and Discovery
Not every quest appears the same way.
Some villagers can offer jobs directly. Others may only give you a rumor. Hearing the right rumor can unlock hidden content, such as smoke below an old mine, a stranger among the dead, or trouble that appears only after a village has already survived a raid.
This lets the world reveal stories gradually as you play.
Companions
Certain spared characters can eventually become permanent companions.
Companions are designed to be useful without turning villages into chaos. They follow your lead, focus on hostile threats, and avoid randomly attacking peaceful villagers, iron golems, or passive animals.
Some companions also support equipment interaction through the companion inventory screen.
Quest Journal and HUD
Press J by default to open the quest journal.
The journal and tracker help you follow active objectives with contextual labels such as:
- Threat location for named enemy targets.
- Destination for escort quests.
- Structure location for exploration objectives.
- Target location when no more specific label applies.
Coordinates in the journal are clickable by default, and active objectives can be followed through the HUD tracker. Coordinate clicking can be disabled in the configuration.
Configuration
Server/world config file:
config/mebahelrpgrquest.json
Current configurable values:
{
"villagerQuestChance": 0.20,
"villagerRumorChance": 0.33,
"disableQuestCoordinateClick": false,
"shareQuestsBetweenPlayers": false,
"inventoryJournalButtonPosition": "left",
"hideInventoryJournalButton": false
}
villagerQuestChanceis the quest assignment weight for a newly loaded villager.villagerRumorChanceis the rumor assignment weight for a newly loaded villager.- The two values compete in one roll. Any remaining weight up to
1.0means no quest or rumor is assigned. - Values are clamped between
0.0and1.0. If their sum is above1.0, quest and rumor are normalized against each other with no empty outcome. disableQuestCoordinateClickcontrols coordinate interaction in the quest journal. Keep it set tofalseto let players click quest coordinates, or set it totrueto disable coordinate clicking.shareQuestsBetweenPlayerscontrols multiplayer quest sharing. Keep it set tofalsefor separate quest progress per player, or set it totrueto share quest progress, failures, completions, claimed rewards, and quest traits between all players on the server.inventoryJournalButtonPositioncontrols where the inventory quest journal button appears. Useleftfor the default left side orrightto move it to the right side. Invalid values fall back toleft.hideInventoryJournalButtonhides the inventory quest journal button when set totrue. It isfalseby default.
Additional Quest Configuration Files
- Guard Villager quests: a dedicated configuration file lets you assign quests to guards from the Guard Villagers mod when it is installed.
- Removed quests: a dedicated configuration file lets you list quest ids that should be removed from the available quest pool. Use it to disable included quests without editing the mod files.
Datapack & Mod Creator Documentation: Story Quests and Rumors
Anyone can create new quests for the mod with JSON files in a datapack or mod. You can add dialogue, objectives, rumors, named enemies, rewards, choices, ambushes, raids, deliveries, escorts, and complete branching questlines.
File Locations
Place quest and rumor files in your own namespace:
data/<namespace>/quests/<quest_file>.json
data/<namespace>/rumors/<rumor_file>.json
For example:
data/my_quests/quests/old_well.json
This creates the quest id:
my_quests:old_well
Quest subfolders are allowed, but they do not become part of the quest id. Keep every quest filename unique inside your namespace.
Quick Start
- Choose the example below that is closest to the quest you want to make.
- Copy its JSON into a new file under
data/<namespace>/quests/ordata/<namespace>/rumors/. - Replace the
examplenamespace with your own namespace. - Change the dialogue, entities, structures, objectives, rewards, and linked quest ids.
- Reload the datapack and test the quest in a development or backup world.
JSON does not allow comments or trailing commas. Always use full identifiers such as minecraft:zombie, and use full quest ids such as my_quests:old_well when one file references another.
Player-facing text can use a translation object:
{
"translate": "quest.my_quests.old_well.title",
"fallback": "The Old Well"
}
The fallback value is displayed when no matching translation is available, so a separate language file is optional.
Quest Examples
Each example is kept in a separate expandable section. Copy the closest template and adapt only the parts your quest needs.
Named Threat with Attack or Spare Branches
Spawn a named enemy, let the player speak to it, then continue into a different quest depending on whether the target is attacked or spared.
Use this template for a quest that spawns a named threat, lets the player talk to it, then branches on attack or spare. #### First Quest
{
"title": "QUEST TITLE",
"summary": "Villager-facing summary shown before acceptance.",
"flow": {
"on_kill": "modid:kill_branch_2",
"on_spare": "modid:spare_branch_2"
},
"goals": [
{
"id": "talk_to_threat",
"talk": "minecraft:zombie",
"amount": 1,
"name": "NAMED THREAT"
},
{
"id": "kill_threat",
"kill": "minecraft:zombie",
"amount": 1,
"attack_only": true,
"from_threats": true
}
],
"threat": {
"entity": "minecraft:zombie",
"name": "NAMED THREAT",
"structure": "minecraft:ruined_portal",
"search_radius": 4000,
"spawn_on_accept": true,
"spawn_min_radius": 3,
"spawn_max_radius": 6,
"spare": true,
"glow": false,
"max_health": 150,
"equipment": {
"mainhand": "minecraft:diamond_sword",
"helmet": {
"item": "minecraft:iron_helmet",
"enchants": {
"minecraft:unbreaking": 3
}
}
},
"line": "Quest giver line that describes the threat.",
"target": "Initial line spoken by the threat.",
"talk": [
["Player question one?", "Threat answer one."],
["Player question two?", "Threat answer two."]
]
},
"choice": {
"attack": {
"label": "Attack choice label.",
"traits": ["trait_from_attack"],
"return": "Quest giver line after the target is killed."
},
"spare": {
"label": "Spare choice label.",
"line": "Immediate line after sparing the target.",
"post": "Follow-up line shown after the spare.",
"villager": "Quest giver line after spare.",
"traits": ["trait_from_spare"],
"rewards_from_giver": true,
"rewards": {
"xp": 160,
"items": {
"minecraft:iron_ingot": 4
}
},
"after": {
"offer_chance": 70,
"ambush_chance": 30,
"nothing_chance": 0,
"ambush": "minecraft:zombie",
"ambush_name": "Fallback Ambush Name",
"count": 5,
"ambush_max_health": 50,
"ambush_equipment": {
"helmet": "minecraft:leather_helmet"
},
"line": "Line used when the spared target offers the next quest.",
"ambush_line": "Line used if mercy triggers an ambush.",
"nothing": "Line used if no follow-up happens."
}
}
},
"dialogue": {
"return": "Quest giver line after kill.",
"reward": "Quest giver reward line.",
"done": "Quest giver already-completed line."
},
"rewards": {
"xp": 260,
"items": {
"minecraft:emerald": 10
}
}
}
For spare-enabled threat confrontations, prefer the talk plus attack_only kill pattern shown above. The first interaction opens dialogue without completing the stage; the stage completes only after the player explicitly chooses attack or spare. #### Kill Branch{
"title": "KILL BRANCH TITLE",
"summary": "Follow-up summary after the player chose attack.",
"dialogue": {
"intro": "Intro line.",
"offer": [
["Player question?", "Quest giver answer."]
],
"return": "Return line.",
"reward": "Reward line.",
"done": "Already completed line."
},
"goals": ["kill 3 minecraft:zombified_piglin"],
"threats": [
{
"entity": "minecraft:zombified_piglin",
"name": "Branch Threat",
"structure": "minecraft:ruined_portal",
"search_radius": 4000,
"spawn_on_accept": true,
"spare": false,
"max_health": 70,
"equipment": {
"mainhand": "minecraft:golden_sword"
}
}
],
"rewards": {
"xp": 360,
"items": {
"minecraft:emerald": 14
}
}
}
#### Spare Branch{
"title": "SPARE BRANCH TITLE",
"summary": "Follow-up summary after the player chose spare.",
"flow": {
"next": "modid:spare_branch_3"
},
"dialogue": {
"intro": "Intro line from the spared target or quest giver.",
"offer": [
["Player question?", "Answer."]
],
"return": "Return line.",
"reward": "Reward line.",
"done": "Already completed line."
},
"goals": [
{
"collect": "minecraft:iron_ingot",
"amount": 4
}
],
"rewards": {
"xp": 240,
"items": {
"minecraft:emerald": 6
}
}
}
Staged Building and Defense
Ask the player to build or gather supplies first, then begin a second stage that spawns attackers around the quest giver.
Use this when the player must build or gather something first, then a new wave of threats appears in a later stage. Based on `questlines/village_build/village_pig_enclosure.json`. Key points: - `sequential_objectives: true` makes stage `0` finish before stage `1` starts. - Build objectives use `place`, `bring`, `collect`, or other normal objective shortcuts. - Threats can be assigned to `stage: 1` and spawned around the quest giver with `spawn_origin: "quest_giver"`. - Use `from_threats: true` on kill goals when the spawned named/custom threats should count. - Add one `threats` entry per mob to spawn. `amount` is not read on threat entries.
{
"title": {
"translate": "quest.example.first_pen_defense.title",
"fallback": "A Pen Worth Defending"
},
"summary": {
"translate": "quest.example.first_pen_defense.summary",
"fallback": "Build a small animal pen, bring livestock inside, then defend it from raiders."
},
"sequential_objectives": true,
"dialogue": {
"intro": {
"translate": "quest.example.first_pen_defense.dialogue.intro",
"fallback": "The villager points to a bare patch of grass near the farm."
},
"offer": [
[
{
"translate": "quest.example.first_pen_defense.dialogue.offer.0.0",
"fallback": "What do you need built?"
},
{
"translate": "quest.example.first_pen_defense.dialogue.offer.0.1",
"fallback": "A fence, a gate, two torches, and enough room for the first herd."
}
]
],
"return": {
"translate": "quest.example.first_pen_defense.dialogue.return",
"fallback": "The pen held. So did you."
},
"reward": {
"translate": "quest.example.first_pen_defense.dialogue.reward",
"fallback": "Take this. A defended farm feeds more than one house."
},
"done": {
"translate": "quest.example.first_pen_defense.dialogue.done",
"fallback": "The animals are still inside, and the raiders are gone."
}
},
"goals": [
{
"id": "place_fences",
"place": "minecraft:oak_fence",
"amount": 12,
"stage": 0,
"range": 60
},
{
"id": "place_gate",
"place": "minecraft:oak_fence_gate",
"amount": 1,
"stage": 0,
"range": 60
},
{
"id": "place_torches",
"place": "minecraft:torch",
"amount": 2,
"stage": 0,
"range": 60,
"say": {
"translate": "quest.example.first_pen_defense.goals.place_torches.say",
"fallback": "The pen is lit. Stay close."
}
},
{
"id": "bring_animals",
"bring": "minecraft:pig",
"amount": 2,
"stage": 0,
"range": 60
},
{
"id": "kill_raiders",
"kill": "minecraft:pillager",
"amount": 3,
"stage": 1,
"from_threats": true
},
{
"id": "kill_raider_captain",
"kill": "minecraft:vindicator",
"amount": 1,
"stage": 1,
"from_threats": true
}
],
"threats": [
{
"entity": "minecraft:pillager",
"name": {
"translate": "quest.example.first_pen_defense.threats.0.name",
"fallback": "Hungry Raider"
},
"stage": 1,
"spawn_origin": "quest_giver",
"spawn_min_radius": 18,
"spawn_max_radius": 30,
"spawn_on_accept": true,
"spare_enabled": false,
"glow": true
},
{
"entity": "minecraft:pillager",
"name": {
"translate": "quest.example.first_pen_defense.threats.1.name",
"fallback": "Fence-Cutting Raider"
},
"stage": 1,
"spawn_origin": "quest_giver",
"spawn_min_radius": 18,
"spawn_max_radius": 30,
"spawn_on_accept": true,
"spare_enabled": false,
"glow": true
},
{
"entity": "minecraft:pillager",
"name": {
"translate": "quest.example.first_pen_defense.threats.2.name",
"fallback": "Torch-Kicking Raider"
},
"stage": 1,
"spawn_origin": "quest_giver",
"spawn_min_radius": 18,
"spawn_max_radius": 30,
"spawn_on_accept": true,
"spare_enabled": false,
"glow": true
},
{
"entity": "minecraft:vindicator",
"name": {
"translate": "quest.example.first_pen_defense.threats.3.name",
"fallback": "Fence Breaker"
},
"stage": 1,
"spawn_origin": "quest_giver",
"spawn_min_radius": 22,
"spawn_max_radius": 34,
"spawn_on_accept": true,
"spare_enabled": false,
"glow": true,
"max_health": 40.0
}
],
"rewards": {
"xp": 180,
"items": {
"minecraft:emerald": 6,
"minecraft:wheat": 12
}
},
"traits": {
"complete": [
"farm_defender"
]
}
}Generated Container, Written Book, and TNT
Place quest items inside a structure container, make the player read a written clue, then complete a demolition objective and spawn enemies.
Use this when a structure should contain generated quest items, a written-book clue, and a demolition step near a target block. Based on `questlines/sculk/sculk_mineshaft_investigation.json`. Key points: - `read_book` objectives must include `item: "minecraft:written_book"`. - `quest_book.title`, `quest_book.author`, and `quest_book.pages` can be translation objects. - Use `in_chest: true` with `container` to spawn the objective item inside a generated container. - Generated chest/container items are placed into random empty slots by the quest item spawner. - `detonate_tnt` should use `block` for the target block near the explosion, not the TNT block itself. - `force_place_block: true` can prepare the target block when the structure does not reliably contain one.
{
"title": {
"translate": "quest.example.mine_demolition.title",
"fallback": "Notes Under the Mine"
},
"summary": {
"translate": "quest.example.mine_demolition.summary",
"fallback": "Find a sealed mineshaft, recover the foreman's notes, and destroy the marked spawner."
},
"sequential_objectives": true,
"goals": [
{
"id": "reach_old_mine",
"reach": "minecraft:mineshaft",
"structure": "minecraft:mineshaft",
"radius": 3200,
"range": 80,
"stage": 0,
"auto_advance": true
},
{
"id": "read_foreman_notes",
"type": "read_book",
"item": "minecraft:written_book",
"amount": 1,
"structure": "minecraft:mineshaft",
"container": "minecraft:barrel",
"stage": 1,
"radius": 3200,
"in_chest": true,
"auto_advance": true,
"tag": "example_foreman_notes",
"quest_book": {
"title": {
"translate": "quest.example.mine_demolition.book.title",
"fallback": "Foreman's Notes"
},
"author": {
"translate": "quest.example.mine_demolition.book.author",
"fallback": "Mine Foreman"
},
"pages": [
{
"translate": "quest.example.mine_demolition.book.page.0",
"fallback": "We sealed the lower drift after the spawner woke again. If anyone returns, place charges near the cage, not in the tunnel mouth."
}
]
},
"block_patch": {
"radius": 4,
"palette": [
"minecraft:sculk",
"minecraft:deepslate"
]
}
},
{
"id": "take_tnt_from_barrel",
"collect": "minecraft:tnt",
"amount": 3,
"mandatory": false,
"sequential": true,
"stage": 1,
"in_chest": true,
"structure": "minecraft:mineshaft",
"container": "minecraft:barrel"
},
{
"id": "place_demolition_charges",
"place": "minecraft:tnt",
"amount": 3,
"structure": "minecraft:mineshaft",
"stage": 2,
"range": 12
},
{
"id": "detonate_spawner",
"type": "detonate_tnt",
"block": "minecraft:spawner",
"required_mob": "minecraft:skeleton",
"structure": "minecraft:mineshaft",
"force_place_block": true,
"amount": 3,
"stage": 2,
"radius": 3200,
"range": 14,
"auto_advance": true,
"block_patch": {
"radius": 3,
"palette": [
"minecraft:sculk",
"minecraft:deepslate"
]
}
},
{
"id": "kill_what_crawls_out",
"kill": "minecraft:zombie",
"amount": 4,
"stage": 3,
"from_threats": true
}
],
"threats": [
{
"entity": "minecraft:zombie",
"name": {
"translate": "quest.example.mine_demolition.threats.0.name",
"fallback": "Sculk-Crowned Dead"
},
"stage": 3,
"spawn_origin": "player",
"spawn_min_radius": 8,
"spawn_max_radius": 16,
"spawn_on_accept": true,
"spare_enabled": false,
"glow": true,
"equipment": {
"head": "minecraft:sculk"
}
},
{
"entity": "minecraft:zombie",
"name": {
"translate": "quest.example.mine_demolition.threats.1.name",
"fallback": "Sculk-Marked Dead"
},
"stage": 3,
"spawn_origin": "player",
"spawn_min_radius": 8,
"spawn_max_radius": 16,
"spawn_on_accept": true,
"spare_enabled": false,
"glow": true,
"equipment": {
"head": "minecraft:sculk"
}
},
{
"entity": "minecraft:zombie",
"name": {
"translate": "quest.example.mine_demolition.threats.2.name",
"fallback": "Sculk-Marked Dead"
},
"stage": 3,
"spawn_origin": "player",
"spawn_min_radius": 8,
"spawn_max_radius": 16,
"spawn_on_accept": true,
"spare_enabled": false,
"glow": true,
"equipment": {
"head": "minecraft:sculk"
}
},
{
"entity": "minecraft:zombie",
"name": {
"translate": "quest.example.mine_demolition.threats.3.name",
"fallback": "Sculk-Marked Dead"
},
"stage": 3,
"spawn_origin": "player",
"spawn_min_radius": 8,
"spawn_max_radius": 16,
"spawn_on_accept": true,
"spare_enabled": false,
"glow": true,
"equipment": {
"head": "minecraft:sculk"
}
}
],
"rewards": {
"xp": 320,
"items": {
"minecraft:emerald": 10,
"minecraft:echo_shard": 1
}
}
}Delivery to Another Structure or Village
Collect supplies, travel to another structure or village, hand the items to a generated target, and return to the original quest giver.
Use this when the player gathers items, travels to another structure, gives the items to a spawned target, then returns to the original quest giver. Based on `delivery_cobblestone_oak_log_other_village.json`. Key points: - The delivery target is configured in `threat`. - `delivery_objectives` must list the objective ids that should be handed over. - The target talk objective should usually use `auto_advance: true`. - Add a final `return: true` objective in the next stage if the player must report back. - `min_structure_distance` is useful when the target should not spawn in the same village.
{
"title": {
"translate": "quest.example.remote_delivery.title",
"fallback": "Stone for the Next Village"
},
"summary": {
"translate": "quest.example.remote_delivery.summary",
"fallback": "Carry supplies to a messenger waiting in another village."
},
"sequential_objectives": true,
"goals": [
{
"id": "delivery_cobblestone",
"collect": "minecraft:cobblestone",
"amount": 32,
"mandatory": true,
"stage": 0
},
{
"id": "delivery_oak_logs",
"collect": "minecraft:oak_log",
"amount": 16,
"mandatory": true,
"stage": 0
},
{
"id": "deliver_to_messenger",
"talk": "minecraft:villager",
"amount": 1,
"mandatory": true,
"stage": 0,
"auto_advance": true,
"name": {
"translate": "quest.example.remote_delivery.goals.deliver_to_messenger.name",
"fallback": "Village Messenger"
},
"say": {
"translate": "quest.example.remote_delivery.goals.deliver_to_messenger.say",
"fallback": "The messenger takes the supplies. Return to the villager who sent you."
}
},
{
"id": "return_to_sender",
"return": true,
"amount": 1,
"mandatory": true,
"stage": 1
}
],
"threat": {
"entity": "minecraft:villager",
"name": {
"translate": "quest.example.remote_delivery.threat.name",
"fallback": "Village Messenger"
},
"structure": "minecraft:villages",
"search_radius": 4200,
"spawn_radius": 10,
"spawn_on_accept": true,
"spare_enabled": false,
"glow": false,
"target_line": {
"translate": "quest.example.remote_delivery.threat.target_line",
"fallback": "If you have the stone and oak, hand them over before the wall gives way."
},
"delivery_objectives": [
"delivery_cobblestone",
"delivery_oak_logs"
],
"delivery_choice_label": {
"translate": "quest.example.remote_delivery.threat.delivery_choice_label",
"fallback": "Hand over supplies"
},
"delivered_line": {
"translate": "quest.example.remote_delivery.threat.delivered_line",
"fallback": "That will hold. Tell them the road between our villages is still worth keeping open."
},
"depart_after_delivery": false,
"min_structure_distance": 700
},
"rewards": {
"xp": 180,
"items": {
"minecraft:emerald": 7,
"minecraft:bread": 6
}
}
}Village Raid Defense
Start a normal Minecraft raid when the quest is accepted and complete the objective when the village survives.
Use this when accepting the quest should start a village raid and completing the raid should complete the objective. Based on `questlines/village_defense/village_defense_chain_3_the_bell_and_the_raid.json`. Key points: - Use `type: "defend_raid"`. - `amount: 1` is the normal value for a single raid defense objective. - This objective depends on the normal Minecraft raid flow, so it should be offered from a villager in or near the village being defended. - Use rewards with enchanted items when the raid reward should feel unique.
{
"title": {
"translate": "quest.example.bell_raid.title",
"fallback": "The Bell and the Raid"
},
"summary": {
"translate": "quest.example.bell_raid.summary",
"fallback": "Stand with the village and survive the raid."
},
"dialogue": {
"intro": {
"translate": "quest.example.bell_raid.dialogue.intro",
"fallback": "The villager stands beside the bell, one hand on the rope."
},
"offer": [
[
{
"translate": "quest.example.bell_raid.dialogue.offer.0.0",
"fallback": "You think they are coming now?"
},
{
"translate": "quest.example.bell_raid.dialogue.offer.0.1",
"fallback": "If we ring the bell, they will know we are ready to fight."
}
]
],
"return": {
"translate": "quest.example.bell_raid.dialogue.return",
"fallback": "The horn is silent. The village still stands."
},
"reward": {
"translate": "quest.example.bell_raid.dialogue.reward",
"fallback": "This was taken from the raid leader. By right of battle, it is yours."
},
"done": {
"translate": "quest.example.bell_raid.dialogue.done",
"fallback": "The bell rings for warning again, not fear."
}
},
"goals": [
{
"id": "defend_the_village",
"type": "defend_raid",
"amount": 1
}
],
"rewards": {
"xp": 650,
"items": {
"minecraft:emerald": 20,
"minecraft:crossbow": {
"count": 1,
"enchantments": [
{
"id": "minecraft:power",
"level": 3
},
{
"id": "minecraft:unbreaking",
"level": 2
},
{
"id": "minecraft:piercing",
"level": 1
}
]
}
}
},
"traits": {
"complete": [
"village_defender"
]
}
}Rumor That Unlocks a Hidden Quest
Keep a quest unavailable until the player hears the correct rumor from a villager.
Use this when a quest should not appear until a villager rumor unlocks it. Based on `rumors/mine_smoke_below.json` and `blaze_mineshaft_threat.json`. Key points: - The rumor file lives under `data/<namespace>/rumors/<rumor_id>.json`. - `unlock_quest` should be the full quest id. - When the rumor is discovered, the player receives the trait `quest_discovered:<full quest id>`. - The hidden quest should require that trait. - Use `conditions.not_completed_quests` so the rumor stops being useful after the quest is complete. - Rumor `line` and `discovered_line` are currently plain strings. Rumor file:
{
"id": "example_smoke_below",
"weight": 15,
"line": "Miners swear smoke is rising from shafts sealed for years.",
"unlock_quest": "example:hidden_mineshaft_fire",
"conditions": {
"not_completed_quests": [
"example:hidden_mineshaft_fire"
]
},
"discovered_line": "Rumor discovered: something hot and hostile is moving in an old mineshaft."
}Hidden quest file:{
"title": {
"translate": "quest.example.hidden_mineshaft_fire.title",
"fallback": "Flame in the Mineshaft"
},
"summary": {
"translate": "quest.example.hidden_mineshaft_fire.summary",
"fallback": "A villager reports a blaze burning through an abandoned mineshaft."
},
"requires": {
"traits": [
"quest_discovered:example:hidden_mineshaft_fire"
]
},
"goals": [
{
"id": "kill_mine_blaze",
"kill": "minecraft:blaze",
"amount": 1
}
],
"threat": {
"entity": "minecraft:blaze",
"name": {
"translate": "quest.example.hidden_mineshaft_fire.threat.name",
"fallback": "Ignivar the Mineflame"
},
"structure": "minecraft:mineshaft",
"search_radius": 4000,
"spawn_on_accept": true,
"spare_enabled": false,
"max_health": 150.0,
"offer_line": {
"translate": "quest.example.hidden_mineshaft_fire.threat.offer_line",
"fallback": "Something from the Nether is burning through an old mineshaft."
},
"target_line": {
"translate": "quest.example.hidden_mineshaft_fire.threat.target_line",
"fallback": "The blaze crackles with hostile heat. There is no sign it understands mercy."
}
},
"rewards": {
"xp": 260,
"items": {
"minecraft:emerald": 12,
"minecraft:blaze_rod": 2
}
}
}Escort to a Structure
Escort a quest entity to a searched structure, with configurable search distance and completion range.
Use this when the quest giver or quest entity must be escorted to a target structure. Based on `questlines/armed_zombie/armed_zombie_chain_spare_2_forgotten_road.json`. Key points: - Use the `escort` shortcut with a structure id. The parser converts it to `escort_entity`. - `radius` controls how far the structure search can go. - `range` controls how close the escorted entity must be to the target structure. - This works well as a follow-up after a spare/recruit branch.
{
"title": {
"translate": "quest.example.forgotten_road.title",
"fallback": "The Forgotten Road"
},
"summary": {
"translate": "quest.example.forgotten_road.summary",
"fallback": "Escort a spared enemy toward the village road it remembers."
},
"flow": {
"next": "example:remembered_name"
},
"dialogue": {
"intro": {
"translate": "quest.example.forgotten_road.dialogue.intro",
"fallback": "The spared creature keeps its weapon low and looks toward the road."
},
"offer": [
[
{
"translate": "quest.example.forgotten_road.dialogue.offer.0.0",
"fallback": "You remember a village?"
},
{
"translate": "quest.example.forgotten_road.dialogue.offer.0.1",
"fallback": "A bell. Smoke. A well with cracked stone. Take me there."
}
]
],
"return": {
"translate": "quest.example.forgotten_road.dialogue.return",
"fallback": "The bell. I know that sound."
},
"reward": {
"translate": "quest.example.forgotten_road.dialogue.reward",
"fallback": "I found this under the well stones. It was mine once."
},
"done": {
"translate": "quest.example.forgotten_road.dialogue.done",
"fallback": "The village road remembers me."
}
},
"goals": [
{
"id": "escort_to_village",
"escort": "minecraft:village_plains",
"radius": 3500,
"range": 40
}
],
"rewards": {
"xp": 220,
"items": {
"minecraft:iron_ingot": 6,
"minecraft:emerald": 4
}
},
"traits": {
"complete": [
"escort_memory"
]
}
}Datapack & Mod Creator Documentation: Quest Board Contracts
Mod and datapack creators can expand the section below to learn how to add custom quest-board contracts, rewards, and equipment.
Quest boards can appear in configured village structures and generate repeatable contracts independently from the included story quests. Their offers refresh over time and can include hunts, deliveries, village protection, and elite targets.
Open a board to browse its current contracts, inspect each objective and reward, and accept the one you want. Accepted contracts are added directly to the normal quest journal and HUD: there is no contract item to keep in the inventory. Each board has its own shared reputation and level. Completing contracts for that board makes harder offers more likely and shortens its refresh time. In multiplayer, offers can be configured as individual per player or claimed globally.
Contracts use five difficulty levels:
| Difficulty | Display | Extra group mobs | Extra health per group mob | Elite count multiplier | Extra health per elite |
|---|---|---|---|---|---|
| Common | 1 star | +0 | +0 HP | x1.00 | +0 HP |
| Dangerous | 2 stars | +1 | +5 HP | x1.15 | +20 HP |
| Deadly | 3 stars | +2 | +10 HP | x1.35 | +50 HP |
| Nightmare | 4 stars | +4 | +20 HP | x1.60 | +75 HP |
| Legendary | 5 stars | +6 | +40 HP | x2.00 | +150 HP |
Elite counts are rounded up after applying the multiplier. A specific elite can opt out of count scaling with "scale_count_with_difficulty": false; health bonuses still apply when it has a configured max_health.
Difficulty also affects equipment, status effects, rewards, and the amount of reputation earned with the board.
Datapack Configuration
Quest-board contracts are fully data-driven. A datapack or mod can add vanilla or modded entities, items, structures, equipment, and rewards without replacing the built-in files.
Use the normal datapack layout:
<datapack>/
pack.mcmeta
data/
<your_namespace>/
quest_board_contracts/
Do not place custom files inside the mebahelrpgrquest namespace unless you deliberately want to override data with the same resource path. Contract definitions from different namespaces are discovered and merged. References such as example:raider_rewards resolve inside the referenced namespace.
Each contract family has its own definition file and optional tables:
quest_board_contracts/kill/mobs.json
quest_board_contracts/kill/reward_tables/
quest_board_contracts/spawn_groups/groups.json
quest_board_contracts/spawn_groups/equipment_tables/
quest_board_contracts/spawn_groups/reward_tables/
quest_board_contracts/deliveries/deliveries.json
quest_board_contracts/deliveries/reward_tables/
quest_board_contracts/protection/protection.json
quest_board_contracts/protection/reward_tables/
quest_board_contracts/elites/elites.json
quest_board_contracts/elites/equipment_tables/
quest_board_contracts/elites/reward_tables/
Definitions whose required modded entity, item, or structure is unavailable are ignored safely. Invalid entries produce a warning in the log without preventing other valid contracts from loading. Missing custom reward tables fall back to the built-in global table for that contract family; missing equipment tables leave the mob's normal equipment unchanged.
Regular Hunts
kill/mobs.json contains a mobs array. These contracts count ordinary kills of the selected entity:
{
"mobs": [
{
"id": "examplemod:mutant_zombie",
"min": 2,
"max": 5,
"reward_table": "example:mutant_hunt"
}
]
}The optional reward table above belongs at:data/example/quest_board_contracts/kill/reward_tables/mutant_hunt.jsonSpawned Group Hunts
spawn_groups/groups.json contains a groups array. Every accepted group contract locates one of its configured structures, generates the group there, and tracks only those generated targets.
A minimal group entry follows this format:
{
"groups": [
{
"entities": [
{
"id": "minecraft:zombie",
"weight": 10
}
],
"min": 1,
"max": 2,
"structures": [
"minecraft:villages"
],
"equipment_table": "example:group_enemies",
"reward_table": "example:group_rewards",
"search_radius": 3000,
"ignore_current_structure": true,
"min_structure_distance": 128,
"spawn_min_radius": 8,
"spawn_max_radius": 32
}
]
}`entities` is a weighted pool rolled separately for every group member. `structures` is also a pool: one destination is selected when the contract is generated. `ignore_current_structure` searches outside the board's village, while `min_structure_distance` sets the exclusion distance.Deliveries
deliveries/deliveries.json contains a deliveries array. When accepted, the contract locates the destination and generates a named recipient. The player must carry the items to that recipient; interacting consumes the required items and completes the contract.
{
"deliveries": [
{
"item": "examplemod:medical_supplies",
"min": 8,
"max": 20,
"structures": [
"minecraft:villages"
],
"reward_table": "example:medical_delivery",
"search_radius": 3000,
"ignore_current_structure": true,
"min_structure_distance": 128,
"spawn_min_radius": 0,
"spawn_max_radius": 24,
"recipient_name": "Village Quartermaster"
}
]
}Village Protection
protection/protection.json contains a contracts array. Supported built-in protection types are iron_golem and lighting.
{
"contracts": [
{
"type": "lighting",
"target": "minecraft:torch",
"min": 6,
"max": 12,
"structures": [
"minecraft:villages"
],
"search_radius": 5000,
"ignore_current_structure": false,
"completion_range": 96
}
]
}Set `ignore_current_structure` to `false` to protect the board's village, or to `true` with `min_structure_distance` to send the player to another village.Elite Contracts
elites/elites.json contains a contracts array. Each contract may contain several elite entries, each with its own count, name, health, effects, and equipment table.
{
"contracts": [
{
"structures": [
"minecraft:pillager_outpost"
],
"reward_table": "example:elite_rewards",
"search_radius": 3000,
"spawn_min_radius": 0,
"spawn_max_radius": 24,
"elites": [
{
"entity": "minecraft:vindicator",
"min": 1,
"max": 1,
"name": "The Iron Captain",
"max_health": 80,
"equipment_table": "example:elite_raiders",
"effects": [
{
"id": "minecraft:strength",
"duration_seconds": 3600,
"amplifier": 1
}
]
}
]
}
]
}Reward Tables
Reward tables live in the reward_tables folder of their contract family:
{
"rolls": {
"min": 1,
"max": 2
},
"rewards": [
{
"type": "item",
"id": "minecraft:emerald",
"weight": 4,
"base_min": 1,
"base_max": 3,
"per_kill_min": 0.2,
"per_kill_max": 0.5
},
{
"type": "xp",
"weight": 2,
"base_min": 20,
"base_max": 40,
"per_kill_min": 8,
"per_kill_max": 12
}
]
}`rolls` controls how many weighted entries are selected. Delivery tables may use `per_item_min` and `per_item_max` as aliases for `per_kill_min` and `per_kill_max`.Equipment Tables
Equipment tables use the same weighted slot format as group hunts. For example:
{
"slots": {
"right_hand": [
{
"id": "minecraft:iron_hoe",
"weight": 1,
"enchantments": [
{
"id": "minecraft:knockback",
"min_level": 3,
"max_level": 3
}
]
}
],
"helmet": [
{
"id": "minecraft:sculk",
"weight": 1
}
]
}
}Supported slot names are `right_hand`, `left_hand`, `mainhand`, `offhand`, `helmet`, `chestplate`, `leggings`, and `boots`. Every configured slot is rolled independently. Use `minecraft:air` as a weighted entry when a slot should sometimes be explicitly empty.The generated server configuration file is:
config/mebahelrpgrquest/quest_board_contracts.json
Its contractTypeWeightsByBoardLevel section controls how frequently each kind of contract appears at every board level.
Current Status and Credits
This mod is in active development. Features are being added and refined regularly so feedback and suggestions are genuinely appreciated.
Join the community and follow development on Discord: https://discord.com/invite/y8uC2NepkB


