Molang is the scripting language that powers everything dynamic in Journey. It’s how you write filters (“only count shiny Pokemon”), conditions (“require 3 gym badges”), and scripts (“give the player a reward and send a message”).
If you’ve written an if statement or a formula in a spreadsheet, you already know the basics. Molang is just expressions that evaluate to values.
Everything in Molang is either a number or a string :
0.0 Zero (also means "false")
1.0 One (also means "true")
'hello' A string (use single quotes)
Booleans don’t exist as a separate type — 0.0 is false, anything non-zero is true.
10 * 5 → 50 Multiplication
10 > 5 → 1.0 Greater than
10 >= 10 → 1.0 Greater than or equal
10 <= 10 → 1.0 Less than or equal
true && false → 0.0 AND (both must be true)
true || false → 1.0 OR (at least one must be true)
!true → 0.0 NOT (flips true/false)
condition ? value_if_true : value_if_false
Example:
q.player.has_flag('vip') ? q.player.tell_minimessage('<gold>Welcome, VIP!') : q.player.tell_minimessage('<gray>Welcome!')
In script contexts (rewards, timeline actions), you can chain multiple statements with semicolons:
q.player.add_flag('quest_done'); q.player.tell_minimessage('<gold>Quest complete!'); q.player.progress_levelable('story', 50);
Context Example Task filters "filter": "q.pokemon.is_shiny"Start requirements "start_requirement": "q.player.has_flag('tutorial_done')"Script rewards "scripts": ["q.player.add_flag('badge_1');"]Timeline actions "script": "q.player.tell_minimessage('<gold>Hello!')"Zone scripts Entry, exit, and inside scripts Levelable filters "filter": {"type": "script", "filter": "q.block.id == 'minecraft:stone'"}Buff scripts on_apply_script, on_tick_script, on_remove_scriptEntity visibility Conditions that control per-player entity visibility NPC dialogues Scripts in Cobblemon NPC dialogue actions
These functions are available in any context that has a player (task filters, rewards, timeline scripts, zone scripts, etc.). All are called on q.player.
Function Returns Description q.player.has_task('journey:task_id')1.0 / 0.0Check if the player has an active task q.player.has_subtask('journey:task_id', 'subtask_id')1.0 / 0.0Check if a specific subtask is active q.player.has_completed_task('journey:task_id')1.0 / 0.0Check if the player has completed a task q.player.has_completed_subtask('journey:task_id', 'subtask_id')1.0 / 0.0Check if a specific subtask is completed q.player.start_task('journey:task_id')1.0 / 0.0Start a task for the player
Function Returns Description q.player.has_flag('flag_name')1.0 / 0.0Check if the player has a flag q.player.add_flag('flag_name')— Add a flag to the player q.player.remove_flag('flag_name')— Remove a flag from the player
Function Returns Description q.player.has_item('minecraft:diamond')1.0 / 0.0Check if player has at least 1 q.player.has_item('minecraft:diamond', 5)1.0 / 0.0Check if player has at least 5 q.player.remove_item('minecraft:diamond', 1)— Remove items from inventory q.player.levelNumber Player’s Minecraft XP level
Function Returns Description q.player.pokedex()Struct Get the player’s Pokedex data q.player.starter_pokemon()Struct / 0.0 Get the player’s starter Pokemon data q.player.has_party_pokemon_matching('criteria')1.0 / 0.0Check if any party Pokemon matches criteria q.player.remove_party_pokemon(slot)— Remove the Pokemon in a specific party slot q.player.party_slot_for_pokemon('criteria')Number Find slot index (0-5) for a matching Pokemon, -1.0 if not found
Pokemon matching criteria use key=value pairs separated by spaces:
q.player.has_party_pokemon_matching('species=pikachu')
q.player.has_party_pokemon_matching('species=pikachu shiny=true')
Function Returns Description q.player.has_levelable('name')1.0 / 0.0Check if player has a levelable q.player.levelable_level('name')Number Get current level q.player.levelable_experience('name')Number Get current XP q.player.give_levelable('name')— Give a levelable to the player q.player.progress_levelable('name', amount)1.0Add XP to a levelable q.player.remove_levelable('name')— Remove a levelable q.player.active_levelable()String Get the currently active levelable ID (or 'none') q.player.is_levelable_active('name')1.0 / 0.0Check if a specific levelable is active q.player.switch_active_levelable('name')1.0 / 0.0Switch the active levelable q.player.levelable_mode()String Get mode: 'exclusive', 'single_active', or 'multi_active'
Function Returns Description q.player.has_buff('buff_id')1.0 / 0.0Check if a buff is active q.player.buff_amplifier('buff_id')Number / -1.0 Get buff amplifier level q.player.buff_remaining_ticks('buff_id')Number / -1.0 Get remaining ticks q.player.buff_count('buff_id')Number Count active instances of this buff q.player.apply_buff('buff_id')— Apply with default duration q.player.apply_buff('buff_id', duration)— Apply with specific duration (ticks) q.player.apply_buff('buff_id', duration, amplifier)— Apply with duration and amplifier q.player.apply_buff('buff_id', duration, amplifier, 'source')— Apply with all parameters q.player.remove_buff('buff_id')Number Remove buff, returns count removed q.player.remove_buff_by_source('source')— Remove all buffs from a source q.player.clear_buffs()Number Remove all buffs, returns count
Function Returns Description q.player.is_in_zone('zone-uuid')1.0 / 0.0Check if player is in a specific zone
Function Returns Description q.player.tell_minimessage('<gold>Hello!')— Send a MiniMessage-formatted chat message q.player.execute_command('give {player} minecraft:diamond 1')— Run a server command ({player} = player name)
Function Returns Description q.player.launch_timeline('journey:timeline_id')— Launch a timeline q.player.play_cutscene('cutscene_id')1.0Play a cutscene q.player.stop_cutscene()1.0Stop the current cutscene q.player.in_cutscene()1.0 / 0.0Check if player is in a cutscene q.player.cutscene_progress()Number Get cutscene progress (0.0 - 1.0)
Function Returns Description q.player.start_watching_entity('entity-uuid')— Make player see an entity q.player.stop_watching_entity('entity-uuid')— Make player stop seeing an entity
See Entity Visibility for the full visibility system including types, groups, and managed spawn commands.
Function Returns Description q.player.stop_battle()1.0Force the player out of their current battle
Function Returns Description q.player.play_per_player_entity_animation('entity-uuid', 'anim')1.0Play entity animation only this player sees
Function Returns Description q.player.push(x, y, z, force)— Apply a force push to the player
Function Returns Description q.player.backpack_add_item('item_id')1.0Add 1 item to backpack q.player.backpack_add_item('item_id', count)1.0Add items to backpack q.player.backpack_has_item('item_id')1.0 / 0.0Check if backpack has at least 1 q.player.backpack_has_item('item_id', count)1.0 / 0.0Check if backpack has at least N q.player.backpack_remove_item('item_id', count)Number Remove items, returns count removed q.player.backpack_count_item('item_id')Number Count items in backpack q.player.backpack_free_slots()Number Get number of empty slots q.player.backpack_clear()1.0Clear all items q.player.backpack_open()1.0Open backpack GUI q.player.backpack_give_configured('config_id', count)— Give a pre-configured item q.player.backpack_has_configured('config_id', count)1.0 / 0.0Check for configured item q.player.backpack_remove_configured('config_id', count)— Remove configured item
Function Returns Description q.player.player_party()Struct Get party data (see below)
The party struct has these sub-functions:
q.player.player_party().exists() 1.0 if in a party
q.player.player_party().size() Number of members
q.player.player_party().is_leader() 1.0 if player is leader
q.player.player_party().has_member('Name') 1.0 if member exists
q.player.player_party().leader_name() Leader's name
q.player.player_party().name() Party name
q.player.player_party().max_members() Max allowed members
q.player.player_party().is_public() 1.0 if party is public
Function Returns Description q.player.toggle_path_visualization()1.0 / 0.0Toggle path debug display q.player.show_path_visualization(show)— 1.0 to show, 0.0 to hideq.player.preview_path('path_id')1.0 / 0.0Preview a specific path
These functions are available in NPC contexts (Cobblemon NPC dialogues, NPC interactions). Called on the npc object.
Function Description npc.play_animation('anim_name')Play animation visible to all nearby players npc.play_animation('anim_name', 'player-uuid')Play animation visible to one player only
Function Description npc.say('Hello! I am %npc%!')NPC says a message (%npc% = NPC name) npc.say('Hello!', 'player-uuid')Say to a specific player only
Function Returns Description npc.distance_to_player('player-uuid')Number Distance in blocks to a player
Function Returns Description npc.walk_path('path_id')1.0 / 0.0Start walking a path npc.stop_walking()1.0 / 0.0Stop walking npc.pause_walking()1.0 / 0.0Pause walking npc.resume_walking()1.0 / 0.0Resume walking npc.is_walking_path()1.0 / 0.0Check if currently walking npc.walking_progress()Number Walking progress (0.0 - 100.0) npc.assign_path('path_id')— Assign a path (auto-starts by default) npc.assign_path('path_id', 0.0)— Assign without auto-starting npc.unassign_path()1.0Unassign current path npc.has_assigned_path()1.0 / 0.0Check if a path is assigned npc.get_assigned_path()String Get assigned path ID
Function Returns Description npc.set_visibility_condition("molang_expression")— Set condition for all players npc.set_player_visibility('player-uuid', "molang_expression")— Set condition for one player npc.force_show_to_player('player-uuid')1.0Force NPC visible to player npc.force_hide_from_player('player-uuid')1.0Force NPC hidden from player npc.is_visible_to_player('player-uuid')1.0 / 0.0Check if visible to player npc.update_visibility()1.0Refresh visibility for all players
When events fire (in task filters and levelable filters), they provide event-specific data through the q namespace. See the Events page for the full reference of what each event provides.
Common patterns:
q.pokemon.species.identifier Pokemon species (e.g., 'cobblemon:pikachu')
q.pokemon.level Pokemon level
q.pokemon.is_shiny 1.0 if shiny
q.battle.is_pvw 1.0 if wild battle
q.battle.is_pvn 1.0 if NPC trainer battle
q.block.id Block registry ID
q.item.id Item registry ID
q.entity.uuid Entity UUID
Standard math functions are available:
math.abs(-5) → 5 Absolute value
math.ceil(4.2) → 5 Round up
math.floor(4.8) → 4 Round down
math.round(4.6) → 5 Round to nearest
math.sqrt(16) → 4 Square root
math.random() → 0.0-1.0 Random decimal
math.random(1, 10) → 1-10 Random integer in range
math.min(5, 10) → 5 Minimum
math.max(5, 10) → 10 Maximum
Only allow this task when two previous quests are done:
"start_requirement" : " q.player.has_completed_task('journey:gym_1') && q.player.has_completed_task('journey:gym_2') "
Show different messages based on a flag:
"script" : " q.player.has_flag('secret_key') ? q.player.tell_minimessage('<green>The door opens!') : q.player.tell_minimessage('<red>The door is locked.') "
Set flags, give XP, send a message, and launch a cutscene:
" q.player.add_flag('champion_defeated'); " ,
" q.player.progress_levelable('story_progress', 500); " ,
" q.player.tell_minimessage('<gold><bold>You are the Champion!'); " ,
" q.player.launch_timeline('journey:champion_celebration'); "
npc.set_visibility_condition("q.player.has_completed_task('journey:rescue_professor')")
This NPC is invisible to players who haven’t completed the rescue quest.
"event" : " POKEMON_CAPTURE " ,
"filter" : " q.player.is_in_zone('safari-zone-uuid') && q.player.has_flag('safari_pass') " ,
Only counts catches inside the Safari Zone when the player has a safari pass.
q.player.has_party_pokemon_matching('species=pikachu') ? 1.0 : 0.0
temp.slot = q.player.party_slot_for_pokemon('species=pikachu');
temp.slot >= 0.0 ? q.player.tell_minimessage('<green>Pikachu is in slot ' + temp.slot) : q.player.tell_minimessage('<red>No Pikachu in your party!')
Short-circuit evaluation: Put cheap checks first — q.player.has_flag('eligible') && q.player.has_party_pokemon_matching('legendary=true') skips the expensive Pokemon check if the flag isn’t set
Strings use single quotes: 'cobblemon:pikachu' not "cobblemon:pikachu"
No semicolons in filters: Filters are single expressions. Semicolons are only for script contexts
Use q. prefix: Always q.player, q.pokemon, q.zone, etc.
No-param functions skip parentheses: q.pokemon.level works, no need for q.pokemon.level()
Test incrementally: Start with "filter": "1.0", verify events fire, then add conditions one at a time
Check server logs: Molang parse errors appear in the console