Quests

Configure the quest system

Overview

The quest system lets you create tasks for players to complete — gathering resources, reaching skill levels, killing entities, and more. Quests are defined as JSON files in mods/mmoskilltree/quests/ and loaded automatically on startup.

Quests are organized into categories (e.g., main, daily, misc) and can have prerequisites, level requirements, and permission gates. Players interact with quests via the Quests UI tab or /quest, and admins manage them with /mmoquestadmin.

Default Quests & Customization

On every server start, default quests are written to mods/mmoskilltree/quests/_defaults/default-quests.json. This file is always overwritten, so defaults stay up-to-date with new mod versions automatically.

To customize quests, create your own .json files anywhere in the quests/ folder (or subdirectories). If any user files exist outside of _defaults/ and backups/, the default quests are ignored entirely. The generated default file remains as a reference you can copy and customize.

Servers upgrading from older versions will have their example-quests.json automatically moved to quests/backups/.

After editing quest files, run /mmoquestadmin reload to apply changes without restarting the server.

File Structure

Each JSON file in the quests/ directory contains a schemaVersion and a quests array. You can split quests across multiple files (e.g., one per category). The directory is scanned recursively.

{
  "schemaVersion": 1,
  "quests": [
    {
      "id": "mining_beginner",
      "displayName": "Novice Miner",
      "description": "Prove your mining skills by breaking some stone.",
      "category": "main",
      "tags": ["gathering", "beginner"],
      "enabled": true,
      "sortOrder": 1,
      "autoAccept": true,
      "sequential": false,
      "repeatable": false,
      "cooldownSeconds": 0,
      "autoClaimRewards": true,
      "permission": null,
      "prerequisites": [],
      "requirements": { "minLevel": 0, "minSkill": null, "minSkillLevel": 0 },
      "objectives": [
        {
          "id": "mine_stone",
          "type": "BREAK_BLOCK",
          "target": "Stone",
          "amount": 150,
          "displayText": "Mine 150 Stone blocks",
          "matchMode": "CONTAINS"
        }
      ],
      "rewards": [
        {
          "type": "COMMAND",
          "command": "/give {player} Tool_Pickaxe_Iron --quantity=1",
          "displayName": "Iron Pickaxe",
          "description": "A sturdy pickaxe for your efforts"
        },
        {
          "type": "XP",
          "skill": "MINING",
          "amount": 200,
          "displayName": "+200 Mining XP"
        }
      ]
    }
  ]
}

Quest Fields

Basic Fields

FieldTypeDefaultDescription
idStringrequiredUnique quest identifier. Cannot contain | = : , characters
displayNameStringidHuman-readable name shown in the UI and notifications
descriptionString""Quest description shown in the quest log
categoryString"misc"Category for grouping (e.g., main, daily, misc)
enabledBooleantrueWhether the quest is active. Disabled quests are not indexed or offered
sortOrderInteger0Sort position within category (lower = first)
tagsString[][]Tags for filtering and organization (e.g., ["epic", "combat", "chapter-2"])
variablesObject{}Key-value metadata for custom data (e.g., { "difficulty": "hard", "region": "mountains" })

Behavior Fields

FieldTypeDefaultDescription
autoAcceptBooleanfalseAutomatically start the quest when a matching event fires (no manual accept needed)
sequentialBooleanfalseObjectives must be completed in order (top to bottom)
repeatableBooleanfalseQuest can be completed multiple times
cooldownSecondsLong0Seconds before a repeatable quest can be accepted again (e.g., 86400 for daily)
autoClaimRewardsBooleantrueRewards are given automatically on completion. If false, player must use /quest claim
permissionStringnullPermission node required to accept the quest (e.g., mmoskilltree.quest.vip)
npcViewIdStringnullNPC identifier that surfaces this quest. When set, the quest is hidden from the quest log until accepted and only appears in the NPC quest UI
npcDisplayNameStringnullDisplay name for the NPC shown in the NPC quest UI header
npcRequiredToAcceptBooleanfalseWhen true, the quest can only be accepted through the NPC quest page, not from the quest log
incompleteMarkdownStringnullNPC dialogue shown before the quest is accepted. Supports # headers, **bold**, and *italic*
activeMarkdownStringnullNPC dialogue shown while the quest is in progress
completeMarkdownStringnullNPC dialogue shown when the quest is complete

Requirements

The requirements field gates who can accept the quest. It accepts either a single object or an array of objects. All conditions must be met before the quest becomes available.

Single Object (one skill)

The simplest format — a single object with an optional total level gate and one skill requirement:

"requirements": {
  "minLevel": 25,
  "minSkill": "MINING",
  "minSkillLevel": 15
}
FieldTypeDefaultDescription
minLevelInteger0Minimum total level across all skills
minSkillStringnullSkill name for the skill-level requirement (e.g., MINING)
minSkillLevelInteger0Minimum level in the specified skill

Array Format (multiple skills)

To require multiple skills, use an array of requirement objects. Each entry can specify a minLevel, a minSkill/minSkillLevel pair, or both. The highest minLevel across all entries is used as the total level gate, and every skill requirement must be met.

"requirements": [
  { "minLevel": 25 },
  { "minSkill": "MINING", "minSkillLevel": 15 },
  { "minSkill": "CRAFTING", "minSkillLevel": 20 }
]

In this example, the player needs total level 25, Mining level 15, and Crafting level 20 to accept the quest. All skill requirements are displayed in the quest log's “Requires:” line.

Both formats are fully supported. Use the single object when you only need one skill gate, and the array when you need multiple.

Prerequisites

Prerequisites control which quests must be completed before this quest becomes available. There are two formats: a simple array (AND-all) and a structured object (AND/OR grouping).

Simple Format (AND)

A plain array of quest IDs — all must be completed:

"prerequisites": ["mining_beginner", "combat_initiate"]

Branching Format (AND/OR)

For branching storylines, use an object with mode and nested groups. This lets you create quest paths where players can choose between different branches:

"prerequisites": {
  "mode": "AND",
  "quests": ["quest_intro"],
  "groups": [
    {
      "mode": "OR",
      "quests": ["quest_path_warrior", "quest_path_mage"]
    }
  ]
}

In this example, the player must complete quest_intro AND either quest_path_warrior OR quest_path_mage.

FieldTypeDescription
modeString"AND" (all must pass) or "OR" (any one must pass)
questsString[]Quest IDs evaluated directly with this group's mode
permissionsString[]Permission nodes evaluated with this group's mode. In AND mode all must be held; in OR mode any one suffices
groupsArrayNested prerequisite groups, each with their own mode, quests, permissions, and groups

Groups can be nested to any depth. The simple array format is fully backward compatible and equivalent to { "mode": "AND", "quests": [...] }.

The quest UI displays branching prerequisites with "OR" labels so players can see which paths are available. Permission requirements display as "Permission: node.name".

Permission Prerequisites

Add a permissions array to any prerequisite group to require permission nodes alongside quest completions. Permissions and quests can be freely mixed in AND/OR logic:

"prerequisites": {
  "mode": "AND",
  "quests": ["first_blood"],
  "permissions": ["rank.vip", "server.quest.unlock"]
}

In this example, the player must have completed first_blood AND hold both rank.vip and server.quest.unlock permissions. In OR mode, completing any quest or holding any permission in the group would be enough.

Permissions work at any nesting level, so you can create complex gates like "complete quest_a AND (have rank.vip OR complete quest_b)".

Visibility

The optional visibility object controls whether a quest appears in the quest log. By default, all quests are visible. Hidden quests remain invisible until their conditions are met — but once a quest is started (active, completed, or on cooldown), it is always visible regardless of visibility settings.

FieldTypeDefaultDescription
hiddenBooleanfalseMaster switch. When true, the quest is hidden until conditions below are met
permissionStringnullQuest only visible to players with this permission
requirePrerequisitesBooleanfalseQuest only visible after all prerequisite quests are completed
requireLevelBooleanfalseQuest only visible when the player meets the level/skill requirements

When multiple conditions are set, all must pass for the quest to be visible. If hidden is true with no other conditions, the quest falls back to the standard acceptance check — it becomes visible when the player meets all requirements and prerequisites.

"visibility": {
  "hidden": true,
  "requirePrerequisites": true
}

This is useful for quest chains where you don't want players to see future quests until they've completed the current step.

Objectives

Each quest has one or more objectives. Objective ordering can be controlled in two ways:

  • sequential: true — All objectives must be completed top-to-bottom (legacy behavior, still supported)
  • Per-objective order field — Group objectives into stages for mixed sequential/parallel completion

Objective Types

TypeTriggered ByTarget Example
BREAK_BLOCKBreaking a blockStone, Ore_Iron
PLACE_BLOCKPlacing a blockPlank
CRAFT_ITEMCrafting an itemPlank
KILL_ENTITYKilling an entityTrork
DEAL_DAMAGEDealing damage to an entityTrork
PICKUP_ITEMPicking up an itemCoin
CATCH_FISHCatching a fish (via fishing mod or fish mob kill)Salmon, Lobster, or "" (any fish)
REACH_LEVELReaching a skill levelMINING (skill name) or TOTAL
TALK_TO_NPCInteracting with an NPC (requires HyCitizens)Citizen ID, or """" (any NPC)
TURN_INPlayer clicks "Turn In" button in quest UIOre_Iron (item ID to remove from inventory)

Objective Fields

FieldTypeDefaultDescription
idStringrequiredUnique ID within the quest. Cannot contain | = : , characters
typeStringrequiredOne of the objective types above
targetString""What to match against (block ID, entity type, skill name, etc.)
amountInteger1How many times the objective must be triggered. For REACH_LEVEL, this is the required level
displayTextStringauto-generatedText shown to the player (e.g., "Mine 150 Stone blocks")
matchModeStringCONTAINSHow the target is matched against event identifiers
qualifierStringnoneSecondary filter that must also match for progress to count. Case-insensitive exact match when set. Omit or null to match any event. Use "" (empty string) to only match events with no qualifier. Primary use: elite mob tier (e.g., "Legendary")
orderInteger0Ordering stage for mixed sequential/parallel objectives (see below)
detailMarkdownStringnullPer-objective NPC dialogue text shown in the NPC quest detail panel when this objective is the current active objective

Objective Ordering

The order field lets you create quests with mixed sequential and parallel objectives. Objectives with the same order value can be completed in any order (parallel). Objectives with a higher order value are locked until all lower-order objectives are complete.

"objectives": [
  { "id": "gather_ore", "type": "BREAK_BLOCK", "target": "Ore_Iron", "amount": 10, "order": 1 },
  { "id": "craft_ingots", "type": "CRAFT_ITEM", "target": "Ingot_Iron", "amount": 5, "order": 1 },
  { "id": "kill_boss", "type": "KILL_ENTITY", "target": "Skeleton", "amount": 3, "order": 2 }
]

In this example, the first two objectives (order 1) can be done in any order. The third objective (order 2) only becomes active after both order-1 objectives are complete. The quest UI groups objectives by stage and shows which are currently active.

  • order: 0 or omitted — No ordering constraint (parallel with everything)
  • Using sequential: true auto-assigns incrementing order values for backward compatibility

Match Modes

ModeBehaviorExample
CONTAINSTarget string appears anywhere in the identifier"Stone" matches Stone, Cobblestone, Sandstone
EXACTIdentifier must match the target exactly"Stone" matches only Stone
PREFIXIdentifier must start with the target"Ore_" matches Ore_Iron, Ore_Gold

Qualifier (Secondary Filter)

The qualifier field adds a secondary filter beyond target. When set, both the target and qualifier must match for progress to count. This is useful for filtering by elite mob tier, weapon type, or other event metadata.

{
  "id": "kill_legendary_bears",
  "type": "KILL_ENTITY",
  "target": "Bear",
  "qualifier": "Legendary",
  "amount": 3,
  "displayText": "Defeat 3 Legendary Bears"
}
  • Omitted or null — matches any event (backward compatible)
  • Empty string "" — only matches events with no qualifier (e.g., normal mobs)
  • Any other value — case-insensitive exact match against the event qualifier

Currently, the elite mobs system provides the mob tier name (e.g., Legendary, Epic, Rare) as the qualifier for KILL_ENTITY and DEAL_DAMAGE objectives.

Rewards

Quest rewards are delivered when the quest is completed (or claimed, if autoClaimRewards is false). Each quest can have multiple rewards. Rewards support four types: commands, XP grants, boost tokens, and currency.

Reward Types

TypeDescriptionRequired Fields
COMMANDExecute a server commandcommand
XPGrant skill XP directlyskill, amount
BOOST_TOKENActivate a timed XP multiplier boostskill, multiplier, durationMinutes
CURRENCYGrant currency (gold)amount

If type is omitted, the reward defaults to COMMAND for backward compatibility. Existing command-based rewards continue to work unchanged.

Reward Examples

"rewards": [
  {
    "type": "COMMAND",
    "command": "/give {player} Tool_Pickaxe_Iron --quantity=1",
    "displayName": "Iron Pickaxe"
  },
  {
    "type": "XP",
    "skill": "MINING",
    "amount": 500,
    "displayName": "+500 Mining XP"
  },
  {
    "type": "BOOST_TOKEN",
    "skill": "ALL",
    "multiplier": 2.0,
    "durationMinutes": 30,
    "displayName": "2x All XP (30m)"
  },
  {
    "type": "CURRENCY",
    "amount": 100,
    "displayName": "100 Gold"
  }
]

Common Reward Fields

FieldTypeDefaultDescription
typeStringCOMMANDReward type: COMMAND, XP, BOOST_TOKEN, or CURRENCY
displayNameString""Shown in the quest UI and completion notification
descriptionString""Additional description shown in the quest UI

Command Reward Fields

FieldTypeDefaultDescription
commandStringrequiredThe command to execute
runAsStringCONSOLECONSOLE or PLAYER
delayTicksInteger0Delay in ticks before executing the command
queueIfOfflineBooleanfalseIf the player is offline, queue the reward for next login

Command Placeholders

PlaceholderReplaced With
{player}Player name
{questId}The quest ID

XP Reward Fields

FieldTypeDescription
skillStringSkill name (e.g., MINING, SWORDS, or a custom skill ID)
amountIntegerXP amount to grant

Boost Token Reward Fields

FieldTypeDescription
skillStringSkill to boost (e.g., MINING) or ALL for all skills
multiplierDoubleXP multiplier (e.g., 2.0 for double XP)
durationMinutesIntegerHow long the boost lasts in minutes

Currency Reward Fields

FieldTypeDescription
amountIntegerCurrency amount to grant

Tags & Variables

Quests can include tags for categorization and variables for custom metadata. Tags are displayed as chips below the quest description in the quest UI and are also used for filtering on the docs site Quest Gallery.

{
  "id": "dragon_slayer",
  "displayName": "Dragon Slayer",
  "tags": ["epic", "combat", "chapter-2"],
  "variables": {
    "difficulty": "hard",
    "region": "mountains"
  }
}

Variables are stored as key-value pairs and are available for future conditional logic and filtering on the docs site quest gallery.

Quest States

Each quest tracks a per-player state:

StateDescription
NOT_STARTEDQuest has not been accepted
ACTIVEQuest is in progress, objectives being tracked
COMPLETED_UNCLAIMEDAll objectives done, rewards not yet claimed (autoClaimRewards: false)
COMPLETEDQuest finished and rewards delivered
ON_COOLDOWNRepeatable quest waiting for cooldown to expire

Flow: NOT_STARTED → ACTIVE → COMPLETED (auto-claim) or COMPLETED_UNCLAIMED → COMPLETED (manual claim). For repeatable quests, the cycle resets after the cooldown period.

Admin Commands

The /mmoquestadmin command requires OP or mmoskilltree.admin permission. Arguments are pipe-separated.

CommandDescription
/mmoquestadmin reloadReload all quest files from disk
/mmoquestadmin list [category]List all quests, optionally filtered by category
/mmoquestadmin give --args=player|questIdGive a quest to a player (use * for all players)
/mmoquestadmin reset --args=player|questIdReset a quest for a player (use all to reset all quests)
/mmoquestadmin complete --args=player|questIdForce-complete a quest and execute rewards (queues rewards if player is offline)
/mmoquestadmin status --args=player[|questId]View quest states and objective progress for a player

Player Commands

The /quest command is available to all players.

CommandDescription
/quest accept <questId>Accept a quest (checks prerequisites, level requirements, and permissions)
/quest claim <questId|all>Claim rewards for completed quests (checks inventory space for /give rewards)
/quest abandon <questId>Abandon an active quest and reset its progress
/quest status [questId]View your active quests and objective progress

Examples

Simple Gathering Quest

A beginner quest that auto-accepts and rewards an iron pickaxe:

{
  "id": "mining_beginner",
  "displayName": "Novice Miner",
  "description": "Prove your mining skills by breaking some stone.",
  "category": "main",
  "sortOrder": 1,
  "autoAccept": true,
  "objectives": [
    {
      "id": "mine_stone",
      "type": "BREAK_BLOCK",
      "target": "Stone",
      "amount": 150,
      "displayText": "Mine 150 Stone blocks"
    }
  ],
  "rewards": [
    {
      "command": "/give {player} Tool_Pickaxe_Iron --quantity=1",
      "displayName": "Iron Pickaxe",
      "description": "A sturdy pickaxe for your efforts"
    }
  ]
}

Sequential Quest with Prerequisites

Requires the mining_beginner quest to be completed first and Mining level 5. Objectives must be completed in order:

{
  "id": "mining_journeyman",
  "displayName": "Journeyman Miner",
  "description": "Advance your mining career with harder materials.",
  "category": "main",
  "sortOrder": 2,
  "autoAccept": true,
  "sequential": true,
  "prerequisites": ["mining_beginner"],
  "requirements": {
    "minSkill": "MINING",
    "minSkillLevel": 5
  },
  "objectives": [
    {
      "id": "mine_iron",
      "type": "BREAK_BLOCK",
      "target": "Ore_Iron",
      "amount": 25,
      "displayText": "Mine 25 Iron Ore"
    },
    {
      "id": "reach_mining_10",
      "type": "REACH_LEVEL",
      "target": "MINING",
      "amount": 10,
      "displayText": "Reach Mining level 10"
    }
  ],
  "rewards": [
    {
      "command": "/give {player} XpToken_Unarmed_Shard --quantity=2",
      "queueIfOffline": true,
      "displayName": "Unarmed XP Shards x2"
    }
  ]
}

Repeatable Daily Quest

Repeatable every 24 hours (86400 seconds). Not auto-accepted — players must start it manually or via admin command:

{
  "id": "daily_woodcutting",
  "displayName": "Daily Lumber",
  "description": "Chop some wood for daily rewards.",
  "category": "daily",
  "sortOrder": 100,
  "autoAccept": false,
  "repeatable": true,
  "cooldownSeconds": 86400,
  "objectives": [
    {
      "id": "chop_logs",
      "type": "BREAK_BLOCK",
      "target": "Wood",
      "amount": 30,
      "displayText": "Chop 30 logs"
    }
  ],
  "rewards": [
    {
      "command": "/give {player} XpToken_Woodcutting_Fragment --quantity=2",
      "queueIfOffline": true,
      "displayName": "2 Woodcutting XP Fragments",
      "description": "Daily woodcutting payment"
    }
  ]
}

Hidden Quest Chain

This quest is invisible until the player completes mining_journeyman. The visibility object with requirePrerequisites: true prevents spoilers for future quest steps:

{
  "id": "mining_expert",
  "displayName": "Mining Expert",
  "description": "Prove yourself as a true mining expert.",
  "category": "main",
  "sortOrder": 3,
  "sequential": true,
  "prerequisites": ["mining_journeyman"],
  "requirements": {
    "minSkill": "MINING",
    "minSkillLevel": 15
  },
  "visibility": {
    "hidden": true,
    "requirePrerequisites": true
  },
  "objectives": [
    {
      "id": "mine_gold",
      "type": "BREAK_BLOCK",
      "target": "Ore_Gold",
      "amount": 50,
      "displayText": "Mine 50 Gold Ore"
    },
    {
      "id": "reach_mining_20",
      "type": "REACH_LEVEL",
      "target": "MINING",
      "amount": 20,
      "displayText": "Reach Mining level 20"
    }
  ],
  "rewards": [
    {
      "command": "/give {player} XpToken_Mining_Token --quantity=3",
      "queueIfOffline": true,
      "displayName": "3 Mining XP Tokens",
      "description": "A reward for the dedicated miner"
    }
  ]
}

Multi-Skill Requirements

This quest requires both Mining 30 and Crafting 20 before it can be accepted. The array format lets you gate quests behind any combination of skills:

{
  "id": "master_smith",
  "displayName": "Master Smith",
  "description": "Only a skilled miner and crafter can forge the ultimate blade.",
  "category": "main",
  "sortOrder": 20,
  "requirements": [
    { "minSkill": "MINING", "minSkillLevel": 30 },
    { "minSkill": "CRAFTING", "minSkillLevel": 20 }
  ],
  "objectives": [
    {
      "id": "craft_blade",
      "type": "CRAFT_ITEM",
      "target": "Weapon_Longsword",
      "amount": 1,
      "displayText": "Craft a Longsword"
    }
  ],
  "rewards": [
    {
      "command": "/give {player} XpToken_Crafting_Token --quantity=2",
      "queueIfOffline": true,
      "displayName": "2 Crafting XP Tokens",
      "description": "A reward for the master smith"
    }
  ]
}

Branching Prerequisites

A quest that requires completing an intro quest AND choosing one of two class paths. Players who completed either the warrior or mage path can continue to this quest:

{
  "id": "chapter2_start",
  "displayName": "Chapter 2: The Convergence",
  "description": "Both paths lead here. Your journey continues.",
  "category": "main",
  "sortOrder": 10,
  "tags": ["chapter-2", "epic"],
  "prerequisites": {
    "mode": "AND",
    "quests": ["chapter1_intro"],
    "groups": [
      {
        "mode": "OR",
        "quests": ["path_warrior_complete", "path_mage_complete"]
      }
    ]
  },
  "objectives": [
    {
      "id": "talk_elder",
      "type": "KILL_ENTITY",
      "target": "Elder_NPC",
      "amount": 1,
      "displayText": "Speak with the Elder"
    }
  ],
  "rewards": [
    {
      "type": "BOOST_TOKEN",
      "skill": "ALL",
      "multiplier": 2.0,
      "durationMinutes": 60,
      "displayName": "2x All XP (1hr)"
    }
  ]
}

Mixed Sequential/Parallel Objectives

Objectives with the same order value can be completed in any order. Higher order values unlock after lower ones are done:

{
  "id": "forge_master",
  "displayName": "Forge Master",
  "description": "Gather materials, then forge the blade.",
  "category": "main",
  "sortOrder": 15,
  "objectives": [
    {
      "id": "mine_ore",
      "type": "BREAK_BLOCK",
      "target": "Ore_Iron",
      "amount": 20,
      "displayText": "Mine 20 Iron Ore",
      "order": 1
    },
    {
      "id": "chop_wood",
      "type": "BREAK_BLOCK",
      "target": "Wood",
      "amount": 10,
      "displayText": "Gather 10 Wood",
      "order": 1
    },
    {
      "id": "craft_blade",
      "type": "CRAFT_ITEM",
      "target": "Weapon_Longsword_Iron",
      "amount": 1,
      "displayText": "Forge an Iron Longsword",
      "order": 2
    }
  ],
  "rewards": [
    {
      "type": "XP",
      "skill": "CRAFTING",
      "amount": 1000,
      "displayName": "+1000 Crafting XP"
    },
    {
      "type": "CURRENCY",
      "amount": 50,
      "displayName": "50 Gold"
    }
  ]
}

Quest with Manual Claim

With autoClaimRewards: false, the quest enters the COMPLETED_UNCLAIMED state when objectives are done. Players must use /quest claim to receive rewards — useful when inventory space matters:

{
  "id": "boss_bounty",
  "displayName": "Boss Bounty",
  "description": "Defeat a powerful boss. Return to claim your reward.",
  "category": "main",
  "sortOrder": 6,
  "autoClaimRewards": false,
  "objectives": [
    {
      "id": "slay_boss",
      "type": "KILL_ENTITY",
      "target": "Trork_Chieftain",
      "amount": 1,
      "displayText": "Defeat the Trork Chieftain",
      "matchMode": "EXACT"
    }
  ],
  "rewards": [
    {
      "command": "/give {player} Diamond_Sword --quantity=1",
      "queueIfOffline": true,
      "displayName": "Diamond Sword",
      "description": "A legendary blade for the champion"
    }
  ]
}

NPC Quest with Turn In

Quests can be tied to NPCs using npcViewId. Players discover these quests through NPC interaction (opened via /mmoquestui). The TURN_IN objective type removes items from the player's inventory when they click the Turn In button. Partial turn-in is supported — players can submit what they have and return later with more.

Hyronix NPC Dialog Integration

To open the NPC quest UI when players interact with an NPC, add mmoquestui as a command in your Hyronix NPC Dialog configuration at mods/Hyronix_NPC Dialog/. Configure the NPC's dialog to run mmoquestui <player> <npc_id> so that interacting with the NPC opens the quest page for that player.

{
  "id": "blacksmith_delivery",
  "displayName": "The Blacksmith's Order",
  "description": "Gorrath needs iron ore for his forge.",
  "category": "main",
  "npcViewId": "blacksmith_01",
  "npcDisplayName": "Gorrath the Blacksmith",
  "npcRequiredToAccept": true,
  "incompleteMarkdown": "# The Blacksmith's Request\n\n**Gorrath** looks up from his anvil.\n\n\"I need iron ore. Can you help?\"",
  "activeMarkdown": "\"Still gathering? I'll be here.\"",
  "completeMarkdown": "\"Excellent work! These will do nicely.\"",
  "objectives": [
    {
      "id": "deliver_iron",
      "type": "TURN_IN",
      "target": "Ore_Iron",
      "amount": 10,
      "displayText": "Deliver 10 Iron Ore",
      "matchMode": "EXACT",
      "detailMarkdown": "\"Bring me **10 Iron Ore** from the northern mines.\""
    }
  ],
  "rewards": [
    {
      "type": "XP",
      "skill": "MINING",
      "amount": 500,
      "displayName": "500 Mining XP"
    }
  ]
}