Skip to content

Flag System

Flags are the simplest and most versatile tool in Journey. They’re true/false values attached to each player that persist across sessions and server restarts. Think of them as checkboxes: “Has this player completed the tutorial? Yes or no.”

Despite their simplicity, flags are the glue that connects Journey’s systems together. Tasks set flags when completed, zones check flags before granting access, NPC visibility depends on flags, and quest chains gate behind flag requirements.

Here’s the fastest way to understand flags:

Set a flag: q.player.add_flag('tutorial_complete')
Check a flag: q.player.has_flag('tutorial_complete') → returns 1.0 (true) or 0.0 (false)
Remove a flag: q.player.remove_flag('tutorial_complete')

That’s it. Three functions cover everything flags do.


The most common pattern — set a flag when a player finishes a task:

{
"type": "script",
"data": {
"scripts": [
"q.player.add_flag('gym_badge_boulder');"
]
}
}

Admins can manage flags directly:

/flag <player> add tutorial_complete
/flag <player> remove tutorial_complete

Gate a quest behind a flag:

{
"start_requirement": "q.player.has_flag('tutorial_complete')"
}

Only count events when a flag is set:

{
"event": "POKEMON_CAPTURE",
"filter": "q.player.has_flag('catching_challenge_active')",
"target": 10
}

Set a flag for each gym badge, then require all 8 for the Elite Four:

Each gym quest reward:

{
"type": "script",
"data": {
"scripts": ["q.player.add_flag('gym_badge_boulder');"]
}
}

Elite Four quest requirement:

{
"start_requirement": "q.player.has_flag('gym_badge_boulder') && q.player.has_flag('gym_badge_cascade') && q.player.has_flag('gym_badge_thunder') && q.player.has_flag('gym_badge_rainbow') && q.player.has_flag('gym_badge_soul') && q.player.has_flag('gym_badge_marsh') && q.player.has_flag('gym_badge_volcano') && q.player.has_flag('gym_badge_earth')"
}

Prevent advanced content until the tutorial is done:

{
"name": "Advanced Battle Tutorial",
"start_requirement": "q.player.has_flag('basic_tutorial_complete') && !q.player.has_flag('advanced_tutorial_complete')",
"rewards": [
{
"type": "script",
"data": {
"scripts": ["q.player.add_flag('advanced_tutorial_complete');"]
}
}
]
}

The ! operator means “NOT” — so this quest only appears when the basic tutorial is done but the advanced one isn’t.

Prevent players from claiming a reward twice:

{
"event": "ENTER_ZONE",
"filter": "q.zone.uuid == 'treasure-room-uuid' && !q.player.has_flag('claimed_treasure')",
"target": 1,
"rewards": [
{
"type": "script",
"data": {
"scripts": [
"q.player.add_flag('claimed_treasure');",
"q.player.tell_minimessage('<gold>You found the hidden treasure!');"
]
}
}
]
}

Unlock server features as players progress:

{
"type": "script",
"data": {
"scripts": [
"q.player.add_flag('unlock_breeding');",
"q.player.tell_minimessage('<green>Pokemon breeding is now unlocked!');"
]
}
}

"q.player.has_flag('badge_1') && q.player.has_flag('badge_2')"
"q.player.has_flag('champion_defeated') || q.player.has_flag('admin_override')"
"!q.player.has_flag('already_claimed')"
"(q.player.has_flag('badge_1') && q.player.has_flag('badge_2')) || q.player.has_flag('skip_gyms')"

Good flag names are descriptive and consistent. Here are recommended patterns:

PrefixUse CaseExamples
tutorial_Tutorial progressiontutorial_complete, tutorial_battle_done
quest_Quest completionquest_starter_town_done, quest_oak_met
gym_badge_Gym achievementsgym_badge_boulder, gym_badge_cascade
story_Main story progressstory_chapter_1, story_rival_defeated
unlock_Feature unlocksunlock_breeding, unlock_elite_four
visited_Location discoveryvisited_mount_silver, visited_lavender_town
defeated_Boss/trainer defeatsdefeated_champion_red, defeated_elite_four
event_Special eventsevent_summer_festival, event_raid_completed
achievement_Achievementsachievement_shiny_hunter, achievement_pokedex_100

FunctionReturnsDescription
q.player.has_flag('name')1.0 or 0.0Check if flag exists
q.player.add_flag('name')Add a flag
q.player.remove_flag('name')Remove a flag

Flags are boolean only. They can only be true (exists) or false (doesn’t exist). They cannot:

  • Store numbers (use Levelables for numeric progression)
  • Store text or data
  • Expire after a time period
  • Count occurrences (use task targets for counting)

If you need to track “how many Pokemon has this player caught?”, use a Levelable. If you need “has this player caught a Pokemon?”, use a flag.


Flags are stored in player data via Cardinal Components and persist across:

  • Server restarts
  • Player disconnects and reconnects
  • Dimension changes

They are per-player and cannot be shared between players (use Global Tasks for shared progress).