Flat unlocks
One condition, one reward list. Perfect for one-shot milestones like “first catch” or “beat the Elite Four”.
Achievements are Journey’s milestone tracker. Each achievement is a self-contained JSON file with an icon, a category, a point value, and a reward list. Players see their unlocked achievements in the Content Book’s Achievements tab.
New in Beta 2Flat unlocks
One condition, one reward list. Perfect for one-shot milestones like “first catch” or “beat the Elite Four”.
Progressive ladders
Named tiers with their own thresholds, ids, and point values. Great for counters: “win 10 / 50 / 200 / 500 battles”.
Hidden spoilers
hidden: true keeps an achievement out of the Content Book list until the player unlocks it. The unlock toast still fires.
Script-grantable
Cutscenes, timelines, and scripts can grant achievements directly without evaluating a criteria expression.
Here’s the simplest possible achievement — unlock “Gotta Start Somewhere” when a player catches their first Pokemon:
File: config/journey/achievements/first_catch.json
{ "id": "first_catch", "name": "<yellow>Gotta Start Somewhere", "description": "Catch your very first Pokemon.", "icon": "cobblemon:poke_ball", "category": "POKEMON", "criteria": "catch_pokemon", "hidden": false, "points": 10, "rewards": [ { "type": "command", "data": { "command": "give {player} cobblemon:poke_ball 5" } } ]}That’s it. When the criteria resolves true, the player unlocks the achievement, earns 10 points, receives five Poke Balls, and sees a toast. Files are loaded recursively from config/journey/achievements/, keyed by the id field — so you can organize them into subdirectories however you like.
Achievements come in two shapes. Pick the one that fits your milestone.
A flat achievement has one unlock condition and one reward list. Use it for one-shot events that either fire or don’t: “beat the first gym,” “catch your starter,” “complete the tutorial.”
{ "id": "first_shiny", "name": "<light_purple>A Different Sparkle", "description": "Catch a shiny Pokemon in the wild.", "icon": "cobblemon:shiny_stone", "category": "POKEMON", "criteria": "q.player.has_flag('journey:shiny_caught')", "hidden": true, "points": 50, "rewards": [ { "type": "currency", "data": { "currency": "impactor:pokedollars", "amount": 10000 } } ]}The criteria field is a Molang expression. When it resolves truthy, the achievement unlocks.
A progressive achievement is a ladder of tiers. Each tier has its own id, threshold, and point value. Use it for counters: catches, battles, trades, zones discovered.
{ "id": "battle_victories", "name": "<red>Rising Champion", "description": "Win battles to prove your strength as a trainer.", "icon": "minecraft:diamond_sword", "category": "COMBAT", "points": 25,
"progressive": [ { "target": 10, "id": "battle_victories_10", "name": "Aspiring Fighter", "points": 10 }, { "target": 50, "id": "battle_victories_50", "name": "Skilled Battler", "points": 25 }, { "target": 200, "id": "battle_victories_200", "name": "Battle Veteran", "points": 50 }, { "target": 500, "id": "battle_victories_500", "name": "Battle Legend", "points": 100 } ],
"progress_source": "journey:battle_victories",
"rewards": [ { "type": "currency", "data": { "currency": "impactor:pokedollars", "amount": 2500 } } ]}For progressive achievements the top-level criteria field is ignored. Only progress_source + tier target values drive unlocks.
| Field | Type | Default | Description |
|---|---|---|---|
id | String | Required | Registry key. Files with an empty id are skipped. |
name | String | "" | Display name. Supports MiniMessage. |
description | String or String[] | [] | Single strings auto-wrap into a one-element list. |
icon | String | minecraft:paper | Vanilla or modded item id. |
category | Enum | GENERAL | One of GENERAL, EXPLORATION, COMBAT, COLLECTION, STORY, POKEMON, SOCIAL. |
criteria | Molang or Condition DSL | "" | Flat achievements only. Empty = grantable only by scripts / cutscenes. |
rewards | Reward[] | [] | Polymorphic — same reward types as tasks. |
hidden | Boolean | false | Hides from the Content Book list until unlocked. Unlock toasts still fire. |
points | Int | 0 | Added to the player’s lifetime achievement points. |
progressive | Tier[] | null | When set, turns the achievement into a ladder. |
progress_source | String | null | Required for progressive achievements. Drives tier progress. |
| Field | Notes |
|---|---|
target | Threshold compared against the player’s current progress count. |
id | Independently tracked as an unlock. Convention: <parent_id>_<target>. |
name | Toast title for the tier. |
points | Awarded when this tier unlocks. |
| Value | Counts |
|---|---|
"pokedex_caught" | Species in the player’s Pokedex with CAUGHT knowledge. |
Any other string X | Player flags that equal X or start with X:. |
A flag-prefix source expects your content to write matching flag entries — via task rewards, cutscene hooks, or scripts.
Achievements can be awarded two ways:
Achievement rewards use the same reward types and behavior as the task system. Any reward kind valid in a task config is valid here: command, currency, item, script, timeline, buff, reputation.
"rewards": [ { "type": "command", "data": { "command": "give {player} cobblemon:rare_candy 3" } }, { "type": "currency", "data": { "currency": "impactor:pokedollars", "amount": 1000 } }, { "type": "script", "data": { "scripts": ["q.player.tell_minimessage('<gold>Legendary!');"] } }]| Query | Returns |
|---|---|
query.has_achievement(id) | 1.0 if unlocked, else 0.0 |
query.achievement_points() | Current lifetime achievement points |
query.has_discovery(zoneId) | 1.0 if the zone has been discovered |
query.discovery_count() | Number of zones the player has discovered |
Ten default definitions ship with Journey and are copied into config/journey/achievements/ on first server start:
| File | Category | Type |
|---|---|---|
first_catch.json | POKEMON | flat |
first_evolution.json | POKEMON | flat |
hatch_first_egg.json | POKEMON | flat |
shiny_encounter.json | POKEMON | flat, hidden |
legendary_hunter.json | POKEMON | flat, hidden |
pokemon_collector.json | COLLECTION | progressive (4 tiers) |
battle_victories.json | COMBAT | progressive (4 tiers) |
world_explorer.json | EXPLORATION | progressive (3 tiers) |
quest_completionist.json | GENERAL | progressive (3 tiers) |
social_butterfly.json | SOCIAL | progressive (3 tiers) |
catch_pokemon resolves against Molang queries — it won’t fire unless you’ve wired a matching query. Use real expressions (q.player.has_flag('journey:shiny_caught')) or the Condition DSL form.criteria. Only progress_source + tier target values drive unlocks.hidden: true only suppresses the Content Book listing before unlock.There are no dedicated /journey achievement subcommands. To grant an achievement from chat, use a command reward that writes a player flag, or grant it from a cutscene, timeline, or script.
<parent>_<target> to keep them unique across your pack.hidden: true for spoilers. Shiny, legendary, and story milestones benefit from hiding the listing until earned.journey: flag namespace so progressive sources don’t collide with other packs.