Skip to content

Flag System

The Flag System provides a simple way to track player state and progress using boolean flags. Flags are true/false values that persist across sessions and can be used throughout Journey’s systems for conditional logic.

Flags in Journey offer:

  • Boolean State Tracking: Track what players have done (true/false only)
  • Conditional Logic: Control access to content based on flags
  • Cross-System Integration: Use flags in tasks, zones, timelines, and scripts
  • Persistent Storage: Flags persist across server restarts and player sessions
  • Simple Management: Easy commands and MoLang API

Important: Flags are boolean only. There are no numeric flags, counter flags, or expiry times.


Via MoLang Functions:

q.player.add_flag('tutorial_complete')
q.player.add_flag('visited_cerulean_city')
q.player.add_flag('gym_leader_defeated_brock')

Via Task Rewards:

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

In Task Start Requirements:

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

In Event Filters:

{
"filter": "q.player.has_flag('elite_four_access')"
}

In MoLang Scripts:

// Returns 1.0 if flag exists, 0.0 if not
q.player.has_flag('special_ability_unlocked')
// Use in conditions
q.player.has_flag('champion_defeated') ? 1.0 : 0.0

// Remove a flag completely
q.player.remove_flag('temporary_buff')

Use consistent naming patterns for better organization:

tutorial_* // Tutorial-related flags
quest_* // Quest completion flags
gym_* // Gym-related achievements
story_* // Main story progress
event_* // Special event participation
achievement_* // General achievements
unlock_* // Feature/area unlocks
visited_* // Location discovery
defeated_* // Boss/trainer defeats
collected_* // Item/collectible flags
tutorial_complete
quest_starter_town_finished
gym_badge_boulder
story_chapter_1_complete
event_summer_festival_2024
achievement_catch_100_pokemon
unlock_elite_four_access
visited_mount_silver
defeated_champion_red
collected_all_gym_badges

Track player tutorial progress:

{
"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');"
]
}
}
]
}

Control access to quest chains:

{
"name": "Elite Four Challenge",
"start_requirement": "q.player.has_flag('all_gym_badges') && q.player.has_flag('victory_road_complete')",
"tasks": []
}

Track player achievements through flags:

{
"event": "POKEMON_CAUGHT",
"filter": "q.pokemon.species.identifier == 'cobblemon:mewtwo'",
"target": 1,
"rewards": [
{
"type": "script",
"data": {
"scripts": [
"q.player.add_flag('achievement_legendary_captured');",
"q.player.tell_minimessage('<gold>Achievement Unlocked: Legendary Trainer!');"
]
}
}
]
}

Unlock features based on progress:

{
"level_rewards": [
{
"level": 25,
"rewards": [
{
"type": "script",
"data": {
"scripts": [
"q.player.add_flag('unlock_breeding');",
"q.player.tell_minimessage('<green>Pokémon breeding unlocked!');"
]
}
}
]
}
]
}

Combine multiple flags for complex logic:

{
"start_requirement": "q.player.has_flag('gym_badge_boulder') && q.player.has_flag('gym_badge_cascade')"
}
{
"start_requirement": "q.player.has_flag('champion_path_complete') || q.player.has_flag('admin_override')"
}
{
"filter": "!q.player.has_flag('already_claimed_reward')"
}
{
"start_requirement": "(q.player.has_flag('badge_1') && q.player.has_flag('badge_2') && q.player.has_flag('badge_3')) || q.player.has_flag('skip_gyms')"
}

Track main story advancement:

story_prologue_complete
story_chapter_1_complete
story_chapter_2_complete
story_rival_first_battle
story_legendary_awakened
story_final_battle_complete

Track player accomplishments:

achievement_first_catch
achievement_100_catches
achievement_shiny_hunter
achievement_gym_challenger
achievement_champion
achievement_pokedex_complete

Control feature and area access:

unlock_pc_storage
unlock_trading
unlock_breeding
unlock_competitive_battles
unlock_elite_four
unlock_post_game_content

Track special event participation:

event_halloween_2024_participant
event_tournament_winner
event_community_day_attended
event_legendary_raid_completed

{
"name": "Elite Four Champion Challenge",
"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')"
}
{
"event": "ENTER_ZONE",
"filter": "q.zone.uuid == 'champion-room-uuid' && !q.player.has_flag('visited_champion')",
"target": 1,
"rewards": [
{
"type": "script",
"data": {
"scripts": [
"q.player.add_flag('visited_champion');",
"q.player.tell_minimessage('<gold>You have reached the Champion!');"
]
}
}
]
}

Set flags progressively as players complete objectives:

{
"tasks": [
{
"id": "defeat_gym_1",
"rewards": [
{
"type": "script",
"data": {
"scripts": ["q.player.add_flag('gym_badge_1');"]
}
}
]
},
{
"id": "defeat_gym_2",
"rewards": [
{
"type": "script",
"data": {
"scripts": ["q.player.add_flag('gym_badge_2');"]
}
}
]
}
]
}

Then check all flags for unlock:

{
"name": "Elite Four Access",
"start_requirement": "q.player.has_flag('gym_badge_1') && q.player.has_flag('gym_badge_2') && q.player.has_flag('gym_badge_3') && q.player.has_flag('gym_badge_4') && q.player.has_flag('gym_badge_5') && q.player.has_flag('gym_badge_6') && q.player.has_flag('gym_badge_7') && q.player.has_flag('gym_badge_8')"
}

// Check if player has a flag (returns 1.0 or 0.0)
q.player.has_flag('flag_name')
// Add a flag to the player
q.player.add_flag('flag_name')
// Remove a flag from the player
q.player.remove_flag('flag_name')
// Simple check
q.player.has_flag('tutorial_complete')
// With condition
q.player.has_flag('champion_defeated') == 1.0
// Negation
q.player.has_flag('banned') == 0.0
// Or
!q.player.has_flag('banned')
// Multiple flags
q.player.has_flag('badge_1') && q.player.has_flag('badge_2')

DO:

  • Use descriptive names: tutorial_complete
  • Use consistent prefixes: quest_, gym_, story_
  • Use underscores: visited_pallet_town
  • Name as boolean statements: has_completed_tutorial

DON’T:

  • Use spaces: tutorial complete
  • Be vague: flag1, temp, done
  • Mix naming schemes: tutorialComplete vs tutorial_complete

DO:

  • Document important flags in your project
  • Use flags for persistent state only
  • Clean up obsolete flags when updating content
  • Test flag conditions before deployment

DON’T:

  • Use flags for temporary state (use in-memory state instead)
  • Create hundreds of player-specific flags without need
  • Change flag names without migration plan
  • Rely on undocumented flags

DO:

  • Check flags in conditional logic (very fast)
  • Use compound conditions efficiently
  • Batch flag operations in scripts

DON’T:

  • Set the same flag repeatedly (check first if needed)
  • Create unnecessary flags
  • Use complex nested conditions (simplify where possible)

✅ Boolean values (true/false) ✅ Persistent across sessions ✅ Per-player storage ✅ Cross-system compatible

Not counters - Cannot store numbers (use levelables for progression) ❌ Not timers - Cannot store expiry times ❌ Not values - Cannot store strings or data ❌ Not temporary - Not designed for short-term state (minutes/seconds)


Use Levelables for numeric progression:

q.player.levelable_level('pokemon_caught_count')
q.player.progress_levelable('pokemon_caught_count', 1)

Use task progress or in-memory tracking.

Use timeline system for timed sequences.

Store in custom NBT or external database.


Flags are stored in player data via Cardinal Components:

  • Location: world/data/cardinal-components/<player-uuid>.dat
  • Format: NBT data within JourneyDataObject
  • Persistence: Automatic on data change, periodic saves, disconnect, shutdown


The flag system provides a simple, efficient way to track boolean player state throughout Journey’s systems. Use flags for persistent “did the player do X?” checks, not for counters, timers, or complex data storage.