Skip to content

NPCs & Path System

Journey extends Cobblemon’s NPC system with MoLang scripting functions and an automated path walking system. Make NPCs play animations, spawn particles, say messages, and walk patrol routes — all without writing code.


These functions are available in Cobblemon NPC dialogue scripts and interactions. Call them on the npc object.

npc.play_animation('wave')
npc.play_animation('point', 'player-uuid-here')
FunctionDescription
npc.play_animation(name)Play animation for all nearby players
npc.play_animation(name, playerUuid)Play animation for a specific player only

Returns 1.0 on success, 0.0 on failure.

npc.say('Hello there! I am %npc%!')
npc.say('Welcome back, trainer!', 'player-uuid')
FunctionDescription
npc.say(message)Send message to all players within 64 blocks
npc.say(message, playerUuid)Send message to a specific player

Use %npc% as a placeholder for the NPC’s name.

npc.distance_to_player('player-uuid')

Returns distance in blocks between the NPC and the specified player.


Control NPC patrol routes from scripts.

FunctionReturnsDescription
npc.walk_path('path_id')1.0/0.0Start walking a path
npc.stop_walking()1.0/0.0Stop the current path
npc.pause_walking()1.0/0.0Pause (can resume later)
npc.resume_walking()1.0/0.0Resume a paused path
npc.is_walking_path()1.0/0.0Check if currently walking
npc.walking_progress()0.0-100.0Progress percentage along path
npc.assign_path('path_id')1.0Assign path (persists across restarts)
npc.assign_path('path_id', 0.0)1.0Assign path without auto-starting
npc.unassign_path()1.0Remove assigned path
npc.has_assigned_path()1.0/0.0Check if a path is assigned
npc.get_assigned_path()StringGet assigned path ID (empty if none)

Paths are JSON files that define a sequence of waypoints for NPCs to walk.

File location: config/journey/paths/<name>.json

{
"id": "guard_patrol",
"name": "Guard Patrol Route",
"nodes": [
{
"position": {"x": 100, "y": 64, "z": 100},
"look_target": {"x": 100, "y": 64, "z": 110},
"script": "q.wait_seconds(2);"
},
{
"position": {"x": 120, "y": 64, "z": 100},
"look_target": {"x": 120, "y": 64, "z": 110},
"script": "q.wait_seconds(2);"
},
{
"position": {"x": 120, "y": 64, "z": 120},
"script": "q.wait(10);"
}
],
"loop": true,
"speed_multiplier": 0.8,
"description": "Rectangular patrol with 2-second pauses"
}
FieldTypeDefaultDescription
idStringRequiredUnique identifier
nameStringRequiredHuman-readable name
nodesArrayRequiredList of waypoints (at least 1)
loopBooleanfalseRepeat from beginning after reaching the end
speed_multiplierFloat1.0Movement speed (0.5 = slow, 2.0 = fast)
descriptionString""Optional description
FieldTypeRequiredDescription
position{x, y, z}YesWorld coordinates to walk to
look_target{x, y, z}NoCoordinates NPC faces at this node
scriptStringNoMoLang to execute when NPC reaches this node

If look_target is omitted, the NPC looks toward the next node.

Scripts run when the NPC arrives at a node. Common uses:

{"script": "q.wait_seconds(5);"}
{"script": "q.wait(20);"}
{"script": ""}
FunctionDescription
q.wait(ticks)Pause for a number of ticks (20 ticks = 1 second)
q.wait_seconds(seconds)Pause for a number of seconds
q.is_waiting()Returns 1.0 if currently paused
q.wait_remaining()Remaining wait ticks

File: config/journey/npc_paths.json

[
{
"npc_uuid": "0af627fe-3254-48b0-9892-881a42512c43",
"assigned_path_id": "guard_patrol",
"auto_start": true,
"current_index": 0,
"is_complete": false,
"is_paused": false,
"reach_threshold": 0.9
}
]
FieldDefaultDescription
npc_uuidRequiredUUID of the Cobblemon NPC entity
assigned_path_idRequiredPath ID to follow
auto_starttrueStart walking when the NPC loads
current_index0Current waypoint (auto-managed)
is_completefalseWhether the path finished (auto-managed)
is_pausedfalseWhether walking is paused
reach_threshold0.9Blocks away to count as “arrived” at a node
npc.assign_path('guard_patrol')

This persists across server restarts.


MultiplierFeel
0.5Slow, cautious
0.8Patrol pace
1.0Normal walking
1.5Brisk walk
2.0Running

How close the NPC must get before moving to the next node:

  • 0.2-0.5 — Precise positioning (tight spaces)
  • 0.9 — Default (works for most paths)
  • 1.5-2.0 — Forgiving (rough terrain)
  • loop: true — Returns to the first node after reaching the last. Repeats forever. Use for patrols and circular routes.
  • loop: false — Stops at the last node. Use for one-way deliveries or scripted movement.

The system automatically handles stuck NPCs:

  • If an NPC moves less than 0.05 blocks for 3 seconds, it’s considered stuck
  • If close to the target node, it force-advances to the next node
  • If far from the target, it gets a speed boost and gentle push toward the waypoint

Path progress saves automatically:

  • Every 10 seconds during normal walking
  • When the path completes, is paused, or is cancelled
  • When the NPC unloads

On server restart, NPCs resume from their saved position.


Preview paths in-game using particle effects.

q.player.toggle_path_visualization()
q.player.show_path_visualization(true)
q.player.preview_path('guard_patrol')
/journey pathmanager

Opens an interactive editor for creating, editing, and previewing paths.

  • END_ROD particles connect nodes in sequence
  • ENCHANT particles show the loop connection (last node back to first)
  • Circular markers at each waypoint
  • Arrows showing look direction
  • Visible up to 64 blocks away, updates every 0.5 seconds

{
"id": "merchant_route",
"name": "Traveling Merchant Route",
"nodes": [
{
"position": {"x": 0, "y": 64, "z": 0},
"look_target": {"x": 5, "y": 64, "z": 0},
"script": "q.wait_seconds(30);"
},
{
"position": {"x": 100, "y": 64, "z": 0},
"script": ""
},
{
"position": {"x": 100, "y": 64, "z": 100},
"look_target": {"x": 105, "y": 64, "z": 105},
"script": "q.wait_seconds(30);"
},
{
"position": {"x": 0, "y": 64, "z": 100},
"script": ""
}
],
"loop": true,
"speed_multiplier": 0.6,
"description": "Merchant visits two towns, stays 30 seconds at each"
}
{
"id": "messenger_delivery",
"name": "Urgent Delivery",
"nodes": [
{"position": {"x": 0, "y": 64, "z": 0}, "script": ""},
{"position": {"x": 50, "y": 64, "z": 50}, "script": "q.wait(10);"},
{
"position": {"x": 100, "y": 64, "z": 0},
"look_target": {"x": 110, "y": 64, "z": 0},
"script": "q.wait_seconds(5);"
}
],
"loop": false,
"speed_multiplier": 1.5,
"description": "Fast one-way delivery"
}
// In a Cobblemon dialogue script:
npc.play_animation('greet');
npc.say('Welcome, %npc% here!');
// Conditional message based on player state
q.player.has_flag('quest_available') ?
npc.say('I have a quest for you!') :
0.0

  • Add intermediate nodes for smooth turns instead of sharp corners
  • Space nodes 2-5 blocks apart for curved paths, 10-20 blocks for straight routes
  • Match speed to the NPC’s role: guards patrol slowly (0.7-0.9), messengers run fast (1.3-1.8)
  • Use look_target to point NPCs at interesting things (shops, signs, other NPCs) when they pause
  • Use descriptive path IDs: town_guard_patrol_north is better than path_1
  • Test paths with visualization before assigning to NPCs
  • If an NPC gets stuck, try increasing reach_threshold to 1.5 or adding intermediate nodes